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