accessible/src/base/TreeWalker.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 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "TreeWalker.h"
     8 #include "Accessible.h"
     9 #include "nsAccessibilityService.h"
    10 #include "DocAccessible.h"
    12 #include "mozilla/dom/Element.h"
    14 using namespace mozilla::a11y;
    16 ////////////////////////////////////////////////////////////////////////////////
    17 // WalkState
    18 ////////////////////////////////////////////////////////////////////////////////
    20 namespace mozilla {
    21 namespace a11y {
    23 struct WalkState
    24 {
    25   WalkState(nsIContent *aContent) :
    26     content(aContent), childIdx(0), prevState(nullptr) {}
    28   nsCOMPtr<nsIContent> content;
    29   nsCOMPtr<nsINodeList> childList;
    30   uint32_t childIdx;
    31   WalkState *prevState;
    32 };
    34 } // namespace a11y
    35 } // namespace mozilla
    37 ////////////////////////////////////////////////////////////////////////////////
    38 // TreeWalker
    39 ////////////////////////////////////////////////////////////////////////////////
    41 TreeWalker::
    42   TreeWalker(Accessible* aContext, nsIContent* aContent, uint32_t aFlags) :
    43   mDoc(aContext->Document()), mContext(aContext),
    44   mFlags(aFlags), mState(nullptr)
    45 {
    46   NS_ASSERTION(aContent, "No node for the accessible tree walker!");
    48   if (aContent)
    49     mState = new WalkState(aContent);
    51   mChildFilter = mContext->CanHaveAnonChildren() ?
    52     nsIContent::eAllChildren : nsIContent::eAllButXBL;
    54   mChildFilter |= nsIContent::eSkipPlaceholderContent;
    56   MOZ_COUNT_CTOR(TreeWalker);
    57 }
    59 TreeWalker::~TreeWalker()
    60 {
    61   // Clear state stack from memory
    62   while (mState)
    63     PopState();
    65   MOZ_COUNT_DTOR(TreeWalker);
    66 }
    68 ////////////////////////////////////////////////////////////////////////////////
    69 // TreeWalker: private
    71 Accessible*
    72 TreeWalker::NextChildInternal(bool aNoWalkUp)
    73 {
    74   if (!mState || !mState->content)
    75     return nullptr;
    77   if (!mState->childList)
    78     mState->childList = mState->content->GetChildren(mChildFilter);
    80   uint32_t length = 0;
    81   if (mState->childList)
    82     mState->childList->GetLength(&length);
    84   while (mState->childIdx < length) {
    85     nsIContent* childNode = mState->childList->Item(mState->childIdx);
    86     mState->childIdx++;
    88     bool isSubtreeHidden = false;
    89     Accessible* accessible = mFlags & eWalkCache ?
    90       mDoc->GetAccessible(childNode) :
    91       GetAccService()->GetOrCreateAccessible(childNode, mContext,
    92                                              &isSubtreeHidden);
    94     if (accessible)
    95       return accessible;
    97     // Walk down into subtree to find accessibles.
    98     if (!isSubtreeHidden) {
    99       PushState(childNode);
   100       accessible = NextChildInternal(true);
   101       if (accessible)
   102         return accessible;
   103     }
   104   }
   106   // No more children, get back to the parent.
   107   nsIContent* anchorNode = mState->content;
   108   PopState();
   109   if (aNoWalkUp)
   110     return nullptr;
   112   if (mState)
   113     return NextChildInternal(false);
   115   // If we traversed the whole subtree of the anchor node. Move to next node
   116   // relative anchor node within the context subtree if possible.
   117   if (mFlags != eWalkContextTree)
   118     return nullptr;
   120   while (anchorNode != mContext->GetNode()) {
   121     nsINode* parentNode = anchorNode->GetFlattenedTreeParent();
   122     if (!parentNode || !parentNode->IsElement())
   123       return nullptr;
   125     PushState(parentNode->AsElement());
   126     mState->childList = mState->content->GetChildren(mChildFilter);
   127     length = 0;
   128     if (mState->childList)
   129       mState->childList->GetLength(&length);
   131     while (mState->childIdx < length) {
   132       nsIContent* childNode = mState->childList->Item(mState->childIdx);
   133       mState->childIdx++;
   134       if (childNode == anchorNode)
   135         return NextChildInternal(false);
   136     }
   137     PopState();
   139     anchorNode = parentNode->AsElement();
   140   }
   142   return nullptr;
   143 }
   145 void
   146 TreeWalker::PopState()
   147 {
   148   WalkState* prevToLastState = mState->prevState;
   149   delete mState;
   150   mState = prevToLastState;
   151 }
   153 void
   154 TreeWalker::PushState(nsIContent* aContent)
   155 {
   156   WalkState* nextToLastState = new WalkState(aContent);
   157   nextToLastState->prevState = mState;
   158   mState = nextToLastState;
   159 }

mercurial