blob: 8c876758b3e0b287642dbc0328e2a8e0bba0b9fa [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
#include <windows.h> // Must be in front of other Windows header files.
#include <psapi.h>
#include <stddef.h>
#include <memory>
#include "base/files/file_path.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "ui/accessibility/platform/ax_platform_node_win.h"
namespace content {
namespace {
// Enables accessibility based on three possible clues that indicate
// accessibility API usage.
//
// TODO(dmazzoni): Rename IAccessible2UsageObserver to something more general.
class WindowsAccessibilityEnabler : public ui::IAccessible2UsageObserver {
public:
WindowsAccessibilityEnabler() {}
private:
// IAccessible2UsageObserver
void OnIAccessible2Used() override {
// When IAccessible2 APIs have been used elsewhere in the codebase,
// enable basic web accessibility support. (Full screen reader support is
// detected later when specific more advanced APIs are accessed.)
BrowserAccessibilityStateImpl::GetInstance()->AddAccessibilityModeFlags(
ui::AXMode::kNativeAPIs | ui::AXMode::kWebContents);
}
void OnScreenReaderHoneyPotQueried() override {
// We used to trust this as a signal that a screen reader is running,
// but it's been abused. Now only enable accessibility if we also
// detect a call to get_accName.
if (screen_reader_honeypot_queried_)
return;
screen_reader_honeypot_queried_ = true;
if (acc_name_called_) {
BrowserAccessibilityStateImpl::GetInstance()->AddAccessibilityModeFlags(
ui::AXMode::kNativeAPIs | ui::AXMode::kWebContents);
}
}
void OnAccNameCalled() override {
// See OnScreenReaderHoneyPotQueried, above.
if (acc_name_called_)
return;
acc_name_called_ = true;
if (screen_reader_honeypot_queried_) {
BrowserAccessibilityStateImpl::GetInstance()->AddAccessibilityModeFlags(
ui::AXMode::kNativeAPIs | ui::AXMode::kWebContents);
}
}
bool screen_reader_honeypot_queried_ = false;
bool acc_name_called_ = false;
};
} // namespace
void BrowserAccessibilityStateImpl::PlatformInitialize() {
ui::GetIAccessible2UsageObserverList().AddObserver(
new WindowsAccessibilityEnabler());
}
void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() {
// NOTE: this method is run from the file thread to reduce jank, since
// there's no guarantee these system calls will return quickly. Be careful
// not to add any code that isn't safe to run from a non-main thread!
AUDIODESCRIPTION audio_description = {0};
audio_description.cbSize = sizeof(AUDIODESCRIPTION);
SystemParametersInfo(SPI_GETAUDIODESCRIPTION, 0, &audio_description, 0);
UMA_HISTOGRAM_BOOLEAN("Accessibility.WinAudioDescription",
!!audio_description.Enabled);
BOOL win_screen_reader = FALSE;
SystemParametersInfo(SPI_GETSCREENREADER, 0, &win_screen_reader, 0);
UMA_HISTOGRAM_BOOLEAN("Accessibility.WinScreenReader",
!!win_screen_reader);
STICKYKEYS sticky_keys = {0};
sticky_keys.cbSize = sizeof(STICKYKEYS);
SystemParametersInfo(SPI_GETSTICKYKEYS, 0, &sticky_keys, 0);
UMA_HISTOGRAM_BOOLEAN("Accessibility.WinStickyKeys",
0 != (sticky_keys.dwFlags & SKF_STICKYKEYSON));
// We only measure systems where SPI_GETCLIENTAREAANIMATION exists.
BOOL win_anim_enabled = TRUE;
if (SystemParametersInfo(SPI_GETCLIENTAREAANIMATION, 0, &win_anim_enabled,
0)) {
UMA_HISTOGRAM_BOOLEAN("Accessibility.Win.AnimationsEnabled",
win_anim_enabled);
}
// Get the file paths of all DLLs loaded.
HANDLE process = GetCurrentProcess();
HMODULE* modules = NULL;
DWORD bytes_required;
if (!EnumProcessModules(process, modules, 0, &bytes_required))
return;
std::unique_ptr<char[]> buffer(new char[bytes_required]);
modules = reinterpret_cast<HMODULE*>(buffer.get());
DWORD ignore;
if (!EnumProcessModules(process, modules, bytes_required, &ignore))
return;
// Look for DLLs of assistive technology known to work with Chrome.
bool jaws = false;
bool nvda = false;
bool satogo = false;
bool zoomtext = false;
size_t module_count = bytes_required / sizeof(HMODULE);
for (size_t i = 0; i < module_count; i++) {
TCHAR filename[MAX_PATH];
GetModuleFileName(modules[i], filename, base::size(filename));
base::string16 module_name(base::FilePath(filename).BaseName().value());
if (base::LowerCaseEqualsASCII(module_name, "fsdomsrv.dll"))
jaws = true;
if (base::LowerCaseEqualsASCII(module_name, "vbufbackend_gecko_ia2.dll"))
nvda = true;
if (base::LowerCaseEqualsASCII(module_name, "stsaw32.dll"))
satogo = true;
if (base::LowerCaseEqualsASCII(module_name, "zslhook.dll"))
zoomtext = true;
}
UMA_HISTOGRAM_BOOLEAN("Accessibility.WinJAWS", jaws);
UMA_HISTOGRAM_BOOLEAN("Accessibility.WinNVDA", nvda);
UMA_HISTOGRAM_BOOLEAN("Accessibility.WinSAToGo", satogo);
UMA_HISTOGRAM_BOOLEAN("Accessibility.WinZoomText", zoomtext);
}
} // namespace content