• 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/pattern/list/list_lanes_layout_algorithm.h"
17 
18 #include "base/log/event_report.h"
19 #include "core/components_ng/property/measure_utils.h"
20 
21 namespace OHOS::Ace::NG {
22 
UpdateListItemConstraint(Axis axis,const OptionalSizeF & selfIdealSize,LayoutConstraintF & contentConstraint)23 void ListLanesLayoutAlgorithm::UpdateListItemConstraint(
24     Axis axis, const OptionalSizeF& selfIdealSize, LayoutConstraintF& contentConstraint)
25 {
26     contentConstraint.parentIdealSize = selfIdealSize;
27     contentConstraint.maxSize.SetMainSize(Infinity<float>(), axis);
28     groupLayoutConstraint_ = contentConstraint;
29     auto crossSizeOptional = selfIdealSize.CrossSize(axis);
30     if (crossSizeOptional.has_value()) {
31         float crossSize = crossSizeOptional.value();
32         groupLayoutConstraint_.maxSize.SetCrossSize(crossSize, axis);
33         if (lanes_ > 1) {
34             float laneGutter = GetLaneGutter();
35             crossSize = (crossSize + laneGutter) / lanes_ - laneGutter;
36             crossSize = crossSize <= 0 ? 1 : crossSize;
37         }
38         if (maxLaneLength_.has_value() && maxLaneLength_.value() < crossSize) {
39             crossSize = maxLaneLength_.value();
40         }
41         contentConstraint.percentReference.SetCrossSize(crossSize, axis);
42         contentConstraint.parentIdealSize.SetCrossSize(crossSize, axis);
43         contentConstraint.maxSize.SetCrossSize(crossSize, axis);
44         if (minLaneLength_.has_value()) {
45             contentConstraint.minSize.SetCrossSize(minLaneLength_.value(), axis);
46         }
47     }
48 }
49 
GetChildHeight(LayoutWrapper * layoutWrapper,int32_t childIndex)50 float ListLanesLayoutAlgorithm::GetChildHeight(LayoutWrapper* layoutWrapper, int32_t childIndex)
51 {
52     CHECK_NULL_RETURN(childrenSize_, 0.0f);
53     float mainLen = 0.0f;
54     int32_t laneCeil = GetLanesCeil(layoutWrapper, childIndex);
55     for (int32_t index = GetLanesFloor(layoutWrapper, childIndex); index <= laneCeil; index++) {
56         mainLen = std::max(mainLen, childrenSize_->GetChildSize(index, isStackFromEnd_));
57     }
58     return mainLen;
59 }
60 
MeasureAndGetChildHeight(LayoutWrapper * layoutWrapper,int32_t childIndex,bool groupLayoutAll)61 float ListLanesLayoutAlgorithm::MeasureAndGetChildHeight(LayoutWrapper* layoutWrapper, int32_t childIndex,
62     bool groupLayoutAll)
63 {
64     auto wrapper = GetListItem(layoutWrapper, childIndex);
65     if (!wrapper) {
66         ReportGetChildError("MeasureAndGetChildHeightLanes", childIndex);
67         return 0.0f;
68     }
69     bool isGroup = wrapper->GetHostTag() == V2::LIST_ITEM_GROUP_ETS_TAG;
70     float mainLen = 0.0f;
71     if (isGroup) {
72         auto listLayoutProperty =
73             AceType::DynamicCast<ListLayoutProperty>(layoutWrapper->GetLayoutProperty());
74         // true: layout forward, true: layout all group items.
75         SetListItemGroupParam(wrapper, childIndex, 0.0f, true, listLayoutProperty, true);
76         wrapper->Measure(groupLayoutConstraint_);
77         mainLen = GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_);
78         CheckGroupMeasureBreak(wrapper);
79     } else {
80         auto laneCeil = GetLanesCeil(layoutWrapper, childIndex);
81         for (int32_t i = GetLanesFloor(layoutWrapper, childIndex); i <= laneCeil; i++) {
82             auto wrapper = GetListItem(layoutWrapper, i);
83             if (!wrapper) {
84                 ReportGetChildError("MeasureAndGetChildHeightLanesItem", i);
85                 continue;
86             }
87             wrapper->Measure(childLayoutConstraint_);
88             mainLen = std::max(mainLen, GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_));
89         }
90     }
91     return mainLen;
92 }
93 
MeasureGroup(LayoutWrapper * listWrapper,const RefPtr<LayoutWrapper> & groupWrapper,int32_t index,float & pos,bool forward)94 void ListLanesLayoutAlgorithm::MeasureGroup(LayoutWrapper* listWrapper, const RefPtr<LayoutWrapper>& groupWrapper,
95     int32_t index, float& pos, bool forward)
96 {
97     CHECK_NULL_VOID(groupWrapper);
98     auto host = groupWrapper->GetHostNode();
99     const char* direction = forward ? "Forward" : "Backward";
100     if (host) {
101         ACE_SCOPED_TRACE("[Measure%sListItemGroup:%d][self:%d][parent:%d]", direction, index, host->GetId(),
102             host->GetParent() ? host->GetParent()->GetId() : 0);
103     }
104     auto listLayoutProperty = AceType::DynamicCast<ListLayoutProperty>(listWrapper->GetLayoutProperty());
105     SetListItemGroupParam(groupWrapper, index, pos, forward, listLayoutProperty, false);
106     groupWrapper->Measure(groupLayoutConstraint_);
107     if (forward && (LessOrEqual(pos, 0.0f) || GetPrevMeasureBreak())) {
108         AdjustStartPosition(groupWrapper, pos);
109     }
110     CheckGroupMeasureBreak(groupWrapper);
111 }
112 
MeasureItem(const RefPtr<LayoutWrapper> & itemWrapper,int32_t index,bool forward)113 void ListLanesLayoutAlgorithm::MeasureItem(const RefPtr<LayoutWrapper>& itemWrapper, int32_t index, bool forward)
114 {
115     CHECK_NULL_VOID(itemWrapper);
116     auto host = itemWrapper->GetHostNode();
117     const char* direction = forward ? "Forward" : "Backward";
118     if (host) {
119         ACE_SCOPED_TRACE("[Measure%sListItem:%d][self:%d][parent:%d]", direction, index, host->GetId(),
120             host->GetParent() ? host->GetParent()->GetId() : 0);
121     }
122     itemWrapper->Measure(childLayoutConstraint_);
123 }
124 
LayoutALineForward(LayoutWrapper * layoutWrapper,int32_t & currentIndex,float startPos,float & endPos)125 int32_t ListLanesLayoutAlgorithm::LayoutALineForward(LayoutWrapper* layoutWrapper,
126     int32_t& currentIndex, float startPos, float& endPos)
127 {
128     float mainLen = 0.0f;
129     bool isGroup = false;
130     int32_t cnt = 0;
131     int32_t lanes = lanes_ > 1 ? lanes_ : 1;
132     if (firstItemInfo_ && firstItemInfo_.value().first == currentIndex + 1) {
133         ++currentIndex;
134         endPos = firstItemInfo_.value().second.endPos;
135         SetItemInfo(currentIndex, std::move(firstItemInfo_.value().second));
136         firstItemInfo_.reset();
137         return 1;
138     } else if (firstItemInfo_) {
139         firstItemInfo_.reset();
140     }
141     for (int32_t i = 0; i < lanes && currentIndex + 1 <= GetMaxListItemIndex() && !isGroup; i++) {
142         auto wrapper = GetListItem(layoutWrapper, currentIndex + 1);
143         if (!wrapper) {
144             ReportGetChildError("LayoutALineForwardLanes", currentIndex + 1);
145             break;
146         }
147         isGroup = wrapper->GetHostTag() == V2::LIST_ITEM_GROUP_ETS_TAG;
148         if (isGroup && cnt > 0) {
149             wrapper->SetActive(false);
150             isGroup = false;
151             break;
152         }
153         cnt++;
154         ++currentIndex;
155         if (isGroup) {
156             MeasureGroup(layoutWrapper, wrapper, currentIndex, startPos, true);
157         } else if (CheckNeedMeasure(wrapper)) {
158             MeasureItem(wrapper, currentIndex, true);
159         }
160         mainLen = std::max(mainLen, childrenSize_ ? childrenSize_->GetChildSize(currentIndex, isStackFromEnd_) :
161             GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_));
162     }
163     if (cnt > 0) {
164         endPos = startPos + mainLen;
165         for (int32_t i = 0; i < cnt; i++) {
166             auto wrap = GetListItem(layoutWrapper, currentIndex - i);
167             int32_t id = wrap->GetHostNode()->GetId();
168             SetItemInfo(currentIndex - i, { id, startPos, endPos, isGroup });
169         }
170     }
171     return cnt;
172 }
173 
LayoutALineBackward(LayoutWrapper * layoutWrapper,int32_t & currentIndex,float endPos,float & startPos)174 int32_t ListLanesLayoutAlgorithm::LayoutALineBackward(LayoutWrapper* layoutWrapper,
175     int32_t& currentIndex, float endPos, float& startPos)
176 {
177     float mainLen = 0.0f;
178     bool isGroup = false;
179     int32_t cnt = 0;
180     int32_t lanes = lanes_ > 1 ? lanes_ : 1;
181     if (firstItemInfo_ && firstItemInfo_.value().first == currentIndex - 1) {
182         --currentIndex;
183         startPos = firstItemInfo_.value().second.startPos;
184         SetItemInfo(currentIndex, std::move(firstItemInfo_.value().second));
185         firstItemInfo_.reset();
186         return 1;
187     } else if (firstItemInfo_) {
188         firstItemInfo_.reset();
189     }
190     for (int32_t i = 0; i < lanes && currentIndex - 1 >= 0; i++) {
191         if (currentIndex > GetMaxListItemIndex() + 1) {
192             --currentIndex;
193             continue;
194         }
195         auto wrapper = GetListItem(layoutWrapper, currentIndex - 1);
196         if (!wrapper) {
197             ReportGetChildError("LayoutALineBackwardLanes", currentIndex - 1);
198             break;
199         }
200         isGroup = wrapper->GetHostTag() == V2::LIST_ITEM_GROUP_ETS_TAG;
201         if (isGroup && cnt > 0) {
202             wrapper->SetActive(false);
203             isGroup = false;
204             break;
205         }
206         --currentIndex;
207         cnt++;
208         if (isGroup) {
209             MeasureGroup(layoutWrapper, wrapper, currentIndex, endPos, false);
210         } else if (CheckNeedMeasure(wrapper)) {
211             MeasureItem(wrapper, currentIndex, false);
212         }
213         mainLen = std::max(mainLen, childrenSize_ ? childrenSize_->GetChildSize(currentIndex, isStackFromEnd_) :
214             GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_));
215         if (CheckCurRowMeasureFinished(layoutWrapper, currentIndex, isGroup)) {
216             break;
217         }
218     }
219     if (cnt > 0) {
220         startPos = endPos - mainLen;
221         for (int32_t i = 0; i < cnt; i++) {
222             auto wrap = GetListItem(layoutWrapper, currentIndex + i);
223             int32_t id = wrap->GetHostNode()->GetId();
224             SetItemInfo(currentIndex + i, { id, startPos, endPos, isGroup });
225         }
226     }
227     return cnt;
228 }
229 
CheckCurRowMeasureFinished(LayoutWrapper * layoutWrapper,int32_t curIndex,bool isGroup)230 bool ListLanesLayoutAlgorithm::CheckCurRowMeasureFinished(LayoutWrapper* layoutWrapper, int32_t curIndex, bool isGroup)
231 {
232     if (childrenSize_) {
233         return isGroup || posMap_->GetRowStartIndex(curIndex) == curIndex;
234     }
235     int32_t lanes = lanes_ > 1 ? lanes_ : 1;
236     return isGroup || (curIndex - FindLanesStartIndex(layoutWrapper, curIndex)) % lanes == 0;
237 }
238 
SetCacheCount(LayoutWrapper * layoutWrapper,int32_t cacheCount)239 void ListLanesLayoutAlgorithm::SetCacheCount(LayoutWrapper* layoutWrapper, int32_t cacheCount)
240 {
241     bool hasGroup = false;
242     auto& itemPosition = GetItemPosition();
243     for (auto &pos : itemPosition) {
244         if (pos.second.isGroup) {
245             hasGroup = true;
246             break;
247         }
248     }
249     int32_t count = hasGroup ? cacheCount : cacheCount * lanes_;
250     layoutWrapper->SetCacheCount(count);
251 }
252 
CalculateLanesParam(std::optional<float> & minLaneLength,std::optional<float> & maxLaneLength,int32_t lanes,std::optional<float> crossSizeOptional,float laneGutter)253 int32_t ListLanesLayoutAlgorithm::CalculateLanesParam(std::optional<float>& minLaneLength,
254     std::optional<float>& maxLaneLength, int32_t lanes, std::optional<float> crossSizeOptional, float laneGutter)
255 {
256     if (lanes < 1) {
257         return 1;
258     }
259     // Case 1: lane length constrain is not set
260     //      1.1: use [lanes] set by user if [lanes] is set
261     //      1.2: set [lanes] to 1 if [lanes] is not set
262     if (!crossSizeOptional.has_value() || GreaterOrEqualToInfinity(crossSizeOptional.value()) ||
263         !minLaneLength.has_value() || !maxLaneLength.has_value()) {
264         maxLaneLength.reset();
265         minLaneLength.reset();
266         return lanes;
267     }
268     // Case 2: lane length constrain is set --> need to calculate [lanes_] according to contraint.
269     // We agreed on such rules (assuming we have a vertical list here):
270     // rule 1: [minLaneLength_] has a higher priority than [maxLaneLength_] when decide [lanes_], for e.g.,
271     //         if [minLaneLength_] is 40, [maxLaneLength_] is 60, list's width is 120,
272     //         the [lanes_] is 3 rather than 2.
273     // rule 2: after [lanes_] is determined by rule 1, the width of lane will be as large as it can be, for
274     // e.g.,
275     //         if [minLaneLength_] is 40, [maxLaneLength_] is 60, list's width is 132, the [lanes_] is 3
276     //         according to rule 1, then the width of lane will be 132 / 3 = 44 rather than 40,
277     //         its [minLaneLength_].
278     auto crossSize = crossSizeOptional.value();
279     ModifyLaneLength(minLaneLength, maxLaneLength, crossSize);
280 
281     // if minLaneLength is 40, maxLaneLength is 60
282     // when list's width is 120, lanes_ = 3
283     // when list's width is 80, lanes_ = 2
284     // when list's width is 70, lanes_ = 1
285     float maxLanes = (crossSize + laneGutter) / (minLaneLength.value() + laneGutter);
286     float minLanes = (crossSize + laneGutter) / (maxLaneLength.value() + laneGutter);
287     // let's considerate scenarios when maxCrossSize > 0
288     // now it's guaranteed that [minLaneLength_] <= [maxLaneLength_], i.e., maxLanes >= minLanes > 0
289     // there are 3 scenarios:
290     // 1. 1 > maxLanes >= minLanes > 0
291     // 2. maxLanes >= 1 >= minLanes > 0
292     // 3. maxLanes >= minLanes > 1
293     // 1. 1 > maxLanes >= minLanes > 0 ---> maxCrossSize < minLaneLength_ =< maxLaneLength
294     if (GreatNotEqual(1, maxLanes) && GreatOrEqual(maxLanes, minLanes)) {
295         lanes = 1;
296         minLaneLength = crossSize;
297         maxLaneLength = crossSize;
298         return lanes;
299     }
300     // 2. maxLanes >= 1 >= minLanes > 0 ---> minLaneLength_ = maxCrossSize < maxLaneLength
301     if (GreatOrEqual(maxLanes, 1) && LessOrEqual(minLanes, 1)) {
302         lanes = std::floor(maxLanes);
303         maxLaneLength = crossSize;
304         return lanes;
305     }
306     // 3. maxLanes >= minLanes > 1 ---> minLaneLength_ <= maxLaneLength < maxCrossSize
307     if (GreatOrEqual(maxLanes, minLanes) && GreatNotEqual(minLanes, 1)) {
308         lanes = std::floor(maxLanes);
309         return lanes;
310     }
311     lanes = 1;
312     return lanes;
313 }
314 
CalculateLanes(const RefPtr<ListLayoutProperty> & layoutProperty,const LayoutConstraintF & layoutConstraint,std::optional<float> crossSizeOptional,Axis axis)315 void ListLanesLayoutAlgorithm::CalculateLanes(const RefPtr<ListLayoutProperty>& layoutProperty,
316     const LayoutConstraintF& layoutConstraint, std::optional<float> crossSizeOptional, Axis axis)
317 {
318     const auto& contentConstraintOps = layoutProperty->GetContentLayoutConstraint();
319     CHECK_NULL_VOID(contentConstraintOps);
320     auto contentConstraint = contentConstraintOps.value();
321     auto mainPercentRefer = GetMainAxisSize(contentConstraint.percentReference, axis);
322     int32_t lanes = layoutProperty->GetLanes().value_or(1);
323     lanes = lanes > 1 ? lanes : 1;
324     if (layoutProperty->GetLaneMinLength().has_value()) {
325         minLaneLength_ =
326             ConvertToPx(layoutProperty->GetLaneMinLength().value(), layoutConstraint.scaleProperty, mainPercentRefer);
327     }
328     if (layoutProperty->GetLaneMaxLength().has_value()) {
329         maxLaneLength_ =
330             ConvertToPx(layoutProperty->GetLaneMaxLength().value(), layoutConstraint.scaleProperty, mainPercentRefer);
331     }
332     float laneGutter = 0.0f;
333     if (layoutProperty->GetLaneGutter().has_value()) {
334         laneGutter = ConvertToPx(layoutProperty->GetLaneGutter().value(),
335             layoutConstraint.scaleProperty, crossSizeOptional.value_or(0.0)).value_or(0.0f);
336         SetLaneGutter(laneGutter);
337     }
338     lanes_ = CalculateLanesParam(minLaneLength_, maxLaneLength_, lanes, crossSizeOptional, laneGutter);
339 }
340 
ModifyLaneLength(std::optional<float> & minLaneLength,std::optional<float> & maxLaneLength,float crossSize)341 void ListLanesLayoutAlgorithm::ModifyLaneLength(
342     std::optional<float>& minLaneLength, std::optional<float>& maxLaneLength, float crossSize)
343 {
344     if (GreatNotEqual(minLaneLength.value(), maxLaneLength.value())) {
345         maxLaneLength = minLaneLength;
346     }
347 }
348 
CalculateLaneCrossOffset(float crossSize,float childCrossSize,bool isGroup)349 float ListLanesLayoutAlgorithm::CalculateLaneCrossOffset(float crossSize, float childCrossSize, bool isGroup)
350 {
351     if (lanes_ <= 0) {
352         return 0.0f;
353     }
354     if (isGroup) {
355         return ListLayoutAlgorithm::CalculateLaneCrossOffset(crossSize, childCrossSize, isGroup);
356     }
357     return ListLayoutAlgorithm::CalculateLaneCrossOffset((crossSize + GetLaneGutter()) / lanes_,
358         childCrossSize / lanes_, isGroup);
359 }
360 
GetLazyForEachIndex(const RefPtr<FrameNode> & host)361 int32_t ListLanesLayoutAlgorithm::GetLazyForEachIndex(const RefPtr<FrameNode>& host)
362 {
363     CHECK_NULL_RETURN(host, -1);
364     auto parent = host->GetParent();
365     auto lazyForEach = AceType::DynamicCast<LazyForEachNode>(parent);
366     if (lazyForEach) {
367         return lazyForEach->GetIndexByUINode(host);
368     }
369     while (parent && !AceType::InstanceOf<FrameNode>(parent)) {
370         if (AceType::InstanceOf<RepeatVirtualScrollNode>(parent)) {
371             return parent->GetFrameNodeIndex(host);
372         }
373         if (AceType::InstanceOf<RepeatVirtualScroll2Node>(parent)) {
374             return parent->GetFrameNodeIndex(host);
375         }
376         parent = parent->GetParent();
377     }
378     return -1;
379 }
380 
FindLanesStartIndex(LayoutWrapper * layoutWrapper,int32_t startIndex,int32_t index)381 int32_t ListLanesLayoutAlgorithm::FindLanesStartIndex(LayoutWrapper* layoutWrapper, int32_t startIndex, int32_t index)
382 {
383     auto wrapper = GetListItem(layoutWrapper, index);
384     CHECK_NULL_RETURN(wrapper, index);
385     if (wrapper->GetHostTag() == V2::LIST_ITEM_GROUP_ETS_TAG) {
386         return index;
387     }
388     auto lazyIndex = GetLazyForEachIndex(wrapper->GetHostNode());
389     if (lazyIndex > 0) {
390         index -= lazyIndex;
391     }
392     for (int32_t idx = index; idx > startIndex; idx--) {
393         auto wrapper = GetListItem(layoutWrapper, idx - 1);
394         CHECK_NULL_RETURN(wrapper, idx);
395         if (wrapper->GetHostTag() == V2::LIST_ITEM_GROUP_ETS_TAG) {
396             return idx;
397         }
398     }
399     if (startIndex == 0) {
400         return 0;
401     }
402     return -1;
403 }
404 
FindLanesStartIndex(LayoutWrapper * layoutWrapper,int32_t index)405 int32_t ListLanesLayoutAlgorithm::FindLanesStartIndex(LayoutWrapper* layoutWrapper, int32_t index)
406 {
407     if (lanes_ == 1) {
408         return 0;
409     }
410     auto it = lanesItemRange_.upper_bound(index);
411     if (it == lanesItemRange_.begin()) {
412         int32_t startIdx = FindLanesStartIndex(layoutWrapper, 0, index);
413         lanesItemRange_[startIdx] = index;
414         return startIdx;
415     }
416     it--;
417     if (it->second >= index) {
418         return it->first;
419     }
420     int32_t startIdx = FindLanesStartIndex(layoutWrapper, it->second, index);
421     if (startIdx >= 0) {
422         lanesItemRange_[startIdx] = index;
423         return startIdx;
424     }
425     it->second = index;
426     return it->first;
427 }
428 
GetLanesFloor(LayoutWrapper * layoutWrapper,int32_t index)429 int32_t ListLanesLayoutAlgorithm::GetLanesFloor(LayoutWrapper* layoutWrapper, int32_t index)
430 {
431     if (lanes_ > 1) {
432         if (childrenSize_) {
433             return posMap_->GetRowStartIndex(index);
434         }
435         int32_t startIndex = FindLanesStartIndex(layoutWrapper, index);
436         return index - (index - startIndex) % lanes_;
437     }
438     return index;
439 }
440 
GetLanesCeil(LayoutWrapper * layoutWrapper,int32_t index)441 int32_t ListLanesLayoutAlgorithm::GetLanesCeil(LayoutWrapper* layoutWrapper, int32_t index)
442 {
443     if (lanes_ > 1) {
444         if (childrenSize_) {
445             return posMap_->GetRowEndIndex(index);
446         }
447         int32_t startIndex = GetLanesFloor(layoutWrapper, index);
448         while (startIndex == GetLanesFloor(layoutWrapper, index + 1)) {
449             index++;
450         }
451     }
452     return index;
453 }
454 
LayoutCachedALine(LayoutWrapper * layoutWrapper,std::pair<const int,ListItemInfo> & pos,int32_t startIndex,float crossSize)455 void ListLanesLayoutAlgorithm::LayoutCachedALine(LayoutWrapper* layoutWrapper,
456     std::pair<const int, ListItemInfo>& pos, int32_t startIndex, float crossSize)
457 {
458     auto wrapper = GetChildByIndex(layoutWrapper, pos.first, true);
459     CHECK_NULL_VOID(wrapper);
460     bool isDirty = wrapper->CheckNeedForceMeasureAndLayout() || !IsListLanesEqual(wrapper);
461     LayoutItem(wrapper, pos.first, pos.second, startIndex, crossSize);
462     SyncGeometry(wrapper, isDirty);
463     wrapper->SetActive(false);
464     SetCachedItemInfo(pos.first, std::move(pos.second));
465 }
466 
CheckACachedItem(const RefPtr<LayoutWrapper> & wrapper,int32_t cnt,bool & isGroup) const467 std::pair<bool, bool> ListLanesLayoutAlgorithm::CheckACachedItem(
468     const RefPtr<LayoutWrapper>& wrapper, int32_t cnt, bool& isGroup) const
469 {
470     if (!wrapper) {
471         return std::make_pair(true, true);
472     }
473     isGroup = wrapper->GetHostTag() == V2::LIST_ITEM_GROUP_ETS_TAG;
474     if (isGroup && cnt > 0) {
475         isGroup = false;
476         return std::make_pair(true, false);
477     }
478     bool isDirty = wrapper->CheckNeedForceMeasureAndLayout() || !IsListLanesEqual(wrapper);
479     if (!isGroup && (isDirty || CheckLayoutConstraintChanged(wrapper))) {
480         if (isDirty && !wrapper->GetHostNode()->IsLayoutComplete()) {
481             return std::make_pair(true, true);
482         }
483         return std::make_pair(false, true);
484     }
485     return std::make_pair(false, false);
486 }
487 
LayoutCachedForward(LayoutWrapper * layoutWrapper,int32_t cacheCount,int32_t & cachedCount,int32_t curIndex,std::list<PredictLayoutItem> & predictList,bool show)488 int32_t ListLanesLayoutAlgorithm::LayoutCachedForward(LayoutWrapper* layoutWrapper,
489     int32_t cacheCount, int32_t& cachedCount, int32_t curIndex, std::list<PredictLayoutItem>& predictList, bool show)
490 {
491     float crossSize = GetLayoutCrossAxisSize(layoutWrapper);
492     RefPtr<LayoutWrapper> wrapper;
493     curIndex = GetItemPosition().rbegin()->first + 1;
494     auto startPos = GetItemPosition().rbegin()->second.endPos + GetSpaceWidth();
495     while (cachedCount < cacheCount && curIndex <= GetMaxListItemIndex()) {
496         ListLayoutAlgorithm::PositionMap posMap;
497         float mainLen = 0.0f;
498         bool isGroup = false;
499         int32_t cnt = 0;
500         for (int32_t i = 0; i < lanes_ && curIndex + i <= GetMaxListItemIndex() && !isGroup; i++) {
501             wrapper = GetChildByIndex(layoutWrapper, curIndex + i, !show);
502             auto [needBreak, needPredict] = CheckACachedItem(wrapper, cnt, isGroup);
503             if (needPredict) {
504                 predictList.emplace_back(PredictLayoutItem { curIndex + i, cachedCount, -1 });
505             }
506             if (needBreak) {
507                 break;
508             }
509             cnt++;
510             mainLen = std::max(mainLen, GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_));
511             posMap[curIndex + i] = { wrapper->GetHostNode()->GetId(), startPos, startPos + mainLen, isGroup };
512         }
513         auto startIndex = curIndex;
514         if (isGroup) {
515             auto res = GetLayoutGroupCachedCount(layoutWrapper, wrapper, cacheCount - cachedCount, -1, curIndex, true);
516             if (res.forwardCachedCount < res.forwardCacheMax && res.forwardCachedCount < cacheCount - cachedCount) {
517                 LayoutItem(wrapper, posMap.begin()->first, posMap.begin()->second, startIndex, crossSize);
518                 predictList.emplace_back(PredictLayoutItem { posMap.begin()->first, cachedCount, -1 });
519                 return res.forwardCachedCount > 0 ? curIndex : curIndex - 1;
520             }
521             cachedCount += std::max(res.forwardCacheMax, 1);
522         } else if (cnt > 0) {
523             cachedCount++;
524         } else {
525             break;
526         }
527         for (auto& pos : posMap) {
528             pos.second.endPos = startPos + mainLen;
529             LayoutCachedALine(layoutWrapper, pos, startIndex, crossSize);
530         }
531         if (isStackFromEnd_) {
532             SetLaneIdx4Divider(cnt - 1);
533         }
534         startPos = startPos + mainLen + GetSpaceWidth();
535         curIndex += cnt;
536     }
537     return curIndex - 1;
538 }
539 
LayoutCachedBackward(LayoutWrapper * layoutWrapper,int32_t cacheCount,int32_t & cachedCount,int32_t curIndex,std::list<PredictLayoutItem> & predictList,bool show)540 int32_t ListLanesLayoutAlgorithm::LayoutCachedBackward(LayoutWrapper* layoutWrapper,
541     int32_t cacheCount, int32_t& cachedCount, int32_t curIndex, std::list<PredictLayoutItem>& predictList, bool show)
542 {
543     float crossSize = GetLayoutCrossAxisSize(layoutWrapper);
544     RefPtr<LayoutWrapper> wrapper;
545     curIndex = GetItemPosition().begin()->first - 1;
546     auto endPos = GetItemPosition().begin()->second.startPos - GetSpaceWidth();
547     while (cachedCount < cacheCount && curIndex >= 0) {
548         ListLayoutAlgorithm::PositionMap posMap;
549         float mainLen = 0.0f;
550         bool isGroup = false;
551         int32_t cnt = 0;
552         for (int32_t i = 0; i < lanes_ && curIndex - i >= 0; i++) {
553             auto idx = curIndex - i;
554             wrapper = GetChildByIndex(layoutWrapper, idx, !show);
555             auto [needBreak, needPredict] = CheckACachedItem(wrapper, cnt, isGroup);
556             if (needPredict) {
557                 predictList.emplace_back(PredictLayoutItem { idx, -1, cachedCount });
558             }
559             if (needBreak) {
560                 break;
561             }
562             cnt++;
563             mainLen = std::max(mainLen, GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_));
564             posMap[idx] = { wrapper->GetHostNode()->GetId(), endPos - mainLen, endPos, isGroup };
565             if (CheckCurRowMeasureFinished(layoutWrapper, idx, isGroup)) {
566                 break;
567             }
568         }
569         auto startIndex = GetLanesFloor(layoutWrapper, curIndex);
570         if (isGroup) {
571             auto res = GetLayoutGroupCachedCount(layoutWrapper, wrapper, -1, cacheCount - cachedCount, curIndex, true);
572             if (res.backwardCachedCount < res.backwardCacheMax && res.backwardCachedCount < cacheCount - cachedCount) {
573                 LayoutItem(wrapper, posMap.begin()->first, posMap.begin()->second, startIndex, crossSize);
574                 predictList.emplace_back(PredictLayoutItem { posMap.begin()->first, -1, cachedCount });
575                 return res.backwardCachedCount > 0 ? curIndex : curIndex + 1;
576             }
577             cachedCount += std::max(res.backwardCacheMax, 1);
578         } else if (cnt > 0) {
579             cachedCount++;
580         } else {
581             break;
582         }
583         for (auto& pos: posMap) {
584             pos.second.startPos = endPos - mainLen;
585             LayoutCachedALine(layoutWrapper, pos, startIndex, crossSize);
586         }
587         if (!isStackFromEnd_) {
588             SetLaneIdx4Divider(curIndex - startIndex + 1 - cnt);
589         }
590         endPos = endPos - mainLen - GetSpaceWidth();
591         curIndex -= cnt;
592     }
593     return curIndex + 1;
594 }
595 } // namespace OHOS::Ace::NG
596