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