1 /*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "frameworks/bridge/common/accessibility/accessibility_node_manager.h"
17
18 #include <cstddef>
19
20 #include "base/geometry/dimension_offset.h"
21 #include "base/log/dump_log.h"
22 #include "base/log/event_report.h"
23 #include "core/accessibility/js_inspector/inspect_badge.h"
24 #include "core/accessibility/js_inspector/inspect_button.h"
25 #include "core/accessibility/js_inspector/inspect_camera.h"
26 #include "core/accessibility/js_inspector/inspect_canvas.h"
27 #include "core/accessibility/js_inspector/inspect_chart.h"
28 #include "core/accessibility/js_inspector/inspect_dialog.h"
29 #include "core/accessibility/js_inspector/inspect_div.h"
30 #include "core/accessibility/js_inspector/inspect_divider.h"
31 #include "core/accessibility/js_inspector/inspect_form.h"
32 #include "core/accessibility/js_inspector/inspect_grid_column.h"
33 #include "core/accessibility/js_inspector/inspect_grid_container.h"
34 #include "core/accessibility/js_inspector/inspect_grid_row.h"
35 #include "core/accessibility/js_inspector/inspect_image.h"
36 #include "core/accessibility/js_inspector/inspect_image_animator.h"
37 #include "core/accessibility/js_inspector/inspect_input.h"
38 #include "core/accessibility/js_inspector/inspect_label.h"
39 #include "core/accessibility/js_inspector/inspect_list.h"
40 #include "core/accessibility/js_inspector/inspect_list_item.h"
41 #include "core/accessibility/js_inspector/inspect_list_item_group.h"
42 #include "core/accessibility/js_inspector/inspect_marquee.h"
43 #include "core/accessibility/js_inspector/inspect_menu.h"
44 #include "core/accessibility/js_inspector/inspect_navigation_bar.h"
45 #include "core/accessibility/js_inspector/inspect_option.h"
46 #include "core/accessibility/js_inspector/inspect_panel.h"
47 #include "core/accessibility/js_inspector/inspect_picker.h"
48 #include "core/accessibility/js_inspector/inspect_picker_view.h"
49 #include "core/accessibility/js_inspector/inspect_piece.h"
50 #include "core/accessibility/js_inspector/inspect_popup.h"
51 #include "core/accessibility/js_inspector/inspect_progress.h"
52 #include "core/accessibility/js_inspector/inspect_qrcode.h"
53 #include "core/accessibility/js_inspector/inspect_rating.h"
54 #include "core/accessibility/js_inspector/inspect_refresh.h"
55 #include "core/accessibility/js_inspector/inspect_search.h"
56 #include "core/accessibility/js_inspector/inspect_select.h"
57 #include "core/accessibility/js_inspector/inspect_slider.h"
58 #include "core/accessibility/js_inspector/inspect_span.h"
59 #include "core/accessibility/js_inspector/inspect_stack.h"
60 #include "core/accessibility/js_inspector/inspect_stepper.h"
61 #include "core/accessibility/js_inspector/inspect_stepper_item.h"
62 #include "core/accessibility/js_inspector/inspect_swiper.h"
63 #include "core/accessibility/js_inspector/inspect_switch.h"
64 #include "core/accessibility/js_inspector/inspect_tab_bar.h"
65 #include "core/accessibility/js_inspector/inspect_tab_content.h"
66 #include "core/accessibility/js_inspector/inspect_tabs.h"
67 #include "core/accessibility/js_inspector/inspect_text.h"
68 #include "core/accessibility/js_inspector/inspect_textarea.h"
69 #include "core/accessibility/js_inspector/inspect_toggle.h"
70 #include "core/accessibility/js_inspector/inspect_toolbar.h"
71 #include "core/accessibility/js_inspector/inspect_toolbar_item.h"
72 #include "core/accessibility/js_inspector/inspect_video.h"
73 #include "core/components_v2/inspector/inspector_composed_element.h"
74
75 namespace OHOS::Ace::Framework {
76 namespace {
77
78 const char PAGE_CHANGE_EVENT[] = "pagechange";
79 const char ROOT_STACK_TAG[] = "rootstacktag";
80 const char ROOT_DECOR_TAG[] = "rootdecortag";
81 constexpr int32_t ROOT_STACK_BASE = 1100000;
82 constexpr int32_t ROOT_DECOR_BASE = 3100000;
83 constexpr int32_t CARD_NODE_ID_RATION = 10000;
84 constexpr int32_t CARD_ROOT_NODE_ID = 21000;
85 constexpr int32_t CARD_BASE = 100000;
86 constexpr int32_t CARD_MAX_AGP_ID = 20000;
87
88 std::atomic<int32_t> g_accessibilityId(ROOT_STACK_BASE);
89
90 const char INSPECTOR_TYPE[] = "$type";
91 const char INSPECTOR_ID[] = "$ID";
92 const char INSPECTOR_RECT[] = "$rect";
93 const char INSPECTOR_ATTRS[] = "$attrs";
94 const char INSPECTOR_STYLES[] = "$styles";
95
96 template<class T>
InspectNodeCreator(NodeId nodeId,const std::string & tag)97 RefPtr<InspectNode> InspectNodeCreator(NodeId nodeId, const std::string& tag)
98 {
99 return AceType::MakeRefPtr<T>(nodeId, tag);
100 }
101
102 #ifndef NG_BUILD
103 const LinearMapNode<RefPtr<InspectNode> (*)(NodeId, const std::string&)> inspectNodeCreators[] = {
104 { DOM_NODE_TAG_BADGE, &InspectNodeCreator<InspectBadge> },
105 { DOM_NODE_TAG_BUTTON, &InspectNodeCreator<InspectButton> },
106 { DOM_NODE_TAG_CAMERA, &InspectNodeCreator<InspectCamera> },
107 { DOM_NODE_TAG_CANVAS, &InspectNodeCreator<InspectCanvas> },
108 { DOM_NODE_TAG_CHART, &InspectNodeCreator<InspectChart> },
109 { DOM_NODE_TAG_DIALOG, &InspectNodeCreator<InspectDialog> },
110 { DOM_NODE_TAG_DIV, &InspectNodeCreator<InspectDiv> },
111 { DOM_NODE_TAG_DIVIDER, &InspectNodeCreator<InspectDivider> },
112 { DOM_NODE_TAG_FORM, &InspectNodeCreator<InspectForm> },
113 { DOM_NODE_TAG_GRID_COLUMN, &InspectNodeCreator<InspectGridColumn> },
114 { DOM_NODE_TAG_GRID_CONTAINER, &InspectNodeCreator<InspectGridContainer> },
115 { DOM_NODE_TAG_GRID_ROW, &InspectNodeCreator<InspectGridRow> },
116 { DOM_NODE_TAG_IMAGE, &InspectNodeCreator<InspectImage> },
117 { DOM_NODE_TAG_IMAGE_ANIMATOR, &InspectNodeCreator<InspectImageAnimator> },
118 { DOM_NODE_TAG_INPUT, &InspectNodeCreator<InspectInput> },
119 { DOM_NODE_TAG_LABEL, &InspectNodeCreator<InspectLabel> },
120 { DOM_NODE_TAG_LIST, &InspectNodeCreator<InspectList> },
121 { DOM_NODE_TAG_LIST_ITEM, &InspectNodeCreator<InspectListItem> },
122 { DOM_NODE_TAG_LIST_ITEM_GROUP, &InspectNodeCreator<InspectListItemGroup> },
123 { DOM_NODE_TAG_MARQUEE, &InspectNodeCreator<InspectMarquee> },
124 { DOM_NODE_TAG_MENU, &InspectNodeCreator<InspectMenu> },
125 { DOM_NODE_TAG_NAVIGATION_BAR, &InspectNodeCreator<InspectNavigationBar> },
126 { DOM_NODE_TAG_OPTION, &InspectNodeCreator<InspectOption> },
127 { DOM_NODE_TAG_PANEL, &InspectNodeCreator<InspectPanel> },
128 { DOM_NODE_TAG_PICKER_DIALOG, &InspectNodeCreator<InspectPicker> },
129 { DOM_NODE_TAG_PICKER_VIEW, &InspectNodeCreator<InspectPickerView> },
130 { DOM_NODE_TAG_PIECE, &InspectNodeCreator<InspectPiece> },
131 { DOM_NODE_TAG_POPUP, &InspectNodeCreator<InspectPopup> },
132 { DOM_NODE_TAG_PROGRESS, &InspectNodeCreator<InspectProgress> },
133 { DOM_NODE_TAG_QRCODE, &InspectNodeCreator<InspectQRcode> },
134 { DOM_NODE_TAG_RATING, &InspectNodeCreator<InspectRating> },
135 { DOM_NODE_TAG_REFRESH, &InspectNodeCreator<InspectRefresh> },
136 { DOM_NODE_TAG_SEARCH, &InspectNodeCreator<InspectSearch> },
137 { DOM_NODE_TAG_SELECT, &InspectNodeCreator<InspectSelect> },
138 { DOM_NODE_TAG_SLIDER, &InspectNodeCreator<InspectSlider> },
139 { DOM_NODE_TAG_SPAN, &InspectNodeCreator<InspectSpan> },
140 { DOM_NODE_TAG_STACK, &InspectNodeCreator<InspectStack> },
141 { DOM_NODE_TAG_STEPPER, &InspectNodeCreator<InspectStepper> },
142 { DOM_NODE_TAG_STEPPER_ITEM, &InspectNodeCreator<InspectStepperItem> },
143 { DOM_NODE_TAG_SWIPER, &InspectNodeCreator<InspectSwiper> },
144 { DOM_NODE_TAG_SWITCH, &InspectNodeCreator<InspectSwitch> },
145 { DOM_NODE_TAG_TAB_BAR, &InspectNodeCreator<InspectTabBar> },
146 { DOM_NODE_TAG_TAB_CONTENT, &InspectNodeCreator<InspectTabContent> },
147 { DOM_NODE_TAG_TABS, &InspectNodeCreator<InspectTabs> },
148 { DOM_NODE_TAG_TEXT, &InspectNodeCreator<InspectText> },
149 { DOM_NODE_TAG_TEXTAREA, &InspectNodeCreator<InspectTextArea> },
150 { DOM_NODE_TAG_TOGGLE, &InspectNodeCreator<InspectToggle> },
151 { DOM_NODE_TAG_TOOL_BAR, &InspectNodeCreator<InspectToolbar> },
152 { DOM_NODE_TAG_TOOL_BAR_ITEM, &InspectNodeCreator<InspectToolbarItem> },
153 { DOM_NODE_TAG_VIDEO, &InspectNodeCreator<InspectVideo> },
154 };
155 #endif
156
ConvertStrToPropertyType(const std::string & typeValue)157 std::string ConvertStrToPropertyType(const std::string& typeValue)
158 {
159 std::string dstStr;
160 std::regex regex("([A-Z])");
161 dstStr = regex_replace(typeValue, regex, "-$1");
162 std::transform(dstStr.begin(), dstStr.end(), dstStr.begin(), ::tolower);
163 return dstStr;
164 }
165
GetRootNodeIdFromPage(const RefPtr<JsAcePage> & page)166 inline int32_t GetRootNodeIdFromPage(const RefPtr<JsAcePage>& page)
167 {
168 #ifndef NG_BUILD
169 auto domDocument = page ? page->GetDomDocument() : nullptr;
170 if (domDocument) {
171 return domDocument->GetRootNodeId();
172 }
173 #endif
174 return -1;
175 }
176
ConvertToNodeId(int32_t cardAccessibilityId)177 int32_t ConvertToNodeId(int32_t cardAccessibilityId)
178 {
179 // cardAccessibilityId is integer total ten digits, top five for agp virtualViewId, end five for ace nodeId,
180 // for example 00032 10001 convert to result is 1000001
181 int result = 0;
182 int32_t nodeId = cardAccessibilityId % CARD_BASE;
183 if (nodeId >= CARD_ROOT_NODE_ID) {
184 return 0;
185 }
186 result =
187 (static_cast<int32_t>(nodeId / CARD_NODE_ID_RATION)) * DOM_ROOT_NODE_ID_BASE + nodeId % CARD_NODE_ID_RATION;
188 return result;
189 }
190
191 } // namespace
192
193 const size_t AccessibilityNodeManager::EVENT_DUMP_PARAM_LENGTH_UPPER = 4;
194 const size_t AccessibilityNodeManager::EVENT_DUMP_PARAM_LENGTH_LOWER = 3;
195 const size_t AccessibilityNodeManager::PROPERTY_DUMP_PARAM_LENGTH = 2;
196 const int32_t AccessibilityNodeManager::EVENT_DUMP_ORDER_INDEX = 0;
197 const int32_t AccessibilityNodeManager::EVENT_DUMP_ID_INDEX = 1;
198 const int32_t AccessibilityNodeManager::EVENT_DUMP_ACTION_INDEX = 2;
199 const int32_t AccessibilityNodeManager::EVENT_DUMP_ACTION_PARAM_INDEX = 3;
200
~AccessibilityNodeManager()201 AccessibilityNodeManager::~AccessibilityNodeManager()
202 {
203 auto rootNode = GetAccessibilityNodeById(rootNodeId_ + ROOT_STACK_BASE);
204 if (rootNode) {
205 RemoveAccessibilityNodes(rootNode);
206 }
207 }
208
InitializeCallback()209 void AccessibilityNodeManager::InitializeCallback() {}
210
RegisterSubWindowInteractionOperation(int windowId)211 void AccessibilityNodeManager::RegisterSubWindowInteractionOperation(int windowId) {}
212
SetPipelineContext(const RefPtr<PipelineBase> & context)213 void AccessibilityNodeManager::SetPipelineContext(const RefPtr<PipelineBase>& context)
214 {
215 context_ = context;
216 }
217
AddSubPipelineContext(const RefPtr<PipelineBase> & context)218 void AccessibilityNodeManager::AddSubPipelineContext(const RefPtr<PipelineBase>& context)
219 {
220 subContexts_.emplace_back(WeakPtr<PipelineBase>(context));
221 }
222
SetRunningPage(const RefPtr<JsAcePage> & page)223 void AccessibilityNodeManager::SetRunningPage(const RefPtr<JsAcePage>& page)
224 {
225 indexPage_ = page;
226 // send page change event to barrier free when page change.
227 AccessibilityEvent accessibilityEvent;
228 accessibilityEvent.eventType = PAGE_CHANGE_EVENT;
229 SendAccessibilityAsyncEvent(accessibilityEvent);
230 #ifndef NG_BUILD
231 if (GetVersion() == AccessibilityVersion::JS_DECLARATIVE_VERSION) {
232 auto domDocument = page ? page->GetDomDocument() : nullptr;
233 if (domDocument) {
234 SetRootNodeId(domDocument->GetRootNodeId());
235 }
236 }
237 #endif
238 }
239
GetNodeChildIds(const RefPtr<AccessibilityNode> & node)240 std::string AccessibilityNodeManager::GetNodeChildIds(const RefPtr<AccessibilityNode>& node)
241 {
242 std::string ids;
243 if (node) {
244 const auto& children = node->GetChildList();
245 if ((node->GetNodeId() == rootNodeId_ + ROOT_STACK_BASE) && !children.empty()) {
246 ids.append(std::to_string(children.back()->GetNodeId()));
247 } else {
248 for (const auto& child : children) {
249 if (!ids.empty()) {
250 ids.append(",");
251 }
252 ids.append(std::to_string(child->GetNodeId()));
253 }
254 }
255 }
256 return ids;
257 }
258
AddNodeWithId(const std::string & key,const RefPtr<AccessibilityNode> & node)259 void AccessibilityNodeManager::AddNodeWithId(const std::string& key, const RefPtr<AccessibilityNode>& node)
260 {
261 if (!node) {
262 return;
263 }
264 nodeWithIdMap_[key] = node;
265 }
266
AddNodeWithTarget(const std::string & key,const RefPtr<AccessibilityNode> & node)267 void AccessibilityNodeManager::AddNodeWithTarget(const std::string& key, const RefPtr<AccessibilityNode>& node)
268 {
269 if (!node) {
270 return;
271 }
272 nodeWithTargetMap_[key] = node;
273 }
274
AddComposedElement(const std::string & key,const RefPtr<ComposedElement> & node)275 void AccessibilityNodeManager::AddComposedElement(const std::string& key, const RefPtr<ComposedElement>& node)
276 {
277 if (!node) {
278 return;
279 }
280 composedElementIdMap_[key] = node;
281 }
282
RemoveComposedElementById(const std::string & key)283 void AccessibilityNodeManager::RemoveComposedElementById(const std::string& key)
284 {
285 auto it = composedElementIdMap_.find(key);
286 if (it != composedElementIdMap_.end()) {
287 composedElementIdMap_.erase(it);
288 }
289 }
290
GetComposedElementFromPage(NodeId nodeId)291 WeakPtr<ComposedElement> AccessibilityNodeManager::GetComposedElementFromPage(NodeId nodeId)
292 {
293 if (isOhosHostCard_) {
294 nodeId = ConvertToNodeId(nodeId);
295 }
296 auto indexPage = indexPage_.Upgrade();
297 if (nodeId == 0 && indexPage) {
298 auto rootNode = GetRootNodeIdFromPage(indexPage);
299 if (rootNode < 0) {
300 return nullptr;
301 }
302 nodeId = rootNode + ROOT_STACK_BASE;
303 }
304
305 const auto itNode = composedElementIdMap_.find(std::to_string(nodeId));
306 if (itNode == composedElementIdMap_.end()) {
307 return nullptr;
308 }
309 return itNode->second;
310 }
311
GetAccessibilityNodeFromPage(NodeId nodeId) const312 RefPtr<AccessibilityNode> AccessibilityNodeManager::GetAccessibilityNodeFromPage(NodeId nodeId) const
313 {
314 if (isOhosHostCard_) {
315 nodeId = ConvertToNodeId(nodeId);
316 }
317 auto indexPage = indexPage_.Upgrade();
318 if (nodeId == 0 && indexPage) {
319 auto rootNode = GetRootNodeIdFromPage(indexPage);
320 if (rootNode < 0) {
321 return nullptr;
322 }
323 nodeId = rootNode + ROOT_STACK_BASE;
324 }
325
326 return GetAccessibilityNodeById(nodeId);
327 }
328
GetInspectorNodeById(NodeId nodeId) const329 std::string AccessibilityNodeManager::GetInspectorNodeById(NodeId nodeId) const
330 {
331 auto node = GetAccessibilityNodeFromPage(nodeId);
332 if (!node) {
333 return "";
334 }
335 auto jsonNode = JsonUtil::Create(true);
336 jsonNode->Put(INSPECTOR_TYPE, node->GetTag().c_str());
337 jsonNode->Put(INSPECTOR_ID, node->GetNodeId());
338 jsonNode->Put(INSPECTOR_RECT, node->GetRect().ToBounds().c_str());
339 auto result = GetDefaultAttrsByType(node->GetTag(), jsonNode);
340 if (!result) {
341 return jsonNode->ToString();
342 }
343 auto attrJsonNode = jsonNode->GetObject(INSPECTOR_ATTRS);
344 for (const auto& attr : node->GetAttrs()) {
345 if (attrJsonNode->Contains(attr.first)) {
346 attrJsonNode->Replace(attr.first.c_str(), attr.second.c_str());
347 } else {
348 attrJsonNode->Put(attr.first.c_str(), attr.second.c_str());
349 }
350 }
351 auto styleJsonNode = jsonNode->GetObject(INSPECTOR_STYLES);
352 for (const auto& style : node->GetStyles()) {
353 auto styleType = ConvertStrToPropertyType(style.first);
354 if (styleJsonNode->Contains(styleType)) {
355 styleJsonNode->Replace(styleType.c_str(), style.second.c_str());
356 } else {
357 styleJsonNode->Put(styleType.c_str(), style.second.c_str());
358 }
359 }
360 return jsonNode->ToString();
361 }
362
ClearNodeRectInfo(RefPtr<AccessibilityNode> & node,bool isPopDialog)363 void AccessibilityNodeManager::ClearNodeRectInfo(RefPtr<AccessibilityNode>& node, bool isPopDialog)
364 {
365 if (!node) {
366 return;
367 }
368 auto children = node->GetChildList();
369 for (auto it = children.begin(); it != children.end(); it++) {
370 ClearNodeRectInfo(*it, isPopDialog);
371 }
372 #if defined(PREVIEW)
373 if (isPopDialog) {
374 node->SetClearRectInfoFlag(true);
375 } else {
376 node->SetClearRectInfoFlag(false);
377 }
378 #endif
379 }
380
SendAccessibilityAsyncEvent(const AccessibilityEvent & accessibilityEvent)381 void AccessibilityNodeManager::SendAccessibilityAsyncEvent(const AccessibilityEvent& accessibilityEvent) {}
382
GenerateNextAccessibilityId()383 int64_t AccessibilityNodeManager::GenerateNextAccessibilityId()
384 {
385 return g_accessibilityId.fetch_add(1, std::memory_order_relaxed);
386 }
387
388 // combined components which pop up through js api, such as dialog/toast
CreateSpecializedNode(const std::string & tag,int32_t nodeId,int32_t parentNodeId)389 RefPtr<AccessibilityNode> AccessibilityNodeManager::CreateSpecializedNode(
390 const std::string& tag, int32_t nodeId, int32_t parentNodeId)
391 {
392 #if defined(PREVIEW)
393 return nullptr;
394 #endif
395 if (nodeId < ROOT_STACK_BASE) {
396 return nullptr;
397 }
398 return CreateAccessibilityNode(tag, nodeId, parentNodeId, -1);
399 }
400
CreateAccessibilityNode(const std::string & tag,int32_t nodeId,int32_t parentNodeId,int32_t itemIndex)401 RefPtr<AccessibilityNode> AccessibilityNodeManager::CreateAccessibilityNode(
402 const std::string& tag, int32_t nodeId, int32_t parentNodeId, int32_t itemIndex)
403 {
404 if (IsDeclarative()) {
405 return CreateDeclarativeAccessibilityNode(tag, nodeId, parentNodeId, itemIndex);
406 } else {
407 return CreateCommonAccessibilityNode(tag, nodeId, parentNodeId, itemIndex);
408 }
409 }
410
CreateDeclarativeAccessibilityNode(const std::string & tag,int32_t nodeId,int32_t parentNodeId,int32_t itemIndex)411 RefPtr<AccessibilityNode> AccessibilityNodeManager::CreateDeclarativeAccessibilityNode(
412 const std::string& tag, int32_t nodeId, int32_t parentNodeId, int32_t itemIndex)
413 {
414 RefPtr<AccessibilityNode> parentNode;
415 if (parentNodeId != -1) {
416 parentNode = GetAccessibilityNodeById(parentNodeId);
417 } else {
418 parentNode = GetRootAccessibilityNode();
419 }
420 auto accessibilityNode = GetAccessibilityNodeById(nodeId);
421 if (!accessibilityNode) {
422 accessibilityNode = AceType::MakeRefPtr<AccessibilityNode>(nodeId, tag);
423 {
424 std::lock_guard<std::mutex> lock(mutex_);
425 auto result = accessibilityNodes_.try_emplace(nodeId, accessibilityNode);
426 if (!result.second) {
427 return nullptr;
428 }
429 }
430 }
431 accessibilityNode->SetTag(tag);
432 accessibilityNode->SetIsRootNode(nodeId == rootNodeId_);
433 accessibilityNode->SetPageId(rootNodeId_ - DOM_ROOT_NODE_ID_BASE);
434 accessibilityNode->SetFocusableState(true);
435 auto container = Container::Current();
436 if (container) {
437 auto context = container->GetPipelineContext();
438 if (context) {
439 accessibilityNode->SetWindowId(context->GetWindowId());
440 }
441 }
442 if (parentNode) {
443 accessibilityNode->SetParentNode(parentNode);
444 accessibilityNode->Mount(itemIndex);
445 }
446 return accessibilityNode;
447 }
448
CreateCommonAccessibilityNode(const std::string & tag,int32_t nodeId,int32_t parentNodeId,int32_t itemIndex)449 RefPtr<AccessibilityNode> AccessibilityNodeManager::CreateCommonAccessibilityNode(
450 const std::string& tag, int32_t nodeId, int32_t parentNodeId, int32_t itemIndex)
451 {
452 RefPtr<AccessibilityNode> parentNode;
453 if (parentNodeId != -1) {
454 parentNode = GetAccessibilityNodeById(parentNodeId);
455 if (!parentNode) {
456 EventReport::SendAccessibilityException(AccessibilityExcepType::CREATE_ACCESSIBILITY_NODE_ERR);
457 return nullptr;
458 }
459 } else {
460 parentNode = GetRootAccessibilityNode();
461 }
462
463 auto accessibilityNode = AceType::MakeRefPtr<AccessibilityNode>(nodeId, tag);
464 auto container = Container::Current();
465 if (container) {
466 auto context = container->GetPipelineContext();
467 if (context) {
468 accessibilityNode->SetWindowId(context->GetWindowId());
469 }
470 }
471 accessibilityNode->SetIsRootNode(nodeId == rootNodeId_);
472 accessibilityNode->SetPageId(rootNodeId_ - DOM_ROOT_NODE_ID_BASE);
473 accessibilityNode->SetParentNode(parentNode);
474 accessibilityNode->Mount(itemIndex);
475 {
476 std::lock_guard<std::mutex> lock(mutex_);
477 auto result = accessibilityNodes_.try_emplace(nodeId, accessibilityNode);
478
479 if (!result.second) {
480 return nullptr;
481 }
482 }
483 return accessibilityNode;
484 }
485
GetRootAccessibilityNode()486 RefPtr<AccessibilityNode> AccessibilityNodeManager::GetRootAccessibilityNode()
487 {
488 // create accessibility root stack node
489 auto rootStackId = rootNodeId_ + (!IsDecor() ? ROOT_STACK_BASE : ROOT_DECOR_BASE);
490 RefPtr<AccessibilityNode> parentNode = GetAccessibilityNodeById(rootStackId);
491 if (!parentNode) {
492 parentNode = AceType::MakeRefPtr<AccessibilityNode>(rootStackId, !IsDecor() ? ROOT_STACK_TAG : ROOT_DECOR_TAG);
493 if (parentNode && !IsDecor()) {
494 parentNode->SetPageId(rootNodeId_ - DOM_ROOT_NODE_ID_BASE);
495 }
496 std::lock_guard<std::mutex> lock(mutex_);
497 accessibilityNodes_.try_emplace(rootStackId, parentNode);
498 }
499 if (!IsDecor()) {
500 auto decor = GetAccessibilityNodeById(ROOT_DECOR_BASE - 1);
501 if (decor) {
502 decor->SetParentNode(parentNode);
503 decor->Mount(-1);
504 }
505 }
506 auto container = Container::Current();
507 if (container) {
508 auto context = container->GetPipelineContext();
509 if (context) {
510 parentNode->SetWindowId(context->GetWindowId());
511 }
512 }
513 return parentNode;
514 }
515
GetAccessibilityNodeById(NodeId nodeId) const516 RefPtr<AccessibilityNode> AccessibilityNodeManager::GetAccessibilityNodeById(NodeId nodeId) const
517 {
518 std::lock_guard<std::mutex> lock(mutex_);
519 const auto itNode = accessibilityNodes_.find(nodeId);
520 if (itNode == accessibilityNodes_.end()) {
521 return nullptr;
522 }
523 return itNode->second;
524 }
525
RemoveAccessibilityNodes(RefPtr<AccessibilityNode> & node)526 void AccessibilityNodeManager::RemoveAccessibilityNodes(RefPtr<AccessibilityNode>& node)
527 {
528 if (!node) {
529 return;
530 }
531 auto children = node->GetChildList();
532 for (auto it = children.begin(); it != children.end();) {
533 RemoveAccessibilityNodes(*it++);
534 }
535 auto parentId = node->GetParentId();
536 RefPtr<AccessibilityNode> parentNode;
537 if (parentId != -1) {
538 parentNode = GetAccessibilityNodeById(parentId);
539 if (parentNode) {
540 parentNode->RemoveNode(node);
541 }
542 }
543 std::lock_guard<std::mutex> lock(mutex_);
544 accessibilityNodes_.erase(node->GetNodeId());
545 RemoveVisibleChangeNode(node->GetNodeId());
546 }
547
RemoveAccessibilityNodeById(NodeId nodeId)548 void AccessibilityNodeManager::RemoveAccessibilityNodeById(NodeId nodeId)
549 {
550 auto accessibilityNode = GetAccessibilityNodeById(nodeId);
551 if (!accessibilityNode) {
552 return;
553 }
554 RemoveAccessibilityNodes(accessibilityNode);
555 }
556
ClearPageAccessibilityNodes(int32_t pageId)557 void AccessibilityNodeManager::ClearPageAccessibilityNodes(int32_t pageId)
558 {
559 auto rootNodeId = pageId + ROOT_STACK_BASE;
560 auto accessibilityNode = GetAccessibilityNodeById(rootNodeId);
561 if (!accessibilityNode) {
562 return;
563 }
564 RemoveAccessibilityNodes(accessibilityNode);
565 }
566
TriggerVisibleChangeEvent()567 void AccessibilityNodeManager::TriggerVisibleChangeEvent()
568 {
569 if (visibleChangeNodes_.empty()) {
570 return;
571 }
572 for (auto& visibleChangeNode : visibleChangeNodes_) {
573 auto visibleNodeId = visibleChangeNode.first;
574 auto accessibilityNode = GetAccessibilityNodeById(visibleNodeId);
575 if (!accessibilityNode) {
576 continue;
577 }
578 // IntersectionObserver observes size exclude margin.
579 auto marginSize = accessibilityNode->GetMarginSize();
580 auto visibleRect = accessibilityNode->GetRect() - marginSize;
581 auto globalRect = accessibilityNode->GetGlobalRect() - marginSize;
582 auto pipeline = context_.Upgrade();
583 if (pipeline) {
584 pipeline->GetBoundingRectData(visibleNodeId, globalRect);
585 globalRect = globalRect * pipeline->GetViewScale() - marginSize;
586 }
587 auto& nodeCallbackInfoList = visibleChangeNode.second;
588 for (auto& nodeCallbackInfo : nodeCallbackInfoList) {
589 if (!globalRect.IsValid() || !accessibilityNode->GetVisible()) {
590 if (nodeCallbackInfo.currentVisibleType) {
591 nodeCallbackInfo.currentVisibleType = false;
592 if (nodeCallbackInfo.callback) {
593 nodeCallbackInfo.callback(false, 0.0);
594 }
595 }
596 continue;
597 }
598 auto visibleRatio = visibleRect.Width() * visibleRect.Height() / (globalRect.Width() * globalRect.Height());
599 visibleRatio = std::clamp(visibleRatio, 0.0, 1.0);
600 if (GreatNotEqual(visibleRatio, nodeCallbackInfo.visibleRatio) && !nodeCallbackInfo.currentVisibleType) {
601 nodeCallbackInfo.currentVisibleType = true;
602 if (nodeCallbackInfo.callback) {
603 nodeCallbackInfo.callback(true, visibleRatio);
604 }
605 }
606 if (LessOrEqual(visibleRatio, nodeCallbackInfo.visibleRatio) && nodeCallbackInfo.currentVisibleType) {
607 nodeCallbackInfo.currentVisibleType = false;
608 if (nodeCallbackInfo.callback) {
609 nodeCallbackInfo.callback(false, visibleRatio);
610 }
611 }
612 }
613 }
614 }
615
AddVisibleChangeNode(NodeId nodeId,double ratio,VisibleRatioCallback callback)616 void AccessibilityNodeManager::AddVisibleChangeNode(NodeId nodeId, double ratio, VisibleRatioCallback callback)
617 {
618 VisibleCallbackInfo info;
619 info.callback = callback;
620 info.visibleRatio = ratio;
621 info.currentVisibleType = false;
622 auto iter = visibleChangeNodes_.find(nodeId);
623 if (iter != visibleChangeNodes_.end()) {
624 auto& callbackList = visibleChangeNodes_[nodeId];
625 callbackList.emplace_back(info);
626 } else {
627 std::list<VisibleCallbackInfo> callbackList;
628 callbackList.emplace_back(info);
629 visibleChangeNodes_[nodeId] = callbackList;
630 }
631 }
632
RemoveVisibleChangeNode(NodeId nodeId)633 void AccessibilityNodeManager::RemoveVisibleChangeNode(NodeId nodeId)
634 {
635 auto key = visibleChangeNodes_.find(nodeId);
636 if (key != visibleChangeNodes_.end()) {
637 visibleChangeNodes_.erase(key);
638 }
639 }
640
TrySaveTargetAndIdNode(const std::string & id,const std::string & target,const RefPtr<AccessibilityNode> & node)641 void AccessibilityNodeManager::TrySaveTargetAndIdNode(
642 const std::string& id, const std::string& target, const RefPtr<AccessibilityNode>& node)
643 {
644 if (!id.empty()) {
645 AddNodeWithId(id, node);
646 }
647
648 if (!target.empty()) {
649 AddNodeWithTarget(target, node);
650 }
651 }
652
OnDumpInfo(const std::vector<std::string> & params)653 void AccessibilityNodeManager::OnDumpInfo(const std::vector<std::string>& params)
654 {
655 if (params.size() == 1) {
656 DumpTree(0, 0);
657 } else if (params.size() == PROPERTY_DUMP_PARAM_LENGTH) {
658 DumpProperty(params);
659 } else if (params.size() >= EVENT_DUMP_PARAM_LENGTH_LOWER) {
660 DumpHandleEvent(params);
661 }
662 }
663
DumpHandleEvent(const std::vector<std::string> & params)664 void AccessibilityNodeManager::DumpHandleEvent(const std::vector<std::string>& params) {}
665
DumpProperty(const std::vector<std::string> & params)666 void AccessibilityNodeManager::DumpProperty(const std::vector<std::string>& params) {}
667
DumpComposedElementsToJson() const668 std::unique_ptr<JsonValue> AccessibilityNodeManager::DumpComposedElementsToJson() const
669 {
670 auto json = JsonUtil::Create(true);
671 auto infos = JsonUtil::CreateArray(true);
672 for (auto& [id, element] : composedElementIdMap_) {
673 auto inspector = element.Upgrade();
674 if (inspector) {
675 auto info = JsonUtil::Create(true);
676 info->Put("id", id.c_str());
677 info->Put("type", TypeInfoHelper::TypeName(*inspector));
678 infos->Put(info);
679 }
680 }
681 json->Put("inspectors", infos);
682 return json;
683 }
684
DumpComposedElementToJson(NodeId nodeId)685 std::unique_ptr<JsonValue> AccessibilityNodeManager::DumpComposedElementToJson(NodeId nodeId)
686 {
687 auto composedElement = GetComposedElementFromPage(nodeId);
688 auto inspector = AceType::DynamicCast<V2::InspectorComposedElement>(composedElement.Upgrade());
689 if (!inspector) {
690 return nullptr;
691 }
692 return inspector->ToJsonObject();
693 }
694
SetCardViewParams(const std::string & key,bool focus)695 void AccessibilityNodeManager::SetCardViewParams(const std::string& key, bool focus) {}
696
SetCardViewPosition(int id,float offsetX,float offsetY)697 void AccessibilityNodeManager::SetCardViewPosition(int id, float offsetX, float offsetY)
698 {
699 cardOffset_ = Offset(offsetX, offsetY);
700 if (id < 0 || id > CARD_MAX_AGP_ID) {
701 cardId_ = 0;
702 } else {
703 cardId_ = id;
704 }
705 isOhosHostCard_ = true;
706 }
707
UpdateEventTarget(NodeId id,BaseEventInfo & info)708 void AccessibilityNodeManager::UpdateEventTarget(NodeId id, BaseEventInfo& info)
709 {
710 #ifndef NG_BUILD
711 auto composedElement = GetComposedElementFromPage(id);
712 auto inspector = AceType::DynamicCast<V2::InspectorComposedElement>(composedElement.Upgrade());
713 if (!inspector) {
714 return;
715 }
716 auto rectInLocal = inspector->GetRenderRectInLocal();
717 auto rectInGlobal = inspector->GetRenderRect();
718 auto marginLeft = inspector->GetMargin(AnimatableType::PROPERTY_MARGIN_LEFT).ConvertToPx();
719 auto marginRight = inspector->GetMargin(AnimatableType::PROPERTY_MARGIN_RIGHT).ConvertToPx();
720 auto marginTop = inspector->GetMargin(AnimatableType::PROPERTY_MARGIN_TOP).ConvertToPx();
721 auto marginBottom = inspector->GetMargin(AnimatableType::PROPERTY_MARGIN_BOTTOM).ConvertToPx();
722 auto& target = info.GetTargetWithModify();
723 auto LocalOffset = rectInLocal.GetOffset();
724 target.area.SetOffset(DimensionOffset(Offset(LocalOffset.GetX() + marginLeft, LocalOffset.GetY() + marginTop)));
725 auto globalOffset = rectInGlobal.GetOffset();
726 target.origin =
727 DimensionOffset(Offset(globalOffset.GetX() - LocalOffset.GetX(), globalOffset.GetY() - LocalOffset.GetY()));
728 target.area.SetWidth(Dimension(rectInLocal.Width() - marginLeft - marginRight));
729 target.area.SetHeight(Dimension(rectInLocal.Height() - marginTop - marginBottom));
730 #endif
731 }
732
SetWindowPos(int32_t left,int32_t top,int32_t windowId)733 void AccessibilityNodeManager::SetWindowPos(int32_t left, int32_t top, int32_t windowId)
734 {
735 WindowPos windowPos;
736 windowPos.left = left;
737 windowPos.top = top;
738 windowPosMap_.insert_or_assign(windowId, windowPos);
739 }
740
IsDeclarative()741 bool AccessibilityNodeManager::IsDeclarative()
742 {
743 auto context = context_.Upgrade();
744 if (!context) {
745 return false;
746 }
747
748 return context->GetIsDeclarative();
749 }
750
GetDefaultAttrsByType(const std::string & type,std::unique_ptr<JsonValue> & jsonDefaultAttrs)751 bool AccessibilityNodeManager::GetDefaultAttrsByType(
752 const std::string& type, std::unique_ptr<JsonValue>& jsonDefaultAttrs)
753 {
754 #ifdef NG_BUILD
755 return false;
756 #else
757 NodeId nodeId = -1;
758 RefPtr<InspectNode> inspectNode;
759 int64_t creatorIndex = BinarySearchFindIndex(inspectNodeCreators, ArraySize(inspectNodeCreators), type.c_str());
760 if (creatorIndex >= 0) {
761 inspectNode = inspectNodeCreators[creatorIndex].value(nodeId, type);
762 } else {
763 return false;
764 }
765 inspectNode->InitCommonStyles();
766 inspectNode->PackAttrAndStyle();
767 inspectNode->SetAllAttr(jsonDefaultAttrs, INSPECTOR_ATTRS);
768 inspectNode->SetAllStyle(jsonDefaultAttrs, INSPECTOR_STYLES);
769 return true;
770 #endif
771 }
772
DumpTree(int32_t depth,int64_t nodeID)773 void AccessibilityNodeManager::DumpTree(int32_t depth, int64_t nodeID)
774 {
775 if (!DumpLog::GetInstance().GetDumpFile()) {
776 return;
777 }
778
779 auto node = GetAccessibilityNodeFromPage(nodeID);
780 if (!node) {
781 DumpLog::GetInstance().Print("Error: failed to get accessibility node with ID " + std::to_string(nodeID));
782 return;
783 }
784
785 DumpLog::GetInstance().AddDesc("ID: " + std::to_string(node->GetNodeId()));
786 DumpLog::GetInstance().AddDesc("compid: " + node->GetJsComponentId());
787 DumpLog::GetInstance().AddDesc("text: " + node->GetText());
788 DumpLog::GetInstance().AddDesc("top: " + std::to_string(node->GetTop() + GetWindowTop(node->GetWindowId())));
789 DumpLog::GetInstance().AddDesc("left: " + std::to_string(node->GetLeft() + GetWindowLeft(node->GetWindowId())));
790 if (node->GetTag() == "SideBarContainer") {
791 Rect sideBarRect = node->GetRect();
792 for (const auto& childNode : node->GetChildList()) {
793 sideBarRect = sideBarRect.CombineRect(childNode->GetRect());
794 }
795 DumpLog::GetInstance().AddDesc("width: " + std::to_string(sideBarRect.Width()));
796 DumpLog::GetInstance().AddDesc("height: " + std::to_string(sideBarRect.Height()));
797 } else {
798 DumpLog::GetInstance().AddDesc("width: " + std::to_string(node->GetWidth()));
799 DumpLog::GetInstance().AddDesc("height: " + std::to_string(node->GetHeight()));
800 }
801 DumpLog::GetInstance().AddDesc("visible: " + std::to_string(node->GetShown() && node->GetVisible()));
802 DumpLog::GetInstance().AddDesc("clickable: " + std::to_string(node->GetClickableState()));
803 DumpLog::GetInstance().AddDesc("checkable: " + std::to_string(node->GetCheckableState()));
804 DumpLog::GetInstance().Print(depth, node->GetTag(), node->GetChildList().size());
805 for (const auto& item : node->GetChildList()) {
806 AccessibilityNodeManager::DumpTree(depth + 1, item->GetNodeId());
807 }
808 }
809
810 } // namespace OHOS::Ace::Framework
811