Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/dom/base/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 188 kB image not shown  

Quelle  Element.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


/*
 * Base class for all element classes; this provides an implementation
 * of DOM Core's Element, implements nsIContent, provides
 * utility methods for subclasses, and so forth.
 */


#include "mozilla/dom/Element.h"
#include "mozilla/dom/ElementInlines.h"

#include <cstddef>
#include <inttypes.h>
#include <initializer_list>
#include <utility>
#include "DOMMatrix.h"
#include "ExpandedPrincipal.h"
#include "PresShellInlines.h"
#include "jsapi.h"
#include "mozAutoDocUpdate.h"
#include "mozilla/AnimationComparator.h"
#include "mozilla/AnimationTarget.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/CORSMode.h"
#include "mozilla/Components.h"
#include "mozilla/ComputedStyle.h"
#include "mozilla/ContentEvents.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/DeclarationBlock.h"
#include "mozilla/EditorBase.h"
#include "mozilla/EffectCompositor.h"
#include "mozilla/EffectSet.h"
#include "mozilla/ElementAnimationData.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/FullscreenChange.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/InternalMutationEvent.h"
#include "mozilla/Likely.h"
#include "mozilla/LinkedList.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/MappedDeclarationsBuilder.h"
#include "mozilla/Maybe.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/NotNull.h"
#include "mozilla/PointerLockManager.h"
#include "mozilla/PresShell.h"
#include "mozilla/PresShellForwards.h"
#include "mozilla/ReflowOutput.h"
#include "mozilla/RefPtr.h"
#include "mozilla/RelativeTo.h"
#include "mozilla/ScrollContainerFrame.h"
#include "mozilla/ScrollTypes.h"
#include "mozilla/ServoStyleConsts.h"
#include "mozilla/ServoStyleConstsInlines.h"
#include "mozilla/SizeOfState.h"
#include "mozilla/SourceLocation.h"
#include "mozilla/StaticAnalysisFunctions.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_full_screen_api.h"
#include "mozilla/StaticString.h"
#include "mozilla/TextControlElement.h"
#include "mozilla/TextEditor.h"
#include "mozilla/TextEvents.h"
#include "mozilla/Try.h"
#include "mozilla/TypedEnumBits.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/AnimatableBinding.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/Attr.h"
#include "mozilla/dom/BindContext.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/CloseWatcher.h"
#include "mozilla/dom/CustomElementRegistry.h"
#include "mozilla/dom/CSPViolationData.h"
#include "mozilla/dom/DOMRect.h"
#include "mozilla/dom/DirectionalityUtils.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentFragment.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/DocumentTimeline.h"
#include "mozilla/dom/ElementBinding.h"
#include "mozilla/dom/Flex.h"
#include "mozilla/dom/FragmentOrElement.h"
#include "mozilla/dom/FromParser.h"
#include "mozilla/dom/Grid.h"
#include "mozilla/dom/HTMLDivElement.h"
#include "mozilla/dom/HTMLElement.h"
#include "mozilla/dom/HTMLParagraphElement.h"
#include "mozilla/dom/HTMLPreElement.h"
#include "mozilla/dom/HTMLSpanElement.h"
#include "mozilla/dom/HTMLTableCellElement.h"
#include "mozilla/dom/HTMLTemplateElement.h"
#include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
#include "mozilla/dom/KeyframeEffect.h"
#include "mozilla/dom/MouseEvent.h"
#include "mozilla/dom/MouseEventBinding.h"
#include "mozilla/dom/MutationEventBinding.h"
#include "mozilla/dom/MutationObservers.h"
#include "mozilla/dom/NodeInfo.h"
#include "mozilla/dom/nsCSPUtils.h"
#include "mozilla/dom/PointerEventHandler.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/Sanitizer.h"
#include "mozilla/dom/SVGElement.h"
#include "mozilla/dom/ScriptLoader.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/Text.h"
#include "mozilla/dom/TrustedHTML.h"
#include "mozilla/dom/TrustedTypesConstants.h"
#include "mozilla/dom/TrustedTypeUtils.h"
#include "mozilla/dom/UnbindContext.h"
#include "mozilla/dom/ViewTransition.h"
#include "mozilla/dom/WindowBinding.h"
#include "mozilla/dom/XULCommandEvent.h"
#include "mozilla/dom/nsCSPContext.h"
#include "mozilla/gfx/BasePoint.h"
#include "mozilla/gfx/BaseRect.h"
#include "mozilla/gfx/BaseSize.h"
#include "mozilla/gfx/Matrix.h"
#include "mozilla/widget/Screen.h"
#include "nsAtom.h"
#include "nsAttrName.h"
#include "nsAttrValueInlines.h"
#include "nsAttrValueOrString.h"
#include "nsBaseHashtable.h"
#include "nsBlockFrame.h"
#include "nsCOMPtr.h"
#include "nsContentUtils.h"
#include "nsCSSPseudoElements.h"
#include "nsCompatibility.h"
#include "nsContainerFrame.h"
#include "nsContentList.h"
#include "nsContentListDeclarations.h"
#include "nsCoord.h"
#include "nsDOMAttributeMap.h"
#include "nsDOMCSSAttrDeclaration.h"
#include "nsDOMMutationObserver.h"
#include "nsDOMString.h"
#include "nsDOMStringMap.h"
#include "nsDOMTokenList.h"
#include "nsDocShell.h"
#include "nsError.h"
#include "nsFlexContainerFrame.h"
#include "nsFocusManager.h"
#include "nsFrameState.h"
#include "nsGenericHTMLElement.h"
#include "nsGkAtoms.h"
#include "nsGridContainerFrame.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIAutoCompletePopup.h"
#include "nsIBrowser.h"
#include "nsIContentInlines.h"
#include "nsIDOMXULButtonElement.h"
#include "nsIDOMXULContainerElement.h"
#include "nsIDOMXULControlElement.h"
#include "nsIDOMXULMenuListElement.h"
#include "nsIDOMXULMultSelectCntrlEl.h"
#include "nsIDOMXULRadioGroupElement.h"
#include "nsIDOMXULRelatedElement.h"
#include "nsIDOMXULSelectCntrlEl.h"
#include "nsIDOMXULSelectCntrlItemEl.h"
#include "nsIDocShell.h"
#include "nsIFocusManager.h"
#include "nsIFrame.h"
#include "nsIGlobalObject.h"
#include "nsIIOService.h"
#include "nsIInterfaceRequestor.h"
#include "nsIMemoryReporter.h"
#include "nsIPrincipal.h"
#include "nsIScriptError.h"
#include "nsISpeculativeConnect.h"
#include "nsISupports.h"
#include "nsISupportsUtils.h"
#include "nsIURI.h"
#include "nsLayoutUtils.h"
#include "nsLineBox.h"
#include "nsLiteralString.h"
#include "nsNameSpaceManager.h"
#include "nsNodeInfoManager.h"
#include "nsPIDOMWindow.h"
#include "nsPoint.h"
#include "nsPresContext.h"
#include "nsQueryFrame.h"
#include "nsRefPtrHashtable.h"
#include "nsSize.h"
#include "nsString.h"
#include "nsStyleConsts.h"
#include "nsStyleStruct.h"
#include "nsStyledElement.h"
#include "nsTArray.h"
#include "nsTextNode.h"
#include "nsThreadUtils.h"
#include "nsViewManager.h"
#include "nsWindowSizes.h"

#include "nsXULElement.h"

#ifdef DEBUG
#  include "nsRange.h"
#endif

#ifdef ACCESSIBILITY
#  include "nsAccessibilityService.h"
#endif

using mozilla::gfx::Matrix4x4;

namespace mozilla::dom {

// Verify sizes of nodes. We use a template rather than a direct static
// assert so that the error message actually displays the sizes.
// On 32 bit systems the actual allocated size varies a bit between
// OSes/compilers.
//
// We need different numbers on certain build types to deal with the owning
// thread pointer that comes with the non-threadsafe refcount on
// nsIContent.
#ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
#  define EXTRA_DOM_NODE_BYTES 8
#else
#  define EXTRA_DOM_NODE_BYTES 0
#endif

#define ASSERT_NODE_SIZE(type, opt_size_64, opt_size_32)              \
  template <int a, int sizeOn64, int sizeOn32>                        \
  struct Check##type##Size {                                          \
    static_assert((sizeof(void*) == 8 && a == sizeOn64) ||            \
                      (sizeof(void*) == 4 && a <= sizeOn32),          \
                  "DOM size changed");                                \
  };                                                                  \
  Check##type##Size<sizeof(type), opt_size_64 + EXTRA_DOM_NODE_BYTES, \
                    opt_size_32 + EXTRA_DOM_NODE_BYTES>               \
      g##type##CES;

// Note that mozjemalloc uses a 16 byte quantum, so 64, 80 and 128 are
// bucket sizes.
ASSERT_NODE_SIZE(Element, 128, 80);
ASSERT_NODE_SIZE(HTMLDivElement, 128, 80);
ASSERT_NODE_SIZE(HTMLElement, 128, 80);
ASSERT_NODE_SIZE(HTMLParagraphElement, 128, 80);
ASSERT_NODE_SIZE(HTMLPreElement, 128, 80);
ASSERT_NODE_SIZE(HTMLSpanElement, 128, 80);
ASSERT_NODE_SIZE(HTMLTableCellElement, 128, 80);
ASSERT_NODE_SIZE(Text, 120, 80);

