cefclient: OSR accessibility enhancements (see issue #2604)
- Implement multi-tree support (e.g. page with iframes contains several trees) - Implement OnAccessibilityLocationChange support - Add scroll offset calculation - Fix new Chromium tree layout parsing - Fix uninitialized OsrAXNode::offset_container_id_ - Fix Windows non ascii AxName, AxValue, AxDescription representation
This commit is contained in:
parent
b3468451f5
commit
af349ade33
|
@ -1362,6 +1362,11 @@ void BrowserWindowOsrGtk::UpdateAccessibilityTree(CefRefPtr<CefValue> value) {
|
|||
CEF_REQUIRE_UI_THREAD();
|
||||
}
|
||||
|
||||
void BrowserWindowOsrGtk::UpdateAccessibilityLocation(
|
||||
CefRefPtr<CefValue> value) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
}
|
||||
|
||||
void BrowserWindowOsrGtk::Create(ClientWindowHandle parent_handle) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
DCHECK(!glarea_);
|
||||
|
|
|
@ -89,6 +89,7 @@ class BrowserWindowOsrGtk : public BrowserWindow,
|
|||
const CefRange& selection_range,
|
||||
const CefRenderHandler::RectList& character_bounds) OVERRIDE;
|
||||
void UpdateAccessibilityTree(CefRefPtr<CefValue> value) OVERRIDE;
|
||||
void UpdateAccessibilityLocation(CefRefPtr<CefValue> value) OVERRIDE;
|
||||
|
||||
private:
|
||||
~BrowserWindowOsrGtk();
|
||||
|
|
|
@ -85,6 +85,7 @@ class BrowserWindowOsrMac : public BrowserWindow,
|
|||
const CefRenderHandler::RectList& character_bounds) OVERRIDE;
|
||||
|
||||
void UpdateAccessibilityTree(CefRefPtr<CefValue> value) OVERRIDE;
|
||||
void UpdateAccessibilityLocation(CefRefPtr<CefValue> value) OVERRIDE;
|
||||
|
||||
private:
|
||||
// Create the NSView.
|
||||
|
|
|
@ -109,6 +109,7 @@ CefTextInputClientOSRMac* GetInputClientFromContext(
|
|||
character_bounds:
|
||||
(const CefRenderHandler::RectList&)character_bounds;
|
||||
- (void)UpdateAccessibilityTree:(CefRefPtr<CefValue>)value;
|
||||
- (void)UpdateAccessibilityLocation:(CefRefPtr<CefValue>)value;
|
||||
@end
|
||||
|
||||
namespace {
|
||||
|
@ -1306,6 +1307,18 @@ NSPoint ConvertPointFromWindowToScreen(NSWindow* window, NSPoint point) {
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
- (void)UpdateAccessibilityLocation:(CefRefPtr<CefValue>)value {
|
||||
if (accessibility_helper_) {
|
||||
accessibility_helper_->UpdateAccessibilityLocation(value);
|
||||
}
|
||||
|
||||
if (accessibility_helper_) {
|
||||
NSAccessibilityPostNotification(self,
|
||||
NSAccessibilityValueChangedNotification);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@end
|
||||
|
||||
namespace client {
|
||||
|
|
|
@ -167,4 +167,12 @@ void ClientHandlerOsr::OnAccessibilityTreeChange(CefRefPtr<CefValue> value) {
|
|||
osr_delegate_->UpdateAccessibilityTree(value);
|
||||
}
|
||||
|
||||
void ClientHandlerOsr::OnAccessibilityLocationChange(
|
||||
CefRefPtr<CefValue> value) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (!osr_delegate_)
|
||||
return;
|
||||
osr_delegate_->UpdateAccessibilityLocation(value);
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
|
|
@ -68,6 +68,8 @@ class ClientHandlerOsr : public ClientHandler,
|
|||
|
||||
virtual void UpdateAccessibilityTree(CefRefPtr<CefValue> value) = 0;
|
||||
|
||||
virtual void UpdateAccessibilityLocation(CefRefPtr<CefValue> value) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~OsrDelegate() {}
|
||||
};
|
||||
|
@ -130,7 +132,7 @@ class ClientHandlerOsr : public ClientHandler,
|
|||
|
||||
// CefAccessibilityHandler methods.
|
||||
void OnAccessibilityTreeChange(CefRefPtr<CefValue> value) OVERRIDE;
|
||||
void OnAccessibilityLocationChange(CefRefPtr<CefValue> value) OVERRIDE {}
|
||||
void OnAccessibilityLocationChange(CefRefPtr<CefValue> value) OVERRIDE;
|
||||
|
||||
private:
|
||||
// Only accessed on the UI thread.
|
||||
|
|
|
@ -7,61 +7,180 @@
|
|||
|
||||
namespace client {
|
||||
|
||||
OsrAXTree::OsrAXTree() : parent_tree_id_(-1), root_node_id_(-1) {}
|
||||
|
||||
OsrAXNode* OsrAXTree::GetNode(int nodeId) const {
|
||||
auto result = node_map_.find(nodeId);
|
||||
if (result != node_map_.end()) {
|
||||
return result->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void OsrAXTree::EraseNode(int nodeId) {
|
||||
node_map_.erase(nodeId);
|
||||
}
|
||||
|
||||
void OsrAXTree::AddNode(OsrAXNode* node) {
|
||||
node_map_[node->OsrAXNodeId()] = node;
|
||||
}
|
||||
|
||||
void OsrAXTree::UpdateTreeData(CefRefPtr<CefDictionaryValue> value) {
|
||||
if (value->HasKey("parent_tree_id")) {
|
||||
parent_tree_id_ =
|
||||
OsrAccessibilityHelper::CastToInt(value->GetValue("parent_tree_id"));
|
||||
} else {
|
||||
parent_tree_id_ = -1;
|
||||
}
|
||||
|
||||
// may also update following:
|
||||
// doctype, title, url, mimetype
|
||||
}
|
||||
|
||||
OsrAccessibilityHelper::OsrAccessibilityHelper(CefRefPtr<CefValue> value,
|
||||
CefRefPtr<CefBrowser> browser)
|
||||
: root_node_id_(-1), focused_node_id_(-1), browser_(browser) {
|
||||
: root_tree_id_(-1),
|
||||
focused_tree_id_(-1),
|
||||
focused_node_id_(-1),
|
||||
browser_(browser) {
|
||||
UpdateAccessibilityTree(value);
|
||||
}
|
||||
|
||||
int OsrAccessibilityHelper::CastToInt(CefRefPtr<CefValue> value) {
|
||||
if (value->GetType() == VTYPE_STRING) {
|
||||
const std::string& str = value->GetString();
|
||||
return atoi(str.c_str());
|
||||
} else {
|
||||
return value->GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
void OsrAccessibilityHelper::UpdateAccessibilityLocation(
|
||||
CefRefPtr<CefValue> value) {
|
||||
if (!value || value->GetType() != VTYPE_LIST) {
|
||||
return;
|
||||
}
|
||||
|
||||
CefRefPtr<CefListValue> locationChangeList = value->GetList();
|
||||
size_t locationChangeCount = locationChangeList->GetSize();
|
||||
if (locationChangeCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < locationChangeCount; i++) {
|
||||
CefRefPtr<CefDictionaryValue> locationChangeDict =
|
||||
locationChangeList->GetDictionary(i);
|
||||
if (!locationChangeDict->HasKey("ax_tree_id") ||
|
||||
!locationChangeDict->HasKey("new_location") ||
|
||||
!locationChangeDict->HasKey("id")) {
|
||||
continue;
|
||||
}
|
||||
int treeId = CastToInt(locationChangeDict->GetValue("ax_tree_id"));
|
||||
int nodeId = CastToInt(locationChangeDict->GetValue("id"));
|
||||
|
||||
CefRefPtr<CefDictionaryValue> newLocationDict =
|
||||
locationChangeDict->GetDictionary("new_location");
|
||||
if (!newLocationDict) {
|
||||
continue;
|
||||
}
|
||||
|
||||
OsrAXNode* node = GetNode(treeId, nodeId);
|
||||
if (!node) {
|
||||
continue;
|
||||
}
|
||||
node->UpdateLocation(newLocationDict);
|
||||
}
|
||||
}
|
||||
|
||||
void OsrAccessibilityHelper::UpdateAccessibilityTree(
|
||||
CefRefPtr<CefValue> value) {
|
||||
if (value && value->GetType() == VTYPE_LIST) {
|
||||
CefRefPtr<CefListValue> list = value->GetList();
|
||||
size_t numEvents = list->GetSize();
|
||||
if (numEvents > 0) {
|
||||
for (size_t i = 0; i < numEvents; i++) {
|
||||
CefRefPtr<CefDictionaryValue> event = list->GetDictionary(i);
|
||||
if (event && event->HasKey("event_type") && event->HasKey("update")) {
|
||||
std::string event_type = event->GetString("event_type");
|
||||
if (!value || value->GetType() != VTYPE_DICTIONARY) {
|
||||
return;
|
||||
}
|
||||
|
||||
CefRefPtr<CefDictionaryValue> update = event->GetDictionary("update");
|
||||
if (event_type == "layoutComplete")
|
||||
UpdateLayout(update);
|
||||
if (event_type == "focus" && event->HasKey("id")) {
|
||||
// Update focused node id
|
||||
focused_node_id_ = event->GetInt("id");
|
||||
UpdateFocusedNode(update);
|
||||
CefRefPtr<CefDictionaryValue> mainDict = value->GetDictionary();
|
||||
if (!mainDict->HasKey("ax_tree_id") || !mainDict->HasKey("updates")) {
|
||||
return;
|
||||
}
|
||||
|
||||
int treeId = CastToInt(mainDict->GetValue("ax_tree_id"));
|
||||
CefRefPtr<CefListValue> updatesList = mainDict->GetList("updates");
|
||||
|
||||
size_t updatesCount = updatesList->GetSize();
|
||||
if (updatesCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < updatesCount; i++) {
|
||||
CefRefPtr<CefDictionaryValue> updateDict = updatesList->GetDictionary(i);
|
||||
UpdateLayout(treeId, updateDict);
|
||||
}
|
||||
}
|
||||
|
||||
OsrAXNode* OsrAccessibilityHelper::GetRootNode() const {
|
||||
return GetTreeRootNode(root_tree_id_);
|
||||
}
|
||||
|
||||
OsrAXNode* OsrAccessibilityHelper::GetFocusedNode() const {
|
||||
auto tree = accessibility_node_map_.find(focused_tree_id_);
|
||||
if (tree != accessibility_node_map_.end()) {
|
||||
return tree->second.GetNode(focused_node_id_);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OsrAXNode* OsrAccessibilityHelper::GetTreeRootNode(int treeId) const {
|
||||
auto tree = accessibility_node_map_.find(treeId);
|
||||
if (tree != accessibility_node_map_.end()) {
|
||||
return tree->second.GetNode(tree->second.GetRootNodeId());
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void OsrAccessibilityHelper::UpdateLayout(
|
||||
int treeId,
|
||||
CefRefPtr<CefDictionaryValue> update) {
|
||||
if (update) {
|
||||
CefRefPtr<CefDictionaryValue> tree_data;
|
||||
// get tree data
|
||||
if (update->HasKey("has_tree_data") && update->GetBool("has_tree_data"))
|
||||
tree_data = update->GetDictionary("tree_data");
|
||||
if (!update) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If a node is to be cleared
|
||||
if (update->HasKey("node_id_to_clear")) {
|
||||
int node_id_to_clear = update->GetInt("node_id_to_clear");
|
||||
int nodeId = CastToInt(update->GetValue("node_id_to_clear"));
|
||||
|
||||
// reset root node if that is to be cleared
|
||||
if (node_id_to_clear == root_node_id_)
|
||||
root_node_id_ = -1;
|
||||
OsrAXNode* node = GetNode(node_id_to_clear);
|
||||
auto tree = accessibility_node_map_.find(treeId);
|
||||
if (tree != accessibility_node_map_.end()) {
|
||||
if (tree->second.GetRootNodeId() == nodeId) {
|
||||
root_tree_id_ = -1;
|
||||
tree->second.SetRootNodeId(-1);
|
||||
}
|
||||
}
|
||||
if ((focused_tree_id_ == treeId) && (focused_node_id_ == nodeId)) {
|
||||
UpdateFocusedNode(-1, -1);
|
||||
}
|
||||
OsrAXNode* node = GetNode(treeId, nodeId);
|
||||
DestroyNode(node);
|
||||
}
|
||||
|
||||
if (update->HasKey("root_id"))
|
||||
root_node_id_ = update->GetInt("root_id");
|
||||
// get tree data
|
||||
if (update->HasKey("tree_data") && update->HasKey("has_tree_data") &&
|
||||
update->GetBool("has_tree_data")) {
|
||||
CefRefPtr<CefDictionaryValue> tree_data =
|
||||
update->GetDictionary("tree_data");
|
||||
auto& tree = accessibility_node_map_[treeId];
|
||||
tree.UpdateTreeData(tree_data);
|
||||
if (tree.GetParentTreeId() == -1) {
|
||||
root_tree_id_ = treeId;
|
||||
}
|
||||
if (tree_data->HasKey("focus_id") && tree_data->HasKey("focused_tree_id")) {
|
||||
UpdateFocusedNode(CastToInt(tree_data->GetValue("focused_tree_id")),
|
||||
CastToInt(tree_data->GetValue("focus_id")));
|
||||
}
|
||||
}
|
||||
|
||||
if (tree_data && tree_data->HasKey("focus_id"))
|
||||
focused_node_id_ = tree_data->GetInt("focus_id");
|
||||
// Now initialize/update the node data.
|
||||
if (update->HasKey("nodes")) {
|
||||
CefRefPtr<CefListValue> nodes = update->GetList("nodes");
|
||||
|
@ -69,72 +188,79 @@ void OsrAccessibilityHelper::UpdateLayout(
|
|||
for (size_t index = 0; index < nodes->GetSize(); index++) {
|
||||
CefRefPtr<CefDictionaryValue> node = nodes->GetDictionary(index);
|
||||
if (node) {
|
||||
int node_id = node->GetInt("id");
|
||||
OsrAXNode* axNode = GetNode(node_id);
|
||||
auto& tree = accessibility_node_map_[treeId];
|
||||
int nodeId = CastToInt(node->GetValue("id"));
|
||||
OsrAXNode* axNode = tree.GetNode(nodeId);
|
||||
// Create if it is a new one
|
||||
if (axNode) {
|
||||
axNode->UpdateValue(node);
|
||||
} else {
|
||||
axNode = OsrAXNode::CreateNode(node, this);
|
||||
accessibility_node_map_[node_id] = axNode;
|
||||
}
|
||||
}
|
||||
axNode = OsrAXNode::CreateNode(treeId, nodeId, node, this);
|
||||
tree.AddNode(axNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OsrAccessibilityHelper::UpdateFocusedNode(
|
||||
CefRefPtr<CefDictionaryValue> update) {
|
||||
if (update && update->HasKey("nodes")) {
|
||||
CefRefPtr<CefListValue> nodes = update->GetList("nodes");
|
||||
if (update->HasKey("root_id")) {
|
||||
int nodeId = CastToInt(update->GetValue("root_id"));
|
||||
OsrAXNode* node = GetNode(treeId, nodeId);
|
||||
if (node != NULL) {
|
||||
auto& tree = accessibility_node_map_[treeId];
|
||||
tree.SetRootNodeId(nodeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < nodes->GetSize(); index++) {
|
||||
CefRefPtr<CefDictionaryValue> node = nodes->GetDictionary(index);
|
||||
if (node) {
|
||||
int node_id = node->GetInt("id");
|
||||
OsrAXNode* axNode = GetNode(node_id);
|
||||
// Create if it is a new one
|
||||
if (axNode) {
|
||||
axNode->UpdateValue(node);
|
||||
} else {
|
||||
axNode = OsrAXNode::CreateNode(node, this);
|
||||
accessibility_node_map_[node_id] = axNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
void OsrAccessibilityHelper::UpdateFocusedNode(int treeId, int nodeId) {
|
||||
if ((focused_tree_id_ == treeId) && (focused_node_id_ == nodeId)) {
|
||||
return;
|
||||
}
|
||||
focused_tree_id_ = treeId;
|
||||
focused_node_id_ = nodeId;
|
||||
|
||||
// Now Notify Screen Reader
|
||||
OsrAXNode* axNode = GetFocusedNode();
|
||||
// Fallback to Root
|
||||
if (!axNode)
|
||||
axNode = GetRootNode();
|
||||
|
||||
if (axNode) {
|
||||
axNode->NotifyAccessibilityEvent("focus");
|
||||
}
|
||||
}
|
||||
|
||||
void OsrAccessibilityHelper::Reset() {
|
||||
accessibility_node_map_.clear();
|
||||
root_node_id_ = focused_node_id_ = -1;
|
||||
root_tree_id_ = -1;
|
||||
focused_tree_id_ = focused_node_id_ = -1;
|
||||
}
|
||||
|
||||
void OsrAccessibilityHelper::DestroyNode(OsrAXNode* node) {
|
||||
if (node) {
|
||||
int treeId = node->OsrAXTreeId();
|
||||
int numChilds = node->GetChildCount();
|
||||
if (numChilds > 0) {
|
||||
for (int i = 0; i < numChilds; i++) {
|
||||
DestroyNode(node->ChildAtIndex(i));
|
||||
OsrAXNode* childNode = node->ChildAtIndex(i);
|
||||
if (!childNode) {
|
||||
continue;
|
||||
}
|
||||
childNode->SetParent(NULL);
|
||||
if (childNode->OsrAXTreeId() == treeId) {
|
||||
DestroyNode(childNode);
|
||||
}
|
||||
}
|
||||
accessibility_node_map_.erase(node->OsrAXNodeId());
|
||||
}
|
||||
auto tree = accessibility_node_map_.find(treeId);
|
||||
if (tree != accessibility_node_map_.end()) {
|
||||
tree->second.EraseNode(node->OsrAXNodeId());
|
||||
}
|
||||
|
||||
node->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
OsrAXNode* OsrAccessibilityHelper::GetNode(int nodeId) const {
|
||||
if (nodeId != -1 &&
|
||||
accessibility_node_map_.find(nodeId) != accessibility_node_map_.end()) {
|
||||
return accessibility_node_map_.at(nodeId);
|
||||
OsrAXNode* OsrAccessibilityHelper::GetNode(int treeId, int nodeId) const {
|
||||
auto tree = accessibility_node_map_.find(treeId);
|
||||
if (tree != accessibility_node_map_.end()) {
|
||||
return tree->second.GetNode(nodeId);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
|
@ -12,6 +12,24 @@
|
|||
namespace client {
|
||||
|
||||
class OsrAXNode;
|
||||
class OsrAccessibilityHelper;
|
||||
|
||||
class OsrAXTree {
|
||||
public:
|
||||
OsrAXTree();
|
||||
OsrAXNode* GetNode(int nodeId) const;
|
||||
void EraseNode(int nodeId);
|
||||
void UpdateTreeData(CefRefPtr<CefDictionaryValue> value);
|
||||
void AddNode(OsrAXNode* node);
|
||||
int GetParentTreeId() const { return parent_tree_id_; }
|
||||
int GetRootNodeId() const { return root_node_id_; }
|
||||
void SetRootNodeId(int nodeId) { root_node_id_ = nodeId; }
|
||||
|
||||
private:
|
||||
int parent_tree_id_;
|
||||
int root_node_id_;
|
||||
std::map<int, OsrAXNode*> node_map_;
|
||||
};
|
||||
|
||||
// Helper class that abstracts Renderer Accessibility tree and provides a
|
||||
// uniform interface to be consumed by IAccessible interface on Windows and
|
||||
|
@ -23,9 +41,11 @@ class OsrAccessibilityHelper {
|
|||
|
||||
void UpdateAccessibilityTree(CefRefPtr<CefValue> value);
|
||||
|
||||
OsrAXNode* GetRootNode() const { return GetNode(root_node_id_); }
|
||||
void UpdateAccessibilityLocation(CefRefPtr<CefValue> value);
|
||||
|
||||
OsrAXNode* GetFocusedNode() const { return GetNode(focused_node_id_); }
|
||||
OsrAXNode* GetRootNode() const;
|
||||
|
||||
OsrAXNode* GetFocusedNode() const;
|
||||
|
||||
CefWindowHandle GetWindowHandle() const {
|
||||
return browser_->GetHost()->GetWindowHandle();
|
||||
|
@ -33,23 +53,26 @@ class OsrAccessibilityHelper {
|
|||
|
||||
CefRefPtr<CefBrowser> GetBrowser() const { return browser_; }
|
||||
|
||||
OsrAXNode* GetNode(int nodeId) const;
|
||||
OsrAXNode* GetNode(int treeId, int nodeId) const;
|
||||
|
||||
OsrAXNode* GetTreeRootNode(int treeId) const;
|
||||
|
||||
static int CastToInt(CefRefPtr<CefValue> value);
|
||||
|
||||
private:
|
||||
OsrAXNode* CreateNode(OsrAXNode* parent, CefRefPtr<CefDictionaryValue> value);
|
||||
|
||||
void Reset();
|
||||
|
||||
void UpdateLayout(CefRefPtr<CefDictionaryValue> update);
|
||||
void UpdateLayout(int treeId, CefRefPtr<CefDictionaryValue> update);
|
||||
|
||||
void UpdateFocusedNode(CefRefPtr<CefDictionaryValue> update);
|
||||
void UpdateFocusedNode(int treeId, int nodeId);
|
||||
|
||||
// Destroy the node and remove from Map
|
||||
void DestroyNode(OsrAXNode* node);
|
||||
int root_node_id_;
|
||||
int root_tree_id_;
|
||||
int focused_tree_id_;
|
||||
int focused_node_id_;
|
||||
CefRefPtr<CefBrowser> browser_;
|
||||
std::map<int, OsrAXNode*> accessibility_node_map_;
|
||||
std::map<int, OsrAXTree> accessibility_node_map_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
|
|
@ -11,19 +11,37 @@
|
|||
|
||||
namespace client {
|
||||
|
||||
OsrAXNode::OsrAXNode(CefRefPtr<CefDictionaryValue> value,
|
||||
OsrAXNode::OsrAXNode(int treeId,
|
||||
int nodeId,
|
||||
CefRefPtr<CefDictionaryValue> value,
|
||||
OsrAccessibilityHelper* helper)
|
||||
: node_id_(-1),
|
||||
: tree_id_(treeId),
|
||||
node_id_(nodeId),
|
||||
child_tree_id_(-1),
|
||||
platform_accessibility_(NULL),
|
||||
parent_(NULL),
|
||||
offset_container_id_(-1),
|
||||
accessibility_helper_(helper) {
|
||||
UpdateValue(value);
|
||||
}
|
||||
|
||||
void OsrAXNode::UpdateValue(CefRefPtr<CefDictionaryValue> value) {
|
||||
if (value && value->HasKey("id")) {
|
||||
node_id_ = value->GetInt("id");
|
||||
void OsrAXNode::UpdateLocation(CefRefPtr<CefDictionaryValue> value) {
|
||||
// Update Bounds
|
||||
if (value->HasKey("bounds")) {
|
||||
CefRefPtr<CefDictionaryValue> loc = value->GetDictionary("bounds");
|
||||
if (loc) {
|
||||
location_ = CefRect(loc->GetDouble("x"), loc->GetDouble("y"),
|
||||
loc->GetDouble("width"), loc->GetDouble("height"));
|
||||
}
|
||||
}
|
||||
// Update offsets
|
||||
if (value->HasKey("offset_container_id")) {
|
||||
offset_container_id_ = OsrAccessibilityHelper::CastToInt(
|
||||
value->GetValue("offset_container_id"));
|
||||
}
|
||||
}
|
||||
|
||||
void OsrAXNode::UpdateValue(CefRefPtr<CefDictionaryValue> value) {
|
||||
if (value->HasKey("role"))
|
||||
role_ = value->GetString("role");
|
||||
|
||||
|
@ -32,7 +50,8 @@ void OsrAXNode::UpdateValue(CefRefPtr<CefDictionaryValue> value) {
|
|||
// Reset child Ids
|
||||
child_ids_.clear();
|
||||
for (size_t idx = 0; idx < childs->GetSize(); idx++)
|
||||
child_ids_.push_back(childs->GetInt(idx));
|
||||
child_ids_.push_back(
|
||||
OsrAccessibilityHelper::CastToInt(childs->GetValue(idx)));
|
||||
}
|
||||
// Update Location
|
||||
if (value->HasKey("location")) {
|
||||
|
@ -44,12 +63,30 @@ void OsrAXNode::UpdateValue(CefRefPtr<CefDictionaryValue> value) {
|
|||
}
|
||||
// Update offsets
|
||||
if (value->HasKey("offset_container_id")) {
|
||||
offset_container_id_ = value->GetInt("offset_container_id");
|
||||
offset_container_id_ = OsrAccessibilityHelper::CastToInt(
|
||||
value->GetValue("offset_container_id"));
|
||||
}
|
||||
// Update attributes
|
||||
if (value->HasKey("attributes")) {
|
||||
child_tree_id_ = -1;
|
||||
|
||||
attributes_ = value->GetDictionary("attributes");
|
||||
|
||||
if (attributes_) {
|
||||
scroll_.x = attributes_->HasKey("scrollX")
|
||||
? OsrAccessibilityHelper::CastToInt(
|
||||
attributes_->GetValue("scrollX"))
|
||||
: 0;
|
||||
scroll_.y = attributes_->HasKey("scrollY")
|
||||
? OsrAccessibilityHelper::CastToInt(
|
||||
attributes_->GetValue("scrollY"))
|
||||
: 0;
|
||||
}
|
||||
|
||||
if (attributes_ && attributes_->HasKey("childTreeId")) {
|
||||
child_tree_id_ = OsrAccessibilityHelper::CastToInt(
|
||||
attributes_->GetValue("childTreeId"));
|
||||
}
|
||||
if (attributes_ && attributes_->HasKey("name"))
|
||||
name_ = attributes_->GetString("name");
|
||||
if (attributes_ && attributes_->HasKey("value"))
|
||||
|
@ -58,7 +95,6 @@ void OsrAXNode::UpdateValue(CefRefPtr<CefDictionaryValue> value) {
|
|||
description_ = attributes_->GetString("description");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CefWindowHandle OsrAXNode::GetWindowHandle() const {
|
||||
if (accessibility_helper_)
|
||||
|
@ -78,8 +114,21 @@ void OsrAXNode::SetParent(OsrAXNode* parent) {
|
|||
|
||||
CefRect OsrAXNode::AxLocation() const {
|
||||
CefRect loc = location_;
|
||||
OsrAXNode* offsetNode = accessibility_helper_->GetNode(offset_container_id_);
|
||||
// Add offset from parent Lcoation
|
||||
loc.x -= scroll_.x;
|
||||
loc.y -= scroll_.y;
|
||||
OsrAXNode* offsetNode =
|
||||
accessibility_helper_->GetNode(OsrAXTreeId(), offset_container_id_);
|
||||
if (!offsetNode) {
|
||||
OsrAXNode* p = parent_;
|
||||
while (p) {
|
||||
if (p->OsrAXTreeId() != OsrAXTreeId()) {
|
||||
offsetNode = p;
|
||||
break;
|
||||
}
|
||||
p = p->parent_;
|
||||
}
|
||||
}
|
||||
// Add offset from parent Location
|
||||
if (offsetNode) {
|
||||
CefRect offset = offsetNode->AxLocation();
|
||||
loc.x += offset.x;
|
||||
|
@ -88,17 +137,39 @@ CefRect OsrAXNode::AxLocation() const {
|
|||
return loc;
|
||||
}
|
||||
|
||||
int OsrAXNode::GetChildCount() const {
|
||||
int count = static_cast<int>(child_ids_.size());
|
||||
if (child_tree_id_ >= 0) {
|
||||
OsrAXNode* childTreeRootNode =
|
||||
accessibility_helper_->GetTreeRootNode(child_tree_id_);
|
||||
if (childTreeRootNode) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
OsrAXNode* OsrAXNode::ChildAtIndex(int index) const {
|
||||
if (index < GetChildCount())
|
||||
return accessibility_helper_->GetNode(child_ids_[index]);
|
||||
else
|
||||
int count = static_cast<int>(child_ids_.size());
|
||||
if (index < count)
|
||||
return accessibility_helper_->GetNode(OsrAXTreeId(), child_ids_[index]);
|
||||
if ((index == count) && (child_tree_id_ >= 0)) {
|
||||
OsrAXNode* childTreeRootNode =
|
||||
accessibility_helper_->GetTreeRootNode(child_tree_id_);
|
||||
if (childTreeRootNode) {
|
||||
return childTreeRootNode;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create and return the platform specific OsrAXNode Object
|
||||
OsrAXNode* OsrAXNode::CreateNode(CefRefPtr<CefDictionaryValue> value,
|
||||
OsrAXNode* OsrAXNode::CreateNode(int treeId,
|
||||
int nodeId,
|
||||
CefRefPtr<CefDictionaryValue> value,
|
||||
OsrAccessibilityHelper* helper) {
|
||||
return new OsrAXNode(value, helper);
|
||||
return new OsrAXNode(treeId, nodeId, value, helper);
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
|
|
@ -33,12 +33,17 @@ class OsrAccessibilityHelper;
|
|||
class OsrAXNode {
|
||||
public:
|
||||
// Create and return the platform specific OsrAXNode Object.
|
||||
static OsrAXNode* CreateNode(CefRefPtr<CefDictionaryValue> value,
|
||||
static OsrAXNode* CreateNode(int treeId,
|
||||
int nodeId,
|
||||
CefRefPtr<CefDictionaryValue> value,
|
||||
OsrAccessibilityHelper* helper);
|
||||
|
||||
// Update Value.
|
||||
void UpdateValue(CefRefPtr<CefDictionaryValue> value);
|
||||
|
||||
// UpdateLocation
|
||||
void UpdateLocation(CefRefPtr<CefDictionaryValue> value);
|
||||
|
||||
// Fire a platform-specific notification that an event has occurred on
|
||||
// this object.
|
||||
void NotifyAccessibilityEvent(std::string event_type) const;
|
||||
|
@ -58,13 +63,15 @@ class OsrAXNode {
|
|||
return accessibility_helper_;
|
||||
}
|
||||
|
||||
int GetChildCount() const { return static_cast<int>(child_ids_.size()); }
|
||||
int GetChildCount() const;
|
||||
|
||||
// Return the Child at the specified index
|
||||
OsrAXNode* ChildAtIndex(int index) const;
|
||||
|
||||
const CefString& AxRole() const { return role_; }
|
||||
|
||||
int OsrAXTreeId() const { return tree_id_; }
|
||||
|
||||
int OsrAXNodeId() const { return node_id_; }
|
||||
|
||||
const CefString& AxValue() const { return value_; }
|
||||
|
@ -82,15 +89,20 @@ class OsrAXNode {
|
|||
void SetParent(OsrAXNode* parent);
|
||||
|
||||
protected:
|
||||
OsrAXNode(CefRefPtr<CefDictionaryValue> value,
|
||||
OsrAXNode(int treeId,
|
||||
int nodeId,
|
||||
CefRefPtr<CefDictionaryValue> value,
|
||||
OsrAccessibilityHelper* helper);
|
||||
|
||||
int tree_id_;
|
||||
int node_id_;
|
||||
int child_tree_id_;
|
||||
CefString role_;
|
||||
CefString value_;
|
||||
CefString name_;
|
||||
CefString description_;
|
||||
CefRect location_;
|
||||
CefPoint scroll_;
|
||||
std::vector<int> child_ids_;
|
||||
CefNativeAccessible* platform_accessibility_;
|
||||
OsrAXNode* parent_;
|
||||
|
|
|
@ -347,7 +347,7 @@ STDMETHODIMP CefIAccessible::get_accName(VARIANT varChild, BSTR* pszName) {
|
|||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
if (pszName && VALID_CHILDID(varChild)) {
|
||||
std::string name = node_->AxName();
|
||||
std::wstring name = node_->AxName();
|
||||
CComBSTR bstrResult(name.c_str());
|
||||
*pszName = bstrResult.Detach();
|
||||
}
|
||||
|
@ -362,7 +362,7 @@ STDMETHODIMP CefIAccessible::get_accValue(VARIANT varChild, BSTR* pszValue) {
|
|||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
if (pszValue && VALID_CHILDID(varChild)) {
|
||||
std::string name = node_->AxValue();
|
||||
std::wstring name = node_->AxValue();
|
||||
CComBSTR bstrResult(name.c_str());
|
||||
*pszValue = bstrResult.Detach();
|
||||
}
|
||||
|
@ -378,7 +378,7 @@ STDMETHODIMP CefIAccessible::get_accDescription(VARIANT varChild,
|
|||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
if (pszDescription && VALID_CHILDID(varChild)) {
|
||||
std::string name = node_->AxDescription();
|
||||
std::wstring name = node_->AxDescription();
|
||||
CComBSTR bstrResult(name.c_str());
|
||||
*pszDescription = bstrResult.Detach();
|
||||
}
|
||||
|
|
|
@ -1058,6 +1058,16 @@ void OsrWindowWin::UpdateAccessibilityTree(CefRefPtr<CefValue> value) {
|
|||
#endif // defined(CEF_USE_ATL)
|
||||
}
|
||||
|
||||
void OsrWindowWin::UpdateAccessibilityLocation(CefRefPtr<CefValue> value) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
#if defined(CEF_USE_ATL)
|
||||
if (accessibility_handler_) {
|
||||
accessibility_handler_->UpdateAccessibilityLocation(value);
|
||||
}
|
||||
#endif // defined(CEF_USE_ATL)
|
||||
}
|
||||
|
||||
#if defined(CEF_USE_ATL)
|
||||
|
||||
CefBrowserHost::DragOperationsMask OsrWindowWin::OnDragEnter(
|
||||
|
|
|
@ -146,7 +146,9 @@ class OsrWindowWin
|
|||
const CefRange& selection_range,
|
||||
const CefRenderHandler::RectList& character_bounds) OVERRIDE;
|
||||
|
||||
void UpdateAccessibilityTree(CefRefPtr<CefValue> value);
|
||||
void UpdateAccessibilityTree(CefRefPtr<CefValue> value) OVERRIDE;
|
||||
|
||||
void UpdateAccessibilityLocation(CefRefPtr<CefValue> value) OVERRIDE;
|
||||
|
||||
#if defined(CEF_USE_ATL)
|
||||
// OsrDragEvents methods.
|
||||
|
|
Loading…
Reference in New Issue