1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : // vim:cindent:ts=2:et:sw=2:
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /*
40 : * used by nsCSSFrameConstructor to determine and iterate the child list
41 : * used to construct frames (normal children or something from XBL)
42 : */
43 :
44 : #include "nsCOMPtr.h"
45 : #include "nsIContent.h"
46 : #include "nsINodeList.h"
47 :
48 : /**
49 : * Helper class for iterating children during frame construction.
50 : * This class should always be used in lieu of the straight content
51 : * node APIs, since it handles XBL-generated anonymous content as
52 : * well.
53 : */
54 : class NS_STACK_CLASS ChildIterator
55 : {
56 : protected:
57 : nsIContent* mContent;
58 : // If mNodes is non-null (so XBLInvolved() is true), mIndex is the
59 : // index into mNodes for our current position. Otherwise, mChild is
60 : // our current child (which might be null if we're done iterating).
61 : union {
62 : PRUint32 mIndex;
63 : nsIContent* mChild;
64 : };
65 : nsINodeList* mNodes;
66 :
67 : public:
68 0 : ChildIterator()
69 0 : : mContent(nsnull), mChild(0), mNodes(nsnull) {}
70 :
71 0 : ChildIterator(const ChildIterator& aOther)
72 : : mContent(aOther.mContent),
73 0 : mNodes(aOther.mNodes) {
74 0 : if (XBLInvolved()) {
75 0 : mIndex = aOther.mIndex;
76 : } else {
77 0 : mChild = aOther.mChild;
78 : }
79 0 : }
80 :
81 0 : ChildIterator& operator=(const ChildIterator& aOther) {
82 0 : mContent = aOther.mContent;
83 0 : mNodes = aOther.mNodes;
84 0 : if (XBLInvolved()) {
85 0 : mIndex = aOther.mIndex;
86 : } else {
87 0 : mChild = aOther.mChild;
88 : }
89 0 : return *this;
90 : }
91 :
92 0 : ChildIterator& operator++() {
93 0 : if (XBLInvolved()) {
94 0 : ++mIndex;
95 : } else {
96 0 : NS_ASSERTION(mChild, "Walking off end of list?");
97 0 : mChild = mChild->GetNextSibling();
98 : }
99 :
100 0 : return *this;
101 : }
102 :
103 : ChildIterator operator++(int) {
104 : ChildIterator result(*this);
105 : ++(*this);
106 : return result;
107 : }
108 :
109 0 : ChildIterator& operator--() {
110 0 : if (XBLInvolved()) {
111 0 : --mIndex;
112 0 : } else if (mChild) {
113 0 : mChild = mChild->GetPreviousSibling();
114 0 : NS_ASSERTION(mChild, "Walking off beginning of list");
115 : } else {
116 0 : mChild = mContent->GetLastChild();
117 : }
118 0 : return *this;
119 : }
120 :
121 0 : ChildIterator operator--(int) {
122 0 : ChildIterator result(*this);
123 0 : --(*this);
124 : return result;
125 : }
126 :
127 0 : nsIContent* get() const {
128 0 : if (XBLInvolved()) {
129 0 : return mNodes->GetNodeAt(mIndex);
130 : }
131 :
132 0 : return mChild;
133 : }
134 :
135 0 : nsIContent* operator*() const { return get(); }
136 :
137 0 : bool operator==(const ChildIterator& aOther) const {
138 0 : if (XBLInvolved()) {
139 0 : return mContent == aOther.mContent && mIndex == aOther.mIndex;
140 : }
141 :
142 0 : return mContent == aOther.mContent && mChild == aOther.mChild;
143 : }
144 :
145 0 : bool operator!=(const ChildIterator& aOther) const {
146 0 : return !aOther.operator==(*this);
147 : }
148 :
149 0 : void seek(nsIContent* aContent) {
150 0 : if (XBLInvolved()) {
151 0 : PRInt32 index = mNodes->IndexOf(aContent);
152 : // XXXbz I wish we could assert that index != -1, but it seems to not be
153 : // the case in some XBL cases with filtered insertion points and no
154 : // default insertion point. I will now claim that XBL's management of
155 : // its insertion points is broken in those cases, since it's returning an
156 : // insertion parent for a node that doesn't actually have the node in its
157 : // child list according to ChildIterator. See bug 474324.
158 0 : if (index != -1) {
159 0 : mIndex = index;
160 : } else {
161 : // If aContent isn't going to get hit by this iterator, just seek to the
162 : // end of the list for lack of anything better to do.
163 0 : mIndex = length();
164 : }
165 0 : } else if (aContent->GetParent() == mContent) {
166 0 : mChild = aContent;
167 : } else {
168 : // XXXbz I wish we could assert this doesn't happen, but I think that's
169 : // not necessarily the case when called from ContentInserted if
170 : // first-letter frames are about.
171 0 : mChild = nsnull;
172 : }
173 0 : }
174 :
175 0 : bool XBLInvolved() const { return mNodes != nsnull; }
176 :
177 : /**
178 : * Create a pair of ChildIterators for a content node. aFirst will
179 : * point to the first child of aContent; aLast will point one past
180 : * the last child of aContent.
181 : */
182 : static nsresult Init(nsIContent* aContent,
183 : ChildIterator* aFirst,
184 : ChildIterator* aLast);
185 :
186 : private:
187 0 : PRUint32 length() {
188 0 : NS_PRECONDITION(XBLInvolved(), "Don't call me");
189 : PRUint32 l;
190 0 : mNodes->GetLength(&l);
191 0 : return l;
192 : }
193 : };
|