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