From 99fd13b6dd86d4025fe85503890e583904148dfa Mon Sep 17 00:00:00 2001 From: Fedor Date: Thu, 12 Mar 2020 20:41:43 +0300 Subject: [PATCH] Implement Custom Elements v1. --- dom/base/CustomElementRegistry.cpp | 1010 ++-- dom/base/CustomElementRegistry.h | 427 +- dom/base/DocGroup.cpp | 3 + dom/base/DocGroup.h | 10 + dom/base/Element.cpp | 158 +- dom/base/Element.h | 41 +- dom/base/FragmentOrElement.cpp | 171 +- dom/base/FragmentOrElement.h | 132 +- dom/base/ShadowRoot.cpp | 4 +- dom/base/crashtests/1341693.html | 13 + dom/base/crashtests/crashtests.list | 1 + dom/base/nsContentCreatorFunctions.h | 4 +- dom/base/nsContentUtils.cpp | 182 +- dom/base/nsContentUtils.h | 60 +- dom/base/nsDOMMutationObserver.cpp | 67 +- dom/base/nsDOMMutationObserver.h | 23 +- dom/base/nsDocument.cpp | 179 +- dom/base/nsDocument.h | 14 - dom/base/nsGenericDOMDataNode.cpp | 11 - dom/base/nsGenericDOMDataNode.h | 3 - dom/base/nsGlobalWindow.cpp | 3 +- dom/base/nsIContent.h | 17 - dom/base/nsIDocument.h | 50 +- dom/base/nsJSUtils.cpp | 11 +- dom/base/nsNodeUtils.cpp | 64 +- dom/base/test/chrome/registerElement_ep.js | 4 +- .../chrome/test_registerElement_content.xul | 25 +- .../test/chrome/test_registerElement_ep.xul | 4 +- dom/base/test/test_mutationobservers.html | 33 +- dom/bindings/BindingUtils.cpp | 212 + dom/bindings/BindingUtils.h | 15 + dom/bindings/Bindings.conf | 9 + dom/bindings/CallbackObject.cpp | 11 +- dom/bindings/Codegen.py | 152 +- dom/bindings/parser/WebIDL.py | 47 +- dom/bindings/parser/tests/test_cereactions.py | 162 + dom/bindings/parser/tests/test_constructor.py | 166 +- .../test_constructor_no_interface_object.py | 33 + dom/bindings/test/TestBindingHeader.h | 30 + dom/bindings/test/TestCodeGen.webidl | 17 + dom/bindings/test/TestExampleGen.webidl | 4 + dom/bindings/test/TestJSImplGen.webidl | 4 + dom/bindings/test/test_bug560072.html | 5 +- dom/events/EventListenerManager.cpp | 10 +- dom/flyweb/FlyWebDiscoveryManager.cpp | 1 + dom/html/HTMLDetailsElement.cpp | 30 +- dom/html/HTMLDetailsElement.h | 2 - dom/html/HTMLElement.cpp | 9 + dom/html/HTMLSummaryElement.cpp | 12 +- dom/html/nsGenericHTMLElement.cpp | 6 +- dom/html/nsGenericHTMLElement.h | 16 + dom/html/nsHTMLContentSink.cpp | 141 +- dom/html/nsHTMLDocument.cpp | 59 +- dom/html/nsHTMLDocument.h | 4 +- dom/jsurl/nsJSProtocolHandler.cpp | 3 +- dom/svg/SVGElementFactory.cpp | 56 +- dom/svg/SVGElementFactory.h | 25 + dom/svg/SVGTagList.h | 9 +- dom/svg/moz.build | 2 + dom/tests/mochitest/webcomponents/chrome.ini | 9 + .../mochitest/webcomponents/dummy_page.html | 10 + .../htmlconstructor_autonomous_tests.js | 81 + .../htmlconstructor_builtin_tests.js | 247 + .../mochitest/webcomponents/mochitest.ini | 18 +- .../webcomponents/test_bug1276240.html | 2 +- .../test_custom_element_adopt_callbacks.html | 29 - ...est_custom_element_callback_innerhtml.html | 12 +- .../test_custom_element_clone_callbacks.html | 54 - ...stom_element_clone_callbacks_extended.html | 40 - .../test_custom_element_htmlconstructor.html | 42 + ...custom_element_htmlconstructor_chrome.html | 41 + ..._element_import_node_created_callback.html | 34 - ...om_element_register_invalid_callbacks.html | 3 - ...ent_throw_on_dynamic_markup_insertion.html | 66 + ..._custom_element_uncatchable_exception.html | 37 + .../webcomponents/test_document_register.html | 40 - .../test_document_register_base_queue.html | 48 - .../test_document_register_parser.html | 4 +- .../test_document_register_stack.html | 4 +- .../test_document_shared_registry.html | 33 - dom/tests/moz.build | 1 + dom/webidl/Attr.webidl | 2 +- dom/webidl/CSSStyleDeclaration.webidl | 6 +- dom/webidl/ChildNode.webidl | 8 +- dom/webidl/CustomElementRegistry.webidl | 2 +- dom/webidl/DOMStringMap.webidl | 3 +- dom/webidl/DOMTokenList.webidl | 12 +- dom/webidl/Document.webidl | 8 +- dom/webidl/Element.webidl | 28 +- dom/webidl/EventHandler.webidl | 1 - dom/webidl/HTMLAnchorElement.webidl | 27 +- dom/webidl/HTMLAreaElement.webidl | 17 +- dom/webidl/HTMLAudioElement.webidl | 2 +- dom/webidl/HTMLBRElement.webidl | 3 +- dom/webidl/HTMLBaseElement.webidl | 5 +- dom/webidl/HTMLBodyElement.webidl | 19 +- dom/webidl/HTMLButtonElement.webidl | 21 +- dom/webidl/HTMLCanvasElement.webidl | 5 +- dom/webidl/HTMLDListElement.webidl | 3 +- dom/webidl/HTMLDataElement.webidl | 3 +- dom/webidl/HTMLDataListElement.webidl | 1 + dom/webidl/HTMLDetailsElement.webidl | 4 +- dom/webidl/HTMLDialogElement.webidl | 10 +- dom/webidl/HTMLDirectoryElement.webidl | 3 +- dom/webidl/HTMLDivElement.webidl | 3 +- dom/webidl/HTMLDocument.webidl | 26 +- dom/webidl/HTMLElement.webidl | 17 +- dom/webidl/HTMLEmbedElement.webidl | 14 +- dom/webidl/HTMLFieldSetElement.webidl | 5 +- dom/webidl/HTMLFontElement.webidl | 7 +- dom/webidl/HTMLFormElement.webidl | 21 +- dom/webidl/HTMLFrameElement.webidl | 19 +- dom/webidl/HTMLFrameSetElement.webidl | 5 +- dom/webidl/HTMLHRElement.webidl | 11 +- dom/webidl/HTMLHeadElement.webidl | 1 + dom/webidl/HTMLHeadingElement.webidl | 3 +- dom/webidl/HTMLHtmlElement.webidl | 3 +- dom/webidl/HTMLHyperlinkElementUtils.webidl | 11 +- dom/webidl/HTMLIFrameElement.webidl | 29 +- dom/webidl/HTMLImageElement.webidl | 36 +- dom/webidl/HTMLInputElement.webidl | 64 +- dom/webidl/HTMLLIElement.webidl | 5 +- dom/webidl/HTMLLabelElement.webidl | 2 + dom/webidl/HTMLLegendElement.webidl | 3 +- dom/webidl/HTMLLinkElement.webidl | 23 +- dom/webidl/HTMLMapElement.webidl | 3 +- dom/webidl/HTMLMediaElement.webidl | 14 +- dom/webidl/HTMLMenuElement.webidl | 7 +- dom/webidl/HTMLMenuItemElement.webidl | 15 +- dom/webidl/HTMLMetaElement.webidl | 9 +- dom/webidl/HTMLMeterElement.webidl | 13 +- dom/webidl/HTMLModElement.webidl | 5 +- dom/webidl/HTMLOListElement.webidl | 9 +- dom/webidl/HTMLObjectElement.webidl | 36 +- dom/webidl/HTMLOptGroupElement.webidl | 5 +- dom/webidl/HTMLOptionElement.webidl | 14 +- dom/webidl/HTMLOptionsCollection.webidl | 9 +- dom/webidl/HTMLOutputElement.webidl | 7 +- dom/webidl/HTMLParagraphElement.webidl | 3 +- dom/webidl/HTMLParamElement.webidl | 9 +- dom/webidl/HTMLPictureElement.webidl | 1 + dom/webidl/HTMLPreElement.webidl | 3 +- dom/webidl/HTMLProgressElement.webidl | 5 +- dom/webidl/HTMLQuoteElement.webidl | 3 +- dom/webidl/HTMLScriptElement.webidl | 23 +- dom/webidl/HTMLSelectElement.webidl | 23 +- dom/webidl/HTMLSourceElement.webidl | 11 +- dom/webidl/HTMLSpanElement.webidl | 1 + dom/webidl/HTMLStyleElement.webidl | 5 +- dom/webidl/HTMLTableCaptionElement.webidl | 3 +- dom/webidl/HTMLTableCellElement.webidl | 30 +- dom/webidl/HTMLTableColElement.webidl | 13 +- dom/webidl/HTMLTableElement.webidl | 33 +- dom/webidl/HTMLTableRowElement.webidl | 14 +- dom/webidl/HTMLTableSectionElement.webidl | 11 +- dom/webidl/HTMLTemplateElement.webidl | 1 + dom/webidl/HTMLTextAreaElement.webidl | 27 +- dom/webidl/HTMLTimeElement.webidl | 3 +- dom/webidl/HTMLTitleElement.webidl | 3 +- dom/webidl/HTMLTrackElement.webidl | 11 +- dom/webidl/HTMLUListElement.webidl | 5 +- dom/webidl/HTMLVideoElement.webidl | 7 +- dom/webidl/NamedNodeMap.webidl | 8 +- dom/webidl/Node.webidl | 14 +- dom/webidl/ParentNode.webidl | 4 +- dom/webidl/Range.webidl | 12 +- dom/webidl/ShadowRoot.webidl | 2 +- dom/webidl/WebComponents.webidl | 18 +- dom/webidl/XSLTProcessor.webidl | 4 +- dom/xul/nsXULElement.cpp | 52 +- dom/xul/nsXULElement.h | 17 +- .../tests/mochitest/test_bug1094930.html | 6 +- layout/base/nsCSSFrameConstructor.cpp | 8 +- layout/build/nsLayoutStatics.cpp | 2 - layout/generic/crashtests/crashtests.list | 16 +- layout/generic/nsContainerFrame.cpp | 10 +- .../disabled-no-summary-ref.html | 11 - .../disabled-single-summary-ref.html | 12 - .../details-summary/reftest-stylo.list | 6 - layout/reftests/details-summary/reftest.list | 7 - layout/style/nsLayoutStylesheetCache.cpp | 10 +- modules/libpref/init/all.js | 3 - parser/html/java/README.txt | 41 +- .../htmlparser/annotation/Creator.java | 30 + .../htmlparser/annotation/HtmlCreator.java | 30 + .../htmlparser/annotation/SvgCreator.java | 30 + .../htmlparser/annotation/Unsigned.java | 30 + .../htmlparser/impl/AttributeName.java | 3609 ++++++------- .../impl/CoalescingTreeBuilder.java | 11 +- .../htmlparser/impl/ElementName.java | 3940 +++++++++----- .../impl/ErrorReportingTokenizer.java | 12 +- .../htmlparser/impl/HtmlAttributes.java | 126 +- .../validator/htmlparser/impl/StackNode.java | 57 +- .../validator/htmlparser/impl/Tokenizer.java | 144 +- .../htmlparser/impl/TreeBuilder.java | 386 +- .../validator/htmlparser/sax/SAXStreamer.java | 20 +- .../htmlparser/sax/SAXTreeBuilder.java | 14 +- .../test/JSONArrayTokenHandler.java | 14 +- .../htmlparser/test/TokenPrinter.java | 14 +- .../cpptranslate/AnnotationHelperVisitor.java | 16 + .../htmlparser/cpptranslate/CppTypes.java | 19 +- .../htmlparser/cpptranslate/CppVisitor.java | 84 +- .../htmlparser/cpptranslate/HVisitor.java | 41 +- .../htmlparser/cpptranslate/Main.java | 19 +- .../htmlparser/cpptranslate/SymbolTable.java | 33 +- parser/html/moz.build | 6 +- parser/html/nsHtml5AtomList.h | 1907 +++---- parser/html/nsHtml5AttributeEntry.h | 91 + parser/html/nsHtml5AttributeName.cpp | 4567 ++++++++--------- parser/html/nsHtml5AttributeName.h | 1221 +++-- parser/html/nsHtml5ContentCreatorFunction.h | 17 + parser/html/nsHtml5ElementName.cpp | 2959 ++++++----- parser/html/nsHtml5ElementName.h | 806 +-- parser/html/nsHtml5Highlighter.cpp | 282 +- parser/html/nsHtml5Highlighter.h | 9 +- parser/html/nsHtml5HtmlAttributes.cpp | 200 +- parser/html/nsHtml5HtmlAttributes.h | 54 +- parser/html/nsHtml5MetaScanner.cpp | 199 +- parser/html/nsHtml5MetaScanner.h | 93 +- parser/html/nsHtml5Portability.h | 8 +- .../html/nsHtml5ReleasableAttributeName.cpp | 34 - parser/html/nsHtml5ReleasableAttributeName.h | 21 - parser/html/nsHtml5ReleasableElementName.cpp | 30 - parser/html/nsHtml5ReleasableElementName.h | 19 - parser/html/nsHtml5StackNode.cpp | 75 +- parser/html/nsHtml5StackNode.h | 13 +- parser/html/nsHtml5StateSnapshot.cpp | 7 +- parser/html/nsHtml5StateSnapshot.h | 9 +- parser/html/nsHtml5Tokenizer.cpp | 859 ++-- parser/html/nsHtml5Tokenizer.h | 243 +- parser/html/nsHtml5TokenizerCppSupplement.h | 2 +- parser/html/nsHtml5TreeBuilder.cpp | 1638 +++--- parser/html/nsHtml5TreeBuilder.h | 349 +- parser/html/nsHtml5TreeBuilderCppSupplement.h | 75 +- parser/html/nsHtml5TreeOperation.cpp | 421 +- parser/html/nsHtml5TreeOperation.h | 67 +- parser/html/nsHtml5UTF16Buffer.cpp | 7 +- parser/html/nsHtml5UTF16Buffer.h | 9 +- parser/htmlparser/nsHTMLTagList.h | 198 +- parser/htmlparser/nsHTMLTags.cpp | 12 +- parser/htmlparser/nsHTMLTags.h | 8 +- .../CustomElementRegistry.html.ini | 18 - .../custom-elements/adopted-callback.html.ini | 87 - .../attribute-changed-callback.html.ini | 16 - .../connected-callbacks.html.ini | 48 - .../custom-element-registry/define.html.ini | 26 - .../disconnected-callbacks.html.ini | 48 - .../custom-elements/reaction-timing.html.ini | 5 - .../reactions/ChildNode.html.ini | 23 - .../reactions/Document.html.ini | 4 - .../custom-elements/reactions/Node.html.ini | 44 - .../reactions/ParentNode.html.ini | 14 - .../custom-elements/reactions/Range.html.ini | 23 - .../meta/html/dom/interfaces.html.ini | 2 +- .../meta/html/dom/reflection-misc.html.ini | 2 +- .../the-details-element/details.html.ini | 3 - .../the-details-element/toggleEvent.html.ini | 3 - .../meta/html/semantics/interfaces.html.ini | 2 +- .../web-platform/meta/svg/interfaces.html.ini | 1 - .../attribute-changed-callback.html | 31 + .../reactions/with-exceptions.html | 31 + .../dom-tree-accessors/Document.body.html | 50 + xpcom/base/CycleCollectedJSContext.cpp | 71 +- xpcom/base/CycleCollectedJSContext.h | 69 + xpcom/base/moz.build | 1 + 265 files changed, 18152 insertions(+), 13653 deletions(-) create mode 100644 dom/base/crashtests/1341693.html create mode 100644 dom/bindings/parser/tests/test_cereactions.py create mode 100644 dom/tests/mochitest/webcomponents/chrome.ini create mode 100644 dom/tests/mochitest/webcomponents/dummy_page.html create mode 100644 dom/tests/mochitest/webcomponents/htmlconstructor_autonomous_tests.js create mode 100644 dom/tests/mochitest/webcomponents/htmlconstructor_builtin_tests.js delete mode 100644 dom/tests/mochitest/webcomponents/test_custom_element_adopt_callbacks.html delete mode 100644 dom/tests/mochitest/webcomponents/test_custom_element_clone_callbacks.html delete mode 100644 dom/tests/mochitest/webcomponents/test_custom_element_clone_callbacks_extended.html create mode 100644 dom/tests/mochitest/webcomponents/test_custom_element_htmlconstructor.html create mode 100644 dom/tests/mochitest/webcomponents/test_custom_element_htmlconstructor_chrome.html delete mode 100644 dom/tests/mochitest/webcomponents/test_custom_element_import_node_created_callback.html create mode 100644 dom/tests/mochitest/webcomponents/test_custom_element_throw_on_dynamic_markup_insertion.html create mode 100644 dom/tests/mochitest/webcomponents/test_custom_element_uncatchable_exception.html delete mode 100644 dom/tests/mochitest/webcomponents/test_document_register_base_queue.html delete mode 100644 layout/reftests/details-summary/disabled-no-summary-ref.html delete mode 100644 layout/reftests/details-summary/disabled-single-summary-ref.html create mode 100644 parser/html/java/htmlparser/src/nu/validator/htmlparser/annotation/Creator.java create mode 100644 parser/html/java/htmlparser/src/nu/validator/htmlparser/annotation/HtmlCreator.java create mode 100644 parser/html/java/htmlparser/src/nu/validator/htmlparser/annotation/SvgCreator.java create mode 100644 parser/html/java/htmlparser/src/nu/validator/htmlparser/annotation/Unsigned.java create mode 100644 parser/html/nsHtml5AttributeEntry.h create mode 100644 parser/html/nsHtml5ContentCreatorFunction.h delete mode 100644 parser/html/nsHtml5ReleasableAttributeName.cpp delete mode 100644 parser/html/nsHtml5ReleasableAttributeName.h delete mode 100644 parser/html/nsHtml5ReleasableElementName.cpp delete mode 100644 parser/html/nsHtml5ReleasableElementName.h delete mode 100644 testing/web-platform/meta/custom-elements/custom-element-registry/define.html.ini delete mode 100644 testing/web-platform/meta/custom-elements/reaction-timing.html.ini delete mode 100644 testing/web-platform/meta/custom-elements/reactions/ChildNode.html.ini delete mode 100644 testing/web-platform/meta/custom-elements/reactions/Node.html.ini delete mode 100644 testing/web-platform/meta/custom-elements/reactions/ParentNode.html.ini delete mode 100644 testing/web-platform/meta/custom-elements/reactions/Range.html.ini delete mode 100644 testing/web-platform/meta/html/semantics/interactive-elements/the-details-element/details.html.ini delete mode 100644 testing/web-platform/meta/html/semantics/interactive-elements/the-details-element/toggleEvent.html.ini create mode 100644 testing/web-platform/tests/custom-elements/reactions/with-exceptions.html diff --git a/dom/base/CustomElementRegistry.cpp b/dom/base/CustomElementRegistry.cpp index 3f202d33b..99452df65 100644 --- a/dom/base/CustomElementRegistry.cpp +++ b/dom/base/CustomElementRegistry.cpp @@ -6,9 +6,11 @@ #include "mozilla/dom/CustomElementRegistry.h" +#include "mozilla/CycleCollectedJSContext.h" #include "mozilla/dom/CustomElementRegistryBinding.h" #include "mozilla/dom/HTMLElementBinding.h" #include "mozilla/dom/WebComponentsBinding.h" +#include "mozilla/dom/DocGroup.h" #include "nsIParserService.h" #include "jsapi.h" @@ -18,40 +20,21 @@ namespace dom { void CustomElementCallback::Call() { - ErrorResult rv; + IgnoredErrorResult rv; switch (mType) { - case nsIDocument::eCreated: - { - // For the duration of this callback invocation, the element is being created - // flag must be set to true. - mOwnerData->mElementIsBeingCreated = true; - - // The callback hasn't actually been invoked yet, but we need to flip - // this now in order to enqueue the attached callback. This is a spec - // bug (w3c bug 27437). - mOwnerData->mCreatedCallbackInvoked = true; - - // If ELEMENT is in a document and this document has a browsing context, - // enqueue attached callback for ELEMENT. - nsIDocument* document = mThisObject->GetComposedDoc(); - if (document && document->GetDocShell()) { - nsContentUtils::EnqueueLifecycleCallback( - document, nsIDocument::eAttached, mThisObject); - } - - static_cast(mCallback.get())->Call(mThisObject, rv); - mOwnerData->mElementIsBeingCreated = false; + case nsIDocument::eConnected: + static_cast(mCallback.get())->Call(mThisObject, rv); break; - } - case nsIDocument::eAttached: - static_cast(mCallback.get())->Call(mThisObject, rv); + case nsIDocument::eDisconnected: + static_cast(mCallback.get())->Call(mThisObject, rv); break; - case nsIDocument::eDetached: - static_cast(mCallback.get())->Call(mThisObject, rv); + case nsIDocument::eAdopted: + static_cast(mCallback.get())->Call(mThisObject, + mAdoptedCallbackArgs.mOldDocument, mAdoptedCallbackArgs.mNewDocument, rv); break; case nsIDocument::eAttributeChanged: static_cast(mCallback.get())->Call(mThisObject, - mArgs.name, mArgs.oldValue, mArgs.newValue, rv); + mArgs.name, mArgs.oldValue, mArgs.newValue, mArgs.namespaceURI, rv); break; } } @@ -68,87 +51,164 @@ CustomElementCallback::Traverse(nsCycleCollectionTraversalCallback& aCb) const CustomElementCallback::CustomElementCallback(Element* aThisObject, nsIDocument::ElementCallbackType aCallbackType, - mozilla::dom::CallbackFunction* aCallback, - CustomElementData* aOwnerData) + mozilla::dom::CallbackFunction* aCallback) : mThisObject(aThisObject), mCallback(aCallback), - mType(aCallbackType), - mOwnerData(aOwnerData) + mType(aCallbackType) { } +//----------------------------------------------------- +// 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.NoteJSContextException(cx); + return nullptr; + } + + RefPtr element; + if (NS_FAILED(UNWRAP_OBJECT(Element, &result, element))) { + return nullptr; + } + + return element.forget(); +} + +//----------------------------------------------------- +// CustomElementData + CustomElementData::CustomElementData(nsIAtom* aType) - : mType(aType), - mCurrentCallback(-1), - mElementIsBeingCreated(false), - mCreatedCallbackInvoked(true), - mAssociatedMicroTask(-1) + : CustomElementData(aType, CustomElementData::State::eUndefined) +{ +} + +CustomElementData::CustomElementData(nsIAtom* aType, State aState) + : mState(aState) + , mType(aType) { } void -CustomElementData::RunCallbackQueue() +CustomElementData::SetCustomElementDefinition(CustomElementDefinition* aDefinition) { - // Note: It's possible to re-enter this method. - while (static_cast(++mCurrentCallback) < mCallbackQueue.Length()) { - mCallbackQueue[mCurrentCallback]->Call(); + MOZ_ASSERT(mState == State::eCustom); + MOZ_ASSERT(!mCustomElementDefinition); + MOZ_ASSERT(aDefinition->mType == mType); + + mCustomElementDefinition = aDefinition; +} + +CustomElementDefinition* +CustomElementData::GetCustomElementDefinition() +{ + MOZ_ASSERT(mCustomElementDefinition ? mState == State::eCustom + : mState != State::eCustom); + + return mCustomElementDefinition; +} + +nsIAtom* +CustomElementData::GetCustomElementType() +{ + return mType; +} + +void +CustomElementData::Traverse(nsCycleCollectionTraversalCallback& aCb) const +{ + for (uint32_t i = 0; i < mReactionQueue.Length(); i++) { + if (mReactionQueue[i]) { + mReactionQueue[i]->Traverse(aCb); + } } - mCallbackQueue.Clear(); - mCurrentCallback = -1; + if (mCustomElementDefinition) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mCustomElementDefinition"); + aCb.NoteNativeChild(mCustomElementDefinition, + NS_CYCLE_COLLECTION_PARTICIPANT(CustomElementDefinition)); + } } +void +CustomElementData::Unlink() +{ + mReactionQueue.Clear(); + mCustomElementDefinition = nullptr; +} + +//----------------------------------------------------- +// 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) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CustomElementRegistry) - tmp->mCustomDefinitions.Clear(); + tmp->mConstructors.clear(); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomDefinitions) NS_IMPL_CYCLE_COLLECTION_UNLINK(mWhenDefinedPromiseMap) NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementRegistry) - for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) { - nsAutoPtr& callbacks = iter.UserData()->mCallbacks; - - if (callbacks->mAttributeChangedCallback.WasPassed()) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mCustomDefinitions->mCallbacks->mAttributeChangedCallback"); - cb.NoteXPCOMChild(callbacks->mAttributeChangedCallback.Value()); - } - - if (callbacks->mCreatedCallback.WasPassed()) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mCustomDefinitions->mCallbacks->mCreatedCallback"); - cb.NoteXPCOMChild(callbacks->mCreatedCallback.Value()); - } - - if (callbacks->mAttachedCallback.WasPassed()) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mCustomDefinitions->mCallbacks->mAttachedCallback"); - cb.NoteXPCOMChild(callbacks->mAttachedCallback.Value()); - } - - if (callbacks->mDetachedCallback.WasPassed()) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mCustomDefinitions->mCallbacks->mDetachedCallback"); - cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value()); - } - } + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomDefinitions) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWhenDefinedPromiseMap) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) 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); } + for (ConstructorMap::Enum iter(tmp->mConstructors); !iter.empty(); iter.popFront()) { + aCallbacks.Trace(&iter.front().mutableKey(), + "mConstructors key", + aClosure); + } NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_TRACE_END @@ -163,77 +223,18 @@ NS_INTERFACE_MAP_END /* static */ bool CustomElementRegistry::IsCustomElementEnabled(JSContext* aCx, JSObject* aObject) { - return Preferences::GetBool("dom.webcomponents.customelements.enabled") || - Preferences::GetBool("dom.webcomponents.enabled"); + return nsContentUtils::IsCustomElementsEnabled(); } -/* static */ already_AddRefed -CustomElementRegistry::Create(nsPIDOMWindowInner* aWindow) -{ - MOZ_ASSERT(aWindow); - MOZ_ASSERT(aWindow->IsInnerWindow()); - - if (!aWindow->GetDocShell()) { - return nullptr; - } - - if (!IsCustomElementEnabled()) { - return nullptr; - } - - RefPtr customElementRegistry = - new CustomElementRegistry(aWindow); - return customElementRegistry.forget(); -} - -/* static */ void -CustomElementRegistry::ProcessTopElementQueue() -{ - MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); - - nsTArray>& stack = *sProcessingStack; - uint32_t firstQueue = stack.LastIndexOf((CustomElementData*) nullptr); - - for (uint32_t i = firstQueue + 1; i < stack.Length(); ++i) { - // Callback queue may have already been processed in an earlier - // element queue or in an element queue that was popped - // off more recently. - if (stack[i]->mAssociatedMicroTask != -1) { - stack[i]->RunCallbackQueue(); - stack[i]->mAssociatedMicroTask = -1; - } - } - - // If this was actually the base element queue, don't bother trying to pop - // the first "queue" marker (sentinel). - if (firstQueue != 0) { - stack.SetLength(firstQueue); - } else { - // Don't pop sentinel for base element queue. - stack.SetLength(1); - } -} - -/* static */ void -CustomElementRegistry::XPCOMShutdown() -{ - sProcessingStack.reset(); -} - -/* static */ Maybe>> -CustomElementRegistry::sProcessingStack; - CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow) : mWindow(aWindow) , mIsCustomDefinitionRunning(false) { - mozilla::HoldJSObjects(this); + MOZ_ASSERT(aWindow); + MOZ_ASSERT(aWindow->IsInnerWindow()); + MOZ_ALWAYS_TRUE(mConstructors.init()); - if (!sProcessingStack) { - sProcessingStack.emplace(); - // Add the base queue sentinel to the processing stack. - sProcessingStack->AppendElement((CustomElementData*) nullptr); - } + mozilla::HoldJSObjects(this); } CustomElementRegistry::~CustomElementRegistry() @@ -242,20 +243,34 @@ CustomElementRegistry::~CustomElementRegistry() } CustomElementDefinition* -CustomElementRegistry::LookupCustomElementDefinition(const nsAString& aLocalName, - const nsAString* aIs) const +CustomElementRegistry::LookupCustomElementDefinition(nsIAtom* aNameAtom, + nsIAtom* aTypeAtom) const { - nsCOMPtr localNameAtom = NS_Atomize(aLocalName); - nsCOMPtr typeAtom = aIs ? NS_Atomize(*aIs) : localNameAtom; - - CustomElementDefinition* data = mCustomDefinitions.Get(typeAtom); - if (data && data->mLocalName == localNameAtom) { + CustomElementDefinition* data = mCustomDefinitions.GetWeak(aTypeAtom); + if (data && data->mLocalName == aNameAtom) { return data; } return nullptr; } +CustomElementDefinition* +CustomElementRegistry::LookupCustomElementDefinition(JSContext* aCx, + JSObject* aConstructor) const +{ + JS::Rooted constructor(aCx, js::CheckedUnwrap(aConstructor)); + + const auto& ptr = mConstructors.lookup(constructor); + if (!ptr) { + return nullptr; + } + + CustomElementDefinition* definition = mCustomDefinitions.GetWeak(ptr->value()); + MOZ_ASSERT(definition, "Definition must be found in mCustomDefinitions"); + + return definition; +} + void CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName) { @@ -269,7 +284,7 @@ CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTy typeName = info->NameAtom(); } - if (mCustomDefinitions.Get(typeName)) { + if (mCustomDefinitions.GetWeak(typeName)) { return; } @@ -282,171 +297,129 @@ CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTy } void -CustomElementRegistry::SetupCustomElement(Element* aElement, - const nsAString* aTypeExtension) +CustomElementRegistry::UnregisterUnresolvedElement(Element* aElement, + nsIAtom* aTypeName) { - nsCOMPtr tagAtom = aElement->NodeInfo()->NameAtom(); - nsCOMPtr typeAtom = aTypeExtension ? - NS_Atomize(*aTypeExtension) : tagAtom; - - if (aTypeExtension && !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::is)) { - // Custom element setup in the parser happens after the "is" - // attribute is added. - aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *aTypeExtension, true); - } - - CustomElementDefinition* data = LookupCustomElementDefinition( - aElement->NodeInfo()->LocalName(), aTypeExtension); - - if (!data) { - // The type extension doesn't exist in the registry, - // thus we don't need to enqueue callback or adjust - // the "is" attribute, but it is possibly an upgrade candidate. - RegisterUnresolvedElement(aElement, typeAtom); - return; - } - - if (data->mLocalName != tagAtom) { - // The element doesn't match the local name for the - // definition, thus the element isn't a custom element - // and we don't need to do anything more. - return; - } - - // Enqueuing the created callback will set the CustomElementData on the - // element, causing prototype swizzling to occur in Element::WrapObject. - EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, data); -} - -void -CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType, - Element* aCustomElement, - LifecycleCallbackArgs* aArgs, - CustomElementDefinition* aDefinition) -{ - CustomElementData* elementData = aCustomElement->GetCustomElementData(); - - // Let DEFINITION be ELEMENT's definition - CustomElementDefinition* definition = aDefinition; - if (!definition) { - mozilla::dom::NodeInfo* info = aCustomElement->NodeInfo(); - - // Make sure we get the correct definition in case the element - // is a extended custom element e.g.