1 /*
2 * Copyright (c) 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/distributed_ui.h"
17
18 #include <chrono>
19 #include <unordered_map>
20
21 #include "base/ressched/ressched_report.h"
22 #include "core/components_ng/pattern/common_view/common_view_pattern.h"
23 #include "core/components_ng/pattern/custom/custom_node.h"
24 #include "core/components_ng/pattern/divider/divider_pattern.h"
25 #include "core/components_ng/pattern/flex/flex_layout_pattern.h"
26 #include "core/components_ng/pattern/image/image_pattern.h"
27 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
28 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
29 #include "core/components_ng/pattern/list/list_item_pattern.h"
30 #include "core/components_ng/pattern/list/list_pattern.h"
31 #include "core/components_ng/pattern/stack/stack_pattern.h"
32 #include "core/components_ng/pattern/stage/page_pattern.h"
33 #include "core/components_ng/pattern/swiper/swiper_pattern.h"
34 #include "core/components_ng/pattern/tabs/tab_bar_pattern.h"
35 #include "core/components_ng/pattern/tabs/tab_content_node.h"
36 #include "core/components_ng/pattern/tabs/tab_content_pattern.h"
37 #include "core/components_ng/pattern/tabs/tabs_model_ng.h"
38 #include "core/components_ng/pattern/tabs/tabs_pattern.h"
39 #include "core/components_ng/pattern/text/text_model_ng.h"
40 #include "core/components_ng/pattern/text/text_pattern.h"
41 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
42 #include "core/components_ng/syntax/for_each_node.h"
43 #include "core/components_ng/syntax/if_else_node.h"
44 #include "core/components_ng/syntax/lazy_for_each_node.h"
45 #include "core/components_ng/syntax/syntax_item.h"
46 #include "core/components_v2/inspector/inspector_constants.h"
47 #include "core/pipeline/base/element_register.h"
48 #include "core/pipeline_ng/pipeline_context.h"
49
50 namespace OHOS::Ace::NG {
51 namespace {
52 const char DISTRIBUTE_UI_TYPE[] = "$type";
53 const char DISTRIBUTE_UI_ID[] = "$ID";
54 const char DISTRIBUTE_UI_ATTRS[] = "$attrs";
55 const char DISTRIBUTE_UI_PARENT[] = "$parent";
56 const char DISTRIBUTE_UI_DEPTH[] = "$depth";
57 const char DISTRIBUTE_UI_OPERATION[] = "$op";
58
59 const int32_t HANDLE_UPDATE_PER_VSYNC = 1;
60
RestorePageNode(const RefPtr<NG::FrameNode> & pageNode)61 void RestorePageNode(const RefPtr<NG::FrameNode>& pageNode)
62 {
63 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
64 CHECK_NULL_VOID(pagePattern);
65 pagePattern->SetOnBackPressed([]() { return true; });
66 }
67 } // namespace
68
DumpUITree()69 SerializeableObjectArray DistributedUI::DumpUITree()
70 {
71 LOGD("UITree interface start");
72 #ifdef ACE_DEBUG_LOG
73 auto timeStart = std::chrono::high_resolution_clock::now();
74 #endif
75
76 ResetDirtyNodes();
77
78 auto context = NG::PipelineContext::GetCurrentContext();
79 CHECK_NULL_RETURN_NOLOG(context, SerializeableObjectArray());
80 auto pageRootNode = currentPageId_ ? context->GetStageManager()->GetPageById(currentPageId_)
81 : context->GetStageManager()->GetLastPage();
82 CHECK_NULL_RETURN_NOLOG(pageRootNode, SerializeableObjectArray());
83 LOGD("UITree Dump page: %{public}d", pageRootNode->GetPageId());
84
85 SerializeableObjectArray objectArray;
86 auto children = pageRootNode->GetChildren();
87 for (const auto& uiNode : children) {
88 DumpTreeInner(uiNode, objectArray, 1);
89 }
90
91 status_ = StateMachine::SOURCE_START;
92
93 #ifdef ACE_DEBUG_LOG
94 auto timeEnd = std::chrono::high_resolution_clock::now();
95 LOGD("UITree process use %{public}lld ms",
96 static_cast<long long>(std::chrono::duration_cast<std::chrono::milliseconds>(timeEnd - timeStart).count()));
97 #endif
98 return objectArray;
99 }
100
SubscribeUpdate(const std::function<void (int32_t,SerializeableObjectArray &)> & onUpdate)101 void DistributedUI::SubscribeUpdate(const std::function<void(int32_t, SerializeableObjectArray&)>& onUpdate)
102 {
103 LOGD("UITree Subscribe Update");
104 onUpdateCb_ = std::move(onUpdate);
105 }
106
UnSubscribeUpdate()107 void DistributedUI::UnSubscribeUpdate()
108 {
109 onUpdateCb_ = nullptr;
110 status_ = StateMachine::STOP;
111 }
112
ProcessSerializeableInputEvent(const SerializeableObjectArray & array)113 void DistributedUI::ProcessSerializeableInputEvent(const SerializeableObjectArray& array)
114 {
115 LOGD("UITree interface start");
116 #ifdef ACE_DEBUG_LOG
117 auto timeStart = std::chrono::high_resolution_clock::now();
118 #endif
119
120 auto context = NG::PipelineContext::GetCurrentContext();
121 CHECK_NULL_VOID_NOLOG(context);
122
123 TouchEvent event;
124 std::unique_ptr<JsonValue>& json = (std::unique_ptr<JsonValue>&)array.front();
125 event.FromJson(json);
126 bool isSubPipe = json->GetBool("sub");
127
128 context->OnTouchEvent(event, isSubPipe);
129
130 #ifdef ACE_DEBUG_LOG
131 auto timeEnd = std::chrono::high_resolution_clock::now();
132 LOGD("UITree process use %{public}lld ms",
133 static_cast<long long>(std::chrono::duration_cast<std::chrono::milliseconds>(timeEnd - timeStart).count()));
134 #endif
135 }
136
RestoreUITree(const SerializeableObjectArray & array)137 void DistributedUI::RestoreUITree(const SerializeableObjectArray& array)
138 {
139 LOGD("UITree interface start");
140 #ifdef ACE_DEBUG_LOG
141 auto timeStart = std::chrono::high_resolution_clock::now();
142 #endif
143
144 status_ = StateMachine::SINK_START;
145 RestoreUITreeInner(array);
146
147 #ifdef ACE_DEBUG_LOG
148 auto timeEnd = std::chrono::high_resolution_clock::now();
149 LOGD("UITree process use %{public}lld ms",
150 static_cast<long long>(std::chrono::duration_cast<std::chrono::milliseconds>(timeEnd - timeStart).count()));
151 #endif
152 }
153
UpdateUITree(const SerializeableObjectArray & array)154 void DistributedUI::UpdateUITree(const SerializeableObjectArray& array)
155 {
156 LOGD("UITree interface start");
157 if (status_ != StateMachine::SINK_START) {
158 LOGE("UpdateUITree failed. status=%{public}d", static_cast<uint8_t>(status_));
159 return;
160 }
161 pendingUpdates_.emplace_back(std::move((SerializeableObjectArray&)array));
162
163 auto context = NG::PipelineContext::GetCurrentContext();
164 CHECK_NULL_VOID_NOLOG(context);
165 context->RequestFrame();
166 }
167
SubscribeInputEventProcess(const std::function<void (SerializeableObjectArray &)> & onEvent)168 void DistributedUI::SubscribeInputEventProcess(const std::function<void(SerializeableObjectArray&)>& onEvent)
169 {
170 LOGD("UITree Subscribe Event");
171 onEventCb_ = std::move(onEvent);
172 }
173
UnSubscribeInputEventProcess()174 void DistributedUI::UnSubscribeInputEventProcess()
175 {
176 onEventCb_ = nullptr;
177 status_ = StateMachine::STOP;
178 pendingUpdates_.clear();
179 }
180
AddDeletedNode(int32_t nodeId)181 void DistributedUI::AddDeletedNode(int32_t nodeId)
182 {
183 if (!ReadyToDumpUpdate()) {
184 return;
185 }
186 deletedNodes_.emplace(nodeId);
187 }
188
AddNewNode(int32_t nodeId)189 void DistributedUI::AddNewNode(int32_t nodeId)
190 {
191 if (!ReadyToDumpUpdate()) {
192 return;
193 }
194 newNodes_.emplace(nodeId);
195 }
196
AddDirtyCustomNode(int32_t nodeId)197 void DistributedUI::AddDirtyCustomNode(int32_t nodeId)
198 {
199 if (!ReadyToDumpUpdate()) {
200 return;
201 }
202 dirtyCustomNodes_.emplace(nodeId);
203 }
204
AddDirtyRenderNode(int32_t nodeId)205 void DistributedUI::AddDirtyRenderNode(int32_t nodeId)
206 {
207 if (!ReadyToDumpUpdate()) {
208 return;
209 }
210 dirtyRenderNodes_.emplace(nodeId);
211 }
212
AddDirtyLayoutNode(int32_t nodeId)213 void DistributedUI::AddDirtyLayoutNode(int32_t nodeId)
214 {
215 if (!ReadyToDumpUpdate()) {
216 return;
217 }
218 dirtyLayoutNodes_.emplace(nodeId);
219 }
220
OnTreeUpdate()221 void DistributedUI::OnTreeUpdate()
222 {
223 if (!ReadyToDumpUpdate()) {
224 return;
225 }
226
227 LOGD("UITree interface start");
228 #ifdef ACE_DEBUG_LOG
229 auto timeStart = std::chrono::high_resolution_clock::now();
230 #endif
231
232 DistributedUI::UpdateType updateType;
233 SerializeableObjectArray update;
234 if (pageChangeFlag_) {
235 LOGD("UITree page changed. dump currentPage:%{public}d", currentPageId_);
236 pageChangeFlag_ = false;
237 ResetDirtyNodes();
238 update = DumpUITree();
239 updateType = UpdateType::PAGE_CHANGE;
240 } else {
241 update = DumpUpdate();
242 if (update.empty()) {
243 LOGD("UITree no need to update");
244 return;
245 }
246 updateType = UpdateType::PAGE_UPDATE;
247 }
248
249 #ifdef ACE_DEBUG_LOG
250 auto timeEnd = std::chrono::high_resolution_clock::now();
251 LOGD("UITree process use %{public}lld ms",
252 static_cast<long long>(std::chrono::duration_cast<std::chrono::milliseconds>(timeEnd - timeStart).count()));
253 timeStart = timeEnd;
254 #endif
255
256 if (onUpdateCb_) {
257 onUpdateCb_(updateType, update);
258 }
259
260 #ifdef ACE_DEBUG_LOG
261 timeEnd = std::chrono::high_resolution_clock::now();
262 LOGD("UITree send process use %{public}lld ms",
263 static_cast<long long>(std::chrono::duration_cast<std::chrono::milliseconds>(timeEnd - timeStart).count()));
264 #endif
265 }
266
OnPageChanged(int32_t pageId)267 void DistributedUI::OnPageChanged(int32_t pageId)
268 {
269 if (status_ == StateMachine::SOURCE_START) {
270 pageChangeFlag_ = true;
271 }
272 currentPageId_ = pageId;
273 LOGD("UITree OnPageChanged to %{public}d", pageId);
274 }
275
GetCurrentPageId()276 int32_t DistributedUI::GetCurrentPageId()
277 {
278 return currentPageId_;
279 }
280
BypassEvent(const TouchEvent & point,bool isSubPipe)281 void DistributedUI::BypassEvent(const TouchEvent& point, bool isSubPipe)
282 {
283 LOGD("UITree interface start");
284 #ifdef ACE_DEBUG_LOG
285 auto timeStart = std::chrono::high_resolution_clock::now();
286 #endif
287
288 std::unique_ptr<JsonValue> json = NodeObject::Create();
289 point.ToJsonValue(json);
290 json->Put("sub", isSubPipe);
291 SerializeableObjectArray eventArray;
292 eventArray.push_back(std::move((std::unique_ptr<NodeObject>&)json));
293
294 #ifdef ACE_DEBUG_LOG
295 auto timeEnd = std::chrono::high_resolution_clock::now();
296 LOGD("UITree process use %{public}lld ms",
297 static_cast<long long>(std::chrono::duration_cast<std::chrono::milliseconds>(timeEnd - timeStart).count()));
298 timeStart = timeEnd;
299 #endif
300
301 if (onEventCb_) {
302 onEventCb_(eventArray);
303 }
304
305 #ifdef ACE_DEBUG_LOG
306 timeEnd = std::chrono::high_resolution_clock::now();
307 LOGD("UITree send process use %{public}lld ms",
308 static_cast<long long>(std::chrono::duration_cast<std::chrono::milliseconds>(timeEnd - timeStart).count()));
309 #endif
310 }
311
IsSinkMode()312 bool DistributedUI::IsSinkMode()
313 {
314 if (onEventCb_ && status_ == StateMachine::SINK_START) {
315 return true;
316 }
317 return false;
318 }
319
ApplyOneUpdate()320 void DistributedUI::ApplyOneUpdate()
321 {
322 LOGD("UITree interface start");
323 #ifdef ACE_DEBUG_LOG
324 auto timeStart = std::chrono::high_resolution_clock::now();
325 #endif
326
327 LOGD("UITree pendingUpdates.size=%{public}zu", pendingUpdates_.size());
328 for (int i = 0; i < HANDLE_UPDATE_PER_VSYNC; i++) {
329 if (pendingUpdates_.empty()) {
330 return;
331 }
332 ResSchedReport::GetInstance().ResSchedDataReport("click");
333 auto update = std::move(pendingUpdates_.front());
334 pendingUpdates_.pop_front();
335 UpdateUITreeInner(update);
336 }
337
338 #ifdef ACE_DEBUG_LOG
339 auto timeEnd = std::chrono::high_resolution_clock::now();
340 LOGD("UITree process use %{public}lld ms",
341 static_cast<long long>(std::chrono::duration_cast<std::chrono::milliseconds>(timeEnd - timeStart).count()));
342 #endif
343 }
344
DumpDirtyRenderNodes(SerializeableObjectArray & objectArray)345 void DistributedUI::DumpDirtyRenderNodes(SerializeableObjectArray& objectArray)
346 {
347 for (const auto& nodeId : dirtyRenderNodes_) {
348 auto node = ElementRegister::GetInstance()->GetUINodeById(nodeId);
349 if (!node || !IsInCurrentPage(node, currentPageId_) || node->GetTag() == V2::PAGE_ETS_TAG) {
350 LOGE("UITree |ERROR| Node not found or not in current page. %{public}d", nodeId);
351 continue;
352 }
353 if (IsNewNode(nodeId)) {
354 continue;
355 }
356 LOGD("UITree dirty Render node: %{public}s%{public}d", node->GetTag().c_str(), nodeId);
357 auto nodeObject = NodeObject::Create();
358 DumpNode(node, -1, OperationType::OP_MODIFY, nodeObject);
359 if (IsRecordHash(nodeId, nodeObject->Hash())) {
360 objectArray.push_back(std::move(nodeObject));
361 }
362 }
363 }
364
DumpDirtyLayoutNodes(SerializeableObjectArray & objectArray)365 void DistributedUI::DumpDirtyLayoutNodes(SerializeableObjectArray& objectArray)
366 {
367 for (const auto& nodeId : dirtyLayoutNodes_) {
368 auto node = ElementRegister::GetInstance()->GetUINodeById(nodeId);
369 if (!node || !IsInCurrentPage(node, currentPageId_)) {
370 LOGE("UITree Node not found or not in current page. %{public}d", nodeId);
371 continue;
372 }
373 if (IsNewNode(nodeId)) {
374 continue;
375 }
376 LOGD("UITree dirty Layout node: %{public}s%{public}d", node->GetTag().c_str(), nodeId);
377 auto nodeObject = NodeObject::Create();
378 DumpNode(node, -1, OperationType::OP_MODIFY, nodeObject);
379 if (IsRecordHash(nodeId, nodeObject->Hash())) {
380 objectArray.push_back(std::move(nodeObject));
381 }
382 }
383 }
384
DumpNewNodes(SerializeableObjectArray & objectArray)385 void DistributedUI::DumpNewNodes(SerializeableObjectArray& objectArray)
386 {
387 for (const auto& nodeId : newNodes_) {
388 auto node = ElementRegister::GetInstance()->GetUINodeById(nodeId);
389 if (node) {
390 LOGD("UITree node");
391 }
392 if (!node || !IsInCurrentPage(node, currentPageId_)) {
393 LOGE("UITree |ERROR| Node not found or not in current page. %{public}d", nodeId);
394 continue;
395 }
396 LOGD("UITree new node: %{public}s%{public}d", node->GetTag().c_str(), nodeId);
397 auto nodeObject = NodeObject::Create();
398 DumpNode(node, -1, OperationType::OP_ADD, nodeObject);
399 AddNodeHash(nodeId, nodeObject->Hash());
400 objectArray.push_back(std::move(nodeObject));
401 }
402 }
403
DumpDelNodes(SerializeableObjectArray & objectArray)404 void DistributedUI::DumpDelNodes(SerializeableObjectArray& objectArray)
405 {
406 for (const auto& nodeId : deletedNodes_) {
407 LOGD("UITree del node: %{public}d", nodeId);
408 auto nodeObject = NodeObject::Create();
409 nodeObject->Put(DISTRIBUTE_UI_ID, nodeId);
410 nodeObject->Put(DISTRIBUTE_UI_OPERATION, static_cast<int32_t>(OperationType::OP_DELETE));
411 objectArray.push_back(std::move(nodeObject));
412 DelNodeHash(nodeId);
413 }
414 }
415
DumpUpdate()416 SerializeableObjectArray DistributedUI::DumpUpdate()
417 {
418 if (newNodes_.size() + dirtyRenderNodes_.size() + deletedNodes_.size() + dirtyLayoutNodes_.size() == 0) {
419 return SerializeableObjectArray();
420 }
421 #ifdef ACE_DEBUG_LOG
422 auto timeStart = std::chrono::high_resolution_clock::now();
423 #endif
424 SerializeableObjectArray objectArray;
425
426 DumpDirtyRenderNodes(objectArray);
427 DumpDirtyLayoutNodes(objectArray);
428 DumpNewNodes(objectArray);
429 DumpDelNodes(objectArray);
430 ResetDirtyNodes();
431
432 #ifdef ACE_DEBUG_LOG
433 auto timeEnd = std::chrono::high_resolution_clock::now();
434 LOGD("UITree process use %{public}lld ms",
435 static_cast<long long>(std::chrono::duration_cast<std::chrono::milliseconds>(timeEnd - timeStart).count()));
436 #endif
437 return objectArray;
438 }
439
ResetDirtyNodes()440 void DistributedUI::ResetDirtyNodes()
441 {
442 newNodes_.clear();
443 dirtyRenderNodes_.clear();
444 deletedNodes_.clear();
445 dirtyLayoutNodes_.clear();
446 }
447
IsNewNode(int32_t nodeId)448 bool DistributedUI::IsNewNode(int32_t nodeId)
449 {
450 if (newNodes_.find(nodeId) != newNodes_.end()) {
451 return true;
452 }
453 return false;
454 }
455
ReadyToDumpUpdate()456 bool DistributedUI::ReadyToDumpUpdate()
457 {
458 if (onUpdateCb_ && status_ == StateMachine::SOURCE_START) {
459 return true;
460 }
461 return false;
462 }
463
SetIdMapping(int32_t srcNodeId,int32_t sinkNodeId)464 void DistributedUI::SetIdMapping(int32_t srcNodeId, int32_t sinkNodeId)
465 {
466 if (nodeIdMapping_.count(srcNodeId)) {
467 LOGW("UITree |WARN| has mapping [%{public}d, %{public}d]", srcNodeId, nodeIdMapping_[srcNodeId]);
468 }
469 nodeIdMapping_[srcNodeId] = sinkNodeId;
470 LOGD("UITree set mapping [%{public}d, %{public}d]", srcNodeId, nodeIdMapping_[srcNodeId]);
471 }
472
GetIdMapping(int32_t srcNodeId)473 int32_t DistributedUI::GetIdMapping(int32_t srcNodeId)
474 {
475 int32_t sinkNodeId = ElementRegister::UndefinedElementId;
476 if (nodeIdMapping_.count(srcNodeId)) {
477 sinkNodeId = nodeIdMapping_[srcNodeId];
478 }
479 LOGD("UITree get mapping [%{public}d, %{public}d]", srcNodeId, sinkNodeId);
480 return sinkNodeId;
481 }
482
AddNodeHash(int32_t nodeId,std::size_t hashValue)483 void DistributedUI::AddNodeHash(int32_t nodeId, std::size_t hashValue)
484 {
485 nodeHashs_[nodeId] = hashValue;
486 LOGD("UITree add hash [%{public}d, %{public}zu]", nodeId, nodeHashs_.at(nodeId));
487 }
488
DelNodeHash(int32_t nodeId)489 void DistributedUI::DelNodeHash(int32_t nodeId)
490 {
491 if (nodeHashs_.count(nodeId)) {
492 LOGD("UITree del hash [%{public}d, %{public}zu]", nodeId, nodeHashs_.at(nodeId));
493 nodeHashs_.erase(nodeId);
494 }
495 }
496
IsRecordHash(int32_t nodeId,std::size_t hashValue)497 bool DistributedUI::IsRecordHash(int32_t nodeId, std::size_t hashValue)
498 {
499 if (nodeHashs_.count(nodeId) && nodeHashs_.at(nodeId) == hashValue) {
500 return false;
501 }
502 AddNodeHash(nodeId, hashValue);
503 return true;
504 }
505
DumpNode(const RefPtr<NG::UINode> & node,int depth,OperationType op,std::unique_ptr<NodeObject> & nodeObject)506 void DistributedUI::DumpNode(
507 const RefPtr<NG::UINode>& node, int depth, OperationType op, std::unique_ptr<NodeObject>& nodeObject)
508 {
509 nodeObject->Put(DISTRIBUTE_UI_TYPE, node->GetTag().c_str());
510 nodeObject->Put(DISTRIBUTE_UI_ID, node->GetId());
511 auto parent = node->GetParent();
512 if (!parent) {
513 LOGE("UITree |ERROR| parent not found %{public}d", node->GetId());
514 nodeObject->Put(DISTRIBUTE_UI_PARENT, -1);
515 } else {
516 nodeObject->Put(DISTRIBUTE_UI_PARENT, parent->GetId());
517 }
518 nodeObject->Put(DISTRIBUTE_UI_DEPTH, depth);
519 nodeObject->Put(DISTRIBUTE_UI_OPERATION, static_cast<int32_t>(op));
520
521 std::unique_ptr<JsonValue> childObject = NodeObject::Create();
522 node->ToJsonValue(childObject);
523 nodeObject->Put(DISTRIBUTE_UI_ATTRS, (std::unique_ptr<NodeObject>&)childObject);
524 }
525
DumpTreeInner(const RefPtr<NG::UINode> & node,SerializeableObjectArray & objectArray,int depth)526 void DistributedUI::DumpTreeInner(const RefPtr<NG::UINode>& node, SerializeableObjectArray& objectArray, int depth)
527 {
528 auto nodeObject = NodeObject::Create();
529 DumpNode(node, depth, OperationType::OP_ADD, nodeObject);
530 LOGD("UITree EstimateBufferSize=%{public}d", nodeObject->EstimateBufferSize());
531 AddNodeHash(node->GetId(), nodeObject->Hash());
532 objectArray.push_back(std::move(nodeObject));
533
534 auto children = node->GetChildren();
535 for (const auto& uiNode : children) {
536 DumpTreeInner(uiNode, objectArray, depth + 1);
537 }
538 }
539
RestoreNode(const std::unique_ptr<NodeObject> & nodeObject)540 RefPtr<UINode> DistributedUI::RestoreNode(const std::unique_ptr<NodeObject>& nodeObject)
541 {
542 static const std::unordered_map<std::string, std::function<RefPtr<UINode>(const std::string&, int32_t)>>
543 nodeCreate {
544 { V2::JS_VIEW_ETS_TAG, [](const std::string& type,
545 int32_t nodeId) { return NG::CustomNode::CreateCustomNode(nodeId, type); } },
546 { V2::TEXT_ETS_TAG,
547 [](const std::string& type, int32_t nodeId) {
548 return FrameNode::GetOrCreateFrameNode(
549 type, nodeId, []() { return AceType::MakeRefPtr<TextPattern>(); });
550 } },
551 { V2::COLUMN_ETS_TAG,
552 [](const std::string& type, int32_t nodeId) {
553 return FrameNode::GetOrCreateFrameNode(
554 type, nodeId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(true); });
555 } },
556 { V2::ROW_ETS_TAG,
557 [](const std::string& type, int32_t nodeId) {
558 return FrameNode::GetOrCreateFrameNode(
559 type, nodeId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(false); });
560 } },
561 { V2::LIST_ITEM_ETS_TAG,
562 [](const std::string& type, int32_t nodeId) {
563 return FrameNode::GetOrCreateFrameNode(type, nodeId,
564 []() { return AceType::MakeRefPtr<ListItemPattern>(nullptr, V2::ListItemStyle::NONE); });
565 } },
566 { V2::LIST_ETS_TAG,
567 [](const std::string& type, int32_t nodeId) {
568 return FrameNode::GetOrCreateFrameNode(
569 type, nodeId, []() { return AceType::MakeRefPtr<ListPattern>(); });
570 } },
571 { V2::STACK_ETS_TAG,
572 [](const std::string& type, int32_t nodeId) {
573 return FrameNode::GetOrCreateFrameNode(
574 type, nodeId, []() { return AceType::MakeRefPtr<StackPattern>(); });
575 } },
576 { V2::IMAGE_ETS_TAG,
577 [](const std::string& type, int32_t nodeId) {
578 return FrameNode::GetOrCreateFrameNode(
579 type, nodeId, []() { return AceType::MakeRefPtr<ImagePattern>(); });
580 } },
581 { V2::FLEX_ETS_TAG,
582 [](const std::string& type, int32_t nodeId) {
583 return FrameNode::GetOrCreateFrameNode(
584 type, nodeId, []() { return AceType::MakeRefPtr<FlexLayoutPattern>(); });
585 } },
586 { V2::TABS_ETS_TAG,
587 [](const std::string& type, int32_t nodeId) {
588 return TabsModelNG::GetOrCreateTabsNode(
589 type, nodeId, []() { return AceType::MakeRefPtr<TabsPattern>(); });
590 } },
591 { V2::TAB_BAR_ETS_TAG,
592 [](const std::string& type, int32_t nodeId) {
593 return FrameNode::GetOrCreateFrameNode(
594 type, nodeId, []() { return AceType::MakeRefPtr<TabBarPattern>(nullptr); });
595 } },
596 { V2::SWIPER_ETS_TAG,
597 [](const std::string& type, int32_t nodeId) {
598 return FrameNode::GetOrCreateFrameNode(
599 type, nodeId, []() { return AceType::MakeRefPtr<SwiperPattern>(); });
600 } },
601 { V2::TAB_CONTENT_ITEM_ETS_TAG,
602 [](const std::string& type, int32_t nodeId) {
603 return TabContentNode::GetOrCreateTabContentNode(
604 type, nodeId, []() { return AceType::MakeRefPtr<TabContentPattern>(nullptr); });
605 } },
606 { V2::COMMON_VIEW_ETS_TAG,
607 [](const std::string& type, int32_t nodeId) {
608 return FrameNode::GetOrCreateFrameNode(
609 type, nodeId, []() { return AceType::MakeRefPtr<CommonViewPattern>(); });
610 } },
611 { V2::JS_FOR_EACH_ETS_TAG,
612 [](const std::string& type, int32_t nodeId) { return ForEachNode::GetOrCreateForEachNode(nodeId); } },
613 { V2::JS_SYNTAX_ITEM_ETS_TAG,
614 [](const std::string& type, int32_t nodeId) { return SyntaxItem::CreateSyntaxItemNode(type); } },
615 { V2::JS_LAZY_FOR_EACH_ETS_TAG,
616 [](const std::string& type, int32_t nodeId) {
617 return LazyForEachNode::GetOrCreateLazyForEachNode(nodeId, nullptr);
618 } },
619 { V2::JS_IF_ELSE_ETS_TAG,
620 [](const std::string& type, int32_t nodeId) { return IfElseNode::GetOrCreateIfElseNode(nodeId); } },
621 { V2::TEXTINPUT_ETS_TAG,
622 [](const std::string& type, int32_t nodeId) {
623 return FrameNode::GetOrCreateFrameNode(
624 type, nodeId, []() { return AceType::MakeRefPtr<TextFieldPattern>(); });
625 } },
626 { V2::DIVIDER_ETS_TAG,
627 [](const std::string& type, int32_t nodeId) {
628 return FrameNode::GetOrCreateFrameNode(
629 type, nodeId, []() { return AceType::MakeRefPtr<DividerPattern>(); });
630 } },
631 };
632
633 auto type = nodeObject->GetString(DISTRIBUTE_UI_TYPE);
634 auto srcNodeId = nodeObject->GetInt(DISTRIBUTE_UI_ID);
635 auto srcParentNodeId = nodeObject->GetInt(DISTRIBUTE_UI_PARENT);
636 auto depth = nodeObject->GetInt(DISTRIBUTE_UI_DEPTH);
637 LOGD("UITree process type %{public}s id %{public}d pid %{public}d depth %{public}d", type.c_str(), srcNodeId,
638 srcParentNodeId, depth);
639
640 if (!nodeCreate.count(type)) {
641 LOGE("UITree |ERROR| found no type %{public}s id %{public}d pid %{public}d depth %{public}d", type.c_str(),
642 srcNodeId, srcParentNodeId, depth);
643 return nullptr;
644 }
645
646 if (!nodeObject->Contains(DISTRIBUTE_UI_ATTRS)) {
647 LOGE("UITree |ERROR| found no attrs");
648 return nullptr;
649 }
650 auto attrs = nodeObject->GetValue(DISTRIBUTE_UI_ATTRS);
651
652 auto sinkNodeId = srcNodeId == -1 ? -1 : ElementRegister::GetInstance()->MakeUniqueId();
653 if (ElementRegister::GetInstance()->GetUINodeById(sinkNodeId)) {
654 LOGE("UITree |ERROR| uiNode exist! id: %{public}d", sinkNodeId);
655 return nullptr;
656 }
657
658 RefPtr<UINode> uiNode = nullptr;
659 if (type == V2::JS_VIEW_ETS_TAG) {
660 uiNode = nodeCreate.at(type)(attrs->GetString("viewKey"), sinkNodeId);
661 } else if (type == V2::JS_SYNTAX_ITEM_ETS_TAG) {
662 uiNode = nodeCreate.at(type)(attrs->GetString("key"), sinkNodeId);
663 } else {
664 uiNode = nodeCreate.at(type)(type, sinkNodeId);
665 }
666 if (!uiNode) {
667 LOGE("UITree |ERROR| node create failed!");
668 return nullptr;
669 }
670
671 SetIdMapping(srcNodeId, uiNode->GetId());
672 uiNode->FromJson(attrs);
673
674 if (type == V2::IMAGE_ETS_TAG) {
675 AceType::DynamicCast<NG::FrameNode>(uiNode)->MarkModifyDone();
676 }
677
678 return uiNode;
679 }
680
AttachToTree(RefPtr<UINode> root,RefPtr<UINode> uiNode,const std::unique_ptr<NodeObject> & nodeObject)681 void DistributedUI::AttachToTree(
682 RefPtr<UINode> root, RefPtr<UINode> uiNode, const std::unique_ptr<NodeObject>& nodeObject)
683 {
684 auto depth = nodeObject->GetInt(DISTRIBUTE_UI_DEPTH);
685 auto sinkNodeId = uiNode->GetId();
686 auto sinkParentNodeId = GetIdMapping(nodeObject->GetInt(DISTRIBUTE_UI_PARENT));
687 LOGD("UITree process [%{public}d, %{public}d, %{public}d]", depth, sinkNodeId, sinkParentNodeId);
688
689 if (depth == 1) {
690 LOGI("UITree attach %{public}d to root", sinkNodeId);
691 root->AddChild(uiNode);
692 } else {
693 LOGI("UITree attach %{public}d to %{public}d", sinkNodeId, sinkParentNodeId);
694 auto parent = ElementRegister::GetInstance()->GetUINodeById(sinkParentNodeId);
695 if (!parent) {
696 LOGE("UITree |ERROR| found no sinkParentNodeId %{public}d", sinkParentNodeId);
697 return;
698 }
699 parent->AddChild(uiNode);
700 }
701 }
702
AddNode(const std::unique_ptr<NodeObject> & nodeObject,RefPtr<FrameNode> pageRootNode)703 void DistributedUI::AddNode(const std::unique_ptr<NodeObject>& nodeObject, RefPtr<FrameNode> pageRootNode)
704 {
705 auto uiNode = RestoreNode(nodeObject);
706 if (!uiNode) {
707 LOGE("UITree |ERROR| Frame Node is Null.");
708 return;
709 }
710 LOGD("UITree new node: %{public}s%{public}d", uiNode->GetTag().c_str(), uiNode->GetId());
711 AttachToTree(pageRootNode, uiNode, nodeObject);
712 }
713
ModNode(const std::unique_ptr<NodeObject> & nodeObject)714 void DistributedUI::ModNode(const std::unique_ptr<NodeObject>& nodeObject)
715 {
716 auto sinkNodeId = GetIdMapping(nodeObject->GetInt(DISTRIBUTE_UI_ID));
717 auto sinkNode = ElementRegister::GetInstance()->GetUINodeById(sinkNodeId);
718 if (!sinkNode) {
719 LOGE("UITree |ERROR| node not found %{public}d", sinkNodeId);
720 return;
721 }
722 LOGD("UITree modify node: %{public}s%{public}d", sinkNode->GetTag().c_str(), sinkNode->GetId());
723 auto attrs = nodeObject->GetValue(DISTRIBUTE_UI_ATTRS);
724 sinkNode->FromJson(attrs);
725 sinkNode->MarkDirtyNode();
726 }
727
DelNode(const std::unique_ptr<NodeObject> & nodeObject)728 void DistributedUI::DelNode(const std::unique_ptr<NodeObject>& nodeObject)
729 {
730 auto sinkNodeId = GetIdMapping(nodeObject->GetInt(DISTRIBUTE_UI_ID));
731 LOGD("UITree delete node: %{public}d", sinkNodeId);
732 auto sinkNode = ElementRegister::GetInstance()->GetUINodeById(sinkNodeId);
733 if (!sinkNode) {
734 LOGE("UITree |ERROR| node not found %{public}d", sinkNodeId);
735 return;
736 }
737 auto parent = sinkNode->GetParent();
738 if (!parent) {
739 LOGE("UITree |ERROR| parent node not found.");
740 return;
741 }
742 parent->RemoveChild(sinkNode);
743 }
744
UpdateUITreeInner(SerializeableObjectArray & nodeArray)745 void DistributedUI::UpdateUITreeInner(SerializeableObjectArray& nodeArray)
746 {
747 #ifdef ACE_DEBUG_LOG
748 auto timeStart = std::chrono::high_resolution_clock::now();
749 #endif
750
751 auto context = NG::PipelineContext::GetCurrentContext();
752 CHECK_NULL_VOID_NOLOG(context);
753 auto pageRootNode = context->GetStageManager()->GetLastPage();
754 CHECK_NULL_VOID_NOLOG(pageRootNode);
755
756 LOGD("UITree Update %{public}zu nodes", nodeArray.size());
757 for (const auto& nodeObject : nodeArray) {
758 OperationType op = static_cast<OperationType>(nodeObject->GetInt(DISTRIBUTE_UI_OPERATION));
759 if (op == OperationType::OP_ADD) {
760 AddNode((std::unique_ptr<NodeObject>&)nodeObject, pageRootNode);
761 } else if (op == OperationType::OP_MODIFY) {
762 ModNode((std::unique_ptr<NodeObject>&)nodeObject);
763 } else if (op == OperationType::OP_DELETE) {
764 DelNode((std::unique_ptr<NodeObject>&)nodeObject);
765 }
766 }
767
768 context->RequestFrame();
769 #ifdef ACE_DEBUG_LOG
770 auto timeEnd = std::chrono::high_resolution_clock::now();
771 LOGD("UITree process use %{public}lld ms",
772 static_cast<long long>(std::chrono::duration_cast<std::chrono::milliseconds>(timeEnd - timeStart).count()));
773 #endif
774 }
775
RestoreUITreeInner(const SerializeableObjectArray & nodeArray)776 void DistributedUI::RestoreUITreeInner(const SerializeableObjectArray& nodeArray)
777 {
778 if (nodeArray.empty()) {
779 LOGE("UITree |ERROR| nodeArray is empty.");
780 return;
781 }
782
783 auto context = NG::PipelineContext::GetCurrentContext();
784 CHECK_NULL_VOID_NOLOG(context);
785 auto pageRootNode = context->GetStageManager()->GetLastPage();
786 CHECK_NULL_VOID_NOLOG(pageRootNode);
787 RestorePageNode(pageRootNode);
788 sinkPageChildren_ = pageRootNode->GetChildren();
789 for (const auto& child : sinkPageChildren_) {
790 pageRootNode->RemoveChild(child);
791 }
792
793 for (const auto& nodeObject : nodeArray) {
794 AddNode((std::unique_ptr<NodeObject>&)nodeObject, pageRootNode);
795 }
796
797 pageRootNode->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
798 }
799
IsInCurrentPage(RefPtr<NG::UINode> node,int32_t pageId)800 bool DistributedUI::IsInCurrentPage(RefPtr<NG::UINode> node, int32_t pageId)
801 {
802 if (node->GetTag() == V2::JS_SYNTAX_ITEM_ETS_TAG) {
803 LOGD("UITree true");
804 return true;
805 }
806 if (pageId != 0 && node->GetPageId() != pageId) {
807 return false;
808 }
809 return true;
810 }
811 } // namespace OHOS::Ace::NG
812