michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:expandtab:shiftwidth=2:tabstop=2: michael@0: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "ARIAMap.h" michael@0: michael@0: #include "nsAccUtils.h" michael@0: #include "nsCoreUtils.h" michael@0: #include "Role.h" michael@0: #include "States.h" michael@0: michael@0: #include "nsAttrName.h" michael@0: #include "nsWhitespaceTokenizer.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::a11y; michael@0: using namespace mozilla::a11y::aria; michael@0: michael@0: static const uint32_t kGenericAccType = 0; michael@0: michael@0: /** michael@0: * This list of WAI-defined roles are currently hardcoded. michael@0: * Eventually we will most likely be loading an RDF resource that contains this information michael@0: * Using RDF will also allow for role extensibility. See bug 280138. michael@0: * michael@0: * Definition of nsRoleMapEntry contains comments explaining this table. michael@0: * michael@0: * When no nsIAccessibleRole enum mapping exists for an ARIA role, the michael@0: * role will be exposed via the object attribute "xml-roles". michael@0: * In addition, in MSAA, the unmapped role will also be exposed as a BSTR string role. michael@0: * michael@0: * There are no nsIAccessibleRole enums for the following landmark roles: michael@0: * banner, contentinfo, main, navigation, note, search, secondary, seealso, breadcrumbs michael@0: */ michael@0: michael@0: static nsRoleMapEntry sWAIRoleMaps[] = michael@0: { michael@0: { // alert michael@0: &nsGkAtoms::alert, michael@0: roles::ALERT, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // alertdialog michael@0: &nsGkAtoms::alertdialog, michael@0: roles::DIALOG, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // application michael@0: &nsGkAtoms::application, michael@0: roles::APPLICATION, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // article michael@0: &nsGkAtoms::article, michael@0: roles::DOCUMENT, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eReadonlyUntilEditable michael@0: }, michael@0: { // button michael@0: &nsGkAtoms::button, michael@0: roles::PUSHBUTTON, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: ePressAction, michael@0: eNoLiveAttr, michael@0: eButton, michael@0: kNoReqStates michael@0: // eARIAPressed is auto applied on any button michael@0: }, michael@0: { // checkbox michael@0: &nsGkAtoms::checkbox, michael@0: roles::CHECKBUTTON, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eCheckUncheckAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eARIACheckableMixed, michael@0: eARIAReadonly michael@0: }, michael@0: { // columnheader michael@0: &nsGkAtoms::columnheader, michael@0: roles::COLUMNHEADER, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eSortAction, michael@0: eNoLiveAttr, michael@0: eTableCell, michael@0: kNoReqStates, michael@0: eARIASelectableIfDefined, michael@0: eARIAReadonlyOrEditableIfDefined michael@0: }, michael@0: { // combobox michael@0: &nsGkAtoms::combobox, michael@0: roles::COMBOBOX, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eOpenCloseAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: states::COLLAPSED | states::HASPOPUP, michael@0: eARIAAutoComplete, michael@0: eARIAReadonly michael@0: }, michael@0: { // dialog michael@0: &nsGkAtoms::dialog, michael@0: roles::DIALOG, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // directory michael@0: &nsGkAtoms::directory, michael@0: roles::LIST, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: eList, michael@0: kNoReqStates michael@0: }, michael@0: { // document michael@0: &nsGkAtoms::document, michael@0: roles::DOCUMENT, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eReadonlyUntilEditable michael@0: }, michael@0: { // form michael@0: &nsGkAtoms::form, michael@0: roles::FORM, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // grid michael@0: &nsGkAtoms::grid, michael@0: roles::TABLE, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: eSelect | eTable, michael@0: kNoReqStates, michael@0: eARIAMultiSelectable, michael@0: eARIAReadonlyOrEditable, michael@0: eFocusableUntilDisabled michael@0: }, michael@0: { // gridcell michael@0: &nsGkAtoms::gridcell, michael@0: roles::GRID_CELL, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: eTableCell, michael@0: kNoReqStates, michael@0: eARIASelectable, michael@0: eARIAReadonlyOrEditableIfDefined michael@0: }, michael@0: { // group michael@0: &nsGkAtoms::group, michael@0: roles::GROUPING, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // heading michael@0: &nsGkAtoms::heading, michael@0: roles::HEADING, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // img michael@0: &nsGkAtoms::img, michael@0: roles::GRAPHIC, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // key michael@0: &nsGkAtoms::key, michael@0: roles::KEY, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: ePressAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eARIAPressed michael@0: }, michael@0: { // link michael@0: &nsGkAtoms::link, michael@0: roles::LINK, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eJumpAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: states::LINKED michael@0: }, michael@0: { // list michael@0: &nsGkAtoms::list, michael@0: roles::LIST, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: eList, michael@0: states::READONLY michael@0: }, michael@0: { // listbox michael@0: &nsGkAtoms::listbox, michael@0: roles::LISTBOX, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: eListControl | eSelect, michael@0: kNoReqStates, michael@0: eARIAMultiSelectable, michael@0: eARIAReadonly, michael@0: eFocusableUntilDisabled michael@0: }, michael@0: { // listitem michael@0: &nsGkAtoms::listitem, michael@0: roles::LISTITEM, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, // XXX: should depend on state, parent accessible michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: states::READONLY michael@0: }, michael@0: { // log michael@0: &nsGkAtoms::log_, michael@0: roles::NOTHING, michael@0: kUseNativeRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: ePoliteLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // marquee michael@0: &nsGkAtoms::marquee, michael@0: roles::ANIMATION, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eOffLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // math michael@0: &nsGkAtoms::math, michael@0: roles::FLAT_EQUATION, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // menu michael@0: &nsGkAtoms::menu, michael@0: roles::MENUPOPUP, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, // XXX: technically accessibles of menupopup role haven't michael@0: // any action, but menu can be open or close. michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // menubar michael@0: &nsGkAtoms::menubar, michael@0: roles::MENUBAR, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // menuitem michael@0: &nsGkAtoms::menuitem, michael@0: roles::MENUITEM, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eClickAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eARIACheckedMixed michael@0: }, michael@0: { // menuitemcheckbox michael@0: &nsGkAtoms::menuitemcheckbox, michael@0: roles::CHECK_MENU_ITEM, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eClickAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eARIACheckableMixed michael@0: }, michael@0: { // menuitemradio michael@0: &nsGkAtoms::menuitemradio, michael@0: roles::RADIO_MENU_ITEM, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eClickAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eARIACheckableBool michael@0: }, michael@0: { // note michael@0: &nsGkAtoms::note_, michael@0: roles::NOTE, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // option michael@0: &nsGkAtoms::option, michael@0: roles::OPTION, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eSelectAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eARIASelectable, michael@0: eARIACheckedMixed michael@0: }, michael@0: { // presentation michael@0: &nsGkAtoms::presentation, michael@0: roles::NOTHING, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // progressbar michael@0: &nsGkAtoms::progressbar, michael@0: roles::PROGRESSBAR, michael@0: kUseMapRole, michael@0: eHasValueMinMax, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: states::READONLY, michael@0: eIndeterminateIfNoValue michael@0: }, michael@0: { // radio michael@0: &nsGkAtoms::radio, michael@0: roles::RADIOBUTTON, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eSelectAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eARIACheckableBool michael@0: }, michael@0: { // radiogroup michael@0: &nsGkAtoms::radiogroup, michael@0: roles::GROUPING, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // region michael@0: &nsGkAtoms::region, michael@0: roles::PANE, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // row michael@0: &nsGkAtoms::row, michael@0: roles::ROW, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: eTableRow, michael@0: kNoReqStates, michael@0: eARIASelectable michael@0: }, michael@0: { // rowgroup michael@0: &nsGkAtoms::rowgroup, michael@0: roles::GROUPING, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // rowheader michael@0: &nsGkAtoms::rowheader, michael@0: roles::ROWHEADER, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eSortAction, michael@0: eNoLiveAttr, michael@0: eTableCell, michael@0: kNoReqStates, michael@0: eARIASelectableIfDefined, michael@0: eARIAReadonlyOrEditableIfDefined michael@0: }, michael@0: { // scrollbar michael@0: &nsGkAtoms::scrollbar, michael@0: roles::SCROLLBAR, michael@0: kUseMapRole, michael@0: eHasValueMinMax, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eARIAOrientation, michael@0: eARIAReadonly michael@0: }, michael@0: { // separator michael@0: &nsGkAtoms::separator_, michael@0: roles::SEPARATOR, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eARIAOrientation michael@0: }, michael@0: { // slider michael@0: &nsGkAtoms::slider, michael@0: roles::SLIDER, michael@0: kUseMapRole, michael@0: eHasValueMinMax, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eARIAOrientation, michael@0: eARIAReadonly michael@0: }, michael@0: { // spinbutton michael@0: &nsGkAtoms::spinbutton, michael@0: roles::SPINBUTTON, michael@0: kUseMapRole, michael@0: eHasValueMinMax, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eARIAReadonly michael@0: }, michael@0: { // status michael@0: &nsGkAtoms::status, michael@0: roles::STATUSBAR, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: ePoliteLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // tab michael@0: &nsGkAtoms::tab, michael@0: roles::PAGETAB, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eSwitchAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eARIASelectable michael@0: }, michael@0: { // tablist michael@0: &nsGkAtoms::tablist, michael@0: roles::PAGETABLIST, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: eSelect, michael@0: kNoReqStates michael@0: }, michael@0: { // tabpanel michael@0: &nsGkAtoms::tabpanel, michael@0: roles::PROPERTYPAGE, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // textbox michael@0: &nsGkAtoms::textbox, michael@0: roles::ENTRY, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eActivateAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eARIAAutoComplete, michael@0: eARIAMultiline, michael@0: eARIAReadonlyOrEditable michael@0: }, michael@0: { // timer michael@0: &nsGkAtoms::timer, michael@0: roles::NOTHING, michael@0: kUseNativeRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eOffLiveAttr, michael@0: kNoReqStates michael@0: }, michael@0: { // toolbar michael@0: &nsGkAtoms::toolbar, michael@0: roles::TOOLBAR, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // tooltip michael@0: &nsGkAtoms::tooltip, michael@0: roles::TOOLTIP, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }, michael@0: { // tree michael@0: &nsGkAtoms::tree, michael@0: roles::OUTLINE, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: eSelect, michael@0: kNoReqStates, michael@0: eARIAReadonly, michael@0: eARIAMultiSelectable, michael@0: eFocusableUntilDisabled michael@0: }, michael@0: { // treegrid michael@0: &nsGkAtoms::treegrid, michael@0: roles::TREE_TABLE, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: eSelect | eTable, michael@0: kNoReqStates, michael@0: eARIAReadonlyOrEditable, michael@0: eARIAMultiSelectable, michael@0: eFocusableUntilDisabled michael@0: }, michael@0: { // treeitem michael@0: &nsGkAtoms::treeitem, michael@0: roles::OUTLINEITEM, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eActivateAction, // XXX: should expose second 'expand/collapse' action based michael@0: // on states michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates, michael@0: eARIASelectable, michael@0: eARIACheckedMixed michael@0: } michael@0: }; michael@0: michael@0: static nsRoleMapEntry sLandmarkRoleMap = { michael@0: &nsGkAtoms::_empty, michael@0: roles::NOTHING, michael@0: kUseNativeRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }; michael@0: michael@0: nsRoleMapEntry aria::gEmptyRoleMap = { michael@0: &nsGkAtoms::_empty, michael@0: roles::NOTHING, michael@0: kUseMapRole, michael@0: eNoValue, michael@0: eNoAction, michael@0: eNoLiveAttr, michael@0: kGenericAccType, michael@0: kNoReqStates michael@0: }; michael@0: michael@0: /** michael@0: * Universal (Global) states: michael@0: * The following state rules are applied to any accessible element, michael@0: * whether there is an ARIA role or not: michael@0: */ michael@0: static const EStateRule sWAIUnivStateMap[] = { michael@0: eARIABusy, michael@0: eARIADisabled, michael@0: eARIAExpanded, // Currently under spec review but precedent exists michael@0: eARIAHasPopup, // Note this is technically a "property" michael@0: eARIAInvalid, michael@0: eARIARequired, // XXX not global, Bug 553117 michael@0: eARIANone michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * ARIA attribute map for attribute characteristics. michael@0: * @note ARIA attributes that don't have any flags are not included here. michael@0: */ michael@0: michael@0: struct AttrCharacteristics michael@0: { michael@0: nsIAtom** attributeName; michael@0: const uint8_t characteristics; michael@0: }; michael@0: michael@0: static const AttrCharacteristics gWAIUnivAttrMap[] = { michael@0: {&nsGkAtoms::aria_activedescendant, ATTR_BYPASSOBJ }, michael@0: {&nsGkAtoms::aria_atomic, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_busy, ATTR_VALTOKEN | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_checked, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, /* exposes checkable obj attr */ michael@0: {&nsGkAtoms::aria_controls, ATTR_BYPASSOBJ | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_describedby, ATTR_BYPASSOBJ | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_disabled, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_dropeffect, ATTR_VALTOKEN | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_expanded, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, michael@0: {&nsGkAtoms::aria_flowto, ATTR_BYPASSOBJ | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_grabbed, ATTR_VALTOKEN | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_haspopup, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_hidden, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_invalid, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_label, ATTR_BYPASSOBJ | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_labelledby, ATTR_BYPASSOBJ | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_level, ATTR_BYPASSOBJ }, /* handled via groupPosition */ michael@0: {&nsGkAtoms::aria_live, ATTR_VALTOKEN | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_multiline, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, michael@0: {&nsGkAtoms::aria_multiselectable, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, michael@0: {&nsGkAtoms::aria_owns, ATTR_BYPASSOBJ | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_orientation, ATTR_VALTOKEN }, michael@0: {&nsGkAtoms::aria_posinset, ATTR_BYPASSOBJ }, /* handled via groupPosition */ michael@0: {&nsGkAtoms::aria_pressed, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, michael@0: {&nsGkAtoms::aria_readonly, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, michael@0: {&nsGkAtoms::aria_relevant, ATTR_BYPASSOBJ | ATTR_GLOBAL }, michael@0: {&nsGkAtoms::aria_required, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, michael@0: {&nsGkAtoms::aria_selected, ATTR_BYPASSOBJ | ATTR_VALTOKEN }, michael@0: {&nsGkAtoms::aria_setsize, ATTR_BYPASSOBJ }, /* handled via groupPosition */ michael@0: {&nsGkAtoms::aria_sort, ATTR_VALTOKEN }, michael@0: {&nsGkAtoms::aria_valuenow, ATTR_BYPASSOBJ }, michael@0: {&nsGkAtoms::aria_valuemin, ATTR_BYPASSOBJ }, michael@0: {&nsGkAtoms::aria_valuemax, ATTR_BYPASSOBJ }, michael@0: {&nsGkAtoms::aria_valuetext, ATTR_BYPASSOBJ } michael@0: }; michael@0: michael@0: nsRoleMapEntry* michael@0: aria::GetRoleMap(nsINode* aNode) michael@0: { michael@0: nsIContent* content = nsCoreUtils::GetRoleContent(aNode); michael@0: nsAutoString roles; michael@0: if (!content || michael@0: !content->GetAttr(kNameSpaceID_None, nsGkAtoms::role, roles) || michael@0: roles.IsEmpty()) { michael@0: // We treat role="" as if the role attribute is absent (per aria spec:8.1.1) michael@0: return nullptr; michael@0: } michael@0: michael@0: nsWhitespaceTokenizer tokenizer(roles); michael@0: while (tokenizer.hasMoreTokens()) { michael@0: // Do a binary search through table for the next role in role list michael@0: const nsDependentSubstring role = tokenizer.nextToken(); michael@0: uint32_t low = 0; michael@0: uint32_t high = ArrayLength(sWAIRoleMaps); michael@0: while (low < high) { michael@0: uint32_t idx = (low + high) / 2; michael@0: int32_t compare = Compare(role, sWAIRoleMaps[idx].ARIARoleString()); michael@0: if (compare == 0) michael@0: return sWAIRoleMaps + idx; michael@0: michael@0: if (compare < 0) michael@0: high = idx; michael@0: else michael@0: low = idx + 1; michael@0: } michael@0: } michael@0: michael@0: // Always use some entry if there is a non-empty role string michael@0: // To ensure an accessible object is created michael@0: return &sLandmarkRoleMap; michael@0: } michael@0: michael@0: uint64_t michael@0: aria::UniversalStatesFor(mozilla::dom::Element* aElement) michael@0: { michael@0: uint64_t state = 0; michael@0: uint32_t index = 0; michael@0: while (MapToState(sWAIUnivStateMap[index], aElement, &state)) michael@0: index++; michael@0: michael@0: return state; michael@0: } michael@0: michael@0: uint8_t michael@0: aria::AttrCharacteristicsFor(nsIAtom* aAtom) michael@0: { michael@0: for (uint32_t i = 0; i < ArrayLength(gWAIUnivAttrMap); i++) michael@0: if (*gWAIUnivAttrMap[i].attributeName == aAtom) michael@0: return gWAIUnivAttrMap[i].characteristics; michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // AttrIterator class michael@0: michael@0: bool michael@0: AttrIterator::Next(nsAString& aAttrName, nsAString& aAttrValue) michael@0: { michael@0: while (mAttrIdx < mAttrCount) { michael@0: const nsAttrName* attr = mContent->GetAttrNameAt(mAttrIdx); michael@0: mAttrIdx++; michael@0: if (attr->NamespaceEquals(kNameSpaceID_None)) { michael@0: nsIAtom* attrAtom = attr->Atom(); michael@0: nsDependentAtomString attrStr(attrAtom); michael@0: if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-"))) michael@0: continue; // Not ARIA michael@0: michael@0: uint8_t attrFlags = aria::AttrCharacteristicsFor(attrAtom); michael@0: if (attrFlags & ATTR_BYPASSOBJ) michael@0: continue; // No need to handle exposing as obj attribute here michael@0: michael@0: if ((attrFlags & ATTR_VALTOKEN) && michael@0: !nsAccUtils::HasDefinedARIAToken(mContent, attrAtom)) michael@0: continue; // only expose token based attributes if they are defined michael@0: michael@0: if ((attrFlags & ATTR_BYPASSOBJ_IF_FALSE) && michael@0: mContent->AttrValueIs(kNameSpaceID_None, attrAtom, michael@0: nsGkAtoms::_false, eCaseMatters)) { michael@0: continue; // only expose token based attribute if value is not 'false'. michael@0: } michael@0: michael@0: nsAutoString value; michael@0: if (mContent->GetAttr(kNameSpaceID_None, attrAtom, value)) { michael@0: aAttrName.Assign(Substring(attrStr, 5)); michael@0: aAttrValue.Assign(value); michael@0: return true; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: