1 /*
2 * Copyright (c) 2021-2022 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 "inspector.h"
17
18 #include "inspector_composed_element.h"
19 #include "shape_composed_element.h"
20
21 #include "core/common/ace_application_info.h"
22 #include "core/components/page/page_element.h"
23 #include "core/components/root/root_element.h"
24
25 namespace OHOS::Ace::V2 {
26 namespace {
27 const char IFELSE_ELEMENT_TAG[] = "IfElseElement";
28 const char INSPECTOR_TYPE[] = "$type";
29 const char INSPECTOR_ROOT[] = "root";
30 const char INSPECTOR_WIDTH[] = "width";
31 const char INSPECTOR_HEIGHT[] = "height";
32 const char INSPECTOR_RESOLUTION[] = "$resolution";
33 const char INSPECTOR_CHILDREN[] = "$children";
34 const char INSPECTOR_ID[] = "$ID";
35 const char INSPECTOR_RECT[] = "$rect";
36 const char INSPECTOR_Z_INDEX[] = "$z-index";
37 const char INSPECTOR_ATTRS[] = "$attrs";
38 #if defined(PREVIEW)
39 const char INSPECTOR_DEBUGLINE[] = "$debugLine";
40 #endif
41
GetInspectorByKey(const RefPtr<RootElement> & root,const std::string & key)42 RefPtr<V2::InspectorComposedElement> GetInspectorByKey(const RefPtr<RootElement>& root, const std::string& key)
43 {
44 std::queue<RefPtr<Element>> elements;
45 elements.push(root);
46 RefPtr<V2::InspectorComposedElement> inspectorElement;
47 while (!elements.empty()) {
48 auto current = elements.front();
49 elements.pop();
50 inspectorElement = AceType::DynamicCast<V2::InspectorComposedElement>(current);
51 if (inspectorElement != nullptr) {
52 if (key == inspectorElement->GetKey()) {
53 return inspectorElement;
54 }
55 }
56 const auto& children = current->GetChildren();
57 for (auto& child : children) {
58 elements.push(child);
59 }
60 }
61 return nullptr;
62 }
63
GetInspectorChildren(const RefPtr<Element> & element,std::list<RefPtr<Element>> & childrenList)64 void GetInspectorChildren(const RefPtr<Element>& element, std::list<RefPtr<Element>>& childrenList)
65 {
66 if (element->GetChildren().empty()) {
67 return;
68 }
69 const auto& children = element->GetChildren();
70 for (auto& childElement : children) {
71 if (AceType::InstanceOf<V2::InspectorComposedElement>(childElement)) {
72 childrenList.emplace_back(childElement);
73 } else {
74 GetInspectorChildren(childElement, childrenList);
75 }
76 }
77 }
78
DumpInspectorTree(const RefPtr<Element> & element,std::map<RefPtr<Element>,std::list<RefPtr<Element>>> & inspectorTreeMap)79 void DumpInspectorTree(
80 const RefPtr<Element>& element, std::map<RefPtr<Element>, std::list<RefPtr<Element>>>& inspectorTreeMap)
81 {
82 std::list<RefPtr<Element>> childrenList;
83 GetInspectorChildren(element, childrenList);
84 if (childrenList.empty()) {
85 return;
86 }
87 inspectorTreeMap.emplace(element, childrenList);
88 for (const auto& child : childrenList) {
89 DumpInspectorTree(child, inspectorTreeMap);
90 }
91 }
92
ToJsonValue(const RefPtr<Element> & element,const std::map<RefPtr<Element>,std::list<RefPtr<Element>>> & inspectorTree,std::unique_ptr<JsonValue> & json)93 void ToJsonValue(const RefPtr<Element>& element,
94 const std::map<RefPtr<Element>, std::list<RefPtr<Element>>>& inspectorTree, std::unique_ptr<JsonValue>& json)
95 {
96 auto inspectorElement = AceType::DynamicCast<V2::InspectorComposedElement>(element);
97 if (inspectorElement == nullptr) {
98 return;
99 }
100 json->Put(INSPECTOR_TYPE, inspectorElement->GetTag().c_str());
101 auto shapeComposedElement = AceType::DynamicCast<V2::ShapeComposedElement>(element);
102 if (shapeComposedElement != nullptr) {
103 int type = StringUtils::StringToInt(shapeComposedElement->GetShapeType());
104 json->Replace(INSPECTOR_TYPE, SHAPE_TYPE_STRINGS[type]);
105 }
106 json->Put(INSPECTOR_ID, std::stoi(inspectorElement->GetId()));
107 json->Put(INSPECTOR_Z_INDEX, inspectorElement->GetZIndex());
108 json->Put(INSPECTOR_RECT, inspectorElement->GetRenderRect().ToBounds().c_str());
109 auto jsonObject = inspectorElement->ToJsonObject();
110 json->Put(INSPECTOR_ATTRS, jsonObject);
111
112 auto iter = inspectorTree.find(element);
113 if (iter == inspectorTree.end()) {
114 return;
115 }
116
117 auto jsonNodeArray = JsonUtil::CreateArray(true);
118 for (const auto& child : iter->second) {
119 auto jsonChild = JsonUtil::Create(true);
120 ToJsonValue(child, inspectorTree, jsonChild);
121 jsonNodeArray->Put(jsonChild);
122 }
123 json->Put(INSPECTOR_CHILDREN, jsonNodeArray);
124 }
125
DumpElementTree(int32_t depth,const RefPtr<Element> & element,std::map<int32_t,std::list<RefPtr<Element>>> & depthElementMap)126 void DumpElementTree(
127 int32_t depth, const RefPtr<Element>& element, std::map<int32_t, std::list<RefPtr<Element>>>& depthElementMap)
128 {
129 if (element->GetChildren().empty()) {
130 return;
131 }
132 const auto& children = element->GetChildren();
133 for (auto& depthElement : children) {
134 if (strcmp(AceType::TypeName(depthElement), IFELSE_ELEMENT_TAG) == 0) {
135 DumpElementTree(depth, depthElement, depthElementMap);
136 continue;
137 }
138 depthElementMap[depth].insert(depthElementMap[depth].end(), depthElement);
139 DumpElementTree(depth + 1, depthElement, depthElementMap);
140 }
141 }
142 } // namespace
143
GetInspectorNodeByKey(const RefPtr<PipelineContext> & context,const std::string & key)144 std::string Inspector::GetInspectorNodeByKey(const RefPtr<PipelineContext>& context, const std::string& key)
145 {
146 auto inspectorElement = GetInspectorByKey(context->GetRootElement(), key);
147 if (inspectorElement == nullptr) {
148 LOGE("no inspector with key:%{public}s is found", key.c_str());
149 return "";
150 }
151
152 auto jsonNode = JsonUtil::Create(true);
153 jsonNode->Put(INSPECTOR_TYPE, inspectorElement->GetTag().c_str());
154 jsonNode->Put(INSPECTOR_ID, std::stoi(inspectorElement->GetId()));
155 jsonNode->Put(INSPECTOR_Z_INDEX, inspectorElement->GetZIndex());
156 jsonNode->Put(INSPECTOR_RECT, inspectorElement->GetRenderRect().ToBounds().c_str());
157 #if defined(PREVIEW)
158 std::string debugLine = inspectorElement->GetDebugLine();
159 jsonNode->Put(INSPECTOR_DEBUGLINE, debugLine.c_str());
160 #endif
161 auto jsonObject = inspectorElement->ToJsonObject();
162 jsonNode->Put(INSPECTOR_ATTRS, jsonObject);
163 return jsonNode->ToString();
164 }
165
GetInspectorTree(const RefPtr<PipelineContext> & context,bool isLayoutInspector)166 std::string Inspector::GetInspectorTree(const RefPtr<PipelineContext>& context, bool isLayoutInspector)
167 {
168 LOGI("GetInspectorTree start");
169 auto jsonRoot = JsonUtil::Create(true);
170 jsonRoot->Put(INSPECTOR_TYPE, INSPECTOR_ROOT);
171
172 float scale = context->GetViewScale();
173 double rootHeight = context->GetRootHeight();
174 double rootWidth = context->GetRootWidth();
175 jsonRoot->Put(INSPECTOR_WIDTH, std::to_string(rootWidth * scale).c_str());
176 jsonRoot->Put(INSPECTOR_HEIGHT, std::to_string(rootHeight * scale).c_str());
177 jsonRoot->Put(INSPECTOR_RESOLUTION, std::to_string(SystemProperties::GetResolution()).c_str());
178
179 auto root = AceType::DynamicCast<Element>(context->GetRootElement());
180 if (root == nullptr) {
181 return jsonRoot->ToString();
182 }
183
184 auto pageElement = AceType::DynamicCast<Element>(context->GetLastPage());
185 if (pageElement == nullptr) {
186 return jsonRoot->ToString();
187 }
188 std::map<RefPtr<Element>, std::list<RefPtr<Element>>> inspectorTree;
189 DumpInspectorTree(pageElement, inspectorTree);
190 auto pageChildren = inspectorTree.find(pageElement);
191 if (pageChildren != inspectorTree.end()) {
192 auto jsonNodeArray = JsonUtil::CreateArray(true);
193 for (const auto& child : pageChildren->second) {
194 auto jsonChild = JsonUtil::Create(true);
195 ToJsonValue(child, inspectorTree, jsonChild);
196 jsonNodeArray->Put(jsonChild);
197 }
198 jsonRoot->Put(INSPECTOR_CHILDREN, jsonNodeArray);
199 }
200
201 if (isLayoutInspector) {
202 auto jsonTree = JsonUtil::Create(true);
203 jsonTree->Put("type", "root");
204 jsonTree->Put("content", jsonRoot);
205 return jsonTree->ToString();
206 }
207 return jsonRoot->ToString();
208 }
209
SendEventByKey(const RefPtr<PipelineContext> & context,const std::string & key,int action,const std::string & params)210 bool Inspector::SendEventByKey(
211 const RefPtr<PipelineContext>& context, const std::string& key, int action, const std::string& params)
212 {
213 auto inspectorElement = GetInspectorByKey(context->GetRootElement(), key);
214 if (inspectorElement == nullptr) {
215 LOGE("no inspector with key:%s is found", key.c_str());
216 return false;
217 }
218
219 Rect rect = inspectorElement->GetRenderRect();
220
221 context->GetTaskExecutor()->PostTask(
222 [weak = AceType::WeakClaim(AceType::RawPtr(context)), rect, action, params, inspectorElement]() {
223 auto context = weak.Upgrade();
224 if (!context) {
225 return;
226 }
227
228 TouchEvent point { .x = static_cast<float>(rect.Left() + rect.Width() / 2),
229 .y = static_cast<float>(rect.Top() + rect.Height() / 2),
230 .type = TouchType::DOWN,
231 .time = std::chrono::high_resolution_clock::now() };
232 context->OnTouchEvent(point);
233
234 switch (action) {
235 case static_cast<int>(AceAction::ACTION_CLICK): {
236 TouchEvent upPoint { .x = point.x,
237 .y = point.y,
238 .type = TouchType::UP,
239 .time = std::chrono::high_resolution_clock::now() };
240 context->OnTouchEvent(upPoint);
241 break;
242 }
243 case static_cast<int>(AceAction::ACTION_LONG_CLICK): {
244 CancelableCallback<void()> inspectorTimer;
245 auto&& callback = [weak, point]() {
246 auto refPtr = weak.Upgrade();
247 if (refPtr) {
248 TouchEvent upPoint { .x = point.x,
249 .y = point.y,
250 .type = TouchType::UP,
251 .time = std::chrono::high_resolution_clock::now() };
252 refPtr->OnTouchEvent(upPoint);
253 }
254 };
255 inspectorTimer.Reset(callback);
256 auto taskExecutor =
257 SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
258 taskExecutor.PostDelayedTask(inspectorTimer, 1000);
259 break;
260 }
261 default:
262 break;
263 }
264 },
265 TaskExecutor::TaskType::UI);
266
267 return true;
268 }
269
SendKeyEvent(const RefPtr<PipelineContext> & context,const JsKeyEvent & event)270 bool Inspector::SendKeyEvent(const RefPtr<PipelineContext>& context, const JsKeyEvent& event)
271 {
272 KeyEvent keyEvent(event.code, event.action);
273 keyEvent.metaKey = event.metaKey;
274 keyEvent.deviceId = event.deviceId;
275 keyEvent.repeatTime = 0;
276 keyEvent.SetTimeStamp(event.timeStamp);
277 keyEvent.sourceType = static_cast<SourceType>(event.sourceDevice);
278 return context->GetTaskExecutor()->PostTask(
279 [context, keyEvent]() { context->OnKeyEvent(keyEvent); }, TaskExecutor::TaskType::UI);
280 }
281 } // namespace OHOS::Ace::V2
282