layout/inspector/inDeepTreeWalker.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial