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/base/view_stack_processor.h"
17
18 #include "core/components_ng/base/group_node.h"
19 #include "core/components_ng/base/view_stack_model_ng.h"
20 #include "core/components_ng/syntax/for_each_node.h"
21 #include "core/components_ng/syntax/if_else_node.h"
22
23 namespace OHOS::Ace::NG {
24 namespace {
25 const RefPtr<UINode> INVALID_NODE = nullptr;
26 }
27 thread_local std::unique_ptr<ViewStackProcessor> ViewStackProcessor::instance = nullptr;
28 thread_local std::unique_ptr<ScopedViewStackProcessor> ViewStackModelNG::scopeStack_ = nullptr;
29
GetInstance()30 ViewStackProcessor* ViewStackProcessor::GetInstance()
31 {
32 if (!instance) {
33 instance.reset(new ViewStackProcessor);
34 }
35 return instance.get();
36 }
37
38 ViewStackProcessor::ViewStackProcessor() = default;
39
GetMainFrameNode() const40 FrameNode* ViewStackProcessor::GetMainFrameNode() const
41 {
42 auto uiNode = GetMainElementNode();
43 if (!uiNode || !uiNode->IsLayoutSeperately()) {
44 return nullptr;
45 }
46 return static_cast<FrameNode*>(Referenced::RawPtr(uiNode));
47 }
48
GetMainElementNode() const49 const RefPtr<UINode>& ViewStackProcessor::GetMainElementNode() const
50 {
51 if (elementsStack_.empty()) {
52 return INVALID_NODE;
53 }
54 return elementsStack_.top();
55 }
56
ApplyParentThemeScopeId(const RefPtr<UINode> & element)57 void ViewStackProcessor::ApplyParentThemeScopeId(const RefPtr<UINode>& element)
58 {
59 auto parent = GetMainElementNode();
60 int32_t elementThemeScopeId = element->GetThemeScopeId();
61 if (parent && elementThemeScopeId == 0) {
62 int32_t themeScopeId = parent->GetThemeScopeId();
63 if (elementThemeScopeId != themeScopeId) {
64 element->SetThemeScopeId(themeScopeId);
65 }
66 }
67 }
68
Push(const RefPtr<UINode> & element,bool)69 void ViewStackProcessor::Push(const RefPtr<UINode>& element, bool /*isCustomView*/)
70 {
71 ApplyParentThemeScopeId(element);
72
73 if (ShouldPopImmediately()) {
74 Pop();
75 }
76 element->SetRemoveSilently(false);
77 elementsStack_.push(element);
78 }
79
80 #ifdef ACE_STATIC
PushPtr(int64_t elementPtr)81 void ViewStackProcessor::PushPtr(int64_t elementPtr)
82 {
83 if (elementPtr == 0) {
84 return;
85 }
86 Push(UINode::Claim(reinterpret_cast<UINode*>(elementPtr)), true);
87 }
88 #endif
89
ShouldPopImmediately()90 bool ViewStackProcessor::ShouldPopImmediately()
91 {
92 if (elementsStack_.size() <= 1) {
93 return false;
94 }
95 // for custom node and atomic node, just pop top node when next node is coming.
96 return GetMainElementNode()->IsAtomicNode();
97 }
98
ImplicitPopBeforeContinue()99 void ViewStackProcessor::ImplicitPopBeforeContinue()
100 {
101 if ((elementsStack_.size() > 1) && ShouldPopImmediately()) {
102 Pop();
103 }
104 }
105
FlushImplicitAnimation()106 void ViewStackProcessor::FlushImplicitAnimation()
107 {
108 auto frameNode = ViewStackProcessor::GetInstance()->GetMainFrameNode();
109 CHECK_NULL_VOID(frameNode);
110 if (frameNode->IsOnMainTree()) {
111 frameNode->MarkDirtyNode();
112 }
113 }
114
FlushRerenderTask()115 void ViewStackProcessor::FlushRerenderTask()
116 {
117 auto node = Finish();
118 CHECK_NULL_VOID(node);
119 node->FlushUpdateAndMarkDirty();
120 }
121
Pop()122 void ViewStackProcessor::Pop()
123 {
124 if (elementsStack_.empty() || elementsStack_.size() == 1) {
125 return;
126 }
127
128 auto currentNode = Finish();
129 currentNode->SetBuildByJs(true);
130 auto parent = GetMainElementNode();
131 if (AceType::InstanceOf<GroupNode>(parent)) {
132 auto groupNode = AceType::DynamicCast<GroupNode>(parent);
133 groupNode->AddChildToGroup(currentNode);
134 return;
135 }
136
137 currentNode->MountToParent(
138 parent, DEFAULT_NODE_SLOT, AceType::InstanceOf<ForEachNode>(parent), AceType::InstanceOf<IfElseNode>(parent));
139 auto currentFrameNode = AceType::DynamicCast<FrameNode>(currentNode);
140 if (currentFrameNode) {
141 currentFrameNode->OnMountToParentDone();
142 }
143 }
144
PopContainer()145 void ViewStackProcessor::PopContainer()
146 {
147 auto top = GetMainElementNode();
148 // for container node.
149 if (top && !top->IsAtomicNode()) {
150 Pop();
151 return;
152 }
153
154 while (top && (top->IsAtomicNode())) {
155 if (elementsStack_.size() == 1) {
156 return;
157 }
158 Pop();
159 top = GetMainElementNode();
160 }
161 Pop();
162 }
163
Finish()164 RefPtr<UINode> ViewStackProcessor::Finish()
165 {
166 if (elementsStack_.empty()) {
167 return nullptr;
168 }
169 auto element = elementsStack_.top();
170 elementsStack_.pop();
171 auto frameNode = AceType::DynamicCast<FrameNode>(element);
172 if (frameNode) {
173 frameNode->MarkBuildDone();
174 frameNode->MarkModifyDone();
175 auto renderContext = frameNode->GetRenderContext();
176 if (renderContext) {
177 renderContext->SetNeedDebugBoundary(true);
178 }
179 }
180 // ForEach Partial Update Path.
181 if (AceType::InstanceOf<ForEachNode>(element)) {
182 auto forEachNode = AceType::DynamicCast<ForEachNode>(element);
183 forEachNode->CompareAndUpdateChildren();
184 }
185 return element;
186 }
187
SetVisualState(VisualState state)188 void ViewStackProcessor::SetVisualState(VisualState state)
189 {
190 switch (state) {
191 case VisualState::DISABLED:
192 visualState_ = UI_STATE_DISABLED;
193 break;
194 case VisualState::FOCUSED:
195 visualState_ = UI_STATE_FOCUSED;
196 break;
197 case VisualState::PRESSED:
198 visualState_ = UI_STATE_PRESSED;
199 break;
200 case VisualState::SELECTED:
201 visualState_ = UI_STATE_SELECTED;
202 break;
203 case VisualState::NORMAL:
204 default:
205 visualState_ = UI_STATE_NORMAL;
206 }
207 auto eventHub = GetMainFrameNodeEventHub<EventHub>();
208 CHECK_NULL_VOID(eventHub);
209 eventHub->AddSupportedState(visualState_.value());
210 }
211
IsCurrentVisualStateProcess()212 bool ViewStackProcessor::IsCurrentVisualStateProcess()
213 {
214 if (!visualState_.has_value()) {
215 return true;
216 }
217 auto eventHub = GetMainFrameNodeEventHub<EventHub>();
218 CHECK_NULL_RETURN(eventHub, false);
219 auto result = eventHub->IsCurrentStateOn(visualState_.value());
220 return result;
221 }
222
PushKey(const std::string & key)223 void ViewStackProcessor::PushKey(const std::string& key)
224 {
225 if (viewKey_.empty()) {
226 // For the root node, the key value is xxx.
227 viewKey_ = key;
228 keyStack_.emplace(key.length());
229 } else {
230 // For descendant nodes, the key value is xxx_xxx
231 viewKey_.append("_").append(key);
232 keyStack_.emplace(key.length() + 1);
233 }
234 }
235
PopKey()236 void ViewStackProcessor::PopKey()
237 {
238 size_t length = keyStack_.top();
239 keyStack_.pop();
240
241 if (length > 0) {
242 viewKey_.erase(viewKey_.length() - length);
243 }
244 }
245
GetKey()246 std::string ViewStackProcessor::GetKey()
247 {
248 return viewKey_.empty() ? "" : viewKey_;
249 }
250
ProcessViewId(const std::string & viewId)251 std::string ViewStackProcessor::ProcessViewId(const std::string& viewId)
252 {
253 return viewKey_.empty() ? viewId : viewKey_ + "_" + viewId;
254 }
255
SetImplicitAnimationOption(const AnimationOption & option)256 void ViewStackProcessor::SetImplicitAnimationOption(const AnimationOption& option)
257 {
258 implicitAnimationOption_ = option;
259 }
260
GetImplicitAnimationOption() const261 const AnimationOption& ViewStackProcessor::GetImplicitAnimationOption() const
262 {
263 return implicitAnimationOption_;
264 }
265
GetNewUINode()266 RefPtr<UINode> ViewStackProcessor::GetNewUINode()
267 {
268 return Finish();
269 }
270
Init(int32_t containerId)271 void ScopedViewStackProcessor::Init(int32_t containerId)
272 {
273 std::swap(instance_, ViewStackProcessor::instance);
274 ViewStackProcessor::GetInstance()->SetRebuildContainerId(containerId);
275 }
276
SwapViewStackProcessor(std::unique_ptr<ViewStackProcessor> & instance)277 void ScopedViewStackProcessor::SwapViewStackProcessor(std::unique_ptr<ViewStackProcessor>& instance)
278 {
279 std::swap(instance, ViewStackProcessor::instance);
280 }
281
ScopedViewStackProcessor(int32_t containerId)282 ScopedViewStackProcessor::ScopedViewStackProcessor(int32_t containerId)
283 {
284 Init(containerId);
285 }
286
ScopedViewStackProcessor(std::unique_ptr<ViewStackProcessor> & instance,int32_t containerId)287 ScopedViewStackProcessor::ScopedViewStackProcessor(std::unique_ptr<ViewStackProcessor>& instance, int32_t containerId)
288 {
289 std::swap(instance_, instance);
290 Init(containerId);
291 }
292
~ScopedViewStackProcessor()293 ScopedViewStackProcessor::~ScopedViewStackProcessor()
294 {
295 ViewStackProcessor::GetInstance()->SetRebuildContainerId(OHOS::Ace::INSTANCE_ID_UNDEFINED);
296 std::swap(instance_, ViewStackProcessor::instance);
297 }
298 } // namespace OHOS::Ace::NG
299