1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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 this file as it was released on July 19 2008.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Craig Topper.
20 : * Portions created by the Initial Developer are Copyright (C) 2008
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Craig Topper <craig.topper@gmail.com> (Original Author)
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : /*
41 : * Implementation of DOM Traversal's nsIDOMNodeIterator
42 : */
43 :
44 : #include "nsNodeIterator.h"
45 :
46 : #include "nsIDOMNode.h"
47 : #include "nsIDOMNodeFilter.h"
48 : #include "nsDOMError.h"
49 :
50 : #include "nsIContent.h"
51 : #include "nsIDocument.h"
52 :
53 : #include "nsContentUtils.h"
54 : #include "nsCOMPtr.h"
55 :
56 : /*
57 : * NodePointer implementation
58 : */
59 0 : nsNodeIterator::NodePointer::NodePointer(nsINode *aNode,
60 : bool aBeforeNode) :
61 : mNode(aNode),
62 0 : mBeforeNode(aBeforeNode)
63 : {
64 0 : }
65 :
66 0 : bool nsNodeIterator::NodePointer::MoveToNext(nsINode *aRoot)
67 : {
68 0 : if (!mNode)
69 0 : return false;
70 :
71 0 : if (mBeforeNode) {
72 0 : mBeforeNode = false;
73 0 : return true;
74 : }
75 :
76 0 : nsINode* child = mNode->GetFirstChild();
77 0 : if (child) {
78 0 : mNode = child;
79 0 : return true;
80 : }
81 :
82 0 : return MoveForward(aRoot, mNode);
83 : }
84 :
85 0 : bool nsNodeIterator::NodePointer::MoveToPrevious(nsINode *aRoot)
86 : {
87 0 : if (!mNode)
88 0 : return false;
89 :
90 0 : if (!mBeforeNode) {
91 0 : mBeforeNode = true;
92 0 : return true;
93 : }
94 :
95 0 : if (mNode == aRoot)
96 0 : return false;
97 :
98 0 : MoveBackward(mNode->GetNodeParent(), mNode->GetPreviousSibling());
99 :
100 0 : return true;
101 : }
102 :
103 0 : void nsNodeIterator::NodePointer::AdjustAfterRemoval(nsINode *aRoot,
104 : nsINode *aContainer,
105 : nsIContent *aChild,
106 : nsIContent *aPreviousSibling)
107 : {
108 : // If mNode is null or the root there is nothing to do.
109 0 : if (!mNode || mNode == aRoot)
110 0 : return;
111 :
112 : // check if ancestor was removed
113 0 : if (!nsContentUtils::ContentIsDescendantOf(mNode, aChild))
114 0 : return;
115 :
116 0 : if (mBeforeNode) {
117 :
118 : // Try the next sibling
119 0 : nsINode *nextSibling = aPreviousSibling ? aPreviousSibling->GetNextSibling()
120 0 : : aContainer->GetFirstChild();
121 :
122 0 : if (nextSibling) {
123 0 : mNode = nextSibling;
124 0 : return;
125 : }
126 :
127 : // Next try siblings of ancestors
128 0 : if (MoveForward(aRoot, aContainer))
129 0 : return;
130 :
131 : // No suitable node was found so try going backwards
132 0 : mBeforeNode = false;
133 : }
134 :
135 0 : MoveBackward(aContainer, aPreviousSibling);
136 : }
137 :
138 0 : bool nsNodeIterator::NodePointer::MoveForward(nsINode *aRoot, nsINode *aNode)
139 : {
140 0 : while (1) {
141 0 : if (aNode == aRoot)
142 : break;
143 :
144 0 : nsINode *sibling = aNode->GetNextSibling();
145 0 : if (sibling) {
146 0 : mNode = sibling;
147 0 : return true;
148 : }
149 0 : aNode = aNode->GetNodeParent();
150 : }
151 :
152 0 : return false;
153 : }
154 :
155 0 : void nsNodeIterator::NodePointer::MoveBackward(nsINode *aParent, nsINode *aNode)
156 : {
157 0 : if (aNode) {
158 0 : do {
159 0 : mNode = aNode;
160 0 : aNode = aNode->GetLastChild();
161 : } while (aNode);
162 : } else {
163 0 : mNode = aParent;
164 : }
165 0 : }
166 :
167 : /*
168 : * Factories, constructors and destructors
169 : */
170 :
171 0 : nsNodeIterator::nsNodeIterator(nsINode *aRoot,
172 : PRUint32 aWhatToShow,
173 : nsIDOMNodeFilter *aFilter) :
174 : nsTraversal(aRoot, aWhatToShow, aFilter),
175 : mDetached(false),
176 0 : mPointer(mRoot, true)
177 : {
178 0 : aRoot->AddMutationObserver(this);
179 0 : }
180 :
181 0 : nsNodeIterator::~nsNodeIterator()
182 : {
183 : /* destructor code */
184 0 : if (!mDetached && mRoot)
185 0 : mRoot->RemoveMutationObserver(this);
186 0 : }
187 :
188 : /*
189 : * nsISupports and cycle collection stuff
190 : */
191 :
192 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsNodeIterator)
193 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsNodeIterator)
194 0 : if (!tmp->mDetached && tmp->mRoot)
195 0 : tmp->mRoot->RemoveMutationObserver(tmp);
196 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRoot)
197 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFilter)
198 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
199 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsNodeIterator)
200 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot)
201 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFilter)
202 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
203 :
204 : DOMCI_DATA(NodeIterator, nsNodeIterator)
205 :
206 : // QueryInterface implementation for nsNodeIterator
207 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNodeIterator)
208 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMNodeIterator)
209 0 : NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
210 0 : NS_INTERFACE_MAP_ENTRY(nsIMutationObserver2)
211 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNodeIterator)
212 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(NodeIterator)
213 0 : NS_INTERFACE_MAP_END
214 :
215 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNodeIterator)
216 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNodeIterator)
217 :
218 : /* readonly attribute nsIDOMNode root; */
219 0 : NS_IMETHODIMP nsNodeIterator::GetRoot(nsIDOMNode * *aRoot)
220 : {
221 0 : if (mRoot)
222 0 : return CallQueryInterface(mRoot, aRoot);
223 :
224 0 : *aRoot = nsnull;
225 :
226 0 : return NS_OK;
227 : }
228 :
229 : /* readonly attribute unsigned long whatToShow; */
230 0 : NS_IMETHODIMP nsNodeIterator::GetWhatToShow(PRUint32 *aWhatToShow)
231 : {
232 0 : *aWhatToShow = mWhatToShow;
233 0 : return NS_OK;
234 : }
235 :
236 : /* readonly attribute nsIDOMNodeFilter filter; */
237 0 : NS_IMETHODIMP nsNodeIterator::GetFilter(nsIDOMNodeFilter **aFilter)
238 : {
239 0 : NS_ENSURE_ARG_POINTER(aFilter);
240 :
241 0 : NS_IF_ADDREF(*aFilter = mFilter);
242 :
243 0 : return NS_OK;
244 : }
245 :
246 : /* readonly attribute boolean expandEntityReferences; */
247 0 : NS_IMETHODIMP nsNodeIterator::GetExpandEntityReferences(bool *aExpandEntityReferences)
248 : {
249 0 : *aExpandEntityReferences = false;
250 0 : return NS_OK;
251 : }
252 :
253 : /* nsIDOMNode nextNode () raises (DOMException); */
254 0 : NS_IMETHODIMP nsNodeIterator::NextNode(nsIDOMNode **_retval)
255 : {
256 0 : return NextOrPrevNode(&NodePointer::MoveToNext, _retval);
257 : }
258 :
259 : /* nsIDOMNode previousNode () raises (DOMException); */
260 0 : NS_IMETHODIMP nsNodeIterator::PreviousNode(nsIDOMNode **_retval)
261 : {
262 0 : return NextOrPrevNode(&NodePointer::MoveToPrevious, _retval);
263 : }
264 :
265 : nsresult
266 0 : nsNodeIterator::NextOrPrevNode(NodePointer::MoveToMethodType aMove,
267 : nsIDOMNode **_retval)
268 : {
269 : nsresult rv;
270 : PRInt16 filtered;
271 :
272 0 : *_retval = nsnull;
273 :
274 0 : if (mDetached || mInAcceptNode)
275 0 : return NS_ERROR_DOM_INVALID_STATE_ERR;
276 :
277 0 : mWorkingPointer = mPointer;
278 :
279 : struct AutoClear {
280 : NodePointer* mPtr;
281 0 : AutoClear(NodePointer* ptr) : mPtr(ptr) {}
282 0 : ~AutoClear() { mPtr->Clear(); }
283 0 : } ac(&mWorkingPointer);
284 :
285 0 : while ((mWorkingPointer.*aMove)(mRoot)) {
286 0 : nsCOMPtr<nsINode> testNode = mWorkingPointer.mNode;
287 0 : rv = TestNode(testNode, &filtered);
288 0 : NS_ENSURE_SUCCESS(rv, rv);
289 :
290 0 : if (mDetached)
291 0 : return NS_ERROR_DOM_INVALID_STATE_ERR;
292 :
293 0 : if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
294 0 : mPointer = mWorkingPointer;
295 0 : return CallQueryInterface(testNode, _retval);
296 : }
297 : }
298 :
299 0 : return NS_OK;
300 : }
301 :
302 : /* void detach (); */
303 0 : NS_IMETHODIMP nsNodeIterator::Detach(void)
304 : {
305 0 : if (!mDetached) {
306 0 : mRoot->RemoveMutationObserver(this);
307 :
308 0 : mPointer.Clear();
309 :
310 0 : mDetached = true;
311 : }
312 :
313 0 : return NS_OK;
314 : }
315 :
316 : /* readonly attribute nsIDOMNode referenceNode; */
317 0 : NS_IMETHODIMP nsNodeIterator::GetReferenceNode(nsIDOMNode * *aRefNode)
318 : {
319 0 : if (mPointer.mNode)
320 0 : return CallQueryInterface(mPointer.mNode, aRefNode);
321 :
322 0 : *aRefNode = nsnull;
323 0 : return NS_OK;
324 : }
325 :
326 : /* readonly attribute boolean pointerBeforeReferenceNode; */
327 0 : NS_IMETHODIMP nsNodeIterator::GetPointerBeforeReferenceNode(bool *aBeforeNode)
328 : {
329 0 : *aBeforeNode = mPointer.mBeforeNode;
330 0 : return NS_OK;
331 : }
332 :
333 : /*
334 : * nsIMutationObserver interface
335 : */
336 :
337 0 : void nsNodeIterator::ContentRemoved(nsIDocument *aDocument,
338 : nsIContent *aContainer,
339 : nsIContent *aChild,
340 : PRInt32 aIndexInContainer,
341 : nsIContent *aPreviousSibling)
342 : {
343 0 : nsINode *container = NODE_FROM(aContainer, aDocument);
344 :
345 0 : mPointer.AdjustAfterRemoval(mRoot, container, aChild, aPreviousSibling);
346 0 : mWorkingPointer.AdjustAfterRemoval(mRoot, container, aChild, aPreviousSibling);
347 0 : }
348 :
349 0 : void nsNodeIterator::AttributeChildRemoved(nsINode* aAttribute,
350 : nsIContent* aChild)
351 : {
352 0 : mPointer.AdjustAfterRemoval(mRoot, aAttribute, aChild, 0);
353 0 : mWorkingPointer.AdjustAfterRemoval(mRoot, aAttribute, aChild, 0);
354 4392 : }
355 :
|