tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CustomElementRegistry.cpp (59566B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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 "js/ForOfIterator.h"       // JS::ForOfIterator
     10 #include "js/PropertyAndElement.h"  // JS_GetProperty, JS_GetUCProperty
     11 #include "jsapi.h"
     12 #include "mozilla/AsyncEventDispatcher.h"
     13 #include "mozilla/AutoRestore.h"
     14 #include "mozilla/CycleCollectedJSContext.h"
     15 #include "mozilla/CycleCollectedUniquePtr.h"
     16 #include "mozilla/HoldDropJSObjects.h"
     17 #include "mozilla/UseCounter.h"
     18 #include "mozilla/dom/AutoEntryScript.h"
     19 #include "mozilla/dom/CustomElementRegistryBinding.h"
     20 #include "mozilla/dom/CustomEvent.h"
     21 #include "mozilla/dom/DocGroup.h"
     22 #include "mozilla/dom/ElementBinding.h"
     23 #include "mozilla/dom/HTMLElement.h"
     24 #include "mozilla/dom/HTMLElementBinding.h"
     25 #include "mozilla/dom/PrimitiveConversions.h"
     26 #include "mozilla/dom/Promise.h"
     27 #include "mozilla/dom/ShadowIncludingTreeIterator.h"
     28 #include "mozilla/dom/ShadowRoot.h"
     29 #include "mozilla/dom/UnionTypes.h"
     30 #include "mozilla/dom/XULElementBinding.h"
     31 #include "nsContentUtils.h"
     32 #include "nsHTMLTags.h"
     33 #include "nsInterfaceHashtable.h"
     34 #include "nsNameSpaceManager.h"
     35 #include "nsPIDOMWindow.h"
     36 #include "xpcprivate.h"
     37 
     38 namespace mozilla::dom {
     39 
     40 //-----------------------------------------------------
     41 // CustomElementUpgradeReaction
     42 
     43 class CustomElementUpgradeReaction final : public CustomElementReaction {
     44 public:
     45  explicit CustomElementUpgradeReaction(CustomElementDefinition* aDefinition)
     46      : mDefinition(aDefinition) {
     47    mIsUpgradeReaction = true;
     48  }
     49 
     50  virtual void Traverse(
     51      nsCycleCollectionTraversalCallback& aCb) const override {
     52    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mDefinition");
     53    aCb.NoteNativeChild(
     54        mDefinition, NS_CYCLE_COLLECTION_PARTICIPANT(CustomElementDefinition));
     55  }
     56 
     57  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
     58    // We don't really own mDefinition.
     59    return aMallocSizeOf(this);
     60  }
     61 
     62 private:
     63  MOZ_CAN_RUN_SCRIPT
     64  virtual void Invoke(Element* aElement, ErrorResult& aRv) override {
     65    CustomElementRegistry::Upgrade(aElement, mDefinition, aRv);
     66  }
     67 
     68  const RefPtr<CustomElementDefinition> mDefinition;
     69 };
     70 
     71 //-----------------------------------------------------
     72 // CustomElementCallbackReaction
     73 
     74 class CustomElementCallback {
     75 public:
     76  CustomElementCallback(Element* aThisObject, ElementCallbackType aCallbackType,
     77                        CallbackFunction* aCallback,
     78                        const LifecycleCallbackArgs& aArgs);
     79  // Secondary callback is needed when moveBefore falls back to
     80  // disconnected/connected callbacks.
     81  void SetSecondaryCallback(ElementCallbackType aType,
     82                            CallbackFunction* aCallback);
     83  void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
     84  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
     85  void Call();
     86 
     87  static UniquePtr<CustomElementCallback> Create(
     88      ElementCallbackType aType, Element* aCustomElement,
     89      const LifecycleCallbackArgs& aArgs, CustomElementDefinition* aDefinition);
     90 
     91 private:
     92  void Call(ElementCallbackType aType, RefPtr<CallbackFunction>& aCallback);
     93  // The this value to use for invocation of the callback.
     94  RefPtr<Element> mThisObject;
     95  RefPtr<CallbackFunction> mCallback;
     96  RefPtr<CallbackFunction> mSecondaryCallback;
     97  // The type of callback (eCreated, eAttached, etc.)
     98  ElementCallbackType mType;
     99  ElementCallbackType mSecondaryType;
    100  // Arguments to be passed to the callback,
    101  LifecycleCallbackArgs mArgs;
    102 };
    103 
    104 class CustomElementCallbackReaction final : public CustomElementReaction {
    105 public:
    106  explicit CustomElementCallbackReaction(
    107      UniquePtr<CustomElementCallback> aCustomElementCallback)
    108      : mCustomElementCallback(std::move(aCustomElementCallback)) {}
    109 
    110  virtual void Traverse(
    111      nsCycleCollectionTraversalCallback& aCb) const override {
    112    mCustomElementCallback->Traverse(aCb);
    113  }
    114 
    115  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
    116    size_t n = aMallocSizeOf(this);
    117 
    118    n += mCustomElementCallback->SizeOfIncludingThis(aMallocSizeOf);
    119 
    120    return n;
    121  }
    122 
    123 private:
    124  virtual void Invoke(Element* aElement, ErrorResult& aRv) override {
    125    mCustomElementCallback->Call();
    126  }
    127 
    128  UniquePtr<CustomElementCallback> mCustomElementCallback;
    129 };
    130 
    131 //-----------------------------------------------------
    132 // CustomElementCallback
    133 
    134 size_t LifecycleCallbackArgs::SizeOfExcludingThis(
    135    MallocSizeOf aMallocSizeOf) const {
    136  size_t n = mOldValue.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
    137  n += mNewValue.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
    138  n += mNamespaceURI.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
    139  return n;
    140 }
    141 
    142 /* static */
    143 UniquePtr<CustomElementCallback> CustomElementCallback::Create(
    144    ElementCallbackType aType, Element* aCustomElement,
    145    const LifecycleCallbackArgs& aArgs, CustomElementDefinition* aDefinition) {
    146  MOZ_ASSERT(aDefinition, "CustomElementDefinition should not be null");
    147  MOZ_ASSERT(aCustomElement->GetCustomElementData(),
    148             "CustomElementData should exist");
    149 
    150  // Let CALLBACK be the callback associated with the key NAME in CALLBACKS.
    151  CallbackFunction* func = nullptr;
    152  switch (aType) {
    153    case ElementCallbackType::eConnected:
    154      if (aDefinition->mCallbacks->mConnectedCallback.WasPassed()) {
    155        func = aDefinition->mCallbacks->mConnectedCallback.Value();
    156      }
    157      break;
    158 
    159    case ElementCallbackType::eDisconnected:
    160      if (aDefinition->mCallbacks->mDisconnectedCallback.WasPassed()) {
    161        func = aDefinition->mCallbacks->mDisconnectedCallback.Value();
    162      }
    163      break;
    164 
    165    case ElementCallbackType::eAdopted:
    166      if (aDefinition->mCallbacks->mAdoptedCallback.WasPassed()) {
    167        func = aDefinition->mCallbacks->mAdoptedCallback.Value();
    168      }
    169      break;
    170 
    171    case ElementCallbackType::eConnectedMove:
    172      if (aDefinition->mCallbacks->mConnectedMoveCallback.WasPassed()) {
    173        func = aDefinition->mCallbacks->mConnectedMoveCallback.Value();
    174      } else if (aDefinition->mCallbacks->mDisconnectedCallback.WasPassed()) {
    175        UniquePtr<CustomElementCallback> callback =
    176            MakeUnique<CustomElementCallback>(
    177                aCustomElement, ElementCallbackType::eDisconnected,
    178                aDefinition->mCallbacks->mDisconnectedCallback.Value(), aArgs);
    179        if (aDefinition->mCallbacks->mConnectedCallback.WasPassed()) {
    180          callback->SetSecondaryCallback(
    181              ElementCallbackType::eConnected,
    182              aDefinition->mCallbacks->mConnectedCallback.Value());
    183        }
    184        return callback;
    185      } else if (aDefinition->mCallbacks->mConnectedCallback.WasPassed()) {
    186        return MakeUnique<CustomElementCallback>(
    187            aCustomElement, ElementCallbackType::eConnected,
    188            aDefinition->mCallbacks->mConnectedCallback.Value(), aArgs);
    189      }
    190      break;
    191 
    192    case ElementCallbackType::eAttributeChanged:
    193      if (aDefinition->mCallbacks->mAttributeChangedCallback.WasPassed()) {
    194        func = aDefinition->mCallbacks->mAttributeChangedCallback.Value();
    195      }
    196      break;
    197 
    198    case ElementCallbackType::eFormAssociated:
    199      if (aDefinition->mFormAssociatedCallbacks->mFormAssociatedCallback
    200              .WasPassed()) {
    201        func = aDefinition->mFormAssociatedCallbacks->mFormAssociatedCallback
    202                   .Value();
    203      }
    204      break;
    205 
    206    case ElementCallbackType::eFormReset:
    207      if (aDefinition->mFormAssociatedCallbacks->mFormResetCallback
    208              .WasPassed()) {
    209        func =
    210            aDefinition->mFormAssociatedCallbacks->mFormResetCallback.Value();
    211      }
    212      break;
    213 
    214    case ElementCallbackType::eFormDisabled:
    215      if (aDefinition->mFormAssociatedCallbacks->mFormDisabledCallback
    216              .WasPassed()) {
    217        func = aDefinition->mFormAssociatedCallbacks->mFormDisabledCallback
    218                   .Value();
    219      }
    220      break;
    221 
    222    case ElementCallbackType::eFormStateRestore:
    223      if (aDefinition->mFormAssociatedCallbacks->mFormStateRestoreCallback
    224              .WasPassed()) {
    225        func = aDefinition->mFormAssociatedCallbacks->mFormStateRestoreCallback
    226                   .Value();
    227      }
    228      break;
    229 
    230    case ElementCallbackType::eGetCustomInterface:
    231      MOZ_ASSERT_UNREACHABLE("Don't call GetCustomInterface through callback");
    232      break;
    233  }
    234 
    235  // If there is no such callback, stop.
    236  if (!func) {
    237    return nullptr;
    238  }
    239 
    240  // Add CALLBACK to ELEMENT's callback queue.
    241  return MakeUnique<CustomElementCallback>(aCustomElement, aType, func, aArgs);
    242 }
    243 
    244 void CustomElementCallback::Call() {
    245  if (mCallback) {
    246    Call(mType, mCallback);
    247  }
    248  if (mSecondaryCallback) {
    249    Call(mSecondaryType, mSecondaryCallback);
    250  }
    251 }
    252 
    253 void CustomElementCallback::Call(ElementCallbackType aType,
    254                                 RefPtr<CallbackFunction>& aCallback) {
    255  switch (aType) {
    256    case ElementCallbackType::eConnected:
    257      static_cast<LifecycleConnectedCallback*>(aCallback.get())
    258          ->Call(mThisObject);
    259      break;
    260    case ElementCallbackType::eDisconnected:
    261      static_cast<LifecycleDisconnectedCallback*>(aCallback.get())
    262          ->Call(mThisObject);
    263      break;
    264    case ElementCallbackType::eAdopted:
    265      static_cast<LifecycleAdoptedCallback*>(aCallback.get())
    266          ->Call(mThisObject, mArgs.mOldDocument, mArgs.mNewDocument);
    267      break;
    268    case ElementCallbackType::eConnectedMove:
    269      static_cast<LifecycleConnectedMoveCallback*>(aCallback.get())
    270          ->Call(mThisObject);
    271      break;
    272    case ElementCallbackType::eAttributeChanged:
    273      static_cast<LifecycleAttributeChangedCallback*>(aCallback.get())
    274          ->Call(mThisObject, nsDependentAtomString(mArgs.mName),
    275                 mArgs.mOldValue, mArgs.mNewValue, mArgs.mNamespaceURI);
    276      break;
    277    case ElementCallbackType::eFormAssociated:
    278      static_cast<LifecycleFormAssociatedCallback*>(aCallback.get())
    279          ->Call(mThisObject, mArgs.mForm);
    280      break;
    281    case ElementCallbackType::eFormReset:
    282      static_cast<LifecycleFormResetCallback*>(aCallback.get())
    283          ->Call(mThisObject);
    284      break;
    285    case ElementCallbackType::eFormDisabled:
    286      static_cast<LifecycleFormDisabledCallback*>(aCallback.get())
    287          ->Call(mThisObject, mArgs.mDisabled);
    288      break;
    289    case ElementCallbackType::eFormStateRestore: {
    290      if (mArgs.mState.IsNull()) {
    291        MOZ_ASSERT_UNREACHABLE(
    292            "A null state should never be restored to a form-associated "
    293            "custom element");
    294        return;
    295      }
    296 
    297      const OwningFileOrUSVStringOrFormData& owningValue = mArgs.mState.Value();
    298      Nullable<FileOrUSVStringOrFormData> value;
    299      if (owningValue.IsFormData()) {
    300        value.SetValue().SetAsFormData() = owningValue.GetAsFormData();
    301      } else if (owningValue.IsFile()) {
    302        value.SetValue().SetAsFile() = owningValue.GetAsFile();
    303      } else {
    304        value.SetValue().SetAsUSVString().ShareOrDependUpon(
    305            owningValue.GetAsUSVString());
    306      }
    307      static_cast<LifecycleFormStateRestoreCallback*>(aCallback.get())
    308          ->Call(mThisObject, value, mArgs.mReason);
    309    } break;
    310    case ElementCallbackType::eGetCustomInterface:
    311      MOZ_ASSERT_UNREACHABLE("Don't call GetCustomInterface through callback");
    312      break;
    313  }
    314 }
    315 
    316 void CustomElementCallback::Traverse(
    317    nsCycleCollectionTraversalCallback& aCb) const {
    318  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mThisObject");
    319  aCb.NoteXPCOMChild(mThisObject);
    320 
    321  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mCallback");
    322  aCb.NoteXPCOMChild(mCallback);
    323 
    324  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mSecondaryCallback");
    325  aCb.NoteXPCOMChild(mSecondaryCallback);
    326 }
    327 
    328 size_t CustomElementCallback::SizeOfIncludingThis(
    329    MallocSizeOf aMallocSizeOf) const {
    330  size_t n = aMallocSizeOf(this);
    331 
    332  // We don't uniquely own mThisObject.
    333 
    334  // We own mCallback but it doesn't have any special memory reporting we can do
    335  // for it other than report its own size.
    336  n += aMallocSizeOf(mCallback);
    337 
    338  n += aMallocSizeOf(mSecondaryCallback);
    339 
    340  n += mArgs.SizeOfExcludingThis(aMallocSizeOf);
    341 
    342  return n;
    343 }
    344 
    345 CustomElementCallback::CustomElementCallback(
    346    Element* aThisObject, ElementCallbackType aCallbackType,
    347    mozilla::dom::CallbackFunction* aCallback,
    348    const LifecycleCallbackArgs& aArgs)
    349    : mThisObject(aThisObject),
    350      mCallback(aCallback),
    351      mType(aCallbackType),
    352      mArgs(aArgs) {}
    353 
    354 void CustomElementCallback::SetSecondaryCallback(
    355    ElementCallbackType aType, mozilla::dom::CallbackFunction* aCallback) {
    356  mSecondaryType = aType;
    357  mSecondaryCallback = aCallback;
    358 }
    359 
    360 //-----------------------------------------------------
    361 // CustomElementData
    362 
    363 CustomElementData::CustomElementData(nsAtom* aType)
    364    : CustomElementData(aType, CustomElementData::State::eUndefined) {}
    365 
    366 CustomElementData::CustomElementData(nsAtom* aType, State aState)
    367    : mState(aState), mType(aType) {}
    368 
    369 void CustomElementData::SetCustomElementDefinition(
    370    CustomElementDefinition* aDefinition) {
    371  // Only allow reset definition to nullptr if the custom element state is
    372  // "failed".
    373  MOZ_ASSERT(aDefinition ? !mCustomElementDefinition
    374                         : mState == State::eFailed);
    375  MOZ_ASSERT_IF(aDefinition, aDefinition->mType == mType);
    376 
    377  mCustomElementDefinition = aDefinition;
    378 }
    379 
    380 void CustomElementData::AttachedInternals() {
    381  MOZ_ASSERT(!mIsAttachedInternals);
    382 
    383  mIsAttachedInternals = true;
    384 }
    385 
    386 CustomElementDefinition* CustomElementData::GetCustomElementDefinition() const {
    387  // Per spec, if there is a definition, the custom element state should be
    388  // either "failed" (during upgrade) or "customized".
    389  MOZ_ASSERT_IF(mCustomElementDefinition, mState != State::eUndefined);
    390 
    391  return mCustomElementDefinition;
    392 }
    393 
    394 bool CustomElementData::IsFormAssociated() const {
    395  // https://html.spec.whatwg.org/#form-associated-custom-element
    396  return mCustomElementDefinition &&
    397         !mCustomElementDefinition->IsCustomBuiltIn() &&
    398         mCustomElementDefinition->mFormAssociated;
    399 }
    400 
    401 void CustomElementData::Traverse(
    402    nsCycleCollectionTraversalCallback& aCb) const {
    403  for (uint32_t i = 0; i < mReactionQueue.Length(); i++) {
    404    if (mReactionQueue[i]) {
    405      mReactionQueue[i]->Traverse(aCb);
    406    }
    407  }
    408 
    409  if (mCustomElementDefinition) {
    410    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mCustomElementDefinition");
    411    aCb.NoteNativeChild(
    412        mCustomElementDefinition,
    413        NS_CYCLE_COLLECTION_PARTICIPANT(CustomElementDefinition));
    414  }
    415 
    416  if (mElementInternals) {
    417    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mElementInternals");
    418    aCb.NoteXPCOMChild(ToSupports(mElementInternals.get()));
    419  }
    420 }
    421 
    422 void CustomElementData::Unlink() {
    423  mReactionQueue.Clear();
    424  if (mElementInternals) {
    425    mElementInternals->Unlink();
    426    mElementInternals = nullptr;
    427  }
    428  mCustomElementDefinition = nullptr;
    429 }
    430 
    431 size_t CustomElementData::SizeOfIncludingThis(
    432    MallocSizeOf aMallocSizeOf) const {
    433  size_t n = aMallocSizeOf(this);
    434 
    435  n += mReactionQueue.ShallowSizeOfExcludingThis(aMallocSizeOf);
    436 
    437  for (auto& reaction : mReactionQueue) {
    438    // "reaction" can be null if we're being called indirectly from
    439    // InvokeReactions (e.g. due to a reaction causing a memory report to be
    440    // captured somehow).
    441    if (reaction) {
    442      n += reaction->SizeOfIncludingThis(aMallocSizeOf);
    443    }
    444  }
    445 
    446  return n;
    447 }
    448 
    449 //-----------------------------------------------------
    450 // CustomElementRegistry
    451 
    452 namespace {
    453 
    454 class MOZ_RAII AutoConstructionStackEntry final {
    455 public:
    456  AutoConstructionStackEntry(nsTArray<RefPtr<Element>>& aStack,
    457                             Element* aElement)
    458      : mStack(aStack) {
    459    MOZ_ASSERT(aElement->IsHTMLElement() || aElement->IsXULElement());
    460 
    461 #ifdef DEBUG
    462    mIndex = mStack.Length();
    463 #endif
    464    mStack.AppendElement(aElement);
    465  }
    466 
    467  ~AutoConstructionStackEntry() {
    468    MOZ_ASSERT(mIndex == mStack.Length() - 1,
    469               "Removed element should be the last element");
    470    mStack.RemoveLastElement();
    471  }
    472 
    473 private:
    474  nsTArray<RefPtr<Element>>& mStack;
    475 #ifdef DEBUG
    476  uint32_t mIndex;
    477 #endif
    478 };
    479 
    480 }  // namespace
    481 
    482 NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementRegistry)
    483 
    484 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CustomElementRegistry)
    485  tmp->mConstructors.clear();
    486  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomDefinitions)
    487  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWhenDefinedPromiseMap)
    488  NS_IMPL_CYCLE_COLLECTION_UNLINK(mElementCreationCallbacks)
    489  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
    490  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
    491 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    492 
    493 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementRegistry)
    494  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomDefinitions)
    495  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWhenDefinedPromiseMap)
    496  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElementCreationCallbacks)
    497  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
    498 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    499 
    500 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CustomElementRegistry)
    501  for (auto iter = tmp->mConstructors.iter(); !iter.done(); iter.next()) {
    502    aCallbacks.Trace(&iter.get().mutableKey(), "mConstructors key", aClosure);
    503  }
    504  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
    505 NS_IMPL_CYCLE_COLLECTION_TRACE_END
    506 
    507 NS_IMPL_CYCLE_COLLECTING_ADDREF(CustomElementRegistry)
    508 NS_IMPL_CYCLE_COLLECTING_RELEASE(CustomElementRegistry)
    509 
    510 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CustomElementRegistry)
    511  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    512  NS_INTERFACE_MAP_ENTRY(nsISupports)
    513 NS_INTERFACE_MAP_END
    514 
    515 CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow)
    516    : mWindow(aWindow), mIsCustomDefinitionRunning(false) {
    517  MOZ_ASSERT(aWindow);
    518 
    519  mozilla::HoldJSObjects(this);
    520 }
    521 
    522 CustomElementRegistry::~CustomElementRegistry() {
    523  mozilla::DropJSObjects(this);
    524 }
    525 
    526 NS_IMETHODIMP
    527 CustomElementRegistry::RunCustomElementCreationCallback::Run() {
    528  ErrorResult er;
    529  nsDependentAtomString value(mAtom);
    530  mCallback->Call(value, er);
    531  MOZ_ASSERT(NS_SUCCEEDED(er.StealNSResult()),
    532             "chrome JavaScript error in the callback.");
    533 
    534  RefPtr<CustomElementDefinition> definition =
    535      mRegistry->mCustomDefinitions.Get(mAtom);
    536  if (!definition) {
    537    // Callback should set the definition of the type.
    538    MOZ_DIAGNOSTIC_CRASH("Callback should set the definition of the type.");
    539    return NS_ERROR_FAILURE;
    540  }
    541 
    542  MOZ_ASSERT(!mRegistry->mElementCreationCallbacks.GetWeak(mAtom),
    543             "Callback should be removed.");
    544 
    545  mozilla::UniquePtr<nsTHashSet<RefPtr<nsIWeakReference>>> elements;
    546  mRegistry->mElementCreationCallbacksUpgradeCandidatesMap.Remove(mAtom,
    547                                                                  &elements);
    548  MOZ_ASSERT(elements, "There should be a list");
    549 
    550  for (const auto& key : *elements) {
    551    nsCOMPtr<Element> elem = do_QueryReferent(key);
    552    if (!elem) {
    553      continue;
    554    }
    555 
    556    CustomElementRegistry::Upgrade(elem, definition, er);
    557    MOZ_ASSERT(NS_SUCCEEDED(er.StealNSResult()),
    558               "chrome JavaScript error in custom element construction.");
    559  }
    560 
    561  return NS_OK;
    562 }
    563 
    564 CustomElementDefinition* CustomElementRegistry::LookupCustomElementDefinition(
    565    nsAtom* aNameAtom, int32_t aNameSpaceID, nsAtom* aTypeAtom) {
    566  CustomElementDefinition* data = mCustomDefinitions.GetWeak(aTypeAtom);
    567 
    568  if (!data) {
    569    RefPtr<CustomElementCreationCallback> callback;
    570    mElementCreationCallbacks.Get(aTypeAtom, getter_AddRefs(callback));
    571    if (callback) {
    572      mElementCreationCallbacks.Remove(aTypeAtom);
    573      mElementCreationCallbacksUpgradeCandidatesMap.GetOrInsertNew(aTypeAtom);
    574      RefPtr<Runnable> runnable =
    575          new RunCustomElementCreationCallback(this, aTypeAtom, callback);
    576      nsContentUtils::AddScriptRunner(runnable.forget());
    577      data = mCustomDefinitions.GetWeak(aTypeAtom);
    578    }
    579  }
    580 
    581  if (data && data->mLocalName == aNameAtom &&
    582      data->mNamespaceID == aNameSpaceID) {
    583    return data;
    584  }
    585 
    586  return nullptr;
    587 }
    588 
    589 CustomElementDefinition* CustomElementRegistry::LookupCustomElementDefinition(
    590    JSContext* aCx, JSObject* aConstructor) const {
    591  // We're looking up things that tested true for JS::IsConstructor,
    592  // so doing a CheckedUnwrapStatic is fine here.
    593  JS::Rooted<JSObject*> constructor(aCx, js::CheckedUnwrapStatic(aConstructor));
    594 
    595  const auto& ptr = mConstructors.lookup(constructor);
    596  if (!ptr) {
    597    return nullptr;
    598  }
    599 
    600  CustomElementDefinition* definition =
    601      mCustomDefinitions.GetWeak(ptr->value());
    602  MOZ_ASSERT(definition, "Definition must be found in mCustomDefinitions");
    603 
    604  return definition;
    605 }
    606 
    607 void CustomElementRegistry::RegisterUnresolvedElement(Element* aElement,
    608                                                      nsAtom* aTypeName) {
    609  // We don't have a use-case for a Custom Element inside NAC, and continuing
    610  // here causes performance issues for NAC + XBL anonymous content.
    611  if (aElement->IsInNativeAnonymousSubtree()) {
    612    return;
    613  }
    614 
    615  mozilla::dom::NodeInfo* info = aElement->NodeInfo();
    616 
    617  // Candidate may be a custom element through extension,
    618  // in which case the custom element type name will not
    619  // match the element tag name. e.g. <button is="x-button">.
    620  RefPtr<nsAtom> typeName = aTypeName;
    621  if (!typeName) {
    622    typeName = info->NameAtom();
    623  }
    624 
    625  if (mCustomDefinitions.GetWeak(typeName)) {
    626    return;
    627  }
    628 
    629  nsTHashSet<RefPtr<nsIWeakReference>>* unresolved =
    630      mCandidatesMap.GetOrInsertNew(typeName);
    631  nsWeakPtr elem = do_GetWeakReference(aElement);
    632  unresolved->Insert(elem);
    633 }
    634 
    635 void CustomElementRegistry::UnregisterUnresolvedElement(Element* aElement,
    636                                                        nsAtom* aTypeName) {
    637  nsIWeakReference* weak = aElement->GetExistingWeakReference();
    638  if (!weak) {
    639    return;
    640  }
    641 
    642 #ifdef DEBUG
    643  {
    644    nsWeakPtr weakPtr = do_GetWeakReference(aElement);
    645    MOZ_ASSERT(
    646        weak == weakPtr.get(),
    647        "do_GetWeakReference should reuse the existing nsIWeakReference.");
    648  }
    649 #endif
    650 
    651  nsTHashSet<RefPtr<nsIWeakReference>>* candidates = nullptr;
    652  if (mCandidatesMap.Get(aTypeName, &candidates)) {
    653    MOZ_ASSERT(candidates);
    654    candidates->Remove(weak);
    655  }
    656 }
    657 
    658 // https://html.spec.whatwg.org/commit-snapshots/65f39c6fc0efa92b0b2b23b93197016af6ac0de6/#enqueue-a-custom-element-callback-reaction
    659 /* static */
    660 void CustomElementRegistry::EnqueueLifecycleCallback(
    661    ElementCallbackType aType, Element* aCustomElement,
    662    const LifecycleCallbackArgs& aArgs, CustomElementDefinition* aDefinition) {
    663  CustomElementDefinition* definition = aDefinition;
    664  if (!definition) {
    665    definition = aCustomElement->GetCustomElementDefinition();
    666    if (!definition ||
    667        definition->mLocalName != aCustomElement->NodeInfo()->NameAtom()) {
    668      return;
    669    }
    670 
    671    if (!definition->mCallbacks && !definition->mFormAssociatedCallbacks) {
    672      // definition has been unlinked.  Don't try to mess with it.
    673      return;
    674    }
    675  }
    676 
    677  auto callback =
    678      CustomElementCallback::Create(aType, aCustomElement, aArgs, definition);
    679  if (!callback) {
    680    return;
    681  }
    682 
    683  DocGroup* docGroup = aCustomElement->OwnerDoc()->GetDocGroup();
    684  if (!docGroup) {
    685    return;
    686  }
    687 
    688  if (aType == ElementCallbackType::eAttributeChanged) {
    689    if (!definition->mObservedAttributes.Contains(aArgs.mName)) {
    690      return;
    691    }
    692  }
    693 
    694  CustomElementReactionsStack* reactionsStack =
    695      docGroup->CustomElementReactionsStack();
    696  reactionsStack->EnqueueCallbackReaction(aCustomElement, std::move(callback));
    697 }
    698 
    699 namespace {
    700 
    701 class CandidateFinder {
    702 public:
    703  CandidateFinder(nsTHashSet<RefPtr<nsIWeakReference>>& aCandidates,
    704                  Document* aDoc);
    705  nsTArray<nsCOMPtr<Element>> OrderedCandidates();
    706 
    707 private:
    708  nsCOMPtr<Document> mDoc;
    709  nsInterfaceHashtable<nsPtrHashKey<Element>, Element> mCandidates;
    710 };
    711 
    712 CandidateFinder::CandidateFinder(
    713    nsTHashSet<RefPtr<nsIWeakReference>>& aCandidates, Document* aDoc)
    714    : mDoc(aDoc), mCandidates(aCandidates.Count()) {
    715  MOZ_ASSERT(mDoc);
    716  for (const auto& candidate : aCandidates) {
    717    nsCOMPtr<Element> elem = do_QueryReferent(candidate);
    718    if (!elem) {
    719      continue;
    720    }
    721 
    722    Element* key = elem.get();
    723    mCandidates.InsertOrUpdate(key, elem.forget());
    724  }
    725 }
    726 
    727 nsTArray<nsCOMPtr<Element>> CandidateFinder::OrderedCandidates() {
    728  if (mCandidates.Count() == 1) {
    729    // Fast path for one candidate.
    730    auto iter = mCandidates.Iter();
    731    nsTArray<nsCOMPtr<Element>> rval({std::move(iter.Data())});
    732    iter.Remove();
    733    return rval;
    734  }
    735 
    736  nsTArray<nsCOMPtr<Element>> orderedElements(mCandidates.Count());
    737  for (nsINode* node : ShadowIncludingTreeIterator(*mDoc)) {
    738    Element* element = Element::FromNode(node);
    739    if (!element) {
    740      continue;
    741    }
    742 
    743    nsCOMPtr<Element> elem;
    744    if (mCandidates.Remove(element, getter_AddRefs(elem))) {
    745      orderedElements.AppendElement(std::move(elem));
    746      if (mCandidates.Count() == 0) {
    747        break;
    748      }
    749    }
    750  }
    751 
    752  return orderedElements;
    753 }
    754 
    755 }  // namespace
    756 
    757 void CustomElementRegistry::UpgradeCandidates(
    758    nsAtom* aKey, CustomElementDefinition* aDefinition, ErrorResult& aRv) {
    759  DocGroup* docGroup = mWindow->GetDocGroup();
    760  if (!docGroup) {
    761    aRv.Throw(NS_ERROR_UNEXPECTED);
    762    return;
    763  }
    764 
    765  mozilla::UniquePtr<nsTHashSet<RefPtr<nsIWeakReference>>> candidates;
    766  if (mCandidatesMap.Remove(aKey, &candidates)) {
    767    MOZ_ASSERT(candidates);
    768    CustomElementReactionsStack* reactionsStack =
    769        docGroup->CustomElementReactionsStack();
    770 
    771    CandidateFinder finder(*candidates, mWindow->GetExtantDoc());
    772    for (auto& elem : finder.OrderedCandidates()) {
    773      reactionsStack->EnqueueUpgradeReaction(elem, aDefinition);
    774    }
    775  }
    776 }
    777 
    778 JSObject* CustomElementRegistry::WrapObject(JSContext* aCx,
    779                                            JS::Handle<JSObject*> aGivenProto) {
    780  return CustomElementRegistry_Binding::Wrap(aCx, this, aGivenProto);
    781 }
    782 
    783 nsISupports* CustomElementRegistry::GetParentObject() const { return mWindow; }
    784 
    785 DocGroup* CustomElementRegistry::GetDocGroup() const {
    786  return mWindow ? mWindow->GetDocGroup() : nullptr;
    787 }
    788 
    789 int32_t CustomElementRegistry::InferNamespace(
    790    JSContext* aCx, JS::Handle<JSObject*> constructor) {
    791  JS::Rooted<JSObject*> XULConstructor(
    792      aCx, XULElement_Binding::GetConstructorObjectHandle(aCx));
    793 
    794  JS::Rooted<JSObject*> proto(aCx, constructor);
    795  while (proto) {
    796    if (proto == XULConstructor) {
    797      return kNameSpaceID_XUL;
    798    }
    799 
    800    JS_GetPrototype(aCx, proto, &proto);
    801  }
    802 
    803  return kNameSpaceID_XHTML;
    804 }
    805 
    806 bool CustomElementRegistry::JSObjectToAtomArray(
    807    JSContext* aCx, JS::Handle<JSObject*> aConstructor, const nsString& aName,
    808    nsTArray<RefPtr<nsAtom>>& aArray, ErrorResult& aRv) {
    809  JS::Rooted<JS::Value> iterable(aCx, JS::UndefinedValue());
    810  if (!JS_GetUCProperty(aCx, aConstructor, aName.get(), aName.Length(),
    811                        &iterable)) {
    812    aRv.NoteJSContextException(aCx);
    813    return false;
    814  }
    815 
    816  if (!iterable.isUndefined()) {
    817    if (!iterable.isObject()) {
    818      aRv.ThrowTypeError<MSG_CONVERSION_ERROR>(NS_ConvertUTF16toUTF8(aName),
    819                                               "sequence");
    820      return false;
    821    }
    822 
    823    JS::ForOfIterator iter(aCx);
    824    if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable)) {
    825      aRv.NoteJSContextException(aCx);
    826      return false;
    827    }
    828 
    829    if (!iter.valueIsIterable()) {
    830      aRv.ThrowTypeError<MSG_CONVERSION_ERROR>(NS_ConvertUTF16toUTF8(aName),
    831                                               "sequence");
    832      return false;
    833    }
    834 
    835    JS::Rooted<JS::Value> attribute(aCx);
    836    while (true) {
    837      bool done;
    838      if (!iter.next(&attribute, &done)) {
    839        aRv.NoteJSContextException(aCx);
    840        return false;
    841      }
    842      if (done) {
    843        break;
    844      }
    845 
    846      nsAutoString attrStr;
    847      if (!ConvertJSValueToString(aCx, attribute, eStringify, eStringify,
    848                                  attrStr)) {
    849        aRv.NoteJSContextException(aCx);
    850        return false;
    851      }
    852 
    853      // XXX(Bug 1631371) Check if this should use a fallible operation as it
    854      // pretended earlier.
    855      aArray.AppendElement(NS_Atomize(attrStr));
    856    }
    857  }
    858 
    859  return true;
    860 }
    861 
    862 // https://html.spec.whatwg.org/commit-snapshots/b48bb2238269d90ea4f455a52cdf29505aff3df0/#dom-customelementregistry-define
    863 void CustomElementRegistry::Define(
    864    JSContext* aCx, const nsAString& aName,
    865    CustomElementConstructor& aFunctionConstructor,
    866    const ElementDefinitionOptions& aOptions, ErrorResult& aRv) {
    867  JS::Rooted<JSObject*> constructor(aCx, aFunctionConstructor.CallableOrNull());
    868 
    869  // We need to do a dynamic unwrap in order to throw the right exception.  We
    870  // could probably avoid that if we just threw MSG_NOT_CONSTRUCTOR if unwrap
    871  // fails.
    872  //
    873  // In any case, aCx represents the global we want to be using for the unwrap
    874  // here.
    875  JS::Rooted<JSObject*> constructorUnwrapped(
    876      aCx, js::CheckedUnwrapDynamic(constructor, aCx));
    877  if (!constructorUnwrapped) {
    878    // If the caller's compartment does not have permission to access the
    879    // unwrapped constructor then throw.
    880    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    881    return;
    882  }
    883 
    884  /**
    885   * 1. If IsConstructor(constructor) is false, then throw a TypeError and abort
    886   *    these steps.
    887   */
    888  if (!JS::IsConstructor(constructorUnwrapped)) {
    889    aRv.ThrowTypeError<MSG_NOT_CONSTRUCTOR>("Argument 2");
    890    return;
    891  }
    892 
    893  int32_t nameSpaceID = InferNamespace(aCx, constructor);
    894 
    895  /**
    896   * 2. If name is not a valid custom element name, then throw a "SyntaxError"
    897   *    DOMException and abort these steps.
    898   */
    899  Document* doc = mWindow->GetExtantDoc();
    900  RefPtr<nsAtom> nameAtom(NS_Atomize(aName));
    901  if (!nsContentUtils::IsCustomElementName(nameAtom, nameSpaceID)) {
    902    aRv.ThrowSyntaxError(
    903        nsPrintfCString("'%s' is not a valid custom element name",
    904                        NS_ConvertUTF16toUTF8(aName).get()));
    905    return;
    906  }
    907 
    908  /**
    909   * 3. If this CustomElementRegistry contains an entry with name name, then
    910   *    throw a "NotSupportedError" DOMException and abort these steps.
    911   */
    912  if (mCustomDefinitions.GetWeak(nameAtom)) {
    913    aRv.ThrowNotSupportedError(
    914        nsPrintfCString("'%s' has already been defined as a custom element",
    915                        NS_ConvertUTF16toUTF8(aName).get()));
    916    return;
    917  }
    918 
    919  /**
    920   * 4. If this CustomElementRegistry contains an entry with constructor
    921   * constructor, then throw a "NotSupportedError" DOMException and abort these
    922   * steps.
    923   */
    924  const auto& ptr = mConstructors.lookup(constructorUnwrapped);
    925  if (ptr) {
    926    MOZ_ASSERT(mCustomDefinitions.GetWeak(ptr->value()),
    927               "Definition must be found in mCustomDefinitions");
    928    nsAutoCString name;
    929    ptr->value()->ToUTF8String(name);
    930    aRv.ThrowNotSupportedError(
    931        nsPrintfCString("'%s' and '%s' have the same constructor",
    932                        NS_ConvertUTF16toUTF8(aName).get(), name.get()));
    933    return;
    934  }
    935 
    936  /**
    937   * 5. Let localName be name.
    938   * 6. Let extends be the value of the extends member of options, or null if
    939   *    no such member exists.
    940   * 7. If extends is not null, then:
    941   *    1. If extends is a valid custom element name, then throw a
    942   *       "NotSupportedError" DOMException.
    943   *    2. If the element interface for extends and the HTML namespace is
    944   *       HTMLUnknownElement (e.g., if extends does not indicate an element
    945   *       definition in this specification), then throw a "NotSupportedError"
    946   *       DOMException.
    947   *    3. Set localName to extends.
    948   *
    949   * Special note for XUL elements:
    950   *
    951   * For step 7.1, we'll subject XUL to the same rules as HTML, so that a
    952   * custom built-in element will not be extending from a dashed name.
    953   * Step 7.2 is disregarded. But, we do check if the name is a dashed name
    954   * (i.e. step 2) given that there is no reason for a custom built-in element
    955   * type to take on a non-dashed name.
    956   * This also ensures the name of the built-in custom element type can never
    957   * be the same as the built-in element name, so we don't break the assumption
    958   * elsewhere.
    959   */
    960  RefPtr<nsAtom> localNameAtom = nameAtom;
    961  if (aOptions.mExtends.WasPassed()) {
    962    doc->SetUseCounter(eUseCounter_custom_CustomizedBuiltin);
    963 
    964    RefPtr<nsAtom> extendsAtom(NS_Atomize(aOptions.mExtends.Value()));
    965    if (nsContentUtils::IsCustomElementName(extendsAtom, kNameSpaceID_XHTML)) {
    966      aRv.ThrowNotSupportedError(
    967          nsPrintfCString("'%s' cannot extend a custom element",
    968                          NS_ConvertUTF16toUTF8(aName).get()));
    969      return;
    970    }
    971 
    972    if (nameSpaceID == kNameSpaceID_XHTML) {
    973      // bgsound and multicol are unknown html element.
    974      int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(extendsAtom);
    975      if (tag == eHTMLTag_userdefined || tag == eHTMLTag_bgsound ||
    976          tag == eHTMLTag_multicol) {
    977        aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    978        return;
    979      }
    980    } else {  // kNameSpaceID_XUL
    981      // As stated above, ensure the name of the customized built-in element
    982      // (the one that goes to the |is| attribute) is a dashed name.
    983      if (!nsContentUtils::IsNameWithDash(nameAtom)) {
    984        aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    985        return;
    986      }
    987    }
    988 
    989    localNameAtom = NS_Atomize(aOptions.mExtends.Value());
    990  }
    991 
    992  /**
    993   * 8. If this CustomElementRegistry's element definition is running flag is
    994   * set, then throw a "NotSupportedError" DOMException and abort these steps.
    995   */
    996  if (mIsCustomDefinitionRunning) {
    997    aRv.ThrowNotSupportedError(
    998        "Cannot define a custom element while defining another custom element");
    999    return;
   1000  }
   1001 
   1002  auto callbacksHolder = MakeUnique<LifecycleCallbacks>();
   1003  auto formAssociatedCallbacksHolder =
   1004      MakeUnique<FormAssociatedLifecycleCallbacks>();
   1005  nsTArray<RefPtr<nsAtom>> observedAttributes;
   1006  AutoTArray<RefPtr<nsAtom>, 2> disabledFeatures;
   1007  bool formAssociated = false;
   1008  bool disableInternals = false;
   1009  bool disableShadow = false;
   1010  {  // Set mIsCustomDefinitionRunning.
   1011    /**
   1012     * 9. Set this CustomElementRegistry's element definition is running flag.
   1013     */
   1014    AutoRestore<bool> restoreRunning(mIsCustomDefinitionRunning);
   1015    mIsCustomDefinitionRunning = true;
   1016 
   1017    /**
   1018     * 14.1. Let prototype be Get(constructor, "prototype"). Rethrow any
   1019     * exceptions.
   1020     */
   1021    // The .prototype on the constructor passed could be an "expando" of a
   1022    // wrapper. So we should get it from wrapper instead of the underlying
   1023    // object.
   1024    JS::Rooted<JS::Value> prototype(aCx);
   1025    if (!JS_GetProperty(aCx, constructor, "prototype", &prototype)) {
   1026      aRv.NoteJSContextException(aCx);
   1027      return;
   1028    }
   1029 
   1030    /**
   1031     * 14.2. If Type(prototype) is not Object, then throw a TypeError exception.
   1032     */
   1033    if (!prototype.isObject()) {
   1034      aRv.ThrowTypeError<MSG_NOT_OBJECT>("constructor.prototype");
   1035      return;
   1036    }
   1037 
   1038    /**
   1039     * 14.3. Let lifecycleCallbacks be a map with the four keys
   1040     *       "connectedCallback", "disconnectedCallback", "adoptedCallback", and
   1041     *       "attributeChangedCallback", each of which belongs to an entry whose
   1042     *       value is null. The 'getCustomInterface' callback is also included
   1043     *       for chrome usage.
   1044     * 14.4. For each of the four keys callbackName in lifecycleCallbacks:
   1045     *       1. Let callbackValue be Get(prototype, callbackName). Rethrow any
   1046     *          exceptions.
   1047     *       2. If callbackValue is not undefined, then set the value of the
   1048     *          entry in lifecycleCallbacks with key callbackName to the result
   1049     *          of converting callbackValue to the Web IDL Function callback
   1050     * type. Rethrow any exceptions from the conversion.
   1051     */
   1052    if (!callbacksHolder->Init(aCx, prototype)) {
   1053      aRv.NoteJSContextException(aCx);
   1054      return;
   1055    }
   1056 
   1057    /**
   1058     * 14.5. If the value of the entry in lifecycleCallbacks with key
   1059     *       "attributeChangedCallback" is not null, then:
   1060     *       1. Let observedAttributesIterable be Get(constructor,
   1061     *          "observedAttributes"). Rethrow any exceptions.
   1062     *       2. If observedAttributesIterable is not undefined, then set
   1063     *          observedAttributes to the result of converting
   1064     *          observedAttributesIterable to a sequence<DOMString>. Rethrow
   1065     *          any exceptions from the conversion.
   1066     */
   1067    if (callbacksHolder->mAttributeChangedCallback.WasPassed()) {
   1068      if (!JSObjectToAtomArray(aCx, constructor, u"observedAttributes"_ns,
   1069                               observedAttributes, aRv)) {
   1070        return;
   1071      }
   1072    }
   1073 
   1074    /**
   1075     * 14.6. Let disabledFeatures be an empty sequence<DOMString>.
   1076     * 14.7. Let disabledFeaturesIterable be Get(constructor,
   1077     *       "disabledFeatures"). Rethrow any exceptions.
   1078     * 14.8. If disabledFeaturesIterable is not undefined, then set
   1079     *       disabledFeatures to the result of converting
   1080     *       disabledFeaturesIterable to a sequence<DOMString>.
   1081     *       Rethrow any exceptions from the conversion.
   1082     */
   1083    if (!JSObjectToAtomArray(aCx, constructor, u"disabledFeatures"_ns,
   1084                             disabledFeatures, aRv)) {
   1085      return;
   1086    }
   1087 
   1088    // 14.9. Set disableInternals to true if disabledFeaturesSequence contains
   1089    //       "internals".
   1090    disableInternals = disabledFeatures.Contains(
   1091        static_cast<nsStaticAtom*>(nsGkAtoms::internals));
   1092 
   1093    // 14.10. Set disableShadow to true if disabledFeaturesSequence contains
   1094    //        "shadow".
   1095    disableShadow = disabledFeatures.Contains(
   1096        static_cast<nsStaticAtom*>(nsGkAtoms::shadow));
   1097 
   1098    // 14.11. Let formAssociatedValue be Get(constructor, "formAssociated").
   1099    //        Rethrow any exceptions.
   1100    JS::Rooted<JS::Value> formAssociatedValue(aCx);
   1101    if (!JS_GetProperty(aCx, constructor, "formAssociated",
   1102                        &formAssociatedValue)) {
   1103      aRv.NoteJSContextException(aCx);
   1104      return;
   1105    }
   1106 
   1107    // 14.12. Set formAssociated to the result of converting
   1108    //        formAssociatedValue to a boolean. Rethrow any exceptions from
   1109    //        the conversion.
   1110    if (!ValueToPrimitive<bool, eDefault>(aCx, formAssociatedValue,
   1111                                          "formAssociated", &formAssociated)) {
   1112      aRv.NoteJSContextException(aCx);
   1113      return;
   1114    }
   1115 
   1116    /**
   1117     * 14.13. If formAssociated is true, for each of "formAssociatedCallback",
   1118     *        "formResetCallback", "formDisabledCallback", and
   1119     *        "formStateRestoreCallback" callbackName:
   1120     *        1. Let callbackValue be ? Get(prototype, callbackName).
   1121     *        2. If callbackValue is not undefined, then set the value of the
   1122     *           entry in lifecycleCallbacks with key callbackName to the result
   1123     *           of converting callbackValue to the Web IDL Function callback
   1124     *           type. Rethrow any exceptions from the conversion.
   1125     */
   1126    if (formAssociated &&
   1127        !formAssociatedCallbacksHolder->Init(aCx, prototype)) {
   1128      aRv.NoteJSContextException(aCx);
   1129      return;
   1130    }
   1131  }  // Unset mIsCustomDefinitionRunning
   1132 
   1133  /**
   1134   * 15. Let definition be a new custom element definition with name name,
   1135   *     local name localName, constructor constructor, prototype prototype,
   1136   *     observed attributes observedAttributes, and lifecycle callbacks
   1137   *     lifecycleCallbacks.
   1138   * 16. Add definition to this CustomElementRegistry.
   1139   */
   1140  if (!mConstructors.put(constructorUnwrapped, nameAtom)) {
   1141    aRv.Throw(NS_ERROR_FAILURE);
   1142    return;
   1143  }
   1144 
   1145  RefPtr<CustomElementDefinition> definition = new CustomElementDefinition(
   1146      nameAtom, localNameAtom, nameSpaceID, &aFunctionConstructor,
   1147      std::move(observedAttributes), std::move(callbacksHolder),
   1148      std::move(formAssociatedCallbacksHolder), formAssociated,
   1149      disableInternals, disableShadow);
   1150 
   1151  CustomElementDefinition* def = definition.get();
   1152  mCustomDefinitions.InsertOrUpdate(nameAtom, std::move(definition));
   1153 
   1154  MOZ_ASSERT(mCustomDefinitions.Count() == mConstructors.count(),
   1155             "Number of entries should be the same");
   1156 
   1157  /**
   1158   * 17. 18. 19. Upgrade candidates
   1159   */
   1160  UpgradeCandidates(nameAtom, def, aRv);
   1161 
   1162  /**
   1163   * 20. If this CustomElementRegistry's when-defined promise map contains an
   1164   *     entry with key name:
   1165   *     1. Let promise be the value of that entry.
   1166   *     2. Resolve promise with undefined.
   1167   *     3. Delete the entry with key name from this CustomElementRegistry's
   1168   *        when-defined promise map.
   1169   */
   1170  RefPtr<Promise> promise;
   1171  mWhenDefinedPromiseMap.Remove(nameAtom, getter_AddRefs(promise));
   1172  if (promise) {
   1173    promise->MaybeResolve(def->mConstructor);
   1174  }
   1175 
   1176  // Dispatch a "customelementdefined" event for DevTools.
   1177  BrowsingContext* browsingContext = mWindow->GetBrowsingContext();
   1178  if (browsingContext && browsingContext->WatchedByDevTools()) {
   1179    JSString* nameJsStr =
   1180        JS_NewUCStringCopyN(aCx, aName.BeginReading(), aName.Length());
   1181 
   1182    JS::Rooted<JS::Value> detail(aCx, JS::StringValue(nameJsStr));
   1183    RefPtr<CustomEvent> event = NS_NewDOMCustomEvent(doc, nullptr, nullptr);
   1184    event->InitCustomEvent(aCx, u"customelementdefined"_ns,
   1185                           /* CanBubble */ true,
   1186                           /* Cancelable */ true, detail);
   1187    event->SetTrusted(true);
   1188 
   1189    AsyncEventDispatcher* dispatcher =
   1190        new AsyncEventDispatcher(doc, event.forget());
   1191    dispatcher->mOnlyChromeDispatch = ChromeOnlyDispatch::eYes;
   1192 
   1193    dispatcher->PostDOMEvent();
   1194  }
   1195 
   1196  /**
   1197   * Clean-up mElementCreationCallbacks (if it exists)
   1198   */
   1199  mElementCreationCallbacks.Remove(nameAtom);
   1200 }
   1201 
   1202 void CustomElementRegistry::SetElementCreationCallback(
   1203    const nsAString& aName, CustomElementCreationCallback& aCallback,
   1204    ErrorResult& aRv) {
   1205  RefPtr<nsAtom> nameAtom(NS_Atomize(aName));
   1206  if (mElementCreationCallbacks.GetWeak(nameAtom) ||
   1207      mCustomDefinitions.GetWeak(nameAtom)) {
   1208    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   1209    return;
   1210  }
   1211 
   1212  RefPtr<CustomElementCreationCallback> callback = &aCallback;
   1213 
   1214  if (mCandidatesMap.Contains(nameAtom)) {
   1215    mElementCreationCallbacksUpgradeCandidatesMap.GetOrInsertNew(nameAtom);
   1216    RefPtr<Runnable> runnable =
   1217        new RunCustomElementCreationCallback(this, nameAtom, callback);
   1218    nsContentUtils::AddScriptRunner(runnable.forget());
   1219  } else {
   1220    mElementCreationCallbacks.InsertOrUpdate(nameAtom, std::move(callback));
   1221  }
   1222 }
   1223 
   1224 void CustomElementRegistry::Upgrade(nsINode& aRoot) {
   1225  for (nsINode* node : ShadowIncludingTreeIterator(aRoot)) {
   1226    Element* element = Element::FromNode(node);
   1227    if (!element) {
   1228      continue;
   1229    }
   1230 
   1231    CustomElementData* ceData = element->GetCustomElementData();
   1232    if (ceData) {
   1233      NodeInfo* nodeInfo = element->NodeInfo();
   1234      nsAtom* typeAtom = ceData->GetCustomElementType();
   1235      CustomElementDefinition* definition =
   1236          nsContentUtils::LookupCustomElementDefinition(
   1237              nodeInfo->GetDocument(), nodeInfo->NameAtom(),
   1238              nodeInfo->NamespaceID(), typeAtom);
   1239      if (definition) {
   1240        nsContentUtils::EnqueueUpgradeReaction(element, definition);
   1241      }
   1242    }
   1243  }
   1244 }
   1245 
   1246 void CustomElementRegistry::Get(
   1247    const nsAString& aName,
   1248    OwningCustomElementConstructorOrUndefined& aRetVal) {
   1249  RefPtr<nsAtom> nameAtom(NS_Atomize(aName));
   1250  CustomElementDefinition* data = mCustomDefinitions.GetWeak(nameAtom);
   1251 
   1252  if (!data) {
   1253    aRetVal.SetUndefined();
   1254    return;
   1255  }
   1256 
   1257  aRetVal.SetAsCustomElementConstructor() = data->mConstructor;
   1258 }
   1259 
   1260 void CustomElementRegistry::GetName(JSContext* aCx,
   1261                                    CustomElementConstructor& aConstructor,
   1262                                    nsAString& aResult) {
   1263  CustomElementDefinition* aDefinition =
   1264      LookupCustomElementDefinition(aCx, aConstructor.CallableOrNull());
   1265 
   1266  if (aDefinition) {
   1267    aDefinition->mType->ToString(aResult);
   1268  } else {
   1269    aResult.SetIsVoid(true);
   1270  }
   1271 }
   1272 
   1273 already_AddRefed<Promise> CustomElementRegistry::WhenDefined(
   1274    const nsAString& aName, ErrorResult& aRv) {
   1275  // Define a function that lazily creates a Promise and perform some action on
   1276  // it when creation succeeded. It's needed in multiple cases below, but not in
   1277  // all of them.
   1278  auto createPromise = [&](auto&& action) -> already_AddRefed<Promise> {
   1279    nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
   1280    RefPtr<Promise> promise = Promise::Create(global, aRv);
   1281 
   1282    if (aRv.Failed()) {
   1283      return nullptr;
   1284    }
   1285 
   1286    action(promise);
   1287 
   1288    return promise.forget();
   1289  };
   1290 
   1291  RefPtr<nsAtom> nameAtom(NS_Atomize(aName));
   1292  Document* doc = mWindow->GetExtantDoc();
   1293  uint32_t nameSpaceID =
   1294      doc ? doc->GetDefaultNamespaceID() : kNameSpaceID_XHTML;
   1295  if (!nsContentUtils::IsCustomElementName(nameAtom, nameSpaceID)) {
   1296    aRv.ThrowSyntaxError(
   1297        nsPrintfCString("'%s' is not a valid custom element name",
   1298                        NS_ConvertUTF16toUTF8(aName).get()));
   1299    return nullptr;
   1300  }
   1301 
   1302  if (CustomElementDefinition* definition =
   1303          mCustomDefinitions.GetWeak(nameAtom)) {
   1304    return createPromise([&](const RefPtr<Promise>& promise) {
   1305      promise->MaybeResolve(definition->mConstructor);
   1306    });
   1307  }
   1308 
   1309  return mWhenDefinedPromiseMap.WithEntryHandle(
   1310      nameAtom, [&](auto&& entry) -> already_AddRefed<Promise> {
   1311        if (!entry) {
   1312          return createPromise([&entry](const RefPtr<Promise>& promise) {
   1313            entry.Insert(promise);
   1314          });
   1315        }
   1316        return do_AddRef(entry.Data());
   1317      });
   1318 }
   1319 
   1320 namespace {
   1321 
   1322 MOZ_CAN_RUN_SCRIPT
   1323 static void DoUpgrade(Element* aElement, CustomElementDefinition* aDefinition,
   1324                      CustomElementConstructor* aConstructor,
   1325                      ErrorResult& aRv) {
   1326  if (aDefinition->mDisableShadow && aElement->GetShadowRoot()) {
   1327    aRv.ThrowNotSupportedError(nsPrintfCString(
   1328        "Custom element upgrade to '%s' is disabled because a shadow root "
   1329        "already exists",
   1330        NS_ConvertUTF16toUTF8(aDefinition->mType->GetUTF16String()).get()));
   1331    return;
   1332  }
   1333 
   1334  CustomElementData* data = aElement->GetCustomElementData();
   1335  MOZ_ASSERT(data, "CustomElementData should exist");
   1336  data->mState = CustomElementData::State::ePrecustomized;
   1337 
   1338  JS::Rooted<JS::Value> constructResult(RootingCx());
   1339  // Rethrow the exception since it might actually throw the exception from the
   1340  // upgrade steps back out to the caller of document.createElement.
   1341  aConstructor->Construct(&constructResult, aRv, "Custom Element Upgrade",
   1342                          CallbackFunction::eRethrowExceptions);
   1343  if (aRv.Failed()) {
   1344    return;
   1345  }
   1346 
   1347  Element* element;
   1348  // constructResult is an ObjectValue because construction with a callback
   1349  // always forms the return value from a JSObject.
   1350  if (NS_FAILED(UNWRAP_OBJECT(Element, &constructResult, element)) ||
   1351      element != aElement) {
   1352    aRv.ThrowTypeError("Custom element constructor returned a wrong element");
   1353    return;
   1354  }
   1355 }
   1356 
   1357 }  // anonymous namespace
   1358 
   1359 // https://html.spec.whatwg.org/commit-snapshots/2793ee4a461c6c39896395f1a45c269ea820c47e/#upgrades
   1360 /* static */
   1361 void CustomElementRegistry::Upgrade(Element* aElement,
   1362                                    CustomElementDefinition* aDefinition,
   1363                                    ErrorResult& aRv) {
   1364  CustomElementData* data = aElement->GetCustomElementData();
   1365  MOZ_ASSERT(data, "CustomElementData should exist");
   1366 
   1367  // Step 1.
   1368  if (data->mState != CustomElementData::State::eUndefined) {
   1369    return;
   1370  }
   1371 
   1372  // Step 2.
   1373  aElement->SetCustomElementDefinition(aDefinition);
   1374 
   1375  // Step 3.
   1376  data->mState = CustomElementData::State::eFailed;
   1377 
   1378  // Step 4.
   1379  if (!aDefinition->mObservedAttributes.IsEmpty()) {
   1380    uint32_t count = aElement->GetAttrCount();
   1381    for (uint32_t i = 0; i < count; i++) {
   1382      mozilla::dom::BorrowedAttrInfo info = aElement->GetAttrInfoAt(i);
   1383 
   1384      const nsAttrName* name = info.mName;
   1385      nsAtom* attrName = name->LocalName();
   1386 
   1387      if (aDefinition->IsInObservedAttributeList(attrName)) {
   1388        int32_t namespaceID = name->NamespaceID();
   1389        nsAutoString attrValue, namespaceURI;
   1390        info.mValue->ToString(attrValue);
   1391        nsNameSpaceManager::GetInstance()->GetNameSpaceURI(namespaceID,
   1392                                                           namespaceURI);
   1393 
   1394        LifecycleCallbackArgs args;
   1395        args.mName = attrName;
   1396        args.mOldValue = VoidString();
   1397        args.mNewValue = attrValue;
   1398        args.mNamespaceURI =
   1399            (namespaceURI.IsEmpty() ? VoidString() : namespaceURI);
   1400 
   1401        nsContentUtils::EnqueueLifecycleCallback(
   1402            ElementCallbackType::eAttributeChanged, aElement, args,
   1403            aDefinition);
   1404      }
   1405    }
   1406  }
   1407 
   1408  // Step 5.
   1409  if (aElement->IsInComposedDoc()) {
   1410    nsContentUtils::EnqueueLifecycleCallback(ElementCallbackType::eConnected,
   1411                                             aElement, {}, aDefinition);
   1412  }
   1413 
   1414  // Step 6.
   1415  AutoConstructionStackEntry acs(aDefinition->mConstructionStack, aElement);
   1416 
   1417  // Step 7 and step 8.
   1418  DoUpgrade(aElement, aDefinition, MOZ_KnownLive(aDefinition->mConstructor),
   1419            aRv);
   1420  if (aRv.Failed()) {
   1421    MOZ_ASSERT(data->mState == CustomElementData::State::eFailed ||
   1422               data->mState == CustomElementData::State::ePrecustomized);
   1423    // Spec doesn't set custom element state to failed here, but without this we
   1424    // would have inconsistent state on a custom elemet that is failed to
   1425    // upgrade, see https://github.com/whatwg/html/issues/6929, and
   1426    // https://github.com/web-platform-tests/wpt/pull/29911 for the test.
   1427    data->mState = CustomElementData::State::eFailed;
   1428    aElement->SetCustomElementDefinition(nullptr);
   1429    // Empty element's custom element reaction queue.
   1430    data->mReactionQueue.Clear();
   1431    return;
   1432  }
   1433 
   1434  // Step 9.
   1435  if (data->IsFormAssociated()) {
   1436    ElementInternals* internals = data->GetElementInternals();
   1437    MOZ_ASSERT(internals);
   1438    MOZ_ASSERT(aElement->IsHTMLElement());
   1439    MOZ_ASSERT(!aDefinition->IsCustomBuiltIn());
   1440 
   1441    internals->UpdateFormOwner();
   1442  }
   1443 
   1444  // Step 10.
   1445  data->mState = CustomElementData::State::eCustom;
   1446  aElement->SetDefined(true);
   1447 }
   1448 
   1449 already_AddRefed<nsISupports> CustomElementRegistry::CallGetCustomInterface(
   1450    Element* aElement, const nsIID& aIID) {
   1451  MOZ_ASSERT(aElement);
   1452 
   1453  if (!nsContentUtils::IsChromeDoc(aElement->OwnerDoc())) {
   1454    return nullptr;
   1455  }
   1456 
   1457  // Try to get our GetCustomInterfaceCallback callback.
   1458  CustomElementDefinition* definition = aElement->GetCustomElementDefinition();
   1459  if (!definition || !definition->mCallbacks ||
   1460      !definition->mCallbacks->mGetCustomInterfaceCallback.WasPassed() ||
   1461      (definition->mLocalName != aElement->NodeInfo()->NameAtom())) {
   1462    return nullptr;
   1463  }
   1464  LifecycleGetCustomInterfaceCallback* func =
   1465      definition->mCallbacks->mGetCustomInterfaceCallback.Value();
   1466 
   1467  // Initialize a AutoJSAPI to enter the compartment of the callback.
   1468  AutoJSAPI jsapi;
   1469  JS::Rooted<JSObject*> funcGlobal(RootingCx(), func->CallbackGlobalOrNull());
   1470  if (!funcGlobal || !jsapi.Init(funcGlobal)) {
   1471    return nullptr;
   1472  }
   1473 
   1474  // Grab our JSContext.
   1475  JSContext* cx = jsapi.cx();
   1476 
   1477  // Convert our IID to a JSValue to call our callback.
   1478  JS::Rooted<JS::Value> jsiid(cx);
   1479  if (!xpc::ID2JSValue(cx, aIID, &jsiid)) {
   1480    return nullptr;
   1481  }
   1482 
   1483  JS::Rooted<JSObject*> customInterface(cx);
   1484  func->Call(aElement, jsiid, &customInterface);
   1485  if (!customInterface) {
   1486    return nullptr;
   1487  }
   1488 
   1489  // Wrap our JSObject into a nsISupports through XPConnect
   1490  nsCOMPtr<nsISupports> wrapper;
   1491  nsresult rv = nsContentUtils::XPConnect()->WrapJSAggregatedToNative(
   1492      aElement, cx, customInterface, aIID, getter_AddRefs(wrapper));
   1493  if (NS_WARN_IF(NS_FAILED(rv))) {
   1494    return nullptr;
   1495  }
   1496 
   1497  return wrapper.forget();
   1498 }
   1499 
   1500 void CustomElementRegistry::TraceDefinitions(JSTracer* aTrc) {
   1501  for (const RefPtr<CustomElementDefinition>& definition :
   1502       mCustomDefinitions.Values()) {
   1503    if (definition && definition->mConstructor) {
   1504      mozilla::TraceScriptHolder(definition->mConstructor, aTrc);
   1505    }
   1506  }
   1507 }
   1508 
   1509 //-----------------------------------------------------
   1510 // CustomElementReactionsStack
   1511 
   1512 void CustomElementReactionsStack::CreateAndPushElementQueue() {
   1513  MOZ_ASSERT(mRecursionDepth);
   1514  MOZ_ASSERT(!mIsElementQueuePushedForCurrentRecursionDepth);
   1515 
   1516  // Push a new element queue onto the custom element reactions stack.
   1517  mReactionsStack.AppendElement(MakeUnique<ElementQueue>());
   1518  mIsElementQueuePushedForCurrentRecursionDepth = true;
   1519 }
   1520 
   1521 void CustomElementReactionsStack::PopAndInvokeElementQueue() {
   1522  MOZ_ASSERT(mRecursionDepth);
   1523  MOZ_ASSERT(mIsElementQueuePushedForCurrentRecursionDepth);
   1524  MOZ_ASSERT(!mReactionsStack.IsEmpty(), "Reaction stack shouldn't be empty");
   1525 
   1526  // Pop the element queue from the custom element reactions stack,
   1527  // and invoke custom element reactions in that queue.
   1528  const uint32_t lastIndex = mReactionsStack.Length() - 1;
   1529  ElementQueue* elementQueue = mReactionsStack.ElementAt(lastIndex).get();
   1530  // Check element queue size in order to reduce function call overhead.
   1531  if (!elementQueue->IsEmpty()) {
   1532    // It is still not clear what error reporting will look like in custom
   1533    // element, see https://github.com/w3c/webcomponents/issues/635.
   1534    // We usually report the error to entry global in gecko, so just follow the
   1535    // same behavior here.
   1536    // This may be null if it's called from parser, see the case of
   1537    // attributeChangedCallback in
   1538    // https://html.spec.whatwg.org/multipage/parsing.html#create-an-element-for-the-token
   1539    // In that case, the exception of callback reactions will be automatically
   1540    // reported in CallSetup.
   1541    nsIGlobalObject* global = GetEntryGlobal();
   1542    InvokeReactions(elementQueue, MOZ_KnownLive(global));
   1543  }
   1544 
   1545  // InvokeReactions() might create other custom element reactions, but those
   1546  // new reactions should be already consumed and removed at this point.
   1547  MOZ_ASSERT(
   1548      lastIndex == mReactionsStack.Length() - 1,
   1549      "reactions created by InvokeReactions() should be consumed and removed");
   1550 
   1551  mReactionsStack.RemoveLastElement();
   1552  mIsElementQueuePushedForCurrentRecursionDepth = false;
   1553 }
   1554 
   1555 void CustomElementReactionsStack::EnqueueUpgradeReaction(
   1556    Element* aElement, CustomElementDefinition* aDefinition) {
   1557  Enqueue(aElement, new CustomElementUpgradeReaction(aDefinition));
   1558 }
   1559 
   1560 void CustomElementReactionsStack::EnqueueCallbackReaction(
   1561    Element* aElement,
   1562    UniquePtr<CustomElementCallback> aCustomElementCallback) {
   1563  Enqueue(aElement,
   1564          new CustomElementCallbackReaction(std::move(aCustomElementCallback)));
   1565 }
   1566 
   1567 void CustomElementReactionsStack::Enqueue(Element* aElement,
   1568                                          CustomElementReaction* aReaction) {
   1569  CustomElementData* elementData = aElement->GetCustomElementData();
   1570  MOZ_ASSERT(elementData, "CustomElementData should exist");
   1571 
   1572  if (mRecursionDepth) {
   1573    // If the element queue is not created for current recursion depth, create
   1574    // and push an element queue to reactions stack first.
   1575    if (!mIsElementQueuePushedForCurrentRecursionDepth) {
   1576      CreateAndPushElementQueue();
   1577    }
   1578 
   1579    MOZ_ASSERT(!mReactionsStack.IsEmpty());
   1580    // Add element to the current element queue.
   1581    mReactionsStack.LastElement()->AppendElement(aElement);
   1582    elementData->mReactionQueue.AppendElement(aReaction);
   1583    return;
   1584  }
   1585 
   1586  // If the custom element reactions stack is empty, then:
   1587  // Add element to the backup element queue.
   1588  MOZ_ASSERT(mReactionsStack.IsEmpty(),
   1589             "custom element reactions stack should be empty");
   1590  mBackupQueue.AppendElement(aElement);
   1591  elementData->mReactionQueue.AppendElement(aReaction);
   1592 
   1593  if (mIsBackupQueueProcessing) {
   1594    return;
   1595  }
   1596 
   1597  CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
   1598  RefPtr<BackupQueueMicroTask> bqmt = new BackupQueueMicroTask(this);
   1599  context->DispatchToMicroTask(bqmt.forget());
   1600 }
   1601 
   1602 void CustomElementReactionsStack::InvokeBackupQueue() {
   1603  // Check backup queue size in order to reduce function call overhead.
   1604  if (!mBackupQueue.IsEmpty()) {
   1605    // Upgrade reactions won't be scheduled in backup queue and the exception of
   1606    // callback reactions will be automatically reported in CallSetup.
   1607    // If the reactions are invoked from backup queue (in microtask check
   1608    // point), we don't need to pass global object for error reporting.
   1609    InvokeReactions(&mBackupQueue, nullptr);
   1610  }
   1611  MOZ_ASSERT(
   1612      mBackupQueue.IsEmpty(),
   1613      "There are still some reactions in BackupQueue not being consumed!?!");
   1614 }
   1615 
   1616 void CustomElementReactionsStack::InvokeReactions(ElementQueue* aElementQueue,
   1617                                                  nsIGlobalObject* aGlobal) {
   1618  // This is used for error reporting.
   1619  Maybe<AutoEntryScript> aes;
   1620  if (aGlobal) {
   1621    aes.emplace(aGlobal, "custom elements reaction invocation");
   1622  }
   1623 
   1624  // Note: It's possible to re-enter this method.
   1625  for (uint32_t i = 0; i < aElementQueue->Length(); ++i) {
   1626    Element* element = aElementQueue->ElementAt(i);
   1627    // ElementQueue hold a element's strong reference, it should not be a
   1628    // nullptr.
   1629    MOZ_ASSERT(element);
   1630 
   1631    CustomElementData* elementData = element->GetCustomElementData();
   1632    if (!elementData || !element->GetOwnerGlobal()) {
   1633      // This happens when the document is destroyed and the element is already
   1634      // unlinked, no need to fire the callbacks in this case.
   1635      continue;
   1636    }
   1637 
   1638    auto& reactions = elementData->mReactionQueue;
   1639    for (uint32_t j = 0; j < reactions.Length(); ++j) {
   1640      // Transfer the ownership of the entry due to reentrant invocation of
   1641      // this function.
   1642      auto reaction(std::move(reactions.ElementAt(j)));
   1643      if (reaction) {
   1644        if (!aGlobal && reaction->IsUpgradeReaction()) {
   1645          nsIGlobalObject* global = element->GetOwnerGlobal();
   1646          MOZ_ASSERT(!aes);
   1647          aes.emplace(global, "custom elements reaction invocation");
   1648        }
   1649        ErrorResult rv;
   1650        reaction->Invoke(MOZ_KnownLive(element), rv);
   1651        if (aes) {
   1652          JSContext* cx = aes->cx();
   1653          if (rv.MaybeSetPendingException(cx)) {
   1654            aes->ReportException();
   1655          }
   1656          MOZ_ASSERT(!JS_IsExceptionPending(cx));
   1657          if (!aGlobal && reaction->IsUpgradeReaction()) {
   1658            aes.reset();
   1659          }
   1660        }
   1661        MOZ_ASSERT(!rv.Failed());
   1662      }
   1663    }
   1664    reactions.Clear();
   1665  }
   1666  aElementQueue->Clear();
   1667 }
   1668 
   1669 //-----------------------------------------------------
   1670 // CustomElementDefinition
   1671 
   1672 NS_IMPL_CYCLE_COLLECTION(CustomElementDefinition, mConstructor, mCallbacks,
   1673                         mFormAssociatedCallbacks, mConstructionStack)
   1674 
   1675 CustomElementDefinition::CustomElementDefinition(
   1676    nsAtom* aType, nsAtom* aLocalName, int32_t aNamespaceID,
   1677    CustomElementConstructor* aConstructor,
   1678    nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
   1679    UniquePtr<LifecycleCallbacks>&& aCallbacks,
   1680    UniquePtr<FormAssociatedLifecycleCallbacks>&& aFormAssociatedCallbacks,
   1681    bool aFormAssociated, bool aDisableInternals, bool aDisableShadow)
   1682    : mType(aType),
   1683      mLocalName(aLocalName),
   1684      mNamespaceID(aNamespaceID),
   1685      mConstructor(aConstructor),
   1686      mObservedAttributes(std::move(aObservedAttributes)),
   1687      mCallbacks(std::move(aCallbacks)),
   1688      mFormAssociatedCallbacks(std::move(aFormAssociatedCallbacks)),
   1689      mFormAssociated(aFormAssociated),
   1690      mDisableInternals(aDisableInternals),
   1691      mDisableShadow(aDisableShadow) {}
   1692 
   1693 }  // namespace mozilla::dom