diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:13:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:13:27 +0000 |
commit | 40a355a42d4a9444dc753c04c6608dade2f06a23 (patch) | |
tree | 871fc667d2de662f171103ce5ec067014ef85e61 /accessible/windows | |
parent | Adding upstream version 124.0.1. (diff) | |
download | firefox-upstream/125.0.1.tar.xz firefox-upstream/125.0.1.zip |
Adding upstream version 125.0.1.upstream/125.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'accessible/windows')
22 files changed, 254 insertions, 101 deletions
diff --git a/accessible/windows/ia2/ia2Accessible.cpp b/accessible/windows/ia2/ia2Accessible.cpp index 2092730932..7318dd5e6f 100644 --- a/accessible/windows/ia2/ia2Accessible.cpp +++ b/accessible/windows/ia2/ia2Accessible.cpp @@ -156,7 +156,7 @@ ia2Accessible::role(long* aRole) { if (!acc) return CO_E_OBJNOTCONNECTED; #define ROLE(_geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \ - msaaRole, ia2Role, androidClass, nameRule) \ + msaaRole, ia2Role, androidClass, iosIsElement, nameRule) \ case roles::_geckoRole: \ *aRole = ia2Role; \ break; diff --git a/accessible/windows/ia2/ia2AccessibleAction.cpp b/accessible/windows/ia2/ia2AccessibleAction.cpp index d89bd79ce1..1e1dbaea7b 100644 --- a/accessible/windows/ia2/ia2AccessibleAction.cpp +++ b/accessible/windows/ia2/ia2AccessibleAction.cpp @@ -11,6 +11,7 @@ #include "AccessibleWrap.h" #include "IUnknownImpl.h" +#include "MsaaAccessible.h" using namespace mozilla::a11y; diff --git a/accessible/windows/ia2/ia2AccessibleComponent.cpp b/accessible/windows/ia2/ia2AccessibleComponent.cpp index 9c22a66cad..a0074bcaa1 100644 --- a/accessible/windows/ia2/ia2AccessibleComponent.cpp +++ b/accessible/windows/ia2/ia2AccessibleComponent.cpp @@ -12,6 +12,7 @@ #include "AccessibleWrap.h" #include "States.h" #include "IUnknownImpl.h" +#include "MsaaAccessible.h" #include "nsIFrame.h" diff --git a/accessible/windows/ia2/ia2AccessibleHyperlink.cpp b/accessible/windows/ia2/ia2AccessibleHyperlink.cpp index 9d71cfb411..40dff39131 100644 --- a/accessible/windows/ia2/ia2AccessibleHyperlink.cpp +++ b/accessible/windows/ia2/ia2AccessibleHyperlink.cpp @@ -5,11 +5,14 @@ * 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 "ia2AccessibleHyperlink.h" + #include "AccessibleHyperlink.h" #include "AccessibleHyperlink_i.c" #include "AccessibleWrap.h" #include "IUnknownImpl.h" +#include "MsaaAccessible.h" #include "nsIURI.h" using namespace mozilla::a11y; diff --git a/accessible/windows/ia2/ia2AccessibleValue.cpp b/accessible/windows/ia2/ia2AccessibleValue.cpp index b0b9a729e3..93640354c2 100644 --- a/accessible/windows/ia2/ia2AccessibleValue.cpp +++ b/accessible/windows/ia2/ia2AccessibleValue.cpp @@ -12,6 +12,7 @@ #include "AccessibleWrap.h" #include "LocalAccessible-inl.h" #include "IUnknownImpl.h" +#include "MsaaAccessible.h" #include "mozilla/FloatingPoint.h" diff --git a/accessible/windows/ia2/moz.build b/accessible/windows/ia2/moz.build index 53f930fd5a..4b566f5a5c 100644 --- a/accessible/windows/ia2/moz.build +++ b/accessible/windows/ia2/moz.build @@ -44,6 +44,7 @@ LOCAL_INCLUDES += [ "/accessible/html", "/accessible/windows", "/accessible/windows/msaa", + "/accessible/windows/uia", "/accessible/xpcom", "/accessible/xul", ] diff --git a/accessible/windows/msaa/AccessibleWrap.cpp b/accessible/windows/msaa/AccessibleWrap.cpp index abab007775..d681e8e658 100644 --- a/accessible/windows/msaa/AccessibleWrap.cpp +++ b/accessible/windows/msaa/AccessibleWrap.cpp @@ -31,6 +31,8 @@ using namespace mozilla::a11y; AccessibleWrap::AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) : LocalAccessible(aContent, aDoc) {} +AccessibleWrap::~AccessibleWrap() = default; + NS_IMPL_ISUPPORTS_INHERITED0(AccessibleWrap, LocalAccessible) void AccessibleWrap::Shutdown() { @@ -75,6 +77,24 @@ bool AccessibleWrap::IsRootForHWND() { return thisHwnd != parentHwnd; } +static void UpdateSystemCaretForHwnd(HWND aCaretWnd, + const LayoutDeviceIntRect& aCaretRect) { + if (!aCaretWnd || aCaretRect.IsEmpty()) { + return; + } + + // Create invisible bitmap for caret, otherwise its appearance interferes + // with Gecko caret + nsAutoBitmap caretBitMap(CreateBitmap(1, aCaretRect.Height(), 1, 1, nullptr)); + if (::CreateCaret(aCaretWnd, caretBitMap, 1, + aCaretRect.Height())) { // Also destroys the last caret + ::ShowCaret(aCaretWnd); + POINT clientPoint{aCaretRect.X(), aCaretRect.Y()}; + ::ScreenToClient(aCaretWnd, &clientPoint); + ::SetCaretPos(clientPoint.x, clientPoint.y); + } +} + /* static */ void AccessibleWrap::UpdateSystemCaretFor( Accessible* aAccessible, const LayoutDeviceIntRect& aCaretRect) { @@ -106,7 +126,7 @@ void AccessibleWrap::UpdateSystemCaretFor(LocalAccessible* aAccessible) { HWND caretWnd = reinterpret_cast<HWND>(widget->GetNativeData(NS_NATIVE_WINDOW)); - UpdateSystemCaretFor(caretWnd, caretRect); + UpdateSystemCaretForHwnd(caretWnd, caretRect); } /* static */ @@ -117,24 +137,5 @@ void AccessibleWrap::UpdateSystemCaretFor( // The HWND should be the real widget HWND, not an emulated HWND. // We get the HWND from the proxy's outer doc to bypass window emulation. LocalAccessible* outerDoc = aProxy->OuterDocOfRemoteBrowser(); - UpdateSystemCaretFor(MsaaAccessible::GetHWNDFor(outerDoc), aCaretRect); -} - -/* static */ -void AccessibleWrap::UpdateSystemCaretFor( - HWND aCaretWnd, const LayoutDeviceIntRect& aCaretRect) { - if (!aCaretWnd || aCaretRect.IsEmpty()) { - return; - } - - // Create invisible bitmap for caret, otherwise its appearance interferes - // with Gecko caret - nsAutoBitmap caretBitMap(CreateBitmap(1, aCaretRect.Height(), 1, 1, nullptr)); - if (::CreateCaret(aCaretWnd, caretBitMap, 1, - aCaretRect.Height())) { // Also destroys the last caret - ::ShowCaret(aCaretWnd); - POINT clientPoint{aCaretRect.X(), aCaretRect.Y()}; - ::ScreenToClient(aCaretWnd, &clientPoint); - ::SetCaretPos(clientPoint.x, clientPoint.y); - } + UpdateSystemCaretForHwnd(MsaaAccessible::GetHWNDFor(outerDoc), aCaretRect); } diff --git a/accessible/windows/msaa/AccessibleWrap.h b/accessible/windows/msaa/AccessibleWrap.h index aeeea87e77..941ac06e40 100644 --- a/accessible/windows/msaa/AccessibleWrap.h +++ b/accessible/windows/msaa/AccessibleWrap.h @@ -9,7 +9,6 @@ #include "nsCOMPtr.h" #include "LocalAccessible.h" -#include "MsaaAccessible.h" #include "mozilla/a11y/RemoteAccessible.h" #include "mozilla/Attributes.h" #include "mozilla/mscom/Utils.h" @@ -20,6 +19,7 @@ namespace mozilla { namespace a11y { class DocRemoteAccessibleWrap; +class MsaaAccessible; /** * Windows specific functionality for an accessibility tree node that originated @@ -50,10 +50,6 @@ class AccessibleWrap : public LocalAccessible { static void UpdateSystemCaretFor(RemoteAccessible* aProxy, const LayoutDeviceIntRect& aCaretRect); - private: - static void UpdateSystemCaretFor(HWND aCaretWnd, - const LayoutDeviceIntRect& aCaretRect); - public: /** * Determine whether this is the root accessible for its HWND. @@ -64,7 +60,7 @@ class AccessibleWrap : public LocalAccessible { virtual void GetNativeInterface(void** aOutAccessible) override; protected: - virtual ~AccessibleWrap() = default; + virtual ~AccessibleWrap(); RefPtr<MsaaAccessible> mMsaa; }; diff --git a/accessible/windows/msaa/ApplicationAccessibleWrap.cpp b/accessible/windows/msaa/ApplicationAccessibleWrap.cpp index 6a10a8bddc..ea0689a694 100644 --- a/accessible/windows/msaa/ApplicationAccessibleWrap.cpp +++ b/accessible/windows/msaa/ApplicationAccessibleWrap.cpp @@ -11,6 +11,7 @@ #include "AccAttributes.h" #include "nsServiceManagerUtils.h" #include "mozilla/Components.h" +#include "MsaaAccessible.h" using namespace mozilla; using namespace mozilla::a11y; diff --git a/accessible/windows/msaa/Compatibility.cpp b/accessible/windows/msaa/Compatibility.cpp index 440f327520..42bc2386bb 100644 --- a/accessible/windows/msaa/Compatibility.cpp +++ b/accessible/windows/msaa/Compatibility.cpp @@ -103,7 +103,7 @@ void Compatibility::Init() { // Note we collect some AT statistics/telemetry here for convenience. InitConsumers(); - CrashReporter::AnnotateCrashReport( + CrashReporter::RecordAnnotationNSCString( CrashReporter::Annotation::AccessibilityInProcClient, nsPrintfCString("0x%X", sConsumers)); @@ -142,9 +142,20 @@ void Compatibility::GetHumanReadableConsumersStr(nsAString& aResult) { } } -// Time when SuppressA11yForClipboardCopy() was called, as returned by -// ::GetTickCount(). -static DWORD sA11yClipboardCopySuppressionStartTime = 0; +struct SuppressionTimer { + constexpr SuppressionTimer() = default; + void Start() { mStart = ::GetTickCount(); } + bool IsActive(DWORD aTickCount) const { + return mStart && aTickCount - mStart < kSuppressTimeout; + } + // Last time Start() was called, as returned by ::GetTickCount(). + DWORD mStart = 0; + + static constexpr DWORD kSuppressTimeout = 1500; // ms +}; + +static SuppressionTimer sClipboardSuppressionTimer; +static SuppressionTimer sSnapLayoutsSuppressionTimer; /* static */ void Compatibility::SuppressA11yForClipboardCopy() { @@ -166,16 +177,40 @@ void Compatibility::SuppressA11yForClipboardCopy() { }(); if (doSuppress) { - sA11yClipboardCopySuppressionStartTime = ::GetTickCount(); + sClipboardSuppressionTimer.Start(); } } /* static */ -bool Compatibility::IsA11ySuppressedForClipboardCopy() { - constexpr DWORD kSuppressTimeout = 1500; // ms - if (!sA11yClipboardCopySuppressionStartTime) { - return false; +void Compatibility::SuppressA11yForSnapLayouts() { + // Bug 1883132: Snap Layouts might enable a11y to find the maximize button + // position. + bool doSuppress = [&] { + switch (StaticPrefs::accessibility_windows_suppress_for_snap_layout()) { + case 0: + return false; + case 1: + return true; + default: + // Our workaround for Snap Layouts is needed from Windows 11 22H2 + return IsWin1122H2OrLater(); + } + }(); + + if (doSuppress) { + sSnapLayoutsSuppressionTimer.Start(); + } +} + +/* static */ +SuppressionReasons Compatibility::A11ySuppressionReasons() { + const auto now = ::GetTickCount(); + auto reasons = SuppressionReasons::None; + if (sClipboardSuppressionTimer.IsActive(now)) { + reasons |= SuppressionReasons::Clipboard; + } + if (sSnapLayoutsSuppressionTimer.IsActive(now)) { + reasons |= SuppressionReasons::SnapLayouts; } - return ::GetTickCount() - sA11yClipboardCopySuppressionStartTime < - kSuppressTimeout; + return reasons; } diff --git a/accessible/windows/msaa/Compatibility.h b/accessible/windows/msaa/Compatibility.h index d1e1b0e9ac..05d2e82400 100644 --- a/accessible/windows/msaa/Compatibility.h +++ b/accessible/windows/msaa/Compatibility.h @@ -13,8 +13,14 @@ #include <stdint.h> -namespace mozilla { -namespace a11y { +namespace mozilla::a11y { + +enum class SuppressionReasons : uint8_t { + None = 0, + Clipboard = 1 << 0, + SnapLayouts = 1 << 1, +}; +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SuppressionReasons); /** * Used to get compatibility modes. Note, modes are computed at accessibility @@ -78,7 +84,11 @@ class Compatibility { unsigned long long aVersion); static void SuppressA11yForClipboardCopy(); - static bool IsA11ySuppressedForClipboardCopy(); + static void SuppressA11yForSnapLayouts(); + static bool IsA11ySuppressed() { + return A11ySuppressionReasons() != SuppressionReasons::None; + } + static SuppressionReasons A11ySuppressionReasons(); private: Compatibility(); @@ -112,8 +122,7 @@ class Compatibility { static uint32_t sConsumers; }; -} // namespace a11y -} // namespace mozilla +} // namespace mozilla::a11y // Convert the 4 (decimal) components of a DLL version number into a // single unsigned long long, as needed by diff --git a/accessible/windows/msaa/LazyInstantiator.cpp b/accessible/windows/msaa/LazyInstantiator.cpp index 5f8ae9a8a4..61814d059a 100644 --- a/accessible/windows/msaa/LazyInstantiator.cpp +++ b/accessible/windows/msaa/LazyInstantiator.cpp @@ -249,11 +249,7 @@ bool LazyInstantiator::ShouldInstantiate(const DWORD aClientPid) { * various different types of clients. */ bool LazyInstantiator::ShouldInstantiate() { - if (Compatibility::IsA11ySuppressedForClipboardCopy()) { - // Bug 1774285: Windows Suggested Actions (introduced in Windows 11 22H2) - // walks the entire a11y tree using UIA whenever anything is copied to the - // clipboard. This causes an unacceptable hang, particularly when the cache - // is disabled. Don't allow a11y to be instantiated by this. + if (Compatibility::IsA11ySuppressed()) { return false; } if (DWORD pid = GetRemoteMsaaClientPid()) { diff --git a/accessible/windows/msaa/MsaaAccessible.cpp b/accessible/windows/msaa/MsaaAccessible.cpp index 702f8341dc..3a0e8fc726 100644 --- a/accessible/windows/msaa/MsaaAccessible.cpp +++ b/accessible/windows/msaa/MsaaAccessible.cpp @@ -522,6 +522,10 @@ MsaaAccessible::QueryInterface(REFIID iid, void** ppv) { if (SUCCEEDED(hr)) { return hr; } + hr = uiaRawElmProvider::QueryInterface(iid, ppv); + if (SUCCEEDED(hr)) { + return hr; + } } if (*ppv) { (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); @@ -604,16 +608,20 @@ MsaaAccessible::get_accChildCount(long __RPC_FAR* pcountChildren) { if (!mAcc) return CO_E_OBJNOTCONNECTED; - if (Compatibility::IsA11ySuppressedForClipboardCopy() && mAcc->IsRoot()) { + if ((Compatibility::A11ySuppressionReasons() & + SuppressionReasons::Clipboard) && + mAcc->IsRoot()) { // Bug 1798098: Windows Suggested Actions (introduced in Windows 11 22H2) - // might walk the entire a11y tree using UIA whenever anything is copied to - // the clipboard. This causes an unacceptable hang, particularly when the - // cache is disabled. We prevent this tree walk by returning a 0 child count - // for the root window, from which Windows might walk. + // might walk the entire a11y tree using UIA whenever anything is copied + // to the clipboard. This causes an unacceptable hang, particularly when + // the cache is disabled. We prevent this tree walk by returning a 0 child + // count for the root window, from which Windows might walk. return S_OK; } - if (nsAccUtils::MustPrune(mAcc)) return S_OK; + if (nsAccUtils::MustPrune(mAcc)) { + return S_OK; + } *pcountChildren = mAcc->ChildCount(); return S_OK; @@ -761,7 +769,7 @@ MsaaAccessible::get_accRole( uint32_t msaaRole = 0; #define ROLE(_geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \ - _msaaRole, ia2Role, androidClass, nameRule) \ + _msaaRole, ia2Role, androidClass, iosIsElement, nameRule) \ case roles::_geckoRole: \ msaaRole = _msaaRole; \ break; diff --git a/accessible/windows/msaa/MsaaAccessible.h b/accessible/windows/msaa/MsaaAccessible.h index 034db860ed..6d6582f010 100644 --- a/accessible/windows/msaa/MsaaAccessible.h +++ b/accessible/windows/msaa/MsaaAccessible.h @@ -12,8 +12,9 @@ #include "ia2AccessibleHyperlink.h" #include "ia2AccessibleValue.h" #include "IUnknownImpl.h" -#include "mozilla/a11y/MsaaIdGenerator.h" +#include "MsaaIdGenerator.h" #include "nsXULAppAPI.h" +#include "uiaRawElmProvider.h" namespace mozilla { namespace a11y { @@ -25,7 +26,8 @@ class sdnAccessible; class MsaaAccessible : public ia2Accessible, public ia2AccessibleComponent, public ia2AccessibleHyperlink, - public ia2AccessibleValue { + public ia2AccessibleValue, + public uiaRawElmProvider { public: static MsaaAccessible* Create(Accessible* aAcc); diff --git a/accessible/windows/msaa/MsaaIdGenerator.cpp b/accessible/windows/msaa/MsaaIdGenerator.cpp index 9f220365e3..8f0040cf02 100644 --- a/accessible/windows/msaa/MsaaIdGenerator.cpp +++ b/accessible/windows/msaa/MsaaIdGenerator.cpp @@ -6,11 +6,11 @@ #include "MsaaIdGenerator.h" -#include "mozilla/a11y/MsaaAccessible.h" #include "mozilla/Assertions.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/DebugOnly.h" #include "mozilla/Unused.h" +#include "MsaaAccessible.h" #include "nsAccessibilityService.h" #include "sdnAccessible.h" diff --git a/accessible/windows/msaa/Platform.cpp b/accessible/windows/msaa/Platform.cpp index 40dddac215..018042c5d3 100644 --- a/accessible/windows/msaa/Platform.cpp +++ b/accessible/windows/msaa/Platform.cpp @@ -9,6 +9,7 @@ #include "AccEvent.h" #include "Compatibility.h" #include "HyperTextAccessible.h" +#include "MsaaAccessible.h" #include "nsWinUtils.h" #include "mozilla/a11y/DocAccessibleParent.h" #include "mozilla/a11y/RemoteAccessible.h" @@ -196,9 +197,8 @@ static void AccumulateInstantiatorTelemetry(const nsAString& aValue) { #if defined(MOZ_TELEMETRY_REPORTING) Telemetry::ScalarSet(Telemetry::ScalarID::A11Y_INSTANTIATORS, aValue); #endif // defined(MOZ_TELEMETRY_REPORTING) - CrashReporter::AnnotateCrashReport( - CrashReporter::Annotation::AccessibilityClient, - NS_ConvertUTF16toUTF8(aValue)); + CrashReporter::RecordAnnotationNSString( + CrashReporter::Annotation::AccessibilityClient, aValue); } } diff --git a/accessible/windows/msaa/ServiceProvider.cpp b/accessible/windows/msaa/ServiceProvider.cpp index b2b005f3b4..ba04d0ecde 100644 --- a/accessible/windows/msaa/ServiceProvider.cpp +++ b/accessible/windows/msaa/ServiceProvider.cpp @@ -16,7 +16,7 @@ #include "uiaRawElmProvider.h" #include "mozilla/a11y/DocAccessibleChild.h" -#include "mozilla/Preferences.h" +#include "mozilla/StaticPrefs_accessibility.h" #include "ISimpleDOM.h" @@ -40,17 +40,6 @@ ServiceProvider::QueryService(REFGUID aGuidService, REFIID aIID, if (!acc) { return CO_E_OBJNOTCONNECTED; } - AccessibleWrap* localAcc = mMsaa->LocalAcc(); - - // UIA IAccessibleEx - if (aGuidService == IID_IAccessibleEx && - Preferences::GetBool("accessibility.uia.enable") && localAcc) { - uiaRawElmProvider* accEx = new uiaRawElmProvider(localAcc); - HRESULT hr = accEx->QueryInterface(aIID, aInstancePtr); - if (FAILED(hr)) delete accEx; - - return hr; - } // Provide a special service ID for getting the accessible for the browser tab // document that contains this accessible object. If this accessible object @@ -96,8 +85,12 @@ ServiceProvider::QueryService(REFGUID aGuidService, REFIID aIID, {0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8}}; if (aGuidService == IID_ISimpleDOMNode || aGuidService == IID_SimpleDOMDeprecated || - aGuidService == IID_IAccessible || aGuidService == IID_IAccessible2) + aGuidService == IID_IAccessible || aGuidService == IID_IAccessible2 || + // UIA IAccessibleEx + (aGuidService == IID_IAccessibleEx && + StaticPrefs::accessibility_uia_enable())) { return mMsaa->QueryInterface(aIID, aInstancePtr); + } return E_INVALIDARG; } diff --git a/accessible/windows/msaa/moz.build b/accessible/windows/msaa/moz.build index 1b56c2eacf..ae5a036ec2 100644 --- a/accessible/windows/msaa/moz.build +++ b/accessible/windows/msaa/moz.build @@ -12,8 +12,6 @@ EXPORTS.mozilla.a11y += [ "AccessibleWrap.h", "Compatibility.h", "LazyInstantiator.h", - "MsaaAccessible.h", - "MsaaIdGenerator.h", "nsWinUtils.h", ] diff --git a/accessible/windows/msaa/nsWinUtils.cpp b/accessible/windows/msaa/nsWinUtils.cpp index 6eb7d290dd..42d3d374f7 100644 --- a/accessible/windows/msaa/nsWinUtils.cpp +++ b/accessible/windows/msaa/nsWinUtils.cpp @@ -9,6 +9,7 @@ #include "Compatibility.h" #include "DocAccessible.h" +#include "MsaaAccessible.h" #include "nsAccessibilityService.h" #include "nsCoreUtils.h" diff --git a/accessible/windows/sdn/moz.build b/accessible/windows/sdn/moz.build index 8d76b7482e..4f7b77efad 100644 --- a/accessible/windows/sdn/moz.build +++ b/accessible/windows/sdn/moz.build @@ -15,6 +15,7 @@ LOCAL_INCLUDES += [ "/accessible/generic", "/accessible/html", "/accessible/windows/msaa", + "/accessible/windows/uia", "/accessible/xpcom", "/accessible/xul", ] diff --git a/accessible/windows/uia/uiaRawElmProvider.cpp b/accessible/windows/uia/uiaRawElmProvider.cpp index c78dbca7fe..881ed22277 100644 --- a/accessible/windows/uia/uiaRawElmProvider.cpp +++ b/accessible/windows/uia/uiaRawElmProvider.cpp @@ -10,6 +10,9 @@ #include "AccessibleWrap.h" #include "ARIAMap.h" #include "LocalAccessible-inl.h" +#include "mozilla/a11y/RemoteAccessible.h" +#include "MsaaAccessible.h" +#include "nsTextEquivUtils.h" using namespace mozilla; using namespace mozilla::a11y; @@ -18,6 +21,23 @@ using namespace mozilla::a11y; // uiaRawElmProvider //////////////////////////////////////////////////////////////////////////////// +Accessible* uiaRawElmProvider::Acc() { + return static_cast<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(); +} + +ULONG STDMETHODCALLTYPE uiaRawElmProvider::Release() { + return static_cast<MsaaAccessible*>(this)->Release(); +} + IMPL_IUNKNOWN2(uiaRawElmProvider, IAccessibleEx, IRawElementProviderSimple) //////////////////////////////////////////////////////////////////////////////// @@ -30,7 +50,7 @@ uiaRawElmProvider::GetObjectForChild( *aAccEx = nullptr; - return mAcc->IsDefunct() ? CO_E_OBJNOTCONNECTED : S_OK; + return Acc() ? S_OK : CO_E_OBJNOTCONNECTED; } STDMETHODIMP @@ -41,11 +61,12 @@ uiaRawElmProvider::GetIAccessiblePair(__RPC__deref_out_opt IAccessible** aAcc, *aAcc = nullptr; *aIdChild = 0; - if (mAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + if (!Acc()) { + return CO_E_OBJNOTCONNECTED; + } *aIdChild = CHILDID_SELF; - RefPtr<IAccessible> copy; - mAcc->GetNativeInterface(getter_AddRefs(copy)); + RefPtr<IAccessible> copy = static_cast<MsaaAccessible*>(this); copy.forget(aAcc); return S_OK; @@ -54,9 +75,12 @@ uiaRawElmProvider::GetIAccessiblePair(__RPC__deref_out_opt IAccessible** aAcc, STDMETHODIMP uiaRawElmProvider::GetRuntimeId(__RPC__deref_out_opt SAFEARRAY** aRuntimeIds) { if (!aRuntimeIds) return E_INVALIDARG; + Accessible* acc = Acc(); + if (!acc) { + return CO_E_OBJNOTCONNECTED; + } - int ids[] = {UiaAppendRuntimeId, - static_cast<int>(reinterpret_cast<intptr_t>(mAcc->UniqueID()))}; + int ids[] = {UiaAppendRuntimeId, MsaaAccessible::GetChildIDFor(acc)}; *aRuntimeIds = SafeArrayCreateVector(VT_I4, 0, 2); if (!*aRuntimeIds) return E_OUTOFMEMORY; @@ -108,16 +132,24 @@ uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId, __RPC__out VARIANT* aPropertyValue) { if (!aPropertyValue) return E_INVALIDARG; - if (mAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED; + Accessible* acc = Acc(); + if (!acc) { + return CO_E_OBJNOTCONNECTED; + } + LocalAccessible* localAcc = acc->AsLocal(); aPropertyValue->vt = VT_EMPTY; switch (aPropertyId) { // Accelerator Key / shortcut. case UIA_AcceleratorKeyPropertyId: { + if (!localAcc) { + // KeyboardShortcut is only currently relevant for LocalAccessible. + break; + } nsAutoString keyString; - mAcc->KeyboardShortcut().ToString(keyString); + localAcc->KeyboardShortcut().ToString(keyString); if (!keyString.IsEmpty()) { aPropertyValue->vt = VT_BSTR; @@ -132,7 +164,7 @@ uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId, case UIA_AccessKeyPropertyId: { nsAutoString keyString; - mAcc->AccessKey().ToString(keyString); + acc->AccessKey().ToString(keyString); if (!keyString.IsEmpty()) { aPropertyValue->vt = VT_BSTR; @@ -147,7 +179,7 @@ uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId, case UIA_AriaRolePropertyId: { nsAutoString xmlRoles; - RefPtr<AccAttributes> attributes = mAcc->Attributes(); + RefPtr<AccAttributes> attributes = acc->Attributes(); attributes->GetAttribute(nsGkAtoms::xmlroles, xmlRoles); if (!xmlRoles.IsEmpty()) { @@ -161,9 +193,16 @@ uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId, // ARIA Properties case UIA_AriaPropertiesPropertyId: { + if (!localAcc) { + // XXX Implement a unified version of this. We don't cache explicit + // values for many ARIA attributes in RemoteAccessible; e.g. we use the + // checked state rather than caching aria-checked:true. Thus, a unified + // implementation will need to work with State(), etc. + break; + } nsAutoString ariaProperties; - aria::AttrIterator attribIter(mAcc->GetContent()); + aria::AttrIterator attribIter(localAcc->GetContent()); while (attribIter.Next()) { nsAutoString attribName, attribValue; nsAutoString value; @@ -190,6 +229,12 @@ uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId, break; } + + case UIA_IsControlElementPropertyId: + case UIA_IsContentElementPropertyId: + aPropertyValue->vt = VT_BOOL; + aPropertyValue->boolVal = IsControl() ? VARIANT_TRUE : VARIANT_FALSE; + return S_OK; } return S_OK; @@ -204,3 +249,68 @@ uiaRawElmProvider::get_HostRawElementProvider( *aRawElmProvider = nullptr; return S_OK; } + +// Private methods + +bool uiaRawElmProvider::IsControl() { + // UIA provides multiple views of the tree: raw, control and content. The + // control and content views should only contain elements which a user cares + // about when navigating. + Accessible* acc = Acc(); + MOZ_ASSERT(acc); + if (acc->IsTextLeaf()) { + // If an ancestor control allows the name to be generated from content, do + // not expose this text leaf as a control. Otherwise, the user will see the + // text twice: once as the label of the control and once for the text leaf. + for (Accessible* ancestor = acc->Parent(); ancestor && !ancestor->IsDoc(); + ancestor = ancestor->Parent()) { + if (nsTextEquivUtils::HasNameRule(ancestor, eNameFromSubtreeRule)) { + return false; + } + } + return true; + } + + if (acc->HasNumericValue() || acc->ActionCount() > 0) { + return true; + } + uint64_t state = acc->State(); + if (state & states::FOCUSABLE) { + return true; + } + if (state & states::EDITABLE) { + Accessible* parent = acc->Parent(); + if (parent && !(parent->State() & states::EDITABLE)) { + // This is the root of a rich editable control. + return true; + } + } + + // Don't treat generic or text containers as controls unless they have a name + // or description. + switch (acc->Role()) { + case roles::EMPHASIS: + case roles::MARK: + case roles::PARAGRAPH: + case roles::SECTION: + case roles::STRONG: + case roles::SUBSCRIPT: + case roles::SUPERSCRIPT: + case roles::TEXT: + case roles::TEXT_CONTAINER: { + if (!acc->NameIsEmpty()) { + return true; + } + nsAutoString text; + acc->Description(text); + if (!text.IsEmpty()) { + return true; + } + return false; + } + default: + break; + } + + return true; +} diff --git a/accessible/windows/uia/uiaRawElmProvider.h b/accessible/windows/uia/uiaRawElmProvider.h index 4a4aecdbe2..0e5172c805 100644 --- a/accessible/windows/uia/uiaRawElmProvider.h +++ b/accessible/windows/uia/uiaRawElmProvider.h @@ -8,25 +8,24 @@ #define mozilla_a11y_uiaRawElmProvider_h__ #include "objbase.h" -#include "AccessibleWrap.h" #include "IUnknownImpl.h" #include "uiautomation.h" namespace mozilla { namespace a11y { -class AccessibleWrap; +class Accessible; /** * IRawElementProviderSimple implementation (maintains IAccessibleEx approach). */ -class uiaRawElmProvider final : public IAccessibleEx, - public IRawElementProviderSimple { +class uiaRawElmProvider : public IAccessibleEx, + public IRawElementProviderSimple { public: - explicit uiaRawElmProvider(AccessibleWrap* aAcc) : mAcc(aAcc) {} - // IUnknown - DECL_IUNKNOWN + DECL_IUNKNOWN_INHERITED + ULONG STDMETHODCALLTYPE AddRef() override; + ULONG STDMETHODCALLTYPE Release() override; // IAccessibleEx virtual HRESULT STDMETHODCALLTYPE GetObjectForChild( @@ -61,12 +60,8 @@ class uiaRawElmProvider final : public IAccessibleEx, aRawElmProvider); private: - uiaRawElmProvider() = delete; - uiaRawElmProvider& operator=(const uiaRawElmProvider&) = delete; - uiaRawElmProvider(const uiaRawElmProvider&) = delete; - - protected: - RefPtr<AccessibleWrap> mAcc; + Accessible* Acc(); + bool IsControl(); }; } // namespace a11y |