#undef ASSERT_NODE_SIZE
#undef EXTRA_DOM_NODE_BYTES

}  // namespace mozilla::dom

nsAtom* nsIContent::DoGetID() const {
  MOZ_ASSERT(HasID(), "Unexpected call");
  MOZ_ASSERT(IsElement(), "Only elements can have IDs");

  return AsElement()->GetParsedAttr(nsGkAtoms::id)->GetAtomValue();
}

nsIFrame* nsIContent::GetPrimaryFrame(mozilla::FlushType aType) {
  Document* doc = GetComposedDoc();
  if (!doc) {
    return nullptr;
  }

  // Cause a flush, so we get up-to-date frame information.
  if (aType != mozilla::FlushType::None) {
    doc->FlushPendingNotifications(aType);
  }

  auto* frame = GetPrimaryFrame();
  if (!frame) {
    return nullptr;
  }

  if (aType == mozilla::FlushType::Layout) {
    frame->PresShell()->EnsureReflowIfFrameHasHiddenContent(frame);
    frame = GetPrimaryFrame();
  }

  return frame;
}

namespace mozilla::dom {

const DOMTokenListSupportedToken Element::sSupportedBlockingValues[] = {
    "render", nullptr};

nsDOMAttributeMap* Element::Attributes() {
  nsDOMSlots* slots = DOMSlots();
  if (!slots->mAttributeMap) {
    slots->mAttributeMap = new nsDOMAttributeMap(this);
  }

  return slots->mAttributeMap;
}

void Element::SetPointerCapture(int32_t aPointerId, ErrorResult& aError) {
  if (OwnerDoc()->ShouldResistFingerprinting(RFPTarget::PointerId) &&
      aPointerId != PointerEventHandler::GetSpoofedPointerIdForRFP()) {
    aError.ThrowNotFoundError("Invalid pointer id");
    return;
  }
  const PointerInfo* pointerInfo =
      PointerEventHandler::GetPointerInfo(aPointerId);
  if (!pointerInfo) {
    aError.ThrowNotFoundError("Invalid pointer id");
    return;
  }
  if (!IsInComposedDoc()) {
    aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    return;
  }
  if (OwnerDoc()->GetPointerLockElement()) {
    // Throw an exception 'InvalidStateError' while the page has a locked
    // element.
    aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    return;
  }
  if (!pointerInfo->mActiveState ||
      pointerInfo->mActiveDocument != OwnerDoc()) {
    return;
  }
  PointerEventHandler::RequestPointerCaptureById(aPointerId, this);
}

void Element::ReleasePointerCapture(int32_t aPointerId, ErrorResult& aError) {
  if (OwnerDoc()->ShouldResistFingerprinting(RFPTarget::PointerId) &&
      aPointerId != PointerEventHandler::GetSpoofedPointerIdForRFP()) {
    aError.ThrowNotFoundError("Invalid pointer id");
    return;
  }
  if (!PointerEventHandler::GetPointerInfo(aPointerId)) {
    aError.ThrowNotFoundError("Invalid pointer id");
    return;
  }
  if (HasPointerCapture(aPointerId)) {
    PointerEventHandler::ReleasePointerCaptureById(aPointerId);
  }
}

bool Element::HasPointerCapture(long aPointerId) {
  PointerCaptureInfo* pointerCaptureInfo =
      PointerEventHandler::GetPointerCaptureInfo(aPointerId);
  if (pointerCaptureInfo && pointerCaptureInfo->mPendingElement == this) {
    return true;
  }
  return false;
}

const nsAttrValue* Element::GetSVGAnimatedClass() const {
  MOZ_ASSERT(MayHaveClass() && IsSVGElement(), "Unexpected call");
  return static_cast<const SVGElement*>(this)->GetAnimatedClassName();
}

NS_IMETHODIMP
Element::QueryInterface(REFNSIID aIID, void** aInstancePtr) {
  if (aIID.Equals(NS_GET_IID(Element))) {
    NS_ADDREF_THIS();
    *aInstancePtr = this;
    return NS_OK;
  }

  NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!");
  nsresult rv = FragmentOrElement::QueryInterface(aIID, aInstancePtr);
  if (NS_SUCCEEDED(rv)) {
    return NS_OK;
  }

  return NS_NOINTERFACE;
}

void Element::NotifyStateChange(ElementState aStates) {
  MOZ_ASSERT(!aStates.IsEmpty());
  if (Document* doc = GetComposedDoc()) {
    nsAutoScriptBlocker scriptBlocker;
    doc->ElementStateChanged(this, aStates);
  }
}

}  // namespace mozilla::dom

void nsIContent::UpdateEditableState(bool aNotify) {
  if (IsInNativeAnonymousSubtree()) {
    // Don't propagate the editable flag into native anonymous subtrees.
    if (IsRootOfNativeAnonymousSubtree()) {
      return;
    }

    // We allow setting the flag on NAC (explicitly, see
    // nsTextControlFrame::CreateAnonymousContent for example), but not
    // unsetting it.
    //
    // Otherwise, just the act of binding the NAC subtree into our non-anonymous
    // parent would clear the flag, which is not good. As we shouldn't move NAC
    // around, this is fine.
    if (HasFlag(NODE_IS_EDITABLE)) {
      return;
    }
  }

  nsIContent* parent = GetParent();
  SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
}

namespace mozilla::dom {

void Element::UpdateEditableState(bool aNotify) {
  nsIContent::UpdateEditableState(aNotify);
  UpdateReadOnlyState(aNotify);
}

bool Element::IsReadOnlyInternal() const { return !IsEditable(); }

void Element::UpdateReadOnlyState(bool aNotify) {
  auto oldState = State();
  if (IsReadOnlyInternal()) {
    RemoveStatesSilently(ElementState::READWRITE);
    AddStatesSilently(ElementState::READONLY);
  } else {
    RemoveStatesSilently(ElementState::READONLY);
    AddStatesSilently(ElementState::READWRITE);
  }
  if (!aNotify) {
    return;
  }
  const auto newState = State();
  if (newState != oldState) {
    NotifyStateChange(newState ^ oldState);
  }
}

Maybe<int32_t> Element::GetTabIndexAttrValue() {
  const nsAttrValue* attrVal = GetParsedAttr(nsGkAtoms::tabindex);
  if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
    return Some(attrVal->GetIntegerValue());
  }

  return Nothing();
}

int32_t Element::TabIndex() {
  Maybe<int32_t> attrVal = GetTabIndexAttrValue();
  if (attrVal.isSome()) {
    return attrVal.value();
  }

  return TabIndexDefault();
}

void Element::Focus(const FocusOptions& aOptions, CallerType aCallerType,
                    ErrorResult& aError) {
  const RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager();
  if (MOZ_UNLIKELY(!fm)) {
    return;
  }
  const OwningNonNull<Element> kungFuDeathGrip(*this);
  // Also other browsers seem to have the hack to not re-focus (and flush) when
  // the element is already focused.
  // Until https://github.com/whatwg/html/issues/4512 is clarified, we'll
  // maintain interoperatibility by not re-focusing, independent of aOptions.
  // I.e., `focus({ preventScroll: true})` followed by `focus( { preventScroll:
  // false })` won't re-focus.
  if (fm->CanSkipFocus(this)) {
    fm->NotifyOfReFocus(kungFuDeathGrip);
    fm->NeedsFlushBeforeEventHandling(this);
    return;
  }
  uint32_t fmFlags = nsFocusManager::ProgrammaticFocusFlags(aOptions);
  if (aCallerType == CallerType::NonSystem) {
    fmFlags |= nsIFocusManager::FLAG_NONSYSTEMCALLER;
  }
  aError = fm->SetFocus(kungFuDeathGrip, fmFlags);
}

void Element::SetTabIndex(int32_t aTabIndex, mozilla::ErrorResult& aError) {
  nsAutoString value;
  value.AppendInt(aTabIndex);

  SetAttr(nsGkAtoms::tabindex, value, aError);
}

void Element::SetShadowRoot(ShadowRoot* aShadowRoot) {
  nsExtendedDOMSlots* slots = ExtendedDOMSlots();
  MOZ_ASSERT(!aShadowRoot || !slots->mShadowRoot,
             "We shouldn't clear the shadow root without unbind first");
  slots->mShadowRoot = aShadowRoot;
}

void Element::SetLastRememberedBSize(float aBSize) {
  ExtendedDOMSlots()->mLastRememberedBSize = Some(aBSize);
}

void Element::SetLastRememberedISize(float aISize) {
  ExtendedDOMSlots()->mLastRememberedISize = Some(aISize);
}

void Element::RemoveLastRememberedBSize() {
  if (nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) {
    slots->mLastRememberedBSize.reset();
  }
}

void Element::RemoveLastRememberedISize() {
  if (nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) {
    slots->mLastRememberedISize.reset();
  }
}

