Line data Source code
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/. */
5 :
6 : #include "nsAccessibilityService.h"
7 :
8 : // NOTE: alphabetically ordered
9 : #include "ApplicationAccessibleWrap.h"
10 : #include "ARIAGridAccessibleWrap.h"
11 : #include "ARIAMap.h"
12 : #include "DocAccessible-inl.h"
13 : #include "FocusManager.h"
14 : #include "HTMLCanvasAccessible.h"
15 : #include "HTMLElementAccessibles.h"
16 : #include "HTMLImageMapAccessible.h"
17 : #include "HTMLLinkAccessible.h"
18 : #include "HTMLListAccessible.h"
19 : #include "HTMLSelectAccessible.h"
20 : #include "HTMLTableAccessibleWrap.h"
21 : #include "HyperTextAccessibleWrap.h"
22 : #include "RootAccessible.h"
23 : #include "nsAccUtils.h"
24 : #include "nsArrayUtils.h"
25 : #include "nsAttrName.h"
26 : #include "nsEventShell.h"
27 : #include "nsIURI.h"
28 : #include "OuterDocAccessible.h"
29 : #include "Platform.h"
30 : #include "Role.h"
31 : #ifdef MOZ_ACCESSIBILITY_ATK
32 : #include "RootAccessibleWrap.h"
33 : #endif
34 : #include "States.h"
35 : #include "Statistics.h"
36 : #include "TextLeafAccessibleWrap.h"
37 : #include "TreeWalker.h"
38 : #include "xpcAccessibleApplication.h"
39 : #include "xpcAccessibleDocument.h"
40 :
41 : #ifdef MOZ_ACCESSIBILITY_ATK
42 : #include "AtkSocketAccessible.h"
43 : #endif
44 :
45 : #ifdef XP_WIN
46 : #include "mozilla/a11y/Compatibility.h"
47 : #include "mozilla/dom/ContentChild.h"
48 : #include "HTMLWin32ObjectAccessible.h"
49 : #include "mozilla/StaticPtr.h"
50 : #endif
51 :
52 : #ifdef A11Y_LOG
53 : #include "Logging.h"
54 : #endif
55 :
56 : #ifdef MOZ_CRASHREPORTER
57 : #include "nsExceptionHandler.h"
58 : #endif
59 :
60 : #include "nsImageFrame.h"
61 : #include "nsIObserverService.h"
62 : #include "nsLayoutUtils.h"
63 : #include "nsPluginFrame.h"
64 : #include "SVGGeometryFrame.h"
65 : #include "nsTreeBodyFrame.h"
66 : #include "nsTreeColumns.h"
67 : #include "nsTreeUtils.h"
68 : #include "nsXBLPrototypeBinding.h"
69 : #include "nsXBLBinding.h"
70 : #include "mozilla/ArrayUtils.h"
71 : #include "mozilla/dom/DOMStringList.h"
72 : #include "mozilla/Preferences.h"
73 : #include "mozilla/Services.h"
74 : #include "nsDeckFrame.h"
75 :
76 : #ifdef MOZ_XUL
77 : #include "XULAlertAccessible.h"
78 : #include "XULColorPickerAccessible.h"
79 : #include "XULComboboxAccessible.h"
80 : #include "XULElementAccessibles.h"
81 : #include "XULFormControlAccessible.h"
82 : #include "XULListboxAccessibleWrap.h"
83 : #include "XULMenuAccessibleWrap.h"
84 : #include "XULSliderAccessible.h"
85 : #include "XULTabAccessible.h"
86 : #include "XULTreeGridAccessibleWrap.h"
87 : #endif
88 :
89 : #if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK)
90 : #include "nsNPAPIPluginInstance.h"
91 : #endif
92 :
93 : using namespace mozilla;
94 : using namespace mozilla::a11y;
95 : using namespace mozilla::dom;
96 :
97 : ////////////////////////////////////////////////////////////////////////////////
98 : // Statics
99 : ////////////////////////////////////////////////////////////////////////////////
100 :
101 : /**
102 : * Return true if the element must be accessible.
103 : */
104 : static bool
105 0 : MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument)
106 : {
107 0 : if (aContent->GetPrimaryFrame()->IsFocusable())
108 0 : return true;
109 :
110 0 : uint32_t attrCount = aContent->GetAttrCount();
111 0 : for (uint32_t attrIdx = 0; attrIdx < attrCount; attrIdx++) {
112 0 : const nsAttrName* attr = aContent->GetAttrNameAt(attrIdx);
113 0 : if (attr->NamespaceEquals(kNameSpaceID_None)) {
114 0 : nsIAtom* attrAtom = attr->Atom();
115 0 : nsDependentAtomString attrStr(attrAtom);
116 0 : if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-")))
117 0 : continue; // not ARIA
118 :
119 : // A global state or a property and in case of token defined.
120 0 : uint8_t attrFlags = aria::AttrCharacteristicsFor(attrAtom);
121 0 : if ((attrFlags & ATTR_GLOBAL) && (!(attrFlags & ATTR_VALTOKEN) ||
122 0 : nsAccUtils::HasDefinedARIAToken(aContent, attrAtom))) {
123 0 : return true;
124 : }
125 : }
126 : }
127 :
128 : // If the given ID is referred by relation attribute then create an accessible
129 : // for it.
130 0 : nsAutoString id;
131 0 : if (nsCoreUtils::GetID(aContent, id) && !id.IsEmpty())
132 0 : return aDocument->IsDependentID(id);
133 :
134 0 : return false;
135 : }
136 :
137 : ////////////////////////////////////////////////////////////////////////////////
138 : // Accessible constructors
139 :
140 : static Accessible*
141 0 : New_HTMLLink(nsIContent* aContent, Accessible* aContext)
142 : {
143 : // Only some roles truly enjoy life as HTMLLinkAccessibles, for details
144 : // see closed bug 494807.
145 0 : const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aContent->AsElement());
146 0 : if (roleMapEntry && roleMapEntry->role != roles::NOTHING &&
147 0 : roleMapEntry->role != roles::LINK) {
148 0 : return new HyperTextAccessibleWrap(aContent, aContext->Document());
149 : }
150 :
151 0 : return new HTMLLinkAccessible(aContent, aContext->Document());
152 : }
153 :
154 0 : static Accessible* New_HyperText(nsIContent* aContent, Accessible* aContext)
155 0 : { return new HyperTextAccessibleWrap(aContent, aContext->Document()); }
156 :
157 0 : static Accessible* New_HTMLFigcaption(nsIContent* aContent, Accessible* aContext)
158 0 : { return new HTMLFigcaptionAccessible(aContent, aContext->Document()); }
159 :
160 0 : static Accessible* New_HTMLFigure(nsIContent* aContent, Accessible* aContext)
161 0 : { return new HTMLFigureAccessible(aContent, aContext->Document()); }
162 :
163 0 : static Accessible* New_HTMLLegend(nsIContent* aContent, Accessible* aContext)
164 0 : { return new HTMLLegendAccessible(aContent, aContext->Document()); }
165 :
166 0 : static Accessible* New_HTMLOption(nsIContent* aContent, Accessible* aContext)
167 0 : { return new HTMLSelectOptionAccessible(aContent, aContext->Document()); }
168 :
169 0 : static Accessible* New_HTMLOptgroup(nsIContent* aContent, Accessible* aContext)
170 0 : { return new HTMLSelectOptGroupAccessible(aContent, aContext->Document()); }
171 :
172 0 : static Accessible* New_HTMLList(nsIContent* aContent, Accessible* aContext)
173 0 : { return new HTMLListAccessible(aContent, aContext->Document()); }
174 :
175 : static Accessible*
176 0 : New_HTMLListitem(nsIContent* aContent, Accessible* aContext)
177 : {
178 : // If list item is a child of accessible list then create an accessible for
179 : // it unconditionally by tag name. nsBlockFrame creates the list item
180 : // accessible for other elements styled as list items.
181 0 : if (aContext->IsList() && aContext->GetContent() == aContent->GetParent())
182 0 : return new HTMLLIAccessible(aContent, aContext->Document());
183 :
184 0 : return nullptr;
185 : }
186 :
187 : static Accessible*
188 0 : New_HTMLDefinition(nsIContent* aContent, Accessible* aContext)
189 : {
190 0 : if (aContext->IsList())
191 0 : return new HyperTextAccessibleWrap(aContent, aContext->Document());
192 0 : return nullptr;
193 : }
194 :
195 0 : static Accessible* New_HTMLLabel(nsIContent* aContent, Accessible* aContext)
196 0 : { return new HTMLLabelAccessible(aContent, aContext->Document()); }
197 :
198 0 : static Accessible* New_HTMLInput(nsIContent* aContent, Accessible* aContext)
199 : {
200 0 : if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
201 : nsGkAtoms::checkbox, eIgnoreCase)) {
202 0 : return new HTMLCheckboxAccessible(aContent, aContext->Document());
203 : }
204 0 : if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
205 : nsGkAtoms::radio, eIgnoreCase)) {
206 0 : return new HTMLRadioButtonAccessible(aContent, aContext->Document());
207 : }
208 0 : return nullptr;
209 : }
210 :
211 0 : static Accessible* New_HTMLOutput(nsIContent* aContent, Accessible* aContext)
212 0 : { return new HTMLOutputAccessible(aContent, aContext->Document()); }
213 :
214 0 : static Accessible* New_HTMLProgress(nsIContent* aContent, Accessible* aContext)
215 0 : { return new HTMLProgressMeterAccessible(aContent, aContext->Document()); }
216 :
217 0 : static Accessible* New_HTMLSummary(nsIContent* aContent, Accessible* aContext)
218 0 : { return new HTMLSummaryAccessible(aContent, aContext->Document()); }
219 :
220 : static Accessible*
221 0 : New_HTMLTableAccessible(nsIContent* aContent, Accessible* aContext)
222 0 : { return new HTMLTableAccessible(aContent, aContext->Document()); }
223 :
224 : static Accessible*
225 0 : New_HTMLTableRowAccessible(nsIContent* aContent, Accessible* aContext)
226 0 : { return new HTMLTableRowAccessible(aContent, aContext->Document()); }
227 :
228 : static Accessible*
229 0 : New_HTMLTableCellAccessible(nsIContent* aContent, Accessible* aContext)
230 0 : { return new HTMLTableCellAccessible(aContent, aContext->Document()); }
231 :
232 : static Accessible*
233 0 : New_HTMLTableHeaderCell(nsIContent* aContent, Accessible* aContext)
234 : {
235 0 : if (aContext->IsTableRow() && aContext->GetContent() == aContent->GetParent())
236 0 : return new HTMLTableHeaderCellAccessibleWrap(aContent, aContext->Document());
237 0 : return nullptr;
238 : }
239 :
240 : static Accessible*
241 0 : New_HTMLTableHeaderCellIfScope(nsIContent* aContent, Accessible* aContext)
242 : {
243 0 : if (aContext->IsTableRow() && aContext->GetContent() == aContent->GetParent() &&
244 0 : aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::scope))
245 0 : return new HTMLTableHeaderCellAccessibleWrap(aContent, aContext->Document());
246 0 : return nullptr;
247 : }
248 :
249 : ////////////////////////////////////////////////////////////////////////////////
250 : // Markup maps array.
251 :
252 : #define Attr(name, value) \
253 : { &nsGkAtoms::name, &nsGkAtoms::value }
254 :
255 : #define AttrFromDOM(name, DOMAttrName) \
256 : { &nsGkAtoms::name, nullptr, &nsGkAtoms::DOMAttrName }
257 :
258 : #define AttrFromDOMIf(name, DOMAttrName, DOMAttrValue) \
259 : { &nsGkAtoms::name, nullptr, &nsGkAtoms::DOMAttrName, &nsGkAtoms::DOMAttrValue }
260 :
261 : #define MARKUPMAP(atom, new_func, r, ... ) \
262 : { &nsGkAtoms::atom, new_func, static_cast<a11y::role>(r), { __VA_ARGS__ } },
263 :
264 : static const MarkupMapInfo sMarkupMapList[] = {
265 : #include "MarkupMap.h"
266 : };
267 :
268 : #undef Attr
269 : #undef AttrFromDOM
270 : #undef AttrFromDOMIf
271 : #undef MARKUPMAP
272 :
273 : ////////////////////////////////////////////////////////////////////////////////
274 : // nsAccessibilityService
275 : ////////////////////////////////////////////////////////////////////////////////
276 :
277 : nsAccessibilityService *nsAccessibilityService::gAccessibilityService = nullptr;
278 : ApplicationAccessible* nsAccessibilityService::gApplicationAccessible = nullptr;
279 : xpcAccessibleApplication* nsAccessibilityService::gXPCApplicationAccessible = nullptr;
280 : uint32_t nsAccessibilityService::gConsumers = 0;
281 :
282 0 : nsAccessibilityService::nsAccessibilityService() :
283 0 : DocManager(), FocusManager(), mMarkupMaps(ArrayLength(sMarkupMapList))
284 : {
285 0 : }
286 :
287 0 : nsAccessibilityService::~nsAccessibilityService()
288 : {
289 0 : NS_ASSERTION(IsShutdown(), "Accessibility wasn't shutdown!");
290 0 : gAccessibilityService = nullptr;
291 0 : }
292 :
293 : ////////////////////////////////////////////////////////////////////////////////
294 : // nsIListenerChangeListener
295 :
296 : NS_IMETHODIMP
297 0 : nsAccessibilityService::ListenersChanged(nsIArray* aEventChanges)
298 : {
299 : uint32_t targetCount;
300 0 : nsresult rv = aEventChanges->GetLength(&targetCount);
301 0 : NS_ENSURE_SUCCESS(rv, rv);
302 :
303 0 : for (uint32_t i = 0 ; i < targetCount ; i++) {
304 0 : nsCOMPtr<nsIEventListenerChange> change = do_QueryElementAt(aEventChanges, i);
305 :
306 0 : nsCOMPtr<nsIDOMEventTarget> target;
307 0 : change->GetTarget(getter_AddRefs(target));
308 0 : nsCOMPtr<nsIContent> node(do_QueryInterface(target));
309 0 : if (!node || !node->IsHTMLElement()) {
310 0 : continue;
311 : }
312 0 : nsCOMPtr<nsIArray> listenerNames;
313 0 : change->GetChangedListenerNames(getter_AddRefs(listenerNames));
314 :
315 : uint32_t changeCount;
316 0 : rv = listenerNames->GetLength(&changeCount);
317 0 : NS_ENSURE_SUCCESS(rv, rv);
318 :
319 0 : for (uint32_t i = 0 ; i < changeCount ; i++) {
320 0 : nsCOMPtr<nsIAtom> listenerName = do_QueryElementAt(listenerNames, i);
321 :
322 : // We are only interested in event listener changes which may
323 : // make an element accessible or inaccessible.
324 0 : if (listenerName != nsGkAtoms::onclick &&
325 0 : listenerName != nsGkAtoms::onmousedown &&
326 0 : listenerName != nsGkAtoms::onmouseup) {
327 0 : continue;
328 : }
329 :
330 0 : nsIDocument* ownerDoc = node->OwnerDoc();
331 0 : DocAccessible* document = GetExistingDocAccessible(ownerDoc);
332 :
333 : // Create an accessible for a inaccessible element having click event
334 : // handler.
335 0 : if (document && !document->HasAccessible(node) &&
336 0 : nsCoreUtils::HasClickListener(node)) {
337 0 : nsIContent* parentEl = node->GetFlattenedTreeParent();
338 0 : if (parentEl) {
339 0 : document->ContentInserted(parentEl, node, node->GetNextSibling());
340 : }
341 0 : break;
342 : }
343 : }
344 : }
345 0 : return NS_OK;
346 : }
347 :
348 : ////////////////////////////////////////////////////////////////////////////////
349 : // nsISupports
350 :
351 0 : NS_IMPL_ISUPPORTS_INHERITED(nsAccessibilityService,
352 : DocManager,
353 : nsIObserver,
354 : nsIListenerChangeListener,
355 : nsISelectionListener) // from SelectionManager
356 :
357 : ////////////////////////////////////////////////////////////////////////////////
358 : // nsIObserver
359 :
360 : NS_IMETHODIMP
361 0 : nsAccessibilityService::Observe(nsISupports *aSubject, const char *aTopic,
362 : const char16_t *aData)
363 : {
364 0 : if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID))
365 0 : Shutdown();
366 :
367 0 : return NS_OK;
368 : }
369 :
370 : void
371 0 : nsAccessibilityService::NotifyOfAnchorJumpTo(nsIContent* aTargetNode)
372 : {
373 0 : nsIDocument* documentNode = aTargetNode->GetUncomposedDoc();
374 0 : if (documentNode) {
375 0 : DocAccessible* document = GetDocAccessible(documentNode);
376 0 : if (document)
377 0 : document->SetAnchorJump(aTargetNode);
378 : }
379 0 : }
380 :
381 : void
382 0 : nsAccessibilityService::FireAccessibleEvent(uint32_t aEvent,
383 : Accessible* aTarget)
384 : {
385 0 : nsEventShell::FireEvent(aEvent, aTarget);
386 0 : }
387 :
388 : Accessible*
389 0 : nsAccessibilityService::GetRootDocumentAccessible(nsIPresShell* aPresShell,
390 : bool aCanCreate)
391 : {
392 0 : nsIPresShell* ps = aPresShell;
393 0 : nsIDocument* documentNode = aPresShell->GetDocument();
394 0 : if (documentNode) {
395 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem(documentNode->GetDocShell());
396 0 : if (treeItem) {
397 0 : nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
398 0 : treeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
399 0 : if (treeItem != rootTreeItem) {
400 0 : nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(rootTreeItem));
401 0 : ps = docShell->GetPresShell();
402 : }
403 :
404 0 : return aCanCreate ? GetDocAccessible(ps) : ps->GetDocAccessible();
405 : }
406 : }
407 0 : return nullptr;
408 : }
409 :
410 : #ifdef XP_WIN
411 : static StaticAutoPtr<nsTArray<nsCOMPtr<nsIContent> > > sPendingPlugins;
412 : static StaticAutoPtr<nsTArray<nsCOMPtr<nsITimer> > > sPluginTimers;
413 :
414 : class PluginTimerCallBack final : public nsITimerCallback
415 : {
416 : ~PluginTimerCallBack() {}
417 :
418 : public:
419 : explicit PluginTimerCallBack(nsIContent* aContent) : mContent(aContent) {}
420 :
421 : NS_DECL_ISUPPORTS
422 :
423 : NS_IMETHOD Notify(nsITimer* aTimer) final
424 : {
425 : if (!mContent->IsInUncomposedDoc())
426 : return NS_OK;
427 :
428 : nsIPresShell* ps = mContent->OwnerDoc()->GetShell();
429 : if (ps) {
430 : DocAccessible* doc = ps->GetDocAccessible();
431 : if (doc) {
432 : // Make sure that if we created an accessible for the plugin that wasn't
433 : // a plugin accessible we remove it before creating the right accessible.
434 : doc->RecreateAccessible(mContent);
435 : sPluginTimers->RemoveElement(aTimer);
436 : return NS_OK;
437 : }
438 : }
439 :
440 : // We couldn't get a doc accessible so presumably the document went away.
441 : // In this case don't leak our ref to the content or timer.
442 : sPendingPlugins->RemoveElement(mContent);
443 : sPluginTimers->RemoveElement(aTimer);
444 : return NS_OK;
445 : }
446 :
447 : private:
448 : nsCOMPtr<nsIContent> mContent;
449 : };
450 :
451 : NS_IMPL_ISUPPORTS(PluginTimerCallBack, nsITimerCallback)
452 : #endif
453 :
454 : already_AddRefed<Accessible>
455 0 : nsAccessibilityService::CreatePluginAccessible(nsPluginFrame* aFrame,
456 : nsIContent* aContent,
457 : Accessible* aContext)
458 : {
459 : // nsPluginFrame means a plugin, so we need to use the accessibility support
460 : // of the plugin.
461 0 : if (aFrame->GetRect().IsEmpty())
462 0 : return nullptr;
463 :
464 : #if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK)
465 0 : RefPtr<nsNPAPIPluginInstance> pluginInstance;
466 0 : if (NS_SUCCEEDED(aFrame->GetPluginInstance(getter_AddRefs(pluginInstance))) &&
467 0 : pluginInstance) {
468 : #ifdef XP_WIN
469 : if (!sPendingPlugins->Contains(aContent) &&
470 : (Preferences::GetBool("accessibility.delay_plugins") ||
471 : Compatibility::IsJAWS() || Compatibility::IsWE())) {
472 : nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
473 : RefPtr<PluginTimerCallBack> cb = new PluginTimerCallBack(aContent);
474 : timer->InitWithCallback(cb, Preferences::GetUint("accessibility.delay_plugin_time"),
475 : nsITimer::TYPE_ONE_SHOT);
476 : sPluginTimers->AppendElement(timer);
477 : sPendingPlugins->AppendElement(aContent);
478 : return nullptr;
479 : }
480 :
481 : // We need to remove aContent from the pending plugins here to avoid
482 : // reentrancy. When the timer fires it calls
483 : // DocAccessible::ContentInserted() which does the work async.
484 : sPendingPlugins->RemoveElement(aContent);
485 :
486 : // Note: pluginPort will be null if windowless.
487 : HWND pluginPort = nullptr;
488 : aFrame->GetPluginPort(&pluginPort);
489 :
490 : RefPtr<Accessible> accessible =
491 : new HTMLWin32ObjectOwnerAccessible(aContent, aContext->Document(),
492 : pluginPort);
493 : return accessible.forget();
494 :
495 : #elif MOZ_ACCESSIBILITY_ATK
496 0 : if (!AtkSocketAccessible::gCanEmbed)
497 0 : return nullptr;
498 :
499 : // Note this calls into the plugin, so crazy things may happen and aFrame
500 : // may go away.
501 0 : nsCString plugId;
502 0 : nsresult rv = pluginInstance->GetValueFromPlugin(
503 0 : NPPVpluginNativeAccessibleAtkPlugId, &plugId);
504 0 : if (NS_SUCCEEDED(rv) && !plugId.IsEmpty()) {
505 : RefPtr<AtkSocketAccessible> socketAccessible =
506 0 : new AtkSocketAccessible(aContent, aContext->Document(), plugId);
507 :
508 0 : return socketAccessible.forget();
509 : }
510 : #endif
511 : }
512 : #endif
513 :
514 0 : return nullptr;
515 : }
516 :
517 : void
518 0 : nsAccessibilityService::DeckPanelSwitched(nsIPresShell* aPresShell,
519 : nsIContent* aDeckNode,
520 : nsIFrame* aPrevBoxFrame,
521 : nsIFrame* aCurrentBoxFrame)
522 : {
523 : // Ignore tabpanels elements (a deck having an accessible) since their
524 : // children are accessible not depending on selected tab.
525 0 : DocAccessible* document = GetDocAccessible(aPresShell);
526 0 : if (!document || document->HasAccessible(aDeckNode))
527 0 : return;
528 :
529 0 : if (aPrevBoxFrame) {
530 0 : nsIContent* panelNode = aPrevBoxFrame->GetContent();
531 : #ifdef A11Y_LOG
532 0 : if (logging::IsEnabled(logging::eTree)) {
533 0 : logging::MsgBegin("TREE", "deck panel unselected");
534 0 : logging::Node("container", panelNode);
535 0 : logging::Node("content", aDeckNode);
536 0 : logging::MsgEnd();
537 : }
538 : #endif
539 :
540 0 : document->ContentRemoved(panelNode);
541 : }
542 :
543 0 : if (aCurrentBoxFrame) {
544 0 : nsIContent* panelNode = aCurrentBoxFrame->GetContent();
545 : #ifdef A11Y_LOG
546 0 : if (logging::IsEnabled(logging::eTree)) {
547 0 : logging::MsgBegin("TREE", "deck panel selected");
548 0 : logging::Node("container", panelNode);
549 0 : logging::Node("content", aDeckNode);
550 0 : logging::MsgEnd();
551 : }
552 : #endif
553 :
554 0 : document->ContentInserted(aDeckNode, panelNode, panelNode->GetNextSibling());
555 : }
556 : }
557 :
558 : void
559 0 : nsAccessibilityService::ContentRangeInserted(nsIPresShell* aPresShell,
560 : nsIContent* aContainer,
561 : nsIContent* aStartChild,
562 : nsIContent* aEndChild)
563 : {
564 0 : DocAccessible* document = GetDocAccessible(aPresShell);
565 : #ifdef A11Y_LOG
566 0 : if (logging::IsEnabled(logging::eTree)) {
567 0 : logging::MsgBegin("TREE", "content inserted; doc: %p", document);
568 0 : logging::Node("container", aContainer);
569 0 : for (nsIContent* child = aStartChild; child != aEndChild;
570 0 : child = child->GetNextSibling()) {
571 0 : logging::Node("content", child);
572 : }
573 0 : logging::MsgEnd();
574 0 : logging::Stack();
575 : }
576 : #endif
577 :
578 0 : if (document) {
579 0 : document->ContentInserted(aContainer, aStartChild, aEndChild);
580 : }
581 0 : }
582 :
583 : void
584 0 : nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell,
585 : nsIContent* aChildNode)
586 : {
587 0 : DocAccessible* document = GetDocAccessible(aPresShell);
588 : #ifdef A11Y_LOG
589 0 : if (logging::IsEnabled(logging::eTree)) {
590 0 : logging::MsgBegin("TREE", "content removed; doc: %p", document);
591 0 : logging::Node("container node", aChildNode->GetFlattenedTreeParent());
592 0 : logging::Node("content node", aChildNode);
593 0 : logging::MsgEnd();
594 : }
595 : #endif
596 :
597 0 : if (document) {
598 0 : document->ContentRemoved(aChildNode);
599 : }
600 :
601 : #ifdef A11Y_LOG
602 0 : if (logging::IsEnabled(logging::eTree)) {
603 0 : logging::MsgEnd();
604 0 : logging::Stack();
605 : }
606 : #endif
607 0 : }
608 :
609 : void
610 0 : nsAccessibilityService::UpdateText(nsIPresShell* aPresShell,
611 : nsIContent* aContent)
612 : {
613 0 : DocAccessible* document = GetDocAccessible(aPresShell);
614 0 : if (document)
615 0 : document->UpdateText(aContent);
616 0 : }
617 :
618 : void
619 0 : nsAccessibilityService::TreeViewChanged(nsIPresShell* aPresShell,
620 : nsIContent* aContent,
621 : nsITreeView* aView)
622 : {
623 0 : DocAccessible* document = GetDocAccessible(aPresShell);
624 0 : if (document) {
625 0 : Accessible* accessible = document->GetAccessible(aContent);
626 0 : if (accessible) {
627 0 : XULTreeAccessible* treeAcc = accessible->AsXULTree();
628 0 : if (treeAcc)
629 0 : treeAcc->TreeViewChanged(aView);
630 : }
631 : }
632 0 : }
633 :
634 : void
635 0 : nsAccessibilityService::RangeValueChanged(nsIPresShell* aPresShell,
636 : nsIContent* aContent)
637 : {
638 0 : DocAccessible* document = GetDocAccessible(aPresShell);
639 0 : if (document) {
640 0 : Accessible* accessible = document->GetAccessible(aContent);
641 0 : if (accessible) {
642 : document->FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
643 0 : accessible);
644 : }
645 : }
646 0 : }
647 :
648 : void
649 0 : nsAccessibilityService::UpdateListBullet(nsIPresShell* aPresShell,
650 : nsIContent* aHTMLListItemContent,
651 : bool aHasBullet)
652 : {
653 0 : DocAccessible* document = GetDocAccessible(aPresShell);
654 0 : if (document) {
655 0 : Accessible* accessible = document->GetAccessible(aHTMLListItemContent);
656 0 : if (accessible) {
657 0 : HTMLLIAccessible* listItem = accessible->AsHTMLListItem();
658 0 : if (listItem)
659 0 : listItem->UpdateBullet(aHasBullet);
660 : }
661 : }
662 0 : }
663 :
664 : void
665 0 : nsAccessibilityService::UpdateImageMap(nsImageFrame* aImageFrame)
666 : {
667 0 : nsIPresShell* presShell = aImageFrame->PresContext()->PresShell();
668 0 : DocAccessible* document = GetDocAccessible(presShell);
669 0 : if (document) {
670 : Accessible* accessible =
671 0 : document->GetAccessible(aImageFrame->GetContent());
672 0 : if (accessible) {
673 0 : HTMLImageMapAccessible* imageMap = accessible->AsImageMap();
674 0 : if (imageMap) {
675 0 : imageMap->UpdateChildAreas();
676 0 : return;
677 : }
678 :
679 : // If image map was initialized after we created an accessible (that'll
680 : // be an image accessible) then recreate it.
681 0 : RecreateAccessible(presShell, aImageFrame->GetContent());
682 : }
683 : }
684 : }
685 :
686 : void
687 0 : nsAccessibilityService::UpdateLabelValue(nsIPresShell* aPresShell,
688 : nsIContent* aLabelElm,
689 : const nsString& aNewValue)
690 : {
691 0 : DocAccessible* document = GetDocAccessible(aPresShell);
692 0 : if (document) {
693 0 : Accessible* accessible = document->GetAccessible(aLabelElm);
694 0 : if (accessible) {
695 0 : XULLabelAccessible* xulLabel = accessible->AsXULLabel();
696 0 : NS_ASSERTION(xulLabel,
697 : "UpdateLabelValue was called for wrong accessible!");
698 0 : if (xulLabel)
699 0 : xulLabel->UpdateLabelValue(aNewValue);
700 : }
701 : }
702 0 : }
703 :
704 : void
705 0 : nsAccessibilityService::PresShellActivated(nsIPresShell* aPresShell)
706 : {
707 0 : DocAccessible* document = aPresShell->GetDocAccessible();
708 0 : if (document) {
709 0 : RootAccessible* rootDocument = document->RootAccessible();
710 0 : NS_ASSERTION(rootDocument, "Entirely broken tree: no root document!");
711 0 : if (rootDocument)
712 0 : rootDocument->DocumentActivated(document);
713 : }
714 0 : }
715 :
716 : void
717 0 : nsAccessibilityService::RecreateAccessible(nsIPresShell* aPresShell,
718 : nsIContent* aContent)
719 : {
720 0 : DocAccessible* document = GetDocAccessible(aPresShell);
721 0 : if (document)
722 0 : document->RecreateAccessible(aContent);
723 0 : }
724 :
725 : void
726 0 : nsAccessibilityService::GetStringRole(uint32_t aRole, nsAString& aString)
727 : {
728 : #define ROLE(geckoRole, stringRole, atkRole, \
729 : macRole, msaaRole, ia2Role, nameRule) \
730 : case roles::geckoRole: \
731 : CopyUTF8toUTF16(stringRole, aString); \
732 : return;
733 :
734 0 : switch (aRole) {
735 : #include "RoleMap.h"
736 : default:
737 0 : aString.AssignLiteral("unknown");
738 0 : return;
739 : }
740 :
741 : #undef ROLE
742 : }
743 :
744 : void
745 0 : nsAccessibilityService::GetStringStates(uint32_t aState, uint32_t aExtraState,
746 : nsISupports** aStringStates)
747 : {
748 : RefPtr<DOMStringList> stringStates =
749 0 : GetStringStates(nsAccUtils::To64State(aState, aExtraState));
750 :
751 : // unknown state
752 0 : if (!stringStates->Length()) {
753 0 : stringStates->Add(NS_LITERAL_STRING("unknown"));
754 : }
755 :
756 0 : stringStates.forget(aStringStates);
757 0 : }
758 :
759 : already_AddRefed<DOMStringList>
760 0 : nsAccessibilityService::GetStringStates(uint64_t aStates) const
761 : {
762 0 : RefPtr<DOMStringList> stringStates = new DOMStringList();
763 :
764 0 : if (aStates & states::UNAVAILABLE) {
765 0 : stringStates->Add(NS_LITERAL_STRING("unavailable"));
766 : }
767 0 : if (aStates & states::SELECTED) {
768 0 : stringStates->Add(NS_LITERAL_STRING("selected"));
769 : }
770 0 : if (aStates & states::FOCUSED) {
771 0 : stringStates->Add(NS_LITERAL_STRING("focused"));
772 : }
773 0 : if (aStates & states::PRESSED) {
774 0 : stringStates->Add(NS_LITERAL_STRING("pressed"));
775 : }
776 0 : if (aStates & states::CHECKED) {
777 0 : stringStates->Add(NS_LITERAL_STRING("checked"));
778 : }
779 0 : if (aStates & states::MIXED) {
780 0 : stringStates->Add(NS_LITERAL_STRING("mixed"));
781 : }
782 0 : if (aStates & states::READONLY) {
783 0 : stringStates->Add(NS_LITERAL_STRING("readonly"));
784 : }
785 0 : if (aStates & states::HOTTRACKED) {
786 0 : stringStates->Add(NS_LITERAL_STRING("hottracked"));
787 : }
788 0 : if (aStates & states::DEFAULT) {
789 0 : stringStates->Add(NS_LITERAL_STRING("default"));
790 : }
791 0 : if (aStates & states::EXPANDED) {
792 0 : stringStates->Add(NS_LITERAL_STRING("expanded"));
793 : }
794 0 : if (aStates & states::COLLAPSED) {
795 0 : stringStates->Add(NS_LITERAL_STRING("collapsed"));
796 : }
797 0 : if (aStates & states::BUSY) {
798 0 : stringStates->Add(NS_LITERAL_STRING("busy"));
799 : }
800 0 : if (aStates & states::FLOATING) {
801 0 : stringStates->Add(NS_LITERAL_STRING("floating"));
802 : }
803 0 : if (aStates & states::ANIMATED) {
804 0 : stringStates->Add(NS_LITERAL_STRING("animated"));
805 : }
806 0 : if (aStates & states::INVISIBLE) {
807 0 : stringStates->Add(NS_LITERAL_STRING("invisible"));
808 : }
809 0 : if (aStates & states::OFFSCREEN) {
810 0 : stringStates->Add(NS_LITERAL_STRING("offscreen"));
811 : }
812 0 : if (aStates & states::SIZEABLE) {
813 0 : stringStates->Add(NS_LITERAL_STRING("sizeable"));
814 : }
815 0 : if (aStates & states::MOVEABLE) {
816 0 : stringStates->Add(NS_LITERAL_STRING("moveable"));
817 : }
818 0 : if (aStates & states::SELFVOICING) {
819 0 : stringStates->Add(NS_LITERAL_STRING("selfvoicing"));
820 : }
821 0 : if (aStates & states::FOCUSABLE) {
822 0 : stringStates->Add(NS_LITERAL_STRING("focusable"));
823 : }
824 0 : if (aStates & states::SELECTABLE) {
825 0 : stringStates->Add(NS_LITERAL_STRING("selectable"));
826 : }
827 0 : if (aStates & states::LINKED) {
828 0 : stringStates->Add(NS_LITERAL_STRING("linked"));
829 : }
830 0 : if (aStates & states::TRAVERSED) {
831 0 : stringStates->Add(NS_LITERAL_STRING("traversed"));
832 : }
833 0 : if (aStates & states::MULTISELECTABLE) {
834 0 : stringStates->Add(NS_LITERAL_STRING("multiselectable"));
835 : }
836 0 : if (aStates & states::EXTSELECTABLE) {
837 0 : stringStates->Add(NS_LITERAL_STRING("extselectable"));
838 : }
839 0 : if (aStates & states::PROTECTED) {
840 0 : stringStates->Add(NS_LITERAL_STRING("protected"));
841 : }
842 0 : if (aStates & states::HASPOPUP) {
843 0 : stringStates->Add(NS_LITERAL_STRING("haspopup"));
844 : }
845 0 : if (aStates & states::REQUIRED) {
846 0 : stringStates->Add(NS_LITERAL_STRING("required"));
847 : }
848 0 : if (aStates & states::ALERT) {
849 0 : stringStates->Add(NS_LITERAL_STRING("alert"));
850 : }
851 0 : if (aStates & states::INVALID) {
852 0 : stringStates->Add(NS_LITERAL_STRING("invalid"));
853 : }
854 0 : if (aStates & states::CHECKABLE) {
855 0 : stringStates->Add(NS_LITERAL_STRING("checkable"));
856 : }
857 0 : if (aStates & states::SUPPORTS_AUTOCOMPLETION) {
858 0 : stringStates->Add(NS_LITERAL_STRING("autocompletion"));
859 : }
860 0 : if (aStates & states::DEFUNCT) {
861 0 : stringStates->Add(NS_LITERAL_STRING("defunct"));
862 : }
863 0 : if (aStates & states::SELECTABLE_TEXT) {
864 0 : stringStates->Add(NS_LITERAL_STRING("selectable text"));
865 : }
866 0 : if (aStates & states::EDITABLE) {
867 0 : stringStates->Add(NS_LITERAL_STRING("editable"));
868 : }
869 0 : if (aStates & states::ACTIVE) {
870 0 : stringStates->Add(NS_LITERAL_STRING("active"));
871 : }
872 0 : if (aStates & states::MODAL) {
873 0 : stringStates->Add(NS_LITERAL_STRING("modal"));
874 : }
875 0 : if (aStates & states::MULTI_LINE) {
876 0 : stringStates->Add(NS_LITERAL_STRING("multi line"));
877 : }
878 0 : if (aStates & states::HORIZONTAL) {
879 0 : stringStates->Add(NS_LITERAL_STRING("horizontal"));
880 : }
881 0 : if (aStates & states::OPAQUE1) {
882 0 : stringStates->Add(NS_LITERAL_STRING("opaque"));
883 : }
884 0 : if (aStates & states::SINGLE_LINE) {
885 0 : stringStates->Add(NS_LITERAL_STRING("single line"));
886 : }
887 0 : if (aStates & states::TRANSIENT) {
888 0 : stringStates->Add(NS_LITERAL_STRING("transient"));
889 : }
890 0 : if (aStates & states::VERTICAL) {
891 0 : stringStates->Add(NS_LITERAL_STRING("vertical"));
892 : }
893 0 : if (aStates & states::STALE) {
894 0 : stringStates->Add(NS_LITERAL_STRING("stale"));
895 : }
896 0 : if (aStates & states::ENABLED) {
897 0 : stringStates->Add(NS_LITERAL_STRING("enabled"));
898 : }
899 0 : if (aStates & states::SENSITIVE) {
900 0 : stringStates->Add(NS_LITERAL_STRING("sensitive"));
901 : }
902 0 : if (aStates & states::EXPANDABLE) {
903 0 : stringStates->Add(NS_LITERAL_STRING("expandable"));
904 : }
905 :
906 0 : return stringStates.forget();
907 : }
908 :
909 : void
910 0 : nsAccessibilityService::GetStringEventType(uint32_t aEventType,
911 : nsAString& aString)
912 : {
913 0 : NS_ASSERTION(nsIAccessibleEvent::EVENT_LAST_ENTRY == ArrayLength(kEventTypeNames),
914 : "nsIAccessibleEvent constants are out of sync to kEventTypeNames");
915 :
916 0 : if (aEventType >= ArrayLength(kEventTypeNames)) {
917 0 : aString.AssignLiteral("unknown");
918 0 : return;
919 : }
920 :
921 0 : CopyUTF8toUTF16(kEventTypeNames[aEventType], aString);
922 : }
923 :
924 : void
925 0 : nsAccessibilityService::GetStringRelationType(uint32_t aRelationType,
926 : nsAString& aString)
927 : {
928 0 : NS_ENSURE_TRUE_VOID(aRelationType <= static_cast<uint32_t>(RelationType::LAST));
929 :
930 : #define RELATIONTYPE(geckoType, geckoTypeName, atkType, msaaType, ia2Type) \
931 : case RelationType::geckoType: \
932 : aString.AssignLiteral(geckoTypeName); \
933 : return;
934 :
935 0 : RelationType relationType = static_cast<RelationType>(aRelationType);
936 0 : switch (relationType) {
937 : #include "RelationTypeMap.h"
938 : default:
939 0 : aString.AssignLiteral("unknown");
940 0 : return;
941 : }
942 :
943 : #undef RELATIONTYPE
944 : }
945 :
946 : ////////////////////////////////////////////////////////////////////////////////
947 : // nsAccessibilityService public
948 :
949 : Accessible*
950 0 : nsAccessibilityService::CreateAccessible(nsINode* aNode,
951 : Accessible* aContext,
952 : bool* aIsSubtreeHidden)
953 : {
954 0 : MOZ_ASSERT(aContext, "No context provided");
955 0 : MOZ_ASSERT(aNode, "No node to create an accessible for");
956 0 : MOZ_ASSERT(gConsumers, "No creation after shutdown");
957 :
958 0 : if (aIsSubtreeHidden)
959 0 : *aIsSubtreeHidden = false;
960 :
961 0 : DocAccessible* document = aContext->Document();
962 0 : MOZ_ASSERT(!document->GetAccessible(aNode),
963 : "We already have an accessible for this node.");
964 :
965 0 : if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
966 : // If it's document node then ask accessible document loader for
967 : // document accessible, otherwise return null.
968 0 : nsCOMPtr<nsIDocument> document(do_QueryInterface(aNode));
969 0 : return GetDocAccessible(document);
970 : }
971 :
972 : // We have a content node.
973 0 : if (!aNode->GetComposedDoc()) {
974 0 : NS_WARNING("Creating accessible for node with no document");
975 0 : return nullptr;
976 : }
977 :
978 0 : if (aNode->OwnerDoc() != document->DocumentNode()) {
979 0 : NS_ERROR("Creating accessible for wrong document");
980 0 : return nullptr;
981 : }
982 :
983 0 : if (!aNode->IsContent())
984 0 : return nullptr;
985 :
986 0 : nsIContent* content = aNode->AsContent();
987 0 : nsIFrame* frame = content->GetPrimaryFrame();
988 :
989 : // Check frame and its visibility. Note, hidden frame allows visible
990 : // elements in subtree.
991 0 : if (!frame || !frame->StyleVisibility()->IsVisible()) {
992 0 : if (aIsSubtreeHidden && !frame)
993 0 : *aIsSubtreeHidden = true;
994 :
995 0 : return nullptr;
996 : }
997 :
998 0 : if (frame->GetContent() != content) {
999 : // Not the main content for this frame. This happens because <area>
1000 : // elements return the image frame as their primary frame. The main content
1001 : // for the image frame is the image content. If the frame is not an image
1002 : // frame or the node is not an area element then null is returned.
1003 : // This setup will change when bug 135040 is fixed. Make sure we don't
1004 : // create area accessible here. Hopefully assertion below will handle that.
1005 :
1006 : #ifdef DEBUG
1007 0 : nsImageFrame* imageFrame = do_QueryFrame(frame);
1008 0 : NS_ASSERTION(imageFrame && content->IsHTMLElement(nsGkAtoms::area),
1009 : "Unknown case of not main content for the frame!");
1010 : #endif
1011 0 : return nullptr;
1012 : }
1013 :
1014 : #ifdef DEBUG
1015 0 : nsImageFrame* imageFrame = do_QueryFrame(frame);
1016 0 : NS_ASSERTION(!imageFrame || !content->IsHTMLElement(nsGkAtoms::area),
1017 : "Image map manages the area accessible creation!");
1018 : #endif
1019 :
1020 : // Attempt to create an accessible based on what we know.
1021 0 : RefPtr<Accessible> newAcc;
1022 :
1023 : // Create accessible for visible text frames.
1024 0 : if (content->IsNodeOfType(nsINode::eTEXT)) {
1025 : nsIFrame::RenderedText text = frame->GetRenderedText(0,
1026 : UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
1027 0 : nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
1028 : // Ignore not rendered text nodes and whitespace text nodes between table
1029 : // cells.
1030 0 : if (text.mString.IsEmpty() ||
1031 0 : (aContext->IsTableRow() && nsCoreUtils::IsWhitespaceString(text.mString))) {
1032 0 : if (aIsSubtreeHidden)
1033 0 : *aIsSubtreeHidden = true;
1034 :
1035 0 : return nullptr;
1036 : }
1037 :
1038 0 : newAcc = CreateAccessibleByFrameType(frame, content, aContext);
1039 0 : document->BindToDocument(newAcc, nullptr);
1040 0 : newAcc->AsTextLeaf()->SetText(text.mString);
1041 0 : return newAcc;
1042 : }
1043 :
1044 0 : if (content->IsHTMLElement(nsGkAtoms::map)) {
1045 : // Create hyper text accessible for HTML map if it is used to group links
1046 : // (see http://www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass). If the HTML
1047 : // map rect is empty then it is used for links grouping. Otherwise it should
1048 : // be used in conjunction with HTML image element and in this case we don't
1049 : // create any accessible for it and don't walk into it. The accessibles for
1050 : // HTML area (HTMLAreaAccessible) the map contains are attached as
1051 : // children of the appropriate accessible for HTML image
1052 : // (ImageAccessible).
1053 0 : if (nsLayoutUtils::GetAllInFlowRectsUnion(frame,
1054 0 : frame->GetParent()).IsEmpty()) {
1055 0 : if (aIsSubtreeHidden)
1056 0 : *aIsSubtreeHidden = true;
1057 :
1058 0 : return nullptr;
1059 : }
1060 :
1061 0 : newAcc = new HyperTextAccessibleWrap(content, document);
1062 0 : document->BindToDocument(newAcc, aria::GetRoleMap(content->AsElement()));
1063 0 : return newAcc;
1064 : }
1065 :
1066 0 : const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(content->AsElement());
1067 :
1068 : // If the element is focusable or global ARIA attribute is applied to it or
1069 : // it is referenced by ARIA relationship then treat role="presentation" on
1070 : // the element as the role is not there.
1071 0 : if (roleMapEntry &&
1072 0 : (roleMapEntry->Is(nsGkAtoms::presentation) ||
1073 0 : roleMapEntry->Is(nsGkAtoms::none))) {
1074 0 : if (!MustBeAccessible(content, document))
1075 0 : return nullptr;
1076 :
1077 0 : roleMapEntry = nullptr;
1078 : }
1079 :
1080 0 : if (!newAcc && content->IsHTMLElement()) { // HTML accessibles
1081 0 : bool isARIATablePart = roleMapEntry &&
1082 0 : (roleMapEntry->accTypes & (eTableCell | eTableRow | eTable));
1083 :
1084 0 : if (!isARIATablePart ||
1085 0 : frame->AccessibleType() == eHTMLTableCellType ||
1086 0 : frame->AccessibleType() == eHTMLTableRowType ||
1087 0 : frame->AccessibleType() == eHTMLTableType) {
1088 : // Prefer to use markup to decide if and what kind of accessible to create,
1089 : const MarkupMapInfo* markupMap =
1090 0 : mMarkupMaps.Get(content->NodeInfo()->NameAtom());
1091 0 : if (markupMap && markupMap->new_func)
1092 0 : newAcc = markupMap->new_func(content, aContext);
1093 :
1094 0 : if (!newAcc) // try by frame accessible type.
1095 0 : newAcc = CreateAccessibleByFrameType(frame, content, aContext);
1096 : }
1097 :
1098 : // In case of ARIA grid or table use table-specific classes if it's not
1099 : // native table based.
1100 0 : if (isARIATablePart && (!newAcc || newAcc->IsGenericHyperText())) {
1101 0 : if ((roleMapEntry->accTypes & eTableCell)) {
1102 0 : if (aContext->IsTableRow())
1103 0 : newAcc = new ARIAGridCellAccessibleWrap(content, document);
1104 :
1105 0 : } else if (roleMapEntry->IsOfType(eTableRow)) {
1106 0 : if (aContext->IsTable())
1107 0 : newAcc = new ARIARowAccessible(content, document);
1108 :
1109 0 : } else if (roleMapEntry->IsOfType(eTable)) {
1110 0 : newAcc = new ARIAGridAccessibleWrap(content, document);
1111 : }
1112 : }
1113 :
1114 : // If table has strong ARIA role then all table descendants shouldn't
1115 : // expose their native roles.
1116 0 : if (!roleMapEntry && newAcc && aContext->HasStrongARIARole()) {
1117 0 : if (frame->AccessibleType() == eHTMLTableRowType) {
1118 0 : const nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap();
1119 0 : if (!contextRoleMap->IsOfType(eTable))
1120 0 : roleMapEntry = &aria::gEmptyRoleMap;
1121 :
1122 0 : } else if (frame->AccessibleType() == eHTMLTableCellType &&
1123 0 : aContext->ARIARoleMap() == &aria::gEmptyRoleMap) {
1124 0 : roleMapEntry = &aria::gEmptyRoleMap;
1125 :
1126 0 : } else if (content->IsAnyOfHTMLElements(nsGkAtoms::dt,
1127 : nsGkAtoms::li,
1128 0 : nsGkAtoms::dd) ||
1129 0 : frame->AccessibleType() == eHTMLLiType) {
1130 0 : const nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap();
1131 0 : if (!contextRoleMap->IsOfType(eList))
1132 0 : roleMapEntry = &aria::gEmptyRoleMap;
1133 : }
1134 : }
1135 : }
1136 :
1137 : // Accessible XBL types and deck stuff are used in XUL only currently.
1138 0 : if (!newAcc && content->IsXULElement()) {
1139 : // No accessible for not selected deck panel and its children.
1140 0 : if (!aContext->IsXULTabpanels()) {
1141 0 : nsDeckFrame* deckFrame = do_QueryFrame(frame->GetParent());
1142 0 : if (deckFrame && deckFrame->GetSelectedBox() != frame) {
1143 0 : if (aIsSubtreeHidden)
1144 0 : *aIsSubtreeHidden = true;
1145 :
1146 0 : return nullptr;
1147 : }
1148 : }
1149 :
1150 : // XBL bindings may use @role attribute to point the accessible type
1151 : // they belong to.
1152 0 : newAcc = CreateAccessibleByType(content, document);
1153 :
1154 : // Any XUL box can be used as tabpanel, make sure we create a proper
1155 : // accessible for it.
1156 0 : if (!newAcc && aContext->IsXULTabpanels() &&
1157 0 : content->GetParent() == aContext->GetContent()) {
1158 0 : LayoutFrameType frameType = frame->Type();
1159 0 : if (frameType == LayoutFrameType::Box ||
1160 : frameType == LayoutFrameType::Scroll) {
1161 0 : newAcc = new XULTabpanelAccessible(content, document);
1162 : }
1163 : }
1164 : }
1165 :
1166 0 : if (!newAcc) {
1167 0 : if (content->IsSVGElement()) {
1168 0 : SVGGeometryFrame* geometryFrame = do_QueryFrame(frame);
1169 0 : if (geometryFrame) {
1170 : // A graphic elements: rect, circle, ellipse, line, path, polygon,
1171 : // polyline and image. A 'use' and 'text' graphic elements require
1172 : // special support.
1173 0 : newAcc = new EnumRoleAccessible<roles::GRAPHIC>(content, document);
1174 0 : } else if (content->IsSVGElement(nsGkAtoms::svg)) {
1175 0 : newAcc = new EnumRoleAccessible<roles::DIAGRAM>(content, document);
1176 : }
1177 :
1178 0 : } else if (content->IsMathMLElement()) {
1179 : const MarkupMapInfo* markupMap =
1180 0 : mMarkupMaps.Get(content->NodeInfo()->NameAtom());
1181 0 : if (markupMap && markupMap->new_func)
1182 0 : newAcc = markupMap->new_func(content, aContext);
1183 :
1184 : // Fall back to text when encountering Content MathML.
1185 0 : if (!newAcc && !content->IsAnyOfMathMLElements(nsGkAtoms::annotation_,
1186 : nsGkAtoms::annotation_xml_,
1187 : nsGkAtoms::mpadded_,
1188 : nsGkAtoms::mphantom_,
1189 : nsGkAtoms::maligngroup_,
1190 : nsGkAtoms::malignmark_,
1191 : nsGkAtoms::mspace_,
1192 : nsGkAtoms::semantics_)) {
1193 0 : newAcc = new HyperTextAccessible(content, document);
1194 : }
1195 : }
1196 : }
1197 :
1198 : // If no accessible, see if we need to create a generic accessible because
1199 : // of some property that makes this object interesting
1200 : // We don't do this for <body>, <html>, <window>, <dialog> etc. which
1201 : // correspond to the doc accessible and will be created in any case
1202 0 : if (!newAcc && !content->IsHTMLElement(nsGkAtoms::body) &&
1203 0 : content->GetParent() &&
1204 0 : (roleMapEntry || MustBeAccessible(content, document) ||
1205 0 : (content->IsHTMLElement() &&
1206 0 : nsCoreUtils::HasClickListener(content)))) {
1207 : // This content is focusable or has an interesting dynamic content accessibility property.
1208 : // If it's interesting we need it in the accessibility hierarchy so that events or
1209 : // other accessibles can point to it, or so that it can hold a state, etc.
1210 0 : if (content->IsHTMLElement()) {
1211 : // Interesting HTML container which may have selectable text and/or embedded objects
1212 0 : newAcc = new HyperTextAccessibleWrap(content, document);
1213 : } else { // XUL, SVG, MathML etc.
1214 : // Interesting generic non-HTML container
1215 0 : newAcc = new AccessibleWrap(content, document);
1216 : }
1217 : }
1218 :
1219 0 : if (newAcc) {
1220 0 : document->BindToDocument(newAcc, roleMapEntry);
1221 : }
1222 0 : return newAcc;
1223 : }
1224 :
1225 : ////////////////////////////////////////////////////////////////////////////////
1226 : // nsAccessibilityService private
1227 :
1228 : bool
1229 0 : nsAccessibilityService::Init()
1230 : {
1231 : // Initialize accessible document manager.
1232 0 : if (!DocManager::Init())
1233 0 : return false;
1234 :
1235 : // Add observers.
1236 : nsCOMPtr<nsIObserverService> observerService =
1237 0 : mozilla::services::GetObserverService();
1238 0 : if (!observerService)
1239 0 : return false;
1240 :
1241 0 : observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
1242 :
1243 : static const char16_t kInitIndicator[] = { '1', 0 };
1244 0 : observerService->NotifyObservers(nullptr, "a11y-init-or-shutdown", kInitIndicator);
1245 :
1246 : // Subscribe to EventListenerService.
1247 : nsCOMPtr<nsIEventListenerService> eventListenerService =
1248 0 : do_GetService("@mozilla.org/eventlistenerservice;1");
1249 0 : if (!eventListenerService)
1250 0 : return false;
1251 :
1252 0 : eventListenerService->AddListenerChangeListener(this);
1253 :
1254 0 : for (uint32_t i = 0; i < ArrayLength(sMarkupMapList); i++)
1255 0 : mMarkupMaps.Put(*sMarkupMapList[i].tag, &sMarkupMapList[i]);
1256 :
1257 : #ifdef A11Y_LOG
1258 0 : logging::CheckEnv();
1259 : #endif
1260 :
1261 0 : gAccessibilityService = this;
1262 0 : NS_ADDREF(gAccessibilityService); // will release in Shutdown()
1263 :
1264 0 : if (XRE_IsParentProcess()) {
1265 0 : gApplicationAccessible = new ApplicationAccessibleWrap();
1266 : } else {
1267 : #if defined(XP_WIN)
1268 : dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
1269 : MOZ_ASSERT(contentChild);
1270 : // If we were instantiated by the chrome process, GetMsaaID() will return
1271 : // a non-zero value and we may safely continue with initialization.
1272 : if (!contentChild->GetMsaaID()) {
1273 : // Since we were not instantiated by chrome, we need to synchronously
1274 : // obtain a MSAA content process id.
1275 : contentChild->SendGetA11yContentId();
1276 : }
1277 : #endif // defined(XP_WIN)
1278 :
1279 0 : gApplicationAccessible = new ApplicationAccessible();
1280 : }
1281 :
1282 0 : NS_ADDREF(gApplicationAccessible); // will release in Shutdown()
1283 0 : gApplicationAccessible->Init();
1284 :
1285 : #ifdef MOZ_CRASHREPORTER
1286 : CrashReporter::
1287 0 : AnnotateCrashReport(NS_LITERAL_CSTRING("Accessibility"),
1288 0 : NS_LITERAL_CSTRING("Active"));
1289 : #endif
1290 :
1291 : #ifdef XP_WIN
1292 : sPendingPlugins = new nsTArray<nsCOMPtr<nsIContent> >;
1293 : sPluginTimers = new nsTArray<nsCOMPtr<nsITimer> >;
1294 : #endif
1295 :
1296 : // Now its safe to start platform accessibility.
1297 0 : if (XRE_IsParentProcess())
1298 0 : PlatformInit();
1299 :
1300 0 : statistics::A11yInitialized();
1301 :
1302 0 : return true;
1303 : }
1304 :
1305 : void
1306 0 : nsAccessibilityService::Shutdown()
1307 : {
1308 : // Application is going to be closed, shutdown accessibility and mark
1309 : // accessibility service as shutdown to prevent calls of its methods.
1310 : // Don't null accessibility service static member at this point to be safe
1311 : // if someone will try to operate with it.
1312 :
1313 0 : MOZ_ASSERT(gConsumers, "Accessibility was shutdown already");
1314 :
1315 0 : gConsumers = 0;
1316 :
1317 : // Remove observers.
1318 : nsCOMPtr<nsIObserverService> observerService =
1319 0 : mozilla::services::GetObserverService();
1320 0 : if (observerService) {
1321 0 : observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
1322 :
1323 : static const char16_t kShutdownIndicator[] = { '0', 0 };
1324 0 : observerService->NotifyObservers(nullptr, "a11y-init-or-shutdown", kShutdownIndicator);
1325 : }
1326 :
1327 : // Stop accessible document loader.
1328 0 : DocManager::Shutdown();
1329 :
1330 0 : SelectionManager::Shutdown();
1331 :
1332 : #ifdef XP_WIN
1333 : sPendingPlugins = nullptr;
1334 :
1335 : uint32_t timerCount = sPluginTimers->Length();
1336 : for (uint32_t i = 0; i < timerCount; i++)
1337 : sPluginTimers->ElementAt(i)->Cancel();
1338 :
1339 : sPluginTimers = nullptr;
1340 : #endif
1341 :
1342 0 : if (XRE_IsParentProcess())
1343 0 : PlatformShutdown();
1344 :
1345 0 : gApplicationAccessible->Shutdown();
1346 0 : NS_RELEASE(gApplicationAccessible);
1347 0 : gApplicationAccessible = nullptr;
1348 :
1349 0 : NS_IF_RELEASE(gXPCApplicationAccessible);
1350 0 : gXPCApplicationAccessible = nullptr;
1351 :
1352 0 : NS_RELEASE(gAccessibilityService);
1353 0 : gAccessibilityService = nullptr;
1354 0 : }
1355 :
1356 : already_AddRefed<Accessible>
1357 0 : nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
1358 : DocAccessible* aDoc)
1359 : {
1360 0 : nsAutoString role;
1361 0 : nsCoreUtils::XBLBindingRole(aContent, role);
1362 0 : if (role.IsEmpty() || role.EqualsLiteral("none"))
1363 0 : return nullptr;
1364 :
1365 0 : if (role.EqualsLiteral("outerdoc")) {
1366 0 : RefPtr<Accessible> accessible = new OuterDocAccessible(aContent, aDoc);
1367 0 : return accessible.forget();
1368 : }
1369 :
1370 0 : RefPtr<Accessible> accessible;
1371 : #ifdef MOZ_XUL
1372 : // XUL controls
1373 0 : if (role.EqualsLiteral("xul:alert")) {
1374 0 : accessible = new XULAlertAccessible(aContent, aDoc);
1375 :
1376 0 : } else if (role.EqualsLiteral("xul:button")) {
1377 0 : accessible = new XULButtonAccessible(aContent, aDoc);
1378 :
1379 0 : } else if (role.EqualsLiteral("xul:checkbox")) {
1380 0 : accessible = new XULCheckboxAccessible(aContent, aDoc);
1381 :
1382 0 : } else if (role.EqualsLiteral("xul:colorpicker")) {
1383 0 : accessible = new XULColorPickerAccessible(aContent, aDoc);
1384 :
1385 0 : } else if (role.EqualsLiteral("xul:colorpickertile")) {
1386 0 : accessible = new XULColorPickerTileAccessible(aContent, aDoc);
1387 :
1388 0 : } else if (role.EqualsLiteral("xul:combobox")) {
1389 0 : accessible = new XULComboboxAccessible(aContent, aDoc);
1390 :
1391 0 : } else if (role.EqualsLiteral("xul:tabpanels")) {
1392 0 : accessible = new XULTabpanelsAccessible(aContent, aDoc);
1393 :
1394 0 : } else if (role.EqualsLiteral("xul:dropmarker")) {
1395 0 : accessible = new XULDropmarkerAccessible(aContent, aDoc);
1396 :
1397 0 : } else if (role.EqualsLiteral("xul:groupbox")) {
1398 0 : accessible = new XULGroupboxAccessible(aContent, aDoc);
1399 :
1400 0 : } else if (role.EqualsLiteral("xul:image")) {
1401 0 : if (aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::onclick)) {
1402 0 : accessible = new XULToolbarButtonAccessible(aContent, aDoc);
1403 :
1404 : } else {
1405 : // Don't include nameless images in accessible tree.
1406 0 : if (!aContent->HasAttr(kNameSpaceID_None,
1407 : nsGkAtoms::tooltiptext))
1408 0 : return nullptr;
1409 :
1410 0 : accessible = new ImageAccessibleWrap(aContent, aDoc);
1411 : }
1412 :
1413 0 : } else if (role.EqualsLiteral("xul:link")) {
1414 0 : accessible = new XULLinkAccessible(aContent, aDoc);
1415 :
1416 0 : } else if (role.EqualsLiteral("xul:listbox")) {
1417 0 : accessible = new XULListboxAccessibleWrap(aContent, aDoc);
1418 :
1419 0 : } else if (role.EqualsLiteral("xul:listcell")) {
1420 : // Only create cells if there's more than one per row.
1421 0 : nsIContent* listItem = aContent->GetParent();
1422 0 : if (!listItem)
1423 0 : return nullptr;
1424 :
1425 0 : for (nsIContent* child = listItem->GetFirstChild(); child;
1426 0 : child = child->GetNextSibling()) {
1427 0 : if (child->IsXULElement(nsGkAtoms::listcell) && child != aContent) {
1428 0 : accessible = new XULListCellAccessibleWrap(aContent, aDoc);
1429 0 : break;
1430 : }
1431 : }
1432 :
1433 0 : } else if (role.EqualsLiteral("xul:listhead")) {
1434 0 : accessible = new XULColumAccessible(aContent, aDoc);
1435 :
1436 0 : } else if (role.EqualsLiteral("xul:listheader")) {
1437 0 : accessible = new XULColumnItemAccessible(aContent, aDoc);
1438 :
1439 0 : } else if (role.EqualsLiteral("xul:listitem")) {
1440 0 : accessible = new XULListitemAccessible(aContent, aDoc);
1441 :
1442 0 : } else if (role.EqualsLiteral("xul:menubar")) {
1443 0 : accessible = new XULMenubarAccessible(aContent, aDoc);
1444 :
1445 0 : } else if (role.EqualsLiteral("xul:menulist")) {
1446 0 : accessible = new XULComboboxAccessible(aContent, aDoc);
1447 :
1448 0 : } else if (role.EqualsLiteral("xul:menuitem")) {
1449 0 : accessible = new XULMenuitemAccessibleWrap(aContent, aDoc);
1450 :
1451 0 : } else if (role.EqualsLiteral("xul:menupopup")) {
1452 : #ifdef MOZ_ACCESSIBILITY_ATK
1453 : // ATK considers this node to be redundant when within menubars, and it makes menu
1454 : // navigation with assistive technologies more difficult
1455 : // XXX In the future we will should this for consistency across the nsIAccessible
1456 : // implementations on each platform for a consistent scripting environment, but
1457 : // then strip out redundant accessibles in the AccessibleWrap class for each platform.
1458 0 : nsIContent *parent = aContent->GetParent();
1459 0 : if (parent && parent->IsXULElement(nsGkAtoms::menu))
1460 0 : return nullptr;
1461 : #endif
1462 :
1463 0 : accessible = new XULMenupopupAccessible(aContent, aDoc);
1464 :
1465 0 : } else if(role.EqualsLiteral("xul:menuseparator")) {
1466 0 : accessible = new XULMenuSeparatorAccessible(aContent, aDoc);
1467 :
1468 0 : } else if(role.EqualsLiteral("xul:pane")) {
1469 0 : accessible = new EnumRoleAccessible<roles::PANE>(aContent, aDoc);
1470 :
1471 0 : } else if (role.EqualsLiteral("xul:panel")) {
1472 0 : if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::noautofocus,
1473 : nsGkAtoms::_true, eCaseMatters))
1474 0 : accessible = new XULAlertAccessible(aContent, aDoc);
1475 : else
1476 0 : accessible = new EnumRoleAccessible<roles::PANE>(aContent, aDoc);
1477 :
1478 0 : } else if (role.EqualsLiteral("xul:progressmeter")) {
1479 0 : accessible = new XULProgressMeterAccessible(aContent, aDoc);
1480 :
1481 0 : } else if (role.EqualsLiteral("xul:statusbar")) {
1482 0 : accessible = new XULStatusBarAccessible(aContent, aDoc);
1483 :
1484 0 : } else if (role.EqualsLiteral("xul:scale")) {
1485 0 : accessible = new XULSliderAccessible(aContent, aDoc);
1486 :
1487 0 : } else if (role.EqualsLiteral("xul:radiobutton")) {
1488 0 : accessible = new XULRadioButtonAccessible(aContent, aDoc);
1489 :
1490 0 : } else if (role.EqualsLiteral("xul:radiogroup")) {
1491 0 : accessible = new XULRadioGroupAccessible(aContent, aDoc);
1492 :
1493 0 : } else if (role.EqualsLiteral("xul:tab")) {
1494 0 : accessible = new XULTabAccessible(aContent, aDoc);
1495 :
1496 0 : } else if (role.EqualsLiteral("xul:tabs")) {
1497 0 : accessible = new XULTabsAccessible(aContent, aDoc);
1498 :
1499 0 : } else if (role.EqualsLiteral("xul:text")) {
1500 0 : accessible = new XULLabelAccessible(aContent, aDoc);
1501 :
1502 0 : } else if (role.EqualsLiteral("xul:textbox")) {
1503 0 : accessible = new EnumRoleAccessible<roles::SECTION>(aContent, aDoc);
1504 :
1505 0 : } else if (role.EqualsLiteral("xul:thumb")) {
1506 0 : accessible = new XULThumbAccessible(aContent, aDoc);
1507 :
1508 0 : } else if (role.EqualsLiteral("xul:tree")) {
1509 0 : accessible = CreateAccessibleForXULTree(aContent, aDoc);
1510 :
1511 0 : } else if (role.EqualsLiteral("xul:treecolumns")) {
1512 0 : accessible = new XULTreeColumAccessible(aContent, aDoc);
1513 :
1514 0 : } else if (role.EqualsLiteral("xul:treecolumnitem")) {
1515 0 : accessible = new XULColumnItemAccessible(aContent, aDoc);
1516 :
1517 0 : } else if (role.EqualsLiteral("xul:toolbar")) {
1518 0 : accessible = new XULToolbarAccessible(aContent, aDoc);
1519 :
1520 0 : } else if (role.EqualsLiteral("xul:toolbarseparator")) {
1521 0 : accessible = new XULToolbarSeparatorAccessible(aContent, aDoc);
1522 :
1523 0 : } else if (role.EqualsLiteral("xul:tooltip")) {
1524 0 : accessible = new XULTooltipAccessible(aContent, aDoc);
1525 :
1526 0 : } else if (role.EqualsLiteral("xul:toolbarbutton")) {
1527 0 : accessible = new XULToolbarButtonAccessible(aContent, aDoc);
1528 :
1529 : }
1530 : #endif // MOZ_XUL
1531 :
1532 0 : return accessible.forget();
1533 : }
1534 :
1535 : already_AddRefed<Accessible>
1536 0 : nsAccessibilityService::CreateAccessibleByFrameType(nsIFrame* aFrame,
1537 : nsIContent* aContent,
1538 : Accessible* aContext)
1539 : {
1540 0 : DocAccessible* document = aContext->Document();
1541 :
1542 0 : RefPtr<Accessible> newAcc;
1543 0 : switch (aFrame->AccessibleType()) {
1544 : case eNoType:
1545 0 : return nullptr;
1546 : case eHTMLBRType:
1547 0 : newAcc = new HTMLBRAccessible(aContent, document);
1548 0 : break;
1549 : case eHTMLButtonType:
1550 0 : newAcc = new HTMLButtonAccessible(aContent, document);
1551 0 : break;
1552 : case eHTMLCanvasType:
1553 0 : newAcc = new HTMLCanvasAccessible(aContent, document);
1554 0 : break;
1555 : case eHTMLCaptionType:
1556 0 : if (aContext->IsTable() &&
1557 0 : aContext->GetContent() == aContent->GetParent()) {
1558 0 : newAcc = new HTMLCaptionAccessible(aContent, document);
1559 : }
1560 0 : break;
1561 : case eHTMLCheckboxType:
1562 0 : newAcc = new HTMLCheckboxAccessible(aContent, document);
1563 0 : break;
1564 : case eHTMLComboboxType:
1565 0 : newAcc = new HTMLComboboxAccessible(aContent, document);
1566 0 : break;
1567 : case eHTMLFileInputType:
1568 0 : newAcc = new HTMLFileInputAccessible(aContent, document);
1569 0 : break;
1570 : case eHTMLGroupboxType:
1571 0 : newAcc = new HTMLGroupboxAccessible(aContent, document);
1572 0 : break;
1573 : case eHTMLHRType:
1574 0 : newAcc = new HTMLHRAccessible(aContent, document);
1575 0 : break;
1576 : case eHTMLImageMapType:
1577 0 : newAcc = new HTMLImageMapAccessible(aContent, document);
1578 0 : break;
1579 : case eHTMLLiType:
1580 0 : if (aContext->IsList() &&
1581 0 : aContext->GetContent() == aContent->GetParent()) {
1582 0 : newAcc = new HTMLLIAccessible(aContent, document);
1583 : } else {
1584 : // Otherwise create a generic text accessible to avoid text jamming.
1585 0 : newAcc = new HyperTextAccessibleWrap(aContent, document);
1586 : }
1587 0 : break;
1588 : case eHTMLSelectListType:
1589 0 : newAcc = new HTMLSelectListAccessible(aContent, document);
1590 0 : break;
1591 : case eHTMLMediaType:
1592 0 : newAcc = new EnumRoleAccessible<roles::GROUPING>(aContent, document);
1593 0 : break;
1594 : case eHTMLRadioButtonType:
1595 0 : newAcc = new HTMLRadioButtonAccessible(aContent, document);
1596 0 : break;
1597 : case eHTMLRangeType:
1598 0 : newAcc = new HTMLRangeAccessible(aContent, document);
1599 0 : break;
1600 : case eHTMLSpinnerType:
1601 0 : newAcc = new HTMLSpinnerAccessible(aContent, document);
1602 0 : break;
1603 : case eHTMLTableType:
1604 0 : if (aContent->IsHTMLElement(nsGkAtoms::table))
1605 0 : newAcc = new HTMLTableAccessibleWrap(aContent, document);
1606 : else
1607 0 : newAcc = new HyperTextAccessibleWrap(aContent, document);
1608 0 : break;
1609 : case eHTMLTableCellType:
1610 : // Accessible HTML table cell should be a child of accessible HTML table
1611 : // or its row (CSS HTML tables are polite to the used markup at
1612 : // certain degree).
1613 : // Otherwise create a generic text accessible to avoid text jamming
1614 : // when reading by AT.
1615 0 : if (aContext->IsHTMLTableRow() || aContext->IsHTMLTable())
1616 0 : newAcc = new HTMLTableCellAccessibleWrap(aContent, document);
1617 : else
1618 0 : newAcc = new HyperTextAccessibleWrap(aContent, document);
1619 0 : break;
1620 :
1621 : case eHTMLTableRowType: {
1622 : // Accessible HTML table row may be a child of tbody/tfoot/thead of
1623 : // accessible HTML table or a direct child of accessible of HTML table.
1624 0 : Accessible* table = aContext->IsTable() ? aContext : nullptr;
1625 0 : if (!table && aContext->Parent() && aContext->Parent()->IsTable())
1626 0 : table = aContext->Parent();
1627 :
1628 0 : if (table) {
1629 0 : nsIContent* parentContent = aContent->GetParent();
1630 0 : nsIFrame* parentFrame = parentContent->GetPrimaryFrame();
1631 0 : if (!parentFrame->IsTableWrapperFrame()) {
1632 0 : parentContent = parentContent->GetParent();
1633 0 : parentFrame = parentContent->GetPrimaryFrame();
1634 : }
1635 :
1636 0 : if (parentFrame->IsTableWrapperFrame() &&
1637 0 : table->GetContent() == parentContent) {
1638 0 : newAcc = new HTMLTableRowAccessible(aContent, document);
1639 : }
1640 : }
1641 0 : break;
1642 : }
1643 : case eHTMLTextFieldType:
1644 0 : newAcc = new HTMLTextFieldAccessible(aContent, document);
1645 0 : break;
1646 : case eHyperTextType:
1647 0 : if (!aContent->IsAnyOfHTMLElements(nsGkAtoms::dt, nsGkAtoms::dd))
1648 0 : newAcc = new HyperTextAccessibleWrap(aContent, document);
1649 0 : break;
1650 :
1651 : case eImageType:
1652 0 : newAcc = new ImageAccessibleWrap(aContent, document);
1653 0 : break;
1654 : case eOuterDocType:
1655 0 : newAcc = new OuterDocAccessible(aContent, document);
1656 0 : break;
1657 : case ePluginType: {
1658 0 : nsPluginFrame* pluginFrame = do_QueryFrame(aFrame);
1659 0 : newAcc = CreatePluginAccessible(pluginFrame, aContent, aContext);
1660 0 : break;
1661 : }
1662 : case eTextLeafType:
1663 0 : newAcc = new TextLeafAccessibleWrap(aContent, document);
1664 0 : break;
1665 : default:
1666 0 : MOZ_ASSERT(false);
1667 : break;
1668 : }
1669 :
1670 0 : return newAcc.forget();
1671 : }
1672 :
1673 : void
1674 0 : nsAccessibilityService::MarkupAttributes(const nsIContent* aContent,
1675 : nsIPersistentProperties* aAttributes) const
1676 : {
1677 : const mozilla::a11y::MarkupMapInfo* markupMap =
1678 0 : mMarkupMaps.Get(aContent->NodeInfo()->NameAtom());
1679 0 : if (!markupMap)
1680 0 : return;
1681 :
1682 0 : for (uint32_t i = 0; i < ArrayLength(markupMap->attrs); i++) {
1683 0 : const MarkupAttrInfo* info = markupMap->attrs + i;
1684 0 : if (!info->name)
1685 0 : break;
1686 :
1687 0 : if (info->DOMAttrName) {
1688 0 : if (info->DOMAttrValue) {
1689 0 : if (aContent->AttrValueIs(kNameSpaceID_None, *info->DOMAttrName,
1690 0 : *info->DOMAttrValue, eCaseMatters)) {
1691 0 : nsAccUtils::SetAccAttr(aAttributes, *info->name, *info->DOMAttrValue);
1692 : }
1693 0 : continue;
1694 : }
1695 :
1696 0 : nsAutoString value;
1697 0 : aContent->GetAttr(kNameSpaceID_None, *info->DOMAttrName, value);
1698 0 : if (!value.IsEmpty())
1699 0 : nsAccUtils::SetAccAttr(aAttributes, *info->name, value);
1700 :
1701 0 : continue;
1702 : }
1703 :
1704 0 : nsAccUtils::SetAccAttr(aAttributes, *info->name, *info->value);
1705 : }
1706 : }
1707 :
1708 : Accessible*
1709 0 : nsAccessibilityService::AddNativeRootAccessible(void* aAtkAccessible)
1710 : {
1711 : #ifdef MOZ_ACCESSIBILITY_ATK
1712 0 : ApplicationAccessible* applicationAcc = ApplicationAcc();
1713 0 : if (!applicationAcc)
1714 0 : return nullptr;
1715 :
1716 : GtkWindowAccessible* nativeWnd =
1717 0 : new GtkWindowAccessible(static_cast<AtkObject*>(aAtkAccessible));
1718 :
1719 0 : if (applicationAcc->AppendChild(nativeWnd))
1720 0 : return nativeWnd;
1721 : #endif
1722 :
1723 0 : return nullptr;
1724 : }
1725 :
1726 : void
1727 0 : nsAccessibilityService::RemoveNativeRootAccessible(Accessible* aAccessible)
1728 : {
1729 : #ifdef MOZ_ACCESSIBILITY_ATK
1730 0 : ApplicationAccessible* applicationAcc = ApplicationAcc();
1731 :
1732 0 : if (applicationAcc)
1733 0 : applicationAcc->RemoveChild(aAccessible);
1734 : #endif
1735 0 : }
1736 :
1737 : bool
1738 0 : nsAccessibilityService::HasAccessible(nsIDOMNode* aDOMNode)
1739 : {
1740 0 : nsCOMPtr<nsINode> node(do_QueryInterface(aDOMNode));
1741 0 : if (!node)
1742 0 : return false;
1743 :
1744 0 : DocAccessible* document = GetDocAccessible(node->OwnerDoc());
1745 0 : if (!document)
1746 0 : return false;
1747 :
1748 0 : return document->HasAccessible(node);
1749 : }
1750 :
1751 : ////////////////////////////////////////////////////////////////////////////////
1752 : // nsAccessibilityService private (DON'T put methods here)
1753 :
1754 : #ifdef MOZ_XUL
1755 : already_AddRefed<Accessible>
1756 0 : nsAccessibilityService::CreateAccessibleForXULTree(nsIContent* aContent,
1757 : DocAccessible* aDoc)
1758 : {
1759 0 : nsIContent* child = nsTreeUtils::GetDescendantChild(aContent,
1760 0 : nsGkAtoms::treechildren);
1761 0 : if (!child)
1762 0 : return nullptr;
1763 :
1764 0 : nsTreeBodyFrame* treeFrame = do_QueryFrame(child->GetPrimaryFrame());
1765 0 : if (!treeFrame)
1766 0 : return nullptr;
1767 :
1768 0 : RefPtr<nsTreeColumns> treeCols = treeFrame->Columns();
1769 0 : int32_t count = 0;
1770 0 : treeCols->GetCount(&count);
1771 :
1772 : // Outline of list accessible.
1773 0 : if (count == 1) {
1774 : RefPtr<Accessible> accessible =
1775 0 : new XULTreeAccessible(aContent, aDoc, treeFrame);
1776 0 : return accessible.forget();
1777 : }
1778 :
1779 : // Table or tree table accessible.
1780 : RefPtr<Accessible> accessible =
1781 0 : new XULTreeGridAccessibleWrap(aContent, aDoc, treeFrame);
1782 0 : return accessible.forget();
1783 : }
1784 : #endif
1785 :
1786 : nsAccessibilityService*
1787 0 : GetOrCreateAccService(uint32_t aNewConsumer)
1788 : {
1789 0 : if (!nsAccessibilityService::gAccessibilityService) {
1790 0 : RefPtr<nsAccessibilityService> service = new nsAccessibilityService();
1791 0 : if (!service->Init()) {
1792 0 : service->Shutdown();
1793 0 : return nullptr;
1794 : }
1795 : }
1796 :
1797 0 : MOZ_ASSERT(nsAccessibilityService::gAccessibilityService,
1798 : "Accessible service is not initialized.");
1799 0 : nsAccessibilityService::gConsumers |= aNewConsumer;
1800 0 : return nsAccessibilityService::gAccessibilityService;
1801 : }
1802 :
1803 : void
1804 0 : MaybeShutdownAccService(uint32_t aFormerConsumer)
1805 : {
1806 : nsAccessibilityService* accService =
1807 0 : nsAccessibilityService::gAccessibilityService;
1808 :
1809 0 : if (!accService || accService->IsShutdown()) {
1810 0 : return;
1811 : }
1812 :
1813 0 : if (nsCoreUtils::AccEventObserversExist() ||
1814 0 : xpcAccessibilityService::IsInUse() ||
1815 0 : accService->HasXPCDocuments()) {
1816 : // Still used by XPCOM
1817 0 : nsAccessibilityService::gConsumers =
1818 0 : (nsAccessibilityService::gConsumers & ~aFormerConsumer) |
1819 : nsAccessibilityService::eXPCOM;
1820 0 : return;
1821 : }
1822 :
1823 0 : if (nsAccessibilityService::gConsumers & ~aFormerConsumer) {
1824 0 : nsAccessibilityService::gConsumers &= ~aFormerConsumer;
1825 : } else {
1826 0 : accService->Shutdown(); // Will unset all nsAccessibilityService::gConsumers
1827 : }
1828 : }
1829 :
1830 : ////////////////////////////////////////////////////////////////////////////////
1831 : // Services
1832 : ////////////////////////////////////////////////////////////////////////////////
1833 :
1834 : namespace mozilla {
1835 : namespace a11y {
1836 :
1837 : FocusManager*
1838 0 : FocusMgr()
1839 : {
1840 0 : return nsAccessibilityService::gAccessibilityService;
1841 : }
1842 :
1843 : SelectionManager*
1844 0 : SelectionMgr()
1845 : {
1846 0 : return nsAccessibilityService::gAccessibilityService;
1847 : }
1848 :
1849 : ApplicationAccessible*
1850 0 : ApplicationAcc()
1851 : {
1852 0 : return nsAccessibilityService::gApplicationAccessible;
1853 : }
1854 :
1855 : xpcAccessibleApplication*
1856 0 : XPCApplicationAcc()
1857 : {
1858 0 : if (!nsAccessibilityService::gXPCApplicationAccessible &&
1859 0 : nsAccessibilityService::gApplicationAccessible) {
1860 0 : nsAccessibilityService::gXPCApplicationAccessible =
1861 0 : new xpcAccessibleApplication(nsAccessibilityService::gApplicationAccessible);
1862 0 : NS_ADDREF(nsAccessibilityService::gXPCApplicationAccessible);
1863 : }
1864 :
1865 0 : return nsAccessibilityService::gXPCApplicationAccessible;
1866 : }
1867 :
1868 : EPlatformDisabledState
1869 1 : PlatformDisabledState()
1870 : {
1871 : static int disabledState = 0xff;
1872 :
1873 1 : if (disabledState == 0xff) {
1874 1 : disabledState = Preferences::GetInt("accessibility.force_disabled", 0);
1875 1 : if (disabledState < ePlatformIsForceEnabled)
1876 0 : disabledState = ePlatformIsForceEnabled;
1877 1 : else if (disabledState > ePlatformIsDisabled)
1878 0 : disabledState = ePlatformIsDisabled;
1879 : }
1880 :
1881 1 : return (EPlatformDisabledState)disabledState;
1882 : }
1883 :
1884 : }
1885 : }
|