summaryrefslogtreecommitdiffstats
path: root/accessible/windows/uia
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/windows/uia')
-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
5 files changed, 731 insertions, 26 deletions
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