void Element::Blur(mozilla::ErrorResult& aError) {
  if (!ShouldBlur(this)) {
    return;
  }

  Document* doc = GetComposedDoc();
  if (!doc) {
    return;
  }

  if (nsCOMPtr<nsPIDOMWindowOuter> win = doc->GetWindow()) {
    if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
      aError = fm->ClearFocus(win);
    }
  }
}

ElementState Element::StyleStateFromLocks() const {
  StyleStateLocks locksAndValues = LockedStyleStates();
  ElementState locks = locksAndValues.mLocks;
  ElementState values = locksAndValues.mValues;
  ElementState state = (mState & ~locks) | (locks & values);

  if (state.HasState(ElementState::VISITED)) {
    return state & ~ElementState::UNVISITED;
  }
  if (state.HasState(ElementState::UNVISITED)) {
    return state & ~ElementState::VISITED;
  }

  return state;
}

Element::StyleStateLocks Element::LockedStyleStates() const {
  StyleStateLocks* locks =
      static_cast<StyleStateLocks*>(GetProperty(nsGkAtoms::lockedStyleStates));
  if (locks) {
    return *locks;
  }
  return StyleStateLocks();
}

void Element::NotifyStyleStateChange(ElementState aStates) {
  if (RefPtr<Document> doc = GetComposedDoc()) {
    if (RefPtr<PresShell> presShell = doc->GetPresShell()) {
      nsAutoScriptBlocker scriptBlocker;
      presShell->ElementStateChanged(doc, this, aStates);
    }
  }
}

void Element::LockStyleStates(ElementState aStates, bool aEnabled) {
  StyleStateLocks* locks = new StyleStateLocks(LockedStyleStates());

  locks->mLocks |= aStates;
  if (aEnabled) {
    locks->mValues |= aStates;
  } else {
    locks->mValues &= ~aStates;
  }

  if (aStates.HasState(ElementState::VISITED)) {
    locks->mLocks &= ~ElementState::UNVISITED;
  }
  if (aStates.HasState(ElementState::UNVISITED)) {
    locks->mLocks &= ~ElementState::VISITED;
  }

  SetProperty(nsGkAtoms::lockedStyleStates, locks,
              nsINode::DeleteProperty<StyleStateLocks>);
  SetHasLockedStyleStates();

  NotifyStyleStateChange(aStates);
}

void Element::UnlockStyleStates(ElementState aStates) {
  StyleStateLocks* locks = new StyleStateLocks(LockedStyleStates());

  locks->mLocks &= ~aStates;

  if (locks->mLocks.IsEmpty()) {
    RemoveProperty(nsGkAtoms::lockedStyleStates);
    ClearHasLockedStyleStates();
    delete locks;
  } else {
    SetProperty(nsGkAtoms::lockedStyleStates, locks,
                nsINode::DeleteProperty<StyleStateLocks>);
  }

  NotifyStyleStateChange(aStates);
}

void Element::ClearStyleStateLocks() {
  StyleStateLocks locks = LockedStyleStates();

  RemoveProperty(nsGkAtoms::lockedStyleStates);
  ClearHasLockedStyleStates();

  NotifyStyleStateChange(locks.mLocks);
}

/* virtual */
nsINode* Element::GetScopeChainParent() const { return OwnerDoc(); }

JSObject* Element::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
  return Element_Binding::Wrap(aCx, this, aGivenProto);
}

nsDOMTokenList* Element::ClassList() {
  nsDOMSlots* slots = DOMSlots();
  if (!slots->mClassList) {
    slots->mClassList = new nsDOMTokenList(this, nsGkAtoms::_class);
  }
  return slots->mClassList;
}

nsDOMTokenList* Element::Part() {
  nsExtendedDOMSlots* slots = ExtendedDOMSlots();
  if (!slots->mPart) {
    slots->mPart = new nsDOMTokenList(this, nsGkAtoms::part);
  }
  return slots->mPart;
}

void Element::RecompileScriptEventListeners() {
  for (uint32_t i = 0, count = mAttrs.AttrCount(); i < count; ++i) {
    BorrowedAttrInfo attrInfo = mAttrs.AttrInfoAt(i);

    // Eventlistenener-attributes are always in the null namespace
    if (!attrInfo.mName->IsAtom()) {
      continue;
    }

    nsAtom* attr = attrInfo.mName->Atom();
    if (!IsEventAttributeName(attr)) {
      continue;
    }

    nsAutoString value;
    attrInfo.mValue->ToString(value);
    SetEventHandler(GetEventNameForAttr(attr), value, true);
  }
}

void Element::GetAttributeNames(nsTArray<nsString>& aResult) {
  uint32_t count = mAttrs.AttrCount();
  for (uint32_t i = 0; i < count; ++i) {
    const nsAttrName* name = mAttrs.AttrNameAt(i);
    name->GetQualifiedName(*aResult.AppendElement());
  }
}

already_AddRefed<nsIHTMLCollection> Element::GetElementsByTagName(
    const nsAString& aLocalName) {
  return NS_GetContentList(this, kNameSpaceID_Unknown, aLocalName);
}

ScrollContainerFrame* Element::GetScrollContainerFrame(nsIFrame** aFrame,
                                                       FlushType aFlushType) {
  nsIFrame* frame = GetPrimaryFrame(aFlushType);
  if (aFrame) {
    *aFrame = frame;
  }
  if (frame) {
    if (frame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT)) {
      // It's unclear what to return for SVG frames, so just return null.
      return nullptr;
    }

    if (ScrollContainerFrame* scrollContainerFrame =
            frame->GetScrollTargetFrame()) {
      MOZ_ASSERT(!OwnerDoc()->IsScrollingElement(this),
                 "How can we have a scroll container frame if we're the "
                 "scrollingElement for our document?");
      return scrollContainerFrame;
    }
  }

  Document* doc = OwnerDoc();
  // Note: This IsScrollingElement() call can flush frames, if we're the body of
  // a quirks mode document.
  const bool isScrollingElement = doc->IsScrollingElement(this);
  if (isScrollingElement) {
    // Our scroll info should map to the root scroll container frame if there is
    // one.
    if (PresShell* presShell = doc->GetPresShell()) {
      if (ScrollContainerFrame* rootScrollContainerFrame =
              presShell->GetRootScrollContainerFrame()) {
        if (aFrame) {
          *aFrame = rootScrollContainerFrame;
        }
        return rootScrollContainerFrame;
      }
    }
  }
  if (aFrame) {
    // Re-get *aFrame if the caller asked for it, because that frame flush can
    // kill it.
    *aFrame = GetPrimaryFrame(FlushType::None);
  }
  return nullptr;
}

bool Element::CheckVisibility(const CheckVisibilityOptions& aOptions) {
  nsIFrame* f =
      GetPrimaryFrame(aOptions.mFlush ? FlushType::Frames : FlushType::None);
  if (!f) {
    // 1. If this does not have an associated box, return false.
    return false;
  }

  EnumSet includeContentVisibility = {
      nsIFrame::IncludeContentVisibility::Hidden};
  if (aOptions.mContentVisibilityAuto) {
    includeContentVisibility += nsIFrame::IncludeContentVisibility::Auto;
  }
  // Steps 2 and 5
  if (f->IsHiddenByContentVisibilityOnAnyAncestor(includeContentVisibility)) {
    // 2. If a shadow-including ancestor of this has content-visibility: hidden,
    // return false.
    // 5. If a shadow-including ancestor of this skips its content due to
    // has content-visibility: auto, return false.
    return false;
  }

  if ((aOptions.mOpacityProperty || aOptions.mCheckOpacity) &&
      f->Style()->IsInOpacityZeroSubtree()) {
    // 3. If the checkOpacity dictionary member of options is true, and this, or
    // a shadow-including ancestor of this, has a computed opacity value of 0,
    // return false.
    return false;
  }

  if ((aOptions.mVisibilityProperty || aOptions.mCheckVisibilityCSS) &&
      !f->StyleVisibility()->IsVisible()) {
    // 4. If the checkVisibilityCSS dictionary member of options is true, and
    // this is invisible, return false.
    return false;
  }

  // 6. Return true
  return true;
}

void Element::ScrollIntoView(const BooleanOrScrollIntoViewOptions& aObject) {
  if (aObject.IsScrollIntoViewOptions()) {
    return ScrollIntoView(aObject.GetAsScrollIntoViewOptions());
  }

  MOZ_DIAGNOSTIC_ASSERT(aObject.IsBoolean());

  ScrollIntoViewOptions options;
  if (aObject.GetAsBoolean()) {
    options.mBlock = ScrollLogicalPosition::Start;
    options.mInline = ScrollLogicalPosition::Nearest;
  } else {
    options.mBlock = ScrollLogicalPosition::End;
    options.mInline = ScrollLogicalPosition::Nearest;
  }
  return ScrollIntoView(options);
}

