• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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