• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
2 // 2013 The Chromium Authors. All rights reserved. Use of this source code is
3 // governed by a BSD-style license that can be found in the LICENSE file.
4 
5 #include "tests/cefclient/browser/osr_accessibility_helper.h"
6 #include "tests/cefclient/browser/osr_accessibility_node.h"
7 
8 namespace client {
9 
OsrAXTree()10 OsrAXTree::OsrAXTree() : root_node_id_(-1) {}
11 
GetNode(int nodeId) const12 OsrAXNode* OsrAXTree::GetNode(int nodeId) const {
13   auto result = node_map_.find(nodeId);
14   if (result != node_map_.end()) {
15     return result->second;
16   }
17   return nullptr;
18 }
19 
EraseNode(int nodeId)20 void OsrAXTree::EraseNode(int nodeId) {
21   node_map_.erase(nodeId);
22 }
23 
AddNode(OsrAXNode * node)24 void OsrAXTree::AddNode(OsrAXNode* node) {
25   node_map_[node->OsrAXNodeId()] = node;
26 }
27 
UpdateTreeData(CefRefPtr<CefDictionaryValue> value)28 void OsrAXTree::UpdateTreeData(CefRefPtr<CefDictionaryValue> value) {
29   if (value->HasKey("parent_tree_id")) {
30     parent_tree_id_ = value->GetString("parent_tree_id");
31   } else {
32     parent_tree_id_ = "";
33   }
34 
35   // may also update following:
36   // doctype, title, url, mimetype
37 }
38 
OsrAccessibilityHelper(CefRefPtr<CefValue> value,CefRefPtr<CefBrowser> browser)39 OsrAccessibilityHelper::OsrAccessibilityHelper(CefRefPtr<CefValue> value,
40                                                CefRefPtr<CefBrowser> browser)
41     : focused_node_id_(-1),
42       browser_(browser) {
43   UpdateAccessibilityTree(value);
44 }
45 
CastToInt(CefRefPtr<CefValue> value)46 int OsrAccessibilityHelper::CastToInt(CefRefPtr<CefValue> value) {
47   if (value->GetType() == VTYPE_STRING) {
48     const std::string& str = value->GetString();
49     return atoi(str.c_str());
50   } else {
51     return value->GetInt();
52   }
53 }
54 
UpdateAccessibilityLocation(CefRefPtr<CefValue> value)55 void OsrAccessibilityHelper::UpdateAccessibilityLocation(
56     CefRefPtr<CefValue> value) {
57   if (!value || value->GetType() != VTYPE_LIST) {
58     return;
59   }
60 
61   CefRefPtr<CefListValue> locationChangeList = value->GetList();
62   size_t locationChangeCount = locationChangeList->GetSize();
63   if (locationChangeCount == 0) {
64     return;
65   }
66 
67   for (size_t i = 0; i < locationChangeCount; i++) {
68     CefRefPtr<CefDictionaryValue> locationChangeDict =
69         locationChangeList->GetDictionary(i);
70     if (!locationChangeDict->HasKey("ax_tree_id") ||
71         !locationChangeDict->HasKey("new_location") ||
72         !locationChangeDict->HasKey("id")) {
73       continue;
74     }
75     CefString treeId = locationChangeDict->GetString("ax_tree_id");
76     int nodeId = CastToInt(locationChangeDict->GetValue("id"));
77 
78     CefRefPtr<CefDictionaryValue> newLocationDict =
79         locationChangeDict->GetDictionary("new_location");
80     if (!newLocationDict) {
81       continue;
82     }
83 
84     OsrAXNode* node = GetNode(treeId, nodeId);
85     if (!node) {
86       continue;
87     }
88     node->UpdateLocation(newLocationDict);
89   }
90 }
91 
UpdateAccessibilityTree(CefRefPtr<CefValue> value)92 void OsrAccessibilityHelper::UpdateAccessibilityTree(
93     CefRefPtr<CefValue> value) {
94   if (!value || value->GetType() != VTYPE_DICTIONARY) {
95     return;
96   }
97 
98   CefRefPtr<CefDictionaryValue> mainDict = value->GetDictionary();
99   if (!mainDict->HasKey("ax_tree_id") || !mainDict->HasKey("updates")) {
100     return;
101   }
102 
103   CefString treeId = mainDict->GetString("ax_tree_id");
104   CefRefPtr<CefListValue> updatesList = mainDict->GetList("updates");
105 
106   size_t updatesCount = updatesList->GetSize();
107   if (updatesCount == 0) {
108     return;
109   }
110 
111   for (size_t i = 0; i < updatesCount; i++) {
112     CefRefPtr<CefDictionaryValue> updateDict = updatesList->GetDictionary(i);
113     UpdateLayout(treeId, updateDict);
114   }
115 }
116 
GetRootNode() const117 OsrAXNode* OsrAccessibilityHelper::GetRootNode() const {
118   return GetTreeRootNode(root_tree_id_);
119 }
120 
GetFocusedNode() const121 OsrAXNode* OsrAccessibilityHelper::GetFocusedNode() const {
122   auto tree = accessibility_node_map_.find(focused_tree_id_);
123   if (tree != accessibility_node_map_.end()) {
124     return tree->second.GetNode(focused_node_id_);
125   }
126 
127   return nullptr;
128 }
129 
GetTreeRootNode(const CefString & treeId) const130 OsrAXNode* OsrAccessibilityHelper::GetTreeRootNode(
131     const CefString& treeId) const {
132   auto tree = accessibility_node_map_.find(treeId);
133   if (tree != accessibility_node_map_.end()) {
134     return tree->second.GetNode(tree->second.GetRootNodeId());
135   }
136 
137   return nullptr;
138 }
139 
UpdateLayout(const CefString & treeId,CefRefPtr<CefDictionaryValue> update)140 void OsrAccessibilityHelper::UpdateLayout(
141     const CefString& treeId,
142     CefRefPtr<CefDictionaryValue> update) {
143   if (!update) {
144     return;
145   }
146 
147   // If a node is to be cleared
148   if (update->HasKey("node_id_to_clear")) {
149     int nodeId = CastToInt(update->GetValue("node_id_to_clear"));
150 
151     // reset root node if that is to be cleared
152     auto tree = accessibility_node_map_.find(treeId);
153     if (tree != accessibility_node_map_.end()) {
154       if (tree->second.GetRootNodeId() == nodeId) {
155         root_tree_id_ = "";
156         tree->second.SetRootNodeId(-1);
157       }
158     }
159     if ((focused_tree_id_ == treeId) && (focused_node_id_ == nodeId)) {
160       UpdateFocusedNode("", -1);
161     }
162     OsrAXNode* node = GetNode(treeId, nodeId);
163     DestroyNode(node);
164   }
165 
166   // get tree data
167   if (update->HasKey("tree_data") && update->HasKey("has_tree_data") &&
168       update->GetBool("has_tree_data")) {
169     CefRefPtr<CefDictionaryValue> tree_data =
170         update->GetDictionary("tree_data");
171     auto& tree = accessibility_node_map_[treeId];
172     tree.UpdateTreeData(tree_data);
173     if (tree.GetParentTreeId().empty()) {
174       root_tree_id_ = treeId;
175     }
176     if (tree_data->HasKey("focus_id") && tree_data->HasKey("focused_tree_id")) {
177       UpdateFocusedNode(tree_data->GetString("focused_tree_id"),
178                         CastToInt(tree_data->GetValue("focus_id")));
179     }
180   }
181 
182   // Now initialize/update the node data.
183   if (update->HasKey("nodes")) {
184     CefRefPtr<CefListValue> nodes = update->GetList("nodes");
185 
186     for (size_t index = 0; index < nodes->GetSize(); index++) {
187       CefRefPtr<CefDictionaryValue> node = nodes->GetDictionary(index);
188       if (node) {
189         auto& tree = accessibility_node_map_[treeId];
190         int nodeId = CastToInt(node->GetValue("id"));
191         OsrAXNode* axNode = tree.GetNode(nodeId);
192         // Create if it is a new one
193         if (axNode) {
194           axNode->UpdateValue(node);
195         } else {
196           axNode = OsrAXNode::CreateNode(treeId, nodeId, node, this);
197           tree.AddNode(axNode);
198         }
199       }
200     }
201   }
202 
203   if (update->HasKey("root_id")) {
204     int nodeId = CastToInt(update->GetValue("root_id"));
205     OsrAXNode* node = GetNode(treeId, nodeId);
206     if (node != nullptr) {
207       auto& tree = accessibility_node_map_[treeId];
208       tree.SetRootNodeId(nodeId);
209     }
210   }
211 }
212 
UpdateFocusedNode(const CefString & treeId,int nodeId)213 void OsrAccessibilityHelper::UpdateFocusedNode(const CefString& treeId,
214                                                int nodeId) {
215   if ((focused_tree_id_ == treeId) && (focused_node_id_ == nodeId)) {
216     return;
217   }
218   focused_tree_id_ = treeId;
219   focused_node_id_ = nodeId;
220 
221   // Now Notify Screen Reader
222   OsrAXNode* axNode = GetFocusedNode();
223   if (axNode) {
224     axNode->NotifyAccessibilityEvent("focus");
225   }
226 }
227 
Reset()228 void OsrAccessibilityHelper::Reset() {
229   accessibility_node_map_.clear();
230   root_tree_id_ = "";
231   focused_tree_id_ = "";
232   focused_node_id_ = -1;
233 }
234 
DestroyNode(OsrAXNode * node)235 void OsrAccessibilityHelper::DestroyNode(OsrAXNode* node) {
236   if (node) {
237     CefString treeId = node->OsrAXTreeId();
238     int numChilds = node->GetChildCount();
239     if (numChilds > 0) {
240       for (int i = 0; i < numChilds; i++) {
241         OsrAXNode* childNode = node->ChildAtIndex(i);
242         if (!childNode) {
243           continue;
244         }
245         childNode->SetParent(nullptr);
246         if (childNode->OsrAXTreeId() == treeId) {
247           DestroyNode(childNode);
248         }
249       }
250     }
251     auto tree = accessibility_node_map_.find(treeId);
252     if (tree != accessibility_node_map_.end()) {
253       tree->second.EraseNode(node->OsrAXNodeId());
254     }
255 
256     node->Destroy();
257   }
258 }
259 
GetNode(const CefString & treeId,int nodeId) const260 OsrAXNode* OsrAccessibilityHelper::GetNode(const CefString& treeId,
261                                            int nodeId) const {
262   auto tree = accessibility_node_map_.find(treeId);
263   if (tree != accessibility_node_map_.end()) {
264     return tree->second.GetNode(nodeId);
265   }
266 
267   return nullptr;
268 }
269 
270 }  // namespace client
271