Tue, 06 Jan 2015 21:39:09 +0100
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 "DocAccessible.h"
7 #include "nsObjCExceptions.h"
9 #include "Accessible-inl.h"
10 #include "nsAccUtils.h"
11 #include "Role.h"
13 #import "mozAccessible.h"
14 #import "mozActionElements.h"
15 #import "mozHTMLAccessible.h"
16 #import "mozTextAccessible.h"
18 using namespace mozilla::a11y;
20 AccessibleWrap::
21 AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
22 Accessible(aContent, aDoc), mNativeObject(nil),
23 mNativeInited(false)
24 {
25 }
27 AccessibleWrap::~AccessibleWrap()
28 {
29 }
31 mozAccessible*
32 AccessibleWrap::GetNativeObject()
33 {
34 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
36 if (!mNativeInited && !mNativeObject && !IsDefunct() && !AncestorIsFlat())
37 mNativeObject = [[GetNativeType() alloc] initWithAccessible:this];
39 mNativeInited = true;
41 return mNativeObject;
43 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
44 }
46 NS_IMETHODIMP
47 AccessibleWrap::GetNativeInterface (void **aOutInterface)
48 {
49 NS_ENSURE_ARG_POINTER(aOutInterface);
51 *aOutInterface = static_cast<void*>(GetNativeObject());
53 return *aOutInterface ? NS_OK : NS_ERROR_FAILURE;
54 }
56 // overridden in subclasses to create the right kind of object. by default we create a generic
57 // 'mozAccessible' node.
58 Class
59 AccessibleWrap::GetNativeType ()
60 {
61 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
63 if (IsXULTabpanels())
64 return [mozPaneAccessible class];
66 roles::Role role = Role();
67 switch (role) {
68 case roles::PUSHBUTTON:
69 case roles::SPLITBUTTON:
70 case roles::TOGGLE_BUTTON:
71 {
72 // if this button may show a popup, let's make it of the popupbutton type.
73 return HasPopup() ? [mozPopupButtonAccessible class] :
74 [mozButtonAccessible class];
75 }
77 case roles::PAGETAB:
78 return [mozButtonAccessible class];
80 case roles::CHECKBUTTON:
81 return [mozCheckboxAccessible class];
83 case roles::HEADING:
84 return [mozHeadingAccessible class];
86 case roles::PAGETABLIST:
87 return [mozTabsAccessible class];
89 case roles::ENTRY:
90 case roles::STATICTEXT:
91 case roles::CAPTION:
92 case roles::ACCEL_LABEL:
93 case roles::PASSWORD_TEXT:
94 // normal textfield (static or editable)
95 return [mozTextAccessible class];
97 case roles::TEXT_LEAF:
98 return [mozTextLeafAccessible class];
100 case roles::LINK:
101 return [mozLinkAccessible class];
103 case roles::COMBOBOX:
104 return [mozPopupButtonAccessible class];
106 default:
107 return [mozAccessible class];
108 }
110 return nil;
112 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
113 }
115 // this method is very important. it is fired when an accessible object "dies". after this point
116 // the object might still be around (because some 3rd party still has a ref to it), but it is
117 // in fact 'dead'.
118 void
119 AccessibleWrap::Shutdown ()
120 {
121 // this ensure we will not try to re-create the native object.
122 mNativeInited = true;
124 // we really intend to access the member directly.
125 if (mNativeObject) {
126 [mNativeObject expire];
127 [mNativeObject release];
128 mNativeObject = nil;
129 }
131 Accessible::Shutdown();
132 }
134 nsresult
135 AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
136 {
137 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
139 nsresult rv = Accessible::HandleAccEvent(aEvent);
140 NS_ENSURE_SUCCESS(rv, rv);
142 uint32_t eventType = aEvent->GetEventType();
144 // ignore everything but focus-changed, value-changed, caret and selection
145 // events for now.
146 if (eventType != nsIAccessibleEvent::EVENT_FOCUS &&
147 eventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE &&
148 eventType != nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED &&
149 eventType != nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED)
150 return NS_OK;
152 Accessible* accessible = aEvent->GetAccessible();
153 NS_ENSURE_STATE(accessible);
155 mozAccessible *nativeAcc = nil;
156 accessible->GetNativeInterface((void**)&nativeAcc);
157 if (!nativeAcc)
158 return NS_ERROR_FAILURE;
160 switch (eventType) {
161 case nsIAccessibleEvent::EVENT_FOCUS:
162 [nativeAcc didReceiveFocus];
163 break;
164 case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
165 [nativeAcc valueDidChange];
166 break;
167 case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED:
168 case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
169 [nativeAcc selectedTextDidChange];
170 break;
171 }
173 return NS_OK;
175 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
176 }
178 void
179 AccessibleWrap::InvalidateChildren()
180 {
181 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
183 [GetNativeObject() invalidateChildren];
185 Accessible::InvalidateChildren();
187 NS_OBJC_END_TRY_ABORT_BLOCK;
188 }
190 bool
191 AccessibleWrap::InsertChildAt(uint32_t aIdx, Accessible* aAccessible)
192 {
193 bool inserted = Accessible::InsertChildAt(aIdx, aAccessible);
194 if (inserted && mNativeObject)
195 [mNativeObject appendChild:aAccessible];
197 return inserted;
198 }
200 bool
201 AccessibleWrap::RemoveChild(Accessible* aAccessible)
202 {
203 bool removed = Accessible::RemoveChild(aAccessible);
205 if (removed && mNativeObject)
206 [mNativeObject invalidateChildren];
208 return removed;
209 }
211 // if we for some reason have no native accessible, we should be skipped over (and traversed)
212 // when fetching all unignored children, etc. when counting unignored children, we will not be counted.
213 bool
214 AccessibleWrap::IsIgnored()
215 {
216 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
218 mozAccessible* nativeObject = GetNativeObject();
219 return (!nativeObject) || [nativeObject accessibilityIsIgnored];
221 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
222 }
224 void
225 AccessibleWrap::GetUnignoredChildren(nsTArray<Accessible*>* aChildrenArray)
226 {
227 // we're flat; there are no children.
228 if (nsAccUtils::MustPrune(this))
229 return;
231 uint32_t childCount = ChildCount();
232 for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
233 AccessibleWrap* childAcc =
234 static_cast<AccessibleWrap*>(GetChildAt(childIdx));
236 // If element is ignored, then add its children as substitutes.
237 if (childAcc->IsIgnored()) {
238 childAcc->GetUnignoredChildren(aChildrenArray);
239 continue;
240 }
242 aChildrenArray->AppendElement(childAcc);
243 }
244 }
246 Accessible*
247 AccessibleWrap::GetUnignoredParent() const
248 {
249 // Go up the chain to find a parent that is not ignored.
250 AccessibleWrap* parentWrap = static_cast<AccessibleWrap*>(Parent());
251 while (parentWrap && parentWrap->IsIgnored())
252 parentWrap = static_cast<AccessibleWrap*>(parentWrap->Parent());
254 return parentWrap;
255 }
257 ////////////////////////////////////////////////////////////////////////////////
258 // AccessibleWrap protected
260 bool
261 AccessibleWrap::AncestorIsFlat()
262 {
263 // We don't create a native object if we're child of a "flat" accessible;
264 // for example, on OS X buttons shouldn't have any children, because that
265 // makes the OS confused.
266 //
267 // To maintain a scripting environment where the XPCOM accessible hierarchy
268 // look the same on all platforms, we still let the C++ objects be created
269 // though.
271 Accessible* parent = Parent();
272 while (parent) {
273 if (nsAccUtils::MustPrune(parent))
274 return true;
276 parent = parent->Parent();
277 }
278 // no parent was flat
279 return false;
280 }