LCOV - code coverage report
Current view: top level - dom/base - ChildIterator.h (source / functions) Hit Total Coverage
Test: output.info Lines: 24 56 42.9 %
Date: 2017-07-14 16:53:18 Functions: 8 16 50.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 file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef ChildIterator_h
       8             : #define ChildIterator_h
       9             : 
      10             : #include "nsIContent.h"
      11             : 
      12             : /**
      13             :  * Iterates over the children on a node. If a child is an insertion point,
      14             :  * iterates over the children inserted there instead, or the default content
      15             :  * if no children are inserted there.
      16             :  *
      17             :  * The FlattenedChildIterator expands any anonymous content bound from an XBL
      18             :  * binding's <xbl:content> element.
      19             :  */
      20             : 
      21             : #include <stdint.h>
      22             : #include "nsAutoPtr.h"
      23             : 
      24             : class nsIContent;
      25             : 
      26             : namespace mozilla {
      27             : namespace dom {
      28             : 
      29             : // This class iterates normal DOM child nodes of a given DOM node with
      30             : // <xbl:children> nodes replaced by the elements that have been filtered into that
      31             : // insertion point. Any bindings on the given element are ignored for purposes
      32             : // of determining which insertion point children are filtered into. The iterator
      33             : // can be initialized to start at the end by providing false for aStartAtBeginning
      34             : // in order to start iterating in reverse from the last child.
      35         770 : class ExplicitChildIterator
      36             : {
      37             : public:
      38         733 :   explicit ExplicitChildIterator(const nsIContent* aParent,
      39             :                                  bool aStartAtBeginning = true)
      40         733 :     : mParent(aParent),
      41             :       mChild(nullptr),
      42             :       mDefaultChild(nullptr),
      43             :       mIsFirst(aStartAtBeginning),
      44         733 :       mIndexInInserted(0)
      45             :   {
      46         733 :   }
      47             : 
      48          37 :   ExplicitChildIterator(const ExplicitChildIterator& aOther)
      49          74 :     : mParent(aOther.mParent), mChild(aOther.mChild),
      50          37 :       mDefaultChild(aOther.mDefaultChild),
      51             :       mShadowIterator(aOther.mShadowIterator ?
      52           0 :                       new ExplicitChildIterator(*aOther.mShadowIterator) :
      53          37 :                       nullptr),
      54          37 :       mIsFirst(aOther.mIsFirst),
      55         185 :       mIndexInInserted(aOther.mIndexInInserted) {}
      56             : 
      57           0 :   ExplicitChildIterator(ExplicitChildIterator&& aOther)
      58           0 :     : mParent(aOther.mParent), mChild(aOther.mChild),
      59           0 :       mDefaultChild(aOther.mDefaultChild),
      60           0 :       mShadowIterator(Move(aOther.mShadowIterator)),
      61           0 :       mIsFirst(aOther.mIsFirst),
      62           0 :       mIndexInInserted(aOther.mIndexInInserted) {}
      63             : 
      64             :   nsIContent* GetNextChild();
      65             : 
      66             :   // Looks for aChildToFind respecting insertion points until aChildToFind is
      67             :   // found.  This version can take shortcuts that the two-argument version
      68             :   // can't, so can be faster (and in fact can be O(1) instead of O(N) in many
      69             :   // cases).
      70             :   bool Seek(nsIContent* aChildToFind);
      71             : 
      72             :   // Looks for aChildToFind respecting insertion points until aChildToFind is found.
      73             :   // or aBound is found. If aBound is nullptr then the seek is unbounded. Returns
      74             :   // whether aChildToFind was found as an explicit child prior to encountering
      75             :   // aBound.
      76          19 :   bool Seek(nsIContent* aChildToFind, nsIContent* aBound)
      77             :   {
      78             :     // It would be nice to assert that we find aChildToFind, but bz thinks that
      79             :     // we might not find aChildToFind when called from ContentInserted
      80             :     // if first-letter frames are about.
      81             : 
      82             :     // We can't easily take shortcuts here because we'd have to have a way to
      83             :     // compare aChildToFind to aBound.
      84             :     nsIContent* child;
      85          10 :     do {
      86          19 :       child = GetNextChild();
      87          19 :     } while (child && child != aChildToFind && child != aBound);
      88             : 
      89           9 :     return child == aChildToFind;
      90             :   }
      91             : 
      92             :   // Returns the current target of this iterator (which might be an explicit
      93             :   // child of the node, fallback content of an insertion point or
      94             :   // a node distributed to an insertion point.
      95             :   nsIContent* Get() const;
      96             : 
      97             :   // The inverse of GetNextChild. Properly steps in and out of insertion
      98             :   // points.
      99             :   nsIContent* GetPreviousChild();
     100             : 
     101             : protected:
     102             :   // The parent of the children being iterated. For the FlattenedChildIterator,
     103             :   // if there is a binding attached to the original parent, mParent points to
     104             :   // the <xbl:content> element for the binding.
     105             :   const nsIContent* mParent;
     106             : 
     107             :   // The current child. When we encounter an insertion point,
     108             :   // mChild remains as the insertion point whose content we're iterating (and
     109             :   // our state is controled by mDefaultChild or mIndexInInserted depending on
     110             :   // whether the insertion point expands to its default content or not).
     111             :   nsIContent* mChild;
     112             : 
     113             :   // If non-null, this points to the current default content for the current
     114             :   // insertion point that we're iterating (i.e. mChild, which must be an
     115             :   // nsXBLChildrenElement or HTMLContentElement). Once this transitions back
     116             :   // to null, we continue iterating at mChild's next sibling.
     117             :   nsIContent* mDefaultChild;
     118             : 
     119             :   // If non-null, this points to an iterator of the explicit children of
     120             :   // the ShadowRoot projected by the current shadow element that we're
     121             :   // iterating.
     122             :   nsAutoPtr<ExplicitChildIterator> mShadowIterator;
     123             : 
     124             :   // A flag to let us know that we haven't started iterating yet.
     125             :   bool mIsFirst;
     126             : 
     127             :   // If not zero, we're iterating inserted children for an insertion point. This
     128             :   // is an index into mChild's inserted children array (mChild must be an
     129             :   // nsXBLChildrenElement). The index is one past the "current" child (as
     130             :   // opposed to mChild which represents the "current" child).
     131             :   uint32_t mIndexInInserted;
     132             : };
     133             : 
     134             : // Iterates over the flattened children of a node, which accounts for anonymous
     135             : // children and nodes moved by insertion points. If a node has anonymous
     136             : // children, those are iterated over.  The iterator can be initialized to start
     137             : // at the end by providing false for aStartAtBeginning in order to start
     138             : // iterating in reverse from the last child.
     139         619 : class FlattenedChildIterator : public ExplicitChildIterator
     140             : {
     141             : public:
     142         582 :   explicit FlattenedChildIterator(const nsIContent* aParent,
     143             :                                   bool aStartAtBeginning = true)
     144         582 :     : ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
     145             :   {
     146         582 :     Init(false);
     147         582 :   }
     148             : 
     149           0 :   FlattenedChildIterator(FlattenedChildIterator&& aOther)
     150           0 :     : ExplicitChildIterator(Move(aOther)), mXBLInvolved(aOther.mXBLInvolved) {}
     151             : 
     152          37 :   FlattenedChildIterator(const FlattenedChildIterator& aOther)
     153          37 :     : ExplicitChildIterator(aOther), mXBLInvolved(aOther.mXBLInvolved) {}
     154             : 
     155        1086 :   bool XBLInvolved() { return mXBLInvolved; }
     156             : 
     157             : protected:
     158             :   /**
     159             :    * This constructor is a hack to help AllChildrenIterator which sometimes
     160             :    * doesn't want to consider XBL.
     161             :    */
     162           0 :   FlattenedChildIterator(const nsIContent* aParent, uint32_t aFlags,
     163             :                          bool aStartAtBeginning = true)
     164           0 :     : ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
     165             :   {
     166           0 :     bool ignoreXBL = aFlags & nsIContent::eAllButXBL;
     167           0 :     Init(ignoreXBL);
     168           0 :   }
     169             : 
     170             :   void Init(bool aIgnoreXBL);
     171             : 
     172             :   // For certain optimizations, nsCSSFrameConstructor needs to know if the
     173             :   // child list of the element that we're iterating matches its .childNodes.
     174             :   bool mXBLInvolved;
     175             : };
     176             : 
     177             : /**
     178             :  * AllChildrenIterator traverses the children of an element including before /
     179             :  * after content and optionally XBL children.  The iterator can be initialized
     180             :  * to start at the end by providing false for aStartAtBeginning in order to
     181             :  * start iterating in reverse from the last child.
     182             :  *
     183             :  * Note: it assumes that no mutation of the DOM or frame tree takes place during
     184             :  * iteration, and will break horribly if that is not true.
     185             :  */
     186             : class AllChildrenIterator : private FlattenedChildIterator
     187             : {
     188             : public:
     189           0 :   AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags,
     190           0 :                       bool aStartAtBeginning = true) :
     191             :     FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
     192           0 :     mOriginalContent(aNode), mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
     193           0 :     mFlags(aFlags), mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) { }
     194             : 
     195           0 :   AllChildrenIterator(AllChildrenIterator&& aOther)
     196           0 :     : FlattenedChildIterator(Move(aOther)),
     197           0 :       mOriginalContent(aOther.mOriginalContent),
     198           0 :       mAnonKids(Move(aOther.mAnonKids)), mAnonKidsIdx(aOther.mAnonKidsIdx),
     199           0 :       mFlags(aOther.mFlags), mPhase(aOther.mPhase)
     200             : #ifdef DEBUG
     201           0 :       , mMutationGuard(aOther.mMutationGuard)
     202             : #endif
     203           0 :       {}
     204             : 
     205             : #ifdef DEBUG
     206           0 :   ~AllChildrenIterator() { MOZ_ASSERT(!mMutationGuard.Mutated(0)); }
     207             : #endif
     208             : 
     209             :   // Returns the current target the iterator is at, or null if the iterator
     210             :   // doesn't point to any child node (either eAtBegin or eAtEnd phase).
     211             :   nsIContent* Get() const;
     212             : 
     213             :   // Seeks the given node in children of a parent element, starting from
     214             :   // the current iterator's position, and sets the iterator at the given child
     215             :   // node if it was found.
     216             :   bool Seek(nsIContent* aChildToFind);
     217             : 
     218             :   nsIContent* GetNextChild();
     219             :   nsIContent* GetPreviousChild();
     220             :   const nsIContent* Parent() const { return mOriginalContent; }
     221             : 
     222             :   enum IteratorPhase
     223             :   {
     224             :     eAtBegin,
     225             :     eAtBeforeKid,
     226             :     eAtExplicitKids,
     227             :     eAtAnonKids,
     228             :     eAtAfterKid,
     229             :     eAtEnd
     230             :   };
     231             :   IteratorPhase Phase() const { return mPhase; }
     232             : 
     233             : private:
     234             :   // Helpers.
     235             :   void AppendNativeAnonymousChildren();
     236             :   const nsIContent* mOriginalContent;
     237             : 
     238             :   // mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
     239             :   // in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is
     240             :   // eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If
     241             :   // mAnonKidsIdx == mAnonKids.Length() then the iterator is somewhere after
     242             :   // the last native anon child. If mAnonKidsIdx == UINT32_MAX then the iterator
     243             :   // is somewhere before the first native anon child.
     244             :   nsTArray<nsIContent*> mAnonKids;
     245             :   uint32_t mAnonKidsIdx;
     246             : 
     247             :   uint32_t mFlags;
     248             :   IteratorPhase mPhase;
     249             : #ifdef DEBUG
     250             :   // XXX we should really assert there are no frame tree changes as well, but
     251             :   // there's no easy way to do that.
     252             :   nsMutationGuard mMutationGuard;
     253             : #endif
     254             : };
     255             : 
     256             : /**
     257             :  * StyleChildrenIterator traverses the children of the element from the
     258             :  * perspective of the style system, particularly the children we need to
     259             :  * traverse during restyle.
     260             :  *
     261             :  * At present, this is identical to AllChildrenIterator with
     262             :  * (eAllChildren | eSkipDocumentLevelNativeAnonymousContent). We used to have
     263             :  * detect and skip any native anonymous children that are used to implement some
     264             :  * special magic in here that went away, but we keep the separate class so
     265             :  * we can reintroduce special magic back if needed.
     266             :  *
     267             :  * Note: it assumes that no mutation of the DOM or frame tree takes place during
     268             :  * iteration, and will break horribly if that is not true.
     269             :  *
     270             :  * We require this to be memmovable since Rust code can create and move
     271             :  * StyleChildrenIterators.
     272             :  */
     273             : class MOZ_NEEDS_MEMMOVABLE_MEMBERS StyleChildrenIterator : private AllChildrenIterator
     274             : {
     275             : public:
     276           0 :   explicit StyleChildrenIterator(const nsIContent* aContent)
     277           0 :     : AllChildrenIterator(aContent,
     278             :                           nsIContent::eAllChildren |
     279           0 :                           nsIContent::eSkipDocumentLevelNativeAnonymousContent)
     280             :   {
     281           0 :     MOZ_COUNT_CTOR(StyleChildrenIterator);
     282           0 :   }
     283           0 :   ~StyleChildrenIterator() { MOZ_COUNT_DTOR(StyleChildrenIterator); }
     284             : 
     285             :   nsIContent* GetNextChild();
     286             : };
     287             : 
     288             : } // namespace dom
     289             : } // namespace mozilla
     290             : 
     291             : #endif

Generated by: LCOV version 1.13