1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * John Gaunt (jgaunt@netscape.com)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "mozilla/Util.h"
40 :
41 : // NOTE: alphabetically ordered
42 : #include "nsAccessibilityService.h"
43 : #include "nsAccessiblePivot.h"
44 : #include "nsCoreUtils.h"
45 : #include "nsAccUtils.h"
46 : #include "nsApplicationAccessibleWrap.h"
47 : #include "nsARIAGridAccessibleWrap.h"
48 : #include "nsARIAMap.h"
49 : #include "FocusManager.h"
50 :
51 : #include "nsIContentViewer.h"
52 : #include "nsCURILoader.h"
53 : #include "nsDocAccessible.h"
54 : #include "nsHTMLCanvasAccessible.h"
55 : #include "nsHTMLImageMapAccessible.h"
56 : #include "nsHTMLLinkAccessible.h"
57 : #include "nsHTMLSelectAccessible.h"
58 : #include "nsHTMLTableAccessibleWrap.h"
59 : #include "nsHTMLTextAccessible.h"
60 : #include "nsHyperTextAccessibleWrap.h"
61 : #include "nsIAccessibilityService.h"
62 : #include "nsIAccessibleProvider.h"
63 : #include "Role.h"
64 : #include "States.h"
65 : #include "Statistics.h"
66 :
67 : #include "nsIDOMDocument.h"
68 : #include "nsIDOMHTMLAreaElement.h"
69 : #include "nsIDOMHTMLLegendElement.h"
70 : #include "nsIDOMHTMLObjectElement.h"
71 : #include "nsIDOMHTMLOptGroupElement.h"
72 : #include "nsIDOMHTMLOptionElement.h"
73 : #include "nsIDOMXULElement.h"
74 : #include "nsIHTMLDocument.h"
75 : #include "nsImageFrame.h"
76 : #include "nsILink.h"
77 : #include "nsIObserverService.h"
78 : #include "nsLayoutUtils.h"
79 : #include "nsNPAPIPluginInstance.h"
80 : #include "nsISupportsUtils.h"
81 : #include "nsObjectFrame.h"
82 : #include "nsOuterDocAccessible.h"
83 : #include "nsRootAccessibleWrap.h"
84 : #include "nsTextFragment.h"
85 : #include "mozilla/Services.h"
86 : #include "nsEventStates.h"
87 :
88 : #ifdef MOZ_XUL
89 : #include "nsXULAlertAccessible.h"
90 : #include "nsXULColorPickerAccessible.h"
91 : #include "nsXULComboboxAccessible.h"
92 : #include "nsXULFormControlAccessible.h"
93 : #include "nsXULListboxAccessibleWrap.h"
94 : #include "nsXULMenuAccessibleWrap.h"
95 : #include "nsXULSliderAccessible.h"
96 : #include "nsXULTabAccessible.h"
97 : #include "nsXULTextAccessible.h"
98 : #include "nsXULTreeGridAccessibleWrap.h"
99 : #endif
100 :
101 : // For native window support for object/embed/applet tags
102 : #ifdef XP_WIN
103 : #include "nsHTMLWin32ObjectAccessible.h"
104 : #endif
105 :
106 : // For embedding plugin accessibles
107 : #ifdef MOZ_ACCESSIBILITY_ATK
108 : #include "AtkSocketAccessible.h"
109 : #endif
110 :
111 : #include "nsXFormsFormControlsAccessible.h"
112 : #include "nsXFormsWidgetsAccessible.h"
113 :
114 : #include "mozilla/FunctionTimer.h"
115 : #include "mozilla/dom/Element.h"
116 :
117 : using namespace mozilla;
118 : using namespace mozilla::a11y;
119 :
120 : ////////////////////////////////////////////////////////////////////////////////
121 : // nsAccessibilityService
122 : ////////////////////////////////////////////////////////////////////////////////
123 :
124 : nsAccessibilityService *nsAccessibilityService::gAccessibilityService = nsnull;
125 : bool nsAccessibilityService::gIsShutdown = true;
126 :
127 0 : nsAccessibilityService::nsAccessibilityService() :
128 0 : nsAccDocManager(), FocusManager()
129 : {
130 : NS_TIME_FUNCTION;
131 0 : }
132 :
133 0 : nsAccessibilityService::~nsAccessibilityService()
134 : {
135 0 : NS_ASSERTION(gIsShutdown, "Accessibility wasn't shutdown!");
136 0 : gAccessibilityService = nsnull;
137 0 : }
138 :
139 : ////////////////////////////////////////////////////////////////////////////////
140 : // nsISupports
141 :
142 0 : NS_IMPL_ISUPPORTS_INHERITED3(nsAccessibilityService,
143 : nsAccDocManager,
144 : nsIAccessibilityService,
145 : nsIAccessibleRetrieval,
146 : nsIObserver)
147 :
148 : ////////////////////////////////////////////////////////////////////////////////
149 : // nsIObserver
150 :
151 : NS_IMETHODIMP
152 0 : nsAccessibilityService::Observe(nsISupports *aSubject, const char *aTopic,
153 : const PRUnichar *aData)
154 : {
155 0 : if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID))
156 0 : Shutdown();
157 :
158 0 : return NS_OK;
159 : }
160 :
161 : // nsIAccessibilityService
162 : void
163 0 : nsAccessibilityService::NotifyOfAnchorJumpTo(nsIContent* aTargetNode)
164 : {
165 0 : nsIDocument* documentNode = aTargetNode->GetCurrentDoc();
166 0 : if (documentNode) {
167 0 : nsDocAccessible* document = GetDocAccessible(documentNode);
168 0 : if (document)
169 0 : document->SetAnchorJump(aTargetNode);
170 : }
171 0 : }
172 :
173 : // nsIAccessibilityService
174 : void
175 0 : nsAccessibilityService::FireAccessibleEvent(PRUint32 aEvent,
176 : nsAccessible* aTarget)
177 : {
178 0 : nsEventShell::FireEvent(aEvent, aTarget);
179 0 : }
180 :
181 : ////////////////////////////////////////////////////////////////////////////////
182 : // nsIAccessibilityService
183 :
184 : nsAccessible*
185 0 : nsAccessibilityService::GetRootDocumentAccessible(nsIPresShell* aPresShell,
186 : bool aCanCreate)
187 : {
188 0 : nsIDocument* documentNode = aPresShell->GetDocument();
189 0 : if (documentNode) {
190 0 : nsCOMPtr<nsISupports> container = documentNode->GetContainer();
191 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(container));
192 0 : if (treeItem) {
193 0 : nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
194 0 : treeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
195 0 : if (treeItem != rootTreeItem) {
196 0 : nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(rootTreeItem));
197 0 : nsCOMPtr<nsIPresShell> presShell;
198 0 : docShell->GetPresShell(getter_AddRefs(presShell));
199 0 : documentNode = presShell->GetDocument();
200 : }
201 :
202 : return aCanCreate ?
203 0 : GetDocAccessible(documentNode) : GetDocAccessibleFromCache(documentNode);
204 : }
205 : }
206 0 : return nsnull;
207 : }
208 :
209 : already_AddRefed<nsAccessible>
210 0 : nsAccessibilityService::CreateOuterDocAccessible(nsIContent* aContent,
211 : nsIPresShell* aPresShell)
212 : {
213 : nsAccessible* accessible =
214 : new nsOuterDocAccessible(aContent,
215 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
216 0 : NS_ADDREF(accessible);
217 0 : return accessible;
218 : }
219 :
220 : already_AddRefed<nsAccessible>
221 0 : nsAccessibilityService::CreateHTMLButtonAccessible(nsIContent* aContent,
222 : nsIPresShell* aPresShell)
223 : {
224 : nsAccessible* accessible =
225 : new nsHTMLButtonAccessible(aContent,
226 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
227 0 : NS_ADDREF(accessible);
228 0 : return accessible;
229 : }
230 :
231 : already_AddRefed<nsAccessible>
232 0 : nsAccessibilityService::CreateHTMLLIAccessible(nsIContent* aContent,
233 : nsIPresShell* aPresShell)
234 : {
235 : nsAccessible* accessible =
236 : new nsHTMLLIAccessible(aContent,
237 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
238 0 : NS_ADDREF(accessible);
239 0 : return accessible;
240 : }
241 :
242 : already_AddRefed<nsAccessible>
243 0 : nsAccessibilityService::CreateHyperTextAccessible(nsIContent* aContent,
244 : nsIPresShell* aPresShell)
245 : {
246 : nsAccessible* accessible =
247 : new nsHyperTextAccessibleWrap(aContent,
248 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
249 0 : NS_ADDREF(accessible);
250 0 : return accessible;
251 : }
252 :
253 : already_AddRefed<nsAccessible>
254 0 : nsAccessibilityService::CreateHTMLCheckboxAccessible(nsIContent* aContent,
255 : nsIPresShell* aPresShell)
256 : {
257 : nsAccessible* accessible =
258 : new nsHTMLCheckboxAccessible(aContent,
259 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
260 0 : NS_ADDREF(accessible);
261 0 : return accessible;
262 : }
263 :
264 : already_AddRefed<nsAccessible>
265 0 : nsAccessibilityService::CreateHTMLComboboxAccessible(nsIContent* aContent,
266 : nsIPresShell* aPresShell)
267 : {
268 : nsAccessible* accessible =
269 : new nsHTMLComboboxAccessible(aContent,
270 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
271 0 : NS_ADDREF(accessible);
272 0 : return accessible;
273 : }
274 :
275 : already_AddRefed<nsAccessible>
276 0 : nsAccessibilityService::CreateHTMLCanvasAccessible(nsIContent* aContent,
277 : nsIPresShell* aPresShell)
278 : {
279 : nsAccessible* accessible =
280 : new nsHTMLCanvasAccessible(aContent,
281 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
282 0 : NS_ADDREF(accessible);
283 0 : return accessible;
284 : }
285 :
286 : already_AddRefed<nsAccessible>
287 0 : nsAccessibilityService::CreateHTMLFileInputAccessible(nsIContent* aContent,
288 : nsIPresShell* aPresShell)
289 : {
290 : nsAccessible* accessible =
291 : new nsHTMLFileInputAccessible(aContent,
292 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
293 0 : NS_ADDREF(accessible);
294 0 : return accessible;
295 : }
296 :
297 : already_AddRefed<nsAccessible>
298 0 : nsAccessibilityService::CreateHTMLImageAccessible(nsIContent* aContent,
299 : nsIPresShell* aPresShell)
300 : {
301 0 : nsAutoString mapElmName;
302 0 : aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::usemap, mapElmName);
303 0 : nsCOMPtr<nsIDOMHTMLMapElement> mapElm;
304 0 : if (nsIDocument* document = aContent->GetCurrentDoc()) {
305 0 : mapElm = do_QueryInterface(document->FindImageMap(mapElmName));
306 : }
307 :
308 : nsAccessible* accessible = mapElm ?
309 : new nsHTMLImageMapAccessible(aContent,
310 : nsAccUtils::GetDocAccessibleFor(aPresShell),
311 0 : mapElm) :
312 : new nsHTMLImageAccessibleWrap(aContent,
313 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
314 0 : NS_ADDREF(accessible);
315 0 : return accessible;
316 : }
317 :
318 : already_AddRefed<nsAccessible>
319 0 : nsAccessibilityService::CreateHTMLGroupboxAccessible(nsIContent* aContent,
320 : nsIPresShell* aPresShell)
321 : {
322 : nsAccessible* accessible =
323 : new nsHTMLGroupboxAccessible(aContent,
324 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
325 0 : NS_ADDREF(accessible);
326 0 : return accessible;
327 : }
328 :
329 : already_AddRefed<nsAccessible>
330 0 : nsAccessibilityService::CreateHTMLListboxAccessible(nsIContent* aContent,
331 : nsIPresShell* aPresShell)
332 : {
333 : nsAccessible* accessible =
334 : new nsHTMLSelectListAccessible(aContent,
335 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
336 0 : NS_ADDREF(accessible);
337 0 : return accessible;
338 : }
339 :
340 : already_AddRefed<nsAccessible>
341 0 : nsAccessibilityService::CreateHTMLMediaAccessible(nsIContent* aContent,
342 : nsIPresShell* aPresShell)
343 : {
344 : nsAccessible* accessible =
345 : new nsEnumRoleAccessible(aContent,
346 : nsAccUtils::GetDocAccessibleFor(aPresShell),
347 0 : roles::GROUPING);
348 0 : NS_ADDREF(accessible);
349 0 : return accessible;
350 : }
351 :
352 : already_AddRefed<nsAccessible>
353 0 : nsAccessibilityService::CreateHTMLObjectFrameAccessible(nsObjectFrame* aFrame,
354 : nsIContent* aContent,
355 : nsIPresShell* aPresShell)
356 : {
357 : // We can have several cases here:
358 : // 1) a text or html embedded document where the contentDocument variable in
359 : // the object element holds the content;
360 : // 2) web content that uses a plugin, which means we will have to go to
361 : // the plugin to get the accessible content;
362 : // 3) an image or imagemap, where the image frame points back to the object
363 : // element DOMNode.
364 :
365 0 : if (aFrame->GetRect().IsEmpty())
366 0 : return nsnull;
367 :
368 :
369 : // 1) for object elements containing either HTML or TXT documents
370 0 : nsCOMPtr<nsIDOMHTMLObjectElement> obj(do_QueryInterface(aContent));
371 0 : if (obj) {
372 0 : nsCOMPtr<nsIDOMDocument> domDoc;
373 0 : obj->GetContentDocument(getter_AddRefs(domDoc));
374 0 : if (domDoc)
375 0 : return CreateOuterDocAccessible(aContent, aPresShell);
376 : }
377 :
378 : #if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK)
379 : // 2) for plugins
380 0 : nsRefPtr<nsNPAPIPluginInstance> pluginInstance;
381 0 : if (NS_SUCCEEDED(aFrame->GetPluginInstance(getter_AddRefs(pluginInstance))) &&
382 0 : pluginInstance) {
383 : #ifdef XP_WIN
384 : // Note: pluginPort will be null if windowless.
385 : HWND pluginPort = nsnull;
386 : aFrame->GetPluginPort(&pluginPort);
387 :
388 : nsAccessible* accessible =
389 : new nsHTMLWin32ObjectOwnerAccessible(aContent,
390 : nsAccUtils::GetDocAccessibleFor(aPresShell),
391 : pluginPort);
392 : NS_ADDREF(accessible);
393 : return accessible;
394 :
395 : #elif MOZ_ACCESSIBILITY_ATK
396 0 : if (!AtkSocketAccessible::gCanEmbed)
397 0 : return nsnull;
398 :
399 0 : nsCString plugId;
400 : nsresult rv = pluginInstance->GetValueFromPlugin(
401 0 : NPPVpluginNativeAccessibleAtkPlugId, &plugId);
402 0 : if (NS_SUCCEEDED(rv) && !plugId.IsEmpty()) {
403 : AtkSocketAccessible* socketAccessible =
404 : new AtkSocketAccessible(aContent,
405 : nsAccUtils::GetDocAccessibleFor(aPresShell),
406 0 : plugId);
407 :
408 0 : NS_ADDREF(socketAccessible);
409 0 : return socketAccessible;
410 : }
411 : #endif
412 : }
413 : #endif
414 :
415 : // 3) for images and imagemaps, or anything else with a child frame
416 : // we have the object frame, get the image frame
417 0 : nsIFrame* frame = aFrame->GetFirstPrincipalChild();
418 0 : return frame ? frame->CreateAccessible() : nsnull;
419 : }
420 :
421 : already_AddRefed<nsAccessible>
422 0 : nsAccessibilityService::CreateHTMLRadioButtonAccessible(nsIContent* aContent,
423 : nsIPresShell* aPresShell)
424 : {
425 : nsAccessible* accessible =
426 : new nsHTMLRadioButtonAccessible(aContent,
427 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
428 0 : NS_ADDREF(accessible);
429 0 : return accessible;
430 : }
431 :
432 : already_AddRefed<nsAccessible>
433 0 : nsAccessibilityService::CreateHTMLTableAccessible(nsIContent* aContent,
434 : nsIPresShell* aPresShell)
435 : {
436 : nsAccessible* accessible =
437 : new nsHTMLTableAccessibleWrap(aContent,
438 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
439 0 : NS_ADDREF(accessible);
440 0 : return accessible;
441 : }
442 :
443 : already_AddRefed<nsAccessible>
444 0 : nsAccessibilityService::CreateHTMLTableCellAccessible(nsIContent* aContent,
445 : nsIPresShell* aPresShell)
446 : {
447 : nsAccessible* accessible =
448 : new nsHTMLTableCellAccessibleWrap(aContent,
449 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
450 0 : NS_ADDREF(accessible);
451 0 : return accessible;
452 : }
453 :
454 : already_AddRefed<nsAccessible>
455 0 : nsAccessibilityService::CreateHTMLTextAccessible(nsIContent* aContent,
456 : nsIPresShell* aPresShell)
457 : {
458 : nsAccessible* accessible =
459 : new nsHTMLTextAccessible(aContent,
460 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
461 0 : NS_ADDREF(accessible);
462 0 : return accessible;
463 : }
464 :
465 : already_AddRefed<nsAccessible>
466 0 : nsAccessibilityService::CreateHTMLTextFieldAccessible(nsIContent* aContent,
467 : nsIPresShell* aPresShell)
468 : {
469 : nsAccessible* accessible =
470 : new nsHTMLTextFieldAccessible(aContent,
471 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
472 0 : NS_ADDREF(accessible);
473 0 : return accessible;
474 : }
475 :
476 : already_AddRefed<nsAccessible>
477 0 : nsAccessibilityService::CreateHTMLLabelAccessible(nsIContent* aContent,
478 : nsIPresShell* aPresShell)
479 : {
480 : nsAccessible* accessible =
481 : new nsHTMLLabelAccessible(aContent,
482 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
483 0 : NS_ADDREF(accessible);
484 0 : return accessible;
485 : }
486 :
487 : already_AddRefed<nsAccessible>
488 0 : nsAccessibilityService::CreateHTMLHRAccessible(nsIContent* aContent,
489 : nsIPresShell* aPresShell)
490 : {
491 : nsAccessible* accessible =
492 : new nsHTMLHRAccessible(aContent,
493 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
494 0 : NS_ADDREF(accessible);
495 0 : return accessible;
496 : }
497 :
498 : already_AddRefed<nsAccessible>
499 0 : nsAccessibilityService::CreateHTMLBRAccessible(nsIContent* aContent,
500 : nsIPresShell* aPresShell)
501 : {
502 : nsAccessible* accessible =
503 : new nsHTMLBRAccessible(aContent,
504 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
505 0 : NS_ADDREF(accessible);
506 0 : return accessible;
507 : }
508 :
509 : already_AddRefed<nsAccessible>
510 0 : nsAccessibilityService::CreateHTMLCaptionAccessible(nsIContent* aContent,
511 : nsIPresShell* aPresShell)
512 : {
513 : nsAccessible* accessible =
514 : new nsHTMLCaptionAccessible(aContent,
515 0 : nsAccUtils::GetDocAccessibleFor(aPresShell));
516 0 : NS_ADDREF(accessible);
517 0 : return accessible;
518 : }
519 :
520 : void
521 0 : nsAccessibilityService::ContentRangeInserted(nsIPresShell* aPresShell,
522 : nsIContent* aContainer,
523 : nsIContent* aStartChild,
524 : nsIContent* aEndChild)
525 : {
526 : #ifdef DEBUG_CONTENTMUTATION
527 : nsAutoString tag;
528 : aStartChild->Tag()->ToString(tag);
529 :
530 : nsIAtom* atomid = aStartChild->GetID();
531 : nsCAutoString id;
532 : if (atomid)
533 : atomid->ToUTF8String(id);
534 :
535 : nsAutoString ctag;
536 : nsCAutoString cid;
537 : nsIAtom* catomid = nsnull;
538 : if (aContainer) {
539 : aContainer->Tag()->ToString(ctag);
540 : catomid = aContainer->GetID();
541 : if (catomid)
542 : catomid->ToUTF8String(cid);
543 : }
544 :
545 : printf("\ncontent inserted: %s@id='%s', container: %s@id='%s', end node: %p\n\n",
546 : NS_ConvertUTF16toUTF8(tag).get(), id.get(),
547 : NS_ConvertUTF16toUTF8(ctag).get(), cid.get(), aEndChild);
548 : #endif
549 :
550 0 : nsDocAccessible* docAccessible = GetDocAccessible(aPresShell->GetDocument());
551 0 : if (docAccessible)
552 0 : docAccessible->ContentInserted(aContainer, aStartChild, aEndChild);
553 0 : }
554 :
555 : void
556 0 : nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell,
557 : nsIContent* aContainer,
558 : nsIContent* aChild)
559 : {
560 : #ifdef DEBUG_CONTENTMUTATION
561 : nsAutoString tag;
562 : aChild->Tag()->ToString(tag);
563 :
564 : nsIAtom* atomid = aChild->GetID();
565 : nsCAutoString id;
566 : if (atomid)
567 : atomid->ToUTF8String(id);
568 :
569 : nsAutoString ctag;
570 : nsCAutoString cid;
571 : nsIAtom* catomid = nsnull;
572 : if (aContainer) {
573 : aContainer->Tag()->ToString(ctag);
574 : catomid = aContainer->GetID();
575 : if (catomid)
576 : catomid->ToUTF8String(cid);
577 : }
578 :
579 : printf("\ncontent removed: %s@id='%s', container: %s@id='%s'\n\n",
580 : NS_ConvertUTF16toUTF8(tag).get(), id.get(),
581 : NS_ConvertUTF16toUTF8(ctag).get(), cid.get());
582 : #endif
583 :
584 0 : nsDocAccessible* docAccessible = GetDocAccessible(aPresShell->GetDocument());
585 0 : if (docAccessible)
586 0 : docAccessible->ContentRemoved(aContainer, aChild);
587 0 : }
588 :
589 : void
590 0 : nsAccessibilityService::UpdateText(nsIPresShell* aPresShell,
591 : nsIContent* aContent)
592 : {
593 0 : nsDocAccessible* document = GetDocAccessible(aPresShell->GetDocument());
594 0 : if (document)
595 0 : document->UpdateText(aContent);
596 0 : }
597 :
598 : void
599 0 : nsAccessibilityService::UpdateListBullet(nsIPresShell* aPresShell,
600 : nsIContent* aHTMLListItemContent,
601 : bool aHasBullet)
602 : {
603 0 : nsDocAccessible* document = GetDocAccessible(aPresShell->GetDocument());
604 0 : if (document) {
605 0 : nsAccessible* accessible = document->GetAccessible(aHTMLListItemContent);
606 0 : if (accessible) {
607 0 : nsHTMLLIAccessible* listItem = accessible->AsHTMLListItem();
608 0 : if (listItem)
609 0 : listItem->UpdateBullet(aHasBullet);
610 : }
611 : }
612 0 : }
613 :
614 : void
615 0 : nsAccessibilityService::PresShellDestroyed(nsIPresShell *aPresShell)
616 : {
617 : // Presshell destruction will automatically destroy shells for descendant
618 : // documents, so no need to worry about those. Just shut down the accessible
619 : // for this one document. That keeps us from having bad behavior in case of
620 : // deep bushy subtrees.
621 : // When document subtree containing iframe is hidden then we don't get
622 : // pagehide event for the iframe's underlying document and its presshell is
623 : // destroyed before we're notified styles were changed. Shutdown the document
624 : // accessible early.
625 0 : nsIDocument* doc = aPresShell->GetDocument();
626 0 : if (!doc)
627 0 : return;
628 :
629 : NS_LOG_ACCDOCDESTROY("presshell destroyed", doc)
630 :
631 0 : nsDocAccessible* docAccessible = GetDocAccessibleFromCache(doc);
632 0 : if (docAccessible)
633 0 : docAccessible->Shutdown();
634 : }
635 :
636 : void
637 0 : nsAccessibilityService::PresShellActivated(nsIPresShell* aPresShell)
638 : {
639 0 : nsIDocument* DOMDoc = aPresShell->GetDocument();
640 0 : if (DOMDoc) {
641 0 : nsDocAccessible* document = GetDocAccessibleFromCache(DOMDoc);
642 0 : if (document) {
643 0 : nsRootAccessible* rootDocument = document->RootAccessible();
644 0 : NS_ASSERTION(rootDocument, "Entirely broken tree: no root document!");
645 0 : if (rootDocument)
646 0 : rootDocument->DocumentActivated(document);
647 : }
648 : }
649 0 : }
650 :
651 : void
652 0 : nsAccessibilityService::RecreateAccessible(nsIPresShell* aPresShell,
653 : nsIContent* aContent)
654 : {
655 0 : nsDocAccessible* document = GetDocAccessible(aPresShell->GetDocument());
656 0 : if (document) {
657 : document->HandleNotification<nsDocAccessible, nsIContent>
658 0 : (document, &nsDocAccessible::RecreateAccessible, aContent);
659 : }
660 0 : }
661 :
662 : ////////////////////////////////////////////////////////////////////////////////
663 : // nsIAccessibleRetrieval
664 :
665 : NS_IMETHODIMP
666 0 : nsAccessibilityService::GetApplicationAccessible(nsIAccessible **aAccessibleApplication)
667 : {
668 0 : NS_ENSURE_ARG_POINTER(aAccessibleApplication);
669 :
670 0 : NS_IF_ADDREF(*aAccessibleApplication = nsAccessNode::GetApplicationAccessible());
671 0 : return NS_OK;
672 : }
673 :
674 : NS_IMETHODIMP
675 0 : nsAccessibilityService::GetAccessibleFor(nsIDOMNode *aNode,
676 : nsIAccessible **aAccessible)
677 : {
678 0 : NS_ENSURE_ARG_POINTER(aAccessible);
679 0 : *aAccessible = nsnull;
680 0 : if (!aNode)
681 0 : return NS_OK;
682 :
683 0 : nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
684 0 : if (!node)
685 0 : return NS_ERROR_INVALID_ARG;
686 :
687 0 : NS_IF_ADDREF(*aAccessible = GetAccessible(node, nsnull));
688 0 : return NS_OK;
689 : }
690 :
691 : NS_IMETHODIMP
692 0 : nsAccessibilityService::GetStringRole(PRUint32 aRole, nsAString& aString)
693 : {
694 0 : if ( aRole >= ArrayLength(kRoleNames)) {
695 0 : aString.AssignLiteral("unknown");
696 0 : return NS_OK;
697 : }
698 :
699 0 : CopyUTF8toUTF16(kRoleNames[aRole], aString);
700 0 : return NS_OK;
701 : }
702 :
703 : NS_IMETHODIMP
704 0 : nsAccessibilityService::GetStringStates(PRUint32 aState, PRUint32 aExtraState,
705 : nsIDOMDOMStringList **aStringStates)
706 : {
707 0 : nsAccessibleDOMStringList *stringStates = new nsAccessibleDOMStringList();
708 0 : NS_ENSURE_TRUE(stringStates, NS_ERROR_OUT_OF_MEMORY);
709 :
710 0 : PRUint64 state = nsAccUtils::To64State(aState, aExtraState);
711 :
712 : // states
713 0 : if (state & states::UNAVAILABLE)
714 0 : stringStates->Add(NS_LITERAL_STRING("unavailable"));
715 0 : if (state & states::SELECTED)
716 0 : stringStates->Add(NS_LITERAL_STRING("selected"));
717 0 : if (state & states::FOCUSED)
718 0 : stringStates->Add(NS_LITERAL_STRING("focused"));
719 0 : if (state & states::PRESSED)
720 0 : stringStates->Add(NS_LITERAL_STRING("pressed"));
721 0 : if (state & states::CHECKED)
722 0 : stringStates->Add(NS_LITERAL_STRING("checked"));
723 0 : if (state & states::MIXED)
724 0 : stringStates->Add(NS_LITERAL_STRING("mixed"));
725 0 : if (state & states::READONLY)
726 0 : stringStates->Add(NS_LITERAL_STRING("readonly"));
727 0 : if (state & states::HOTTRACKED)
728 0 : stringStates->Add(NS_LITERAL_STRING("hottracked"));
729 0 : if (state & states::DEFAULT)
730 0 : stringStates->Add(NS_LITERAL_STRING("default"));
731 0 : if (state & states::EXPANDED)
732 0 : stringStates->Add(NS_LITERAL_STRING("expanded"));
733 0 : if (state & states::COLLAPSED)
734 0 : stringStates->Add(NS_LITERAL_STRING("collapsed"));
735 0 : if (state & states::BUSY)
736 0 : stringStates->Add(NS_LITERAL_STRING("busy"));
737 0 : if (state & states::FLOATING)
738 0 : stringStates->Add(NS_LITERAL_STRING("floating"));
739 0 : if (state & states::ANIMATED)
740 0 : stringStates->Add(NS_LITERAL_STRING("animated"));
741 0 : if (state & states::INVISIBLE)
742 0 : stringStates->Add(NS_LITERAL_STRING("invisible"));
743 0 : if (state & states::OFFSCREEN)
744 0 : stringStates->Add(NS_LITERAL_STRING("offscreen"));
745 0 : if (state & states::SIZEABLE)
746 0 : stringStates->Add(NS_LITERAL_STRING("sizeable"));
747 0 : if (state & states::MOVEABLE)
748 0 : stringStates->Add(NS_LITERAL_STRING("moveable"));
749 0 : if (state & states::SELFVOICING)
750 0 : stringStates->Add(NS_LITERAL_STRING("selfvoicing"));
751 0 : if (state & states::FOCUSABLE)
752 0 : stringStates->Add(NS_LITERAL_STRING("focusable"));
753 0 : if (state & states::SELECTABLE)
754 0 : stringStates->Add(NS_LITERAL_STRING("selectable"));
755 0 : if (state & states::LINKED)
756 0 : stringStates->Add(NS_LITERAL_STRING("linked"));
757 0 : if (state & states::TRAVERSED)
758 0 : stringStates->Add(NS_LITERAL_STRING("traversed"));
759 0 : if (state & states::MULTISELECTABLE)
760 0 : stringStates->Add(NS_LITERAL_STRING("multiselectable"));
761 0 : if (state & states::EXTSELECTABLE)
762 0 : stringStates->Add(NS_LITERAL_STRING("extselectable"));
763 0 : if (state & states::PROTECTED)
764 0 : stringStates->Add(NS_LITERAL_STRING("protected"));
765 0 : if (state & states::HASPOPUP)
766 0 : stringStates->Add(NS_LITERAL_STRING("haspopup"));
767 0 : if (state & states::REQUIRED)
768 0 : stringStates->Add(NS_LITERAL_STRING("required"));
769 0 : if (state & states::ALERT)
770 0 : stringStates->Add(NS_LITERAL_STRING("alert"));
771 0 : if (state & states::INVALID)
772 0 : stringStates->Add(NS_LITERAL_STRING("invalid"));
773 0 : if (state & states::CHECKABLE)
774 0 : stringStates->Add(NS_LITERAL_STRING("checkable"));
775 :
776 : // extraStates
777 0 : if (state & states::SUPPORTS_AUTOCOMPLETION)
778 0 : stringStates->Add(NS_LITERAL_STRING("autocompletion"));
779 0 : if (state & states::DEFUNCT)
780 0 : stringStates->Add(NS_LITERAL_STRING("defunct"));
781 0 : if (state & states::SELECTABLE_TEXT)
782 0 : stringStates->Add(NS_LITERAL_STRING("selectable text"));
783 0 : if (state & states::EDITABLE)
784 0 : stringStates->Add(NS_LITERAL_STRING("editable"));
785 0 : if (state & states::ACTIVE)
786 0 : stringStates->Add(NS_LITERAL_STRING("active"));
787 0 : if (state & states::MODAL)
788 0 : stringStates->Add(NS_LITERAL_STRING("modal"));
789 0 : if (state & states::MULTI_LINE)
790 0 : stringStates->Add(NS_LITERAL_STRING("multi line"));
791 0 : if (state & states::HORIZONTAL)
792 0 : stringStates->Add(NS_LITERAL_STRING("horizontal"));
793 0 : if (state & states::OPAQUE1)
794 0 : stringStates->Add(NS_LITERAL_STRING("opaque"));
795 0 : if (state & states::SINGLE_LINE)
796 0 : stringStates->Add(NS_LITERAL_STRING("single line"));
797 0 : if (state & states::TRANSIENT)
798 0 : stringStates->Add(NS_LITERAL_STRING("transient"));
799 0 : if (state & states::VERTICAL)
800 0 : stringStates->Add(NS_LITERAL_STRING("vertical"));
801 0 : if (state & states::STALE)
802 0 : stringStates->Add(NS_LITERAL_STRING("stale"));
803 0 : if (state & states::ENABLED)
804 0 : stringStates->Add(NS_LITERAL_STRING("enabled"));
805 0 : if (state & states::SENSITIVE)
806 0 : stringStates->Add(NS_LITERAL_STRING("sensitive"));
807 0 : if (state & states::EXPANDABLE)
808 0 : stringStates->Add(NS_LITERAL_STRING("expandable"));
809 :
810 : //unknown states
811 0 : PRUint32 stringStatesLength = 0;
812 0 : stringStates->GetLength(&stringStatesLength);
813 0 : if (!stringStatesLength)
814 0 : stringStates->Add(NS_LITERAL_STRING("unknown"));
815 :
816 0 : NS_ADDREF(*aStringStates = stringStates);
817 0 : return NS_OK;
818 : }
819 :
820 : // nsIAccessibleRetrieval::getStringEventType()
821 : NS_IMETHODIMP
822 0 : nsAccessibilityService::GetStringEventType(PRUint32 aEventType,
823 : nsAString& aString)
824 : {
825 0 : NS_ASSERTION(nsIAccessibleEvent::EVENT_LAST_ENTRY == ArrayLength(kEventTypeNames),
826 : "nsIAccessibleEvent constants are out of sync to kEventTypeNames");
827 :
828 0 : if (aEventType >= ArrayLength(kEventTypeNames)) {
829 0 : aString.AssignLiteral("unknown");
830 0 : return NS_OK;
831 : }
832 :
833 0 : CopyUTF8toUTF16(kEventTypeNames[aEventType], aString);
834 0 : return NS_OK;
835 : }
836 :
837 : // nsIAccessibleRetrieval::getStringRelationType()
838 : NS_IMETHODIMP
839 0 : nsAccessibilityService::GetStringRelationType(PRUint32 aRelationType,
840 : nsAString& aString)
841 : {
842 0 : if (aRelationType >= ArrayLength(kRelationTypeNames)) {
843 0 : aString.AssignLiteral("unknown");
844 0 : return NS_OK;
845 : }
846 :
847 0 : CopyUTF8toUTF16(kRelationTypeNames[aRelationType], aString);
848 0 : return NS_OK;
849 : }
850 :
851 : NS_IMETHODIMP
852 0 : nsAccessibilityService::GetAccessibleFromCache(nsIDOMNode* aNode,
853 : nsIAccessible** aAccessible)
854 : {
855 0 : NS_ENSURE_ARG_POINTER(aAccessible);
856 0 : *aAccessible = nsnull;
857 0 : if (!aNode)
858 0 : return NS_OK;
859 :
860 0 : nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
861 0 : if (!node)
862 0 : return NS_ERROR_INVALID_ARG;
863 :
864 : // Search for an accessible in each of our per document accessible object
865 : // caches. If we don't find it, and the given node is itself a document, check
866 : // our cache of document accessibles (document cache). Note usually shutdown
867 : // document accessibles are not stored in the document cache, however an
868 : // "unofficially" shutdown document (i.e. not from nsAccDocManager) can still
869 : // exist in the document cache.
870 0 : nsAccessible* accessible = FindAccessibleInCache(node);
871 0 : if (!accessible) {
872 0 : nsCOMPtr<nsIDocument> document(do_QueryInterface(node));
873 0 : if (document)
874 0 : accessible = GetDocAccessibleFromCache(document);
875 : }
876 :
877 0 : NS_IF_ADDREF(*aAccessible = accessible);
878 0 : return NS_OK;
879 : }
880 :
881 : NS_IMETHODIMP
882 0 : nsAccessibilityService::CreateAccessiblePivot(nsIAccessible* aRoot,
883 : nsIAccessiblePivot** aPivot)
884 : {
885 0 : NS_ENSURE_ARG_POINTER(aPivot);
886 0 : NS_ENSURE_ARG(aRoot);
887 0 : *aPivot = nsnull;
888 :
889 0 : nsRefPtr<nsAccessible> accessibleRoot(do_QueryObject(aRoot));
890 0 : NS_ENSURE_TRUE(accessibleRoot, NS_ERROR_INVALID_ARG);
891 :
892 0 : nsAccessiblePivot* pivot = new nsAccessiblePivot(accessibleRoot);
893 0 : NS_ADDREF(*aPivot = pivot);
894 :
895 0 : return NS_OK;
896 : }
897 :
898 : ////////////////////////////////////////////////////////////////////////////////
899 : // nsAccessibilityService public
900 :
901 : nsAccessible*
902 0 : nsAccessibilityService::GetAccessible(nsINode* aNode, nsIPresShell* aPresShell)
903 : {
904 0 : NS_PRECONDITION(aNode, "Getting an accessible for null node! Crash.");
905 :
906 : // XXX handle the presshell
907 0 : nsDocAccessible* document = GetDocAccessible(aNode->OwnerDoc());
908 0 : return document ? document->GetAccessible(aNode) : nsnull;
909 : }
910 :
911 0 : static bool HasRelatedContent(nsIContent *aContent)
912 : {
913 0 : nsAutoString id;
914 0 : if (!aContent || !nsCoreUtils::GetID(aContent, id) || id.IsEmpty()) {
915 0 : return false;
916 : }
917 :
918 : // If the given ID is referred by relation attribute then create an accessible
919 : // for it. Take care of HTML elements only for now.
920 0 : return aContent->IsHTML() &&
921 0 : nsAccUtils::GetDocAccessibleFor(aContent)->IsDependentID(id);
922 : }
923 :
924 : nsAccessible*
925 0 : nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
926 : nsDocAccessible* aDoc,
927 : bool* aIsSubtreeHidden)
928 : {
929 0 : if (!aDoc || !aNode || gIsShutdown)
930 0 : return nsnull;
931 :
932 0 : if (aIsSubtreeHidden)
933 0 : *aIsSubtreeHidden = false;
934 :
935 : // Check to see if we already have an accessible for this node in the cache.
936 0 : nsAccessible* cachedAccessible = aDoc->GetAccessible(aNode);
937 0 : if (cachedAccessible)
938 0 : return cachedAccessible;
939 :
940 : // No cache entry, so we must create the accessible.
941 :
942 0 : if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
943 : // If it's document node then ask accessible document loader for
944 : // document accessible, otherwise return null.
945 0 : nsCOMPtr<nsIDocument> document(do_QueryInterface(aNode));
946 0 : return GetDocAccessible(document);
947 : }
948 :
949 : // We have a content node.
950 0 : if (!aNode->IsInDoc()) {
951 0 : NS_WARNING("Creating accessible for node with no document");
952 0 : return nsnull;
953 : }
954 :
955 0 : if (aNode->OwnerDoc() != aDoc->GetDocumentNode()) {
956 0 : NS_ERROR("Creating accessible for wrong document");
957 0 : return nsnull;
958 : }
959 :
960 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
961 0 : if (!content)
962 0 : return nsnull;
963 :
964 : // Frames can be deallocated when we flush layout, or when we call into code
965 : // that can flush layout, either directly, or via DOM manipulation, or some
966 : // CSS styles like :hover. We use the weak frame checks to avoid calling
967 : // methods on a dead frame pointer.
968 0 : nsWeakFrame weakFrame = content->GetPrimaryFrame();
969 :
970 : // Check frame and its visibility. Note, hidden frame allows visible
971 : // elements in subtree.
972 0 : if (!weakFrame.GetFrame() || !weakFrame->GetStyleVisibility()->IsVisible()) {
973 0 : if (aIsSubtreeHidden && !weakFrame.GetFrame())
974 0 : *aIsSubtreeHidden = true;
975 :
976 0 : return nsnull;
977 : }
978 :
979 0 : if (weakFrame.GetFrame()->GetContent() != content) {
980 : // Not the main content for this frame. This happens because <area>
981 : // elements return the image frame as their primary frame. The main content
982 : // for the image frame is the image content. If the frame is not an image
983 : // frame or the node is not an area element then null is returned.
984 : // This setup will change when bug 135040 is fixed. Make sure we don't
985 : // create area accessible here. Hopefully assertion below will handle that.
986 :
987 : #ifdef DEBUG
988 0 : nsImageFrame* imageFrame = do_QueryFrame(weakFrame.GetFrame());
989 0 : NS_ASSERTION(imageFrame && content->IsHTML() && content->Tag() == nsGkAtoms::area,
990 : "Unknown case of not main content for the frame!");
991 : #endif
992 0 : return nsnull;
993 : }
994 :
995 : #ifdef DEBUG
996 0 : nsImageFrame* imageFrame = do_QueryFrame(weakFrame.GetFrame());
997 0 : NS_ASSERTION(!imageFrame || !content->IsHTML() || content->Tag() != nsGkAtoms::area,
998 : "Image map manages the area accessible creation!");
999 : #endif
1000 :
1001 : nsDocAccessible* docAcc =
1002 0 : GetAccService()->GetDocAccessible(aNode->OwnerDoc());
1003 0 : if (!docAcc) {
1004 0 : NS_NOTREACHED("Node has no host document accessible!");
1005 0 : return nsnull;
1006 : }
1007 :
1008 : // Attempt to create an accessible based on what we know.
1009 0 : nsRefPtr<nsAccessible> newAcc;
1010 :
1011 : // Create accessible for visible text frames.
1012 0 : if (content->IsNodeOfType(nsINode::eTEXT)) {
1013 0 : nsAutoString text;
1014 0 : weakFrame->GetRenderedText(&text, nsnull, nsnull, 0, PR_UINT32_MAX);
1015 0 : if (text.IsEmpty()) {
1016 0 : if (aIsSubtreeHidden)
1017 0 : *aIsSubtreeHidden = true;
1018 :
1019 0 : return nsnull;
1020 : }
1021 :
1022 0 : newAcc = weakFrame->CreateAccessible();
1023 0 : if (docAcc->BindToDocument(newAcc, nsnull)) {
1024 0 : newAcc->AsTextLeaf()->SetText(text);
1025 0 : return newAcc;
1026 : }
1027 :
1028 0 : return nsnull;
1029 : }
1030 :
1031 0 : bool isHTML = content->IsHTML();
1032 0 : if (isHTML && content->Tag() == nsGkAtoms::map) {
1033 : // Create hyper text accessible for HTML map if it is used to group links
1034 : // (see http://www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass). If the HTML
1035 : // map rect is empty then it is used for links grouping. Otherwise it should
1036 : // be used in conjunction with HTML image element and in this case we don't
1037 : // create any accessible for it and don't walk into it. The accessibles for
1038 : // HTML area (nsHTMLAreaAccessible) the map contains are attached as
1039 : // children of the appropriate accessible for HTML image
1040 : // (nsHTMLImageAccessible).
1041 0 : if (nsLayoutUtils::GetAllInFlowRectsUnion(weakFrame,
1042 0 : weakFrame->GetParent()).IsEmpty()) {
1043 0 : if (aIsSubtreeHidden)
1044 0 : *aIsSubtreeHidden = true;
1045 :
1046 0 : return nsnull;
1047 : }
1048 :
1049 0 : newAcc = new nsHyperTextAccessibleWrap(content, docAcc);
1050 0 : if (docAcc->BindToDocument(newAcc, nsAccUtils::GetRoleMapEntry(aNode)))
1051 0 : return newAcc;
1052 0 : return nsnull;
1053 : }
1054 :
1055 0 : nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(aNode);
1056 0 : if (roleMapEntry && !nsCRT::strcmp(roleMapEntry->roleString, "presentation")) {
1057 : // Ignore presentation role if element is focusable (focus event shouldn't
1058 : // be ever lost and should be sensible).
1059 0 : if (content->IsFocusable())
1060 0 : roleMapEntry = nsnull;
1061 : else
1062 0 : return nsnull;
1063 : }
1064 :
1065 0 : if (weakFrame.IsAlive() && !newAcc && isHTML) { // HTML accessibles
1066 0 : bool tryTagNameOrFrame = true;
1067 :
1068 0 : nsIAtom *frameType = weakFrame.GetFrame()->GetType();
1069 :
1070 : bool partOfHTMLTable =
1071 : frameType == nsGkAtoms::tableCaptionFrame ||
1072 : frameType == nsGkAtoms::tableCellFrame ||
1073 : frameType == nsGkAtoms::tableRowGroupFrame ||
1074 0 : frameType == nsGkAtoms::tableRowFrame;
1075 :
1076 0 : if (partOfHTMLTable) {
1077 : // Table-related frames don't get table-related roles
1078 : // unless they are inside a table, but they may still get generic
1079 : // accessibles
1080 0 : nsIContent *tableContent = content;
1081 0 : while ((tableContent = tableContent->GetParent()) != nsnull) {
1082 0 : nsIFrame *tableFrame = tableContent->GetPrimaryFrame();
1083 0 : if (!tableFrame)
1084 0 : continue;
1085 :
1086 0 : if (tableFrame->GetType() == nsGkAtoms::tableOuterFrame) {
1087 0 : nsAccessible* tableAccessible = aDoc->GetAccessible(tableContent);
1088 :
1089 0 : if (tableAccessible) {
1090 0 : if (!roleMapEntry) {
1091 0 : roles::Role role = tableAccessible->Role();
1092 : // No ARIA role and not in table: override role. For example,
1093 : // <table role="label"><td>content</td></table>
1094 0 : if (role != roles::TABLE && role != roles::TREE_TABLE)
1095 0 : roleMapEntry = &nsARIAMap::gEmptyRoleMap;
1096 : }
1097 :
1098 0 : break;
1099 : }
1100 :
1101 : #ifdef DEBUG
1102 : nsRoleMapEntry *tableRoleMapEntry =
1103 0 : nsAccUtils::GetRoleMapEntry(tableContent);
1104 0 : NS_ASSERTION(tableRoleMapEntry &&
1105 : !nsCRT::strcmp(tableRoleMapEntry->roleString, "presentation"),
1106 : "No accessible for parent table and it didn't have role of presentation");
1107 : #endif
1108 :
1109 0 : if (!roleMapEntry && !content->IsFocusable()) {
1110 : // Table-related descendants of presentation table are also
1111 : // presentation if they aren't focusable and have not explicit ARIA
1112 : // role (don't create accessibles for them unless they need to fire
1113 : // focus events).
1114 0 : return nsnull;
1115 : }
1116 :
1117 : // otherwise create ARIA based accessible.
1118 0 : tryTagNameOrFrame = false;
1119 0 : break;
1120 : }
1121 :
1122 0 : if (tableContent->Tag() == nsGkAtoms::table) {
1123 : // Stop before we are fooled by any additional table ancestors
1124 : // This table cell frameis part of a separate ancestor table.
1125 0 : tryTagNameOrFrame = false;
1126 0 : break;
1127 : }
1128 : }
1129 :
1130 0 : if (!tableContent)
1131 0 : tryTagNameOrFrame = false;
1132 : }
1133 :
1134 0 : if (roleMapEntry) {
1135 : // Create ARIA grid/treegrid accessibles if node is not of a child or
1136 : // valid child of HTML table and is not a HTML table.
1137 0 : if ((!partOfHTMLTable || !tryTagNameOrFrame) &&
1138 : frameType != nsGkAtoms::tableOuterFrame) {
1139 :
1140 0 : if (roleMapEntry->role == roles::TABLE ||
1141 : roleMapEntry->role == roles::TREE_TABLE) {
1142 0 : newAcc = new nsARIAGridAccessibleWrap(content, docAcc);
1143 :
1144 0 : } else if (roleMapEntry->role == roles::GRID_CELL ||
1145 : roleMapEntry->role == roles::ROWHEADER ||
1146 : roleMapEntry->role == roles::COLUMNHEADER) {
1147 0 : newAcc = new nsARIAGridCellAccessibleWrap(content, docAcc);
1148 : }
1149 : }
1150 : }
1151 :
1152 0 : if (!newAcc && tryTagNameOrFrame) {
1153 : // Prefer to use markup (mostly tag name, perhaps attributes) to
1154 : // decide if and what kind of accessible to create.
1155 : // The method creates accessibles for table related content too therefore
1156 : // we do not call it if accessibles for table related content are
1157 : // prevented above.
1158 : newAcc = CreateHTMLAccessibleByMarkup(weakFrame.GetFrame(), content,
1159 0 : docAcc);
1160 :
1161 0 : if (!newAcc) {
1162 : // Do not create accessible object subtrees for non-rendered table
1163 : // captions. This could not be done in
1164 : // nsTableCaptionFrame::GetAccessible() because the descendants of
1165 : // the table caption would still be created. By setting
1166 : // *aIsSubtreeHidden = true we ensure that no descendant accessibles
1167 : // are created.
1168 0 : nsIFrame* f = weakFrame.GetFrame();
1169 0 : if (!f) {
1170 0 : f = aDoc->PresShell()->GetRealPrimaryFrameFor(content);
1171 : }
1172 0 : if (f->GetType() == nsGkAtoms::tableCaptionFrame &&
1173 0 : f->GetRect().IsEmpty()) {
1174 : // XXX This is not the ideal place for this code, but right now there
1175 : // is no better place:
1176 0 : if (aIsSubtreeHidden)
1177 0 : *aIsSubtreeHidden = true;
1178 :
1179 0 : return nsnull;
1180 : }
1181 :
1182 : // Try using frame to do it.
1183 0 : newAcc = f->CreateAccessible();
1184 : }
1185 : }
1186 : }
1187 :
1188 0 : if (!newAcc) {
1189 : // Elements may implement nsIAccessibleProvider via XBL. This allows them to
1190 : // say what kind of accessible to create.
1191 0 : newAcc = CreateAccessibleByType(content, docAcc);
1192 : }
1193 :
1194 0 : if (!newAcc) {
1195 : // Create generic accessibles for SVG and MathML nodes.
1196 0 : if (content->IsSVG(nsGkAtoms::svg)) {
1197 : newAcc = new nsEnumRoleAccessible(content, docAcc,
1198 0 : roles::DIAGRAM);
1199 : }
1200 0 : else if (content->IsMathML(nsGkAtoms::math)) {
1201 : newAcc = new nsEnumRoleAccessible(content, docAcc,
1202 0 : roles::EQUATION);
1203 : }
1204 : }
1205 :
1206 0 : if (!newAcc) {
1207 : newAcc = CreateAccessibleForDeckChild(weakFrame.GetFrame(), content,
1208 0 : docAcc);
1209 : }
1210 :
1211 : // If no accessible, see if we need to create a generic accessible because
1212 : // of some property that makes this object interesting
1213 : // We don't do this for <body>, <html>, <window>, <dialog> etc. which
1214 : // correspond to the doc accessible and will be created in any case
1215 0 : if (!newAcc && content->Tag() != nsGkAtoms::body && content->GetParent() &&
1216 0 : ((weakFrame.GetFrame() && weakFrame.GetFrame()->IsFocusable()) ||
1217 0 : (isHTML && nsCoreUtils::HasClickListener(content)) ||
1218 0 : HasUniversalAriaProperty(content) || roleMapEntry ||
1219 0 : HasRelatedContent(content) || nsCoreUtils::IsXLink(content))) {
1220 : // This content is focusable or has an interesting dynamic content accessibility property.
1221 : // If it's interesting we need it in the accessibility hierarchy so that events or
1222 : // other accessibles can point to it, or so that it can hold a state, etc.
1223 0 : if (isHTML) {
1224 : // Interesting HTML container which may have selectable text and/or embedded objects
1225 0 : newAcc = new nsHyperTextAccessibleWrap(content, docAcc);
1226 : }
1227 : else { // XUL, SVG, MathML etc.
1228 : // Interesting generic non-HTML container
1229 0 : newAcc = new nsAccessibleWrap(content, docAcc);
1230 : }
1231 : }
1232 :
1233 0 : return docAcc->BindToDocument(newAcc, roleMapEntry) ? newAcc : nsnull;
1234 : }
1235 :
1236 : ////////////////////////////////////////////////////////////////////////////////
1237 : // nsAccessibilityService private
1238 :
1239 : bool
1240 0 : nsAccessibilityService::Init()
1241 : {
1242 : // Initialize accessible document manager.
1243 0 : if (!nsAccDocManager::Init())
1244 0 : return false;
1245 :
1246 : // Add observers.
1247 : nsCOMPtr<nsIObserverService> observerService =
1248 0 : mozilla::services::GetObserverService();
1249 0 : if (!observerService)
1250 0 : return false;
1251 :
1252 0 : observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
1253 :
1254 : // Initialize accessibility.
1255 0 : nsAccessNodeWrap::InitAccessibility();
1256 :
1257 0 : gIsShutdown = false;
1258 0 : return true;
1259 : }
1260 :
1261 : void
1262 0 : nsAccessibilityService::Shutdown()
1263 : {
1264 : // Remove observers.
1265 : nsCOMPtr<nsIObserverService> observerService =
1266 0 : mozilla::services::GetObserverService();
1267 0 : if (observerService)
1268 0 : observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
1269 :
1270 : // Stop accessible document loader.
1271 0 : nsAccDocManager::Shutdown();
1272 :
1273 : // Application is going to be closed, shutdown accessibility and mark
1274 : // accessibility service as shutdown to prevent calls of its methods.
1275 : // Don't null accessibility service static member at this point to be safe
1276 : // if someone will try to operate with it.
1277 :
1278 0 : NS_ASSERTION(!gIsShutdown, "Accessibility was shutdown already");
1279 :
1280 0 : gIsShutdown = true;
1281 :
1282 0 : nsAccessNodeWrap::ShutdownAccessibility();
1283 0 : }
1284 :
1285 : bool
1286 0 : nsAccessibilityService::HasUniversalAriaProperty(nsIContent *aContent)
1287 : {
1288 : // ARIA attributes that take token values (NMTOKEN, bool) are special cased
1289 : // because of special value "undefined" (see HasDefinedARIAToken).
1290 0 : return nsAccUtils::HasDefinedARIAToken(aContent, nsGkAtoms::aria_atomic) ||
1291 0 : nsAccUtils::HasDefinedARIAToken(aContent, nsGkAtoms::aria_busy) ||
1292 0 : aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_controls) ||
1293 0 : aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_describedby) ||
1294 0 : aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_disabled) ||
1295 0 : nsAccUtils::HasDefinedARIAToken(aContent, nsGkAtoms::aria_dropeffect) ||
1296 0 : aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_flowto) ||
1297 0 : nsAccUtils::HasDefinedARIAToken(aContent, nsGkAtoms::aria_grabbed) ||
1298 0 : nsAccUtils::HasDefinedARIAToken(aContent, nsGkAtoms::aria_haspopup) ||
1299 0 : aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_hidden) ||
1300 0 : nsAccUtils::HasDefinedARIAToken(aContent, nsGkAtoms::aria_invalid) ||
1301 0 : aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_label) ||
1302 0 : aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_labelledby) ||
1303 0 : nsAccUtils::HasDefinedARIAToken(aContent, nsGkAtoms::aria_live) ||
1304 0 : nsAccUtils::HasDefinedARIAToken(aContent, nsGkAtoms::aria_owns) ||
1305 0 : nsAccUtils::HasDefinedARIAToken(aContent, nsGkAtoms::aria_relevant);
1306 : }
1307 :
1308 : already_AddRefed<nsAccessible>
1309 0 : nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
1310 : nsDocAccessible* aDoc)
1311 : {
1312 0 : nsCOMPtr<nsIAccessibleProvider> accessibleProvider(do_QueryInterface(aContent));
1313 0 : if (!accessibleProvider)
1314 0 : return nsnull;
1315 :
1316 : PRInt32 type;
1317 0 : nsresult rv = accessibleProvider->GetAccessibleType(&type);
1318 0 : if (NS_FAILED(rv))
1319 0 : return nsnull;
1320 :
1321 0 : if (type == nsIAccessibleProvider::OuterDoc) {
1322 0 : nsAccessible* accessible = new nsOuterDocAccessible(aContent, aDoc);
1323 0 : NS_IF_ADDREF(accessible);
1324 0 : return accessible;
1325 : }
1326 :
1327 0 : nsAccessible* accessible = nsnull;
1328 0 : switch (type)
1329 : {
1330 : #ifdef MOZ_XUL
1331 : case nsIAccessibleProvider::NoAccessible:
1332 0 : return nsnull;
1333 :
1334 : // XUL controls
1335 : case nsIAccessibleProvider::XULAlert:
1336 0 : accessible = new nsXULAlertAccessible(aContent, aDoc);
1337 0 : break;
1338 :
1339 : case nsIAccessibleProvider::XULButton:
1340 0 : accessible = new nsXULButtonAccessible(aContent, aDoc);
1341 0 : break;
1342 :
1343 : case nsIAccessibleProvider::XULCheckbox:
1344 0 : accessible = new nsXULCheckboxAccessible(aContent, aDoc);
1345 0 : break;
1346 :
1347 : case nsIAccessibleProvider::XULColorPicker:
1348 0 : accessible = new nsXULColorPickerAccessible(aContent, aDoc);
1349 0 : break;
1350 :
1351 : case nsIAccessibleProvider::XULColorPickerTile:
1352 0 : accessible = new nsXULColorPickerTileAccessible(aContent, aDoc);
1353 0 : break;
1354 :
1355 : case nsIAccessibleProvider::XULCombobox:
1356 0 : accessible = new nsXULComboboxAccessible(aContent, aDoc);
1357 0 : break;
1358 :
1359 : case nsIAccessibleProvider::XULDropmarker:
1360 0 : accessible = new nsXULDropmarkerAccessible(aContent, aDoc);
1361 0 : break;
1362 :
1363 : case nsIAccessibleProvider::XULGroupbox:
1364 0 : accessible = new nsXULGroupboxAccessible(aContent, aDoc);
1365 0 : break;
1366 :
1367 : case nsIAccessibleProvider::XULImage:
1368 : {
1369 : // Don't include nameless images in accessible tree.
1370 0 : if (!aContent->HasAttr(kNameSpaceID_None,
1371 0 : nsGkAtoms::tooltiptext))
1372 0 : return nsnull;
1373 :
1374 0 : accessible = new nsHTMLImageAccessibleWrap(aContent, aDoc);
1375 0 : break;
1376 :
1377 : }
1378 : case nsIAccessibleProvider::XULLink:
1379 0 : accessible = new nsXULLinkAccessible(aContent, aDoc);
1380 0 : break;
1381 :
1382 : case nsIAccessibleProvider::XULListbox:
1383 0 : accessible = new nsXULListboxAccessibleWrap(aContent, aDoc);
1384 0 : break;
1385 :
1386 : case nsIAccessibleProvider::XULListCell:
1387 0 : accessible = new nsXULListCellAccessibleWrap(aContent, aDoc);
1388 0 : break;
1389 :
1390 : case nsIAccessibleProvider::XULListHead:
1391 0 : accessible = new nsXULColumnsAccessible(aContent, aDoc);
1392 0 : break;
1393 :
1394 : case nsIAccessibleProvider::XULListHeader:
1395 0 : accessible = new nsXULColumnItemAccessible(aContent, aDoc);
1396 0 : break;
1397 :
1398 : case nsIAccessibleProvider::XULListitem:
1399 0 : accessible = new nsXULListitemAccessible(aContent, aDoc);
1400 0 : break;
1401 :
1402 : case nsIAccessibleProvider::XULMenubar:
1403 0 : accessible = new nsXULMenubarAccessible(aContent, aDoc);
1404 0 : break;
1405 :
1406 : case nsIAccessibleProvider::XULMenuitem:
1407 0 : accessible = new nsXULMenuitemAccessibleWrap(aContent, aDoc);
1408 0 : break;
1409 :
1410 : case nsIAccessibleProvider::XULMenupopup:
1411 : {
1412 : #ifdef MOZ_ACCESSIBILITY_ATK
1413 : // ATK considers this node to be redundant when within menubars, and it makes menu
1414 : // navigation with assistive technologies more difficult
1415 : // XXX In the future we will should this for consistency across the nsIAccessible
1416 : // implementations on each platform for a consistent scripting environment, but
1417 : // then strip out redundant accessibles in the nsAccessibleWrap class for each platform.
1418 0 : nsIContent *parent = aContent->GetParent();
1419 0 : if (parent && parent->NodeInfo()->Equals(nsGkAtoms::menu,
1420 0 : kNameSpaceID_XUL))
1421 0 : return nsnull;
1422 : #endif
1423 0 : accessible = new nsXULMenupopupAccessible(aContent, aDoc);
1424 0 : break;
1425 :
1426 : }
1427 : case nsIAccessibleProvider::XULMenuSeparator:
1428 0 : accessible = new nsXULMenuSeparatorAccessible(aContent, aDoc);
1429 0 : break;
1430 :
1431 : case nsIAccessibleProvider::XULPane:
1432 : accessible = new nsEnumRoleAccessible(aContent, aDoc,
1433 0 : roles::PANE);
1434 0 : break;
1435 :
1436 : case nsIAccessibleProvider::XULProgressMeter:
1437 0 : accessible = new XULProgressMeterAccessible(aContent, aDoc);
1438 0 : break;
1439 :
1440 : case nsIAccessibleProvider::XULStatusBar:
1441 0 : accessible = new nsXULStatusBarAccessible(aContent, aDoc);
1442 0 : break;
1443 :
1444 : case nsIAccessibleProvider::XULScale:
1445 0 : accessible = new nsXULSliderAccessible(aContent, aDoc);
1446 0 : break;
1447 :
1448 : case nsIAccessibleProvider::XULRadioButton:
1449 0 : accessible = new nsXULRadioButtonAccessible(aContent, aDoc);
1450 0 : break;
1451 :
1452 : case nsIAccessibleProvider::XULRadioGroup:
1453 0 : accessible = new nsXULRadioGroupAccessible(aContent, aDoc);
1454 0 : break;
1455 :
1456 : case nsIAccessibleProvider::XULTab:
1457 0 : accessible = new nsXULTabAccessible(aContent, aDoc);
1458 0 : break;
1459 :
1460 : case nsIAccessibleProvider::XULTabs:
1461 0 : accessible = new nsXULTabsAccessible(aContent, aDoc);
1462 0 : break;
1463 :
1464 : case nsIAccessibleProvider::XULTabpanels:
1465 0 : accessible = new nsXULTabpanelsAccessible(aContent, aDoc);
1466 0 : break;
1467 :
1468 : case nsIAccessibleProvider::XULText:
1469 0 : accessible = new nsXULTextAccessible(aContent, aDoc);
1470 0 : break;
1471 :
1472 : case nsIAccessibleProvider::XULTextBox:
1473 0 : accessible = new nsXULTextFieldAccessible(aContent, aDoc);
1474 0 : break;
1475 :
1476 : case nsIAccessibleProvider::XULThumb:
1477 0 : accessible = new nsXULThumbAccessible(aContent, aDoc);
1478 0 : break;
1479 :
1480 : case nsIAccessibleProvider::XULTree:
1481 0 : return CreateAccessibleForXULTree(aContent, aDoc);
1482 :
1483 : case nsIAccessibleProvider::XULTreeColumns:
1484 0 : accessible = new nsXULTreeColumnsAccessible(aContent, aDoc);
1485 0 : break;
1486 :
1487 : case nsIAccessibleProvider::XULTreeColumnItem:
1488 0 : accessible = new nsXULColumnItemAccessible(aContent, aDoc);
1489 0 : break;
1490 :
1491 : case nsIAccessibleProvider::XULToolbar:
1492 0 : accessible = new nsXULToolbarAccessible(aContent, aDoc);
1493 0 : break;
1494 :
1495 : case nsIAccessibleProvider::XULToolbarSeparator:
1496 0 : accessible = new nsXULToolbarSeparatorAccessible(aContent, aDoc);
1497 0 : break;
1498 :
1499 : case nsIAccessibleProvider::XULTooltip:
1500 0 : accessible = new nsXULTooltipAccessible(aContent, aDoc);
1501 0 : break;
1502 :
1503 : case nsIAccessibleProvider::XULToolbarButton:
1504 0 : accessible = new nsXULToolbarButtonAccessible(aContent, aDoc);
1505 0 : break;
1506 :
1507 : #endif // MOZ_XUL
1508 :
1509 : // XForms elements
1510 : case nsIAccessibleProvider::XFormsContainer:
1511 0 : accessible = new nsXFormsContainerAccessible(aContent, aDoc);
1512 0 : break;
1513 :
1514 : case nsIAccessibleProvider::XFormsLabel:
1515 0 : accessible = new nsXFormsLabelAccessible(aContent, aDoc);
1516 0 : break;
1517 :
1518 : case nsIAccessibleProvider::XFormsOutput:
1519 0 : accessible = new nsXFormsOutputAccessible(aContent, aDoc);
1520 0 : break;
1521 :
1522 : case nsIAccessibleProvider::XFormsTrigger:
1523 0 : accessible = new nsXFormsTriggerAccessible(aContent, aDoc);
1524 0 : break;
1525 :
1526 : case nsIAccessibleProvider::XFormsInput:
1527 0 : accessible = new nsXFormsInputAccessible(aContent, aDoc);
1528 0 : break;
1529 :
1530 : case nsIAccessibleProvider::XFormsInputBoolean:
1531 0 : accessible = new nsXFormsInputBooleanAccessible(aContent, aDoc);
1532 0 : break;
1533 :
1534 : case nsIAccessibleProvider::XFormsInputDate:
1535 0 : accessible = new nsXFormsInputDateAccessible(aContent, aDoc);
1536 0 : break;
1537 :
1538 : case nsIAccessibleProvider::XFormsSecret:
1539 0 : accessible = new nsXFormsSecretAccessible(aContent, aDoc);
1540 0 : break;
1541 :
1542 : case nsIAccessibleProvider::XFormsSliderRange:
1543 0 : accessible = new nsXFormsRangeAccessible(aContent, aDoc);
1544 0 : break;
1545 :
1546 : case nsIAccessibleProvider::XFormsSelect:
1547 0 : accessible = new nsXFormsSelectAccessible(aContent, aDoc);
1548 0 : break;
1549 :
1550 : case nsIAccessibleProvider::XFormsChoices:
1551 0 : accessible = new nsXFormsChoicesAccessible(aContent, aDoc);
1552 0 : break;
1553 :
1554 : case nsIAccessibleProvider::XFormsSelectFull:
1555 0 : accessible = new nsXFormsSelectFullAccessible(aContent, aDoc);
1556 0 : break;
1557 :
1558 : case nsIAccessibleProvider::XFormsItemCheckgroup:
1559 0 : accessible = new nsXFormsItemCheckgroupAccessible(aContent, aDoc);
1560 0 : break;
1561 :
1562 : case nsIAccessibleProvider::XFormsItemRadiogroup:
1563 0 : accessible = new nsXFormsItemRadiogroupAccessible(aContent, aDoc);
1564 0 : break;
1565 :
1566 : case nsIAccessibleProvider::XFormsSelectCombobox:
1567 0 : accessible = new nsXFormsSelectComboboxAccessible(aContent, aDoc);
1568 0 : break;
1569 :
1570 : case nsIAccessibleProvider::XFormsItemCombobox:
1571 0 : accessible = new nsXFormsItemComboboxAccessible(aContent, aDoc);
1572 0 : break;
1573 :
1574 : case nsIAccessibleProvider::XFormsDropmarkerWidget:
1575 0 : accessible = new nsXFormsDropmarkerWidgetAccessible(aContent, aDoc);
1576 0 : break;
1577 :
1578 : case nsIAccessibleProvider::XFormsCalendarWidget:
1579 0 : accessible = new nsXFormsCalendarWidgetAccessible(aContent, aDoc);
1580 0 : break;
1581 :
1582 : case nsIAccessibleProvider::XFormsComboboxPopupWidget:
1583 0 : accessible = new nsXFormsComboboxPopupWidgetAccessible(aContent, aDoc);
1584 0 : break;
1585 :
1586 : default:
1587 0 : return nsnull;
1588 : }
1589 :
1590 0 : NS_IF_ADDREF(accessible);
1591 0 : return accessible;
1592 : }
1593 :
1594 : already_AddRefed<nsAccessible>
1595 0 : nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
1596 : nsIContent* aContent,
1597 : nsDocAccessible* aDoc)
1598 : {
1599 : // This method assumes we're in an HTML namespace.
1600 0 : nsIAtom* tag = aContent->Tag();
1601 0 : if (tag == nsGkAtoms::figcaption) {
1602 : nsAccessible* accessible =
1603 0 : new nsHTMLFigcaptionAccessible(aContent, aDoc);
1604 0 : NS_IF_ADDREF(accessible);
1605 0 : return accessible;
1606 : }
1607 :
1608 0 : if (tag == nsGkAtoms::figure) {
1609 0 : nsAccessible* accessible = new nsHTMLFigureAccessible(aContent, aDoc);
1610 0 : NS_IF_ADDREF(accessible);
1611 0 : return accessible;
1612 : }
1613 :
1614 0 : if (tag == nsGkAtoms::legend) {
1615 0 : nsAccessible* accessible = new nsHTMLLegendAccessible(aContent, aDoc);
1616 0 : NS_IF_ADDREF(accessible);
1617 0 : return accessible;
1618 : }
1619 :
1620 0 : if (tag == nsGkAtoms::option) {
1621 0 : nsAccessible* accessible = new nsHTMLSelectOptionAccessible(aContent, aDoc);
1622 0 : NS_IF_ADDREF(accessible);
1623 0 : return accessible;
1624 : }
1625 :
1626 0 : if (tag == nsGkAtoms::optgroup) {
1627 : nsAccessible* accessible = new nsHTMLSelectOptGroupAccessible(aContent,
1628 0 : aDoc);
1629 0 : NS_IF_ADDREF(accessible);
1630 0 : return accessible;
1631 : }
1632 :
1633 0 : if (tag == nsGkAtoms::ul || tag == nsGkAtoms::ol ||
1634 : tag == nsGkAtoms::dl) {
1635 0 : nsAccessible* accessible = new nsHTMLListAccessible(aContent, aDoc);
1636 0 : NS_IF_ADDREF(accessible);
1637 0 : return accessible;
1638 : }
1639 :
1640 0 : if (tag == nsGkAtoms::a) {
1641 : // Only some roles truly enjoy life as nsHTMLLinkAccessibles, for details
1642 : // see closed bug 494807.
1643 0 : nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(aContent);
1644 0 : if (roleMapEntry && roleMapEntry->role != roles::NOTHING &&
1645 : roleMapEntry->role != roles::LINK) {
1646 0 : nsAccessible* accessible = new nsHyperTextAccessibleWrap(aContent, aDoc);
1647 0 : NS_IF_ADDREF(accessible);
1648 0 : return accessible;
1649 : }
1650 :
1651 0 : nsAccessible* accessible = new nsHTMLLinkAccessible(aContent, aDoc);
1652 0 : NS_IF_ADDREF(accessible);
1653 0 : return accessible;
1654 : }
1655 :
1656 0 : if (tag == nsGkAtoms::dt ||
1657 : (tag == nsGkAtoms::li &&
1658 0 : aFrame->GetType() != nsGkAtoms::blockFrame)) {
1659 : // Normally for li, it is created by the list item frame (in nsBlockFrame)
1660 : // which knows about the bullet frame; however, in this case the list item
1661 : // must have been styled using display: foo
1662 0 : nsAccessible* accessible = new nsHTMLLIAccessible(aContent, aDoc);
1663 0 : NS_IF_ADDREF(accessible);
1664 0 : return accessible;
1665 : }
1666 :
1667 0 : if (tag == nsGkAtoms::abbr ||
1668 : tag == nsGkAtoms::acronym ||
1669 : tag == nsGkAtoms::blockquote ||
1670 : tag == nsGkAtoms::dd ||
1671 : tag == nsGkAtoms::form ||
1672 : tag == nsGkAtoms::h1 ||
1673 : tag == nsGkAtoms::h2 ||
1674 : tag == nsGkAtoms::h3 ||
1675 : tag == nsGkAtoms::h4 ||
1676 : tag == nsGkAtoms::h5 ||
1677 : tag == nsGkAtoms::h6 ||
1678 : tag == nsGkAtoms::q) {
1679 0 : nsAccessible* accessible = new nsHyperTextAccessibleWrap(aContent, aDoc);
1680 0 : NS_IF_ADDREF(accessible);
1681 0 : return accessible;
1682 : }
1683 :
1684 0 : if (tag == nsGkAtoms::tr) {
1685 : nsAccessible* accessible = new nsEnumRoleAccessible(aContent, aDoc,
1686 0 : roles::ROW);
1687 0 : NS_IF_ADDREF(accessible);
1688 0 : return accessible;
1689 : }
1690 :
1691 0 : if (nsCoreUtils::IsHTMLTableHeader(aContent)) {
1692 : nsAccessible* accessible = new nsHTMLTableHeaderCellAccessibleWrap(aContent,
1693 0 : aDoc);
1694 0 : NS_IF_ADDREF(accessible);
1695 0 : return accessible;
1696 : }
1697 :
1698 0 : if (tag == nsGkAtoms::output) {
1699 0 : nsAccessible* accessible = new nsHTMLOutputAccessible(aContent, aDoc);
1700 0 : NS_IF_ADDREF(accessible);
1701 0 : return accessible;
1702 : }
1703 :
1704 0 : if (tag == nsGkAtoms::progress) {
1705 : nsAccessible* accessible =
1706 0 : new HTMLProgressMeterAccessible(aContent, aDoc);
1707 0 : NS_IF_ADDREF(accessible);
1708 0 : return accessible;
1709 : }
1710 :
1711 0 : return nsnull;
1712 : }
1713 :
1714 : ////////////////////////////////////////////////////////////////////////////////
1715 : // nsIAccessibilityService (DON'T put methods here)
1716 :
1717 : nsAccessible*
1718 0 : nsAccessibilityService::AddNativeRootAccessible(void* aAtkAccessible)
1719 : {
1720 : #ifdef MOZ_ACCESSIBILITY_ATK
1721 : nsApplicationAccessible* applicationAcc =
1722 0 : nsAccessNode::GetApplicationAccessible();
1723 0 : if (!applicationAcc)
1724 0 : return nsnull;
1725 :
1726 : nsRefPtr<nsNativeRootAccessibleWrap> nativeRootAcc =
1727 0 : new nsNativeRootAccessibleWrap((AtkObject*)aAtkAccessible);
1728 0 : if (!nativeRootAcc)
1729 0 : return nsnull;
1730 :
1731 0 : if (applicationAcc->AppendChild(nativeRootAcc))
1732 0 : return nativeRootAcc;
1733 : #endif
1734 :
1735 0 : return nsnull;
1736 : }
1737 :
1738 : void
1739 0 : nsAccessibilityService::RemoveNativeRootAccessible(nsAccessible* aAccessible)
1740 : {
1741 : #ifdef MOZ_ACCESSIBILITY_ATK
1742 : nsApplicationAccessible* applicationAcc =
1743 0 : nsAccessNode::GetApplicationAccessible();
1744 :
1745 0 : if (applicationAcc)
1746 0 : applicationAcc->RemoveChild(aAccessible);
1747 : #endif
1748 0 : }
1749 :
1750 : ////////////////////////////////////////////////////////////////////////////////
1751 : // NS_GetAccessibilityService
1752 : ////////////////////////////////////////////////////////////////////////////////
1753 :
1754 : /**
1755 : * Return accessibility service; creating one if necessary.
1756 : */
1757 : nsresult
1758 0 : NS_GetAccessibilityService(nsIAccessibilityService** aResult)
1759 : {
1760 0 : NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
1761 0 : *aResult = nsnull;
1762 :
1763 0 : if (nsAccessibilityService::gAccessibilityService) {
1764 0 : NS_ADDREF(*aResult = nsAccessibilityService::gAccessibilityService);
1765 0 : return NS_OK;
1766 : }
1767 :
1768 0 : nsRefPtr<nsAccessibilityService> service = new nsAccessibilityService();
1769 0 : NS_ENSURE_TRUE(service, NS_ERROR_OUT_OF_MEMORY);
1770 :
1771 0 : if (!service->Init()) {
1772 0 : service->Shutdown();
1773 0 : return NS_ERROR_FAILURE;
1774 : }
1775 :
1776 0 : statistics::A11yInitialized();
1777 :
1778 0 : nsAccessibilityService::gAccessibilityService = service;
1779 0 : NS_ADDREF(*aResult = service);
1780 :
1781 0 : return NS_OK;
1782 : }
1783 :
1784 : ////////////////////////////////////////////////////////////////////////////////
1785 : // nsAccessibilityService private (DON'T put methods here)
1786 :
1787 : already_AddRefed<nsAccessible>
1788 0 : nsAccessibilityService::CreateAccessibleForDeckChild(nsIFrame* aFrame,
1789 : nsIContent* aContent,
1790 : nsDocAccessible* aDoc)
1791 : {
1792 0 : if (aFrame->GetType() == nsGkAtoms::boxFrame ||
1793 0 : aFrame->GetType() == nsGkAtoms::scrollFrame) {
1794 :
1795 0 : nsIFrame* parentFrame = aFrame->GetParent();
1796 0 : if (parentFrame && parentFrame->GetType() == nsGkAtoms::deckFrame) {
1797 : // If deck frame is for xul:tabpanels element then the given node has
1798 : // tabpanel accessible.
1799 0 : nsCOMPtr<nsIContent> parentContent = parentFrame->GetContent();
1800 : #ifdef MOZ_XUL
1801 0 : if (parentContent->NodeInfo()->Equals(nsGkAtoms::tabpanels,
1802 0 : kNameSpaceID_XUL)) {
1803 0 : nsAccessible* accessible = new nsXULTabpanelAccessible(aContent, aDoc);
1804 0 : NS_IF_ADDREF(accessible);
1805 0 : return accessible;
1806 : }
1807 : #endif
1808 : nsAccessible* accessible = new nsEnumRoleAccessible(aContent, aDoc,
1809 0 : roles::PROPERTYPAGE);
1810 0 : NS_IF_ADDREF(accessible);
1811 0 : return accessible;
1812 : }
1813 : }
1814 :
1815 0 : return nsnull;
1816 : }
1817 :
1818 : #ifdef MOZ_XUL
1819 : already_AddRefed<nsAccessible>
1820 0 : nsAccessibilityService::CreateAccessibleForXULTree(nsIContent* aContent,
1821 : nsDocAccessible* aDoc)
1822 : {
1823 0 : nsCOMPtr<nsITreeBoxObject> treeBoxObj = nsCoreUtils::GetTreeBoxObject(aContent);
1824 0 : if (!treeBoxObj)
1825 0 : return nsnull;
1826 :
1827 0 : nsCOMPtr<nsITreeColumns> treeColumns;
1828 0 : treeBoxObj->GetColumns(getter_AddRefs(treeColumns));
1829 0 : if (!treeColumns)
1830 0 : return nsnull;
1831 :
1832 0 : PRInt32 count = 0;
1833 0 : treeColumns->GetCount(&count);
1834 :
1835 : // Outline of list accessible.
1836 0 : if (count == 1) {
1837 0 : nsAccessible* accessible = new nsXULTreeAccessible(aContent, aDoc);
1838 0 : NS_IF_ADDREF(accessible);
1839 0 : return accessible;
1840 : }
1841 :
1842 : // Table or tree table accessible.
1843 0 : nsAccessible* accessible = new nsXULTreeGridAccessibleWrap(aContent, aDoc);
1844 0 : NS_IF_ADDREF(accessible);
1845 0 : return accessible;
1846 : }
1847 : #endif
1848 :
1849 : ////////////////////////////////////////////////////////////////////////////////
1850 : // Services
1851 : ////////////////////////////////////////////////////////////////////////////////
1852 :
1853 : mozilla::a11y::FocusManager*
1854 0 : mozilla::a11y::FocusMgr()
1855 : {
1856 0 : return nsAccessibilityService::gAccessibilityService;
1857 : }
|