summaryrefslogtreecommitdiffstats
path: root/accessible/windows/uia
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/windows/uia')
-rw-r--r--accessible/windows/uia/UiaGrid.cpp151
-rw-r--r--accessible/windows/uia/UiaGrid.h52
-rw-r--r--accessible/windows/uia/UiaGridItem.cpp130
-rw-r--r--accessible/windows/uia/UiaGridItem.h51
-rw-r--r--accessible/windows/uia/moz.build3
-rw-r--r--accessible/windows/uia/uiaRawElmProvider.cpp594
-rw-r--r--accessible/windows/uia/uiaRawElmProvider.h75
7 files changed, 1042 insertions, 14 deletions
diff --git a/accessible/windows/uia/UiaGrid.cpp b/accessible/windows/uia/UiaGrid.cpp
new file mode 100644
index 0000000000..2a22a1f4da
--- /dev/null
+++ b/accessible/windows/uia/UiaGrid.cpp
@@ -0,0 +1,151 @@
+/* -*- 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 "ia2AccessibleTable.h"
+#include "mozilla/a11y/TableAccessible.h"
+#include "nsIAccessiblePivot.h"
+#include "Pivot.h"
+#include "UiaGrid.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+// Helpers
+
+// Used to search for all row and column headers in a table. This could be slow,
+// as it potentially walks all cells in the table. However, it's unclear if,
+// when or how often clients will use this. If this proves to be a performance
+// problem, we will need to add methods to TableAccessible to get all row and
+// column headers in a faster way.
+class HeaderRule : public PivotRule {
+ public:
+ explicit HeaderRule(role aRole) : mRole(aRole) {}
+
+ virtual uint16_t Match(Accessible* aAcc) override {
+ role accRole = aAcc->Role();
+ if (accRole == mRole) {
+ return nsIAccessibleTraversalRule::FILTER_MATCH |
+ nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
+ }
+ if (accRole == roles::CAPTION || aAcc->IsTableCell()) {
+ return nsIAccessibleTraversalRule::FILTER_IGNORE |
+ nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
+ }
+ return nsIAccessibleTraversalRule::FILTER_IGNORE;
+ }
+
+ private:
+ role mRole;
+};
+
+static SAFEARRAY* GetAllHeaders(Accessible* aTable, role aRole) {
+ AutoTArray<Accessible*, 20> headers;
+ Pivot pivot(aTable);
+ HeaderRule rule(aRole);
+ for (Accessible* header = pivot.Next(aTable, rule); header;
+ header = pivot.Next(header, rule)) {
+ headers.AppendElement(header);
+ }
+ return AccessibleArrayToUiaArray(headers);
+}
+
+// UiaGrid
+
+Accessible* UiaGrid::Acc() {
+ auto* ia2t = static_cast<ia2AccessibleTable*>(this);
+ return ia2t->MsaaAccessible::Acc();
+}
+
+TableAccessible* UiaGrid::TableAcc() {
+ Accessible* acc = Acc();
+ return acc ? acc->AsTable() : nullptr;
+}
+
+// IGridProvider methods
+
+STDMETHODIMP
+UiaGrid::GetItem(int aRow, int aColumn,
+ __RPC__deref_out_opt IRawElementProviderSimple** aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ *aRetVal = nullptr;
+ TableAccessible* table = TableAcc();
+ if (!table) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ Accessible* cell = table->CellAt(aRow, aColumn);
+ if (!cell) {
+ return E_INVALIDARG;
+ }
+ RefPtr<IRawElementProviderSimple> uia = MsaaAccessible::GetFrom(cell);
+ uia.forget(aRetVal);
+ return S_OK;
+}
+
+STDMETHODIMP
+UiaGrid::get_RowCount(__RPC__out int* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ TableAccessible* table = TableAcc();
+ if (!table) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = table->RowCount();
+ return S_OK;
+}
+
+STDMETHODIMP
+UiaGrid::get_ColumnCount(__RPC__out int* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ TableAccessible* table = TableAcc();
+ if (!table) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = table->ColCount();
+ return S_OK;
+}
+
+// ITableProvider methods
+
+STDMETHODIMP
+UiaGrid::GetRowHeaders(__RPC__deref_out_opt SAFEARRAY** aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = GetAllHeaders(acc, roles::ROWHEADER);
+ return S_OK;
+}
+
+STDMETHODIMP
+UiaGrid::GetColumnHeaders(__RPC__deref_out_opt SAFEARRAY** aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = GetAllHeaders(acc, roles::COLUMNHEADER);
+ return S_OK;
+}
+
+STDMETHODIMP
+UiaGrid::get_RowOrColumnMajor(__RPC__out enum RowOrColumnMajor* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ // HTML and ARIA tables are always in row major order.
+ *aRetVal = RowOrColumnMajor_RowMajor;
+ return S_OK;
+}
diff --git a/accessible/windows/uia/UiaGrid.h b/accessible/windows/uia/UiaGrid.h
new file mode 100644
index 0000000000..c38442246c
--- /dev/null
+++ b/accessible/windows/uia/UiaGrid.h
@@ -0,0 +1,52 @@
+/* -*- 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_UiaGrid_h__
+#define mozilla_a11y_UiaGrid_h__
+
+#include "objbase.h"
+#include "uiautomation.h"
+
+namespace mozilla::a11y {
+class Accessible;
+class TableAccessible;
+
+/**
+ * IGridProvider and ITableProvider implementations.
+ */
+class UiaGrid : public IGridProvider, public ITableProvider {
+ public:
+ // IGridProvider
+ virtual HRESULT STDMETHODCALLTYPE GetItem(
+ /* [in] */ int aRow,
+ /* [in] */ int aColumn,
+ /* [retval][out] */
+ __RPC__deref_out_opt IRawElementProviderSimple** aRetVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_RowCount(
+ /* [retval][out] */ __RPC__out int* aRetVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ColumnCount(
+ /* [retval][out] */ __RPC__out int* aRetVal);
+
+ // ITableProvider
+ virtual HRESULT STDMETHODCALLTYPE GetRowHeaders(
+ /* [retval][out] */ __RPC__deref_out_opt SAFEARRAY** aRetVal);
+
+ virtual HRESULT STDMETHODCALLTYPE GetColumnHeaders(
+ /* [retval][out] */ __RPC__deref_out_opt SAFEARRAY** aRetVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_RowOrColumnMajor(
+ /* [retval][out] */ __RPC__out enum RowOrColumnMajor* aRetVal);
+
+ private:
+ Accessible* Acc();
+ TableAccessible* TableAcc();
+};
+
+} // namespace mozilla::a11y
+
+#endif
diff --git a/accessible/windows/uia/UiaGridItem.cpp b/accessible/windows/uia/UiaGridItem.cpp
new file mode 100644
index 0000000000..89c56b8d45
--- /dev/null
+++ b/accessible/windows/uia/UiaGridItem.cpp
@@ -0,0 +1,130 @@
+/* -*- 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 "ia2AccessibleTableCell.h"
+#include "mozilla/a11y/TableAccessible.h"
+#include "mozilla/a11y/TableCellAccessible.h"
+#include "UiaGridItem.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+// UiaGridItem
+
+TableCellAccessible* UiaGridItem::CellAcc() {
+ auto* derived = static_cast<ia2AccessibleTableCell*>(this);
+ Accessible* acc = derived->Acc();
+ return acc ? acc->AsTableCell() : nullptr;
+}
+
+// IGridItemProvider methods
+
+STDMETHODIMP
+UiaGridItem::get_Row(__RPC__out int* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ TableCellAccessible* cell = CellAcc();
+ if (!cell) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = cell->RowIdx();
+ return S_OK;
+}
+
+STDMETHODIMP
+UiaGridItem::get_Column(__RPC__out int* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ TableCellAccessible* cell = CellAcc();
+ if (!cell) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = cell->ColIdx();
+ return S_OK;
+}
+
+STDMETHODIMP
+UiaGridItem::get_RowSpan(__RPC__out int* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ TableCellAccessible* cell = CellAcc();
+ if (!cell) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = cell->RowExtent();
+ return S_OK;
+}
+
+STDMETHODIMP
+UiaGridItem::get_ColumnSpan(__RPC__out int* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ TableCellAccessible* cell = CellAcc();
+ if (!cell) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = cell->ColExtent();
+ return S_OK;
+}
+
+STDMETHODIMP
+UiaGridItem::get_ContainingGrid(
+ __RPC__deref_out_opt IRawElementProviderSimple** aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ *aRetVal = nullptr;
+ TableCellAccessible* cell = CellAcc();
+ if (!cell) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ TableAccessible* table = cell->Table();
+ if (!table) {
+ return E_FAIL;
+ }
+ Accessible* tableAcc = table->AsAccessible();
+ RefPtr<IRawElementProviderSimple> uia = MsaaAccessible::GetFrom(tableAcc);
+ uia.forget(aRetVal);
+ return S_OK;
+}
+
+// ITableItemProvider methods
+
+STDMETHODIMP
+UiaGridItem::GetRowHeaderItems(__RPC__deref_out_opt SAFEARRAY** aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ *aRetVal = nullptr;
+ TableCellAccessible* cell = CellAcc();
+ if (!cell) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ AutoTArray<Accessible*, 10> cells;
+ cell->RowHeaderCells(&cells);
+ *aRetVal = AccessibleArrayToUiaArray(cells);
+ return S_OK;
+}
+
+STDMETHODIMP
+UiaGridItem::GetColumnHeaderItems(__RPC__deref_out_opt SAFEARRAY** aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ *aRetVal = nullptr;
+ TableCellAccessible* cell = CellAcc();
+ if (!cell) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ AutoTArray<Accessible*, 10> cells;
+ cell->ColHeaderCells(&cells);
+ *aRetVal = AccessibleArrayToUiaArray(cells);
+ return S_OK;
+}
diff --git a/accessible/windows/uia/UiaGridItem.h b/accessible/windows/uia/UiaGridItem.h
new file mode 100644
index 0000000000..6c59630b0f
--- /dev/null
+++ b/accessible/windows/uia/UiaGridItem.h
@@ -0,0 +1,51 @@
+/* -*- 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_UiaGridItem_h__
+#define mozilla_a11y_UiaGridItem_h__
+
+#include "objbase.h"
+#include "uiautomation.h"
+
+namespace mozilla::a11y {
+class TableCellAccessible;
+
+/**
+ * IGridItemProvider and ITableItemProvider implementations.
+ */
+class UiaGridItem : public IGridItemProvider, public ITableItemProvider {
+ public:
+ // IGridItemProvider
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Row(
+ /* [retval][out] */ __RPC__out int* aRetVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Column(
+ /* [retval][out] */ __RPC__out int* aRetVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_RowSpan(
+ /* [retval][out] */ __RPC__out int* aRetVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ColumnSpan(
+ /* [retval][out] */ __RPC__out int* aRetVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ContainingGrid(
+ /* [retval][out] */ __RPC__deref_out_opt IRawElementProviderSimple**
+ aRetVal);
+
+ // ITableItemProvider
+ virtual HRESULT STDMETHODCALLTYPE GetRowHeaderItems(
+ /* [retval][out] */ __RPC__deref_out_opt SAFEARRAY** aRetVal);
+
+ virtual HRESULT STDMETHODCALLTYPE GetColumnHeaderItems(
+ /* [retval][out] */ __RPC__deref_out_opt SAFEARRAY** aRetVal);
+
+ private:
+ TableCellAccessible* CellAcc();
+};
+
+} // namespace mozilla::a11y
+
+#endif
diff --git a/accessible/windows/uia/moz.build b/accessible/windows/uia/moz.build
index c52a24d612..2061261494 100644
--- a/accessible/windows/uia/moz.build
+++ b/accessible/windows/uia/moz.build
@@ -5,6 +5,8 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
SOURCES += [
+ "UiaGrid.cpp",
+ "UiaGridItem.cpp",
"uiaRawElmProvider.cpp",
"UiaRoot.cpp",
]
@@ -13,6 +15,7 @@ LOCAL_INCLUDES += [
"/accessible/base",
"/accessible/generic",
"/accessible/html",
+ "/accessible/windows/ia2",
"/accessible/windows/msaa",
"/accessible/xpcom",
"/accessible/xul",
diff --git a/accessible/windows/uia/uiaRawElmProvider.cpp b/accessible/windows/uia/uiaRawElmProvider.cpp
index c022e40cef..82726bb9aa 100644
--- a/accessible/windows/uia/uiaRawElmProvider.cpp
+++ b/accessible/windows/uia/uiaRawElmProvider.cpp
@@ -11,7 +11,10 @@
#include "AccAttributes.h"
#include "AccessibleWrap.h"
+#include "ApplicationAccessible.h"
#include "ARIAMap.h"
+#include "ia2AccessibleTable.h"
+#include "ia2AccessibleTableCell.h"
#include "LocalAccessible-inl.h"
#include "mozilla/a11y/RemoteAccessible.h"
#include "mozilla/StaticPrefs_accessibility.h"
@@ -19,12 +22,25 @@
#include "MsaaRootAccessible.h"
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
+#include "nsIAccessiblePivot.h"
#include "nsTextEquivUtils.h"
+#include "Pivot.h"
+#include "Relation.h"
#include "RootAccessible.h"
using namespace mozilla;
using namespace mozilla::a11y;
+#ifdef __MINGW32__
+// These constants are missing in mingw-w64. This code should be removed once
+// we update to a version which includes them.
+const long UIA_CustomLandmarkTypeId = 80000;
+const long UIA_FormLandmarkTypeId = 80001;
+const long UIA_MainLandmarkTypeId = 80002;
+const long UIA_NavigationLandmarkTypeId = 80003;
+const long UIA_SearchLandmarkTypeId = 80004;
+#endif // __MINGW32__
+
// Helper functions
static ToggleState ToToggleState(uint64_t aState) {
@@ -51,6 +67,34 @@ static ExpandCollapseState ToExpandCollapseState(uint64_t aState) {
return ExpandCollapseState_LeafNode;
}
+static bool IsRadio(Accessible* aAcc) {
+ role r = aAcc->Role();
+ return r == roles::RADIOBUTTON || r == roles::RADIO_MENU_ITEM;
+}
+
+// Used to search for a text leaf descendant for the LabeledBy property.
+class LabelTextLeafRule : public PivotRule {
+ public:
+ virtual uint16_t Match(Accessible* aAcc) override {
+ if (aAcc->IsTextLeaf()) {
+ nsAutoString name;
+ aAcc->Name(name);
+ if (name.IsEmpty() || name.EqualsLiteral(" ")) {
+ // An empty or white space text leaf isn't useful as a label.
+ return nsIAccessibleTraversalRule::FILTER_IGNORE;
+ }
+ return nsIAccessibleTraversalRule::FILTER_MATCH;
+ }
+ if (!nsTextEquivUtils::HasNameRule(aAcc, eNameFromSubtreeIfReqRule)) {
+ // Don't descend into things that can't be used as label content; e.g.
+ // text boxes.
+ return nsIAccessibleTraversalRule::FILTER_IGNORE |
+ nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
+ }
+ return nsIAccessibleTraversalRule::FILTER_IGNORE;
+ }
+};
+
////////////////////////////////////////////////////////////////////////////////
// uiaRawElmProvider
////////////////////////////////////////////////////////////////////////////////
@@ -84,12 +128,32 @@ void uiaRawElmProvider::RaiseUiaEventForGeckoEvent(Accessible* aAcc,
case nsIAccessibleEvent::EVENT_NAME_CHANGE:
property = UIA_NamePropertyId;
break;
+ case nsIAccessibleEvent::EVENT_SELECTION:
+ ::UiaRaiseAutomationEvent(uia, UIA_SelectionItem_ElementSelectedEventId);
+ return;
+ case nsIAccessibleEvent::EVENT_SELECTION_ADD:
+ ::UiaRaiseAutomationEvent(
+ uia, UIA_SelectionItem_ElementAddedToSelectionEventId);
+ return;
+ case nsIAccessibleEvent::EVENT_SELECTION_REMOVE:
+ ::UiaRaiseAutomationEvent(
+ uia, UIA_SelectionItem_ElementRemovedFromSelectionEventId);
+ return;
+ case nsIAccessibleEvent::EVENT_SELECTION_WITHIN:
+ ::UiaRaiseAutomationEvent(uia, UIA_Selection_InvalidatedEventId);
+ return;
case nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE:
property = UIA_ValueValuePropertyId;
newVal.vt = VT_BSTR;
uia->get_Value(&newVal.bstrVal);
gotNewVal = true;
break;
+ case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
+ property = UIA_RangeValueValuePropertyId;
+ newVal.vt = VT_R8;
+ uia->get_Value(&newVal.dblVal);
+ gotNewVal = true;
+ break;
}
if (property && ::UiaClientsAreListening()) {
// We can't get the old value. Thankfully, clients don't seem to need it.
@@ -117,6 +181,13 @@ void uiaRawElmProvider::RaiseUiaEventForStateChange(Accessible* aAcc,
_variant_t newVal;
switch (aState) {
case states::CHECKED:
+ if (aEnabled && IsRadio(aAcc)) {
+ ::UiaRaiseAutomationEvent(uia,
+ UIA_SelectionItem_ElementSelectedEventId);
+ return;
+ }
+ // For other checkable things, the Toggle pattern is used.
+ [[fallthrough]];
case states::MIXED:
case states::PRESSED:
property = UIA_ToggleToggleStatePropertyId;
@@ -161,8 +232,14 @@ uiaRawElmProvider::QueryInterface(REFIID aIid, void** aInterface) {
*aInterface = static_cast<IExpandCollapseProvider*>(this);
} else if (aIid == IID_IInvokeProvider) {
*aInterface = static_cast<IInvokeProvider*>(this);
+ } else if (aIid == IID_IRangeValueProvider) {
+ *aInterface = static_cast<IRangeValueProvider*>(this);
} else if (aIid == IID_IScrollItemProvider) {
*aInterface = static_cast<IScrollItemProvider*>(this);
+ } else if (aIid == IID_ISelectionItemProvider) {
+ *aInterface = static_cast<ISelectionItemProvider*>(this);
+ } else if (aIid == IID_ISelectionProvider) {
+ *aInterface = static_cast<ISelectionProvider*>(this);
} else if (aIid == IID_IToggleProvider) {
*aInterface = static_cast<IToggleProvider*>(this);
} else if (aIid == IID_IValueProvider) {
@@ -248,9 +325,7 @@ uiaRawElmProvider::get_ProviderOptions(
__RPC__out enum ProviderOptions* aOptions) {
if (!aOptions) return E_INVALIDARG;
- *aOptions = static_cast<enum ProviderOptions>(
- ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading |
- ProviderOptions_HasNativeIAccessible);
+ *aOptions = kProviderOptions;
return S_OK;
}
@@ -270,21 +345,78 @@ uiaRawElmProvider::GetPatternProvider(
expand.forget(aPatternProvider);
}
return S_OK;
+ case UIA_GridPatternId:
+ if (acc->IsTable()) {
+ auto grid = GetPatternFromDerived<ia2AccessibleTable, IGridProvider>();
+ grid.forget(aPatternProvider);
+ }
+ return S_OK;
+ case UIA_GridItemPatternId:
+ if (acc->IsTableCell()) {
+ auto item =
+ GetPatternFromDerived<ia2AccessibleTableCell, IGridItemProvider>();
+ item.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()) {
+ !HasExpandCollapsePattern() && !HasSelectionItemPattern()) {
RefPtr<IInvokeProvider> invoke = this;
invoke.forget(aPatternProvider);
}
return S_OK;
+ case UIA_RangeValuePatternId:
+ if (acc->HasNumericValue()) {
+ RefPtr<IValueProvider> value = this;
+ value.forget(aPatternProvider);
+ }
+ return S_OK;
case UIA_ScrollItemPatternId: {
RefPtr<IScrollItemProvider> scroll = this;
scroll.forget(aPatternProvider);
return S_OK;
}
+ case UIA_SelectionItemPatternId:
+ if (HasSelectionItemPattern()) {
+ RefPtr<ISelectionItemProvider> item = this;
+ item.forget(aPatternProvider);
+ }
+ return S_OK;
+ case UIA_SelectionPatternId:
+ // According to the UIA documentation, radio button groups should support
+ // the Selection pattern. However:
+ // 1. The Core AAM spec doesn't specify the Selection pattern for
+ // the radiogroup role.
+ // 2. HTML radio buttons might not be contained by a dedicated group.
+ // 3. Chromium exposes the Selection pattern on radio groups, but it
+ // doesn't expose any selected items, even when there is a checked radio
+ // child.
+ // 4. Radio menu items are similar to radio buttons and all the above
+ // also applies to menus.
+ // For now, we don't support the Selection pattern for radio groups or
+ // menus, only for list boxes, tab lists, etc.
+ if (acc->IsSelect()) {
+ RefPtr<ISelectionProvider> selection = this;
+ selection.forget(aPatternProvider);
+ }
+ return S_OK;
+ case UIA_TablePatternId:
+ if (acc->IsTable()) {
+ auto table =
+ GetPatternFromDerived<ia2AccessibleTable, ITableProvider>();
+ table.forget(aPatternProvider);
+ }
+ return S_OK;
+ case UIA_TableItemPatternId:
+ if (acc->IsTableCell()) {
+ auto item =
+ GetPatternFromDerived<ia2AccessibleTableCell, ITableItemProvider>();
+ item.forget(aPatternProvider);
+ }
+ return S_OK;
case UIA_TogglePatternId:
if (HasTogglePattern()) {
RefPtr<IToggleProvider> toggle = this;
@@ -349,19 +481,19 @@ uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId,
break;
}
- // ARIA Role / shortcut
case UIA_AriaRolePropertyId: {
- nsAutoString xmlRoles;
-
- RefPtr<AccAttributes> attributes = acc->Attributes();
- attributes->GetAttribute(nsGkAtoms::xmlroles, xmlRoles);
-
- if (!xmlRoles.IsEmpty()) {
+ nsAutoString role;
+ if (acc->HasARIARole()) {
+ RefPtr<AccAttributes> attributes = acc->Attributes();
+ attributes->GetAttribute(nsGkAtoms::xmlroles, role);
+ } else if (nsStaticAtom* computed = acc->ComputedARIARole()) {
+ computed->ToString(role);
+ }
+ if (!role.IsEmpty()) {
aPropertyValue->vt = VT_BSTR;
- aPropertyValue->bstrVal = ::SysAllocString(xmlRoles.get());
+ aPropertyValue->bstrVal = ::SysAllocString(role.get());
return S_OK;
}
-
break;
}
@@ -415,11 +547,57 @@ uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId,
break;
}
+ case UIA_ClassNamePropertyId: {
+ nsAutoString className;
+ acc->DOMNodeClass(className);
+ if (!className.IsEmpty()) {
+ aPropertyValue->vt = VT_BSTR;
+ aPropertyValue->bstrVal = ::SysAllocString(className.get());
+ return S_OK;
+ }
+ break;
+ }
+
+ case UIA_ControllerForPropertyId:
+ aPropertyValue->vt = VT_UNKNOWN | VT_ARRAY;
+ aPropertyValue->parray = AccRelationsToUiaArray(
+ {RelationType::CONTROLLER_FOR, RelationType::ERRORMSG});
+ return S_OK;
+
case UIA_ControlTypePropertyId:
aPropertyValue->vt = VT_I4;
aPropertyValue->lVal = GetControlType();
break;
+ case UIA_DescribedByPropertyId:
+ aPropertyValue->vt = VT_UNKNOWN | VT_ARRAY;
+ aPropertyValue->parray = AccRelationsToUiaArray(
+ {RelationType::DESCRIBED_BY, RelationType::DETAILS});
+ return S_OK;
+
+ case UIA_FlowsFromPropertyId:
+ aPropertyValue->vt = VT_UNKNOWN | VT_ARRAY;
+ aPropertyValue->parray =
+ AccRelationsToUiaArray({RelationType::FLOWS_FROM});
+ return S_OK;
+
+ case UIA_FlowsToPropertyId:
+ aPropertyValue->vt = VT_UNKNOWN | VT_ARRAY;
+ aPropertyValue->parray = AccRelationsToUiaArray({RelationType::FLOWS_TO});
+ return S_OK;
+
+ case UIA_FrameworkIdPropertyId:
+ if (ApplicationAccessible* app = ApplicationAcc()) {
+ nsAutoString name;
+ app->PlatformName(name);
+ if (!name.IsEmpty()) {
+ aPropertyValue->vt = VT_BSTR;
+ aPropertyValue->bstrVal = ::SysAllocString(name.get());
+ return S_OK;
+ }
+ }
+ break;
+
case UIA_FullDescriptionPropertyId: {
nsAutoString desc;
acc->Description(desc);
@@ -459,6 +637,39 @@ uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId,
(acc->State() & states::FOCUSABLE) ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
+ case UIA_LabeledByPropertyId:
+ if (Accessible* target = GetLabeledBy()) {
+ aPropertyValue->vt = VT_UNKNOWN;
+ RefPtr<IRawElementProviderSimple> uia = MsaaAccessible::GetFrom(target);
+ uia.forget(&aPropertyValue->punkVal);
+ return S_OK;
+ }
+ break;
+
+ case UIA_LandmarkTypePropertyId:
+ if (long type = GetLandmarkType()) {
+ aPropertyValue->vt = VT_I4;
+ aPropertyValue->lVal = type;
+ return S_OK;
+ }
+ break;
+
+ case UIA_LevelPropertyId:
+ aPropertyValue->vt = VT_I4;
+ aPropertyValue->lVal = acc->GroupPosition().level;
+ return S_OK;
+
+ case UIA_LocalizedLandmarkTypePropertyId: {
+ nsAutoString landmark;
+ GetLocalizedLandmarkType(landmark);
+ if (!landmark.IsEmpty()) {
+ aPropertyValue->vt = VT_BSTR;
+ aPropertyValue->bstrVal = ::SysAllocString(landmark.get());
+ return S_OK;
+ }
+ break;
+ }
+
case UIA_NamePropertyId: {
nsAutoString name;
acc->Name(name);
@@ -469,6 +680,16 @@ uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId,
}
break;
}
+
+ case UIA_PositionInSetPropertyId:
+ aPropertyValue->vt = VT_I4;
+ aPropertyValue->lVal = acc->GroupPosition().posInSet;
+ return S_OK;
+
+ case UIA_SizeOfSetPropertyId:
+ aPropertyValue->vt = VT_I4;
+ aPropertyValue->lVal = acc->GroupPosition().setSize;
+ return S_OK;
}
return S_OK;
@@ -749,6 +970,223 @@ uiaRawElmProvider::get_IsReadOnly(__RPC__out BOOL* aRetVal) {
return S_OK;
}
+// IRangeValueProvider methods
+
+STDMETHODIMP
+uiaRawElmProvider::SetValue(double aVal) {
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ if (!acc->SetCurValue(aVal)) {
+ return UIA_E_INVALIDOPERATION;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_Value(__RPC__out double* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = acc->CurValue();
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_Maximum(__RPC__out double* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = acc->MaxValue();
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_Minimum(
+ /* [retval][out] */ __RPC__out double* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = acc->MinValue();
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_LargeChange(
+ /* [retval][out] */ __RPC__out double* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ // We want the change that would occur if the user pressed page up or page
+ // down. For HTML input elements, this is 10% of the total range unless step
+ // is larger. See:
+ // https://searchfox.org/mozilla-central/rev/c7df16ffad1f12a19c81c16bce0b65e4a15304d0/dom/html/HTMLInputElement.cpp#3878
+ double step = acc->Step();
+ double min = acc->MinValue();
+ double max = acc->MaxValue();
+ if (std::isnan(step) || std::isnan(min) || std::isnan(max)) {
+ *aRetVal = UnspecifiedNaN<double>();
+ } else {
+ *aRetVal = std::max(step, (max - min) / 10);
+ }
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_SmallChange(
+ /* [retval][out] */ __RPC__out double* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = acc->Step();
+ return S_OK;
+}
+
+// ISelectionProvider methods
+
+STDMETHODIMP
+uiaRawElmProvider::GetSelection(__RPC__deref_out_opt SAFEARRAY** aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ *aRetVal = nullptr;
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ AutoTArray<Accessible*, 10> items;
+ acc->SelectedItems(&items);
+ *aRetVal = AccessibleArrayToUiaArray(items);
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_CanSelectMultiple(__RPC__out BOOL* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = acc->State() & states::MULTISELECTABLE;
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_IsSelectionRequired(__RPC__out BOOL* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ *aRetVal = acc->State() & states::REQUIRED;
+ return S_OK;
+}
+
+// ISelectionItemProvider methods
+
+STDMETHODIMP
+uiaRawElmProvider::Select() {
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ if (IsRadio(acc)) {
+ acc->DoAction(0);
+ } else {
+ acc->TakeSelection();
+ }
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::AddToSelection() {
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ if (IsRadio(acc)) {
+ acc->DoAction(0);
+ } else {
+ acc->SetSelected(true);
+ }
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::RemoveFromSelection() {
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ if (IsRadio(acc)) {
+ return UIA_E_INVALIDOPERATION;
+ }
+ acc->SetSelected(false);
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_IsSelected(__RPC__out BOOL* aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ if (IsRadio(acc)) {
+ *aRetVal = acc->State() & states::CHECKED;
+ } else {
+ *aRetVal = acc->State() & states::SELECTED;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP
+uiaRawElmProvider::get_SelectionContainer(
+ __RPC__deref_out_opt IRawElementProviderSimple** aRetVal) {
+ if (!aRetVal) {
+ return E_INVALIDARG;
+ }
+ *aRetVal = nullptr;
+ Accessible* acc = Acc();
+ if (!acc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+ Accessible* container = nsAccUtils::GetSelectableContainer(acc, acc->State());
+ if (!container) {
+ return E_FAIL;
+ }
+ RefPtr<IRawElementProviderSimple> uia = MsaaAccessible::GetFrom(container);
+ uia.forget(aRetVal);
+ return S_OK;
+}
+
// Private methods
bool uiaRawElmProvider::IsControl() {
@@ -854,3 +1292,133 @@ bool uiaRawElmProvider::HasValuePattern() const {
const nsRoleMapEntry* roleMapEntry = acc->ARIARoleMap();
return roleMapEntry && roleMapEntry->Is(nsGkAtoms::textbox);
}
+
+template <class Derived, class Interface>
+RefPtr<Interface> uiaRawElmProvider::GetPatternFromDerived() {
+ // MsaaAccessible inherits from uiaRawElmProvider. Derived
+ // inherits from MsaaAccessible and Interface. The compiler won't let us
+ // directly static_cast to Interface, hence the intermediate casts.
+ auto* msaa = static_cast<MsaaAccessible*>(this);
+ auto* derived = static_cast<Derived*>(msaa);
+ return derived;
+}
+
+bool uiaRawElmProvider::HasSelectionItemPattern() {
+ Accessible* acc = Acc();
+ MOZ_ASSERT(acc);
+ // In UIA, radio buttons and radio menu items are exposed as selected or
+ // unselected.
+ return acc->State() & states::SELECTABLE || IsRadio(acc);
+}
+
+SAFEARRAY* uiaRawElmProvider::AccRelationsToUiaArray(
+ std::initializer_list<RelationType> aTypes) const {
+ Accessible* acc = Acc();
+ MOZ_ASSERT(acc);
+ AutoTArray<Accessible*, 10> targets;
+ for (RelationType type : aTypes) {
+ Relation rel = acc->RelationByType(type);
+ while (Accessible* target = rel.Next()) {
+ targets.AppendElement(target);
+ }
+ }
+ return AccessibleArrayToUiaArray(targets);
+}
+
+Accessible* uiaRawElmProvider::GetLabeledBy() const {
+ // Per the UIA documentation, some control types should never get a value for
+ // the LabeledBy property.
+ switch (GetControlType()) {
+ case UIA_ButtonControlTypeId:
+ case UIA_CheckBoxControlTypeId:
+ case UIA_DataItemControlTypeId:
+ case UIA_MenuControlTypeId:
+ case UIA_MenuBarControlTypeId:
+ case UIA_RadioButtonControlTypeId:
+ case UIA_ScrollBarControlTypeId:
+ case UIA_SeparatorControlTypeId:
+ case UIA_StatusBarControlTypeId:
+ case UIA_TabItemControlTypeId:
+ case UIA_TextControlTypeId:
+ case UIA_ToolBarControlTypeId:
+ case UIA_ToolTipControlTypeId:
+ case UIA_TreeItemControlTypeId:
+ return nullptr;
+ }
+
+ Accessible* acc = Acc();
+ MOZ_ASSERT(acc);
+ // Even when LabeledBy is supported, it can only return a single "static text"
+ // element.
+ Relation rel = acc->RelationByType(RelationType::LABELLED_BY);
+ LabelTextLeafRule rule;
+ while (Accessible* target = rel.Next()) {
+ // If target were a text leaf, we should return that, but that shouldn't be
+ // possible because only an element (not a text node) can be the target of a
+ // relation.
+ MOZ_ASSERT(!target->IsTextLeaf());
+ Pivot pivot(target);
+ if (Accessible* leaf = pivot.Next(target, rule)) {
+ return leaf;
+ }
+ }
+ return nullptr;
+}
+
+long uiaRawElmProvider::GetLandmarkType() const {
+ Accessible* acc = Acc();
+ MOZ_ASSERT(acc);
+ nsStaticAtom* landmark = acc->LandmarkRole();
+ if (!landmark) {
+ return 0;
+ }
+ if (landmark == nsGkAtoms::form) {
+ return UIA_FormLandmarkTypeId;
+ }
+ if (landmark == nsGkAtoms::main) {
+ return UIA_MainLandmarkTypeId;
+ }
+ if (landmark == nsGkAtoms::navigation) {
+ return UIA_NavigationLandmarkTypeId;
+ }
+ if (landmark == nsGkAtoms::search) {
+ return UIA_SearchLandmarkTypeId;
+ }
+ return UIA_CustomLandmarkTypeId;
+}
+
+void uiaRawElmProvider::GetLocalizedLandmarkType(nsAString& aLocalized) const {
+ Accessible* acc = Acc();
+ MOZ_ASSERT(acc);
+ nsStaticAtom* landmark = acc->LandmarkRole();
+ // The system provides strings for landmarks explicitly supported by the UIA
+ // LandmarkType property; i.e. form, main, navigation and search. We must
+ // provide strings for landmarks considered custom by UIA. For now, we only
+ // support landmarks in the core ARIA specification, not other ARIA modules
+ // such as DPub.
+ if (landmark == nsGkAtoms::banner || landmark == nsGkAtoms::complementary ||
+ landmark == nsGkAtoms::contentinfo || landmark == nsGkAtoms::region) {
+ nsAutoString unlocalized;
+ landmark->ToString(unlocalized);
+ Accessible::TranslateString(unlocalized, aLocalized);
+ }
+}
+
+SAFEARRAY* a11y::AccessibleArrayToUiaArray(const nsTArray<Accessible*>& aAccs) {
+ if (aAccs.IsEmpty()) {
+ // The UIA documentation is unclear about this, but the UIA client
+ // framework seems to treat a null value the same as an empty array. This
+ // is also what Chromium does.
+ return nullptr;
+ }
+ SAFEARRAY* uias = SafeArrayCreateVector(VT_UNKNOWN, 0, aAccs.Length());
+ LONG indices[1] = {0};
+ for (Accessible* acc : aAccs) {
+ // SafeArrayPutElement calls AddRef on the element, so we use a raw pointer
+ // here.
+ IRawElementProviderSimple* uia = MsaaAccessible::GetFrom(acc);
+ SafeArrayPutElement(uias, indices, uia);
+ ++indices[0];
+ }
+ return uias;
+}
diff --git a/accessible/windows/uia/uiaRawElmProvider.h b/accessible/windows/uia/uiaRawElmProvider.h
index 0e05d1a030..ea713d8bc1 100644
--- a/accessible/windows/uia/uiaRawElmProvider.h
+++ b/accessible/windows/uia/uiaRawElmProvider.h
@@ -11,10 +11,20 @@
#include <stdint.h>
#include <uiautomation.h>
+#include <initializer_list>
+
+#include "nsString.h"
+
+template <class T>
+class nsTArray;
+template <class T>
+class RefPtr;
+
namespace mozilla {
namespace a11y {
class Accessible;
+enum class RelationType;
/**
* IRawElementProviderSimple implementation (maintains IAccessibleEx approach).
@@ -26,8 +36,16 @@ class uiaRawElmProvider : public IAccessibleEx,
public IToggleProvider,
public IExpandCollapseProvider,
public IScrollItemProvider,
- public IValueProvider {
+ public IValueProvider,
+ public IRangeValueProvider,
+ public ISelectionProvider,
+ public ISelectionItemProvider {
public:
+ static constexpr enum ProviderOptions kProviderOptions =
+ static_cast<enum ProviderOptions>(ProviderOptions_ServerSideProvider |
+ ProviderOptions_UseComThreading |
+ ProviderOptions_HasNativeIAccessible);
+
static void RaiseUiaEventForGeckoEvent(Accessible* aAcc,
uint32_t aGeckoEvent);
static void RaiseUiaEventForStateChange(Accessible* aAcc, uint64_t aState,
@@ -118,6 +136,51 @@ class uiaRawElmProvider : public IAccessibleEx,
virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsReadOnly(
/* [retval][out] */ __RPC__out BOOL* pRetVal);
+ // IRangeValueProvider
+ virtual HRESULT STDMETHODCALLTYPE SetValue(
+ /* [in] */ double aVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Value(
+ /* [retval][out] */ __RPC__out double* aRetVal);
+
+ // get_IsReadOnly is shared with IValueProvider.
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Maximum(
+ /* [retval][out] */ __RPC__out double* aRetVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Minimum(
+ /* [retval][out] */ __RPC__out double* aRetVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_LargeChange(
+ /* [retval][out] */ __RPC__out double* aRetVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_SmallChange(
+ /* [retval][out] */ __RPC__out double* aRetVal);
+
+ // ISelectionProvider
+ virtual HRESULT STDMETHODCALLTYPE GetSelection(
+ /* [retval][out] */ __RPC__deref_out_opt SAFEARRAY** aRetVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_CanSelectMultiple(
+ /* [retval][out] */ __RPC__out BOOL* aRetVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsSelectionRequired(
+ /* [retval][out] */ __RPC__out BOOL* aRetVal);
+
+ // ISelectionItemProvider methods
+ virtual HRESULT STDMETHODCALLTYPE Select(void);
+
+ virtual HRESULT STDMETHODCALLTYPE AddToSelection(void);
+
+ virtual HRESULT STDMETHODCALLTYPE RemoveFromSelection(void);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_IsSelected(
+ /* [retval][out] */ __RPC__out BOOL* aRetVal);
+
+ virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_SelectionContainer(
+ /* [retval][out] */ __RPC__deref_out_opt IRawElementProviderSimple**
+ aRetVal);
+
private:
Accessible* Acc() const;
bool IsControl();
@@ -125,8 +188,18 @@ class uiaRawElmProvider : public IAccessibleEx,
bool HasTogglePattern();
bool HasExpandCollapsePattern();
bool HasValuePattern() const;
+ template <class Derived, class Interface>
+ RefPtr<Interface> GetPatternFromDerived();
+ bool HasSelectionItemPattern();
+ SAFEARRAY* AccRelationsToUiaArray(
+ std::initializer_list<RelationType> aTypes) const;
+ Accessible* GetLabeledBy() const;
+ long GetLandmarkType() const;
+ void GetLocalizedLandmarkType(nsAString& aLocalized) const;
};
+SAFEARRAY* AccessibleArrayToUiaArray(const nsTArray<Accessible*>& aAccs);
+
} // namespace a11y
} // namespace mozilla