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