1 /*
2 * Copyright (c) 2022-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 "core/components_ng/base/inspector.h"
17
18 #include <unistd.h>
19 #include <unordered_set>
20
21 #include "base/memory/ace_type.h"
22 #include "base/utils/utils.h"
23 #include "core/common/ace_application_info.h"
24 #include "core/common/recorder/event_recorder.h"
25 #include "core/components_ng/base/inspector_filter.h"
26 #include "core/components_ng/base/ui_node.h"
27 #include "core/components_ng/pattern/custom/custom_node.h"
28 #include "core/components_ng/pattern/stage/page_info.h"
29 #include "core/components_ng/pattern/stage/page_pattern.h"
30 #include "core/components_ng/pattern/text/span_node.h"
31 #include "core/components_v2/inspector/inspector_constants.h"
32 #include "core/event/touch_event.h"
33 #include "core/pipeline_ng/pipeline_context.h"
34 #include "frameworks/base/memory/type_info_base.h"
35 #include "foundation/arkui/ace_engine/frameworks/base/utils/utf.h"
36
37 namespace OHOS::Ace::NG {
38 namespace {
39 const char INSPECTOR_TYPE[] = "$type";
40 const char INSPECTOR_ID[] = "$ID";
41 const char INSPECTOR_RECT[] = "$rect";
42 const char INSPECTOR_ATTRS[] = "$attrs";
43 const char INSPECTOR_ROOT[] = "root";
44 const char INSPECTOR_PAGE_URL[] = "pageUrl";
45 const char INSPECTOR_NAV_DST_NAME[] = "navDstName";
46 const char INSPECTOR_WIDTH[] = "width";
47 const char INSPECTOR_HEIGHT[] = "height";
48 const char INSPECTOR_RESOLUTION[] = "$resolution";
49 const char INSPECTOR_CHILDREN[] = "$children";
50 const char INSPECTOR_DEBUGLINE[] = "$debugLine";
51 #ifdef PREVIEW
52 const char INSPECTOR_VIEW_ID[] = "$viewID";
53 #else
54 const char INSPECTOR_CUSTOM_VIEW_TAG[] = "viewTag";
55 const char INSPECTOR_COMPONENT_TYPE[] = "type";
56 const char INSPECTOR_STATE_VAR[] = "state";
57 #endif
58 const char INSPECTOR_ATTR_ID[] = "id";
59 const char INSPECTOR_LABEL[] = "label";
60 const char INSPECTOR_CONTENT[] = "content";
61 const char INSPECTOR_ENABLED[] = "enabled";
62 const char INSPECTOR_OPACITY[] = "opacity";
63 const char INSPECTOR_ZINDEX[] = "zindex";
64 const char INSPECTOR_VISIBILITY[] = "visibility";
65
66
67 const uint32_t LONG_PRESS_DELAY = 1000;
68 RectF deviceRect;
69
GetInspectorByKey(const RefPtr<FrameNode> & root,const std::string & key,bool notDetach=false)70 RefPtr<UINode> GetInspectorByKey(const RefPtr<FrameNode>& root, const std::string& key, bool notDetach = false)
71 {
72 std::queue<RefPtr<UINode>> elements;
73 elements.push(root);
74 RefPtr<UINode> inspectorElement;
75 while (!elements.empty()) {
76 auto current = elements.front();
77 elements.pop();
78 if (key == current->GetInspectorId().value_or("")) {
79 return current;
80 }
81
82 const auto& children = current->GetChildren(notDetach);
83 for (const auto& child : children) {
84 elements.push(child);
85 }
86 }
87 return nullptr;
88 }
89
DumpElementTree(int32_t depth,const RefPtr<UINode> & element,std::map<int32_t,std::list<RefPtr<UINode>>> & depthElementMap)90 void DumpElementTree(
91 int32_t depth, const RefPtr<UINode>& element, std::map<int32_t, std::list<RefPtr<UINode>>>& depthElementMap)
92 {
93 if (element->GetChildren().empty()) {
94 return;
95 }
96 const auto& children = element->GetChildren();
97 depthElementMap[depth].insert(depthElementMap[depth].end(), children.begin(), children.end());
98 for (const auto& depthElement : children) {
99 DumpElementTree(depth + 1, depthElement, depthElementMap);
100 }
101 }
102
GetUpPoint(const TouchEvent & downPoint)103 TouchEvent GetUpPoint(const TouchEvent& downPoint)
104 {
105 return TouchEvent {}
106 .SetX(downPoint.x)
107 .SetY(downPoint.y)
108 .SetType(TouchType::UP)
109 .SetTime(std::chrono::high_resolution_clock::now())
110 .SetSourceType(SourceType::TOUCH);
111 }
112 #ifdef PREVIEW
GetFrameNodeChildren(const RefPtr<NG::UINode> & uiNode,std::vector<RefPtr<NG::UINode>> & children,int32_t pageId,bool isLayoutInspector=false)113 void GetFrameNodeChildren(const RefPtr<NG::UINode>& uiNode, std::vector<RefPtr<NG::UINode>>& children, int32_t pageId,
114 bool isLayoutInspector = false)
115 {
116 // Set ViewId for the fast preview.
117 auto parent = uiNode->GetParent();
118 if (parent && parent->GetTag() == "JsView") {
119 uiNode->SetViewId(std::to_string(parent->GetId()));
120 } else {
121 uiNode->SetViewId(parent->GetViewId());
122 }
123 if (uiNode->GetTag() == "stage") {
124 } else if (uiNode->GetTag() == "page") {
125 if (uiNode->GetPageId() != pageId) {
126 return;
127 }
128 } else {
129 if (!uiNode->GetDebugLine().empty()) {
130 children.emplace_back(uiNode);
131 return;
132 }
133 }
134
135 for (const auto& frameChild : uiNode->GetChildren()) {
136 GetFrameNodeChildren(frameChild, children, pageId);
137 }
138 }
139
GetSpanInspector(const RefPtr<NG::UINode> & parent,std::unique_ptr<OHOS::Ace::JsonValue> & jsonNodeArray,int pageId)140 void GetSpanInspector(
141 const RefPtr<NG::UINode>& parent, std::unique_ptr<OHOS::Ace::JsonValue>& jsonNodeArray, int pageId)
142 {
143 // span rect follows parent text size
144 auto spanParentNode = parent->GetParent();
145 while (spanParentNode != nullptr) {
146 if (AceType::InstanceOf<NG::FrameNode>(spanParentNode)) {
147 break;
148 }
149 spanParentNode = spanParentNode->GetParent();
150 }
151 CHECK_NULL_VOID(spanParentNode);
152 auto node = AceType::DynamicCast<FrameNode>(spanParentNode);
153 auto jsonNode = JsonUtil::Create(true);
154 auto jsonObject = JsonUtil::Create(true);
155
156 InspectorFilter filter;
157 parent->ToJsonValue(jsonObject, filter);
158 jsonNode->PutRef(INSPECTOR_ATTRS, std::move(jsonObject));
159 jsonNode->Put(INSPECTOR_TYPE, parent->GetTag().c_str());
160 jsonNode->Put(INSPECTOR_ID, parent->GetId());
161 RectF rect = node->GetTransformRectRelativeToWindow();
162 rect = rect.Constrain(deviceRect);
163 if (rect.IsEmpty()) {
164 rect.SetRect(0, 0, 0, 0);
165 }
166 auto strRec = std::to_string(rect.Left())
167 .append(",")
168 .append(std::to_string(rect.Top()))
169 .append(",")
170 .append(std::to_string(rect.Width()))
171 .append(",")
172 .append(std::to_string(rect.Height()));
173 jsonNode->Put(INSPECTOR_RECT, strRec.c_str());
174 jsonNode->Put(INSPECTOR_DEBUGLINE, parent->GetDebugLine().c_str());
175 jsonNode->Put(INSPECTOR_VIEW_ID, parent->GetViewId().c_str());
176 jsonNodeArray->PutRef(std::move(jsonNode));
177 }
178
GetInspectorChildren(const RefPtr<NG::UINode> & parent,std::unique_ptr<OHOS::Ace::JsonValue> & jsonNodeArray,int pageId,bool isActive,const InspectorFilter & filter=InspectorFilter (),uint32_t depth=UINT32_MAX,bool isLayoutInspector=false)179 void GetInspectorChildren(const RefPtr<NG::UINode>& parent, std::unique_ptr<OHOS::Ace::JsonValue>& jsonNodeArray,
180 int pageId, bool isActive, const InspectorFilter& filter = InspectorFilter(), uint32_t depth = UINT32_MAX,
181 bool isLayoutInspector = false)
182 {
183 // Span is a special case in Inspector since span inherits from UINode
184 if (AceType::InstanceOf<SpanNode>(parent)) {
185 GetSpanInspector(parent, jsonNodeArray, pageId);
186 return;
187 }
188 auto jsonNode = JsonUtil::Create(true);
189 jsonNode->Put(INSPECTOR_TYPE, parent->GetTag().c_str());
190 jsonNode->Put(INSPECTOR_ID, parent->GetId());
191 auto node = AceType::DynamicCast<FrameNode>(parent);
192 if (node) {
193 RectF rect;
194 isActive = isActive && node->IsActive();
195 if (isActive) {
196 rect = node->GetTransformRectRelativeToWindow();
197 }
198 rect = rect.Constrain(deviceRect);
199 if (rect.IsEmpty()) {
200 rect.SetRect(0, 0, 0, 0);
201 }
202 auto strRec = std::to_string(rect.Left()).append(",")
203 .append(std::to_string(rect.Top())).append(",")
204 .append(std::to_string(rect.Width())).append(",")
205 .append(std::to_string(rect.Height()));
206 jsonNode->Put(INSPECTOR_RECT, strRec.c_str());
207 jsonNode->Put(INSPECTOR_DEBUGLINE, node->GetDebugLine().c_str());
208 jsonNode->Put(INSPECTOR_VIEW_ID, node->GetViewId().c_str());
209 auto jsonObject = JsonUtil::Create(true);
210
211 InspectorFilter filter;
212 parent->ToJsonValue(jsonObject, filter);
213 jsonNode->PutRef(INSPECTOR_ATTRS, std::move(jsonObject));
214 }
215
216 std::vector<RefPtr<NG::UINode>> children;
217 for (const auto& item : parent->GetChildren()) {
218 GetFrameNodeChildren(item, children, pageId);
219 }
220 if (node != nullptr) {
221 auto overlayNode = node->GetOverlayNode();
222 if (overlayNode != nullptr) {
223 GetFrameNodeChildren(overlayNode, children, pageId);
224 }
225 }
226 if (depth) {
227 auto jsonChildrenArray = JsonUtil::CreateArray(true);
228 for (auto uiNode : children) {
229 GetInspectorChildren(uiNode, jsonChildrenArray, pageId, isActive, filter, depth - 1);
230 }
231 if (jsonChildrenArray->GetArraySize()) {
232 jsonNode->PutRef(INSPECTOR_CHILDREN, std::move(jsonChildrenArray));
233 }
234 }
235 jsonNodeArray->PutRef(std::move(jsonNode));
236 }
237
238 #else
GetFrameNodeChildren(const RefPtr<NG::UINode> & uiNode,std::vector<RefPtr<NG::UINode>> & children,int32_t pageId,bool isLayoutInspector=false)239 void GetFrameNodeChildren(const RefPtr<NG::UINode>& uiNode, std::vector<RefPtr<NG::UINode>>& children,
240 int32_t pageId, bool isLayoutInspector = false)
241 {
242 if (AceType::InstanceOf<NG::FrameNode>(uiNode) || AceType::InstanceOf<SpanNode>(uiNode) ||
243 AceType::InstanceOf<CustomNode>(uiNode)) {
244 if (uiNode->GetTag() == "stage") {
245 } else if (uiNode->GetTag() == "page") {
246 if (uiNode->GetPageId() != pageId) {
247 return;
248 }
249 } else {
250 auto custom = AceType::DynamicCast<NG::CustomNode>(uiNode);
251 auto frameNode = AceType::DynamicCast<NG::FrameNode>(uiNode);
252 auto spanNode = AceType::DynamicCast<NG::SpanNode>(uiNode);
253 if ((frameNode && !frameNode->IsInternal()) || spanNode || (custom && isLayoutInspector)) {
254 children.emplace_back(uiNode);
255 return;
256 }
257 }
258 }
259 for (const auto& frameChild : uiNode->GetChildren()) {
260 GetFrameNodeChildren(frameChild, children, pageId, isLayoutInspector);
261 }
262 }
263
GetSpanInspector(const RefPtr<NG::UINode> & parent,std::unique_ptr<OHOS::Ace::JsonValue> & jsonNodeArray,int pageId)264 void GetSpanInspector(
265 const RefPtr<NG::UINode>& parent, std::unique_ptr<OHOS::Ace::JsonValue>& jsonNodeArray, int pageId)
266 {
267 // span rect follows parent text size
268 auto spanParentNode = parent->GetParent();
269 while (spanParentNode != nullptr) {
270 if (AceType::InstanceOf<NG::FrameNode>(spanParentNode)) {
271 break;
272 }
273 spanParentNode = spanParentNode->GetParent();
274 }
275 CHECK_NULL_VOID(spanParentNode);
276 auto node = AceType::DynamicCast<FrameNode>(spanParentNode);
277 auto jsonNode = JsonUtil::Create(true);
278 auto jsonObject = JsonUtil::Create(true);
279
280 InspectorFilter filter;
281 parent->ToJsonValue(jsonObject, filter);
282 jsonNode->PutRef(INSPECTOR_ATTRS, std::move(jsonObject));
283 jsonNode->Put(INSPECTOR_TYPE, parent->GetTag().c_str());
284 jsonNode->Put(INSPECTOR_ID, parent->GetId());
285 jsonNode->Put(INSPECTOR_DEBUGLINE, parent->GetDebugLine().c_str());
286 RectF rect = node->GetTransformRectRelativeToWindow();
287 jsonNode->Put(INSPECTOR_RECT, rect.ToBounds().c_str());
288 jsonNodeArray->PutRef(std::move(jsonNode));
289 }
290
GetCustomNodeInfo(const RefPtr<NG::UINode> & customNode,std::unique_ptr<OHOS::Ace::JsonValue> & jsonNode)291 void GetCustomNodeInfo(const RefPtr<NG::UINode> &customNode, std::unique_ptr<OHOS::Ace::JsonValue> &jsonNode)
292 {
293 // custom node rect follows parent size
294 auto hostNode = customNode->GetParent();
295 while (hostNode != nullptr) {
296 if (AceType::InstanceOf<NG::FrameNode>(hostNode)) {
297 break;
298 }
299 hostNode = hostNode->GetParent();
300 }
301 CHECK_NULL_VOID(hostNode);
302 jsonNode->Put(INSPECTOR_COMPONENT_TYPE, "custom");
303 auto node = AceType::DynamicCast<CustomNode>(customNode);
304 CHECK_NULL_VOID(node);
305 auto parentNode = AceType::DynamicCast<FrameNode>(hostNode);
306 jsonNode->Put(INSPECTOR_STATE_VAR, node->GetStateInspectorInfo());
307 RectF rect = parentNode->GetTransformRectRelativeToWindow();
308 jsonNode->Put(INSPECTOR_RECT, rect.ToBounds().c_str());
309 jsonNode->Put(INSPECTOR_DEBUGLINE, customNode->GetDebugLine().c_str());
310 jsonNode->Put(INSPECTOR_CUSTOM_VIEW_TAG, node->GetCustomTag().c_str());
311 }
312
GetInspectorChildren(const RefPtr<NG::UINode> & parent,std::unique_ptr<OHOS::Ace::JsonValue> & jsonNodeArray,int pageId,bool isActive,const InspectorFilter & filter=InspectorFilter (),uint32_t depth=UINT32_MAX,bool isLayoutInspector=false)313 void GetInspectorChildren(const RefPtr<NG::UINode>& parent, std::unique_ptr<OHOS::Ace::JsonValue>& jsonNodeArray,
314 int pageId, bool isActive, const InspectorFilter& filter = InspectorFilter(), uint32_t depth = UINT32_MAX,
315 bool isLayoutInspector = false)
316 {
317 // Span is a special case in Inspector since span inherits from UINode
318 if (AceType::InstanceOf<SpanNode>(parent)) {
319 GetSpanInspector(parent, jsonNodeArray, pageId);
320 return;
321 }
322 if (AceType::InstanceOf<CustomNode>(parent) && !isLayoutInspector) {
323 return;
324 }
325 auto jsonNode = JsonUtil::Create(true);
326 jsonNode->Put(INSPECTOR_TYPE, parent->GetTag().c_str());
327 jsonNode->Put(INSPECTOR_ID, parent->GetId());
328 if (parent->GetTag() == V2::JS_VIEW_ETS_TAG) {
329 GetCustomNodeInfo(parent, jsonNode);
330 } else {
331 jsonNode->Put(INSPECTOR_COMPONENT_TYPE, "build-in");
332 }
333 auto node = AceType::DynamicCast<FrameNode>(parent);
334 if (node) {
335 RectF rect;
336 isActive = isActive && node->IsActive();
337 if (isActive) {
338 rect = node->GetTransformRectRelativeToWindow();
339 }
340 jsonNode->Put(INSPECTOR_RECT, rect.ToBounds().c_str());
341 jsonNode->Put(INSPECTOR_DEBUGLINE, node->GetDebugLine().c_str());
342 }
343 auto jsonObject = JsonUtil::Create(true);
344 parent->ToJsonValue(jsonObject, filter);
345 jsonNode->PutRef(INSPECTOR_ATTRS, std::move(jsonObject));
346 std::string jsonNodeStr = jsonNode->ToString();
347 ConvertIllegalStr(jsonNodeStr);
348 auto jsonNodeNew = JsonUtil::ParseJsonString(jsonNodeStr);
349 std::vector<RefPtr<NG::UINode>> children;
350 for (const auto& item : parent->GetChildren()) {
351 GetFrameNodeChildren(item, children, pageId, isLayoutInspector);
352 }
353 if (node) {
354 auto overlayNode = node->GetOverlayNode();
355 if (overlayNode != nullptr) {
356 GetFrameNodeChildren(overlayNode, children, pageId, isLayoutInspector);
357 }
358 }
359 if (depth) {
360 auto jsonChildrenArray = JsonUtil::CreateArray(true);
361 for (auto uiNode : children) {
362 GetInspectorChildren(uiNode, jsonChildrenArray, pageId, isActive, filter, depth - 1, isLayoutInspector);
363 }
364 if (jsonChildrenArray->GetArraySize()) {
365 jsonNodeNew->PutRef(INSPECTOR_CHILDREN, std::move(jsonChildrenArray));
366 }
367 }
368 jsonNodeArray->PutRef(std::move(jsonNodeNew));
369 }
370 #endif
371
GetOverlayNode(const RefPtr<NG::UINode> & pageNode)372 RefPtr<NG::UINode> GetOverlayNode(const RefPtr<NG::UINode>& pageNode)
373 {
374 CHECK_NULL_RETURN(pageNode, nullptr);
375 auto stageNode = pageNode->GetParent();
376 CHECK_NULL_RETURN(stageNode, nullptr);
377 auto stageParent = stageNode->GetParent();
378 CHECK_NULL_RETURN(stageParent, nullptr);
379 auto overlayNode = stageParent->GetChildren().back();
380 if (overlayNode->GetTag() == "stage") {
381 return nullptr;
382 }
383 return overlayNode;
384 }
385
GetContextInfo(const RefPtr<PipelineContext> & context,std::unique_ptr<JsonValue> & jsonRoot)386 void GetContextInfo(const RefPtr<PipelineContext>& context, std::unique_ptr<JsonValue>& jsonRoot)
387 {
388 auto scale = context->GetViewScale();
389 auto rootHeight = context->GetRootHeight();
390 auto rootWidth = context->GetRootWidth();
391 deviceRect.SetRect(0, 0, rootWidth * scale, rootHeight * scale);
392 jsonRoot->Put(INSPECTOR_WIDTH, std::to_string(rootWidth * scale).c_str());
393 jsonRoot->Put(INSPECTOR_HEIGHT, std::to_string(rootHeight * scale).c_str());
394 jsonRoot->Put(INSPECTOR_RESOLUTION, std::to_string(PipelineBase::GetCurrentDensity()).c_str());
395 }
396
GetInspectorInfo(std::vector<RefPtr<NG::UINode>> children,int32_t pageId,std::unique_ptr<JsonValue> jsonRoot,bool isLayoutInspector,const InspectorFilter & filter=InspectorFilter ())397 std::string GetInspectorInfo(std::vector<RefPtr<NG::UINode>> children, int32_t pageId,
398 std::unique_ptr<JsonValue> jsonRoot, bool isLayoutInspector, const InspectorFilter& filter = InspectorFilter())
399 {
400 auto jsonNodeArray = JsonUtil::CreateArray(true);
401 auto depth = filter.GetFilterDepth();
402 for (auto& uiNode : children) {
403 GetInspectorChildren(uiNode, jsonNodeArray, pageId, true, filter, depth - 1, isLayoutInspector);
404 }
405 if (jsonNodeArray->GetArraySize()) {
406 jsonRoot->PutRef(INSPECTOR_CHILDREN, std::move(jsonNodeArray));
407 }
408
409 if (isLayoutInspector) {
410 auto jsonTree = JsonUtil::Create(true);
411 jsonTree->Put("type", "root");
412 jsonTree->PutRef("content", std::move(jsonRoot));
413 auto pipeline = PipelineContext::GetCurrentContextSafely();
414 if (pipeline) {
415 jsonTree->Put("VsyncID", (int32_t)pipeline->GetFrameCount());
416 jsonTree->Put("ProcessID", getpid());
417 jsonTree->Put("WindowID", (int32_t)pipeline->GetWindowId());
418 }
419 return jsonTree->ToString();
420 }
421
422 return jsonRoot->ToString();
423 }
424 } // namespace
425
426 std::set<RefPtr<FrameNode>> Inspector::offscreenNodes;
427
GetFrameNodeByKey(const std::string & key,bool notDetach)428 RefPtr<FrameNode> Inspector::GetFrameNodeByKey(const std::string& key, bool notDetach)
429 {
430 if (!offscreenNodes.empty()) {
431 for (auto node : offscreenNodes) {
432 auto frameNode = AceType::DynamicCast<FrameNode>(GetInspectorByKey(node, key, notDetach));
433 if (frameNode) {
434 return frameNode;
435 }
436 }
437 }
438 auto context = NG::PipelineContext::GetCurrentContext();
439 if (!context) {
440 LOGW("Internal error! Context is null. key: %{public}s", key.c_str());
441 return nullptr;
442 }
443 auto rootNode = context->GetRootElement();
444 if (!rootNode) {
445 LOGW("Internal error! RootNode is null. key: %{public}s", key.c_str());
446 return nullptr;
447 }
448
449 return AceType::DynamicCast<FrameNode>(GetInspectorByKey(rootNode, key, notDetach));
450 }
451
GetInspectorNodeByKey(const std::string & key,const InspectorFilter & filter)452 std::string Inspector::GetInspectorNodeByKey(const std::string& key, const InspectorFilter& filter)
453 {
454 auto context = NG::PipelineContext::GetCurrentContext();
455 CHECK_NULL_RETURN(context, "");
456 auto rootNode = context->GetRootElement();
457 CHECK_NULL_RETURN(rootNode, "");
458
459 auto inspectorElement = GetInspectorByKey(rootNode, key);
460 CHECK_NULL_RETURN(inspectorElement, "");
461
462 auto jsonNode = JsonUtil::Create(true);
463 jsonNode->Put(INSPECTOR_TYPE, inspectorElement->GetTag().c_str());
464 jsonNode->Put(INSPECTOR_ID, inspectorElement->GetId());
465 auto frameNode = AceType::DynamicCast<FrameNode>(inspectorElement);
466 if (frameNode) {
467 auto rect = frameNode->GetTransformRectRelativeToWindow();
468 jsonNode->Put(INSPECTOR_RECT, rect.ToBounds().c_str());
469 }
470 auto jsonAttrs = JsonUtil::Create(true);
471 std::string debugLine = inspectorElement->GetDebugLine();
472 jsonNode->Put(INSPECTOR_DEBUGLINE, debugLine.c_str());
473
474 inspectorElement->ToJsonValue(jsonAttrs, filter);
475 jsonNode->PutRef(INSPECTOR_ATTRS, std::move(jsonAttrs));
476 return jsonNode->ToString();
477 }
478
GetRectangleById(const std::string & key,Rectangle & rectangle)479 void Inspector::GetRectangleById(const std::string& key, Rectangle& rectangle)
480 {
481 auto frameNode = Inspector::GetFrameNodeByKey(key, true);
482 if (!frameNode) {
483 LOGW("Can't find component:%{public}s, check your parameters", key.c_str());
484 return;
485 }
486 rectangle.size = frameNode->GetGeometryNode()->GetFrameSize();
487 auto context = frameNode->GetRenderContext();
488 if (!context) {
489 LOGW("Internal error! Component(id=%{public}s) is null", key.c_str());
490 return;
491 }
492 rectangle.localOffset = context->GetPaintRectWithTransform().GetOffset();
493 rectangle.windowOffset = frameNode->GetOffsetRelativeToWindow();
494 auto pipeline = frameNode->GetContext();
495 CHECK_NULL_VOID(pipeline);
496 rectangle.screenRect = pipeline->GetCurrentWindowRect();
497 ACE_SCOPED_TRACE("Inspector::GetRectangleById_Id=%d_Tag=%s_Key=%s",
498 frameNode->GetId(), frameNode->GetTag().c_str(), key.c_str());
499 LOGI("GetRectangleById Id:%{public}d key:%{public}s tag:%{public}s localOffset:%{public}s"
500 " windowOffset:%{public}s screenRect:%{public}s",
501 frameNode->GetId(), key.c_str(), frameNode->GetTag().c_str(), rectangle.localOffset.ToString().c_str(),
502 rectangle.windowOffset.ToString().c_str(), rectangle.screenRect.ToString().c_str());
503 auto renderContext = frameNode->GetRenderContext();
504 CHECK_NULL_VOID(renderContext);
505 Matrix4 defMatrix4 = Matrix4::CreateIdentity();
506 Matrix4 matrix4 = renderContext->GetTransformMatrixValue(defMatrix4);
507 rectangle.matrix4 = matrix4;
508 auto rect = renderContext->GetPaintRectWithoutTransform();
509 const double halfDimension = 50.0;
510 auto center = renderContext->GetTransformCenter().value_or(DimensionOffset(
511 Dimension(halfDimension, DimensionUnit::PERCENT), Dimension(halfDimension, DimensionUnit::PERCENT)));
512 double centerX = 0.0;
513 double centerY = 0.0;
514 if (center.GetX().Unit() == DimensionUnit::PERCENT || center.GetY().Unit() == DimensionUnit::PERCENT) {
515 if (rect.IsValid()) {
516 centerX = Dimension(center.GetX().ConvertToPxWithSize(rect.Width()), DimensionUnit::PX).ConvertToVp();
517 centerY = Dimension(center.GetY().ConvertToPxWithSize(rect.Height()), DimensionUnit::PX).ConvertToVp();
518 }
519 } else {
520 centerX = center.GetX().ConvertToVp();
521 centerY = center.GetY().ConvertToVp();
522 }
523 VectorF defScale = VectorF(1.0, 1.0);
524 VectorF scale = renderContext->GetTransformScaleValue(defScale);
525 rectangle.scale.x = scale.x;
526 rectangle.scale.y = scale.y;
527 rectangle.scale.z = 1.0;
528 rectangle.scale.centerX = centerX;
529 rectangle.scale.centerY = centerY;
530 Vector5F defRotate = Vector5F(0.0, 0.0, 0.0, 0.0, 0.0);
531 Vector5F rotate = renderContext->GetTransformRotateValue(defRotate);
532 rectangle.rotate.x = rotate.x;
533 rectangle.rotate.y = rotate.y;
534 rectangle.rotate.z = rotate.z;
535 rectangle.rotate.angle = rotate.w;
536 rectangle.rotate.centerX = centerX;
537 rectangle.rotate.centerY = centerY;
538 TranslateOptions defTranslate = TranslateOptions(0.0, 0.0, 0.0);
539 TranslateOptions translate = renderContext->GetTransformTranslateValue(defTranslate);
540 if ((translate.x.Unit() == DimensionUnit::PERCENT) && rect.IsValid()) {
541 rectangle.translate.x =
542 Dimension(translate.x.ConvertToPxWithSize(rect.Width()), DimensionUnit::PX).ConvertToVp();
543 } else {
544 rectangle.translate.x = translate.x.ConvertToVp();
545 }
546 if ((translate.y.Unit() == DimensionUnit::PERCENT) && rect.IsValid()) {
547 rectangle.translate.y =
548 Dimension(translate.y.ConvertToPxWithSize(rect.Height()), DimensionUnit::PX).ConvertToVp();
549 } else {
550 rectangle.translate.y = translate.y.ConvertToVp();
551 }
552 rectangle.translate.z = translate.z.ConvertToVp();
553 }
554
GetInspector(bool isLayoutInspector)555 std::string Inspector::GetInspector(bool isLayoutInspector)
556 {
557 InspectorFilter filter;
558 bool needThrow = false;
559 return GetInspector(isLayoutInspector, filter, needThrow);
560 }
561
GetInspector(bool isLayoutInspector,const InspectorFilter & filter,bool & needThrow)562 std::string Inspector::GetInspector(bool isLayoutInspector, const InspectorFilter& filter, bool& needThrow)
563 {
564 auto jsonRoot = JsonUtil::Create(true);
565 jsonRoot->Put(INSPECTOR_TYPE, INSPECTOR_ROOT);
566 needThrow = false;
567 auto context = NG::PipelineContext::GetCurrentContext();
568 if (context == nullptr) {
569 needThrow = true;
570 return jsonRoot->ToString();
571 }
572 GetContextInfo(context, jsonRoot);
573
574 RefPtr<UINode> pageRootNode;
575 const std::string key = filter.GetFilterID();
576 if (key.empty()) {
577 pageRootNode = context->GetStageManager()->GetLastPage();
578 } else {
579 auto rootNode = context->GetStageManager()->GetLastPage();
580 if (rootNode == nullptr) {
581 needThrow = true;
582 return jsonRoot->ToString();
583 }
584 pageRootNode = GetInspectorByKey(rootNode, key);
585 }
586 if (pageRootNode == nullptr) {
587 needThrow = true;
588 return jsonRoot->ToString();
589 }
590 auto pageId = context->GetStageManager()->GetLastPage()->GetPageId();
591 std::vector<RefPtr<NG::UINode>> children;
592 if (key.empty()) {
593 for (const auto& item : pageRootNode->GetChildren()) {
594 GetFrameNodeChildren(item, children, pageId, isLayoutInspector);
595 }
596 auto overlayNode = GetOverlayNode(pageRootNode);
597 if (overlayNode) {
598 GetFrameNodeChildren(overlayNode, children, pageId, isLayoutInspector);
599 }
600 } else {
601 children.emplace_back(pageRootNode);
602 }
603 return GetInspectorInfo(children, pageId, std::move(jsonRoot), isLayoutInspector, filter);
604 }
605
GetInspectorOfNode(RefPtr<NG::UINode> node)606 std::string Inspector::GetInspectorOfNode(RefPtr<NG::UINode> node)
607 {
608 auto jsonRoot = JsonUtil::Create(true);
609
610 auto context = NG::PipelineContext::GetCurrentContext();
611 CHECK_NULL_RETURN(context, jsonRoot->ToString());
612 GetContextInfo(context, jsonRoot);
613 CHECK_NULL_RETURN(node, jsonRoot->ToString());
614 auto pageId = context->GetStageManager()->GetLastPage()->GetPageId();
615 auto jsonNodeArray = JsonUtil::CreateArray(true);
616 GetInspectorChildren(node, jsonNodeArray, pageId, true, InspectorFilter(), 0);
617 if (jsonNodeArray->GetArraySize()) {
618 jsonRoot = jsonNodeArray->GetArrayItem(0);
619 GetContextInfo(context, jsonRoot);
620 }
621
622 return jsonRoot->ToString();
623 }
624
GetSubWindowInspector(bool isLayoutInspector)625 std::string Inspector::GetSubWindowInspector(bool isLayoutInspector)
626 {
627 auto jsonRoot = JsonUtil::Create(true);
628 jsonRoot->Put(INSPECTOR_TYPE, INSPECTOR_ROOT);
629
630 auto context = NG::PipelineContext::GetCurrentContext();
631 CHECK_NULL_RETURN(context, jsonRoot->ToString());
632 GetContextInfo(context, jsonRoot);
633 auto overlayNode = context->GetOverlayManager()->GetRootNode().Upgrade();
634 CHECK_NULL_RETURN(overlayNode, jsonRoot->ToString());
635 auto pageId = 0;
636 std::vector<RefPtr<NG::UINode>> children;
637 GetFrameNodeChildren(overlayNode, children, pageId, isLayoutInspector);
638
639 return GetInspectorInfo(children, 0, std::move(jsonRoot), isLayoutInspector);
640 }
641
FillSimplifiedInspectorAttrs(const RefPtr<NG::UINode> & parent,std::unique_ptr<OHOS::Ace::JsonValue> & jsonNode)642 void FillSimplifiedInspectorAttrs(const RefPtr<NG::UINode>& parent, std::unique_ptr<OHOS::Ace::JsonValue>& jsonNode)
643 {
644 auto tmpJson = JsonUtil::Create(true);
645
646 InspectorFilter filter;
647 parent->ToJsonValue(tmpJson, filter);
648 jsonNode->Put(INSPECTOR_ATTR_ID, tmpJson->GetString(INSPECTOR_ATTR_ID).c_str());
649
650 auto jsonObject = JsonUtil::Create(true);
651 if (tmpJson->Contains(INSPECTOR_LABEL)) {
652 jsonObject->Put(INSPECTOR_LABEL, tmpJson->GetString(INSPECTOR_LABEL).c_str());
653 }
654 if (tmpJson->Contains(INSPECTOR_CONTENT)) {
655 jsonObject->Put(INSPECTOR_CONTENT, tmpJson->GetString(INSPECTOR_CONTENT).c_str());
656 }
657 jsonObject->Put(INSPECTOR_ENABLED, tmpJson->GetBool(INSPECTOR_ENABLED));
658 jsonObject->Put(INSPECTOR_OPACITY, tmpJson->GetDouble(INSPECTOR_OPACITY));
659 jsonObject->Put(INSPECTOR_ZINDEX, tmpJson->GetInt(INSPECTOR_ZINDEX));
660 jsonObject->Put(INSPECTOR_VISIBILITY, tmpJson->GetString(INSPECTOR_VISIBILITY).c_str());
661 jsonNode->PutRef(INSPECTOR_ATTRS, std::move(jsonObject));
662 }
663
GetSimplifiedSpanInspector(const RefPtr<NG::UINode> & parent,std::unique_ptr<OHOS::Ace::JsonValue> & jsonNodeArray,int pageId)664 void GetSimplifiedSpanInspector(
665 const RefPtr<NG::UINode>& parent, std::unique_ptr<OHOS::Ace::JsonValue>& jsonNodeArray, int pageId)
666 {
667 // span rect follows parent text size
668 auto spanParentNode = parent->GetParent();
669 CHECK_NULL_VOID(spanParentNode);
670 auto node = AceType::DynamicCast<FrameNode>(spanParentNode);
671 CHECK_NULL_VOID(node);
672 auto jsonNode = JsonUtil::Create(true);
673
674 FillSimplifiedInspectorAttrs(parent, jsonNode);
675
676 jsonNode->Put(INSPECTOR_TYPE, parent->GetTag().c_str());
677 RectF rect = node->GetTransformRectRelativeToWindow();
678 jsonNode->Put(INSPECTOR_RECT, rect.ToBounds().c_str());
679 jsonNodeArray->PutRef(std::move(jsonNode));
680 }
681
GetSimplifiedInspectorChildren(const RefPtr<NG::UINode> & parent,std::unique_ptr<OHOS::Ace::JsonValue> & jsonNodeArray,int pageId,bool isActive)682 void GetSimplifiedInspectorChildren(
683 const RefPtr<NG::UINode>& parent, std::unique_ptr<OHOS::Ace::JsonValue>& jsonNodeArray, int pageId, bool isActive)
684 {
685 // Span is a special case in Inspector since span inherits from UINode
686 if (AceType::InstanceOf<SpanNode>(parent)) {
687 GetSimplifiedSpanInspector(parent, jsonNodeArray, pageId);
688 return;
689 }
690 auto jsonNode = JsonUtil::Create(true);
691 jsonNode->Put(INSPECTOR_TYPE, parent->GetTag().c_str());
692 auto node = AceType::DynamicCast<FrameNode>(parent);
693
694 RectF rect;
695 isActive = isActive && node->IsActive();
696 if (isActive) {
697 rect = node->GetTransformRectRelativeToWindow();
698 }
699
700 jsonNode->Put(INSPECTOR_RECT, rect.ToBounds().c_str());
701
702 FillSimplifiedInspectorAttrs(parent, jsonNode);
703
704 std::vector<RefPtr<NG::UINode>> children;
705 for (const auto& item : parent->GetChildren()) {
706 GetFrameNodeChildren(item, children, pageId);
707 }
708 auto jsonChildrenArray = JsonUtil::CreateArray(true);
709 for (auto uiNode : children) {
710 GetSimplifiedInspectorChildren(uiNode, jsonChildrenArray, pageId, isActive);
711 }
712 if (jsonChildrenArray->GetArraySize()) {
713 jsonNode->PutRef(INSPECTOR_CHILDREN, std::move(jsonChildrenArray));
714 }
715 jsonNodeArray->PutRef(std::move(jsonNode));
716 }
717
GetSimplifiedInspector(int32_t containerId)718 std::string Inspector::GetSimplifiedInspector(int32_t containerId)
719 {
720 TAG_LOGI(AceLogTag::ACE_UIEVENT, "GetSimplifiedInspector start: container %{public}d", containerId);
721 auto jsonRoot = JsonUtil::Create(true);
722 jsonRoot->Put(INSPECTOR_TYPE, INSPECTOR_ROOT);
723
724 auto context = NG::PipelineContext::GetContextByContainerId(containerId);
725 CHECK_NULL_RETURN(context, jsonRoot->ToString());
726 auto scale = context->GetViewScale();
727 auto rootHeight = context->GetRootHeight();
728 auto rootWidth = context->GetRootWidth();
729 deviceRect.SetRect(0, 0, rootWidth * scale, rootHeight * scale);
730 jsonRoot->Put(INSPECTOR_WIDTH, std::to_string(rootWidth * scale).c_str());
731 jsonRoot->Put(INSPECTOR_HEIGHT, std::to_string(rootHeight * scale).c_str());
732 jsonRoot->Put(INSPECTOR_RESOLUTION, std::to_string(SystemProperties::GetResolution()).c_str());
733
734 auto pageRootNode = context->GetStageManager()->GetLastPage();
735 CHECK_NULL_RETURN(pageRootNode, jsonRoot->ToString());
736
737 auto pagePattern = pageRootNode->GetPattern<PagePattern>();
738 CHECK_NULL_RETURN(pagePattern, jsonRoot->ToString());
739 auto pageInfo = pagePattern->GetPageInfo();
740 CHECK_NULL_RETURN(pageInfo, jsonRoot->ToString());
741 jsonRoot->Put(INSPECTOR_PAGE_URL, pageInfo->GetPageUrl().c_str());
742 jsonRoot->Put(INSPECTOR_NAV_DST_NAME, Recorder::EventRecorder::Get().GetNavDstName().c_str());
743
744 auto pageId = context->GetStageManager()->GetLastPage()->GetPageId();
745 std::vector<RefPtr<NG::UINode>> children;
746 for (const auto& item : pageRootNode->GetChildren()) {
747 GetFrameNodeChildren(item, children, pageId);
748 }
749 auto overlayNode = GetOverlayNode(pageRootNode);
750 if (overlayNode) {
751 GetFrameNodeChildren(overlayNode, children, pageId);
752 }
753 auto jsonNodeArray = JsonUtil::CreateArray(true);
754 for (auto& uiNode : children) {
755 GetSimplifiedInspectorChildren(uiNode, jsonNodeArray, pageId, true);
756 }
757 if (jsonNodeArray->GetArraySize()) {
758 jsonRoot->PutRef(INSPECTOR_CHILDREN, std::move(jsonNodeArray));
759 }
760
761 return jsonRoot->ToString();
762 }
763
SendEventByKey(const std::string & key,int action,const std::string & params)764 bool Inspector::SendEventByKey(const std::string& key, int action, const std::string& params)
765 {
766 auto context = NG::PipelineContext::GetCurrentContext();
767 CHECK_NULL_RETURN(context, false);
768 auto rootNode = context->GetRootElement();
769 CHECK_NULL_RETURN(rootNode, false);
770
771 auto inspectorElement = AceType::DynamicCast<FrameNode>(GetInspectorByKey(rootNode, key));
772 CHECK_NULL_RETURN(inspectorElement, false);
773
774 auto size = inspectorElement->GetGeometryNode()->GetFrameSize();
775 auto offset = inspectorElement->GetTransformRelativeOffset();
776 Rect rect { offset.GetX(), offset.GetY(), size.Width(), size.Height() };
777 context->GetTaskExecutor()->PostTask(
778 [weak = AceType::WeakClaim(AceType::RawPtr(context)), rect, action, params]() {
779 auto context = weak.Upgrade();
780 if (!context) {
781 return;
782 }
783 TouchEvent point;
784 point.SetX(static_cast<float>(rect.Left() + rect.Width() / 2))
785 .SetY(static_cast<float>(rect.Top() + rect.Height() / 2))
786 .SetType(TouchType::DOWN)
787 .SetTime(std::chrono::high_resolution_clock::now())
788 .SetSourceType(SourceType::TOUCH);
789 context->OnTouchEvent(point.UpdatePointers());
790
791 switch (action) {
792 case static_cast<int>(AceAction::ACTION_CLICK): {
793 context->OnTouchEvent(GetUpPoint(point).UpdatePointers());
794 break;
795 }
796 case static_cast<int>(AceAction::ACTION_LONG_CLICK): {
797 CancelableCallback<void()> inspectorTimer;
798 auto&& callback = [weak, point]() {
799 auto refPtr = weak.Upgrade();
800 if (refPtr) {
801 refPtr->OnTouchEvent(GetUpPoint(point).UpdatePointers());
802 }
803 };
804 inspectorTimer.Reset(callback);
805 auto taskExecutor =
806 SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
807 taskExecutor.PostDelayedTask(inspectorTimer, LONG_PRESS_DELAY, "ArkUIInspectorLongPressTouchEvent");
808 break;
809 }
810 default:
811 break;
812 }
813 },
814 TaskExecutor::TaskType::UI, "ArkUIInspectorSendEventByKey");
815
816 return true;
817 }
818
HideAllMenus()819 void Inspector::HideAllMenus()
820 {
821 auto context = NG::PipelineContext::GetCurrentContext();
822 CHECK_NULL_VOID(context);
823 auto overlayManager = context->GetOverlayManager();
824 CHECK_NULL_VOID(overlayManager);
825 overlayManager->HideAllMenus();
826 }
827
AddOffscreenNode(RefPtr<FrameNode> node)828 void Inspector::AddOffscreenNode(RefPtr<FrameNode> node)
829 {
830 CHECK_NULL_VOID(node);
831 offscreenNodes.insert(node);
832 }
833
RemoveOffscreenNode(RefPtr<FrameNode> node)834 void Inspector::RemoveOffscreenNode(RefPtr<FrameNode> node)
835 {
836 CHECK_NULL_VOID(node);
837 offscreenNodes.erase(node);
838 }
839
840 } // namespace OHOS::Ace::NG
841