• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 #include "core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.h"
16 
17 #include <algorithm>
18 #include <cstdint>
19 
20 #include "base/utils/utils.h"
21 
22 namespace OHOS::Ace::NG {
Sync(int32_t itemCnt,float mainSize,const std::vector<float> & mainGap)23 void WaterFlowLayoutInfoSW::Sync(int32_t itemCnt, float mainSize, const std::vector<float>& mainGap)
24 {
25     if (lanes_.empty()) {
26         return;
27     }
28     startIndex_ = StartIndex();
29     endIndex_ = EndIndex();
30     if (startIndex_ > endIndex_) {
31         SyncOnEmptyLanes();
32         return;
33     }
34     if (!idxToLane_.count(startIndex_) || lanes_[GetSegment(startIndex_)].size() <= idxToLane_.at(startIndex_)) {
35         return;
36     }
37     storedOffset_ = lanes_[GetSegment(startIndex_)][idxToLane_.at(startIndex_)].startPos;
38 
39     delta_ = 0.0f;
40     lastMainSize_ = mainSize;
41     mainGap_ = mainGap;
42     startPos_ = StartPos();
43     endPos_ = EndPos();
44 
45     itemStart_ = startIndex_ == 0 && NonNegative(startPos_ - TopMargin());
46     itemEnd_ = endIndex_ == itemCnt - 1;
47     if (footerIndex_ == 0) {
48         itemEnd_ &= LessOrEqual(endPos_, mainSize);
49     }
50     offsetEnd_ = itemEnd_ && LessOrEqual(endPos_ + footerHeight_ + BotMargin(), mainSize);
51     maxHeight_ = std::max(endPos_ - startPos_ + footerHeight_, maxHeight_);
52 
53     if (!itemEnd_) {
54         footerHeight_ = 0.0f;
55     }
56 
57     newStartIndex_ = EMPTY_NEW_START_INDEX;
58 
59     synced_ = true;
60 }
61 
CalibrateOffset()62 float WaterFlowLayoutInfoSW::CalibrateOffset()
63 {
64     if (startIndex_ == 0) {
65         // can calibrate totalOffset when at top
66         const float prev = totalOffset_;
67         totalOffset_ = startPos_ - TopMargin();
68         return totalOffset_ - prev;
69     }
70     return 0.0f;
71 }
72 
DistanceToTop(int32_t itemIdx,float mainGap) const73 float WaterFlowLayoutInfoSW::DistanceToTop(int32_t itemIdx, float mainGap) const
74 {
75     if (!ItemInView(itemIdx)) {
76         return 0.0f;
77     }
78     const auto& lane = lanes_[GetSegment(itemIdx)][idxToLane_.at(itemIdx)];
79     float dist = lane.startPos;
80     for (const auto& item : lane.items_) {
81         if (item.idx == itemIdx) {
82             break;
83         }
84         dist += item.mainSize + mainGap;
85     }
86     return dist;
87 }
88 
DistanceToBottom(int32_t itemIdx,float mainSize,float mainGap) const89 float WaterFlowLayoutInfoSW::DistanceToBottom(int32_t itemIdx, float mainSize, float mainGap) const
90 {
91     if (!ItemInView(itemIdx)) {
92         return 0.0f;
93     }
94     const auto& lane = lanes_[GetSegment(itemIdx)][idxToLane_.at(itemIdx)];
95     float dist = mainSize - lane.endPos;
96     for (auto item = lane.items_.rbegin(); item != lane.items_.rend(); ++item) {
97         if (item->idx == itemIdx) {
98             break;
99         }
100         dist += item->mainSize + mainGap;
101     }
102     return dist;
103 }
104 
OutOfBounds() const105 bool WaterFlowLayoutInfoSW::OutOfBounds() const
106 {
107     if (lanes_.empty()) {
108         return false;
109     }
110     // checking first lane is enough because re-align automatically happens when reaching start
111     if (itemStart_ && Positive(lanes_[0][0].startPos - TopMargin())) {
112         return true;
113     }
114     if (!itemStart_ && offsetEnd_) {
115         return std::all_of(lanes_.back().begin(), lanes_.back().end(), [this](const Lane& lane) {
116             return LessNotEqual(lane.endPos + footerHeight_ + BotMargin(), lastMainSize_);
117         });
118     }
119     return false;
120 }
121 
GetOverScrolledDelta(float delta) const122 OverScrollOffset WaterFlowLayoutInfoSW::GetOverScrolledDelta(float delta) const
123 {
124     OverScrollOffset res {};
125     if (lanes_.empty()) {
126         return res;
127     }
128 
129     if (startIndex_ == 0) {
130         float disToTop = -StartPosWithMargin();
131         if (!itemStart_) {
132             res.start = std::max(0.0f, delta - disToTop);
133         } else if (Positive(delta)) {
134             res.start = delta;
135         } else {
136             res.start = std::max(delta, disToTop);
137         }
138     }
139 
140     if (!itemEnd_) {
141         return res;
142     }
143     float disToBot = EndPosWithMargin() + footerHeight_ - std::min(lastMainSize_, maxHeight_);
144     if (Positive(disToBot) && LessNotEqual(maxHeight_, lastMainSize_)) {
145         res.end = std::min(0.0f, disToBot + delta);
146         return res;
147     }
148     if (!offsetEnd_) {
149         res.end = std::min(0.0f, disToBot + delta);
150     } else if (Negative(delta)) {
151         res.end = delta;
152     } else {
153         res.end = std::min(delta, -disToBot);
154     }
155     return res;
156 }
157 
CalcOverScroll(float mainSize,float delta) const158 float WaterFlowLayoutInfoSW::CalcOverScroll(float mainSize, float delta) const
159 {
160     if (lanes_.empty()) {
161         return 0.0f;
162     }
163     float res = 0.0f;
164     if (itemStart_) {
165         res = StartPosWithMargin() + delta;
166     }
167     if (offsetEnd_) {
168         res = mainSize - (EndPosWithMargin() + footerHeight_ + delta);
169     }
170     return res;
171 }
172 
173 namespace {
174 using Lane = WaterFlowLayoutInfoSW::Lane;
SectionEmpty(const std::vector<WaterFlowLayoutInfoSW::Lane> & section)175 inline bool SectionEmpty(const std::vector<WaterFlowLayoutInfoSW::Lane>& section)
176 {
177     return section.empty() ||
178            std::all_of(section.begin(), section.end(), [](const auto& lane) { return lane.items_.empty(); });
179 }
SectionEndPos(const std::vector<WaterFlowLayoutInfoSW::Lane> & section)180 inline float SectionEndPos(const std::vector<WaterFlowLayoutInfoSW::Lane>& section)
181 {
182     return std::max_element(section.begin(), section.end(), [](const Lane& left, const Lane& right) {
183         return LessNotEqual(left.endPos, right.endPos);
184     })->endPos;
185 }
186 
SectionStartPos(const std::vector<WaterFlowLayoutInfoSW::Lane> & section)187 inline float SectionStartPos(const std::vector<WaterFlowLayoutInfoSW::Lane>& section)
188 {
189     return std::min_element(section.begin(), section.end(), [](const Lane& left, const Lane& right) {
190         return LessNotEqual(left.startPos, right.startPos);
191     })->startPos;
192 }
193 } // namespace
194 
EndPos() const195 float WaterFlowLayoutInfoSW::EndPos() const
196 {
197     if (synced_) {
198         return endPos_;
199     }
200     for (auto it = lanes_.rbegin(); it != lanes_.rend(); ++it) {
201         if (SectionEmpty(*it)) {
202             continue;
203         }
204         return SectionEndPos(*it);
205     }
206     return 0.0f;
207 }
208 
StartPos() const209 float WaterFlowLayoutInfoSW::StartPos() const
210 {
211     if (synced_) {
212         return startPos_;
213     }
214     for (const auto& section : lanes_) {
215         if (SectionEmpty(section)) {
216             continue;
217         }
218         return SectionStartPos(section);
219     }
220     return 0.0f;
221 }
222 
ReachStart(float prevPos,bool firstLayout) const223 bool WaterFlowLayoutInfoSW::ReachStart(float prevPos, bool firstLayout) const
224 {
225     if (!itemStart_ || lanes_.empty()) {
226         return false;
227     }
228     return firstLayout || Negative(prevPos);
229 }
230 
ReachEnd(float prevPos,bool firstLayout) const231 bool WaterFlowLayoutInfoSW::ReachEnd(float prevPos, bool firstLayout) const
232 {
233     if (!offsetEnd_ || lanes_.empty()) {
234         return false;
235     }
236     float prevEndPos = EndPos() - (totalOffset_ - prevPos);
237     return firstLayout || GreatNotEqual(prevEndPos + footerHeight_, lastMainSize_);
238 }
239 
GetContentHeight() const240 float WaterFlowLayoutInfoSW::GetContentHeight() const
241 {
242     // only height in view are remembered
243     return maxHeight_;
244 }
245 
GetMainCount() const246 int32_t WaterFlowLayoutInfoSW::GetMainCount() const
247 {
248     if (lanes_.empty()) {
249         return 0;
250     }
251     for (const auto& section : lanes_) {
252         if (SectionEmpty(section)) {
253             continue;
254         }
255         return static_cast<int32_t>(
256             std::max_element(section.begin(), section.end(), [](const Lane& left, const Lane& right) {
257                 return left.items_.size() < right.items_.size();
258             })->items_.size());
259     }
260     return 0;
261 }
262 
CalcTargetPosition(int32_t idx,int32_t) const263 float WaterFlowLayoutInfoSW::CalcTargetPosition(int32_t idx, int32_t /* crossIdx */) const
264 {
265     if (!ItemInView(idx)) {
266         return Infinity<float>();
267     }
268     const auto& lane = lanes_[GetSegment(idx)][idxToLane_.at(idx)];
269     float pos = 0.0f; // main-axis position of the item's top edge relative to viewport top. Positive if below viewport
270     float itemSize = 0.0f;
271     if (idx < endIndex_) {
272         pos = DistanceToTop(idx, mainGap_[GetSegment(idx)]);
273         auto it = std::find_if(
274             lane.items_.begin(), lane.items_.end(), [idx](const ItemInfo& item) { return item.idx == idx; });
275         itemSize = it->mainSize;
276     } else {
277         itemSize = lane.items_.back().mainSize;
278         pos = lane.endPos - itemSize;
279     }
280     switch (align_) {
281         case ScrollAlign::START:
282             break;
283         case ScrollAlign::END:
284             pos = pos - lastMainSize_ + itemSize;
285             break;
286         case ScrollAlign::AUTO:
287             if (Negative(pos)) {
288                 /* */
289             } else if (GreatNotEqual(pos + itemSize, lastMainSize_)) {
290                 pos = pos - lastMainSize_ + itemSize;
291             } else {
292                 pos = 0.0f; // already in viewport, no movement needed
293             }
294             break;
295         case ScrollAlign::CENTER:
296             pos = pos - (lastMainSize_ - itemSize) / 2.0f;
297             break;
298         default:
299             pos = 0.0f;
300             break;
301     }
302     // convert to absolute position
303     return pos - totalOffset_;
304 }
305 
PrepareJump()306 void WaterFlowLayoutInfoSW::PrepareJump()
307 {
308     if (startIndex_ > endIndex_) {
309         return;
310     }
311     align_ = ScrollAlign::START;
312     jumpIndex_ = startIndex_;
313     delta_ = storedOffset_;
314 }
315 
Reset()316 void WaterFlowLayoutInfoSW::Reset()
317 {
318     PrepareJump();
319     for (auto& section : lanes_) {
320         for (auto& lane : section) {
321             lane.items_.clear();
322         }
323     }
324     idxToLane_.clear();
325     maxHeight_ = 0.0f;
326     synced_ = false;
327 }
328 
EndIndex() const329 int32_t WaterFlowLayoutInfoSW::EndIndex() const
330 {
331     if (synced_) {
332         return endIndex_;
333     }
334     int32_t maxIdx = -1;
335     for (auto it = lanes_.rbegin(); it != lanes_.rend(); ++it) {
336         bool flag = false;
337         for (const auto& lane : *it) {
338             if (lane.items_.empty()) {
339                 continue;
340             }
341             flag = true;
342             maxIdx = std::max(maxIdx, lane.items_.back().idx);
343         }
344         if (flag) {
345             break;
346         }
347     }
348     return maxIdx;
349 }
350 
StartIndex() const351 int32_t WaterFlowLayoutInfoSW::StartIndex() const
352 {
353     if (synced_) {
354         return startIndex_;
355     }
356     auto minIdx = Infinity<int32_t>();
357     for (const auto& section : lanes_) {
358         bool flag = false;
359         for (const auto& lane : section) {
360             if (lane.items_.empty()) {
361                 continue;
362             }
363             flag = true;
364             minIdx = std::min(minIdx, lane.items_.front().idx);
365         }
366         if (flag) {
367             break;
368         }
369     }
370     return minIdx;
371 }
372 
GetCrossIndex(int32_t itemIndex) const373 int32_t WaterFlowLayoutInfoSW::GetCrossIndex(int32_t itemIndex) const
374 {
375     if (ItemInView(itemIndex)) {
376         return static_cast<int32_t>(idxToLane_.at(itemIndex));
377     }
378     return -1;
379 }
380 
ResetWithLaneOffset(std::optional<float> laneBasePos)381 void WaterFlowLayoutInfoSW::ResetWithLaneOffset(std::optional<float> laneBasePos)
382 {
383     for (auto& section : lanes_) {
384         std::for_each(section.begin(), section.end(), [&laneBasePos](auto& lane) {
385             lane.items_.clear();
386             if (laneBasePos) {
387                 lane.startPos = *laneBasePos;
388                 lane.endPos = *laneBasePos;
389             } else {
390                 lane.endPos = lane.startPos;
391             }
392         });
393     }
394     maxHeight_ = 0.0f;
395     idxToLane_.clear();
396     synced_ = false;
397 }
398 
ToString() const399 std::string WaterFlowLayoutInfoSW::Lane::ToString() const
400 {
401     std::string res = "{StartPos: " + std::to_string(startPos) + " EndPos: " + std::to_string(endPos) + " ";
402     if (items_.empty()) {
403         res += "empty";
404     } else {
405         res += "Items [";
406         for (const auto& item : items_) {
407             res += std::to_string(item.idx) + " ";
408         }
409         res += "] ";
410     }
411     res += "}";
412     return res;
413 }
414 
ItemCloseToView(int32_t idx) const415 bool WaterFlowLayoutInfoSW::ItemCloseToView(int32_t idx) const
416 {
417     if (lanes_.empty() || std::all_of(lanes_.begin(), lanes_.end(), [](const auto& lanes) { return lanes.empty(); })) {
418         return false;
419     }
420     int32_t startIdx = StartIndex();
421     int32_t endIdx = EndIndex();
422     using std::abs, std::min;
423     return min(abs(idx - endIdx), abs(idx - startIdx)) < endIdx - startIdx + 1;
424 }
425 
ClearDataFrom(int32_t idx,const std::vector<float> & mainGap)426 void WaterFlowLayoutInfoSW::ClearDataFrom(int32_t idx, const std::vector<float>& mainGap)
427 {
428     for (auto it = idxToLane_.begin(); it != idxToLane_.end();) {
429         if (it->first >= idx) {
430             it = idxToLane_.erase(it); // Erase and get the iterator to the next element
431         } else {
432             ++it;
433         }
434     }
435     for (int32_t i = GetSegment(idx); i < static_cast<int32_t>(lanes_.size()); ++i) {
436         for (auto& lane : lanes_[i]) {
437             while (!lane.items_.empty() && lane.items_.back().idx >= idx) {
438                 lane.endPos -= lane.items_.back().mainSize + mainGap[i];
439                 lane.items_.pop_back();
440             }
441             lane.endPos = std::max(lane.endPos, lane.startPos);
442         }
443     }
444 }
445 
TopFinalPos() const446 float WaterFlowLayoutInfoSW::TopFinalPos() const
447 {
448     return -(StartPosWithMargin() + delta_);
449 };
450 
BottomFinalPos(float viewHeight) const451 float WaterFlowLayoutInfoSW::BottomFinalPos(float viewHeight) const
452 {
453     return -(EndPosWithMargin() + delta_ + footerHeight_) + std::min(maxHeight_, viewHeight);
454 };
455 
IsMisaligned() const456 bool WaterFlowLayoutInfoSW::IsMisaligned() const
457 {
458     if (lanes_.empty()) {
459         return false;
460     }
461 
462     const int32_t startIdx = StartIndex();
463     int32_t startSeg = GetSegment(startIdx);
464     if (startSeg < 0) {
465         return false;
466     }
467     if (startSeg == 0) {
468         if (startIdx > 0) {
469             ++startSeg;
470         }
471     } else if (startIdx != segmentTails_[startSeg - 1] + 1) {
472         ++startSeg;
473     }
474 
475     const int32_t endSeg = GetSegment(EndIndex());
476     for (int32_t i = startSeg; i <= endSeg; ++i) {
477         if (SectionEmpty(lanes_[i])) {
478             continue;
479         }
480         const float startPos = SectionStartPos(lanes_[i]);
481         if (std::any_of(lanes_[i].begin(), lanes_[i].end(),
482                         [&startPos](const auto& lane) { return !NearEqual(lane.startPos, startPos); })) {
483             return true;
484         }
485         const int32_t sectionStart = (i == 0) ? 0 : segmentTails_[i - 1] + 1;
486         if (sectionStart != lanes_[i][0].items_.front().idx) {
487             return true;
488         }
489     }
490     return false;
491 }
492 
InitSegments(const std::vector<WaterFlowSections::Section> & sections,int32_t start)493 void WaterFlowLayoutInfoSW::InitSegments(const std::vector<WaterFlowSections::Section>& sections, int32_t start)
494 {
495     synced_ = false;
496     const size_t n = sections.size();
497     if (n == 0) {
498         return;
499     }
500 
501     InitSegmentTails(sections);
502 
503     InitLanes(sections, start);
504 
505     margins_.clear(); // to be initialized during layout
506 }
507 
PrepareSectionPos(int32_t idx,bool fillBack)508 void WaterFlowLayoutInfoSW::PrepareSectionPos(int32_t idx, bool fillBack)
509 {
510     int32_t prevSeg = GetSegment(fillBack ? idx - 1 : idx + 1);
511     int32_t curSeg = GetSegment(idx);
512     if (prevSeg == curSeg) {
513         return;
514     }
515     if (SectionEmpty(lanes_[prevSeg])) {
516         // previous section is invalid
517         return;
518     }
519     // prepare sections below
520     if (prevSeg < curSeg) {
521         for (int32_t i = prevSeg + 1; i <= curSeg; ++i) {
522             float pos = SectionEndPos(lanes_[i - 1]);
523             pos += axis_ == Axis::VERTICAL ? margins_[i - 1].bottom.value_or(0.0f) + margins_[i].top.value_or(0.0f)
524                                            : margins_[i - 1].right.value_or(0.0f) + margins_[i].left.value_or(0.0f);
525             std::for_each(lanes_[i].begin(), lanes_[i].end(), [pos](Lane& lane) {
526                 lane.startPos = lane.endPos = pos;
527                 lane.items_.clear();
528             });
529         }
530         return;
531     }
532     // prepare sections above
533     for (int32_t i = prevSeg - 1; i >= curSeg; --i) {
534         float pos = SectionStartPos(lanes_[i + 1]);
535         pos -= axis_ == Axis::VERTICAL ? margins_[i + 1].top.value_or(0.0f) + margins_[i].bottom.value_or(0.0f)
536                                        : margins_[i + 1].left.value_or(0.0f) + margins_[i].right.value_or(0.0f);
537         float diff = SectionEndPos(lanes_[i]) - pos;
538         if (NearZero(diff)) {
539             continue;
540         }
541         // use subtraction to keep the end positions staggered
542         std::for_each(lanes_[i].begin(), lanes_[i].end(), [diff](Lane& lane) {
543             lane.endPos -= diff;
544             lane.startPos = lane.endPos;
545             lane.items_.clear();
546         });
547     }
548 }
549 
InitSegmentTails(const std::vector<WaterFlowSections::Section> & sections)550 void WaterFlowLayoutInfoSW::InitSegmentTails(const std::vector<WaterFlowSections::Section>& sections)
551 {
552     const size_t n = sections.size();
553     segmentCache_.clear();
554     segmentTails_ = { sections[0].itemsCount - 1 };
555     for (size_t i = 1; i < n; ++i) {
556         segmentTails_.push_back(segmentTails_[i - 1] + sections[i].itemsCount);
557     }
558 }
559 
InitLanes(const std::vector<WaterFlowSections::Section> & sections,const int32_t start)560 void WaterFlowLayoutInfoSW::InitLanes(const std::vector<WaterFlowSections::Section>& sections, const int32_t start)
561 {
562     const size_t n = sections.size();
563 
564     const int32_t lastValidIdx = start > 0 ? segmentTails_[start - 1] : -1;
565     if (lastValidIdx < endIndex_) {
566         PrepareJump();
567     }
568 
569     lanes_.resize(n);
570     for (size_t i = static_cast<size_t>(start); i < n; ++i) {
571         lanes_[i] = std::vector<Lane>(sections[i].crossCount.value_or(1));
572     }
573 
574     for (auto it = idxToLane_.begin(); it != idxToLane_.end();) {
575         if (it->first > lastValidIdx) {
576             it = idxToLane_.erase(it);
577         } else {
578             ++it;
579         }
580     }
581 }
582 
InitSegmentsForKeepPositionMode(const std::vector<WaterFlowSections::Section> & sections,const std::vector<WaterFlowSections::Section> & prevSections,int32_t start)583 void WaterFlowLayoutInfoSW::InitSegmentsForKeepPositionMode(const std::vector<WaterFlowSections::Section>& sections,
584     const std::vector<WaterFlowSections::Section>& prevSections, int32_t start)
585 {
586     synced_ = false;
587     const size_t n = sections.size();
588     if (n == 0) {
589         ClearData();
590         return;
591     }
592 
593     WaterFlowSections::Section prevSection;
594     auto prevSegIdx = GetSegment(startIndex_);
595     if (prevSections.size() > static_cast<size_t>(prevSegIdx)) {
596         prevSection = prevSections[prevSegIdx];
597     }
598 
599     InitSegmentTails(sections);
600 
601     if (AdjustLanes(sections, prevSection, start, prevSegIdx)) {
602         margins_.clear();
603         return;
604     }
605 
606     InitLanes(sections, start);
607 
608     margins_.clear(); // to be initialized during layout
609 }
610 
AdjustLanes(const std::vector<WaterFlowSections::Section> & sections,const WaterFlowSections::Section & prevSection,int32_t start,int32_t prevSegIdx)611 bool WaterFlowLayoutInfoSW::AdjustLanes(const std::vector<WaterFlowSections::Section>& sections,
612     const WaterFlowSections::Section& prevSection, int32_t start, int32_t prevSegIdx)
613 {
614     if (newStartIndex_ < 0) {
615         return false;
616     }
617     const size_t n = sections.size();
618     const size_t curSegIdx = static_cast<size_t>(GetSegment(newStartIndex_));
619     const auto& curSection = sections[curSegIdx];
620     if (curSection.OnlyCountDiff(prevSection)) {
621         // move old lanes_[prevSegIdx,...] to Lanes_[curSegIdx,...]
622         if (n <= lanes_.size()) {
623             // means curSegIdx <= prevSegIdx
624             for (size_t i = 0; i < curSegIdx; ++i) {
625                 lanes_[i] = std::vector<Lane>(sections[i].crossCount.value_or(1));
626             }
627             for (size_t i = curSegIdx; i < n; ++i) {
628                 lanes_[i] = lanes_[prevSegIdx++];
629             }
630             lanes_.resize(n);
631         } else {
632             // 分组增加了,means curSegIdx > prevSegIdx
633             size_t oriSize = lanes_.size() - 1;
634             lanes_.resize(n);
635             for (size_t i = n - 1; i >= curSegIdx; i--) {
636                 lanes_[i] = lanes_[oriSize--];
637             }
638             for (size_t i = 0; i < curSegIdx; ++i) {
639                 lanes_[i] = std::vector<Lane>(sections[i].crossCount.value_or(1));
640             }
641         }
642         margins_.clear();
643         return true;
644     } else {
645         newStartIndex_ = INVALID_NEW_START_INDEX;
646     }
647     return false;
648 }
649 
PrepareNewStartIndex()650 bool WaterFlowLayoutInfoSW::PrepareNewStartIndex()
651 {
652     if (newStartIndex_ == EMPTY_NEW_START_INDEX) {
653         newStartIndex_ = StartIndex();
654     }
655     if (newStartIndex_ == Infinity<int32_t>()) {
656         newStartIndex_ = INVALID_NEW_START_INDEX;
657     }
658     if (newStartIndex_ == INVALID_NEW_START_INDEX) {
659         return false;
660     }
661     return true;
662 }
663 
NotifyDataChange(int32_t index,int32_t count)664 void WaterFlowLayoutInfoSW::NotifyDataChange(int32_t index, int32_t count)
665 {
666     if (!PrepareNewStartIndex()) {
667         return;
668     }
669     // 更新的index是否在newStartIndex_上方、是否会影响newStartIndex_
670     if ((count == 0 && newStartIndex_ <= index) || (count > 0 && newStartIndex_ < index) ||
671         (count < 0 && newStartIndex_ <= index - count - 1)) {
672         newStartIndex_ = INVALID_NEW_START_INDEX;
673         return;
674     }
675     newStartIndex_ += count;
676 }
677 
UpdateLanesIndex(int32_t updateIdx)678 void WaterFlowLayoutInfoSW::UpdateLanesIndex(int32_t updateIdx)
679 {
680     idxToLane_.clear();
681     const int32_t diff = newStartIndex_ - startIndex_;
682     for (auto& section : lanes_) {
683         for (size_t i = 0; i < section.size(); i++) {
684             for (auto& item : section[i].items_) {
685                 item.idx += diff;
686                 idxToLane_[item.idx] = i;
687             }
688         }
689     }
690     startIndex_ = StartIndex();
691     endIndex_ = EndIndex();
692 }
693 
BeginCacheUpdate()694 void WaterFlowLayoutInfoSW::BeginCacheUpdate()
695 {
696     savedLanes_ = std::make_unique<decltype(lanes_)>(lanes_);
697     synced_ = false;
698 }
699 
EndCacheUpdate()700 void WaterFlowLayoutInfoSW::EndCacheUpdate()
701 {
702     synced_ = true;
703     if (savedLanes_) {
704         lanes_ = std::move(*savedLanes_);
705         savedLanes_.reset();
706     }
707 }
708 
ClearData()709 void WaterFlowLayoutInfoSW::ClearData()
710 {
711     segmentCache_.clear();
712     segmentTails_.clear();
713     lanes_.clear();
714     idxToLane_.clear();
715     margins_.clear();
716     maxHeight_ = 0.0f;
717     synced_ = false;
718     startIndex_ = 0;
719     endIndex_ = -1;
720 }
721 
SyncOnEmptyLanes()722 void WaterFlowLayoutInfoSW::SyncOnEmptyLanes()
723 {
724     startPos_ = 0.0f;
725     endPos_ = 0.0f;
726     itemStart_ = true;
727     itemEnd_ = true;
728     offsetEnd_ = true;
729     maxHeight_ = footerHeight_;
730     newStartIndex_ = EMPTY_NEW_START_INDEX;
731     synced_ = true;
732 }
733 } // namespace OHOS::Ace::NG
734