void Element::ScrollIntoView(const ScrollIntoViewOptions& aOptions) {
  Document* document = GetComposedDoc();
  if (!document) {
    return;
  }

  // Get the presentation shell
  RefPtr<PresShell> presShell = document->GetPresShell();
  if (!presShell) {
    return;
  }

  const auto ToWhereToScroll =
      [](ScrollLogicalPosition aPosition) -> WhereToScroll {
    switch (aPosition) {
      case ScrollLogicalPosition::Start:
        return WhereToScroll::Start;
      case ScrollLogicalPosition::Center:
        return WhereToScroll::Center;
      case ScrollLogicalPosition::End:
        return WhereToScroll::End;
      case ScrollLogicalPosition::Nearest:
        break;
    }
    return WhereToScroll::Nearest;
  };

  const auto block = ToWhereToScroll(aOptions.mBlock);
  const auto inline_ = ToWhereToScroll(aOptions.mInline);

  ScrollFlags scrollFlags =
      ScrollFlags::ScrollOverflowHidden | ScrollFlags::TriggeredByScript;
  if (aOptions.mBehavior == ScrollBehavior::Smooth) {
    scrollFlags |= ScrollFlags::ScrollSmooth;
  } else if (aOptions.mBehavior == ScrollBehavior::Auto) {
    scrollFlags |= ScrollFlags::ScrollSmoothAuto;
  }

  // TODO: Propagate whether the axes are logical or not down (via scrollflags).
  presShell->ScrollContentIntoView(
      this, ScrollAxis(block, WhenToScroll::Always),
      ScrollAxis(inline_, WhenToScroll::Always), scrollFlags);
}

void Element::ScrollTo(double aXScroll, double aYScroll) {
  ScrollToOptions options;
  options.mLeft.Construct(aXScroll);
  options.mTop.Construct(aYScroll);
  ScrollTo(options);
}

void Element::ScrollTo(const ScrollToOptions& aOptions) {
  // When the scroll top is 0, we don't need to flush layout to scroll to that
  // point; we know 0 is always in range.  At least we think so...  But we do
  // need to flush frames so we ensure we find the right scrollable frame if
  // there is one. If it's nonzero, we need to flush layout because we need to
  // figure out what our real scrollTopMax is.
  //
  // If we have a left value, we can't assume things based on it's value,
  // depending on our direction and layout 0 may or may not be in our scroll
  // range.  So we need to flush layout no matter what then.
  const bool needsLayoutFlush =
      aOptions.mLeft.WasPassed() ||
      (aOptions.mTop.WasPassed() && aOptions.mTop.Value() != 0.0);

  nsIFrame* frame;
  ScrollContainerFrame* sf = GetScrollContainerFrame(
      &frame, needsLayoutFlush ? FlushType::Layout : FlushType::Frames);
  if (!sf) {
    return;
  }
  CSSIntPoint scrollPos = sf->GetRoundedScrollPositionCSSPixels();
  if (aOptions.mLeft.WasPassed()) {
    scrollPos.x = int32_t(mozilla::ToZeroIfNonfinite(
        frame->Style()->EffectiveZoom().Zoom(aOptions.mLeft.Value())));
  }
  if (aOptions.mTop.WasPassed()) {
    scrollPos.y = int32_t(mozilla::ToZeroIfNonfinite(
        frame->Style()->EffectiveZoom().Zoom(aOptions.mTop.Value())));
  }
  ScrollMode scrollMode = sf->IsSmoothScroll(aOptions.mBehavior)
                              ? ScrollMode::SmoothMsd
                              : ScrollMode::Instant;
  sf->ScrollToCSSPixels(scrollPos, scrollMode);
}

void Element::ScrollBy(double aXScrollDif, double aYScrollDif) {
  ScrollToOptions options;
  options.mLeft.Construct(aXScrollDif);
  options.mTop.Construct(aYScrollDif);
  ScrollBy(options);
}

void Element::ScrollBy(const ScrollToOptions& aOptions) {
  nsIFrame* frame;
  ScrollContainerFrame* sf = GetScrollContainerFrame(&frame);
  if (!sf) {
    return;
  }

  CSSIntPoint scrollDelta;
  if (aOptions.mLeft.WasPassed()) {
    scrollDelta.x = int32_t(mozilla::ToZeroIfNonfinite(
        frame->Style()->EffectiveZoom().Zoom(aOptions.mLeft.Value())));
  }

  if (aOptions.mTop.WasPassed()) {
    scrollDelta.y = int32_t(mozilla::ToZeroIfNonfinite(
        frame->Style()->EffectiveZoom().Zoom(aOptions.mTop.Value())));
  }

  auto scrollMode = sf->IsSmoothScroll(aOptions.mBehavior)
                        ? ScrollMode::SmoothMsd
                        : ScrollMode::Instant;
  sf->ScrollByCSSPixels(scrollDelta, scrollMode);
}

int32_t Element::ScrollTop() {
  return CSSPixel::FromAppUnitsRounded(GetScrollOrigin().y);
}

void Element::SetScrollTop(int32_t aScrollTop) {
  ScrollToOptions options;
  options.mTop.Construct(aScrollTop);
  ScrollTo(options);
}

int32_t Element::ScrollLeft() {
  return CSSPixel::FromAppUnitsRounded(GetScrollOrigin().x);
}

void Element::SetScrollLeft(int32_t aScrollLeft) {
  ScrollToOptions options;
  options.mLeft.Construct(aScrollLeft);
  ScrollTo(options);
}

void Element::MozScrollSnap() {
  if (ScrollContainerFrame* sf =
          GetScrollContainerFrame(nullptr, FlushType::None)) {
    sf->ScrollSnap();
  }
}

nsRect Element::GetScrollRange() {
  nsIFrame* frame;
  ScrollContainerFrame* sf = GetScrollContainerFrame(&frame);
  if (!sf) {
    return nsRect();
  }
  return frame->Style()->EffectiveZoom().Unzoom(sf->GetScrollRange());
}

int32_t Element::ScrollTopMin() {
  return CSSPixel::FromAppUnitsRounded(GetScrollRange().Y());
}

int32_t Element::ScrollTopMax() {
  return CSSPixel::FromAppUnitsRounded(GetScrollRange().YMost());
}

int32_t Element::ScrollLeftMin() {
  return CSSPixel::FromAppUnitsRounded(GetScrollRange().X());
}

int32_t Element::ScrollLeftMax() {
  return CSSPixel::FromAppUnitsRounded(GetScrollRange().XMost());
}

static nsSize GetScrollRectSizeForOverflowVisibleFrame(nsIFrame* aFrame) {
  if (!aFrame || aFrame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT)) {
    return nsSize();
  }

  // This matches WebKit and Blink, which in turn (apparently, according to
  // their source) matched old IE.
  const nsRect paddingRect = aFrame->GetPaddingRectRelativeToSelf();
  const nsRect overflowRect = [&] {
    OverflowAreas overflowAreas(paddingRect, paddingRect);
    // Add the scrollable overflow areas of children (if any) to the
    // paddingRect, as if aFrame was a scrolled frame. It's important to start
    // with the paddingRect, otherwise if there are no children the overflow
    // rect will be 0,0,0,0 which will force the point 0,0 to be included in the
    // final rect.
    aFrame->UnionChildOverflow(overflowAreas, /* aAsIfScrolled = */ true);
    // Make sure that an empty padding-rect's edges are included, by adding
    // the padding-rect in again with UnionEdges.
    return overflowAreas.ScrollableOverflow().UnionEdges(paddingRect);
  }();

  auto directions =
      ScrollContainerFrame::ComputePerAxisScrollDirections(aFrame);
  const nscoord height = directions.mToBottom
                             ? overflowRect.YMost() - paddingRect.Y()
                             : paddingRect.YMost() - overflowRect.Y();
  const nscoord width = directions.mToRight
                            ? overflowRect.XMost() - paddingRect.X()
                            : paddingRect.XMost() - overflowRect.X();
  return nsSize(width, height);
}

nsSize Element::GetScrollSize() {
  nsIFrame* frame;
  nsSize size;
  if (ScrollContainerFrame* sf = GetScrollContainerFrame(&frame)) {
    size = sf->GetScrollRange().Size() + sf->GetScrollPortRect().Size();
  } else {
    size = GetScrollRectSizeForOverflowVisibleFrame(frame);
  }
  if (!frame) {
    return size;
  }
  return frame->Style()->EffectiveZoom().Unzoom(size);
}

nsPoint Element::GetScrollOrigin() {
  nsIFrame* frame;
  ScrollContainerFrame* sf = GetScrollContainerFrame(&frame);
  if (!sf) {
    return nsPoint();
  }
  return frame->Style()->EffectiveZoom().Unzoom(sf->GetScrollPosition());
}

int32_t Element::ScrollHeight() {
  return nsPresContext::AppUnitsToIntCSSPixels(GetScrollSize().height);
}

int32_t Element::ScrollWidth() {
  return nsPresContext::AppUnitsToIntCSSPixels(GetScrollSize().width);
}

