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 LOGW("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 auto node = weak.Upgrade();
84 CHECK_NULL_VOID(node);
85 node->needPredict_ = false;
86 auto canRunLongPredictTask = node->requestLongPredict_ && canUseLongPredictTask;
87 if (node->builder_) {
88 auto preBuildResult = node->builder_->PreBuild(deadline, node->itemConstraint_, canRunLongPredictTask);
89 if (!preBuildResult) {
90 node->PostIdleTask();
91 }
92 }
93 node->requestLongPredict_ = false;
94 node->itemConstraint_.reset();
95 });
96 }
97
OnDataReloaded()98 void LazyForEachNode::OnDataReloaded()
99 {
100 ACE_SCOPED_TRACE("OnDataReloaded");
101 children_.clear();
102 if (builder_) {
103 builder_->OnDataReloaded();
104 }
105 NotifyDataCountChanged(0);
106 MarkNeedSyncRenderTree(true);
107 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
108 }
109
OnDataAdded(size_t index)110 void LazyForEachNode::OnDataAdded(size_t index)
111 {
112 ACE_SCOPED_TRACE("OnDataAdded");
113 auto insertIndex = static_cast<int32_t>(index);
114 if (builder_) {
115 builder_->OnDataAdded(index);
116 }
117 children_.clear();
118 NotifyDataCountChanged(insertIndex);
119 MarkNeedSyncRenderTree(true);
120 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
121 }
122
OnDataDeleted(size_t index)123 void LazyForEachNode::OnDataDeleted(size_t index)
124 {
125 ACE_SCOPED_TRACE("OnDataDeleted");
126 auto deletedIndex = static_cast<int32_t>(index);
127 if (builder_) {
128 auto node = builder_->OnDataDeleted(index);
129
130 if (node) {
131 if (!node->OnRemoveFromParent(true)) {
132 const_cast<LazyForEachNode*>(this)->AddDisappearingChild(node);
133 } else {
134 node->DetachFromMainTree();
135 }
136 }
137 }
138 children_.clear();
139 NotifyDataCountChanged(deletedIndex);
140 MarkNeedSyncRenderTree(true);
141 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
142 }
143
OnDataChanged(size_t index)144 void LazyForEachNode::OnDataChanged(size_t index)
145 {
146 if (builder_) {
147 builder_->OnDataChanged(index);
148 }
149 children_.clear();
150 MarkNeedSyncRenderTree(true);
151 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
152 }
153
OnDataMoved(size_t from,size_t to)154 void LazyForEachNode::OnDataMoved(size_t from, size_t to)
155 {
156 // TODO: data move
157 }
158
NotifyDataCountChanged(int32_t index)159 void LazyForEachNode::NotifyDataCountChanged(int32_t index)
160 {
161 auto parent = GetParent();
162 if (parent) {
163 parent->ChildrenUpdatedFrom(index);
164 }
165 }
166
MarkNeedSyncRenderTree(bool needRebuild)167 void LazyForEachNode::MarkNeedSyncRenderTree(bool needRebuild)
168 {
169 if (needMarkParent_) {
170 UINode::MarkNeedSyncRenderTree(needRebuild);
171 }
172 }
173
GetFrameChildByIndex(uint32_t index,bool needBuild)174 RefPtr<UINode> LazyForEachNode::GetFrameChildByIndex(uint32_t index, bool needBuild)
175 {
176 if (index < static_cast<uint32_t>(FrameCount())) {
177 auto child = builder_->GetChildByIndex(index, needBuild);
178 if (child.second) {
179 child.second->SetJSViewActive(true);
180 if (child.second->GetDepth() != GetDepth() + 1) {
181 child.second->SetDepth(GetDepth() + 1);
182 }
183 MarkNeedSyncRenderTree();
184 children_.clear();
185 child.second->SetParent(WeakClaim(this));
186 if (IsOnMainTree()) {
187 child.second->AttachToMainTree();
188 }
189 PostIdleTask();
190 return child.second->GetFrameChildByIndex(0, needBuild);
191 }
192 }
193 return nullptr;
194 }
195
GetIndexByUINode(const RefPtr<UINode> & uiNode) const196 int32_t LazyForEachNode::GetIndexByUINode(const RefPtr<UINode>& uiNode) const
197 {
198 if (!builder_) {
199 return -1;
200 }
201 auto items = builder_->GetAllChildren();
202 for (auto& [index, item] : items) {
203 if (item.second == uiNode) {
204 return index;
205 }
206 }
207 return -1;
208 }
209
DoRemoveChildInRenderTree(uint32_t index,bool isAll)210 void LazyForEachNode::DoRemoveChildInRenderTree(uint32_t index, bool isAll)
211 {
212 if (!builder_) {
213 return;
214 }
215 children_.clear();
216 if (isAll) {
217 builder_->RemoveAllChild();
218 MarkNeedSyncRenderTree();
219 PostIdleTask();
220 }
221 return;
222 }
223
GetChildren() const224 const std::list<RefPtr<UINode>>& LazyForEachNode::GetChildren() const
225 {
226 if (children_.empty()) {
227 std::list<RefPtr<UINode>> childList;
228 auto items = builder_->GetItems(childList);
229
230 for (auto& node : childList) {
231 if (!node->OnRemoveFromParent(true)) {
232 const_cast<LazyForEachNode*>(this)->AddDisappearingChild(node);
233 } else {
234 node->DetachFromMainTree();
235 }
236 }
237 for (auto& [index, item] : items) {
238 if (item.second) {
239 children_.push_back(item.second);
240 }
241 }
242 }
243 return children_;
244 }
245
246 } // namespace OHOS::Ace::NG