Blame dom/base/ShadowRoot.cpp

Packit f0b94e
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
Packit f0b94e
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
Packit f0b94e
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
Packit f0b94e
#include "mozilla/Preferences.h"
Packit f0b94e
#include "mozilla/dom/ShadowRoot.h"
Packit f0b94e
#include "mozilla/dom/ShadowRootBinding.h"
Packit f0b94e
#include "mozilla/dom/DocumentFragment.h"
Packit f0b94e
#include "ChildIterator.h"
Packit f0b94e
#include "nsContentUtils.h"
Packit f0b94e
#include "nsDOMClassInfoID.h"
Packit f0b94e
#include "nsIStyleSheetLinkingElement.h"
Packit f0b94e
#include "mozilla/dom/Element.h"
Packit f0b94e
#include "mozilla/dom/HTMLSlotElement.h"
Packit f0b94e
#include "nsXBLPrototypeBinding.h"
Packit f0b94e
#include "mozilla/EventDispatcher.h"
Packit f0b94e
#include "mozilla/StyleSheet.h"
Packit f0b94e
#include "mozilla/StyleSheetInlines.h"
Packit f0b94e
Packit f0b94e
using namespace mozilla;
Packit f0b94e
using namespace mozilla::dom;
Packit f0b94e
Packit f0b94e
NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
Packit f0b94e
Packit f0b94e
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot, DocumentFragment)
Packit f0b94e
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
Packit f0b94e
  for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done(); iter.Next()) {
Packit f0b94e
    iter.Get()->Traverse(&cb;;
Packit f0b94e
  }
Packit f0b94e
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
Packit f0b94e
Packit f0b94e
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
Packit f0b94e
  if (tmp->GetHost()) {
Packit f0b94e
    tmp->GetHost()->RemoveMutationObserver(tmp);
Packit f0b94e
  }
Packit f0b94e
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
Packit f0b94e
  tmp->mIdentifierMap.Clear();
Packit f0b94e
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
Packit f0b94e
Packit f0b94e
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ShadowRoot)
Packit f0b94e
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
Packit f0b94e
  NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
