mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Implement accessibility enhancements (issue #1217)
- Add new CefBrowserHost::SetAccessibilityState method for toggling accessibility state when readers are detected by the client. - Add new CefAccessibilityHandler interface for the delivery of accessibility notifications to windowless (OSR) clients. - Fix delivery of CefFocusHandler callbacks to windowless clients. - cefclient: Add example windowless accessibility implementation on Windows and macOS. - cefclient: Automatically detect screen readers on Windows and macOS.
This commit is contained in:
committed by
Marshall Greenblatt
parent
64fcfa6068
commit
816f700d3e
@@ -46,6 +46,7 @@
|
||||
#include "components/zoom/zoom_controller.h"
|
||||
#include "content/browser/renderer_host/render_view_host_impl.h"
|
||||
#include "content/browser/gpu/compositor_util.h"
|
||||
#include "content/browser/web_contents/web_contents_impl.h"
|
||||
#include "content/common/view_messages.h"
|
||||
#include "content/public/browser/desktop_media_id.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
@@ -930,6 +931,39 @@ CefRefPtr<CefNavigationEntry> CefBrowserHostImpl::GetVisibleNavigationEntry() {
|
||||
return new CefNavigationEntryImpl(entry);
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::SetAccessibilityState(
|
||||
cef_state_t accessibility_state) {
|
||||
// Do nothing if state is set to default. It'll be disabled by default and
|
||||
// controlled by the commmand-line flags "force-renderer-accessibility" and
|
||||
// "disable-renderer-accessibility".
|
||||
if (accessibility_state == STATE_DEFAULT)
|
||||
return;
|
||||
|
||||
if (!CEF_CURRENTLY_ON_UIT()) {
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::Bind(&CefBrowserHostImpl::SetAccessibilityState,
|
||||
this, accessibility_state));
|
||||
return;
|
||||
}
|
||||
|
||||
content::WebContentsImpl* web_contents_impl =
|
||||
static_cast<content::WebContentsImpl*>(web_contents());
|
||||
|
||||
if (!web_contents_impl)
|
||||
return;
|
||||
|
||||
content::AccessibilityMode accMode;
|
||||
// In windowless mode set accessibility to TreeOnly mode. Else native
|
||||
// accessibility APIs, specific to each platform, are also created.
|
||||
if (accessibility_state == STATE_ENABLED) {
|
||||
if (IsWindowless())
|
||||
accMode = content::kAccessibilityModeWebContentsOnly;
|
||||
else
|
||||
accMode = content::kAccessibilityModeComplete;
|
||||
}
|
||||
web_contents_impl->SetAccessibilityMode(accMode);
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::SetMouseCursorChangeDisabled(bool disabled) {
|
||||
base::AutoLock lock_scope(state_lock_);
|
||||
mouse_cursor_change_disabled_ = disabled;
|
||||
@@ -2690,6 +2724,28 @@ bool CefBrowserHostImpl::OnMessageReceived(const IPC::Message& message) {
|
||||
return handled;
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::AccessibilityEventReceived(
|
||||
const std::vector<content::AXEventNotificationDetails>& eventData) {
|
||||
// Only needed in windowless mode.
|
||||
if (IsWindowless()) {
|
||||
if (!web_contents() || !platform_delegate_)
|
||||
return;
|
||||
|
||||
platform_delegate_->AccessibilityEventReceived(eventData);
|
||||
}
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::AccessibilityLocationChangesReceived(
|
||||
const std::vector<content::AXLocationChangeNotificationDetails>& locData) {
|
||||
// Only needed in windowless mode.
|
||||
if (IsWindowless()) {
|
||||
if (!web_contents() || !platform_delegate_)
|
||||
return;
|
||||
|
||||
platform_delegate_->AccessibilityLocationChangesReceived(locData);
|
||||
}
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::OnWebContentsFocused() {
|
||||
if (client_.get()) {
|
||||
CefRefPtr<CefFocusHandler> handler = client_->GetFocusHandler();
|
||||
|
@@ -229,6 +229,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
||||
void DragSourceSystemDragEnded() override;
|
||||
void DragSourceEndedAt(int x, int y, DragOperationsMask op) override;
|
||||
CefRefPtr<CefNavigationEntry> GetVisibleNavigationEntry() override;
|
||||
void SetAccessibilityState(cef_state_t accessibility_state) override;
|
||||
|
||||
// CefBrowser methods.
|
||||
CefRefPtr<CefBrowserHost> GetHost() override;
|
||||
@@ -471,6 +472,13 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
||||
void DidUpdateFaviconURL(
|
||||
const std::vector<content::FaviconURL>& candidates) override;
|
||||
bool OnMessageReceived(const IPC::Message& message) override;
|
||||
void AccessibilityEventReceived(
|
||||
const std::vector<content::AXEventNotificationDetails>& eventData)
|
||||
override;
|
||||
void AccessibilityLocationChangesReceived(
|
||||
const std::vector<content::AXLocationChangeNotificationDetails>& locData)
|
||||
override;
|
||||
|
||||
void OnWebContentsFocused() override;
|
||||
// Override to provide a thread safe implementation.
|
||||
bool Send(IPC::Message* message) override;
|
||||
|
@@ -202,6 +202,16 @@ void CefBrowserPlatformDelegate::DragSourceSystemDragEnded() {
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
void CefBrowserPlatformDelegate::AccessibilityEventReceived(
|
||||
const std::vector<content::AXEventNotificationDetails>& eventData) {
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
void CefBrowserPlatformDelegate::AccessibilityLocationChangesReceived(
|
||||
const std::vector<content::AXLocationChangeNotificationDetails>& locData) {
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
// static
|
||||
int CefBrowserPlatformDelegate::TranslateModifiers(uint32 cef_modifiers) {
|
||||
int webkit_modifiers = 0;
|
||||
|
@@ -262,6 +262,10 @@ class CefBrowserPlatformDelegate {
|
||||
virtual void DragSourceEndedAt(int x, int y,
|
||||
cef_drag_operations_mask_t op);
|
||||
virtual void DragSourceSystemDragEnded();
|
||||
virtual void AccessibilityEventReceived(
|
||||
const std::vector<content::AXEventNotificationDetails>& eventData);
|
||||
virtual void AccessibilityLocationChangesReceived(
|
||||
const std::vector<content::AXLocationChangeNotificationDetails>& locData);
|
||||
|
||||
protected:
|
||||
// Allow deletion via scoped_ptr only.
|
||||
|
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "libcef/browser/browser_host_impl.h"
|
||||
#include "libcef/browser/image_impl.h"
|
||||
#include "libcef/browser/osr/osr_accessibility_util.h"
|
||||
#include "libcef/browser/osr/render_widget_host_view_osr.h"
|
||||
#include "libcef/browser/osr/web_contents_view_osr.h"
|
||||
#include "libcef/common/drag_data_impl.h"
|
||||
@@ -522,6 +523,34 @@ void CefBrowserPlatformDelegateOsr::DragSourceSystemDragEnded() {
|
||||
drag_start_rwh_ = nullptr;
|
||||
}
|
||||
|
||||
void CefBrowserPlatformDelegateOsr::AccessibilityEventReceived(
|
||||
const std::vector<content::AXEventNotificationDetails>& eventData) {
|
||||
CefRefPtr<CefRenderHandler> handler = browser_->client()->GetRenderHandler();
|
||||
if (handler.get()) {
|
||||
CefRefPtr<CefAccessibilityHandler> acchandler =
|
||||
handler->GetAccessibilityHandler();
|
||||
|
||||
if (acchandler.get()) {
|
||||
acchandler->OnAccessibilityTreeChange(
|
||||
osr_accessibility_util::ParseAccessibilityEventData(eventData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CefBrowserPlatformDelegateOsr::AccessibilityLocationChangesReceived(
|
||||
const std::vector<content::AXLocationChangeNotificationDetails>& locData) {
|
||||
CefRefPtr<CefRenderHandler> handler = browser_->client()->GetRenderHandler();
|
||||
if (handler.get()) {
|
||||
CefRefPtr<CefAccessibilityHandler> acchandler =
|
||||
handler->GetAccessibilityHandler();
|
||||
|
||||
if (acchandler.get()) {
|
||||
acchandler->OnAccessibilityLocationChange(
|
||||
osr_accessibility_util::ParseAccessibilityLocationData(locData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CefWindowHandle CefBrowserPlatformDelegateOsr::GetParentWindowHandle() const {
|
||||
return GetHostWindowHandle();
|
||||
}
|
||||
|
@@ -88,6 +88,12 @@ class CefBrowserPlatformDelegateOsr :
|
||||
void DragSourceEndedAt(int x, int y,
|
||||
cef_drag_operations_mask_t op) override;
|
||||
void DragSourceSystemDragEnded() override;
|
||||
void AccessibilityEventReceived(
|
||||
const std::vector<content::AXEventNotificationDetails>& eventData)
|
||||
override;
|
||||
void AccessibilityLocationChangesReceived(
|
||||
const std::vector<content::AXLocationChangeNotificationDetails>& locData)
|
||||
override;
|
||||
|
||||
// CefBrowserPlatformDelegateNative::WindowlessHandler methods:
|
||||
CefWindowHandle GetParentWindowHandle() const override;
|
||||
|
457
libcef/browser/osr/osr_accessibility_util.cc
Normal file
457
libcef/browser/osr/osr_accessibility_util.cc
Normal file
@@ -0,0 +1,457 @@
|
||||
// Copyright 2017 The Chromium Embedded Framework 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 "libcef/browser/osr/osr_accessibility_util.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/json/string_escape.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "content/public/browser/ax_event_notification_details.h"
|
||||
#include "ui/accessibility/ax_tree_update.h"
|
||||
#include "ui/accessibility/ax_text_utils.h"
|
||||
#include "ui/gfx/transform.h"
|
||||
|
||||
namespace {
|
||||
using ui::ToString;
|
||||
|
||||
template<typename T>
|
||||
CefRefPtr<CefListValue> ToCefValue(const std::vector<T>& vecData);
|
||||
|
||||
template<>
|
||||
CefRefPtr<CefListValue> ToCefValue<int>(const std::vector<int>& vecData) {
|
||||
CefRefPtr<CefListValue> value = CefListValue::Create();
|
||||
for (size_t i = 0; i <vecData.size(); i ++)
|
||||
value->SetInt(i, vecData[i]);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Helper function for AXNodeData::ToCefValue - Converts AXState attributes to
|
||||
// CefListValue.
|
||||
CefRefPtr<CefListValue> ToCefValue(uint32_t state) {
|
||||
CefRefPtr<CefListValue> value = CefListValue::Create();
|
||||
|
||||
static ui::AXState state_arr[] = {
|
||||
ui::AX_STATE_NONE,
|
||||
ui::AX_STATE_BUSY,
|
||||
ui::AX_STATE_CHECKED,
|
||||
ui::AX_STATE_COLLAPSED,
|
||||
ui::AX_STATE_DEFAULT,
|
||||
ui::AX_STATE_DISABLED,
|
||||
ui::AX_STATE_EDITABLE,
|
||||
ui::AX_STATE_EXPANDED,
|
||||
ui::AX_STATE_FOCUSABLE,
|
||||
ui::AX_STATE_HASPOPUP,
|
||||
ui::AX_STATE_HORIZONTAL,
|
||||
ui::AX_STATE_HOVERED,
|
||||
ui::AX_STATE_INVISIBLE,
|
||||
ui::AX_STATE_LINKED,
|
||||
ui::AX_STATE_MULTILINE,
|
||||
ui::AX_STATE_MULTISELECTABLE,
|
||||
ui::AX_STATE_OFFSCREEN,
|
||||
ui::AX_STATE_PRESSED,
|
||||
ui::AX_STATE_PROTECTED,
|
||||
ui::AX_STATE_READ_ONLY,
|
||||
ui::AX_STATE_REQUIRED,
|
||||
ui::AX_STATE_RICHLY_EDITABLE,
|
||||
ui::AX_STATE_SELECTABLE,
|
||||
ui::AX_STATE_SELECTED,
|
||||
ui::AX_STATE_VERTICAL,
|
||||
ui::AX_STATE_VISITED,
|
||||
ui::AX_STATE_LAST
|
||||
};
|
||||
|
||||
int index = 0;
|
||||
// Iterate and find which states are set.
|
||||
for (unsigned i = 0; i < arraysize(state_arr); i++) {
|
||||
if (state & (1 << state_arr[i]))
|
||||
value->SetString(index++, ToString(state_arr[i]));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Helper function for AXNodeData::ToCefValue - converts GfxRect to
|
||||
// CefDictionaryValue.
|
||||
CefRefPtr<CefDictionaryValue> ToCefValue(const gfx::RectF& bounds) {
|
||||
CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
|
||||
value->SetDouble("x", bounds.x());
|
||||
value->SetDouble("y", bounds.y());
|
||||
value->SetDouble("width", bounds.width());
|
||||
value->SetDouble("height", bounds.height());
|
||||
return value;
|
||||
}
|
||||
|
||||
// Helper Functor for adding AxNodeData::attributes to AXNodeData::ToCefValue.
|
||||
struct PopulateAxNodeAttributes {
|
||||
CefRefPtr<CefDictionaryValue> attributes;
|
||||
|
||||
explicit PopulateAxNodeAttributes(CefRefPtr<CefDictionaryValue> attrs) :
|
||||
attributes(attrs) {}
|
||||
|
||||
// Int Attributes
|
||||
void operator()(const std::pair<ui::AXIntAttribute, int32_t> attr) {
|
||||
if (attr.first == ui::AX_INT_ATTRIBUTE_NONE)
|
||||
return;
|
||||
|
||||
switch (attr.first) {
|
||||
case ui::AX_INT_ATTRIBUTE_NONE:
|
||||
break;
|
||||
case ui::AX_ATTR_SCROLL_X:
|
||||
case ui::AX_ATTR_SCROLL_X_MIN:
|
||||
case ui::AX_ATTR_SCROLL_X_MAX:
|
||||
case ui::AX_ATTR_SCROLL_Y:
|
||||
case ui::AX_ATTR_SCROLL_Y_MIN:
|
||||
case ui::AX_ATTR_SCROLL_Y_MAX:
|
||||
case ui::AX_ATTR_HIERARCHICAL_LEVEL:
|
||||
case ui::AX_ATTR_TEXT_SEL_START:
|
||||
case ui::AX_ATTR_TEXT_SEL_END:
|
||||
case ui::AX_ATTR_ARIA_COL_COUNT:
|
||||
case ui::AX_ATTR_ARIA_COL_INDEX:
|
||||
case ui::AX_ATTR_ARIA_ROW_COUNT:
|
||||
case ui::AX_ATTR_ARIA_ROW_INDEX:
|
||||
case ui::AX_ATTR_TABLE_ROW_COUNT:
|
||||
case ui::AX_ATTR_TABLE_COLUMN_COUNT:
|
||||
case ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX:
|
||||
case ui::AX_ATTR_TABLE_CELL_ROW_INDEX:
|
||||
case ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN:
|
||||
case ui::AX_ATTR_TABLE_CELL_ROW_SPAN:
|
||||
case ui::AX_ATTR_TABLE_COLUMN_HEADER_ID:
|
||||
case ui::AX_ATTR_TABLE_COLUMN_INDEX:
|
||||
case ui::AX_ATTR_TABLE_HEADER_ID:
|
||||
case ui::AX_ATTR_TABLE_ROW_HEADER_ID:
|
||||
case ui::AX_ATTR_TABLE_ROW_INDEX:
|
||||
case ui::AX_ATTR_ACTIVEDESCENDANT_ID:
|
||||
case ui::AX_ATTR_IN_PAGE_LINK_TARGET_ID:
|
||||
case ui::AX_ATTR_ERRORMESSAGE_ID:
|
||||
case ui::AX_ATTR_MEMBER_OF_ID:
|
||||
case ui::AX_ATTR_NEXT_ON_LINE_ID:
|
||||
case ui::AX_ATTR_PREVIOUS_ON_LINE_ID:
|
||||
case ui::AX_ATTR_CHILD_TREE_ID:
|
||||
case ui::AX_ATTR_SET_SIZE:
|
||||
case ui::AX_ATTR_POS_IN_SET:
|
||||
attributes->SetInt(ToString(attr.first), attr.second);
|
||||
break;
|
||||
case ui::AX_ATTR_ACTION:
|
||||
attributes->SetString(ToString(attr.first),
|
||||
ui::ActionToUnlocalizedString(
|
||||
static_cast<ui::AXSupportedAction>(attr.second)));
|
||||
break;
|
||||
case ui::AX_ATTR_INVALID_STATE:
|
||||
if (ui::AX_INVALID_STATE_NONE != attr.second) {
|
||||
attributes->SetString(ToString(attr.first), ToString(
|
||||
static_cast<ui::AXInvalidState>(attr.second)));
|
||||
}
|
||||
break;
|
||||
case ui::AX_ATTR_SORT_DIRECTION:
|
||||
if (ui::AX_SORT_DIRECTION_NONE != attr.second) {
|
||||
attributes->SetString(ToString(attr.first), ToString(
|
||||
static_cast<ui::AXSortDirection>(attr.second)));
|
||||
}
|
||||
break;
|
||||
case ui::AX_ATTR_NAME_FROM:
|
||||
attributes->SetString(ToString(attr.first), ToString(
|
||||
static_cast<ui::AXNameFrom>(attr.second)));
|
||||
break;
|
||||
case ui::AX_ATTR_COLOR_VALUE:
|
||||
case ui::AX_ATTR_BACKGROUND_COLOR:
|
||||
case ui::AX_ATTR_COLOR:
|
||||
attributes->SetString(ToString(attr.first),
|
||||
base::StringPrintf("0x%X", attr.second));
|
||||
break;
|
||||
case ui::AX_ATTR_DESCRIPTION_FROM:
|
||||
attributes->SetString(ToString(attr.first), ToString(
|
||||
static_cast<ui::AXDescriptionFrom>(attr.second)));
|
||||
break;
|
||||
case ui::AX_ATTR_ARIA_CURRENT_STATE:
|
||||
if (ui::AX_ARIA_CURRENT_STATE_NONE != attr.second) {
|
||||
attributes->SetString(ToString(attr.first), ToString(
|
||||
static_cast<ui::AXAriaCurrentState>(attr.second)));
|
||||
}
|
||||
break;
|
||||
case ui::AX_ATTR_TEXT_DIRECTION:
|
||||
if (ui::AX_TEXT_DIRECTION_NONE != attr.second) {
|
||||
attributes->SetString(ToString(attr.first), ToString(
|
||||
static_cast<ui::AXTextDirection>(attr.second)));
|
||||
}
|
||||
break;
|
||||
case ui::AX_ATTR_TEXT_STYLE: {
|
||||
auto text_style = static_cast<ui::AXTextStyle>(attr.second);
|
||||
if (text_style == ui::AX_TEXT_STYLE_NONE)
|
||||
break;
|
||||
|
||||
static ui::AXTextStyle textStyleArr[] = {
|
||||
ui::AX_TEXT_STYLE_BOLD,
|
||||
ui::AX_TEXT_STYLE_ITALIC,
|
||||
ui::AX_TEXT_STYLE_UNDERLINE,
|
||||
ui::AX_TEXT_STYLE_LINE_THROUGH
|
||||
};
|
||||
|
||||
CefRefPtr<CefListValue> list = CefListValue::Create();
|
||||
int index = 0;
|
||||
// Iterate and find which states are set.
|
||||
for (unsigned i = 0; i < arraysize(textStyleArr); i++) {
|
||||
if (text_style & textStyleArr[i])
|
||||
list->SetString(index++, ToString(textStyleArr[i]));
|
||||
}
|
||||
attributes->SetList(ToString(attr.first), list);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set Bool Attributes.
|
||||
void operator()(const std::pair<ui::AXBoolAttribute, bool> attr) {
|
||||
if (attr.first != ui::AX_BOOL_ATTRIBUTE_NONE)
|
||||
attributes->SetBool(ToString(attr.first), attr.second);
|
||||
}
|
||||
// Set String Attributes.
|
||||
void operator()(const std::pair<ui::AXStringAttribute, std::string>& attr) {
|
||||
if (attr.first != ui::AX_STRING_ATTRIBUTE_NONE)
|
||||
attributes->SetString(ToString(attr.first), attr.second);
|
||||
}
|
||||
// Set Float attributes.
|
||||
void operator()(const std::pair<ui::AXFloatAttribute, float>& attr) {
|
||||
if (attr.first != ui::AX_FLOAT_ATTRIBUTE_NONE)
|
||||
attributes->SetDouble(ToString(attr.first), attr.second);
|
||||
}
|
||||
|
||||
// Set Int list attributes.
|
||||
void operator()(const std::pair<ui::AXIntListAttribute,
|
||||
std::vector<int32_t>>& attr) {
|
||||
if (attr.first != ui::AX_INT_LIST_ATTRIBUTE_NONE) {
|
||||
CefRefPtr<CefListValue> list;
|
||||
|
||||
if (ui::AX_ATTR_MARKER_TYPES == attr.first) {
|
||||
list = CefListValue::Create();
|
||||
int index = 0;
|
||||
for (size_t i = 0; i < attr.second.size(); ++i) {
|
||||
auto type = static_cast<ui::AXMarkerType>(attr.second[i]);
|
||||
|
||||
if (type == ui::AX_MARKER_TYPE_NONE)
|
||||
continue;
|
||||
|
||||
static ui::AXMarkerType marktypeArr[] = {
|
||||
ui::AX_MARKER_TYPE_SPELLING,
|
||||
ui::AX_MARKER_TYPE_GRAMMAR,
|
||||
ui::AX_MARKER_TYPE_TEXT_MATCH
|
||||
};
|
||||
|
||||
// Iterate and find which markers are set.
|
||||
for (unsigned j = 0; j < arraysize(marktypeArr); j++) {
|
||||
if (type & marktypeArr[j])
|
||||
list->SetString(index++, ToString(marktypeArr[j]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
list = ToCefValue(attr.second);
|
||||
}
|
||||
attributes->SetList(ToString(attr.first), list);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Converts AXNodeData to CefDictionaryValue(like AXNodeData::ToString).
|
||||
CefRefPtr<CefDictionaryValue> ToCefValue(const ui::AXNodeData& node) {
|
||||
CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
|
||||
|
||||
if (node.id != -1)
|
||||
value->SetInt("id", node.id);
|
||||
|
||||
value->SetString("role", ToString(node.role));
|
||||
value->SetList("state", ToCefValue(node.state));
|
||||
|
||||
if (node.offset_container_id != -1)
|
||||
value->SetInt("offset_container_id", node.offset_container_id);
|
||||
|
||||
value->SetDictionary("location", ToCefValue(node.location));
|
||||
|
||||
// Transform matrix is private, so we set the string that Clients can parse
|
||||
// and use if needed.
|
||||
if (node.transform && !node.transform->IsIdentity())
|
||||
value->SetString("transform", node.transform->ToString());
|
||||
|
||||
if (!node.child_ids.empty())
|
||||
value->SetList("child_ids", ToCefValue(node.child_ids));
|
||||
|
||||
CefRefPtr<CefDictionaryValue> attributes = CefDictionaryValue::Create();
|
||||
PopulateAxNodeAttributes func(attributes);
|
||||
|
||||
// Poupulate Int Attributes.
|
||||
std::for_each(node.int_attributes.begin(), node.int_attributes.end(), func);
|
||||
|
||||
// Poupulate String Attributes.
|
||||
std::for_each(node.string_attributes.begin(),
|
||||
node.string_attributes.end(), func);
|
||||
|
||||
// Poupulate Float Attributes.
|
||||
std::for_each(node.float_attributes.begin(),
|
||||
node.float_attributes.end(), func);
|
||||
|
||||
// Poupulate Bool Attributes.
|
||||
std::for_each(node.bool_attributes.begin(), node.bool_attributes.end(), func);
|
||||
|
||||
// Populate int list attributes.
|
||||
std::for_each(node.intlist_attributes.begin(),
|
||||
node.intlist_attributes.end(), func);
|
||||
|
||||
value->SetDictionary("attributes", attributes);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Converts AXTreeData to CefDictionaryValue(like AXTreeData::ToString).
|
||||
CefRefPtr<CefDictionaryValue> ToCefValue(const ui::AXTreeData& treeData) {
|
||||
CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
|
||||
|
||||
if (treeData.tree_id != -1)
|
||||
value->SetInt("tree_id", treeData.tree_id);
|
||||
|
||||
if (treeData.parent_tree_id != -1)
|
||||
value->SetInt("parent_tree_id", treeData.parent_tree_id);
|
||||
|
||||
if (treeData.focused_tree_id != -1)
|
||||
value->SetInt("focused_tree_id", treeData.focused_tree_id);
|
||||
|
||||
if (!treeData.doctype.empty())
|
||||
value->SetString("doctype", treeData.doctype);
|
||||
|
||||
value->SetBool("loaded", treeData.loaded);
|
||||
|
||||
if (treeData.loading_progress != 0.0)
|
||||
value->SetDouble("loading_progress", treeData.loading_progress);
|
||||
|
||||
if (!treeData.mimetype.empty())
|
||||
value->SetString("mimetype", treeData.mimetype);
|
||||
if (!treeData.url.empty())
|
||||
value->SetString("url", treeData.url);
|
||||
if (!treeData.title.empty())
|
||||
value->SetString("title", treeData.title);
|
||||
|
||||
if (treeData.sel_anchor_object_id != -1) {
|
||||
value->SetInt("sel_anchor_object_id", treeData.sel_anchor_object_id);
|
||||
value->SetInt("sel_anchor_offset", treeData.sel_anchor_offset);
|
||||
value->SetString("sel_anchor_affinity",
|
||||
ToString(treeData.sel_anchor_affinity));
|
||||
}
|
||||
if (treeData.sel_focus_object_id != -1) {
|
||||
value->SetInt("sel_focus_object_id", treeData.sel_anchor_object_id);
|
||||
value->SetInt("sel_focus_offset", treeData.sel_anchor_offset);
|
||||
value->SetString("sel_focus_affinity",
|
||||
ToString(treeData.sel_anchor_affinity));
|
||||
}
|
||||
|
||||
if (treeData.focus_id != -1)
|
||||
value->SetInt("focus_id", treeData.focus_id);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Converts AXTreeUpdate to CefDictionaryValue(like AXTreeUpdate::ToString).
|
||||
CefRefPtr<CefDictionaryValue> ToCefValue(const ui::AXTreeUpdate& update) {
|
||||
CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
|
||||
|
||||
if (update.has_tree_data) {
|
||||
value->SetBool("has_tree_data", true);
|
||||
value->SetDictionary("tree_data", ToCefValue(update.tree_data));
|
||||
}
|
||||
|
||||
if (update.node_id_to_clear != 0)
|
||||
value->SetInt("node_id_to_clear", update.node_id_to_clear);
|
||||
|
||||
if (update.root_id != 0)
|
||||
value->SetInt("root_id", update.root_id);
|
||||
|
||||
value->SetList("nodes", ToCefValue(update.nodes));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Convert AXEventNotificationDetails to CefDictionaryValue.
|
||||
CefRefPtr<CefDictionaryValue> ToCefValue(
|
||||
const content::AXEventNotificationDetails& eventData) {
|
||||
CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
|
||||
|
||||
if (eventData.id != -1)
|
||||
value->SetInt("id", eventData.id);
|
||||
|
||||
if (eventData.ax_tree_id != -1)
|
||||
value->SetInt("ax_tree_id", eventData.ax_tree_id);
|
||||
|
||||
if (eventData.event_type != ui::AX_EVENT_NONE)
|
||||
value->SetString("event_type", ToString(eventData.event_type));
|
||||
|
||||
if (eventData.event_from != ui::AX_EVENT_FROM_NONE)
|
||||
value->SetString("event_from", ToString(eventData.event_from));
|
||||
|
||||
value->SetDictionary("update", ToCefValue(eventData.update));
|
||||
return value;
|
||||
}
|
||||
|
||||
// Convert AXRelativeBounds to CefDictionaryValue. Similar to
|
||||
// AXRelativeBounds::ToString. See that for more details
|
||||
CefRefPtr<CefDictionaryValue> ToCefValue(const ui::AXRelativeBounds& location) {
|
||||
CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
|
||||
|
||||
if (location.offset_container_id != -1)
|
||||
value->SetInt("offset_container_id", location.offset_container_id);
|
||||
|
||||
value->SetDictionary("bounds", ToCefValue(location.bounds));
|
||||
|
||||
// Transform matrix is private, so we set the string that Clients can parse
|
||||
// and use if needed.
|
||||
if (location.transform && !location.transform->IsIdentity())
|
||||
value->SetString("transform", location.transform->ToString());
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Convert AXEventNotificationDetails to CefDictionaryValue.
|
||||
CefRefPtr<CefDictionaryValue> ToCefValue(
|
||||
const content::AXLocationChangeNotificationDetails& locData) {
|
||||
CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
|
||||
|
||||
if (locData.id != -1)
|
||||
value->SetInt("id", locData.id);
|
||||
|
||||
if (locData.ax_tree_id != -1)
|
||||
value->SetInt("ax_tree_id", locData.ax_tree_id);
|
||||
|
||||
value->SetDictionary("new_location", ToCefValue(locData.new_location));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CefRefPtr<CefListValue> ToCefValue(const std::vector<T>& vecData) {
|
||||
CefRefPtr<CefListValue> value = CefListValue::Create();
|
||||
|
||||
for (size_t i = 0; i <vecData.size(); i ++)
|
||||
value->SetDictionary(i, ToCefValue(vecData[i]));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace osr_accessibility_util {
|
||||
|
||||
CefRefPtr<CefValue> ParseAccessibilityEventData(
|
||||
const std::vector<content::AXEventNotificationDetails>& data) {
|
||||
CefRefPtr<CefValue> value = CefValue::Create();
|
||||
value->SetList(ToCefValue(data));
|
||||
return value;
|
||||
}
|
||||
|
||||
CefRefPtr<CefValue> ParseAccessibilityLocationData(
|
||||
const std::vector<content::AXLocationChangeNotificationDetails>& data) {
|
||||
CefRefPtr<CefValue> value = CefValue::Create();
|
||||
value->SetList(ToCefValue(data));
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace osr_accessibility_util
|
29
libcef/browser/osr/osr_accessibility_util.h
Normal file
29
libcef/browser/osr/osr_accessibility_util.h
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright 2017 The Chromium Embedded Framework Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
#ifndef CEF_LIBCEF_BROWSER_OSR_ACCESSIBILITY_UTIL_H_
|
||||
#define CEF_LIBCEF_BROWSER_OSR_ACCESSIBILITY_UTIL_H_
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "include/cef_values.h"
|
||||
|
||||
namespace content {
|
||||
struct AXEventNotificationDetails;
|
||||
struct AXLocationChangeNotificationDetails;
|
||||
}
|
||||
|
||||
namespace osr_accessibility_util {
|
||||
|
||||
// Convert Accessibility Event and location updates to CefValue, which may be
|
||||
// consumed or serialized with CefJSONWrite.
|
||||
CefRefPtr<CefValue> ParseAccessibilityEventData(
|
||||
const std::vector<content::AXEventNotificationDetails>& data);
|
||||
|
||||
CefRefPtr<CefValue> ParseAccessibilityLocationData(
|
||||
const std::vector<content::AXLocationChangeNotificationDetails>& data);
|
||||
|
||||
} // namespace osr_accessibility_util
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_ACCESSIBILITY_UTIL_H_
|
@@ -71,6 +71,20 @@ void CefWebContentsViewOSR::StoreFocus() {
|
||||
void CefWebContentsViewOSR::RestoreFocus() {
|
||||
}
|
||||
|
||||
void CefWebContentsViewOSR::GotFocus() {
|
||||
if (web_contents_) {
|
||||
content::WebContentsImpl* web_contents_impl =
|
||||
static_cast<content::WebContentsImpl*>(web_contents_);
|
||||
if (web_contents_impl)
|
||||
web_contents_impl->NotifyWebContentsFocused();
|
||||
}
|
||||
}
|
||||
|
||||
void CefWebContentsViewOSR::TakeFocus(bool reverse) {
|
||||
if (web_contents_->GetDelegate())
|
||||
web_contents_->GetDelegate()->TakeFocus(web_contents_, reverse);
|
||||
}
|
||||
|
||||
content::DropData* CefWebContentsViewOSR::GetDropData() const {
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -70,6 +70,8 @@ class CefWebContentsViewOSR : public content::WebContentsView,
|
||||
const content::DragEventSourceInfo& event_info,
|
||||
content::RenderWidgetHostImpl* source_rwh) override;
|
||||
void UpdateDragCursor(blink::WebDragOperation operation) override;
|
||||
virtual void GotFocus() override;
|
||||
virtual void TakeFocus(bool reverse) override;
|
||||
|
||||
private:
|
||||
CefRenderWidgetHostViewOSR* GetView() const;
|
||||
|
Reference in New Issue
Block a user