[A11yPerformance] Reintroduce AXMode::kScreenReader, for actual screen reader usage
Reintroduce AXMode::kScreenReader, but now, it actually means a screen reader is present, based on detecting all screen readers that work with Chrome. We will be able to use this information to greatly improve our optimization paths, in most cases avoiding work that is only necessary for screen readers. Examples of optimization opportunities: https://docs.google.com/document/d/1QbjIuNI3IYBxMDCg2xCSYWu5fXspfyr-2H8jlqc4UZM/edit?tab=t.0 Bug: none Change-Id: I31f4f19305d73bf4c3cd8ccec2ee98714a187f91 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6455185 Reviewed-by: Zijie He <zijiehe@google.com> Reviewed-by: Greg Thompson <grt@chromium.org> Reviewed-by: Elly FJ <ellyjones@chromium.org> Reviewed-by: Alex Rudenko <alexrudenko@chromium.org> Reviewed-by: Kevin Ellis <kevers@chromium.org> Reviewed-by: Mark Schillaci <mschillaci@google.com> Reviewed-by: Jeremy Roman <jbroman@chromium.org> Commit-Queue: Aaron Leventhal <aleventhal@chromium.org> Cr-Commit-Position: refs/heads/main@{#1454413}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
f56c35fa40
commit
eab7a1366e
chrome
browser
accessibility
ash
accessibility
metrics
pdf
performance_manager
metrics
renderer_context_menu
resources
accessibility
screen_ai
ui
webui
accessibility
test
data
webui
new_tab_page
content
browser
accessibility
accessibility_browsertest.ccax_platform_node_textprovider_win_browsertest.ccbrowser_accessibility_state_impl.ccbrowser_accessibility_state_impl.hbrowser_accessibility_state_impl_android.ccbrowser_accessibility_state_impl_android.hbrowser_accessibility_state_impl_auralinux.ccbrowser_accessibility_state_impl_chromeos.ccbrowser_accessibility_state_impl_mac.mmbrowser_accessibility_state_impl_unittest.ccbrowser_accessibility_state_impl_win.ccdump_accessibility_browsertest_base.ccweb_contents_accessibility_android.cc
web_contents
public
android
javatests
src
org
chromium
content
browser
accessibility
browser
shell
web_test
renderer
fuchsia_web/webengine/browser
third_party/blink
renderer
core
accessibility
frame
inspector
modules
tools
blinkpy
presubmit
tools/metrics/histograms
ui/accessibility
@ -101,14 +101,13 @@ class AXMainNodeAnnotatorControllerBrowserTest : public InProcessBrowserTest {
|
||||
speech_monitor_.Replay();
|
||||
}
|
||||
#else
|
||||
content::BrowserAccessibilityState::GetInstance()->SetScreenReaderAppActive(
|
||||
enabled);
|
||||
// Spoof a screen reader.
|
||||
if (!enabled) {
|
||||
ax_mode_override_.reset();
|
||||
} else if (!ax_mode_override_) {
|
||||
ax_mode_override_.emplace(ui::AXMode::kWebContents |
|
||||
ui::AXMode::kExtendedProperties);
|
||||
ui::AXMode::kExtendedProperties |
|
||||
ui::AXMode::kScreenReader);
|
||||
}
|
||||
#endif // BUILDFLAG(IS_CHROMEOS)
|
||||
}
|
||||
|
@ -115,10 +115,9 @@ class PdfOcrControllerBrowserTest : public base::test::WithFeatureOverride,
|
||||
scoped_accessibility_override_.reset();
|
||||
} else if (!scoped_accessibility_override_) {
|
||||
scoped_accessibility_override_.emplace(ui::AXMode::kWebContents |
|
||||
ui::AXMode::kExtendedProperties);
|
||||
ui::AXMode::kExtendedProperties |
|
||||
ui::AXMode::kScreenReader);
|
||||
}
|
||||
content::BrowserAccessibilityState::GetInstance()->SetScreenReaderAppActive(
|
||||
enabled);
|
||||
#endif // BUILDFLAG(IS_CHROMEOS)
|
||||
}
|
||||
|
||||
|
@ -796,10 +796,6 @@ void AccessibilityManager::OnSpokenFeedbackChanged() {
|
||||
const bool enabled = profile_->GetPrefs()->GetBoolean(
|
||||
prefs::kAccessibilitySpokenFeedbackEnabled);
|
||||
|
||||
content::BrowserAccessibilityState* browser_ax_state =
|
||||
content::BrowserAccessibilityState::GetInstance();
|
||||
browser_ax_state->SetScreenReaderAppActive(enabled);
|
||||
|
||||
if (IsUserBrowserContext(profile_)) {
|
||||
user_manager::KnownUser known_user(g_browser_process->local_state());
|
||||
known_user.SetBooleanPref(
|
||||
@ -819,14 +815,22 @@ void AccessibilityManager::OnSpokenFeedbackChanged() {
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
if (spoken_feedback_enabled_ == enabled)
|
||||
bool was_enabled = spoken_feedback_enabled();
|
||||
if (was_enabled == enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
screen_reader_mode_ =
|
||||
content::BrowserAccessibilityState::GetInstance()
|
||||
->CreateScopedModeForProcess(ui::AXMode::kScreenReader);
|
||||
} else {
|
||||
screen_reader_mode_.reset();
|
||||
}
|
||||
|
||||
if (accessibility_service_client_)
|
||||
accessibility_service_client_->SetChromeVoxEnabled(enabled);
|
||||
|
||||
spoken_feedback_enabled_ = enabled;
|
||||
|
||||
AccessibilityStatusEventDetails details(
|
||||
AccessibilityNotificationType::kToggleSpokenFeedback, enabled);
|
||||
NotifyAccessibilityStatusChanged(details);
|
||||
@ -2203,8 +2207,9 @@ void AccessibilityManager::PostLoadChromeVox() {
|
||||
base::Value::List()));
|
||||
event_router->DispatchEventWithLazyListener(extension_id, std::move(event));
|
||||
|
||||
if (!chromevox_panel_ && spoken_feedback_enabled_)
|
||||
if (!chromevox_panel_ && spoken_feedback_enabled()) {
|
||||
CreateChromeVoxPanel();
|
||||
}
|
||||
|
||||
audio_focus_manager_->SetEnforcementMode(
|
||||
media_session::mojom::EnforcementMode::kNone);
|
||||
@ -2245,7 +2250,7 @@ void AccessibilityManager::PostUnloadChromeVox() {
|
||||
}
|
||||
|
||||
void AccessibilityManager::CreateChromeVoxPanel() {
|
||||
DCHECK(!chromevox_panel_ && spoken_feedback_enabled_);
|
||||
DCHECK(!chromevox_panel_ && spoken_feedback_enabled());
|
||||
chromevox_panel_ = new ChromeVoxPanel(profile_);
|
||||
chromevox_panel_widget_observer_ =
|
||||
std::make_unique<AccessibilityPanelWidgetObserver>(
|
||||
@ -2259,8 +2264,9 @@ void AccessibilityManager::PostSwitchChromeVoxProfile() {
|
||||
chromevox_panel_->CloseNow();
|
||||
chromevox_panel_ = nullptr;
|
||||
}
|
||||
if (!chromevox_panel_ && spoken_feedback_enabled_)
|
||||
if (!chromevox_panel_ && spoken_feedback_enabled()) {
|
||||
CreateChromeVoxPanel();
|
||||
}
|
||||
}
|
||||
|
||||
void AccessibilityManager::OnChromeVoxPanelDestroying() {
|
||||
@ -2548,7 +2554,7 @@ const std::string AccessibilityManager::GetBluetoothBrailleDisplayAddress()
|
||||
|
||||
void AccessibilityManager::UpdateBluetoothBrailleDisplayAddress(
|
||||
const std::string& address) {
|
||||
CHECK(spoken_feedback_enabled_);
|
||||
CHECK(spoken_feedback_enabled());
|
||||
if (!profile_)
|
||||
return;
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "components/session_manager/core/session_manager_observer.h"
|
||||
#include "components/soda/soda_installer.h"
|
||||
#include "components/user_manager/user_manager.h"
|
||||
#include "content/public/browser/scoped_accessibility_mode.h"
|
||||
#include "extensions/browser/event_router.h"
|
||||
#include "extensions/browser/extension_registry.h"
|
||||
#include "extensions/browser/extension_registry_observer.h"
|
||||
@ -675,6 +676,8 @@ class AccessibilityManager
|
||||
|
||||
void MaybeLogBrailleDisplayConnectedTime();
|
||||
|
||||
bool spoken_feedback_enabled() const { return bool(screen_reader_mode_); }
|
||||
|
||||
// Profile which has the current a11y context.
|
||||
raw_ptr<Profile> profile_ = nullptr;
|
||||
base::ScopedObservation<Profile, ProfileObserver> profile_observation_{this};
|
||||
@ -686,7 +689,8 @@ class AccessibilityManager
|
||||
std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
|
||||
std::unique_ptr<PrefChangeRegistrar> local_state_pref_change_registrar_;
|
||||
|
||||
bool spoken_feedback_enabled_ = false;
|
||||
// Only used for ChromeVox aka when spoken feedback is enabled.
|
||||
std::unique_ptr<content::ScopedAccessibilityMode> screen_reader_mode_;
|
||||
bool select_to_speak_enabled_ = false;
|
||||
bool switch_access_enabled_ = false;
|
||||
|
||||
|
@ -215,9 +215,6 @@ std::string DescriptionForNSEvent(NSEvent* event) {
|
||||
|
||||
if ([newValueNumber isKindOfClass:[NSNumber class]]) {
|
||||
[self voiceOverStateChanged:[newValueNumber boolValue]];
|
||||
content::BrowserAccessibilityState* browser_ax_state =
|
||||
content::BrowserAccessibilityState::GetInstance();
|
||||
browser_ax_state->SetScreenReaderAppActive([newValueNumber boolValue]);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -457,7 +454,8 @@ std::string DescriptionForNSEvent(NSEvent* event) {
|
||||
_scoped_accessibility_mode_voiceover =
|
||||
content::BrowserAccessibilityState::GetInstance()
|
||||
->CreateScopedModeForProcess(ui::kAXModeComplete |
|
||||
ui::AXMode::kFromPlatform);
|
||||
ui::AXMode::kFromPlatform |
|
||||
ui::AXMode::kScreenReader);
|
||||
}
|
||||
} else {
|
||||
_scoped_accessibility_mode_voiceover.reset();
|
||||
|
@ -104,7 +104,8 @@ class ChromeBrowserAppMacBrowserTest : public InProcessBrowserTest {
|
||||
}
|
||||
|
||||
bool BrowserIsInCompleteAccessibilityMode() {
|
||||
return BrowserIsInAccessibilityMode(ui::kAXModeComplete);
|
||||
return BrowserIsInAccessibilityMode(ui::kAXModeComplete |
|
||||
ui::AXMode::kScreenReader);
|
||||
}
|
||||
|
||||
bool BrowserIsInBasicAccessibilityMode() {
|
||||
@ -320,5 +321,6 @@ IN_PROC_BROWSER_TEST_F(ChromeBrowserAppMacBrowserMacVoiceOverEnabledTest,
|
||||
|
||||
// Enable VoiceOver.
|
||||
EXPECT_TRUE(VoiceOverEnabled());
|
||||
EXPECT_EQ(accessibility_state->GetAccessibilityMode(), ui::kAXModeComplete);
|
||||
EXPECT_EQ(accessibility_state->GetAccessibilityMode(),
|
||||
ui::kAXModeComplete | ui::AXMode::kScreenReader);
|
||||
}
|
||||
|
@ -20,7 +20,8 @@ metrics::SystemProfileProto::AccessibilityState::AXMode ModeFlagsToProtoEnum(
|
||||
case ui::AXMode::kInlineTextBoxes:
|
||||
return metrics::SystemProfileProto::AccessibilityState::INLINE_TEXT_BOXES;
|
||||
case ui::AXMode::kExtendedProperties:
|
||||
return metrics::SystemProfileProto::AccessibilityState::SCREEN_READER;
|
||||
return metrics::SystemProfileProto::AccessibilityState::
|
||||
EXTENDED_PROPERTIES;
|
||||
case ui::AXMode::kHTML:
|
||||
return metrics::SystemProfileProto::AccessibilityState::HTML;
|
||||
case ui::AXMode::kHTMLMetadata:
|
||||
@ -34,6 +35,8 @@ metrics::SystemProfileProto::AccessibilityState::AXMode ModeFlagsToProtoEnum(
|
||||
case ui::AXMode::kAnnotateMainNode:
|
||||
return metrics::SystemProfileProto::AccessibilityState::
|
||||
ANNOTATE_MAIN_NODE;
|
||||
case ui::AXMode::kScreenReader:
|
||||
return metrics::SystemProfileProto::AccessibilityState::SCREEN_READER;
|
||||
default:
|
||||
NOTREACHED();
|
||||
}
|
||||
@ -74,4 +77,6 @@ void AccessibilityStateProvider::ProvideSystemProfileMetrics(
|
||||
MaybeAddAccessibilityModeFlags(mode, ui::AXMode::kAnnotateMainNode, state);
|
||||
// ui::AXMode::kFromPlatform is unconditionally filtered out and is therefore
|
||||
// never present in `mode`.
|
||||
CHECK(!mode.has_mode(ui::AXMode::kFromPlatform));
|
||||
MaybeAddAccessibilityModeFlags(mode, ui::AXMode::kScreenReader, state);
|
||||
}
|
||||
|
@ -42,7 +42,6 @@
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "components/zoom/zoom_controller.h"
|
||||
#include "content/public/browser/ax_inspect_factory.h"
|
||||
#include "content/public/browser/browser_accessibility_state.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/test/accessibility_notification_waiter.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
@ -237,9 +236,7 @@ class PDFExtensionAccessibilityTest : public PDFExtensionTestBase {
|
||||
|
||||
void EnableScreenReader() {
|
||||
// Spoof a screen reader.
|
||||
mode_override_.emplace(ui::kAXModeComplete);
|
||||
content::BrowserAccessibilityState::GetInstance()->SetScreenReaderAppActive(
|
||||
true);
|
||||
mode_override_.emplace(ui::kAXModeDefaultForTests);
|
||||
}
|
||||
|
||||
void TearDownOnMainThread() override {
|
||||
|
@ -30,7 +30,8 @@ ui::AXMode::ModeFlagHistogramValue ModeFlagsToEnum(uint32_t mode_flags) {
|
||||
case ui::AXMode::kInlineTextBoxes:
|
||||
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_INLINE_TEXT_BOXES;
|
||||
case ui::AXMode::kExtendedProperties:
|
||||
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_SCREEN_READER;
|
||||
return ui::AXMode::ModeFlagHistogramValue::
|
||||
UMA_AX_MODE_EXTENDED_PROPERTIES;
|
||||
case ui::AXMode::kHTML:
|
||||
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_HTML;
|
||||
case ui::AXMode::kHTMLMetadata:
|
||||
@ -43,6 +44,8 @@ ui::AXMode::ModeFlagHistogramValue ModeFlagsToEnum(uint32_t mode_flags) {
|
||||
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_PDF_OCR;
|
||||
case ui::AXMode::kAnnotateMainNode:
|
||||
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_ANNOTATE_MAIN_NODE;
|
||||
case ui::AXMode::kScreenReader:
|
||||
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_SCREEN_READER;
|
||||
default:
|
||||
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_MAX;
|
||||
}
|
||||
@ -116,6 +119,7 @@ void MetricsProviderCommon::RecordA11yFlags() {
|
||||
MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kAnnotateMainNode);
|
||||
// ui::AXMode::kFromPlatform is unconditionally filtered out and is
|
||||
// therefore never present in `mode`.
|
||||
MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kScreenReader);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "content/public/browser/browser_accessibility_state.h"
|
||||
#include "content/public/browser/context_menu_params.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
#include "content/public/test/scoped_accessibility_mode_override.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
@ -102,8 +103,8 @@ IN_PROC_BROWSER_TEST_F(AccessibilityLabelsMenuObserverTest,
|
||||
IN_PROC_BROWSER_TEST_F(AccessibilityLabelsMenuObserverTest,
|
||||
MAYBE_AccessibilityLabelsShowWithScreenReaderEnabled) {
|
||||
// Spoof a screen reader.
|
||||
content::BrowserAccessibilityState::GetInstance()->SetScreenReaderAppActive(
|
||||
true);
|
||||
content::ScopedAccessibilityModeOverride screen_reader_mode(
|
||||
ui::AXMode::kScreenReader);
|
||||
menu()->GetPrefs()->SetBoolean(prefs::kAccessibilityImageLabelsEnabled,
|
||||
false);
|
||||
InitMenu();
|
||||
|
@ -80,8 +80,21 @@ found in the LICENSE file.
|
||||
</label>
|
||||
</div>
|
||||
<div id="extended_properties_secondary" class="secondary">
|
||||
Exposes accessibility APIs needed by
|
||||
advanced assistive technologies.
|
||||
Exposes accessibility APIs needed only by advanced assistive
|
||||
technologies.
|
||||
</div>
|
||||
|
||||
<div class="checkbox-row">
|
||||
<label>
|
||||
<span class="checkbox-wrapper">
|
||||
<input type="checkbox" id="screenReader"
|
||||
aria-describedby="screen_reader_secondary">
|
||||
</span>
|
||||
Screen reader
|
||||
</label>
|
||||
</div>
|
||||
<div id="screen_reader_secondary" class="secondary">
|
||||
Exposes accessibility APIs needed only by screen readers.
|
||||
</div>
|
||||
|
||||
<div class="checkbox-row">
|
||||
|
@ -23,6 +23,7 @@ enum AxMode {
|
||||
PDF_OCR = 1 << 8,
|
||||
ANNOTATE_MAIN_NODE = 1 << 9,
|
||||
FROM_PLATFORM = 1 << 10,
|
||||
SCREEN_READER = 1 << 11,
|
||||
}
|
||||
|
||||
interface Data {
|
||||
@ -79,6 +80,7 @@ interface InitData {
|
||||
extendedProperties: boolean;
|
||||
text: boolean;
|
||||
web: boolean;
|
||||
screenReader: boolean;
|
||||
|
||||
lockedPlatformModes: {
|
||||
native: boolean,
|
||||
@ -86,13 +88,14 @@ interface InitData {
|
||||
html: boolean,
|
||||
extendedProperties: boolean,
|
||||
text: boolean,
|
||||
screenReader: boolean,
|
||||
};
|
||||
}
|
||||
|
||||
type RequestType = 'showOrRefreshTree';
|
||||
|
||||
type GlobalStateName =
|
||||
'native'|'web'|'metadata'|'pdfPrinting'|'extendedProperties';
|
||||
type GlobalStateName = 'native'|'web'|'html'|'text'|'metadata'|'pdfPrinting'|
|
||||
'extendedProperties'|'screenReader'|'labelImages'|'annotateMainNode';
|
||||
|
||||
class BrowserProxy {
|
||||
toggleAccessibility(
|
||||
@ -258,6 +261,8 @@ function initialize() {
|
||||
bindCheckbox(
|
||||
'extendedProperties', data.extendedProperties,
|
||||
data.lockedPlatformModes.extendedProperties);
|
||||
bindCheckbox(
|
||||
'screenReader', data.screenReader, data.lockedPlatformModes.screenReader);
|
||||
bindCheckbox('html', data.html, data.lockedPlatformModes.html);
|
||||
bindDropdown('apiType', data.supportedApiTypes, data.apiType);
|
||||
bindCheckbox('isolate', data.isolate);
|
||||
@ -404,22 +409,26 @@ function formatRow(
|
||||
}
|
||||
row.appendChild(siteInfo);
|
||||
|
||||
// Create a row of buttons that can be used to read and modify the
|
||||
// AXModes scoped to a specific WebContents.
|
||||
row.appendChild(createModeElement(AxMode.NATIVE_APIS, pageData, 'native'));
|
||||
row.appendChild(createModeElement(AxMode.WEB_CONTENTS, pageData, 'native'));
|
||||
row.appendChild(createModeElement(AxMode.WEB_CONTENTS, pageData, 'web'));
|
||||
row.appendChild(
|
||||
createModeElement(AxMode.INLINE_TEXT_BOXES, pageData, 'web'));
|
||||
createModeElement(AxMode.INLINE_TEXT_BOXES, pageData, 'text'));
|
||||
row.appendChild(createModeElement(
|
||||
AxMode.EXTENDED_PROPERTIES, pageData, 'extendedProperties'));
|
||||
row.appendChild(
|
||||
createModeElement(AxMode.EXTENDED_PROPERTIES, pageData, 'web'));
|
||||
row.appendChild(createModeElement(AxMode.HTML, pageData, 'web'));
|
||||
createModeElement(AxMode.SCREEN_READER, pageData, 'screenReader'));
|
||||
row.appendChild(createModeElement(AxMode.HTML, pageData, 'html'));
|
||||
row.appendChild(
|
||||
createModeElement(AxMode.HTML_METADATA, pageData, 'metadata'));
|
||||
row.appendChild(
|
||||
createModeElement(AxMode.PDF_PRINTING, pageData, 'pdfPrinting'));
|
||||
row.appendChild(createModeElement(
|
||||
AxMode.LABEL_IMAGES, pageData, 'extendedProperties',
|
||||
AxMode.LABEL_IMAGES, pageData, 'labelImages',
|
||||
/*readonly=*/ true));
|
||||
row.appendChild(createModeElement(
|
||||
AxMode.ANNOTATE_MAIN_NODE, pageData, 'extendedProperties',
|
||||
AxMode.ANNOTATE_MAIN_NODE, pageData, 'annotateMainNode',
|
||||
/* readOnly= */ true));
|
||||
// AxMode.FROM_PLATFORM is unconditionally filtered out and is therefore
|
||||
// never presented to renderers or the user.
|
||||
@ -528,11 +537,17 @@ function getNameForAccessibilityMode(mode: AxMode): string {
|
||||
return 'PDF OCR';
|
||||
case AxMode.ANNOTATE_MAIN_NODE:
|
||||
return 'Annotate main node';
|
||||
case AxMode.SCREEN_READER:
|
||||
return 'Screen reader';
|
||||
default:
|
||||
assertNotReached();
|
||||
}
|
||||
}
|
||||
|
||||
// Create a button element that can be used to modify the AXMode in the given
|
||||
// WebContents/page only. The label consists of the name for the AXMode
|
||||
// (via globalStateName) and the value of the AXMode (via PageData).
|
||||
// AXModes that do not allow modification this way should pass readOnly == true.
|
||||
function createModeElement(
|
||||
mode: AxMode, data: PageData, globalStateName: GlobalStateName,
|
||||
readOnly = false) {
|
||||
|
@ -121,7 +121,7 @@ class MainContentExtractionTest : public InProcessBrowserTest {
|
||||
|
||||
base::test::TestFuture<ui::AXTreeUpdate&> future;
|
||||
web_contents->RequestAXTreeSnapshot(
|
||||
future.GetCallback(), ui::kAXModeComplete,
|
||||
future.GetCallback(), ui::kAXModeDefaultForTests,
|
||||
/* max_nodes= */ 0,
|
||||
/* timeout= */ {}, content::WebContents::AXTreeSnapshotPolicy::kAll);
|
||||
EXPECT_TRUE(future.Wait());
|
||||
|
@ -107,6 +107,7 @@ static const char kNative[] = "native";
|
||||
static const char kPage[] = "page";
|
||||
static const char kPDFPrinting[] = "pdfPrinting";
|
||||
static const char kExtendedProperties[] = "extendedProperties";
|
||||
static const char kScreenReader[] = "screenReader";
|
||||
static const char kShowOrRefreshTree[] = "showOrRefreshTree";
|
||||
static const char kText[] = "text";
|
||||
static const char kWeb[] = "web";
|
||||
@ -198,6 +199,7 @@ void HandleAccessibilityRequestCallback(
|
||||
bool web = mode.has_mode(ui::AXMode::kWebContents);
|
||||
bool text = mode.has_mode(ui::AXMode::kInlineTextBoxes);
|
||||
bool extended_properties = mode.has_mode(ui::AXMode::kExtendedProperties);
|
||||
bool screen_reader = mode.has_mode(ui::AXMode::kScreenReader);
|
||||
bool html = mode.has_mode(ui::AXMode::kHTML);
|
||||
bool pdf_printing = mode.has_mode(ui::AXMode::kPDFPrinting);
|
||||
bool allow_platform_activation =
|
||||
@ -212,6 +214,7 @@ void HandleAccessibilityRequestCallback(
|
||||
// meaningful if "web" is enabled.
|
||||
data.Set(kText, text);
|
||||
data.Set(kExtendedProperties, extended_properties);
|
||||
data.Set(kScreenReader, screen_reader);
|
||||
data.Set(kHTML, html);
|
||||
|
||||
// The "pdfPrinting" flag is independent of the others.
|
||||
@ -236,6 +239,9 @@ void HandleAccessibilityRequestCallback(
|
||||
extended_properties &&
|
||||
initial_process_mode.has_mode(
|
||||
ui::AXMode::kExtendedProperties))
|
||||
.Set(kScreenReader,
|
||||
allow_platform_activation && screen_reader &&
|
||||
initial_process_mode.has_mode(ui::AXMode::kScreenReader))
|
||||
.Set(kHTML, allow_platform_activation &&
|
||||
initial_process_mode.has_mode(ui::AXMode::kHTML)));
|
||||
|
||||
@ -301,6 +307,7 @@ void HandleAccessibilityRequestCallback(
|
||||
base::Value::Dict descriptor = BuildTargetDescriptor(rvh);
|
||||
descriptor.Set(kNative, native);
|
||||
descriptor.Set(kExtendedProperties, extended_properties);
|
||||
descriptor.Set(kScreenReader, screen_reader);
|
||||
descriptor.Set(kWeb, web);
|
||||
page_list.Append(std::move(descriptor));
|
||||
}
|
||||
@ -748,6 +755,8 @@ void AccessibilityUIMessageHandler::SetGlobalFlag(
|
||||
new_mode = ui::AXMode::kInlineTextBoxes;
|
||||
} else if (flag_name == kExtendedProperties) {
|
||||
new_mode = ui::AXMode::kExtendedProperties;
|
||||
} else if (flag_name == kScreenReader) {
|
||||
new_mode = ui::AXMode::kScreenReader;
|
||||
} else if (flag_name == kHTML) {
|
||||
new_mode = ui::AXMode::kHTML;
|
||||
} else {
|
||||
|
@ -30,7 +30,7 @@ using NewTabPageAppA11yTest = NewTabPageA11yBrowserTest;
|
||||
IN_PROC_BROWSER_TEST_F(NewTabPageAppA11yTest, Clicks) {
|
||||
ASSERT_EQ(
|
||||
content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode(),
|
||||
ui::kAXModeComplete);
|
||||
ui::kAXModeComplete | ui::AXMode::kScreenReader);
|
||||
RunTest("new_tab_page/app_test.js",
|
||||
"runMochaSuite('NewTabPageAppTest Clicks')");
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ void AccessibilityBrowserTest::ExecuteScript(const std::u16string& script) {
|
||||
void AccessibilityBrowserTest::LoadInitialAccessibilityTreeFromHtml(
|
||||
const std::string& html) {
|
||||
if (!accessibility_mode_) {
|
||||
accessibility_mode_.emplace(ui::kAXModeComplete);
|
||||
accessibility_mode_.emplace(ui::kAXModeDefaultForTests);
|
||||
}
|
||||
AccessibilityNotificationWaiter waiter(shell()->web_contents(),
|
||||
ax::mojom::Event::kLoadComplete);
|
||||
|
@ -60,7 +60,7 @@ namespace content {
|
||||
class AXPlatformNodeTextProviderWinBrowserTest : public ContentBrowserTest {
|
||||
protected:
|
||||
void SetUpOnMainThread() override {
|
||||
accessibility_mode_.emplace(ui::kAXModeComplete);
|
||||
accessibility_mode_.emplace(ui::kAXModeDefaultForTests);
|
||||
}
|
||||
|
||||
void TearDownOnMainThread() override { accessibility_mode_.reset(); }
|
||||
|
@ -49,13 +49,10 @@ constexpr int kAutoDisableAccessibilityEventCount = 3;
|
||||
// good for perf. Instead, delay the update task.
|
||||
constexpr int kOnAccessibilityUsageUpdateDelaySecs = 5;
|
||||
|
||||
// Used for validating the 'basic' bundle parameter for
|
||||
// --force-renderer-accessibility.
|
||||
// Parameter values for --force-renderer-accessibility=[bundle-name].
|
||||
const char kAXModeBundleBasic[] = "basic";
|
||||
|
||||
// Used for validating the 'form-controls' bundle parameter for
|
||||
// --force-renderer-accessibility.
|
||||
const char kAXModeBundleFormControls[] = "form-controls";
|
||||
const char kAXModeBundleComplete[] = "complete";
|
||||
|
||||
// A holder of a ScopedModeCollection targeting a specific BrowserContext or
|
||||
// WebContents. The collection is bound to the lifetime of the target.
|
||||
@ -216,17 +213,23 @@ BrowserAccessibilityStateImpl::BrowserAccessibilityStateImpl() {
|
||||
|
||||
if (ax_mode_bundle.empty()) {
|
||||
// For backwards compatibility, when --force-renderer-accessibility has no
|
||||
// parameter, use the complete bundle but allow changes.
|
||||
initial_mode = ui::kAXModeComplete;
|
||||
// parameter, use the screen reader bundle but allow changes.
|
||||
// This is the best general choice in development and testing scenarios.
|
||||
initial_mode = ui::kAXModeComplete | ui::AXMode::kScreenReader;
|
||||
} else {
|
||||
// Support --force-renderer-accessibility=[basic|form-controls|complete]
|
||||
// Support
|
||||
// --force-renderer-accessibility=[basic|form-controls|complete|
|
||||
// screen-reader]
|
||||
if (ax_mode_bundle.compare(kAXModeBundleBasic) == 0) {
|
||||
initial_mode = ui::kAXModeBasic;
|
||||
} else if (ax_mode_bundle.compare(kAXModeBundleFormControls) == 0) {
|
||||
initial_mode = ui::kAXModeFormControls;
|
||||
} else {
|
||||
// If AXMode is 'complete' or invalid, default to complete bundle.
|
||||
} else if (ax_mode_bundle.compare(kAXModeBundleComplete) == 0) {
|
||||
initial_mode = ui::kAXModeComplete;
|
||||
} else {
|
||||
// If 'screen-reader', or invalid, default to screen reader bundle,
|
||||
// which is the most useful in development and testing scenarios.
|
||||
initial_mode = ui::kAXModeComplete | ui::AXMode::kScreenReader;
|
||||
}
|
||||
disallow_changes = true;
|
||||
}
|
||||
@ -258,13 +261,28 @@ void BrowserAccessibilityStateImpl::OnAssistiveTechFound(
|
||||
ax_platform_.NotifyAssistiveTechChanged(assistive_tech);
|
||||
}
|
||||
|
||||
void BrowserAccessibilityStateImpl::SetScreenReaderAppActive(bool is_active) {
|
||||
OnAssistiveTechFound(is_active ? ui::AssistiveTech::kGenericScreenReader
|
||||
void BrowserAccessibilityStateImpl::RefreshAssistiveTech() {
|
||||
bool sr_active = GetAccessibilityMode().has_mode(ui::AXMode::kScreenReader);
|
||||
OnAssistiveTechFound(sr_active ? ui::AssistiveTech::kGenericScreenReader
|
||||
: ui::AssistiveTech::kNone);
|
||||
}
|
||||
|
||||
void BrowserAccessibilityStateImpl::RefreshAssistiveTechIfNecessary(
|
||||
ui::AXMode new_mode) {
|
||||
// Platforms that use this default implementation have a perfect signal
|
||||
// for screen reader launches. These platforms use AXMode::kScreenReader to
|
||||
// actively indicate that a screen reader is active.
|
||||
// Other platforms don't have this perfect signal and compute this off-thread,
|
||||
// adding/removing AXMode::kScreenReader after detection is complete.
|
||||
bool was_screen_reader_active = ax_platform_.IsScreenReaderActive();
|
||||
bool has_screen_reader_mode = new_mode.has_mode(ui::AXMode::kScreenReader);
|
||||
if (was_screen_reader_active != has_screen_reader_mode) {
|
||||
RefreshAssistiveTech();
|
||||
}
|
||||
}
|
||||
|
||||
ui::AssistiveTech BrowserAccessibilityStateImpl::ActiveAssistiveTech() const {
|
||||
return ui::AXPlatform::GetInstance().active_assistive_tech();
|
||||
return ax_platform_.active_assistive_tech();
|
||||
}
|
||||
|
||||
void BrowserAccessibilityStateImpl::SetPerformanceFilteringAllowed(
|
||||
@ -469,12 +487,6 @@ BrowserAccessibilityStateImpl::CreateScopedModeForProcess(ui::AXMode mode) {
|
||||
// scopers targeting the process changes.
|
||||
void BrowserAccessibilityStateImpl::OnModeChanged(ui::AXMode old_mode,
|
||||
ui::AXMode new_mode) {
|
||||
// If the AXMode changes, there's a good chance an assistive technology was
|
||||
// activated. Allow platforms that must perform special detection to update
|
||||
// their notion of which tech is running. The platform-specific implementation
|
||||
// is responsible for calling `OnAssistiveTechFound()` in response.
|
||||
RefreshAssistiveTech();
|
||||
|
||||
if (!new_mode.is_mode_off()) {
|
||||
// Unless the mode is being turned off, setting accessibility flags is
|
||||
// generally caused by accessibility API call, so we should also reset the
|
||||
@ -495,6 +507,9 @@ void BrowserAccessibilityStateImpl::OnModeChanged(ui::AXMode old_mode,
|
||||
UMA_HISTOGRAM_COUNTS_10000("Accessibility.EngineUse.PageNavsUntilStart",
|
||||
num_page_navs_before_first_use_);
|
||||
}
|
||||
|
||||
RefreshAssistiveTechIfNecessary(new_mode);
|
||||
|
||||
// Add a crash key with the ax_mode, to enable searching for top crashes that
|
||||
// occur when accessibility is turned on. This adds it for the browser
|
||||
// process, and elsewhere the same key is added to renderer processes.
|
||||
|
@ -63,13 +63,6 @@ class CONTENT_EXPORT BrowserAccessibilityStateImpl
|
||||
ui::AXMode GetAccessibilityMode() override;
|
||||
ui::AXMode GetAccessibilityModeForBrowserContext(
|
||||
BrowserContext* browser_context) override;
|
||||
// Some platforms have a strong signal indicating the presence of a
|
||||
// screen reader and can call in to let us know when one has
|
||||
// been enabled/disabled.
|
||||
// Other platforms require looking through running processes or modules
|
||||
// attached to the process, for the name of known assistive tech such as
|
||||
// screen readers, which takes time, and must override RefreshAssistiveTech().
|
||||
void SetScreenReaderAppActive(bool is_active) override;
|
||||
// Any currently running assistive tech that should prevent accessibility from
|
||||
// being auto-disabled.
|
||||
ui::AssistiveTech ActiveAssistiveTech() const override;
|
||||
@ -123,6 +116,19 @@ class CONTENT_EXPORT BrowserAccessibilityStateImpl
|
||||
// platform-specific means.
|
||||
void OnAssistiveTechFound(ui::AssistiveTech assistive_tech);
|
||||
|
||||
// Refreshes the assistive tech if an AXMode change indicates that the
|
||||
// presence of an active screen reader may have changed.
|
||||
// * Platforms that have a perfect signal for the presence of a screen reader
|
||||
// should not override this method: the default implementation treats the
|
||||
// screen reader flag as a deterministic indicator.
|
||||
// * Platforms such as Windows and Linux that require a slow computation
|
||||
// to determine the presence of a screen reader should begin the computation
|
||||
// when the presence of AXMode::kExtendedProperties is inconsistent with the
|
||||
// current known screen reader state.
|
||||
virtual void RefreshAssistiveTechIfNecessary(ui::AXMode new_mode);
|
||||
|
||||
ui::AXPlatform& ax_platform() { return ax_platform_; }
|
||||
|
||||
private:
|
||||
void UpdateAccessibilityActivityTask();
|
||||
|
||||
@ -147,8 +153,8 @@ class CONTENT_EXPORT BrowserAccessibilityStateImpl
|
||||
|
||||
// Refreshes the instance's notion of active assistive technologies.
|
||||
// Implementations must call `OnAssistiveTechFound()` with the results of any
|
||||
// discovery. Does nothing by default.
|
||||
virtual void RefreshAssistiveTech() {}
|
||||
// discovery.
|
||||
virtual void RefreshAssistiveTech();
|
||||
|
||||
// The process's single AXPlatform instance.
|
||||
ui::AXPlatform ax_platform_{*this};
|
||||
@ -202,12 +208,6 @@ class CONTENT_EXPORT BrowserAccessibilityStateImpl
|
||||
// The time accessibility was auto-disabled, for statistics.
|
||||
base::TimeTicks accessibility_disabled_time_;
|
||||
|
||||
// The time of the most-recent, explicit request to disable accessibility
|
||||
// support. This is set in `OnScreenReaderStopped`. We keep track of this
|
||||
// in order to prevent destroying and/or (re)creating large accessibility
|
||||
// trees in response to an assistive technology being toggled.
|
||||
base::TimeTicks disable_accessibility_request_time_;
|
||||
|
||||
base::RepeatingCallbackList<void(const FocusedNodeDetails&)>
|
||||
focus_changed_callbacks_;
|
||||
|
||||
|
@ -430,8 +430,8 @@ void BrowserAccessibilityStateImplAndroid::OnContrastLevelChanged(
|
||||
native_theme->NotifyOnNativeThemeUpdated();
|
||||
}
|
||||
|
||||
void BrowserAccessibilityStateImplAndroid::SetScreenReaderAppActive(
|
||||
bool is_active) {
|
||||
void BrowserAccessibilityStateImplAndroid::RefreshAssistiveTech() {
|
||||
bool is_active = GetAccessibilityMode().has_mode(ui::AXMode::kScreenReader);
|
||||
static auto* ax_talkback_crash_key = base::debug::AllocateCrashKeyString(
|
||||
"ax_talkback", base::debug::CrashKeySize::Size32);
|
||||
|
||||
|
@ -23,8 +23,8 @@ class BrowserAccessibilityStateImplAndroid
|
||||
void OnContrastLevelChanged(bool highContrastEnabled) override;
|
||||
void RecordAccessibilityServiceInfoHistograms() override;
|
||||
|
||||
// BrowserAccessibilityState implementation.
|
||||
void SetScreenReaderAppActive(bool is_active) override;
|
||||
// BrowserAccessibilityStateImpl implementation.
|
||||
void RefreshAssistiveTech() override;
|
||||
|
||||
protected:
|
||||
void RecordAccessibilityServiceStatsHistogram(int event_type_mask,
|
||||
|
@ -91,11 +91,16 @@ class BrowserAccessibilityStateImplAuralinux
|
||||
|
||||
// BrowserAccessibilityStateImpl:
|
||||
void RefreshAssistiveTech() override;
|
||||
void RefreshAssistiveTechIfNecessary(ui::AXMode new_mode) override;
|
||||
void OnExtendedPropertiesUsed() override;
|
||||
|
||||
private:
|
||||
void OnDiscoveredOrca(bool is_orca_active);
|
||||
|
||||
// A ScopedAccessibilityMode that holds AXMode::kScreenReader when
|
||||
// an active screen reader has been detected.
|
||||
std::unique_ptr<ScopedAccessibilityMode> screen_reader_mode_;
|
||||
|
||||
// The presence of an AssistiveTech is currently being recomputed.
|
||||
// Will be updated via DiscoverOrca().
|
||||
bool awaiting_known_assistive_tech_computation_ = false;
|
||||
@ -117,6 +122,32 @@ void BrowserAccessibilityStateImplAuralinux::RefreshAssistiveTech() {
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserAccessibilityStateImplAuralinux::RefreshAssistiveTechIfNecessary(
|
||||
ui::AXMode new_mode) {
|
||||
bool was_screen_reader_active = ax_platform().IsScreenReaderActive();
|
||||
bool has_screen_reader_mode = new_mode.has_mode(ui::AXMode::kScreenReader);
|
||||
if (was_screen_reader_active != has_screen_reader_mode) {
|
||||
OnAssistiveTechFound(has_screen_reader_mode
|
||||
? ui::AssistiveTech::kGenericScreenReader
|
||||
: ui::AssistiveTech::kNone);
|
||||
return;
|
||||
}
|
||||
|
||||
// An expensive check is required to determine which type of assistive tech is
|
||||
// in use. Make this check only when `kExtendedProperties` is added or removed
|
||||
// from the process-wide mode flags and no previous assistive tech has been
|
||||
// discovered (in the former case) or one had been discovered (in the latter
|
||||
// case). `kScreenReader` will be added/removed from the process-wide mode
|
||||
// flags on completion and `OnAssistiveTechFound()` will be called with the
|
||||
// results of the check.
|
||||
bool has_extended_properties =
|
||||
new_mode.has_mode(ui::AXMode::kExtendedProperties);
|
||||
if (was_screen_reader_active != has_extended_properties) {
|
||||
// Perform expensive assistive tech detection.
|
||||
RefreshAssistiveTech();
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserAccessibilityStateImplAuralinux::OnExtendedPropertiesUsed() {
|
||||
if (!complete_ax_mode_) {
|
||||
complete_ax_mode_ = CreateScopedModeForProcess(ui::kAXModeComplete |
|
||||
@ -137,12 +168,19 @@ void BrowserAccessibilityStateImplAuralinux::OnDiscoveredOrca(
|
||||
UMA_HISTOGRAM_BOOLEAN("Accessibility.Linux.Orca", is_orca_active);
|
||||
static auto* ax_orca_crash_key = base::debug::AllocateCrashKeyString(
|
||||
"ax_orca", base::debug::CrashKeySize::Size32);
|
||||
// Save the current assistive tech before toggling AXModes, so
|
||||
// that RefreshAssistiveTechIfNecessary() is a noop.
|
||||
if (is_orca_active) {
|
||||
base::debug::SetCrashKeyString(ax_orca_crash_key, "true");
|
||||
OnAssistiveTechFound(ui::AssistiveTech::kOrca);
|
||||
if (!screen_reader_mode_) {
|
||||
screen_reader_mode_ = CreateScopedModeForProcess(
|
||||
ui::kAXModeComplete | ui::AXMode::kScreenReader);
|
||||
}
|
||||
} else {
|
||||
base::debug::ClearCrashKeyString(ax_orca_crash_key);
|
||||
OnAssistiveTechFound(ui::AssistiveTech::kNone);
|
||||
screen_reader_mode_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,9 @@ class BrowserAccessibilityStateImplChromeOS
|
||||
|
||||
protected:
|
||||
// BrowserAccessibilityStateImpl:
|
||||
void SetScreenReaderAppActive(bool is_active) override {
|
||||
void RefreshAssistiveTech() override {
|
||||
bool is_active = GetAccessibilityMode().has_mode(ui::AXMode::kScreenReader);
|
||||
|
||||
// Set/clear crash key (similar to crash keys for other screen readers).
|
||||
static auto* ax_chromevox_crash_key = base::debug::AllocateCrashKeyString(
|
||||
"ax_chromevox", base::debug::CrashKeySize::Size32);
|
||||
|
@ -22,7 +22,7 @@ class BrowserAccessibilityStateImplMac : public BrowserAccessibilityStateImpl {
|
||||
~BrowserAccessibilityStateImplMac() override {}
|
||||
|
||||
protected:
|
||||
void SetScreenReaderAppActive(bool is_active) override;
|
||||
void RefreshAssistiveTech() override;
|
||||
};
|
||||
|
||||
BrowserAccessibilityStateImplMac::BrowserAccessibilityStateImplMac() {
|
||||
@ -64,8 +64,9 @@ BrowserAccessibilityStateImplMac::BrowserAccessibilityStateImplMac() {
|
||||
context:this];
|
||||
}
|
||||
|
||||
void BrowserAccessibilityStateImplMac::SetScreenReaderAppActive(
|
||||
bool is_active) {
|
||||
void BrowserAccessibilityStateImplMac::RefreshAssistiveTech() {
|
||||
bool is_active = GetAccessibilityMode().has_mode(ui::AXMode::kScreenReader);
|
||||
|
||||
static auto* ax_voiceover_crash_key = base::debug::AllocateCrashKeyString(
|
||||
"ax_voiceover", base::debug::CrashKeySize::Size32);
|
||||
if (is_active) {
|
||||
|
@ -58,9 +58,6 @@ TEST_F(BrowserAccessibilityStateImplTest,
|
||||
|
||||
// Enable accessibility.
|
||||
ScopedAccessibilityModeOverride scoped_mode(ui::kAXModeComplete);
|
||||
// Indicate that an actual screen reader is not running (a screen reader
|
||||
// will prevent auto-disable from taking place).
|
||||
state_->SetScreenReaderAppActive(false);
|
||||
EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::kAXModeComplete);
|
||||
|
||||
// Send user input, wait 31 seconds, then send another user input event -
|
||||
|
@ -449,6 +449,7 @@ class BrowserAccessibilityStateImplWin : public BrowserAccessibilityStateImpl {
|
||||
|
||||
protected:
|
||||
void RefreshAssistiveTech() override;
|
||||
void RefreshAssistiveTechIfNecessary(ui::AXMode new_mode) override;
|
||||
ui::AXPlatform::ProductStrings GetProductStrings() override;
|
||||
void OnUiaProviderRequested(bool uia_provider_enabled) override;
|
||||
void OnUiaProviderDisabled() override;
|
||||
@ -459,6 +460,10 @@ class BrowserAccessibilityStateImplWin : public BrowserAccessibilityStateImpl {
|
||||
|
||||
std::unique_ptr<gfx::SingletonHwndObserver> singleton_hwnd_observer_;
|
||||
|
||||
// A ScopedAccessibilityMode that holds AXMode::kScreenReader when
|
||||
// an active screen reader has been detected.
|
||||
std::unique_ptr<ScopedAccessibilityMode> screen_reader_mode_;
|
||||
|
||||
// The presence of an AssistiveTech is currently being recomputed.
|
||||
// Will be updated via DiscoverAssistiveTech().
|
||||
bool awaiting_known_assistive_tech_computation_ = false;
|
||||
@ -488,6 +493,32 @@ void BrowserAccessibilityStateImplWin::RefreshAssistiveTech() {
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserAccessibilityStateImplWin::RefreshAssistiveTechIfNecessary(
|
||||
ui::AXMode new_mode) {
|
||||
bool was_screen_reader_active = ax_platform().IsScreenReaderActive();
|
||||
bool has_screen_reader_mode = new_mode.has_mode(ui::AXMode::kScreenReader);
|
||||
if (was_screen_reader_active != has_screen_reader_mode) {
|
||||
OnAssistiveTechFound(has_screen_reader_mode
|
||||
? ui::AssistiveTech::kGenericScreenReader
|
||||
: ui::AssistiveTech::kNone);
|
||||
return;
|
||||
}
|
||||
|
||||
// An expensive check is required to determine which type of assistive tech is
|
||||
// in use. Make this check only when `kExtendedProperties` is added or removed
|
||||
// from the process-wide mode flags and no previous assistive tech has been
|
||||
// discovered (in the former case) or one had been discovered (in the latter
|
||||
// case). `kScreenReader` will be added/removed from the process-wide mode
|
||||
// flags on completion and `OnAssistiveTechFound()` will be called with the
|
||||
// results of the check.
|
||||
bool has_extended_properties =
|
||||
new_mode.has_mode(ui::AXMode::kExtendedProperties);
|
||||
if (was_screen_reader_active != has_extended_properties) {
|
||||
// Perform expensive assistive tech detection.
|
||||
RefreshAssistiveTech();
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserAccessibilityStateImplWin::OnDiscoveredAssistiveTech(
|
||||
const std::vector<AssistiveTechInfo>& at_infos) {
|
||||
awaiting_known_assistive_tech_computation_ = false;
|
||||
@ -629,7 +660,21 @@ void BrowserAccessibilityStateImplWin::OnDiscoveredAssistiveTech(
|
||||
}
|
||||
}
|
||||
|
||||
// Save the current assistive tech before toggling AXModes, so
|
||||
// that RefreshAssistiveTechIfNecessary() is a noop.
|
||||
OnAssistiveTechFound(most_important_assistive_tech);
|
||||
|
||||
// Add kScreenReader mode flag for products with screen reader features, which
|
||||
// includes some magnifiers with light screen reader features (e.g.) heading
|
||||
// navigation).
|
||||
if (ui::IsScreenReader(most_important_assistive_tech)) {
|
||||
if (!screen_reader_mode_) {
|
||||
screen_reader_mode_ = CreateScopedModeForProcess(
|
||||
ui::kAXModeComplete | ui::AXMode::kScreenReader);
|
||||
}
|
||||
} else {
|
||||
screen_reader_mode_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
ui::AXPlatform::ProductStrings
|
||||
|
@ -316,8 +316,8 @@ void DumpAccessibilityTestBase::RunTest(
|
||||
const base::FilePath file_path,
|
||||
const char* file_dir,
|
||||
const base::FilePath::StringType& expectations_qualifier) {
|
||||
RunTestForPlatform(ui::kAXModeComplete | ui::AXMode::kHTML, file_path,
|
||||
file_dir, expectations_qualifier);
|
||||
RunTestForPlatform(ui::kAXModeDefaultForTests, file_path, file_dir,
|
||||
expectations_qualifier);
|
||||
}
|
||||
|
||||
// TODO(accessibility) Consider renaming these things to
|
||||
|
@ -626,14 +626,6 @@ void WebContentsAccessibilityAndroid::SetBrowserAXMode(
|
||||
jboolean is_complex_accessibility_service_enabled,
|
||||
jboolean is_form_controls_candidate,
|
||||
jboolean is_on_screen_mode_candidate) {
|
||||
BrowserAccessibilityStateImpl* accessibility_state =
|
||||
BrowserAccessibilityStateImpl::GetInstance();
|
||||
|
||||
auto* accessibility_state_android =
|
||||
static_cast<BrowserAccessibilityStateImplAndroid*>(accessibility_state);
|
||||
accessibility_state_android->SetScreenReaderAppActive(
|
||||
is_known_screen_reader_enabled);
|
||||
|
||||
// Set the AXMode based on currently running services, sent from Java-side
|
||||
// code, in the following priority:
|
||||
//
|
||||
@ -642,17 +634,15 @@ void WebContentsAccessibilityAndroid::SetBrowserAXMode(
|
||||
// mode must be the most complete mode possible (i.e. no performance
|
||||
// optimizations). (ui::kAXModeComplete)
|
||||
//
|
||||
// 2. When a known screen reader is running, use the complete mode.
|
||||
// (ui::kAXModeComplete)
|
||||
// 2. When a known screen reader is running, use
|
||||
// ui::kAXModeComplete | ui::AXMode::kAXModeScreenReader.
|
||||
// 2a. (Experimental) If a known screen reader is the only service
|
||||
// running, then this is a candidate to use the "on screen only"
|
||||
// experimental mode. (ui::kAXModeOnScreen)
|
||||
// experimental mode. (ui::kAXModeOnScreen | ui::kAXModeScreenReader)
|
||||
//
|
||||
// 3. When services are running that require detailed information according to
|
||||
// the Java-side code (i.e. a "complex" accessibility service), use the
|
||||
// complete mode. (ui::kAXModeComplete)
|
||||
// TODO(aleventahl): We should split this from the known screen reader case by
|
||||
// adding a mode specific to screen readers.
|
||||
//
|
||||
// 4. When the only services running are password managers, then this is a
|
||||
// candidate for filtering for only form controls. (ui::kAXModeFormControls)
|
||||
@ -668,16 +658,17 @@ void WebContentsAccessibilityAndroid::SetBrowserAXMode(
|
||||
// seconds before turning off accessibility, to account for quick toggling of
|
||||
// the state. Analysis of existing data could show whether the 5 second wait
|
||||
// is necessary.
|
||||
BrowserAccessibilityStateImpl* accessibility_state =
|
||||
BrowserAccessibilityStateImpl::GetInstance();
|
||||
ui::AXMode target_mode;
|
||||
if (!accessibility_state->IsPerformanceFilteringAllowed()) {
|
||||
target_mode = ui::kAXModeComplete;
|
||||
// Adds kScreenReader to ensure no filtering via the non-screen-reader case.
|
||||
target_mode = ui::kAXModeComplete | ui::AXMode::kScreenReader;
|
||||
} else if (is_known_screen_reader_enabled) {
|
||||
if (is_on_screen_mode_candidate) {
|
||||
target_mode = features::IsAccessibilityOnScreenAXModeEnabled()
|
||||
? ui::kAXModeOnScreen
|
||||
: ui::kAXModeComplete;
|
||||
} else {
|
||||
target_mode = ui::kAXModeComplete;
|
||||
target_mode = ui::kAXModeComplete | ui::AXMode::kScreenReader;
|
||||
if (is_on_screen_mode_candidate &&
|
||||
features::IsAccessibilityOnScreenAXModeEnabled()) {
|
||||
target_mode = ui::kAXModeOnScreen | ui::AXMode::kScreenReader;
|
||||
}
|
||||
} else if (is_complex_accessibility_service_enabled) {
|
||||
target_mode = ui::kAXModeComplete;
|
||||
@ -687,8 +678,10 @@ void WebContentsAccessibilityAndroid::SetBrowserAXMode(
|
||||
target_mode = ui::kAXModeBasic;
|
||||
}
|
||||
|
||||
scoped_accessibility_mode_ = accessibility_state->CreateScopedModeForProcess(
|
||||
target_mode | ui::AXMode::kFromPlatform);
|
||||
target_mode |= ui::AXMode::kFromPlatform;
|
||||
|
||||
scoped_accessibility_mode_ =
|
||||
accessibility_state->CreateScopedModeForProcess(target_mode);
|
||||
}
|
||||
|
||||
jboolean WebContentsAccessibilityAndroid::IsRootManagerConnected(JNIEnv* env) {
|
||||
@ -1773,6 +1766,9 @@ void WebContentsAccessibilityAndroid::RecordInlineTextBoxMetrics(
|
||||
ui::AXMode mode = accessibility_state->GetAccessibilityMode();
|
||||
|
||||
ui::AXMode::BundleHistogramValue bundle;
|
||||
// Clear out any modes that will confuse the bundle detection.
|
||||
mode &= ui::kAXModeComplete | ui::kAXModeFormControls;
|
||||
|
||||
if (mode == ui::kAXModeBasic) {
|
||||
bundle = ui::AXMode::BundleHistogramValue::kBasic;
|
||||
} else if (mode == ui::kAXModeWebContentsOnly) {
|
||||
|
@ -2495,7 +2495,7 @@ bool WebContentsImpl::IsWebContentsOnlyAccessibilityModeForTesting() {
|
||||
}
|
||||
|
||||
bool WebContentsImpl::IsFullAccessibilityModeForTesting() {
|
||||
return accessibility_mode_ == ui::kAXModeComplete;
|
||||
return accessibility_mode_ == ui::kAXModeDefaultForTests;
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
|
@ -103,7 +103,7 @@ public class AccessibilityContentShellActivityTestRule extends ContentShellActiv
|
||||
ThreadUtils.runOnUiThreadBlocking(
|
||||
() -> {
|
||||
AccessibilityState.setIsAnyAccessibilityServiceEnabledForTesting(true);
|
||||
AccessibilityState.setIsComplexUserInteractionServiceEnabledForTesting(true);
|
||||
AccessibilityState.setIsKnownScreenReaderEnabledForTesting(true);
|
||||
AccessibilityState.setStateMaskForTesting(EVENT_TYPE_MASK, EVENT_TYPE_MASK_ALL);
|
||||
});
|
||||
|
||||
|
@ -60,11 +60,6 @@ class CONTENT_EXPORT BrowserAccessibilityState {
|
||||
CreateScopedModeForWebContents(WebContents* web_contents,
|
||||
ui::AXMode mode) = 0;
|
||||
|
||||
// Some platforms have a strong signal indicating the presence of a
|
||||
// screen reader and can call in to let us know when one has
|
||||
// been enabled/disabled. This should be called for screen readers only.
|
||||
virtual void SetScreenReaderAppActive(bool is_active) = 0;
|
||||
|
||||
// Return the last active assistive technology. If multiple ATs are
|
||||
// running concurrently (rare case), the result will prefer a screen reader.
|
||||
// This will use the last known value, so it is possible for it to be out of
|
||||
|
@ -430,11 +430,10 @@ std::unique_ptr<content::ScopedAccessibilityMode> _scoped_accessibility_mode;
|
||||
if (UIAccessibilityIsVoiceOverRunning()) {
|
||||
_scoped_accessibility_mode =
|
||||
accessibility_state->CreateScopedModeForProcess(
|
||||
ui::kAXModeComplete | ui::AXMode::kFromPlatform);
|
||||
accessibility_state->SetScreenReaderAppActive(true);
|
||||
ui::kAXModeComplete | ui::AXMode::kFromPlatform |
|
||||
ui::AXMode::kScreenReader);
|
||||
} else {
|
||||
_scoped_accessibility_mode.reset();
|
||||
accessibility_state->SetScreenReaderAppActive(false);
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
@ -165,8 +165,8 @@ void AccessibilityController::Reset() {
|
||||
}
|
||||
|
||||
void AccessibilityController::Install(blink::WebLocalFrame* frame) {
|
||||
ax_context_ = std::make_unique<blink::WebAXContext>(frame->GetDocument(),
|
||||
ui::kAXModeComplete);
|
||||
ax_context_ = std::make_unique<blink::WebAXContext>(
|
||||
frame->GetDocument(), ui::kAXModeDefaultForTests);
|
||||
elements_ = std::make_unique<WebAXObjectProxyList>(
|
||||
frame->GetAgentGroupScheduler()->Isolate(), *ax_context_);
|
||||
|
||||
|
@ -129,14 +129,15 @@ class FuchsiaFrameAccessibilityTest : public WebEngineBrowserTest {
|
||||
|
||||
// Change the accessibility mode on the Fuchsia side and check that it is
|
||||
// propagated correctly.
|
||||
ASSERT_FALSE(frame_impl_->web_contents_for_test()
|
||||
->IsFullAccessibilityModeForTesting());
|
||||
ASSERT_TRUE(frame_impl_->web_contents_for_test()
|
||||
->GetAccessibilityMode()
|
||||
.is_mode_off());
|
||||
|
||||
semantics_manager_.SetSemanticsModeEnabled(true);
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
||||
ASSERT_TRUE(frame_impl_->web_contents_for_test()
|
||||
->IsFullAccessibilityModeForTesting());
|
||||
ASSERT_EQ(frame_impl_->web_contents_for_test()->GetAccessibilityMode(),
|
||||
ui::kAXModeComplete | ui::AXMode::kScreenReader);
|
||||
}
|
||||
|
||||
void TearDownOnMainThread() override {
|
||||
@ -411,16 +412,17 @@ IN_PROC_BROWSER_TEST_F(FuchsiaFrameAccessibilityTest, TogglesSemanticsUpdates) {
|
||||
semantics_manager_.SetSemanticsModeEnabled(false);
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
||||
EXPECT_FALSE(frame_impl_->web_contents_for_test()
|
||||
->IsFullAccessibilityModeForTesting());
|
||||
EXPECT_TRUE(frame_impl_->web_contents_for_test()
|
||||
->GetAccessibilityMode()
|
||||
.is_mode_off());
|
||||
|
||||
// The tree gets cleared when semantic updates are off.
|
||||
EXPECT_EQ(semantics_manager_.semantic_tree()->tree_size(), 0u);
|
||||
semantics_manager_.SetSemanticsModeEnabled(true);
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
||||
EXPECT_TRUE(frame_impl_->web_contents_for_test()
|
||||
->IsFullAccessibilityModeForTesting());
|
||||
EXPECT_EQ(frame_impl_->web_contents_for_test()->GetAccessibilityMode(),
|
||||
ui::kAXModeComplete | ui::AXMode::kScreenReader);
|
||||
}
|
||||
|
||||
// This test performs several tree modifications (insertions, changes, and
|
||||
|
@ -1651,10 +1651,12 @@ void FrameImpl::SetAccessibilityEnabled(bool enabled) {
|
||||
if (!enabled) {
|
||||
scoped_accessibility_mode_.reset();
|
||||
} else if (!scoped_accessibility_mode_) {
|
||||
// Fuchsia a11y only has one consumer, which is the Fuchsia screen reader.
|
||||
scoped_accessibility_mode_ =
|
||||
content::BrowserAccessibilityState::GetInstance()
|
||||
->CreateScopedModeForProcess(ui::kAXModeComplete |
|
||||
ui::AXMode::kFromPlatform);
|
||||
ui::AXMode::kFromPlatform |
|
||||
ui::AXMode::kScreenReader);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace blink {
|
||||
using ScopedBlinkAXEventIntentTest = RenderingTest;
|
||||
|
||||
TEST_F(ScopedBlinkAXEventIntentTest, SingleIntent) {
|
||||
AXContext ax_context(GetDocument(), ui::kAXModeComplete);
|
||||
AXContext ax_context(GetDocument(), ui::kAXModeDefaultForTests);
|
||||
AXObjectCache* cache = GetDocument().ExistingAXObjectCache();
|
||||
ASSERT_NE(nullptr, cache);
|
||||
|
||||
@ -39,7 +39,7 @@ TEST_F(ScopedBlinkAXEventIntentTest, SingleIntent) {
|
||||
}
|
||||
|
||||
TEST_F(ScopedBlinkAXEventIntentTest, MultipleIdenticalIntents) {
|
||||
AXContext ax_context(GetDocument(), ui::kAXModeComplete);
|
||||
AXContext ax_context(GetDocument(), ui::kAXModeDefaultForTests);
|
||||
AXObjectCache* cache = GetDocument().ExistingAXObjectCache();
|
||||
ASSERT_NE(nullptr, cache);
|
||||
|
||||
@ -64,7 +64,7 @@ TEST_F(ScopedBlinkAXEventIntentTest, MultipleIdenticalIntents) {
|
||||
}
|
||||
|
||||
TEST_F(ScopedBlinkAXEventIntentTest, NestedIndividualIntents) {
|
||||
AXContext ax_context(GetDocument(), ui::kAXModeComplete);
|
||||
AXContext ax_context(GetDocument(), ui::kAXModeDefaultForTests);
|
||||
AXObjectCache* cache = GetDocument().ExistingAXObjectCache();
|
||||
ASSERT_NE(nullptr, cache);
|
||||
|
||||
@ -102,7 +102,7 @@ TEST_F(ScopedBlinkAXEventIntentTest, NestedIndividualIntents) {
|
||||
}
|
||||
|
||||
TEST_F(ScopedBlinkAXEventIntentTest, NestedMultipleIntents) {
|
||||
AXContext ax_context(GetDocument(), ui::kAXModeComplete);
|
||||
AXContext ax_context(GetDocument(), ui::kAXModeDefaultForTests);
|
||||
AXObjectCache* cache = GetDocument().ExistingAXObjectCache();
|
||||
ASSERT_NE(nullptr, cache);
|
||||
|
||||
@ -156,7 +156,7 @@ TEST_F(ScopedBlinkAXEventIntentTest, NestedMultipleIntents) {
|
||||
}
|
||||
|
||||
TEST_F(ScopedBlinkAXEventIntentTest, NestedIdenticalIntents) {
|
||||
AXContext ax_context(GetDocument(), ui::kAXModeComplete);
|
||||
AXContext ax_context(GetDocument(), ui::kAXModeDefaultForTests);
|
||||
AXObjectCache* cache = GetDocument().ExistingAXObjectCache();
|
||||
ASSERT_NE(nullptr, cache);
|
||||
|
||||
|
@ -1832,7 +1832,7 @@ TEST_P(VisualViewportTest, AccessibilityHitTestWhileZoomedIn) {
|
||||
WebDocument web_doc = WebView()->MainFrameImpl()->GetDocument();
|
||||
LocalFrameView& frame_view = *WebView()->MainFrameImpl()->GetFrameView();
|
||||
|
||||
WebAXContext ax_context(web_doc, ui::kAXModeComplete);
|
||||
WebAXContext ax_context(web_doc, ui::kAXModeDefaultForTests);
|
||||
|
||||
WebView()->SetPageScaleFactor(2);
|
||||
WebView()->SetVisualViewportOffset(gfx::PointF(200, 230));
|
||||
|
@ -495,7 +495,7 @@ void InspectorOverlayAgent::EnsureAXContext(Node* node) {
|
||||
|
||||
void InspectorOverlayAgent::EnsureAXContext(Document& document) {
|
||||
if (!document_to_ax_context_.Contains(&document)) {
|
||||
auto context = std::make_unique<AXContext>(document, ui::kAXModeComplete);
|
||||
auto context = std::make_unique<AXContext>(document, ui::kAXModeInspector);
|
||||
document_to_ax_context_.Set(&document, std::move(context));
|
||||
}
|
||||
}
|
||||
|
@ -282,9 +282,7 @@ TEST_F(AccessibilitySelectionTest, SetSelectionInText) {
|
||||
TEST_F(AccessibilitySelectionTest, SetSelectionInMultilineTextarea) {
|
||||
// On Android we use an ifdef to disable inline text boxes.
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
ui::AXMode mode(ui::kAXModeComplete);
|
||||
mode.set_mode(ui::AXMode::kInlineTextBoxes, true);
|
||||
ax_context_->SetAXMode(mode);
|
||||
ax_context_->SetAXMode(ui::kAXModeDefaultForTests);
|
||||
GetAXObjectCache().MarkDocumentDirty();
|
||||
GetAXObjectCache().UpdateAXForAllDocuments();
|
||||
|
||||
|
@ -453,7 +453,7 @@ void InspectorAccessibilityAgent::CompleteQuery(
|
||||
continue;
|
||||
}
|
||||
ui::AXNodeData node_data;
|
||||
ax_object->Serialize(&node_data, ui::kAXModeComplete);
|
||||
ax_object->Serialize(&node_data, ui::kAXModeInspector);
|
||||
reachable.pop_back();
|
||||
const AXObject::AXObjectVector& children =
|
||||
ax_object->ChildrenIncludingIgnored();
|
||||
|
@ -925,7 +925,7 @@ std::unique_ptr<AXNode> BuildProtocolAXNodeForUnignoredAXObject(
|
||||
.build();
|
||||
auto properties = std::make_unique<protocol::Array<AXProperty>>();
|
||||
ui::AXNodeData node_data;
|
||||
ax_object.Serialize(&node_data, ui::kAXModeComplete);
|
||||
ax_object.Serialize(&node_data, ui::kAXModeInspector);
|
||||
node_object->setRole(CreateRoleNameValue(node_data.role));
|
||||
node_object->setChromeRole(CreateInternalRoleValue(node_data.role));
|
||||
FillLiveRegionProperties(ax_object, node_data, *(properties.get()));
|
||||
|
@ -21,7 +21,8 @@ AccessibilityTest::AccessibilityTest(LocalFrameClient* local_frame_client)
|
||||
|
||||
void AccessibilityTest::SetUp() {
|
||||
RenderingTest::SetUp();
|
||||
ax_context_ = std::make_unique<AXContext>(GetDocument(), ui::kAXModeComplete);
|
||||
ax_context_ =
|
||||
std::make_unique<AXContext>(GetDocument(), ui::kAXModeDefaultForTests);
|
||||
}
|
||||
|
||||
AXObjectCacheImpl& AccessibilityTest::GetAXObjectCache() const {
|
||||
|
@ -858,6 +858,7 @@ _CONFIG = [
|
||||
'ui::AXTreeUpdate',
|
||||
'ui::kAXModeBasic',
|
||||
'ui::kAXModeComplete',
|
||||
'ui::kAXModeInspector',
|
||||
'ui::kFirstGeneratedRendererNodeID',
|
||||
'ui::kInvalidAXNodeID',
|
||||
'ui::kLastGeneratedRendererNodeID',
|
||||
|
@ -105,7 +105,7 @@ uploading your change for review. These are checked by presubmit scripts.
|
||||
<int value="0" label="Native APIs"/>
|
||||
<int value="1" label="Web Contents"/>
|
||||
<int value="2" label="Inline Text Boxes"/>
|
||||
<int value="3" label="Screen Reader"/>
|
||||
<int value="3" label="Extended Properties"/>
|
||||
<int value="4" label="HTML"/>
|
||||
<int value="5" label="HTML Metadata"/>
|
||||
<int value="6" label="Label images"/>
|
||||
@ -113,6 +113,7 @@ uploading your change for review. These are checked by presubmit scripts.
|
||||
<int value="8" label="PDF OCR"/>
|
||||
<int value="9" label="Annotate Main Node"/>
|
||||
<int value="10" label="From Platform"/>
|
||||
<int value="11" label="Screen Reader"/>
|
||||
</enum>
|
||||
|
||||
<enum name="AccountManagerAccountAdditionSource">
|
||||
|
@ -66,6 +66,9 @@ std::string AXMode::ToString() const {
|
||||
case kFromPlatform:
|
||||
flag_name = "kFromPlatform";
|
||||
break;
|
||||
case AXMode::kScreenReader:
|
||||
flag_name = "kScreenReader";
|
||||
break;
|
||||
}
|
||||
|
||||
DCHECK(!flag_name.empty());
|
||||
|
@ -101,11 +101,16 @@ class AX_BASE_EXPORT AXMode {
|
||||
// interactions from accessibility tools.
|
||||
static constexpr uint32_t kFromPlatform = 1 << 10;
|
||||
|
||||
// The accessibility tree will contain content and properties only needed by
|
||||
// actual screen readers. This mode is only present when a known screen reader
|
||||
// is detected, e.g. ChromeVox, Talkback, JAWS, NVDA, Narrator, etc.
|
||||
static constexpr uint32_t kScreenReader = 1 << 11;
|
||||
|
||||
// Update this to include the last supported mode flag. If you add
|
||||
// another, be sure to update the stream insertion operator for
|
||||
// logging and debugging, as well as AccessibilityModeFlagEnum (and
|
||||
// related metrics callsites, see: |ModeFlagHistogramValue|).
|
||||
static constexpr uint32_t kLastModeFlag = 1 << 10;
|
||||
static constexpr uint32_t kLastModeFlag = 1 << 11;
|
||||
// LINT.ThenChange(//chrome/browser/metrics/accessibility_state_provider.cc,//chrome/browser/performance_manager/metrics/metrics_provider_common.cc,//chrome/browser/resources/accessibility/accessibility.ts,//tools/metrics/histograms/enums.xml,//ui/accessibility/ax_mode_histogram_logger.cc)
|
||||
|
||||
constexpr AXMode() : flags_(kNone), filter_flags_(kNone) {}
|
||||
@ -153,7 +158,7 @@ class AX_BASE_EXPORT AXMode {
|
||||
UMA_AX_MODE_NATIVE_APIS = 0,
|
||||
UMA_AX_MODE_WEB_CONTENTS = 1,
|
||||
UMA_AX_MODE_INLINE_TEXT_BOXES = 2,
|
||||
UMA_AX_MODE_SCREEN_READER = 3,
|
||||
UMA_AX_MODE_EXTENDED_PROPERTIES = 3,
|
||||
UMA_AX_MODE_HTML = 4,
|
||||
UMA_AX_MODE_HTML_METADATA = 5,
|
||||
UMA_AX_MODE_LABEL_IMAGES = 6,
|
||||
@ -161,6 +166,7 @@ class AX_BASE_EXPORT AXMode {
|
||||
UMA_AX_MODE_PDF_OCR = 8,
|
||||
UMA_AX_MODE_ANNOTATE_MAIN_NODE = 9,
|
||||
UMA_AX_MODE_FROM_PLATFORM = 10,
|
||||
UMA_AX_MODE_SCREEN_READER = 11,
|
||||
|
||||
// This must always be the last enum. It's okay for its value to
|
||||
// increase, but none of the other enum values may change.
|
||||
@ -246,6 +252,21 @@ inline constexpr AXMode kAXModeComplete(AXMode::kNativeAPIs |
|
||||
AXMode::kInlineTextBoxes |
|
||||
AXMode::kExtendedProperties);
|
||||
|
||||
// Used for DOM Inspector.
|
||||
// TODO(accessibility) Inspector should not need kInlineTextBoxes.
|
||||
inline constexpr AXMode kAXModeInspector(AXMode::kWebContents |
|
||||
AXMode::kInlineTextBoxes |
|
||||
AXMode::kExtendedProperties |
|
||||
AXMode::kScreenReader);
|
||||
|
||||
// The default for tests is to include kScreenReader mode, ensuring that the
|
||||
// entire tree is built, rather than the default for API consumers, which
|
||||
// assumes there is no screen reader present, enabling optimizations such as
|
||||
// removal of AXNodes that are not currently relevant.
|
||||
inline constexpr AXMode kAXModeDefaultForTests(
|
||||
AXMode::kNativeAPIs | AXMode::kWebContents | AXMode::kInlineTextBoxes |
|
||||
AXMode::kExtendedProperties | AXMode::kHTML | AXMode::kScreenReader);
|
||||
|
||||
// Used when tools that only need autofill functionality are present.
|
||||
inline constexpr AXMode kAXModeFormControls(AXMode::kNativeAPIs |
|
||||
AXMode::kWebContents,
|
||||
|
@ -55,8 +55,9 @@ void RecordAccessibilityModeHistograms(AXHistogramPrefix prefix,
|
||||
}
|
||||
|
||||
if (new_mode_flags & AXMode::kExtendedProperties) {
|
||||
RecordModeFlag(prefix,
|
||||
AXMode::ModeFlagHistogramValue::UMA_AX_MODE_SCREEN_READER);
|
||||
RecordModeFlag(
|
||||
prefix,
|
||||
AXMode::ModeFlagHistogramValue::UMA_AX_MODE_EXTENDED_PROPERTIES);
|
||||
}
|
||||
|
||||
if (new_mode_flags & AXMode::kHTML) {
|
||||
@ -85,6 +86,12 @@ void RecordAccessibilityModeHistograms(AXHistogramPrefix prefix,
|
||||
|
||||
// ui::AXMode::kFromPlatform is unconditionally filtered out and is
|
||||
// therefore never present in `mode`.
|
||||
CHECK(!mode.has_mode(ui::AXMode::kFromPlatform));
|
||||
|
||||
if (new_mode_flags & AXMode::kScreenReader) {
|
||||
RecordModeFlag(prefix,
|
||||
AXMode::ModeFlagHistogramValue::UMA_AX_MODE_SCREEN_READER);
|
||||
}
|
||||
}
|
||||
|
||||
// Record forms control flag transitioning from unset to set.
|
||||
|
@ -925,6 +925,10 @@ void AXTree::Destroy() {
|
||||
if (!root_)
|
||||
return;
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
is_destroyed_ = true;
|
||||
#endif
|
||||
|
||||
std::set<AXNodeID> deleting_node_ids;
|
||||
RecursivelyNotifyNodeWillBeDeletedForTreeTeardown(*root_, deleting_node_ids);
|
||||
|
||||
@ -1178,6 +1182,13 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
|
||||
}
|
||||
#endif // AX_FAIL_FAST_BUILD()
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
++unserialize_count_;
|
||||
DCHECK(!is_destroyed_) << "Attempt to unserialize on a destroyed tree: #"
|
||||
<< unserialize_count_ << " on "
|
||||
<< update.ToString(true).substr(0, 1000);
|
||||
#endif
|
||||
|
||||
event_data_ = std::make_unique<AXEvent>();
|
||||
event_data_->event_from = update.event_from;
|
||||
event_data_->event_from_action = update.event_from_action;
|
||||
@ -1187,11 +1198,17 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
|
||||
AXTreeUpdateState update_state(*this, update);
|
||||
const AXNodeID old_root_id = root_ ? root_->id() : kInvalidAXNodeID;
|
||||
if (old_root_id == kInvalidAXNodeID && update.root_id == kInvalidAXNodeID) {
|
||||
#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
|
||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
|
||||
return false;
|
||||
#elif DCHECK_IS_ON()
|
||||
DCHECK(false)
|
||||
<< "Tree must have already a valid root or update must have a "
|
||||
"valid root: update #"
|
||||
<< unserialize_count_ << " with update:\n"
|
||||
<< update.ToString(true).substr(0, 1000);
|
||||
#else
|
||||
NOTREACHED() << "Tree must have already a valid root or update must have a "
|
||||
"valid root.";
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
// Accumulates the work that will be required to update the AXTree.
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "base/dcheck_is_on.h"
|
||||
#include "base/debug/crash_logging.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/observer_list.h"
|
||||
@ -542,6 +543,11 @@ class AX_EXPORT AXTree {
|
||||
// Indicates if the tree represents a paginated document
|
||||
bool has_pagination_support_ = false;
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
bool is_destroyed_ = false;
|
||||
int unserialize_count_ = 0;
|
||||
#endif
|
||||
|
||||
std::unique_ptr<AXEvent> event_data_;
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
|
@ -14,8 +14,6 @@ bool IsScreenReader(AssistiveTech assistive_tech) {
|
||||
// the most appropriate for most call sites.
|
||||
case AssistiveTech::kUnknown:
|
||||
case AssistiveTech::kNone:
|
||||
// ZoomText is a screen magnifier.
|
||||
case AssistiveTech::kZoomText:
|
||||
return false;
|
||||
case AssistiveTech::kChromeVox:
|
||||
case AssistiveTech::kJaws:
|
||||
@ -26,6 +24,9 @@ bool IsScreenReader(AssistiveTech assistive_tech) {
|
||||
case AssistiveTech::kTalkback:
|
||||
case AssistiveTech::kVoiceOver:
|
||||
case AssistiveTech::kZdsr:
|
||||
// ZoomText is a screen magnifier with some screen reader features, such
|
||||
// as the ability to navigate by heading.
|
||||
case AssistiveTech::kZoomText:
|
||||
case AssistiveTech::kGenericScreenReader:
|
||||
return true;
|
||||
}
|
||||
|
@ -1062,6 +1062,12 @@ void AutomationTreeManagerOwner::DispatchAccessibilityEvents(
|
||||
if (is_new_tree) {
|
||||
tree_wrapper = new AutomationAXTreeWrapper(this);
|
||||
CacheAutomationTreeWrapperForTreeID(tree_id, tree_wrapper);
|
||||
// A new tree requires at least a root node. This is similar to early
|
||||
// return logic in RenderFrameHostImpl::UpdateAXTreeData() for the case
|
||||
// where needs_ax_root_id_ is true.
|
||||
if (updates.size() == 1 && updates[0].nodes.empty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tree_wrapper->OnAccessibilityEvents(tree_id, updates, events,
|
||||
|
Reference in New Issue
Block a user