michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 sw=2 et tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef ChildIterator_h michael@0: #define ChildIterator_h michael@0: michael@0: /** michael@0: * Iterates over the children on a node. If a child is an insertion point, michael@0: * iterates over the children inserted there instead, or the default content michael@0: * if no children are inserted there. michael@0: * michael@0: * The FlattenedChildIterator expands any anonymous content bound from an XBL michael@0: * binding's element. michael@0: */ michael@0: michael@0: #include "nsIContent.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: // This class iterates normal DOM child nodes of a given DOM node with michael@0: // nodes replaced by the elements that have been filtered into that michael@0: // insertion point. Any bindings on the given element are ignored for purposes michael@0: // of determining which insertion point children are filtered into. The iterator michael@0: // can be initialized to start at the end by providing false for aStartAtBeginning michael@0: // in order to start iterating in reverse from the last child. michael@0: class ExplicitChildIterator michael@0: { michael@0: public: michael@0: ExplicitChildIterator(nsIContent* aParent, bool aStartAtBeginning = true) michael@0: : mParent(aParent), michael@0: mChild(nullptr), michael@0: mDefaultChild(nullptr), michael@0: mIndexInInserted(0), michael@0: mIsFirst(aStartAtBeginning) michael@0: { michael@0: } michael@0: michael@0: nsIContent* GetNextChild(); michael@0: michael@0: // Looks for aChildToFind respecting insertion points until aChildToFind michael@0: // or aBound is found. If aBound is nullptr then the seek is unbounded. Returns michael@0: // whether aChildToFind was found as an explicit child prior to encountering michael@0: // aBound. michael@0: bool Seek(nsIContent* aChildToFind, nsIContent* aBound = nullptr) michael@0: { michael@0: // It would be nice to assert that we find aChildToFind, but bz thinks that michael@0: // we might not find aChildToFind when called from ContentInserted michael@0: // if first-letter frames are about. michael@0: michael@0: nsIContent* child; michael@0: do { michael@0: child = GetNextChild(); michael@0: } while (child && child != aChildToFind && child != aBound); michael@0: michael@0: return child == aChildToFind; michael@0: } michael@0: michael@0: // Returns the current target of this iterator (which might be an explicit michael@0: // child of the node, fallback content of an insertion point or michael@0: // a node distributed to an insertion point. michael@0: nsIContent* Get(); michael@0: michael@0: // The inverse of GetNextChild. Properly steps in and out of insertion michael@0: // points. michael@0: nsIContent* GetPreviousChild(); michael@0: michael@0: protected: michael@0: // The parent of the children being iterated. For the FlattenedChildIterator, michael@0: // if there is a binding attached to the original parent, mParent points to michael@0: // the element for the binding. michael@0: nsIContent* mParent; michael@0: michael@0: // The current child. When we encounter an insertion point, michael@0: // mChild remains as the insertion point whose content we're iterating (and michael@0: // our state is controled by mDefaultChild or mIndexInInserted depending on michael@0: // whether the insertion point expands to its default content or not). michael@0: nsIContent* mChild; michael@0: michael@0: // If non-null, this points to the current default content for the current michael@0: // insertion point that we're iterating (i.e. mChild, which must be an michael@0: // nsXBLChildrenElement or HTMLContentElement). Once this transitions back michael@0: // to null, we continue iterating at mChild's next sibling. michael@0: nsIContent* mDefaultChild; michael@0: michael@0: // If non-null, this points to an iterator of the explicit children of michael@0: // the ShadowRoot projected by the current shadow element that we're michael@0: // iterating. michael@0: nsAutoPtr mShadowIterator; michael@0: michael@0: // If not zero, we're iterating inserted children for an insertion point. This michael@0: // is an index into mChild's inserted children array (mChild must be an michael@0: // nsXBLChildrenElement). The index is one past the "current" child (as michael@0: // opposed to mChild which represents the "current" child). michael@0: uint32_t mIndexInInserted; michael@0: michael@0: // A flag to let us know that we haven't started iterating yet. michael@0: bool mIsFirst; michael@0: }; michael@0: michael@0: // Iterates over the flattened children of a node, which accounts for anonymous michael@0: // children and nodes moved by insertion points. If a node has anonymous michael@0: // children, those are iterated over. michael@0: class FlattenedChildIterator : public ExplicitChildIterator michael@0: { michael@0: public: michael@0: FlattenedChildIterator(nsIContent* aParent); michael@0: michael@0: bool XBLInvolved() { return mXBLInvolved; } michael@0: michael@0: private: michael@0: // For certain optimizations, nsCSSFrameConstructor needs to know if the michael@0: // child list of the element that we're iterating matches its .childNodes. michael@0: bool mXBLInvolved; michael@0: }; michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla michael@0: michael@0: #endif