diff --git a/dom/base/CustomElementRegistry.cpp b/dom/base/CustomElementRegistry.cpp index 9d7e9547f856..bd077d8857a8 100644 --- a/dom/base/CustomElementRegistry.cpp +++ b/dom/base/CustomElementRegistry.cpp @@ -103,6 +103,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementRegistry) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CustomElementRegistry) tmp->mCustomDefinitions.Clear(); + tmp->mConstructors.clear(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mWhenDefinedPromiseMap) NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER @@ -150,6 +151,12 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CustomElementRegistry) "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 @@ -190,6 +197,11 @@ CustomElementRegistry::Create(nsPIDOMWindowInner* aWindow) RefPtr customElementRegistry = new CustomElementRegistry(aWindow); + + if (!customElementRegistry->Init()) { + return nullptr; + } + return customElementRegistry.forget(); } @@ -248,6 +260,12 @@ CustomElementRegistry::~CustomElementRegistry() mozilla::DropJSObjects(this); } +bool +CustomElementRegistry::Init() +{ + return mConstructors.init(); +} + CustomElementDefinition* CustomElementRegistry::LookupCustomElementDefinition(const nsAString& aLocalName, const nsAString* aIs) const @@ -616,9 +634,13 @@ CustomElementRegistry::Define(const nsAString& aName, * 4. If this CustomElementRegistry contains an entry with constructor constructor, * then throw a "NotSupportedError" DOMException and abort these steps. */ - // TODO: Step 3 of HTMLConstructor also needs a way to look up definition by - // using constructor. So I plans to figure out a solution to support both of - // them in bug 1274159. + const auto& ptr = mConstructors.lookup(constructorUnwrapped); + if (ptr) { + MOZ_ASSERT(mCustomDefinitions.Get(ptr->value()), + "Definition must be found in mCustomDefinitions"); + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return; + } /** * 5. Let localName be name. @@ -774,8 +796,16 @@ CustomElementRegistry::Define(const nsAString& aName, /** * 12. Add definition to this CustomElementRegistry. */ + if (!mConstructors.put(constructorUnwrapped, nameAtom)) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + mCustomDefinitions.Put(nameAtom, definition); + MOZ_ASSERT(mCustomDefinitions.Count() == mConstructors.count(), + "Number of entries should be the same"); + /** * 13. 14. 15. Upgrade candidates */ @@ -860,4 +890,4 @@ CustomElementDefinition::CustomElementDefinition(nsIAtom* aType, } } // namespace dom -} // namespace mozilla \ No newline at end of file +} // namespace mozilla diff --git a/dom/base/CustomElementRegistry.h b/dom/base/CustomElementRegistry.h index 8b2f2e93315a..1df1aed9fb8c 100644 --- a/dom/base/CustomElementRegistry.h +++ b/dom/base/CustomElementRegistry.h @@ -7,13 +7,14 @@ #ifndef mozilla_dom_CustomElementRegistry_h #define mozilla_dom_CustomElementRegistry_h +#include "js/GCHashTable.h" #include "js/TypeDecls.h" #include "mozilla/Attributes.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/FunctionBinding.h" #include "nsCycleCollectionParticipant.h" #include "nsWrapperCache.h" -#include "mozilla/dom/FunctionBinding.h" class nsDocument; @@ -172,6 +173,8 @@ private: explicit CustomElementRegistry(nsPIDOMWindowInner* aWindow); ~CustomElementRegistry(); + bool Init(); + /** * Registers an unresolved custom element that is a candidate for * upgrade when the definition is registered via registerElement. @@ -191,15 +194,25 @@ private: DefinitionMap; typedef nsClassHashtable> CandidateMap; + typedef JS::GCHashMap, + nsCOMPtr, + js::MovableCellHasher>, + js::SystemAllocPolicy> ConstructorMap; // Hashtable for custom element definitions in web components. // Custom prototypes are stored in the compartment where // registerElement was called. DefinitionMap mCustomDefinitions; + // Hashtable for looking up definitions by using constructor as key. + // Custom elements' name are stored here and we need to lookup + // mCustomDefinitions again to get definitions. + ConstructorMap mConstructors; + typedef nsRefPtrHashtable WhenDefinedPromiseMap; WhenDefinedPromiseMap mWhenDefinedPromiseMap; + // The "upgrade candidates map" from the web components spec. Maps from a // namespace id and local name to a list of elements to upgrade if that // element is registered as a custom element. diff --git a/testing/web-platform/meta/custom-elements/CustomElementRegistry.html.ini b/testing/web-platform/meta/custom-elements/CustomElementRegistry.html.ini index 9e2bf738569b..f62b64dfb547 100644 --- a/testing/web-platform/meta/custom-elements/CustomElementRegistry.html.ini +++ b/testing/web-platform/meta/custom-elements/CustomElementRegistry.html.ini @@ -1,8 +1,5 @@ [CustomElementRegistry.html] type: testharness - [customElements.define must throw a NotSupportedError when there is already a custom element with the same class] - expected: FAIL - [customElements.define must get callbacks of the constructor prototype] expected: FAIL diff --git a/testing/web-platform/meta/custom-elements/custom-element-registry/define.html.ini b/testing/web-platform/meta/custom-elements/custom-element-registry/define.html.ini deleted file mode 100644 index 122abccd31aa..000000000000 --- a/testing/web-platform/meta/custom-elements/custom-element-registry/define.html.ini +++ /dev/null @@ -1,26 +0,0 @@ -[define.html] - type: testharness - [If constructor is HTMLElement, should throw a TypeError] - expected: FAIL - - [If constructor is HTMLButtonElement, should throw a TypeError] - expected: FAIL - - [If constructor is HTMLImageElement, should throw a TypeError] - expected: FAIL - - [If constructor is HTMLMediaElement, should throw a TypeError] - expected: FAIL - - [If constructor is Image, should throw a TypeError] - expected: FAIL - - [If constructor is Audio, should throw a TypeError] - expected: FAIL - - [If constructor is Option, should throw a TypeError] - expected: FAIL - - [If the constructor is already defined, should throw a NotSupportedError] - expected: FAIL -