LCOV - code coverage report
Current view: top level - dom/base - CustomElementRegistry.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 14 426 3.3 %
Date: 2017-07-14 16:53:18 Functions: 3 41 7.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/dom/CustomElementRegistry.h"
       8             : 
       9             : #include "mozilla/dom/CustomElementRegistryBinding.h"
      10             : #include "mozilla/dom/HTMLElementBinding.h"
      11             : #include "mozilla/dom/WebComponentsBinding.h"
      12             : #include "mozilla/dom/DocGroup.h"
      13             : #include "nsIParserService.h"
      14             : #include "jsapi.h"
      15             : 
      16             : namespace mozilla {
      17             : namespace dom {
      18             : 
      19             : void
      20           0 : CustomElementCallback::Call()
      21             : {
      22           0 :   ErrorResult rv;
      23           0 :   switch (mType) {
      24             :     case nsIDocument::eCreated:
      25             :     {
      26             :       // For the duration of this callback invocation, the element is being created
      27             :       // flag must be set to true.
      28           0 :       mOwnerData->mElementIsBeingCreated = true;
      29             : 
      30             :       // The callback hasn't actually been invoked yet, but we need to flip
      31             :       // this now in order to enqueue the attached callback. This is a spec
      32             :       // bug (w3c bug 27437).
      33           0 :       mOwnerData->mCreatedCallbackInvoked = true;
      34             : 
      35             :       // If ELEMENT is in a document and this document has a browsing context,
      36             :       // enqueue attached callback for ELEMENT.
      37           0 :       nsIDocument* document = mThisObject->GetComposedDoc();
      38           0 :       if (document && document->GetDocShell()) {
      39           0 :         nsContentUtils::EnqueueLifecycleCallback(
      40           0 :           document, nsIDocument::eAttached, mThisObject);
      41             :       }
      42             : 
      43           0 :       static_cast<LifecycleCreatedCallback *>(mCallback.get())->Call(mThisObject, rv);
      44           0 :       mOwnerData->mElementIsBeingCreated = false;
      45           0 :       break;
      46             :     }
      47             :     case nsIDocument::eAttached:
      48           0 :       static_cast<LifecycleAttachedCallback *>(mCallback.get())->Call(mThisObject, rv);
      49           0 :       break;
      50             :     case nsIDocument::eDetached:
      51           0 :       static_cast<LifecycleDetachedCallback *>(mCallback.get())->Call(mThisObject, rv);
      52           0 :       break;
      53             :     case nsIDocument::eAttributeChanged:
      54           0 :       static_cast<LifecycleAttributeChangedCallback *>(mCallback.get())->Call(mThisObject,
      55           0 :         mArgs.name, mArgs.oldValue, mArgs.newValue, rv);
      56           0 :       break;
      57             :   }
      58           0 : }
      59             : 
      60             : void
      61           0 : CustomElementCallback::Traverse(nsCycleCollectionTraversalCallback& aCb) const
      62             : {
      63           0 :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mThisObject");
      64           0 :   aCb.NoteXPCOMChild(mThisObject);
      65             : 
      66           0 :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mCallback");
      67           0 :   aCb.NoteXPCOMChild(mCallback);
      68           0 : }
      69             : 
      70           0 : CustomElementCallback::CustomElementCallback(Element* aThisObject,
      71             :                                              nsIDocument::ElementCallbackType aCallbackType,
      72             :                                              mozilla::dom::CallbackFunction* aCallback,
      73           0 :                                              CustomElementData* aOwnerData)
      74             :   : mThisObject(aThisObject),
      75             :     mCallback(aCallback),
      76             :     mType(aCallbackType),
      77           0 :     mOwnerData(aOwnerData)
      78             : {
      79           0 : }
      80             : 
      81             : //-----------------------------------------------------
      82             : // CustomElementData
      83             : 
      84           0 : CustomElementData::CustomElementData(nsIAtom* aType)
      85           0 :   : CustomElementData(aType, CustomElementData::State::eUndefined)
      86             : {
      87           0 : }
      88             : 
      89           0 : CustomElementData::CustomElementData(nsIAtom* aType, State aState)
      90             :   : mType(aType)
      91             :   , mCurrentCallback(-1)
      92             :   , mElementIsBeingCreated(false)
      93             :   , mCreatedCallbackInvoked(true)
      94             :   , mAssociatedMicroTask(-1)
      95           0 :   , mState(aState)
      96             : {
      97           0 : }
      98             : 
      99             : void
     100           0 : CustomElementData::RunCallbackQueue()
     101             : {
     102             :   // Note: It's possible to re-enter this method.
     103           0 :   while (static_cast<uint32_t>(++mCurrentCallback) < mCallbackQueue.Length()) {
     104           0 :     mCallbackQueue[mCurrentCallback]->Call();
     105             :   }
     106             : 
     107           0 :   mCallbackQueue.Clear();
     108           0 :   mCurrentCallback = -1;
     109           0 : }
     110             : 
     111             : //-----------------------------------------------------
     112             : // CustomElementRegistry
     113             : 
     114             : // Only needed for refcounted objects.
     115             : NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementRegistry)
     116             : 
     117           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CustomElementRegistry)
     118           0 :   tmp->mCustomDefinitions.Clear();
     119           0 :   tmp->mConstructors.clear();
     120           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWhenDefinedPromiseMap)
     121           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
     122           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
     123           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     124             : 
     125           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementRegistry)
     126           0 :   for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) {
     127           0 :     nsAutoPtr<LifecycleCallbacks>& callbacks = iter.UserData()->mCallbacks;
     128             : 
     129           0 :     if (callbacks->mAttributeChangedCallback.WasPassed()) {
     130             :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
     131           0 :         "mCustomDefinitions->mCallbacks->mAttributeChangedCallback");
     132           0 :       cb.NoteXPCOMChild(callbacks->mAttributeChangedCallback.Value());
     133             :     }
     134             : 
     135           0 :     if (callbacks->mCreatedCallback.WasPassed()) {
     136             :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
     137           0 :         "mCustomDefinitions->mCallbacks->mCreatedCallback");
     138           0 :       cb.NoteXPCOMChild(callbacks->mCreatedCallback.Value());
     139             :     }
     140             : 
     141           0 :     if (callbacks->mAttachedCallback.WasPassed()) {
     142             :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
     143           0 :         "mCustomDefinitions->mCallbacks->mAttachedCallback");
     144           0 :       cb.NoteXPCOMChild(callbacks->mAttachedCallback.Value());
     145             :     }
     146             : 
     147           0 :     if (callbacks->mDetachedCallback.WasPassed()) {
     148             :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
     149           0 :         "mCustomDefinitions->mCallbacks->mDetachedCallback");
     150           0 :       cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value());
     151             :     }
     152             :   }
     153             : 
     154           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWhenDefinedPromiseMap)
     155           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
     156           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     157             : 
     158           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CustomElementRegistry)
     159           0 :   for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) {
     160           0 :     aCallbacks.Trace(&iter.UserData()->mConstructor,
     161             :                      "mCustomDefinitions constructor",
     162           0 :                      aClosure);
     163           0 :     aCallbacks.Trace(&iter.UserData()->mPrototype,
     164             :                      "mCustomDefinitions prototype",
     165           0 :                      aClosure);
     166             :   }
     167             : 
     168           0 :   for (ConstructorMap::Enum iter(tmp->mConstructors); !iter.empty(); iter.popFront()) {
     169           0 :     aCallbacks.Trace(&iter.front().mutableKey(),
     170             :                      "mConstructors key",
     171           0 :                      aClosure);
     172             :   }
     173           0 :   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
     174           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
     175             : 
     176           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(CustomElementRegistry)
     177           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(CustomElementRegistry)
     178             : 
     179           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CustomElementRegistry)
     180           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     181           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     182           0 : NS_INTERFACE_MAP_END
     183             : 
     184             : /* static */ bool
     185         169 : CustomElementRegistry::IsCustomElementEnabled(JSContext* aCx, JSObject* aObject)
     186             : {
     187         338 :   return nsContentUtils::IsCustomElementsEnabled() ||
     188         338 :          nsContentUtils::IsWebComponentsEnabled();
     189             : }
     190             : 
     191             : /* static */ void
     192           0 : CustomElementRegistry::ProcessTopElementQueue()
     193             : {
     194           0 :   MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
     195             : 
     196           0 :   nsTArray<RefPtr<CustomElementData>>& stack = *sProcessingStack;
     197           0 :   uint32_t firstQueue = stack.LastIndexOf((CustomElementData*) nullptr);
     198             : 
     199           0 :   for (uint32_t i = firstQueue + 1; i < stack.Length(); ++i) {
     200             :     // Callback queue may have already been processed in an earlier
     201             :     // element queue or in an element queue that was popped
     202             :     // off more recently.
     203           0 :     if (stack[i]->mAssociatedMicroTask != -1) {
     204           0 :       stack[i]->RunCallbackQueue();
     205           0 :       stack[i]->mAssociatedMicroTask = -1;
     206             :     }
     207             :   }
     208             : 
     209             :   // If this was actually the base element queue, don't bother trying to pop
     210             :   // the first "queue" marker (sentinel).
     211           0 :   if (firstQueue != 0) {
     212           0 :     stack.SetLength(firstQueue);
     213             :   } else {
     214             :     // Don't pop sentinel for base element queue.
     215           0 :     stack.SetLength(1);
     216             :   }
     217           0 : }
     218             : 
     219             : /* static */ void
     220           0 : CustomElementRegistry::XPCOMShutdown()
     221             : {
     222           0 :   sProcessingStack.reset();
     223           0 : }
     224             : 
     225             : /* static */ Maybe<nsTArray<RefPtr<CustomElementData>>>
     226           3 : CustomElementRegistry::sProcessingStack;
     227             : 
     228           0 : CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow)
     229             :  : mWindow(aWindow)
     230           0 :  , mIsCustomDefinitionRunning(false)
     231             : {
     232           0 :   MOZ_ASSERT(aWindow);
     233           0 :   MOZ_ASSERT(aWindow->IsInnerWindow());
     234           0 :   MOZ_ALWAYS_TRUE(mConstructors.init());
     235             : 
     236           0 :   mozilla::HoldJSObjects(this);
     237             : 
     238           0 :   if (!sProcessingStack) {
     239           0 :     sProcessingStack.emplace();
     240             :     // Add the base queue sentinel to the processing stack.
     241           0 :     sProcessingStack->AppendElement((CustomElementData*) nullptr);
     242             :   }
     243           0 : }
     244             : 
     245           0 : CustomElementRegistry::~CustomElementRegistry()
     246             : {
     247           0 :   mozilla::DropJSObjects(this);
     248           0 : }
     249             : 
     250             : CustomElementDefinition*
     251           0 : CustomElementRegistry::LookupCustomElementDefinition(const nsAString& aLocalName,
     252             :                                                      const nsAString* aIs) const
     253             : {
     254           0 :   nsCOMPtr<nsIAtom> localNameAtom = NS_Atomize(aLocalName);
     255           0 :   nsCOMPtr<nsIAtom> typeAtom = aIs ? NS_Atomize(*aIs) : localNameAtom;
     256             : 
     257           0 :   CustomElementDefinition* data = mCustomDefinitions.Get(typeAtom);
     258           0 :   if (data && data->mLocalName == localNameAtom) {
     259           0 :     return data;
     260             :   }
     261             : 
     262           0 :   return nullptr;
     263             : }
     264             : 
     265             : CustomElementDefinition*
     266           0 : CustomElementRegistry::LookupCustomElementDefinition(JSContext* aCx,
     267             :                                                      JSObject* aConstructor) const
     268             : {
     269           0 :   JS::Rooted<JSObject*> constructor(aCx, js::CheckedUnwrap(aConstructor));
     270             : 
     271           0 :   const auto& ptr = mConstructors.lookup(constructor);
     272           0 :   if (!ptr) {
     273           0 :     return nullptr;
     274             :   }
     275             : 
     276           0 :   CustomElementDefinition* definition = mCustomDefinitions.Get(ptr->value());
     277           0 :   MOZ_ASSERT(definition, "Definition must be found in mCustomDefinitions");
     278             : 
     279           0 :   return definition;
     280             : }
     281             : 
     282             : void
     283           0 : CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName)
     284             : {
     285           0 :   mozilla::dom::NodeInfo* info = aElement->NodeInfo();
     286             : 
     287             :   // Candidate may be a custom element through extension,
     288             :   // in which case the custom element type name will not
     289             :   // match the element tag name. e.g. <button is="x-button">.
     290           0 :   nsCOMPtr<nsIAtom> typeName = aTypeName;
     291           0 :   if (!typeName) {
     292           0 :     typeName = info->NameAtom();
     293             :   }
     294             : 
     295           0 :   if (mCustomDefinitions.Get(typeName)) {
     296           0 :     return;
     297             :   }
     298             : 
     299           0 :   nsTArray<nsWeakPtr>* unresolved = mCandidatesMap.LookupOrAdd(typeName);
     300           0 :   nsWeakPtr* elem = unresolved->AppendElement();
     301           0 :   *elem = do_GetWeakReference(aElement);
     302           0 :   aElement->AddStates(NS_EVENT_STATE_UNRESOLVED);
     303             : 
     304           0 :   return;
     305             : }
     306             : 
     307             : void
     308           0 : CustomElementRegistry::SetupCustomElement(Element* aElement,
     309             :                                           const nsAString* aTypeExtension)
     310             : {
     311           0 :   nsCOMPtr<nsIAtom> tagAtom = aElement->NodeInfo()->NameAtom();
     312             :   nsCOMPtr<nsIAtom> typeAtom = aTypeExtension ?
     313           0 :     NS_Atomize(*aTypeExtension) : tagAtom;
     314             : 
     315           0 :   if (aTypeExtension && !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::is)) {
     316             :     // Custom element setup in the parser happens after the "is"
     317             :     // attribute is added.
     318           0 :     aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *aTypeExtension, true);
     319             :   }
     320             : 
     321             :   // SetupCustomElement() should be called with an element that don't have
     322             :   // CustomElementData setup, if not we will hit the assertion in
     323             :   // SetCustomElementData().
     324           0 :   aElement->SetCustomElementData(new CustomElementData(typeAtom));
     325             : 
     326           0 :   CustomElementDefinition* definition = LookupCustomElementDefinition(
     327           0 :     aElement->NodeInfo()->LocalName(), aTypeExtension);
     328             : 
     329           0 :   if (!definition) {
     330             :     // The type extension doesn't exist in the registry,
     331             :     // thus we don't need to enqueue callback or adjust
     332             :     // the "is" attribute, but it is possibly an upgrade candidate.
     333           0 :     RegisterUnresolvedElement(aElement, typeAtom);
     334           0 :     return;
     335             :   }
     336             : 
     337           0 :   if (definition->mLocalName != tagAtom) {
     338             :     // The element doesn't match the local name for the
     339             :     // definition, thus the element isn't a custom element
     340             :     // and we don't need to do anything more.
     341           0 :     return;
     342             :   }
     343             : 
     344             :   // Enqueuing the created callback will set the CustomElementData on the
     345             :   // element, causing prototype swizzling to occur in Element::WrapObject.
     346           0 :   EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, definition);
     347             : }
     348             : 
     349             : void
     350           0 : CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
     351             :                                                 Element* aCustomElement,
     352             :                                                 LifecycleCallbackArgs* aArgs,
     353             :                                                 CustomElementDefinition* aDefinition)
     354             : {
     355           0 :   RefPtr<CustomElementData> elementData = aCustomElement->GetCustomElementData();
     356           0 :   MOZ_ASSERT(elementData, "CustomElementData should exist");
     357             : 
     358             :   // Let DEFINITION be ELEMENT's definition
     359           0 :   CustomElementDefinition* definition = aDefinition;
     360           0 :   if (!definition) {
     361           0 :     mozilla::dom::NodeInfo* info = aCustomElement->NodeInfo();
     362             : 
     363             :     // Make sure we get the correct definition in case the element
     364             :     // is a extended custom element e.g. <button is="x-button">.
     365             :     nsCOMPtr<nsIAtom> typeAtom = elementData ?
     366           0 :       elementData->mType.get() : info->NameAtom();
     367             : 
     368           0 :     definition = mCustomDefinitions.Get(typeAtom);
     369           0 :     if (!definition || definition->mLocalName != info->NameAtom()) {
     370             :       // Trying to enqueue a callback for an element that is not
     371             :       // a custom element. We are done, nothing to do.
     372           0 :       return;
     373             :     }
     374             :   }
     375             : 
     376             :   // Let CALLBACK be the callback associated with the key NAME in CALLBACKS.
     377           0 :   CallbackFunction* func = nullptr;
     378           0 :   switch (aType) {
     379             :     case nsIDocument::eCreated:
     380           0 :       if (definition->mCallbacks->mCreatedCallback.WasPassed()) {
     381           0 :         func = definition->mCallbacks->mCreatedCallback.Value();
     382             :       }
     383           0 :       break;
     384             : 
     385             :     case nsIDocument::eAttached:
     386           0 :       if (definition->mCallbacks->mAttachedCallback.WasPassed()) {
     387           0 :         func = definition->mCallbacks->mAttachedCallback.Value();
     388             :       }
     389           0 :       break;
     390             : 
     391             :     case nsIDocument::eDetached:
     392           0 :       if (definition->mCallbacks->mDetachedCallback.WasPassed()) {
     393           0 :         func = definition->mCallbacks->mDetachedCallback.Value();
     394             :       }
     395           0 :       break;
     396             : 
     397             :     case nsIDocument::eAttributeChanged:
     398           0 :       if (definition->mCallbacks->mAttributeChangedCallback.WasPassed()) {
     399           0 :         func = definition->mCallbacks->mAttributeChangedCallback.Value();
     400             :       }
     401           0 :       break;
     402             :   }
     403             : 
     404             :   // If there is no such callback, stop.
     405           0 :   if (!func) {
     406           0 :     return;
     407             :   }
     408             : 
     409           0 :   if (aType == nsIDocument::eCreated) {
     410           0 :     elementData->mCreatedCallbackInvoked = false;
     411           0 :   } else if (!elementData->mCreatedCallbackInvoked) {
     412             :     // Callbacks other than created callback must not be enqueued
     413             :     // until after the created callback has been invoked.
     414           0 :     return;
     415             :   }
     416             : 
     417             :   // Add CALLBACK to ELEMENT's callback queue.
     418             :   CustomElementCallback* callback = new CustomElementCallback(aCustomElement,
     419             :                                                               aType,
     420             :                                                               func,
     421           0 :                                                               elementData);
     422             :   // Ownership of callback is taken by mCallbackQueue.
     423           0 :   elementData->mCallbackQueue.AppendElement(callback);
     424           0 :   if (aArgs) {
     425           0 :     callback->SetArgs(*aArgs);
     426             :   }
     427             : 
     428           0 :   if (!elementData->mElementIsBeingCreated) {
     429             :     CustomElementData* lastData =
     430           0 :       sProcessingStack->SafeLastElement(nullptr);
     431             : 
     432             :     // A new element queue needs to be pushed if the queue at the
     433             :     // top of the stack is associated with another microtask level.
     434             :     bool shouldPushElementQueue =
     435           0 :       (!lastData || lastData->mAssociatedMicroTask <
     436           0 :          static_cast<int32_t>(nsContentUtils::MicroTaskLevel()));
     437             : 
     438             :     // Push a new element queue onto the processing stack when appropriate
     439             :     // (when we enter a new microtask).
     440           0 :     if (shouldPushElementQueue) {
     441             :       // Push a sentinel value on the processing stack to mark the
     442             :       // boundary between the element queues.
     443           0 :       sProcessingStack->AppendElement((CustomElementData*) nullptr);
     444             :     }
     445             : 
     446           0 :     sProcessingStack->AppendElement(elementData);
     447           0 :     elementData->mAssociatedMicroTask =
     448           0 :       static_cast<int32_t>(nsContentUtils::MicroTaskLevel());
     449             : 
     450             :     // Add a script runner to pop and process the element queue at
     451             :     // the top of the processing stack.
     452           0 :     if (shouldPushElementQueue) {
     453             :       // Lifecycle callbacks enqueued by user agent implementation
     454             :       // should be invoked prior to returning control back to script.
     455             :       // Create a script runner to process the top of the processing
     456             :       // stack as soon as it is safe to run script.
     457           0 :       nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
     458             :         "dom::CustomElementRegistry::EnqueueLifecycleCallback",
     459           0 :         &CustomElementRegistry::ProcessTopElementQueue);
     460           0 :       nsContentUtils::AddScriptRunner(runnable);
     461             :     }
     462             :   }
     463             : }
     464             : 
     465             : void
     466           0 : CustomElementRegistry::GetCustomPrototype(nsIAtom* aAtom,
     467             :                                           JS::MutableHandle<JSObject*> aPrototype)
     468             : {
     469           0 :   mozilla::dom::CustomElementDefinition* definition = mCustomDefinitions.Get(aAtom);
     470           0 :   if (definition) {
     471           0 :     aPrototype.set(definition->mPrototype);
     472             :   } else {
     473           0 :     aPrototype.set(nullptr);
     474             :   }
     475           0 : }
     476             : 
     477             : void
     478           0 : CustomElementRegistry::UpgradeCandidates(JSContext* aCx,
     479             :                                          nsIAtom* aKey,
     480             :                                          CustomElementDefinition* aDefinition,
     481             :                                          ErrorResult& aRv)
     482             : {
     483           0 :   DocGroup* docGroup = mWindow->GetDocGroup();
     484           0 :   if (!docGroup) {
     485           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
     486           0 :     return;
     487             :   }
     488             : 
     489           0 :   nsAutoPtr<nsTArray<nsWeakPtr>> candidates;
     490           0 :   if (mCandidatesMap.Remove(aKey, &candidates)) {
     491           0 :     MOZ_ASSERT(candidates);
     492             :     CustomElementReactionsStack* reactionsStack =
     493           0 :       docGroup->CustomElementReactionsStack();
     494           0 :     for (size_t i = 0; i < candidates->Length(); ++i) {
     495           0 :       nsCOMPtr<Element> elem = do_QueryReferent(candidates->ElementAt(i));
     496           0 :       if (!elem) {
     497           0 :         continue;
     498             :       }
     499             : 
     500           0 :       reactionsStack->EnqueueUpgradeReaction(this, elem, aDefinition);
     501             :     }
     502             :   }
     503             : }
     504             : 
     505             : JSObject*
     506           0 : CustomElementRegistry::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     507             : {
     508           0 :   return CustomElementRegistryBinding::Wrap(aCx, this, aGivenProto);
     509             : }
     510             : 
     511           0 : nsISupports* CustomElementRegistry::GetParentObject() const
     512             : {
     513           0 :   return mWindow;
     514             : }
     515             : 
     516             : static const char* kLifeCycleCallbackNames[] = {
     517             :   "connectedCallback",
     518             :   "disconnectedCallback",
     519             :   "adoptedCallback",
     520             :   "attributeChangedCallback",
     521             :   // The life cycle callbacks from v0 spec.
     522             :   "createdCallback",
     523             :   "attachedCallback",
     524             :   "detachedCallback"
     525             : };
     526             : 
     527             : static void
     528           0 : CheckLifeCycleCallbacks(JSContext* aCx,
     529             :                         JS::Handle<JSObject*> aConstructor,
     530             :                         ErrorResult& aRv)
     531             : {
     532           0 :   for (size_t i = 0; i < ArrayLength(kLifeCycleCallbackNames); ++i) {
     533           0 :     const char* callbackName = kLifeCycleCallbackNames[i];
     534           0 :     JS::Rooted<JS::Value> callbackValue(aCx);
     535           0 :     if (!JS_GetProperty(aCx, aConstructor, callbackName, &callbackValue)) {
     536           0 :       aRv.StealExceptionFromJSContext(aCx);
     537           0 :       return;
     538             :     }
     539           0 :     if (!callbackValue.isUndefined()) {
     540           0 :       if (!callbackValue.isObject()) {
     541           0 :         aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_ConvertASCIItoUTF16(callbackName));
     542           0 :         return;
     543             :       }
     544           0 :       JS::Rooted<JSObject*> callback(aCx, &callbackValue.toObject());
     545           0 :       if (!JS::IsCallable(callback)) {
     546           0 :         aRv.ThrowTypeError<MSG_NOT_CALLABLE>(NS_ConvertASCIItoUTF16(callbackName));
     547           0 :         return;
     548             :       }
     549             :     }
     550             :   }
     551             : }
     552             : 
     553             : // https://html.spec.whatwg.org/multipage/scripting.html#element-definition
     554             : void
     555           0 : CustomElementRegistry::Define(const nsAString& aName,
     556             :                               Function& aFunctionConstructor,
     557             :                               const ElementDefinitionOptions& aOptions,
     558             :                               ErrorResult& aRv)
     559             : {
     560           0 :   aRv.MightThrowJSException();
     561             : 
     562           0 :   AutoJSAPI jsapi;
     563           0 :   if (NS_WARN_IF(!jsapi.Init(mWindow))) {
     564           0 :     aRv.Throw(NS_ERROR_FAILURE);
     565           0 :     return;
     566             :   }
     567             : 
     568           0 :   JSContext *cx = jsapi.cx();
     569           0 :   JS::Rooted<JSObject*> constructor(cx, aFunctionConstructor.CallableOrNull());
     570             : 
     571             :   /**
     572             :    * 1. If IsConstructor(constructor) is false, then throw a TypeError and abort
     573             :    *    these steps.
     574             :    */
     575             :   // For now, all wrappers are constructable if they are callable. So we need to
     576             :   // unwrap constructor to check it is really constructable.
     577           0 :   JS::Rooted<JSObject*> constructorUnwrapped(cx, js::CheckedUnwrap(constructor));
     578           0 :   if (!constructorUnwrapped) {
     579             :     // If the caller's compartment does not have permission to access the
     580             :     // unwrapped constructor then throw.
     581           0 :     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     582           0 :     return;
     583             :   }
     584             : 
     585           0 :   if (!JS::IsConstructor(constructorUnwrapped)) {
     586           0 :     aRv.ThrowTypeError<MSG_NOT_CONSTRUCTOR>(NS_LITERAL_STRING("Argument 2 of CustomElementRegistry.define"));
     587           0 :     return;
     588             :   }
     589             : 
     590             :   /**
     591             :    * 2. If name is not a valid custom element name, then throw a "SyntaxError"
     592             :    *    DOMException and abort these steps.
     593             :    */
     594           0 :   nsCOMPtr<nsIAtom> nameAtom(NS_Atomize(aName));
     595           0 :   if (!nsContentUtils::IsCustomElementName(nameAtom)) {
     596           0 :     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     597           0 :     return;
     598             :   }
     599             : 
     600             :   /**
     601             :    * 3. If this CustomElementRegistry contains an entry with name name, then
     602             :    *    throw a "NotSupportedError" DOMException and abort these steps.
     603             :    */
     604           0 :   if (mCustomDefinitions.Get(nameAtom)) {
     605           0 :     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     606           0 :     return;
     607             :   }
     608             : 
     609             :   /**
     610             :    * 4. If this CustomElementRegistry contains an entry with constructor constructor,
     611             :    *    then throw a "NotSupportedError" DOMException and abort these steps.
     612             :    */
     613           0 :   const auto& ptr = mConstructors.lookup(constructorUnwrapped);
     614           0 :   if (ptr) {
     615           0 :     MOZ_ASSERT(mCustomDefinitions.Get(ptr->value()),
     616             :                "Definition must be found in mCustomDefinitions");
     617           0 :     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     618           0 :     return;
     619             :   }
     620             : 
     621             :   /**
     622             :    * 5. Let localName be name.
     623             :    * 6. Let extends be the value of the extends member of options, or null if
     624             :    *    no such member exists.
     625             :    * 7. If extends is not null, then:
     626             :    *    1. If extends is a valid custom element name, then throw a
     627             :    *       "NotSupportedError" DOMException.
     628             :    *    2. If the element interface for extends and the HTML namespace is
     629             :    *       HTMLUnknownElement (e.g., if extends does not indicate an element
     630             :    *       definition in this specification), then throw a "NotSupportedError"
     631             :    *       DOMException.
     632             :    *    3. Set localName to extends.
     633             :    */
     634           0 :   nsAutoString localName(aName);
     635           0 :   if (aOptions.mExtends.WasPassed()) {
     636           0 :     nsCOMPtr<nsIAtom> extendsAtom(NS_Atomize(aOptions.mExtends.Value()));
     637           0 :     if (nsContentUtils::IsCustomElementName(extendsAtom)) {
     638           0 :       aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     639           0 :       return;
     640             :     }
     641             : 
     642           0 :     nsIParserService* ps = nsContentUtils::GetParserService();
     643           0 :     if (!ps) {
     644           0 :       aRv.Throw(NS_ERROR_UNEXPECTED);
     645           0 :       return;
     646             :     }
     647             : 
     648             :     // bgsound and multicol are unknown html element.
     649           0 :     int32_t tag = ps->HTMLCaseSensitiveAtomTagToId(extendsAtom);
     650           0 :     if (tag == eHTMLTag_userdefined ||
     651           0 :         tag == eHTMLTag_bgsound ||
     652             :         tag == eHTMLTag_multicol) {
     653           0 :       aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     654           0 :       return;
     655             :     }
     656             : 
     657           0 :     localName.Assign(aOptions.mExtends.Value());
     658             :   }
     659             : 
     660             :   /**
     661             :    * 8. If this CustomElementRegistry's element definition is running flag is set,
     662             :    *    then throw a "NotSupportedError" DOMException and abort these steps.
     663             :    */
     664           0 :   if (mIsCustomDefinitionRunning) {
     665           0 :     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     666           0 :     return;
     667             :   }
     668             : 
     669           0 :   JS::Rooted<JSObject*> constructorPrototype(cx);
     670           0 :   nsAutoPtr<LifecycleCallbacks> callbacksHolder(new LifecycleCallbacks());
     671             :   { // Set mIsCustomDefinitionRunning.
     672             :     /**
     673             :      * 9. Set this CustomElementRegistry's element definition is running flag.
     674             :      */
     675           0 :     AutoSetRunningFlag as(this);
     676             : 
     677             :     { // Enter constructor's compartment.
     678             :       /**
     679             :        * 10.1. Let prototype be Get(constructor, "prototype"). Rethrow any exceptions.
     680             :        */
     681           0 :       JSAutoCompartment ac(cx, constructor);
     682           0 :       JS::Rooted<JS::Value> prototypev(cx);
     683             :       // The .prototype on the constructor passed from document.registerElement
     684             :       // is the "expando" of a wrapper. So we should get it from wrapper instead
     685             :       // instead of underlying object.
     686           0 :       if (!JS_GetProperty(cx, constructor, "prototype", &prototypev)) {
     687           0 :         aRv.StealExceptionFromJSContext(cx);
     688           0 :         return;
     689             :       }
     690             : 
     691             :       /**
     692             :        * 10.2. If Type(prototype) is not Object, then throw a TypeError exception.
     693             :        */
     694           0 :       if (!prototypev.isObject()) {
     695           0 :         aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("constructor.prototype"));
     696           0 :         return;
     697             :       }
     698             : 
     699           0 :       constructorPrototype = &prototypev.toObject();
     700             :     } // Leave constructor's compartment.
     701             : 
     702           0 :     JS::Rooted<JSObject*> constructorProtoUnwrapped(cx, js::CheckedUnwrap(constructorPrototype));
     703           0 :     if (!constructorProtoUnwrapped) {
     704             :       // If the caller's compartment does not have permission to access the
     705             :       // unwrapped prototype then throw.
     706           0 :       aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     707           0 :       return;
     708             :     }
     709             : 
     710             :     { // Enter constructorProtoUnwrapped's compartment
     711           0 :       JSAutoCompartment ac(cx, constructorProtoUnwrapped);
     712             : 
     713             :       /**
     714             :        * 10.3. Let lifecycleCallbacks be a map with the four keys
     715             :        *       "connectedCallback", "disconnectedCallback", "adoptedCallback", and
     716             :        *       "attributeChangedCallback", each of which belongs to an entry whose
     717             :        *       value is null.
     718             :        * 10.4. For each of the four keys callbackName in lifecycleCallbacks:
     719             :        *       1. Let callbackValue be Get(prototype, callbackName). Rethrow any
     720             :        *          exceptions.
     721             :        *       2. If callbackValue is not undefined, then set the value of the
     722             :        *          entry in lifecycleCallbacks with key callbackName to the result
     723             :        *          of converting callbackValue to the Web IDL Function callback type.
     724             :        *          Rethrow any exceptions from the conversion.
     725             :        */
     726             :       // Will do the same checking for the life cycle callbacks from v0 spec.
     727           0 :       CheckLifeCycleCallbacks(cx, constructorProtoUnwrapped, aRv);
     728           0 :       if (aRv.Failed()) {
     729           0 :         return;
     730             :       }
     731             : 
     732             :       /**
     733             :        * 10.5. Let observedAttributes be an empty sequence<DOMString>.
     734             :        * 10.6. If the value of the entry in lifecycleCallbacks with key
     735             :        *       "attributeChangedCallback" is not null, then:
     736             :        *       1. Let observedAttributesIterable be Get(constructor,
     737             :        *          "observedAttributes"). Rethrow any exceptions.
     738             :        *       2. If observedAttributesIterable is not undefined, then set
     739             :        *          observedAttributes to the result of converting
     740             :        *          observedAttributesIterable to a sequence<DOMString>. Rethrow
     741             :        *          any exceptions from the conversion.
     742             :        */
     743             :       // TODO: Bug 1293921 - Implement connected/disconnected/adopted/attributeChanged lifecycle callbacks for custom elements
     744             : 
     745             :       // Note: We call the init from the constructorProtoUnwrapped's compartment
     746             :       //       here.
     747           0 :       JS::RootedValue rootedv(cx, JS::ObjectValue(*constructorProtoUnwrapped));
     748           0 :       if (!JS_WrapValue(cx, &rootedv) || !callbacksHolder->Init(cx, rootedv)) {
     749           0 :         aRv.StealExceptionFromJSContext(cx);
     750           0 :         return;
     751             :       }
     752             :     } // Leave constructorProtoUnwrapped's compartment.
     753             :   } // Unset mIsCustomDefinitionRunning
     754             : 
     755             :   /**
     756             :    * 11. Let definition be a new custom element definition with name name,
     757             :    *     local name localName, constructor constructor, prototype prototype,
     758             :    *     observed attributes observedAttributes, and lifecycle callbacks
     759             :    *     lifecycleCallbacks.
     760             :    */
     761             :   // Associate the definition with the custom element.
     762           0 :   nsCOMPtr<nsIAtom> localNameAtom(NS_Atomize(localName));
     763           0 :   LifecycleCallbacks* callbacks = callbacksHolder.forget();
     764             : 
     765             :   /**
     766             :    * 12. Add definition to this CustomElementRegistry.
     767             :    */
     768           0 :   if (!mConstructors.put(constructorUnwrapped, nameAtom)) {
     769           0 :     aRv.Throw(NS_ERROR_FAILURE);
     770           0 :     return;
     771             :   }
     772             : 
     773             :   CustomElementDefinition* definition =
     774             :     new CustomElementDefinition(nameAtom,
     775             :                                 localNameAtom,
     776             :                                 constructor,
     777             :                                 constructorPrototype,
     778             :                                 callbacks,
     779           0 :                                 0 /* TODO dependent on HTML imports. Bug 877072 */);
     780             : 
     781           0 :   mCustomDefinitions.Put(nameAtom, definition);
     782             : 
     783           0 :   MOZ_ASSERT(mCustomDefinitions.Count() == mConstructors.count(),
     784             :              "Number of entries should be the same");
     785             : 
     786             :   /**
     787             :    * 13. 14. 15. Upgrade candidates
     788             :    */
     789             :   // TODO: Bug 1299363 - Implement custom element v1 upgrade algorithm
     790           0 :   UpgradeCandidates(cx, nameAtom, definition, aRv);
     791             : 
     792             :   /**
     793             :    * 16. If this CustomElementRegistry's when-defined promise map contains an
     794             :    *     entry with key name:
     795             :    *     1. Let promise be the value of that entry.
     796             :    *     2. Resolve promise with undefined.
     797             :    *     3. Delete the entry with key name from this CustomElementRegistry's
     798             :    *        when-defined promise map.
     799             :    */
     800           0 :   RefPtr<Promise> promise;
     801           0 :   mWhenDefinedPromiseMap.Remove(nameAtom, getter_AddRefs(promise));
     802           0 :   if (promise) {
     803           0 :     promise->MaybeResolveWithUndefined();
     804             :   }
     805             : 
     806             : }
     807             : 
     808             : void
     809           0 : CustomElementRegistry::Get(JSContext* aCx, const nsAString& aName,
     810             :                            JS::MutableHandle<JS::Value> aRetVal)
     811             : {
     812           0 :   nsCOMPtr<nsIAtom> nameAtom(NS_Atomize(aName));
     813           0 :   CustomElementDefinition* data = mCustomDefinitions.Get(nameAtom);
     814             : 
     815           0 :   if (!data) {
     816           0 :     aRetVal.setUndefined();
     817           0 :     return;
     818             :   }
     819             : 
     820           0 :   aRetVal.setObject(*data->mConstructor);
     821           0 :   return;
     822             : }
     823             : 
     824             : already_AddRefed<Promise>
     825           0 : CustomElementRegistry::WhenDefined(const nsAString& aName, ErrorResult& aRv)
     826             : {
     827           0 :   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
     828           0 :   RefPtr<Promise> promise = Promise::Create(global, aRv);
     829             : 
     830           0 :   if (aRv.Failed()) {
     831           0 :     return nullptr;
     832             :   }
     833             : 
     834           0 :   nsCOMPtr<nsIAtom> nameAtom(NS_Atomize(aName));
     835           0 :   if (!nsContentUtils::IsCustomElementName(nameAtom)) {
     836           0 :     promise->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
     837           0 :     return promise.forget();
     838             :   }
     839             : 
     840           0 :   if (mCustomDefinitions.Get(nameAtom)) {
     841           0 :     promise->MaybeResolve(JS::UndefinedHandleValue);
     842           0 :     return promise.forget();
     843             :   }
     844             : 
     845           0 :   auto entry = mWhenDefinedPromiseMap.LookupForAdd(nameAtom);
     846           0 :   if (entry) {
     847           0 :     promise = entry.Data();
     848             :   } else {
     849           0 :     entry.OrInsert([&promise](){ return promise; });
     850             :   }
     851             : 
     852           0 :   return promise.forget();
     853             : }
     854             : 
     855             : void
     856           0 : CustomElementRegistry::Upgrade(Element* aElement,
     857             :                                CustomElementDefinition* aDefinition)
     858             : {
     859             :   // TODO: This function will be replaced to v1 upgrade in bug 1299363
     860           0 :   aElement->RemoveStates(NS_EVENT_STATE_UNRESOLVED);
     861             : 
     862             :   // Make sure that the element name matches the name in the definition.
     863             :   // (e.g. a definition for x-button extending button should match
     864             :   // <button is="x-button"> but not <x-button>.
     865           0 :   if (aElement->NodeInfo()->NameAtom() != aDefinition->mLocalName) {
     866             :     //Skip over this element because definition does not apply.
     867           0 :     return;
     868             :   }
     869             : 
     870           0 :   MOZ_ASSERT(aElement->IsHTMLElement(aDefinition->mLocalName));
     871             : 
     872           0 :   AutoJSAPI jsapi;
     873           0 :   if (NS_WARN_IF(!jsapi.Init(mWindow))) {
     874           0 :     return;
     875             :   }
     876             : 
     877           0 :   JSContext* cx = jsapi.cx();
     878             : 
     879           0 :   JS::Rooted<JSObject*> reflector(cx, aElement->GetWrapper());
     880           0 :   if (reflector) {
     881           0 :     Maybe<JSAutoCompartment> ac;
     882           0 :     JS::Rooted<JSObject*> prototype(cx, aDefinition->mPrototype);
     883           0 :     if (aElement->NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(prototype))) {
     884           0 :       ac.emplace(cx, reflector);
     885           0 :       if (!JS_WrapObject(cx, &prototype) ||
     886           0 :           !JS_SetPrototype(cx, reflector, prototype)) {
     887           0 :         return;
     888             :       }
     889             :     } else {
     890             :       // We want to set the custom prototype in the compartment where it was
     891             :       // registered. We store the prototype from define() without unwrapped,
     892             :       // hence the prototype's compartment is the compartment where it was
     893             :       // registered.
     894             :       // In the case that |reflector| and |prototype| are in different
     895             :       // compartments, this will set the prototype on the |reflector|'s wrapper
     896             :       // and thus only visible in the wrapper's compartment, since we know
     897             :       // reflector's principal does not subsume prototype's in this case.
     898           0 :       ac.emplace(cx, prototype);
     899           0 :       if (!JS_WrapObject(cx, &reflector) ||
     900           0 :           !JS_SetPrototype(cx, reflector, prototype)) {
     901           0 :         return;
     902             :       }
     903             :     }
     904             :   }
     905             : 
     906           0 :   EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, aDefinition);
     907             : }
     908             : 
     909             : //-----------------------------------------------------
     910             : // CustomElementReactionsStack
     911             : 
     912             : void
     913         602 : CustomElementReactionsStack::CreateAndPushElementQueue()
     914             : {
     915             :   // Push a new element queue onto the custom element reactions stack.
     916         602 :   mReactionsStack.AppendElement();
     917         602 : }
     918             : 
     919             : void
     920         602 : CustomElementReactionsStack::PopAndInvokeElementQueue()
     921             : {
     922             :   // Pop the element queue from the custom element reactions stack,
     923             :   // and invoke custom element reactions in that queue.
     924         602 :   MOZ_ASSERT(!mReactionsStack.IsEmpty(),
     925             :              "Reaction stack shouldn't be empty");
     926             : 
     927         602 :   ElementQueue& elementQueue = mReactionsStack.LastElement();
     928             :   // Check element queue size in order to reduce function call overhead.
     929         602 :   if (!elementQueue.IsEmpty()) {
     930           0 :     InvokeReactions(elementQueue);
     931             :   }
     932             : 
     933        1204 :   DebugOnly<bool> isRemovedElement = mReactionsStack.RemoveElement(elementQueue);
     934         602 :   MOZ_ASSERT(isRemovedElement,
     935             :              "Reaction stack should have an element queue to remove");
     936         602 : }
     937             : 
     938             : void
     939           0 : CustomElementReactionsStack::EnqueueUpgradeReaction(CustomElementRegistry* aRegistry,
     940             :                                                     Element* aElement,
     941             :                                                     CustomElementDefinition* aDefinition)
     942             : {
     943           0 :   Enqueue(aElement, new CustomElementUpgradeReaction(aRegistry, aDefinition));
     944           0 : }
     945             : 
     946             : void
     947           0 : CustomElementReactionsStack::Enqueue(Element* aElement,
     948             :                                      CustomElementReaction* aReaction)
     949             : {
     950           0 :   RefPtr<CustomElementData> elementData = aElement->GetCustomElementData();
     951           0 :   MOZ_ASSERT(elementData, "CustomElementData should exist");
     952             : 
     953             :   // Add element to the current element queue.
     954           0 :   if (!mReactionsStack.IsEmpty()) {
     955           0 :     mReactionsStack.LastElement().AppendElement(do_GetWeakReference(aElement));
     956           0 :     elementData->mReactionQueue.AppendElement(aReaction);
     957           0 :     return;
     958             :   }
     959             : 
     960             :   // If the custom element reactions stack is empty, then:
     961             :   // Add element to the backup element queue.
     962           0 :   mBackupQueue.AppendElement(do_GetWeakReference(aElement));
     963           0 :   elementData->mReactionQueue.AppendElement(aReaction);
     964             : 
     965           0 :   if (mIsBackupQueueProcessing) {
     966           0 :     return;
     967             :   }
     968             : 
     969           0 :   CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
     970             :   RefPtr<ProcessBackupQueueRunnable> processBackupQueueRunnable =
     971           0 :     new ProcessBackupQueueRunnable(this);
     972           0 :   context->DispatchToMicroTask(processBackupQueueRunnable.forget());
     973             : }
     974             : 
     975             : void
     976           0 : CustomElementReactionsStack::InvokeBackupQueue()
     977             : {
     978             :   // Check backup queue size in order to reduce function call overhead.
     979           0 :   if (!mBackupQueue.IsEmpty()) {
     980           0 :     InvokeReactions(mBackupQueue);
     981             :   }
     982           0 : }
     983             : 
     984             : void
     985           0 : CustomElementReactionsStack::InvokeReactions(ElementQueue& aElementQueue)
     986             : {
     987           0 :   for (uint32_t i = 0; i < aElementQueue.Length(); ++i) {
     988           0 :     nsCOMPtr<Element> element = do_QueryReferent(aElementQueue[i]);
     989             : 
     990           0 :     if (!element) {
     991           0 :       continue;
     992             :     }
     993             : 
     994           0 :     RefPtr<CustomElementData> elementData = element->GetCustomElementData();
     995           0 :     MOZ_ASSERT(elementData, "CustomElementData should exist");
     996             : 
     997             :     nsTArray<nsAutoPtr<CustomElementReaction>>& reactions =
     998           0 :       elementData->mReactionQueue;
     999           0 :     for (uint32_t j = 0; j < reactions.Length(); ++j) {
    1000           0 :       reactions.ElementAt(j)->Invoke(element);
    1001             :     }
    1002           0 :     reactions.Clear();
    1003             :   }
    1004           0 :   aElementQueue.Clear();
    1005           0 : }
    1006             : 
    1007             : //-----------------------------------------------------
    1008             : // CustomElementDefinition
    1009             : 
    1010           0 : CustomElementDefinition::CustomElementDefinition(nsIAtom* aType,
    1011             :                                                  nsIAtom* aLocalName,
    1012             :                                                  JSObject* aConstructor,
    1013             :                                                  JSObject* aPrototype,
    1014             :                                                  LifecycleCallbacks* aCallbacks,
    1015           0 :                                                  uint32_t aDocOrder)
    1016             :   : mType(aType),
    1017             :     mLocalName(aLocalName),
    1018             :     mConstructor(aConstructor),
    1019             :     mPrototype(aPrototype),
    1020             :     mCallbacks(aCallbacks),
    1021           0 :     mDocOrder(aDocOrder)
    1022             : {
    1023           0 : }
    1024             : 
    1025             : 
    1026             : //-----------------------------------------------------
    1027             : // CustomElementUpgradeReaction
    1028             : 
    1029             : /* virtual */ void
    1030           0 : CustomElementUpgradeReaction::Invoke(Element* aElement)
    1031             : {
    1032           0 :   mRegistry->Upgrade(aElement, mDefinition);
    1033           0 : }
    1034             : 
    1035             : } // namespace dom
    1036             : } // namespace mozilla

Generated by: LCOV version 1.13