ARIAMap.cpp (40213B)
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 "AccAttributes.h" 11 #include "nsAccUtils.h" 12 #include "nsCoreUtils.h" 13 #include "mozilla/a11y/Role.h" 14 #include "States.h" 15 16 #include "nsAttrName.h" 17 #include "nsGenericHTMLElement.h" 18 #include "nsWhitespaceTokenizer.h" 19 20 #include "mozilla/BinarySearch.h" 21 #include "mozilla/dom/Document.h" 22 #include "mozilla/dom/Element.h" 23 24 #include "nsUnicharUtils.h" 25 26 using namespace mozilla; 27 using namespace mozilla::a11y; 28 using namespace mozilla::a11y::aria; 29 30 static const uint32_t kGenericAccType = 0; 31 32 /** 33 * This list of WAI-defined roles are currently hardcoded. 34 * Eventually we will most likely be loading an RDF resource that contains this 35 * information Using RDF will also allow for role extensibility. See bug 280138. 36 * 37 * Definition of nsRoleMapEntry contains comments explaining this table. 38 * 39 * When no Role enum mapping exists for an ARIA role, the role will be exposed 40 * via the object attribute "xml-roles". 41 * 42 * Note: the list must remain alphabetically ordered to support binary search. 43 */ 44 45 static const nsRoleMapEntry sWAIRoleMaps[] = { 46 // clang-format off 47 { // alert 48 nsGkAtoms::alert, 49 roles::ALERT, 50 kUseMapRole, 51 eNoValue, 52 eNoAction, 53 #if defined(XP_MACOSX) 54 eAssertiveLiveAttr, 55 #else 56 eNoLiveAttr, 57 #endif 58 eAlert, 59 kNoReqStates 60 }, 61 { // alertdialog 62 nsGkAtoms::alertdialog, 63 roles::DIALOG, 64 kUseMapRole, 65 eNoValue, 66 eNoAction, 67 eNoLiveAttr, 68 kGenericAccType, 69 kNoReqStates 70 }, 71 { // application 72 nsGkAtoms::application, 73 roles::APPLICATION, 74 kUseMapRole, 75 eNoValue, 76 eNoAction, 77 eNoLiveAttr, 78 eLandmark, 79 kNoReqStates 80 }, 81 { // article 82 nsGkAtoms::article, 83 roles::ARTICLE, 84 kUseMapRole, 85 eNoValue, 86 eNoAction, 87 eNoLiveAttr, 88 kGenericAccType, 89 kNoReqStates, 90 eReadonlyUntilEditable 91 }, 92 { // banner 93 nsGkAtoms::banner, 94 roles::LANDMARK, 95 kUseMapRole, 96 eNoValue, 97 eNoAction, 98 eNoLiveAttr, 99 eLandmark, 100 kNoReqStates 101 }, 102 { // blockquote 103 nsGkAtoms::blockquote, 104 roles::BLOCKQUOTE, 105 kUseMapRole, 106 eNoValue, 107 eNoAction, 108 eNoLiveAttr, 109 kGenericAccType, 110 }, 111 { // button 112 nsGkAtoms::button, 113 roles::PUSHBUTTON, 114 kUseMapRole, 115 eNoValue, 116 ePressAction, 117 eNoLiveAttr, 118 eButton, 119 kNoReqStates 120 // eARIAPressed is auto applied on any button 121 }, 122 { // caption 123 nsGkAtoms::caption, 124 roles::CAPTION, 125 kUseMapRole, 126 eNoValue, 127 eNoAction, 128 eNoLiveAttr, 129 kGenericAccType, 130 }, 131 { // cell 132 nsGkAtoms::cell, 133 roles::CELL, 134 kUseMapRole, 135 eNoValue, 136 eNoAction, 137 eNoLiveAttr, 138 eTableCell, 139 kNoReqStates 140 }, 141 { // checkbox 142 nsGkAtoms::checkbox, 143 roles::CHECKBUTTON, 144 kUseMapRole, 145 eNoValue, 146 eCheckUncheckAction, 147 eNoLiveAttr, 148 kGenericAccType, 149 kNoReqStates, 150 eARIACheckableMixed, 151 eARIAReadonly 152 }, 153 { // code 154 nsGkAtoms::code, 155 roles::CODE, 156 kUseMapRole, 157 eNoValue, 158 eNoAction, 159 eNoLiveAttr, 160 kGenericAccType, 161 }, 162 { // columnheader 163 nsGkAtoms::columnheader, 164 roles::COLUMNHEADER, 165 kUseMapRole, 166 eNoValue, 167 eSortAction, 168 eNoLiveAttr, 169 eTableCell, 170 kNoReqStates, 171 eARIASelectableIfDefined, 172 eARIAReadonly 173 }, 174 { // combobox, which consists of text input and popup 175 nsGkAtoms::combobox, 176 roles::EDITCOMBOBOX, 177 kUseMapRole, 178 eNoValue, 179 eOpenCloseAction, 180 eNoLiveAttr, 181 eCombobox, 182 states::EXPANDABLE | states::HASPOPUP, 183 eARIAAutoComplete, 184 eARIAReadonly, 185 eARIAOrientation 186 }, 187 { // comment 188 nsGkAtoms::comment, 189 roles::COMMENT, 190 kUseMapRole, 191 eNoValue, 192 eNoAction, 193 eNoLiveAttr, 194 kGenericAccType, 195 }, 196 { // complementary 197 nsGkAtoms::complementary, 198 roles::LANDMARK, 199 kUseMapRole, 200 eNoValue, 201 eNoAction, 202 eNoLiveAttr, 203 eLandmark, 204 kNoReqStates 205 }, 206 { // contentinfo 207 nsGkAtoms::contentinfo, 208 roles::LANDMARK, 209 kUseMapRole, 210 eNoValue, 211 eNoAction, 212 eNoLiveAttr, 213 eLandmark, 214 kNoReqStates 215 }, 216 { // definition 217 nsGkAtoms::definition, 218 roles::DEFINITION, 219 kUseMapRole, 220 eNoValue, 221 eNoAction, 222 eNoLiveAttr, 223 kGenericAccType, 224 }, 225 { // deletion 226 nsGkAtoms::deletion, 227 roles::CONTENT_DELETION, 228 kUseMapRole, 229 eNoValue, 230 eNoAction, 231 eNoLiveAttr, 232 kGenericAccType, 233 }, 234 { // dialog 235 nsGkAtoms::dialog, 236 roles::DIALOG, 237 kUseMapRole, 238 eNoValue, 239 eNoAction, 240 eNoLiveAttr, 241 kGenericAccType, 242 kNoReqStates 243 }, 244 { // directory 245 nsGkAtoms::directory, 246 roles::LIST, 247 kUseMapRole, 248 eNoValue, 249 eNoAction, 250 eNoLiveAttr, 251 eList, 252 states::READONLY 253 }, 254 { // doc-abstract 255 nsGkAtoms::docAbstract, 256 roles::SECTION, 257 kUseMapRole, 258 eNoValue, 259 eNoAction, 260 eNoLiveAttr, 261 eDPub, 262 kNoReqStates 263 }, 264 { // doc-acknowledgments 265 nsGkAtoms::docAcknowledgments, 266 roles::LANDMARK, 267 kUseMapRole, 268 eNoValue, 269 eNoAction, 270 eNoLiveAttr, 271 eLandmark, 272 kNoReqStates 273 }, 274 { // doc-afterword 275 nsGkAtoms::docAfterword, 276 roles::LANDMARK, 277 kUseMapRole, 278 eNoValue, 279 eNoAction, 280 eNoLiveAttr, 281 eLandmark, 282 kNoReqStates 283 }, 284 { // doc-appendix 285 nsGkAtoms::docAppendix, 286 roles::LANDMARK, 287 kUseMapRole, 288 eNoValue, 289 eNoAction, 290 eNoLiveAttr, 291 eDPub | eLandmark, 292 kNoReqStates 293 }, 294 { // doc-backlink 295 nsGkAtoms::docBacklink, 296 roles::LINK, 297 kUseMapRole, 298 eNoValue, 299 eJumpAction, 300 eNoLiveAttr, 301 eDPub, 302 states::LINKED 303 }, 304 { // doc-biblioentry 305 nsGkAtoms::docBiblioentry, 306 roles::LISTITEM, 307 kUseMapRole, 308 eNoValue, 309 eNoAction, 310 eNoLiveAttr, 311 eDPub, 312 states::READONLY 313 }, 314 { // doc-bibliography 315 nsGkAtoms::docBibliography, 316 roles::LANDMARK, 317 kUseMapRole, 318 eNoValue, 319 eNoAction, 320 eNoLiveAttr, 321 eDPub | eLandmark, 322 kNoReqStates 323 }, 324 { // doc-biblioref 325 nsGkAtoms::docBiblioref, 326 roles::LINK, 327 kUseMapRole, 328 eNoValue, 329 eJumpAction, 330 eNoLiveAttr, 331 eDPub, 332 states::LINKED 333 }, 334 { // doc-chapter 335 nsGkAtoms::docChapter, 336 roles::LANDMARK, 337 kUseMapRole, 338 eNoValue, 339 eNoAction, 340 eNoLiveAttr, 341 eDPub | eLandmark, 342 kNoReqStates 343 }, 344 { // doc-colophon 345 nsGkAtoms::docColophon, 346 roles::SECTION, 347 kUseMapRole, 348 eNoValue, 349 eNoAction, 350 eNoLiveAttr, 351 eDPub, 352 kNoReqStates 353 }, 354 { // doc-conclusion 355 nsGkAtoms::docConclusion, 356 roles::LANDMARK, 357 kUseMapRole, 358 eNoValue, 359 eNoAction, 360 eNoLiveAttr, 361 eDPub | eLandmark, 362 kNoReqStates 363 }, 364 { // doc-cover 365 nsGkAtoms::docCover, 366 roles::GRAPHIC, 367 kUseMapRole, 368 eNoValue, 369 eNoAction, 370 eNoLiveAttr, 371 eDPub, 372 kNoReqStates 373 }, 374 { // doc-credit 375 nsGkAtoms::docCredit, 376 roles::SECTION, 377 kUseMapRole, 378 eNoValue, 379 eNoAction, 380 eNoLiveAttr, 381 eDPub, 382 kNoReqStates 383 }, 384 { // doc-credits 385 nsGkAtoms::docCredits, 386 roles::LANDMARK, 387 kUseMapRole, 388 eNoValue, 389 eNoAction, 390 eNoLiveAttr, 391 eDPub | eLandmark, 392 kNoReqStates 393 }, 394 { // doc-dedication 395 nsGkAtoms::docDedication, 396 roles::SECTION, 397 kUseMapRole, 398 eNoValue, 399 eNoAction, 400 eNoLiveAttr, 401 eDPub, 402 kNoReqStates 403 }, 404 { // doc-endnote 405 nsGkAtoms::docEndnote, 406 roles::LISTITEM, 407 kUseMapRole, 408 eNoValue, 409 eNoAction, 410 eNoLiveAttr, 411 eDPub, 412 states::READONLY 413 }, 414 { // doc-endnotes 415 nsGkAtoms::docEndnotes, 416 roles::LANDMARK, 417 kUseMapRole, 418 eNoValue, 419 eNoAction, 420 eNoLiveAttr, 421 eDPub | eLandmark, 422 kNoReqStates 423 }, 424 { // doc-epigraph 425 nsGkAtoms::docEpigraph, 426 roles::SECTION, 427 kUseMapRole, 428 eNoValue, 429 eNoAction, 430 eNoLiveAttr, 431 eDPub, 432 kNoReqStates 433 }, 434 { // doc-epilogue 435 nsGkAtoms::docEpilogue, 436 roles::LANDMARK, 437 kUseMapRole, 438 eNoValue, 439 eNoAction, 440 eNoLiveAttr, 441 eDPub | eLandmark, 442 kNoReqStates 443 }, 444 { // doc-errata 445 nsGkAtoms::docErrata, 446 roles::LANDMARK, 447 kUseMapRole, 448 eNoValue, 449 eNoAction, 450 eNoLiveAttr, 451 eDPub | eLandmark, 452 kNoReqStates 453 }, 454 { // doc-example 455 nsGkAtoms::docExample, 456 roles::FIGURE, 457 kUseMapRole, 458 eNoValue, 459 eNoAction, 460 eNoLiveAttr, 461 eDPub, 462 kNoReqStates 463 }, 464 { // doc-footnote 465 nsGkAtoms::docFootnote, 466 roles::FOOTNOTE, 467 kUseMapRole, 468 eNoValue, 469 eNoAction, 470 eNoLiveAttr, 471 eDPub | eLandmark, 472 kNoReqStates 473 }, 474 { // doc-foreword 475 nsGkAtoms::docForeword, 476 roles::LANDMARK, 477 kUseMapRole, 478 eNoValue, 479 eNoAction, 480 eNoLiveAttr, 481 eDPub | eLandmark, 482 kNoReqStates 483 }, 484 { // doc-glossary 485 nsGkAtoms::docGlossary, 486 roles::LANDMARK, 487 kUseMapRole, 488 eNoValue, 489 eNoAction, 490 eNoLiveAttr, 491 eDPub | eLandmark, 492 kNoReqStates 493 }, 494 { // doc-glossref 495 nsGkAtoms::docGlossref, 496 roles::LINK, 497 kUseMapRole, 498 eNoValue, 499 eJumpAction, 500 eNoLiveAttr, 501 eDPub, 502 states::LINKED 503 }, 504 { // doc-index 505 nsGkAtoms::docIndex, 506 roles::NAVIGATION, 507 kUseMapRole, 508 eNoValue, 509 eNoAction, 510 eNoLiveAttr, 511 eDPub | eLandmark, 512 kNoReqStates 513 }, 514 { // doc-introduction 515 nsGkAtoms::docIntroduction, 516 roles::LANDMARK, 517 kUseMapRole, 518 eNoValue, 519 eNoAction, 520 eNoLiveAttr, 521 eDPub | eLandmark, 522 kNoReqStates 523 }, 524 { // doc-noteref 525 nsGkAtoms::docNoteref, 526 roles::LINK, 527 kUseMapRole, 528 eNoValue, 529 eJumpAction, 530 eNoLiveAttr, 531 eDPub, 532 states::LINKED 533 }, 534 { // doc-notice 535 nsGkAtoms::docNotice, 536 roles::NOTE, 537 kUseMapRole, 538 eNoValue, 539 eNoAction, 540 eNoLiveAttr, 541 eDPub, 542 kNoReqStates 543 }, 544 { // doc-pagebreak 545 nsGkAtoms::docPagebreak, 546 roles::SEPARATOR, 547 kUseMapRole, 548 eNoValue, 549 eNoAction, 550 eNoLiveAttr, 551 eDPub, 552 kNoReqStates 553 }, 554 { // doc-pagefooter 555 nsGkAtoms::docPagefooter, 556 roles::SECTION, 557 kUseMapRole, 558 eNoValue, 559 eNoAction, 560 eNoLiveAttr, 561 eDPub, 562 kNoReqStates 563 }, 564 { // doc-pageheader 565 nsGkAtoms::docPageheader, 566 roles::SECTION, 567 kUseMapRole, 568 eNoValue, 569 eNoAction, 570 eNoLiveAttr, 571 eDPub, 572 kNoReqStates 573 }, 574 { // doc-pagelist 575 nsGkAtoms::docPagelist, 576 roles::NAVIGATION, 577 kUseMapRole, 578 eNoValue, 579 eNoAction, 580 eNoLiveAttr, 581 eDPub | eLandmark, 582 kNoReqStates 583 }, 584 { // doc-part 585 nsGkAtoms::docPart, 586 roles::LANDMARK, 587 kUseMapRole, 588 eNoValue, 589 eNoAction, 590 eNoLiveAttr, 591 eDPub | eLandmark, 592 kNoReqStates 593 }, 594 { // doc-preface 595 nsGkAtoms::docPreface, 596 roles::LANDMARK, 597 kUseMapRole, 598 eNoValue, 599 eNoAction, 600 eNoLiveAttr, 601 eDPub | eLandmark, 602 kNoReqStates 603 }, 604 { // doc-prologue 605 nsGkAtoms::docPrologue, 606 roles::LANDMARK, 607 kUseMapRole, 608 eNoValue, 609 eNoAction, 610 eNoLiveAttr, 611 eDPub | eLandmark, 612 kNoReqStates 613 }, 614 { // doc-pullquote 615 nsGkAtoms::docPullquote, 616 roles::SECTION, 617 kUseMapRole, 618 eNoValue, 619 eNoAction, 620 eNoLiveAttr, 621 eDPub, 622 kNoReqStates 623 }, 624 { // doc-qna 625 nsGkAtoms::docQna, 626 roles::SECTION, 627 kUseMapRole, 628 eNoValue, 629 eNoAction, 630 eNoLiveAttr, 631 eDPub, 632 kNoReqStates 633 }, 634 { // doc-subtitle 635 nsGkAtoms::docSubtitle, 636 roles::HEADING, 637 kUseMapRole, 638 eNoValue, 639 eNoAction, 640 eNoLiveAttr, 641 eDPub, 642 kNoReqStates 643 }, 644 { // doc-tip 645 nsGkAtoms::docTip, 646 roles::NOTE, 647 kUseMapRole, 648 eNoValue, 649 eNoAction, 650 eNoLiveAttr, 651 eDPub, 652 kNoReqStates 653 }, 654 { // doc-toc 655 nsGkAtoms::docToc, 656 roles::NAVIGATION, 657 kUseMapRole, 658 eNoValue, 659 eNoAction, 660 eNoLiveAttr, 661 eDPub | eLandmark, 662 kNoReqStates 663 }, 664 { // document 665 nsGkAtoms::document, 666 roles::NON_NATIVE_DOCUMENT, 667 kUseMapRole, 668 eNoValue, 669 eNoAction, 670 eNoLiveAttr, 671 kGenericAccType, 672 kNoReqStates, 673 eReadonlyUntilEditable 674 }, 675 { // emphasis 676 nsGkAtoms::emphasis, 677 roles::EMPHASIS, 678 kUseMapRole, 679 eNoValue, 680 eNoAction, 681 eNoLiveAttr, 682 kGenericAccType, 683 kNoReqStates 684 }, 685 { // feed 686 nsGkAtoms::feed, 687 roles::GROUPING, 688 kUseMapRole, 689 eNoValue, 690 eNoAction, 691 eNoLiveAttr, 692 kGenericAccType, 693 kNoReqStates 694 }, 695 { // figure 696 nsGkAtoms::figure, 697 roles::FIGURE, 698 kUseMapRole, 699 eNoValue, 700 eNoAction, 701 eNoLiveAttr, 702 kGenericAccType, 703 kNoReqStates 704 }, 705 { // form 706 nsGkAtoms::form, 707 roles::FORM, 708 kUseMapRole, 709 eNoValue, 710 eNoAction, 711 eNoLiveAttr, 712 eLandmark, 713 kNoReqStates 714 }, 715 { // generic 716 nsGkAtoms::generic, 717 roles::SECTION, 718 kUseMapRole, 719 eNoValue, 720 eNoAction, 721 eNoLiveAttr, 722 kGenericAccType, 723 kNoReqStates 724 }, 725 { // graphics-document 726 nsGkAtoms::graphicsDocument, 727 roles::NON_NATIVE_DOCUMENT, 728 kUseMapRole, 729 eNoValue, 730 eNoAction, 731 eNoLiveAttr, 732 kGenericAccType, 733 kNoReqStates, 734 eReadonlyUntilEditable 735 }, 736 { // graphics-object 737 nsGkAtoms::graphicsObject, 738 roles::GROUPING, 739 kUseMapRole, 740 eNoValue, 741 eNoAction, 742 eNoLiveAttr, 743 kGenericAccType, 744 kNoReqStates 745 }, 746 { // graphics-symbol 747 nsGkAtoms::graphicsSymbol, 748 roles::GRAPHIC, 749 kUseMapRole, 750 eNoValue, 751 eNoAction, 752 eNoLiveAttr, 753 kGenericAccType, 754 kNoReqStates 755 }, 756 { // grid 757 nsGkAtoms::grid, 758 roles::GRID, 759 kUseMapRole, 760 eNoValue, 761 eNoAction, 762 eNoLiveAttr, 763 eSelect | eTable, 764 kNoReqStates, 765 eARIAMultiSelectable, 766 eARIAReadonly, 767 eFocusableUntilDisabled 768 }, 769 { // gridcell 770 nsGkAtoms::gridcell, 771 roles::GRID_CELL, 772 kUseMapRole, 773 eNoValue, 774 eNoAction, 775 eNoLiveAttr, 776 eTableCell, 777 kNoReqStates, 778 eARIASelectable, 779 eARIAReadonly 780 }, 781 { // group 782 nsGkAtoms::group, 783 roles::GROUPING, 784 kUseMapRole, 785 eNoValue, 786 eNoAction, 787 eNoLiveAttr, 788 kGenericAccType, 789 kNoReqStates 790 }, 791 { // heading 792 nsGkAtoms::heading, 793 roles::HEADING, 794 kUseMapRole, 795 eNoValue, 796 eNoAction, 797 eNoLiveAttr, 798 kGenericAccType, 799 kNoReqStates 800 }, 801 { // image 802 nsGkAtoms::image, 803 roles::GRAPHIC, 804 kUseMapRole, 805 eNoValue, 806 eNoAction, 807 eNoLiveAttr, 808 kGenericAccType, 809 kNoReqStates 810 }, 811 { // img 812 nsGkAtoms::img, 813 roles::GRAPHIC, 814 kUseMapRole, 815 eNoValue, 816 eNoAction, 817 eNoLiveAttr, 818 kGenericAccType, 819 kNoReqStates 820 }, 821 { // insertion 822 nsGkAtoms::insertion, 823 roles::CONTENT_INSERTION, 824 kUseMapRole, 825 eNoValue, 826 eNoAction, 827 eNoLiveAttr, 828 kGenericAccType, 829 }, 830 { // key 831 nsGkAtoms::key, 832 roles::KEY, 833 kUseMapRole, 834 eNoValue, 835 ePressAction, 836 eNoLiveAttr, 837 kGenericAccType, 838 kNoReqStates, 839 eARIAPressed 840 }, 841 { // link 842 nsGkAtoms::link, 843 roles::LINK, 844 kUseMapRole, 845 eNoValue, 846 eJumpAction, 847 eNoLiveAttr, 848 kGenericAccType, 849 states::LINKED 850 }, 851 { // list 852 nsGkAtoms::list, 853 roles::LIST, 854 kUseMapRole, 855 eNoValue, 856 eNoAction, 857 eNoLiveAttr, 858 eList, 859 states::READONLY 860 }, 861 { // listbox 862 nsGkAtoms::listbox, 863 roles::LISTBOX, 864 kUseMapRole, 865 eNoValue, 866 eNoAction, 867 eNoLiveAttr, 868 eListControl | eSelect, 869 states::VERTICAL, 870 eARIAMultiSelectable, 871 eARIAReadonly, 872 eFocusableUntilDisabled, 873 eARIAOrientation 874 }, 875 { // listitem 876 nsGkAtoms::listitem, 877 roles::LISTITEM, 878 kUseMapRole, 879 eNoValue, 880 eNoAction, // XXX: should depend on state, parent accessible 881 eNoLiveAttr, 882 kGenericAccType, 883 states::READONLY 884 }, 885 { // log 886 nsGkAtoms::log, 887 roles::NOTHING, 888 kUseNativeRole, 889 eNoValue, 890 eNoAction, 891 ePoliteLiveAttr, 892 kGenericAccType, 893 kNoReqStates 894 }, 895 { // main 896 nsGkAtoms::main, 897 roles::LANDMARK, 898 kUseMapRole, 899 eNoValue, 900 eNoAction, 901 eNoLiveAttr, 902 eLandmark, 903 kNoReqStates 904 }, 905 { // mark 906 nsGkAtoms::mark, 907 roles::MARK, 908 kUseMapRole, 909 eNoValue, 910 eNoAction, 911 eNoLiveAttr, 912 kGenericAccType, 913 }, 914 { // marquee 915 nsGkAtoms::marquee, 916 roles::ANIMATION, 917 kUseMapRole, 918 eNoValue, 919 eNoAction, 920 eOffLiveAttr, 921 kGenericAccType, 922 kNoReqStates 923 }, 924 { // math 925 nsGkAtoms::math, 926 roles::FLAT_EQUATION, 927 kUseMapRole, 928 eNoValue, 929 eNoAction, 930 eNoLiveAttr, 931 kGenericAccType, 932 kNoReqStates 933 }, 934 { // menu 935 nsGkAtoms::menu, 936 roles::MENUPOPUP, 937 kUseMapRole, 938 eNoValue, 939 eNoAction, // XXX: technically accessibles of menupopup role haven't 940 // any action, but menu can be open or close. 941 eNoLiveAttr, 942 kGenericAccType, 943 states::VERTICAL, 944 eARIAOrientation 945 }, 946 { // menubar 947 nsGkAtoms::menubar, 948 roles::MENUBAR, 949 kUseMapRole, 950 eNoValue, 951 eNoAction, 952 eNoLiveAttr, 953 kGenericAccType, 954 states::HORIZONTAL, 955 eARIAOrientation 956 }, 957 { // menuitem 958 nsGkAtoms::menuitem, 959 roles::MENUITEM, 960 kUseMapRole, 961 eNoValue, 962 eClickAction, 963 eNoLiveAttr, 964 kGenericAccType, 965 kNoReqStates 966 }, 967 { // menuitemcheckbox 968 nsGkAtoms::menuitemcheckbox, 969 roles::CHECK_MENU_ITEM, 970 kUseMapRole, 971 eNoValue, 972 eClickAction, 973 eNoLiveAttr, 974 kGenericAccType, 975 kNoReqStates, 976 eARIACheckableMixed, 977 eARIAReadonly 978 }, 979 { // menuitemradio 980 nsGkAtoms::menuitemradio, 981 roles::RADIO_MENU_ITEM, 982 kUseMapRole, 983 eNoValue, 984 eClickAction, 985 eNoLiveAttr, 986 kGenericAccType, 987 kNoReqStates, 988 eARIACheckableBool, 989 eARIAReadonly 990 }, 991 { // meter 992 nsGkAtoms::meter, 993 roles::METER, 994 kUseMapRole, 995 eHasValueMinMax, 996 eNoAction, 997 eNoLiveAttr, 998 kGenericAccType, 999 states::READONLY 1000 }, 1001 { // navigation 1002 nsGkAtoms::navigation, 1003 roles::LANDMARK, 1004 kUseMapRole, 1005 eNoValue, 1006 eNoAction, 1007 eNoLiveAttr, 1008 eLandmark, 1009 kNoReqStates 1010 }, 1011 { // none 1012 nsGkAtoms::none, 1013 roles::NOTHING, 1014 kUseMapRole, 1015 eNoValue, 1016 eNoAction, 1017 eNoLiveAttr, 1018 kGenericAccType, 1019 kNoReqStates 1020 }, 1021 { // note 1022 nsGkAtoms::note, 1023 roles::NOTE, 1024 kUseMapRole, 1025 eNoValue, 1026 eNoAction, 1027 eNoLiveAttr, 1028 kGenericAccType, 1029 kNoReqStates 1030 }, 1031 { // option 1032 nsGkAtoms::option, 1033 roles::OPTION, 1034 kUseMapRole, 1035 eNoValue, 1036 eSelectAction, 1037 eNoLiveAttr, 1038 kGenericAccType, 1039 kNoReqStates, 1040 eARIASelectable, 1041 eARIACheckedMixed 1042 }, 1043 { // paragraph 1044 nsGkAtoms::paragraph, 1045 roles::PARAGRAPH, 1046 kUseMapRole, 1047 eNoValue, 1048 eNoAction, 1049 eNoLiveAttr, 1050 kGenericAccType, 1051 }, 1052 { // presentation 1053 nsGkAtoms::presentation, 1054 roles::NOTHING, 1055 kUseMapRole, 1056 eNoValue, 1057 eNoAction, 1058 eNoLiveAttr, 1059 kGenericAccType, 1060 kNoReqStates 1061 }, 1062 { // progressbar 1063 nsGkAtoms::progressbar, 1064 roles::PROGRESSBAR, 1065 kUseMapRole, 1066 eHasValueMinMax, 1067 eNoAction, 1068 eNoLiveAttr, 1069 kGenericAccType, 1070 states::READONLY, 1071 eIndeterminateIfNoValue 1072 }, 1073 { // radio 1074 nsGkAtoms::radio, 1075 roles::RADIOBUTTON, 1076 kUseMapRole, 1077 eNoValue, 1078 eSelectAction, 1079 eNoLiveAttr, 1080 kGenericAccType, 1081 kNoReqStates, 1082 eARIACheckableBool 1083 }, 1084 { // radiogroup 1085 nsGkAtoms::radiogroup, 1086 roles::RADIO_GROUP, 1087 kUseMapRole, 1088 eNoValue, 1089 eNoAction, 1090 eNoLiveAttr, 1091 kGenericAccType, 1092 kNoReqStates, 1093 eARIAOrientation, 1094 eARIAReadonly 1095 }, 1096 { // region 1097 nsGkAtoms::region, 1098 roles::REGION, 1099 kUseMapRole, 1100 eNoValue, 1101 eNoAction, 1102 eNoLiveAttr, 1103 eLandmark, 1104 kNoReqStates 1105 }, 1106 { // row 1107 nsGkAtoms::row, 1108 roles::ROW, 1109 kUseMapRole, 1110 eNoValue, 1111 eNoAction, 1112 eNoLiveAttr, 1113 eTableRow, 1114 kNoReqStates, 1115 eARIASelectable 1116 }, 1117 { // rowgroup 1118 nsGkAtoms::rowgroup, 1119 roles::ROWGROUP, 1120 kUseMapRole, 1121 eNoValue, 1122 eNoAction, 1123 eNoLiveAttr, 1124 kGenericAccType, 1125 kNoReqStates 1126 }, 1127 { // rowheader 1128 nsGkAtoms::rowheader, 1129 roles::ROWHEADER, 1130 kUseMapRole, 1131 eNoValue, 1132 eSortAction, 1133 eNoLiveAttr, 1134 eTableCell, 1135 kNoReqStates, 1136 eARIASelectableIfDefined, 1137 eARIAReadonly 1138 }, 1139 { // scrollbar 1140 nsGkAtoms::scrollbar, 1141 roles::SCROLLBAR, 1142 kUseMapRole, 1143 eHasValueMinMax, 1144 eNoAction, 1145 eNoLiveAttr, 1146 kGenericAccType, 1147 states::VERTICAL, 1148 eARIAOrientation, 1149 eARIAReadonly 1150 }, 1151 { // search 1152 nsGkAtoms::search, 1153 roles::LANDMARK, 1154 kUseMapRole, 1155 eNoValue, 1156 eNoAction, 1157 eNoLiveAttr, 1158 eLandmark, 1159 kNoReqStates 1160 }, 1161 { // searchbox 1162 nsGkAtoms::searchbox, 1163 roles::SEARCHBOX, 1164 kUseMapRole, 1165 eNoValue, 1166 eActivateAction, 1167 eNoLiveAttr, 1168 kGenericAccType, 1169 kNoReqStates, 1170 eARIAAutoComplete, 1171 eARIAMultiline, 1172 eARIAReadonlyOrEditable 1173 }, 1174 { // separator 1175 nsGkAtoms::separator, 1176 roles::SEPARATOR, 1177 kUseMapRole, 1178 eHasValueMinMaxIfFocusable, 1179 eNoAction, 1180 eNoLiveAttr, 1181 kGenericAccType, 1182 states::HORIZONTAL, 1183 eARIAOrientation 1184 }, 1185 { // slider 1186 nsGkAtoms::slider, 1187 roles::SLIDER, 1188 kUseMapRole, 1189 eHasValueMinMax, 1190 eNoAction, 1191 eNoLiveAttr, 1192 kGenericAccType, 1193 states::HORIZONTAL, 1194 eARIAOrientation, 1195 eARIAReadonly 1196 }, 1197 { // spinbutton 1198 nsGkAtoms::spinbutton, 1199 roles::SPINBUTTON, 1200 kUseMapRole, 1201 eHasValueMinMax, 1202 eNoAction, 1203 eNoLiveAttr, 1204 kGenericAccType, 1205 kNoReqStates, 1206 eARIAReadonly 1207 }, 1208 { // status 1209 nsGkAtoms::status, 1210 roles::STATUSBAR, 1211 kUseMapRole, 1212 eNoValue, 1213 eNoAction, 1214 ePoliteLiveAttr, 1215 kGenericAccType, 1216 kNoReqStates 1217 }, 1218 { // strong 1219 nsGkAtoms::strong, 1220 roles::STRONG, 1221 kUseMapRole, 1222 eNoValue, 1223 eNoAction, 1224 eNoLiveAttr, 1225 kGenericAccType, 1226 kNoReqStates 1227 }, 1228 { // subscript 1229 nsGkAtoms::subscript, 1230 roles::SUBSCRIPT, 1231 kUseMapRole, 1232 eNoValue, 1233 eNoAction, 1234 eNoLiveAttr, 1235 kGenericAccType 1236 }, 1237 { // suggestion 1238 nsGkAtoms::suggestion, 1239 roles::SUGGESTION, 1240 kUseMapRole, 1241 eNoValue, 1242 eNoAction, 1243 eNoLiveAttr, 1244 kGenericAccType, 1245 }, 1246 { // superscript 1247 nsGkAtoms::superscript, 1248 roles::SUPERSCRIPT, 1249 kUseMapRole, 1250 eNoValue, 1251 eNoAction, 1252 eNoLiveAttr, 1253 kGenericAccType 1254 }, 1255 { // switch 1256 nsGkAtoms::svgSwitch, 1257 roles::SWITCH, 1258 kUseMapRole, 1259 eNoValue, 1260 eCheckUncheckAction, 1261 eNoLiveAttr, 1262 kGenericAccType, 1263 kNoReqStates, 1264 eARIACheckableBool, 1265 eARIAReadonly 1266 }, 1267 { // tab 1268 nsGkAtoms::tab, 1269 roles::PAGETAB, 1270 kUseMapRole, 1271 eNoValue, 1272 eSwitchAction, 1273 eNoLiveAttr, 1274 kGenericAccType, 1275 kNoReqStates, 1276 eARIASelectable 1277 }, 1278 { // table 1279 nsGkAtoms::table, 1280 roles::TABLE, 1281 kUseMapRole, 1282 eNoValue, 1283 eNoAction, 1284 eNoLiveAttr, 1285 eTable, 1286 kNoReqStates, 1287 eARIASelectable 1288 }, 1289 { // tablist 1290 nsGkAtoms::tablist, 1291 roles::PAGETABLIST, 1292 kUseMapRole, 1293 eNoValue, 1294 eNoAction, 1295 eNoLiveAttr, 1296 eSelect, 1297 states::HORIZONTAL, 1298 eARIAOrientation, 1299 eARIAMultiSelectable 1300 }, 1301 { // tabpanel 1302 nsGkAtoms::tabpanel, 1303 roles::PROPERTYPAGE, 1304 kUseMapRole, 1305 eNoValue, 1306 eNoAction, 1307 eNoLiveAttr, 1308 kGenericAccType, 1309 kNoReqStates 1310 }, 1311 { // term 1312 nsGkAtoms::term, 1313 roles::TERM, 1314 kUseMapRole, 1315 eNoValue, 1316 eNoAction, 1317 eNoLiveAttr, 1318 kGenericAccType, 1319 states::READONLY 1320 }, 1321 { // textbox 1322 nsGkAtoms::textbox, 1323 roles::ENTRY, 1324 kUseMapRole, 1325 eNoValue, 1326 eActivateAction, 1327 eNoLiveAttr, 1328 kGenericAccType, 1329 kNoReqStates, 1330 eARIAAutoComplete, 1331 eARIAMultiline, 1332 eARIAReadonlyOrEditable 1333 }, 1334 { // time 1335 nsGkAtoms::time, 1336 roles::TIME, 1337 kUseMapRole, 1338 eNoValue, 1339 eNoAction, 1340 eNoLiveAttr, 1341 kNoReqStates 1342 }, 1343 { // timer 1344 nsGkAtoms::timer, 1345 roles::NOTHING, 1346 kUseNativeRole, 1347 eNoValue, 1348 eNoAction, 1349 eOffLiveAttr, 1350 kNoReqStates 1351 }, 1352 { // toolbar 1353 nsGkAtoms::toolbar, 1354 roles::TOOLBAR, 1355 kUseMapRole, 1356 eNoValue, 1357 eNoAction, 1358 eNoLiveAttr, 1359 kGenericAccType, 1360 states::HORIZONTAL, 1361 eARIAOrientation 1362 }, 1363 { // tooltip 1364 nsGkAtoms::tooltip, 1365 roles::TOOLTIP, 1366 kUseMapRole, 1367 eNoValue, 1368 eNoAction, 1369 eNoLiveAttr, 1370 kGenericAccType, 1371 kNoReqStates 1372 }, 1373 { // tree 1374 nsGkAtoms::tree, 1375 roles::OUTLINE, 1376 kUseMapRole, 1377 eNoValue, 1378 eNoAction, 1379 eNoLiveAttr, 1380 eSelect, 1381 states::VERTICAL, 1382 eARIAReadonly, 1383 eARIAMultiSelectable, 1384 eFocusableUntilDisabled, 1385 eARIAOrientation 1386 }, 1387 { // treegrid 1388 nsGkAtoms::treegrid, 1389 roles::TREE_TABLE, 1390 kUseMapRole, 1391 eNoValue, 1392 eNoAction, 1393 eNoLiveAttr, 1394 eSelect | eTable, 1395 kNoReqStates, 1396 eARIAReadonly, 1397 eARIAMultiSelectable, 1398 eFocusableUntilDisabled, 1399 eARIAOrientation 1400 }, 1401 { // treeitem 1402 nsGkAtoms::treeitem, 1403 roles::OUTLINEITEM, 1404 kUseMapRole, 1405 eNoValue, 1406 eActivateAction, // XXX: should expose second 'expand/collapse' action based 1407 // on states 1408 eNoLiveAttr, 1409 kGenericAccType, 1410 kNoReqStates, 1411 eARIASelectable, 1412 eARIACheckedMixed 1413 } 1414 // clang-format on 1415 }; 1416 1417 static const nsRoleMapEntry sLandmarkRoleMap = { 1418 nsGkAtoms::_empty, roles::NOTHING, kUseNativeRole, eNoValue, 1419 eNoAction, eNoLiveAttr, kGenericAccType, kNoReqStates}; 1420 1421 nsRoleMapEntry aria::gEmptyRoleMap = { 1422 nsGkAtoms::_empty, roles::TEXT_CONTAINER, kUseMapRole, eNoValue, 1423 eNoAction, eNoLiveAttr, kGenericAccType, kNoReqStates}; 1424 1425 /** 1426 * Universal (Global) states: 1427 * The following state rules are applied to any accessible element, 1428 * whether there is an ARIA role or not: 1429 */ 1430 static const EStateRule sWAIUnivStateMap[] = { 1431 eARIABusy, eARIACurrent, eARIADisabled, 1432 eARIAExpanded, // Currently under spec review but precedent exists 1433 eARIAHasPopup, // Note this is a tokenised attribute starting in ARIA 1.1 1434 eARIAInvalid, eARIAModal, 1435 eARIARequired, // XXX not global, Bug 553117 1436 eARIANone}; 1437 1438 /** 1439 * ARIA attribute map for attribute characteristics. 1440 * @note ARIA attributes that don't have any flags are not included here. 1441 */ 1442 1443 struct AttrCharacteristics { 1444 const nsStaticAtom* const attributeName; 1445 const uint8_t characteristics; 1446 }; 1447 1448 static const AttrCharacteristics gWAIUnivAttrMap[] = { 1449 // clang-format off 1450 {nsGkAtoms::aria_actions, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, 1451 {nsGkAtoms::aria_activedescendant, ATTR_BYPASSOBJ }, 1452 {nsGkAtoms::aria_atomic, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL }, 1453 {nsGkAtoms::aria_busy, ATTR_VALTOKEN | ATTR_GLOBAL }, 1454 {nsGkAtoms::aria_checked, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, /* exposes checkable obj attr */ 1455 {nsGkAtoms::aria_colcount, ATTR_VALINT }, 1456 {nsGkAtoms::aria_colindex, ATTR_VALINT }, 1457 {nsGkAtoms::aria_controls, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, 1458 {nsGkAtoms::aria_current, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL }, 1459 {nsGkAtoms::aria_describedby, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, 1460 // XXX Ideally, aria-description shouldn't expose a description object 1461 // attribute (i.e. it should have ATTR_BYPASSOBJ). However, until the 1462 // description-from attribute is implemented (bug 1726087), clients such as 1463 // NVDA depend on the description object attribute to work out whether the 1464 // accDescription originated from aria-description. 1465 {nsGkAtoms::aria_description, ATTR_GLOBAL }, 1466 {nsGkAtoms::aria_details, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, 1467 {nsGkAtoms::aria_disabled, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, 1468 {nsGkAtoms::aria_dropeffect, ATTR_VALTOKEN | ATTR_GLOBAL }, 1469 {nsGkAtoms::aria_errormessage, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, 1470 {nsGkAtoms::aria_expanded, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, 1471 {nsGkAtoms::aria_flowto, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, 1472 {nsGkAtoms::aria_grabbed, ATTR_VALTOKEN | ATTR_GLOBAL }, 1473 {nsGkAtoms::aria_haspopup, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL }, 1474 {nsGkAtoms::aria_hidden, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, /* handled special way */ 1475 {nsGkAtoms::aria_invalid, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, 1476 {nsGkAtoms::aria_label, ATTR_BYPASSOBJ | ATTR_GLOBAL }, 1477 {nsGkAtoms::aria_labelledby, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, 1478 {nsGkAtoms::aria_level, ATTR_BYPASSOBJ }, /* handled via groupPosition */ 1479 {nsGkAtoms::aria_live, ATTR_VALTOKEN | ATTR_GLOBAL }, 1480 {nsGkAtoms::aria_modal, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, 1481 {nsGkAtoms::aria_multiline, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, 1482 {nsGkAtoms::aria_multiselectable, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, 1483 {nsGkAtoms::aria_owns, ATTR_BYPASSOBJ | ATTR_GLOBAL | ATTR_REFLECT_ELEMENTS }, 1484 {nsGkAtoms::aria_orientation, ATTR_VALTOKEN }, 1485 {nsGkAtoms::aria_posinset, ATTR_BYPASSOBJ }, /* handled via groupPosition */ 1486 {nsGkAtoms::aria_pressed, ATTR_VALTOKEN }, 1487 {nsGkAtoms::aria_readonly, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, 1488 {nsGkAtoms::aria_relevant, ATTR_GLOBAL }, 1489 {nsGkAtoms::aria_required, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, 1490 {nsGkAtoms::aria_rowcount, ATTR_VALINT }, 1491 {nsGkAtoms::aria_rowindex, ATTR_VALINT }, 1492 {nsGkAtoms::aria_selected, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, 1493 {nsGkAtoms::aria_setsize, ATTR_BYPASSOBJ }, /* handled via groupPosition */ 1494 {nsGkAtoms::aria_sort, ATTR_VALTOKEN }, 1495 {nsGkAtoms::aria_valuenow, ATTR_BYPASSOBJ }, 1496 {nsGkAtoms::aria_valuemin, ATTR_BYPASSOBJ }, 1497 {nsGkAtoms::aria_valuemax, ATTR_BYPASSOBJ }, 1498 {nsGkAtoms::aria_valuetext, ATTR_BYPASSOBJ } 1499 // clang-format on 1500 }; 1501 1502 const nsRoleMapEntry* aria::GetRoleMap(dom::Element* aEl) { 1503 return GetRoleMapFromIndex(GetRoleMapIndex(aEl)); 1504 } 1505 1506 uint8_t aria::GetFirstValidRoleMapIndexExcluding( 1507 const nsString& aRoleAttrValue, 1508 std::initializer_list<nsStaticAtom*> aRolesToSkip) { 1509 if (aRoleAttrValue.IsEmpty()) { 1510 // We treat role="" as if the role attribute is absent (per aria spec:8.1.1) 1511 return NO_ROLE_MAP_ENTRY_INDEX; 1512 } 1513 1514 nsWhitespaceTokenizer tokenizer(aRoleAttrValue); 1515 while (tokenizer.hasMoreTokens()) { 1516 // Do a binary search through table for the next role in role list 1517 const nsDependentSubstring role = tokenizer.nextToken(); 1518 1519 // Skip any roles that we aren't interested in. 1520 bool shouldSkip = false; 1521 for (nsStaticAtom* atomRole : aRolesToSkip) { 1522 if (role.Equals(atomRole->GetUTF16String(), 1523 nsCaseInsensitiveStringComparator)) { 1524 shouldSkip = true; 1525 break; 1526 } 1527 } 1528 if (shouldSkip) { 1529 continue; 1530 } 1531 1532 size_t idx; 1533 auto comparator = [&role](const nsRoleMapEntry& aEntry) { 1534 return Compare(role, aEntry.ARIARoleString(), 1535 nsCaseInsensitiveStringComparator); 1536 }; 1537 if (BinarySearchIf(sWAIRoleMaps, 0, std::size(sWAIRoleMaps), comparator, 1538 &idx)) { 1539 return idx; 1540 } 1541 } 1542 1543 // Always use some entry index if there is a non-empty role string 1544 // To ensure an accessible object is created 1545 return LANDMARK_ROLE_MAP_ENTRY_INDEX; 1546 } 1547 1548 uint8_t aria::GetRoleMapIndex(dom::Element* aEl) { 1549 nsAutoString roles; 1550 if (!aEl || !nsAccUtils::GetARIAAttr(aEl, nsGkAtoms::role, roles)) { 1551 return NO_ROLE_MAP_ENTRY_INDEX; 1552 } 1553 1554 // Get the rolemap index of the first valid role, excluding nothing. 1555 return GetFirstValidRoleMapIndexExcluding(roles, {}); 1556 } 1557 1558 const nsRoleMapEntry* aria::GetRoleMapFromIndex(uint8_t aRoleMapIndex) { 1559 switch (aRoleMapIndex) { 1560 case NO_ROLE_MAP_ENTRY_INDEX: 1561 return nullptr; 1562 case EMPTY_ROLE_MAP_ENTRY_INDEX: 1563 return &gEmptyRoleMap; 1564 case LANDMARK_ROLE_MAP_ENTRY_INDEX: 1565 return &sLandmarkRoleMap; 1566 default: 1567 return sWAIRoleMaps + aRoleMapIndex; 1568 } 1569 } 1570 1571 uint8_t aria::GetIndexFromRoleMap(const nsRoleMapEntry* aRoleMapEntry) { 1572 if (aRoleMapEntry == nullptr) { 1573 return NO_ROLE_MAP_ENTRY_INDEX; 1574 } else if (aRoleMapEntry == &gEmptyRoleMap) { 1575 return EMPTY_ROLE_MAP_ENTRY_INDEX; 1576 } else if (aRoleMapEntry == &sLandmarkRoleMap) { 1577 return LANDMARK_ROLE_MAP_ENTRY_INDEX; 1578 } else { 1579 uint8_t index = aRoleMapEntry - sWAIRoleMaps; 1580 MOZ_ASSERT(aria::IsRoleMapIndexValid(index)); 1581 return index; 1582 } 1583 } 1584 1585 bool aria::IsRoleMapIndexValid(uint8_t aRoleMapIndex) { 1586 switch (aRoleMapIndex) { 1587 case NO_ROLE_MAP_ENTRY_INDEX: 1588 case EMPTY_ROLE_MAP_ENTRY_INDEX: 1589 case LANDMARK_ROLE_MAP_ENTRY_INDEX: 1590 return true; 1591 } 1592 return aRoleMapIndex < std::size(sWAIRoleMaps); 1593 } 1594 1595 uint64_t aria::UniversalStatesFor(mozilla::dom::Element* aElement) { 1596 uint64_t state = 0; 1597 uint32_t index = 0; 1598 while (MapToState(sWAIUnivStateMap[index], aElement, &state)) index++; 1599 1600 return state; 1601 } 1602 1603 uint8_t aria::AttrCharacteristicsFor(nsAtom* aAtom) { 1604 for (uint32_t i = 0; i < std::size(gWAIUnivAttrMap); i++) { 1605 if (gWAIUnivAttrMap[i].attributeName == aAtom) { 1606 return gWAIUnivAttrMap[i].characteristics; 1607 } 1608 } 1609 1610 return 0; 1611 } 1612 1613 bool aria::IsValidARIAHidden(nsIContent* aContent) { 1614 return aContent && aContent->IsElement() && 1615 nsAccUtils::ARIAAttrValueIs(aContent->AsElement(), 1616 nsGkAtoms::aria_hidden, nsGkAtoms::_true, 1617 eCaseMatters) && 1618 !ShouldIgnoreARIAHidden(aContent); 1619 } 1620 1621 bool aria::IsValidARIAHidden(DocAccessible* aDocAcc) { 1622 nsCOMPtr<nsIContent> docContent = aDocAcc->GetContent(); 1623 // First, check if our Doc Accessible has aria-hidden set on its content 1624 bool isValid = IsValidARIAHidden(docContent); 1625 1626 // If our Doc Accessible was created using an element other than the 1627 // root element, we need to verify the validity of any aria-hidden on 1628 // the root element as well. 1629 auto* rootElement = aDocAcc->DocumentNode()->GetRootElement(); 1630 if (docContent != rootElement) { 1631 isValid |= IsValidARIAHidden(rootElement); 1632 } 1633 1634 return isValid; 1635 } 1636 1637 bool aria::ShouldIgnoreARIAHidden(nsIContent* aContent) { 1638 if (!aContent) { 1639 return false; 1640 } 1641 1642 dom::Document* doc = aContent->OwnerDoc(); 1643 bool isValidElementType = (aContent == doc->GetDocumentElement()); 1644 1645 if (auto docBody = doc->GetBody()) { 1646 isValidElementType |= (aContent == docBody->AsContent()); 1647 } 1648 1649 return isValidElementType && doc->IsTopLevelContentDocument(); 1650 } 1651 1652 const nsRoleMapEntry* aria::GetRoleMap(const nsStaticAtom* aAriaRole) { 1653 const nsDependentAtomString role(aAriaRole); 1654 auto comparator = [&role](const nsRoleMapEntry& aEntry) { 1655 return Compare(role, aEntry.ARIARoleString()); 1656 }; 1657 size_t idx; 1658 if (BinarySearchIf(sWAIRoleMaps, 0, std::size(sWAIRoleMaps), comparator, 1659 &idx)) { 1660 return GetRoleMapFromIndex(idx); 1661 } 1662 return nullptr; 1663 } 1664 1665 //////////////////////////////////////////////////////////////////////////////// 1666 // AttrIterator class 1667 1668 AttrIterator::AttrIterator(nsIContent* aContent) 1669 : mElement(dom::Element::FromNode(aContent)), 1670 mIteratingDefaults(false), 1671 mAttrIdx(0), 1672 mAttrCharacteristics(0) { 1673 mAttrs = mElement ? &mElement->GetAttrs() : nullptr; 1674 mAttrCount = mAttrs ? mAttrs->AttrCount() : 0; 1675 } 1676 1677 bool AttrIterator::Next() { 1678 while (mAttrIdx < mAttrCount) { 1679 const nsAttrName* attr = mAttrs->GetSafeAttrNameAt(mAttrIdx); 1680 mAttrIdx++; 1681 if (attr->NamespaceEquals(kNameSpaceID_None)) { 1682 mAttrAtom = attr->Atom(); 1683 nsDependentAtomString attrStr(mAttrAtom); 1684 if (!StringBeginsWith(attrStr, u"aria-"_ns)) continue; // Not ARIA 1685 1686 if (mIteratingDefaults) { 1687 if (mOverriddenAttrs.Contains(mAttrAtom)) { 1688 continue; 1689 } 1690 } else { 1691 mOverriddenAttrs.Insert(mAttrAtom); 1692 } 1693 1694 // AttrCharacteristicsFor has to search for the entry, so cache it here 1695 // rather than having to search again later. 1696 mAttrCharacteristics = aria::AttrCharacteristicsFor(mAttrAtom); 1697 if (mAttrCharacteristics & ATTR_BYPASSOBJ) { 1698 continue; // No need to handle exposing as obj attribute here 1699 } 1700 1701 if ((mAttrCharacteristics & ATTR_VALTOKEN) && 1702 !nsAccUtils::HasDefinedARIAToken(mAttrs, mAttrAtom)) { 1703 continue; // only expose token based attributes if they are defined 1704 } 1705 1706 if ((mAttrCharacteristics & ATTR_BYPASSOBJ_IF_FALSE) && 1707 mAttrs->AttrValueIs(kNameSpaceID_None, mAttrAtom, nsGkAtoms::_false, 1708 eCaseMatters)) { 1709 continue; // only expose token based attribute if value is not 'false'. 1710 } 1711 1712 return true; 1713 } 1714 } 1715 1716 mAttrCharacteristics = 0; 1717 mAttrAtom = nullptr; 1718 1719 if (const auto* defaults = nsAccUtils::GetARIADefaults(mElement); 1720 !mIteratingDefaults && defaults) { 1721 mIteratingDefaults = true; 1722 mAttrs = defaults; 1723 mAttrCount = mAttrs->AttrCount(); 1724 mAttrIdx = 0; 1725 return Next(); 1726 } 1727 1728 return false; 1729 } 1730 1731 nsAtom* AttrIterator::AttrName() const { return mAttrAtom; } 1732 1733 void AttrIterator::AttrValue(nsAString& aAttrValue) const { 1734 nsAutoString value; 1735 if (mAttrs->GetAttr(mAttrAtom, value)) { 1736 if (mAttrCharacteristics & ATTR_VALTOKEN) { 1737 nsAtom* normalizedValue = 1738 nsAccUtils::NormalizeARIAToken(mAttrs, mAttrAtom); 1739 if (normalizedValue) { 1740 nsDependentAtomString normalizedValueStr(normalizedValue); 1741 aAttrValue.Assign(normalizedValueStr); 1742 return; 1743 } 1744 } 1745 aAttrValue.Assign(value); 1746 } 1747 } 1748 1749 bool AttrIterator::ExposeAttr(AccAttributes* aTargetAttrs) const { 1750 if (mAttrCharacteristics & ATTR_VALTOKEN) { 1751 nsAtom* normalizedValue = nsAccUtils::NormalizeARIAToken(mAttrs, mAttrAtom); 1752 if (normalizedValue) { 1753 aTargetAttrs->SetAttribute(mAttrAtom, normalizedValue); 1754 return true; 1755 } 1756 } else if (mAttrCharacteristics & ATTR_VALINT) { 1757 int32_t intVal; 1758 if (nsCoreUtils::GetUIntAttrValue(mAttrs->GetAttr(mAttrAtom), &intVal)) { 1759 aTargetAttrs->SetAttribute(mAttrAtom, intVal); 1760 return true; 1761 } 1762 if (mAttrAtom == nsGkAtoms::aria_colcount || 1763 mAttrAtom == nsGkAtoms::aria_rowcount) { 1764 // These attributes allow a value of -1. 1765 if (mAttrs->AttrValueIs(kNameSpaceID_None, mAttrAtom, u"-1"_ns, 1766 eCaseMatters)) { 1767 aTargetAttrs->SetAttribute(mAttrAtom, -1); 1768 return true; 1769 } 1770 } 1771 return false; // Invalid value. 1772 } 1773 nsAutoString value; 1774 if (mAttrs->GetAttr(mAttrAtom, value)) { 1775 aTargetAttrs->SetAttribute(mAttrAtom, std::move(value)); 1776 return true; 1777 } 1778 return false; 1779 } 1780 1781 //////////////////////////////////////////////////////////////////////////////// 1782 // AttrWithCharacteristicsIterator class 1783 bool AttrWithCharacteristicsIterator::Next() { 1784 for (mIdx++; mIdx < static_cast<int32_t>(std::size(gWAIUnivAttrMap)); 1785 mIdx++) { 1786 if (gWAIUnivAttrMap[mIdx].characteristics & mCharacteristics) { 1787 return true; 1788 } 1789 } 1790 1791 return false; 1792 } 1793 1794 nsStaticAtom* AttrWithCharacteristicsIterator::AttrName() const { 1795 return mIdx >= 0 1796 ? const_cast<nsStaticAtom*>(gWAIUnivAttrMap[mIdx].attributeName) 1797 : nullptr; 1798 }