• 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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H
18 
19 #include <cstdint>
20 #include <list>
21 #include <map>
22 #include <optional>
23 #include <string>
24 #include <unordered_map>
25 #include <unordered_set>
26 #include <utility>
27 
28 #include "base/log/ace_trace.h"
29 #include "base/utils/noncopyable.h"
30 #include "base/utils/time_util.h"
31 #include "base/utils/utils.h"
32 #include "core/components_ng/base/frame_node.h"
33 #include "core/components_ng/base/inspector.h"
34 #include "core/components_ng/base/ui_node.h"
35 #include "core/components_v2/foreach/lazy_foreach_component.h"
36 #include "core/pipeline_ng/pipeline_context.h"
37 
38 namespace OHOS::Ace::NG {
39 
40 typedef struct OperationInfo {
OperationInfoOperationInfo41     OperationInfo():node(nullptr) {}
42     int32_t changeCount = 0;
43     int32_t fromDiffTo = 0;
44     std::string key;
45     RefPtr<UINode> node;
46     bool isDeleting = false;
47     bool isChanged = false;
48     bool moveIn = false;
49     bool isExchange = false;
50     std::vector<std::string> extraKey;
51 } OperationInfo;
52 
53 using LazyForEachChild = std::pair<std::string, RefPtr<UINode>>;
54 using LazyForEachCacheChild = std::pair<int32_t, RefPtr<UINode>>;
55 
56 class ACE_EXPORT LazyForEachBuilder : public virtual AceType {
57     DECLARE_ACE_TYPE(NG::LazyForEachBuilder, AceType);
58 public:
59     LazyForEachBuilder() = default;
60     ~LazyForEachBuilder() override = default;
61 
GetTotalCount()62     int32_t GetTotalCount()
63     {
64         return OnGetTotalCount();
65     }
66 
UpdateHistoricalTotalCount(int32_t count)67     void UpdateHistoricalTotalCount(int32_t count)
68     {
69         historicalTotalCount_ = count;
70     }
71 
72     int32_t GetTotalCountOfOriginalDataset();
73 
74     std::pair<std::string, RefPtr<UINode>> GetChildByIndex(int32_t index, bool needBuild, bool isCache = false);
75 
ExpandChildrenOnInitial()76     void ExpandChildrenOnInitial()
77     {
78         OnExpandChildrenOnInitialInNG();
79     }
80 
81     void OnDataReloaded();
82 
83     bool OnDataAdded(size_t index);
84 
85     bool OnDataBulkAdded(size_t index, size_t count);
86 
87     RefPtr<UINode> OnDataDeleted(size_t index);
88 
89     std::list<std::pair<std::string, RefPtr<UINode>>>& OnDataBulkDeleted(size_t index, size_t count);
90 
91     bool OnDataChanged(size_t index);
92 
93     std::list<std::pair<std::string, RefPtr<UINode>>>& OnDataBulkChanged(size_t index, size_t count);
94 
95     void OnDataMoveToNewPlace(size_t from, size_t to);
96 
97     bool OnDataMoved(size_t from, size_t to);
98 
99     std::pair<int32_t, std::list<std::pair<std::string, RefPtr<UINode>>>> OnDatasetChange(
100         std::list<V2::Operation> DataOperations);
101 
102     void RepairDatasetItems(std::map<int32_t, LazyForEachChild>& cachedTemp,
103         std::map<int32_t, LazyForEachChild>& expiringTempItem_, std::map<int32_t, int32_t>& indexChangedMap);
104 
105     void RepairMoveOrExchange(std::map<int32_t, LazyForEachChild>& expiringTempItem_,
106         OperationInfo& info, LazyForEachChild& child, int32_t index, int32_t changedIndex);
107 
108     void CollectIndexChangedCount(std::map<int32_t, int32_t>& indexChangedMap);
109 
110     bool ClassifyOperation(V2::Operation& operation, int32_t& initialIndex,
111         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp);
112 
113     bool ValidateIndex(int32_t index, const std::string& type);
114 
115     void OperateAdd(V2::Operation& operation, int32_t& initialIndex);
116 
117     void OperateDelete(V2::Operation& operation, int32_t& initialIndex);
118 
119     void OperateMove(V2::Operation& operation, int32_t& initialIndex,
120         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp);
121 
122     void OperateChange(V2::Operation& operation, int32_t& initialIndex,
123         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp);
124 
125     std::map<int32_t, LazyForEachChild>::iterator FindItem(int32_t index,
126         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp);
127 
128     void OperateExchange(V2::Operation& operation, int32_t& initialIndex,
129         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp);
130 
131     void OperateReload(std::map<int32_t, LazyForEachChild>& expiringTemp);
132 
133     void ThrowRepeatOperationError(int32_t index);
134 
135     void RecordOutOfBoundaryNodes(int32_t index);
136 
InvalidIndexOfChangedData(size_t index)137     void InvalidIndexOfChangedData(size_t index)
138     {
139         for (auto& [key, child] : expiringItem_) {
140             if (static_cast<size_t>(child.first) == index) {
141                 child.first = -1;
142                 break;
143             }
144         }
145     }
146 
GetChildByKey(const std::string & key)147     RefPtr<UINode> GetChildByKey(const std::string& key)
148     {
149         return nullptr;
150     }
151 
152     void Transit(std::list<std::pair<std::string, RefPtr<UINode>>>& childList);
153 
154     std::map<int32_t, LazyForEachChild>& GetItems(std::list<std::pair<std::string, RefPtr<UINode>>>& childList);
155 
156     void RemoveAllChild();
157 
158     bool SetActiveChildRange(int32_t start, int32_t end);
159 
160     int32_t GetChildIndex(const RefPtr<FrameNode>& targetNode);
161 
162     void UpdateMoveFromTo(int32_t from, int32_t to);
163     void ResetMoveFromTo();
164     int32_t ConvertFromToIndex(int32_t index);
165 
SetFlagForGeneratedItem(PropertyChangeFlag propertyChangeFlag)166     void SetFlagForGeneratedItem(PropertyChangeFlag propertyChangeFlag)
167     {
168         for (const auto& item : cachedItems_) {
169             if (!item.second.second) {
170                 continue;
171             }
172             item.second.second->ForceUpdateLayoutPropertyFlag(propertyChangeFlag);
173         }
174     }
175 
176     RefPtr<UINode> CacheItem(int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cache,
177         const std::optional<LayoutConstraintF>& itemConstraint, int64_t deadline, bool& isTimeout);
178 
179     void CheckCacheIndex(std::set<int32_t>& idleIndexes, int32_t count);
180 
181     bool PreBuildByIndex(int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cache,
182         int64_t deadline, const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask);
183 
ProcessPreBuildingIndex(std::unordered_map<std::string,LazyForEachCacheChild> & cache,int64_t deadline,const std::optional<LayoutConstraintF> & itemConstraint,bool canRunLongPredictTask,std::set<int32_t> & idleIndexes)184     bool ProcessPreBuildingIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, int64_t deadline,
185         const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask,
186         std::set<int32_t>& idleIndexes)
187     {
188         if (idleIndexes.find(preBuildingIndex_) == idleIndexes.end()) {
189             preBuildingIndex_ = -1;
190             return true;
191         }
192         idleIndexes.erase(preBuildingIndex_);
193         return PreBuildByIndex(preBuildingIndex_, cache, deadline, itemConstraint, canRunLongPredictTask);
194     }
195 
196     bool PreBuild(int64_t deadline, const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask);
197 
198     void ProcessCachedIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache,
199         std::set<int32_t>& idleIndexes);
200 
LoadCacheByIndex(std::unordered_map<std::string,LazyForEachCacheChild> & cache,std::set<int32_t> & idleIndexes,const LazyForEachCacheChild & node,const std::string & key,const std::set<int32_t>::iterator & iter,std::unordered_map<std::string,LazyForEachCacheChild>::iterator & expiringIter)201     void LoadCacheByIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, std::set<int32_t>& idleIndexes,
202         const LazyForEachCacheChild& node, const std::string& key, const std::set<int32_t>::iterator& iter,
203         std::unordered_map<std::string, LazyForEachCacheChild>::iterator& expiringIter)
204     {
205         ProcessOffscreenNode(node.second, false);
206 
207         if (node.first == preBuildingIndex_) {
208             cache.try_emplace(key, node);
209         } else {
210             cache.try_emplace(key, std::move(node));
211             cachedItems_.try_emplace(node.first, LazyForEachChild(key, nullptr));
212             idleIndexes.erase(iter);
213         }
214 
215         expiringIter++;
216     }
217 
LoadCacheByKey(std::unordered_map<std::string,LazyForEachCacheChild> & cache,std::set<int32_t> & idleIndexes,const LazyForEachCacheChild & node,const std::string & key,std::unordered_map<std::string,LazyForEachCacheChild>::iterator & expiringIter)218     void LoadCacheByKey(std::unordered_map<std::string, LazyForEachCacheChild>& cache, std::set<int32_t>& idleIndexes,
219         const LazyForEachCacheChild& node, const std::string& key,
220         std::unordered_map<std::string, LazyForEachCacheChild>::iterator& expiringIter)
221     {
222         NotifyDataDeleted(node.second, static_cast<size_t>(node.first), true);
223         ProcessOffscreenNode(node.second, true);
224         NotifyItemDeleted(RawPtr(node.second), key);
225 
226         if (node.second) {
227             node.second->DetachFromMainTree();
228         }
229         if (DeleteExpiringItemImmediately()) {
230             expiringIter = expiringItem_.erase(expiringIter);
231         } else {
232             expiringIter++;
233         }
234     }
235 
236     void ProcessOffscreenNode(RefPtr<UINode> uiNode, bool remove);
237 
ClearAllOffscreenNode()238     void ClearAllOffscreenNode()
239     {
240         for (auto& [key, node] : expiringItem_) {
241             ProcessOffscreenNode(node.second, true);
242         }
243         for (auto& [key, node] : cachedItems_) {
244             ProcessOffscreenNode(node.second, true);
245         }
246     }
247 
248     virtual void ReleaseChildGroupById(const std::string& id) = 0;
249 
250     virtual void RegisterDataChangeListener(const RefPtr<V2::DataChangeListener>& listener) = 0;
251 
252     virtual void UnregisterDataChangeListener(V2::DataChangeListener* listener) = 0;
253 
SetCacheCount(int32_t cacheCount)254     void SetCacheCount(int32_t cacheCount)
255     {
256         cacheCount_ = cacheCount;
257     }
258 
SetIsLoop(bool isLoop)259     void SetIsLoop(bool isLoop)
260     {
261         isLoop_ = isLoop;
262     }
263 
clearDeletedNodes()264     void clearDeletedNodes()
265     {
266         nodeList_.clear();
267     }
268 
SetUseNewInterface(bool useNewInterface)269     void SetUseNewInterface(bool useNewInterface)
270     {
271         useNewInterface_ = useNewInterface;
272     }
273 
GetCachedUINodeMap()274     const std::unordered_map<std::string, LazyForEachCacheChild>& GetCachedUINodeMap()
275     {
276         return expiringItem_;
277     }
278 
279     const std::map<int32_t, LazyForEachChild>& GetAllChildren();
280 
281     void SetJSViewActive(bool active);
282 
283     void PaintDebugBoundaryTreeAll(bool flag);
284 
NotifyItemDeleted(UINode * node,const std::string & key)285     void NotifyItemDeleted(UINode* node, const std::string& key)
286     {
287         OnItemDeleted(node, key);
288     }
289 
290     void GetAllItems(std::vector<UINode*>& items);
291 
SetShowCached(int32_t start,int32_t end)292     void SetShowCached(int32_t start, int32_t end)
293     {
294         startShowCached_ = start;
295         endShowCached_ = end;
296     }
297 
GetHistoryTotalCount()298     int32_t GetHistoryTotalCount() const
299     {
300         return historicalTotalCount_;
301     }
302 
303     void SetDestroying(bool isDestroying, bool cleanStatus);
304     void NotifyColorModeChange(uint32_t colorMode, bool rerenderable);
305 
EnablePreBuild(bool enable)306     void EnablePreBuild(bool enable)
307     {
308         enablePreBuild_ = enable;
309     }
310 
311 protected:
312     virtual int32_t OnGetTotalCount() = 0;
313 
OnItemDeleted(UINode * node,const std::string & key)314     virtual void OnItemDeleted(UINode* node, const std::string& key) {};
315 
DeleteExpiringItemImmediately()316     virtual bool DeleteExpiringItemImmediately()
317     {
318         return false;
319     }
320 
321     virtual LazyForEachChild OnGetChildByIndex(
322         int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cachedItems) = 0;
323 
324     virtual LazyForEachChild OnGetChildByIndexNew(int32_t index,
325         std::map<int32_t, LazyForEachChild>& cachedItems,
326         std::unordered_map<std::string, LazyForEachCacheChild>& expiringItems) = 0;
327 
328     virtual void OnExpandChildrenOnInitialInNG() = 0;
329 
330     virtual void NotifyDataChanged(size_t index, const RefPtr<UINode>& lazyForEachNode, bool isRebuild = true) = 0;
331 
332     virtual void NotifyDataDeleted(const RefPtr<UINode>& lazyForEachNode, size_t index, bool removeIds) = 0;
333 
334     virtual void NotifyDataAdded(size_t index) = 0;
335 
336     virtual void KeepRemovedItemInCache(NG::LazyForEachChild node,
337         std::unordered_map<std::string, NG::LazyForEachCacheChild>& cachedItems) = 0;
338 
339 private:
340     void RecycleItemsOutOfBoundary();
341     void RecycleChildByIndex(int32_t index);
342 
343     std::map<int32_t, LazyForEachChild> cachedItems_;
344     std::unordered_map<std::string, LazyForEachCacheChild> expiringItem_;
345     std::list<std::pair<std::string, RefPtr<UINode>>> nodeList_;
346     std::map<int32_t, OperationInfo> operationList_;
347     enum class OP { ADD, DEL, CHANGE, MOVE, EXCHANGE, RELOAD };
348     std::map<std::string, OP> operationTypeMap = {{"add", OP::ADD},
349         {"delete", OP::DEL},
350         {"change", OP::CHANGE},
351         {"move", OP::MOVE},
352         {"exchange", OP::EXCHANGE},
353         {"reload", OP::RELOAD}};
354     std::list<int32_t> outOfBoundaryNodes_;
355     std::optional<std::pair<int32_t, int32_t>> moveFromTo_;
356 
357     int32_t startIndex_ = -1;
358     int32_t endIndex_ = -1;
359     int32_t cacheCount_ = 0;
360     int32_t startShowCached_ = 0;
361     int32_t endShowCached_ = 0;
362     int32_t preBuildingIndex_ = -1;
363     int32_t totalCountOfOriginalDataset_ = 0;
364     int32_t historicalTotalCount_ = 0;
365     bool needTransition = false;
366     bool isLoop_ = false;
367     bool useNewInterface_ = false;
368     bool enablePreBuild_ = true;
369     ACE_DISALLOW_COPY_AND_MOVE(LazyForEachBuilder);
370 };
371 } // namespace OHOS::Ace::NG
372 
373 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H
374