tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ChildIterator.h (7324B)


      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 <stdint.h>
     11 
     12 #include "nsIContent.h"
     13 #include "nsIContentInlines.h"
     14 
     15 class nsIContent;
     16 
     17 namespace mozilla::dom {
     18 
     19 // Iterates over the flattened children of a node, that is, the regular DOM
     20 // child nodes of a given DOM node, with assigned nodes as slot children, and
     21 // shadow host children replaced by their shadow root.
     22 //
     23 // The iterator can be initialized to start at the end by providing false for
     24 // aStartAtBeginning in order to start iterating in reverse from the last child.
     25 class FlattenedChildIterator {
     26 public:
     27  explicit FlattenedChildIterator(const nsIContent* aParent,
     28                                  bool aStartAtBeginning = true);
     29 
     30  nsIContent* GetNextChild();
     31 
     32  // Looks for aChildToFind respecting insertion points until aChildToFind is
     33  // found.  This can be O(1) instead of O(N) in many cases.
     34  bool Seek(const nsIContent* aChildToFind);
     35 
     36  // Returns the current target of this iterator (which might be an explicit
     37  // child of the node, or a node assigned to a slot.
     38  nsIContent* Get() const { return mChild; }
     39 
     40  // Returns the original parent we were initialized with.
     41  const nsIContent* Parent() const { return mOriginalParent; }
     42 
     43  // The inverse of GetNextChild. Properly steps in and out of insertion
     44  // points.
     45  nsIContent* GetPreviousChild();
     46 
     47  bool ShadowDOMInvolved() const { return mShadowDOMInvolved; }
     48 
     49  static uint32_t GetLength(const nsINode* aParent);
     50  static Maybe<uint32_t> GetIndexOf(const nsINode* aParent,
     51                                    const nsINode* aPossibleChild);
     52 
     53 protected:
     54  // The parent of the children being iterated. For shadow hosts this will point
     55  // to its shadow root.
     56  const nsIContent* mParent;
     57 
     58  // If parent is a slot element with assigned slots, this points to the parent
     59  // as HTMLSlotElement, otherwise, it's null.
     60  const HTMLSlotElement* mParentAsSlot = nullptr;
     61 
     62  const nsIContent* mOriginalParent = nullptr;
     63 
     64  // The current child.
     65  nsIContent* mChild = nullptr;
     66 
     67  // A flag to let us know that we haven't started iterating yet.
     68  bool mIsFirst = false;
     69 
     70  // The index of the current element in the slot assigned nodes. One-past the
     71  // end to represent the last position.
     72  uint32_t mIndexInInserted = 0u;
     73 
     74  // For certain optimizations, nsCSSFrameConstructor needs to know if the child
     75  // list of the element that we're iterating matches its .childNodes.
     76  bool mShadowDOMInvolved = false;
     77 };
     78 
     79 /**
     80 * AllChildrenIterator traverses the children of an element including before /
     81 * after content and shadow DOM.  The iterator can be initialized to start at
     82 * the end by providing false for aStartAtBeginning in order to start iterating
     83 * in reverse from the last child.
     84 *
     85 * Note: it assumes that no mutation of the DOM or frame tree takes place during
     86 * iteration, and will break horribly if that is not true.
     87 */
     88 class AllChildrenIterator : private FlattenedChildIterator {
     89 public:
     90  AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags,
     91                      bool aStartAtBeginning = true)
     92      : FlattenedChildIterator(aNode, aStartAtBeginning),
     93        mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
     94        mFlags(aFlags),
     95        mPhase(aStartAtBeginning ? Phase::AtBegin : Phase::AtEnd) {}
     96 
     97 #ifdef DEBUG
     98  AllChildrenIterator(AllChildrenIterator&&) = default;
     99 
    100  AllChildrenIterator& operator=(AllChildrenIterator&& aOther) {
    101    // Explicitly call the destructor to ensure the assertion in the destructor
    102    // is checked.
    103    this->~AllChildrenIterator();
    104    new (this) AllChildrenIterator(std::move(aOther));
    105    return *this;
    106  }
    107 
    108  ~AllChildrenIterator() { MOZ_ASSERT(!mMutationGuard.Mutated(0)); }
    109 #endif
    110 
    111  // Returns the current target the iterator is at, or null if the iterator
    112  // doesn't point to any child node (either eAtBegin or eAtEnd phase).
    113  nsIContent* Get() const;
    114 
    115  // Seeks the given node in children of a parent element, starting from
    116  // the current iterator's position, and sets the iterator at the given child
    117  // node if it was found.
    118  bool Seek(const nsIContent* aChildToFind);
    119 
    120  nsIContent* GetNextChild();
    121  nsIContent* GetPreviousChild();
    122 
    123 private:
    124  enum class Phase : uint8_t {
    125    AtBegin,
    126    AtBackdropKid,
    127    AtMarkerKid,
    128    AtBeforeKid,
    129    AtFlatTreeKids,
    130    AtAnonKids,
    131    AtAfterKid,
    132    AtEnd
    133  };
    134 
    135  // Helpers.
    136  void AppendNativeAnonymousChildren();
    137 
    138  // mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
    139  // in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is
    140  // eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If
    141  // mAnonKidsIdx == mAnonKids.Length() then the iterator is somewhere after
    142  // the last native anon child. If mAnonKidsIdx == UINT32_MAX then the iterator
    143  // is somewhere before the first native anon child.
    144  nsTArray<nsIContent*> mAnonKids;
    145  uint32_t mAnonKidsIdx;
    146 
    147  uint32_t mFlags;
    148  Phase mPhase;
    149 #ifdef DEBUG
    150  // XXX we should really assert there are no frame tree changes as well, but
    151  // there's no easy way to do that.
    152  nsMutationGuard mMutationGuard;
    153 #endif
    154 };
    155 
    156 /**
    157 * StyleChildrenIterator traverses the children of the element from the
    158 * perspective of the style system, particularly the children we need to
    159 * traverse during restyle.
    160 *
    161 * At present, this is identical to AllChildrenIterator with
    162 * (eAllChildren | eSkipDocumentLevelNativeAnonymousContent). We used to have
    163 * detect and skip any native anonymous children that are used to implement some
    164 * special magic in here that went away, but we keep the separate class so
    165 * we can reintroduce special magic back if needed.
    166 *
    167 * Note: it assumes that no mutation of the DOM or frame tree takes place during
    168 * iteration, and will break horribly if that is not true.
    169 *
    170 * We require this to be memmovable since Rust code can create and move
    171 * StyleChildrenIterators.
    172 */
    173 class MOZ_NEEDS_MEMMOVABLE_MEMBERS StyleChildrenIterator
    174    : private AllChildrenIterator {
    175 public:
    176  static nsIContent* GetParent(const nsIContent& aContent) {
    177    nsINode* node = aContent.GetFlattenedTreeParentNodeForStyle();
    178    return node && node->IsContent() ? node->AsContent() : nullptr;
    179  }
    180 
    181  explicit StyleChildrenIterator(const nsIContent* aContent,
    182                                 bool aStartAtBeginning = true)
    183      : AllChildrenIterator(
    184            aContent,
    185            nsIContent::eAllChildren |
    186                nsIContent::eSkipDocumentLevelNativeAnonymousContent,
    187            aStartAtBeginning) {
    188    MOZ_COUNT_CTOR(StyleChildrenIterator);
    189  }
    190 
    191  StyleChildrenIterator(StyleChildrenIterator&& aOther)
    192      : AllChildrenIterator(std::move(aOther)) {
    193    MOZ_COUNT_CTOR(StyleChildrenIterator);
    194  }
    195 
    196  StyleChildrenIterator& operator=(StyleChildrenIterator&& aOther) = default;
    197 
    198  MOZ_COUNTED_DTOR(StyleChildrenIterator)
    199 
    200  using AllChildrenIterator::GetNextChild;
    201  using AllChildrenIterator::GetPreviousChild;
    202  using AllChildrenIterator::Seek;
    203 };
    204 
    205 }  // namespace mozilla::dom
    206 
    207 #endif