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/syntax/lazy_for_each_node.h"
17
18 #include "base/log/ace_trace.h"
19 #include "base/log/dump_log.h"
20 #include "base/memory/referenced.h"
21 #include "base/utils/time_util.h"
22 #include "base/utils/utils.h"
23 #include "core/components_ng/base/view_stack_processor.h"
24 #include "core/components_ng/property/property.h"
25 #include "core/components_ng/syntax/lazy_layout_wrapper_builder.h"
26 #include "core/components_v2/inspector/inspector_constants.h"
27 #include "core/pipeline/base/element_register.h"
28 #include "core/pipeline_ng/pipeline_context.h"
29
30 namespace OHOS::Ace::NG {
31
GetOrCreateLazyForEachNode(int32_t nodeId,const RefPtr<LazyForEachBuilder> & forEachBuilder)32 RefPtr<LazyForEachNode> LazyForEachNode::GetOrCreateLazyForEachNode(
33 int32_t nodeId, const RefPtr<LazyForEachBuilder>& forEachBuilder)
34 {
35 auto node = ElementRegister::GetInstance()->GetSpecificItemById<LazyForEachNode>(nodeId);
36 if (node) {
37 if (node->builder_ != forEachBuilder) {
38 TAG_LOGI(AceLogTag::ACE_LAZY_FOREACH, "replace old lazy for each builder");
39 node->builder_ = forEachBuilder;
40 }
41 return node;
42 }
43 node = MakeRefPtr<LazyForEachNode>(nodeId, forEachBuilder);
44 ElementRegister::GetInstance()->AddUINode(node);
45 return node;
46 }
47
AdjustLayoutWrapperTree(const RefPtr<LayoutWrapperNode> & parent,bool forceMeasure,bool forceLayout)48 void LazyForEachNode::AdjustLayoutWrapperTree(
49 const RefPtr<LayoutWrapperNode>& parent, bool forceMeasure, bool forceLayout)
50 {
51 CHECK_NULL_VOID(builder_);
52 auto lazyLayoutWrapperBuilder = MakeRefPtr<LazyLayoutWrapperBuilder>(builder_, WeakClaim(this));
53 if (parent->GetHostTag() == V2::SWIPER_ETS_TAG) {
54 lazyLayoutWrapperBuilder->SetLazySwiper();
55 }
56 lazyLayoutWrapperBuilder->UpdateForceFlag(forceMeasure, forceLayout);
57 parent->SetLayoutWrapperBuilder(lazyLayoutWrapperBuilder);
58 }
59
BuildAllChildren()60 void LazyForEachNode::BuildAllChildren()
61 {
62 for (int i = 0; i < FrameCount(); i++) {
63 GetFrameChildByIndex(i, true);
64 }
65 children_.clear();
66 auto items = builder_->GetAllChildren();
67 for (auto& [index, item] : items) {
68 if (item.second) {
69 children_.push_back(item.second);
70 }
71 }
72 }
73
PostIdleTask()74 void LazyForEachNode::PostIdleTask()
75 {
76 if (needPredict_) {
77 return;
78 }
79 needPredict_ = true;
80 auto context = GetContext();
81 CHECK_NULL_VOID(context);
82 context->AddPredictTask([weak = AceType::WeakClaim(this)](int64_t deadline, bool canUseLongPredictTask) {
83 ACE_SCOPED_TRACE("LazyForEach predict");
84 auto node = weak.Upgrade();
85 CHECK_NULL_VOID(node);
86 node->needPredict_ = false;
87 auto canRunLongPredictTask = node->requestLongPredict_ && canUseLongPredictTask;
88 if (node->builder_) {
89 node->GetChildren();
90 auto preBuildResult = node->builder_->PreBuild(deadline, node->itemConstraint_, canRunLongPredictTask);
91 if (!preBuildResult) {
92 node->PostIdleTask();
93 } else {
94 node->requestLongPredict_ = false;
95 node->itemConstraint_.reset();
96 }
97 }
98 });
99 }
100
OnDataReloaded()101 void LazyForEachNode::OnDataReloaded()
102 {
103 ACE_SCOPED_TRACE("OnDataReloaded");
104 children_.clear();
105 if (builder_) {
106 builder_->OnDataReloaded();
107 }
108 NotifyDataCountChanged(0);
109 MarkNeedSyncRenderTree(true);
110 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
111 }
112
OnDataAdded(size_t index)113 void LazyForEachNode::OnDataAdded(size_t index)
114 {
115 ACE_SCOPED_TRACE("OnDataAdded");
116 auto insertIndex = static_cast<int32_t>(index);
117 if (builder_) {
118 builder_->OnDataAdded(index);
119 }
120 children_.clear();
121 NotifyDataCountChanged(insertIndex);
122 MarkNeedSyncRenderTree(true);
123 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
124 }
125
OnDataDeleted(size_t index)126 void LazyForEachNode::OnDataDeleted(size_t index)
127 {
128 ACE_SCOPED_TRACE("OnDataDeleted");
129 auto deletedIndex = static_cast<int32_t>(index);
130 if (builder_) {
131 auto node = builder_->OnDataDeleted(index);
132
133 if (node) {
134 if (!node->OnRemoveFromParent(true)) {
135 const_cast<LazyForEachNode*>(this)->AddDisappearingChild(node);
136 } else {
137 node->DetachFromMainTree();
138 }
139 builder_->ProcessOffscreenNode(node, true);
140 }
141 }
142 children_.clear();
143 NotifyDataCountChanged(deletedIndex);
144 MarkNeedSyncRenderTree(true);
145 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
146 }
147
OnDataChanged(size_t index)148 void LazyForEachNode::OnDataChanged(size_t index)
149 {
150 if (builder_) {
151 builder_->OnDataChanged(index);
152 }
153 children_.clear();
154 MarkNeedSyncRenderTree(true);
155 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
156 }
157
OnDataMoved(size_t from,size_t to)158 void LazyForEachNode::OnDataMoved(size_t from, size_t to)
159 {
160 if (builder_) {
161 builder_->OnDataMoved(from, to);
162 }
163 children_.clear();
164 MarkNeedSyncRenderTree(true);
165 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
166 }
167
NotifyDataCountChanged(int32_t index)168 void LazyForEachNode::NotifyDataCountChanged(int32_t index)
169 {
170 auto parent = GetParent();
171 if (parent) {
172 parent->ChildrenUpdatedFrom(index);
173 }
174 }
175
MarkNeedSyncRenderTree(bool needRebuild)176 void LazyForEachNode::MarkNeedSyncRenderTree(bool needRebuild)
177 {
178 if (needMarkParent_) {
179 UINode::MarkNeedSyncRenderTree(needRebuild);
180 }
181 }
182
GetFrameChildByIndex(uint32_t index,bool needBuild)183 RefPtr<UINode> LazyForEachNode::GetFrameChildByIndex(uint32_t index, bool needBuild)
184 {
185 if (index < static_cast<uint32_t>(FrameCount())) {
186 auto child = builder_->GetChildByIndex(index, needBuild);
187 if (child.second) {
188 if (isActive_) {
189 child.second->SetJSViewActive(true);
190 }
191 if (child.second->GetDepth() != GetDepth() + 1) {
192 child.second->SetDepth(GetDepth() + 1);
193 }
194 MarkNeedSyncRenderTree();
195 children_.clear();
196 child.second->SetParent(WeakClaim(this));
197 if (IsOnMainTree()) {
198 child.second->AttachToMainTree();
199 }
200 PostIdleTask();
201 return child.second->GetFrameChildByIndex(0, needBuild);
202 }
203 }
204 return nullptr;
205 }
206
GetIndexByUINode(const RefPtr<UINode> & uiNode) const207 int32_t LazyForEachNode::GetIndexByUINode(const RefPtr<UINode>& uiNode) const
208 {
209 if (!builder_) {
210 return -1;
211 }
212 auto items = builder_->GetAllChildren();
213 for (auto& [index, item] : items) {
214 if (item.second == uiNode) {
215 return index;
216 }
217 }
218 return -1;
219 }
220
DoRemoveChildInRenderTree(uint32_t index,bool isAll)221 void LazyForEachNode::DoRemoveChildInRenderTree(uint32_t index, bool isAll)
222 {
223 if (!builder_) {
224 return;
225 }
226 children_.clear();
227 if (isAll) {
228 builder_->RemoveAllChild();
229 MarkNeedSyncRenderTree();
230 PostIdleTask();
231 }
232 return;
233 }
234
DoSetActiveChildRange(int32_t start,int32_t end)235 void LazyForEachNode::DoSetActiveChildRange(int32_t start, int32_t end)
236 {
237 if (!builder_) {
238 return;
239 }
240 children_.clear();
241 builder_->SetActiveChildRange(start, end);
242 MarkNeedSyncRenderTree();
243 PostIdleTask();
244 }
245
GetChildren() const246 const std::list<RefPtr<UINode>>& LazyForEachNode::GetChildren() const
247 {
248 if (children_.empty()) {
249 std::list<RefPtr<UINode>> childList;
250 auto items = builder_->GetItems(childList);
251
252 for (auto& node : childList) {
253 if (!node->OnRemoveFromParent(true)) {
254 const_cast<LazyForEachNode*>(this)->AddDisappearingChild(node);
255 } else {
256 node->DetachFromMainTree();
257 }
258 }
259 for (auto& [index, item] : items) {
260 if (item.second) {
261 const_cast<LazyForEachNode*>(this)->RemoveDisappearingChild(item.second);
262 children_.push_back(item.second);
263 }
264 }
265 }
266 return children_;
267 }
268
OnConfigurationUpdate(const ConfigurationChange & configurationChange)269 void LazyForEachNode::OnConfigurationUpdate(const ConfigurationChange& configurationChange)
270 {
271 if ((configurationChange.colorModeUpdate || configurationChange.fontUpdate) && builder_) {
272 auto map = builder_->GetCachedUINodeMap();
273 for (auto &it : map) {
274 auto node = DynamicCast<UINode>(it.second.second);
275 if (node) {
276 node->UpdateConfigurationUpdate(configurationChange);
277 }
278 }
279 }
280 }
281
282 } // namespace OHOS::Ace::NG
283