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/swiper/swiper_layout_algorithm.h"
17 
18 #include <algorithm>
19 #include <cstdint>
20 
21 #include "base/geometry/axis.h"
22 #include "base/geometry/ng/offset_t.h"
23 #include "base/geometry/ng/size_t.h"
24 #include "base/log/ace_trace.h"
25 #include "base/utils/utils.h"
26 #include "core/components_ng/base/frame_node.h"
27 #include "core/components_ng/layout/layout_algorithm.h"
28 #include "core/components_ng/pattern/swiper/swiper_layout_property.h"
29 #include "core/components_ng/pattern/swiper/swiper_pattern.h"
30 #include "core/components_ng/pattern/swiper/swiper_utils.h"
31 #include "core/components_ng/pattern/swiper_indicator/dot_indicator/dot_indicator_paint_property.h"
32 #include "core/components_ng/pattern/swiper_indicator/indicator_common/swiper_indicator_utils.h"
33 #include "core/components_ng/property/layout_constraint.h"
34 #include "core/components_ng/property/measure_property.h"
35 #include "core/components_ng/property/measure_utils.h"
36 #include "core/components_v2/inspector/inspector_constants.h"
37 
38 namespace OHOS::Ace::NG {
39 
40 namespace {
41 constexpr Dimension INDICATOR_PADDING = 8.0_vp;
42 constexpr uint32_t INDICATOR_HAS_CHILD = 2;
43 constexpr uint32_t SWIPER_HAS_CHILD = 5;
44 } // namespace
45 
CheckIsSingleCase(const RefPtr<SwiperLayoutProperty> & property)46 bool SwiperLayoutAlgorithm::CheckIsSingleCase(const RefPtr<SwiperLayoutProperty>& property)
47 {
48     bool hasMinSize = property->GetMinSize().has_value() && !LessOrEqual(property->GetMinSizeValue().Value(), 0);
49     bool hasPrevMargin = Positive(property->GetCalculatedPrevMargin());
50     bool hasNextMargin = Positive(property->GetCalculatedNextMargin());
51 
52     return !hasMinSize && (!hasPrevMargin && !hasNextMargin) &&
53            ((property->GetDisplayCount().has_value() && property->GetDisplayCountValue() == 1) ||
54                (!property->GetDisplayCount().has_value() && SwiperUtils::IsStretch(property)));
55 }
56 
IndicatorAndArrowMeasure(LayoutWrapper * layoutWrapper,const OptionalSizeF & parentIdealSize)57 void SwiperLayoutAlgorithm::IndicatorAndArrowMeasure(LayoutWrapper* layoutWrapper, const OptionalSizeF& parentIdealSize)
58 {
59     auto property = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
60     CHECK_NULL_VOID(property);
61 
62     // Measure swiper indicator
63     if (property->GetShowIndicatorValue(true)) {
64         auto hostNode = layoutWrapper->GetHostNode();
65         CHECK_NULL_VOID(hostNode);
66         auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
67         CHECK_NULL_VOID(swiperPattern);
68         auto indicatorWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_INDICATOR_ETS_TAG);
69         if (indicatorWrapper) {
70             auto indicatorLayoutConstraint = property->CreateChildConstraint();
71             indicatorLayoutConstraint.parentIdealSize = parentIdealSize;
72             indicatorWrapper->Measure(indicatorLayoutConstraint);
73         }
74     }
75 
76     if (property->GetDisplayArrowValue(false)) {
77         auto hostNode = layoutWrapper->GetHostNode();
78         CHECK_NULL_VOID(hostNode);
79         auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
80         CHECK_NULL_VOID(swiperPattern);
81 
82         if (swiperPattern->HasLeftButtonNode() && swiperPattern->HasRightButtonNode()) {
83             auto leftArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_ARROW_ETS_TAG);
84             auto rightArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_ARROW_ETS_TAG);
85             CHECK_NULL_VOID(leftArrowWrapper);
86             CHECK_NULL_VOID(rightArrowWrapper);
87             if (leftArrowWrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG &&
88                 rightArrowWrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
89                 MeasureArrow(leftArrowWrapper, property);
90                 MeasureArrow(rightArrowWrapper, property);
91             }
92         }
93     }
94 }
95 
UpdateLayoutInfoBeforeMeasureSwiper(const RefPtr<SwiperLayoutProperty> & property)96 void SwiperLayoutAlgorithm::UpdateLayoutInfoBeforeMeasureSwiper(const RefPtr<SwiperLayoutProperty>& property)
97 {
98     if (measured_) {
99         // flex property causes Swiper to be measured twice, and itemPosition_ would
100         // reset after the first measure. Restore to that on second measure.
101         itemPosition_ = prevItemPosition_;
102         // targetIndex_ has also been reset during the first measure.
103         targetIndex_ = currentTargetIndex_;
104         if (duringInteraction_ || NearEqual(oldContentMainSize_, contentMainSize_)) {
105             jumpIndex_ = currentJumpIndex_;
106         }
107         ignoreBlankOffset_ = currentIgnoreBlankOffset_;
108     }
109     currentOffset_ = currentDelta_;
110     startMainPos_ = currentOffset_;
111     ACE_SCOPED_TRACE("measure swiper startMainPos_:%f", startMainPos_);
112     if (SwiperUtils::IsStretch(property)) {
113         prevMargin_ = property->GetCalculatedPrevMargin();
114         nextMargin_ = property->GetCalculatedNextMargin();
115     }
116     auto itemSpace = SwiperUtils::GetItemSpace(property);
117     spaceWidth_ = itemSpace > (contentMainSize_ + paddingBeforeContent_ + paddingAfterContent_) ? 0.0f : itemSpace;
118     auto prevMargin = NearZero(prevMargin_) ? 0.0f : prevMargin_ + spaceWidth_;
119     auto nextMargin = NearZero(nextMargin_) ? 0.0f : nextMargin_ + spaceWidth_;
120     endMainPos_ = currentOffset_ + contentMainSize_ - prevMargin - nextMargin;
121 
122     if (!isLoop_ && jumpIndex_.has_value()) {
123         if (property->GetPrevMarginIgnoreBlank().value_or(false) && jumpIndex_.value() == 0) {
124             ignoreBlankOffset_ = Positive(prevMargin_) ? -(prevMargin_ + spaceWidth_) : 0.0f;
125         } else if (property->GetNextMarginIgnoreBlank().value_or(false) &&
126                    jumpIndex_.value() >= (totalItemCount_ - property->GetDisplayCount().value_or(1))) {
127             ignoreBlankOffset_ = Positive(nextMargin_) ? nextMargin_ + spaceWidth_ : 0.0f;
128         } else {
129             ignoreBlankOffset_ = 0.0f;
130         }
131     }
132 }
133 
GetLoopIndex(int32_t originalIndex) const134 int32_t SwiperLayoutAlgorithm::GetLoopIndex(int32_t originalIndex) const
135 {
136     auto loopIndex = originalIndex;
137     while (loopIndex < 0) {
138         loopIndex = loopIndex + totalItemCount_;
139     }
140     loopIndex %= totalItemCount_;
141     return loopIndex;
142 }
143 
Measure(LayoutWrapper * layoutWrapper)144 void SwiperLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
145 {
146     std::lock_guard<std::mutex> lock(swiperMutex_);
147     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
148     CHECK_NULL_VOID(swiperLayoutProperty);
149 
150     if (!measured_) {
151         currentTargetIndex_ = targetIndex_;
152         currentJumpIndex_ = jumpIndex_;
153         currentIgnoreBlankOffset_ = ignoreBlankOffset_;
154     }
155     if (swiperLayoutProperty->GetIsCustomAnimation().value_or(false)) {
156         MeasureTabsCustomAnimation(layoutWrapper);
157         return;
158     }
159 
160     auto axis = swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
161     // calculate main size.
162     auto contentConstraint = swiperLayoutProperty->GetContentLayoutConstraint().value();
163     swiperLayoutProperty->ResetIgnorePrevMarginAndNextMargin();
164     auto isSingleCase = CheckIsSingleCase(swiperLayoutProperty);
165     OptionalSizeF contentIdealSize;
166     if (isSingleCase) {
167         contentIdealSize = CreateIdealSizeByPercentRef(contentConstraint, axis, MeasureType::MATCH_CONTENT);
168         if (mainSizeIsMeasured_) {
169             if (layoutWrapper->IsConstraintNoChanged()) {
170                 contentIdealSize.SetMainSize(contentMainSize_, axis);
171             } else {
172                 mainSizeIsMeasured_ = false;
173             }
174         }
175     } else {
176         contentIdealSize = CreateIdealSizeByPercentRef(contentConstraint, axis, MeasureType::MATCH_PARENT_MAIN_AXIS);
177         if (!layoutWrapper->IsConstraintNoChanged()) {
178             mainSizeIsMeasured_ = false;
179             jumpIndex_ = jumpIndex_.value_or(currentIndex_);
180         }
181     }
182 
183     auto mainSize = contentIdealSize.MainSize(axis);
184     if (mainSize.has_value()) {
185         SwiperUtils::CheckAutoFillDisplayCount(swiperLayoutProperty, mainSize.value(), realTotalCount_);
186     }
187     const auto& padding = swiperLayoutProperty->CreatePaddingAndBorder();
188     paddingBeforeContent_ = axis == Axis::HORIZONTAL ? padding.left.value_or(0) : padding.top.value_or(0);
189     paddingAfterContent_ = axis == Axis::HORIZONTAL ? padding.right.value_or(0) : padding.bottom.value_or(0);
190     contentMainSize_ = 0.0f;
191     if (!GetMainAxisSize(contentIdealSize, axis) && (!isSingleCase || !mainSizeIsMeasured_)) {
192         if (totalItemCount_ == 0) {
193             contentMainSize_ = 0.0f;
194         } else {
195             // use parent percentReference size first.
196             auto parentPercentReference = contentConstraint.percentReference;
197             contentMainSize_ =
198                 GetMainAxisSize(parentPercentReference, axis) - paddingBeforeContent_ - paddingAfterContent_;
199             mainSizeIsDefined_ = false;
200         }
201     } else {
202         contentMainSize_ = GetMainAxisSize(contentIdealSize.ConvertToSizeT(), axis);
203         mainSizeIsDefined_ = true;
204     }
205     auto hostNode = layoutWrapper->GetHostNode();
206     CHECK_NULL_VOID(hostNode);
207     auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
208     CHECK_NULL_VOID(swiperPattern);
209     auto getAutoFill = swiperPattern->IsAutoFill();
210 
211     // calculate child layout constraint and check if need to reset prevMargin,nextMargin,itemspace.
212     auto childLayoutConstraint =
213         SwiperUtils::CreateChildConstraint(swiperLayoutProperty, contentIdealSize, getAutoFill);
214     childLayoutConstraint_ = childLayoutConstraint;
215     if (totalItemCount_ > 0) {
216         UpdateLayoutInfoBeforeMeasureSwiper(swiperLayoutProperty);
217         MeasureSwiper(layoutWrapper, childLayoutConstraint, axis);
218     } else {
219         itemPosition_.clear();
220     }
221 
222     auto crossSize = contentIdealSize.CrossSize(axis);
223     if ((crossSize.has_value() && GreaterOrEqualToInfinity(crossSize.value())) || !crossSize.has_value()) {
224         contentCrossSize_ = GetChildMaxSize(layoutWrapper, axis, false) == 0.0f
225                                 ? contentCrossSize_
226                                 : GetChildMaxSize(layoutWrapper, axis, false);
227         contentIdealSize.SetCrossSize(contentCrossSize_, axis);
228         crossMatchChild_ = true;
229     }
230 
231     if (!mainSizeIsDefined_ && isSingleCase) {
232         auto childMaxMainSize = GetChildMaxSize(layoutWrapper, axis, true);
233         if (childMaxMainSize != contentMainSize_) {
234             contentMainSize_ = childMaxMainSize;
235             // CheckInactive
236             SetInactive(layoutWrapper, 0.0f, contentMainSize_, currentTargetIndex_);
237         }
238     }
239     MeasureSwiperCustomAnimation(layoutWrapper, childLayoutConstraint);
240     if (itemPosition_.empty()) {
241         layoutWrapper->SetActiveChildRange(-1, -1);
242     } else if (itemPositionInAnimation_.empty()) {
243         int32_t startIndex = GetLoopIndex(GetStartIndex());
244         int32_t endIndex = GetLoopIndex(GetEndIndex());
245         CheckCachedItem(startIndex, endIndex, layoutWrapper);
246         // startIndex maybe target to invalid blank items in group mode, need to be adjusted.
247         startIndex = startIndex < realTotalCount_ ? startIndex : 0;
248         endIndex = std::min(endIndex, realTotalCount_ - 1);
249         if (!isLoop_) {
250             layoutWrapper->SetActiveChildRange(startIndex, endIndex, std::min(cachedCount_, startIndex),
251                 std::min(cachedCount_, totalItemCount_ - 1 - endIndex));
252         } else {
253             layoutWrapper->SetActiveChildRange(startIndex, endIndex, cachedCount_, cachedCount_);
254         }
255     } else {
256         int32_t startIndex = std::min(GetLoopIndex(itemPositionInAnimation_.begin()->first), realTotalCount_ - 1);
257         int32_t endIndex = std::min(GetLoopIndex(itemPositionInAnimation_.rbegin()->first), realTotalCount_ - 1);
258         while (startIndex + 1 < realTotalCount_ &&
259             itemPositionInAnimation_.find(startIndex + 1) != itemPositionInAnimation_.end()) {
260             startIndex++;
261         }
262         while (endIndex - 1 >= 0 &&
263             itemPositionInAnimation_.find(endIndex - 1) != itemPositionInAnimation_.end()) {
264             endIndex--;
265         }
266         CheckCachedItem(endIndex, startIndex, layoutWrapper);
267         if (!isLoop_) {
268             layoutWrapper->SetActiveChildRange(endIndex, startIndex, std::min(cachedCount_, endIndex),
269                 std::min(cachedCount_, totalItemCount_ - 1 - startIndex));
270         } else {
271             layoutWrapper->SetActiveChildRange(endIndex, startIndex, cachedCount_, cachedCount_);
272         }
273     }
274 
275     contentIdealSize.SetMainSize(contentMainSize_, axis);
276     AddPaddingToSize(padding, contentIdealSize);
277     layoutWrapper->GetGeometryNode()->SetFrameSize(contentIdealSize.ConvertToSizeT());
278     if (!itemPosition_.empty()) {
279         mainSizeIsMeasured_ = true;
280     }
281 
282     // set swiper cache info.
283     auto measuredItemCount = static_cast<int32_t>(measuredItems_.size());
284     auto maxCachedCount =
285         isLoop_ ? static_cast<int32_t>(std::ceil(static_cast<float>(realTotalCount_ - measuredItemCount) / 2))
286                 : realTotalCount_;
287     layoutWrapper->SetCacheCount(std::min(swiperPattern->GetCachedCount(), maxCachedCount), childLayoutConstraint);
288     layoutWrapper->SetLongPredictTask();
289 
290     IndicatorAndArrowMeasure(layoutWrapper, contentIdealSize);
291     CaptureMeasure(layoutWrapper, childLayoutConstraint);
292 
293     measured_ = true;
294 }
295 
CaptureMeasure(LayoutWrapper * layoutWrapper,LayoutConstraintF & childLayoutConstraint)296 void SwiperLayoutAlgorithm::CaptureMeasure(LayoutWrapper* layoutWrapper, LayoutConstraintF& childLayoutConstraint)
297 {
298     if (!hasCachedCapture_ || itemPosition_.empty()) {
299         return;
300     }
301     auto hostNode = layoutWrapper->GetHostNode();
302     CHECK_NULL_VOID(hostNode);
303     auto leftCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_CAPTURE_ETS_TAG);
304     auto rightCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_CAPTURE_ETS_TAG);
305     if (isCaptureReverse_) {
306         leftCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_CAPTURE_ETS_TAG);
307         rightCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_CAPTURE_ETS_TAG);
308     }
309     CHECK_NULL_VOID(leftCaptureWrapper);
310     CHECK_NULL_VOID(rightCaptureWrapper);
311     auto lastWrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(itemPosition_.rbegin()->first));
312     CHECK_NULL_VOID(lastWrapper);
313     auto lastNode = lastWrapper->GetGeometryNode();
314     CHECK_NULL_VOID(lastNode);
315     auto leftCaptureGeometryNode = leftCaptureWrapper->GetGeometryNode();
316     CHECK_NULL_VOID(leftCaptureGeometryNode);
317     auto leftOldSize = leftCaptureGeometryNode->GetFrameSize();
318     childLayoutConstraint.UpdateSelfMarginSizeWithCheck(OptionalSizeF(lastNode->GetMarginFrameSize()));
319     leftCaptureWrapper->Measure(childLayoutConstraint);
320 
321     auto firstWrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(itemPosition_.begin()->first));
322     CHECK_NULL_VOID(firstWrapper);
323     auto firstNode = firstWrapper->GetGeometryNode();
324     CHECK_NULL_VOID(firstNode);
325     auto rightCaptureGeometryNode = rightCaptureWrapper->GetGeometryNode();
326     CHECK_NULL_VOID(rightCaptureGeometryNode);
327     auto rightOldSize = rightCaptureGeometryNode->GetFrameSize();
328     childLayoutConstraint.UpdateSelfMarginSizeWithCheck(OptionalSizeF(firstNode->GetMarginFrameSize()));
329     rightCaptureWrapper->Measure(childLayoutConstraint);
330 
331     isNeedUpdateCapture_ = leftOldSize != lastNode->GetFrameSize() || rightOldSize != firstNode->GetFrameSize();
332 }
333 
MeasureTabsCustomAnimation(LayoutWrapper * layoutWrapper)334 void SwiperLayoutAlgorithm::MeasureTabsCustomAnimation(LayoutWrapper* layoutWrapper)
335 {
336     auto layoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
337     CHECK_NULL_VOID(layoutProperty);
338     auto axis = layoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
339     auto contentConstraint = layoutProperty->GetContentLayoutConstraint().value();
340     auto contentIdealSize = CreateIdealSizeByPercentRef(contentConstraint, axis, MeasureType::MATCH_PARENT_MAIN_AXIS);
341     auto childLayoutConstraint = SwiperUtils::CreateChildConstraint(layoutProperty, contentIdealSize, false);
342     auto childCrossSize = 0.0f;
343 
344     auto currentIndex = layoutProperty->GetIndex().value_or(0);
345     auto currentIndexWrapper = layoutWrapper->GetOrCreateChildByIndex(currentIndex);
346     CHECK_NULL_VOID(currentIndexWrapper);
347     currentIndexWrapper->Measure(childLayoutConstraint);
348     auto currentIndexGeometryNode = currentIndexWrapper->GetGeometryNode();
349     if (currentIndexGeometryNode) {
350         childCrossSize = std::max(childCrossSize, currentIndexGeometryNode->GetMarginFrameSize().CrossSize(axis));
351     }
352 
353     if (customAnimationToIndex_) {
354         auto toIndexWrapper = layoutWrapper->GetOrCreateChildByIndex(customAnimationToIndex_.value());
355         CHECK_NULL_VOID(toIndexWrapper);
356         toIndexWrapper->Measure(childLayoutConstraint);
357         auto toIndexGeometryNode = toIndexWrapper->GetGeometryNode();
358         if (toIndexGeometryNode) {
359             childCrossSize = std::max(childCrossSize, toIndexGeometryNode->GetMarginFrameSize().CrossSize(axis));
360         }
361     }
362 
363     auto crossSize = contentIdealSize.CrossSize(axis);
364     if ((crossSize.has_value() && GreaterOrEqualToInfinity(crossSize.value())) || !crossSize.has_value()) {
365         contentIdealSize.SetCrossSize(childCrossSize, axis);
366     }
367     layoutWrapper->GetGeometryNode()->SetFrameSize(contentIdealSize.ConvertToSizeT());
368 
369     std::set<int32_t> removeIndexs;
370     for (const auto& index : needUnmountIndexs_) {
371         if (indexsInAnimation_.find(index) != indexsInAnimation_.end()) {
372             continue;
373         }
374 
375         layoutWrapper->RemoveChildInRenderTree(index);
376         removeIndexs.insert(index);
377     }
378 
379     for (const auto& index : removeIndexs) {
380         needUnmountIndexs_.erase(index);
381     }
382 }
383 
MeasureSwiperCustomAnimation(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint)384 void SwiperLayoutAlgorithm::MeasureSwiperCustomAnimation(LayoutWrapper* layoutWrapper,
385     const LayoutConstraintF& layoutConstraint)
386 {
387     std::set<int32_t> measureIndexSet;
388     for (const auto& pos : itemPosition_) {
389         measureIndexSet.insert(GetLoopIndex(pos.first));
390     }
391     for (const auto& pos : itemPositionInAnimation_) {
392         if (measureIndexSet.find(pos.first) == measureIndexSet.end()) {
393             auto currentIndexWrapper = layoutWrapper->GetOrCreateChildByIndex(pos.first);
394             CHECK_NULL_VOID(currentIndexWrapper);
395             currentIndexWrapper->Measure(layoutConstraint);
396         }
397     }
398 }
399 
GetChildMaxSize(LayoutWrapper * layoutWrapper,Axis axis,bool isMainAxis) const400 float SwiperLayoutAlgorithm::GetChildMaxSize(LayoutWrapper* layoutWrapper, Axis axis, bool isMainAxis) const
401 {
402     if (itemPosition_.empty()) {
403         return 0.0f;
404     }
405     float maxSize = 0.0f;
406     float size = 0.0f;
407     for (const auto& pos : itemPosition_) {
408         auto wrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(pos.first), false);
409         if (!wrapper) {
410             continue;
411         }
412         auto geometryNode = wrapper->GetGeometryNode();
413         if (!geometryNode) {
414             continue;
415         }
416         size = isMainAxis ? geometryNode->GetMarginFrameSize().MainSize(axis)
417                           : geometryNode->GetMarginFrameSize().CrossSize(axis);
418         maxSize = std::max(size, maxSize);
419     }
420     return maxSize;
421 }
422 
AdjustStartInfoOnSwipeByGroup(int32_t startIndex,const PositionMap & itemPosition,int32_t & startIndexInVisibleWindow,float & startPos)423 void SwiperLayoutAlgorithm::AdjustStartInfoOnSwipeByGroup(
424     int32_t startIndex, const PositionMap& itemPosition, int32_t& startIndexInVisibleWindow, float& startPos)
425 {
426     if (!swipeByGroup_ || isFrameAnimation_) {
427         return;
428     }
429 
430     startIndexInVisibleWindow = startIndex;
431     auto iter = itemPosition.find(startIndex);
432     if (iter != itemPosition.end()) {
433         startPos = iter->second.startPos;
434     }
435 }
436 
MeasureSwiper(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis)437 void SwiperLayoutAlgorithm::MeasureSwiper(
438     LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, Axis axis)
439 {
440     int32_t startIndex = 0;
441     int32_t endIndex = 0;
442     float startPos = 0.0f;
443     float endPos = 0.0f;
444     int32_t startIndexInVisibleWindow = 0;
445     prevItemPosition_ = itemPosition_;
446     if (!itemPosition_.empty()) {
447         startPos = itemPosition_.begin()->second.startPos;
448         endPos = itemPosition_.rbegin()->second.endPos;
449         for (const auto& item : itemPosition_) {
450             float endPos = Positive(prevMargin_) ? item.second.endPos + prevMargin_ + spaceWidth_ : item.second.endPos;
451             if (Positive(endPos)) {
452                 startIndexInVisibleWindow = item.first;
453                 startPos = item.second.startPos;
454                 break;
455             }
456         }
457         if (!isLoop_) {
458             startIndex = std::min(GetLoopIndex(GetStartIndex()), totalItemCount_ - 1);
459             endIndex = std::min(GetLoopIndex(GetEndIndex()), totalItemCount_ - 1);
460             startIndexInVisibleWindow = std::min(GetLoopIndex(startIndexInVisibleWindow), totalItemCount_ - 1);
461             if (targetIndex_.has_value()) {
462                 targetIndex_ = GetLoopIndex(targetIndex_.value());
463             }
464         } else {
465             startIndex = GetStartIndex();
466             endIndex = GetEndIndex();
467         }
468 
469         itemPosition_.clear();
470     }
471 
472     if (!placeItemWidth_ && !prevItemPosition_.empty()) {
473         placeItemWidth_ = prevItemPosition_.begin()->second.endPos - prevItemPosition_.begin()->second.startPos;
474     }
475 
476     if (jumpIndex_.has_value()) {
477         needUnmountIndexs_.clear();
478         itemPositionInAnimation_.clear();
479         startPos = (jumpIndex_.value() == 0) && Negative(startMainPos_) ? startMainPos_ : 0;
480         LayoutForward(layoutWrapper, layoutConstraint, axis, jumpIndex_.value(), startPos);
481         auto prevMarginMontage = Positive(prevMargin_) ? prevMargin_ + spaceWidth_ : 0.0f;
482         if (Positive(ignoreBlankOffset_)) {
483             prevMarginMontage += ignoreBlankOffset_;
484         }
485 
486         if ((jumpIndex_.value() > 0 && GreatNotEqual(GetStartPosition(), startMainPos_ - prevMarginMontage)) ||
487             (isLoop_ && Positive(prevMargin_))) {
488             LayoutBackward(layoutWrapper, layoutConstraint, axis, jumpIndex_.value() - 1, GetStartPosition());
489         }
490         currentIndex_ = jumpIndex_.value();
491     } else if (hasCachedCapture_) {
492         for (auto it = prevItemPosition_.rbegin(); it != prevItemPosition_.rend(); ++it) {
493             auto pos = Positive(prevMargin_) ? it->second.startPos + prevMargin_ : it->second.startPos;
494             // search for last item in visible window as endIndex
495             if (LessNotEqual(pos, contentMainSize_)) {
496                 endIndex = it->first;
497                 endPos = it->second.endPos;
498                 break;
499             }
500         }
501         if ((targetIndex_.has_value() && targetIndex_.value() >= startIndexInVisibleWindow)
502             || (!targetIndex_.has_value() && Negative(currentOffset_))) {
503             LayoutForward(layoutWrapper, layoutConstraint, axis, startIndexInVisibleWindow, startPos);
504             LayoutBackward(layoutWrapper, layoutConstraint, axis, GetStartIndex() - 1, GetStartPosition());
505         } else {
506             LayoutBackward(layoutWrapper, layoutConstraint, axis, endIndex, endPos);
507             LayoutForward(layoutWrapper, layoutConstraint, axis, GetEndIndex() + 1, GetEndPosition());
508         }
509         // captures need to be updated, swap capture to avoid flickering of disappearing real node's position
510         if (targetIndex_.has_value() && itemPosition_.begin()->first != prevItemPosition_.begin()->first) {
511             isCaptureReverse_ = !isCaptureReverse_;
512         }
513     } else if (targetIndex_.has_value()) {
514         // isMeasureOneMoreItem_ param is used to ensure item continuity when play property animation.
515         if (LessNotEqual(startIndexInVisibleWindow, targetIndex_.value())) {
516             if (isMeasureOneMoreItem_) {
517                 targetIndex_ =
518                     isLoop_ ? targetIndex_.value() + 1 : std::clamp(targetIndex_.value() + 1, 0, realTotalCount_ - 1);
519             }
520             AdjustStartInfoOnSwipeByGroup(startIndex, prevItemPosition_, startIndexInVisibleWindow, startPos);
521             LayoutForward(layoutWrapper, layoutConstraint, axis, startIndexInVisibleWindow, startPos);
522             if (GreatNotEqualCustomPrecision(GetStartPosition(), startMainPos_, 0.01f)) {
523                 LayoutBackward(layoutWrapper, layoutConstraint, axis, GetStartIndex() - 1, GetStartPosition());
524             }
525         } else if (GreatNotEqual(startIndexInVisibleWindow, targetIndex_.value())) {
526             if (isMeasureOneMoreItem_) {
527                 targetIndex_ =
528                     isLoop_ ? targetIndex_.value() - 1 : std::clamp(targetIndex_.value() - 1, 0, realTotalCount_ - 1);
529             }
530             LayoutBackward(layoutWrapper, layoutConstraint, axis, endIndex, endPos);
531             if (LessNotEqualCustomPrecision(GetEndPosition(), endMainPos_, -0.01f)) {
532                 LayoutForward(layoutWrapper, layoutConstraint, axis, GetEndIndex() + 1, GetEndPosition());
533             }
534         } else {
535             targetIsSameWithStartFlag_ = true;
536             AdjustStartInfoOnSwipeByGroup(startIndex, prevItemPosition_, startIndexInVisibleWindow, startPos);
537             LayoutForward(layoutWrapper, layoutConstraint, axis, startIndexInVisibleWindow, startPos);
538             if (isMeasureOneMoreItem_ || Positive(prevMargin_)) {
539                 float startPosition =
540                     itemPosition_.empty() ? 0.0f : itemPosition_.begin()->second.startPos - spaceWidth_;
541                 LayoutBackward(layoutWrapper, layoutConstraint, axis, GetStartIndex() - 1, startPosition);
542             }
543         }
544     } else {
545         AdjustStartInfoOnSwipeByGroup(startIndex, prevItemPosition_, startIndexInVisibleWindow, startPos);
546         bool overScrollTop = startIndexInVisibleWindow == 0 && GreatNotEqual(startPos, startMainPos_);
547         if ((!overScrollFeature_ && NonNegative(currentOffset_)) || (overScrollFeature_ && overScrollTop)) {
548             LayoutForward(layoutWrapper, layoutConstraint, axis, startIndexInVisibleWindow, startPos);
549             auto adjustStartMainPos =
550                 startMainPos_ - prevMargin_ - spaceWidth_ - (Positive(ignoreBlankOffset_) ? ignoreBlankOffset_ : 0.0f);
551             if (GetStartIndex() > 0 && GreatNotEqual(GetStartPosition(), adjustStartMainPos)) {
552                 LayoutBackward(layoutWrapper, layoutConstraint, axis, GetStartIndex() - 1, GetStartPosition());
553             }
554         } else {
555             LayoutBackward(layoutWrapper, layoutConstraint, axis, endIndex, endPos);
556             if (GetEndIndex() < (totalItemCount_ - 1) && LessNotEqual(GetEndPosition(), endMainPos_)) {
557                 LayoutForward(layoutWrapper, layoutConstraint, axis, GetEndIndex() + 1, GetEndPosition());
558             }
559         }
560     }
561 }
562 
LayoutForwardItem(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis,int32_t & currentIndex,float startPos,float & endPos)563 bool SwiperLayoutAlgorithm::LayoutForwardItem(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
564     Axis axis, int32_t& currentIndex, float startPos, float& endPos)
565 {
566     if ((currentIndex + 1 >= totalItemCount_ && !isLoop_) ||
567         (static_cast<int32_t>(itemPosition_.size()) >= totalItemCount_)) {
568         return false;
569     }
570 
571     auto measureIndex = GetLoopIndex(currentIndex + 1);
572     if (isMeasureOneMoreItem_ && !itemPosition_.empty() && measureIndex == GetLoopIndex(itemPosition_.begin()->first)) {
573         return false;
574     }
575 
576     if (swipeByGroup_ && measureIndex >= realTotalCount_) {
577         ++currentIndex;
578         endPos = startPos + placeItemWidth_.value_or(0.0f);
579         itemPosition_[currentIndex] = { startPos, endPos, nullptr };
580         return true;
581     }
582 
583     auto wrapper = layoutWrapper->GetOrCreateChildByIndex(measureIndex);
584     if (!IsNormalItem(wrapper)) {
585         return false;
586     }
587     ++currentIndex;
588     wrapper->Measure(layoutConstraint);
589     measuredItems_.insert(measureIndex);
590 
591     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
592     CHECK_NULL_RETURN(swiperLayoutProperty, false);
593 
594     float mainAxisSize = GetChildMainAxisSize(wrapper, swiperLayoutProperty, axis);
595     endPos = startPos + mainAxisSize;
596     itemPosition_[currentIndex] = { startPos, endPos, wrapper->GetHostNode() };
597     return true;
598 }
599 
LayoutBackwardItem(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis,int32_t & currentIndex,float endPos,float & startPos)600 bool SwiperLayoutAlgorithm::LayoutBackwardItem(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
601     Axis axis, int32_t& currentIndex, float endPos, float& startPos)
602 {
603     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
604     CHECK_NULL_RETURN(swiperLayoutProperty, false);
605     int32_t displayCount =
606         swiperLayoutProperty->GetDisplayCount().has_value() ? swiperLayoutProperty->GetDisplayCount().value() : 1;
607     bool itemPositionIsFull = static_cast<int32_t>(itemPosition_.size()) >= totalItemCount_ + displayCount - 1;
608     if ((currentIndex - 1 < 0 && !isLoop_) || (SwiperUtils::IsStretch(swiperLayoutProperty) && itemPositionIsFull)) {
609         return false;
610     }
611     if (hasCachedCapture_ && static_cast<int32_t>(itemPosition_.size()) >= totalItemCount_) {
612         return false;
613     }
614 
615     auto measureIndex = GetLoopIndex(currentIndex - 1);
616     if (isMeasureOneMoreItem_ && !itemPosition_.empty() &&
617         measureIndex == GetLoopIndex(itemPosition_.rbegin()->first)) {
618         return false;
619     }
620 
621     if (swipeByGroup_ && measureIndex >= realTotalCount_) {
622         --currentIndex;
623         startPos = endPos - placeItemWidth_.value_or(0.0f);
624         itemPosition_[currentIndex] = { startPos, endPos, nullptr };
625         return true;
626     }
627 
628     auto wrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(measureIndex));
629     if (!IsNormalItem(wrapper)) {
630         return false;
631     }
632     --currentIndex;
633     wrapper->Measure(layoutConstraint);
634     measuredItems_.insert(measureIndex);
635 
636     float mainAxisSize = GetChildMainAxisSize(wrapper, swiperLayoutProperty, axis);
637     startPos = endPos - mainAxisSize;
638     if (!itemPositionIsFull) {
639         itemPosition_[currentIndex] = { startPos, endPos, wrapper->GetHostNode() };
640     }
641     if (targetIndex_ && currentIndex == targetIndex_.value()) {
642         targetStartPos_ = startPos;
643     }
644     return true;
645 }
646 
SetInactiveOnForward(LayoutWrapper * layoutWrapper,Axis axis)647 void SwiperLayoutAlgorithm::SetInactiveOnForward(LayoutWrapper* layoutWrapper, Axis axis)
648 {
649     auto displayCount = GetDisplayCount(layoutWrapper);
650     for (auto pos = itemPosition_.begin(); pos != itemPosition_.end();) {
651         auto endPos = pos->second.endPos;
652         auto index = pos->first;
653         if (swipeByGroup_) {
654             auto endPageIndex = SwiperUtils::ComputePageEndIndex(index, displayCount);
655             auto iter = itemPosition_.find(endPageIndex);
656             if (iter != itemPosition_.end()) {
657                 endPos = iter->second.endPos;
658             }
659         }
660         endPos += ignoreBlankOffset_;
661         if (GreatNotEqual(endPos, prevMargin_ != 0.0f ? startMainPos_ - prevMargin_ - spaceWidth_ : startMainPos_)) {
662             break;
663         }
664 
665         ResetOffscreenItemPosition(layoutWrapper, GetLoopIndex(pos->first), true, axis);
666         itemPosition_.erase(pos++);
667     }
668 }
669 
GetDisplayCount(LayoutWrapper * layoutWrapper) const670 int32_t SwiperLayoutAlgorithm::GetDisplayCount(LayoutWrapper* layoutWrapper) const
671 {
672     auto layoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
673     CHECK_NULL_RETURN(layoutProperty, 1);
674     return layoutProperty->GetDisplayCount().value_or(1);
675 }
676 
GetChildMainAxisSize(const RefPtr<LayoutWrapper> & childWrapper,const RefPtr<SwiperLayoutProperty> & swiperProperty,Axis axis)677 float SwiperLayoutAlgorithm::GetChildMainAxisSize(
678     const RefPtr<LayoutWrapper>& childWrapper, const RefPtr<SwiperLayoutProperty>& swiperProperty, Axis axis)
679 {
680     CHECK_NULL_RETURN(childWrapper, 0.0f);
681 
682     float mainAxisSize = GetMainAxisSize(childWrapper->GetGeometryNode()->GetMarginFrameSize(), axis);
683     if (!placeItemWidth_.has_value()) {
684         placeItemWidth_ = mainAxisSize;
685     }
686 
687     auto displayCount = swiperProperty->GetDisplayCountValue(1);
688     if (!SwiperUtils::IsStretch(swiperProperty) || displayCount == 0) {
689         return mainAxisSize;
690     }
691 
692     auto childProperty = childWrapper->GetLayoutProperty();
693     CHECK_NULL_RETURN(childProperty, mainAxisSize);
694     auto visibilityValue = childProperty->GetVisibilityValue(VisibleType::VISIBLE);
695     if (visibilityValue == VisibleType::INVISIBLE || visibilityValue == VisibleType::GONE) {
696         mainAxisSize = (contentMainSize_ - nextMargin_ - prevMargin_ - (displayCount - 1) * spaceWidth_)
697             / displayCount;
698     }
699 
700     return mainAxisSize;
701 }
702 
LayoutForward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis,int32_t startIndex,float startPos)703 void SwiperLayoutAlgorithm::LayoutForward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
704     Axis axis, int32_t startIndex, float startPos)
705 {
706     float currentEndPos = startPos;
707     float currentStartPos = 0.0f;
708     float endMainPos = overScrollFeature_ ? std::max(startPos + contentMainSize_, endMainPos_) : endMainPos_;
709     if (targetIndex_) {
710         endMainPos = Infinity<float>();
711     }
712     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
713     CHECK_NULL_VOID(swiperLayoutProperty);
714 
715     auto currentIndex = startIndex - 1;
716     auto marginValue = NearZero(nextMargin_) ? 0.0f : nextMargin_ + spaceWidth_;
717     if (!NearZero(prevMargin_) && startIndex == 0 && swiperLayoutProperty->GetPrevMarginIgnoreBlankValue(false)) {
718         marginValue += prevMargin_ + spaceWidth_;
719     }
720     do {
721         currentStartPos = currentEndPos;
722         auto result =
723             LayoutForwardItem(layoutWrapper, layoutConstraint, axis, currentIndex, currentStartPos, currentEndPos);
724         if (!result) {
725             break;
726         }
727         if (CheckIsSingleCase(swiperLayoutProperty) && !mainSizeIsDefined_) {
728             endMainPos = itemPosition_.begin()->second.endPos - itemPosition_.begin()->second.startPos;
729             if (measured_) {
730                 endMainPos += currentOffset_;
731             }
732             endMainPos_ = endMainPos;
733         }
734         if ((currentIndex >= 0 && currentIndex < (totalItemCount_ - 1)) || isLoop_) {
735             currentEndPos += spaceWidth_;
736         }
737         // reach the valid target index
738         if (targetIndex_ && currentIndex >= targetIndex_.value()) {
739             endMainPos = targetIsSameWithStartFlag_ ? endMainPos_ : currentStartPos + contentMainSize_;
740             targetIndex_.reset();
741         }
742     } while (LessNotEqual(currentEndPos, endMainPos + marginValue)
743         || (targetIndex_ && currentIndex < targetIndex_.value()));
744 
745     if (overScrollFeature_ && canOverScroll_) {
746         return;
747     }
748 
749     // adjust offset.
750     if (LessNotEqual(currentEndPos, endMainPos_) && !itemPosition_.empty()) {
751         auto firstItemTop = itemPosition_.begin()->second.startPos;
752         auto itemTotalSize = currentEndPos - firstItemTop;
753         if (LessOrEqual(itemTotalSize, contentMainSize_) && (itemPosition_.begin()->first == 0)) {
754             // all items size is less than swiper.
755             if (!canOverScroll_) {
756                 currentOffset_ = firstItemTop;
757                 startMainPos_ = currentOffset_;
758             }
759             if (!mainSizeIsDefined_) {
760                 // adapt child size.
761                 contentMainSize_ = itemTotalSize;
762             }
763         } else {
764             // adjust offset. If edgeEffect is SPRING, jump adjust to allow swiper scroll through boundary
765             if (!canOverScroll_ || jumpIndex_.has_value()) {
766                 auto prevMarginMontage = Positive(prevMargin_) ? prevMargin_ + spaceWidth_ : 0.0f;
767                 auto nextMarginMontage = Positive(nextMargin_) ? nextMargin_ + spaceWidth_ : 0.0f;
768                 currentOffset_ = currentEndPos - contentMainSize_ + prevMarginMontage + nextMarginMontage;
769             }
770             startMainPos_ = currentEndPos - contentMainSize_;
771             endMainPos_ = currentEndPos;
772         }
773     }
774 
775     // Mark inactive in wrapper.
776     SetInactiveOnForward(layoutWrapper, axis);
777 }
778 
SetInactive(LayoutWrapper * layoutWrapper,float startMainPos,float endMainPos,std::optional<int32_t> targetIndex)779 void SwiperLayoutAlgorithm::SetInactive(
780     LayoutWrapper* layoutWrapper, float startMainPos, float endMainPos, std::optional<int32_t> targetIndex)
781 {
782     if (measured_) {
783         // Theoretically, offset should be added in all cases to get correct results. Only apply in flex for now.
784         startMainPos += currentOffset_;
785         endMainPos += currentOffset_;
786     }
787     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
788     CHECK_NULL_VOID(swiperLayoutProperty);
789     std::list<int32_t> removeIndexes;
790     for (auto pos = itemPosition_.rbegin(); pos != itemPosition_.rend(); ++pos) {
791         if (targetIndex.has_value() && targetIndex.value() == pos->first) {
792             continue;
793         }
794         if (LessOrEqual(
795             pos->second.endPos, prevMargin_ != 0.0f ? startMainPos - prevMargin_ - spaceWidth_ : startMainPos) ||
796             GreatOrEqual(
797                 pos->second.startPos, nextMargin_ != 0.0f ? endMainPos + nextMargin_ + spaceWidth_ : endMainPos)) {
798             removeIndexes.emplace_back(pos->first);
799         }
800     }
801     for (const auto& index : removeIndexes) {
802         itemPosition_.erase(index);
803     }
804 }
805 
SetInactiveOnBackward(LayoutWrapper * layoutWrapper,Axis axis)806 void SwiperLayoutAlgorithm::SetInactiveOnBackward(LayoutWrapper* layoutWrapper, Axis axis)
807 {
808     std::list<int32_t> removeIndexes;
809     auto displayCount = GetDisplayCount(layoutWrapper);
810     for (auto pos = itemPosition_.rbegin(); pos != itemPosition_.rend(); ++pos) {
811         auto startPos = pos->second.startPos;
812         auto index = pos->first;
813 
814         if (swipeByGroup_) {
815             auto startPageIndex = SwiperUtils::ComputePageIndex(index, displayCount);
816             auto iter = itemPosition_.find(startPageIndex);
817             if (iter != itemPosition_.end()) {
818                 startPos = iter->second.startPos;
819             }
820         }
821         startPos += ignoreBlankOffset_;
822         if (LessNotEqual(startPos, nextMargin_ != 0.0f ? endMainPos_ + nextMargin_ + spaceWidth_ : endMainPos_)) {
823             break;
824         }
825 
826         ResetOffscreenItemPosition(layoutWrapper, GetLoopIndex(index), false, axis);
827         removeIndexes.emplace_back(index);
828     }
829 
830     for (const auto& index : removeIndexes) {
831         itemPosition_.erase(index);
832     }
833 }
834 
LayoutBackward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis,int32_t endIndex,float endPos)835 void SwiperLayoutAlgorithm::LayoutBackward(
836     LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, Axis axis, int32_t endIndex, float endPos)
837 {
838     float currentStartPos = endPos;
839     float currentEndPos = 0.0f;
840     float startMainPos = overScrollFeature_ ? std::min(endPos - contentMainSize_, startMainPos_) : startMainPos_;
841     if (targetIndex_) {
842         startMainPos = -Infinity<float>();
843     }
844     auto currentIndex = endIndex + 1;
845 
846     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
847     CHECK_NULL_VOID(swiperLayoutProperty);
848     float adjustStartMainPos = 0.0f;
849     do {
850         currentEndPos = currentStartPos;
851         auto result =
852             LayoutBackwardItem(layoutWrapper, layoutConstraint, axis, currentIndex, currentEndPos, currentStartPos);
853         if (!result) {
854             break;
855         }
856         if (currentIndex > 0 || isLoop_) {
857             currentStartPos = currentStartPos - spaceWidth_;
858         }
859         // reach the valid target index
860         if (targetIndex_ && LessOrEqual(currentIndex, targetIndex_.value())) {
861             startMainPos = currentStartPos;
862             targetIndex_.reset();
863         }
864         adjustStartMainPos = startMainPos - (Positive(prevMargin_) ? prevMargin_ + spaceWidth_ : 0.0f) -
865                              (Positive(ignoreBlankOffset_) ? ignoreBlankOffset_ : 0.0f);
866     } while (GreatNotEqual(currentStartPos, adjustStartMainPos) ||
867              (!SwiperUtils::IsStretch(swiperLayoutProperty) && targetIndex_ && currentIndex > targetIndex_.value()));
868 
869     // adjust offset. If edgeEffect is SPRING, jump adjust to allow swiper scroll through boundary
870     if (GreatNotEqual(currentStartPos, startMainPos_)) {
871         if (!canOverScroll_ || jumpIndex_.has_value()) {
872             currentOffset_ = currentStartPos;
873             if (!mainSizeIsDefined_ && GetEndIndex() == totalItemCount_ - 1) {
874                 auto itemTotalSize = GetEndPosition() - currentStartPos;
875                 contentMainSize_ = std::min(contentMainSize_, itemTotalSize);
876             }
877         }
878         endMainPos_ = currentStartPos + contentMainSize_;
879         startMainPos_ = currentStartPos;
880     }
881 
882     if (overScrollFeature_) {
883         return;
884     }
885 
886     // Mark inactive in wrapper.
887     SetInactiveOnBackward(layoutWrapper, axis);
888 }
889 
LayoutCustomAnimation(LayoutWrapper * layoutWrapper) const890 void SwiperLayoutAlgorithm::LayoutCustomAnimation(LayoutWrapper* layoutWrapper) const
891 {
892     auto layoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
893     CHECK_NULL_VOID(layoutProperty);
894 
895     auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
896     auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
897     MinusPaddingToSize(padding, size);
898     auto paddingOffset = padding.Offset();
899 
900     if (customAnimationToIndex_) {
901         auto toIndexWrapper = layoutWrapper->GetOrCreateChildByIndex(customAnimationToIndex_.value());
902         CHECK_NULL_VOID(toIndexWrapper);
903 
904         toIndexWrapper->GetGeometryNode()->SetMarginFrameOffset(paddingOffset);
905         toIndexWrapper->Layout();
906     }
907 
908     auto currentIndex = layoutProperty->GetIndex().value_or(0);
909     auto currentIndexWrapper = layoutWrapper->GetOrCreateChildByIndex(currentIndex);
910     CHECK_NULL_VOID(currentIndexWrapper);
911 
912     currentIndexWrapper->GetGeometryNode()->SetMarginFrameOffset(paddingOffset);
913     currentIndexWrapper->Layout();
914 }
915 
Layout(LayoutWrapper * layoutWrapper)916 void SwiperLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
917 {
918     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
919     CHECK_NULL_VOID(swiperLayoutProperty);
920 
921     if (swiperLayoutProperty->GetIsCustomAnimation().value_or(false)) {
922         LayoutCustomAnimation(layoutWrapper);
923         return;
924     }
925 
926     auto axis = swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
927     auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
928     auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
929     MinusPaddingToSize(padding, size);
930     auto paddingOffset = padding.Offset();
931 
932     // layout items.
933     std::set<int32_t> layoutIndexSet;
934     for (auto& pos : itemPosition_) {
935         layoutIndexSet.insert(GetLoopIndex(pos.first));
936         pos.second.startPos -= currentOffset_;
937         pos.second.endPos -= currentOffset_;
938         LayoutItem(layoutWrapper, axis, paddingOffset, pos);
939     }
940     for (auto& pos : itemPositionInAnimation_) {
941         if (layoutIndexSet.find(pos.first) == layoutIndexSet.end()) {
942             LayoutItem(layoutWrapper, axis, paddingOffset, pos);
943         }
944     }
945     LayoutSwiperIndicator(layoutWrapper, swiperLayoutProperty, padding);
946     CaptureLayout(layoutWrapper);
947 }
948 
LayoutSwiperIndicator(LayoutWrapper * layoutWrapper,const RefPtr<SwiperLayoutProperty> & swiperLayoutProperty,const PaddingPropertyF & padding)949 void SwiperLayoutAlgorithm::LayoutSwiperIndicator(
950     LayoutWrapper* layoutWrapper, const RefPtr<SwiperLayoutProperty>& swiperLayoutProperty,
951     const PaddingPropertyF& padding)
952 {
953     auto hostNode = layoutWrapper->GetHostNode();
954     CHECK_NULL_VOID(hostNode);
955     auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
956     CHECK_NULL_VOID(swiperPattern);
957 
958     // Layout swiper indicator
959     if (swiperLayoutProperty->GetShowIndicatorValue(true)) {
960         auto indicatorWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_INDICATOR_ETS_TAG);
961         if (indicatorWrapper) {
962             if (swiperLayoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT) == SwiperIndicatorType::DIGIT) {
963                 PlaceDigitChild(indicatorWrapper, swiperLayoutProperty);
964             }
965             indicatorWrapper->Layout();
966         }
967     }
968 
969     if (swiperLayoutProperty->GetDisplayArrowValue(false)) {
970         if (swiperPattern->HasLeftButtonNode() && swiperPattern->HasRightButtonNode()) {
971             auto leftArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_ARROW_ETS_TAG);
972             auto rightArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_ARROW_ETS_TAG);
973             if (leftArrowWrapper && (leftArrowWrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG)) {
974                 ArrowLayout(layoutWrapper, leftArrowWrapper, padding);
975             }
976             if (rightArrowWrapper && (rightArrowWrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG)) {
977                 ArrowLayout(layoutWrapper, rightArrowWrapper, padding);
978             }
979         }
980     }
981 }
982 
LayoutItem(LayoutWrapper * layoutWrapper,Axis axis,OffsetF offset,std::pair<int32_t,SwiperItemInfo> pos)983 void SwiperLayoutAlgorithm::LayoutItem(LayoutWrapper* layoutWrapper, Axis axis, OffsetF offset,
984     std::pair<int32_t, SwiperItemInfo> pos)
985 {
986     pos.second.startPos += ignoreBlankOffset_;
987     pos.second.endPos += ignoreBlankOffset_;
988 
989     auto layoutIndex = GetLoopIndex(pos.first);
990     if (swipeByGroup_ && layoutIndex >= realTotalCount_) {
991         return;
992     }
993 
994     auto wrapper = layoutWrapper->GetOrCreateChildByIndex(layoutIndex);
995     if (!IsNormalItem(wrapper)) {
996         return;
997     }
998 
999     float crossOffset = 0.0f;
1000     if (axis == Axis::VERTICAL) {
1001         offset += OffsetF(crossOffset, pos.second.startPos);
1002         if (!NearZero(prevMargin_)) {
1003             offset += OffsetF(crossOffset, prevMargin_ + spaceWidth_);
1004         }
1005     } else {
1006         CHECK_NULL_VOID(layoutWrapper->GetLayoutProperty());
1007         bool isRtl = layoutWrapper->GetLayoutProperty()->GetNonAutoLayoutDirection() == TextDirection::RTL;
1008         float offsetPos = isRtl ? contentMainSize_ - pos.second.endPos : pos.second.startPos;
1009         offset += OffsetF(offsetPos, crossOffset);
1010         if (!NearZero(prevMargin_) && !isRtl) {
1011             offset += OffsetF(prevMargin_ + spaceWidth_, crossOffset);
1012         }
1013         if (!NearZero(prevMargin_) && isRtl) {
1014             offset -= OffsetF(prevMargin_ + spaceWidth_, crossOffset);
1015         }
1016     }
1017     wrapper->GetGeometryNode()->SetMarginFrameOffset(offset);
1018     wrapper->Layout();
1019 }
1020 
CaptureLayout(LayoutWrapper * layoutWrapper)1021 void SwiperLayoutAlgorithm::CaptureLayout(LayoutWrapper* layoutWrapper)
1022 {
1023     if (!hasCachedCapture_ || itemPosition_.empty()) {
1024         return;
1025     }
1026     auto leftCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_CAPTURE_ETS_TAG);
1027     auto rightCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_CAPTURE_ETS_TAG);
1028     if (isCaptureReverse_) {
1029         leftCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_CAPTURE_ETS_TAG);
1030         rightCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_CAPTURE_ETS_TAG);
1031     }
1032     CHECK_NULL_VOID(leftCaptureWrapper);
1033     CHECK_NULL_VOID(rightCaptureWrapper);
1034     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
1035     CHECK_NULL_VOID(swiperLayoutProperty);
1036     auto axis = swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
1037     auto geometryNode = leftCaptureWrapper->GetGeometryNode();
1038     CHECK_NULL_VOID(geometryNode);
1039     auto leftCaptureSize = axis == Axis::VERTICAL ? geometryNode->GetMarginFrameSize().Height()
1040                                                   : geometryNode->GetMarginFrameSize().Width();
1041     auto leftPosition = itemPosition_.begin()->second.startPos - spaceWidth_ - leftCaptureSize;
1042     auto rightPosition = itemPosition_.rbegin()->second.endPos + spaceWidth_;
1043 
1044     auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
1045     auto leftOffset = padding.Offset();
1046     auto rightOffset = padding.Offset();
1047     auto deltaOffset = 0.0f;
1048     if (!NearZero(prevMargin_)) {
1049         deltaOffset = prevMargin_ + spaceWidth_;
1050     }
1051     if (axis == Axis::VERTICAL) {
1052         leftOffset += OffsetF(0.0f, leftPosition + deltaOffset);
1053         rightOffset += OffsetF(0.0f, rightPosition + deltaOffset);
1054     } else {
1055         bool isRtl = swiperLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
1056         if (isRtl) {
1057             leftPosition = contentMainSize_ - itemPosition_.begin()->second.startPos + spaceWidth_;
1058             rightPosition = contentMainSize_ - itemPosition_.rbegin()->second.endPos - spaceWidth_ - leftCaptureSize;
1059             leftOffset += OffsetF(leftPosition - deltaOffset, 0.0f);
1060             rightOffset += OffsetF(rightPosition - deltaOffset, 0.0f);
1061         } else {
1062             leftOffset += OffsetF(leftPosition + deltaOffset, 0.0f);
1063             rightOffset += OffsetF(rightPosition + deltaOffset, 0.0f);
1064         }
1065     }
1066     leftCaptureWrapper->GetGeometryNode()->SetMarginFrameOffset(leftOffset);
1067     leftCaptureWrapper->Layout();
1068     rightCaptureWrapper->GetGeometryNode()->SetMarginFrameOffset(rightOffset);
1069     rightCaptureWrapper->Layout();
1070 }
1071 
PlaceDigitChild(const RefPtr<LayoutWrapper> & indicatorWrapper,const RefPtr<LayoutProperty> & layoutProperty)1072 void SwiperLayoutAlgorithm::PlaceDigitChild(
1073     const RefPtr<LayoutWrapper>& indicatorWrapper, const RefPtr<LayoutProperty>& layoutProperty)
1074 {
1075     if (indicatorWrapper->GetTotalChildCount() != INDICATOR_HAS_CHILD) {
1076         return;
1077     }
1078     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutProperty);
1079     CHECK_NULL_VOID(swiperLayoutProperty);
1080     auto indicatorGeometryNode = indicatorWrapper->GetGeometryNode();
1081     CHECK_NULL_VOID(indicatorGeometryNode);
1082     auto indicatorWidth = INDICATOR_PADDING.ConvertToPx() * 2.0;
1083     auto indicatorHeight = 0.0f;
1084     for (auto&& child : indicatorWrapper->GetAllChildrenWithBuild()) {
1085         auto textGeometryNode = child->GetGeometryNode();
1086         CHECK_NULL_VOID(textGeometryNode);
1087         auto textFrameSize = textGeometryNode->GetFrameSize();
1088         indicatorWidth += textFrameSize.Width();
1089         if (indicatorHeight < textFrameSize.Height()) {
1090             indicatorHeight = textFrameSize.Height();
1091         }
1092     }
1093 
1094     auto pipelineContext = PipelineBase::GetCurrentContext();
1095     CHECK_NULL_VOID(pipelineContext);
1096     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
1097     CHECK_NULL_VOID(swiperIndicatorTheme);
1098     if (LessNotEqual(indicatorHeight, swiperIndicatorTheme->GetIndicatorDigitHeight().ConvertToPx())) {
1099         indicatorHeight = swiperIndicatorTheme->GetIndicatorDigitHeight().ConvertToPx();
1100     }
1101 
1102     auto frameNode = indicatorWrapper->GetHostNode();
1103     CHECK_NULL_VOID(frameNode);
1104     auto indicatorlayoutProperty = frameNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
1105     CHECK_NULL_VOID(indicatorlayoutProperty);
1106 
1107     auto currentOffset = SwiperIndicatorUtils::CalcIndicatrFrameOffSet(
1108         swiperLayoutProperty, indicatorlayoutProperty, indicatorWidth, indicatorHeight);
1109 
1110     if (swiperLayoutProperty->GetDisplayArrowValue(false) && !swiperLayoutProperty->GetIsSidebarMiddleValue(false) &&
1111         HasCustomIndicatorOffset(indicatorWrapper)) {
1112         useCustomIndicatorOffset = true;
1113         auto indicatorOffset = CalculateCustomOffset(indicatorWrapper, currentOffset);
1114         if (swiperLayoutProperty->GetDirectionValue(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
1115             currentOffset.SetX(indicatorOffset.GetX());
1116         } else {
1117             currentOffset.SetY(indicatorOffset.GetY());
1118         }
1119     }
1120     if (swiperLayoutProperty->GetDirectionValue(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
1121         auto top = indicatorlayoutProperty->GetTop();
1122         auto bottom = indicatorlayoutProperty->GetBottom();
1123         if ((!top.has_value() || NearZero(top.value().Value())) &&
1124             (!bottom.has_value() || NearZero(bottom.value().Value()))) {
1125             auto themeHeight = swiperIndicatorTheme->GetIndicatorDigitHeight().ConvertToPx();
1126             auto dightPadding = 0.0;
1127             if (themeHeight > indicatorHeight) {
1128                 dightPadding = (themeHeight - indicatorHeight) / 2;
1129             }
1130             auto dightVerPadding = swiperIndicatorTheme->GetIndicatorDigitVerticalPadding().ConvertToPx();
1131             currentOffset.SetY(currentOffset.GetY() - dightVerPadding + dightPadding);
1132         }
1133     }
1134 
1135     indicatorGeometryNode->SetMarginFrameOffset(currentOffset);
1136 }
1137 
GetNodeLayoutWrapperByTag(LayoutWrapper * layoutWrapper,const std::string & tagName) const1138 RefPtr<LayoutWrapper> SwiperLayoutAlgorithm::GetNodeLayoutWrapperByTag(
1139     LayoutWrapper* layoutWrapper, const std::string& tagName) const
1140 {
1141     CHECK_NULL_RETURN(layoutWrapper, nullptr);
1142     auto hostNode = layoutWrapper->GetHostNode();
1143     CHECK_NULL_RETURN(hostNode, nullptr);
1144     auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
1145     CHECK_NULL_RETURN(swiperPattern, nullptr);
1146     RefPtr<LayoutWrapper> nodeWrapper = nullptr;
1147     int32_t totalChildCount = layoutWrapper->GetTotalChildCount();
1148     if (totalChildCount == 0) {
1149         return nullptr;
1150     }
1151     int32_t lastChildIndex = totalChildCount - 1;
1152     int32_t endLoopChildIndex = lastChildIndex - SWIPER_HAS_CHILD;
1153     for (int32_t index = lastChildIndex; index > endLoopChildIndex && index >= 0; index--) {
1154         nodeWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
1155         if (nodeWrapper && (nodeWrapper->GetHostTag() == tagName)) {
1156             return nodeWrapper;
1157         }
1158     }
1159 
1160     return nullptr;
1161 }
1162 
HasCustomIndicatorOffset(const RefPtr<LayoutWrapper> & indicatorWrapper)1163 bool SwiperLayoutAlgorithm::HasCustomIndicatorOffset(const RefPtr<LayoutWrapper>& indicatorWrapper)
1164 {
1165     auto frameNode = indicatorWrapper->GetHostNode();
1166     CHECK_NULL_RETURN(frameNode, false);
1167     auto indicatorLayoutProperty = frameNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
1168     CHECK_NULL_RETURN(indicatorLayoutProperty, false);
1169     return indicatorLayoutProperty->GetLeft().has_value() || indicatorLayoutProperty->GetRight().has_value() ||
1170            indicatorLayoutProperty->GetTop().has_value() || indicatorLayoutProperty->GetBottom().has_value();
1171 }
1172 
CalculateCustomOffset(const RefPtr<LayoutWrapper> & indicatorWrapper,const OffsetF & currentOffset)1173 const OffsetF SwiperLayoutAlgorithm::CalculateCustomOffset(
1174     const RefPtr<LayoutWrapper>& indicatorWrapper, const OffsetF& currentOffset)
1175 {
1176     OffsetF indicatorOffset(currentOffset.GetX(), currentOffset.GetY());
1177     auto indicatorGeometryNode = indicatorWrapper->GetGeometryNode();
1178     CHECK_NULL_RETURN(indicatorGeometryNode, indicatorOffset);
1179     SizeF indicatorFrameSize = indicatorGeometryNode->GetFrameSize();
1180     auto indicatorLayoutProperty =
1181         AceType::DynamicCast<SwiperIndicatorLayoutProperty>(indicatorWrapper->GetLayoutProperty());
1182     CHECK_NULL_RETURN(indicatorLayoutProperty, indicatorOffset);
1183 
1184     auto swiperNode = DynamicCast<FrameNode>(indicatorWrapper->GetHostNode()->GetParent());
1185     CHECK_NULL_RETURN(swiperNode, indicatorOffset);
1186     auto swiperLayoutProperty = swiperNode->GetLayoutProperty<SwiperLayoutProperty>();
1187     CHECK_NULL_RETURN(swiperLayoutProperty, indicatorOffset);
1188     SizeF swiperFrameSize = swiperNode->GetGeometryNode()->GetFrameSize();
1189     auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
1190     CHECK_NULL_RETURN(swiperPattern, indicatorOffset);
1191     auto arrowNode = DynamicCast<FrameNode>(
1192         swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(swiperPattern->GetLeftButtonId())));
1193     CHECK_NULL_RETURN(arrowNode, indicatorOffset);
1194     SizeF arrowFrameSize = arrowNode->GetGeometryNode()->GetFrameSize();
1195     auto left = indicatorLayoutProperty->GetLeft();
1196     auto right = indicatorLayoutProperty->GetRight();
1197     auto top = indicatorLayoutProperty->GetTop();
1198     auto bottom = indicatorLayoutProperty->GetBottom();
1199     auto pipelineContext = PipelineBase::GetCurrentContext();
1200     CHECK_NULL_RETURN(pipelineContext, indicatorOffset);
1201     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
1202     CHECK_NULL_RETURN(swiperIndicatorTheme, indicatorOffset);
1203     auto indicatorPadding = swiperIndicatorTheme->GetIndicatorDigitPadding().ConvertToPx();
1204 
1205     if (swiperLayoutProperty->GetDirectionValue(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
1206         auto horizonOffset = arrowFrameSize.Width() + indicatorPadding;
1207         auto offset = 0.0;
1208         if (left.has_value()) {
1209             offset = currentOffset.GetX() + horizonOffset;
1210             indicatorOffset.SetX(
1211                 std::min(offset, swiperFrameSize.Width() - indicatorFrameSize.Width() - horizonOffset));
1212         } else if (right.has_value()) {
1213             offset = currentOffset.GetX() - horizonOffset;
1214             indicatorOffset.SetX(std::max(offset, horizonOffset));
1215         }
1216     } else {
1217         auto verticleOffset = arrowFrameSize.Height() + indicatorPadding;
1218         auto offset = 0.0;
1219         if (top.has_value()) {
1220             offset = currentOffset.GetY() + verticleOffset;
1221             indicatorOffset.SetY(
1222                 std::min(offset, swiperFrameSize.Height() - indicatorFrameSize.Height() - verticleOffset));
1223         } else if (bottom.has_value()) {
1224             offset = currentOffset.GetY() - verticleOffset;
1225             indicatorOffset.SetY(std::max(offset, verticleOffset));
1226         }
1227     }
1228     return indicatorOffset;
1229 }
1230 
MeasureArrow(const RefPtr<LayoutWrapper> & arrowWrapper,const RefPtr<LayoutProperty> & layoutProperty) const1231 void SwiperLayoutAlgorithm::MeasureArrow(
1232     const RefPtr<LayoutWrapper>& arrowWrapper, const RefPtr<LayoutProperty>& layoutProperty) const
1233 {
1234     CHECK_NULL_VOID(arrowWrapper);
1235     CHECK_NULL_VOID(layoutProperty);
1236     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutProperty);
1237     CHECK_NULL_VOID(swiperLayoutProperty);
1238     auto arrowGeometryNode = arrowWrapper->GetGeometryNode();
1239     CHECK_NULL_VOID(arrowGeometryNode);
1240 
1241     auto pipelineContext = PipelineBase::GetCurrentContext();
1242     CHECK_NULL_VOID(pipelineContext);
1243     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
1244     CHECK_NULL_VOID(swiperIndicatorTheme);
1245 
1246     arrowGeometryNode->SetFrameSize(
1247         SizeF { static_cast<float>(
1248                     swiperLayoutProperty->GetBackgroundSizeValue(swiperIndicatorTheme->GetBigArrowBackgroundSize())
1249                         .ConvertToPx()),
1250             static_cast<float>(
1251                 swiperLayoutProperty->GetBackgroundSizeValue(swiperIndicatorTheme->GetBigArrowBackgroundSize())
1252                     .ConvertToPx()) });
1253     auto indicatorLayoutConstraint = swiperLayoutProperty->CreateChildConstraint();
1254     arrowWrapper->Measure(indicatorLayoutConstraint);
1255 }
1256 
ArrowLayout(LayoutWrapper * layoutWrapper,const RefPtr<LayoutWrapper> & arrowWrapper,const PaddingPropertyF padding) const1257 void SwiperLayoutAlgorithm::ArrowLayout(
1258     LayoutWrapper* layoutWrapper, const RefPtr<LayoutWrapper>& arrowWrapper, const PaddingPropertyF padding) const
1259 {
1260     CHECK_NULL_VOID(layoutWrapper);
1261     CHECK_NULL_VOID(arrowWrapper);
1262     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
1263     CHECK_NULL_VOID(swiperLayoutProperty);
1264     auto axis = swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
1265     auto indicatorType = swiperLayoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT);
1266     auto arrowGeometryNode = arrowWrapper->GetGeometryNode();
1267     CHECK_NULL_VOID(arrowGeometryNode);
1268     auto arrowFrameSize = arrowGeometryNode->GetFrameSize();
1269     auto layoutGeometryNode = layoutWrapper->GetGeometryNode();
1270     CHECK_NULL_VOID(layoutGeometryNode);
1271     auto swiperFrameSize = layoutGeometryNode->GetFrameSize();
1272     auto isShowIndicatorArrow =
1273         (!swiperLayoutProperty->GetIsSidebarMiddleValue(false) && swiperLayoutProperty->GetShowIndicatorValue(true));
1274     SizeF indicatorFrameSize;
1275     RectF indicatorFrameRect;
1276     auto normalArrowMargin = 0.0f;
1277     if (isShowIndicatorArrow) {
1278         auto indicatorWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_INDICATOR_ETS_TAG);
1279         CHECK_NULL_VOID(indicatorWrapper);
1280         auto indicatorGeometry = indicatorWrapper->GetGeometryNode();
1281         CHECK_NULL_VOID(indicatorGeometry);
1282         indicatorFrameSize = indicatorGeometry->GetFrameSize();
1283         indicatorFrameRect = indicatorGeometry->GetFrameRect();
1284         if (indicatorType == SwiperIndicatorType::DOT) {
1285             auto hostNode = layoutWrapper->GetHostNode();
1286             CHECK_NULL_VOID(hostNode);
1287             auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
1288             CHECK_NULL_VOID(swiperPattern);
1289             auto itemCount = swiperPattern->TotalCount();
1290             auto indicatorNode = indicatorWrapper->GetHostNode();
1291             CHECK_NULL_VOID(indicatorNode);
1292             auto pipeline = PipelineBase::GetCurrentContext();
1293             CHECK_NULL_VOID(pipeline);
1294             auto theme = pipeline->GetTheme<SwiperIndicatorTheme>();
1295             CHECK_NULL_VOID(theme);
1296             auto indicatorPaintProperty = indicatorNode->GetPaintProperty<DotIndicatorPaintProperty>();
1297             CHECK_NULL_VOID(indicatorPaintProperty);
1298             auto itemWidth =
1299                 static_cast<float>(indicatorPaintProperty->GetItemWidthValue(theme->GetSize()).ConvertToPx());
1300             auto selectedItemWidth =
1301                 static_cast<float>(indicatorPaintProperty->GetSelectedItemWidthValue(theme->GetSize()).ConvertToPx());
1302             auto indicatorPadding = static_cast<float>(theme->GetIndicatorDotPadding().ConvertToPx());
1303             auto allPointDiameterSum = itemWidth * static_cast<float>(itemCount + 1);
1304             if (indicatorPaintProperty->GetIsCustomSizeValue(false)) {
1305                 allPointDiameterSum = itemWidth * static_cast<float>(itemCount - 1) + selectedItemWidth;
1306             }
1307             auto allPointSpaceSum =
1308                 static_cast<float>(theme->GetIndicatorDotItemSpace().ConvertToPx()) * (itemCount - 1);
1309             auto indicatorWidth = indicatorPadding + allPointDiameterSum + allPointSpaceSum + indicatorPadding;
1310             normalArrowMargin = ((axis == Axis::HORIZONTAL ? indicatorFrameSize.Width() : indicatorFrameSize.Height()) -
1311                                     indicatorWidth) * 0.5f;
1312         }
1313     }
1314     auto isLeftArrow = arrowWrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG;
1315     auto pipelineContext = PipelineBase::GetCurrentContext();
1316     CHECK_NULL_VOID(pipelineContext);
1317     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
1318     CHECK_NULL_VOID(swiperIndicatorTheme);
1319     OffsetF arrowOffset(0.0f, 0.0f);
1320     float startPoint = 0.0f;
1321     if (axis == Axis::HORIZONTAL && isShowIndicatorArrow) {
1322         auto indicatorPadding = indicatorType == SwiperIndicatorType::DIGIT
1323                                     ? swiperIndicatorTheme->GetIndicatorDigitPadding().ConvertToPx()
1324                                     : swiperIndicatorTheme->GetIndicatorDotPadding().ConvertToPx();
1325         if (useCustomIndicatorOffset && indicatorType == SwiperIndicatorType::DIGIT) {
1326             startPoint = isLeftArrow ? (indicatorFrameRect.Left() - arrowFrameSize.Width() - indicatorPadding)
1327                                      : (indicatorFrameRect.Right() + indicatorPadding);
1328         } else {
1329             startPoint =
1330                 isLeftArrow
1331                     ? (indicatorFrameRect.Left() - arrowFrameSize.Width() -
1332                           swiperIndicatorTheme->GetArrowScale().ConvertToPx() + indicatorPadding + normalArrowMargin)
1333                     : (indicatorFrameRect.Right() + swiperIndicatorTheme->GetArrowScale().ConvertToPx() -
1334                           indicatorPadding - normalArrowMargin);
1335         }
1336         arrowOffset.SetX(startPoint);
1337         if (isLeftArrow && !NonNegative(arrowOffset.GetX() - padding.left.value_or(0.0f))) {
1338             arrowOffset.SetX(padding.left.value_or(0.0f));
1339         }
1340         if (GreatOrEqual(
1341             arrowOffset.GetX() + arrowFrameSize.Width(), swiperFrameSize.Width() - padding.right.value_or(0.0f))) {
1342             arrowOffset.SetX(swiperFrameSize.Width() - arrowFrameSize.Width() - padding.right.value_or(0.0f));
1343         }
1344         arrowOffset.SetY(indicatorFrameRect.Top() + (indicatorFrameSize.Height() - arrowFrameSize.Height()) * 0.5f);
1345     } else if (axis == Axis::HORIZONTAL && !isShowIndicatorArrow) {
1346         startPoint = isLeftArrow
1347                          ? swiperIndicatorTheme->GetArrowHorizontalMargin().ConvertToPx() + padding.left.value_or(0.0f)
1348                          : (swiperFrameSize.Width() - padding.right.value_or(0.0f) - arrowFrameSize.Width() -
1349                                swiperIndicatorTheme->GetArrowHorizontalMargin().ConvertToPx());
1350         arrowOffset.SetX(startPoint);
1351         arrowOffset.SetY((swiperFrameSize.Height() - padding.top.value_or(0.0f) - padding.bottom.value_or(0.0f) -
1352                              arrowFrameSize.Height()) *
1353                              0.5f +
1354                          padding.top.value_or(0.0f));
1355     } else if (axis != Axis::HORIZONTAL && isShowIndicatorArrow) {
1356         auto indicatorPadding = indicatorType == SwiperIndicatorType::DIGIT
1357                                     ? swiperIndicatorTheme->GetIndicatorDigitPadding().ConvertToPx()
1358                                     : swiperIndicatorTheme->GetIndicatorDotPadding().ConvertToPx();
1359         if (useCustomIndicatorOffset && indicatorType == SwiperIndicatorType::DIGIT) {
1360             startPoint = isLeftArrow ? (indicatorFrameRect.Top() - arrowFrameSize.Height() -
1361                                            padding.top.value_or(0.0f) - indicatorPadding)
1362                                      : (indicatorFrameRect.Bottom() + padding.bottom.value_or(0.0f) + indicatorPadding);
1363         } else {
1364             startPoint =
1365                 isLeftArrow
1366                     ? (indicatorFrameRect.Top() - arrowFrameSize.Height() - padding.top.value_or(0.0f) -
1367                           swiperIndicatorTheme->GetArrowScale().ConvertToPx() + indicatorPadding + normalArrowMargin)
1368                     : (indicatorFrameRect.Bottom() + padding.bottom.value_or(0.0f) +
1369                           swiperIndicatorTheme->GetArrowScale().ConvertToPx() - indicatorPadding - normalArrowMargin);
1370         }
1371         arrowOffset.SetX(indicatorFrameRect.Left() + (indicatorFrameSize.Width() - arrowFrameSize.Width()) * 0.5f);
1372         arrowOffset.SetY(startPoint);
1373         if (isLeftArrow && !NonNegative(arrowOffset.GetY() - padding.top.value_or(0.0f))) {
1374             arrowOffset.SetY(padding.top.value_or(0.0f));
1375         }
1376         if (GreatOrEqual(arrowOffset.GetY() + arrowFrameSize.Height(),
1377             swiperFrameSize.Height() - padding.bottom.value_or(0.0f))) {
1378             arrowOffset.SetY(swiperFrameSize.Height() - arrowFrameSize.Height() - padding.bottom.value_or(0.0f));
1379         }
1380     } else {
1381         startPoint = isLeftArrow
1382                          ? swiperIndicatorTheme->GetArrowVerticalMargin().ConvertToPx() + padding.top.value_or(0.0f)
1383                          : (swiperFrameSize.Height() - arrowFrameSize.Width() - padding.bottom.value_or(0.0f) -
1384                                swiperIndicatorTheme->GetArrowVerticalMargin().ConvertToPx());
1385         arrowOffset.SetX(padding.left.value_or(0.0f) + (swiperFrameSize.Width() - padding.left.value_or(0.0f) -
1386                                                            padding.right.value_or(0.0f) - arrowFrameSize.Width()) *
1387                                                            0.5f);
1388         arrowOffset.SetY(startPoint);
1389     }
1390     arrowGeometryNode->SetMarginFrameOffset(arrowOffset);
1391     arrowWrapper->Layout();
1392 }
1393 
ResetOffscreenItemPosition(LayoutWrapper * layoutWrapper,int32_t index,bool isForward,Axis axis) const1394 void SwiperLayoutAlgorithm::ResetOffscreenItemPosition(
1395     LayoutWrapper* layoutWrapper, int32_t index, bool isForward, Axis axis) const
1396 {
1397     auto swiperGeometryNode = layoutWrapper->GetGeometryNode();
1398     CHECK_NULL_VOID(swiperGeometryNode);
1399     auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
1400     CHECK_NULL_VOID(childWrapper);
1401 
1402     if (childWrapper->GetHostTag() == V2::SWIPER_INDICATOR_ETS_TAG ||
1403         childWrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG ||
1404         childWrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
1405         return;
1406     }
1407 
1408     auto childGeometryNode = childWrapper->GetGeometryNode();
1409     CHECK_NULL_VOID(childGeometryNode);
1410     auto swiperFrameRect = swiperGeometryNode->GetFrameRect();
1411     auto childFrameRect = childGeometryNode->GetFrameRect();
1412 
1413     OffsetF offset(0.0f, 0.0f);
1414     if (axis == Axis::HORIZONTAL) {
1415         offset.SetX(isForward ? -childFrameRect.Width() : swiperFrameRect.Width());
1416     } else {
1417         offset.SetY(isForward ? -childFrameRect.Height() : swiperFrameRect.Height());
1418     }
1419 
1420     childGeometryNode->SetMarginFrameOffset(offset);
1421     childWrapper->Layout();
1422 }
1423 
IsNormalItem(const RefPtr<LayoutWrapper> & wrapper) const1424 bool SwiperLayoutAlgorithm::IsNormalItem(const RefPtr<LayoutWrapper>& wrapper) const
1425 {
1426     CHECK_NULL_RETURN(wrapper, false);
1427     auto tag = wrapper->GetHostTag();
1428     if (tag == V2::SWIPER_INDICATOR_ETS_TAG || tag == V2::SWIPER_LEFT_ARROW_ETS_TAG ||
1429         tag == V2::SWIPER_RIGHT_ARROW_ETS_TAG || tag == V2::SWIPER_LEFT_CAPTURE_ETS_TAG ||
1430         tag == V2::SWIPER_RIGHT_CAPTURE_ETS_TAG) {
1431         return false;
1432     }
1433     return true;
1434 }
1435 
CheckCachedItem(int32_t startIndex,int32_t endIndex,LayoutWrapper * layoutWrapper)1436 void SwiperLayoutAlgorithm::CheckCachedItem(int32_t startIndex, int32_t endIndex, LayoutWrapper* layoutWrapper)
1437 {
1438     if (!layoutWrapper) {
1439         return;
1440     }
1441     if (startIndex <= endIndex) {
1442         for (auto i = startIndex; i <= endIndex; ++i) {
1443             activeItems_.insert(i);
1444         }
1445     } else {
1446         for (auto i = 0; i <= endIndex; ++i) {
1447             activeItems_.insert(i);
1448         }
1449         for (auto i = startIndex; i < totalItemCount_; ++i) {
1450             activeItems_.insert(i);
1451         }
1452     }
1453     auto cachedCount = cachedCount_;
1454     while (cachedCount > 0) {
1455         if (isLoop_) {
1456             startIndex = GetLoopIndex(startIndex - 1);
1457             endIndex = GetLoopIndex(endIndex + 1);
1458         } else {
1459             startIndex = startIndex >= 0 ? startIndex - 1 : startIndex;
1460             endIndex = endIndex < totalItemCount_ ? endIndex + 1 : endIndex;
1461         }
1462         if (startIndex >= 0) {
1463             if (activeItems_.find(startIndex) == activeItems_.end()
1464                 && layoutWrapper->GetChildByIndex(startIndex, true) == nullptr) {
1465                 cachedItems_.insert(startIndex);
1466             }
1467         }
1468         if (endIndex < totalItemCount_) {
1469             if (activeItems_.find(endIndex) == activeItems_.end()
1470                 && layoutWrapper->GetChildByIndex(endIndex, true) == nullptr) {
1471                 cachedItems_.insert(endIndex);
1472             }
1473         }
1474         --cachedCount;
1475     }
1476     if (swipeByGroup_) {
1477         for (auto i = realTotalCount_; i < totalItemCount_; ++i) {
1478             activeItems_.erase(i);
1479             cachedItems_.erase(i);
1480         }
1481     }
1482 }
1483 } // namespace OHOS::Ace::NG
1484