From 704318ea0a9f55cad18c4ea7f2a6805485a33d39 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 5 Jan 2020 11:21:03 -0500 Subject: Bug 1299363 - Part 5-2: Implement new upgrade steps. Tag UXP Issue #1344 --- dom/base/CustomElementRegistry.cpp | 182 +++++++++++++++++++++++++++++++------ dom/base/CustomElementRegistry.h | 30 ++++-- 2 files changed, 177 insertions(+), 35 deletions(-) diff --git a/dom/base/CustomElementRegistry.cpp b/dom/base/CustomElementRegistry.cpp index ce2e4b04f..e619ad599 100644 --- a/dom/base/CustomElementRegistry.cpp +++ b/dom/base/CustomElementRegistry.cpp @@ -19,7 +19,7 @@ namespace dom { void CustomElementCallback::Call() { - ErrorResult rv; + IgnoredErrorResult rv; switch (mType) { case nsIDocument::eCreated: { @@ -55,10 +55,6 @@ CustomElementCallback::Call() mArgs.name, mArgs.oldValue, mArgs.newValue, rv); break; } - - // If callbacks throw exceptions, it'll be handled and reported in - // Lifecycle*Callback::Call function. - rv.SuppressException(); } void @@ -82,6 +78,38 @@ CustomElementCallback::CustomElementCallback(Element* aThisObject, { } +//----------------------------------------------------- +// CustomElementConstructor + +already_AddRefed +CustomElementConstructor::Construct(const char* aExecutionReason, + ErrorResult& aRv) +{ + CallSetup s(this, aRv, aExecutionReason, + CallbackFunction::eRethrowExceptions); + + JSContext* cx = s.GetContext(); + if (!cx) { + MOZ_ASSERT(aRv.Failed()); + return nullptr; + } + + JS::Rooted result(cx); + JS::Rooted constructor(cx, JS::ObjectValue(*mCallback)); + if (!JS::Construct(cx, constructor, JS::HandleValueArray::empty(), &result)) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } + + RefPtr element; + if (NS_FAILED(UNWRAP_OBJECT(Element, &result, element))) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } + + return element.forget(); +} + //----------------------------------------------------- // CustomElementData @@ -101,6 +129,33 @@ CustomElementData::CustomElementData(nsIAtom* aType, State aState) //----------------------------------------------------- // CustomElementRegistry +namespace { + +class MOZ_RAII AutoConstructionStackEntry final +{ +public: + AutoConstructionStackEntry(nsTArray>& aStack, + nsGenericHTMLElement* aElement) + : mStack(aStack) + { + mIndex = mStack.Length(); + mStack.AppendElement(aElement); + } + + ~AutoConstructionStackEntry() + { + MOZ_ASSERT(mIndex == mStack.Length() - 1, + "Removed element should be the last element"); + mStack.RemoveElementAt(mIndex); + } + +private: + nsTArray>& mStack; + uint32_t mIndex; +}; + +} // namespace anonymous + // Only needed for refcounted objects. NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementRegistry) @@ -139,6 +194,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementRegistry) "mCustomDefinitions->mCallbacks->mDetachedCallback"); cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value()); } + + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, + "mCustomDefinitions->mConstructor"); + cb.NoteXPCOMChild(iter.UserData()->mConstructor); } NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWhenDefinedPromiseMap) @@ -147,9 +206,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CustomElementRegistry) for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) { - aCallbacks.Trace(&iter.UserData()->mConstructor, - "mCustomDefinitions constructor", - aClosure); aCallbacks.Trace(&iter.UserData()->mPrototype, "mCustomDefinitions prototype", aClosure); @@ -418,6 +474,7 @@ CustomElementRegistry::UpgradeCandidates(nsIAtom* aKey, return; } + // TODO: Bug 1326028 - Upgrade custom element in shadow-including tree order nsAutoPtr> candidates; mCandidatesMap.RemoveAndForget(aKey, candidates); if (candidates) { @@ -696,7 +753,7 @@ CustomElementRegistry::Define(const nsAString& aName, CustomElementDefinition* definition = new CustomElementDefinition(nameAtom, localNameAtom, - constructor, + &aFunctionConstructor, constructorPrototype, callbacks, 0 /* TODO dependent on HTML imports. Bug 877072 */); @@ -717,7 +774,6 @@ CustomElementRegistry::Define(const nsAString& aName, /** * 13. 14. 15. Upgrade candidates */ - // TODO: Bug 1299363 - Implement custom element v1 upgrade algorithm UpgradeCandidates(nameAtom, definition, aRv); /** @@ -748,7 +804,7 @@ CustomElementRegistry::Get(JSContext* aCx, const nsAString& aName, return; } - aRetVal.setObject(*data->mConstructor); + aRetVal.setObjectOrNull(data->mConstructor->Callable()); return; } @@ -782,23 +838,67 @@ CustomElementRegistry::WhenDefined(const nsAString& aName, ErrorResult& aRv) return promise.forget(); } +namespace { + +static void +DoUpgrade(Element* aElement, + CustomElementConstructor* aConstructor, + ErrorResult& aRv) +{ + // Rethrow the exception since it might actually throw the exception from the + // upgrade steps back out to the caller of document.createElement. + RefPtr constructResult = + aConstructor->Construct("Custom Element Upgrade", aRv); + if (aRv.Failed()) { + return; + } + + if (constructResult.get() != aElement) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return; + } +} + +} // anonymous namespace + +// https://html.spec.whatwg.org/multipage/scripting.html#upgrades void CustomElementRegistry::Upgrade(Element* aElement, - CustomElementDefinition* aDefinition) + CustomElementDefinition* aDefinition, + ErrorResult& aRv) { - // TODO: This function will be replaced to v1 upgrade in bug 1299363 aElement->RemoveStates(NS_EVENT_STATE_UNRESOLVED); - // Make sure that the element name matches the name in the definition. - // (e.g. a definition for x-button extending button should match - //