1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/inspector/inDeepTreeWalker.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,406 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=79: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "inDeepTreeWalker.h" 1.11 +#include "inLayoutUtils.h" 1.12 + 1.13 +#include "nsString.h" 1.14 +#include "nsIDOMDocument.h" 1.15 +#include "nsIDOMNodeFilter.h" 1.16 +#include "nsIDOMNodeList.h" 1.17 +#include "nsServiceManagerUtils.h" 1.18 +#include "inIDOMUtils.h" 1.19 +#include "nsIContent.h" 1.20 +#include "nsContentList.h" 1.21 +#include "ChildIterator.h" 1.22 +#include "mozilla/dom/Element.h" 1.23 + 1.24 +/***************************************************************************** 1.25 + * This implementation does not currently operaate according to the W3C spec. 1.26 + * In particular it does NOT handle DOM mutations during the walk. It also 1.27 + * ignores whatToShow and the filter. 1.28 + *****************************************************************************/ 1.29 + 1.30 +//////////////////////////////////////////////////// 1.31 + 1.32 +inDeepTreeWalker::inDeepTreeWalker() 1.33 + : mShowAnonymousContent(false), 1.34 + mShowSubDocuments(false), 1.35 + mWhatToShow(nsIDOMNodeFilter::SHOW_ALL) 1.36 +{ 1.37 +} 1.38 + 1.39 +inDeepTreeWalker::~inDeepTreeWalker() 1.40 +{ 1.41 +} 1.42 + 1.43 +NS_IMPL_ISUPPORTS(inDeepTreeWalker, 1.44 + inIDeepTreeWalker, 1.45 + nsIDOMTreeWalker) 1.46 + 1.47 +//////////////////////////////////////////////////// 1.48 +// inIDeepTreeWalker 1.49 + 1.50 +NS_IMETHODIMP 1.51 +inDeepTreeWalker::GetShowAnonymousContent(bool *aShowAnonymousContent) 1.52 +{ 1.53 + *aShowAnonymousContent = mShowAnonymousContent; 1.54 + return NS_OK; 1.55 +} 1.56 + 1.57 +NS_IMETHODIMP 1.58 +inDeepTreeWalker::SetShowAnonymousContent(bool aShowAnonymousContent) 1.59 +{ 1.60 + mShowAnonymousContent = aShowAnonymousContent; 1.61 + return NS_OK; 1.62 +} 1.63 + 1.64 +NS_IMETHODIMP 1.65 +inDeepTreeWalker::GetShowSubDocuments(bool *aShowSubDocuments) 1.66 +{ 1.67 + *aShowSubDocuments = mShowSubDocuments; 1.68 + return NS_OK; 1.69 +} 1.70 + 1.71 +NS_IMETHODIMP 1.72 +inDeepTreeWalker::SetShowSubDocuments(bool aShowSubDocuments) 1.73 +{ 1.74 + mShowSubDocuments = aShowSubDocuments; 1.75 + return NS_OK; 1.76 +} 1.77 + 1.78 +NS_IMETHODIMP 1.79 +inDeepTreeWalker::Init(nsIDOMNode* aRoot, uint32_t aWhatToShow) 1.80 +{ 1.81 + mRoot = aRoot; 1.82 + mWhatToShow = aWhatToShow; 1.83 + 1.84 + PushNode(aRoot); 1.85 + 1.86 + return NS_OK; 1.87 +} 1.88 + 1.89 +//////////////////////////////////////////////////// 1.90 +// nsIDOMTreeWalker 1.91 + 1.92 +NS_IMETHODIMP 1.93 +inDeepTreeWalker::GetRoot(nsIDOMNode** aRoot) 1.94 +{ 1.95 + *aRoot = mRoot; 1.96 + NS_IF_ADDREF(*aRoot); 1.97 + 1.98 + return NS_OK; 1.99 +} 1.100 + 1.101 +NS_IMETHODIMP 1.102 +inDeepTreeWalker::GetWhatToShow(uint32_t* aWhatToShow) 1.103 +{ 1.104 + *aWhatToShow = mWhatToShow; 1.105 + return NS_OK; 1.106 +} 1.107 + 1.108 +NS_IMETHODIMP 1.109 +inDeepTreeWalker::GetFilter(nsIDOMNodeFilter** aFilter) 1.110 +{ 1.111 + return NS_ERROR_NOT_IMPLEMENTED; 1.112 +} 1.113 + 1.114 +NS_IMETHODIMP 1.115 +inDeepTreeWalker::GetCurrentNode(nsIDOMNode** aCurrentNode) 1.116 +{ 1.117 + *aCurrentNode = mCurrentNode; 1.118 + NS_IF_ADDREF(*aCurrentNode); 1.119 + 1.120 + return NS_OK; 1.121 +} 1.122 + 1.123 +NS_IMETHODIMP 1.124 +inDeepTreeWalker::SetCurrentNode(nsIDOMNode* aCurrentNode) 1.125 +{ 1.126 + return NS_ERROR_NOT_IMPLEMENTED; 1.127 +} 1.128 + 1.129 +NS_IMETHODIMP 1.130 +inDeepTreeWalker::ParentNode(nsIDOMNode** _retval) 1.131 +{ 1.132 + *_retval = nullptr; 1.133 + if (!mCurrentNode) return NS_OK; 1.134 + 1.135 + if (mStack.Length() == 1) { 1.136 + // No parent 1.137 + return NS_OK; 1.138 + } 1.139 + 1.140 + // Pop off the current node, and push the new one 1.141 + mStack.RemoveElementAt(mStack.Length()-1); 1.142 + DeepTreeStackItem& top = mStack.ElementAt(mStack.Length() - 1); 1.143 + mCurrentNode = top.node; 1.144 + top.lastIndex = 0; 1.145 + NS_ADDREF(*_retval = mCurrentNode); 1.146 + return NS_OK; 1.147 +} 1.148 + 1.149 +NS_IMETHODIMP 1.150 +inDeepTreeWalker::FirstChild(nsIDOMNode **_retval) 1.151 +{ 1.152 + *_retval = nullptr; 1.153 + if (!mCurrentNode) { 1.154 + return NS_OK; 1.155 + } 1.156 + 1.157 + DeepTreeStackItem& top = mStack.ElementAt(mStack.Length() - 1); 1.158 + nsCOMPtr<nsIDOMNode> kid; 1.159 + top.kids->Item(0, getter_AddRefs(kid)); 1.160 + if (!kid) { 1.161 + return NS_OK; 1.162 + } 1.163 + top.lastIndex = 1; 1.164 + PushNode(kid); 1.165 + kid.forget(_retval); 1.166 + return NS_OK; 1.167 +} 1.168 + 1.169 +NS_IMETHODIMP 1.170 +inDeepTreeWalker::LastChild(nsIDOMNode **_retval) 1.171 +{ 1.172 + *_retval = nullptr; 1.173 + if (!mCurrentNode) { 1.174 + return NS_OK; 1.175 + } 1.176 + 1.177 + DeepTreeStackItem& top = mStack.ElementAt(mStack.Length() - 1); 1.178 + nsCOMPtr<nsIDOMNode> kid; 1.179 + uint32_t length; 1.180 + top.kids->GetLength(&length); 1.181 + top.kids->Item(length - 1, getter_AddRefs(kid)); 1.182 + if (!kid) { 1.183 + return NS_OK; 1.184 + } 1.185 + top.lastIndex = length; 1.186 + PushNode(kid); 1.187 + kid.forget(_retval); 1.188 + return NS_OK; 1.189 +} 1.190 + 1.191 +NS_IMETHODIMP 1.192 +inDeepTreeWalker::PreviousSibling(nsIDOMNode **_retval) 1.193 +{ 1.194 + *_retval = nullptr; 1.195 + if (!mCurrentNode) { 1.196 + return NS_OK; 1.197 + } 1.198 + 1.199 + NS_ASSERTION(mStack.Length() > 0, "Should have things in mStack"); 1.200 + 1.201 + if (mStack.Length() == 1) { 1.202 + // No previous sibling 1.203 + return NS_OK; 1.204 + } 1.205 + 1.206 + DeepTreeStackItem& parent = mStack.ElementAt(mStack.Length()-2); 1.207 + nsCOMPtr<nsIDOMNode> previousSibling; 1.208 + parent.kids->Item(parent.lastIndex-2, getter_AddRefs(previousSibling)); 1.209 + if (!previousSibling) { 1.210 + return NS_OK; 1.211 + } 1.212 + 1.213 + // Our mStack's topmost element is our current node. Since we're trying to 1.214 + // change that to the previous sibling, pop off the current node, and push 1.215 + // the new one. 1.216 + mStack.RemoveElementAt(mStack.Length() - 1); 1.217 + parent.lastIndex--; 1.218 + PushNode(previousSibling); 1.219 + previousSibling.forget(_retval); 1.220 + return NS_OK; 1.221 +} 1.222 + 1.223 +NS_IMETHODIMP 1.224 +inDeepTreeWalker::NextSibling(nsIDOMNode **_retval) 1.225 +{ 1.226 + *_retval = nullptr; 1.227 + if (!mCurrentNode) { 1.228 + return NS_OK; 1.229 + } 1.230 + 1.231 + NS_ASSERTION(mStack.Length() > 0, "Should have things in mStack"); 1.232 + 1.233 + if (mStack.Length() == 1) { 1.234 + // No next sibling 1.235 + return NS_OK; 1.236 + } 1.237 + 1.238 + DeepTreeStackItem& parent = mStack.ElementAt(mStack.Length()-2); 1.239 + nsCOMPtr<nsIDOMNode> nextSibling; 1.240 + parent.kids->Item(parent.lastIndex, getter_AddRefs(nextSibling)); 1.241 + if (!nextSibling) { 1.242 + return NS_OK; 1.243 + } 1.244 + 1.245 + // Our mStack's topmost element is our current node. Since we're trying to 1.246 + // change that to the next sibling, pop off the current node, and push 1.247 + // the new one. 1.248 + mStack.RemoveElementAt(mStack.Length() - 1); 1.249 + parent.lastIndex++; 1.250 + PushNode(nextSibling); 1.251 + nextSibling.forget(_retval); 1.252 + return NS_OK; 1.253 +} 1.254 + 1.255 +NS_IMETHODIMP 1.256 +inDeepTreeWalker::PreviousNode(nsIDOMNode **_retval) 1.257 +{ 1.258 + if (!mCurrentNode || mStack.Length() == 1) { 1.259 + // Nowhere to go from here 1.260 + *_retval = nullptr; 1.261 + return NS_OK; 1.262 + } 1.263 + 1.264 + nsCOMPtr<nsIDOMNode> node; 1.265 + PreviousSibling(getter_AddRefs(node)); 1.266 + 1.267 + if (!node) { 1.268 + return ParentNode(_retval); 1.269 + } 1.270 + 1.271 + // Now we're positioned at our previous sibling. But since the DOM tree 1.272 + // traversal is depth-first, the previous node is its most deeply nested last 1.273 + // child. Just loop until LastChild() returns null; since the LastChild() 1.274 + // call that returns null won't affect our position, we will then be 1.275 + // positioned at the correct node. 1.276 + while (node) { 1.277 + LastChild(getter_AddRefs(node)); 1.278 + } 1.279 + 1.280 + NS_ADDREF(*_retval = mCurrentNode); 1.281 + return NS_OK; 1.282 +} 1.283 + 1.284 +NS_IMETHODIMP 1.285 +inDeepTreeWalker::NextNode(nsIDOMNode **_retval) 1.286 +{ 1.287 + // First try our kids 1.288 + FirstChild(_retval); 1.289 + 1.290 + if (*_retval) { 1.291 + return NS_OK; 1.292 + } 1.293 + 1.294 + // Now keep trying next siblings up the parent chain, but if we 1.295 + // discover there's nothing else restore our state. 1.296 +#ifdef DEBUG 1.297 + nsIDOMNode* origCurrentNode = mCurrentNode; 1.298 +#endif 1.299 + uint32_t lastChildCallsToMake = 0; 1.300 + while (1) { 1.301 + NextSibling(_retval); 1.302 + 1.303 + if (*_retval) { 1.304 + return NS_OK; 1.305 + } 1.306 + 1.307 + nsCOMPtr<nsIDOMNode> parent; 1.308 + ParentNode(getter_AddRefs(parent)); 1.309 + if (!parent) { 1.310 + // Nowhere else to go; we're done. Restore our state. 1.311 + while (lastChildCallsToMake--) { 1.312 + nsCOMPtr<nsIDOMNode> dummy; 1.313 + LastChild(getter_AddRefs(dummy)); 1.314 + } 1.315 + NS_ASSERTION(mCurrentNode == origCurrentNode, 1.316 + "Didn't go back to the right node?"); 1.317 + *_retval = nullptr; 1.318 + return NS_OK; 1.319 + } 1.320 + ++lastChildCallsToMake; 1.321 + } 1.322 + 1.323 + NS_NOTREACHED("how did we get here?"); 1.324 + return NS_OK; 1.325 +} 1.326 + 1.327 +void 1.328 +inDeepTreeWalker::PushNode(nsIDOMNode* aNode) 1.329 +{ 1.330 + mCurrentNode = aNode; 1.331 + if (!aNode) return; 1.332 + 1.333 + DeepTreeStackItem item; 1.334 + item.node = aNode; 1.335 + 1.336 + nsCOMPtr<nsIDOMNodeList> kids; 1.337 + if (mShowSubDocuments) { 1.338 + nsCOMPtr<nsIDOMDocument> domdoc = inLayoutUtils::GetSubDocumentFor(aNode); 1.339 + if (domdoc) { 1.340 + domdoc->GetChildNodes(getter_AddRefs(kids)); 1.341 + } 1.342 + } 1.343 + 1.344 + if (!kids) { 1.345 + nsCOMPtr<nsIContent> content = do_QueryInterface(aNode); 1.346 + if (content && mShowAnonymousContent) { 1.347 + kids = content->GetChildren(nsIContent::eAllChildren); 1.348 + } 1.349 + } 1.350 + if (!kids) { 1.351 + aNode->GetChildNodes(getter_AddRefs(kids)); 1.352 + } 1.353 + 1.354 + item.kids = kids; 1.355 + item.lastIndex = 0; 1.356 + mStack.AppendElement(item); 1.357 +} 1.358 + 1.359 +/* 1.360 +// This NextNode implementation does not require the use of stacks, 1.361 +// as does the one above. However, it does not handle anonymous 1.362 +// content and sub-documents. 1.363 +NS_IMETHODIMP 1.364 +inDeepTreeWalker::NextNode(nsIDOMNode **_retval) 1.365 +{ 1.366 + if (!mCurrentNode) return NS_OK; 1.367 + 1.368 + // walk down the tree first 1.369 + nsCOMPtr<nsIDOMNode> next; 1.370 + mCurrentNode->GetFirstChild(getter_AddRefs(next)); 1.371 + if (!next) { 1.372 + mCurrentNode->GetNextSibling(getter_AddRefs(next)); 1.373 + if (!next) { 1.374 + // we've hit the end, so walk back up the tree until another 1.375 + // downward opening is found, or the top of the tree 1.376 + nsCOMPtr<nsIDOMNode> subject = mCurrentNode; 1.377 + nsCOMPtr<nsIDOMNode> parent; 1.378 + while (1) { 1.379 + subject->GetParentNode(getter_AddRefs(parent)); 1.380 + if (!parent) // hit the top of the tree 1.381 + break; 1.382 + parent->GetNextSibling(getter_AddRefs(subject)); 1.383 + if (subject) { // found a downward opening 1.384 + next = subject; 1.385 + break; 1.386 + } else // walk up another level 1.387 + subject = parent; 1.388 + } 1.389 + } 1.390 + } 1.391 + 1.392 + mCurrentNode = next; 1.393 + 1.394 + *_retval = next; 1.395 + NS_IF_ADDREF(*_retval); 1.396 + 1.397 + return NS_OK; 1.398 +} 1.399 + 1.400 + 1.401 +char* getURL(nsIDOMDocument* aDoc) 1.402 +{ 1.403 + nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc); 1.404 + nsIURI *uri = doc->GetDocumentURI(); 1.405 + char* s; 1.406 + uri->GetSpec(&s); 1.407 + return s; 1.408 +} 1.409 +*/