nsRect Element::GetClientAreaRect() {
  Document* doc = OwnerDoc();
  nsPresContext* presContext = doc->GetPresContext();

  // We can avoid a layout flush if this is the scrolling element of the
  // document, we have overlay scrollbars, and we aren't embedded in another
  // document
  if (presContext && presContext->UseOverlayScrollbars() &&
      !doc->StyleOrLayoutObservablyDependsOnParentDocumentLayout() &&
      doc->IsScrollingElement(this)) {
    if (PresShell* presShell = doc->GetPresShell()) {
      // Ensure up to date dimensions, but don't reflow
      if (RefPtr<nsViewManager> viewManager = presShell->GetViewManager()) {
        viewManager->FlushDelayedResize();
      }
      return nsRect(nsPoint(), presContext->GetVisibleArea().Size());
    }
  }

  nsIFrame* frame;
  if (ScrollContainerFrame* sf = GetScrollContainerFrame(&frame)) {
    nsRect scrollPort = sf->GetScrollPortRect();

    if (!sf->IsRootScrollFrameOfDocument()) {
      MOZ_ASSERT(frame);
      // We want the offset to be relative to `frame`, not `sf`... Except for
      // the root scroll frame, which is an ancestor of frame rather than a
      // descendant and thus this wouldn't particularly make sense.
      if (frame != sf) {
        scrollPort.MoveBy(sf->GetOffsetTo(frame));
      }
    }

    // The scroll port value might be expanded to the minimum scale size, we
    // should limit the size to the ICB in such cases.
    scrollPort.SizeTo(sf->GetLayoutSize());
    return frame->Style()->EffectiveZoom().Unzoom(scrollPort);
  }

  if (frame &&
      // The display check is OK even though we're not looking at the style
      // frame, because the style frame only differs from "frame" for tables,
      // and table wrappers have the same display as the table itself.
      (!frame->StyleDisplay()->IsInlineFlow() || frame->IsReplaced())) {
    // Special case code to make client area work even when there isn't
    // a scroll view, see bug 180552, bug 227567.
    return frame->Style()->EffectiveZoom().Unzoom(
        frame->GetPaddingRect() - frame->GetPositionIgnoringScrolling());
  }

  // SVG nodes reach here and just return 0
  return nsRect();
}

int32_t Element::ScreenX() {
  nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
  return frame ? frame->GetScreenRect().x : 0;
}

int32_t Element::ScreenY() {
  nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
  return frame ? frame->GetScreenRect().y : 0;
}

already_AddRefed<nsIScreen> Element::GetScreen() {
  // Flush layout to guarantee that frames are created if needed, and preserve
  // behavior.
  Unused << GetPrimaryFrame(FlushType::Frames);
  if (nsIWidget* widget = nsContentUtils::WidgetForContent(this)) {
    return widget->GetWidgetScreen();
  }
  return nullptr;
}

double Element::CurrentCSSZoom() {
  nsIFrame* f = GetPrimaryFrame(FlushType::Frames);
  if (!f) {
    return 1.0;
  }
  return f->Style()->EffectiveZoom().ToFloat();
}

already_AddRefed<DOMRect> Element::GetBoundingClientRect() {
  RefPtr<DOMRect> rect = new DOMRect(ToSupports(OwnerDoc()));

  nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
  if (!frame) {
    // display:none, perhaps? Return the empty rect
    return rect.forget();
  }

  rect->SetLayoutRect(frame->GetBoundingClientRect());
  return rect.forget();
}

already_AddRefed<DOMRectList> Element::GetClientRects() {
  RefPtr<DOMRectList> rectList = new DOMRectList(this);

  nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
  if (!frame) {
    // display:none, perhaps? Return an empty list
    return rectList.forget();
  }

  nsLayoutUtils::RectListBuilder builder(rectList);
  nsLayoutUtils::GetAllInFlowRects(
      frame, nsLayoutUtils::GetContainingBlockForClientRect(frame), &builder,
      nsLayoutUtils::GetAllInFlowRectsFlag::AccountForTransforms);
  return rectList.forget();
}

const DOMTokenListSupportedToken Element::sAnchorAndFormRelValues[] = {
    "noreferrer""noopener""opener", nullptr};

// https://html.spec.whatwg.org/multipage/urls-and-fetching.html#lazy-loading-attribute
static constexpr nsAttrValue::EnumTable kLoadingTable[] = {
    {"eager", Element::Loading::Eager},
    {"lazy", Element::Loading::Lazy},
    {nullptr, 0}};

void Element::GetLoading(nsAString& aValue) const {
  GetEnumAttr(nsGkAtoms::loading, kLoadingTable[0].tag, aValue);
}

bool Element::ParseLoadingAttribute(const nsAString& aValue,
                                    nsAttrValue& aResult) {
  return aResult.ParseEnumValue(aValue, kLoadingTable,
                                /* aCaseSensitive = */ false, kLoadingTable);
}

Element::Loading Element::LoadingState() const {
  const nsAttrValue* val = mAttrs.GetAttr(nsGkAtoms::loading);
  if (!val) {
    return Loading::Eager;
  }
  return static_cast<Loading>(val->GetEnumValue());
}

//----------------------------------------------------------------------

void Element::AddToIdTable(nsAtom* aId) {
  NS_ASSERTION(HasID(), "Node doesn't have an ID?");
  if (IsInShadowTree()) {
    ShadowRoot* containingShadow = GetContainingShadow();
    containingShadow->AddToIdTable(this, aId);
  } else {
    Document* doc = GetUncomposedDoc();
    if (doc && !IsInNativeAnonymousSubtree()) {
      doc->AddToIdTable(this, aId);
    }
  }
}

void Element::RemoveFromIdTable() {
  if (!HasID()) {
    return;
  }

  nsAtom* id = DoGetID();
  if (IsInShadowTree()) {
    ShadowRoot* containingShadow = GetContainingShadow();
    // Check for containingShadow because it may have
    // been deleted during unlinking.
    if (containingShadow) {
      containingShadow->RemoveFromIdTable(this, id);
    }
  } else {
    Document* doc = GetUncomposedDoc();
    if (doc && !IsInNativeAnonymousSubtree()) {
      doc->RemoveFromIdTable(this, id);
    }
  }
}

void Element::SetSlot(const nsAString& aName, ErrorResult& aError) {
  aError = SetAttr(kNameSpaceID_None, nsGkAtoms::slot, aName, true);
}

void Element::GetSlot(nsAString& aName) { GetAttr(nsGkAtoms::slot, aName); }

// https://dom.spec.whatwg.org/#dom-element-shadowroot
ShadowRoot* Element::GetShadowRootByMode() const {
  /**
   * 1. Let shadow be context object's shadow root.
   * 2. If shadow is null or its mode is "closed", then return null.
   */

  ShadowRoot* shadowRoot = GetShadowRoot();
  if (!shadowRoot || shadowRoot->IsClosed()) {
    return nullptr;
  }

  /**
   * 3. Return shadow.
   */

  return shadowRoot;
}

bool Element::CanAttachShadowDOM() const {
  /**
   * If context object's namespace is not the HTML namespace,
   * return false.
   *
   * Deviate from the spec here to allow shadow dom attachement to
   * XUL elements.
   */

  if (!IsHTMLElement() &&
      !(IsXULElement() &&
        nsContentUtils::AllowXULXBLForPrincipal(NodePrincipal()))) {
    return false;
  }

  /**
   * If context object's local name is not
   *    a valid custom element name, "article", "aside", "blockquote",
   *    "body", "div", "footer", "h1", "h2", "h3", "h4", "h5", "h6",
   *    "header", "main" "nav", "p", "section", "search", or "span",
   *  return false.
   */

  nsAtom* nameAtom = NodeInfo()->NameAtom();
  uint32_t namespaceID = NodeInfo()->NamespaceID();
  if (!(nsContentUtils::IsCustomElementName(nameAtom, namespaceID) ||
        nameAtom == nsGkAtoms::article || nameAtom == nsGkAtoms::aside ||
        nameAtom == nsGkAtoms::blockquote || nameAtom == nsGkAtoms::body ||
        nameAtom == nsGkAtoms::div || nameAtom == nsGkAtoms::footer ||
        nameAtom == nsGkAtoms::h1 || nameAtom == nsGkAtoms::h2 ||
        nameAtom == nsGkAtoms::h3 || nameAtom == nsGkAtoms::h4 ||
        nameAtom == nsGkAtoms::h5 || nameAtom == nsGkAtoms::h6 ||
        nameAtom == nsGkAtoms::header || nameAtom == nsGkAtoms::main ||
        nameAtom == nsGkAtoms::nav || nameAtom == nsGkAtoms::p ||
        nameAtom == nsGkAtoms::section || nameAtom == nsGkAtoms::search ||
        nameAtom == nsGkAtoms::span)) {
    return false;
  }

  /**
   * 3. If context object’s local name is a valid custom element name, or
   *    context object’s is value is not null, then:
   *    If definition is not null and definition’s disable shadow is true, then
   *    return false.
   */

  // It will always have CustomElementData when the element is a valid custom
  // element or has is value.
  if (CustomElementData* ceData = GetCustomElementData()) {
    CustomElementDefinition* definition = ceData->GetCustomElementDefinition();
    // If the definition is null, the element possible hasn't yet upgraded.
    // Fallback to use LookupCustomElementDefinition to find its definition.
    if (!definition) {
      definition = nsContentUtils::LookupCustomElementDefinition(
          NodeInfo()->GetDocument(), nameAtom, namespaceID,
          ceData->GetCustomElementType());
    }

    if (definition && definition->mDisableShadow) {
      return false;
    }
  }

  return true;
}

// https://dom.spec.whatwg.org/#dom-element-attachshadow
already_AddRefed<ShadowRoot> Element::AttachShadow(const ShadowRootInit& aInit,
                                                   ErrorResult& aError) {
  /**
   * Step 1, 2, and 3.
   */

  if (!CanAttachShadowDOM()) {
    aError.ThrowNotSupportedError("Unable to attach ShadowDOM");
    return nullptr;
  }

  /**
   * 4. If element is a shadow host, then:
   */

  if (RefPtr<ShadowRoot> root = GetShadowRoot()) {
    /**
     *  1. Let currentShadowRoot be element’s shadow root.
     *
     *  2. If any of the following are true:
     *      currentShadowRoot’s declarative is false; or
     *      currentShadowRoot’s mode is not mode,
     *  then throw a "NotSupportedError" DOMException.
     */

    if (!root->IsDeclarative() || root->Mode() != aInit.mMode) {
      aError.ThrowNotSupportedError(
          "Unable to re-attach to existing ShadowDOM");
      return nullptr;
    }
    /**
     * 3. Otherwise:
     *      1. Remove all of currentShadowRoot’s children, in tree order.
     *      2. Set currentShadowRoot’s declarative to false.
     *      3. Return.
     */

    root->ReplaceChildren(nullptr, aError);
    root->SetIsDeclarative(ShadowRootDeclarative::No);
    return root.forget();
  }

  if (StaticPrefs::dom_webcomponents_shadowdom_report_usage()) {
    OwnerDoc()->ReportShadowDOMUsage();
  }

  return AttachShadowWithoutNameChecks(
      aInit.mMode, DelegatesFocus(aInit.mDelegatesFocus), aInit.mSlotAssignment,
      ShadowRootClonable(aInit.mClonable),
      ShadowRootSerializable(aInit.mSerializable));
}

already_AddRefed<ShadowRoot> Element::AttachShadowWithoutNameChecks(
    ShadowRootMode aMode, DelegatesFocus aDelegatesFocus,
    SlotAssignmentMode aSlotAssignment, ShadowRootClonable aClonable,
    ShadowRootSerializable aSerializable) {
  nsAutoScriptBlocker scriptBlocker;

  auto* nim = mNodeInfo->NodeInfoManager();
  RefPtr<mozilla::dom::NodeInfo> nodeInfo =
      nim->GetNodeInfo(nsGkAtoms::documentFragmentNodeName, nullptr,
                       kNameSpaceID_None, DOCUMENT_FRAGMENT_NODE);

  // If there are no children, the flat tree is not changing due to the presence
  // of the shadow root, so we don't need to invalidate style / layout.
  //
  // This is a minor optimization, but also works around nasty stuff like
  // bug 1397876.
  if (Document* doc = GetComposedDoc()) {
    if (PresShell* presShell = doc->GetPresShell()) {
      presShell->ShadowRootWillBeAttached(*this);
    }
  }

  /**
   * 5. Let shadow be a new shadow root whose node document is
   *    context object's node document, host is context object,
   *    and mode is init's mode.
   */

  RefPtr<ShadowRoot> shadowRoot = new (nim)
      ShadowRoot(this, aMode, aDelegatesFocus, aSlotAssignment, aClonable,
                 aSerializable, ShadowRootDeclarative::No, nodeInfo.forget());

  if (NodeOrAncestorHasDirAuto()) {
    shadowRoot->SetAncestorHasDirAuto();
  }

  /**
   * 7. If this’s custom element state is "precustomized" or "custom", then set
   *    shadow’s available to element internals to true.
   */

  CustomElementData* ceData = GetCustomElementData();
  if (ceData && (ceData->mState == CustomElementData::State::ePrecustomized ||
                 ceData->mState == CustomElementData::State::eCustom)) {
    shadowRoot->SetAvailableToElementInternals();
  }

  /**
   * 9. Set context object's shadow root to shadow.
   */

  SetShadowRoot(shadowRoot);

  // Dispatch a "shadowrootattached" event for devtools if needed.
  if (MOZ_UNLIKELY(
          nim->GetDocument()->DevToolsAnonymousAndShadowEventsEnabled())) {
    AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher(
        this, u"shadowrootattached"_ns, CanBubble::eYes,
        ChromeOnlyDispatch::eYes, Composed::eYes);
    dispatcher->PostDOMEvent();
  }

  const LinkedList<AbstractRange>* ranges =
      GetExistingClosestCommonInclusiveAncestorRanges();
  if (ranges) {
    for (const AbstractRange* range : *ranges) {
      if (range->MayCrossShadowBoundary()) {
        MOZ_ASSERT(range->IsDynamicRange());
        CrossShadowBoundaryRange* crossBoundaryRange =
            range->AsDynamicRange()->GetCrossShadowBoundaryRange();
        MOZ_ASSERT(crossBoundaryRange);
        // We may have previously selected this node before it
        // becomes a shadow host, so we need to reset the values
        // in RangeBoundaries to accommodate the change.
        crossBoundaryRange->NotifyNodeBecomesShadowHost(this);
      }
    }
  }
  /**
   * 10. Return shadow.
   */

  return shadowRoot.forget();
}

void Element::AttachAndSetUAShadowRoot(NotifyUAWidgetSetup aNotify,
                                       DelegatesFocus aDelegatesFocus) {
  MOZ_DIAGNOSTIC_ASSERT(!CanAttachShadowDOM(),
                        "Cannot be used to attach UI shadow DOM");
  if (OwnerDoc()->IsStaticDocument()) {
    return;
  }

  if (!GetShadowRoot()) {
    RefPtr<ShadowRoot> shadowRoot =
        AttachShadowWithoutNameChecks(ShadowRootMode::Closed, aDelegatesFocus);
    shadowRoot->SetIsUAWidget();
  }

  MOZ_ASSERT(GetShadowRoot()->IsUAWidget());
  if (aNotify == NotifyUAWidgetSetup::Yes) {
    NotifyUAWidgetSetupOrChange();
  }
}

void Element::NotifyUAWidgetSetupOrChange() {
  MOZ_ASSERT(IsInComposedDoc());
  Document* doc = OwnerDoc();
  if (doc->IsStaticDocument()) {
    return;
  }

  // Schedule a runnable, ensure the event dispatches before
  // returning to content script.
  // This event cause UA Widget to construct or cause onchange callback
  // of existing UA Widget to run; dispatching this event twice should not cause
  // UA Widget to re-init.
  nsContentUtils::AddScriptRunner(NS_NewRunnableFunction(
      "Element::NotifyUAWidgetSetupOrChange::UAWidgetSetupOrChange",
      [self = RefPtr<Element>(this), doc = RefPtr<Document>(doc)]() {
        nsContentUtils::DispatchChromeEvent(doc, self,
                                            u"UAWidgetSetupOrChange"_ns,
                                            CanBubble::eYes, Cancelable::eNo);
      }));
}

void Element::NotifyUAWidgetTeardown(UnattachShadowRoot aUnattachShadowRoot) {
  MOZ_ASSERT(IsInComposedDoc());
  if (!GetShadowRoot()) {
    return;
  }
  MOZ_ASSERT(GetShadowRoot()->IsUAWidget());
  if (aUnattachShadowRoot == UnattachShadowRoot::Yes) {
    UnattachShadow();
  }

  Document* doc = OwnerDoc();
  if (doc->IsStaticDocument()) {
    return;
  }

  // The runnable will dispatch an event to tear down UA Widget.
  nsContentUtils::AddScriptRunner(NS_NewRunnableFunction(
      "Element::NotifyUAWidgetTeardownAndUnattachShadow::UAWidgetTeardown",
      [self = RefPtr<Element>(this), doc = RefPtr<Document>(doc)]() {
        // Bail out if the element is being collected by CC
        bool hasHadScriptObject = true;
        nsIScriptGlobalObject* scriptObject =
            doc->GetScriptHandlingObject(hasHadScriptObject);
        if (!scriptObject && hasHadScriptObject) {
          return;
        }

        Unused << nsContentUtils::DispatchChromeEvent(
            doc, self, u"UAWidgetTeardown"_ns, CanBubble::eYes,
            Cancelable::eNo);
      }));
}

void Element::UnattachShadow() {
  RefPtr<ShadowRoot> shadowRoot = GetShadowRoot();
  if (!shadowRoot) {
    return;
  }

  nsAutoScriptBlocker scriptBlocker;

  if (RefPtr<Document> doc = GetComposedDoc()) {
    if (PresShell* presShell = doc->GetPresShell()) {
      presShell->DestroyFramesForAndRestyle(this);
#ifdef ACCESSIBILITY
      // We need to notify the accessibility service here explicitly because,
      // even though we're going to reconstruct the _host_, the shadow root and
      // its children are never really going to come back. We could plumb that
      // further down to DestroyFramesForAndRestyle and add a new flag to
      // nsCSSFrameConstructor::ContentRemoved or such, but this seems simpler
      // instead.
      if (nsAccessibilityService* accService = GetAccService()) {
        accService->ContentRemoved(presShell, shadowRoot);
      }
#endif
    }
    // ContentRemoved doesn't really run script in the cases we care about (it
    // can only call ClearFocus when removing iframes and so on...)
    [&]() MOZ_CAN_RUN_SCRIPT_BOUNDARY {
      if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
        fm->ContentRemoved(doc, shadowRoot);
      }
    }();
  }
  MOZ_ASSERT(!GetPrimaryFrame());

  shadowRoot->Unattach();
  SetShadowRoot(nullptr);
}

