LCOV - code coverage report
Current view: top level - dom/base - ShadowRoot.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 7 328 2.1 %
Date: 2017-07-14 16:53:18 Functions: 2 52 3.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/Preferences.h"
       8             : #include "mozilla/dom/ShadowRoot.h"
       9             : #include "mozilla/dom/ShadowRootBinding.h"
      10             : #include "mozilla/dom/DocumentFragment.h"
      11             : #include "ChildIterator.h"
      12             : #include "nsContentUtils.h"
      13             : #include "nsDOMClassInfoID.h"
      14             : #include "nsIDOMHTMLElement.h"
      15             : #include "nsIStyleSheetLinkingElement.h"
      16             : #include "mozilla/dom/Element.h"
      17             : #include "mozilla/dom/HTMLContentElement.h"
      18             : #include "mozilla/dom/HTMLShadowElement.h"
      19             : #include "nsXBLPrototypeBinding.h"
      20             : #include "mozilla/StyleSheet.h"
      21             : #include "mozilla/StyleSheetInlines.h"
      22             : 
      23             : using namespace mozilla;
      24             : using namespace mozilla::dom;
      25             : 
      26             : NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
      27             : 
      28           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
      29             :                                                   DocumentFragment)
      30           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPoolHost)
      31           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetList)
      32           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOlderShadow)
      33           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mYoungerShadow)
      34           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAssociatedBinding)
      35           0 :   for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done();
      36           0 :        iter.Next()) {
      37           0 :     iter.Get()->Traverse(&cb);
      38             :   }
      39           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      40             : 
      41           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ShadowRoot,
      42             :                                                 DocumentFragment)
      43           0 :   if (tmp->mPoolHost) {
      44           0 :     tmp->mPoolHost->RemoveMutationObserver(tmp);
      45             :   }
      46           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPoolHost)
      47           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mStyleSheetList)
      48           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOlderShadow)
      49           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mYoungerShadow)
      50           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAssociatedBinding)
      51           0 :   tmp->mIdentifierMap.Clear();
      52           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      53             : 
      54           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRoot)
      55           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
      56           0 :   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
      57           0 : NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
      58             : 
      59           0 : NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
      60           0 : NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
      61             : 
      62           0 : ShadowRoot::ShadowRoot(nsIContent* aContent,
      63             :                        already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
      64           0 :                        nsXBLPrototypeBinding* aProtoBinding)
      65             :   : DocumentFragment(aNodeInfo), mPoolHost(aContent),
      66             :     mProtoBinding(aProtoBinding), mShadowElement(nullptr),
      67           0 :     mInsertionPointChanged(false), mIsComposedDocParticipant(false)
      68             : {
      69           0 :   SetHost(aContent);
      70             : 
      71             :   // Nodes in a shadow tree should never store a value
      72             :   // in the subtree root pointer, nodes in the shadow tree
      73             :   // track the subtree root using GetContainingShadow().
      74           0 :   ClearSubtreeRootPointer();
      75             : 
      76           0 :   SetFlags(NODE_IS_IN_SHADOW_TREE);
      77             : 
      78           0 :   DOMSlots()->mBindingParent = aContent;
      79           0 :   DOMSlots()->mContainingShadow = this;
      80             : 
      81             :   // Add the ShadowRoot as a mutation observer on the host to watch
      82             :   // for mutations because the insertion points in this ShadowRoot
      83             :   // may need to be updated when the host children are modified.
      84           0 :   mPoolHost->AddMutationObserver(this);
      85           0 : }
      86             : 
      87           0 : ShadowRoot::~ShadowRoot()
      88             : {
      89           0 :   if (mPoolHost) {
      90             :     // mPoolHost may have been unlinked or a new ShadowRoot may have been
      91             :     // creating, making this one obsolete.
      92           0 :     mPoolHost->RemoveMutationObserver(this);
      93             :   }
      94             : 
      95           0 :   UnsetFlags(NODE_IS_IN_SHADOW_TREE);
      96             : 
      97             :   // nsINode destructor expects mSubtreeRoot == this.
      98           0 :   SetSubtreeRootPointer(this);
      99             : 
     100           0 :   SetHost(nullptr);
     101           0 : }
     102             : 
     103             : JSObject*
     104           0 : ShadowRoot::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     105             : {
     106           0 :   return mozilla::dom::ShadowRootBinding::Wrap(aCx, this, aGivenProto);
     107             : }
     108             : 
     109             : ShadowRoot*
     110      156964 : ShadowRoot::FromNode(nsINode* aNode)
     111             : {
     112      156964 :   if (aNode->IsInShadowTree() && !aNode->GetParentNode()) {
     113           0 :     MOZ_ASSERT(aNode->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE,
     114             :                "ShadowRoot is a document fragment.");
     115           0 :     return static_cast<ShadowRoot*>(aNode);
     116             :   }
     117             : 
     118      156964 :   return nullptr;
     119             : }
     120             : 
     121             : void
     122           0 : ShadowRoot::StyleSheetChanged()
     123             : {
     124           0 :   mProtoBinding->FlushSkinSheets();
     125             : 
     126           0 :   nsIPresShell* shell = OwnerDoc()->GetShell();
     127           0 :   if (shell) {
     128           0 :     OwnerDoc()->BeginUpdate(UPDATE_STYLE);
     129           0 :     shell->RecordShadowStyleChange(this);
     130           0 :     OwnerDoc()->EndUpdate(UPDATE_STYLE);
     131             :   }
     132           0 : }
     133             : 
     134             : void
     135           0 : ShadowRoot::InsertSheet(StyleSheet* aSheet,
     136             :                         nsIContent* aLinkingContent)
     137             : {
     138             :   nsCOMPtr<nsIStyleSheetLinkingElement>
     139           0 :     linkingElement = do_QueryInterface(aLinkingContent);
     140           0 :   MOZ_ASSERT(linkingElement, "The only styles in a ShadowRoot should come "
     141             :                              "from <style>.");
     142             : 
     143           0 :   linkingElement->SetStyleSheet(aSheet); // This sets the ownerNode on the sheet
     144             : 
     145             :   // Find the correct position to insert into the style sheet list (must
     146             :   // be in tree order).
     147           0 :   for (size_t i = 0; i <= mProtoBinding->SheetCount(); i++) {
     148           0 :     if (i == mProtoBinding->SheetCount()) {
     149           0 :       mProtoBinding->AppendStyleSheet(aSheet);
     150           0 :       break;
     151             :     }
     152             : 
     153           0 :     nsINode* sheetOwningNode = mProtoBinding->StyleSheetAt(i)->GetOwnerNode();
     154           0 :     if (nsContentUtils::PositionIsBefore(aLinkingContent, sheetOwningNode)) {
     155           0 :       mProtoBinding->InsertStyleSheetAt(i, aSheet);
     156           0 :       break;
     157             :     }
     158             :   }
     159             : 
     160           0 :   if (aSheet->IsApplicable()) {
     161           0 :     StyleSheetChanged();
     162             :   }
     163           0 : }
     164             : 
     165             : void
     166           0 : ShadowRoot::RemoveSheet(StyleSheet* aSheet)
     167             : {
     168           0 :   mProtoBinding->RemoveStyleSheet(aSheet);
     169             : 
     170           0 :   if (aSheet->IsApplicable()) {
     171           0 :     StyleSheetChanged();
     172             :   }
     173           0 : }
     174             : 
     175             : Element*
     176           0 : ShadowRoot::GetElementById(const nsAString& aElementId)
     177             : {
     178           0 :   nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
     179           0 :   return entry ? entry->GetIdElement() : nullptr;
     180             : }
     181             : 
     182             : already_AddRefed<nsContentList>
     183           0 : ShadowRoot::GetElementsByTagName(const nsAString& aTagName)
     184             : {
     185           0 :   return NS_GetContentList(this, kNameSpaceID_Unknown, aTagName);
     186             : }
     187             : 
     188             : already_AddRefed<nsContentList>
     189           0 : ShadowRoot::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
     190             :                                    const nsAString& aLocalName)
     191             : {
     192           0 :   int32_t nameSpaceId = kNameSpaceID_Wildcard;
     193             : 
     194           0 :   if (!aNamespaceURI.EqualsLiteral("*")) {
     195             :     nsresult rv =
     196           0 :       nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
     197           0 :                                                             nameSpaceId);
     198           0 :     NS_ENSURE_SUCCESS(rv, nullptr);
     199             :   }
     200             : 
     201           0 :   NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
     202             : 
     203           0 :   return NS_GetContentList(this, nameSpaceId, aLocalName);
     204             : }
     205             : 
     206             : void
     207           0 : ShadowRoot::AddToIdTable(Element* aElement, nsIAtom* aId)
     208             : {
     209           0 :   nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aId);
     210           0 :   if (entry) {
     211           0 :     entry->AddIdElement(aElement);
     212             :   }
     213           0 : }
     214             : 
     215             : void
     216           0 : ShadowRoot::RemoveFromIdTable(Element* aElement, nsIAtom* aId)
     217             : {
     218           0 :   nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aId);
     219           0 :   if (entry) {
     220           0 :     entry->RemoveIdElement(aElement);
     221           0 :     if (entry->IsEmpty()) {
     222           0 :       mIdentifierMap.RemoveEntry(entry);
     223             :     }
     224             :   }
     225           0 : }
     226             : 
     227             : already_AddRefed<nsContentList>
     228           0 : ShadowRoot::GetElementsByClassName(const nsAString& aClasses)
     229             : {
     230           0 :   return nsContentUtils::GetElementsByClassName(this, aClasses);
     231             : }
     232             : 
     233             : void
     234           0 : ShadowRoot::AddInsertionPoint(HTMLContentElement* aInsertionPoint)
     235             : {
     236             :   TreeOrderComparator comparator;
     237           0 :   mInsertionPoints.InsertElementSorted(aInsertionPoint, comparator);
     238           0 : }
     239             : 
     240             : void
     241           0 : ShadowRoot::RemoveInsertionPoint(HTMLContentElement* aInsertionPoint)
     242             : {
     243           0 :   mInsertionPoints.RemoveElement(aInsertionPoint);
     244           0 : }
     245             : 
     246             : void
     247           0 : ShadowRoot::SetYoungerShadow(ShadowRoot* aYoungerShadow)
     248             : {
     249           0 :   mYoungerShadow = aYoungerShadow;
     250           0 :   mYoungerShadow->mOlderShadow = this;
     251             : 
     252           0 :   ChangePoolHost(mYoungerShadow->GetShadowElement());
     253           0 : }
     254             : 
     255             : void
     256           0 : ShadowRoot::RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
     257             :                                      nsTArray<nsIContent*>& aDestInsertionPoints)
     258             : {
     259             :   // Remove the insertion point from the destination insertion points.
     260             :   // Also remove all succeeding insertion points because it is no longer
     261             :   // possible for the content to be distributed into deeper node trees.
     262           0 :   int32_t index = aDestInsertionPoints.IndexOf(aInsertionPoint);
     263             : 
     264             :   // It's possible that we already removed the insertion point while processing
     265             :   // other insertion point removals.
     266           0 :   if (index >= 0) {
     267           0 :     aDestInsertionPoints.SetLength(index);
     268             :   }
     269           0 : }
     270             : 
     271             : void
     272           0 : ShadowRoot::DistributeSingleNode(nsIContent* aContent)
     273             : {
     274             :   // Find the insertion point to which the content belongs.
     275           0 :   HTMLContentElement* insertionPoint = nullptr;
     276           0 :   for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
     277           0 :     if (mInsertionPoints[i]->Match(aContent)) {
     278           0 :       if (mInsertionPoints[i]->MatchedNodes().Contains(aContent)) {
     279             :         // Node is already matched into the insertion point. We are done.
     280           0 :         return;
     281             :       }
     282             : 
     283             :       // Matching may cause the insertion point to drop fallback content.
     284           0 :       if (mInsertionPoints[i]->MatchedNodes().IsEmpty() &&
     285           0 :           static_cast<nsINode*>(mInsertionPoints[i])->GetFirstChild()) {
     286             :         // This match will cause the insertion point to drop all fallback
     287             :         // content and used matched nodes instead. Give up on the optimization
     288             :         // and just distribute all nodes.
     289           0 :         DistributeAllNodes();
     290           0 :         return;
     291             :       }
     292           0 :       insertionPoint = mInsertionPoints[i];
     293           0 :       break;
     294             :     }
     295             :   }
     296             : 
     297             :   // Find the index into the insertion point.
     298           0 :   if (insertionPoint) {
     299           0 :     nsCOMArray<nsIContent>& matchedNodes = insertionPoint->MatchedNodes();
     300             :     // Find the appropriate position in the matched node list for the
     301             :     // newly distributed content.
     302           0 :     bool isIndexFound = false;
     303           0 :     MOZ_ASSERT(mPoolHost, "Where did the content come from if there is no pool host?");
     304           0 :     ExplicitChildIterator childIterator(mPoolHost);
     305           0 :     for (uint32_t i = 0; i < matchedNodes.Length(); i++) {
     306             :       // Seek through the host's explicit children until the inserted content
     307             :       // is found or when the current matched node is reached.
     308           0 :       if (childIterator.Seek(aContent, matchedNodes[i])) {
     309             :         // aContent was found before the current matched node.
     310           0 :         insertionPoint->InsertMatchedNode(i, aContent);
     311           0 :         isIndexFound = true;
     312           0 :         break;
     313             :       }
     314             :     }
     315             : 
     316           0 :     if (!isIndexFound) {
     317             :       // We have still not found an index in the insertion point,
     318             :       // thus it must be at the end.
     319           0 :       MOZ_ASSERT(childIterator.Seek(aContent, nullptr),
     320             :                  "Trying to match a node that is not a candidate to be matched");
     321           0 :       insertionPoint->AppendMatchedNode(aContent);
     322             :     }
     323             : 
     324             :     // Handle the case where the parent of the insertion point is a ShadowRoot
     325             :     // that is projected into the younger ShadowRoot's shadow insertion point.
     326             :     // The node distributed into the insertion point must be reprojected
     327             :     // to the shadow insertion point.
     328           0 :     if (insertionPoint->GetParent() == this &&
     329           0 :         mYoungerShadow && mYoungerShadow->GetShadowElement()) {
     330           0 :       mYoungerShadow->GetShadowElement()->DistributeSingleNode(aContent);
     331             :     }
     332             : 
     333             :     // Handle the case where the parent of the insertion point has a ShadowRoot.
     334             :     // The node distributed into the insertion point must be reprojected to the
     335             :     // insertion points of the parent's ShadowRoot.
     336           0 :     ShadowRoot* parentShadow = insertionPoint->GetParent()->GetShadowRoot();
     337           0 :     if (parentShadow) {
     338           0 :       parentShadow->DistributeSingleNode(aContent);
     339             :     }
     340             : 
     341             :     // Handle the case where the parent of the insertion point is the <shadow>
     342             :     // element. The node distributed into the insertion point must be reprojected
     343             :     // into the older ShadowRoot's insertion points.
     344           0 :     if (mShadowElement && mShadowElement == insertionPoint->GetParent()) {
     345           0 :       ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
     346           0 :       if (olderShadow) {
     347           0 :         olderShadow->DistributeSingleNode(aContent);
     348             :       }
     349             :     }
     350             :   }
     351             : }
     352             : 
     353             : void
     354           0 : ShadowRoot::RemoveDistributedNode(nsIContent* aContent)
     355             : {
     356             :   // Find insertion point containing the content and remove the node.
     357           0 :   for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
     358           0 :     if (mInsertionPoints[i]->MatchedNodes().Contains(aContent)) {
     359             :       // Removing the matched node may cause the insertion point to use
     360             :       // fallback content.
     361           0 :       if (mInsertionPoints[i]->MatchedNodes().Length() == 1 &&
     362           0 :           static_cast<nsINode*>(mInsertionPoints[i])->GetFirstChild()) {
     363             :         // Removing the matched node will cause fallback content to be
     364             :         // used instead. Give up optimization and distribute all nodes.
     365           0 :         DistributeAllNodes();
     366           0 :         return;
     367             :       }
     368             : 
     369           0 :       mInsertionPoints[i]->RemoveMatchedNode(aContent);
     370             : 
     371             :       // Handle the case where the parent of the insertion point is a ShadowRoot
     372             :       // that is projected into the younger ShadowRoot's shadow insertion point.
     373             :       // The removed node needs to be removed from the shadow insertion point.
     374           0 :       if (mInsertionPoints[i]->GetParent() == this) {
     375           0 :         if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
     376           0 :           mYoungerShadow->GetShadowElement()->RemoveDistributedNode(aContent);
     377             :         }
     378             :       }
     379             : 
     380             :       // Handle the case where the parent of the insertion point has a ShadowRoot.
     381             :       // The removed node needs to be removed from the insertion points of the
     382             :       // parent's ShadowRoot.
     383           0 :       ShadowRoot* parentShadow = mInsertionPoints[i]->GetParent()->GetShadowRoot();
     384           0 :       if (parentShadow) {
     385           0 :         parentShadow->RemoveDistributedNode(aContent);
     386             :       }
     387             : 
     388             :       // Handle the case where the parent of the insertion point is the <shadow>
     389             :       // element. The removed node must be removed from the older ShadowRoot's
     390             :       // insertion points.
     391           0 :       if (mShadowElement && mShadowElement == mInsertionPoints[i]->GetParent()) {
     392           0 :         ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
     393           0 :         if (olderShadow) {
     394           0 :           olderShadow->RemoveDistributedNode(aContent);
     395             :         }
     396             :       }
     397             : 
     398           0 :       break;
     399             :     }
     400             :   }
     401             : }
     402             : 
     403             : void
     404           0 : ShadowRoot::DistributeAllNodes()
     405             : {
     406             :   // Create node pool.
     407           0 :   nsTArray<nsIContent*> nodePool;
     408             : 
     409             :   // Make sure there is a pool host, an older shadow may not have
     410             :   // one if the younger shadow does not have a <shadow> element.
     411           0 :   if (mPoolHost) {
     412           0 :     ExplicitChildIterator childIterator(mPoolHost);
     413           0 :     for (nsIContent* content = childIterator.GetNextChild();
     414           0 :          content;
     415           0 :          content = childIterator.GetNextChild()) {
     416           0 :       nodePool.AppendElement(content);
     417             :     }
     418             :   }
     419             : 
     420           0 :   nsTArray<ShadowRoot*> shadowsToUpdate;
     421             : 
     422           0 :   for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
     423           0 :     mInsertionPoints[i]->ClearMatchedNodes();
     424             :     // Assign matching nodes from node pool.
     425           0 :     for (uint32_t j = 0; j < nodePool.Length(); j++) {
     426           0 :       if (mInsertionPoints[i]->Match(nodePool[j])) {
     427           0 :         mInsertionPoints[i]->AppendMatchedNode(nodePool[j]);
     428           0 :         nodePool.RemoveElementAt(j--);
     429             :       }
     430             :     }
     431             : 
     432             :     // Keep track of instances where the content insertion point is distributed
     433             :     // (parent of insertion point has a ShadowRoot).
     434           0 :     nsIContent* insertionParent = mInsertionPoints[i]->GetParent();
     435           0 :     MOZ_ASSERT(insertionParent, "The only way for an insertion point to be in the"
     436             :                                 "mInsertionPoints array is to be a descendant of a"
     437             :                                 "ShadowRoot, in which case, it should have a parent");
     438             : 
     439             :     // If the parent of the insertion point has a ShadowRoot, the nodes distributed
     440             :     // to the insertion point must be reprojected to the insertion points of the
     441             :     // parent's ShadowRoot.
     442           0 :     ShadowRoot* parentShadow = insertionParent->GetShadowRoot();
     443           0 :     if (parentShadow && !shadowsToUpdate.Contains(parentShadow)) {
     444           0 :       shadowsToUpdate.AppendElement(parentShadow);
     445             :     }
     446             :   }
     447             : 
     448             :   // If there is a shadow insertion point in this ShadowRoot, the children
     449             :   // of the shadow insertion point needs to be distributed into the insertion
     450             :   // points of the older ShadowRoot.
     451           0 :   if (mShadowElement && mOlderShadow) {
     452           0 :     mOlderShadow->DistributeAllNodes();
     453             :   }
     454             : 
     455             :   // If there is a younger ShadowRoot with a shadow insertion point,
     456             :   // then the children of this ShadowRoot needs to be distributed to
     457             :   // the younger ShadowRoot's shadow insertion point.
     458           0 :   if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
     459           0 :     mYoungerShadow->GetShadowElement()->DistributeAllNodes();
     460             :   }
     461             : 
     462           0 :   for (uint32_t i = 0; i < shadowsToUpdate.Length(); i++) {
     463           0 :     shadowsToUpdate[i]->DistributeAllNodes();
     464             :   }
     465           0 : }
     466             : 
     467             : void
     468           0 : ShadowRoot::GetInnerHTML(nsAString& aInnerHTML)
     469             : {
     470           0 :   GetMarkup(false, aInnerHTML);
     471           0 : }
     472             : 
     473             : void
     474           0 : ShadowRoot::SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError)
     475             : {
     476           0 :   SetInnerHTMLInternal(aInnerHTML, aError);
     477           0 : }
     478             : 
     479             : Element*
     480           0 : ShadowRoot::Host()
     481             : {
     482           0 :   nsIContent* host = GetHost();
     483           0 :   MOZ_ASSERT(host && host->IsElement(),
     484             :              "ShadowRoot host should always be an element, "
     485             :              "how else did we create this ShadowRoot?");
     486           0 :   return host->AsElement();
     487             : }
     488             : 
     489             : bool
     490           0 : ShadowRoot::ApplyAuthorStyles()
     491             : {
     492           0 :   return mProtoBinding->InheritsStyle();
     493             : }
     494             : 
     495             : void
     496           0 : ShadowRoot::SetApplyAuthorStyles(bool aApplyAuthorStyles)
     497             : {
     498           0 :   mProtoBinding->SetInheritsStyle(aApplyAuthorStyles);
     499             : 
     500           0 :   nsIPresShell* shell = OwnerDoc()->GetShell();
     501           0 :   if (shell) {
     502           0 :     OwnerDoc()->BeginUpdate(UPDATE_STYLE);
     503           0 :     shell->RecordShadowStyleChange(this);
     504           0 :     OwnerDoc()->EndUpdate(UPDATE_STYLE);
     505             :   }
     506           0 : }
     507             : 
     508             : StyleSheetList*
     509           0 : ShadowRoot::StyleSheets()
     510             : {
     511           0 :   if (!mStyleSheetList) {
     512           0 :     mStyleSheetList = new ShadowRootStyleSheetList(this);
     513             :   }
     514             : 
     515           0 :   return mStyleSheetList;
     516             : }
     517             : 
     518             : void
     519           0 : ShadowRoot::SetShadowElement(HTMLShadowElement* aShadowElement)
     520             : {
     521             :   // If there is already a shadow element point, remove
     522             :   // the projected shadow because it is no longer an insertion
     523             :   // point.
     524           0 :   if (mShadowElement) {
     525           0 :     mShadowElement->SetProjectedShadow(nullptr);
     526             :   }
     527             : 
     528           0 :   if (mOlderShadow) {
     529             :     // Nodes for distribution will come from the new shadow element.
     530           0 :     mOlderShadow->ChangePoolHost(aShadowElement);
     531             :   }
     532             : 
     533             :   // Set the new shadow element to project the older ShadowRoot because
     534             :   // it is the current shadow insertion point.
     535           0 :   mShadowElement = aShadowElement;
     536           0 :   if (mShadowElement) {
     537           0 :     mShadowElement->SetProjectedShadow(mOlderShadow);
     538             :   }
     539           0 : }
     540             : 
     541             : void
     542           0 : ShadowRoot::ChangePoolHost(nsIContent* aNewHost)
     543             : {
     544           0 :   if (mPoolHost) {
     545           0 :     mPoolHost->RemoveMutationObserver(this);
     546             :   }
     547             : 
     548             :   // Clear the nodes matched to content insertion points
     549             :   // because it is no longer relevant.
     550           0 :   for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
     551           0 :     mInsertionPoints[i]->ClearMatchedNodes();
     552             :   }
     553             : 
     554           0 :   mPoolHost = aNewHost;
     555           0 :   if (mPoolHost) {
     556           0 :     mPoolHost->AddMutationObserver(this);
     557             :   }
     558           0 : }
     559             : 
     560             : bool
     561        1638 : ShadowRoot::IsShadowInsertionPoint(nsIContent* aContent)
     562             : {
     563        1638 :   if (!aContent) {
     564           0 :     return false;
     565             :   }
     566             : 
     567        1638 :   HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(aContent);
     568        1638 :   return shadowElem && shadowElem->IsInsertionPoint();
     569             : }
     570             : 
     571             : /**
     572             :  * Returns whether the web components pool population algorithm
     573             :  * on the host would contain |aContent|. This function ignores
     574             :  * insertion points in the pool, thus should only be used to
     575             :  * test nodes that have not yet been distributed.
     576             :  */
     577             : bool
     578           0 : ShadowRoot::IsPooledNode(nsIContent* aContent, nsIContent* aContainer,
     579             :                          nsIContent* aHost)
     580             : {
     581           0 :   if (nsContentUtils::IsContentInsertionPoint(aContent) ||
     582           0 :       IsShadowInsertionPoint(aContent)) {
     583             :     // Insertion points never end up in the pool.
     584           0 :     return false;
     585             :   }
     586             : 
     587           0 :   if (aContainer == aHost &&
     588           0 :       nsContentUtils::IsInSameAnonymousTree(aContainer, aContent)) {
     589             :     // Children of the host will end up in the pool. We check to ensure
     590             :     // that the content is in the same anonymous tree as the container
     591             :     // because anonymous content may report its container as the host
     592             :     // but it may not be in the host's child list.
     593           0 :     return true;
     594             :   }
     595             : 
     596           0 :   if (aContainer) {
     597             :     // Fallback content will end up in pool if its parent is a child of the host.
     598           0 :     HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
     599           0 :     return content && content->IsInsertionPoint() &&
     600           0 :            content->MatchedNodes().IsEmpty() &&
     601           0 :            aContainer->GetParentNode() == aHost;
     602             :   }
     603             : 
     604           0 :   return false;
     605             : }
     606             : 
     607             : void
     608           0 : ShadowRoot::AttributeChanged(nsIDocument* aDocument,
     609             :                              Element* aElement,
     610             :                              int32_t aNameSpaceID,
     611             :                              nsIAtom* aAttribute,
     612             :                              int32_t aModType,
     613             :                              const nsAttrValue* aOldValue)
     614             : {
     615           0 :   if (!IsPooledNode(aElement, aElement->GetParent(), mPoolHost)) {
     616           0 :     return;
     617             :   }
     618             : 
     619             :   // Attributes may change insertion point matching, find its new distribution.
     620           0 :   RemoveDistributedNode(aElement);
     621           0 :   DistributeSingleNode(aElement);
     622             : }
     623             : 
     624             : void
     625           0 : ShadowRoot::ContentAppended(nsIDocument* aDocument,
     626             :                             nsIContent* aContainer,
     627             :                             nsIContent* aFirstNewContent,
     628             :                             int32_t aNewIndexInContainer)
     629             : {
     630           0 :   if (mInsertionPointChanged) {
     631           0 :     DistributeAllNodes();
     632           0 :     mInsertionPointChanged = false;
     633           0 :     return;
     634             :   }
     635             : 
     636             :   // Watch for new nodes added to the pool because the node
     637             :   // may need to be added to an insertion point.
     638           0 :   nsIContent* currentChild = aFirstNewContent;
     639           0 :   while (currentChild) {
     640             :     // Add insertion point to destination insertion points of fallback content.
     641           0 :     if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
     642           0 :       HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
     643           0 :       if (content->MatchedNodes().IsEmpty()) {
     644           0 :         currentChild->DestInsertionPoints().AppendElement(aContainer);
     645             :       }
     646             :     }
     647             : 
     648           0 :     if (IsPooledNode(currentChild, aContainer, mPoolHost)) {
     649           0 :       DistributeSingleNode(currentChild);
     650             :     }
     651             : 
     652           0 :     currentChild = currentChild->GetNextSibling();
     653             :   }
     654             : }
     655             : 
     656             : void
     657           0 : ShadowRoot::ContentInserted(nsIDocument* aDocument,
     658             :                             nsIContent* aContainer,
     659             :                             nsIContent* aChild,
     660             :                             int32_t aIndexInContainer)
     661             : {
     662           0 :   if (mInsertionPointChanged) {
     663           0 :     DistributeAllNodes();
     664           0 :     mInsertionPointChanged = false;
     665           0 :     return;
     666             :   }
     667             : 
     668             :   // Watch for new nodes added to the pool because the node
     669             :   // may need to be added to an insertion point.
     670           0 :   if (IsPooledNode(aChild, aContainer, mPoolHost)) {
     671             :     // Add insertion point to destination insertion points of fallback content.
     672           0 :     if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
     673           0 :       HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
     674           0 :       if (content->MatchedNodes().IsEmpty()) {
     675           0 :         aChild->DestInsertionPoints().AppendElement(aContainer);
     676             :       }
     677             :     }
     678             : 
     679           0 :     DistributeSingleNode(aChild);
     680             :   }
     681             : }
     682             : 
     683             : void
     684           0 : ShadowRoot::ContentRemoved(nsIDocument* aDocument,
     685             :                            nsIContent* aContainer,
     686             :                            nsIContent* aChild,
     687             :                            int32_t aIndexInContainer,
     688             :                            nsIContent* aPreviousSibling)
     689             : {
     690           0 :   if (mInsertionPointChanged) {
     691           0 :     DistributeAllNodes();
     692           0 :     mInsertionPointChanged = false;
     693           0 :     return;
     694             :   }
     695             : 
     696             :   // Clear destination insertion points for removed
     697             :   // fallback content.
     698           0 :   if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
     699           0 :     HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
     700           0 :     if (content->MatchedNodes().IsEmpty()) {
     701           0 :       aChild->DestInsertionPoints().Clear();
     702             :     }
     703             :   }
     704             : 
     705             :   // Watch for node that is removed from the pool because
     706             :   // it may need to be removed from an insertion point.
     707           0 :   if (IsPooledNode(aChild, aContainer, mPoolHost)) {
     708           0 :     RemoveDistributedNode(aChild);
     709             :   }
     710             : }
     711             : 
     712             : nsresult
     713           0 : ShadowRoot::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
     714             :                   bool aPreallocateChildren) const
     715             : {
     716           0 :   *aResult = nullptr;
     717           0 :   return NS_ERROR_DOM_DATA_CLONE_ERR;
     718             : }
     719             : 
     720             : void
     721           0 : ShadowRoot::DestroyContent()
     722             : {
     723           0 :   if (mOlderShadow) {
     724           0 :     mOlderShadow->DestroyContent();
     725             :   }
     726           0 :   DocumentFragment::DestroyContent();
     727           0 : }
     728             : 
     729           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList, StyleSheetList,
     730             :                                    mShadowRoot)
     731             : 
     732           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList)
     733           0 : NS_INTERFACE_MAP_END_INHERITING(StyleSheetList)
     734             : 
     735           0 : NS_IMPL_ADDREF_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
     736           0 : NS_IMPL_RELEASE_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
     737             : 
     738           0 : ShadowRootStyleSheetList::ShadowRootStyleSheetList(ShadowRoot* aShadowRoot)
     739           0 :   : mShadowRoot(aShadowRoot)
     740             : {
     741           0 : }
     742             : 
     743           0 : ShadowRootStyleSheetList::~ShadowRootStyleSheetList()
     744             : {
     745           0 : }
     746             : 
     747             : StyleSheet*
     748           0 : ShadowRootStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
     749             : {
     750           0 :   aFound = aIndex < mShadowRoot->mProtoBinding->SheetCount();
     751           0 :   if (!aFound) {
     752           0 :     return nullptr;
     753             :   }
     754           0 :   return mShadowRoot->mProtoBinding->StyleSheetAt(aIndex);
     755             : }
     756             : 
     757             : uint32_t
     758           0 : ShadowRootStyleSheetList::Length()
     759             : {
     760           0 :   return mShadowRoot->mProtoBinding->SheetCount();
     761             : }
     762             : 

Generated by: LCOV version 1.13