layout/inspector/inDeepTreeWalker.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:3e5c64ece398
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=79: */
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
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "inDeepTreeWalker.h"
8 #include "inLayoutUtils.h"
9
10 #include "nsString.h"
11 #include "nsIDOMDocument.h"
12 #include "nsIDOMNodeFilter.h"
13 #include "nsIDOMNodeList.h"
14 #include "nsServiceManagerUtils.h"
15 #include "inIDOMUtils.h"
16 #include "nsIContent.h"
17 #include "nsContentList.h"
18 #include "ChildIterator.h"
19 #include "mozilla/dom/Element.h"
20
21 /*****************************************************************************
22 * This implementation does not currently operaate according to the W3C spec.
23 * In particular it does NOT handle DOM mutations during the walk. It also
24 * ignores whatToShow and the filter.
25 *****************************************************************************/
26
27 ////////////////////////////////////////////////////
28
29 inDeepTreeWalker::inDeepTreeWalker()
30 : mShowAnonymousContent(false),
31 mShowSubDocuments(false),
32 mWhatToShow(nsIDOMNodeFilter::SHOW_ALL)
33 {
34 }
35
36 inDeepTreeWalker::~inDeepTreeWalker()
37 {
38 }
39
40 NS_IMPL_ISUPPORTS(inDeepTreeWalker,
41 inIDeepTreeWalker,
42 nsIDOMTreeWalker)
43
44 ////////////////////////////////////////////////////
45 // inIDeepTreeWalker
46
47 NS_IMETHODIMP
48 inDeepTreeWalker::GetShowAnonymousContent(bool *aShowAnonymousContent)
49 {
50 *aShowAnonymousContent = mShowAnonymousContent;
51 return NS_OK;
52 }
53
54 NS_IMETHODIMP
55 inDeepTreeWalker::SetShowAnonymousContent(bool aShowAnonymousContent)
56 {
57 mShowAnonymousContent = aShowAnonymousContent;
58 return NS_OK;
59 }
60
61 NS_IMETHODIMP
62 inDeepTreeWalker::GetShowSubDocuments(bool *aShowSubDocuments)
63 {
64 *aShowSubDocuments = mShowSubDocuments;
65 return NS_OK;
66 }
67
68 NS_IMETHODIMP
69 inDeepTreeWalker::SetShowSubDocuments(bool aShowSubDocuments)
70 {
71 mShowSubDocuments = aShowSubDocuments;
72 return NS_OK;
73 }
74
75 NS_IMETHODIMP
76 inDeepTreeWalker::Init(nsIDOMNode* aRoot, uint32_t aWhatToShow)
77 {
78 mRoot = aRoot;
79 mWhatToShow = aWhatToShow;
80
81 PushNode(aRoot);
82
83 return NS_OK;
84 }
85
86 ////////////////////////////////////////////////////
87 // nsIDOMTreeWalker
88
89 NS_IMETHODIMP
90 inDeepTreeWalker::GetRoot(nsIDOMNode** aRoot)
91 {
92 *aRoot = mRoot;
93 NS_IF_ADDREF(*aRoot);
94
95 return NS_OK;
96 }
97
98 NS_IMETHODIMP
99 inDeepTreeWalker::GetWhatToShow(uint32_t* aWhatToShow)
100 {
101 *aWhatToShow = mWhatToShow;
102 return NS_OK;
103 }
104
105 NS_IMETHODIMP
106 inDeepTreeWalker::GetFilter(nsIDOMNodeFilter** aFilter)
107 {
108 return NS_ERROR_NOT_IMPLEMENTED;
109 }
110
111 NS_IMETHODIMP
112 inDeepTreeWalker::GetCurrentNode(nsIDOMNode** aCurrentNode)
113 {
114 *aCurrentNode = mCurrentNode;
115 NS_IF_ADDREF(*aCurrentNode);
116
117 return NS_OK;
118 }
119
120 NS_IMETHODIMP
121 inDeepTreeWalker::SetCurrentNode(nsIDOMNode* aCurrentNode)
122 {
123 return NS_ERROR_NOT_IMPLEMENTED;
124 }
125
126 NS_IMETHODIMP
127 inDeepTreeWalker::ParentNode(nsIDOMNode** _retval)
128 {
129 *_retval = nullptr;
130 if (!mCurrentNode) return NS_OK;
131
132 if (mStack.Length() == 1) {
133 // No parent
134 return NS_OK;
135 }
136
137 // Pop off the current node, and push the new one
138 mStack.RemoveElementAt(mStack.Length()-1);
139 DeepTreeStackItem& top = mStack.ElementAt(mStack.Length() - 1);
140 mCurrentNode = top.node;
141 top.lastIndex = 0;
142 NS_ADDREF(*_retval = mCurrentNode);
143 return NS_OK;
144 }
145
146 NS_IMETHODIMP
147 inDeepTreeWalker::FirstChild(nsIDOMNode **_retval)
148 {
149 *_retval = nullptr;
150 if (!mCurrentNode) {
151 return NS_OK;
152 }
153
154 DeepTreeStackItem& top = mStack.ElementAt(mStack.Length() - 1);
155 nsCOMPtr<nsIDOMNode> kid;
156 top.kids->Item(0, getter_AddRefs(kid));
157 if (!kid) {
158 return NS_OK;
159 }
160 top.lastIndex = 1;
161 PushNode(kid);
162 kid.forget(_retval);
163 return NS_OK;
164 }
165
166 NS_IMETHODIMP
167 inDeepTreeWalker::LastChild(nsIDOMNode **_retval)
168 {
169 *_retval = nullptr;
170 if (!mCurrentNode) {
171 return NS_OK;
172 }
173
174 DeepTreeStackItem& top = mStack.ElementAt(mStack.Length() - 1);
175 nsCOMPtr<nsIDOMNode> kid;
176 uint32_t length;
177 top.kids->GetLength(&length);
178 top.kids->Item(length - 1, getter_AddRefs(kid));
179 if (!kid) {
180 return NS_OK;
181 }
182 top.lastIndex = length;
183 PushNode(kid);
184 kid.forget(_retval);
185 return NS_OK;
186 }
187
188 NS_IMETHODIMP
189 inDeepTreeWalker::PreviousSibling(nsIDOMNode **_retval)
190 {
191 *_retval = nullptr;
192 if (!mCurrentNode) {
193 return NS_OK;
194 }
195
196 NS_ASSERTION(mStack.Length() > 0, "Should have things in mStack");
197
198 if (mStack.Length() == 1) {
199 // No previous sibling
200 return NS_OK;
201 }
202
203 DeepTreeStackItem& parent = mStack.ElementAt(mStack.Length()-2);
204 nsCOMPtr<nsIDOMNode> previousSibling;
205 parent.kids->Item(parent.lastIndex-2, getter_AddRefs(previousSibling));
206 if (!previousSibling) {
207 return NS_OK;
208 }
209
210 // Our mStack's topmost element is our current node. Since we're trying to
211 // change that to the previous sibling, pop off the current node, and push
212 // the new one.
213 mStack.RemoveElementAt(mStack.Length() - 1);
214 parent.lastIndex--;
215 PushNode(previousSibling);
216 previousSibling.forget(_retval);
217 return NS_OK;
218 }
219
220 NS_IMETHODIMP
221 inDeepTreeWalker::NextSibling(nsIDOMNode **_retval)
222 {
223 *_retval = nullptr;
224 if (!mCurrentNode) {
225 return NS_OK;
226 }
227
228 NS_ASSERTION(mStack.Length() > 0, "Should have things in mStack");
229
230 if (mStack.Length() == 1) {
231 // No next sibling
232 return NS_OK;
233 }
234
235 DeepTreeStackItem& parent = mStack.ElementAt(mStack.Length()-2);
236 nsCOMPtr<nsIDOMNode> nextSibling;
237 parent.kids->Item(parent.lastIndex, getter_AddRefs(nextSibling));
238 if (!nextSibling) {
239 return NS_OK;
240 }
241
242 // Our mStack's topmost element is our current node. Since we're trying to
243 // change that to the next sibling, pop off the current node, and push
244 // the new one.
245 mStack.RemoveElementAt(mStack.Length() - 1);
246 parent.lastIndex++;
247 PushNode(nextSibling);
248 nextSibling.forget(_retval);
249 return NS_OK;
250 }
251
252 NS_IMETHODIMP
253 inDeepTreeWalker::PreviousNode(nsIDOMNode **_retval)
254 {
255 if (!mCurrentNode || mStack.Length() == 1) {
256 // Nowhere to go from here
257 *_retval = nullptr;
258 return NS_OK;
259 }
260
261 nsCOMPtr<nsIDOMNode> node;
262 PreviousSibling(getter_AddRefs(node));
263
264 if (!node) {
265 return ParentNode(_retval);
266 }
267
268 // Now we're positioned at our previous sibling. But since the DOM tree
269 // traversal is depth-first, the previous node is its most deeply nested last
270 // child. Just loop until LastChild() returns null; since the LastChild()
271 // call that returns null won't affect our position, we will then be
272 // positioned at the correct node.
273 while (node) {
274 LastChild(getter_AddRefs(node));
275 }
276
277 NS_ADDREF(*_retval = mCurrentNode);
278 return NS_OK;
279 }
280
281 NS_IMETHODIMP
282 inDeepTreeWalker::NextNode(nsIDOMNode **_retval)
283 {
284 // First try our kids
285 FirstChild(_retval);
286
287 if (*_retval) {
288 return NS_OK;
289 }
290
291 // Now keep trying next siblings up the parent chain, but if we
292 // discover there's nothing else restore our state.
293 #ifdef DEBUG
294 nsIDOMNode* origCurrentNode = mCurrentNode;
295 #endif
296 uint32_t lastChildCallsToMake = 0;
297 while (1) {
298 NextSibling(_retval);
299
300 if (*_retval) {
301 return NS_OK;
302 }
303
304 nsCOMPtr<nsIDOMNode> parent;
305 ParentNode(getter_AddRefs(parent));
306 if (!parent) {
307 // Nowhere else to go; we're done. Restore our state.
308 while (lastChildCallsToMake--) {
309 nsCOMPtr<nsIDOMNode> dummy;
310 LastChild(getter_AddRefs(dummy));
311 }
312 NS_ASSERTION(mCurrentNode == origCurrentNode,
313 "Didn't go back to the right node?");
314 *_retval = nullptr;
315 return NS_OK;
316 }
317 ++lastChildCallsToMake;
318 }
319
320 NS_NOTREACHED("how did we get here?");
321 return NS_OK;
322 }
323
324 void
325 inDeepTreeWalker::PushNode(nsIDOMNode* aNode)
326 {
327 mCurrentNode = aNode;
328 if (!aNode) return;
329
330 DeepTreeStackItem item;
331 item.node = aNode;
332
333 nsCOMPtr<nsIDOMNodeList> kids;
334 if (mShowSubDocuments) {
335 nsCOMPtr<nsIDOMDocument> domdoc = inLayoutUtils::GetSubDocumentFor(aNode);
336 if (domdoc) {
337 domdoc->GetChildNodes(getter_AddRefs(kids));
338 }
339 }
340
341 if (!kids) {
342 nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
343 if (content && mShowAnonymousContent) {
344 kids = content->GetChildren(nsIContent::eAllChildren);
345 }
346 }
347 if (!kids) {
348 aNode->GetChildNodes(getter_AddRefs(kids));
349 }
350
351 item.kids = kids;
352 item.lastIndex = 0;
353 mStack.AppendElement(item);
354 }
355
356 /*
357 // This NextNode implementation does not require the use of stacks,
358 // as does the one above. However, it does not handle anonymous
359 // content and sub-documents.
360 NS_IMETHODIMP
361 inDeepTreeWalker::NextNode(nsIDOMNode **_retval)
362 {
363 if (!mCurrentNode) return NS_OK;
364
365 // walk down the tree first
366 nsCOMPtr<nsIDOMNode> next;
367 mCurrentNode->GetFirstChild(getter_AddRefs(next));
368 if (!next) {
369 mCurrentNode->GetNextSibling(getter_AddRefs(next));
370 if (!next) {
371 // we've hit the end, so walk back up the tree until another
372 // downward opening is found, or the top of the tree
373 nsCOMPtr<nsIDOMNode> subject = mCurrentNode;
374 nsCOMPtr<nsIDOMNode> parent;
375 while (1) {
376 subject->GetParentNode(getter_AddRefs(parent));
377 if (!parent) // hit the top of the tree
378 break;
379 parent->GetNextSibling(getter_AddRefs(subject));
380 if (subject) { // found a downward opening
381 next = subject;
382 break;
383 } else // walk up another level
384 subject = parent;
385 }
386 }
387 }
388
389 mCurrentNode = next;
390
391 *_retval = next;
392 NS_IF_ADDREF(*_retval);
393
394 return NS_OK;
395 }
396
397
398 char* getURL(nsIDOMDocument* aDoc)
399 {
400 nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
401 nsIURI *uri = doc->GetDocumentURI();
402 char* s;
403 uri->GetSpec(&s);
404 return s;
405 }
406 */

mercurial