1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/accessible/src/base/TreeWalker.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,159 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "TreeWalker.h" 1.10 + 1.11 +#include "Accessible.h" 1.12 +#include "nsAccessibilityService.h" 1.13 +#include "DocAccessible.h" 1.14 + 1.15 +#include "mozilla/dom/Element.h" 1.16 + 1.17 +using namespace mozilla::a11y; 1.18 + 1.19 +//////////////////////////////////////////////////////////////////////////////// 1.20 +// WalkState 1.21 +//////////////////////////////////////////////////////////////////////////////// 1.22 + 1.23 +namespace mozilla { 1.24 +namespace a11y { 1.25 + 1.26 +struct WalkState 1.27 +{ 1.28 + WalkState(nsIContent *aContent) : 1.29 + content(aContent), childIdx(0), prevState(nullptr) {} 1.30 + 1.31 + nsCOMPtr<nsIContent> content; 1.32 + nsCOMPtr<nsINodeList> childList; 1.33 + uint32_t childIdx; 1.34 + WalkState *prevState; 1.35 +}; 1.36 + 1.37 +} // namespace a11y 1.38 +} // namespace mozilla 1.39 + 1.40 +//////////////////////////////////////////////////////////////////////////////// 1.41 +// TreeWalker 1.42 +//////////////////////////////////////////////////////////////////////////////// 1.43 + 1.44 +TreeWalker:: 1.45 + TreeWalker(Accessible* aContext, nsIContent* aContent, uint32_t aFlags) : 1.46 + mDoc(aContext->Document()), mContext(aContext), 1.47 + mFlags(aFlags), mState(nullptr) 1.48 +{ 1.49 + NS_ASSERTION(aContent, "No node for the accessible tree walker!"); 1.50 + 1.51 + if (aContent) 1.52 + mState = new WalkState(aContent); 1.53 + 1.54 + mChildFilter = mContext->CanHaveAnonChildren() ? 1.55 + nsIContent::eAllChildren : nsIContent::eAllButXBL; 1.56 + 1.57 + mChildFilter |= nsIContent::eSkipPlaceholderContent; 1.58 + 1.59 + MOZ_COUNT_CTOR(TreeWalker); 1.60 +} 1.61 + 1.62 +TreeWalker::~TreeWalker() 1.63 +{ 1.64 + // Clear state stack from memory 1.65 + while (mState) 1.66 + PopState(); 1.67 + 1.68 + MOZ_COUNT_DTOR(TreeWalker); 1.69 +} 1.70 + 1.71 +//////////////////////////////////////////////////////////////////////////////// 1.72 +// TreeWalker: private 1.73 + 1.74 +Accessible* 1.75 +TreeWalker::NextChildInternal(bool aNoWalkUp) 1.76 +{ 1.77 + if (!mState || !mState->content) 1.78 + return nullptr; 1.79 + 1.80 + if (!mState->childList) 1.81 + mState->childList = mState->content->GetChildren(mChildFilter); 1.82 + 1.83 + uint32_t length = 0; 1.84 + if (mState->childList) 1.85 + mState->childList->GetLength(&length); 1.86 + 1.87 + while (mState->childIdx < length) { 1.88 + nsIContent* childNode = mState->childList->Item(mState->childIdx); 1.89 + mState->childIdx++; 1.90 + 1.91 + bool isSubtreeHidden = false; 1.92 + Accessible* accessible = mFlags & eWalkCache ? 1.93 + mDoc->GetAccessible(childNode) : 1.94 + GetAccService()->GetOrCreateAccessible(childNode, mContext, 1.95 + &isSubtreeHidden); 1.96 + 1.97 + if (accessible) 1.98 + return accessible; 1.99 + 1.100 + // Walk down into subtree to find accessibles. 1.101 + if (!isSubtreeHidden) { 1.102 + PushState(childNode); 1.103 + accessible = NextChildInternal(true); 1.104 + if (accessible) 1.105 + return accessible; 1.106 + } 1.107 + } 1.108 + 1.109 + // No more children, get back to the parent. 1.110 + nsIContent* anchorNode = mState->content; 1.111 + PopState(); 1.112 + if (aNoWalkUp) 1.113 + return nullptr; 1.114 + 1.115 + if (mState) 1.116 + return NextChildInternal(false); 1.117 + 1.118 + // If we traversed the whole subtree of the anchor node. Move to next node 1.119 + // relative anchor node within the context subtree if possible. 1.120 + if (mFlags != eWalkContextTree) 1.121 + return nullptr; 1.122 + 1.123 + while (anchorNode != mContext->GetNode()) { 1.124 + nsINode* parentNode = anchorNode->GetFlattenedTreeParent(); 1.125 + if (!parentNode || !parentNode->IsElement()) 1.126 + return nullptr; 1.127 + 1.128 + PushState(parentNode->AsElement()); 1.129 + mState->childList = mState->content->GetChildren(mChildFilter); 1.130 + length = 0; 1.131 + if (mState->childList) 1.132 + mState->childList->GetLength(&length); 1.133 + 1.134 + while (mState->childIdx < length) { 1.135 + nsIContent* childNode = mState->childList->Item(mState->childIdx); 1.136 + mState->childIdx++; 1.137 + if (childNode == anchorNode) 1.138 + return NextChildInternal(false); 1.139 + } 1.140 + PopState(); 1.141 + 1.142 + anchorNode = parentNode->AsElement(); 1.143 + } 1.144 + 1.145 + return nullptr; 1.146 +} 1.147 + 1.148 +void 1.149 +TreeWalker::PopState() 1.150 +{ 1.151 + WalkState* prevToLastState = mState->prevState; 1.152 + delete mState; 1.153 + mState = prevToLastState; 1.154 +} 1.155 + 1.156 +void 1.157 +TreeWalker::PushState(nsIContent* aContent) 1.158 +{ 1.159 + WalkState* nextToLastState = new WalkState(aContent); 1.160 + nextToLastState->prevState = mState; 1.161 + mState = nextToLastState; 1.162 +}