summaryrefslogtreecommitdiffstats
path: root/accessible
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:35:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:35:49 +0000
commitd8bbc7858622b6d9c278469aab701ca0b609cddf (patch)
treeeff41dc61d9f714852212739e6b3738b82a2af87 /accessible
parentReleasing progress-linux version 125.0.3-1~progress7.99u1. (diff)
downloadfirefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.tar.xz
firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.zip
Merging upstream version 126.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'accessible')
-rw-r--r--accessible/android/AccessibleWrap.cpp3
-rw-r--r--accessible/android/Platform.cpp3
-rw-r--r--accessible/atk/AccessibleWrap.cpp3
-rw-r--r--accessible/base/ARIAMap.cpp2
-rw-r--r--accessible/base/AccGroupInfo.cpp1
-rw-r--r--accessible/base/Asserts.cpp3
-rw-r--r--accessible/base/CachedTableAccessible.cpp2
-rw-r--r--accessible/base/DocManager.cpp14
-rw-r--r--accessible/base/HTMLMarkupMap.h6
-rw-r--r--accessible/base/RoleMap.h154
-rw-r--r--accessible/base/nsAccUtils.cpp10
-rw-r--r--accessible/base/nsAccessibilityService.cpp5
-rw-r--r--accessible/base/nsTextEquivUtils.cpp4
-rw-r--r--accessible/basetypes/Accessible.cpp15
-rw-r--r--accessible/basetypes/Accessible.h40
-rw-r--r--accessible/generic/LocalAccessible.cpp163
-rw-r--r--accessible/html/HTMLSelectAccessible.cpp1
-rw-r--r--accessible/html/HTMLTableAccessible.cpp1
-rw-r--r--accessible/interfaces/nsIAccessibleCaretMoveEvent.idl4
-rw-r--r--accessible/interfaces/nsIAccessibleMacInterface.idl2
-rw-r--r--accessible/interfaces/nsIAccessibleRole.idl7
-rw-r--r--accessible/ios/MUIAccessible.mm3
-rw-r--r--accessible/mac/MOXAccessibleProtocol.h3
-rw-r--r--accessible/mac/mozAccessible.h3
-rw-r--r--accessible/mac/mozAccessible.mm16
-rw-r--r--accessible/tests/browser/.eslintrc.js2
-rw-r--r--accessible/tests/browser/bounds/browser.toml1
-rw-r--r--accessible/tests/browser/e10s/browser.toml1
-rw-r--r--accessible/tests/browser/e10s/browser_aria_activedescendant.js10
-rw-r--r--accessible/tests/browser/e10s/browser_caching_value.js10
-rw-r--r--accessible/tests/browser/events/browser.toml3
-rw-r--r--accessible/tests/browser/events/browser_content_prompt.js48
-rw-r--r--accessible/tests/browser/fission/browser.toml1
-rw-r--r--accessible/tests/browser/hittest/browser.toml1
-rw-r--r--accessible/tests/browser/mac/browser.toml3
-rw-r--r--accessible/tests/browser/mac/browser_aria_placeholder.js70
-rw-r--r--accessible/tests/browser/mac/browser_roles_elements.js4
-rw-r--r--accessible/tests/browser/mac/browser_selectables.js23
-rw-r--r--accessible/tests/browser/role/browser_computedARIARole.js4
-rw-r--r--accessible/tests/browser/scroll/browser.toml1
-rw-r--r--accessible/tests/browser/selectable/browser.toml1
-rw-r--r--accessible/tests/browser/selectable/browser_test_aria_select.js26
-rw-r--r--accessible/tests/browser/states/browser.toml1
-rw-r--r--accessible/tests/browser/text/browser.toml1
-rw-r--r--accessible/tests/browser/tree/browser.toml1
-rw-r--r--accessible/tests/browser/windows/a11y_setup.py154
-rw-r--r--accessible/tests/browser/windows/uia/browser.toml5
-rw-r--r--accessible/tests/browser/windows/uia/browser_focus.js61
-rw-r--r--accessible/tests/browser/windows/uia/browser_generalProps.js105
-rw-r--r--accessible/tests/browser/windows/uia/browser_simplePatterns.js445
-rw-r--r--accessible/tests/browser/windows/uia/browser_tree.js20
-rw-r--r--accessible/tests/browser/windows/uia/head.js75
-rw-r--r--accessible/tests/mochitest/attributes/test_obj_group.xhtml24
-rw-r--r--accessible/tests/mochitest/focus/test_takeFocus.html1
-rw-r--r--accessible/tests/mochitest/name/test_general.html36
-rw-r--r--accessible/tests/mochitest/relations/a11y.toml2
-rw-r--r--accessible/tests/mochitest/relations/test_ui_modalprompt.html111
-rw-r--r--accessible/tests/mochitest/role/test_aria.html99
-rw-r--r--accessible/tests/mochitest/test_custom_element_accessibility_defaults.html18
-rw-r--r--accessible/tests/mochitest/tree/test_aria_display_contents.html88
-rw-r--r--accessible/tests/mochitest/tree/test_aria_grid.html2
-rw-r--r--accessible/tests/mochitest/tree/test_aria_table.html2
-rw-r--r--accessible/tests/mochitest/tree/test_display_contents.html2
-rw-r--r--accessible/tests/mochitest/tree/test_table.html2
-rw-r--r--accessible/windows/ia2/ia2Accessible.cpp3
-rw-r--r--accessible/windows/msaa/MsaaAccessible.cpp12
-rw-r--r--accessible/windows/msaa/MsaaAccessible.h6
-rw-r--r--accessible/windows/msaa/MsaaRootAccessible.cpp8
-rw-r--r--accessible/windows/msaa/MsaaRootAccessible.h4
-rw-r--r--accessible/windows/msaa/Platform.cpp7
-rw-r--r--accessible/windows/uia/UiaRoot.cpp61
-rw-r--r--accessible/windows/uia/UiaRoot.h40
-rw-r--r--accessible/windows/uia/moz.build1
-rw-r--r--accessible/windows/uia/uiaRawElmProvider.cpp576
-rw-r--r--accessible/windows/uia/uiaRawElmProvider.h79
-rw-r--r--accessible/xpcom/xpcAccessible.cpp3
76 files changed, 2269 insertions, 463 deletions
diff --git a/accessible/android/AccessibleWrap.cpp b/accessible/android/AccessibleWrap.cpp
index 4ca06dea88..5b69866c05 100644
--- a/accessible/android/AccessibleWrap.cpp
+++ b/accessible/android/AccessibleWrap.cpp
@@ -356,7 +356,8 @@ void AccessibleWrap::SetVirtualViewID(Accessible* aAccessible,
int32_t AccessibleWrap::GetAndroidClass(role aRole) {
#define ROLE(geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \
- msaaRole, ia2Role, androidClass, iosIsElement, nameRule) \
+ msaaRole, ia2Role, androidClass, iosIsElement, uiaControlType, \
+ nameRule) \
case roles::geckoRole: \
return androidClass;
diff --git a/accessible/android/Platform.cpp b/accessible/android/Platform.cpp
index 312dbc9636..788dc44284 100644
--- a/accessible/android/Platform.cpp
+++ b/accessible/android/Platform.cpp
@@ -65,7 +65,8 @@ void a11y::PlatformInit() {
// Preload any roles that have localized versions
#define ROLE(geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \
- msaaRole, ia2Role, androidClass, iosIsElement, nameRule) \
+ msaaRole, ia2Role, androidClass, iosIsElement, uiaControlType, \
+ nameRule) \
rv = stringBundle->GetStringFromName(stringRole, localizedStr); \
if (NS_SUCCEEDED(rv)) { \
sLocalizedStrings.InsertOrUpdate(u##stringRole##_ns, localizedStr); \
diff --git a/accessible/atk/AccessibleWrap.cpp b/accessible/atk/AccessibleWrap.cpp
index 522434561f..0f17fc59ee 100644
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -582,7 +582,8 @@ AtkRole getRoleCB(AtkObject* aAtkObj) {
#endif
#define ROLE(geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \
- msaaRole, ia2Role, androidClass, iosIsElement, nameRule) \
+ msaaRole, ia2Role, androidClass, iosIsElement, uiaControlType, \
+ nameRule) \
case roles::geckoRole: \
aAtkObj->role = atkRole; \
break;
diff --git a/accessible/base/ARIAMap.cpp b/accessible/base/ARIAMap.cpp
index bfc41db82e..d53592acf0 100644
--- a/accessible/base/ARIAMap.cpp
+++ b/accessible/base/ARIAMap.cpp
@@ -1094,7 +1094,7 @@ static const nsRoleMapEntry sWAIRoleMaps[] = {
},
{ // rowgroup
nsGkAtoms::rowgroup,
- roles::GROUPING,
+ roles::ROWGROUP,
kUseMapRole,
eNoValue,
eNoAction,
diff --git a/accessible/base/AccGroupInfo.cpp b/accessible/base/AccGroupInfo.cpp
index c3501dc36e..336ce9ecf5 100644
--- a/accessible/base/AccGroupInfo.cpp
+++ b/accessible/base/AccGroupInfo.cpp
@@ -292,6 +292,7 @@ uint32_t AccGroupInfo::TotalItemCount(Accessible* aContainer,
case roles::MENUPOPUP:
case roles::COMBOBOX:
case roles::GROUPING:
+ case roles::ROWGROUP:
case roles::TREE_TABLE:
case roles::COMBOBOX_LIST:
case roles::LISTBOX:
diff --git a/accessible/base/Asserts.cpp b/accessible/base/Asserts.cpp
index 729b4e1ea5..454eaffef6 100644
--- a/accessible/base/Asserts.cpp
+++ b/accessible/base/Asserts.cpp
@@ -12,7 +12,8 @@
using namespace mozilla::a11y;
#define ROLE(geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \
- msaaRole, ia2Role, androidClass, iosIsElement, nameRule) \
+ msaaRole, ia2Role, androidClass, iosIsElement, uiaControlType, \
+ nameRule) \
static_assert( \
static_cast<uint32_t>(roles::geckoRole) == \
static_cast<uint32_t>(nsIAccessibleRole::ROLE_##geckoRole), \
diff --git a/accessible/base/CachedTableAccessible.cpp b/accessible/base/CachedTableAccessible.cpp
index e780bd2a89..8f56352acd 100644
--- a/accessible/base/CachedTableAccessible.cpp
+++ b/accessible/base/CachedTableAccessible.cpp
@@ -35,7 +35,7 @@ class TablePartRule : public PivotRule {
accRole == roles::TEXT || accRole == roles::TEXT_CONTAINER ||
accRole == roles::SECTION ||
// Row groups.
- accRole == roles::GROUPING) {
+ accRole == roles::ROWGROUP) {
// Walk inside these, but don't match them.
return nsIAccessibleTraversalRule::FILTER_IGNORE;
}
diff --git a/accessible/base/DocManager.cpp b/accessible/base/DocManager.cpp
index b7a5203e40..18bf9c0433 100644
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -17,6 +17,7 @@
# include "Logging.h"
#endif
+#include "mozilla/BasePrincipal.h"
#include "mozilla/Components.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/PresShell.h"
@@ -464,7 +465,18 @@ DocAccessible* DocManager::CreateDocOrRootAccessible(Document* aDocument) {
// XXXaaronl: ideally we would traverse the presshell chain. Since there's
// no easy way to do that, we cheat and use the document hierarchy.
parentDocAcc = GetDocAccessible(aDocument->GetInProcessParentDocument());
- NS_ASSERTION(parentDocAcc, "Can't create an accessible for the document!");
+ // We should always get parentDocAcc except sometimes for background
+ // extension pages, where the parent has an invisible DocShell but the child
+ // does not. See bug 1888649.
+ NS_ASSERTION(
+ parentDocAcc ||
+ (BasePrincipal::Cast(aDocument->GetPrincipal())->AddonPolicy() &&
+ aDocument->GetInProcessParentDocument() &&
+ aDocument->GetInProcessParentDocument()->GetDocShell() &&
+ aDocument->GetInProcessParentDocument()
+ ->GetDocShell()
+ ->IsInvisible()),
+ "Can't create an accessible for the document!");
if (!parentDocAcc) return nullptr;
}
diff --git a/accessible/base/HTMLMarkupMap.h b/accessible/base/HTMLMarkupMap.h
index c607616518..3b422ac09c 100644
--- a/accessible/base/HTMLMarkupMap.h
+++ b/accessible/base/HTMLMarkupMap.h
@@ -376,7 +376,7 @@ MARKUPMAP(
MARKUPMAP(time, New_HyperText, roles::TIME, Attr(xmlroles, time),
AttrFromDOM(datetime, datetime))
-MARKUPMAP(tbody, nullptr, roles::GROUPING)
+MARKUPMAP(tbody, nullptr, roles::ROWGROUP)
MARKUPMAP(
td,
@@ -392,7 +392,7 @@ MARKUPMAP(
},
0)
-MARKUPMAP(tfoot, nullptr, roles::GROUPING)
+MARKUPMAP(tfoot, nullptr, roles::ROWGROUP)
MARKUPMAP(
th,
@@ -404,7 +404,7 @@ MARKUPMAP(
},
0)
-MARKUPMAP(thead, nullptr, roles::GROUPING)
+MARKUPMAP(thead, nullptr, roles::ROWGROUP)
MARKUPMAP(
tr,
diff --git a/accessible/base/RoleMap.h b/accessible/base/RoleMap.h
index 58cbb82165..6008dc4bbf 100644
--- a/accessible/base/RoleMap.h
+++ b/accessible/base/RoleMap.h
@@ -5,7 +5,7 @@
// clang-format off
/**
* Usage: declare the macro ROLE()with the following arguments:
- * ROLE(geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, msaaRole, ia2Role, nameRule)
+ * ROLE(geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, msaaRole, ia2Role, iosIsElement, uiaControlType, nameRule)
*/
ROLE(NOTHING,
@@ -18,6 +18,7 @@ ROLE(NOTHING,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::No,
+ UIA_CustomControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(MENUBAR,
@@ -30,6 +31,7 @@ ROLE(MENUBAR,
ROLE_SYSTEM_MENUBAR,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_MenuBarControlTypeId,
eNoNameRule)
ROLE(SCROLLBAR,
@@ -42,6 +44,7 @@ ROLE(SCROLLBAR,
ROLE_SYSTEM_SCROLLBAR,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_ScrollBarControlTypeId,
eNameFromValueRule)
ROLE(ALERT,
@@ -54,6 +57,7 @@ ROLE(ALERT,
ROLE_SYSTEM_ALERT,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(INTERNAL_FRAME,
@@ -66,6 +70,7 @@ ROLE(INTERNAL_FRAME,
IA2_ROLE_INTERNAL_FRAME,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_PaneControlTypeId,
eNoNameRule)
ROLE(MENUPOPUP,
@@ -78,6 +83,7 @@ ROLE(MENUPOPUP,
ROLE_SYSTEM_MENUPOPUP,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_MenuControlTypeId,
eNoNameRule)
ROLE(MENUITEM,
@@ -90,6 +96,7 @@ ROLE(MENUITEM,
ROLE_SYSTEM_MENUITEM,
java::SessionAccessibility::CLASSNAME_MENUITEM,
IsAccessibilityElementRule::Yes,
+ UIA_MenuItemControlTypeId,
eNameFromSubtreeRule)
ROLE(TOOLTIP,
@@ -102,6 +109,7 @@ ROLE(TOOLTIP,
ROLE_SYSTEM_TOOLTIP,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::Yes,
+ UIA_ToolTipControlTypeId,
eNameFromSubtreeRule)
ROLE(APPLICATION,
@@ -114,6 +122,7 @@ ROLE(APPLICATION,
ROLE_SYSTEM_APPLICATION,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_PaneControlTypeId,
eNoNameRule)
ROLE(DOCUMENT,
@@ -126,6 +135,7 @@ ROLE(DOCUMENT,
ROLE_SYSTEM_DOCUMENT,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_DocumentControlTypeId,
eNoNameRule)
/**
@@ -147,6 +157,7 @@ ROLE(PANE,
ROLE_SYSTEM_GROUPING,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_PaneControlTypeId,
eNoNameRule)
ROLE(DIALOG,
@@ -159,6 +170,7 @@ ROLE(DIALOG,
ROLE_SYSTEM_DIALOG,
java::SessionAccessibility::CLASSNAME_DIALOG,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_PaneControlTypeId,
eNoNameRule)
ROLE(GROUPING,
@@ -171,6 +183,7 @@ ROLE(GROUPING,
ROLE_SYSTEM_GROUPING,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(SEPARATOR,
@@ -183,6 +196,7 @@ ROLE(SEPARATOR,
ROLE_SYSTEM_SEPARATOR,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::Yes,
+ UIA_SeparatorControlTypeId,
eNoNameRule)
ROLE(TOOLBAR,
@@ -195,6 +209,7 @@ ROLE(TOOLBAR,
ROLE_SYSTEM_TOOLBAR,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_ToolBarControlTypeId,
eNoNameRule)
ROLE(STATUSBAR,
@@ -207,6 +222,7 @@ ROLE(STATUSBAR,
ROLE_SYSTEM_STATUSBAR,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(TABLE,
@@ -219,6 +235,7 @@ ROLE(TABLE,
ROLE_SYSTEM_TABLE,
java::SessionAccessibility::CLASSNAME_GRIDVIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TableControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(COLUMNHEADER,
@@ -231,6 +248,7 @@ ROLE(COLUMNHEADER,
ROLE_SYSTEM_COLUMNHEADER,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_DataItemControlTypeId,
eNameFromSubtreeRule)
ROLE(ROWHEADER,
@@ -243,6 +261,7 @@ ROLE(ROWHEADER,
ROLE_SYSTEM_ROWHEADER,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_HeaderItemControlTypeId,
eNameFromSubtreeRule)
ROLE(ROW,
@@ -255,6 +274,7 @@ ROLE(ROW,
ROLE_SYSTEM_ROW,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_DataItemControlTypeId,
eNameFromSubtreeRule)
ROLE(CELL,
@@ -267,6 +287,7 @@ ROLE(CELL,
ROLE_SYSTEM_CELL,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_DataItemControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(LINK,
@@ -279,6 +300,7 @@ ROLE(LINK,
ROLE_SYSTEM_LINK,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfBrokenUp,
+ UIA_HyperlinkControlTypeId,
eNameFromSubtreeRule)
ROLE(LIST,
@@ -291,6 +313,7 @@ ROLE(LIST,
ROLE_SYSTEM_LIST,
java::SessionAccessibility::CLASSNAME_LISTVIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_ListControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(LISTITEM,
@@ -303,6 +326,7 @@ ROLE(LISTITEM,
ROLE_SYSTEM_LISTITEM,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_ListItemControlTypeId,
eNameFromSubtreeRule)
ROLE(OUTLINE,
@@ -315,6 +339,7 @@ ROLE(OUTLINE,
ROLE_SYSTEM_OUTLINE,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TreeControlTypeId,
eNoNameRule)
ROLE(OUTLINEITEM,
@@ -327,6 +352,7 @@ ROLE(OUTLINEITEM,
ROLE_SYSTEM_OUTLINEITEM,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TreeItemControlTypeId,
eNameFromSubtreeRule)
ROLE(PAGETAB,
@@ -339,6 +365,7 @@ ROLE(PAGETAB,
ROLE_SYSTEM_PAGETAB,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::Yes,
+ UIA_TabItemControlTypeId,
eNameFromSubtreeRule)
ROLE(PROPERTYPAGE,
@@ -351,6 +378,7 @@ ROLE(PROPERTYPAGE,
ROLE_SYSTEM_PROPERTYPAGE,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_PaneControlTypeId,
eNoNameRule)
ROLE(GRAPHIC,
@@ -363,6 +391,7 @@ ROLE(GRAPHIC,
ROLE_SYSTEM_GRAPHIC,
java::SessionAccessibility::CLASSNAME_IMAGE,
IsAccessibilityElementRule::Yes,
+ UIA_ImageControlTypeId,
eNoNameRule)
ROLE(STATICTEXT,
@@ -375,6 +404,7 @@ ROLE(STATICTEXT,
ROLE_SYSTEM_STATICTEXT,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfParentIsntElementWithName,
+ UIA_TextControlTypeId,
eNoNameRule)
ROLE(TEXT_LEAF,
@@ -387,6 +417,7 @@ ROLE(TEXT_LEAF,
ROLE_SYSTEM_TEXT,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfParentIsntElementWithName,
+ UIA_TextControlTypeId,
eNoNameRule)
ROLE(PUSHBUTTON,
@@ -399,6 +430,7 @@ ROLE(PUSHBUTTON,
ROLE_SYSTEM_PUSHBUTTON,
java::SessionAccessibility::CLASSNAME_BUTTON,
IsAccessibilityElementRule::Yes,
+ UIA_ButtonControlTypeId,
eNameFromSubtreeRule)
ROLE(CHECKBUTTON,
@@ -411,6 +443,7 @@ ROLE(CHECKBUTTON,
ROLE_SYSTEM_CHECKBUTTON,
java::SessionAccessibility::CLASSNAME_CHECKBOX,
IsAccessibilityElementRule::Yes,
+ UIA_CheckBoxControlTypeId,
eNameFromSubtreeRule)
ROLE(RADIOBUTTON,
@@ -423,6 +456,7 @@ ROLE(RADIOBUTTON,
ROLE_SYSTEM_RADIOBUTTON,
java::SessionAccessibility::CLASSNAME_RADIOBUTTON,
IsAccessibilityElementRule::Yes,
+ UIA_RadioButtonControlTypeId,
eNameFromSubtreeRule)
// Equivalent of HTML select element with size="1". See also EDITCOMBOBOX.
@@ -436,6 +470,7 @@ ROLE(COMBOBOX,
ROLE_SYSTEM_COMBOBOX,
java::SessionAccessibility::CLASSNAME_SPINNER,
IsAccessibilityElementRule::Yes,
+ UIA_ComboBoxControlTypeId,
eNameFromValueRule)
ROLE(PROGRESSBAR,
@@ -448,6 +483,7 @@ ROLE(PROGRESSBAR,
ROLE_SYSTEM_PROGRESSBAR,
java::SessionAccessibility::CLASSNAME_PROGRESSBAR,
IsAccessibilityElementRule::Yes,
+ UIA_ProgressBarControlTypeId,
eNameFromValueRule)
ROLE(SLIDER,
@@ -460,6 +496,7 @@ ROLE(SLIDER,
ROLE_SYSTEM_SLIDER,
java::SessionAccessibility::CLASSNAME_SEEKBAR,
IsAccessibilityElementRule::Yes,
+ UIA_SliderControlTypeId,
eNameFromValueRule)
ROLE(SPINBUTTON,
@@ -472,6 +509,7 @@ ROLE(SPINBUTTON,
ROLE_SYSTEM_SPINBUTTON,
java::SessionAccessibility::CLASSNAME_EDITTEXT,
IsAccessibilityElementRule::Yes,
+ UIA_SpinnerControlTypeId,
eNameFromValueRule)
ROLE(DIAGRAM,
@@ -484,6 +522,7 @@ ROLE(DIAGRAM,
ROLE_SYSTEM_DIAGRAM,
java::SessionAccessibility::CLASSNAME_IMAGE,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_ImageControlTypeId,
eNoNameRule)
ROLE(ANIMATION,
@@ -496,6 +535,7 @@ ROLE(ANIMATION,
ROLE_SYSTEM_ANIMATION,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(BUTTONDROPDOWN,
@@ -508,6 +548,7 @@ ROLE(BUTTONDROPDOWN,
ROLE_SYSTEM_BUTTONDROPDOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::Yes,
+ UIA_SplitButtonControlTypeId,
eNameFromSubtreeRule)
ROLE(BUTTONMENU,
@@ -520,6 +561,7 @@ ROLE(BUTTONMENU,
ROLE_SYSTEM_BUTTONMENU,
java::SessionAccessibility::CLASSNAME_SPINNER,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_ButtonControlTypeId,
eNameFromSubtreeRule)
ROLE(WHITESPACE,
@@ -532,6 +574,7 @@ ROLE(WHITESPACE,
ROLE_SYSTEM_WHITESPACE,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::No,
+ UIA_TextControlTypeId,
eNoNameRule)
ROLE(PAGETABLIST,
@@ -544,6 +587,7 @@ ROLE(PAGETABLIST,
ROLE_SYSTEM_PAGETABLIST,
java::SessionAccessibility::CLASSNAME_TABWIDGET,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TabControlTypeId,
eNoNameRule)
ROLE(CANVAS,
@@ -556,6 +600,7 @@ ROLE(CANVAS,
IA2_ROLE_CANVAS,
java::SessionAccessibility::CLASSNAME_IMAGE,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_ImageControlTypeId,
eNoNameRule)
ROLE(CHECK_MENU_ITEM,
@@ -568,6 +613,7 @@ ROLE(CHECK_MENU_ITEM,
IA2_ROLE_CHECK_MENU_ITEM,
java::SessionAccessibility::CLASSNAME_MENUITEM,
IsAccessibilityElementRule::Yes,
+ UIA_MenuItemControlTypeId,
eNameFromSubtreeRule)
ROLE(DATE_EDITOR,
@@ -580,6 +626,7 @@ ROLE(DATE_EDITOR,
IA2_ROLE_DATE_EDITOR,
java::SessionAccessibility::CLASSNAME_SPINNER,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(CHROME_WINDOW,
@@ -592,6 +639,7 @@ ROLE(CHROME_WINDOW,
IA2_ROLE_FRAME,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_WindowControlTypeId,
eNoNameRule)
ROLE(LABEL,
@@ -604,6 +652,7 @@ ROLE(LABEL,
IA2_ROLE_LABEL,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeRule)
ROLE(PASSWORD_TEXT,
@@ -616,6 +665,7 @@ ROLE(PASSWORD_TEXT,
ROLE_SYSTEM_TEXT,
java::SessionAccessibility::CLASSNAME_EDITTEXT,
IsAccessibilityElementRule::Yes,
+ UIA_EditControlTypeId,
eNoNameRule)
ROLE(RADIO_MENU_ITEM,
@@ -628,6 +678,7 @@ ROLE(RADIO_MENU_ITEM,
IA2_ROLE_RADIO_MENU_ITEM,
java::SessionAccessibility::CLASSNAME_MENUITEM,
IsAccessibilityElementRule::Yes,
+ UIA_MenuItemControlTypeId,
eNameFromSubtreeRule)
ROLE(TEXT_CONTAINER,
@@ -640,6 +691,7 @@ ROLE(TEXT_CONTAINER,
IA2_ROLE_TEXT_FRAME,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(TOGGLE_BUTTON,
@@ -652,6 +704,7 @@ ROLE(TOGGLE_BUTTON,
IA2_ROLE_TOGGLE_BUTTON,
java::SessionAccessibility::CLASSNAME_TOGGLEBUTTON,
IsAccessibilityElementRule::Yes,
+ UIA_ButtonControlTypeId,
eNameFromSubtreeRule)
ROLE(TREE_TABLE,
@@ -664,6 +717,7 @@ ROLE(TREE_TABLE,
ROLE_SYSTEM_OUTLINE,
java::SessionAccessibility::CLASSNAME_GRIDVIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_DataGridControlTypeId,
eNoNameRule)
ROLE(PARAGRAPH,
@@ -676,6 +730,7 @@ ROLE(PARAGRAPH,
IA2_ROLE_PARAGRAPH,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TextControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(ENTRY,
@@ -688,6 +743,7 @@ ROLE(ENTRY,
ROLE_SYSTEM_TEXT,
java::SessionAccessibility::CLASSNAME_EDITTEXT,
IsAccessibilityElementRule::Yes,
+ UIA_EditControlTypeId,
eNameFromValueRule)
ROLE(CAPTION,
@@ -700,6 +756,7 @@ ROLE(CAPTION,
IA2_ROLE_CAPTION,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TextControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(NON_NATIVE_DOCUMENT,
@@ -712,6 +769,7 @@ ROLE(NON_NATIVE_DOCUMENT,
ROLE_SYSTEM_DOCUMENT,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_DocumentControlTypeId,
eNoNameRule)
ROLE(HEADING,
@@ -724,6 +782,7 @@ ROLE(HEADING,
IA2_ROLE_HEADING,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildless,
+ UIA_TextControlTypeId,
eNameFromSubtreeRule)
ROLE(SECTION,
@@ -736,6 +795,7 @@ ROLE(SECTION,
IA2_ROLE_SECTION,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(FORM,
@@ -748,6 +808,7 @@ ROLE(FORM,
IA2_ROLE_FORM,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(APP_ROOT,
@@ -760,6 +821,7 @@ ROLE(APP_ROOT,
ROLE_SYSTEM_APPLICATION,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_WindowControlTypeId,
eNoNameRule)
ROLE(PARENT_MENUITEM,
@@ -772,6 +834,7 @@ ROLE(PARENT_MENUITEM,
ROLE_SYSTEM_MENUITEM,
java::SessionAccessibility::CLASSNAME_MENUITEM,
IsAccessibilityElementRule::Yes,
+ UIA_MenuItemControlTypeId,
eNameFromSubtreeRule)
ROLE(COMBOBOX_LIST,
@@ -784,6 +847,7 @@ ROLE(COMBOBOX_LIST,
ROLE_SYSTEM_LIST,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::No,
+ UIA_ListControlTypeId,
eNoNameRule)
ROLE(COMBOBOX_OPTION,
@@ -796,6 +860,7 @@ ROLE(COMBOBOX_OPTION,
ROLE_SYSTEM_LISTITEM,
java::SessionAccessibility::CLASSNAME_MENUITEM,
IsAccessibilityElementRule::Yes,
+ UIA_ListItemControlTypeId,
eNameFromSubtreeRule)
ROLE(IMAGE_MAP,
@@ -808,6 +873,7 @@ ROLE(IMAGE_MAP,
ROLE_SYSTEM_GRAPHIC,
java::SessionAccessibility::CLASSNAME_IMAGE,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_ImageControlTypeId,
eNoNameRule)
ROLE(OPTION,
@@ -820,6 +886,7 @@ ROLE(OPTION,
ROLE_SYSTEM_LISTITEM,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::Yes,
+ UIA_ListItemControlTypeId,
eNameFromSubtreeRule)
ROLE(RICH_OPTION,
@@ -832,6 +899,7 @@ ROLE(RICH_OPTION,
ROLE_SYSTEM_LISTITEM,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_ListItemControlTypeId,
eNameFromSubtreeRule)
ROLE(LISTBOX,
@@ -844,6 +912,7 @@ ROLE(LISTBOX,
ROLE_SYSTEM_LIST,
java::SessionAccessibility::CLASSNAME_LISTVIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_ListControlTypeId,
eNameFromValueRule)
ROLE(FLAT_EQUATION,
@@ -856,6 +925,7 @@ ROLE(FLAT_EQUATION,
ROLE_SYSTEM_EQUATION,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::Yes,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(GRID_CELL,
@@ -868,6 +938,7 @@ ROLE(GRID_CELL,
ROLE_SYSTEM_CELL,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_DataItemControlTypeId,
eNameFromSubtreeRule)
ROLE(NOTE,
@@ -880,6 +951,7 @@ ROLE(NOTE,
IA2_ROLE_NOTE,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(FIGURE,
@@ -892,6 +964,7 @@ ROLE(FIGURE,
ROLE_SYSTEM_GROUPING,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(CHECK_RICH_OPTION,
@@ -904,6 +977,7 @@ ROLE(CHECK_RICH_OPTION,
ROLE_SYSTEM_CHECKBUTTON,
java::SessionAccessibility::CLASSNAME_CHECKBOX,
IsAccessibilityElementRule::Yes,
+ UIA_CheckBoxControlTypeId,
eNameFromSubtreeRule)
ROLE(DEFINITION_LIST,
@@ -916,6 +990,7 @@ ROLE(DEFINITION_LIST,
ROLE_SYSTEM_LIST,
java::SessionAccessibility::CLASSNAME_LISTVIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_ListControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(TERM,
@@ -928,6 +1003,7 @@ ROLE(TERM,
ROLE_SYSTEM_LISTITEM,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TextControlTypeId,
eNameFromSubtreeRule)
ROLE(DEFINITION,
@@ -940,6 +1016,7 @@ ROLE(DEFINITION,
IA2_ROLE_PARAGRAPH,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeRule)
ROLE(KEY,
@@ -952,6 +1029,7 @@ ROLE(KEY,
ROLE_SYSTEM_PUSHBUTTON,
java::SessionAccessibility::CLASSNAME_BUTTON,
IsAccessibilityElementRule::Yes,
+ UIA_ButtonControlTypeId,
eNameFromSubtreeRule)
ROLE(SWITCH,
@@ -964,6 +1042,7 @@ ROLE(SWITCH,
IA2_ROLE_TOGGLE_BUTTON,
java::SessionAccessibility::CLASSNAME_CHECKBOX,
IsAccessibilityElementRule::Yes,
+ UIA_ButtonControlTypeId,
eNameFromSubtreeRule)
ROLE(MATHML_MATH,
@@ -976,6 +1055,7 @@ ROLE(MATHML_MATH,
ROLE_SYSTEM_EQUATION,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_IDENTIFIER,
@@ -988,6 +1068,7 @@ ROLE(MATHML_IDENTIFIER,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeRule)
ROLE(MATHML_NUMBER,
@@ -1000,6 +1081,7 @@ ROLE(MATHML_NUMBER,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeRule)
ROLE(MATHML_OPERATOR,
@@ -1017,6 +1099,7 @@ ROLE(MATHML_OPERATOR,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeRule)
ROLE(MATHML_TEXT,
@@ -1029,6 +1112,7 @@ ROLE(MATHML_TEXT,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeRule)
ROLE(MATHML_STRING_LITERAL,
@@ -1041,6 +1125,7 @@ ROLE(MATHML_STRING_LITERAL,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeRule)
ROLE(MATHML_GLYPH,
@@ -1053,6 +1138,7 @@ ROLE(MATHML_GLYPH,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_IMAGE,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeRule)
ROLE(MATHML_ROW,
@@ -1065,6 +1151,7 @@ ROLE(MATHML_ROW,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_FRACTION,
@@ -1077,6 +1164,7 @@ ROLE(MATHML_FRACTION,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_SQUARE_ROOT,
@@ -1089,6 +1177,7 @@ ROLE(MATHML_SQUARE_ROOT,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_ROOT,
@@ -1101,6 +1190,7 @@ ROLE(MATHML_ROOT,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_ENCLOSED,
@@ -1113,6 +1203,7 @@ ROLE(MATHML_ENCLOSED,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_STYLE,
@@ -1125,6 +1216,7 @@ ROLE(MATHML_STYLE,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_SUB,
@@ -1137,6 +1229,7 @@ ROLE(MATHML_SUB,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_SUP,
@@ -1149,6 +1242,7 @@ ROLE(MATHML_SUP,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_SUB_SUP,
@@ -1161,6 +1255,7 @@ ROLE(MATHML_SUB_SUP,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_UNDER,
@@ -1173,6 +1268,7 @@ ROLE(MATHML_UNDER,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_OVER,
@@ -1185,6 +1281,7 @@ ROLE(MATHML_OVER,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_UNDER_OVER,
@@ -1197,6 +1294,7 @@ ROLE(MATHML_UNDER_OVER,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_MULTISCRIPTS,
@@ -1209,6 +1307,7 @@ ROLE(MATHML_MULTISCRIPTS,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_TABLE,
@@ -1221,6 +1320,7 @@ ROLE(MATHML_TABLE,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_GRIDVIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_LABELED_ROW,
@@ -1233,6 +1333,7 @@ ROLE(MATHML_LABELED_ROW,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_TABLE_ROW,
@@ -1245,6 +1346,7 @@ ROLE(MATHML_TABLE_ROW,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_CELL,
@@ -1257,6 +1359,7 @@ ROLE(MATHML_CELL,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_ACTION,
@@ -1269,6 +1372,7 @@ ROLE(MATHML_ACTION,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_ERROR,
@@ -1281,6 +1385,7 @@ ROLE(MATHML_ERROR,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_STACK,
@@ -1293,6 +1398,7 @@ ROLE(MATHML_STACK,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_LONG_DIVISION,
@@ -1305,6 +1411,7 @@ ROLE(MATHML_LONG_DIVISION,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_STACK_GROUP,
@@ -1317,6 +1424,7 @@ ROLE(MATHML_STACK_GROUP,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_STACK_ROW,
@@ -1329,6 +1437,7 @@ ROLE(MATHML_STACK_ROW,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_STACK_CARRIES,
@@ -1341,6 +1450,7 @@ ROLE(MATHML_STACK_CARRIES,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_STACK_CARRY,
@@ -1353,6 +1463,7 @@ ROLE(MATHML_STACK_CARRY,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MATHML_STACK_LINE,
@@ -1365,6 +1476,7 @@ ROLE(MATHML_STACK_LINE,
IA2_ROLE_UNKNOWN,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(RADIO_GROUP,
@@ -1377,6 +1489,7 @@ ROLE(RADIO_GROUP,
ROLE_SYSTEM_GROUPING,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_ListControlTypeId,
eNoNameRule)
ROLE(TEXT,
@@ -1389,6 +1502,7 @@ ROLE(TEXT,
IA2_ROLE_TEXT_FRAME,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(DETAILS,
@@ -1401,6 +1515,7 @@ ROLE(DETAILS,
ROLE_SYSTEM_GROUPING,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(SUMMARY,
@@ -1413,6 +1528,7 @@ ROLE(SUMMARY,
ROLE_SYSTEM_PUSHBUTTON,
java::SessionAccessibility::CLASSNAME_BUTTON,
IsAccessibilityElementRule::Yes,
+ UIA_ButtonControlTypeId,
eNameFromSubtreeRule)
ROLE(LANDMARK,
@@ -1425,6 +1541,7 @@ ROLE(LANDMARK,
IA2_ROLE_LANDMARK,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(NAVIGATION,
@@ -1437,6 +1554,7 @@ ROLE(NAVIGATION,
IA2_ROLE_LANDMARK,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(FOOTNOTE,
@@ -1449,6 +1567,7 @@ ROLE(FOOTNOTE,
IA2_ROLE_FOOTNOTE,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(ARTICLE,
@@ -1461,6 +1580,7 @@ ROLE(ARTICLE,
ROLE_SYSTEM_DOCUMENT,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(REGION,
@@ -1473,6 +1593,7 @@ ROLE(REGION,
IA2_ROLE_LANDMARK,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
// A composite widget with a text input and popup. Used for ARIA role combobox.
@@ -1487,6 +1608,7 @@ ROLE(EDITCOMBOBOX,
ROLE_SYSTEM_COMBOBOX,
java::SessionAccessibility::CLASSNAME_EDITTEXT,
IsAccessibilityElementRule::Yes,
+ UIA_ComboBoxControlTypeId,
eNameFromValueRule)
ROLE(BLOCKQUOTE,
@@ -1499,6 +1621,7 @@ ROLE(BLOCKQUOTE,
IA2_ROLE_BLOCK_QUOTE,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(CONTENT_DELETION,
@@ -1511,6 +1634,7 @@ ROLE(CONTENT_DELETION,
IA2_ROLE_CONTENT_DELETION,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TextControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(CONTENT_INSERTION,
@@ -1523,6 +1647,7 @@ ROLE(CONTENT_INSERTION,
IA2_ROLE_CONTENT_INSERTION,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TextControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(FORM_LANDMARK,
@@ -1535,6 +1660,7 @@ ROLE(FORM_LANDMARK,
IA2_ROLE_FORM,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(MARK,
@@ -1547,6 +1673,7 @@ ROLE(MARK,
IA2_ROLE_MARK,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(SUGGESTION,
@@ -1559,6 +1686,7 @@ ROLE(SUGGESTION,
IA2_ROLE_SUGGESTION,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(COMMENT,
@@ -1571,6 +1699,7 @@ ROLE(COMMENT,
IA2_ROLE_COMMENT,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNoNameRule)
ROLE(CODE,
@@ -1583,6 +1712,7 @@ ROLE(CODE,
IA2_ROLE_TEXT_FRAME,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TextControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(TIME_EDITOR,
@@ -1595,6 +1725,7 @@ ROLE(TIME_EDITOR,
ROLE_SYSTEM_GROUPING,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(LISTITEM_MARKER,
@@ -1607,6 +1738,7 @@ ROLE(LISTITEM_MARKER,
ROLE_SYSTEM_STATICTEXT,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TextControlTypeId,
eNoNameRule)
ROLE(METER,
@@ -1619,6 +1751,7 @@ ROLE(METER,
ROLE_SYSTEM_PROGRESSBAR,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::Yes,
+ UIA_ProgressBarControlTypeId,
eNameFromValueRule)
ROLE(SUBSCRIPT,
@@ -1631,6 +1764,7 @@ ROLE(SUBSCRIPT,
IA2_ROLE_TEXT_FRAME,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TextControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(SUPERSCRIPT,
@@ -1643,6 +1777,7 @@ ROLE(SUPERSCRIPT,
IA2_ROLE_TEXT_FRAME,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TextControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(EMPHASIS,
@@ -1655,6 +1790,7 @@ ROLE(EMPHASIS,
IA2_ROLE_TEXT_FRAME,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TextControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(STRONG,
@@ -1667,6 +1803,7 @@ ROLE(STRONG,
IA2_ROLE_TEXT_FRAME,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TextControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(TIME,
@@ -1679,6 +1816,7 @@ ROLE(TIME,
ROLE_SYSTEM_GROUPING,
java::SessionAccessibility::CLASSNAME_VIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_TextControlTypeId,
eNameFromSubtreeIfReqRule)
ROLE(GRID,
@@ -1691,5 +1829,19 @@ ROLE(GRID,
ROLE_SYSTEM_TABLE,
java::SessionAccessibility::CLASSNAME_GRIDVIEW,
IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_DataGridControlTypeId,
+ eNameFromSubtreeIfReqRule)
+
+ROLE(ROWGROUP,
+ "rowgroup",
+ nsGkAtoms::rowgroup,
+ ATK_ROLE_PANEL,
+ NSAccessibilityGroupRole,
+ NSAccessibilityUnknownSubrole,
+ ROLE_SYSTEM_GROUPING,
+ ROLE_SYSTEM_GROUPING,
+ java::SessionAccessibility::CLASSNAME_VIEW,
+ IsAccessibilityElementRule::IfChildlessWithNameAndFocusable,
+ UIA_GroupControlTypeId,
eNameFromSubtreeIfReqRule)
// clang-format on
diff --git a/accessible/base/nsAccUtils.cpp b/accessible/base/nsAccUtils.cpp
index 82af56348f..61211068ca 100644
--- a/accessible/base/nsAccUtils.cpp
+++ b/accessible/base/nsAccUtils.cpp
@@ -583,8 +583,9 @@ const nsAttrValue* nsAccUtils::GetARIAAttr(dom::Element* aElement,
bool nsAccUtils::ARIAAttrValueIs(dom::Element* aElement, const nsAtom* aName,
const nsAString& aValue,
nsCaseTreatment aCaseSensitive) {
- if (aElement->AttrValueIs(kNameSpaceID_None, aName, aValue, aCaseSensitive)) {
- return true;
+ if (aElement->HasAttr(kNameSpaceID_None, aName)) {
+ return aElement->AttrValueIs(kNameSpaceID_None, aName, aValue,
+ aCaseSensitive);
}
const auto* defaults = GetARIADefaults(aElement);
if (!defaults) {
@@ -597,8 +598,9 @@ bool nsAccUtils::ARIAAttrValueIs(dom::Element* aElement, const nsAtom* aName,
bool nsAccUtils::ARIAAttrValueIs(dom::Element* aElement, const nsAtom* aName,
const nsAtom* aValue,
nsCaseTreatment aCaseSensitive) {
- if (aElement->AttrValueIs(kNameSpaceID_None, aName, aValue, aCaseSensitive)) {
- return true;
+ if (aElement->HasAttr(kNameSpaceID_None, aName)) {
+ return aElement->AttrValueIs(kNameSpaceID_None, aName, aValue,
+ aCaseSensitive);
}
const auto* defaults = GetARIADefaults(aElement);
if (!defaults) {
diff --git a/accessible/base/nsAccessibilityService.cpp b/accessible/base/nsAccessibilityService.cpp
index d38276572b..615af596a7 100644
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -122,7 +122,7 @@ static LocalAccessible* MaybeCreateSpecificARIAAccessible(
if (!parent) {
return nullptr;
}
- if (!parent->IsTable() && parent->Role() == roles::GROUPING) {
+ if (!parent->IsTable() && parent->Role() == roles::ROWGROUP) {
parent = parent->GetNonGenericParent();
if (!parent) {
return nullptr;
@@ -838,7 +838,8 @@ void nsAccessibilityService::RecreateAccessible(PresShell* aPresShell,
void nsAccessibilityService::GetStringRole(uint32_t aRole, nsAString& aString) {
#define ROLE(geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \
- msaaRole, ia2Role, androidClass, iosIsElement, nameRule) \
+ msaaRole, ia2Role, androidClass, iosIsElement, uiaControlType, \
+ nameRule) \
case roles::geckoRole: \
aString.AssignLiteral(stringRole); \
return;
diff --git a/accessible/base/nsTextEquivUtils.cpp b/accessible/base/nsTextEquivUtils.cpp
index f222930981..769559a2c9 100644
--- a/accessible/base/nsTextEquivUtils.cpp
+++ b/accessible/base/nsTextEquivUtils.cpp
@@ -165,6 +165,7 @@ nsresult nsTextEquivUtils::AppendFromAccessible(Accessible* aAccessible,
// together in final name.
const nsStyleDisplay* display = frame->StyleDisplay();
if (display->IsBlockOutsideStyle() ||
+ display->mDisplay == StyleDisplay::InlineBlock ||
display->mDisplay == StyleDisplay::TableCell) {
isHTMLBlock = true;
if (!aString->IsEmpty()) {
@@ -323,7 +324,8 @@ bool nsTextEquivUtils::AppendString(nsAString* aString,
uint32_t nsTextEquivUtils::GetRoleRule(role aRole) {
#define ROLE(geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \
- msaaRole, ia2Role, androidClass, iosIsElement, nameRule) \
+ msaaRole, ia2Role, androidClass, iosIsElement, uiaControlType, \
+ nameRule) \
case roles::geckoRole: \
return nameRule;
diff --git a/accessible/basetypes/Accessible.cpp b/accessible/basetypes/Accessible.cpp
index de9740dd18..8b433a0ddd 100644
--- a/accessible/basetypes/Accessible.cpp
+++ b/accessible/basetypes/Accessible.cpp
@@ -569,8 +569,7 @@ nsStaticAtom* Accessible::ComputedARIARole() const {
roleMap->roleAtom != nsGkAtoms::form &&
(roleMap->roleRule == kUseNativeRole || roleMap->IsOfType(eLandmark) ||
roleMap->roleAtom == nsGkAtoms::alertdialog ||
- roleMap->roleAtom == nsGkAtoms::feed ||
- roleMap->roleAtom == nsGkAtoms::rowgroup)) {
+ roleMap->roleAtom == nsGkAtoms::feed)) {
// Explicit ARIA role (e.g. specified via the role attribute) which does not
// map to a unique Gecko role.
return roleMap->roleAtom;
@@ -583,18 +582,10 @@ nsStaticAtom* Accessible::ComputedARIARole() const {
// Landmark role from native markup; e.g. <main>, <nav>.
return LandmarkRole();
}
- if (geckoRole == roles::GROUPING) {
- // Gecko doesn't differentiate between group and rowgroup. It uses
- // roles::GROUPING for both.
- nsAtom* tag = TagName();
- if (tag == nsGkAtoms::tbody || tag == nsGkAtoms::tfoot ||
- tag == nsGkAtoms::thead) {
- return nsGkAtoms::rowgroup;
- }
- }
// Role from native markup or layout.
#define ROLE(_geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \
- msaaRole, ia2Role, androidClass, iosIsElement, nameRule) \
+ msaaRole, ia2Role, androidClass, iosIsElement, uiaControlType, \
+ nameRule) \
case roles::_geckoRole: \
return ariaRole;
switch (geckoRole) {
diff --git a/accessible/basetypes/Accessible.h b/accessible/basetypes/Accessible.h
index 77ac0bb4fc..9068115d01 100644
--- a/accessible/basetypes/Accessible.h
+++ b/accessible/basetypes/Accessible.h
@@ -185,6 +185,46 @@ class Accessible {
*/
bool IsBefore(const Accessible* aAcc) const;
+ /**
+ * A utility enum for controlling FindAncestorIf.
+ * Continue: this is not the desired ancestor node, keep searching
+ * Found: this is the desired ancestor node
+ * NotFound: this is not the desired ancestor node, stop searching
+ */
+ enum class AncestorSearchOption { Continue, Found, NotFound };
+ /**
+ * Return a non-generic ancestor for which the given predicate returns
+ * AncestorSearchOption::Found, if any exist. If none exist, return nullptr.
+ * The predicate may choose to return options from AncestorSearchOption to
+ * control the flow of the ancestor search.
+ */
+ template <typename Callable>
+ Accessible* FindAncestorIf(Callable&& aPredicate) const {
+ static_assert(
+ std::is_same_v<std::invoke_result_t<Callable, const Accessible&>,
+ AncestorSearchOption>,
+ "Given callable must return AncestorSearchOption.");
+ static_assert(std::is_invocable_v<Callable, const Accessible&>,
+ "Given callable must accept const Accessible&.");
+ Accessible* search = GetNonGenericParent();
+ while (search) {
+ const AncestorSearchOption option = aPredicate(*search);
+ switch (option) {
+ case AncestorSearchOption::Continue:
+ search = search->GetNonGenericParent();
+ continue;
+ case AncestorSearchOption::Found:
+ return search;
+ case AncestorSearchOption::NotFound:
+ return nullptr;
+ default:
+ MOZ_ASSERT(false, "Unhandled AncestorSearchOption");
+ break;
+ }
+ }
+ return nullptr;
+ }
+
bool IsAncestorOf(const Accessible* aAcc) const {
for (const Accessible* parent = aAcc->Parent(); parent;
parent = parent->Parent()) {
diff --git a/accessible/generic/LocalAccessible.cpp b/accessible/generic/LocalAccessible.cpp
index a758164e2b..aaf0337a1a 100644
--- a/accessible/generic/LocalAccessible.cpp
+++ b/accessible/generic/LocalAccessible.cpp
@@ -744,22 +744,8 @@ LayoutDeviceIntRect LocalAccessible::Bounds() const {
void LocalAccessible::SetSelected(bool aSelect) {
if (!HasOwnContent()) return;
- LocalAccessible* select = nsAccUtils::GetSelectableContainer(this, State());
- if (select) {
- if (select->State() & states::MULTISELECTABLE) {
- if (mContent->IsElement() && ARIARoleMap()) {
- if (aSelect) {
- mContent->AsElement()->SetAttr(
- kNameSpaceID_None, nsGkAtoms::aria_selected, u"true"_ns, true);
- } else {
- mContent->AsElement()->UnsetAttr(kNameSpaceID_None,
- nsGkAtoms::aria_selected, true);
- }
- }
- return;
- }
-
- if (aSelect) TakeFocus();
+ if (nsAccUtils::GetSelectableContainer(this, State()) && aSelect) {
+ TakeFocus();
}
}
@@ -1819,27 +1805,7 @@ double LocalAccessible::CurValue() const {
return checkValue;
}
-bool LocalAccessible::SetCurValue(double aValue) {
- const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
- if (!roleMapEntry || roleMapEntry->valueRule == eNoValue) return false;
-
- const uint32_t kValueCannotChange = states::READONLY | states::UNAVAILABLE;
- if (State() & kValueCannotChange) return false;
-
- double checkValue = MinValue();
- if (!std::isnan(checkValue) && aValue < checkValue) return false;
-
- checkValue = MaxValue();
- if (!std::isnan(checkValue) && aValue > checkValue) return false;
-
- nsAutoString strValue;
- strValue.AppendFloat(aValue);
-
- if (!mContent->IsElement()) return true;
-
- return NS_SUCCEEDED(mContent->AsElement()->SetAttr(
- kNameSpaceID_None, nsGkAtoms::aria_valuenow, strValue, true));
-}
+bool LocalAccessible::SetCurValue(double aValue) { return false; }
role LocalAccessible::FindNextValidARIARole(
std::initializer_list<nsStaticAtom*> aRolesToSkip) const {
@@ -1925,6 +1891,16 @@ role LocalAccessible::ARIATransformRole(role aRole) const {
return roles::COMBOBOX_OPTION;
}
+ // Orphaned option outside the context of a listbox.
+ const Accessible* listbox = FindAncestorIf([](const Accessible& aAcc) {
+ const role accRole = aAcc.Role();
+ return accRole == roles::LISTBOX ? AncestorSearchOption::Found
+ : accRole == roles::GROUPING ? AncestorSearchOption::Continue
+ : AncestorSearchOption::NotFound;
+ });
+ if (!listbox) {
+ return NativeRole();
+ }
} else if (aRole == roles::MENUITEM) {
// Menuitem has a submenu.
if (mContent->IsElement() &&
@@ -1934,6 +1910,30 @@ role LocalAccessible::ARIATransformRole(role aRole) const {
return roles::PARENT_MENUITEM;
}
+ // Orphaned menuitem outside the context of a menu/menubar.
+ const Accessible* menu = FindAncestorIf([](const Accessible& aAcc) {
+ const role accRole = aAcc.Role();
+ return (accRole == roles::MENUBAR || accRole == roles::MENUPOPUP)
+ ? AncestorSearchOption::Found
+ : accRole == roles::GROUPING ? AncestorSearchOption::Continue
+ : AncestorSearchOption::NotFound;
+ });
+ if (!menu) {
+ return NativeRole();
+ }
+ } else if (aRole == roles::RADIO_MENU_ITEM ||
+ aRole == roles::CHECK_MENU_ITEM) {
+ // Orphaned radio/checkbox menuitem outside the context of a menu/menubar.
+ const Accessible* menu = FindAncestorIf([](const Accessible& aAcc) {
+ const role accRole = aAcc.Role();
+ return (accRole == roles::MENUBAR || accRole == roles::MENUPOPUP)
+ ? AncestorSearchOption::Found
+ : accRole == roles::GROUPING ? AncestorSearchOption::Continue
+ : AncestorSearchOption::NotFound;
+ });
+ if (!menu) {
+ return NativeRole();
+ }
} else if (aRole == roles::CELL) {
// A cell inside an ancestor table element that has a grid role needs a
// gridcell role
@@ -1942,6 +1942,63 @@ role LocalAccessible::ARIATransformRole(role aRole) const {
if (table && table->IsARIARole(nsGkAtoms::grid)) {
return roles::GRID_CELL;
}
+ } else if (aRole == roles::ROW) {
+ // Orphaned rows outside the context of a table.
+ const LocalAccessible* table = nsAccUtils::TableFor(this);
+ if (!table) {
+ return NativeRole();
+ }
+ } else if (aRole == roles::ROWGROUP) {
+ // Orphaned rowgroups outside the context of a table.
+ const Accessible* table = FindAncestorIf([](const Accessible& aAcc) {
+ return aAcc.IsTable() ? AncestorSearchOption::Found
+ : AncestorSearchOption::NotFound;
+ });
+ if (!table) {
+ return NativeRole();
+ }
+ } else if (aRole == roles::GRID_CELL || aRole == roles::ROWHEADER ||
+ aRole == roles::COLUMNHEADER) {
+ // Orphaned gridcell/rowheader/columnheader outside the context of a row.
+ const Accessible* row = FindAncestorIf([](const Accessible& aAcc) {
+ return aAcc.IsTableRow() ? AncestorSearchOption::Found
+ : AncestorSearchOption::NotFound;
+ });
+ if (!row) {
+ return NativeRole();
+ }
+ } else if (aRole == roles::LISTITEM) {
+ // doc-biblioentry and doc-endnote should not be treated as listitems.
+ const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+ if (!roleMapEntry || (roleMapEntry->roleAtom != nsGkAtoms::docBiblioentry &&
+ roleMapEntry->roleAtom != nsGkAtoms::docEndnote)) {
+ // Orphaned listitem outside the context of a list.
+ const Accessible* list = FindAncestorIf([](const Accessible& aAcc) {
+ return aAcc.IsList() ? AncestorSearchOption::Found
+ : AncestorSearchOption::Continue;
+ });
+ if (!list) {
+ return NativeRole();
+ }
+ }
+ } else if (aRole == roles::PAGETAB) {
+ // Orphaned tab outside the context of a tablist.
+ const Accessible* tablist = FindAncestorIf([](const Accessible& aAcc) {
+ return aAcc.Role() == roles::PAGETABLIST ? AncestorSearchOption::Found
+ : AncestorSearchOption::NotFound;
+ });
+ if (!tablist) {
+ return NativeRole();
+ }
+ } else if (aRole == roles::OUTLINEITEM) {
+ // Orphaned treeitem outside the context of a tree.
+ const Accessible* tree = FindAncestorIf([](const Accessible& aAcc) {
+ return aAcc.Role() == roles::OUTLINE ? AncestorSearchOption::Found
+ : AncestorSearchOption::Continue;
+ });
+ if (!tree) {
+ return NativeRole();
+ }
}
return aRole;
@@ -2149,12 +2206,14 @@ Relation LocalAccessible::RelationByType(RelationType aType) const {
if (roleMapEntry && (roleMapEntry->role == roles::OUTLINEITEM ||
roleMapEntry->role == roles::LISTITEM ||
roleMapEntry->role == roles::ROW)) {
- Accessible* parent = const_cast<LocalAccessible*>(this)
- ->GetOrCreateGroupInfo()
- ->ConceptualParent();
- if (parent) {
- MOZ_ASSERT(parent->IsLocal());
- rel.AppendTarget(parent->AsLocal());
+ AccGroupInfo* groupInfo =
+ const_cast<LocalAccessible*>(this)->GetOrCreateGroupInfo();
+ if (groupInfo) {
+ Accessible* parent = groupInfo->ConceptualParent();
+ if (parent) {
+ MOZ_ASSERT(parent->IsLocal());
+ rel.AppendTarget(parent->AsLocal());
+ }
}
}
@@ -2274,7 +2333,7 @@ Relation LocalAccessible::RelationByType(RelationType aType) const {
}
// If this node is an anchor element, query its hash to find the
// target.
- nsAutoString hash;
+ nsAutoCString hash;
anchor->GetHash(hash);
if (hash.IsEmpty()) {
return rel;
@@ -2282,11 +2341,11 @@ Relation LocalAccessible::RelationByType(RelationType aType) const {
// GetHash returns an ID or name with a leading '#', trim it so we can
// search the doc by ID or name alone.
- hash.Trim("#");
- if (dom::Element* elm = mContent->OwnerDoc()->GetElementById(hash)) {
+ NS_ConvertUTF8toUTF16 hash16(Substring(hash, 1));
+ if (dom::Element* elm = mContent->OwnerDoc()->GetElementById(hash16)) {
rel.AppendTarget(mDoc->GetAccessibleOrContainer(elm));
} else if (nsCOMPtr<nsINodeList> list =
- mContent->OwnerDoc()->GetElementsByName(hash)) {
+ mContent->OwnerDoc()->GetElementsByName(hash16)) {
// Loop through the named nodes looking for the first anchor
uint32_t length = list->Length();
for (uint32_t i = 0; i < length; i++) {
@@ -3069,15 +3128,7 @@ LocalAccessible* LocalAccessible::CurrentItem() const {
return nullptr;
}
-void LocalAccessible::SetCurrentItem(const LocalAccessible* aItem) {
- nsAtom* id = aItem->GetContent()->GetID();
- if (id) {
- nsAutoString idStr;
- id->ToString(idStr);
- mContent->AsElement()->SetAttr(
- kNameSpaceID_None, nsGkAtoms::aria_activedescendant, idStr, true);
- }
-}
+void LocalAccessible::SetCurrentItem(const LocalAccessible* aItem) {}
LocalAccessible* LocalAccessible::ContainerWidget() const {
if (HasARIARole() && mContent->HasID()) {
diff --git a/accessible/html/HTMLSelectAccessible.cpp b/accessible/html/HTMLSelectAccessible.cpp
index f8fb4180c7..02d449df36 100644
--- a/accessible/html/HTMLSelectAccessible.cpp
+++ b/accessible/html/HTMLSelectAccessible.cpp
@@ -6,6 +6,7 @@
#include "HTMLSelectAccessible.h"
#include "LocalAccessible-inl.h"
+#include "DocAccessible-inl.h"
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "DocAccessible.h"
diff --git a/accessible/html/HTMLTableAccessible.cpp b/accessible/html/HTMLTableAccessible.cpp
index 2c3dc6b82d..f4b8f9964a 100644
--- a/accessible/html/HTMLTableAccessible.cpp
+++ b/accessible/html/HTMLTableAccessible.cpp
@@ -12,6 +12,7 @@
#include "ARIAMap.h"
#include "CacheConstants.h"
#include "LocalAccessible-inl.h"
+#include "DocAccessible-inl.h"
#include "nsTextEquivUtils.h"
#include "Relation.h"
#include "mozilla/a11y/Role.h"
diff --git a/accessible/interfaces/nsIAccessibleCaretMoveEvent.idl b/accessible/interfaces/nsIAccessibleCaretMoveEvent.idl
index 4cdece16cc..2f750002a2 100644
--- a/accessible/interfaces/nsIAccessibleCaretMoveEvent.idl
+++ b/accessible/interfaces/nsIAccessibleCaretMoveEvent.idl
@@ -19,12 +19,12 @@ interface nsIAccessibleCaretMoveEvent: nsIAccessibleEvent
/**
* Return true if there is no selection.
*/
- readonly attribute bool isSelectionCollapsed;
+ readonly attribute boolean isSelectionCollapsed;
/**
* Return true if the caret is at the end of a line.
*/
- readonly attribute bool isAtEndOfLine;
+ readonly attribute boolean isAtEndOfLine;
/**
* Return caret move granularity.
diff --git a/accessible/interfaces/nsIAccessibleMacInterface.idl b/accessible/interfaces/nsIAccessibleMacInterface.idl
index 384d09d5f0..952ac2a9fe 100644
--- a/accessible/interfaces/nsIAccessibleMacInterface.idl
+++ b/accessible/interfaces/nsIAccessibleMacInterface.idl
@@ -67,7 +67,7 @@ interface nsIAccessibleMacInterface : nsISupports
* Returns true if the given attribute is settable on the object.
* Emulates `AXUIElementIsAttributeSettable`.
**/
- bool isAttributeSettable(in AString attributeName);
+ boolean isAttributeSettable(in AString attributeName);
/**
* Sets the given attribute with the given value on the object.
diff --git a/accessible/interfaces/nsIAccessibleRole.idl b/accessible/interfaces/nsIAccessibleRole.idl
index 9c3376ab48..192f93f01d 100644
--- a/accessible/interfaces/nsIAccessibleRole.idl
+++ b/accessible/interfaces/nsIAccessibleRole.idl
@@ -806,4 +806,11 @@ interface nsIAccessibleRole : nsISupports
* by using methods of two-dimensional navigation.
*/
const unsigned long ROLE_GRID = 138;
+
+ /**
+ * Represents a structure containing one or more row elements in a tabular
+ * container. It is the structural equivalent to the thead, tfoot, and tbody
+ * elements in an HTML table element.
+ */
+ const unsigned long ROLE_ROWGROUP = 139;
};
diff --git a/accessible/ios/MUIAccessible.mm b/accessible/ios/MUIAccessible.mm
index 46c4712e2e..d72ed77172 100644
--- a/accessible/ios/MUIAccessible.mm
+++ b/accessible/ios/MUIAccessible.mm
@@ -159,7 +159,8 @@ static bool isAccessibilityElementInternal(Accessible* aAccessible) {
IsAccessibilityElementRule rule = IsAccessibilityElementRule::No;
#define ROLE(_geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \
- msaaRole, ia2Role, androidClass, iosIsElement, nameRule) \
+ msaaRole, ia2Role, androidClass, iosIsElement, uiaControlType, \
+ nameRule) \
case roles::_geckoRole: \
rule = iosIsElement; \
break;
diff --git a/accessible/mac/MOXAccessibleProtocol.h b/accessible/mac/MOXAccessibleProtocol.h
index e3535c1628..51ad3ccef4 100644
--- a/accessible/mac/MOXAccessibleProtocol.h
+++ b/accessible/mac/MOXAccessibleProtocol.h
@@ -335,6 +335,9 @@
// AXARIARelevant
- (NSString* _Nullable)moxARIARelevant;
+// AXPlaceholderValue
+- (NSString* _Nullable)moxPlaceholderValue;
+
// AXMozDebugDescription
- (NSString* _Nullable)moxMozDebugDescription;
diff --git a/accessible/mac/mozAccessible.h b/accessible/mac/mozAccessible.h
index 175e25d508..c5e3b7d4f8 100644
--- a/accessible/mac/mozAccessible.h
+++ b/accessible/mac/mozAccessible.h
@@ -216,6 +216,9 @@ enum CheckedState {
- (NSString*)moxARIARelevant;
// override
+- (NSString*)moxPlaceholderValue;
+
+// override
- (id)moxTitleUIElement;
// override
diff --git a/accessible/mac/mozAccessible.mm b/accessible/mac/mozAccessible.mm
index aa98496511..0609cc7afc 100644
--- a/accessible/mac/mozAccessible.mm
+++ b/accessible/mac/mozAccessible.mm
@@ -295,7 +295,8 @@ using namespace mozilla::a11y;
- (NSString*)moxRole {
#define ROLE(geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \
- msaaRole, ia2Role, androidClass, iosIsElement, nameRule) \
+ msaaRole, ia2Role, androidClass, iosIsElement, uiaControlType, \
+ nameRule) \
case roles::geckoRole: \
return macRole;
@@ -366,7 +367,8 @@ using namespace mozilla::a11y;
}
#define ROLE(geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \
- msaaRole, ia2Role, androidClass, iosIsElement, nameRule) \
+ msaaRole, ia2Role, androidClass, iosIsElement, uiaControlType, \
+ nameRule) \
case roles::geckoRole: \
if (![macSubrole isEqualToString:NSAccessibilityUnknownSubrole]) { \
return macSubrole; \
@@ -646,6 +648,16 @@ struct RoleDescrComparator {
return @"additions text";
}
+- (NSString*)moxPlaceholderValue {
+ // First, check for plaecholder HTML attribute
+ if (NSString* placeholder = utils::GetAccAttr(self, nsGkAtoms::placeholder)) {
+ return placeholder;
+ }
+
+ // If no placeholder HTML attribute, check for the aria version.
+ return utils::GetAccAttr(self, nsGkAtoms::aria_placeholder);
+}
+
- (id)moxTitleUIElement {
MOZ_ASSERT(mGeckoAccessible);
diff --git a/accessible/tests/browser/.eslintrc.js b/accessible/tests/browser/.eslintrc.js
index 528797cb91..96c0859468 100644
--- a/accessible/tests/browser/.eslintrc.js
+++ b/accessible/tests/browser/.eslintrc.js
@@ -18,7 +18,7 @@ module.exports = {
"no-proto": "error",
"no-return-assign": "error",
"no-shadow": "error",
- "no-unused-vars": ["error", { vars: "all", args: "none" }],
+ "no-unused-vars": ["error", { vars: "all", argsIgnorePattern: "^_" }],
"one-var": ["error", "never"],
radix: "error",
strict: ["error", "global"],
diff --git a/accessible/tests/browser/bounds/browser.toml b/accessible/tests/browser/bounds/browser.toml
index da1fe37a1e..c4c421cdeb 100644
--- a/accessible/tests/browser/bounds/browser.toml
+++ b/accessible/tests/browser/bounds/browser.toml
@@ -3,7 +3,6 @@ subsuite = "a11y"
support-files = [
"head.js",
"!/accessible/tests/browser/shared-head.js",
- "!/accessible/tests/browser/*.jsm",
"!/accessible/tests/mochitest/*.js",
"!/accessible/tests/mochitest/letters.gif",
]
diff --git a/accessible/tests/browser/e10s/browser.toml b/accessible/tests/browser/e10s/browser.toml
index 914f839993..dff9b1c712 100644
--- a/accessible/tests/browser/e10s/browser.toml
+++ b/accessible/tests/browser/e10s/browser.toml
@@ -10,7 +10,6 @@ support-files = [
"doc_treeupdate_whitespace.html",
"fonts/Ahem.sjs",
"!/accessible/tests/browser/shared-head.js",
- "!/accessible/tests/browser/*.jsm",
"!/accessible/tests/mochitest/*.js",
"!/accessible/tests/mochitest/events/slow_image.sjs",
"!/accessible/tests/mochitest/letters.gif",
diff --git a/accessible/tests/browser/e10s/browser_aria_activedescendant.js b/accessible/tests/browser/e10s/browser_aria_activedescendant.js
index f58c5aab39..fadda0f964 100644
--- a/accessible/tests/browser/e10s/browser_aria_activedescendant.js
+++ b/accessible/tests/browser/e10s/browser_aria_activedescendant.js
@@ -277,7 +277,7 @@ async function basicListboxTest(browser, elementReflection) {
addAccessibleTask(
LISTBOX_MARKUP,
- async function (browser, docAcc) {
+ async function (browser) {
info("Test aria-activedescendant content attribute");
await basicListboxTest(browser, false);
@@ -303,7 +303,7 @@ addAccessibleTask(
addAccessibleTask(
LISTBOX_MARKUP,
- async function (browser, docAcc) {
+ async function (browser) {
info("Test ariaActiveDescendantElement element reflection");
await basicListboxTest(browser, true);
},
@@ -316,7 +316,7 @@ addAccessibleTask(
<div role="listbox">
<div role="option" id="activedesc_nondesc_option">option</div>
</div>`,
- async function (browser, docAcc) {
+ async function (browser) {
info("Test aria-activedescendant non-descendant");
await synthFocus(
browser,
@@ -348,7 +348,7 @@ addAccessibleTask(
item.setAttribute("role", "option");
listbox.appendChild(item);
</script>`,
- async function (browser, docAcc) {
+ async function (browser) {
info("Test aria-activedescendant in shadow root");
// We want to retrieve elements using their IDs inside the shadow root, so
// we define a custom get element by ID method that our utility functions
@@ -448,7 +448,7 @@ customElements.define("custom-listbox",
}
);
</script>`,
- async function (browser, docAcc) {
+ async function (browser) {
await synthFocus(browser, "custom-listbox1", "l1_3");
let evtProm = Promise.all([
diff --git a/accessible/tests/browser/e10s/browser_caching_value.js b/accessible/tests/browser/e10s/browser_caching_value.js
index 2b968b5948..926110199e 100644
--- a/accessible/tests/browser/e10s/browser_caching_value.js
+++ b/accessible/tests/browser/e10s/browser_caching_value.js
@@ -46,16 +46,6 @@ const valueTests = [
expected: ["5", 5, 0, 7, 0],
},
{
- desc: "Value should change when currentValue is called",
- id: "slider",
- async action(browser, acc) {
- acc.QueryInterface(nsIAccessibleValue);
- acc.currentValue = 4;
- },
- waitFor: EVENT_VALUE_CHANGE,
- expected: ["4", 4, 0, 7, 0],
- },
- {
desc: "Value should change when @aria-valuenow is updated",
id: "slider",
attrs: [
diff --git a/accessible/tests/browser/events/browser.toml b/accessible/tests/browser/events/browser.toml
index 7ec3c3621a..ffbb96cfbb 100644
--- a/accessible/tests/browser/events/browser.toml
+++ b/accessible/tests/browser/events/browser.toml
@@ -4,12 +4,13 @@ support-files = [
"head.js",
"!/accessible/tests/browser/shared-head.js",
"!/accessible/tests/mochitest/*.js",
- "!/accessible/tests/browser/*.jsm",
]
prefs = ["javascript.options.asyncstack_capture_debuggee_only=false"]
["browser_alert.js"]
+["browser_content_prompt.js"]
+
["browser_test_A11yUtils_announce.js"]
["browser_test_caret_move_granularity.js"]
diff --git a/accessible/tests/browser/events/browser_content_prompt.js b/accessible/tests/browser/events/browser_content_prompt.js
new file mode 100644
index 0000000000..7677c0258a
--- /dev/null
+++ b/accessible/tests/browser/events/browser_content_prompt.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ https://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Want to test relations.
+/* import-globals-from ../../mochitest/name.js */
+/* import-globals-from ../../mochitest/relations.js */
+/* import-globals-from ../../mochitest/role.js */
+loadScripts(
+ { name: "relations.js", dir: MOCHITESTS_DIR },
+ { name: "name.js", dir: MOCHITESTS_DIR },
+ { name: "role.js", dir: MOCHITESTS_DIR }
+);
+
+addAccessibleTask(``, async function (browser) {
+ info("Showing alert");
+ let shown = waitForEvent(
+ EVENT_SHOW,
+ evt => evt.accessible.role == ROLE_INTERNAL_FRAME
+ );
+ // Let's make sure the dialog content gets focus.
+ // On macOS, we unfortunately focus the label. We focus the OK button on
+ // all other platforms. See https://phabricator.services.mozilla.com/D204908
+ // for more discussion.
+ let expectedRole =
+ AppConstants.platform == "macosx" ? ROLE_LABEL : ROLE_PUSHBUTTON;
+ let focused = waitForEvent(EVENT_FOCUS, evt => {
+ return evt.accessible.role == expectedRole;
+ });
+ await invokeContentTask(browser, [], () => {
+ // Use setTimeout to avoid blocking the return of the content task
+ // on the alert, which is otherwise synchronous.
+ content.setTimeout(() => content.alert("test"), 0);
+ });
+ const frame = (await shown).accessible;
+ const focusedEl = (await focused).accessible;
+ ok(true, "Dialog shown and something got focused");
+ let dialog = getAccessible(focusedEl.DOMNode.ownerDocument);
+ testRole(dialog, ROLE_DIALOG);
+ let infoBody = focusedEl.DOMNode.ownerDocument.getElementById("infoBody");
+ testRelation(dialog, RELATION_DESCRIBED_BY, infoBody);
+ testDescr(dialog, "test ");
+ info("Dismissing alert");
+ let hidden = waitForEvent(EVENT_HIDE, frame);
+ EventUtils.synthesizeKey("KEY_Escape", {}, frame.DOMNode.contentWindow);
+ await hidden;
+});
diff --git a/accessible/tests/browser/fission/browser.toml b/accessible/tests/browser/fission/browser.toml
index 0332573db9..f795ec6b3d 100644
--- a/accessible/tests/browser/fission/browser.toml
+++ b/accessible/tests/browser/fission/browser.toml
@@ -3,7 +3,6 @@ subsuite = "a11y"
support-files = [
"head.js",
"!/accessible/tests/browser/shared-head.js",
- "!/accessible/tests/browser/*.jsm",
"!/accessible/tests/mochitest/*.js",
]
prefs = ["javascript.options.asyncstack_capture_debuggee_only=false"]
diff --git a/accessible/tests/browser/hittest/browser.toml b/accessible/tests/browser/hittest/browser.toml
index 7f82a6ff49..894bf05c39 100644
--- a/accessible/tests/browser/hittest/browser.toml
+++ b/accessible/tests/browser/hittest/browser.toml
@@ -3,7 +3,6 @@ subsuite = "a11y"
support-files = [
"head.js",
"!/accessible/tests/browser/shared-head.js",
- "!/accessible/tests/browser/*.jsm",
"!/accessible/tests/mochitest/*.js",
"!/accessible/tests/mochitest/letters.gif",
]
diff --git a/accessible/tests/browser/mac/browser.toml b/accessible/tests/browser/mac/browser.toml
index b180a42ab7..227575fb4d 100644
--- a/accessible/tests/browser/mac/browser.toml
+++ b/accessible/tests/browser/mac/browser.toml
@@ -9,7 +9,6 @@ support-files = [
"doc_menulist.xhtml",
"doc_tree.xhtml",
"!/accessible/tests/browser/shared-head.js",
- "!/accessible/tests/browser/*.jsm",
"!/accessible/tests/mochitest/*.js",
"!/accessible/tests/mochitest/letters.gif",
"!/accessible/tests/mochitest/moz.png",
@@ -29,6 +28,8 @@ https_first_disabled = true
["browser_aria_haspopup.js"]
+["browser_aria_placeholder.js"]
+
["browser_aria_setsize.js"]
["browser_attributed_text.js"]
diff --git a/accessible/tests/browser/mac/browser_aria_placeholder.js b/accessible/tests/browser/mac/browser_aria_placeholder.js
new file mode 100644
index 0000000000..e5102fd093
--- /dev/null
+++ b/accessible/tests/browser/mac/browser_aria_placeholder.js
@@ -0,0 +1,70 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/**
+ * Test that inputs with placeholder text expose it via AXPlaceholderValue and
+ * correctly _avoid_ exposing it via AXTItle, AXValue, or AXDescription. Verify AXPlaceholderValue is not exposed when the placeholder is used as the name.
+ */
+addAccessibleTask(
+ `
+ <input id="input" placeholder="Name"><br>
+ <label for="input2">Enter Name</label><input id="input2" placeholder="Name" value="Elmer Fudd">
+ `,
+ (browser, accDoc) => {
+ let input = getNativeInterface(accDoc, "input");
+ let input2 = getNativeInterface(accDoc, "input2");
+
+ is(
+ input.getAttributeValue("AXPlaceholderValue"),
+ null,
+ "Placeholder is used as name, so no AXPlaceholderValue is stored."
+ );
+ is(input.getAttributeValue("AXDescription"), "Name");
+ is(input.getAttributeValue("AXTitle"), "", "Correct title");
+ is(input.getAttributeValue("AXValue"), "", "Correct value");
+
+ is(
+ input2.getAttributeValue("AXPlaceholderValue"),
+ "Name",
+ "Correct placeholder value in presence of value"
+ );
+ is(
+ input2.getAttributeValue("AXDescription"),
+ "Enter Name",
+ "Correct label"
+ );
+ is(input2.getAttributeValue("AXTitle"), "", "Correct title");
+ is(input2.getAttributeValue("AXValue"), "Elmer Fudd", "Correct value");
+ }
+);
+
+/**
+ * Test that aria-placeholder gets exposed via AXPlaceholderValue and correctly
+ * contributes to AXValue (but not title or description).
+ */
+addAccessibleTask(
+ `
+ <span id="date-of-birth">Birthday</span>
+ <div
+ id="bday"
+ contenteditable
+ role="textbox"
+ aria-labelledby="date-of-birth"
+ aria-placeholder="MM-DD-YYYY">MM-DD-YYYY</div>
+ `,
+ (browser, accDoc) => {
+ let bday = getNativeInterface(accDoc, "bday");
+
+ is(
+ bday.getAttributeValue("AXPlaceholderValue"),
+ "MM-DD-YYYY",
+ "Correct placeholder value"
+ );
+ is(bday.getAttributeValue("AXDescription"), "Birthday", "Correct label");
+ is(bday.getAttributeValue("AXTitle"), "", "Correct title");
+ is(bday.getAttributeValue("AXValue"), "MM-DD-YYYY", "Correct value");
+ }
+);
diff --git a/accessible/tests/browser/mac/browser_roles_elements.js b/accessible/tests/browser/mac/browser_roles_elements.js
index b6049e7afd..65caf308c4 100644
--- a/accessible/tests/browser/mac/browser_roles_elements.js
+++ b/accessible/tests/browser/mac/browser_roles_elements.js
@@ -73,8 +73,8 @@ addAccessibleTask(
<div id="switch" role="switch"></div>
<div id="timer" role="timer"></div>
<div id="tooltip" role="tooltip"></div>
- <input type="radio" role="menuitemradio" id="menuitemradio">
- <input type="checkbox" role="menuitemcheckbox" id="menuitemcheckbox">
+ <div role="menu"><input type="radio" role="menuitemradio" id="menuitemradio"></div>
+ <div role="menu"><input type="checkbox" role="menuitemcheckbox" id="menuitemcheckbox"></div>
<input type="datetime-local" id="datetime">
<!-- text entries -->
diff --git a/accessible/tests/browser/mac/browser_selectables.js b/accessible/tests/browser/mac/browser_selectables.js
index af88c2e136..cc489e566d 100644
--- a/accessible/tests/browser/mac/browser_selectables.js
+++ b/accessible/tests/browser/mac/browser_selectables.js
@@ -300,9 +300,6 @@ addAccessibleTask(
async (browser, accDoc) => {
let select = getNativeInterface(accDoc, "select");
let one = getNativeInterface(accDoc, "one");
- let two = getNativeInterface(accDoc, "two");
- let three = getNativeInterface(accDoc, "three");
- let four = getNativeInterface(accDoc, "four");
is(
select.getAttributeValue("AXTitle"),
@@ -339,25 +336,5 @@ addAccessibleTask(
});
await evt;
is(select.getAttributeValue("AXSelectedChildren").length, 0);
- evt = waitForMacEvent("AXSelectedChildrenChanged");
- three.setAttributeValue("AXSelected", true);
- await evt;
- is(select.getAttributeValue("AXSelectedChildren").length, 1);
- ok(getSelectedIds(select).includes("three"), "'three' is selected");
- evt = waitForMacEvent("AXSelectedChildrenChanged");
- select.setAttributeValue("AXSelectedChildren", [one, two]);
- await evt;
- await untilCacheOk(() => {
- let ids = getSelectedIds(select);
- return ids[0] == "one" && ids[1] == "two";
- }, "Got correct selected children");
-
- evt = waitForMacEvent("AXSelectedChildrenChanged");
- select.setAttributeValue("AXSelectedChildren", [three, two, four]);
- await evt;
- await untilCacheOk(() => {
- let ids = getSelectedIds(select);
- return ids[0] == "two" && ids[1] == "three";
- }, "Got correct selected children");
}
);
diff --git a/accessible/tests/browser/role/browser_computedARIARole.js b/accessible/tests/browser/role/browser_computedARIARole.js
index 50cfe43c98..a87d0a0eae 100644
--- a/accessible/tests/browser/role/browser_computedARIARole.js
+++ b/accessible/tests/browser/role/browser_computedARIARole.js
@@ -14,7 +14,9 @@ addAccessibleTask(
<div id="ariaDirectory" role="directory">ARIA directory</div>
<div id="ariaAlertdialog" role="alertdialog">ARIA alertdialog</div>
<div id="ariaFeed" role="feed">ARIA feed</div>
-<div id="ariaRowgroup" role="rowgroup">ARIA rowgroup</div>
+<div role="table">
+ <div id="ariaRowgroup" role="rowgroup">ARIA rowgroup</div>
+</div>
<div id="ariaSearchbox" role="searchbox">ARIA searchbox</div>
<div id="ariaUnknown" role="unknown">unknown ARIA role</div>
<button id="htmlButton">HTML button</button>
diff --git a/accessible/tests/browser/scroll/browser.toml b/accessible/tests/browser/scroll/browser.toml
index ef637fe9a5..390e07db8e 100644
--- a/accessible/tests/browser/scroll/browser.toml
+++ b/accessible/tests/browser/scroll/browser.toml
@@ -3,7 +3,6 @@ subsuite = "a11y"
support-files = [
"head.js",
"!/accessible/tests/browser/shared-head.js",
- "!/accessible/tests/browser/*.jsm",
"!/accessible/tests/mochitest/*.js",
]
prefs = ["javascript.options.asyncstack_capture_debuggee_only=false"]
diff --git a/accessible/tests/browser/selectable/browser.toml b/accessible/tests/browser/selectable/browser.toml
index 38a13c25f4..144555b6a0 100644
--- a/accessible/tests/browser/selectable/browser.toml
+++ b/accessible/tests/browser/selectable/browser.toml
@@ -3,7 +3,6 @@ subsuite = "a11y"
support-files = [
"head.js",
"!/accessible/tests/browser/shared-head.js",
- "!/accessible/tests/browser/*.jsm",
"!/accessible/tests/mochitest/*.js",
]
prefs = ["javascript.options.asyncstack_capture_debuggee_only=false"]
diff --git a/accessible/tests/browser/selectable/browser_test_aria_select.js b/accessible/tests/browser/selectable/browser_test_aria_select.js
index f52603d1cb..dbc36956f8 100644
--- a/accessible/tests/browser/selectable/browser_test_aria_select.js
+++ b/accessible/tests/browser/selectable/browser_test_aria_select.js
@@ -72,16 +72,16 @@ addAccessibleTask(
// role="tablist" aria-multiselectable
addAccessibleTask(
`<div role="tablist" id="tablist" aria-multiselectable="true">
- <div role="tab" id="tab_multi1">tab1</div>
+ <div role="tab" id="tab_multi1" aria-selected="true">tab1</div>
<div role="tab" id="tab_multi2">tab2</div>
+ <div role="tab" id="tab_multi3" aria-selected="true">tab3</div>
</div>`,
async function (browser, docAcc) {
info('role="tablist" aria-multiselectable');
let tablist = findAccessibleChildByID(docAcc, "tablist", [
nsIAccessibleSelectable,
]);
-
- await testMultiSelectable(tablist, ["tab_multi1", "tab_multi2"]);
+ testSelectableSelection(tablist, ["tab_multi1", "tab_multi3"]);
},
{
chrome: true,
@@ -95,16 +95,16 @@ addAccessibleTask(
// role="listbox" aria-multiselectable
addAccessibleTask(
`<div role="listbox" id="listbox" aria-multiselectable="true">
- <div role="option" id="listbox2_item1">item1</div>
+ <div role="option" id="listbox2_item1" aria-selected="true">item1</div>
<div role="option" id="listbox2_item2">item2</div>
+ <div role="option" id="listbox2_item3" aria-selected="true">item2</div>
</div>`,
async function (browser, docAcc) {
info('role="listbox" aria-multiselectable');
let listbox = findAccessibleChildByID(docAcc, "listbox", [
nsIAccessibleSelectable,
]);
-
- await testMultiSelectable(listbox, ["listbox2_item1", "listbox2_item2"]);
+ testSelectableSelection(listbox, ["listbox2_item1", "listbox2_item3"]);
},
{
chrome: true,
@@ -122,7 +122,7 @@ addAccessibleTask(
<thead>
<tr>
<th tabindex="-1" role="columnheader" id="grid_colhead1"
- style="width:6em">Entry #</th>
+ style="width:6em" aria-selected="true">Entry #</th>
<th tabindex="-1" role="columnheader" id="grid_colhead2"
style="width:10em">Date</th>
<th tabindex="-1" role="columnheader" id="grid_colhead3"
@@ -134,7 +134,7 @@ addAccessibleTask(
<td tabindex="-1" role="rowheader" id="grid_rowhead"
aria-readonly="true">1</td>
<td tabindex="-1" role="gridcell" id="grid_cell1"
- aria-selected="false">03/14/05</td>
+ aria-selected="true">03/14/05</td>
<td tabindex="-1" role="gridcell" id="grid_cell2"
aria-selected="false">Conference Fee</td>
</tr>
@@ -145,15 +145,7 @@ addAccessibleTask(
let grid = findAccessibleChildByID(docAcc, "grid", [
nsIAccessibleSelectable,
]);
-
- await testMultiSelectable(grid, [
- "grid_colhead1",
- "grid_colhead2",
- "grid_colhead3",
- "grid_rowhead",
- "grid_cell1",
- "grid_cell2",
- ]);
+ testSelectableSelection(grid, ["grid_colhead1", "grid_cell1"]);
},
{
chrome: true,
diff --git a/accessible/tests/browser/states/browser.toml b/accessible/tests/browser/states/browser.toml
index fe29597d27..6b2d20ae14 100644
--- a/accessible/tests/browser/states/browser.toml
+++ b/accessible/tests/browser/states/browser.toml
@@ -4,7 +4,6 @@ support-files = [
"head.js",
"!/accessible/tests/browser/shared-head.js",
"!/accessible/tests/mochitest/*.js",
- "!/accessible/tests/browser/*.jsm",
]
prefs = ["javascript.options.asyncstack_capture_debuggee_only=false"]
diff --git a/accessible/tests/browser/text/browser.toml b/accessible/tests/browser/text/browser.toml
index c04531b126..4bc64866fc 100644
--- a/accessible/tests/browser/text/browser.toml
+++ b/accessible/tests/browser/text/browser.toml
@@ -3,7 +3,6 @@ subsuite = "a11y"
support-files = [
"head.js",
"!/accessible/tests/browser/shared-head.js",
- "!/accessible/tests/browser/*.jsm",
"!/accessible/tests/mochitest/*.js",
]
prefs = ["javascript.options.asyncstack_capture_debuggee_only=false"]
diff --git a/accessible/tests/browser/tree/browser.toml b/accessible/tests/browser/tree/browser.toml
index 64be6853d1..a7d9894fcb 100644
--- a/accessible/tests/browser/tree/browser.toml
+++ b/accessible/tests/browser/tree/browser.toml
@@ -4,7 +4,6 @@ support-files = [
"head.js",
"!/accessible/tests/browser/shared-head.js",
"!/accessible/tests/mochitest/*.js",
- "!/accessible/tests/browser/*.jsm",
]
prefs = ["javascript.options.asyncstack_capture_debuggee_only=false"]
diff --git a/accessible/tests/browser/windows/a11y_setup.py b/accessible/tests/browser/windows/a11y_setup.py
index 726eea07a4..860364d99b 100644
--- a/accessible/tests/browser/windows/a11y_setup.py
+++ b/accessible/tests/browser/windows/a11y_setup.py
@@ -61,9 +61,6 @@ uiaClient = comtypes.CoCreateInstance(
interface=uiaMod.IUIAutomation,
clsctx=comtypes.CLSCTX_INPROC_SERVER,
)
-TreeScope_Descendants = uiaMod.TreeScope_Descendants
-UIA_AutomationIdPropertyId = uiaMod.UIA_AutomationIdPropertyId
-del uiaMod
def AccessibleObjectFromWindow(hwnd, objectID=OBJID_CLIENT):
@@ -173,7 +170,7 @@ class WaitForWinEvent:
"""
def __init__(self, eventId, match):
- """event is the event id to wait for.
+ """eventId is the event id to wait for.
match is either None to match any object, an str containing the DOM id
of the desired object, or a function taking a WinEvent which should
return True if this is the requested event.
@@ -235,6 +232,7 @@ class WaitForWinEvent:
raise
finally:
user32.UnhookWinEvent(self._hook)
+ ctypes.windll.kernel32.CloseHandle(self._signal)
self._proc = None
if isinstance(self._matched, Exception):
raise self._matched from self._matched
@@ -243,17 +241,153 @@ class WaitForWinEvent:
def getDocUia():
"""Get the IUIAutomationElement for the document being tested."""
- # We start with IAccessible2 because there's no efficient way to
- # find the document we want with UIA.
- ia2 = getDocIa2()
- return uiaClient.ElementFromIAccessible(ia2, CHILDID_SELF)
+ # There's no efficient way to find the document we want with UIA. We can't
+ # get the IA2 and then get UIA from that because that will always use the
+ # IA2 -> UIA proxy, but we don't want that if we're trying to test our
+ # native implementation. For now, we just search the tree. In future, we
+ # could perhaps implement a custom property.
+ hwnd = getFirefoxHwnd()
+ root = uiaClient.ElementFromHandle(hwnd)
+ doc = findUiaByDomId(root, "body")
+ if not doc:
+ # Sometimes, when UIA is disabled, we can't find the document for some
+ # unknown reason. Since this only happens when UIA is disabled, we want
+ # the IA2 -> UIA proxy anyway, so we can start with IA2 in this case.
+ info("getUiaDoc: Falling back to IA2") # noqa: F821
+ ia2 = getDocIa2()
+ return uiaClient.ElementFromIAccessible(ia2, CHILDID_SELF)
+ child = uiaClient.RawViewWalker.GetFirstChildElement(doc)
+ if child and child.CurrentAutomationId == "default-iframe-id":
+ # This is an iframe or remoteIframe test.
+ doc = uiaClient.RawViewWalker.GetFirstChildElement(child)
+ return doc
def findUiaByDomId(root, id):
- cond = uiaClient.CreatePropertyCondition(UIA_AutomationIdPropertyId, id)
+ cond = uiaClient.CreatePropertyCondition(uiaMod.UIA_AutomationIdPropertyId, id)
# FindFirst ignores elements in the raw tree, so we have to use
# FindFirstBuildCache to override that, even though we don't want to cache
# anything.
request = uiaClient.CreateCacheRequest()
request.TreeFilter = uiaClient.RawViewCondition
- return root.FindFirstBuildCache(TreeScope_Descendants, cond, request)
+ el = root.FindFirstBuildCache(uiaMod.TreeScope_Descendants, cond, request)
+ if not el:
+ return None
+ # We need to test things that were introduced after UIA was initially
+ # introduced in Windows 7.
+ return el.QueryInterface(uiaMod.IUIAutomationElement9)
+
+
+class WaitForUiaEvent(comtypes.COMObject):
+ """Wait for a UIA event.
+ This should be used as follows:
+ 1. Create an instance to wait for the desired event.
+ 2. Perform the action that should fire the event.
+ 3. Call wait() on the instance you created in 1) to wait for the event.
+ """
+
+ # This tells comtypes which COM interfaces we implement. It will then call
+ # either `ISomeInterface_SomeMethod` or just `SomeMethod` on this instance
+ # when that method is called using COM. We use the shorter convention, since
+ # we don't anticipate method name conflicts with UIA interfaces.
+ _com_interfaces_ = [
+ uiaMod.IUIAutomationFocusChangedEventHandler,
+ uiaMod.IUIAutomationPropertyChangedEventHandler,
+ uiaMod.IUIAutomationEventHandler,
+ ]
+
+ def __init__(self, *, eventId=None, property=None, match=None):
+ """eventId is the event id to wait for. Alternatively, you can pass
+ property to wait for a particular property to change.
+ match is either None to match any object, an str containing the DOM id
+ of the desired object, or a function taking a IUIAutomationElement which
+ should return True if this is the requested event.
+ """
+ self._match = match
+ self._matched = None
+ # A kernel event used to signal when we get the desired event.
+ self._signal = ctypes.windll.kernel32.CreateEventW(None, True, False, None)
+ if eventId == uiaMod.UIA_AutomationFocusChangedEventId:
+ uiaClient.AddFocusChangedEventHandler(None, self)
+ elif eventId:
+ # Generic automation event.
+ uiaClient.AddAutomationEventHandler(
+ eventId,
+ uiaClient.GetRootElement(),
+ uiaMod.TreeScope_Subtree,
+ None,
+ self,
+ )
+ elif property:
+ uiaClient.AddPropertyChangedEventHandler(
+ uiaClient.GetRootElement(),
+ uiaMod.TreeScope_Subtree,
+ None,
+ self,
+ [property],
+ )
+ else:
+ raise ValueError("No supported event specified")
+
+ def _checkMatch(self, sender):
+ if isinstance(self._match, str):
+ try:
+ if sender.CurrentAutomationId == self._match:
+ self._matched = sender
+ except comtypes.COMError:
+ pass
+ elif callable(self._match):
+ try:
+ if self._match(sender):
+ self._matched = sender
+ except Exception as e:
+ self._matched = e
+ else:
+ self._matched = sender
+ if self._matched:
+ ctypes.windll.kernel32.SetEvent(self._signal)
+
+ def HandleFocusChangedEvent(self, sender):
+ self._checkMatch(sender)
+
+ def HandlePropertyChangedEvent(self, sender, propertyId, newValue):
+ self._checkMatch(sender)
+
+ def HandleAutomationEvent(self, sender, eventId):
+ self._checkMatch(sender)
+
+ def wait(self):
+ """Wait for and return the IUIAutomationElement which sent the desired
+ event."""
+ # Pump Windows messages until we get the desired event, which will be
+ # signalled using a kernel event.
+ handles = (ctypes.c_void_p * 1)(self._signal)
+ index = ctypes.wintypes.DWORD()
+ TIMEOUT = 10000
+ try:
+ ctypes.oledll.ole32.CoWaitForMultipleHandles(
+ COWAIT_DEFAULT, TIMEOUT, 1, handles, ctypes.byref(index)
+ )
+ except WindowsError as e:
+ if e.winerror == RPC_S_CALLPENDING:
+ raise TimeoutError("Timeout before desired event received")
+ raise
+ finally:
+ uiaClient.RemoveAllEventHandlers()
+ ctypes.windll.kernel32.CloseHandle(self._signal)
+ if isinstance(self._matched, Exception):
+ raise self._matched from self._matched
+ return self._matched
+
+
+def getUiaPattern(element, patternName):
+ """Get a control pattern interface from an IUIAutomationElement."""
+ patternId = getattr(uiaMod, f"UIA_{patternName}PatternId")
+ unknown = element.GetCurrentPattern(patternId)
+ if not unknown:
+ return None
+ # GetCurrentPattern returns an IUnknown. We have to QI to the real
+ # interface.
+ # Get the comtypes interface object.
+ interface = getattr(uiaMod, f"IUIAutomation{patternName}Pattern")
+ return unknown.QueryInterface(interface)
diff --git a/accessible/tests/browser/windows/uia/browser.toml b/accessible/tests/browser/windows/uia/browser.toml
index d1513c1822..75728f56d7 100644
--- a/accessible/tests/browser/windows/uia/browser.toml
+++ b/accessible/tests/browser/windows/uia/browser.toml
@@ -10,4 +10,9 @@ support-files = ["head.js"]
["browser_elementFromPoint.js"]
+["browser_focus.js"]
+["browser_generalProps.js"]
+
+["browser_simplePatterns.js"]
+
["browser_tree.js"]
diff --git a/accessible/tests/browser/windows/uia/browser_focus.js b/accessible/tests/browser/windows/uia/browser_focus.js
new file mode 100644
index 0000000000..f26c9e1d1b
--- /dev/null
+++ b/accessible/tests/browser/windows/uia/browser_focus.js
@@ -0,0 +1,61 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+async function testIsFocusable(pyVar, isFocusable) {
+ const result = await runPython(`${pyVar}.CurrentIsKeyboardFocusable`);
+ if (isFocusable) {
+ ok(result, `${pyVar} is focusable`);
+ } else {
+ ok(!result, `${pyVar} isn't focusable`);
+ }
+}
+
+async function testHasFocus(pyVar, hasFocus) {
+ const result = await runPython(`${pyVar}.CurrentHasKeyboardFocus`);
+ if (hasFocus) {
+ ok(result, `${pyVar} has focus`);
+ } else {
+ ok(!result, `${pyVar} doesn't have focus`);
+ }
+}
+
+addUiaTask(
+ `
+<button id="button1">button1</button>
+<p id="p">p</p>
+<button id="button2">button2</button>
+ `,
+ async function (browser) {
+ await definePyVar("doc", `getDocUia()`);
+ await testIsFocusable("doc", true);
+ await testHasFocus("doc", true);
+
+ await assignPyVarToUiaWithId("button1");
+ await testIsFocusable("button1", true);
+ await testHasFocus("button1", false);
+ info("Focusing button1");
+ await setUpWaitForUiaEvent("AutomationFocusChanged", "button1");
+ await invokeFocus(browser, "button1");
+ await waitForUiaEvent();
+ ok(true, "Got AutomationFocusChanged event on button1");
+ await testHasFocus("button1", true);
+
+ await assignPyVarToUiaWithId("p");
+ await testIsFocusable("p", false);
+ await testHasFocus("p", false);
+
+ await assignPyVarToUiaWithId("button2");
+ await testIsFocusable("button2", true);
+ await testHasFocus("button2", false);
+ info("Focusing button2");
+ await setUpWaitForUiaEvent("AutomationFocusChanged", "button2");
+ await invokeFocus(browser, "button2");
+ await waitForUiaEvent();
+ ok(true, "Got AutomationFocusChanged event on button2");
+ await testHasFocus("button2", true);
+ await testHasFocus("button1", false);
+ }
+);
diff --git a/accessible/tests/browser/windows/uia/browser_generalProps.js b/accessible/tests/browser/windows/uia/browser_generalProps.js
new file mode 100644
index 0000000000..5cfda226d0
--- /dev/null
+++ b/accessible/tests/browser/windows/uia/browser_generalProps.js
@@ -0,0 +1,105 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/**
+ * Test the Name property.
+ */
+addUiaTask(
+ `
+<button id="button">before</button>
+<div id="div">div</div>
+ `,
+ async function testName(browser) {
+ await definePyVar("doc", `getDocUia()`);
+ await assignPyVarToUiaWithId("button");
+ is(
+ await runPython(`button.CurrentName`),
+ "before",
+ "button has correct name"
+ );
+ await assignPyVarToUiaWithId("div");
+ is(await runPython(`div.CurrentName`), "", "div has no name");
+
+ info("Setting aria-label on button");
+ await setUpWaitForUiaPropEvent("Name", "button");
+ await invokeSetAttribute(browser, "button", "aria-label", "after");
+ await waitForUiaEvent();
+ ok(true, "Got Name prop change event on button");
+ is(
+ await runPython(`button.CurrentName`),
+ "after",
+ "button has correct name"
+ );
+ }
+);
+
+/**
+ * Test the FullDescription property.
+ */
+addUiaTask(
+ `
+<button id="button" aria-description="before">button</button>
+<div id="div">div</div>
+ `,
+ async function testFullDescription(browser) {
+ await definePyVar("doc", `getDocUia()`);
+ await assignPyVarToUiaWithId("button");
+ is(
+ await runPython(`button.CurrentFullDescription`),
+ "before",
+ "button has correct FullDescription"
+ );
+ await assignPyVarToUiaWithId("div");
+ is(
+ await runPython(`div.CurrentFullDescription`),
+ "",
+ "div has no FullDescription"
+ );
+
+ info("Setting aria-description on button");
+ await setUpWaitForUiaPropEvent("FullDescription", "button");
+ await invokeSetAttribute(browser, "button", "aria-description", "after");
+ await waitForUiaEvent();
+ ok(true, "Got FullDescription prop change event on button");
+ is(
+ await runPython(`button.CurrentFullDescription`),
+ "after",
+ "button has correct FullDescription"
+ );
+ },
+ // The IA2 -> UIA proxy doesn't support FullDescription.
+ { uiaEnabled: true, uiaDisabled: false }
+);
+
+/**
+ * Test the IsEnabled property.
+ */
+addUiaTask(
+ `
+<button id="button">button</button>
+<p id="p">p</p>
+ `,
+ async function testIsEnabled(browser) {
+ await definePyVar("doc", `getDocUia()`);
+ await assignPyVarToUiaWithId("button");
+ ok(await runPython(`button.CurrentIsEnabled`), "button has IsEnabled true");
+ // The IA2 -> UIA proxy doesn't fire IsEnabled prop change events.
+ if (gIsUiaEnabled) {
+ info("Setting disabled on button");
+ await setUpWaitForUiaPropEvent("IsEnabled", "button");
+ await invokeSetAttribute(browser, "button", "disabled", true);
+ await waitForUiaEvent();
+ ok(true, "Got IsEnabled prop change event on button");
+ ok(
+ !(await runPython(`button.CurrentIsEnabled`)),
+ "button has IsEnabled false"
+ );
+ }
+
+ await assignPyVarToUiaWithId("p");
+ ok(await runPython(`p.CurrentIsEnabled`), "p has IsEnabled true");
+ }
+);
diff --git a/accessible/tests/browser/windows/uia/browser_simplePatterns.js b/accessible/tests/browser/windows/uia/browser_simplePatterns.js
new file mode 100644
index 0000000000..f464db0e13
--- /dev/null
+++ b/accessible/tests/browser/windows/uia/browser_simplePatterns.js
@@ -0,0 +1,445 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/* import-globals-from ../../../mochitest/role.js */
+/* import-globals-from ../../../mochitest/states.js */
+loadScripts(
+ { name: "role.js", dir: MOCHITESTS_DIR },
+ { name: "states.js", dir: MOCHITESTS_DIR }
+);
+
+/* eslint-disable camelcase */
+const ExpandCollapseState_Collapsed = 0;
+const ExpandCollapseState_Expanded = 1;
+const ToggleState_Off = 0;
+const ToggleState_On = 1;
+const ToggleState_Indeterminate = 2;
+/* eslint-enable camelcase */
+
+/**
+ * Test the Invoke pattern.
+ */
+addUiaTask(
+ `
+<button id="button">button</button>
+<p id="p">p</p>
+<input id="checkbox" type="checkbox">
+ `,
+ async function testInvoke() {
+ await definePyVar("doc", `getDocUia()`);
+ await assignPyVarToUiaWithId("button");
+ await definePyVar("pattern", `getUiaPattern(button, "Invoke")`);
+ ok(await runPython(`bool(pattern)`), "button has Invoke pattern");
+ info("Calling Invoke on button");
+ // The button will get focus when it is clicked.
+ let focused = waitForEvent(EVENT_FOCUS, "button");
+ // The UIA -> IA2 proxy doesn't fire the Invoked event.
+ if (gIsUiaEnabled) {
+ await setUpWaitForUiaEvent("Invoke_Invoked", "button");
+ }
+ await runPython(`pattern.Invoke()`);
+ await focused;
+ ok(true, "button got focus");
+ if (gIsUiaEnabled) {
+ await waitForUiaEvent();
+ ok(true, "button got Invoked event");
+ }
+
+ await testPatternAbsent("p", "Invoke");
+ // The Microsoft IA2 -> UIA proxy doesn't follow Microsoft's own rules.
+ if (gIsUiaEnabled) {
+ // Check boxes expose the Toggle pattern, so they should not expose the
+ // Invoke pattern.
+ await testPatternAbsent("checkbox", "Invoke");
+ }
+ }
+);
+
+/**
+ * Test the Toggle pattern.
+ */
+addUiaTask(
+ `
+<input id="checkbox" type="checkbox" checked>
+<button id="toggleButton" aria-pressed="false">toggle</button>
+<button id="button">button</button>
+<p id="p">p</p>
+
+<script>
+ // When checkbox is clicked and it is not checked, make it indeterminate.
+ document.getElementById("checkbox").addEventListener("click", evt => {
+ // Within the event listener, .checked is reversed and you can't set
+ // .indeterminate. Work around this by deferring and handling the changes
+ // ourselves.
+ evt.preventDefault();
+ const target = evt.target;
+ setTimeout(() => {
+ if (target.checked) {
+ target.checked = false;
+ } else {
+ target.indeterminate = true;
+ }
+ }, 0);
+ });
+
+ // When toggleButton is clicked, set aria-pressed to true.
+ document.getElementById("toggleButton").addEventListener("click", evt => {
+ evt.target.ariaPressed = "true";
+ });
+</script>
+ `,
+ async function testToggle() {
+ await definePyVar("doc", `getDocUia()`);
+ await assignPyVarToUiaWithId("checkbox");
+ await definePyVar("pattern", `getUiaPattern(checkbox, "Toggle")`);
+ ok(await runPython(`bool(pattern)`), "checkbox has Toggle pattern");
+ is(
+ await runPython(`pattern.CurrentToggleState`),
+ ToggleState_On,
+ "checkbox has ToggleState_On"
+ );
+ // The IA2 -> UIA proxy doesn't fire ToggleState prop change events.
+ if (gIsUiaEnabled) {
+ info("Calling Toggle on checkbox");
+ await setUpWaitForUiaPropEvent("ToggleToggleState", "checkbox");
+ await runPython(`pattern.Toggle()`);
+ await waitForUiaEvent();
+ ok(true, "Got ToggleState prop change event on checkbox");
+ is(
+ await runPython(`pattern.CurrentToggleState`),
+ ToggleState_Off,
+ "checkbox has ToggleState_Off"
+ );
+ info("Calling Toggle on checkbox");
+ await setUpWaitForUiaPropEvent("ToggleToggleState", "checkbox");
+ await runPython(`pattern.Toggle()`);
+ await waitForUiaEvent();
+ ok(true, "Got ToggleState prop change event on checkbox");
+ is(
+ await runPython(`pattern.CurrentToggleState`),
+ ToggleState_Indeterminate,
+ "checkbox has ToggleState_Indeterminate"
+ );
+ }
+
+ await assignPyVarToUiaWithId("toggleButton");
+ await definePyVar("pattern", `getUiaPattern(toggleButton, "Toggle")`);
+ ok(await runPython(`bool(pattern)`), "toggleButton has Toggle pattern");
+ is(
+ await runPython(`pattern.CurrentToggleState`),
+ ToggleState_Off,
+ "toggleButton has ToggleState_Off"
+ );
+ if (gIsUiaEnabled) {
+ info("Calling Toggle on toggleButton");
+ await setUpWaitForUiaPropEvent("ToggleToggleState", "toggleButton");
+ await runPython(`pattern.Toggle()`);
+ await waitForUiaEvent();
+ ok(true, "Got ToggleState prop change event on toggleButton");
+ is(
+ await runPython(`pattern.CurrentToggleState`),
+ ToggleState_On,
+ "toggleButton has ToggleState_Off"
+ );
+ }
+
+ await testPatternAbsent("button", "Toggle");
+ await testPatternAbsent("p", "Toggle");
+ }
+);
+
+/**
+ * Test the ExpandCollapse pattern.
+ */
+addUiaTask(
+ `
+<details>
+ <summary id="summary">summary</summary>
+ details
+</details>
+<button id="popup" aria-haspopup="true">popup</button>
+<button id="button">button</button>
+<script>
+ // When popup is clicked, set aria-expanded to true.
+ document.getElementById("popup").addEventListener("click", evt => {
+ evt.target.ariaExpanded = "true";
+ });
+</script>
+ `,
+ async function testExpandCollapse() {
+ await definePyVar("doc", `getDocUia()`);
+ await assignPyVarToUiaWithId("summary");
+ await definePyVar("pattern", `getUiaPattern(summary, "ExpandCollapse")`);
+ ok(await runPython(`bool(pattern)`), "summary has ExpandCollapse pattern");
+ is(
+ await runPython(`pattern.CurrentExpandCollapseState`),
+ ExpandCollapseState_Collapsed,
+ "summary has ExpandCollapseState_Collapsed"
+ );
+ // The IA2 -> UIA proxy doesn't fire ToggleState prop change events, nor
+ // does it fail when Expand/Collapse is called on a control which is
+ // already in the desired state.
+ if (gIsUiaEnabled) {
+ info("Calling Expand on summary");
+ await setUpWaitForUiaPropEvent(
+ "ExpandCollapseExpandCollapseState",
+ "summary"
+ );
+ await runPython(`pattern.Expand()`);
+ await waitForUiaEvent();
+ ok(
+ true,
+ "Got ExpandCollapseExpandCollapseState prop change event on summary"
+ );
+ is(
+ await runPython(`pattern.CurrentExpandCollapseState`),
+ ExpandCollapseState_Expanded,
+ "summary has ExpandCollapseState_Expanded"
+ );
+ info("Calling Expand on summary");
+ await testPythonRaises(`pattern.Expand()`, "Expand on summary failed");
+ info("Calling Collapse on summary");
+ await setUpWaitForUiaPropEvent(
+ "ExpandCollapseExpandCollapseState",
+ "summary"
+ );
+ await runPython(`pattern.Collapse()`);
+ await waitForUiaEvent();
+ ok(
+ true,
+ "Got ExpandCollapseExpandCollapseState prop change event on summary"
+ );
+ is(
+ await runPython(`pattern.CurrentExpandCollapseState`),
+ ExpandCollapseState_Collapsed,
+ "summary has ExpandCollapseState_Collapsed"
+ );
+ info("Calling Collapse on summary");
+ await testPythonRaises(
+ `pattern.Collapse()`,
+ "Collapse on summary failed"
+ );
+ }
+
+ await assignPyVarToUiaWithId("popup");
+ // Initially, popup has aria-haspopup but not aria-expanded. That should
+ // be exposed as collapsed.
+ await definePyVar("pattern", `getUiaPattern(popup, "ExpandCollapse")`);
+ ok(await runPython(`bool(pattern)`), "popup has ExpandCollapse pattern");
+ // The IA2 -> UIA proxy doesn't expose ExpandCollapseState_Collapsed for
+ // aria-haspopup without aria-expanded.
+ if (gIsUiaEnabled) {
+ is(
+ await runPython(`pattern.CurrentExpandCollapseState`),
+ ExpandCollapseState_Collapsed,
+ "popup has ExpandCollapseState_Collapsed"
+ );
+ info("Calling Expand on popup");
+ await setUpWaitForUiaPropEvent(
+ "ExpandCollapseExpandCollapseState",
+ "popup"
+ );
+ await runPython(`pattern.Expand()`);
+ await waitForUiaEvent();
+ ok(
+ true,
+ "Got ExpandCollapseExpandCollapseState prop change event on popup"
+ );
+ is(
+ await runPython(`pattern.CurrentExpandCollapseState`),
+ ExpandCollapseState_Expanded,
+ "popup has ExpandCollapseState_Expanded"
+ );
+ }
+
+ await testPatternAbsent("button", "ExpandCollapse");
+ }
+);
+
+/**
+ * Test the ScrollItem pattern.
+ */
+addUiaTask(
+ `
+<hr style="height: 100vh;">
+<button id="button">button</button>
+ `,
+ async function testScrollItem(browser, docAcc) {
+ await definePyVar("doc", `getDocUia()`);
+ await assignPyVarToUiaWithId("button");
+ await definePyVar("pattern", `getUiaPattern(button, "ScrollItem")`);
+ ok(await runPython(`bool(pattern)`), "button has ScrollItem pattern");
+ const button = findAccessibleChildByID(docAcc, "button");
+ testStates(button, STATE_OFFSCREEN);
+ info("Calling ScrollIntoView on button");
+ // UIA doesn't have an event for this.
+ let scrolled = waitForEvent(EVENT_SCROLLING_END, docAcc);
+ await runPython(`pattern.ScrollIntoView()`);
+ await scrolled;
+ ok(true, "Document scrolled");
+ testStates(button, 0, 0, STATE_OFFSCREEN);
+ }
+);
+
+/**
+ * Test the Value pattern.
+ */
+addUiaTask(
+ `
+<input id="text" value="before">
+<input id="textRo" readonly value="textRo">
+<input id="textDis" disabled value="textDis">
+<select id="select"><option selected>a</option><option>b</option></select>
+<progress id="progress" value="0.5"></progress>
+<input id="range" type="range" aria-valuetext="02:00:00">
+<a id="link" href="https://example.com/">Link</a>
+<div id="ariaTextbox" contenteditable role="textbox">before</div>
+<button id="button">button</button>
+ `,
+ async function testValue() {
+ await definePyVar("doc", `getDocUia()`);
+ await assignPyVarToUiaWithId("text");
+ await definePyVar("pattern", `getUiaPattern(text, "Value")`);
+ ok(await runPython(`bool(pattern)`), "text has Value pattern");
+ ok(
+ !(await runPython(`pattern.CurrentIsReadOnly`)),
+ "text has IsReadOnly false"
+ );
+ is(
+ await runPython(`pattern.CurrentValue`),
+ "before",
+ "text has correct Value"
+ );
+ info("SetValue on text");
+ await setUpWaitForUiaPropEvent("ValueValue", "text");
+ await runPython(`pattern.SetValue("after")`);
+ await waitForUiaEvent();
+ is(
+ await runPython(`pattern.CurrentValue`),
+ "after",
+ "text has correct Value"
+ );
+
+ await assignPyVarToUiaWithId("textRo");
+ await definePyVar("pattern", `getUiaPattern(textRo, "Value")`);
+ ok(await runPython(`bool(pattern)`), "textRo has Value pattern");
+ ok(
+ await runPython(`pattern.CurrentIsReadOnly`),
+ "textRo has IsReadOnly true"
+ );
+ is(
+ await runPython(`pattern.CurrentValue`),
+ "textRo",
+ "textRo has correct Value"
+ );
+ info("SetValue on textRo");
+ await testPythonRaises(
+ `pattern.SetValue("after")`,
+ "SetValue on textRo failed"
+ );
+
+ await assignPyVarToUiaWithId("textDis");
+ await definePyVar("pattern", `getUiaPattern(textDis, "Value")`);
+ ok(await runPython(`bool(pattern)`), "textDis has Value pattern");
+ ok(
+ !(await runPython(`pattern.CurrentIsReadOnly`)),
+ "textDis has IsReadOnly false"
+ );
+ is(
+ await runPython(`pattern.CurrentValue`),
+ "textDis",
+ "textDis has correct Value"
+ );
+ // The IA2 -> UIA proxy doesn't fail SetValue for a disabled element.
+ if (gIsUiaEnabled) {
+ info("SetValue on textDis");
+ await testPythonRaises(
+ `pattern.SetValue("after")`,
+ "SetValue on textDis failed"
+ );
+ }
+
+ await assignPyVarToUiaWithId("select");
+ await definePyVar("pattern", `getUiaPattern(select, "Value")`);
+ ok(await runPython(`bool(pattern)`), "select has Value pattern");
+ ok(
+ !(await runPython(`pattern.CurrentIsReadOnly`)),
+ "select has IsReadOnly false"
+ );
+ is(
+ await runPython(`pattern.CurrentValue`),
+ "a",
+ "select has correct Value"
+ );
+ info("SetValue on select");
+ await testPythonRaises(
+ `pattern.SetValue("b")`,
+ "SetValue on select failed"
+ );
+
+ await assignPyVarToUiaWithId("progress");
+ await definePyVar("pattern", `getUiaPattern(progress, "Value")`);
+ ok(await runPython(`bool(pattern)`), "progress has Value pattern");
+ // Gecko a11y doesn't treat progress bars as read only, but it probably
+ // should.
+ todo(
+ await runPython(`pattern.CurrentIsReadOnly`),
+ "progress has IsReadOnly true"
+ );
+ is(
+ await runPython(`pattern.CurrentValue`),
+ "50%",
+ "progress has correct Value"
+ );
+ info("SetValue on progress");
+ await testPythonRaises(
+ `pattern.SetValue("60%")`,
+ "SetValue on progress failed"
+ );
+
+ await assignPyVarToUiaWithId("range");
+ await definePyVar("pattern", `getUiaPattern(range, "Value")`);
+ ok(await runPython(`bool(pattern)`), "range has Value pattern");
+ is(
+ await runPython(`pattern.CurrentValue`),
+ "02:00:00",
+ "range has correct Value"
+ );
+
+ await assignPyVarToUiaWithId("link");
+ await definePyVar("pattern", `getUiaPattern(link, "Value")`);
+ ok(await runPython(`bool(pattern)`), "link has Value pattern");
+ is(
+ await runPython(`pattern.CurrentValue`),
+ "https://example.com/",
+ "link has correct Value"
+ );
+
+ await assignPyVarToUiaWithId("ariaTextbox");
+ await definePyVar("pattern", `getUiaPattern(ariaTextbox, "Value")`);
+ ok(await runPython(`bool(pattern)`), "ariaTextbox has Value pattern");
+ ok(
+ !(await runPython(`pattern.CurrentIsReadOnly`)),
+ "ariaTextbox has IsReadOnly false"
+ );
+ is(
+ await runPython(`pattern.CurrentValue`),
+ "before",
+ "ariaTextbox has correct Value"
+ );
+ info("SetValue on ariaTextbox");
+ await setUpWaitForUiaPropEvent("ValueValue", "ariaTextbox");
+ await runPython(`pattern.SetValue("after")`);
+ await waitForUiaEvent();
+ is(
+ await runPython(`pattern.CurrentValue`),
+ "after",
+ "ariaTextbox has correct Value"
+ );
+
+ await testPatternAbsent("button", "Value");
+ }
+);
diff --git a/accessible/tests/browser/windows/uia/browser_tree.js b/accessible/tests/browser/windows/uia/browser_tree.js
index 778609bedb..c63045b6d1 100644
--- a/accessible/tests/browser/windows/uia/browser_tree.js
+++ b/accessible/tests/browser/windows/uia/browser_tree.js
@@ -13,24 +13,6 @@ async function testIsControl(pyVar, isControl) {
}
}
-/**
- * Define a global Python variable and assign it to a given Python expression.
- */
-function definePyVar(varName, expression) {
- return runPython(`
- global ${varName}
- ${varName} = ${expression}
- `);
-}
-
-/**
- * Get the UIA element with the given id and assign it to a global Python
- * variable using the id as the variable name.
- */
-function assignPyVarToUiaWithId(id) {
- return definePyVar(id, `findUiaByDomId(doc, "${id}")`);
-}
-
addUiaTask(
`
<p id="p">paragraph</p>
@@ -46,7 +28,7 @@ addUiaTask(
<div id="editable" contenteditable>editable</div>
<table id="table"><tr><th>th</th></tr></table>
`,
- async function (browser, docAcc) {
+ async function () {
await definePyVar("doc", `getDocUia()`);
await assignPyVarToUiaWithId("p");
await testIsControl("p", false);
diff --git a/accessible/tests/browser/windows/uia/head.js b/accessible/tests/browser/windows/uia/head.js
index e659354c7c..5b453ce6fe 100644
--- a/accessible/tests/browser/windows/uia/head.js
+++ b/accessible/tests/browser/windows/uia/head.js
@@ -4,7 +4,7 @@
"use strict";
-/* exported gIsUiaEnabled, addUiaTask */
+/* exported gIsUiaEnabled, addUiaTask, definePyVar, assignPyVarToUiaWithId, setUpWaitForUiaEvent, setUpWaitForUiaPropEvent, waitForUiaEvent, testPatternAbsent, testPythonRaises */
// Load the shared-head file first.
Services.scriptloader.loadSubScript(
@@ -53,3 +53,76 @@ function addUiaTask(doc, task, options = {}) {
addTask(false);
}
}
+
+/**
+ * Define a global Python variable and assign it to a given Python expression.
+ */
+function definePyVar(varName, expression) {
+ return runPython(`
+ global ${varName}
+ ${varName} = ${expression}
+ `);
+}
+
+/**
+ * Get the UIA element with the given id and assign it to a global Python
+ * variable using the id as the variable name.
+ */
+function assignPyVarToUiaWithId(id) {
+ return definePyVar(id, `findUiaByDomId(doc, "${id}")`);
+}
+
+/**
+ * Set up to wait for a UIA event. You must await this before performing the
+ * action which fires the event.
+ */
+function setUpWaitForUiaEvent(eventName, id) {
+ return definePyVar(
+ "onEvent",
+ `WaitForUiaEvent(eventId=UIA_${eventName}EventId, match="${id}")`
+ );
+}
+
+/**
+ * Set up to wait for a UIA property change event. You must await this before
+ * performing the action which fires the event.
+ */
+function setUpWaitForUiaPropEvent(propName, id) {
+ return definePyVar(
+ "onEvent",
+ `WaitForUiaEvent(property=UIA_${propName}PropertyId, match="${id}")`
+ );
+}
+
+/**
+ * Wait for the event requested in setUpWaitForUia*Event.
+ */
+function waitForUiaEvent() {
+ return runPython(`
+ onEvent.wait()
+ `);
+}
+
+/**
+ * Verify that a UIA element does *not* support the given control pattern.
+ */
+async function testPatternAbsent(id, patternName) {
+ const hasPattern = await runPython(`
+ el = findUiaByDomId(doc, "${id}")
+ return bool(getUiaPattern(el, "${patternName}"))
+ `);
+ ok(!hasPattern, `${id} doesn't have ${patternName} pattern`);
+}
+
+/**
+ * Verify that a Python expression raises an exception.
+ */
+async function testPythonRaises(expression, message) {
+ let failed = false;
+ try {
+ await runPython(expression);
+ } catch {
+ failed = true;
+ }
+ ok(failed, message);
+}
diff --git a/accessible/tests/mochitest/attributes/test_obj_group.xhtml b/accessible/tests/mochitest/attributes/test_obj_group.xhtml
index 0eda4b6f2d..ba0c8bd357 100644
--- a/accessible/tests/mochitest/attributes/test_obj_group.xhtml
+++ b/accessible/tests/mochitest/attributes/test_obj_group.xhtml
@@ -196,17 +196,19 @@
</menulist>
<vbox>
- <description role="menuitem" id="aria-menuitem"
- value="conventional menuitem"/>
- <description role="menuitemcheckbox" id="aria-menuitemcheckbox"
- value="conventional checkbox menuitem"/>
- <description role="menuitem" hidden="true"/>
- <description role="menuitemradio" id="aria-menuitemradio"
- value="conventional radio menuitem"/>
- <description role="separator"
- value="conventional separator"/>
- <description role="menuitem" id="aria-menuitem2"
- value="conventional menuitem"/>
+ <div role="menu">
+ <description role="menuitem" id="aria-menuitem"
+ value="conventional menuitem"/>
+ <description role="menuitemcheckbox" id="aria-menuitemcheckbox"
+ value="conventional checkbox menuitem"/>
+ <description role="menuitem" hidden="true"/>
+ <description role="menuitemradio" id="aria-menuitemradio"
+ value="conventional radio menuitem"/>
+ <description role="separator"
+ value="conventional separator"/>
+ <description role="menuitem" id="aria-menuitem2"
+ value="conventional menuitem"/>
+ </div>
</vbox>
</vbox>
diff --git a/accessible/tests/mochitest/focus/test_takeFocus.html b/accessible/tests/mochitest/focus/test_takeFocus.html
index 752ed66b36..6384fbfcb8 100644
--- a/accessible/tests/mochitest/focus/test_takeFocus.html
+++ b/accessible/tests/mochitest/focus/test_takeFocus.html
@@ -48,7 +48,6 @@
gQueue.push(new takeFocusInvoker("aria-link"));
gQueue.push(new takeFocusInvoker("aria-link2"));
gQueue.push(new takeFocusInvoker("link"));
- gQueue.push(new takeFocusInvoker("item2"));
gQueue.push(new takeFocusInvoker(document));
gQueue.push(new takeFocusInvoker("lb_item2"));
gQueue.push(new takeFocusInvoker(document));
diff --git a/accessible/tests/mochitest/name/test_general.html b/accessible/tests/mochitest/name/test_general.html
index 09723e6222..47104ced3e 100644
--- a/accessible/tests/mochitest/name/test_general.html
+++ b/accessible/tests/mochitest/name/test_general.html
@@ -105,7 +105,7 @@
// The label element contains the button. The name is calculated from
// this button.
// Note: the name contains the content of the button.
- testName("btn_label_inside", "text10text");
+ testName("btn_label_inside", "text 10 text");
// The label element and the button are placed in the same form. Gets
// the name from the label subtree.
@@ -713,17 +713,21 @@
<div id="grouping" role="group">label</div>
<button id="requested_name_from_grouping"aria-labelledby="grouping"></button>
<!-- Name from sub tree of tbody marked as display:block;, which is also a grouping -->
- <div id="listitem_containing_block_tbody" role="listitem">
- <table>
- <tbody style="display: block;">
- <tr><td>label</td></tr>
- </tbody>
- </table>
+ <div role="list">
+ <div id="listitem_containing_block_tbody" role="listitem">
+ <table>
+ <tbody style="display: block;">
+ <tr><td>label</td></tr>
+ </tbody>
+ </table>
+ </div>
</div>
<!-- Name from subtree of treeitem containing grouping -->
- <div id="treeitem_containing_grouping" role="treeitem" aria-level="1" aria-expanded="true">root
- <div role="group">
- <div role="treeitem" aria-level="2">sub</div>
+ <div role="tree">
+ <div id="treeitem_containing_grouping" role="treeitem" aria-level="1" aria-expanded="true">root
+ <div role="group">
+ <div role="treeitem" aria-level="2">sub</div>
+ </div>
</div>
</div>
@@ -735,11 +739,13 @@
</div>
<!-- Text nodes and inline elements. -->
- <div id="container_text_inline" role="option">a<strong>b</strong>c</div>
- <!-- Text nodes and block elements. -->
- <div id="container_text_block" role="option">a<p>b</p>c</div>
- <!-- Text nodes and empty block elements. -->
- <div id="container_text_emptyblock" role="option">a<p></p><p></p>b</div>
+ <div role="listbox">
+ <div id="container_text_inline" role="option">a<strong>b</strong>c</div>
+ <!-- Text nodes and block elements. -->
+ <div id="container_text_block" role="option">a<p>b</p>c</div>
+ <!-- Text nodes and empty block elements. -->
+ <div id="container_text_emptyblock" role="option">a<p></p><p></p>b</div>
+ </div>
<!-- aria-labelledby referring to a slot -->
<div id="shadowHost">
diff --git a/accessible/tests/mochitest/relations/a11y.toml b/accessible/tests/mochitest/relations/a11y.toml
index ae41bf91a5..77021c28cf 100644
--- a/accessible/tests/mochitest/relations/a11y.toml
+++ b/accessible/tests/mochitest/relations/a11y.toml
@@ -18,6 +18,4 @@ skip-if = [
["test_tree.xhtml"]
-["test_ui_modalprompt.html"]
-
["test_update.html"]
diff --git a/accessible/tests/mochitest/relations/test_ui_modalprompt.html b/accessible/tests/mochitest/relations/test_ui_modalprompt.html
deleted file mode 100644
index a05b273d86..0000000000
--- a/accessible/tests/mochitest/relations/test_ui_modalprompt.html
+++ /dev/null
@@ -1,111 +0,0 @@
-<html>
-
-<head>
- <title>Modal prompts</title>
- <link rel="stylesheet" type="text/css"
- href="chrome://mochikit/content/tests/SimpleTest/test.css" />
-
- <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
-
- <script type="application/javascript"
- src="../common.js"></script>
- <script type="application/javascript"
- src="../relations.js"></script>
- <script type="application/javascript"
- src="../role.js"></script>
- <script type="application/javascript"
- src="../events.js"></script>
- <script type="application/javascript"
- src="../browser.js"></script>
-
- <script type="application/javascript">
- SpecialPowers.pushPrefEnv({
- set: [["prompts.contentPromptSubDialog", false]],
- });
- function showAlert() {
- this.eventSeq = [
- {
- type: EVENT_SHOW,
- match(aEvent) {
- return aEvent.accessible.role == ROLE_DIALOG;
- },
- },
- ];
-
- this.invoke = function showAlert_invoke() {
- window.setTimeout(
- function() {
- currentTabDocument().defaultView.alert("hello");
- }, 0);
- };
-
- this.check = function showAlert_finalCheck(aEvent) {
- if(aEvent.type === EVENT_HIDE) {
- return;
- }
- var dialog = aEvent.accessible.DOMNode;
- var info = dialog.querySelector(".tabmodalprompt-infoBody");
- testRelation(info, RELATION_DESCRIPTION_FOR, dialog);
- testRelation(dialog, RELATION_DESCRIBED_BY, info);
- };
-
- this.getID = function showAlert_getID() {
- return "show alert";
- };
- }
-
- function closeAlert() {
- this.eventSeq = [
- {
- type: EVENT_HIDE,
- match(aEvent) {
- return aEvent.accessible.role == ROLE_DIALOG;
- },
- },
- ];
-
- this.invoke = function showAlert_invoke() {
- synthesizeKey("VK_RETURN", {}, browserWindow());
- };
-
- this.getID = function showAlert_getID() {
- return "cleanup alert";
- };
- }
-
-
- // gA11yEventDumpToConsole = true; // debug
-
- var gQueue = null;
- function doTests() {
- gQueue = new eventQueue();
- gQueue.push(new showAlert());
- gQueue.push(new closeAlert());
- gQueue.onFinish = function() {
- closeBrowserWindow();
- };
- gQueue.invoke(); // will call SimpleTest.finish()
- }
-
- SimpleTest.waitForExplicitFinish();
- openBrowserWindow(doTests);
- </script>
-
-</head>
-
-<body id="body">
-
- <a target="_blank"
- href="https://bugzilla.mozilla.org/show_bug.cgi?id=661293"
- title="The tabmodalprompt dialog's prompt label doesn't get the text properly associated for accessibility">
- Mozilla Bug 661293
- </a>
- <br>
- <p id="display"></p>
- <div id="content" style="display: none"></div>
- <pre id="test">
- </pre>
-
-</body>
-</html>
diff --git a/accessible/tests/mochitest/role/test_aria.html b/accessible/tests/mochitest/role/test_aria.html
index 0e7873c485..dcd2c7839e 100644
--- a/accessible/tests/mochitest/role/test_aria.html
+++ b/accessible/tests/mochitest/role/test_aria.html
@@ -42,8 +42,6 @@
testRole("aria_checkbox_mixed", ROLE_CHECKBUTTON);
testRole("aria_code", ROLE_CODE);
testRole("aria_code_mixed", ROLE_CODE);
- testRole("aria_columnheader", ROLE_COLUMNHEADER);
- testRole("aria_columnheader_mixed", ROLE_COLUMNHEADER);
testRole("aria_combobox", ROLE_EDITCOMBOBOX);
testRole("aria_combobox_mixed", ROLE_EDITCOMBOBOX);
testRole("aria_comment", ROLE_COMMENT);
@@ -66,8 +64,6 @@
testRole("aria_figure_mixed", ROLE_FIGURE);
testRole("aria_grid", ROLE_GRID);
testRole("aria_grid_mixed", ROLE_GRID);
- testRole("aria_gridcell", ROLE_GRID_CELL);
- testRole("aria_gridcell_mixed", ROLE_GRID_CELL);
testRole("aria_group", ROLE_GROUPING);
testRole("aria_group_mixed", ROLE_GROUPING);
testRole("aria_heading", ROLE_HEADING);
@@ -82,8 +78,6 @@
testRole("aria_list_mixed", ROLE_LIST);
testRole("aria_listbox", ROLE_LISTBOX);
testRole("aria_listbox_mixed", ROLE_LISTBOX);
- testRole("aria_listitem", ROLE_LISTITEM);
- testRole("aria_listitem_mixed", ROLE_LISTITEM);
testRole("aria_log", ROLE_TEXT); // weak role
testRole("aria_log_mixed", ROLE_TEXT); // weak role
testRole("aria_mark", ROLE_MARK);
@@ -96,12 +90,6 @@
testRole("aria_menu_mixed", ROLE_MENUPOPUP);
testRole("aria_menubar", ROLE_MENUBAR);
testRole("aria_menubar_mixed", ROLE_MENUBAR);
- testRole("aria_menuitem", ROLE_MENUITEM);
- testRole("aria_menuitem_mixed", ROLE_MENUITEM);
- testRole("aria_menuitemcheckbox", ROLE_CHECK_MENU_ITEM);
- testRole("aria_menuitemcheckbox_mixed", ROLE_CHECK_MENU_ITEM);
- testRole("aria_menuitemradio", ROLE_RADIO_MENU_ITEM);
- testRole("aria_menuitemradio_mixed", ROLE_RADIO_MENU_ITEM);
testRole("aria_meter", ROLE_METER);
testRole("aria_meter_mixed", ROLE_METER);
testRole("aria_note", ROLE_NOTE);
@@ -130,10 +118,6 @@
testRole("aria_region_as_table_with_caption_mixed", ROLE_REGION);
testRole("aria_region_as_table_with_miscaption", ROLE_TABLE);
testRole("aria_region_as_table_with_miscaption_mixed", ROLE_TABLE);
- testRole("aria_row", ROLE_ROW);
- testRole("aria_row_mixed", ROLE_ROW);
- testRole("aria_rowheader", ROLE_ROWHEADER);
- testRole("aria_rowheader_mixed", ROLE_ROWHEADER);
testRole("aria_scrollbar", ROLE_SCROLLBAR);
testRole("aria_scrollbar_mixed", ROLE_SCROLLBAR);
testRole("aria_searchbox", ROLE_ENTRY);
@@ -154,8 +138,6 @@
testRole("aria_superscript_mixed", ROLE_SUPERSCRIPT);
testRole("aria_switch", ROLE_SWITCH);
testRole("aria_switch_mixed", ROLE_SWITCH);
- testRole("aria_tab", ROLE_PAGETAB);
- testRole("aria_tab_mixed", ROLE_PAGETAB);
testRole("aria_tablist", ROLE_PAGETABLIST);
testRole("aria_tablist_mixed", ROLE_PAGETABLIST);
testRole("aria_tabpanel", ROLE_PROPERTYPAGE);
@@ -174,8 +156,6 @@
testRole("aria_tree_mixed", ROLE_OUTLINE);
testRole("aria_treegrid", ROLE_TREE_TABLE);
testRole("aria_treegrid_mixed", ROLE_TREE_TABLE);
- testRole("aria_treeitem", ROLE_OUTLINEITEM);
- testRole("aria_treeitem_mixed", ROLE_OUTLINEITEM);
// Note:
// The phrase "weak foo" here means that there is no good foo-to-platform
@@ -262,6 +242,29 @@
testRole("implicit_gridcell_mixed", ROLE_GRID_CELL);
// ////////////////////////////////////////////////////////////////////////
+ // child roles dependent on ancestor role presence
+ testRole("aria_columnheader", ROLE_COLUMNHEADER);
+ testRole("aria_columnheader_mixed", ROLE_COLUMNHEADER);
+ testRole("aria_gridcell", ROLE_GRID_CELL);
+ testRole("aria_gridcell_mixed", ROLE_GRID_CELL);
+ testRole("aria_rowheader", ROLE_ROWHEADER);
+ testRole("aria_rowheader_mixed", ROLE_ROWHEADER);
+ testRole("aria_listitem", ROLE_LISTITEM);
+ testRole("aria_listitem_mixed", ROLE_LISTITEM);
+ testRole("aria_menuitem", ROLE_MENUITEM);
+ testRole("aria_menuitem_mixed", ROLE_MENUITEM);
+ testRole("aria_menuitemcheckbox", ROLE_CHECK_MENU_ITEM);
+ testRole("aria_menuitemcheckbox_mixed", ROLE_CHECK_MENU_ITEM);
+ testRole("aria_menuitemradio", ROLE_RADIO_MENU_ITEM);
+ testRole("aria_menuitemradio_mixed", ROLE_RADIO_MENU_ITEM);
+ testRole("aria_row", ROLE_ROW);
+ testRole("aria_row_mixed", ROLE_ROW);
+ testRole("aria_tab", ROLE_PAGETAB);
+ testRole("aria_tab_mixed", ROLE_PAGETAB);
+ testRole("aria_treeitem", ROLE_OUTLINEITEM);
+ testRole("aria_treeitem_mixed", ROLE_OUTLINEITEM);
+
+ // ////////////////////////////////////////////////////////////////////////
// ignore unknown roles, take first known
testRole("unknown_roles", ROLE_PUSHBUTTON);
testRole("unknown_roles_mixed", ROLE_PUSHBUTTON);
@@ -400,8 +403,6 @@
<span id="aria_checkbox_mixed" role="cHECKBOx"></span>
<span id="aria_code" role="code"></span>
<span id="aria_code_mixed" role="cODe"></span>
- <span id="aria_columnheader" role="columnheader"></span>
- <span id="aria_columnheader_mixed" role="cOLUMNHEADEr"></span>
<span id="aria_combobox" role="combobox"></span>
<span id="aria_combobox_mixed" role="cOMBOBOx"></span>
<span id="aria_comment" role="comment"></span>
@@ -424,8 +425,6 @@
<span id="aria_figure_mixed" role="fIGURe"></span>
<span id="aria_grid" role="grid"></span>
<span id="aria_grid_mixed" role="gRId"></span>
- <span id="aria_gridcell" role="gridcell"></span>
- <span id="aria_gridcell_mixed" role="gRIDCELl"></span>
<span id="aria_group" role="group"></span>
<span id="aria_group_mixed" role="gROUp"></span>
<span id="aria_heading" role="heading"></span>
@@ -440,8 +439,6 @@
<span id="aria_list_mixed" role="lISt"></span>
<span id="aria_listbox" role="listbox"></span>
<span id="aria_listbox_mixed" role="lISTBOx"></span>
- <span id="aria_listitem" role="listitem"></span>
- <span id="aria_listitem_mixed" role="lISTITEm"></span>
<span id="aria_log" role="log"></span>
<span id="aria_log_mixed" role="lOg"></span>
<span id="aria_mark" role="mark"></span>
@@ -454,12 +451,6 @@
<span id="aria_menu_mixed" role="mENu"></span>
<span id="aria_menubar" role="menubar"></span>
<span id="aria_menubar_mixed" role="mENUBAr"></span>
- <span id="aria_menuitem" role="menuitem"></span>
- <span id="aria_menuitem_mixed" role="mENUITEm"></span>
- <span id="aria_menuitemcheckbox" role="menuitemcheckbox"></span>
- <span id="aria_menuitemcheckbox_mixed" role="mENUITEMCHECKBOx"></span>
- <span id="aria_menuitemradio" role="menuitemradio"></span>
- <span id="aria_menuitemradio_mixed" role="mENUITEMRADIo"></span>
<span id="aria_meter" role="meter"></span>
<span id="aria_meter_mixed" role="meTer"></span>
<span id="aria_note" role="note"></span>
@@ -488,10 +479,6 @@
<table id="aria_region_as_table_with_caption_mixed" role="rEGIOn"><caption>hello</caption></table>
<table id="aria_region_as_table_with_miscaption" role="region"><caption role="option">hello</caption></table>
<table id="aria_region_as_table_with_miscaption_mixed" role="rEGIOn"><caption role="option">hello</caption></table>
- <span id="aria_row" role="row"></span>
- <span id="aria_row_mixed" role="rOw"></span>
- <span id="aria_rowheader" role="rowheader"></span>
- <span id="aria_rowheader_mixed" role="rOWHEADEr"></span>
<span id="aria_scrollbar" role="scrollbar"></span>
<span id="aria_scrollbar_mixed" role="sCROLLBAr"></span>
<span id="aria_searchbox" role="textbox"></span>
@@ -512,8 +499,6 @@
<span id="aria_superscript_mixed" role="sUPERSCRIPt"></span>
<span id="aria_switch" role="switch"></span>
<span id="aria_switch_mixed" role="sWITCh"></span>
- <span id="aria_tab" role="tab"></span>
- <span id="aria_tab_mixed" role="tAb"></span>
<span id="aria_tablist" role="tablist"></span>
<span id="aria_tablist_mixed" role="tABLISt"></span>
<span id="aria_tabpanel" role="tabpanel"></span>
@@ -532,8 +517,6 @@
<span id="aria_tree_mixed" role="tREe"></span>
<span id="aria_treegrid" role="treegrid"></span>
<span id="aria_treegrid_mixed" role="tREEGRId"></span>
- <span id="aria_treeitem" role="treeitem"></span>
- <span id="aria_treeitem_mixed" role="tREEITEm"></span>
<article id="articlemain" role="main">a main area</article>
<article id="articlemain_mixed" role="mAIn">a main area</article>
@@ -665,6 +648,42 @@
</tr>
</table>
+ <!-- child roles dependent on ancestor role presence -->
+ <div role="grid">
+ <div role="row">
+ <span id="aria_columnheader" role="columnheader"></span>
+ <span id="aria_columnheader_mixed" role="cOLUMNHEADEr"></span>
+ <span id="aria_gridcell" role="gridcell"></span>
+ <span id="aria_gridcell_mixed" role="gRIDCELl"></span>
+ <span id="aria_rowheader" role="rowheader"></span>
+ <span id="aria_rowheader_mixed" role="rOWHEADEr"></span>
+ </div>
+ </div>
+ <div role="list">
+ <span id="aria_listitem" role="listitem"></span>
+ <span id="aria_listitem_mixed" role="lISTITEm"></span>
+ </div>
+ <div role="menu">
+ <span id="aria_menuitem" role="menuitem"></span>
+ <span id="aria_menuitem_mixed" role="mENUITEm"></span>
+ <span id="aria_menuitemcheckbox" role="menuitemcheckbox"></span>
+ <span id="aria_menuitemcheckbox_mixed" role="mENUITEMCHECKBOx"></span>
+ <span id="aria_menuitemradio" role="menuitemradio"></span>
+ <span id="aria_menuitemradio_mixed" role="mENUITEMRADIo"></span>
+ </div>
+ <div role="table">
+ <span id="aria_row" role="row"></span>
+ <span id="aria_row_mixed" role="rOw"></span>
+ </div>
+ <div role="tablist">
+ <span id="aria_tab" role="tab"></span>
+ <span id="aria_tab_mixed" role="tAb"></span>
+ </div>
+ <div role="tree">
+ <span id="aria_treeitem" role="treeitem"></span>
+ <span id="aria_treeitem_mixed" role="tREEITEm"></span>
+ </div>
+
<!-- roles transformed by ARIA state attributes -->
<button aria-pressed="true" id="togglebutton"></button>
<button aria-pressed="tRUe" id="togglebutton_mixed"></button>
diff --git a/accessible/tests/mochitest/test_custom_element_accessibility_defaults.html b/accessible/tests/mochitest/test_custom_element_accessibility_defaults.html
index 672b5c36ad..799aefc163 100644
--- a/accessible/tests/mochitest/test_custom_element_accessibility_defaults.html
+++ b/accessible/tests/mochitest/test_custom_element_accessibility_defaults.html
@@ -33,7 +33,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1665151
["disabled", "button", internals => internals.ariaDisabled = "true"],
["expanded", "button", internals => internals.ariaExpanded = "true"],
["haspopup", "button", internals => internals.ariaHasPopup = "true"],
- ["hidden", "region", internals => internals.ariaHidden = "false"],
+ ["hidden", "region", internals => internals.ariaHidden = "true"],
["invalid", "textbox", internals => internals.ariaInvalid = "true"],
["keyshortcuts", "button", internals => internals.ariaKeyShortcuts = "Alt+Shift+A"],
["label", "button", internals => internals.ariaLabel = "Default"],
@@ -122,8 +122,8 @@ async function runTest() {
testAttrs("default-haspopup", {"haspopup": "true"}, true);
testAbsentAttrs("custom-haspopup", {"haspopup": "false"});
- ok(isAccessible("default-hidden"), "Accessible for not aria-hidden");
- ok(!isAccessible("custom-hidden"), "No accessible for aria-hidden");
+ ok(!isAccessible("default-hidden"), "Accessible for aria-hidden default");
+ ok(isAccessible("custom-hidden"), "Accessible for custom aria-hidden=false");
testStates("default-invalid", STATE_INVALID);
testStates("custom-invalid", 0, 0, STATE_INVALID);
@@ -277,7 +277,7 @@ addA11yLoadEvent(runTest);
<custom-haspopup id="custom-haspopup" aria-haspopup="false"></custom-haspopup>
<custom-hidden id="default-hidden"></custom-hidden>
-<custom-hidden id="custom-hidden" aria-hidden="true"></custom-hidden>
+<custom-hidden id="custom-hidden" aria-hidden="false"></custom-hidden>
<custom-invalid id="default-invalid"></custom-invalid>
<custom-invalid id="custom-invalid" aria-invalid="false"></custom-invalid>
@@ -306,8 +306,10 @@ addA11yLoadEvent(runTest);
<custom-orientation id="default-orientation"></custom-orientation>
<custom-orientation id="custom-orientation" aria-orientation="horizontal"></custom-orientation>
-<custom-posinset id="default-posinset"></custom-posinset>
-<custom-posinset id="custom-posinset" aria-posinset="2"></custom-posinset>
+<div role="listbox">
+ <custom-posinset id="default-posinset"></custom-posinset>
+ <custom-posinset id="custom-posinset" aria-posinset="2"></custom-posinset>
+</div>
<custom-pressed id="default-pressed"></custom-pressed>
<custom-pressed id="custom-pressed" aria-pressed="false"></custom-pressed>
@@ -345,10 +347,10 @@ addA11yLoadEvent(runTest);
<custom-selected id="default-selected"></custom-selected>
<custom-selected id="custom-selected" aria-selected="false"></custom-selected>
-<div role="listbox">
+<div role="list">
<custom-setsize id="default-setsize"></custom-setsize>
</div>
-<div role="listbox">
+<div role="list">
<custom-setsize id="custom-setsize" aria-setsize="2"></custom-setsize>
<div role="listitem" aria-setsize="2"></div>
</div>
diff --git a/accessible/tests/mochitest/tree/test_aria_display_contents.html b/accessible/tests/mochitest/tree/test_aria_display_contents.html
index 454e4e46e1..5b2331e730 100644
--- a/accessible/tests/mochitest/tree/test_aria_display_contents.html
+++ b/accessible/tests/mochitest/tree/test_aria_display_contents.html
@@ -53,11 +53,11 @@
] },
] },
{ SECTION: [
- { LISTITEM: [
+ { SECTION: [
{ TEXT_LEAF: [ ] }
] },
] },
- { LISTITEM: [
+ { SECTION: [
{ TEXT_LEAF: [ ] }
] },
] };
@@ -93,63 +93,63 @@
</pre>
<div id="gridWithoutDisplayContents" role="grid">
- <div role="row">
- <div role="columnheader">col1</div>
- <div role="columnheader">col2</div>
- </div>
- <div role="row">
- <div role="rowheader">row1</div>
- <div role="gridcell">cell1</div>
+ <div role="row">
+ <div role="columnheader">col1</div>
+ <div role="columnheader">col2</div>
+ </div>
+ <div role="row">
+ <div role="rowheader">row1</div>
+ <div role="gridcell">cell1</div>
</div>
</div>
<div id="gridWithDisplayContents" role="grid" style="display:contents;">
- <div role="row">
- <div role="columnheader">col1</div>
- <div role="columnheader">col2</div>
- </div>
- <div role="row">
- <div role="rowheader">row1</div>
- <div role="gridcell">cell1</div>
+ <div role="row">
+ <div role="columnheader">col1</div>
+ <div role="columnheader">col2</div>
+ </div>
+ <div role="row">
+ <div role="rowheader">row1</div>
+ <div role="gridcell">cell1</div>
</div>
</div>
<div id="gridWithDisplayContentsRow" role="grid">
- <div role="row" style="display:contents;">
- <div role="columnheader">col1</div>
- <div role="columnheader">col2</div>
- </div>
- <div role="row">
- <div role="rowheader">row1</div>
- <div role="gridcell">cell1</div>
+ <div role="row" style="display:contents;">
+ <div role="columnheader">col1</div>
+ <div role="columnheader">col2</div>
+ </div>
+ <div role="row">
+ <div role="rowheader">row1</div>
+ <div role="gridcell">cell1</div>
</div>
</div>
<div id="gridWithDisplayContentsColHeader" role="grid">
- <div role="row">
- <div role="columnheader" style="display:contents;">col1</div>
- <div role="columnheader">col2</div>
- </div>
- <div role="row">
- <div role="rowheader">row1</div>
- <div role="gridcell">cell1</div>
+ <div role="row">
+ <div role="columnheader" style="display:contents;">col1</div>
+ <div role="columnheader">col2</div>
+ </div>
+ <div role="row">
+ <div role="rowheader">row1</div>
+ <div role="gridcell">cell1</div>
</div>
</div>
<div id="gridWithDisplayContentsRowHeader" role="grid">
- <div role="row">
- <div role="columnheader">col1</div>
- <div role="columnheader">col2</div>
- </div>
- <div role="row">
- <div role="rowheader" style="display:contents;">row1</div>
- <div role="gridcell">cell1</div>
+ <div role="row">
+ <div role="columnheader">col1</div>
+ <div role="columnheader">col2</div>
+ </div>
+ <div role="row">
+ <div role="rowheader" style="display:contents;">row1</div>
+ <div role="gridcell">cell1</div>
</div>
</div>
<div id="gridWithDisplayContentsGridCell" role="grid">
- <div role="row">
- <div role="columnheader">col1</div>
- <div role="columnheader">col2</div>
- </div>
- <div role="row">
- <div role="rowheader">row1</div>
- <div role="gridcell" style="display:contents;">cell1</div>
+ <div role="row">
+ <div role="columnheader">col1</div>
+ <div role="columnheader">col2</div>
+ </div>
+ <div role="row">
+ <div role="rowheader">row1</div>
+ <div role="gridcell" style="display:contents;">cell1</div>
</div>
</div>
diff --git a/accessible/tests/mochitest/tree/test_aria_grid.html b/accessible/tests/mochitest/tree/test_aria_grid.html
index 4dd30e4183..d409c87c34 100644
--- a/accessible/tests/mochitest/tree/test_aria_grid.html
+++ b/accessible/tests/mochitest/tree/test_aria_grid.html
@@ -19,7 +19,7 @@
var accTree =
{ GRID: [
- { GROUPING: [
+ { ROWGROUP: [
{ ROW: [
{ GRID_CELL: [
{ TEXT_LEAF: [ ] },
diff --git a/accessible/tests/mochitest/tree/test_aria_table.html b/accessible/tests/mochitest/tree/test_aria_table.html
index 22375faf59..2d4a0f00ae 100644
--- a/accessible/tests/mochitest/tree/test_aria_table.html
+++ b/accessible/tests/mochitest/tree/test_aria_table.html
@@ -19,7 +19,7 @@
var accTree =
{ TABLE: [
- { GROUPING: [
+ { ROWGROUP: [
{ ROW: [
{ CELL: [
{ TEXT_LEAF: [ ] },
diff --git a/accessible/tests/mochitest/tree/test_display_contents.html b/accessible/tests/mochitest/tree/test_display_contents.html
index 8393a35b41..9573a845d3 100644
--- a/accessible/tests/mochitest/tree/test_display_contents.html
+++ b/accessible/tests/mochitest/tree/test_display_contents.html
@@ -41,7 +41,7 @@ function doTest() {
tree =
{ TABLE: [
- { GROUPING : [
+ { ROWGROUP : [
{ ROW: [
{ CELL: [{ TEXT_LEAF: [] } ] },
{ CELL: [{ TEXT_LEAF: [] } ] },
diff --git a/accessible/tests/mochitest/tree/test_table.html b/accessible/tests/mochitest/tree/test_table.html
index 5f34c12067..7f7f4fe6db 100644
--- a/accessible/tests/mochitest/tree/test_table.html
+++ b/accessible/tests/mochitest/tree/test_table.html
@@ -283,7 +283,7 @@
// The tbody should get a grouping accessible.
accTree =
{ TABLE: [
- { GROUPING: [
+ { ROWGROUP: [
{ ROW: [
{ CELL: [
{ TEXT_LEAF: [ ] },
diff --git a/accessible/windows/ia2/ia2Accessible.cpp b/accessible/windows/ia2/ia2Accessible.cpp
index 7318dd5e6f..5bc421d086 100644
--- a/accessible/windows/ia2/ia2Accessible.cpp
+++ b/accessible/windows/ia2/ia2Accessible.cpp
@@ -156,7 +156,8 @@ ia2Accessible::role(long* aRole) {
if (!acc) return CO_E_OBJNOTCONNECTED;
#define ROLE(_geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \
- msaaRole, ia2Role, androidClass, iosIsElement, nameRule) \
+ msaaRole, ia2Role, androidClass, iosIsElement, uiaControlType, \
+ nameRule) \
case roles::_geckoRole: \
*aRole = ia2Role; \
break;
diff --git a/accessible/windows/msaa/MsaaAccessible.cpp b/accessible/windows/msaa/MsaaAccessible.cpp
index 3a0e8fc726..56e8cfd058 100644
--- a/accessible/windows/msaa/MsaaAccessible.cpp
+++ b/accessible/windows/msaa/MsaaAccessible.cpp
@@ -14,6 +14,7 @@
#include "mozilla/a11y/AccessibleWrap.h"
#include "mozilla/a11y/Compatibility.h"
#include "mozilla/a11y/DocAccessibleParent.h"
+#include "mozilla/StaticPrefs_accessibility.h"
#include "MsaaAccessible.h"
#include "MsaaDocAccessible.h"
#include "MsaaRootAccessible.h"
@@ -522,9 +523,11 @@ MsaaAccessible::QueryInterface(REFIID iid, void** ppv) {
if (SUCCEEDED(hr)) {
return hr;
}
- hr = uiaRawElmProvider::QueryInterface(iid, ppv);
- if (SUCCEEDED(hr)) {
- return hr;
+ if (StaticPrefs::accessibility_uia_enable()) {
+ hr = uiaRawElmProvider::QueryInterface(iid, ppv);
+ if (SUCCEEDED(hr)) {
+ return hr;
+ }
}
}
if (*ppv) {
@@ -769,7 +772,8 @@ MsaaAccessible::get_accRole(
uint32_t msaaRole = 0;
#define ROLE(_geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \
- _msaaRole, ia2Role, androidClass, iosIsElement, nameRule) \
+ _msaaRole, ia2Role, androidClass, iosIsElement, uiaControlType, \
+ nameRule) \
case roles::_geckoRole: \
msaaRole = _msaaRole; \
break;
diff --git a/accessible/windows/msaa/MsaaAccessible.h b/accessible/windows/msaa/MsaaAccessible.h
index 6d6582f010..fa43c441bf 100644
--- a/accessible/windows/msaa/MsaaAccessible.h
+++ b/accessible/windows/msaa/MsaaAccessible.h
@@ -31,7 +31,7 @@ class MsaaAccessible : public ia2Accessible,
public:
static MsaaAccessible* Create(Accessible* aAcc);
- Accessible* Acc() { return mAcc; }
+ Accessible* Acc() const { return mAcc; }
AccessibleWrap* LocalAcc();
uint32_t GetExistingID() const { return mID; }
@@ -146,6 +146,10 @@ class MsaaAccessible : public ia2Accessible,
EXCEPINFO* pExcepInfo,
UINT* puArgErr) override;
+ // UIA's IInvokeProvider has a method called Invoke too, but it's fine because
+ // it accepts very different parameters.
+ using uiaRawElmProvider::Invoke;
+
protected:
explicit MsaaAccessible(Accessible* aAcc);
virtual ~MsaaAccessible();
diff --git a/accessible/windows/msaa/MsaaRootAccessible.cpp b/accessible/windows/msaa/MsaaRootAccessible.cpp
index ac747ff3d1..2b28edb9b5 100644
--- a/accessible/windows/msaa/MsaaRootAccessible.cpp
+++ b/accessible/windows/msaa/MsaaRootAccessible.cpp
@@ -5,6 +5,7 @@
#include "mozilla/a11y/DocAccessibleParent.h"
#include "mozilla/dom/BrowserParent.h"
+#include "mozilla/StaticPrefs_accessibility.h"
#include "mozilla/WindowsVersion.h"
#include "MsaaRootAccessible.h"
#include "Relation.h"
@@ -36,6 +37,13 @@ MsaaRootAccessible::InternalQueryInterface(REFIID aIid, void** aOutInterface) {
return S_OK;
}
+ if (StaticPrefs::accessibility_uia_enable() &&
+ aIid == IID_IRawElementProviderFragmentRoot) {
+ RefPtr<IRawElementProviderFragmentRoot> root = this;
+ root.forget(aOutInterface);
+ return S_OK;
+ }
+
// ...Otherwise we pass through to the base COM implementation of
// QueryInterface which is provided by MsaaDocAccessible.
return MsaaDocAccessible::QueryInterface(aIid, aOutInterface);
diff --git a/accessible/windows/msaa/MsaaRootAccessible.h b/accessible/windows/msaa/MsaaRootAccessible.h
index a51533d7ba..efc42bc094 100644
--- a/accessible/windows/msaa/MsaaRootAccessible.h
+++ b/accessible/windows/msaa/MsaaRootAccessible.h
@@ -8,12 +8,14 @@
#include "mozilla/mscom/Aggregation.h"
#include "MsaaDocAccessible.h"
+#include "UiaRoot.h"
namespace mozilla {
namespace a11y {
+class RootAccessible;
-class MsaaRootAccessible : public MsaaDocAccessible {
+class MsaaRootAccessible : public MsaaDocAccessible, public UiaRoot {
public:
explicit MsaaRootAccessible(Accessible* aAcc)
: MsaaDocAccessible(aAcc), mOuter(&mInternalUnknown) {}
diff --git a/accessible/windows/msaa/Platform.cpp b/accessible/windows/msaa/Platform.cpp
index 018042c5d3..f4d1c7b176 100644
--- a/accessible/windows/msaa/Platform.cpp
+++ b/accessible/windows/msaa/Platform.cpp
@@ -69,10 +69,13 @@ void a11y::ProxyDestroyed(RemoteAccessible* aProxy) {
void a11y::PlatformEvent(Accessible* aTarget, uint32_t aEventType) {
MsaaAccessible::FireWinEvent(aTarget, aEventType);
+ uiaRawElmProvider::RaiseUiaEventForGeckoEvent(aTarget, aEventType);
}
-void a11y::PlatformStateChangeEvent(Accessible* aTarget, uint64_t, bool) {
+void a11y::PlatformStateChangeEvent(Accessible* aTarget, uint64_t aState,
+ bool aEnabled) {
MsaaAccessible::FireWinEvent(aTarget, nsIAccessibleEvent::EVENT_STATE_CHANGE);
+ uiaRawElmProvider::RaiseUiaEventForStateChange(aTarget, aState, aEnabled);
}
void a11y::PlatformFocusEvent(Accessible* aTarget,
@@ -91,6 +94,8 @@ void a11y::PlatformFocusEvent(Accessible* aTarget,
AccessibleWrap::UpdateSystemCaretFor(aTarget, aCaretRect);
MsaaAccessible::FireWinEvent(aTarget, nsIAccessibleEvent::EVENT_FOCUS);
+ uiaRawElmProvider::RaiseUiaEventForGeckoEvent(
+ aTarget, nsIAccessibleEvent::EVENT_FOCUS);
}
void a11y::PlatformCaretMoveEvent(Accessible* aTarget, int32_t aOffset,
diff --git a/accessible/windows/uia/UiaRoot.cpp b/accessible/windows/uia/UiaRoot.cpp
new file mode 100644
index 0000000000..0e8c86ce6a
--- /dev/null
+++ b/accessible/windows/uia/UiaRoot.cpp
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "UiaRoot.h"
+
+#include "MsaaRootAccessible.h"
+#include "RootAccessible.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+// UiaRoot
+
+Accessible* UiaRoot::Acc() {
+ auto* mr = static_cast<MsaaRootAccessible*>(this);
+ return static_cast<MsaaAccessible*>(mr)->Acc();
+}
+
+// IRawElementProviderFragmentRoot
+
+STDMETHODIMP
+UiaRoot::ElementProviderFromPoint(
+ double aX, double aY,
+ __RPC__deref_out_opt IRawElementProviderFragment** aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ *aRetVal = nullptr;
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ if (Accessible* target = acc->ChildAtPoint(
+ aX, aY, Accessible::EWhichChildAtPoint::DeepestChild)) {
+ RefPtr<IRawElementProviderFragment> fragment =
+ MsaaAccessible::GetFrom(target);
+ fragment.forget(aRetVal);
+ }
+ return S_OK;
+}
+
+STDMETHODIMP
+UiaRoot::GetFocus(__RPC__deref_out_opt IRawElementProviderFragment** aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ *aRetVal = nullptr;
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ if (Accessible* focus = acc->FocusedChild()) {
+ RefPtr<IRawElementProviderFragment> fragment =
+ MsaaAccessible::GetFrom(focus);
+ fragment.forget(aRetVal);
+ }
+ return S_OK;
+}
diff --git a/accessible/windows/uia/UiaRoot.h b/accessible/windows/uia/UiaRoot.h
new file mode 100644
index 0000000000..91d1c00b3d
--- /dev/null
+++ b/accessible/windows/uia/UiaRoot.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_UiaRoot_h__
+#define mozilla_a11y_UiaRoot_h__
+
+#include "objbase.h"
+#include "uiautomation.h"
+
+namespace mozilla {
+namespace a11y {
+class Accessible;
+
+/**
+ * IRawElementProviderFragmentRoot implementation.
+ */
+class UiaRoot : public IRawElementProviderFragmentRoot {
+ public:
+ // IRawElementProviderFragmentRoot
+ virtual HRESULT STDMETHODCALLTYPE ElementProviderFromPoint(
+ /* [in] */ double aX,
+ /* [in] */ double aY,
+ /* [retval][out] */
+ __RPC__deref_out_opt IRawElementProviderFragment** aRetVal);
+
+ virtual HRESULT STDMETHODCALLTYPE GetFocus(
+ /* [retval][out] */ __RPC__deref_out_opt IRawElementProviderFragment**
+ aRetVal);
+
+ private:
+ Accessible* Acc();
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/windows/uia/moz.build b/accessible/windows/uia/moz.build
index 058aacc579..c52a24d612 100644
--- a/accessible/windows/uia/moz.build
+++ b/accessible/windows/uia/moz.build
@@ -6,6 +6,7 @@
SOURCES += [
"uiaRawElmProvider.cpp",
+ "UiaRoot.cpp",
]
LOCAL_INCLUDES += [
diff --git a/accessible/windows/uia/uiaRawElmProvider.cpp b/accessible/windows/uia/uiaRawElmProvider.cpp
index 881ed22277..c022e40cef 100644
--- a/accessible/windows/uia/uiaRawElmProvider.cpp
+++ b/accessible/windows/uia/uiaRawElmProvider.cpp
@@ -6,39 +6,174 @@
#include "uiaRawElmProvider.h"
+#include <comdef.h>
+#include <uiautomationcoreapi.h>
+
#include "AccAttributes.h"
#include "AccessibleWrap.h"
#include "ARIAMap.h"
#include "LocalAccessible-inl.h"
#include "mozilla/a11y/RemoteAccessible.h"
+#include "mozilla/StaticPrefs_accessibility.h"
#include "MsaaAccessible.h"
+#include "MsaaRootAccessible.h"
+#include "nsAccessibilityService.h"
+#include "nsAccUtils.h"
#include "nsTextEquivUtils.h"
+#include "RootAccessible.h"
using namespace mozilla;
using namespace mozilla::a11y;
+// Helper functions
+
+static ToggleState ToToggleState(uint64_t aState) {
+ if (aState & states::MIXED) {
+ return ToggleState_Indeterminate;
+ }
+ if (aState & (states::CHECKED | states::PRESSED)) {
+ return ToggleState_On;
+ }
+ return ToggleState_Off;
+}
+
+static ExpandCollapseState ToExpandCollapseState(uint64_t aState) {
+ if (aState & states::EXPANDED) {
+ return ExpandCollapseState_Expanded;
+ }
+ // If aria-haspopup is specified without aria-expanded, we should still expose
+ // collapsed, since aria-haspopup infers that it can be expanded. The
+ // alternative is ExpandCollapseState_LeafNode, but that means that the
+ // element can't be expanded nor collapsed.
+ if (aState & (states::COLLAPSED | states::HASPOPUP)) {
+ return ExpandCollapseState_Collapsed;
+ }
+ return ExpandCollapseState_LeafNode;
+}
+
////////////////////////////////////////////////////////////////////////////////
// uiaRawElmProvider
////////////////////////////////////////////////////////////////////////////////
-Accessible* uiaRawElmProvider::Acc() {
- return static_cast<MsaaAccessible*>(this)->Acc();
+Accessible* uiaRawElmProvider::Acc() const {
+ return static_cast<const MsaaAccessible*>(this)->Acc();
}
-// IUnknown
-
-// Because uiaRawElmProvider inherits multiple COM interfaces (and thus multiple
-// IUnknowns), we need to explicitly implement AddRef and Release to make
-// our QueryInterface implementation (IMPL_IUNKNOWN2) happy.
-ULONG STDMETHODCALLTYPE uiaRawElmProvider::AddRef() {
- return static_cast<MsaaAccessible*>(this)->AddRef();
+/* static */
+void uiaRawElmProvider::RaiseUiaEventForGeckoEvent(Accessible* aAcc,
+ uint32_t aGeckoEvent) {
+ if (!StaticPrefs::accessibility_uia_enable()) {
+ return;
+ }
+ auto* uia = MsaaAccessible::GetFrom(aAcc);
+ if (!uia) {
+ return;
+ }
+ PROPERTYID property = 0;
+ _variant_t newVal;
+ bool gotNewVal = false;
+ // For control pattern properties, we can't use GetPropertyValue. In those
+ // cases, we must set newVal appropriately and set gotNewVal to true.
+ switch (aGeckoEvent) {
+ case nsIAccessibleEvent::EVENT_DESCRIPTION_CHANGE:
+ property = UIA_FullDescriptionPropertyId;
+ break;
+ case nsIAccessibleEvent::EVENT_FOCUS:
+ ::UiaRaiseAutomationEvent(uia, UIA_AutomationFocusChangedEventId);
+ return;
+ case nsIAccessibleEvent::EVENT_NAME_CHANGE:
+ property = UIA_NamePropertyId;
+ break;
+ case nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE:
+ property = UIA_ValueValuePropertyId;
+ newVal.vt = VT_BSTR;
+ uia->get_Value(&newVal.bstrVal);
+ gotNewVal = true;
+ break;
+ }
+ if (property && ::UiaClientsAreListening()) {
+ // We can't get the old value. Thankfully, clients don't seem to need it.
+ _variant_t oldVal;
+ if (!gotNewVal) {
+ // This isn't a pattern property, so we can use GetPropertyValue.
+ uia->GetPropertyValue(property, &newVal);
+ }
+ ::UiaRaiseAutomationPropertyChangedEvent(uia, property, oldVal, newVal);
+ }
}
-ULONG STDMETHODCALLTYPE uiaRawElmProvider::Release() {
- return static_cast<MsaaAccessible*>(this)->Release();
+/* static */
+void uiaRawElmProvider::RaiseUiaEventForStateChange(Accessible* aAcc,
+ uint64_t aState,
+ bool aEnabled) {
+ if (!StaticPrefs::accessibility_uia_enable()) {
+ return;
+ }
+ auto* uia = MsaaAccessible::GetFrom(aAcc);
+ if (!uia) {
+ return;
+ }
+ PROPERTYID property = 0;
+ _variant_t newVal;
+ switch (aState) {
+ case states::CHECKED:
+ case states::MIXED:
+ case states::PRESSED:
+ property = UIA_ToggleToggleStatePropertyId;
+ newVal.vt = VT_I4;
+ newVal.lVal = ToToggleState(aEnabled ? aState : 0);
+ break;
+ case states::COLLAPSED:
+ case states::EXPANDED:
+ case states::HASPOPUP:
+ property = UIA_ExpandCollapseExpandCollapseStatePropertyId;
+ newVal.vt = VT_I4;
+ newVal.lVal = ToExpandCollapseState(aEnabled ? aState : 0);
+ break;
+ case states::UNAVAILABLE:
+ property = UIA_IsEnabledPropertyId;
+ newVal.vt = VT_BOOL;
+ newVal.boolVal = aEnabled ? VARIANT_FALSE : VARIANT_TRUE;
+ break;
+ default:
+ return;
+ }
+ MOZ_ASSERT(property);
+ if (::UiaClientsAreListening()) {
+ // We can't get the old value. Thankfully, clients don't seem to need it.
+ _variant_t oldVal;
+ ::UiaRaiseAutomationPropertyChangedEvent(uia, property, oldVal, newVal);
+ }
}
-IMPL_IUNKNOWN2(uiaRawElmProvider, IAccessibleEx, IRawElementProviderSimple)
+// IUnknown
+
+STDMETHODIMP
+uiaRawElmProvider::QueryInterface(REFIID aIid, void** aInterface) {
+ *aInterface = nullptr;
+ if (aIid == IID_IAccessibleEx) {
+ *aInterface = static_cast<IAccessibleEx*>(this);
+ } else if (aIid == IID_IRawElementProviderSimple) {
+ *aInterface = static_cast<IRawElementProviderSimple*>(this);
+ } else if (aIid == IID_IRawElementProviderFragment) {
+ *aInterface = static_cast<IRawElementProviderFragment*>(this);
+ } else if (aIid == IID_IExpandCollapseProvider) {
+ *aInterface = static_cast<IExpandCollapseProvider*>(this);
+ } else if (aIid == IID_IInvokeProvider) {
+ *aInterface = static_cast<IInvokeProvider*>(this);
+ } else if (aIid == IID_IScrollItemProvider) {
+ *aInterface = static_cast<IScrollItemProvider*>(this);
+ } else if (aIid == IID_IToggleProvider) {
+ *aInterface = static_cast<IToggleProvider*>(this);
+ } else if (aIid == IID_IValueProvider) {
+ *aInterface = static_cast<IValueProvider*>(this);
+ } else {
+ return E_NOINTERFACE;
+ }
+ MOZ_ASSERT(*aInterface);
+ static_cast<MsaaAccessible*>(this)->AddRef();
+ return S_OK;
+}
////////////////////////////////////////////////////////////////////////////////
// IAccessibleEx
@@ -113,8 +248,9 @@ uiaRawElmProvider::get_ProviderOptions(
__RPC__out enum ProviderOptions* aOptions) {
if (!aOptions) return E_INVALIDARG;
- // This method is not used with IAccessibleEx implementations.
- *aOptions = ProviderOptions_ServerSideProvider;
+ *aOptions = static_cast<enum ProviderOptions>(
+ ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading |
+ ProviderOptions_HasNativeIAccessible);
return S_OK;
}
@@ -122,8 +258,46 @@ STDMETHODIMP
uiaRawElmProvider::GetPatternProvider(
PATTERNID aPatternId, __RPC__deref_out_opt IUnknown** aPatternProvider) {
if (!aPatternProvider) return E_INVALIDARG;
-
*aPatternProvider = nullptr;
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ switch (aPatternId) {
+ case UIA_ExpandCollapsePatternId:
+ if (HasExpandCollapsePattern()) {
+ RefPtr<IExpandCollapseProvider> expand = this;
+ expand.forget(aPatternProvider);
+ }
+ return S_OK;
+ case UIA_InvokePatternId:
+ // Per the UIA documentation, we should only expose the Invoke pattern "if
+ // the same behavior is not exposed through another control pattern
+ // provider".
+ if (acc->ActionCount() > 0 && !HasTogglePattern() &&
+ !HasExpandCollapsePattern()) {
+ RefPtr<IInvokeProvider> invoke = this;
+ invoke.forget(aPatternProvider);
+ }
+ return S_OK;
+ case UIA_ScrollItemPatternId: {
+ RefPtr<IScrollItemProvider> scroll = this;
+ scroll.forget(aPatternProvider);
+ return S_OK;
+ }
+ case UIA_TogglePatternId:
+ if (HasTogglePattern()) {
+ RefPtr<IToggleProvider> toggle = this;
+ toggle.forget(aPatternProvider);
+ }
+ return S_OK;
+ case UIA_ValuePatternId:
+ if (HasValuePattern()) {
+ RefPtr<IValueProvider> value = this;
+ value.forget(aPatternProvider);
+ }
+ return S_OK;
+ }
return S_OK;
}
@@ -230,11 +404,71 @@ uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId,
break;
}
- case UIA_IsControlElementPropertyId:
+ case UIA_AutomationIdPropertyId: {
+ nsAutoString id;
+ acc->DOMNodeID(id);
+ if (!id.IsEmpty()) {
+ aPropertyValue->vt = VT_BSTR;
+ aPropertyValue->bstrVal = ::SysAllocString(id.get());
+ return S_OK;
+ }
+ break;
+ }
+
+ case UIA_ControlTypePropertyId:
+ aPropertyValue->vt = VT_I4;
+ aPropertyValue->lVal = GetControlType();
+ break;
+
+ case UIA_FullDescriptionPropertyId: {
+ nsAutoString desc;
+ acc->Description(desc);
+ if (!desc.IsEmpty()) {
+ aPropertyValue->vt = VT_BSTR;
+ aPropertyValue->bstrVal = ::SysAllocString(desc.get());
+ return S_OK;
+ }
+ break;
+ }
+
+ case UIA_HasKeyboardFocusPropertyId:
+ aPropertyValue->vt = VT_BOOL;
+ aPropertyValue->boolVal = VARIANT_FALSE;
+ if (auto* focusMgr = FocusMgr()) {
+ if (focusMgr->IsFocused(acc)) {
+ aPropertyValue->boolVal = VARIANT_TRUE;
+ }
+ }
+ return S_OK;
+
case UIA_IsContentElementPropertyId:
+ case UIA_IsControlElementPropertyId:
aPropertyValue->vt = VT_BOOL;
aPropertyValue->boolVal = IsControl() ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
+
+ case UIA_IsEnabledPropertyId:
+ aPropertyValue->vt = VT_BOOL;
+ aPropertyValue->boolVal =
+ (acc->State() & states::UNAVAILABLE) ? VARIANT_FALSE : VARIANT_TRUE;
+ return S_OK;
+
+ case UIA_IsKeyboardFocusablePropertyId:
+ aPropertyValue->vt = VT_BOOL;
+ aPropertyValue->boolVal =
+ (acc->State() & states::FOCUSABLE) ? VARIANT_TRUE : VARIANT_FALSE;
+ return S_OK;
+
+ case UIA_NamePropertyId: {
+ nsAutoString name;
+ acc->Name(name);
+ if (!name.IsEmpty()) {
+ aPropertyValue->vt = VT_BSTR;
+ aPropertyValue->bstrVal = ::SysAllocString(name.get());
+ return S_OK;
+ }
+ break;
+ }
}
return S_OK;
@@ -244,9 +478,274 @@ STDMETHODIMP
uiaRawElmProvider::get_HostRawElementProvider(
__RPC__deref_out_opt IRawElementProviderSimple** aRawElmProvider) {
if (!aRawElmProvider) return E_INVALIDARG;
-
- // This method is not used with IAccessibleEx implementations.
*aRawElmProvider = nullptr;
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ if (acc->IsRoot()) {
+ HWND hwnd = MsaaAccessible::GetHWNDFor(acc);
+ return UiaHostProviderFromHwnd(hwnd, aRawElmProvider);
+ }
+ return S_OK;
+}
+
+// IRawElementProviderFragment
+
+STDMETHODIMP
+uiaRawElmProvider::Navigate(
+ enum NavigateDirection aDirection,
+ __RPC__deref_out_opt IRawElementProviderFragment** aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ *aRetVal = nullptr;
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ Accessible* target = nullptr;
+ switch (aDirection) {
+ case NavigateDirection_Parent:
+ if (!acc->IsRoot()) {
+ target = acc->Parent();
+ }
+ break;
+ case NavigateDirection_NextSibling:
+ if (!acc->IsRoot()) {
+ target = acc->NextSibling();
+ }
+ break;
+ case NavigateDirection_PreviousSibling:
+ if (!acc->IsRoot()) {
+ target = acc->PrevSibling();
+ }
+ break;
+ case NavigateDirection_FirstChild:
+ if (!nsAccUtils::MustPrune(acc)) {
+ target = acc->FirstChild();
+ }
+ break;
+ case NavigateDirection_LastChild:
+ if (!nsAccUtils::MustPrune(acc)) {
+ target = acc->LastChild();
+ }
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+ RefPtr<IRawElementProviderFragment> fragment =
+ MsaaAccessible::GetFrom(target);
+ fragment.forget(aRetVal);
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_BoundingRectangle(__RPC__out struct UiaRect* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ LayoutDeviceIntRect rect = acc->Bounds();
+ aRetVal->left = rect.X();
+ aRetVal->top = rect.Y();
+ aRetVal->width = rect.Width();
+ aRetVal->height = rect.Height();
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::GetEmbeddedFragmentRoots(
+ __RPC__deref_out_opt SAFEARRAY** aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ *aRetVal = nullptr;
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::SetFocus() {
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ acc->TakeFocus();
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_FragmentRoot(
+ __RPC__deref_out_opt IRawElementProviderFragmentRoot** aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ *aRetVal = nullptr;
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ LocalAccessible* localAcc = acc->AsLocal();
+ if (!localAcc) {
+ localAcc = acc->AsRemote()->OuterDocOfRemoteBrowser();
+ if (!localAcc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ }
+ MsaaAccessible* msaa = MsaaAccessible::GetFrom(localAcc->RootAccessible());
+ RefPtr<IRawElementProviderFragmentRoot> fragRoot =
+ static_cast<MsaaRootAccessible*>(msaa);
+ fragRoot.forget(aRetVal);
+ return S_OK;
+}
+
+// IInvokeProvider methods
+
+STDMETHODIMP
+uiaRawElmProvider::Invoke() {
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ if (acc->DoAction(0)) {
+ // We don't currently have a way to notify when the action was actually
+ // handled. The UIA documentation says it's okay to fire this immediately if
+ // it "is not possible or practical to wait until the action is complete".
+ ::UiaRaiseAutomationEvent(this, UIA_Invoke_InvokedEventId);
+ }
+ return S_OK;
+}
+
+// IToggleProvider methods
+
+STDMETHODIMP
+uiaRawElmProvider::Toggle() {
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ acc->DoAction(0);
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_ToggleState(__RPC__out enum ToggleState* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = ToToggleState(acc->State());
+ return S_OK;
+}
+
+// IExpandCollapseProvider methods
+
+STDMETHODIMP
+uiaRawElmProvider::Expand() {
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ if (acc->State() & states::EXPANDED) {
+ return UIA_E_INVALIDOPERATION;
+ }
+ acc->DoAction(0);
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::Collapse() {
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ if (acc->State() & states::COLLAPSED) {
+ return UIA_E_INVALIDOPERATION;
+ }
+ acc->DoAction(0);
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_ExpandCollapseState(
+ __RPC__out enum ExpandCollapseState* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = ToExpandCollapseState(acc->State());
+ return S_OK;
+}
+
+// IScrollItemProvider methods
+
+MOZ_CAN_RUN_SCRIPT_BOUNDARY STDMETHODIMP uiaRawElmProvider::ScrollIntoView() {
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ acc->ScrollTo(nsIAccessibleScrollType::SCROLL_TYPE_ANYWHERE);
+ return S_OK;
+}
+
+// IValueProvider methods
+
+STDMETHODIMP
+uiaRawElmProvider::SetValue(__RPC__in LPCWSTR aVal) {
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ HyperTextAccessibleBase* ht = acc->AsHyperTextBase();
+ if (!ht || !acc->IsTextRole()) {
+ return UIA_E_INVALIDOPERATION;
+ }
+ if (acc->State() & (states::READONLY | states::UNAVAILABLE)) {
+ return UIA_E_INVALIDOPERATION;
+ }
+ nsAutoString text(aVal);
+ ht->ReplaceText(text);
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_Value(__RPC__deref_out_opt BSTR* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ *aRetVal = nullptr;
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ nsAutoString value;
+ acc->Value(value);
+ *aRetVal = ::SysAllocStringLen(value.get(), value.Length());
+ if (!*aRetVal) {
+ return E_OUTOFMEMORY;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_IsReadOnly(__RPC__out BOOL* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = acc->State() & states::READONLY;
return S_OK;
}
@@ -314,3 +813,44 @@ bool uiaRawElmProvider::IsControl() {
return true;
}
+
+long uiaRawElmProvider::GetControlType() const {
+ Accessible* acc = Acc();
+ MOZ_ASSERT(acc);
+#define ROLE(_geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \
+ msaaRole, ia2Role, androidClass, iosIsElement, uiaControlType, \
+ nameRule) \
+ case roles::_geckoRole: \
+ return uiaControlType; \
+ break;
+ switch (acc->Role()) {
+#include "RoleMap.h"
+ }
+#undef ROLE
+ MOZ_CRASH("Unknown role.");
+ return 0;
+}
+
+bool uiaRawElmProvider::HasTogglePattern() {
+ Accessible* acc = Acc();
+ MOZ_ASSERT(acc);
+ return acc->State() & states::CHECKABLE ||
+ acc->Role() == roles::TOGGLE_BUTTON;
+}
+
+bool uiaRawElmProvider::HasExpandCollapsePattern() {
+ Accessible* acc = Acc();
+ MOZ_ASSERT(acc);
+ return acc->State() & (states::EXPANDABLE | states::HASPOPUP);
+}
+
+bool uiaRawElmProvider::HasValuePattern() const {
+ Accessible* acc = Acc();
+ MOZ_ASSERT(acc);
+ if (acc->HasNumericValue() || acc->IsCombobox() || acc->IsHTMLLink() ||
+ acc->IsTextField()) {
+ return true;
+ }
+ const nsRoleMapEntry* roleMapEntry = acc->ARIARoleMap();
+ return roleMapEntry && roleMapEntry->Is(nsGkAtoms::textbox);
+}
diff --git a/accessible/windows/uia/uiaRawElmProvider.h b/accessible/windows/uia/uiaRawElmProvider.h
index 0e5172c805..0e05d1a030 100644
--- a/accessible/windows/uia/uiaRawElmProvider.h
+++ b/accessible/windows/uia/uiaRawElmProvider.h
@@ -7,9 +7,9 @@
#ifndef mozilla_a11y_uiaRawElmProvider_h__
#define mozilla_a11y_uiaRawElmProvider_h__
-#include "objbase.h"
-#include "IUnknownImpl.h"
-#include "uiautomation.h"
+#include <objbase.h>
+#include <stdint.h>
+#include <uiautomation.h>
namespace mozilla {
namespace a11y {
@@ -20,12 +20,21 @@ class Accessible;
* IRawElementProviderSimple implementation (maintains IAccessibleEx approach).
*/
class uiaRawElmProvider : public IAccessibleEx,
- public IRawElementProviderSimple {
+ public IRawElementProviderSimple,
+ public IRawElementProviderFragment,
+ public IInvokeProvider,
+ public IToggleProvider,
+ public IExpandCollapseProvider,
+ public IScrollItemProvider,
+ public IValueProvider {
public:
+ static void RaiseUiaEventForGeckoEvent(Accessible* aAcc,
+ uint32_t aGeckoEvent);
+ static void RaiseUiaEventForStateChange(Accessible* aAcc, uint64_t aState,
+ bool aEnabled);
+
// IUnknown
- DECL_IUNKNOWN_INHERITED
- ULONG STDMETHODCALLTYPE AddRef() override;
- ULONG STDMETHODCALLTYPE Release() override;
+ STDMETHODIMP QueryInterface(REFIID aIid, void** aInterface);
// IAccessibleEx
virtual HRESULT STDMETHODCALLTYPE GetObjectForChild(
@@ -59,9 +68,63 @@ class uiaRawElmProvider : public IAccessibleEx,
/* [retval][out] */ __RPC__deref_out_opt IRawElementProviderSimple**
aRawElmProvider);
+ // IRawElementProviderFragment
+ virtual HRESULT STDMETHODCALLTYPE Navigate(
+ /* [in] */ enum NavigateDirection aDirection,
+ /* [retval][out] */ __RPC__deref_out_opt IRawElementProviderFragment**
+ aRetVal);
+
+ // GetRuntimeId is shared with IAccessibleEx.
+
+ virtual HRESULT STDMETHODCALLTYPE get_BoundingRectangle(
+ /* [retval][out] */ __RPC__out struct UiaRect* aRetVal);
+
+ virtual HRESULT STDMETHODCALLTYPE GetEmbeddedFragmentRoots(
+ /* [retval][out] */ __RPC__deref_out_opt SAFEARRAY** aRetVal);
+
+ virtual HRESULT STDMETHODCALLTYPE SetFocus(void);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_FragmentRoot(
+ /* [retval][out] */ __RPC__deref_out_opt IRawElementProviderFragmentRoot**
+ aRetVal);
+
+ // IInvokeProvider
+ virtual HRESULT STDMETHODCALLTYPE Invoke(void);
+
+ // IToggleProvider
+ virtual HRESULT STDMETHODCALLTYPE Toggle(void);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ToggleState(
+ /* [retval][out] */ __RPC__out enum ToggleState* aRetVal);
+
+ // IExpandCollapseProvider
+ virtual HRESULT STDMETHODCALLTYPE Expand(void);
+
+ virtual HRESULT STDMETHODCALLTYPE Collapse(void);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ExpandCollapseState(
+ /* [retval][out] */ __RPC__out enum ExpandCollapseState* aRetVal);
+
+ // IScrollItemProvider
+ virtual HRESULT STDMETHODCALLTYPE ScrollIntoView(void);
+
+ // IValueProvider
+ virtual HRESULT STDMETHODCALLTYPE SetValue(
+ /* [in] */ __RPC__in LPCWSTR val);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Value(
+ /* [retval][out] */ __RPC__deref_out_opt BSTR* pRetVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsReadOnly(
+ /* [retval][out] */ __RPC__out BOOL* pRetVal);
+
private:
- Accessible* Acc();
+ Accessible* Acc() const;
bool IsControl();
+ long GetControlType() const;
+ bool HasTogglePattern();
+ bool HasExpandCollapsePattern();
+ bool HasValuePattern() const;
};
} // namespace a11y
diff --git a/accessible/xpcom/xpcAccessible.cpp b/accessible/xpcom/xpcAccessible.cpp
index 37901e3ec2..ebf7ba8e80 100644
--- a/accessible/xpcom/xpcAccessible.cpp
+++ b/accessible/xpcom/xpcAccessible.cpp
@@ -636,7 +636,8 @@ xpcAccessible::ScrollToPoint(uint32_t aCoordinateType, int32_t aX, int32_t aY) {
NS_IMETHODIMP
xpcAccessible::Announce(const nsAString& aAnnouncement, uint16_t aPriority) {
- if (RemoteAccessible* proxy = IntlGeneric()->AsRemote()) {
+ RemoteAccessible* proxy = IntlGeneric()->AsRemote();
+ if (proxy) {
#if defined(XP_WIN)
return NS_ERROR_NOT_IMPLEMENTED;
#else