Packit f0b94e
NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
Packit f0b94e
Packit f0b94e
NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
Packit f0b94e
NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
Packit f0b94e
Packit f0b94e
ShadowRoot::ShadowRoot(Element* aElement, ShadowRootMode aMode,
Packit f0b94e
                       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
Packit f0b94e
    : DocumentFragment(aNodeInfo),
Packit f0b94e
      DocumentOrShadowRoot(*this),
Packit f0b94e
      mMode(aMode),
Packit f0b94e
      mServoStyles(Servo_AuthorStyles_Create()),
Packit f0b94e
      mIsComposedDocParticipant(false) {
Packit f0b94e
  SetHost(aElement);
Packit f0b94e
Packit f0b94e
  // Nodes in a shadow tree should never store a value
Packit f0b94e
  // in the subtree root pointer, nodes in the shadow tree
Packit f0b94e
  // track the subtree root using GetContainingShadow().
Packit f0b94e
  ClearSubtreeRootPointer();
Packit f0b94e
Packit f0b94e
  SetFlags(NODE_IS_IN_SHADOW_TREE);
Packit f0b94e
Packit f0b94e
  ExtendedDOMSlots()->mBindingParent = aElement;
Packit f0b94e
  ExtendedDOMSlots()->mContainingShadow = this;
Packit f0b94e
Packit f0b94e
  // Add the ShadowRoot as a mutation observer on the host to watch
Packit f0b94e
  // for mutations because the insertion points in this ShadowRoot
Packit f0b94e
  // may need to be updated when the host children are modified.
Packit f0b94e
  GetHost()->AddMutationObserver(this);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
ShadowRoot::~ShadowRoot() {
Packit f0b94e
  if (auto* host = GetHost()) {
Packit f0b94e
    // mHost may have been unlinked.
Packit f0b94e
    host->RemoveMutationObserver(this);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  UnsetFlags(NODE_IS_IN_SHADOW_TREE);
Packit f0b94e
Packit f0b94e
  // nsINode destructor expects mSubtreeRoot == this.
Packit f0b94e
  SetSubtreeRootPointer(this);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
JSObject* ShadowRoot::WrapObject(JSContext* aCx,
Packit f0b94e
                                 JS::Handle<JSObject*> aGivenProto) {
Packit f0b94e
  return mozilla::dom::ShadowRootBinding::Wrap(aCx, this, aGivenProto);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ShadowRoot::CloneInternalDataFrom(ShadowRoot* aOther) {
Packit f0b94e
  size_t sheetCount = aOther->SheetCount();
Packit f0b94e
  for (size_t i = 0; i < sheetCount; ++i) {
Packit f0b94e
    StyleSheet* sheet = aOther->SheetAt(i);
Packit f0b94e
    if (sheet->IsApplicable()) {
Packit f0b94e
      RefPtr<StyleSheet> clonedSheet =
Packit f0b94e
          sheet->Clone(nullptr, nullptr, nullptr, nullptr);
Packit f0b94e
      if (clonedSheet) {
Packit f0b94e
        AppendStyleSheet(*clonedSheet.get());
Packit f0b94e
        Servo_AuthorStyles_AppendStyleSheet(mServoStyles.get(),
Packit f0b94e
                                            clonedSheet->AsServo());
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ShadowRoot::AddSlot(HTMLSlotElement* aSlot) {
Packit f0b94e
  MOZ_ASSERT(aSlot);
Packit f0b94e
Packit f0b94e
  // Note that if name attribute missing, the slot is a default slot.
Packit f0b94e
  nsAutoString name;
Packit f0b94e
  aSlot->GetName(name);
Packit f0b94e
Packit f0b94e
  nsTArray<HTMLSlotElement*>* currentSlots = mSlotMap.LookupOrAdd(name);
Packit f0b94e
  MOZ_ASSERT(currentSlots);
Packit f0b94e
Packit f0b94e
  HTMLSlotElement* oldSlot = currentSlots->SafeElementAt(0);
Packit f0b94e
Packit f0b94e
  TreeOrderComparator comparator;
Packit f0b94e
  currentSlots->InsertElementSorted(aSlot, comparator);
Packit f0b94e
Packit f0b94e
  HTMLSlotElement* currentSlot = currentSlots->ElementAt(0);
Packit f0b94e
  if (currentSlot != aSlot) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  bool doEnqueueSlotChange = false;
Packit f0b94e
  if (oldSlot && oldSlot != currentSlot) {
Packit f0b94e
    // Move assigned nodes from old slot to new slot.
Packit f0b94e
    const nsTArray<RefPtr<nsINode>>& assignedNodes = oldSlot->AssignedNodes();
Packit f0b94e
    while (assignedNodes.Length() > 0) {
Packit f0b94e
      nsINode* assignedNode = assignedNodes[0];
Packit f0b94e
Packit f0b94e
      oldSlot->RemoveAssignedNode(assignedNode);
Packit f0b94e
      currentSlot->AppendAssignedNode(assignedNode);
Packit f0b94e
      doEnqueueSlotChange = true;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    if (doEnqueueSlotChange) {
Packit f0b94e
      oldSlot->EnqueueSlotChangeEvent();
Packit f0b94e
      currentSlot->EnqueueSlotChangeEvent();
Packit f0b94e
    }
Packit f0b94e
  } else {
Packit f0b94e
    // Otherwise add appropriate nodes to this slot from the host.
Packit f0b94e
    for (nsIContent* child = GetHost()->GetFirstChild(); child;
Packit f0b94e
         child = child->GetNextSibling()) {
Packit f0b94e
      nsAutoString slotName;
Packit f0b94e
      if (child->IsElement()) {
Packit f0b94e
        child->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::slot,
Packit f0b94e
                                    slotName);
Packit f0b94e
      }
Packit f0b94e
      if (child->IsSlotable() && slotName.Equals(name)) {
Packit f0b94e
        currentSlot->AppendAssignedNode(child);
Packit f0b94e
        doEnqueueSlotChange = true;
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    if (doEnqueueSlotChange) {
Packit f0b94e
      currentSlot->EnqueueSlotChangeEvent();
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ShadowRoot::RemoveSlot(HTMLSlotElement* aSlot) {
Packit f0b94e
  MOZ_ASSERT(aSlot);
Packit f0b94e
Packit f0b94e
  nsAutoString name;
Packit f0b94e
  aSlot->GetName(name);
Packit f0b94e
Packit f0b94e
  SlotArray* currentSlots = mSlotMap.Get(name);
Packit f0b94e
  MOZ_DIAGNOSTIC_ASSERT(currentSlots && currentSlots->Contains(aSlot),
Packit f0b94e
                        "Slot to deregister wasn't found?");
Packit f0b94e
  if (currentSlots->Length() == 1) {
Packit f0b94e
    MOZ_ASSERT(currentSlots->ElementAt(0) == aSlot);
Packit f0b94e
    mSlotMap.Remove(name);
Packit f0b94e
Packit f0b94e
    if (!aSlot->AssignedNodes().IsEmpty()) {
Packit f0b94e
      aSlot->ClearAssignedNodes();
Packit f0b94e
      aSlot->EnqueueSlotChangeEvent();
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  const bool wasFirstSlot = currentSlots->ElementAt(0) == aSlot;
Packit f0b94e
  currentSlots->RemoveElement(aSlot);
Packit f0b94e
Packit f0b94e
  // Move assigned nodes from removed slot to the next slot in
Packit f0b94e
  // tree order with the same name.
Packit f0b94e
  if (!wasFirstSlot) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  HTMLSlotElement* replacementSlot = currentSlots->ElementAt(0);
Packit f0b94e
  const nsTArray<RefPtr<nsINode>>& assignedNodes = aSlot->AssignedNodes();
Packit f0b94e
  bool slottedNodesChanged = !assignedNodes.IsEmpty();
Packit f0b94e
  while (!assignedNodes.IsEmpty()) {
Packit f0b94e
    nsINode* assignedNode = assignedNodes[0];
Packit f0b94e
Packit f0b94e
    aSlot->RemoveAssignedNode(assignedNode);
Packit f0b94e
    replacementSlot->AppendAssignedNode(assignedNode);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (slottedNodesChanged) {
Packit f0b94e
    aSlot->EnqueueSlotChangeEvent();
Packit f0b94e
    replacementSlot->EnqueueSlotChangeEvent();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ShadowRoot::StyleSheetChanged() {
Packit f0b94e
  // FIXME(emilio): This is not needed to handle sheet additions / removals,
Packit f0b94e
  // only for CSSOM mutations, we should distinguish both.
Packit f0b94e
  Servo_AuthorStyles_ForceDirty(mServoStyles.get());
Packit f0b94e
  // FIXME(emilio): Similarly, we should notify of the particular mutation to
Packit f0b94e
  // the rule map, instead of this...
Packit f0b94e
  mStyleRuleMap.reset(nullptr);
Packit f0b94e
Packit f0b94e
  nsIDocument* doc = OwnerDoc();
Packit f0b94e
  if (nsIPresShell* shell = doc->GetShell()) {
Packit f0b94e
    doc->BeginUpdate(UPDATE_STYLE);
Packit f0b94e
    shell->RecordShadowStyleChange(*this);
Packit f0b94e
    doc->EndUpdate(UPDATE_STYLE);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ShadowRoot::InsertSheet(StyleSheet* aSheet, nsIContent* aLinkingContent) {
Packit f0b94e
  nsCOMPtr<nsIStyleSheetLinkingElement> linkingElement =
Packit f0b94e
      do_QueryInterface(aLinkingContent);
Packit f0b94e
Packit f0b94e
  // FIXME(emilio, bug 1410578): <link> should probably also be allowed here.
Packit f0b94e
  MOZ_ASSERT(linkingElement,
Packit f0b94e
             "The only styles in a ShadowRoot should come "
Packit f0b94e
             "from <style>.");
Packit f0b94e
Packit f0b94e
  linkingElement->SetStyleSheet(
Packit f0b94e
      aSheet);  // This sets the ownerNode on the sheet
Packit f0b94e
Packit f0b94e
  // Find the correct position to insert into the style sheet list (must
Packit f0b94e
  // be in tree order).
Packit f0b94e
  for (size_t i = 0; i <= SheetCount(); i++) {
Packit f0b94e
    if (i == SheetCount()) {
Packit f0b94e
      AppendStyleSheet(*aSheet);
Packit f0b94e
      Servo_AuthorStyles_AppendStyleSheet(mServoStyles.get(),
Packit f0b94e
                                          aSheet->AsServo());
Packit f0b94e
      break;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    StyleSheet* sheet = SheetAt(i);
Packit f0b94e
    nsINode* sheetOwningNode = sheet->GetOwnerNode();
Packit f0b94e
    if (nsContentUtils::PositionIsBefore(aLinkingContent, sheetOwningNode)) {
Packit f0b94e
      InsertSheetAt(i, *aSheet);
Packit f0b94e
      Servo_AuthorStyles_InsertStyleSheetBefore(
Packit f0b94e
          mServoStyles.get(), aSheet->AsServo(), sheet->AsServo());
Packit f0b94e
      break;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (aSheet->IsApplicable()) {
Packit f0b94e
    StyleSheetChanged();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ShadowRoot::RemoveSheet(StyleSheet* aSheet) {
Packit f0b94e
  DocumentOrShadowRoot::RemoveSheet(*aSheet);
Packit f0b94e
  Servo_AuthorStyles_RemoveStyleSheet(mServoStyles.get(), aSheet->AsServo());
Packit f0b94e
Packit f0b94e
  if (aSheet->IsApplicable()) {
Packit f0b94e
    StyleSheetChanged();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ShadowRoot::AddToIdTable(Element* aElement, nsAtom* aId) {
Packit f0b94e
  nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aId);
Packit f0b94e
  if (entry) {
Packit f0b94e
    entry->AddIdElement(aElement);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ShadowRoot::RemoveFromIdTable(Element* aElement, nsAtom* aId) {
Packit f0b94e
  nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aId);
Packit f0b94e
  if (entry) {
Packit f0b94e
    entry->RemoveIdElement(aElement);
Packit f0b94e
    if (entry->IsEmpty()) {
Packit f0b94e
      mIdentifierMap.RemoveEntry(entry);
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsresult ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
Packit f0b94e
  aVisitor.mCanHandle = true;
Packit f0b94e
  aVisitor.mRootOfClosedTree = IsClosed();
Packit f0b94e
  // Inform that we're about to exit the current scope.
Packit f0b94e
  aVisitor.mRelatedTargetRetargetedInCurrentScope = false;
Packit f0b94e
Packit f0b94e
  // https://dom.spec.whatwg.org/#ref-for-get-the-parent%E2%91%A6
Packit f0b94e
  if (!aVisitor.mEvent->mFlags.mComposed) {
Packit f0b94e
    nsCOMPtr<nsIContent> originalTarget =
Packit f0b94e
        do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
Packit f0b94e
    if (originalTarget->GetContainingShadow() == this) {
Packit f0b94e
      // If we do stop propagation, we still want to propagate
Packit f0b94e
      // the event to chrome (nsPIDOMWindow::GetParentTarget()).
Packit f0b94e
      // The load event is special in that we don't ever propagate it
Packit f0b94e
      // to chrome.
Packit f0b94e
      nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
Packit f0b94e
      EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
Packit f0b94e
                                      ? win->GetParentTarget()
Packit f0b94e
                                      : nullptr;
Packit f0b94e
Packit f0b94e
      aVisitor.SetParentTarget(parentTarget, true);
Packit f0b94e
      return NS_OK;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsIContent* shadowHost = GetHost();
Packit f0b94e
  aVisitor.SetParentTarget(shadowHost, false);
Packit f0b94e
Packit f0b94e
  nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->mTarget));
Packit f0b94e
  if (content && content->GetBindingParent() == shadowHost) {
Packit f0b94e
    aVisitor.mEventTargetAtParent = shadowHost;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
const HTMLSlotElement* ShadowRoot::AssignSlotFor(nsIContent* aContent) {
Packit f0b94e
  nsAutoString slotName;
Packit f0b94e
  // Note that if slot attribute is missing, assign it to the first default
Packit f0b94e
  // slot, if exists.
Packit f0b94e
  if (aContent->IsElement()) {
Packit f0b94e
    aContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::slot,
Packit f0b94e
                                   slotName);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsTArray<HTMLSlotElement*>* slots = mSlotMap.Get(slotName);
Packit f0b94e
  if (!slots) {
Packit f0b94e
    return nullptr;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  HTMLSlotElement* slot = slots->ElementAt(0);
Packit f0b94e
  MOZ_ASSERT(slot);
Packit f0b94e
Packit f0b94e
  // Find the appropriate position in the assigned node list for the
Packit f0b94e
  // newly assigned content.
Packit f0b94e
  const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
Packit f0b94e
  nsIContent* currentContent = GetHost()->GetFirstChild();
Packit f0b94e
  Maybe<uint32_t> insertionIndex;
Packit f0b94e
  for (uint32_t i = 0; i < assignedNodes.Length(); i++) {
Packit f0b94e
    // Seek through the host's explicit children until the
Packit f0b94e
    // assigned content is found.
Packit f0b94e
    while (currentContent && currentContent != assignedNodes[i]) {
Packit f0b94e
      if (currentContent == aContent) {
Packit f0b94e
        insertionIndex.emplace(i);
Packit f0b94e
        break;
Packit f0b94e
      }
Packit f0b94e
Packit f0b94e
      currentContent = currentContent->GetNextSibling();
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    if (insertionIndex) {
Packit f0b94e
      break;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (insertionIndex) {
Packit f0b94e
    slot->InsertAssignedNode(*insertionIndex, aContent);
Packit f0b94e
  } else {
Packit f0b94e
    slot->AppendAssignedNode(aContent);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return slot;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
const HTMLSlotElement* ShadowRoot::UnassignSlotFor(nsIContent* aNode,
Packit f0b94e
                                                   const nsAString& aSlotName) {
Packit f0b94e
  // Find the insertion point to which the content belongs. Note that if slot
Packit f0b94e
  // attribute is missing, unassign it from the first default slot, if exists.
Packit f0b94e
  nsTArray<HTMLSlotElement*>* slots = mSlotMap.Get(aSlotName);
Packit f0b94e
  if (!slots) {
Packit f0b94e
    return nullptr;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  HTMLSlotElement* slot = slots->ElementAt(0);
Packit f0b94e
  MOZ_ASSERT(slot);
Packit f0b94e
Packit f0b94e
  if (!slot->AssignedNodes().Contains(aNode)) {
Packit f0b94e
    return nullptr;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  slot->RemoveAssignedNode(aNode);
Packit f0b94e
  return slot;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
bool ShadowRoot::MaybeReassignElement(Element* aElement,
Packit f0b94e
                                      const nsAttrValue* aOldValue) {
Packit f0b94e
  nsIContent* parent = aElement->GetParent();
Packit f0b94e
  if (parent && parent == GetHost()) {
Packit f0b94e
    const HTMLSlotElement* oldSlot = UnassignSlotFor(
Packit f0b94e
        aElement, aOldValue ? aOldValue->GetStringValue() : EmptyString());
Packit f0b94e
    const HTMLSlotElement* newSlot = AssignSlotFor(aElement);
Packit f0b94e
Packit f0b94e
    if (oldSlot != newSlot) {
Packit f0b94e
      if (oldSlot) {
Packit f0b94e
        oldSlot->EnqueueSlotChangeEvent();
Packit f0b94e
      }
Packit f0b94e
      if (newSlot) {
Packit f0b94e
        newSlot->EnqueueSlotChangeEvent();
Packit f0b94e
      }
Packit f0b94e
      return true;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return false;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
Element* ShadowRoot::GetActiveElement() {
Packit f0b94e
  return GetRetargetedFocusedElement();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ShadowRoot::GetInnerHTML(nsAString& aInnerHTML) {
Packit f0b94e
  GetMarkup(false, aInnerHTML);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ShadowRoot::SetInnerHTML(const nsAString& aInnerHTML,
Packit f0b94e
                              ErrorResult& aError) {
Packit f0b94e
  SetInnerHTMLInternal(aInnerHTML, aError);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ShadowRoot::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
Packit f0b94e
                                  nsAtom* aAttribute, int32_t aModType,
Packit f0b94e
                                  const nsAttrValue* aOldValue) {
Packit f0b94e
  if (aNameSpaceID != kNameSpaceID_None || aAttribute != nsGkAtoms::slot) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Attributes may change insertion point matching, find its new distribution.
Packit f0b94e
  if (!MaybeReassignElement(aElement, aOldValue)) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (!aElement->IsInComposedDoc()) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  auto* shell = OwnerDoc()->GetShell();
Packit f0b94e
  if (!shell) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // FIXME(emilio): We could be more granular in a bunch of cases.
Packit f0b94e
  shell->DestroyFramesForAndRestyle(aElement);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ShadowRoot::ContentAppended(nsIContent* aFirstNewContent) {
Packit f0b94e
  for (nsIContent* content = aFirstNewContent; content;
Packit f0b94e
       content = content->GetNextSibling()) {
Packit f0b94e
    ContentInserted(content);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ShadowRoot::ContentInserted(nsIContent* aChild) {
Packit f0b94e
  // Check to ensure that the child not an anonymous subtree root because
Packit f0b94e
  // even though its parent could be the host it may not be in the host's child
Packit f0b94e
  // list.
Packit f0b94e
  if (aChild->IsRootOfAnonymousSubtree()) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (!aChild->IsSlotable()) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (aChild->GetParent() == GetHost()) {
Packit f0b94e
    if (const HTMLSlotElement* slot = AssignSlotFor(aChild)) {
Packit f0b94e
      slot->EnqueueSlotChangeEvent();
Packit f0b94e
    }
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // If parent's root is a shadow root, and parent is a slot whose assigned
Packit f0b94e
  // nodes is the empty list, then run signal a slot change for parent.
Packit f0b94e
  HTMLSlotElement* slot =
Packit f0b94e
      HTMLSlotElement::FromContentOrNull(aChild->GetParent());
Packit f0b94e
  if (slot && slot->GetContainingShadow() == this &&
Packit f0b94e
      slot->AssignedNodes().IsEmpty()) {
Packit f0b94e
    slot->EnqueueSlotChangeEvent();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ShadowRoot::ContentRemoved(nsIContent* aChild,
Packit f0b94e
                                nsIContent* aPreviousSibling) {
Packit f0b94e
  // Check to ensure that the child not an anonymous subtree root because
Packit f0b94e
  // even though its parent could be the host it may not be in the host's child
Packit f0b94e
  // list.
Packit f0b94e
  if (aChild->IsRootOfAnonymousSubtree()) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (!aChild->IsSlotable()) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (aChild->GetParent() == GetHost()) {
Packit f0b94e
    nsAutoString slotName;
Packit f0b94e
    if (aChild->IsElement()) {
Packit f0b94e
      aChild->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::slot,
Packit f0b94e
                                   slotName);
Packit f0b94e
    }
Packit f0b94e
    if (const HTMLSlotElement* slot = UnassignSlotFor(aChild, slotName)) {
Packit f0b94e
      slot->EnqueueSlotChangeEvent();
Packit f0b94e
    }
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // If parent's root is a shadow root, and parent is a slot whose assigned
Packit f0b94e
  // nodes is the empty list, then run signal a slot change for parent.
Packit f0b94e
  HTMLSlotElement* slot =
Packit f0b94e
      HTMLSlotElement::FromContentOrNull(aChild->GetParent());
Packit f0b94e
  if (slot && slot->GetContainingShadow() == this &&
Packit f0b94e
      slot->AssignedNodes().IsEmpty()) {
Packit f0b94e
    slot->EnqueueSlotChangeEvent();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
ServoStyleRuleMap& ShadowRoot::ServoStyleRuleMap() {
Packit f0b94e
  if (!mStyleRuleMap) {
Packit f0b94e
    mStyleRuleMap = MakeUnique<mozilla::ServoStyleRuleMap>();
Packit f0b94e
  }
Packit f0b94e
  mStyleRuleMap->EnsureTable(*this);
Packit f0b94e
  return *mStyleRuleMap;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsresult ShadowRoot::Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
Packit f0b94e
                           bool aPreallocateChildren) const {
Packit f0b94e
  *aResult = nullptr;
Packit f0b94e
  return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
Packit f0b94e
}