fix: chrome://accessibility drift (#49559)

https://chromium-review.googlesource.com/c/chromium/src/+/6870052

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
This commit is contained in:
trop[bot]
2026-01-28 15:37:39 +01:00
committed by GitHub
parent 81ae20905c
commit 2f3a1ca461
2 changed files with 96 additions and 2 deletions

View File

@@ -49,6 +49,10 @@
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#if BUILDFLAG(IS_WIN)
#include "ui/accessibility/platform/ax_platform_node_win.h"
#endif
namespace {
constexpr std::string_view kTargetsDataFile = "targets-data.json";
@@ -151,6 +155,28 @@ bool ShouldHandleAccessibilityRequestCallback(const std::string& path) {
return path == kTargetsDataFile;
}
// Sets boolean values in `data` for each bit in `new_ax_mode` that differs from
// that in `last_ax_mode`. Returns `true` if `data` was modified.
void SetProcessModeBools(ui::AXMode ax_mode, base::Value::Dict& data) {
data.Set(kNative, ax_mode.has_mode(ui::AXMode::kNativeAPIs));
data.Set(kWeb, ax_mode.has_mode(ui::AXMode::kWebContents));
data.Set(kText, ax_mode.has_mode(ui::AXMode::kInlineTextBoxes));
data.Set(kExtendedProperties,
ax_mode.has_mode(ui::AXMode::kExtendedProperties));
data.Set(kHTML, ax_mode.has_mode(ui::AXMode::kHTML));
data.Set(kScreenReader, ax_mode.has_mode(ui::AXMode::kScreenReader));
}
#if BUILDFLAG(IS_WIN)
// Sets values in `data` for the platform node counts in `counts`.
void SetNodeCounts(const ui::AXPlatformNodeWin::Counts& counts,
base::Value::Dict& data) {
data.Set("dormantCount", base::NumberToString(counts.dormant_nodes));
data.Set("liveCount", base::NumberToString(counts.live_nodes));
data.Set("ghostCount", base::NumberToString(counts.ghost_nodes));
}
#endif
void HandleAccessibilityRequestCallback(
content::BrowserContext* current_context,
ui::AXMode initial_process_mode,
@@ -294,6 +320,10 @@ void HandleAccessibilityRequestCallback(
}
data.Set(kBrowsersField, std::move(window_list));
#if BUILDFLAG(IS_WIN)
SetNodeCounts(ui::AXPlatformNodeWin::GetCounts(), data);
#endif
std::move(callback).Run(base::MakeRefCounted<base::RefCountedString>(
base::WriteJson(data).value_or("")));
}
@@ -381,8 +411,13 @@ ElectronAccessibilityUI::ElectronAccessibilityUI(content::WebUI* web_ui)
ElectronAccessibilityUI::~ElectronAccessibilityUI() = default;
ElectronAccessibilityUIMessageHandler::ElectronAccessibilityUIMessageHandler() =
default;
ElectronAccessibilityUIMessageHandler::ElectronAccessibilityUIMessageHandler()
: update_display_timer_(
FROM_HERE,
base::Seconds(1),
base::BindRepeating(
&ElectronAccessibilityUIMessageHandler::OnUpdateDisplayTimer,
base::Unretained(this))) {}
void ElectronAccessibilityUIMessageHandler::GetRequestTypeAndFilters(
const base::Value::Dict& data,
@@ -472,6 +507,10 @@ void ElectronAccessibilityUIMessageHandler::RegisterMessages() {
base::BindRepeating(
&AccessibilityUIMessageHandler::RequestAccessibilityEvents,
base::Unretained(this)));
auto* web_contents = web_ui()->GetWebContents();
Observe(web_contents);
OnVisibilityChanged(web_contents->GetVisibility());
}
// static
@@ -482,3 +521,45 @@ void ElectronAccessibilityUIMessageHandler::RegisterPrefs(
registry->RegisterStringPref(prefs::kShownAccessibilityApiType,
std::string(default_api_type));
}
void ElectronAccessibilityUIMessageHandler::OnVisibilityChanged(
content::Visibility visibility) {
if (visibility == content::Visibility::HIDDEN) {
update_display_timer_.Stop();
} else {
update_display_timer_.Reset();
}
}
void ElectronAccessibilityUIMessageHandler::OnUpdateDisplayTimer() {
// Collect the current state.
base::Value::Dict data;
SetProcessModeBools(
content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode(),
data);
#if BUILDFLAG(IS_WIN)
SetNodeCounts(ui::AXPlatformNodeWin::GetCounts(), data);
#endif // BUILDFLAG(IS_WIN)
// Compute the delta from the last transmission.
for (auto scan = data.begin(); scan != data.end();) {
const auto& [new_key, new_value] = *scan;
if (const auto* old_value = last_data_.Find(new_key);
!old_value || *old_value != new_value) {
// This is a new value; remember it for the future.
last_data_.Set(new_key, new_value.Clone());
++scan;
} else {
// This is the same as the last value; forget about it.
scan = data.erase(scan);
}
}
// Transmit any new values to the UI.
if (!data.empty()) {
AllowJavascript();
FireWebUIListener("updateDisplay", data);
}
}

View File

@@ -40,6 +40,19 @@ class ElectronAccessibilityUIMessageHandler
std::string& allow_empty,
std::string& deny);
void RequestNativeUITree(const base::Value::List& args);
// content::WebContentsObserver:
void OnVisibilityChanged(content::Visibility visibility) override;
// Updates the UI with new data. Called periodically to keep the UI up-to-date
// while it is visible.
void OnUpdateDisplayTimer();
// The last data for display sent to the UI by OnUpdateDisplayTimer.
base::Value::Dict last_data_;
// A timer that runs while the UI is visible to call OnUpdateDisplayTimer.
base::RepeatingTimer update_display_timer_;
};
#endif // ELECTRON_SHELL_BROWSER_UI_WEBUI_ACCESSIBILITY_UI_H_