• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2025 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/grid/grid_scroll/grid_scroll_with_options_layout_algorithm.h"
17 
18 #include "core/components_ng/pattern/grid/grid_utils.h"
19 #include "core/components_ng/pattern/grid/irregular/grid_layout_utils.h"
20 #include "core/components_ng/property/measure_utils.h"
21 
22 namespace OHOS::Ace::NG {
23 namespace {
UpdateGridItemRowAndColumnInfo(const RefPtr<LayoutWrapper> & itemLayoutWrapper,GridItemIndexInfo irregualItemInfo)24 void UpdateGridItemRowAndColumnInfo(const RefPtr<LayoutWrapper>& itemLayoutWrapper, GridItemIndexInfo irregualItemInfo)
25 {
26     auto gridItemHost = itemLayoutWrapper->GetHostNode();
27     CHECK_NULL_VOID(gridItemHost);
28     auto gridItemPattern = gridItemHost->GetPattern<GridItemPattern>();
29     CHECK_NULL_VOID(gridItemPattern);
30     gridItemPattern->SetIrregularItemInfo(irregualItemInfo);
31 }
32 } // namespace
33 
AdjustRowColSpan(const RefPtr<LayoutWrapper> & itemLayoutWrapper,LayoutWrapper * layoutWrapper,int32_t itemIndex)34 void GridScrollWithOptionsLayoutAlgorithm::AdjustRowColSpan(
35     const RefPtr<LayoutWrapper>& itemLayoutWrapper, LayoutWrapper* layoutWrapper, int32_t itemIndex)
36 {
37     auto layoutProperty = DynamicCast<GridLayoutProperty>(layoutWrapper->GetLayoutProperty());
38     CHECK_NULL_VOID(layoutProperty);
39     const auto& options = *layoutProperty->GetLayoutOptions();
40     auto result = GetCrossStartAndSpan(options, itemIndex);
41     if (info_.axis_ == Axis::VERTICAL) {
42         currentItemColStart_ = result.first;
43         currentItemColSpan_ = result.second;
44         currentItemColEnd_ = currentItemColStart_ + currentItemColSpan_ - 1;
45         currentItemRowStart_ = -1;
46         currentItemRowEnd_ = -1;
47         currentItemRowSpan_ = 1;
48     } else {
49         currentItemRowStart_ = result.first;
50         currentItemRowSpan_ = result.second;
51         currentItemRowEnd_ = currentItemRowStart_ + currentItemRowSpan_ - 1;
52         currentItemColStart_ = -1;
53         currentItemColEnd_ = -1;
54         currentItemColSpan_ = 1;
55     }
56 
57     if (currentItemRowSpan_ > 1 || currentItemColSpan_ > 1) {
58         info_.hasBigItem_ = true;
59         bool isVertical = info_.axis_ == Axis::VERTICAL;
60         GridItemIndexInfo irregualItemInfo;
61         irregualItemInfo.mainStart = isVertical ? currentItemRowStart_ : currentItemColStart_;
62         irregualItemInfo.mainEnd = isVertical ? currentItemRowEnd_ : currentItemColEnd_;
63         irregualItemInfo.mainSpan = isVertical ? currentItemRowSpan_ : currentItemColSpan_;
64         irregualItemInfo.crossStart = isVertical ? currentItemColStart_ : currentItemRowStart_;
65         irregualItemInfo.crossEnd = isVertical ? currentItemColEnd_ : currentItemRowEnd_;
66         irregualItemInfo.crossSpan = isVertical ? currentItemColSpan_ : currentItemRowSpan_;
67         UpdateGridItemRowAndColumnInfo(itemLayoutWrapper, irregualItemInfo);
68     }
69 }
70 
LargeItemLineHeight(const RefPtr<LayoutWrapper> & itemWrapper)71 void GridScrollWithOptionsLayoutAlgorithm::LargeItemLineHeight(const RefPtr<LayoutWrapper>& itemWrapper)
72 {
73     auto itemSize = itemWrapper->GetGeometryNode()->GetMarginFrameSize();
74     auto itemMainSize = GetMainAxisSize(itemSize, info_.axis_);
75     if (LessNotEqual(itemMainSize, 0.0f)) {
76         TAG_LOGI(
77             AceLogTag::ACE_GRID, "item height of index %{public}d is less than zero", info_.endIndex_ + 1);
78         itemMainSize = 0.0f;
79     }
80     cellAveLength_ = std::max(itemMainSize, cellAveLength_);
81 }
82 
GetTargetIndexInfoWithBenchMark(LayoutWrapper * layoutWrapper,bool isTargetBackward,int32_t targetIndex)83 void GridScrollWithOptionsLayoutAlgorithm::GetTargetIndexInfoWithBenchMark(
84     LayoutWrapper* layoutWrapper, bool isTargetBackward, int32_t targetIndex)
85 {
86     int32_t benchmarkIndex = (isTargetBackward && !info_.gridMatrix_.empty())
87                                  ? info_.gridMatrix_.rbegin()->second.rbegin()->second + 1
88                                  : 0;
89     int32_t mainStartIndex = (isTargetBackward && !info_.gridMatrix_.empty())
90                                  ? info_.gridMatrix_.rbegin()->first + 1
91                                  : 0;
92     int32_t currentIndex = benchmarkIndex;
93     int32_t headOfMainStartLine = currentIndex;
94     auto layoutProperty = DynamicCast<GridLayoutProperty>(layoutWrapper->GetLayoutProperty());
95     CHECK_NULL_VOID(layoutProperty);
96     const auto& options = *layoutProperty->GetLayoutOptions();
97     while (currentIndex < targetIndex) {
98         int32_t crossGridReserve = info_.crossCount_;
99         /* go through a new line */
100         while ((crossGridReserve > 0) && (currentIndex <= targetIndex)) {
101             auto crossPos = GetCrossStartAndSpan(options, currentIndex);
102             auto gridSpan = crossPos.second;
103             if (crossGridReserve >= gridSpan) {
104                 crossGridReserve -= gridSpan;
105             } else if (info_.crossCount_ >= gridSpan) {
106                 ++mainStartIndex;
107                 headOfMainStartLine = currentIndex;
108                 crossGridReserve = info_.crossCount_ - gridSpan;
109             }
110             ++currentIndex;
111         }
112         if (currentIndex > targetIndex) {
113             break;
114         }
115         ++mainStartIndex;
116         headOfMainStartLine = currentIndex;
117     }
118     info_.startMainLineIndex_ = mainStartIndex;
119     info_.startIndex_ = headOfMainStartLine;
120     info_.endIndex_ = headOfMainStartLine - 1;
121     info_.prevOffset_ = 0;
122     info_.currentOffset_ = 0;
123     info_.ResetPositionFlags();
124     info_.gridMatrix_.clear();
125     info_.lineHeightMap_.clear();
126     info_.irregularItemsPosition_.clear();
127 }
128 
GetCrossStartAndSpan(const GridLayoutOptions & options,int32_t itemIndex)129 std::pair<int32_t, int32_t> GridScrollWithOptionsLayoutAlgorithm::GetCrossStartAndSpan(
130     const GridLayoutOptions& options, int32_t itemIndex)
131 {
132     if (options.irregularIndexes.empty()) {
133         return std::make_pair(-1, 1);
134     }
135 
136     auto firstIrregularIndex = *(options.irregularIndexes.begin());
137     if (itemIndex < firstIrregularIndex) {
138         return std::make_pair(itemIndex % crossCount_, 1);
139     }
140 
141     // without function
142     if (!options.getSizeByIndex) {
143         if (options.irregularIndexes.find(itemIndex) != options.irregularIndexes.end()) {
144             return std::make_pair(0, crossCount_);
145         }
146         int32_t crossStart = -1;
147         auto iter = options.irregularIndexes.upper_bound(itemIndex);
148         auto crossCount = static_cast<int32_t>(crossCount_);
149         if (iter == options.irregularIndexes.end()) {
150             crossStart = (itemIndex - (*(options.irregularIndexes.rbegin()) + 1)) % crossCount;
151         } else {
152             if (iter != options.irregularIndexes.begin()) {
153                 crossStart = (itemIndex - (*(--iter) + 1)) % crossCount;
154             } else {
155                 crossStart = itemIndex % crossCount;
156             }
157         }
158         return std::make_pair(crossStart, 1);
159     }
160 
161     return GetCrossStartAndSpanWithUserFunction(itemIndex, options, firstIrregularIndex);
162 }
163 
JumpToLastIrregularItem(const std::map<int32_t,int32_t> & irregularItemsPosition,int32_t & sum,int32_t & lastIndex,int32_t targetIndex)164 static void JumpToLastIrregularItem(
165     const std::map<int32_t, int32_t>& irregularItemsPosition, int32_t& sum, int32_t& lastIndex, int32_t targetIndex)
166 {
167     if (irregularItemsPosition.empty()) {
168         return;
169     }
170 
171     auto iter = irregularItemsPosition.lower_bound(targetIndex);
172     if (iter == irregularItemsPosition.begin()) {
173         return;
174     }
175     if (iter != irregularItemsPosition.end()) {
176         --iter;
177         sum = iter->second;
178         lastIndex = iter->first;
179     } else {
180         auto lastIter = irregularItemsPosition.rbegin();
181         sum = lastIter->second;
182         lastIndex = lastIter->first;
183     }
184 }
185 
ResetInvalidCrossSpan(uint32_t crossCount,int32_t & crossSpan)186 static void ResetInvalidCrossSpan(uint32_t crossCount, int32_t& crossSpan)
187 {
188     if (crossSpan > static_cast<int32_t>(crossCount) || crossSpan <= 0) {
189         crossSpan = 1;
190     }
191 }
192 
InitIrregularItemsPosition(std::map<int32_t,int32_t> & irregularItemsPosition,const GridLayoutOptions & options,int32_t firstIrregularIndex,Axis axis,int32_t crossCount)193 static void InitIrregularItemsPosition(std::map<int32_t, int32_t>& irregularItemsPosition,
194     const GridLayoutOptions& options, int32_t firstIrregularIndex, Axis axis, int32_t crossCount)
195 {
196     if (irregularItemsPosition.empty()) {
197         auto sum = firstIrregularIndex;
198         auto crossSpan = options.getSizeByIndex(firstIrregularIndex).GetCrossSize(axis);
199         ResetInvalidCrossSpan(crossCount, crossSpan);
200         // first irregular item in new line
201         if (crossCount != 0) {
202             auto crossStart = sum % crossCount;
203             if (crossStart + crossSpan > crossCount) {
204                 sum += (crossCount - crossStart);
205             }
206         }
207         irregularItemsPosition.emplace(firstIrregularIndex, sum + crossSpan);
208     }
209 }
210 
GetCrossStartAndSpanWithUserFunction(int32_t itemIndex,const GridLayoutOptions & options,int32_t firstIrregularIndex)211 std::pair<int32_t, int32_t> GridScrollWithOptionsLayoutAlgorithm::GetCrossStartAndSpanWithUserFunction(
212     int32_t itemIndex, const GridLayoutOptions& options, int32_t firstIrregularIndex)
213 {
214     auto crossCount = static_cast<int32_t>(crossCount_);
215     InitIrregularItemsPosition(
216         info_.irregularItemsPosition_, options, firstIrregularIndex, info_.axis_, crossCount);
217     auto sum = firstIrregularIndex;
218     auto lastIndex = firstIrregularIndex;
219     JumpToLastIrregularItem(info_.irregularItemsPosition_, sum, lastIndex, itemIndex);
220     auto iter = options.irregularIndexes.find(lastIndex);
221     if (iter == options.irregularIndexes.end()) {
222         iter = options.irregularIndexes.begin();
223     }
224     for (; iter != options.irregularIndexes.end(); ++iter) {
225         auto index = *iter;
226         if (index >= itemIndex) {
227             break;
228         }
229 
230         if (index == lastIndex) {
231             continue;
232         }
233 
234         auto crossSpan = options.getSizeByIndex(index).GetCrossSize(info_.axis_);
235         ResetInvalidCrossSpan(crossCount_, crossSpan);
236         auto irregularStart = (sum + index - lastIndex - 1) % crossCount;
237         // put it into next line
238         if (irregularStart + crossSpan > crossCount) {
239             sum += (crossCount - irregularStart);
240         }
241         sum += (index - lastIndex - 1);
242         sum += crossSpan;
243         lastIndex = index;
244         info_.irregularItemsPosition_.emplace(index, sum);
245     }
246     sum += ((itemIndex > lastIndex) ? (itemIndex - lastIndex - 1) : 0);
247     auto crossStart = sum % crossCount;
248     bool isRegularItem = (options.irregularIndexes.find(itemIndex) == options.irregularIndexes.end());
249     auto crossSpan = isRegularItem ? 1 : options.getSizeByIndex(itemIndex).GetCrossSize(info_.axis_);
250     ResetInvalidCrossSpan(crossCount_, crossSpan);
251     if (crossStart + crossSpan > crossCount) {
252         sum += (crossCount - crossStart);
253         crossStart = 0;
254     }
255     if (!isRegularItem) {
256         sum += crossSpan;
257         info_.irregularItemsPosition_.emplace(itemIndex, sum);
258     }
259     return std::make_pair(crossStart, crossSpan);
260 }
261 
SkipLargeOffset(float mainSize,LayoutWrapper * layoutWrapper)262 void GridScrollWithOptionsLayoutAlgorithm::SkipLargeOffset(float mainSize, LayoutWrapper* layoutWrapper)
263 {
264     SkipForwardLines(mainSize, layoutWrapper);
265     SkipBackwardLines(mainSize, layoutWrapper);
266 }
267 
SkipIrregularLines(LayoutWrapper * layoutWrapper,bool forward)268 void GridScrollWithOptionsLayoutAlgorithm::SkipIrregularLines(LayoutWrapper* layoutWrapper, bool forward)
269 {
270     auto layoutProperty = DynamicCast<GridLayoutProperty>(layoutWrapper->GetLayoutProperty());
271     CHECK_NULL_VOID(layoutProperty);
272     const auto& options = *layoutProperty->GetLayoutOptions();
273     if (options.irregularIndexes.empty()) {
274         return SkipRegularLines(forward);
275     }
276     if (options.getSizeByIndex) {
277         return GridScrollLayoutAlgorithm::SkipIrregularLines(layoutWrapper, forward);
278     }
279 
280     info_.SkipStartIndexByOffset(options, mainGap_);
281 }
282 
CalculateCachedCount(LayoutWrapper * layoutWrapper,int32_t cachedCount)283 std::pair<int32_t, int32_t> GridScrollWithOptionsLayoutAlgorithm::CalculateCachedCount(
284     LayoutWrapper* layoutWrapper, int32_t cachedCount)
285 {
286     if (cachedCount == 0 || info_.crossCount_ == 1) {
287         return std::make_pair(cachedCount, cachedCount);
288     }
289     int32_t cache = cachedCount * info_.crossCount_;
290 
291     CHECK_NULL_RETURN(layoutWrapper, std::make_pair(cache, cache));
292     auto props = DynamicCast<GridLayoutProperty>(layoutWrapper->GetLayoutProperty());
293     CHECK_NULL_RETURN(props, std::make_pair(cache, cache));
294 
295     const auto& options = *props->GetLayoutOptions();
296     if (options.irregularIndexes.empty()) {
297         return std::make_pair(cache, cache);
298     }
299     int32_t start = CalculateStartCachedCount(options, cachedCount);
300     int32_t end = CalculateEndCachedCount(options, cachedCount);
301     return std::make_pair(start, end);
302 }
303 
CalculateStartCachedCount(const GridLayoutOptions & options,int32_t cachedCount)304 int32_t GridScrollWithOptionsLayoutAlgorithm::CalculateStartCachedCount(
305     const GridLayoutOptions& options, int32_t cachedCount)
306 {
307     int32_t start = cachedCount * info_.crossCount_;
308 
309     if (info_.startMainLineIndex_ - cachedCount <= 0) {
310         return std::min(info_.startIndex_, start);
311     }
312 
313     auto startLine = info_.gridMatrix_.find(info_.startMainLineIndex_ - cachedCount);
314     if (startLine != info_.gridMatrix_.end()) {
315         auto line = startLine->second;
316         if (!line.empty()) {
317             auto index = line.begin()->second;
318             return info_.startIndex_ - index;
319         }
320     }
321 
322     auto firstIrregularIndex = *(options.irregularIndexes.begin());
323     if (info_.startIndex_ <= firstIrregularIndex) {
324         return start;
325     }
326 
327     if (!options.getSizeByIndex) {
328         auto iter = options.irregularIndexes.lower_bound(info_.startIndex_);
329         auto crossCount = static_cast<int32_t>(crossCount_);
330         if (iter == options.irregularIndexes.end()) {
331             return start;
332         }
333         if (*iter == info_.startIndex_ && iter != options.irregularIndexes.begin()) {
334             iter--;
335         }
336 
337         int lineCount = 0;
338         int sum = 0;
339         int32_t diff = info_.startIndex_ - *(iter)-1;
340         while (lineCount < cachedCount) {
341             if (diff >= (cachedCount - lineCount) * crossCount) {
342                 return (cachedCount - lineCount) * crossCount + sum;
343             }
344 
345             if (diff == 0) {
346                 sum++;
347                 lineCount++;
348             }
349 
350             if (diff > 0 && diff <= (cachedCount - lineCount - 1) * crossCount) {
351                 lineCount += std::ceil(diff / crossCount) + 1;
352                 sum += diff;
353             }
354 
355             if (iter == options.irregularIndexes.begin()) {
356                 return (cachedCount - lineCount) * crossCount + sum;
357             }
358 
359             diff = (*iter) - (*(--iter)) - 1;
360         }
361         return sum;
362     }
363     return start;
364 }
365 
CalculateEndCachedCount(const GridLayoutOptions & options,int32_t cachedCount)366 int32_t GridScrollWithOptionsLayoutAlgorithm::CalculateEndCachedCount(
367     const GridLayoutOptions& options, int32_t cachedCount)
368 {
369     if (info_.startIndex_ + cachedCount >= info_.GetChildrenCount() - 1) {
370         return info_.startIndex_;
371     }
372 
373     int32_t end = cachedCount * info_.crossCount_;
374 
375     auto endLine = info_.gridMatrix_.find(info_.endMainLineIndex_ + cachedCount);
376     if (endLine != info_.gridMatrix_.end()) {
377         auto line = endLine->second;
378         if (!line.empty()) {
379             auto index = line.rbegin()->second;
380             return index - info_.endIndex_;
381         }
382     }
383 
384     auto lastIrregularIndex = *(options.irregularIndexes.rbegin());
385     if (info_.endIndex_ >= lastIrregularIndex) {
386         return end;
387     }
388 
389     if (!options.getSizeByIndex) {
390         auto iter = options.irregularIndexes.upper_bound(info_.endIndex_);
391         auto crossCount = static_cast<int32_t>(crossCount_);
392         if (iter == options.irregularIndexes.end()) {
393             return end;
394         }
395 
396         int lineCount = 0;
397         int sum = 0;
398         int32_t diff = *(iter)-info_.endIndex_ - 1;
399         while (lineCount < cachedCount) {
400             if (diff >= (cachedCount - lineCount) * crossCount) {
401                 return (cachedCount - lineCount) * crossCount + sum;
402             }
403 
404             if (diff == 0) {
405                 sum++;
406                 lineCount++;
407             }
408 
409             if (diff > 0 && diff <= (cachedCount - lineCount - 1) * crossCount) {
410                 lineCount += std::ceil(diff / crossCount) + 1;
411                 sum += diff;
412             }
413 
414             if (iter == options.irregularIndexes.end()) {
415                 return (cachedCount - lineCount) * crossCount + sum;
416             }
417 
418             diff = -*(iter) + *(++iter) - 1;
419         }
420         return sum;
421     }
422     return end;
423 }
424 
PreloadItems(LayoutWrapper * layoutWrapper)425 void GridScrollWithOptionsLayoutAlgorithm::PreloadItems(LayoutWrapper* layoutWrapper)
426 {
427     auto layoutProperty = DynamicCast<GridLayoutProperty>(layoutWrapper->GetLayoutProperty());
428     CHECK_NULL_VOID(layoutProperty);
429     const auto& options = *layoutProperty->GetLayoutOptions();
430     std::map<int32_t, std::pair<int32_t, int32_t>> itemCrossMap;
431     for (auto item : predictBuildList_) {
432         auto result = GetCrossStartAndSpan(options, item.idx);
433         itemCrossMap.emplace(item.idx, result);
434     }
435     GridLayoutUtils::PreloadGridItems(layoutWrapper->GetHostNode()->GetPattern<GridPattern>(),
436         std::move(predictBuildList_),
437         [param = GridPredictLayoutParam { cachedChildConstraint_, itemsCrossSize_, crossGap_ }, itemCrossMap](
438             const RefPtr<FrameNode>& host, int32_t itemIdx) {
439             CHECK_NULL_RETURN(host, false);
440             return PredictBuildItem(*host, itemIdx, param, itemCrossMap);
441         });
442 }
443 
444 namespace {
GenerateCacheItemConstraint(std::pair<int32_t,int32_t> cross,Axis axis,const GridPredictLayoutParam & param)445 LayoutConstraintF GenerateCacheItemConstraint(
446     std::pair<int32_t, int32_t> cross, Axis axis, const GridPredictLayoutParam& param)
447 {
448     auto constraint = param.layoutConstraint;
449     int32_t crossStart = cross.first;
450     int32_t crossSpan = cross.second;
451     if (crossSpan > 1) {
452         float itemCrossSize = param.crossGap * (crossSpan - 1);
453         for (int32_t index = 0; index < crossSpan; ++index) {
454             int32_t crossIndex = (crossStart + index) % static_cast<int32_t>(param.itemsCrossSizes.size());
455             if (crossIndex >= 0 && crossIndex < static_cast<int32_t>(param.itemsCrossSizes.size())) {
456                 itemCrossSize += GetOrDefault(param.itemsCrossSizes, crossIndex, 0.0f);
457             }
458         }
459         constraint.maxSize.SetCrossSize(itemCrossSize, axis);
460         constraint.selfIdealSize.SetCrossSize(itemCrossSize, axis);
461     }
462     return constraint;
463 }
464 } // namespace
465 
PredictBuildItem(FrameNode & host,int32_t itemIdx,const GridPredictLayoutParam & param,std::map<int32_t,std::pair<int32_t,int32_t>> itemCrossMap)466 bool GridScrollWithOptionsLayoutAlgorithm::PredictBuildItem(FrameNode& host, int32_t itemIdx,
467     const GridPredictLayoutParam& param, std::map<int32_t, std::pair<int32_t, int32_t>> itemCrossMap)
468 {
469     // build callback
470     auto wrapper = host.GetOrCreateChildByIndex(itemIdx, false, true);
471     CHECK_NULL_RETURN(wrapper, false);
472     auto itemCross = itemCrossMap.find(itemIdx);
473     if (itemCross == itemCrossMap.end()) {
474         return false;
475     }
476     const Axis axis = host.GetPattern<GridPattern>()->GetAxis();
477 
478     auto constraint = GenerateCacheItemConstraint(itemCross->second, axis, param);
479     wrapper->SetActive(false);
480     auto frameNode = wrapper->GetHostNode();
481     CHECK_NULL_RETURN(frameNode, false);
482     frameNode->GetGeometryNode()->SetParentLayoutConstraint(constraint);
483     FrameNode::ProcessOffscreenNode(frameNode);
484     return true;
485 }
486 
GetStartingItem(LayoutWrapper * layoutWrapper,int32_t currentIndex)487 int32_t GridScrollWithOptionsLayoutAlgorithm::GetStartingItem(LayoutWrapper* layoutWrapper, int32_t currentIndex)
488 {
489     int32_t firstIndex = 0;
490     currentIndex = currentIndex < info_.GetChildrenCount() ? currentIndex : info_.GetChildrenCount() - 1;
491     auto index = currentIndex;
492     while (index > 0) {
493         auto childLayoutWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
494         if (!childLayoutWrapper) {
495             TAG_LOGW(AceLogTag::ACE_GRID, "item [%{public}d] does not exist, reload to [0]", index);
496             break;
497         }
498 
499         AdjustRowColSpan(childLayoutWrapper, layoutWrapper, index);
500         auto crossIndex = info_.axis_ == Axis::VERTICAL ? currentItemColStart_ : currentItemRowStart_;
501         if (crossIndex == -1 && index % info_.crossCount_ == 0) {
502             firstIndex = index;
503             break;
504         }
505         if (crossIndex == 0) {
506             firstIndex = index;
507             break;
508         }
509         --index;
510     }
511 
512     return firstIndex;
513 }
514 } // namespace OHOS::Ace::NG
515