Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:expandtab:shiftwidth=2:tabstop=2:
3 : */
4 : /* This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 :
8 : #include "ARIAMap.h"
9 :
10 : #include "nsAccUtils.h"
11 : #include "nsCoreUtils.h"
12 : #include "Role.h"
13 : #include "States.h"
14 :
15 : #include "nsAttrName.h"
16 : #include "nsWhitespaceTokenizer.h"
17 :
18 : #include "mozilla/BinarySearch.h"
19 : #include "mozilla/dom/Element.h"
20 :
21 : using namespace mozilla;
22 : using namespace mozilla::a11y;
23 : using namespace mozilla::a11y::aria;
24 :
25 : static const uint32_t kGenericAccType = 0;
26 :
27 : /**
28 : * This list of WAI-defined roles are currently hardcoded.
29 : * Eventually we will most likely be loading an RDF resource that contains this information
30 : * Using RDF will also allow for role extensibility. See bug 280138.
31 : *
32 : * Definition of nsRoleMapEntry contains comments explaining this table.
33 : *
34 : * When no Role enum mapping exists for an ARIA role, the role will be exposed
35 : * via the object attribute "xml-roles".
36 : */
37 :
38 : static const nsRoleMapEntry sWAIRoleMaps[] =
39 : {
40 : { // alert
41 : &nsGkAtoms::alert,
42 : roles::ALERT,
43 : kUseMapRole,
44 : eNoValue,
45 : eNoAction,
46 : eNoLiveAttr,
47 : eAlert,
48 : kNoReqStates
49 : },
50 : { // alertdialog
51 : &nsGkAtoms::alertdialog,
52 : roles::DIALOG,
53 : kUseMapRole,
54 : eNoValue,
55 : eNoAction,
56 : eNoLiveAttr,
57 : kGenericAccType,
58 : kNoReqStates
59 : },
60 : { // application
61 : &nsGkAtoms::application,
62 : roles::APPLICATION,
63 : kUseMapRole,
64 : eNoValue,
65 : eNoAction,
66 : eNoLiveAttr,
67 : eLandmark,
68 : kNoReqStates
69 : },
70 : { // article
71 : &nsGkAtoms::article,
72 : roles::ARTICLE,
73 : kUseMapRole,
74 : eNoValue,
75 : eNoAction,
76 : eNoLiveAttr,
77 : kGenericAccType,
78 : kNoReqStates,
79 : eReadonlyUntilEditable
80 : },
81 : { // banner
82 : &nsGkAtoms::banner,
83 : roles::NOTHING,
84 : kUseNativeRole,
85 : eNoValue,
86 : eNoAction,
87 : eNoLiveAttr,
88 : eLandmark,
89 : kNoReqStates
90 : },
91 : { // button
92 : &nsGkAtoms::button,
93 : roles::PUSHBUTTON,
94 : kUseMapRole,
95 : eNoValue,
96 : ePressAction,
97 : eNoLiveAttr,
98 : eButton,
99 : kNoReqStates
100 : // eARIAPressed is auto applied on any button
101 : },
102 : { // cell
103 : &nsGkAtoms::cell,
104 : roles::CELL,
105 : kUseMapRole,
106 : eNoValue,
107 : eNoAction,
108 : eNoLiveAttr,
109 : eTableCell,
110 : kNoReqStates
111 : },
112 : { // checkbox
113 : &nsGkAtoms::checkbox,
114 : roles::CHECKBUTTON,
115 : kUseMapRole,
116 : eNoValue,
117 : eCheckUncheckAction,
118 : eNoLiveAttr,
119 : kGenericAccType,
120 : kNoReqStates,
121 : eARIACheckableMixed,
122 : eARIAReadonly
123 : },
124 : { // columnheader
125 : &nsGkAtoms::columnheader,
126 : roles::COLUMNHEADER,
127 : kUseMapRole,
128 : eNoValue,
129 : eSortAction,
130 : eNoLiveAttr,
131 : eTableCell,
132 : kNoReqStates,
133 : eARIASelectableIfDefined,
134 : eARIAReadonlyOrEditableIfDefined
135 : },
136 : { // combobox, which consists of text input and popup
137 : &nsGkAtoms::combobox,
138 : roles::EDITCOMBOBOX,
139 : kUseMapRole,
140 : eNoValue,
141 : eOpenCloseAction,
142 : eNoLiveAttr,
143 : eCombobox,
144 : states::COLLAPSED | states::HASPOPUP,
145 : eARIAAutoComplete,
146 : eARIAReadonly,
147 : eARIAOrientation
148 : },
149 : { // complementary
150 : &nsGkAtoms::complementary,
151 : roles::NOTHING,
152 : kUseNativeRole,
153 : eNoValue,
154 : eNoAction,
155 : eNoLiveAttr,
156 : eLandmark,
157 : kNoReqStates
158 : },
159 : { // contentinfo
160 : &nsGkAtoms::contentinfo,
161 : roles::NOTHING,
162 : kUseNativeRole,
163 : eNoValue,
164 : eNoAction,
165 : eNoLiveAttr,
166 : eLandmark,
167 : kNoReqStates
168 : },
169 : { // dialog
170 : &nsGkAtoms::dialog,
171 : roles::DIALOG,
172 : kUseMapRole,
173 : eNoValue,
174 : eNoAction,
175 : eNoLiveAttr,
176 : kGenericAccType,
177 : kNoReqStates
178 : },
179 : { // directory
180 : &nsGkAtoms::directory,
181 : roles::LIST,
182 : kUseMapRole,
183 : eNoValue,
184 : eNoAction,
185 : eNoLiveAttr,
186 : eList,
187 : states::READONLY
188 : },
189 : { // doc-abstract
190 : &nsGkAtoms::docAbstract,
191 : roles::SECTION,
192 : kUseMapRole,
193 : eNoValue,
194 : eNoAction,
195 : eNoLiveAttr,
196 : kGenericAccType,
197 : kNoReqStates
198 : },
199 : { // doc-acknowledgments
200 : &nsGkAtoms::docAcknowledgments,
201 : roles::LANDMARK,
202 : kUseMapRole,
203 : eNoValue,
204 : eNoAction,
205 : eNoLiveAttr,
206 : eLandmark,
207 : kNoReqStates
208 : },
209 : { // doc-afterword
210 : &nsGkAtoms::docAfterword,
211 : roles::LANDMARK,
212 : kUseMapRole,
213 : eNoValue,
214 : eNoAction,
215 : eNoLiveAttr,
216 : eLandmark,
217 : kNoReqStates
218 : },
219 : { // doc-appendix
220 : &nsGkAtoms::docAppendix,
221 : roles::LANDMARK,
222 : kUseMapRole,
223 : eNoValue,
224 : eNoAction,
225 : eNoLiveAttr,
226 : eLandmark,
227 : kNoReqStates
228 : },
229 : { // doc-backlink
230 : &nsGkAtoms::docBacklink,
231 : roles::LINK,
232 : kUseMapRole,
233 : eNoValue,
234 : eJumpAction,
235 : eNoLiveAttr,
236 : kGenericAccType,
237 : states::LINKED
238 : },
239 : { // doc-biblioentry
240 : &nsGkAtoms::docBiblioentry,
241 : roles::LISTITEM,
242 : kUseMapRole,
243 : eNoValue,
244 : eNoAction,
245 : eNoLiveAttr,
246 : kGenericAccType,
247 : states::READONLY
248 : },
249 : { // doc-bibliography
250 : &nsGkAtoms::docBibliography,
251 : roles::LANDMARK,
252 : kUseMapRole,
253 : eNoValue,
254 : eNoAction,
255 : eNoLiveAttr,
256 : eLandmark,
257 : kNoReqStates
258 : },
259 : { // doc-biblioref
260 : &nsGkAtoms::docBiblioref,
261 : roles::LINK,
262 : kUseMapRole,
263 : eNoValue,
264 : eJumpAction,
265 : eNoLiveAttr,
266 : kGenericAccType,
267 : states::LINKED
268 : },
269 : { // doc-chapter
270 : &nsGkAtoms::docChapter,
271 : roles::LANDMARK,
272 : kUseMapRole,
273 : eNoValue,
274 : eNoAction,
275 : eNoLiveAttr,
276 : eLandmark,
277 : kNoReqStates
278 : },
279 : { // doc-colophon
280 : &nsGkAtoms::docColophon,
281 : roles::SECTION,
282 : kUseMapRole,
283 : eNoValue,
284 : eNoAction,
285 : eNoLiveAttr,
286 : kGenericAccType,
287 : kNoReqStates
288 : },
289 : { // doc-conclusion
290 : &nsGkAtoms::docConclusion,
291 : roles::LANDMARK,
292 : kUseMapRole,
293 : eNoValue,
294 : eNoAction,
295 : eNoLiveAttr,
296 : eLandmark,
297 : kNoReqStates
298 : },
299 : { // doc-cover
300 : &nsGkAtoms::docCover,
301 : roles::GRAPHIC,
302 : kUseMapRole,
303 : eNoValue,
304 : eNoAction,
305 : eNoLiveAttr,
306 : kGenericAccType,
307 : kNoReqStates
308 : },
309 : { // doc-credit
310 : &nsGkAtoms::docCredit,
311 : roles::SECTION,
312 : kUseMapRole,
313 : eNoValue,
314 : eNoAction,
315 : eNoLiveAttr,
316 : kGenericAccType,
317 : kNoReqStates
318 : },
319 : { // doc-credits
320 : &nsGkAtoms::docCredits,
321 : roles::LANDMARK,
322 : kUseMapRole,
323 : eNoValue,
324 : eNoAction,
325 : eNoLiveAttr,
326 : eLandmark,
327 : kNoReqStates
328 : },
329 : { // doc-dedication
330 : &nsGkAtoms::docDedication,
331 : roles::SECTION,
332 : kUseMapRole,
333 : eNoValue,
334 : eNoAction,
335 : eNoLiveAttr,
336 : kGenericAccType,
337 : kNoReqStates
338 : },
339 : { // doc-endnote
340 : &nsGkAtoms::docEndnote,
341 : roles::LISTITEM,
342 : kUseMapRole,
343 : eNoValue,
344 : eNoAction,
345 : eNoLiveAttr,
346 : kGenericAccType,
347 : states::READONLY
348 : },
349 : { // doc-endnotes
350 : &nsGkAtoms::docEndnotes,
351 : roles::LANDMARK,
352 : kUseMapRole,
353 : eNoValue,
354 : eNoAction,
355 : eNoLiveAttr,
356 : eLandmark,
357 : kNoReqStates
358 : },
359 : { // doc-epigraph
360 : &nsGkAtoms::docEpigraph,
361 : roles::SECTION,
362 : kUseMapRole,
363 : eNoValue,
364 : eNoAction,
365 : eNoLiveAttr,
366 : kGenericAccType,
367 : kNoReqStates
368 : },
369 : { // doc-epilogue
370 : &nsGkAtoms::docEpilogue,
371 : roles::LANDMARK,
372 : kUseMapRole,
373 : eNoValue,
374 : eNoAction,
375 : eNoLiveAttr,
376 : eLandmark,
377 : kNoReqStates
378 : },
379 : { // doc-errata
380 : &nsGkAtoms::docErrata,
381 : roles::LANDMARK,
382 : kUseMapRole,
383 : eNoValue,
384 : eNoAction,
385 : eNoLiveAttr,
386 : eLandmark,
387 : kNoReqStates
388 : },
389 : { // doc-example
390 : &nsGkAtoms::docExample,
391 : roles::SECTION,
392 : kUseMapRole,
393 : eNoValue,
394 : eNoAction,
395 : eNoLiveAttr,
396 : kGenericAccType,
397 : kNoReqStates
398 : },
399 : { // doc-footnote
400 : &nsGkAtoms::docFootnote,
401 : roles::FOOTNOTE,
402 : kUseMapRole,
403 : eNoValue,
404 : eNoAction,
405 : eNoLiveAttr,
406 : eLandmark,
407 : kNoReqStates
408 : },
409 : { // doc-foreword
410 : &nsGkAtoms::docForeword,
411 : roles::LANDMARK,
412 : kUseMapRole,
413 : eNoValue,
414 : eNoAction,
415 : eNoLiveAttr,
416 : eLandmark,
417 : kNoReqStates
418 : },
419 : { // doc-glossary
420 : &nsGkAtoms::docGlossary,
421 : roles::LANDMARK,
422 : kUseMapRole,
423 : eNoValue,
424 : eNoAction,
425 : eNoLiveAttr,
426 : eLandmark,
427 : kNoReqStates
428 : },
429 : { // doc-glossref
430 : &nsGkAtoms::docGlossref,
431 : roles::LINK,
432 : kUseMapRole,
433 : eNoValue,
434 : eJumpAction,
435 : eNoLiveAttr,
436 : kGenericAccType,
437 : states::LINKED
438 : },
439 : { // doc-index
440 : &nsGkAtoms::docIndex,
441 : roles::NAVIGATION,
442 : kUseMapRole,
443 : eNoValue,
444 : eNoAction,
445 : eNoLiveAttr,
446 : eLandmark,
447 : kNoReqStates
448 : },
449 : { // doc-introduction
450 : &nsGkAtoms::docIntroduction,
451 : roles::LANDMARK,
452 : kUseMapRole,
453 : eNoValue,
454 : eNoAction,
455 : eNoLiveAttr,
456 : eLandmark,
457 : kNoReqStates
458 : },
459 : { // doc-noteref
460 : &nsGkAtoms::docNoteref,
461 : roles::LINK,
462 : kUseMapRole,
463 : eNoValue,
464 : eJumpAction,
465 : eNoLiveAttr,
466 : kGenericAccType,
467 : states::LINKED
468 : },
469 : { // doc-notice
470 : &nsGkAtoms::docNotice,
471 : roles::NOTE,
472 : kUseMapRole,
473 : eNoValue,
474 : eNoAction,
475 : eNoLiveAttr,
476 : kGenericAccType,
477 : kNoReqStates
478 : },
479 : { // doc-pagebreak
480 : &nsGkAtoms::docPagebreak,
481 : roles::SEPARATOR,
482 : kUseMapRole,
483 : eNoValue,
484 : eNoAction,
485 : eNoLiveAttr,
486 : kGenericAccType,
487 : kNoReqStates
488 : },
489 : { // doc-pagelist
490 : &nsGkAtoms::docPagelist,
491 : roles::NAVIGATION,
492 : kUseMapRole,
493 : eNoValue,
494 : eNoAction,
495 : eNoLiveAttr,
496 : eLandmark,
497 : kNoReqStates
498 : },
499 : { // doc-part
500 : &nsGkAtoms::docPart,
501 : roles::LANDMARK,
502 : kUseMapRole,
503 : eNoValue,
504 : eNoAction,
505 : eNoLiveAttr,
506 : eLandmark,
507 : kNoReqStates
508 : },
509 : { // doc-preface
510 : &nsGkAtoms::docPreface,
511 : roles::LANDMARK,
512 : kUseMapRole,
513 : eNoValue,
514 : eNoAction,
515 : eNoLiveAttr,
516 : eLandmark,
517 : kNoReqStates
518 : },
519 : { // doc-prologue
520 : &nsGkAtoms::docPrologue,
521 : roles::LANDMARK,
522 : kUseMapRole,
523 : eNoValue,
524 : eNoAction,
525 : eNoLiveAttr,
526 : eLandmark,
527 : kNoReqStates
528 : },
529 : { // doc-pullquote
530 : &nsGkAtoms::docPullquote,
531 : roles::SECTION,
532 : kUseMapRole,
533 : eNoValue,
534 : eNoAction,
535 : eNoLiveAttr,
536 : kGenericAccType,
537 : kNoReqStates
538 : },
539 : { // doc-qna
540 : &nsGkAtoms::docQna,
541 : roles::SECTION,
542 : kUseMapRole,
543 : eNoValue,
544 : eNoAction,
545 : eNoLiveAttr,
546 : kGenericAccType,
547 : kNoReqStates
548 : },
549 : { // doc-subtitle
550 : &nsGkAtoms::docSubtitle,
551 : roles::HEADING,
552 : kUseMapRole,
553 : eNoValue,
554 : eNoAction,
555 : eNoLiveAttr,
556 : kGenericAccType,
557 : kNoReqStates
558 : },
559 : { // doc-tip
560 : &nsGkAtoms::docTip,
561 : roles::NOTE,
562 : kUseMapRole,
563 : eNoValue,
564 : eNoAction,
565 : eNoLiveAttr,
566 : kGenericAccType,
567 : kNoReqStates
568 : },
569 : { // doc-toc
570 : &nsGkAtoms::docToc,
571 : roles::NAVIGATION,
572 : kUseMapRole,
573 : eNoValue,
574 : eNoAction,
575 : eNoLiveAttr,
576 : eLandmark,
577 : kNoReqStates
578 : },
579 : { // document
580 : &nsGkAtoms::document,
581 : roles::DOCUMENT,
582 : kUseMapRole,
583 : eNoValue,
584 : eNoAction,
585 : eNoLiveAttr,
586 : kGenericAccType,
587 : kNoReqStates,
588 : eReadonlyUntilEditable
589 : },
590 : { // feed
591 : &nsGkAtoms::feed,
592 : roles::GROUPING,
593 : kUseMapRole,
594 : eNoValue,
595 : eNoAction,
596 : eNoLiveAttr,
597 : kGenericAccType,
598 : kNoReqStates
599 : },
600 : { // figure
601 : &nsGkAtoms::figure,
602 : roles::FIGURE,
603 : kUseMapRole,
604 : eNoValue,
605 : eNoAction,
606 : eNoLiveAttr,
607 : kGenericAccType,
608 : kNoReqStates
609 : },
610 : { // form
611 : &nsGkAtoms::form,
612 : roles::FORM,
613 : kUseMapRole,
614 : eNoValue,
615 : eNoAction,
616 : eNoLiveAttr,
617 : eLandmark,
618 : kNoReqStates
619 : },
620 : { // grid
621 : &nsGkAtoms::grid,
622 : roles::TABLE,
623 : kUseMapRole,
624 : eNoValue,
625 : eNoAction,
626 : eNoLiveAttr,
627 : eSelect | eTable,
628 : kNoReqStates,
629 : eARIAMultiSelectable,
630 : eARIAReadonlyOrEditable,
631 : eFocusableUntilDisabled
632 : },
633 : { // gridcell
634 : &nsGkAtoms::gridcell,
635 : roles::GRID_CELL,
636 : kUseMapRole,
637 : eNoValue,
638 : eNoAction,
639 : eNoLiveAttr,
640 : eTableCell,
641 : kNoReqStates,
642 : eARIASelectable,
643 : eARIAReadonlyOrEditableIfDefined
644 : },
645 : { // group
646 : &nsGkAtoms::group,
647 : roles::GROUPING,
648 : kUseMapRole,
649 : eNoValue,
650 : eNoAction,
651 : eNoLiveAttr,
652 : kGenericAccType,
653 : kNoReqStates
654 : },
655 : { // heading
656 : &nsGkAtoms::heading,
657 : roles::HEADING,
658 : kUseMapRole,
659 : eNoValue,
660 : eNoAction,
661 : eNoLiveAttr,
662 : kGenericAccType,
663 : kNoReqStates
664 : },
665 : { // img
666 : &nsGkAtoms::img,
667 : roles::GRAPHIC,
668 : kUseMapRole,
669 : eNoValue,
670 : eNoAction,
671 : eNoLiveAttr,
672 : kGenericAccType,
673 : kNoReqStates
674 : },
675 : { // key
676 : &nsGkAtoms::key,
677 : roles::KEY,
678 : kUseMapRole,
679 : eNoValue,
680 : ePressAction,
681 : eNoLiveAttr,
682 : kGenericAccType,
683 : kNoReqStates,
684 : eARIAPressed
685 : },
686 : { // link
687 : &nsGkAtoms::link,
688 : roles::LINK,
689 : kUseMapRole,
690 : eNoValue,
691 : eJumpAction,
692 : eNoLiveAttr,
693 : kGenericAccType,
694 : states::LINKED
695 : },
696 : { // list
697 : &nsGkAtoms::list,
698 : roles::LIST,
699 : kUseMapRole,
700 : eNoValue,
701 : eNoAction,
702 : eNoLiveAttr,
703 : eList,
704 : states::READONLY
705 : },
706 : { // listbox
707 : &nsGkAtoms::listbox,
708 : roles::LISTBOX,
709 : kUseMapRole,
710 : eNoValue,
711 : eNoAction,
712 : eNoLiveAttr,
713 : eListControl | eSelect,
714 : states::VERTICAL,
715 : eARIAMultiSelectable,
716 : eARIAReadonly,
717 : eFocusableUntilDisabled,
718 : eARIAOrientation
719 : },
720 : { // listitem
721 : &nsGkAtoms::listitem,
722 : roles::LISTITEM,
723 : kUseMapRole,
724 : eNoValue,
725 : eNoAction, // XXX: should depend on state, parent accessible
726 : eNoLiveAttr,
727 : kGenericAccType,
728 : states::READONLY
729 : },
730 : { // log
731 : &nsGkAtoms::log_,
732 : roles::NOTHING,
733 : kUseNativeRole,
734 : eNoValue,
735 : eNoAction,
736 : ePoliteLiveAttr,
737 : kGenericAccType,
738 : kNoReqStates
739 : },
740 : { // main
741 : &nsGkAtoms::main,
742 : roles::NOTHING,
743 : kUseNativeRole,
744 : eNoValue,
745 : eNoAction,
746 : eNoLiveAttr,
747 : eLandmark,
748 : kNoReqStates
749 : },
750 : { // marquee
751 : &nsGkAtoms::marquee,
752 : roles::ANIMATION,
753 : kUseMapRole,
754 : eNoValue,
755 : eNoAction,
756 : eOffLiveAttr,
757 : kGenericAccType,
758 : kNoReqStates
759 : },
760 : { // math
761 : &nsGkAtoms::math,
762 : roles::FLAT_EQUATION,
763 : kUseMapRole,
764 : eNoValue,
765 : eNoAction,
766 : eNoLiveAttr,
767 : kGenericAccType,
768 : kNoReqStates
769 : },
770 : { // menu
771 : &nsGkAtoms::menu,
772 : roles::MENUPOPUP,
773 : kUseMapRole,
774 : eNoValue,
775 : eNoAction, // XXX: technically accessibles of menupopup role haven't
776 : // any action, but menu can be open or close.
777 : eNoLiveAttr,
778 : kGenericAccType,
779 : states::VERTICAL,
780 : eARIAOrientation
781 : },
782 : { // menubar
783 : &nsGkAtoms::menubar,
784 : roles::MENUBAR,
785 : kUseMapRole,
786 : eNoValue,
787 : eNoAction,
788 : eNoLiveAttr,
789 : kGenericAccType,
790 : states::HORIZONTAL,
791 : eARIAOrientation
792 : },
793 : { // menuitem
794 : &nsGkAtoms::menuitem,
795 : roles::MENUITEM,
796 : kUseMapRole,
797 : eNoValue,
798 : eClickAction,
799 : eNoLiveAttr,
800 : kGenericAccType,
801 : kNoReqStates
802 : },
803 : { // menuitemcheckbox
804 : &nsGkAtoms::menuitemcheckbox,
805 : roles::CHECK_MENU_ITEM,
806 : kUseMapRole,
807 : eNoValue,
808 : eClickAction,
809 : eNoLiveAttr,
810 : kGenericAccType,
811 : kNoReqStates,
812 : eARIACheckableMixed,
813 : eARIAReadonly
814 : },
815 : { // menuitemradio
816 : &nsGkAtoms::menuitemradio,
817 : roles::RADIO_MENU_ITEM,
818 : kUseMapRole,
819 : eNoValue,
820 : eClickAction,
821 : eNoLiveAttr,
822 : kGenericAccType,
823 : kNoReqStates,
824 : eARIACheckableBool,
825 : eARIAReadonly
826 : },
827 : { // navigation
828 : &nsGkAtoms::navigation,
829 : roles::NOTHING,
830 : kUseNativeRole,
831 : eNoValue,
832 : eNoAction,
833 : eNoLiveAttr,
834 : eLandmark,
835 : kNoReqStates
836 : },
837 : { // none
838 : &nsGkAtoms::none,
839 : roles::NOTHING,
840 : kUseMapRole,
841 : eNoValue,
842 : eNoAction,
843 : eNoLiveAttr,
844 : kGenericAccType,
845 : kNoReqStates
846 : },
847 : { // note
848 : &nsGkAtoms::note_,
849 : roles::NOTE,
850 : kUseMapRole,
851 : eNoValue,
852 : eNoAction,
853 : eNoLiveAttr,
854 : kGenericAccType,
855 : kNoReqStates
856 : },
857 : { // option
858 : &nsGkAtoms::option,
859 : roles::OPTION,
860 : kUseMapRole,
861 : eNoValue,
862 : eSelectAction,
863 : eNoLiveAttr,
864 : kGenericAccType,
865 : kNoReqStates,
866 : eARIASelectable,
867 : eARIACheckedMixed
868 : },
869 : { // presentation
870 : &nsGkAtoms::presentation,
871 : roles::NOTHING,
872 : kUseMapRole,
873 : eNoValue,
874 : eNoAction,
875 : eNoLiveAttr,
876 : kGenericAccType,
877 : kNoReqStates
878 : },
879 : { // progressbar
880 : &nsGkAtoms::progressbar,
881 : roles::PROGRESSBAR,
882 : kUseMapRole,
883 : eHasValueMinMax,
884 : eNoAction,
885 : eNoLiveAttr,
886 : kGenericAccType,
887 : states::READONLY,
888 : eIndeterminateIfNoValue
889 : },
890 : { // radio
891 : &nsGkAtoms::radio,
892 : roles::RADIOBUTTON,
893 : kUseMapRole,
894 : eNoValue,
895 : eSelectAction,
896 : eNoLiveAttr,
897 : kGenericAccType,
898 : kNoReqStates,
899 : eARIACheckableBool
900 : },
901 : { // radiogroup
902 : &nsGkAtoms::radiogroup,
903 : roles::RADIO_GROUP,
904 : kUseMapRole,
905 : eNoValue,
906 : eNoAction,
907 : eNoLiveAttr,
908 : kGenericAccType,
909 : kNoReqStates,
910 : eARIAOrientation,
911 : eARIAReadonly
912 : },
913 : { // region
914 : &nsGkAtoms::region,
915 : roles::REGION,
916 : kUseMapRole,
917 : eNoValue,
918 : eNoAction,
919 : eNoLiveAttr,
920 : eLandmark,
921 : kNoReqStates
922 : },
923 : { // row
924 : &nsGkAtoms::row,
925 : roles::ROW,
926 : kUseMapRole,
927 : eNoValue,
928 : eNoAction,
929 : eNoLiveAttr,
930 : eTableRow,
931 : kNoReqStates,
932 : eARIASelectable
933 : },
934 : { // rowgroup
935 : &nsGkAtoms::rowgroup,
936 : roles::GROUPING,
937 : kUseMapRole,
938 : eNoValue,
939 : eNoAction,
940 : eNoLiveAttr,
941 : kGenericAccType,
942 : kNoReqStates
943 : },
944 : { // rowheader
945 : &nsGkAtoms::rowheader,
946 : roles::ROWHEADER,
947 : kUseMapRole,
948 : eNoValue,
949 : eSortAction,
950 : eNoLiveAttr,
951 : eTableCell,
952 : kNoReqStates,
953 : eARIASelectableIfDefined,
954 : eARIAReadonlyOrEditableIfDefined
955 : },
956 : { // scrollbar
957 : &nsGkAtoms::scrollbar,
958 : roles::SCROLLBAR,
959 : kUseMapRole,
960 : eHasValueMinMax,
961 : eNoAction,
962 : eNoLiveAttr,
963 : kGenericAccType,
964 : states::VERTICAL,
965 : eARIAOrientation,
966 : eARIAReadonly
967 : },
968 : { // search
969 : &nsGkAtoms::search,
970 : roles::NOTHING,
971 : kUseNativeRole,
972 : eNoValue,
973 : eNoAction,
974 : eNoLiveAttr,
975 : eLandmark,
976 : kNoReqStates
977 : },
978 : { // searchbox
979 : &nsGkAtoms::searchbox,
980 : roles::ENTRY,
981 : kUseMapRole,
982 : eNoValue,
983 : eActivateAction,
984 : eNoLiveAttr,
985 : kGenericAccType,
986 : kNoReqStates,
987 : eARIAAutoComplete,
988 : eARIAMultiline,
989 : eARIAReadonlyOrEditable
990 : },
991 : { // separator
992 : &nsGkAtoms::separator_,
993 : roles::SEPARATOR,
994 : kUseMapRole,
995 : eHasValueMinMaxIfFocusable,
996 : eNoAction,
997 : eNoLiveAttr,
998 : kGenericAccType,
999 : states::HORIZONTAL,
1000 : eARIAOrientation
1001 : },
1002 : { // slider
1003 : &nsGkAtoms::slider,
1004 : roles::SLIDER,
1005 : kUseMapRole,
1006 : eHasValueMinMax,
1007 : eNoAction,
1008 : eNoLiveAttr,
1009 : kGenericAccType,
1010 : states::HORIZONTAL,
1011 : eARIAOrientation,
1012 : eARIAReadonly
1013 : },
1014 : { // spinbutton
1015 : &nsGkAtoms::spinbutton,
1016 : roles::SPINBUTTON,
1017 : kUseMapRole,
1018 : eHasValueMinMax,
1019 : eNoAction,
1020 : eNoLiveAttr,
1021 : kGenericAccType,
1022 : kNoReqStates,
1023 : eARIAReadonly
1024 : },
1025 : { // status
1026 : &nsGkAtoms::status,
1027 : roles::STATUSBAR,
1028 : kUseMapRole,
1029 : eNoValue,
1030 : eNoAction,
1031 : ePoliteLiveAttr,
1032 : kGenericAccType,
1033 : kNoReqStates
1034 : },
1035 : { // switch
1036 : &nsGkAtoms::_switch,
1037 : roles::SWITCH,
1038 : kUseMapRole,
1039 : eNoValue,
1040 : eCheckUncheckAction,
1041 : eNoLiveAttr,
1042 : kGenericAccType,
1043 : kNoReqStates,
1044 : eARIACheckableBool,
1045 : eARIAReadonly
1046 : },
1047 : { // tab
1048 : &nsGkAtoms::tab,
1049 : roles::PAGETAB,
1050 : kUseMapRole,
1051 : eNoValue,
1052 : eSwitchAction,
1053 : eNoLiveAttr,
1054 : kGenericAccType,
1055 : kNoReqStates,
1056 : eARIASelectable
1057 : },
1058 : { // table
1059 : &nsGkAtoms::table,
1060 : roles::TABLE,
1061 : kUseMapRole,
1062 : eNoValue,
1063 : eNoAction,
1064 : eNoLiveAttr,
1065 : eTable,
1066 : kNoReqStates,
1067 : eARIASelectable
1068 : },
1069 : { // tablist
1070 : &nsGkAtoms::tablist,
1071 : roles::PAGETABLIST,
1072 : kUseMapRole,
1073 : eNoValue,
1074 : eNoAction,
1075 : eNoLiveAttr,
1076 : eSelect,
1077 : states::HORIZONTAL,
1078 : eARIAOrientation
1079 : },
1080 : { // tabpanel
1081 : &nsGkAtoms::tabpanel,
1082 : roles::PROPERTYPAGE,
1083 : kUseMapRole,
1084 : eNoValue,
1085 : eNoAction,
1086 : eNoLiveAttr,
1087 : kGenericAccType,
1088 : kNoReqStates
1089 : },
1090 : { // term
1091 : &nsGkAtoms::term,
1092 : roles::TERM,
1093 : kUseMapRole,
1094 : eNoValue,
1095 : eNoAction,
1096 : eNoLiveAttr,
1097 : kGenericAccType,
1098 : states::READONLY
1099 : },
1100 : { // textbox
1101 : &nsGkAtoms::textbox,
1102 : roles::ENTRY,
1103 : kUseMapRole,
1104 : eNoValue,
1105 : eActivateAction,
1106 : eNoLiveAttr,
1107 : kGenericAccType,
1108 : kNoReqStates,
1109 : eARIAAutoComplete,
1110 : eARIAMultiline,
1111 : eARIAReadonlyOrEditable
1112 : },
1113 : { // timer
1114 : &nsGkAtoms::timer,
1115 : roles::NOTHING,
1116 : kUseNativeRole,
1117 : eNoValue,
1118 : eNoAction,
1119 : eOffLiveAttr,
1120 : kNoReqStates
1121 : },
1122 : { // toolbar
1123 : &nsGkAtoms::toolbar,
1124 : roles::TOOLBAR,
1125 : kUseMapRole,
1126 : eNoValue,
1127 : eNoAction,
1128 : eNoLiveAttr,
1129 : kGenericAccType,
1130 : states::HORIZONTAL,
1131 : eARIAOrientation
1132 : },
1133 : { // tooltip
1134 : &nsGkAtoms::tooltip,
1135 : roles::TOOLTIP,
1136 : kUseMapRole,
1137 : eNoValue,
1138 : eNoAction,
1139 : eNoLiveAttr,
1140 : kGenericAccType,
1141 : kNoReqStates
1142 : },
1143 : { // tree
1144 : &nsGkAtoms::tree,
1145 : roles::OUTLINE,
1146 : kUseMapRole,
1147 : eNoValue,
1148 : eNoAction,
1149 : eNoLiveAttr,
1150 : eSelect,
1151 : states::VERTICAL,
1152 : eARIAReadonly,
1153 : eARIAMultiSelectable,
1154 : eFocusableUntilDisabled,
1155 : eARIAOrientation
1156 : },
1157 : { // treegrid
1158 : &nsGkAtoms::treegrid,
1159 : roles::TREE_TABLE,
1160 : kUseMapRole,
1161 : eNoValue,
1162 : eNoAction,
1163 : eNoLiveAttr,
1164 : eSelect | eTable,
1165 : kNoReqStates,
1166 : eARIAReadonlyOrEditable,
1167 : eARIAMultiSelectable,
1168 : eFocusableUntilDisabled,
1169 : eARIAOrientation
1170 : },
1171 : { // treeitem
1172 : &nsGkAtoms::treeitem,
1173 : roles::OUTLINEITEM,
1174 : kUseMapRole,
1175 : eNoValue,
1176 : eActivateAction, // XXX: should expose second 'expand/collapse' action based
1177 : // on states
1178 : eNoLiveAttr,
1179 : kGenericAccType,
1180 : kNoReqStates,
1181 : eARIASelectable,
1182 : eARIACheckedMixed
1183 : }
1184 : };
1185 :
1186 : static const nsRoleMapEntry sLandmarkRoleMap = {
1187 : &nsGkAtoms::_empty,
1188 : roles::NOTHING,
1189 : kUseNativeRole,
1190 : eNoValue,
1191 : eNoAction,
1192 : eNoLiveAttr,
1193 : kGenericAccType,
1194 : kNoReqStates
1195 : };
1196 :
1197 : nsRoleMapEntry aria::gEmptyRoleMap = {
1198 : &nsGkAtoms::_empty,
1199 : roles::NOTHING,
1200 : kUseMapRole,
1201 : eNoValue,
1202 : eNoAction,
1203 : eNoLiveAttr,
1204 : kGenericAccType,
1205 : kNoReqStates
1206 : };
1207 :
1208 : /**
1209 : * Universal (Global) states:
1210 : * The following state rules are applied to any accessible element,
1211 : * whether there is an ARIA role or not:
1212 : */
1213 : static const EStateRule sWAIUnivStateMap[] = {
1214 : eARIABusy,
1215 : eARIACurrent,
1216 : eARIADisabled,
1217 : eARIAExpanded, // Currently under spec review but precedent exists
1218 : eARIAHasPopup, // Note this is technically a "property"
1219 : eARIAInvalid,
1220 : eARIAModal,
1221 : eARIARequired, // XXX not global, Bug 553117
1222 : eARIANone
1223 : };
1224 :
1225 :
1226 : /**
1227 : * ARIA attribute map for attribute characteristics.
1228 : * @note ARIA attributes that don't have any flags are not included here.
1229 : */
1230 :
1231 : struct AttrCharacteristics
1232 : {
1233 : nsIAtom** attributeName;
1234 : const uint8_t characteristics;
1235 : };
1236 :
1237 : static const AttrCharacteristics gWAIUnivAttrMap[] = {
1238 : {&nsGkAtoms::aria_activedescendant, ATTR_BYPASSOBJ },
1239 : {&nsGkAtoms::aria_atomic, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL },
1240 : {&nsGkAtoms::aria_busy, ATTR_VALTOKEN | ATTR_GLOBAL },
1241 : {&nsGkAtoms::aria_checked, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, /* exposes checkable obj attr */
1242 : {&nsGkAtoms::aria_controls, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1243 : {&nsGkAtoms::aria_describedby, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1244 : {&nsGkAtoms::aria_details, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1245 : {&nsGkAtoms::aria_disabled, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
1246 : {&nsGkAtoms::aria_dropeffect, ATTR_VALTOKEN | ATTR_GLOBAL },
1247 : {&nsGkAtoms::aria_errormessage, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1248 : {&nsGkAtoms::aria_expanded, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
1249 : {&nsGkAtoms::aria_flowto, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1250 : {&nsGkAtoms::aria_grabbed, ATTR_VALTOKEN | ATTR_GLOBAL },
1251 : {&nsGkAtoms::aria_haspopup, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
1252 : {&nsGkAtoms::aria_hidden, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, /* handled special way */
1253 : {&nsGkAtoms::aria_invalid, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
1254 : {&nsGkAtoms::aria_label, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1255 : {&nsGkAtoms::aria_labelledby, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1256 : {&nsGkAtoms::aria_level, ATTR_BYPASSOBJ }, /* handled via groupPosition */
1257 : {&nsGkAtoms::aria_live, ATTR_VALTOKEN | ATTR_GLOBAL },
1258 : {&nsGkAtoms::aria_modal, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
1259 : {&nsGkAtoms::aria_multiline, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
1260 : {&nsGkAtoms::aria_multiselectable, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
1261 : {&nsGkAtoms::aria_owns, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1262 : {&nsGkAtoms::aria_orientation, ATTR_VALTOKEN },
1263 : {&nsGkAtoms::aria_posinset, ATTR_BYPASSOBJ }, /* handled via groupPosition */
1264 : {&nsGkAtoms::aria_pressed, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
1265 : {&nsGkAtoms::aria_readonly, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
1266 : {&nsGkAtoms::aria_relevant, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1267 : {&nsGkAtoms::aria_required, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
1268 : {&nsGkAtoms::aria_selected, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
1269 : {&nsGkAtoms::aria_setsize, ATTR_BYPASSOBJ }, /* handled via groupPosition */
1270 : {&nsGkAtoms::aria_sort, ATTR_VALTOKEN },
1271 : {&nsGkAtoms::aria_valuenow, ATTR_BYPASSOBJ },
1272 : {&nsGkAtoms::aria_valuemin, ATTR_BYPASSOBJ },
1273 : {&nsGkAtoms::aria_valuemax, ATTR_BYPASSOBJ },
1274 : {&nsGkAtoms::aria_valuetext, ATTR_BYPASSOBJ }
1275 : };
1276 :
1277 : namespace {
1278 :
1279 : struct RoleComparator
1280 : {
1281 : const nsDependentSubstring& mRole;
1282 0 : explicit RoleComparator(const nsDependentSubstring& aRole) : mRole(aRole) {}
1283 0 : int operator()(const nsRoleMapEntry& aEntry) const {
1284 0 : return Compare(mRole, aEntry.ARIARoleString());
1285 : }
1286 : };
1287 :
1288 : }
1289 :
1290 : const nsRoleMapEntry*
1291 0 : aria::GetRoleMap(dom::Element* aEl)
1292 : {
1293 0 : return GetRoleMapFromIndex(GetRoleMapIndex(aEl));
1294 : }
1295 :
1296 : uint8_t
1297 0 : aria::GetRoleMapIndex(dom::Element* aEl)
1298 : {
1299 0 : nsAutoString roles;
1300 0 : if (!aEl || !aEl->GetAttr(kNameSpaceID_None, nsGkAtoms::role, roles) ||
1301 0 : roles.IsEmpty()) {
1302 : // We treat role="" as if the role attribute is absent (per aria spec:8.1.1)
1303 0 : return NO_ROLE_MAP_ENTRY_INDEX;
1304 : }
1305 :
1306 0 : nsWhitespaceTokenizer tokenizer(roles);
1307 0 : while (tokenizer.hasMoreTokens()) {
1308 : // Do a binary search through table for the next role in role list
1309 0 : const nsDependentSubstring role = tokenizer.nextToken();
1310 : size_t idx;
1311 0 : if (BinarySearchIf(sWAIRoleMaps, 0, ArrayLength(sWAIRoleMaps),
1312 0 : RoleComparator(role), &idx)) {
1313 0 : return idx;
1314 : }
1315 : }
1316 :
1317 : // Always use some entry index if there is a non-empty role string
1318 : // To ensure an accessible object is created
1319 0 : return LANDMARK_ROLE_MAP_ENTRY_INDEX;
1320 : }
1321 :
1322 :
1323 : const nsRoleMapEntry*
1324 0 : aria::GetRoleMapFromIndex(uint8_t aRoleMapIndex)
1325 : {
1326 0 : switch (aRoleMapIndex) {
1327 : case NO_ROLE_MAP_ENTRY_INDEX:
1328 0 : return nullptr;
1329 : case EMPTY_ROLE_MAP_ENTRY_INDEX:
1330 0 : return &gEmptyRoleMap;
1331 : case LANDMARK_ROLE_MAP_ENTRY_INDEX:
1332 0 : return &sLandmarkRoleMap;
1333 : default:
1334 0 : return sWAIRoleMaps + aRoleMapIndex;
1335 : }
1336 : }
1337 :
1338 : uint8_t
1339 0 : aria::GetIndexFromRoleMap(const nsRoleMapEntry* aRoleMapEntry)
1340 : {
1341 0 : if (aRoleMapEntry == nullptr) {
1342 0 : return NO_ROLE_MAP_ENTRY_INDEX;
1343 0 : } else if (aRoleMapEntry == &gEmptyRoleMap) {
1344 0 : return EMPTY_ROLE_MAP_ENTRY_INDEX;
1345 0 : } else if (aRoleMapEntry == &sLandmarkRoleMap) {
1346 0 : return LANDMARK_ROLE_MAP_ENTRY_INDEX;
1347 : } else {
1348 0 : return aRoleMapEntry - sWAIRoleMaps;
1349 : }
1350 : }
1351 :
1352 : uint64_t
1353 0 : aria::UniversalStatesFor(mozilla::dom::Element* aElement)
1354 : {
1355 0 : uint64_t state = 0;
1356 0 : uint32_t index = 0;
1357 0 : while (MapToState(sWAIUnivStateMap[index], aElement, &state))
1358 0 : index++;
1359 :
1360 0 : return state;
1361 : }
1362 :
1363 : uint8_t
1364 0 : aria::AttrCharacteristicsFor(nsIAtom* aAtom)
1365 : {
1366 0 : for (uint32_t i = 0; i < ArrayLength(gWAIUnivAttrMap); i++)
1367 0 : if (*gWAIUnivAttrMap[i].attributeName == aAtom)
1368 0 : return gWAIUnivAttrMap[i].characteristics;
1369 :
1370 0 : return 0;
1371 : }
1372 :
1373 : bool
1374 0 : aria::HasDefinedARIAHidden(nsIContent* aContent)
1375 : {
1376 0 : return aContent &&
1377 0 : nsAccUtils::HasDefinedARIAToken(aContent, nsGkAtoms::aria_hidden) &&
1378 0 : !aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_hidden,
1379 0 : nsGkAtoms::_false, eCaseMatters);
1380 : }
1381 :
1382 : ////////////////////////////////////////////////////////////////////////////////
1383 : // AttrIterator class
1384 :
1385 : bool
1386 0 : AttrIterator::Next(nsAString& aAttrName, nsAString& aAttrValue)
1387 : {
1388 0 : while (mAttrIdx < mAttrCount) {
1389 0 : const nsAttrName* attr = mContent->GetAttrNameAt(mAttrIdx);
1390 0 : mAttrIdx++;
1391 0 : if (attr->NamespaceEquals(kNameSpaceID_None)) {
1392 0 : nsIAtom* attrAtom = attr->Atom();
1393 0 : nsDependentAtomString attrStr(attrAtom);
1394 0 : if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-")))
1395 0 : continue; // Not ARIA
1396 :
1397 0 : uint8_t attrFlags = aria::AttrCharacteristicsFor(attrAtom);
1398 0 : if (attrFlags & ATTR_BYPASSOBJ)
1399 0 : continue; // No need to handle exposing as obj attribute here
1400 :
1401 0 : if ((attrFlags & ATTR_VALTOKEN) &&
1402 0 : !nsAccUtils::HasDefinedARIAToken(mContent, attrAtom))
1403 0 : continue; // only expose token based attributes if they are defined
1404 :
1405 0 : if ((attrFlags & ATTR_BYPASSOBJ_IF_FALSE) &&
1406 0 : mContent->AttrValueIs(kNameSpaceID_None, attrAtom,
1407 : nsGkAtoms::_false, eCaseMatters)) {
1408 0 : continue; // only expose token based attribute if value is not 'false'.
1409 : }
1410 :
1411 0 : nsAutoString value;
1412 0 : if (mContent->GetAttr(kNameSpaceID_None, attrAtom, value)) {
1413 0 : aAttrName.Assign(Substring(attrStr, 5));
1414 0 : aAttrValue.Assign(value);
1415 0 : return true;
1416 : }
1417 : }
1418 : }
1419 :
1420 0 : return false;
1421 : }
1422 :
|