1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/accessible/src/mac/AccessibleWrap.mm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,280 @@ 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 "DocAccessible.h" 1.10 +#include "nsObjCExceptions.h" 1.11 + 1.12 +#include "Accessible-inl.h" 1.13 +#include "nsAccUtils.h" 1.14 +#include "Role.h" 1.15 + 1.16 +#import "mozAccessible.h" 1.17 +#import "mozActionElements.h" 1.18 +#import "mozHTMLAccessible.h" 1.19 +#import "mozTextAccessible.h" 1.20 + 1.21 +using namespace mozilla::a11y; 1.22 + 1.23 +AccessibleWrap:: 1.24 + AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) : 1.25 + Accessible(aContent, aDoc), mNativeObject(nil), 1.26 + mNativeInited(false) 1.27 +{ 1.28 +} 1.29 + 1.30 +AccessibleWrap::~AccessibleWrap() 1.31 +{ 1.32 +} 1.33 + 1.34 +mozAccessible* 1.35 +AccessibleWrap::GetNativeObject() 1.36 +{ 1.37 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; 1.38 + 1.39 + if (!mNativeInited && !mNativeObject && !IsDefunct() && !AncestorIsFlat()) 1.40 + mNativeObject = [[GetNativeType() alloc] initWithAccessible:this]; 1.41 + 1.42 + mNativeInited = true; 1.43 + 1.44 + return mNativeObject; 1.45 + 1.46 + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 1.47 +} 1.48 + 1.49 +NS_IMETHODIMP 1.50 +AccessibleWrap::GetNativeInterface (void **aOutInterface) 1.51 +{ 1.52 + NS_ENSURE_ARG_POINTER(aOutInterface); 1.53 + 1.54 + *aOutInterface = static_cast<void*>(GetNativeObject()); 1.55 + 1.56 + return *aOutInterface ? NS_OK : NS_ERROR_FAILURE; 1.57 +} 1.58 + 1.59 +// overridden in subclasses to create the right kind of object. by default we create a generic 1.60 +// 'mozAccessible' node. 1.61 +Class 1.62 +AccessibleWrap::GetNativeType () 1.63 +{ 1.64 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; 1.65 + 1.66 + if (IsXULTabpanels()) 1.67 + return [mozPaneAccessible class]; 1.68 + 1.69 + roles::Role role = Role(); 1.70 + switch (role) { 1.71 + case roles::PUSHBUTTON: 1.72 + case roles::SPLITBUTTON: 1.73 + case roles::TOGGLE_BUTTON: 1.74 + { 1.75 + // if this button may show a popup, let's make it of the popupbutton type. 1.76 + return HasPopup() ? [mozPopupButtonAccessible class] : 1.77 + [mozButtonAccessible class]; 1.78 + } 1.79 + 1.80 + case roles::PAGETAB: 1.81 + return [mozButtonAccessible class]; 1.82 + 1.83 + case roles::CHECKBUTTON: 1.84 + return [mozCheckboxAccessible class]; 1.85 + 1.86 + case roles::HEADING: 1.87 + return [mozHeadingAccessible class]; 1.88 + 1.89 + case roles::PAGETABLIST: 1.90 + return [mozTabsAccessible class]; 1.91 + 1.92 + case roles::ENTRY: 1.93 + case roles::STATICTEXT: 1.94 + case roles::CAPTION: 1.95 + case roles::ACCEL_LABEL: 1.96 + case roles::PASSWORD_TEXT: 1.97 + // normal textfield (static or editable) 1.98 + return [mozTextAccessible class]; 1.99 + 1.100 + case roles::TEXT_LEAF: 1.101 + return [mozTextLeafAccessible class]; 1.102 + 1.103 + case roles::LINK: 1.104 + return [mozLinkAccessible class]; 1.105 + 1.106 + case roles::COMBOBOX: 1.107 + return [mozPopupButtonAccessible class]; 1.108 + 1.109 + default: 1.110 + return [mozAccessible class]; 1.111 + } 1.112 + 1.113 + return nil; 1.114 + 1.115 + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 1.116 +} 1.117 + 1.118 +// this method is very important. it is fired when an accessible object "dies". after this point 1.119 +// the object might still be around (because some 3rd party still has a ref to it), but it is 1.120 +// in fact 'dead'. 1.121 +void 1.122 +AccessibleWrap::Shutdown () 1.123 +{ 1.124 + // this ensure we will not try to re-create the native object. 1.125 + mNativeInited = true; 1.126 + 1.127 + // we really intend to access the member directly. 1.128 + if (mNativeObject) { 1.129 + [mNativeObject expire]; 1.130 + [mNativeObject release]; 1.131 + mNativeObject = nil; 1.132 + } 1.133 + 1.134 + Accessible::Shutdown(); 1.135 +} 1.136 + 1.137 +nsresult 1.138 +AccessibleWrap::HandleAccEvent(AccEvent* aEvent) 1.139 +{ 1.140 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.141 + 1.142 + nsresult rv = Accessible::HandleAccEvent(aEvent); 1.143 + NS_ENSURE_SUCCESS(rv, rv); 1.144 + 1.145 + uint32_t eventType = aEvent->GetEventType(); 1.146 + 1.147 + // ignore everything but focus-changed, value-changed, caret and selection 1.148 + // events for now. 1.149 + if (eventType != nsIAccessibleEvent::EVENT_FOCUS && 1.150 + eventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE && 1.151 + eventType != nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED && 1.152 + eventType != nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED) 1.153 + return NS_OK; 1.154 + 1.155 + Accessible* accessible = aEvent->GetAccessible(); 1.156 + NS_ENSURE_STATE(accessible); 1.157 + 1.158 + mozAccessible *nativeAcc = nil; 1.159 + accessible->GetNativeInterface((void**)&nativeAcc); 1.160 + if (!nativeAcc) 1.161 + return NS_ERROR_FAILURE; 1.162 + 1.163 + switch (eventType) { 1.164 + case nsIAccessibleEvent::EVENT_FOCUS: 1.165 + [nativeAcc didReceiveFocus]; 1.166 + break; 1.167 + case nsIAccessibleEvent::EVENT_VALUE_CHANGE: 1.168 + [nativeAcc valueDidChange]; 1.169 + break; 1.170 + case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: 1.171 + case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED: 1.172 + [nativeAcc selectedTextDidChange]; 1.173 + break; 1.174 + } 1.175 + 1.176 + return NS_OK; 1.177 + 1.178 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.179 +} 1.180 + 1.181 +void 1.182 +AccessibleWrap::InvalidateChildren() 1.183 +{ 1.184 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.185 + 1.186 + [GetNativeObject() invalidateChildren]; 1.187 + 1.188 + Accessible::InvalidateChildren(); 1.189 + 1.190 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.191 +} 1.192 + 1.193 +bool 1.194 +AccessibleWrap::InsertChildAt(uint32_t aIdx, Accessible* aAccessible) 1.195 +{ 1.196 + bool inserted = Accessible::InsertChildAt(aIdx, aAccessible); 1.197 + if (inserted && mNativeObject) 1.198 + [mNativeObject appendChild:aAccessible]; 1.199 + 1.200 + return inserted; 1.201 +} 1.202 + 1.203 +bool 1.204 +AccessibleWrap::RemoveChild(Accessible* aAccessible) 1.205 +{ 1.206 + bool removed = Accessible::RemoveChild(aAccessible); 1.207 + 1.208 + if (removed && mNativeObject) 1.209 + [mNativeObject invalidateChildren]; 1.210 + 1.211 + return removed; 1.212 +} 1.213 + 1.214 +// if we for some reason have no native accessible, we should be skipped over (and traversed) 1.215 +// when fetching all unignored children, etc. when counting unignored children, we will not be counted. 1.216 +bool 1.217 +AccessibleWrap::IsIgnored() 1.218 +{ 1.219 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.220 + 1.221 + mozAccessible* nativeObject = GetNativeObject(); 1.222 + return (!nativeObject) || [nativeObject accessibilityIsIgnored]; 1.223 + 1.224 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false); 1.225 +} 1.226 + 1.227 +void 1.228 +AccessibleWrap::GetUnignoredChildren(nsTArray<Accessible*>* aChildrenArray) 1.229 +{ 1.230 + // we're flat; there are no children. 1.231 + if (nsAccUtils::MustPrune(this)) 1.232 + return; 1.233 + 1.234 + uint32_t childCount = ChildCount(); 1.235 + for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) { 1.236 + AccessibleWrap* childAcc = 1.237 + static_cast<AccessibleWrap*>(GetChildAt(childIdx)); 1.238 + 1.239 + // If element is ignored, then add its children as substitutes. 1.240 + if (childAcc->IsIgnored()) { 1.241 + childAcc->GetUnignoredChildren(aChildrenArray); 1.242 + continue; 1.243 + } 1.244 + 1.245 + aChildrenArray->AppendElement(childAcc); 1.246 + } 1.247 +} 1.248 + 1.249 +Accessible* 1.250 +AccessibleWrap::GetUnignoredParent() const 1.251 +{ 1.252 + // Go up the chain to find a parent that is not ignored. 1.253 + AccessibleWrap* parentWrap = static_cast<AccessibleWrap*>(Parent()); 1.254 + while (parentWrap && parentWrap->IsIgnored()) 1.255 + parentWrap = static_cast<AccessibleWrap*>(parentWrap->Parent()); 1.256 + 1.257 + return parentWrap; 1.258 +} 1.259 + 1.260 +//////////////////////////////////////////////////////////////////////////////// 1.261 +// AccessibleWrap protected 1.262 + 1.263 +bool 1.264 +AccessibleWrap::AncestorIsFlat() 1.265 +{ 1.266 + // We don't create a native object if we're child of a "flat" accessible; 1.267 + // for example, on OS X buttons shouldn't have any children, because that 1.268 + // makes the OS confused. 1.269 + // 1.270 + // To maintain a scripting environment where the XPCOM accessible hierarchy 1.271 + // look the same on all platforms, we still let the C++ objects be created 1.272 + // though. 1.273 + 1.274 + Accessible* parent = Parent(); 1.275 + while (parent) { 1.276 + if (nsAccUtils::MustPrune(parent)) 1.277 + return true; 1.278 + 1.279 + parent = parent->Parent(); 1.280 + } 1.281 + // no parent was flat 1.282 + return false; 1.283 +}