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