void Element::GetAttribute(const nsAString& aName, DOMString& aReturn) {
  const nsAttrValue* val = mAttrs.GetAttr(
      aName,
      IsHTMLElement() && IsInHTMLDocument() ? eIgnoreCase : eCaseMatters);
  if (val) {
    val->ToString(aReturn);
  } else {
    aReturn.SetNull();
  }
}

bool Element::ToggleAttribute(const nsAString& aName,
                              const Optional<bool>& aForce,
                              nsIPrincipal* aTriggeringPrincipal,
                              ErrorResult& aError) {
  aError = nsContentUtils::CheckQName(aName, false);
  if (aError.Failed()) {
    return false;
  }

  nsAutoString nameToUse;
  const nsAttrName* name = InternalGetAttrNameFromQName(aName, &nameToUse);
  if (!name) {
    if (aForce.WasPassed() && !aForce.Value()) {
      return false;
    }
    RefPtr<nsAtom> nameAtom = NS_AtomizeMainThread(nameToUse);
    if (!nameAtom) {
      aError.Throw(NS_ERROR_OUT_OF_MEMORY);
      return false;
    }
    aError = SetAttr(kNameSpaceID_None, nameAtom, u""_ns, aTriggeringPrincipal,
                     true);
    return true;
  }
  if (aForce.WasPassed() && aForce.Value()) {
    return true;
  }
  // Hold a strong reference here so that the atom or nodeinfo doesn't go
  // away during UnsetAttr. If it did UnsetAttr would be left with a
  // dangling pointer as argument without knowing it.
  nsAttrName tmp(*name);

  aError = UnsetAttr(name->NamespaceID(), name->LocalName(), true);
  return false;
}

void Element::SetAttribute(const nsAString& aName, const nsAString& aValue,
                           nsIPrincipal* aTriggeringPrincipal,
                           ErrorResult& aError) {
  aError = nsContentUtils::CheckQName(aName, false);
  if (aError.Failed()) {
    return;
  }

  nsAutoString nameToUse;
  const nsAttrName* name = InternalGetAttrNameFromQName(aName, &nameToUse);
  if (!name) {
    RefPtr<nsAtom> nameAtom = NS_AtomizeMainThread(nameToUse);
    if (!nameAtom) {
      aError.Throw(NS_ERROR_OUT_OF_MEMORY);
      return;
    }
    aError = SetAttr(kNameSpaceID_None, nameAtom, aValue, aTriggeringPrincipal,
                     true);
    return;
  }

  aError = SetAttr(name->NamespaceID(), name->LocalName(), name->GetPrefix(),
                   aValue, aTriggeringPrincipal, true);
}

void Element::RemoveAttribute(const nsAString& aName, ErrorResult& aError) {
  const nsAttrName* name = InternalGetAttrNameFromQName(aName);

  if (!name) {
    // If there is no canonical nsAttrName for this attribute name, then the
    // attribute does not exist and we can't get its namespace ID and
    // local name below, so we return early.
    return;
  }

  // Hold a strong reference here so that the atom or nodeinfo doesn't go
  // away during UnsetAttr. If it did UnsetAttr would be left with a
  // dangling pointer as argument without knowing it.
  nsAttrName tmp(*name);

  aError = UnsetAttr(name->NamespaceID(), name->LocalName(), true);
}

Attr* Element::GetAttributeNode(const nsAString& aName) {
  return Attributes()->GetNamedItem(aName);
}

already_AddRefed<Attr> Element::SetAttributeNode(Attr& aNewAttr,
                                                 ErrorResult& aError) {
  return Attributes()->SetNamedItemNS(aNewAttr, aError);
}

already_AddRefed<Attr> Element::RemoveAttributeNode(Attr& aAttribute,
                                                    ErrorResult& aError) {
  Element* elem = aAttribute.GetElement();
  if (elem != this) {
    aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
    return nullptr;
  }

  nsAutoString nameSpaceURI;
  aAttribute.NodeInfo()->GetNamespaceURI(nameSpaceURI);
  return Attributes()->RemoveNamedItemNS(
      nameSpaceURI, aAttribute.NodeInfo()->LocalName(), aError);
}

void Element::GetAttributeNS(const nsAString& aNamespaceURI,
                             const nsAString& aLocalName, nsAString& aReturn) {
  int32_t nsid = nsNameSpaceManager::GetInstance()->GetNameSpaceID(
      aNamespaceURI, nsContentUtils::IsChromeDoc(OwnerDoc()));

  if (nsid == kNameSpaceID_Unknown) {
    // Unknown namespace means no attribute.
    SetDOMStringToNull(aReturn);
    return;
  }

  RefPtr<nsAtom> name = NS_AtomizeMainThread(aLocalName);
  bool hasAttr = GetAttr(nsid, name, aReturn);
  if (!hasAttr) {
    SetDOMStringToNull(aReturn);
  }
}

void Element::SetAttributeNS(const nsAString& aNamespaceURI,
                             const nsAString& aQualifiedName,
                             const nsAString& aValue,
                             nsIPrincipal* aTriggeringPrincipal,
                             ErrorResult& aError) {
  RefPtr<mozilla::dom::NodeInfo> ni;
  aError = nsContentUtils::GetNodeInfoFromQName(
      aNamespaceURI, aQualifiedName, mNodeInfo->NodeInfoManager(),
      ATTRIBUTE_NODE, getter_AddRefs(ni));
  if (aError.Failed()) {
    return;
  }

  aError = SetAttr(ni->NamespaceID(), ni->NameAtom(), ni->GetPrefixAtom(),
                   aValue, aTriggeringPrincipal, true);
}

already_AddRefed<nsIPrincipal> Element::CreateDevtoolsPrincipal() {
  // Return an ExpandedPrincipal that subsumes this Element's Principal,
  // and expands this Element's CSP to allow the actions that devtools
  // needs to perform.
  AutoTArray<nsCOMPtr<nsIPrincipal>, 1> allowList = {NodePrincipal()};
  RefPtr<ExpandedPrincipal> dtPrincipal = ExpandedPrincipal::Create(
      allowList, NodePrincipal()->OriginAttributesRef());

  if (nsIContentSecurityPolicy* csp = GetCsp()) {
    RefPtr<nsCSPContext> dtCsp = new nsCSPContext();
    dtCsp->InitFromOther(static_cast<nsCSPContext*>(csp));
    dtCsp->SetSkipAllowInlineStyleCheck(true);

    dtPrincipal->SetCsp(dtCsp);
  }

  return dtPrincipal.forget();
}

void Element::SetAttribute(
    const nsAString& aName,
    const TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString& aValue,
    nsIPrincipal* aTriggeringPrincipal, ErrorResult& aError) {
  aError = nsContentUtils::CheckQName(aName, false);
  if (aError.Failed()) {
    return;
  }

  nsAutoString nameToUse;
  const nsAttrName* name = InternalGetAttrNameFromQName(aName, &nameToUse);
  if (!name) {
    RefPtr<nsAtom> nameAtom = NS_AtomizeMainThread(nameToUse);
    Maybe<nsAutoString> compliantStringHolder;
    const nsAString* compliantString =
        TrustedTypeUtils::GetTrustedTypesCompliantAttributeValue(
            *this, nameAtom, kNameSpaceID_None, aValue, compliantStringHolder,
            aError);
    if (aError.Failed()) {
      return;
    }
    aError = SetAttr(kNameSpaceID_None, nameAtom, *compliantString,
                     aTriggeringPrincipal, true);
    return;
  }

  Maybe<nsAutoString> compliantStringHolder;
  RefPtr<nsAtom> attributeName = name->LocalName();
  nsMutationGuard guard;
  const nsAString* compliantString =
      TrustedTypeUtils::GetTrustedTypesCompliantAttributeValue(
          *this, attributeName, name->NamespaceID(), aValue,
          compliantStringHolder, aError);
  if (aError.Failed()) {
    return;
  }
  if (!guard.Mutated(0)) {
    aError = SetAttr(name->NamespaceID(), name->LocalName(), name->GetPrefix(),
                     *compliantString, aTriggeringPrincipal, true);
    return;
  }

  // GetTrustedTypesCompliantAttributeValue may have modified mAttrs and made
  // the result of InternalGetAttrNameFromQName above invalid. It may now return
  // a different value, perhaps a nullptr. To be safe, just call the version of
  // Element::SetAttribute accepting a string value.
  SetAttribute(aName, *compliantString, aTriggeringPrincipal, aError);
}

