Bug 1687263: part 4) Defer and in some cases avoid removing spellchecking-ranges...
[gecko.git] / accessible / base / ARIAMap.cpp
blobaf9b6e3af86d2371e2757a835ad9e52d14122e53
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 { // navigation
928 nsGkAtoms::navigation,
929 roles::LANDMARK,
930 kUseMapRole,
931 eNoValue,
932 eNoAction,
933 eNoLiveAttr,
934 eLandmark,
935 kNoReqStates
937 { // none
938 nsGkAtoms::none,
939 roles::NOTHING,
940 kUseMapRole,
941 eNoValue,
942 eNoAction,
943 eNoLiveAttr,
944 kGenericAccType,
945 kNoReqStates
947 { // note
948 nsGkAtoms::note_,
949 roles::NOTE,
950 kUseMapRole,
951 eNoValue,
952 eNoAction,
953 eNoLiveAttr,
954 kGenericAccType,
955 kNoReqStates
957 { // option
958 nsGkAtoms::option,
959 roles::OPTION,
960 kUseMapRole,
961 eNoValue,
962 eSelectAction,
963 eNoLiveAttr,
964 kGenericAccType,
965 kNoReqStates,
966 eARIASelectable,
967 eARIACheckedMixed
969 { // paragraph
970 nsGkAtoms::paragraph,
971 roles::PARAGRAPH,
972 kUseMapRole,
973 eNoValue,
974 eNoAction,
975 eNoLiveAttr,
976 kGenericAccType,
978 { // presentation
979 nsGkAtoms::presentation,
980 roles::NOTHING,
981 kUseMapRole,
982 eNoValue,
983 eNoAction,
984 eNoLiveAttr,
985 kGenericAccType,
986 kNoReqStates
988 { // progressbar
989 nsGkAtoms::progressbar,
990 roles::PROGRESSBAR,
991 kUseMapRole,
992 eHasValueMinMax,
993 eNoAction,
994 eNoLiveAttr,
995 kGenericAccType,
996 states::READONLY,
997 eIndeterminateIfNoValue
999 { // radio
1000 nsGkAtoms::radio,
1001 roles::RADIOBUTTON,
1002 kUseMapRole,
1003 eNoValue,
1004 eSelectAction,
1005 eNoLiveAttr,
1006 kGenericAccType,
1007 kNoReqStates,
1008 eARIACheckableBool
1010 { // radiogroup
1011 nsGkAtoms::radiogroup,
1012 roles::RADIO_GROUP,
1013 kUseMapRole,
1014 eNoValue,
1015 eNoAction,
1016 eNoLiveAttr,
1017 kGenericAccType,
1018 kNoReqStates,
1019 eARIAOrientation,
1020 eARIAReadonly
1022 { // region
1023 nsGkAtoms::region,
1024 roles::REGION,
1025 kUseMapRole,
1026 eNoValue,
1027 eNoAction,
1028 eNoLiveAttr,
1029 eLandmark,
1030 kNoReqStates
1032 { // row
1033 nsGkAtoms::row,
1034 roles::ROW,
1035 kUseMapRole,
1036 eNoValue,
1037 eNoAction,
1038 eNoLiveAttr,
1039 eTableRow,
1040 kNoReqStates,
1041 eARIASelectable
1043 { // rowgroup
1044 nsGkAtoms::rowgroup,
1045 roles::GROUPING,
1046 kUseMapRole,
1047 eNoValue,
1048 eNoAction,
1049 eNoLiveAttr,
1050 kGenericAccType,
1051 kNoReqStates
1053 { // rowheader
1054 nsGkAtoms::rowheader,
1055 roles::ROWHEADER,
1056 kUseMapRole,
1057 eNoValue,
1058 eSortAction,
1059 eNoLiveAttr,
1060 eTableCell,
1061 kNoReqStates,
1062 eARIASelectableIfDefined,
1063 eARIAReadonly
1065 { // scrollbar
1066 nsGkAtoms::scrollbar,
1067 roles::SCROLLBAR,
1068 kUseMapRole,
1069 eHasValueMinMax,
1070 eNoAction,
1071 eNoLiveAttr,
1072 kGenericAccType,
1073 states::VERTICAL,
1074 eARIAOrientation,
1075 eARIAReadonly
1077 { // search
1078 nsGkAtoms::search,
1079 roles::LANDMARK,
1080 kUseMapRole,
1081 eNoValue,
1082 eNoAction,
1083 eNoLiveAttr,
1084 eLandmark,
1085 kNoReqStates
1087 { // searchbox
1088 nsGkAtoms::searchbox,
1089 roles::ENTRY,
1090 kUseMapRole,
1091 eNoValue,
1092 eActivateAction,
1093 eNoLiveAttr,
1094 kGenericAccType,
1095 kNoReqStates,
1096 eARIAAutoComplete,
1097 eARIAMultiline,
1098 eARIAReadonlyOrEditable
1100 { // separator
1101 nsGkAtoms::separator_,
1102 roles::SEPARATOR,
1103 kUseMapRole,
1104 eHasValueMinMaxIfFocusable,
1105 eNoAction,
1106 eNoLiveAttr,
1107 kGenericAccType,
1108 states::HORIZONTAL,
1109 eARIAOrientation
1111 { // slider
1112 nsGkAtoms::slider,
1113 roles::SLIDER,
1114 kUseMapRole,
1115 eHasValueMinMax,
1116 eNoAction,
1117 eNoLiveAttr,
1118 kGenericAccType,
1119 states::HORIZONTAL,
1120 eARIAOrientation,
1121 eARIAReadonly
1123 { // spinbutton
1124 nsGkAtoms::spinbutton,
1125 roles::SPINBUTTON,
1126 kUseMapRole,
1127 eHasValueMinMax,
1128 eNoAction,
1129 eNoLiveAttr,
1130 kGenericAccType,
1131 kNoReqStates,
1132 eARIAReadonly
1134 { // status
1135 nsGkAtoms::status,
1136 roles::STATUSBAR,
1137 kUseMapRole,
1138 eNoValue,
1139 eNoAction,
1140 ePoliteLiveAttr,
1141 kGenericAccType,
1142 kNoReqStates
1144 { // suggestion
1145 nsGkAtoms::suggestion,
1146 roles::SUGGESTION,
1147 kUseMapRole,
1148 eNoValue,
1149 eNoAction,
1150 eNoLiveAttr,
1151 kGenericAccType,
1153 { // switch
1154 nsGkAtoms::svgSwitch,
1155 roles::SWITCH,
1156 kUseMapRole,
1157 eNoValue,
1158 eCheckUncheckAction,
1159 eNoLiveAttr,
1160 kGenericAccType,
1161 kNoReqStates,
1162 eARIACheckableBool,
1163 eARIAReadonly
1165 { // tab
1166 nsGkAtoms::tab,
1167 roles::PAGETAB,
1168 kUseMapRole,
1169 eNoValue,
1170 eSwitchAction,
1171 eNoLiveAttr,
1172 kGenericAccType,
1173 kNoReqStates,
1174 eARIASelectable
1176 { // table
1177 nsGkAtoms::table,
1178 roles::TABLE,
1179 kUseMapRole,
1180 eNoValue,
1181 eNoAction,
1182 eNoLiveAttr,
1183 eTable,
1184 kNoReqStates,
1185 eARIASelectable
1187 { // tablist
1188 nsGkAtoms::tablist,
1189 roles::PAGETABLIST,
1190 kUseMapRole,
1191 eNoValue,
1192 eNoAction,
1193 eNoLiveAttr,
1194 eSelect,
1195 states::HORIZONTAL,
1196 eARIAOrientation,
1197 eARIAMultiSelectable
1199 { // tabpanel
1200 nsGkAtoms::tabpanel,
1201 roles::PROPERTYPAGE,
1202 kUseMapRole,
1203 eNoValue,
1204 eNoAction,
1205 eNoLiveAttr,
1206 kGenericAccType,
1207 kNoReqStates
1209 { // term
1210 nsGkAtoms::term,
1211 roles::TERM,
1212 kUseMapRole,
1213 eNoValue,
1214 eNoAction,
1215 eNoLiveAttr,
1216 kGenericAccType,
1217 states::READONLY
1219 { // textbox
1220 nsGkAtoms::textbox,
1221 roles::ENTRY,
1222 kUseMapRole,
1223 eNoValue,
1224 eActivateAction,
1225 eNoLiveAttr,
1226 kGenericAccType,
1227 kNoReqStates,
1228 eARIAAutoComplete,
1229 eARIAMultiline,
1230 eARIAReadonlyOrEditable
1232 { // timer
1233 nsGkAtoms::timer,
1234 roles::NOTHING,
1235 kUseNativeRole,
1236 eNoValue,
1237 eNoAction,
1238 eOffLiveAttr,
1239 kNoReqStates
1241 { // toolbar
1242 nsGkAtoms::toolbar,
1243 roles::TOOLBAR,
1244 kUseMapRole,
1245 eNoValue,
1246 eNoAction,
1247 eNoLiveAttr,
1248 kGenericAccType,
1249 states::HORIZONTAL,
1250 eARIAOrientation
1252 { // tooltip
1253 nsGkAtoms::tooltip,
1254 roles::TOOLTIP,
1255 kUseMapRole,
1256 eNoValue,
1257 eNoAction,
1258 eNoLiveAttr,
1259 kGenericAccType,
1260 kNoReqStates
1262 { // tree
1263 nsGkAtoms::tree,
1264 roles::OUTLINE,
1265 kUseMapRole,
1266 eNoValue,
1267 eNoAction,
1268 eNoLiveAttr,
1269 eSelect,
1270 states::VERTICAL,
1271 eARIAReadonly,
1272 eARIAMultiSelectable,
1273 eFocusableUntilDisabled,
1274 eARIAOrientation
1276 { // treegrid
1277 nsGkAtoms::treegrid,
1278 roles::TREE_TABLE,
1279 kUseMapRole,
1280 eNoValue,
1281 eNoAction,
1282 eNoLiveAttr,
1283 eSelect | eTable,
1284 kNoReqStates,
1285 eARIAReadonly,
1286 eARIAMultiSelectable,
1287 eFocusableUntilDisabled,
1288 eARIAOrientation
1290 { // treeitem
1291 nsGkAtoms::treeitem,
1292 roles::OUTLINEITEM,
1293 kUseMapRole,
1294 eNoValue,
1295 eActivateAction, // XXX: should expose second 'expand/collapse' action based
1296 // on states
1297 eNoLiveAttr,
1298 kGenericAccType,
1299 kNoReqStates,
1300 eARIASelectable,
1301 eARIACheckedMixed
1303 // clang-format on
1306 static const nsRoleMapEntry sLandmarkRoleMap = {
1307 nsGkAtoms::_empty, roles::NOTHING, kUseNativeRole, eNoValue,
1308 eNoAction, eNoLiveAttr, kGenericAccType, kNoReqStates};
1310 nsRoleMapEntry aria::gEmptyRoleMap = {
1311 nsGkAtoms::_empty, roles::TEXT_CONTAINER, kUseMapRole, eNoValue,
1312 eNoAction, eNoLiveAttr, kGenericAccType, kNoReqStates};
1315 * Universal (Global) states:
1316 * The following state rules are applied to any accessible element,
1317 * whether there is an ARIA role or not:
1319 static const EStateRule sWAIUnivStateMap[] = {
1320 eARIABusy, eARIACurrent, eARIADisabled,
1321 eARIAExpanded, // Currently under spec review but precedent exists
1322 eARIAHasPopup, // Note this is a tokenised attribute starting in ARIA 1.1
1323 eARIAInvalid, eARIAModal,
1324 eARIARequired, // XXX not global, Bug 553117
1325 eARIANone};
1328 * ARIA attribute map for attribute characteristics.
1329 * @note ARIA attributes that don't have any flags are not included here.
1332 struct AttrCharacteristics {
1333 const nsStaticAtom* const attributeName;
1334 const uint8_t characteristics;
1337 static const AttrCharacteristics gWAIUnivAttrMap[] = {
1338 // clang-format off
1339 {nsGkAtoms::aria_activedescendant, ATTR_BYPASSOBJ },
1340 {nsGkAtoms::aria_atomic, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL },
1341 {nsGkAtoms::aria_busy, ATTR_VALTOKEN | ATTR_GLOBAL },
1342 {nsGkAtoms::aria_checked, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, /* exposes checkable obj attr */
1343 {nsGkAtoms::aria_controls, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1344 {nsGkAtoms::aria_current, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL },
1345 {nsGkAtoms::aria_describedby, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1346 {nsGkAtoms::aria_details, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1347 {nsGkAtoms::aria_disabled, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
1348 {nsGkAtoms::aria_dropeffect, ATTR_VALTOKEN | ATTR_GLOBAL },
1349 {nsGkAtoms::aria_errormessage, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1350 {nsGkAtoms::aria_expanded, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
1351 {nsGkAtoms::aria_flowto, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1352 {nsGkAtoms::aria_grabbed, ATTR_VALTOKEN | ATTR_GLOBAL },
1353 {nsGkAtoms::aria_haspopup, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL },
1354 {nsGkAtoms::aria_hidden, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, /* handled special way */
1355 {nsGkAtoms::aria_invalid, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
1356 {nsGkAtoms::aria_label, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1357 {nsGkAtoms::aria_labelledby, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1358 {nsGkAtoms::aria_level, ATTR_BYPASSOBJ }, /* handled via groupPosition */
1359 {nsGkAtoms::aria_live, ATTR_VALTOKEN | ATTR_GLOBAL },
1360 {nsGkAtoms::aria_modal, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
1361 {nsGkAtoms::aria_multiline, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
1362 {nsGkAtoms::aria_multiselectable, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
1363 {nsGkAtoms::aria_owns, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1364 {nsGkAtoms::aria_orientation, ATTR_VALTOKEN },
1365 {nsGkAtoms::aria_posinset, ATTR_BYPASSOBJ }, /* handled via groupPosition */
1366 {nsGkAtoms::aria_pressed, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
1367 {nsGkAtoms::aria_readonly, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
1368 {nsGkAtoms::aria_relevant, ATTR_BYPASSOBJ | ATTR_GLOBAL },
1369 {nsGkAtoms::aria_required, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
1370 {nsGkAtoms::aria_selected, ATTR_BYPASSOBJ | ATTR_VALTOKEN },
1371 {nsGkAtoms::aria_setsize, ATTR_BYPASSOBJ }, /* handled via groupPosition */
1372 {nsGkAtoms::aria_sort, ATTR_VALTOKEN },
1373 {nsGkAtoms::aria_valuenow, ATTR_BYPASSOBJ },
1374 {nsGkAtoms::aria_valuemin, ATTR_BYPASSOBJ },
1375 {nsGkAtoms::aria_valuemax, ATTR_BYPASSOBJ },
1376 {nsGkAtoms::aria_valuetext, ATTR_BYPASSOBJ }
1377 // clang-format on
1380 const nsRoleMapEntry* aria::GetRoleMap(dom::Element* aEl) {
1381 return GetRoleMapFromIndex(GetRoleMapIndex(aEl));
1384 uint8_t aria::GetRoleMapIndex(dom::Element* aEl) {
1385 nsAutoString roles;
1386 if (!aEl || !aEl->GetAttr(kNameSpaceID_None, nsGkAtoms::role, roles) ||
1387 roles.IsEmpty()) {
1388 // We treat role="" as if the role attribute is absent (per aria spec:8.1.1)
1389 return NO_ROLE_MAP_ENTRY_INDEX;
1392 nsWhitespaceTokenizer tokenizer(roles);
1393 while (tokenizer.hasMoreTokens()) {
1394 // Do a binary search through table for the next role in role list
1395 const nsDependentSubstring role = tokenizer.nextToken();
1396 size_t idx;
1397 auto comparator = [&role](const nsRoleMapEntry& aEntry) {
1398 return Compare(role, aEntry.ARIARoleString(),
1399 nsCaseInsensitiveStringComparator);
1401 if (BinarySearchIf(sWAIRoleMaps, 0, ArrayLength(sWAIRoleMaps), comparator,
1402 &idx)) {
1403 return idx;
1407 // Always use some entry index if there is a non-empty role string
1408 // To ensure an accessible object is created
1409 return LANDMARK_ROLE_MAP_ENTRY_INDEX;
1412 const nsRoleMapEntry* aria::GetRoleMapFromIndex(uint8_t aRoleMapIndex) {
1413 switch (aRoleMapIndex) {
1414 case NO_ROLE_MAP_ENTRY_INDEX:
1415 return nullptr;
1416 case EMPTY_ROLE_MAP_ENTRY_INDEX:
1417 return &gEmptyRoleMap;
1418 case LANDMARK_ROLE_MAP_ENTRY_INDEX:
1419 return &sLandmarkRoleMap;
1420 default:
1421 return sWAIRoleMaps + aRoleMapIndex;
1425 uint8_t aria::GetIndexFromRoleMap(const nsRoleMapEntry* aRoleMapEntry) {
1426 if (aRoleMapEntry == nullptr) {
1427 return NO_ROLE_MAP_ENTRY_INDEX;
1428 } else if (aRoleMapEntry == &gEmptyRoleMap) {
1429 return EMPTY_ROLE_MAP_ENTRY_INDEX;
1430 } else if (aRoleMapEntry == &sLandmarkRoleMap) {
1431 return LANDMARK_ROLE_MAP_ENTRY_INDEX;
1432 } else {
1433 return aRoleMapEntry - sWAIRoleMaps;
1437 uint64_t aria::UniversalStatesFor(mozilla::dom::Element* aElement) {
1438 uint64_t state = 0;
1439 uint32_t index = 0;
1440 while (MapToState(sWAIUnivStateMap[index], aElement, &state)) index++;
1442 return state;
1445 uint8_t aria::AttrCharacteristicsFor(nsAtom* aAtom) {
1446 for (uint32_t i = 0; i < ArrayLength(gWAIUnivAttrMap); i++) {
1447 if (gWAIUnivAttrMap[i].attributeName == aAtom) {
1448 return gWAIUnivAttrMap[i].characteristics;
1452 return 0;
1455 bool aria::HasDefinedARIAHidden(nsIContent* aContent) {
1456 return aContent && aContent->IsElement() &&
1457 aContent->AsElement()->AttrValueIs(kNameSpaceID_None,
1458 nsGkAtoms::aria_hidden,
1459 nsGkAtoms::_true, eCaseMatters);
1462 ////////////////////////////////////////////////////////////////////////////////
1463 // AttrIterator class
1465 AttrIterator::AttrIterator(nsIContent* aContent)
1466 : mElement(dom::Element::FromNode(aContent)), mAttrIdx(0) {
1467 mAttrCount = mElement ? mElement->GetAttrCount() : 0;
1470 bool AttrIterator::Next(nsAString& aAttrName, nsAString& aAttrValue) {
1471 while (mAttrIdx < mAttrCount) {
1472 const nsAttrName* attr = mElement->GetAttrNameAt(mAttrIdx);
1473 mAttrIdx++;
1474 if (attr->NamespaceEquals(kNameSpaceID_None)) {
1475 nsAtom* attrAtom = attr->Atom();
1476 nsDependentAtomString attrStr(attrAtom);
1477 if (!StringBeginsWith(attrStr, u"aria-"_ns)) continue; // Not ARIA
1479 uint8_t attrFlags = aria::AttrCharacteristicsFor(attrAtom);
1480 if (attrFlags & ATTR_BYPASSOBJ) {
1481 continue; // No need to handle exposing as obj attribute here
1484 if ((attrFlags & ATTR_VALTOKEN) &&
1485 !nsAccUtils::HasDefinedARIAToken(mElement, attrAtom)) {
1486 continue; // only expose token based attributes if they are defined
1489 if ((attrFlags & ATTR_BYPASSOBJ_IF_FALSE) &&
1490 mElement->AttrValueIs(kNameSpaceID_None, attrAtom, nsGkAtoms::_false,
1491 eCaseMatters)) {
1492 continue; // only expose token based attribute if value is not 'false'.
1495 nsAutoString value;
1496 if (mElement->GetAttr(kNameSpaceID_None, attrAtom, value)) {
1497 aAttrName.Assign(Substring(attrStr, 5));
1498 if (attrFlags & ATTR_VALTOKEN) {
1499 nsAtom* normalizedValue =
1500 nsAccUtils::NormalizeARIAToken(mElement, attrAtom);
1501 if (normalizedValue) {
1502 nsDependentAtomString normalizedValueStr(normalizedValue);
1503 aAttrValue.Assign(normalizedValueStr);
1504 return true;
1507 aAttrValue.Assign(value);
1508 return true;
1513 return false;