Bug 1883132 - Suppress a11y instantiation on Win11 for the snap layouts feature. r=Jamie

This is not ideal, because they fall back to position the popup under
the cursor, but it's probably better.

The right thing to do would be for Windows to use the TITLEBARINFOEX
message. We should probably still land that code just so they can
eventually use it, seems worth doing anyways.

Differential Revision: https://phabricator.services.mozilla.com/D203423
This commit is contained in:
Emilio Cobos Álvarez 2024-03-06 15:13:58 +00:00
Родитель 0545327c12
Коммит 6c57980b8f
6 изменённых файлов: 88 добавлений и 30 удалений

Просмотреть файл

@ -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();
}
return ::GetTickCount() - sA11yClipboardCopySuppressionStartTime <
kSuppressTimeout;
}
/* 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 reasons;
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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()) {

Просмотреть файл

@ -608,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;

Просмотреть файл

@ -260,6 +260,18 @@
value: 2
mirror: always
# Whether to avoid accessibility activation on Windows shortly after max button
# hit-test for the "snap layout" feature.
#
# Possible values are:
# * 0: never
# * 1: always
# * 2 (or others): when needed
- name: accessibility.windows.suppress-for-snap-layout
type: uint32_t
value: 2
mirror: always
#---------------------------------------------------------------------------
# Prefs starting with "alerts."
#---------------------------------------------------------------------------

Просмотреть файл

@ -175,12 +175,11 @@
#include <zmouse.h>
#include <richedit.h>
#if defined(ACCESSIBILITY)
#ifdef ACCESSIBILITY
# ifdef DEBUG
# include "mozilla/a11y/Logging.h"
# endif
# include "mozilla/a11y/Compatibility.h"
# include "oleidl.h"
# include <winuser.h>
# include "nsAccessibilityService.h"
@ -190,7 +189,7 @@
# if !defined(WINABLEAPI)
# include <winable.h>
# endif // !defined(WINABLEAPI)
#endif // defined(ACCESSIBILITY)
#endif
#include "WindowsUIUtils.h"
@ -6169,6 +6168,9 @@ int32_t nsWindow::ClientMarginHitTestPoint(int32_t aX, int32_t aY) {
if (mWindowBtnRect[WindowButtonType::Minimize].Contains(pt)) {
testResult = HTMINBUTTON;
} else if (mWindowBtnRect[WindowButtonType::Maximize].Contains(pt)) {
#ifdef ACCESSIBILITY
a11y::Compatibility::SuppressA11yForSnapLayouts();
#endif
testResult = HTMAXBUTTON;
} else if (mWindowBtnRect[WindowButtonType::Close].Contains(pt)) {
testResult = HTCLOSE;