From 93313b0ce3aada87f76948e6c65d455ee4998acf Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 19 Jan 2020 23:33:52 -0500 Subject: Bug 1406325 - Part 5: Implement try to upgrade. Tag UXP Issue #1344 --- dom/base/CustomElementRegistry.cpp | 18 +++++++++++ dom/base/CustomElementRegistry.h | 24 +++++++++------ dom/base/Element.cpp | 22 +++++++++++--- dom/base/nsContentUtils.cpp | 62 ++++++++++++++++++++++++++++++++++++++ dom/base/nsContentUtils.h | 9 ++++++ 5 files changed, 121 insertions(+), 14 deletions(-) diff --git a/dom/base/CustomElementRegistry.cpp b/dom/base/CustomElementRegistry.cpp index fe2837f2a..59e107b14 100644 --- a/dom/base/CustomElementRegistry.cpp +++ b/dom/base/CustomElementRegistry.cpp @@ -333,6 +333,24 @@ CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTy return; } +void +CustomElementRegistry::UnregisterUnresolvedElement(Element* aElement, + nsIAtom* aTypeName) +{ + nsTArray* candidates; + if (mCandidatesMap.Get(aTypeName, &candidates)) { + MOZ_ASSERT(candidates); + // We don't need to iterate the candidates array and remove the element from + // the array for performance reason. It'll be handled by bug 1396620. + for (size_t i = 0; i < candidates->Length(); ++i) { + nsCOMPtr elem = do_QueryReferent(candidates->ElementAt(i)); + if (elem && elem.get() == aElement) { + candidates->RemoveElementAt(i); + } + } + } +} + /* static */ UniquePtr CustomElementRegistry::CreateCustomElementCallback( nsIDocument::ElementCallbackType aType, Element* aCustomElement, diff --git a/dom/base/CustomElementRegistry.h b/dom/base/CustomElementRegistry.h index 81d1c003c..eb4285fd2 100644 --- a/dom/base/CustomElementRegistry.h +++ b/dom/base/CustomElementRegistry.h @@ -383,15 +383,6 @@ public: */ static void Upgrade(Element* aElement, CustomElementDefinition* aDefinition, ErrorResult& aRv); -private: - ~CustomElementRegistry(); - - static UniquePtr CreateCustomElementCallback( - nsIDocument::ElementCallbackType aType, Element* aCustomElement, - LifecycleCallbackArgs* aArgs, - LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs, - CustomElementDefinition* aDefinition); - /** * Registers an unresolved custom element that is a candidate for * upgrade when the definition is registered via registerElement. @@ -403,6 +394,21 @@ private: void RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName = nullptr); + /** + * Unregister an unresolved custom element that is a candidate for + * upgrade when a custom element is removed from tree. + */ + void UnregisterUnresolvedElement(Element* aElement, + nsIAtom* aTypeName = nullptr); +private: + ~CustomElementRegistry(); + + static UniquePtr CreateCustomElementCallback( + nsIDocument::ElementCallbackType aType, Element* aCustomElement, + LifecycleCallbackArgs* aArgs, + LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs, + CustomElementDefinition* aDefinition); + void UpgradeCandidates(nsIAtom* aKey, CustomElementDefinition* aDefinition, ErrorResult& aRv); diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index fdaaed62a..e77b43b86 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -1688,8 +1688,13 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent, // Connected callback must be enqueued whenever a custom element becomes // connected. CustomElementData* data = GetCustomElementData(); - if (data && data->mState == CustomElementData::State::eCustom) { - nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eConnected, this); + if (data) { + if (data->mState == CustomElementData::State::eCustom) { + nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eConnected, this); + } else { + // Step 7.7.2.2 https://dom.spec.whatwg.org/#concept-node-insert + nsContentUtils::TryToUpgradeElement(this); + } } } @@ -1988,9 +1993,16 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent) // disconnected. if (CustomElementRegistry::IsCustomElementEnabled()) { CustomElementData* data = GetCustomElementData(); - if (data && data->mState == CustomElementData::State::eCustom) { - nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eDisconnected, - this); + if (data) { + if (data->mState == CustomElementData::State::eCustom) { + nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eDisconnected, + this); + } else { + // Remove an unresolved custom element that is a candidate for + // upgrade when a custom element is disconnected. + // We will make sure it's shadow-including tree order in bug 1326028. + nsContentUtils::UnregisterUnresolvedElement(this); + } } } } diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 8c157a8ee..87c879746 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -227,6 +227,7 @@ extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end, int ns_aware, const char** colon); class imgLoader; +class nsIAtom; using namespace mozilla::dom; using namespace mozilla::ipc; @@ -9575,6 +9576,27 @@ nsContentUtils::HttpsStateIsModern(nsIDocument* aDocument) return false; } +/* static */ void +nsContentUtils::TryToUpgradeElement(Element* aElement) +{ + NodeInfo* nodeInfo = aElement->NodeInfo(); + RefPtr typeAtom = + aElement->GetCustomElementData()->GetCustomElementType(); + CustomElementDefinition* definition = + nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(), + nodeInfo->LocalName(), + nodeInfo->NamespaceID(), + typeAtom); + if (definition) { + nsContentUtils::EnqueueUpgradeReaction(aElement, definition); + } else { + // Add an unresolved custom element that is a candidate for + // upgrade when a custom element is connected to the document. + // We will make sure it's shadow-including tree order in bug 1326028. + nsContentUtils::RegisterUnresolvedElement(aElement, typeAtom); + } +} + /* static */ CustomElementDefinition* nsContentUtils::LookupCustomElementDefinition(nsIDocument* aDoc, const nsAString& aLocalName, @@ -9604,6 +9626,46 @@ nsContentUtils::LookupCustomElementDefinition(nsIDocument* aDoc, return registry->LookupCustomElementDefinition(aLocalName, aTypeAtom); } +/* static */ void +nsContentUtils::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName) +{ + MOZ_ASSERT(aElement); + + nsIDocument* doc = aElement->OwnerDoc(); + nsPIDOMWindowInner* window(doc->GetInnerWindow()); + if (!window) { + return; + } + + RefPtr registry(window->CustomElements()); + if (!registry) { + return; + } + + registry->RegisterUnresolvedElement(aElement, aTypeName); +} + +/* static */ void +nsContentUtils::UnregisterUnresolvedElement(Element* aElement) +{ + MOZ_ASSERT(aElement); + + RefPtr typeAtom = + aElement->GetCustomElementData()->GetCustomElementType(); + nsIDocument* doc = aElement->OwnerDoc(); + nsPIDOMWindowInner* window(doc->GetInnerWindow()); + if (!window) { + return; + } + + RefPtr registry(window->CustomElements()); + if (!registry) { + return; + } + + registry->UnregisterUnresolvedElement(aElement, typeAtom); +} + /* static */ CustomElementDefinition* nsContentUtils::GetElementDefinitionIfObservingAttr(Element* aCustomElement, nsIAtom* aExtensionType, diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 367ea7c13..19b007591 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2711,6 +2711,12 @@ public: */ static bool HttpsStateIsModern(nsIDocument* aDocument); + /** + * Try to upgrade an element. + * https://html.spec.whatwg.org/multipage/custom-elements.html#concept-try-upgrade + */ + static void TryToUpgradeElement(Element* aElement); + /** * Looking up a custom element definition. * https://html.spec.whatwg.org/#look-up-a-custom-element-definition @@ -2721,6 +2727,9 @@ public: uint32_t aNameSpaceID, nsIAtom* aTypeAtom); + static void RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName); + static void UnregisterUnresolvedElement(Element* aElement); + static mozilla::dom::CustomElementDefinition* GetElementDefinitionIfObservingAttr(Element* aCustomElement, nsIAtom* aExtensionType, -- cgit v1.2.3