LCOV - code coverage report
Current view: top level - dom/html - HTMLShadowElement.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 156 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 21 0.0 %
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/dom/ShadowRoot.h"
       8             : 
       9             : #include "ChildIterator.h"
      10             : #include "nsContentUtils.h"
      11             : #include "nsDocument.h"
      12             : #include "mozilla/dom/HTMLShadowElement.h"
      13             : #include "mozilla/dom/HTMLUnknownElement.h"
      14             : #include "mozilla/dom/HTMLShadowElementBinding.h"
      15             : 
      16             : // Expand NS_IMPL_NS_NEW_HTML_ELEMENT(Shadow) to add check for web components
      17             : // being enabled.
      18             : nsGenericHTMLElement*
      19           0 : NS_NewHTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
      20             :                         mozilla::dom::FromParser aFromParser)
      21             : {
      22             :   // When this check is removed, remove the nsDocument.h and
      23             :   // HTMLUnknownElement.h includes.  Also remove nsINode::IsHTMLShadowElement.
      24             :   //
      25             :   // We have to jump through some hoops to be able to produce both NodeInfo* and
      26             :   // already_AddRefed<NodeInfo>& for our callees.
      27           0 :   RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
      28           0 :   if (!nsDocument::IsWebComponentsEnabled(nodeInfo)) {
      29           0 :     already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
      30           0 :     return new mozilla::dom::HTMLUnknownElement(nodeInfoArg);
      31             :   }
      32             : 
      33           0 :   already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
      34           0 :   return new mozilla::dom::HTMLShadowElement(nodeInfoArg);
      35             : }
      36             : 
      37             : using namespace mozilla::dom;
      38             : 
      39           0 : HTMLShadowElement::HTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
      40           0 :   : nsGenericHTMLElement(aNodeInfo), mIsInsertionPoint(false)
      41             : {
      42           0 : }
      43             : 
      44           0 : HTMLShadowElement::~HTMLShadowElement()
      45             : {
      46           0 :   if (mProjectedShadow) {
      47           0 :     mProjectedShadow->RemoveMutationObserver(this);
      48             :   }
      49           0 : }
      50             : 
      51             : NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLShadowElement)
      52             : 
      53           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLShadowElement,
      54             :                                                   nsGenericHTMLElement)
      55           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProjectedShadow)
      56           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      57             : 
      58           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLShadowElement,
      59             :                                                 nsGenericHTMLElement)
      60           0 :   if (tmp->mProjectedShadow) {
      61           0 :     tmp->mProjectedShadow->RemoveMutationObserver(tmp);
      62           0 :     tmp->mProjectedShadow = nullptr;
      63             :   }
      64           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      65             : 
      66           0 : NS_IMPL_ADDREF_INHERITED(HTMLShadowElement, Element)
      67           0 : NS_IMPL_RELEASE_INHERITED(HTMLShadowElement, Element)
      68             : 
      69           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLShadowElement)
      70           0 : NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
      71             : 
      72           0 : NS_IMPL_ELEMENT_CLONE(HTMLShadowElement)
      73             : 
      74             : JSObject*
      75           0 : HTMLShadowElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
      76             : {
      77           0 :   return HTMLShadowElementBinding::Wrap(aCx, this, aGivenProto);
      78             : }
      79             : 
      80             : void
      81           0 : HTMLShadowElement::SetProjectedShadow(ShadowRoot* aProjectedShadow)
      82             : {
      83           0 :   if (mProjectedShadow) {
      84           0 :     mProjectedShadow->RemoveMutationObserver(this);
      85             : 
      86             :     // The currently projected ShadowRoot is going away,
      87             :     // thus the destination insertion points need to be updated.
      88           0 :     ExplicitChildIterator childIterator(mProjectedShadow);
      89           0 :     for (nsIContent* content = childIterator.GetNextChild();
      90           0 :          content;
      91             :          content = childIterator.GetNextChild()) {
      92           0 :       ShadowRoot::RemoveDestInsertionPoint(this, content->DestInsertionPoints());
      93             :     }
      94             :   }
      95             : 
      96           0 :   mProjectedShadow = aProjectedShadow;
      97           0 :   if (mProjectedShadow) {
      98             :     // A new ShadowRoot is being projected, thus its explcit
      99             :     // children will be distributed to this shadow insertion point.
     100           0 :     ExplicitChildIterator childIterator(mProjectedShadow);
     101           0 :     for (nsIContent* content = childIterator.GetNextChild();
     102           0 :          content;
     103             :          content = childIterator.GetNextChild()) {
     104           0 :       content->DestInsertionPoints().AppendElement(this);
     105             :     }
     106             : 
     107             :     // Watch for mutations on the projected shadow because
     108             :     // it affects the nodes that are distributed to this shadow
     109             :     // insertion point.
     110           0 :     mProjectedShadow->AddMutationObserver(this);
     111             :   }
     112           0 : }
     113             : 
     114             : static bool
     115           0 : IsInFallbackContent(nsIContent* aContent)
     116             : {
     117           0 :   nsINode* parentNode = aContent->GetParentNode();
     118           0 :   while (parentNode) {
     119           0 :     if (parentNode->IsHTMLElement(nsGkAtoms::content)) {
     120           0 :       return true;
     121             :     }
     122           0 :     parentNode = parentNode->GetParentNode();
     123             :   }
     124             : 
     125           0 :   return false;
     126             : }
     127             : 
     128             : nsresult
     129           0 : HTMLShadowElement::BindToTree(nsIDocument* aDocument,
     130             :                               nsIContent* aParent,
     131             :                               nsIContent* aBindingParent,
     132             :                               bool aCompileEventHandlers)
     133             : {
     134           0 :   RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
     135             : 
     136           0 :   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
     137             :                                                  aBindingParent,
     138           0 :                                                  aCompileEventHandlers);
     139           0 :   NS_ENSURE_SUCCESS(rv, rv);
     140             : 
     141           0 :   ShadowRoot* containingShadow = GetContainingShadow();
     142           0 :   if (containingShadow && !oldContainingShadow) {
     143             :     // Keep track of all descendant <shadow> elements in tree order so
     144             :     // that when the current shadow insertion point is removed, the next
     145             :     // one can be found quickly.
     146             :     TreeOrderComparator comparator;
     147           0 :     containingShadow->ShadowDescendants().InsertElementSorted(this, comparator);
     148             : 
     149           0 :     if (containingShadow->ShadowDescendants()[0] != this) {
     150             :       // Only the first <shadow> (in tree order) of a ShadowRoot can be an insertion point.
     151           0 :       return NS_OK;
     152             :     }
     153             : 
     154           0 :     if (IsInFallbackContent(this)) {
     155             :       // If the first shadow element in tree order is invalid (in fallback content),
     156             :       // the containing ShadowRoot will not have a shadow insertion point.
     157           0 :       containingShadow->SetShadowElement(nullptr);
     158             :     } else {
     159           0 :       mIsInsertionPoint = true;
     160           0 :       containingShadow->SetShadowElement(this);
     161             :     }
     162             : 
     163           0 :     containingShadow->SetInsertionPointChanged();
     164             :   }
     165             : 
     166           0 :   if (mIsInsertionPoint && containingShadow) {
     167             :     // Propagate BindToTree calls to projected shadow root children.
     168           0 :     ShadowRoot* projectedShadow = containingShadow->GetOlderShadowRoot();
     169           0 :     if (projectedShadow) {
     170           0 :       projectedShadow->SetIsComposedDocParticipant(IsInComposedDoc());
     171             : 
     172           0 :       for (nsIContent* child = projectedShadow->GetFirstChild(); child;
     173           0 :            child = child->GetNextSibling()) {
     174           0 :         rv = child->BindToTree(nullptr, projectedShadow,
     175           0 :                                projectedShadow->GetBindingParent(),
     176           0 :                                aCompileEventHandlers);
     177           0 :         NS_ENSURE_SUCCESS(rv, rv);
     178             :       }
     179             :     }
     180             :   }
     181             : 
     182           0 :   return NS_OK;
     183             : }
     184             : 
     185             : void
     186           0 : HTMLShadowElement::UnbindFromTree(bool aDeep, bool aNullParent)
     187             : {
     188           0 :   RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
     189             : 
     190           0 :   if (mIsInsertionPoint && oldContainingShadow) {
     191             :     // Propagate UnbindFromTree call to previous projected shadow
     192             :     // root children.
     193           0 :     ShadowRoot* projectedShadow = oldContainingShadow->GetOlderShadowRoot();
     194           0 :     if (projectedShadow) {
     195           0 :       for (nsIContent* child = projectedShadow->GetFirstChild(); child;
     196           0 :            child = child->GetNextSibling()) {
     197           0 :         child->UnbindFromTree(true, false);
     198             :       }
     199             : 
     200           0 :       projectedShadow->SetIsComposedDocParticipant(false);
     201             :     }
     202             :   }
     203             : 
     204           0 :   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
     205             : 
     206           0 :   if (oldContainingShadow && !GetContainingShadow() && mIsInsertionPoint) {
     207             :     nsTArray<HTMLShadowElement*>& shadowDescendants =
     208           0 :       oldContainingShadow->ShadowDescendants();
     209           0 :     shadowDescendants.RemoveElement(this);
     210           0 :     oldContainingShadow->SetShadowElement(nullptr);
     211             : 
     212             :     // Find the next shadow insertion point.
     213           0 :     if (shadowDescendants.Length() > 0 &&
     214           0 :         !IsInFallbackContent(shadowDescendants[0])) {
     215           0 :       oldContainingShadow->SetShadowElement(shadowDescendants[0]);
     216             :     }
     217             : 
     218           0 :     oldContainingShadow->SetInsertionPointChanged();
     219             : 
     220           0 :     mIsInsertionPoint = false;
     221             :   }
     222           0 : }
     223             : 
     224             : void
     225           0 : HTMLShadowElement::DistributeSingleNode(nsIContent* aContent)
     226             : {
     227           0 :   if (aContent->DestInsertionPoints().Contains(this)) {
     228             :     // Node has already been distrbuted this this node,
     229             :     // we are done.
     230           0 :     return;
     231             :   }
     232             : 
     233           0 :   aContent->DestInsertionPoints().AppendElement(this);
     234             : 
     235             :   // Handle the case where the shadow element is a child of
     236             :   // a node with a ShadowRoot. The nodes that have been distributed to
     237             :   // this shadow insertion point will need to be reprojected into the
     238             :   // insertion points of the parent's ShadowRoot.
     239           0 :   ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
     240           0 :   if (parentShadowRoot) {
     241           0 :     parentShadowRoot->DistributeSingleNode(aContent);
     242           0 :     return;
     243             :   }
     244             : 
     245             :   // Handle the case where the parent of this shadow element is a ShadowRoot
     246             :   // that is projected into a shadow insertion point in the younger ShadowRoot.
     247           0 :   ShadowRoot* containingShadow = GetContainingShadow();
     248           0 :   ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
     249           0 :   if (youngerShadow && GetParent() == containingShadow) {
     250           0 :     HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
     251           0 :     if (youngerShadowElement) {
     252           0 :       youngerShadowElement->DistributeSingleNode(aContent);
     253             :     }
     254             :   }
     255             : }
     256             : 
     257             : void
     258           0 : HTMLShadowElement::RemoveDistributedNode(nsIContent* aContent)
     259             : {
     260           0 :   ShadowRoot::RemoveDestInsertionPoint(this, aContent->DestInsertionPoints());
     261             : 
     262             :   // Handle the case where the shadow element is a child of
     263             :   // a node with a ShadowRoot. The nodes that have been distributed to
     264             :   // this shadow insertion point will need to be removed from the
     265             :   // insertion points of the parent's ShadowRoot.
     266           0 :   ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
     267           0 :   if (parentShadowRoot) {
     268           0 :     parentShadowRoot->RemoveDistributedNode(aContent);
     269           0 :     return;
     270             :   }
     271             : 
     272             :   // Handle the case where the parent of this shadow element is a ShadowRoot
     273             :   // that is projected into a shadow insertion point in the younger ShadowRoot.
     274           0 :   ShadowRoot* containingShadow = GetContainingShadow();
     275           0 :   ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
     276           0 :   if (youngerShadow && GetParent() == containingShadow) {
     277           0 :     HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
     278           0 :     if (youngerShadowElement) {
     279           0 :       youngerShadowElement->RemoveDistributedNode(aContent);
     280             :     }
     281             :   }
     282             : }
     283             : 
     284             : void
     285           0 : HTMLShadowElement::DistributeAllNodes()
     286             : {
     287             :   // All the explicit children of the projected ShadowRoot are distributed
     288             :   // into this shadow insertion point so update the destination insertion
     289             :   // points.
     290           0 :   ShadowRoot* containingShadow = GetContainingShadow();
     291           0 :   ShadowRoot* olderShadow = containingShadow->GetOlderShadowRoot();
     292           0 :   if (olderShadow) {
     293           0 :     ExplicitChildIterator childIterator(olderShadow);
     294           0 :     for (nsIContent* content = childIterator.GetNextChild();
     295           0 :          content;
     296             :          content = childIterator.GetNextChild()) {
     297           0 :       ShadowRoot::RemoveDestInsertionPoint(this, content->DestInsertionPoints());
     298           0 :       content->DestInsertionPoints().AppendElement(this);
     299             :     }
     300             :   }
     301             : 
     302             :   // Handle the case where the shadow element is a child of
     303             :   // a node with a ShadowRoot. The nodes that have been distributed to
     304             :   // this shadow insertion point will need to be reprojected into the
     305             :   // insertion points of the parent's ShadowRoot.
     306           0 :   ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
     307           0 :   if (parentShadowRoot) {
     308           0 :     parentShadowRoot->DistributeAllNodes();
     309           0 :     return;
     310             :   }
     311             : 
     312             :   // Handle the case where the parent of this shadow element is a ShadowRoot
     313             :   // that is projected into a shadow insertion point in the younger ShadowRoot.
     314           0 :   ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
     315           0 :   if (youngerShadow && GetParent() == containingShadow) {
     316           0 :     HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
     317           0 :     if (youngerShadowElement) {
     318           0 :       youngerShadowElement->DistributeAllNodes();
     319             :     }
     320             :   }
     321             : }
     322             : 
     323             : void
     324           0 : HTMLShadowElement::ContentAppended(nsIDocument* aDocument,
     325             :                                    nsIContent* aContainer,
     326             :                                    nsIContent* aFirstNewContent,
     327             :                                    int32_t aNewIndexInContainer)
     328             : {
     329             :   // Watch for content appended to the projected shadow (the ShadowRoot that
     330             :   // will be rendered in place of this shadow insertion point) because the
     331             :   // nodes may need to be distributed into other insertion points.
     332           0 :   nsIContent* currentChild = aFirstNewContent;
     333           0 :   while (currentChild) {
     334           0 :     if (ShadowRoot::IsPooledNode(currentChild, aContainer, mProjectedShadow)) {
     335           0 :       DistributeSingleNode(currentChild);
     336             :     }
     337           0 :     currentChild = currentChild->GetNextSibling();
     338             :   }
     339           0 : }
     340             : 
     341             : void
     342           0 : HTMLShadowElement::ContentInserted(nsIDocument* aDocument,
     343             :                                    nsIContent* aContainer,
     344             :                                    nsIContent* aChild,
     345             :                                    int32_t aIndexInContainer)
     346             : {
     347             :   // Watch for content appended to the projected shadow (the ShadowRoot that
     348             :   // will be rendered in place of this shadow insertion point) because the
     349             :   // nodes may need to be distributed into other insertion points.
     350           0 :   if (!ShadowRoot::IsPooledNode(aChild, aContainer, mProjectedShadow)) {
     351           0 :     return;
     352             :   }
     353             : 
     354           0 :   DistributeSingleNode(aChild);
     355             : }
     356             : 
     357             : void
     358           0 : HTMLShadowElement::ContentRemoved(nsIDocument* aDocument,
     359             :                                   nsIContent* aContainer,
     360             :                                   nsIContent* aChild,
     361             :                                   int32_t aIndexInContainer,
     362             :                                   nsIContent* aPreviousSibling)
     363             : {
     364             :   // Watch for content removed from the projected shadow (the ShadowRoot that
     365             :   // will be rendered in place of this shadow insertion point) because the
     366             :   // nodes may need to be removed from other insertion points.
     367           0 :   if (!ShadowRoot::IsPooledNode(aChild, aContainer, mProjectedShadow)) {
     368           0 :     return;
     369             :   }
     370             : 
     371           0 :   RemoveDistributedNode(aChild);
     372             : }
     373             : 

Generated by: LCOV version 1.13