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