1 /*
2  * Copyright (c) 2022-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 
16 #include "core/components_v2/water_flow/render_water_flow.h"
17 
18 #include <cinttypes>
19 #include <cstdint>
20 
21 #include "base/log/event_report.h"
22 #include "base/utils/time_util.h"
23 #include "base/utils/utils.h"
24 #include "core/animation/curve_animation.h"
25 #include "core/components/common/layout/templates_parser.h"
26 #include "core/components_v2/water_flow/water_flow_scroll_controller.h"
27 #include "core/event/ace_event_helper.h"
28 #include "core/pipeline/base/position_layout_utils.h"
29 
30 namespace OHOS::Ace::V2 {
31 namespace {
32 constexpr int64_t MICROSEC_TO_NANOSEC = 1000;
33 constexpr int64_t MILLISEC_TO_NANOSEC = 1000000;
34 constexpr int64_t TIME_THRESHOLD = 3 * MILLISEC_TO_NANOSEC; // milliseconds
35 constexpr int32_t ANIMATE_DURATION = 800;                   // ms
36 const RefPtr<CubicCurve> CURVE_SCROLL_TO_TOP = AceType::MakeRefPtr<CubicCurve>(0.0f, 0.3f, 0.2f, 1.0f);
37 constexpr int32_t DEFAULT_DEPTH = 10;
38 constexpr double MAX_CONSTRAINT_SCALE = 3.0;
39 constexpr double CENTER_POINT = 2.0;
40 constexpr int32_t CACHE_SIZE_SCALE = 3;
41 const std::string UNIT_AUTO = "auto";
42 } // namespace
43 
~RenderWaterFlow()44 RenderWaterFlow::~RenderWaterFlow()
45 {
46     if (scrollBarProxy_) {
47         scrollBarProxy_->UnRegisterScrollableNode(AceType::WeakClaim(this));
48     }
49 }
50 
Update(const RefPtr<Component> & component)51 void RenderWaterFlow::Update(const RefPtr<Component>& component)
52 {
53     component_ = AceType::DynamicCast<V2::WaterFlowComponent>(component);
54     if (!component_) {
55         LOGE("RenderWaterFlow update failed.");
56         EventReport::SendRenderException(RenderExcepType::RENDER_COMPONENT_ERR);
57         return;
58     }
59 
60     auto controller = component_->GetController();
61     if (controller) {
62         controller->SetScrollNode(WeakClaim(this));
63     }
64     if (!animator_) {
65         animator_ = CREATE_ANIMATOR(GetContext());
66     }
67 
68     updateFlag_ = true;
69     direction_ = component_->GetDirection();
70     userColGap_ = component_->GetColumnsGap();
71     userRowGap_ = component_->GetRowsGap();
72     colsArgs_ = component_->GetColumnsArgs();
73     rowsArgs_ = component_->GetRowsArgs();
74     scrollBarProxy_ = component_->GetScrollBarProxy();
75     InitScrollBar();
76     InitScrollBarProxy();
77     CreateScrollable();
78     MarkNeedLayout();
79 }
80 
PerformLayout()81 void RenderWaterFlow::PerformLayout()
82 {
83     if (RenderNode::GetChildren().empty() && !buildChildByIndex_) {
84         return;
85     }
86     InitialFlowProp();
87     // Adjust the view port out of items, caused by scrolling that may occur.
88     AdjustViewPort();
89     size_t itemIndex = GetNextSupplyedIndex();
90     double targetPos = GetTargetPos();
91     SupplyItems(itemIndex, targetPos);
92     // Adjust the view port out of items, caused by supply items that may occur.
93     // (view port at the tail and delete tail item continuously)
94     AdjustViewPort();
95     UpdateCacheItems();
96     LayoutItems(cacheItems_);
97     LayoutFooter();
98     // Check if reach the tail of waterFlow
99     reachTail_ = CheckReachTail();
100     // Check if reach the head of waterFlow
101     reachHead_ = CheckReachHead();
102     if (reachHead_) {
103         viewportStartPos_ = 0.0;
104     }
105 
106     if (!scrollBar_) {
107         return;
108     }
109     scrollBar_->SetScrollable(false);
110     if (scrollBar_ && (GetEstimatedHeight() > mainSize_)) {
111         scrollBar_->SetScrollable(true);
112     }
113 
114     if (!lastReachHead_ && reachHead_) {
115         waterflowEventFlags_[WaterFlowEvents::REACH_START] = true;
116     }
117     if (!lastReachTail_ && reachTail_) {
118         waterflowEventFlags_[WaterFlowEvents::REACH_END] = true;
119     }
120 
121     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
122         SetLayoutSize(GetLayoutParam().Constrain(Size(crossSize_, mainSize_)));
123     } else {
124         SetLayoutSize(GetLayoutParam().Constrain(Size(mainSize_, crossSize_)));
125     }
126     HandleScrollEvent();
127     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
128         lastOffset_ = viewportStartPos_;
129     } else {
130         lastOffset_ = estimateHeight_ + viewportStartPos_ - mainSize_;
131     }
132     lastReachHead_ = reachHead_;
133     lastReachTail_ = reachTail_;
134     MarkNeedPredictLayout();
135 }
136 
AddChildByIndex(size_t index,const RefPtr<RenderNode> & renderNode)137 void RenderWaterFlow::AddChildByIndex(size_t index, const RefPtr<RenderNode>& renderNode)
138 {
139     auto iter = items_.find(index);
140     if (iter != items_.end() && iter->second == nullptr) {
141         items_.erase(index);
142     }
143 
144     auto itor = items_.try_emplace(index, renderNode);
145     if (itor.second) {
146         AddChild(renderNode);
147     }
148 }
149 
CreateScrollable()150 void RenderWaterFlow::CreateScrollable()
151 {
152     scrollable_ = nullptr;
153     if (useScrollable_ == SCROLLABLE::NO_SCROLL) {
154         return;
155     }
156 
157     auto callback = [weak = AceType::WeakClaim(this)](double offset, int32_t source) {
158         auto flow = weak.Upgrade();
159         if (!flow) {
160             return false;
161         }
162         // Stop animator of scroll bar.
163         auto scrollBarProxy = flow->scrollBarProxy_;
164         if (scrollBarProxy) {
165             scrollBarProxy->StopScrollBarAnimator();
166         }
167         return flow->UpdateScrollPosition(offset, source);
168     };
169     scrollable_ = AceType::MakeRefPtr<Scrollable>(
170         callback, useScrollable_ == SCROLLABLE::HORIZONTAL ? Axis::HORIZONTAL : Axis::VERTICAL);
171     scrollable_->SetScrollEndCallback([weak = AceType::WeakClaim(this)]() {
172         auto flow = weak.Upgrade();
173         if (flow) {
174             auto proxy = flow->scrollBarProxy_;
175             if (proxy) {
176                 proxy->StartScrollBarAnimator();
177             }
178             auto scrollBar = flow->scrollBar_;
179             if (scrollBar) {
180                 scrollBar->HandleScrollBarEnd();
181             }
182         }
183     });
184     scrollable_->Initialize(context_);
185 }
186 
UpdateScrollPosition(double offset,int32_t source)187 bool RenderWaterFlow::UpdateScrollPosition(double offset, int32_t source)
188 {
189     if (source == SCROLL_FROM_START) {
190         return true;
191     }
192 
193     if (NearZero(offset)) {
194         return true;
195     }
196     if (scrollBar_ && scrollBar_->NeedScrollBar()) {
197         scrollBar_->SetActive(SCROLL_FROM_CHILD != source);
198     }
199 
200     if (reachHead_ && reachTail_) {
201         return false;
202     }
203 
204     if (offset > 0.0) {
205         // view port move up
206         if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
207             if (reachHead_) {
208                 return false;
209             }
210         } else {
211             if (reachTail_) {
212                 return false;
213             }
214         }
215     } else {
216         // view port move down
217         if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
218             if (reachTail_) {
219                 return false;
220             }
221         } else {
222             if (reachHead_) {
223                 return false;
224             }
225         }
226     }
227     viewportStartPos_ -= offset;
228     MarkNeedLayout(true);
229 
230     return true;
231 }
232 
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)233 void RenderWaterFlow::OnTouchTestHit(
234     const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
235 {
236     if (!GetVisible()) {
237         return;
238     }
239     if (!scrollable_ || !scrollable_->Available()) {
240         return;
241     }
242     if (scrollBar_ && scrollBar_->InBarRegion(globalPoint_ - coordinateOffset)) {
243         scrollBar_->AddScrollBarController(coordinateOffset, result);
244     } else {
245         scrollable_->SetCoordinateOffset(coordinateOffset);
246         scrollable_->SetDragTouchRestrict(touchRestrict);
247         result.emplace_back(scrollable_);
248     }
249     result.emplace_back(scrollable_);
250 }
251 
IsChildrenTouchEnable()252 bool RenderWaterFlow::IsChildrenTouchEnable()
253 {
254     bool ret = scrollable_->IsMotionStop();
255     return ret;
256 }
257 
SetChildPosition(const RefPtr<RenderNode> & child,size_t itemIndex)258 void RenderWaterFlow::SetChildPosition(const RefPtr<RenderNode>& child, size_t itemIndex)
259 {
260     Offset offset;
261     double mainPos = 0.0;
262     double crossPos = 0.0;
263     double mainSize = 0.0;
264     auto iter = flowMatrix_.find(itemIndex);
265     if (iter != flowMatrix_.end()) {
266         mainPos = iter->second.mainPos;
267         crossPos = iter->second.crossPos;
268         mainSize = iter->second.mainSize;
269     }
270     // need to support set position with Flex::Direction
271     switch (direction_) {
272         case FlexDirection::COLUMN:
273             // offset.y : item mainPos - viewPort offset
274             offset = Offset(crossPos, mainPos - viewportStartPos_);
275             break;
276         case FlexDirection::COLUMN_REVERSE:
277             // offset.y : [viewPort mainSize - (item mainSize + item mainPos)] - viewPort offse
278             offset = Offset(crossPos, (mainSize_ - (mainPos + mainSize)) - viewportStartPos_);
279             break;
280         case FlexDirection::ROW:
281             // offset.x : item mainPos - viewPort offset
282             offset = Offset(mainPos - viewportStartPos_, crossPos);
283             break;
284         case FlexDirection::ROW_REVERSE:
285             // offset.x : [viewPort mainSize - (item mainSize + item mainPos)] - viewPort offse
286             offset = Offset((mainSize_ - (mainPos + mainSize)) - viewportStartPos_, crossPos);
287             break;
288         default:
289             return;
290     }
291     child->SetPosition(offset);
292     child->SetVisible(true);
293 }
294 
GetFlowSize()295 void RenderWaterFlow::GetFlowSize()
296 {
297     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
298         mainSize_ = GetLayoutParam().GetMaxSize().Height();
299         crossSize_ = GetLayoutParam().GetMaxSize().Width();
300         if (NearEqual(mainSize_, Size::INFINITE_SIZE)) {
301             mainSize_ = viewPort_.Height();
302         }
303         if (NearEqual(crossSize_, Size::INFINITE_SIZE)) {
304             crossSize_ = viewPort_.Width();
305         }
306     } else {
307         crossSize_ = GetLayoutParam().GetMaxSize().Height();
308         mainSize_ = GetLayoutParam().GetMaxSize().Width();
309         if (NearEqual(crossSize_, Size::INFINITE_SIZE)) {
310             crossSize_ = viewPort_.Height();
311         }
312         if (NearEqual(mainSize_, Size::INFINITE_SIZE)) {
313             mainSize_ = viewPort_.Width();
314         }
315     }
316     cacheSize_ = mainSize_ * CACHE_SIZE_SCALE;
317 }
318 
CallGap()319 void RenderWaterFlow::CallGap()
320 {
321     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
322         mainGap_ = NormalizePercentToPx(userRowGap_, true);
323         crossGap_ = NormalizePercentToPx(userColGap_, false);
324     } else {
325         crossGap_ = NormalizePercentToPx(userRowGap_, true);
326         mainGap_ = NormalizePercentToPx(userColGap_, false);
327     }
328     if (GreatOrEqual(crossGap_, crossSize_)) {
329         crossGap_ = 0.0;
330     }
331 }
332 
CallItemConstraintSize()333 void RenderWaterFlow::CallItemConstraintSize()
334 {
335     ItemConstraintSize size;
336     auto pipelineContext = GetContext().Upgrade();
337     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
338         size.maxCrossSize = std::max(NormalizePercentToPx(component_->GetMaxWidth(), false),
339             NormalizePercentToPx(component_->GetMinWidth(), false));
340         size.minCrossSize = std::min(NormalizePercentToPx(component_->GetMaxWidth(), false),
341             NormalizePercentToPx(component_->GetMinWidth(), false));
342         size.maxMainSize = std::max(NormalizePercentToPx(component_->GetMaxHeight(), true),
343             NormalizePercentToPx(component_->GetMinHeight(), true));
344         size.minMainSize = std::min(NormalizePercentToPx(component_->GetMaxHeight(), true),
345             NormalizePercentToPx(component_->GetMinHeight(), true));
346         mainMaxConstraintSize_ = MAX_CONSTRAINT_SCALE * pipelineContext->GetRootHeight();
347     } else {
348         size.maxCrossSize = std::max(NormalizePercentToPx(component_->GetMaxHeight(), true),
349             NormalizePercentToPx(component_->GetMinHeight(), true));
350         size.minCrossSize = std::min(NormalizePercentToPx(component_->GetMaxHeight(), true),
351             NormalizePercentToPx(component_->GetMinHeight(), true));
352         size.maxMainSize = std::max(NormalizePercentToPx(component_->GetMaxWidth(), false),
353             NormalizePercentToPx(component_->GetMinWidth(), false));
354         size.minMainSize = std::min(NormalizePercentToPx(component_->GetMaxWidth(), false),
355             NormalizePercentToPx(component_->GetMinWidth(), false));
356         mainMaxConstraintSize_ = MAX_CONSTRAINT_SCALE * pipelineContext->GetRootWidth();
357     }
358 
359     // exchange and make sure the max is larger then the min.
360     itemConstraintSize_.maxCrossSize = std::max(size.maxCrossSize, size.minCrossSize);
361     itemConstraintSize_.minCrossSize = std::min(size.maxCrossSize, size.minCrossSize);
362     itemConstraintSize_.maxMainSize = std::max(size.maxMainSize, size.minMainSize);
363     itemConstraintSize_.minMainSize = std::min(size.maxMainSize, size.minMainSize);
364 
365     // constraint with 3times of root.
366     if (GreatOrEqual(itemConstraintSize_.maxMainSize, mainMaxConstraintSize_)) {
367         itemConstraintSize_.maxMainSize = mainMaxConstraintSize_;
368     }
369     if (GreatOrEqual(itemConstraintSize_.minMainSize, mainMaxConstraintSize_)) {
370         itemConstraintSize_.minMainSize = 0.0;
371     }
372     // constraint with 0, and set with default.
373     if (LessOrEqual(itemConstraintSize_.maxMainSize, 0.0)) {
374         itemConstraintSize_.maxMainSize = mainMaxConstraintSize_;
375     }
376     if (LessOrEqual(itemConstraintSize_.minMainSize, 0.0)) {
377         itemConstraintSize_.minMainSize = 0.0;
378     }
379 }
380 
InitialFlowProp()381 void RenderWaterFlow::InitialFlowProp()
382 {
383     // Not first time layout after update, no need to initialize.
384     if (!updateFlag_) {
385         return;
386     }
387 
388     // Not valid layout size, no need to initialize.
389     auto maxLayoutSize = GetLayoutParam().GetMaxSize();
390     if (!maxLayoutSize.IsValid() || maxLayoutSize.IsEmpty()) {
391         return;
392     }
393 
394     GetFlowSize();
395     CallGap();
396     CallItemConstraintSize();
397     crossSideSize_.clear();
398     TemplatesParser parser;
399     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
400         crossSideSize_ = parser.ParseArgs(WeakClaim(this), PreParseArgs(colsArgs_), crossSize_, crossGap_);
401     } else {
402         crossSideSize_ = parser.ParseArgs(WeakClaim(this), PreParseArgs(rowsArgs_), crossSize_, crossGap_);
403     }
404     if (crossSideSize_.empty()) {
405         crossSideSize_.push_back(crossSize_);
406     }
407     // Initialize the crossCount, default is 1
408     crossCount_ = crossSideSize_.size();
409     InitMainSideEndPos();
410     viewportStartPos_ = 0.0;
411     RemoveAllChild();
412     ClearLayout(0, true);
413     if (footer_) {
414         RemoveChild(footer_);
415         footer_ = nullptr;
416     }
417     RequestWaterFlowFooter();
418     updateFlag_ = false;
419 }
420 
MakeInnerLayoutParam(size_t itemIndex)421 LayoutParam RenderWaterFlow::MakeInnerLayoutParam(size_t itemIndex)
422 {
423     LayoutParam innerLayout;
424     double crossSize = 0.0;
425     size_t crossIndex = 0;
426     auto iter = flowMatrix_.find(itemIndex);
427     if (iter != flowMatrix_.end()) {
428         crossSize = iter->second.crossSize;
429     } else {
430         crossIndex = GetLastMainBlankCross();
431         if (crossIndex < crossSideSize_.size()) {
432             crossSize = crossSideSize_[crossIndex];
433         }
434     }
435     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
436         innerLayout.SetMinSize(Size(crossSize, 0));
437         innerLayout.SetMaxSize(Size(crossSize, Size::INFINITE_SIZE));
438     } else {
439         innerLayout.SetMinSize(Size(0, crossSize));
440         innerLayout.SetMaxSize(Size(Size::INFINITE_SIZE, crossSize));
441     }
442     return innerLayout;
443 }
444 
SupplyItems(size_t startIndex,double targetPos)445 void RenderWaterFlow::SupplyItems(size_t startIndex, double targetPos)
446 {
447     size_t itemCrossIndex = 0;
448     FlowStyle itemFlowStyle;
449     while (LessNotEqual(GetLastMainBlankPos().GetY(), targetPos)) {
450         if (items_.find(startIndex) == items_.end()) {
451             if (!buildChildByIndex_(startIndex)) {
452                 break;
453             }
454         }
455 
456         auto flowItem = GetFlowItemByChild(items_[startIndex]);
457         if (flowItem == nullptr) {
458             startIndex++;
459             continue;
460         }
461         flowItem->SetNeedRender(false);
462         flowItem->Layout(MakeInnerLayoutParam(startIndex));
463         flowItem->SetVisible(false);
464         itemCrossIndex = GetLastMainBlankCross();
465         itemFlowStyle.mainPos = GetLastMainBlankPos().GetY();
466         itemFlowStyle.crossPos = GetLastMainBlankPos().GetX();
467         itemFlowStyle.mainSize = GetMainSize(flowItem);
468         itemFlowStyle = ConstraintItemSize(itemFlowStyle, itemCrossIndex);
469         flowMatrix_.emplace(std::make_pair(startIndex, itemFlowStyle));
470         if (itemsByCrossIndex_.size() > itemCrossIndex) {
471             itemsByCrossIndex_.at(itemCrossIndex).emplace_back(startIndex);
472         }
473         if (itemCrossIndex < mainSideEndPos_.size()) {
474             mainSideEndPos_[itemCrossIndex] +=
475                 Positive(itemFlowStyle.mainSize) ? (itemFlowStyle.mainSize + mainGap_) : itemFlowStyle.mainSize;
476         }
477 
478         // reach the valid target index
479         if (targetIndex_ >= 0 && static_cast<size_t>(targetIndex_) == startIndex) {
480             targetPos = itemFlowStyle.mainPos + mainSize_;
481         }
482         startIndex++;
483     }
484     targetIndex_ = -1;
485 }
486 
LayoutItems(std::set<size_t> & items)487 void RenderWaterFlow::LayoutItems(std::set<size_t>& items)
488 {
489     LayoutParam innerLayoutParam;
490     for (const auto& itemIndex : items) {
491         if (items_.find(itemIndex) == items_.end()) {
492             if (!buildChildByIndex_(itemIndex)) {
493                 continue;
494             }
495         }
496         innerLayoutParam = MakeInnerLayoutParam(itemIndex);
497         auto flowItem = GetFlowItemByChild(items_[itemIndex]);
498         if (flowItem == nullptr) {
499             continue;
500         }
501         flowItem->Layout(innerLayoutParam);
502         SetChildPosition(flowItem, itemIndex);
503     }
504 }
505 
GetFooterSize(double mainSize,double crossSize)506 void RenderWaterFlow::GetFooterSize(double mainSize, double crossSize)
507 {
508     if (!footer_ || NonPositive(mainSize) || NonPositive(crossSize)) {
509         LOGE("footer is null");
510         return;
511     }
512     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
513         footerMaxSize_.SetWidth(std::min(crossSize, crossSize_));
514         footerMaxSize_.SetHeight(std::min(mainSize, mainSize_));
515     } else {
516         footerMaxSize_.SetWidth(std::min(mainSize, mainSize_));
517         footerMaxSize_.SetHeight(std::min(crossSize, crossSize_));
518     }
519 }
520 
LayoutFooter()521 void RenderWaterFlow::LayoutFooter()
522 {
523     if (!footer_) {
524         LOGE("footer is null");
525         return;
526     }
527     footer_->SetVisible(false);
528     LayoutParam innerLayoutParam;
529     innerLayoutParam.SetMaxSize(footerMaxSize_);
530     footer_->Layout(innerLayoutParam);
531     SetFooterPosition();
532 }
533 
SetFooterPosition()534 void RenderWaterFlow::SetFooterPosition()
535 {
536     if (!footer_) {
537         return;
538     }
539     Offset offset;
540     auto width = footerMaxSize_.Width();
541     auto height = footerMaxSize_.Height();
542     auto footerCurrentPos = GetTailPos();
543     switch (direction_) {
544         case FlexDirection::COLUMN:
545             offset = Offset((crossSize_ - width) / CENTER_POINT, footerCurrentPos - viewportStartPos_);
546             if (GreatOrEqual(offset.GetY(), mainSize_)) {
547                 return;
548             }
549             break;
550         case FlexDirection::COLUMN_REVERSE:
551             offset = Offset((crossSize_ - width) / CENTER_POINT, footerCurrentPos - viewportStartPos_ - height);
552             if (LessOrEqual(offset.GetY(), -height)) {
553                 return;
554             }
555             break;
556         case FlexDirection::ROW:
557             offset = Offset(footerCurrentPos - viewportStartPos_, (crossSize_ - height) / CENTER_POINT);
558             if (GreatOrEqual(offset.GetX(), mainSize_)) {
559                 return;
560             }
561             break;
562         case FlexDirection::ROW_REVERSE:
563             offset = Offset(footerCurrentPos - viewportStartPos_ - width, (crossSize_ - height) / CENTER_POINT);
564             if (LessOrEqual(offset.GetX(), -width)) {
565                 return;
566             }
567             break;
568         default:
569             return;
570     }
571     footer_->SetPosition(offset);
572     footer_->SetVisible(true);
573 }
574 
UpdateCacheItems()575 void RenderWaterFlow::UpdateCacheItems()
576 {
577     cacheItems_.clear();
578     double itemMainMinPos = 0.0;
579     double itemMainMaxPos = 0.0;
580     double viewportEndPos = viewportStartPos_ + mainSize_ + cacheSize_;
581     for (const auto& item : flowMatrix_) {
582         if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
583             itemMainMinPos = item.second.mainPos;
584             itemMainMaxPos = item.second.mainPos + item.second.mainSize;
585         } else {
586             itemMainMinPos = (mainSize_ - (item.second.mainPos + item.second.mainSize));
587             itemMainMaxPos = (mainSize_ - (item.second.mainPos + item.second.mainSize)) + item.second.mainSize;
588         }
589         if (!(GreatNotEqual(itemMainMinPos, viewportEndPos) ||
590                 LessNotEqual(itemMainMaxPos, viewportStartPos_ - cacheSize_))) {
591             cacheItems_.emplace(item.first);
592         }
593     }
594 }
595 
GetShowItems()596 std::set<size_t> RenderWaterFlow::GetShowItems()
597 {
598     std::set<size_t> showItems;
599     showItems.clear();
600     double itemMainMinPos = 0.0;
601     double itemMainMaxPos = 0.0;
602     double viewportEndPos = viewportStartPos_ + mainSize_;
603     for (const auto& item : cacheItems_) {
604         auto iter = flowMatrix_.find(item);
605         if (iter != flowMatrix_.end()) {
606             if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
607                 itemMainMinPos = iter->second.mainPos;
608                 itemMainMaxPos = iter->second.mainPos + iter->second.mainSize;
609             } else {
610                 itemMainMinPos = (mainSize_ - (iter->second.mainPos + iter->second.mainSize));
611                 itemMainMaxPos = (mainSize_ - (iter->second.mainPos + iter->second.mainSize)) + iter->second.mainSize;
612             }
613             if (!(GreatNotEqual(itemMainMinPos, viewportEndPos) || LessNotEqual(itemMainMaxPos, viewportStartPos_))) {
614                 showItems.emplace(item);
615             }
616         }
617     }
618     return showItems;
619 }
620 
DealCache()621 void RenderWaterFlow::DealCache()
622 {
623     std::set<size_t> deleteItem;
624     double itemMainMinPos = 0.0;
625     double itemMainMaxPos = 0.0;
626     double cacheStartPos = viewportStartPos_ - cacheSize_;
627     double cacheEndPos = viewportStartPos_ + mainSize_ + cacheSize_;
628     for (const auto& item : items_) {
629         auto iter = flowMatrix_.find(item.first);
630         if (iter != flowMatrix_.end()) {
631             if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
632                 itemMainMinPos = iter->second.mainPos;
633                 itemMainMaxPos = iter->second.mainPos + iter->second.mainSize;
634             } else {
635                 itemMainMinPos = (mainSize_ - (iter->second.mainPos + iter->second.mainSize));
636                 itemMainMaxPos = (mainSize_ - (iter->second.mainPos + iter->second.mainSize)) + iter->second.mainSize;
637             }
638             if (GreatNotEqual(itemMainMinPos, cacheEndPos) || LessNotEqual(itemMainMaxPos, cacheStartPos)) {
639                 deleteItem.emplace(item.first);
640             }
641         }
642     }
643 
644     for (const auto& item : deleteItem) {
645         DeleteItems(item);
646     }
647 }
648 
DeleteItems(size_t index)649 void RenderWaterFlow::DeleteItems(size_t index)
650 {
651     if (!deleteChildByIndex_) {
652         return;
653     }
654 
655     auto iter = items_.find(index);
656     if (iter == items_.end()) {
657         return;
658     }
659     deleteChildByIndex_(index);
660     RemoveChildByIndex(index);
661 }
662 
ClearLayout(size_t index,bool clearAll)663 void RenderWaterFlow::ClearLayout(size_t index, bool clearAll)
664 {
665     cacheItems_.clear();
666     reachHead_ = false;
667     reachTail_ = false;
668     lastOffset_ = 0.0;
669     ClearFlowMatrix(index, clearAll);
670     ClearItemsByCrossIndex(index, clearAll);
671     UpdateMainSideEndPos();
672 }
673 
ClearItems(size_t index)674 void RenderWaterFlow::ClearItems(size_t index)
675 {
676     for (auto item = items_.begin(); item != items_.end();) {
677         if (index <= item->first) {
678             item->second->SetVisible(false);
679             item = items_.erase(item);
680         } else {
681             item++;
682         }
683     }
684 }
685 
OnDataSourceUpdated(size_t index)686 void RenderWaterFlow::OnDataSourceUpdated(size_t index)
687 {
688     if (items_.empty() && updateFlag_) {
689         return;
690     }
691 
692     if (!getTotalCount_) {
693         return;
694     }
695 
696     totalCount_ = getTotalCount_();
697     ClearItems(index);
698     ClearLayout(index);
699     MarkNeedLayout();
700 }
701 
GetEstimatedHeight()702 double RenderWaterFlow::GetEstimatedHeight()
703 {
704     estimateHeight_ =
705         std::min(std::max(estimateHeight_, (std::abs(viewportStartPos_) + mainSize_)), GetLastMainPos().GetY());
706     return estimateHeight_;
707 }
708 
InitScrollBar()709 void RenderWaterFlow::InitScrollBar()
710 {
711     if (!component_) {
712         LOGE("RenderWaterFlow update failed.");
713         EventReport::SendRenderException(RenderExcepType::RENDER_COMPONENT_ERR);
714         return;
715     }
716 
717     if (scrollBar_) {
718         scrollBar_->SetDisplayMode(component_->GetScrollBarDisplayMode());
719         scrollBar_->Reset();
720         return;
721     }
722 
723     const RefPtr<ScrollBarTheme> theme = GetTheme<ScrollBarTheme>();
724     if (!theme) {
725         return;
726     }
727 
728     RefPtr<WaterFlowScrollController> controller = AceType::MakeRefPtr<WaterFlowScrollController>();
729     scrollBar_ = AceType::MakeRefPtr<ScrollBar>(component_->GetScrollBarDisplayMode(), theme->GetShapeMode());
730     scrollBar_->SetScrollBarController(controller);
731 
732     // set the scroll bar style
733     scrollBar_->SetMinHeight(theme->GetMinHeight());
734     scrollBar_->SetMinDynamicHeight(theme->GetMinDynamicHeight());
735     scrollBar_->SetForegroundColor(theme->GetForegroundColor());
736     scrollBar_->SetBackgroundColor(theme->GetBackgroundColor());
737     scrollBar_->SetPadding(theme->GetPadding());
738     scrollBar_->SetInactiveWidth(theme->GetNormalWidth());
739     scrollBar_->SetNormalWidth(theme->GetNormalWidth());
740     scrollBar_->SetActiveWidth(theme->GetActiveWidth());
741     scrollBar_->SetTouchWidth(theme->GetTouchWidth());
742     switch (direction_) {
743         case FlexDirection::COLUMN:
744         case FlexDirection::COLUMN_REVERSE:
745             useScrollable_ = SCROLLABLE::VERTICAL;
746             scrollBar_->SetPositionMode(PositionMode::RIGHT);
747             break;
748         case FlexDirection::ROW:
749         case FlexDirection::ROW_REVERSE:
750             useScrollable_ = SCROLLABLE::HORIZONTAL;
751             scrollBar_->SetPositionMode(PositionMode::BOTTOM);
752             break;
753         default:
754             break;
755     }
756     scrollBar_->InitScrollBar(AceType::WeakClaim(this), GetContext());
757     SetScrollBarCallback();
758 }
759 
InitScrollBarProxy()760 void RenderWaterFlow::InitScrollBarProxy()
761 {
762     if (!scrollBarProxy_) {
763         return;
764     }
765     auto&& scrollCallback = [weakScroll = AceType::WeakClaim(this)](double value, int32_t source) {
766         auto flow = weakScroll.Upgrade();
767         if (!flow) {
768             return false;
769         }
770         return flow->UpdateScrollPosition(value, source);
771     };
772     scrollBarProxy_->UnRegisterScrollableNode(AceType::WeakClaim(this));
773     scrollBarProxy_->RegisterScrollableNode({ AceType::WeakClaim(this), scrollCallback });
774 }
775 
SetScrollBarCallback()776 void RenderWaterFlow::SetScrollBarCallback()
777 {
778     if (!scrollBar_ || !scrollBar_->NeedScrollBar()) {
779         return;
780     }
781     auto&& barEndCallback = [weakFlow = AceType::WeakClaim(this)](int32_t value) {
782         auto flow = weakFlow.Upgrade();
783         if (!flow) {
784             return;
785         }
786         flow->scrollBarOpacity_ = value;
787         flow->MarkNeedLayout(true);
788     };
789     auto&& scrollEndCallback = [weakFlow = AceType::WeakClaim(this)]() {
790         auto flow = weakFlow.Upgrade();
791         if (!flow) {
792             return;
793         }
794     };
795     auto&& scrollCallback = [weakScroll = AceType::WeakClaim(this)](double value, int32_t source) {
796         auto flow = weakScroll.Upgrade();
797         if (!flow) {
798             return false;
799         }
800         return flow->UpdateScrollPosition(value, source);
801     };
802     scrollBar_->SetCallBack(scrollCallback, barEndCallback, scrollEndCallback);
803 }
804 
ScrollToIndex(int32_t index)805 void RenderWaterFlow::ScrollToIndex(int32_t index)
806 {
807     if (useScrollable_ == SCROLLABLE::NO_SCROLL || index < 0) {
808         LOGW("Not supported.");
809         return;
810     }
811 
812     auto context = context_.Upgrade();
813     if (!context) {
814         LOGE("context is null");
815         return;
816     }
817 
818     auto iter = flowMatrix_.find(index);
819     if (iter == flowMatrix_.end()) {
820         targetIndex_ = index;
821         size_t itemIndex = GetNextSupplyedIndex();
822         SupplyItems(itemIndex, GetTargetPos());
823         iter = flowMatrix_.find(index);
824         if (iter == flowMatrix_.end()) {
825             LOGE("scrollToIndex[item:%{public}d] failed.", index);
826             return;
827         }
828     }
829 
830     double scrollToPos = 0.0;
831     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
832         scrollToPos = iter->second.mainPos;
833     } else {
834         scrollToPos = (mainSize_ - (iter->second.mainPos + iter->second.mainSize)) + iter->second.mainSize - mainSize_;
835     }
836     AnimateToPos(scrollToPos, ANIMATE_DURATION, CURVE_SCROLL_TO_TOP);
837 }
838 
DoJump(double position,int32_t source)839 void RenderWaterFlow::DoJump(double position, int32_t source)
840 {
841     UpdateScrollPosition(viewportStartPos_ - position, source);
842 }
843 
OnPredictLayout(int64_t deadline)844 void RenderWaterFlow::OnPredictLayout(int64_t deadline)
845 {
846     if (!NeedPredictLayout()) {
847         return;
848     }
849     auto context = context_.Upgrade();
850     if (!context) {
851         return;
852     }
853     if (!context->IsTransitionStop()) {
854         MarkNeedPredictLayout();
855         return;
856     }
857 
858     auto startTime = GetSysTimestamp(); // unit: ns
859     DealCache();
860     if (GetSysTimestamp() - startTime + TIME_THRESHOLD > deadline * MICROSEC_TO_NANOSEC) {
861         MarkNeedPredictLayout();
862         return;
863     }
864 
865     // just need supply forward the main side, backwards already supply and keep in flowMatrix.
866     size_t itemIndex = GetNextSupplyedIndex();
867     SupplyItems(itemIndex, GetCacheTargetPos());
868     UpdateCacheItems();
869     LayoutItems(cacheItems_);
870     dVPStartPosBackup_ = viewportStartPos_;
871     totalCountBack_ = getTotalCount_();
872     MarkNeedPredictLayout();
873 }
874 
IsAxisScrollable(AxisDirection direction)875 bool RenderWaterFlow::IsAxisScrollable(AxisDirection direction)
876 {
877     bool ret = true;
878     switch (direction_) {
879         case FlexDirection::COLUMN:
880             if ((direction == AxisDirection::UP && reachHead_) ||
881                 (direction == AxisDirection::DOWN && reachTail_)) {
882                 ret = false;
883             }
884             break;
885         case FlexDirection::ROW:
886             if ((direction == AxisDirection::LEFT && reachHead_) ||
887                 (direction == AxisDirection::RIGHT && reachTail_)) {
888                 ret = false;
889             }
890             break;
891         case FlexDirection::COLUMN_REVERSE:
892             if ((direction == AxisDirection::DOWN && reachHead_) ||
893                 (direction == AxisDirection::UP && reachTail_)) {
894                 ret = false;
895             }
896             break;
897         case FlexDirection::ROW_REVERSE:
898             if ((direction == AxisDirection::RIGHT && reachHead_) ||
899                 (direction == AxisDirection::LEFT && reachTail_)) {
900                 ret = false;
901             }
902             break;
903         default:
904             ret = false;
905             break;
906     }
907     if (direction == AxisDirection::NONE) {
908         ret = false;
909     }
910     return ret;
911 }
912 
HandleAxisEvent(const AxisEvent & event)913 void RenderWaterFlow::HandleAxisEvent(const AxisEvent& event)
914 {
915     double degree = 0.0;
916     if (!NearZero(event.horizontalAxis)) {
917         degree = event.horizontalAxis;
918     } else if (!NearZero(event.verticalAxis)) {
919         degree = event.verticalAxis;
920     }
921     double offset =
922         PipelineBase::Vp2PxWithCurrentDensity(DP_PER_LINE_DESKTOP * LINE_NUMBER_DESKTOP * degree / MOUSE_WHEEL_DEGREES);
923     UpdateScrollPosition(-offset, SCROLL_FROM_ROTATE);
924 }
925 
CheckAxisNode()926 WeakPtr<RenderNode> RenderWaterFlow::CheckAxisNode()
927 {
928     return AceType::WeakClaim<RenderNode>(this);
929 }
930 
OnChildAdded(const RefPtr<RenderNode> & renderNode)931 void RenderWaterFlow::OnChildAdded(const RefPtr<RenderNode>& renderNode)
932 {
933     Offset offset;
934     switch (direction_) {
935         case FlexDirection::COLUMN:
936             offset.SetX(crossSize_ / CENTER_POINT);
937             offset.SetY(mainSize_ + cacheSize_);
938             break;
939         case FlexDirection::ROW:
940             offset.SetX(mainSize_ + cacheSize_);
941             offset.SetY(crossSize_ / CENTER_POINT);
942             break;
943         case FlexDirection::COLUMN_REVERSE:
944             offset.SetX(crossSize_ / CENTER_POINT);
945             offset.SetY(0.0 - cacheSize_);
946             break;
947         case FlexDirection::ROW_REVERSE:
948             offset.SetX(0.0 - cacheSize_);
949             offset.SetY(crossSize_ / CENTER_POINT);
950             break;
951         default:
952             break;
953     }
954     // set default position for animateTo(covering animation)
955     renderNode->SetPosition(offset);
956     RenderNode::OnChildAdded(renderNode);
957 }
958 
IsUseOnly()959 bool RenderWaterFlow::IsUseOnly()
960 {
961     return true;
962 }
963 
GetFlowItemByChild(const RefPtr<RenderNode> & child)964 RefPtr<RenderWaterFlowItem> RenderWaterFlow::GetFlowItemByChild(const RefPtr<RenderNode>& child)
965 {
966     int32_t depth = DEFAULT_DEPTH;
967     auto item = child;
968     auto flowItem = AceType::DynamicCast<RenderWaterFlowItem>(item);
969     while (!flowItem && depth > 0) {
970         if (!item || item->GetChildren().empty()) {
971             return nullptr;
972         }
973         item = item->GetChildren().front();
974         flowItem = AceType::DynamicCast<RenderWaterFlowItem>(item);
975         --depth;
976     }
977     return flowItem;
978 }
979 
OutputMatrix()980 void RenderWaterFlow::OutputMatrix() {}
981 
RequestWaterFlowFooter()982 void RenderWaterFlow::RequestWaterFlowFooter()
983 {
984     auto generator = itemGenerator_.Upgrade();
985     footer_ = generator ? generator->RequestWaterFlowFooter() : RefPtr<RenderNode>();
986     if (footer_) {
987         AddChild(footer_);
988         footer_->Layout(GetLayoutParam());
989         footer_->SetVisible(false);
990         auto mainSize = GetMainSize(footer_);
991         auto crossSize = GetCrossSize(footer_);
992         if (NonPositive(mainSize) || NonPositive(crossSize)) {
993             RemoveChild(footer_);
994             footer_ = nullptr;
995         } else {
996             GetFooterSize(mainSize, crossSize);
997         }
998     }
999 }
1000 
GetLastSupplyedIndex()1001 size_t RenderWaterFlow::GetLastSupplyedIndex()
1002 {
1003     return flowMatrix_.empty() ? 0 : (--flowMatrix_.end())->first;
1004 }
1005 
GetNextSupplyedIndex()1006 size_t RenderWaterFlow::GetNextSupplyedIndex()
1007 {
1008     size_t index = 0;
1009     if (!flowMatrix_.empty()) {
1010         index = (--flowMatrix_.end())->first;
1011         index++;
1012     }
1013     return index;
1014 }
1015 
GetLastSupplyedMainSize()1016 double RenderWaterFlow::GetLastSupplyedMainSize()
1017 {
1018     double result = 0.0;
1019     if (flowMatrix_.empty()) {
1020         return result;
1021     }
1022     size_t index = GetLastSupplyedIndex();
1023     auto iter = flowMatrix_.find(index);
1024     if (iter != flowMatrix_.end()) {
1025         result = iter->second.mainSize + iter->second.mainPos;
1026     }
1027     return result;
1028 }
1029 
GetLastMainBlankPos()1030 Offset RenderWaterFlow::GetLastMainBlankPos()
1031 {
1032     Offset pos;
1033     size_t crossIndex = 0;
1034     if (mainSideEndPos_.empty() || mainSideEndPos_.size() != crossSideSize_.size()) {
1035         return pos;
1036     }
1037     pos.SetY(mainSideEndPos_.at(0));
1038     for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1039         if (LessNotEqual(mainSideEndPos_.at(i), pos.GetY())) {
1040             pos.SetY(mainSideEndPos_.at(i));
1041             crossIndex = i;
1042         }
1043     }
1044     pos.SetX(GetCrossEndPos(crossIndex));
1045     return pos;
1046 }
1047 
GetLastMainBlankCross()1048 size_t RenderWaterFlow::GetLastMainBlankCross()
1049 {
1050     double pos = 0.0;
1051     size_t crossIndex = 0;
1052     if (mainSideEndPos_.empty()) {
1053         return crossIndex;
1054     }
1055     pos = mainSideEndPos_.at(0);
1056     for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1057         if (LessNotEqual(mainSideEndPos_.at(i), pos)) {
1058             pos = mainSideEndPos_.at(i);
1059             crossIndex = i;
1060         }
1061     }
1062     return crossIndex;
1063 }
1064 
GetLastMainPos()1065 Offset RenderWaterFlow::GetLastMainPos()
1066 {
1067     Offset pos(0.0, 0.0);
1068     size_t crossIndex = 0;
1069     if (mainSideEndPos_.empty() || mainSideEndPos_.size() != crossSideSize_.size()) {
1070         return pos;
1071     }
1072     double tempMainSidePos = mainSideEndPos_.at(0);
1073     for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1074         if (GreatNotEqual(mainSideEndPos_.at(i), tempMainSidePos)) {
1075             tempMainSidePos = mainSideEndPos_.at(i);
1076             crossIndex = i;
1077         }
1078     }
1079     pos.SetY(mainSideEndPos_.at(crossIndex) - mainGap_);
1080     pos.SetX(GetCrossEndPos(crossIndex));
1081     return pos;
1082 }
1083 
GetCrossEndPos(size_t crossIndex)1084 double RenderWaterFlow::GetCrossEndPos(size_t crossIndex)
1085 {
1086     double pos = 0.0;
1087     if (crossIndex >= crossSideSize_.size()) {
1088         return pos;
1089     }
1090     for (size_t i = 0; i < crossIndex; i++) {
1091         pos += crossSideSize_[i];
1092     }
1093     if (crossIndex > 0) {
1094         pos += crossIndex * crossGap_;
1095     }
1096 
1097     return pos;
1098 }
1099 
GetMainSize(const RefPtr<RenderNode> & item) const1100 double RenderWaterFlow::GetMainSize(const RefPtr<RenderNode>& item) const
1101 {
1102     double size = 0.0;
1103     if (!item) {
1104         return size;
1105     }
1106     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
1107         size = item->GetLayoutSize().Height();
1108     } else {
1109         size = item->GetLayoutSize().Width();
1110     }
1111 
1112     return size;
1113 }
1114 
GetCrossSize(const RefPtr<RenderNode> & item) const1115 double RenderWaterFlow::GetCrossSize(const RefPtr<RenderNode>& item) const
1116 {
1117     double size = 0.0;
1118     if (!item) {
1119         return size;
1120     }
1121 
1122     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
1123         size = item->GetLayoutSize().Width();
1124     } else {
1125         size = item->GetLayoutSize().Height();
1126     }
1127 
1128     return size;
1129 }
1130 
ConstraintItemSize(FlowStyle item,size_t crossIndex)1131 FlowStyle RenderWaterFlow::ConstraintItemSize(FlowStyle item, size_t crossIndex)
1132 {
1133     FlowStyle result = item;
1134     if (GreatNotEqual(result.mainSize, itemConstraintSize_.maxMainSize)) {
1135         result.mainSize = itemConstraintSize_.maxMainSize;
1136     }
1137     if (LessNotEqual(result.mainSize, itemConstraintSize_.minMainSize)) {
1138         result.mainSize = itemConstraintSize_.minMainSize;
1139     }
1140     if (crossIndex < crossSideSize_.size()) {
1141         result.crossSize = crossSideSize_[crossIndex];
1142     }
1143     return result;
1144 }
1145 
CheckReachHead()1146 bool RenderWaterFlow::CheckReachHead()
1147 {
1148     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1149         return LessOrEqual(viewportStartPos_, 0.0);
1150     }
1151     return LessOrEqual(0.0, viewportStartPos_);
1152 }
1153 
CheckReachTail()1154 bool RenderWaterFlow::CheckReachTail()
1155 {
1156     double tailPos = GetTailPos();
1157     double footerOffset = 0.0;
1158     if (footer_) {
1159         switch (direction_) {
1160             case FlexDirection::COLUMN:
1161             case FlexDirection::COLUMN_REVERSE:
1162                 footerOffset = footerMaxSize_.Height();
1163                 break;
1164             case FlexDirection::ROW:
1165             case FlexDirection::ROW_REVERSE:
1166                 footerOffset = footerMaxSize_.Width();
1167                 break;
1168             default:
1169                 break;
1170         }
1171     }
1172     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1173         return (GreatOrEqual((viewportStartPos_) + mainSize_, tailPos + footerOffset));
1174     }
1175     return (GreatOrEqual(tailPos - footerOffset, viewportStartPos_));
1176 }
1177 
AdjustViewPort()1178 void RenderWaterFlow::AdjustViewPort()
1179 {
1180     double tailPos = GetTailPos();
1181     double footerOffset = 0.0;
1182     if (footer_) {
1183         switch (direction_) {
1184             case FlexDirection::COLUMN:
1185             case FlexDirection::COLUMN_REVERSE:
1186                 footerOffset = footerMaxSize_.Height();
1187                 break;
1188             case FlexDirection::ROW:
1189             case FlexDirection::ROW_REVERSE:
1190                 footerOffset = footerMaxSize_.Width();
1191                 break;
1192             default:
1193                 break;
1194         }
1195     }
1196 
1197     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1198         // Correct the position of view port to avoid oversize offset from scroller
1199         viewportStartPos_ = std::max(viewportStartPos_, 0.0);
1200         if (GreatOrEqual((viewportStartPos_) + mainSize_, tailPos + footerOffset)) {
1201             viewportStartPos_ = std::max((tailPos + footerOffset - mainSize_), 0.0);
1202         }
1203     } else {
1204         // Correct the position of view port to avoid oversize offset from scroller
1205         viewportStartPos_ = std::min(viewportStartPos_, 0.0);
1206         if (GreatOrEqual(tailPos - footerOffset, viewportStartPos_)) {
1207             viewportStartPos_ = std::min(tailPos - footerOffset, 0.0);
1208         }
1209     }
1210 }
1211 
GetTailPos()1212 double RenderWaterFlow::GetTailPos()
1213 {
1214     double result = 0.0;
1215     if (!getTotalCount_) {
1216         return result;
1217     }
1218 
1219     if (flowMatrix_.empty()) {
1220         if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1221             return result;
1222         }
1223         return mainSize_;
1224     }
1225 
1226     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1227         result = DBL_MAX;
1228     } else {
1229         result = -DBL_MAX;
1230     }
1231 
1232     totalCount_ = getTotalCount_();
1233     auto iter = flowMatrix_.find(totalCount_ - 1);
1234     if (iter != flowMatrix_.end()) {
1235         if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1236             result = GetLastMainPos().GetY();
1237         } else {
1238             result = mainSize_ - GetLastMainPos().GetY();
1239         }
1240     }
1241     return result;
1242 }
1243 
GetTargetPos()1244 double RenderWaterFlow::GetTargetPos()
1245 {
1246     double result = 0.0;
1247     // valid targetIndex_
1248     if (targetIndex_ >= 0) {
1249         auto iter = flowMatrix_.find(targetIndex_);
1250         if (iter != flowMatrix_.end()) {
1251             result = iter->second.mainPos;
1252         } else {
1253             result = DBL_MAX;
1254         }
1255     } else {
1256         if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1257             result = viewportStartPos_ + mainSize_;
1258         } else {
1259             result = -viewportStartPos_ + mainSize_;
1260         }
1261     }
1262     return result;
1263 }
1264 
GetCacheTargetPos() const1265 double RenderWaterFlow::GetCacheTargetPos() const
1266 {
1267     return viewportStartPos_ + mainSize_ + cacheSize_;
1268 }
1269 
AnimateToPos(const double & position,int32_t duration,const RefPtr<Curve> & curve)1270 void RenderWaterFlow::AnimateToPos(const double& position, int32_t duration, const RefPtr<Curve>& curve)
1271 {
1272     if (!animator_->IsStopped()) {
1273         animator_->Stop();
1274     }
1275     animator_->ClearInterpolators();
1276     auto animation = AceType::MakeRefPtr<CurveAnimation<double>>(viewportStartPos_, position, curve);
1277     animation->AddListener([weakScroll = AceType::WeakClaim(this)](double value) {
1278         auto scroll = weakScroll.Upgrade();
1279         if (scroll) {
1280             scroll->DoJump(value, SCROLL_FROM_ANIMATION);
1281         }
1282     });
1283     animator_->AddInterpolator(animation);
1284     animator_->SetDuration(duration);
1285     animator_->ClearStopListeners();
1286     animator_->Play();
1287 }
1288 
ClearFlowMatrix(size_t index,bool clearAll)1289 void RenderWaterFlow::ClearFlowMatrix(size_t index, bool clearAll)
1290 {
1291     if (!clearAll) {
1292         for (auto it = flowMatrix_.begin(); it != flowMatrix_.end();) {
1293             if (it->first >= index) {
1294                 it = flowMatrix_.erase(it);
1295             } else {
1296                 it++;
1297             }
1298         }
1299     } else {
1300         flowMatrix_.clear();
1301     }
1302 }
1303 
ClearItemsByCrossIndex(size_t index,bool clearAll)1304 void RenderWaterFlow::ClearItemsByCrossIndex(size_t index, bool clearAll)
1305 {
1306     if (!clearAll) {
1307         for (auto& cross : itemsByCrossIndex_) {
1308             for (auto item = cross.begin(); item != cross.end();) {
1309                 if (*item >= index) {
1310                     item = cross.erase(item);
1311                 } else {
1312                     item++;
1313                 }
1314             }
1315         }
1316     } else {
1317         itemsByCrossIndex_.clear();
1318         std::vector<size_t> item;
1319         for (size_t i = 0; i < crossCount_; i++) {
1320             itemsByCrossIndex_.emplace_back(item);
1321         }
1322     }
1323 }
1324 
UpdateMainSideEndPos()1325 void RenderWaterFlow::UpdateMainSideEndPos()
1326 {
1327     if (mainSideEndPos_.size() != itemsByCrossIndex_.size()) {
1328         return;
1329     }
1330 
1331     for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1332         int32_t maxIndex = -1;
1333         for (size_t j : itemsByCrossIndex_[i]) {
1334             maxIndex = std::max(maxIndex, static_cast<int32_t>(j));
1335         }
1336         auto iter = flowMatrix_.find(maxIndex);
1337         if (iter != flowMatrix_.end()) {
1338             mainSideEndPos_.at(i) = iter->second.mainPos + iter->second.mainSize + mainGap_;
1339         } else {
1340             mainSideEndPos_.at(i) = 0.0;
1341         }
1342     }
1343 }
1344 
InitMainSideEndPos()1345 void RenderWaterFlow::InitMainSideEndPos()
1346 {
1347     mainSideEndPos_.clear();
1348     for (size_t i = 0; i < crossCount_; i++) {
1349         mainSideEndPos_.emplace_back(0.0);
1350     }
1351 }
1352 
RemoveAllChild()1353 void RenderWaterFlow::RemoveAllChild()
1354 {
1355     items_.clear();
1356     ClearChildren();
1357 }
1358 
NeedPredictLayout()1359 bool RenderWaterFlow::NeedPredictLayout()
1360 {
1361     return !(updateFlag_ || (NearEqual(dVPStartPosBackup_, viewportStartPos_) &&
1362        (totalCountBack_ == getTotalCount_())));
1363 }
1364 
PreParseArgs(const std::string & args)1365 std::string RenderWaterFlow::PreParseArgs(const std::string& args)
1366 {
1367     if (args.empty() || args.find(UNIT_AUTO) == std::string::npos) {
1368         return args;
1369     }
1370     std::string rowsArgs;
1371     std::vector<std::string> strs;
1372     StringUtils::StringSplitter(args, ' ', strs);
1373     std::string current;
1374     size_t rowArgSize = strs.size();
1375     for (size_t i = 0; i < rowArgSize; ++i) {
1376         current = strs[i];
1377         // "auto" means 1fr in waterflow
1378         if (strs[i] == std::string(UNIT_AUTO)) {
1379             current = "1fr";
1380         }
1381         rowsArgs += ' ' + current;
1382     }
1383     return rowsArgs;
1384 }
1385 
HandleScrollEvent()1386 void RenderWaterFlow::HandleScrollEvent()
1387 {
1388     for (auto& event : waterflowEventFlags_) {
1389         switch (event.first) {
1390             case WaterFlowEvents::REACH_START:
1391                 if (event.second) {
1392                     ResumeEventCallback(component_, &WaterFlowComponent::GetOnReachStart);
1393                     event.second = false;
1394                 }
1395                 break;
1396             case WaterFlowEvents::REACH_END:
1397                 if (event.second) {
1398                     ResumeEventCallback(component_, &WaterFlowComponent::GetOnReachEnd);
1399                     event.second = false;
1400                 }
1401                 break;
1402             default:
1403                 LOGW("This event does not handle in here, please check. event number: %{public}d", event.first);
1404                 break;
1405         }
1406     }
1407 }
1408 } // namespace OHOS::Ace::V2
1409