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