1 /*
2  * Copyright (c) 2022 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/pattern/custom/custom_node.h"
17 
18 #include "base/json/json_util.h"
19 #include "base/log/ace_performance_monitor.h"
20 #include "base/log/dump_log.h"
21 #include "core/components_ng/base/frame_node.h"
22 #include "core/components_ng/base/view_stack_processor.h"
23 #include "core/components_ng/pattern/custom/custom_node_pattern.h"
24 #include "core/components_v2/inspector/inspector_constants.h"
25 #include "core/pipeline/base/element_register.h"
26 #include "core/pipeline_ng/pipeline_context.h"
27 #include "core/pipeline_ng/ui_task_scheduler.h"
28 
29 namespace OHOS::Ace::NG {
CreateCustomNode(int32_t nodeId,const std::string & viewKey)30 RefPtr<CustomNode> CustomNode::CreateCustomNode(int32_t nodeId, const std::string& viewKey)
31 {
32     auto node = MakeRefPtr<CustomNode>(nodeId, viewKey);
33     ElementRegister::GetInstance()->AddUINode(node);
34     return node;
35 }
36 
CustomNode(int32_t nodeId,const std::string & viewKey)37 CustomNode::CustomNode(int32_t nodeId, const std::string& viewKey)
38     : UINode(V2::JS_VIEW_ETS_TAG, nodeId, MakeRefPtr<CustomNodePattern>()), viewKey_(viewKey)
39 {}
40 
Build(std::shared_ptr<std::list<ExtraInfo>> extraInfos)41 void CustomNode::Build(std::shared_ptr<std::list<ExtraInfo>> extraInfos)
42 {
43     Render();
44     if (extraInfos) {
45         extraInfos_ = *extraInfos;
46     }
47     UINode::Build(extraInfos);
48 }
49 
Render()50 void CustomNode::Render()
51 {
52     needMarkParent_ = false;
53     if (renderFunction_) {
54         RenderFunction renderFunction = nullptr;
55         std::swap(renderFunction, renderFunction_);
56         {
57             ACE_SCOPED_TRACE("CustomNode:OnAppear");
58             FireOnAppear();
59         }
60         {
61             COMPONENT_CREATION_DURATION();
62             ACE_SCOPED_TRACE("CustomNode:BuildItem [%s][self:%d][parent:%d]", GetJSViewName().c_str(), GetId(),
63                 GetParent() ? GetParent()->GetId() : 0);
64             // first create child node and wrapper.
65             ScopedViewStackProcessor scopedViewStackProcessor;
66             auto parent = GetParent();
67             bool parentNeedExportTexture = parent ? parent->IsNeedExportTexture() : false;
68             ViewStackProcessor::GetInstance()->SetIsExportTexture(parentNeedExportTexture || IsNeedExportTexture());
69             auto child = renderFunction();
70             if (child) {
71                 child->MountToParent(Claim(this));
72             }
73         }
74         {
75             ACE_SCOPED_TRACE("CustomNode::DidBuild");
76             FireDidBuild();
77         }
78     }
79     {
80         FireRecycleRenderFunc();
81     }
82     needMarkParent_ = true;
83 }
84 
FireCustomDisappear()85 void CustomNode::FireCustomDisappear()
86 {
87     if (!CheckFireOnAppear()) {
88         FireOnAppear();
89         FireDidBuild();
90     }
91     FireOnDisappear();
92     Reset();
93     UINode::FireCustomDisappear();
94 }
95 
96 // used in HotReload to update root view @Component
FlushReload()97 void CustomNode::FlushReload()
98 {
99     CHECK_NULL_VOID(completeReloadFunc_);
100     Clean();
101     renderFunction_ = completeReloadFunc_;
102     Build(nullptr);
103 }
104 
RenderCustomChild(int64_t deadline)105 bool CustomNode::RenderCustomChild(int64_t deadline)
106 {
107     if (GetSysTimestamp() > deadline) {
108         return false;
109     }
110     Render();
111     return UINode::RenderCustomChild(deadline);
112 }
113 
SetJSViewActive(bool active,bool isLazyForEachNode)114 void CustomNode::SetJSViewActive(bool active, bool isLazyForEachNode)
115 {
116     if (GetJsActive() != active) {
117         SetJsActive(active);
118         FireSetActiveFunc(active);
119     }
120 }
121 
AdjustLayoutWrapperTree(const RefPtr<LayoutWrapperNode> & parent,bool forceMeasure,bool forceLayout)122 void CustomNode::AdjustLayoutWrapperTree(const RefPtr<LayoutWrapperNode>& parent, bool forceMeasure, bool forceLayout)
123 {
124     if (parent->GetHostTag() != V2::TAB_CONTENT_ITEM_ETS_TAG) {
125         Render();
126         UINode::AdjustLayoutWrapperTree(parent, forceMeasure, forceLayout);
127         return;
128     }
129 
130     if (!renderFunction_ && !HasRecycleRenderFunc()) {
131         UINode::AdjustLayoutWrapperTree(parent, forceMeasure, forceLayout);
132         return;
133     }
134 
135     parent->AppendChild(MakeRefPtr<LayoutWrapperNode>(
136         [weak = AceType::WeakClaim(this), forceMeasure, forceLayout](RefPtr<LayoutWrapperNode> layoutWrapper) {
137             auto customNode = weak.Upgrade();
138             CHECK_NULL_VOID(customNode);
139 
140             customNode->Render();
141             if (customNode->GetChildren().empty()) {
142                 return;
143             }
144             auto child = customNode->GetChildren().front();
145             while (!InstanceOf<FrameNode>(child)) {
146                 auto custom = DynamicCast<CustomNode>(child);
147                 if (custom) {
148                     custom->Render();
149                 }
150                 auto children = child->GetChildren();
151                 if (children.empty()) {
152                     return;
153                 }
154                 child = children.front();
155             }
156             auto frameChild = DynamicCast<FrameNode>(child);
157             CHECK_NULL_VOID(frameChild);
158             frameChild->UpdateLayoutWrapper(layoutWrapper, forceMeasure, forceLayout);
159         }));
160 }
161 
CreateLayoutWrapper(bool forceMeasure,bool forceLayout)162 RefPtr<LayoutWrapperNode> CustomNode::CreateLayoutWrapper(bool forceMeasure, bool forceLayout)
163 {
164     Build(nullptr);
165     return UINode::CreateLayoutWrapper(forceMeasure, forceLayout);
166 }
167 
MarkNeedSyncRenderTree(bool needRebuild)168 void CustomNode::MarkNeedSyncRenderTree(bool needRebuild)
169 {
170     if (needMarkParent_) {
171         UINode::MarkNeedSyncRenderTree(needRebuild);
172     }
173 }
174 
GetFrameChildByIndex(uint32_t index,bool needBuild,bool isCache,bool addToRenderTree)175 RefPtr<UINode> CustomNode::GetFrameChildByIndex(uint32_t index, bool needBuild, bool isCache, bool addToRenderTree)
176 {
177     if (!isCache) {
178         SetJSViewActive(true);
179     }
180     Render();
181     return UINode::GetFrameChildByIndex(index, needBuild, isCache, addToRenderTree);
182 }
183 
DoSetActiveChildRange(int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd,bool showCache)184 void CustomNode::DoSetActiveChildRange(
185     int32_t start, int32_t end, int32_t cacheStart, int32_t cacheEnd, bool showCache)
186 {
187     if (showCache) {
188         start -= cacheStart;
189         end += cacheEnd;
190     }
191     if (start <= end) {
192         if (start > 0 || end < 0) {
193             SetActive(false);
194             SetJSViewActive(false);
195         } else {
196             SetJSViewActive(true);
197         }
198     } else {
199         if (end < 0 && start > 0) {
200             SetActive(false);
201             SetJSViewActive(false);
202         } else {
203             SetJSViewActive(true);
204         }
205     }
206 }
207 
GetStateInspectorInfo()208 std::unique_ptr<JsonValue> CustomNode::GetStateInspectorInfo()
209 {
210     std::string res = FireOnDumpInspectorFunc();
211     TAG_LOGD(AceLogTag::ACE_STATE_MGMT, "ArkUI State Inspector dump info %{public}s", res.c_str());
212     auto json = JsonUtil::ParseJsonString(res);
213     return json;
214 }
215 } // namespace OHOS::Ace::NG
216