gecko-dev/dom/base/ShadowRoot.cpp
Kirk Steuber 7fdb378650 Bug 1359556 - Optimize cloneNode by preinitializing attribute and child arrays r=bz
Currently, attribute and child arrays (implemented in dom/base/nsAttrAndChildArray.h) start out empty. When cloning, the array ends up being resized multiple times in order to add the attributes and children that are being cloned from the original node. This would be quicker if the array was initialized to the correct size in the first place so that resizes are not necessary.

However, preallocating space for children is only necessary when performing a deep clone. Therefore, an additional parameter is being added to the Clone, CopyInnerTo, and CloneDocHelper methods to indicate whether preallocation of children should happen. Attributes are copied either way, so that part of the array is preallocated in both cases.

MozReview-Commit-ID: 3iVezeAKXnI

--HG--
extra : rebase_source : 9c3deec6d7aafd6411044d623d4863637b45fd58
2017-04-20 12:57:48 -07:00

763 lines
24 KiB
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/. */
#include "mozilla/Preferences.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/ShadowRootBinding.h"
#include "mozilla/dom/DocumentFragment.h"
#include "ChildIterator.h"
#include "nsContentUtils.h"
#include "nsDOMClassInfoID.h"
#include "nsIDOMHTMLElement.h"
#include "nsIStyleSheetLinkingElement.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLContentElement.h"
#include "mozilla/dom/HTMLShadowElement.h"
#include "nsXBLPrototypeBinding.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
DocumentFragment)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPoolHost)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOlderShadow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mYoungerShadow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAssociatedBinding)
for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done();
iter.Next()) {
iter.Get()->Traverse(&cb);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ShadowRoot,
DocumentFragment)
if (tmp->mPoolHost) {
tmp->mPoolHost->RemoveMutationObserver(tmp);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPoolHost)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mStyleSheetList)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOlderShadow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mYoungerShadow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAssociatedBinding)
tmp->mIdentifierMap.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRoot)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
ShadowRoot::ShadowRoot(nsIContent* aContent,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
nsXBLPrototypeBinding* aProtoBinding)
: DocumentFragment(aNodeInfo), mPoolHost(aContent),
mProtoBinding(aProtoBinding), mShadowElement(nullptr),
mInsertionPointChanged(false), mIsComposedDocParticipant(false)
{
SetHost(aContent);
// Nodes in a shadow tree should never store a value
// in the subtree root pointer, nodes in the shadow tree
// track the subtree root using GetContainingShadow().
ClearSubtreeRootPointer();
SetFlags(NODE_IS_IN_SHADOW_TREE);
DOMSlots()->mBindingParent = aContent;
DOMSlots()->mContainingShadow = this;
// Add the ShadowRoot as a mutation observer on the host to watch
// for mutations because the insertion points in this ShadowRoot
// may need to be updated when the host children are modified.
mPoolHost->AddMutationObserver(this);
}
ShadowRoot::~ShadowRoot()
{
if (mPoolHost) {
// mPoolHost may have been unlinked or a new ShadowRoot may have been
// creating, making this one obsolete.
mPoolHost->RemoveMutationObserver(this);
}
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
// nsINode destructor expects mSubtreeRoot == this.
SetSubtreeRootPointer(this);
SetHost(nullptr);
}
JSObject*
ShadowRoot::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return mozilla::dom::ShadowRootBinding::Wrap(aCx, this, aGivenProto);
}
ShadowRoot*
ShadowRoot::FromNode(nsINode* aNode)
{
if (aNode->IsInShadowTree() && !aNode->GetParentNode()) {
MOZ_ASSERT(aNode->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE,
"ShadowRoot is a document fragment.");
return static_cast<ShadowRoot*>(aNode);
}
return nullptr;
}
void
ShadowRoot::StyleSheetChanged()
{
mProtoBinding->FlushSkinSheets();
nsIPresShell* shell = OwnerDoc()->GetShell();
if (shell) {
OwnerDoc()->BeginUpdate(UPDATE_STYLE);
shell->RecordShadowStyleChange(this);
OwnerDoc()->EndUpdate(UPDATE_STYLE);
}
}
void
ShadowRoot::InsertSheet(StyleSheet* aSheet,
nsIContent* aLinkingContent)
{
nsCOMPtr<nsIStyleSheetLinkingElement>
linkingElement = do_QueryInterface(aLinkingContent);
MOZ_ASSERT(linkingElement, "The only styles in a ShadowRoot should come "
"from <style>.");
linkingElement->SetStyleSheet(aSheet); // This sets the ownerNode on the sheet
// Find the correct position to insert into the style sheet list (must
// be in tree order).
for (size_t i = 0; i <= mProtoBinding->SheetCount(); i++) {
if (i == mProtoBinding->SheetCount()) {
mProtoBinding->AppendStyleSheet(aSheet);
break;
}
nsINode* sheetOwningNode = mProtoBinding->StyleSheetAt(i)->GetOwnerNode();
if (nsContentUtils::PositionIsBefore(aLinkingContent, sheetOwningNode)) {
mProtoBinding->InsertStyleSheetAt(i, aSheet);
break;
}
}
if (aSheet->IsApplicable()) {
StyleSheetChanged();
}
}
void
ShadowRoot::RemoveSheet(StyleSheet* aSheet)
{
mProtoBinding->RemoveStyleSheet(aSheet);
if (aSheet->IsApplicable()) {
StyleSheetChanged();
}
}
Element*
ShadowRoot::GetElementById(const nsAString& aElementId)
{
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
return entry ? entry->GetIdElement() : nullptr;
}
already_AddRefed<nsContentList>
ShadowRoot::GetElementsByTagName(const nsAString& aTagName)
{
return NS_GetContentList(this, kNameSpaceID_Unknown, aTagName);
}
already_AddRefed<nsContentList>
ShadowRoot::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName)
{
int32_t nameSpaceId = kNameSpaceID_Wildcard;
if (!aNamespaceURI.EqualsLiteral("*")) {
nsresult rv =
nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
nameSpaceId);
NS_ENSURE_SUCCESS(rv, nullptr);
}
NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
return NS_GetContentList(this, nameSpaceId, aLocalName);
}
void
ShadowRoot::AddToIdTable(Element* aElement, nsIAtom* aId)
{
nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aId);
if (entry) {
entry->AddIdElement(aElement);
}
}
void
ShadowRoot::RemoveFromIdTable(Element* aElement, nsIAtom* aId)
{
nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aId);
if (entry) {
entry->RemoveIdElement(aElement);
if (entry->IsEmpty()) {
mIdentifierMap.RemoveEntry(entry);
}
}
}
already_AddRefed<nsContentList>
ShadowRoot::GetElementsByClassName(const nsAString& aClasses)
{
return nsContentUtils::GetElementsByClassName(this, aClasses);
}
void
ShadowRoot::AddInsertionPoint(HTMLContentElement* aInsertionPoint)
{
TreeOrderComparator comparator;
mInsertionPoints.InsertElementSorted(aInsertionPoint, comparator);
}
void
ShadowRoot::RemoveInsertionPoint(HTMLContentElement* aInsertionPoint)
{
mInsertionPoints.RemoveElement(aInsertionPoint);
}
void
ShadowRoot::SetYoungerShadow(ShadowRoot* aYoungerShadow)
{
mYoungerShadow = aYoungerShadow;
mYoungerShadow->mOlderShadow = this;
ChangePoolHost(mYoungerShadow->GetShadowElement());
}
void
ShadowRoot::RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
nsTArray<nsIContent*>& aDestInsertionPoints)
{
// Remove the insertion point from the destination insertion points.
// Also remove all succeeding insertion points because it is no longer
// possible for the content to be distributed into deeper node trees.
int32_t index = aDestInsertionPoints.IndexOf(aInsertionPoint);
// It's possible that we already removed the insertion point while processing
// other insertion point removals.
if (index >= 0) {
aDestInsertionPoints.SetLength(index);
}
}
void
ShadowRoot::DistributeSingleNode(nsIContent* aContent)
{
// Find the insertion point to which the content belongs.
HTMLContentElement* insertionPoint = nullptr;
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
if (mInsertionPoints[i]->Match(aContent)) {
if (mInsertionPoints[i]->MatchedNodes().Contains(aContent)) {
// Node is already matched into the insertion point. We are done.
return;
}
// Matching may cause the insertion point to drop fallback content.
if (mInsertionPoints[i]->MatchedNodes().IsEmpty() &&
static_cast<nsINode*>(mInsertionPoints[i])->GetFirstChild()) {
// This match will cause the insertion point to drop all fallback
// content and used matched nodes instead. Give up on the optimization
// and just distribute all nodes.
DistributeAllNodes();
return;
}
insertionPoint = mInsertionPoints[i];
break;
}
}
// Find the index into the insertion point.
if (insertionPoint) {
nsCOMArray<nsIContent>& matchedNodes = insertionPoint->MatchedNodes();
// Find the appropriate position in the matched node list for the
// newly distributed content.
bool isIndexFound = false;
MOZ_ASSERT(mPoolHost, "Where did the content come from if there is no pool host?");
ExplicitChildIterator childIterator(mPoolHost);
for (uint32_t i = 0; i < matchedNodes.Length(); i++) {
// Seek through the host's explicit children until the inserted content
// is found or when the current matched node is reached.
if (childIterator.Seek(aContent, matchedNodes[i])) {
// aContent was found before the current matched node.
insertionPoint->InsertMatchedNode(i, aContent);
isIndexFound = true;
break;
}
}
if (!isIndexFound) {
// We have still not found an index in the insertion point,
// thus it must be at the end.
MOZ_ASSERT(childIterator.Seek(aContent, nullptr),
"Trying to match a node that is not a candidate to be matched");
insertionPoint->AppendMatchedNode(aContent);
}
// Handle the case where the parent of the insertion point is a ShadowRoot
// that is projected into the younger ShadowRoot's shadow insertion point.
// The node distributed into the insertion point must be reprojected
// to the shadow insertion point.
if (insertionPoint->GetParent() == this &&
mYoungerShadow && mYoungerShadow->GetShadowElement()) {
mYoungerShadow->GetShadowElement()->DistributeSingleNode(aContent);
}
// Handle the case where the parent of the insertion point has a ShadowRoot.
// The node distributed into the insertion point must be reprojected to the
// insertion points of the parent's ShadowRoot.
ShadowRoot* parentShadow = insertionPoint->GetParent()->GetShadowRoot();
if (parentShadow) {
parentShadow->DistributeSingleNode(aContent);
}
// Handle the case where the parent of the insertion point is the <shadow>
// element. The node distributed into the insertion point must be reprojected
// into the older ShadowRoot's insertion points.
if (mShadowElement && mShadowElement == insertionPoint->GetParent()) {
ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
if (olderShadow) {
olderShadow->DistributeSingleNode(aContent);
}
}
}
}
void
ShadowRoot::RemoveDistributedNode(nsIContent* aContent)
{
// Find insertion point containing the content and remove the node.
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
if (mInsertionPoints[i]->MatchedNodes().Contains(aContent)) {
// Removing the matched node may cause the insertion point to use
// fallback content.
if (mInsertionPoints[i]->MatchedNodes().Length() == 1 &&
static_cast<nsINode*>(mInsertionPoints[i])->GetFirstChild()) {
// Removing the matched node will cause fallback content to be
// used instead. Give up optimization and distribute all nodes.
DistributeAllNodes();
return;
}
mInsertionPoints[i]->RemoveMatchedNode(aContent);
// Handle the case where the parent of the insertion point is a ShadowRoot
// that is projected into the younger ShadowRoot's shadow insertion point.
// The removed node needs to be removed from the shadow insertion point.
if (mInsertionPoints[i]->GetParent() == this) {
if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
mYoungerShadow->GetShadowElement()->RemoveDistributedNode(aContent);
}
}
// Handle the case where the parent of the insertion point has a ShadowRoot.
// The removed node needs to be removed from the insertion points of the
// parent's ShadowRoot.
ShadowRoot* parentShadow = mInsertionPoints[i]->GetParent()->GetShadowRoot();
if (parentShadow) {
parentShadow->RemoveDistributedNode(aContent);
}
// Handle the case where the parent of the insertion point is the <shadow>
// element. The removed node must be removed from the older ShadowRoot's
// insertion points.
if (mShadowElement && mShadowElement == mInsertionPoints[i]->GetParent()) {
ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
if (olderShadow) {
olderShadow->RemoveDistributedNode(aContent);
}
}
break;
}
}
}
void
ShadowRoot::DistributeAllNodes()
{
// Create node pool.
nsTArray<nsIContent*> nodePool;
// Make sure there is a pool host, an older shadow may not have
// one if the younger shadow does not have a <shadow> element.
if (mPoolHost) {
ExplicitChildIterator childIterator(mPoolHost);
for (nsIContent* content = childIterator.GetNextChild();
content;
content = childIterator.GetNextChild()) {
nodePool.AppendElement(content);
}
}
nsTArray<ShadowRoot*> shadowsToUpdate;
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
mInsertionPoints[i]->ClearMatchedNodes();
// Assign matching nodes from node pool.
for (uint32_t j = 0; j < nodePool.Length(); j++) {
if (mInsertionPoints[i]->Match(nodePool[j])) {
mInsertionPoints[i]->AppendMatchedNode(nodePool[j]);
nodePool.RemoveElementAt(j--);
}
}
// Keep track of instances where the content insertion point is distributed
// (parent of insertion point has a ShadowRoot).
nsIContent* insertionParent = mInsertionPoints[i]->GetParent();
MOZ_ASSERT(insertionParent, "The only way for an insertion point to be in the"
"mInsertionPoints array is to be a descendant of a"
"ShadowRoot, in which case, it should have a parent");
// If the parent of the insertion point has a ShadowRoot, the nodes distributed
// to the insertion point must be reprojected to the insertion points of the
// parent's ShadowRoot.
ShadowRoot* parentShadow = insertionParent->GetShadowRoot();
if (parentShadow && !shadowsToUpdate.Contains(parentShadow)) {
shadowsToUpdate.AppendElement(parentShadow);
}
}
// If there is a shadow insertion point in this ShadowRoot, the children
// of the shadow insertion point needs to be distributed into the insertion
// points of the older ShadowRoot.
if (mShadowElement && mOlderShadow) {
mOlderShadow->DistributeAllNodes();
}
// If there is a younger ShadowRoot with a shadow insertion point,
// then the children of this ShadowRoot needs to be distributed to
// the younger ShadowRoot's shadow insertion point.
if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
mYoungerShadow->GetShadowElement()->DistributeAllNodes();
}
for (uint32_t i = 0; i < shadowsToUpdate.Length(); i++) {
shadowsToUpdate[i]->DistributeAllNodes();
}
}
void
ShadowRoot::GetInnerHTML(nsAString& aInnerHTML)
{
GetMarkup(false, aInnerHTML);
}
void
ShadowRoot::SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError)
{
SetInnerHTMLInternal(aInnerHTML, aError);
}
Element*
ShadowRoot::Host()
{
nsIContent* host = GetHost();
MOZ_ASSERT(host && host->IsElement(),
"ShadowRoot host should always be an element, "
"how else did we create this ShadowRoot?");
return host->AsElement();
}
bool
ShadowRoot::ApplyAuthorStyles()
{
return mProtoBinding->InheritsStyle();
}
void
ShadowRoot::SetApplyAuthorStyles(bool aApplyAuthorStyles)
{
mProtoBinding->SetInheritsStyle(aApplyAuthorStyles);
nsIPresShell* shell = OwnerDoc()->GetShell();
if (shell) {
OwnerDoc()->BeginUpdate(UPDATE_STYLE);
shell->RecordShadowStyleChange(this);
OwnerDoc()->EndUpdate(UPDATE_STYLE);
}
}
StyleSheetList*
ShadowRoot::StyleSheets()
{
if (!mStyleSheetList) {
mStyleSheetList = new ShadowRootStyleSheetList(this);
}
return mStyleSheetList;
}
void
ShadowRoot::SetShadowElement(HTMLShadowElement* aShadowElement)
{
// If there is already a shadow element point, remove
// the projected shadow because it is no longer an insertion
// point.
if (mShadowElement) {
mShadowElement->SetProjectedShadow(nullptr);
}
if (mOlderShadow) {
// Nodes for distribution will come from the new shadow element.
mOlderShadow->ChangePoolHost(aShadowElement);
}
// Set the new shadow element to project the older ShadowRoot because
// it is the current shadow insertion point.
mShadowElement = aShadowElement;
if (mShadowElement) {
mShadowElement->SetProjectedShadow(mOlderShadow);
}
}
void
ShadowRoot::ChangePoolHost(nsIContent* aNewHost)
{
if (mPoolHost) {
mPoolHost->RemoveMutationObserver(this);
}
// Clear the nodes matched to content insertion points
// because it is no longer relevant.
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
mInsertionPoints[i]->ClearMatchedNodes();
}
mPoolHost = aNewHost;
if (mPoolHost) {
mPoolHost->AddMutationObserver(this);
}
}
bool
ShadowRoot::IsShadowInsertionPoint(nsIContent* aContent)
{
if (!aContent) {
return false;
}
HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(aContent);
return shadowElem && shadowElem->IsInsertionPoint();
}
/**
* Returns whether the web components pool population algorithm
* on the host would contain |aContent|. This function ignores
* insertion points in the pool, thus should only be used to
* test nodes that have not yet been distributed.
*/
bool
ShadowRoot::IsPooledNode(nsIContent* aContent, nsIContent* aContainer,
nsIContent* aHost)
{
if (nsContentUtils::IsContentInsertionPoint(aContent) ||
IsShadowInsertionPoint(aContent)) {
// Insertion points never end up in the pool.
return false;
}
if (aContainer == aHost &&
nsContentUtils::IsInSameAnonymousTree(aContainer, aContent)) {
// Children of the host will end up in the pool. We check to ensure
// that the content is in the same anonymous tree as the container
// because anonymous content may report its container as the host
// but it may not be in the host's child list.
return true;
}
if (aContainer) {
// Fallback content will end up in pool if its parent is a child of the host.
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
return content && content->IsInsertionPoint() &&
content->MatchedNodes().IsEmpty() &&
aContainer->GetParentNode() == aHost;
}
return false;
}
void
ShadowRoot::AttributeChanged(nsIDocument* aDocument,
Element* aElement,
int32_t aNameSpaceID,
nsIAtom* aAttribute,
int32_t aModType,
const nsAttrValue* aOldValue)
{
if (!IsPooledNode(aElement, aElement->GetParent(), mPoolHost)) {
return;
}
// Attributes may change insertion point matching, find its new distribution.
RemoveDistributedNode(aElement);
DistributeSingleNode(aElement);
}
void
ShadowRoot::ContentAppended(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aFirstNewContent,
int32_t aNewIndexInContainer)
{
if (mInsertionPointChanged) {
DistributeAllNodes();
mInsertionPointChanged = false;
return;
}
// Watch for new nodes added to the pool because the node
// may need to be added to an insertion point.
nsIContent* currentChild = aFirstNewContent;
while (currentChild) {
// Add insertion point to destination insertion points of fallback content.
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
if (content->MatchedNodes().IsEmpty()) {
currentChild->DestInsertionPoints().AppendElement(aContainer);
}
}
if (IsPooledNode(currentChild, aContainer, mPoolHost)) {
DistributeSingleNode(currentChild);
}
currentChild = currentChild->GetNextSibling();
}
}
void
ShadowRoot::ContentInserted(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aChild,
int32_t aIndexInContainer)
{
if (mInsertionPointChanged) {
DistributeAllNodes();
mInsertionPointChanged = false;
return;
}
// Watch for new nodes added to the pool because the node
// may need to be added to an insertion point.
if (IsPooledNode(aChild, aContainer, mPoolHost)) {
// Add insertion point to destination insertion points of fallback content.
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
if (content->MatchedNodes().IsEmpty()) {
aChild->DestInsertionPoints().AppendElement(aContainer);
}
}
DistributeSingleNode(aChild);
}
}
void
ShadowRoot::ContentRemoved(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aChild,
int32_t aIndexInContainer,
nsIContent* aPreviousSibling)
{
if (mInsertionPointChanged) {
DistributeAllNodes();
mInsertionPointChanged = false;
return;
}
// Clear destination insertion points for removed
// fallback content.
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
if (content->MatchedNodes().IsEmpty()) {
aChild->DestInsertionPoints().Clear();
}
}
// Watch for node that is removed from the pool because
// it may need to be removed from an insertion point.
if (IsPooledNode(aChild, aContainer, mPoolHost)) {
RemoveDistributedNode(aChild);
}
}
nsresult
ShadowRoot::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const
{
*aResult = nullptr;
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
void
ShadowRoot::DestroyContent()
{
if (mOlderShadow) {
mOlderShadow->DestroyContent();
}
DocumentFragment::DestroyContent();
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList, StyleSheetList,
mShadowRoot)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList)
NS_INTERFACE_MAP_END_INHERITING(StyleSheetList)
NS_IMPL_ADDREF_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
NS_IMPL_RELEASE_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
ShadowRootStyleSheetList::ShadowRootStyleSheetList(ShadowRoot* aShadowRoot)
: mShadowRoot(aShadowRoot)
{
}
ShadowRootStyleSheetList::~ShadowRootStyleSheetList()
{
}
StyleSheet*
ShadowRootStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
{
aFound = aIndex < mShadowRoot->mProtoBinding->SheetCount();
if (!aFound) {
return nullptr;
}
return mShadowRoot->mProtoBinding->StyleSheetAt(aIndex);
}
uint32_t
ShadowRootStyleSheetList::Length()
{
return mShadowRoot->mProtoBinding->SheetCount();
}