layout/inspector/inDeepTreeWalker.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     7 #include "inDeepTreeWalker.h"
     8 #include "inLayoutUtils.h"
    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"
    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  *****************************************************************************/
    27 ////////////////////////////////////////////////////
    29 inDeepTreeWalker::inDeepTreeWalker() 
    30   : mShowAnonymousContent(false),
    31     mShowSubDocuments(false),
    32     mWhatToShow(nsIDOMNodeFilter::SHOW_ALL)
    33 {
    34 }
    36 inDeepTreeWalker::~inDeepTreeWalker() 
    37 { 
    38 }
    40 NS_IMPL_ISUPPORTS(inDeepTreeWalker,
    41                   inIDeepTreeWalker,
    42                   nsIDOMTreeWalker)
    44 ////////////////////////////////////////////////////
    45 // inIDeepTreeWalker
    47 NS_IMETHODIMP
    48 inDeepTreeWalker::GetShowAnonymousContent(bool *aShowAnonymousContent)
    49 {
    50   *aShowAnonymousContent = mShowAnonymousContent;
    51   return NS_OK;
    52 }
    54 NS_IMETHODIMP
    55 inDeepTreeWalker::SetShowAnonymousContent(bool aShowAnonymousContent)
    56 {
    57   mShowAnonymousContent = aShowAnonymousContent;
    58   return NS_OK;
    59 }
    61 NS_IMETHODIMP
    62 inDeepTreeWalker::GetShowSubDocuments(bool *aShowSubDocuments)
    63 {
    64   *aShowSubDocuments = mShowSubDocuments;
    65   return NS_OK;
    66 }
    68 NS_IMETHODIMP
    69 inDeepTreeWalker::SetShowSubDocuments(bool aShowSubDocuments)
    70 {
    71   mShowSubDocuments = aShowSubDocuments;
    72   return NS_OK;
    73 }
    75 NS_IMETHODIMP
    76 inDeepTreeWalker::Init(nsIDOMNode* aRoot, uint32_t aWhatToShow)
    77 {
    78   mRoot = aRoot;
    79   mWhatToShow = aWhatToShow;
    81   PushNode(aRoot);
    83   return NS_OK;
    84 }
    86 ////////////////////////////////////////////////////
    87 // nsIDOMTreeWalker
    89 NS_IMETHODIMP
    90 inDeepTreeWalker::GetRoot(nsIDOMNode** aRoot)
    91 {
    92   *aRoot = mRoot;
    93   NS_IF_ADDREF(*aRoot);
    95   return NS_OK;
    96 }
    98 NS_IMETHODIMP 
    99 inDeepTreeWalker::GetWhatToShow(uint32_t* aWhatToShow)
   100 {
   101   *aWhatToShow = mWhatToShow;
   102   return NS_OK;
   103 }
   105 NS_IMETHODIMP
   106 inDeepTreeWalker::GetFilter(nsIDOMNodeFilter** aFilter)
   107 {
   108   return NS_ERROR_NOT_IMPLEMENTED;
   109 }
   111 NS_IMETHODIMP
   112 inDeepTreeWalker::GetCurrentNode(nsIDOMNode** aCurrentNode)
   113 {
   114   *aCurrentNode = mCurrentNode;
   115   NS_IF_ADDREF(*aCurrentNode);
   117   return NS_OK;
   118 }
   120 NS_IMETHODIMP
   121 inDeepTreeWalker::SetCurrentNode(nsIDOMNode* aCurrentNode)
   122 {
   123   return NS_ERROR_NOT_IMPLEMENTED;
   124 }
   126 NS_IMETHODIMP
   127 inDeepTreeWalker::ParentNode(nsIDOMNode** _retval)
   128 {
   129   *_retval = nullptr;
   130   if (!mCurrentNode) return NS_OK;
   132   if (mStack.Length() == 1) {
   133     // No parent
   134     return NS_OK;
   135   }
   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 }
   146 NS_IMETHODIMP
   147 inDeepTreeWalker::FirstChild(nsIDOMNode **_retval)
   148 {
   149   *_retval = nullptr;
   150   if (!mCurrentNode) {
   151     return NS_OK;
   152   }
   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 }
   166 NS_IMETHODIMP
   167 inDeepTreeWalker::LastChild(nsIDOMNode **_retval)
   168 {
   169   *_retval = nullptr;
   170   if (!mCurrentNode) {
   171     return NS_OK;
   172   }
   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 }
   188 NS_IMETHODIMP
   189 inDeepTreeWalker::PreviousSibling(nsIDOMNode **_retval)
   190 {
   191   *_retval = nullptr;
   192   if (!mCurrentNode) {
   193     return NS_OK;
   194   }
   196   NS_ASSERTION(mStack.Length() > 0, "Should have things in mStack");
   198   if (mStack.Length() == 1) {
   199     // No previous sibling
   200     return NS_OK;
   201   }
   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   }
   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 }
   220 NS_IMETHODIMP
   221 inDeepTreeWalker::NextSibling(nsIDOMNode **_retval)
   222 {
   223   *_retval = nullptr;
   224   if (!mCurrentNode) {
   225     return NS_OK;
   226   }
   228   NS_ASSERTION(mStack.Length() > 0, "Should have things in mStack");
   230   if (mStack.Length() == 1) {
   231     // No next sibling
   232     return NS_OK;
   233   }
   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   }
   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 }
   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   }
   261   nsCOMPtr<nsIDOMNode> node;
   262   PreviousSibling(getter_AddRefs(node));
   264   if (!node) {
   265     return ParentNode(_retval);
   266   }
   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   }
   277   NS_ADDREF(*_retval = mCurrentNode);
   278   return NS_OK;
   279 }
   281 NS_IMETHODIMP
   282 inDeepTreeWalker::NextNode(nsIDOMNode **_retval)
   283 {
   284   // First try our kids
   285   FirstChild(_retval);
   287   if (*_retval) {
   288     return NS_OK;
   289   }
   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);
   300     if (*_retval) {
   301       return NS_OK;
   302     }
   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   }
   320   NS_NOTREACHED("how did we get here?");
   321   return NS_OK;
   322 }
   324 void
   325 inDeepTreeWalker::PushNode(nsIDOMNode* aNode)
   326 {
   327   mCurrentNode = aNode;
   328   if (!aNode) return;
   330   DeepTreeStackItem item;
   331   item.node = aNode;
   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   }
   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   }
   351   item.kids = kids;
   352   item.lastIndex = 0;
   353   mStack.AppendElement(item);
   354 }
   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;
   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   }
   389   mCurrentNode = next;
   391   *_retval = next;
   392   NS_IF_ADDREF(*_retval);
   394   return NS_OK;
   395 }
   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