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