void Element::SetAttributeNS(
    const nsAString& aNamespaceURI, const nsAString& aQualifiedName,
    const TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString& aValue,
    nsIPrincipal* aTriggeringPrincipal, ErrorResult& aError) {
  RefPtr<mozilla::dom::NodeInfo> ni;
  aError = nsContentUtils::GetNodeInfoFromQName(
      aNamespaceURI, aQualifiedName, mNodeInfo->NodeInfoManager(),
      ATTRIBUTE_NODE, getter_AddRefs(ni));
  if (aError.Failed()) {
    return;
  }

  Maybe<nsAutoString> compliantStringHolder;
  RefPtr<nsAtom> attributeName = ni->NameAtom();
  const nsAString* compliantString =
      TrustedTypeUtils::GetTrustedTypesCompliantAttributeValue(
          *this, attributeName, ni->NamespaceID(), aValue,
          compliantStringHolder, aError);
  if (aError.Failed()) {
    return;
  }
  aError = SetAttr(ni->NamespaceID(), ni->NameAtom(), ni->GetPrefixAtom(),
                   *compliantString, aTriggeringPrincipal, true);
}

void Element::SetAttributeDevtools(const nsAString& aName,
                                   const nsAString& aValue,
                                   ErrorResult& aError) {
  // Run this through SetAttribute with a devtools-ready principal.
  RefPtr<nsIPrincipal> dtPrincipal = CreateDevtoolsPrincipal();
  SetAttribute(aName, aValue, dtPrincipal, aError);
}

void Element::SetAttributeDevtoolsNS(const nsAString& aNamespaceURI,
                                     const nsAString& aLocalName,
                                     const nsAString& aValue,
                                     ErrorResult& aError) {
  // Run this through SetAttributeNS with a devtools-ready principal.
  RefPtr<nsIPrincipal> dtPrincipal = CreateDevtoolsPrincipal();
  SetAttributeNS(aNamespaceURI, aLocalName, aValue, dtPrincipal, aError);
}

void Element::RemoveAttributeNS(const nsAString& aNamespaceURI,
                                const nsAString& aLocalName,
                                ErrorResult& aError) {
  RefPtr<nsAtom> name = NS_AtomizeMainThread(aLocalName);
  int32_t nsid = nsNameSpaceManager::GetInstance()->GetNameSpaceID(
      aNamespaceURI, nsContentUtils::IsChromeDoc(OwnerDoc()));

  if (nsid == kNameSpaceID_Unknown) {
    // If the namespace ID is unknown, it means there can't possibly be an
    // existing attribute. We would need a known namespace ID to pass into
    // UnsetAttr, so we return early if we don't have one.
    return;
  }

  aError = UnsetAttr(nsid, name, true);
}

Attr* Element::GetAttributeNodeNS(const nsAString& aNamespaceURI,
                                  const nsAString& aLocalName) {
  return GetAttributeNodeNSInternal(aNamespaceURI, aLocalName);
}

Attr* Element::GetAttributeNodeNSInternal(const nsAString& aNamespaceURI,
                                          const nsAString& aLocalName) {
  return Attributes()->GetNamedItemNS(aNamespaceURI, aLocalName);
}

already_AddRefed<Attr> Element::SetAttributeNodeNS(Attr& aNewAttr,
                                                   ErrorResult& aError) {
  return Attributes()->SetNamedItemNS(aNewAttr, aError);
}

already_AddRefed<nsIHTMLCollection> Element::GetElementsByTagNameNS(
    const nsAString& aNamespaceURI, const nsAString& aLocalName,
    ErrorResult& aError) {
  int32_t nameSpaceId = kNameSpaceID_Wildcard;

  if (!aNamespaceURI.EqualsLiteral("*")) {
    aError = nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI,
                                                                  nameSpaceId);
    if (aError.Failed()) {
      return nullptr;
    }
  }

  NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");

  return NS_GetContentList(this, nameSpaceId, aLocalName);
}

bool Element::HasAttributeNS(const nsAString& aNamespaceURI,
                             const nsAString& aLocalName) const {
  int32_t nsid = nsNameSpaceManager::GetInstance()->GetNameSpaceID(
      aNamespaceURI, nsContentUtils::IsChromeDoc(OwnerDoc()));

  if (nsid == kNameSpaceID_Unknown) {
    // Unknown namespace means no attr...
    return false;
  }

  RefPtr<nsAtom> name = NS_AtomizeMainThread(aLocalName);
  return HasAttr(nsid, name);
}

already_AddRefed<nsIHTMLCollection> Element::GetElementsByClassName(
    const nsAString& aClassNames) {
  return nsContentUtils::GetElementsByClassName(this, aClassNames);
}

bool Element::HasSharedRoot(const Element* aElement) const {
  nsINode* root = SubtreeRoot();
  nsINode* attrSubtreeRoot = aElement->SubtreeRoot();
  do {
    if (root == attrSubtreeRoot) {
      return true;
    }
    auto* shadow = ShadowRoot::FromNode(root);
    if (!shadow || !shadow->GetHost()) {
      break;
    }
    root = shadow->GetHost()->SubtreeRoot();
  } while (true);
  return false;
}

Element* Element::GetElementByIdInDocOrSubtree(nsAtom* aID) const {
  if (auto* docOrShadowRoot = GetContainingDocumentOrShadowRoot()) {
    return docOrShadowRoot->GetElementById(aID);
  }

  return nsContentUtils::MatchElementId(SubtreeRoot()->AsContent(), aID);
}

Element* Element::GetAttrAssociatedElement(nsAtom* aAttr) const {
  if (const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) {
    nsWeakPtr weakAttrEl = slots->mExplicitlySetAttrElementMap.Get(aAttr);
    if (nsCOMPtr<Element> attrEl = do_QueryReferent(weakAttrEl)) {
      // If reflectedTarget's explicitly set attr-element |attrEl| is
      // a descendant of any of element's shadow-including ancestors, then
      // return |atrEl|.
      if (HasSharedRoot(attrEl)) {
        return attrEl;
      }
      return nullptr;
    }
  }

  const nsAttrValue* value = GetParsedAttr(aAttr);
  if (!value) {
    return nullptr;
  }

  MOZ_ASSERT(value->Type() == nsAttrValue::eAtom,
             "Attribute used for attr associated element must be parsed");

  return GetElementByIdInDocOrSubtree(value->GetAtomValue());
}

void Element::GetAttrAssociatedElements(
    nsAtom* aAttr, bool* aUseCachedValue,
    Nullable<nsTArray<RefPtr<Element>>>& aElements) {
  MOZ_ASSERT(aElements.IsNull());

  auto& [explicitlySetAttrElements, cachedAttrElements] =
      ExtendedDOMSlots()->mAttrElementsMap.LookupOrInsert(aAttr);

  // https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#attr-associated-elements
  auto getAttrAssociatedElements =
      [&, &explicitlySetAttrElements =
              explicitlySetAttrElements]() -> Maybe<nsTArray<RefPtr<Element>>> {
    nsTArray<RefPtr<Element>> elements;

    if (explicitlySetAttrElements) {
      // 3. If reflectedTarget's explicitly set attr-elements is not null
      for (const nsWeakPtr& weakEl : *explicitlySetAttrElements) {
        // For each attrElement in reflectedTarget's explicitly set
        // attr-elements:
        if (nsCOMPtr<Element> attrEl = do_QueryReferent(weakEl)) {
          // If attrElement is not a descendant of any of element's
          // shadow-including ancestors, then continue.
          if (!HasSharedRoot(attrEl)) {
            continue;
          }
          // Append attrElement to elements.
          elements.AppendElement(attrEl);
        }
      }
    } else {
      // 4. Otherwise
      //   1. Let contentAttributeValue be the result of running
      //   reflectedTarget's get the content attribute.
      const nsAttrValue* value = GetParsedAttr(aAttr);
      //   2. If contentAttributeValue is null, then return null.
      if (!value) {
        return Nothing();
      }

      //   3. Let tokens be contentAttributeValue, split on ASCII whitespace.
      MOZ_ASSERT(value->Type() == nsAttrValue::eAtomArray ||
                     value->Type() == nsAttrValue::eAtom,
                 "Attribute used for attr associated elements must be parsed");
      for (uint32_t i = 0; i < value->GetAtomCount(); i++) {
        // For each id of tokens:
        if (auto* candidate = GetElementByIdInDocOrSubtree(
                value->AtomAt(static_cast<int32_t>(i)))) {
          // Append candidate to elements.
          elements.AppendElement(candidate);
        }
      }
    }

    return Some(std::move(elements));
  };

  // getter steps:
  // 1. Let elements be the result of running this's get the attr-associated
  // elements.
  auto elements = getAttrAssociatedElements();

  if (elements && elements == cachedAttrElements) {
    // 2. If the contents of elements is equal to the contents of this's cached
    // attr-associated elements, then return this's cached attr-associated
    // elements object.
    MOZ_ASSERT(!*aUseCachedValue);
    *aUseCachedValue = true;
    return;
  }

  // 3. Let elementsAsFrozenArray be elements, converted to a FrozenArray<T>?.
  //    (the binding code takes aElements and returns it as a FrozenArray)
  // 5. Set this's cached attr-associated elements object to
  //    elementsAsFrozenArray.
  //    (the binding code stores the attr-associated elements object in a slot)
  // 6. Return elementsAsFrozenArray.
  if (elements) {
--> --------------------

--> maximum size reached

--> --------------------

98%


¤ Dauer der Verarbeitung: 0.76 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.