• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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