• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_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_ = AceType::MakeRefPtr<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,int32_t source)805 void RenderWaterFlow::ScrollToIndex(int32_t index, int32_t source)
806 {
807     if (source != SCROLL_FROM_JUMP) {
808         LOGW("Not from scroll jump.");
809         return;
810     }
811 
812     if (useScrollable_ == SCROLLABLE::NO_SCROLL || index < 0) {
813         LOGW("Not supported.");
814         return;
815     }
816 
817     auto context = context_.Upgrade();
818     if (!context) {
819         LOGE("context is null");
820         return;
821     }
822 
823     auto iter = flowMatrix_.find(index);
824     if (iter == flowMatrix_.end()) {
825         targetIndex_ = index;
826         size_t itemIndex = GetNextSupplyedIndex();
827         SupplyItems(itemIndex, GetTargetPos());
828         iter = flowMatrix_.find(index);
829         if (iter == flowMatrix_.end()) {
830             LOGE("scrollToIndex[item:%{public}d] failed.", index);
831             return;
832         }
833     }
834 
835     double scrollToPos = 0.0;
836     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
837         scrollToPos = iter->second.mainPos;
838     } else {
839         scrollToPos = (mainSize_ - (iter->second.mainPos + iter->second.mainSize)) + iter->second.mainSize - mainSize_;
840     }
841     AnimateToPos(scrollToPos, ANIMATE_DURATION, CURVE_SCROLL_TO_TOP);
842 }
843 
DoJump(double position,int32_t source)844 void RenderWaterFlow::DoJump(double position, int32_t source)
845 {
846     UpdateScrollPosition(viewportStartPos_ - position, source);
847 }
848 
OnPredictLayout(int64_t deadline)849 void RenderWaterFlow::OnPredictLayout(int64_t deadline)
850 {
851     if (!NeedPredictLayout()) {
852         return;
853     }
854     auto context = context_.Upgrade();
855     if (!context) {
856         return;
857     }
858     if (!context->IsTransitionStop()) {
859         MarkNeedPredictLayout();
860         return;
861     }
862 
863     auto startTime = GetSysTimestamp(); // unit: ns
864     DealCache();
865     if (GetSysTimestamp() - startTime + TIME_THRESHOLD > deadline * MICROSEC_TO_NANOSEC) {
866         MarkNeedPredictLayout();
867         return;
868     }
869 
870     // just need supply forward the main side, backwards already supply and keep in flowMatrix.
871     size_t itemIndex = GetNextSupplyedIndex();
872     SupplyItems(itemIndex, GetCacheTargetPos());
873     UpdateCacheItems();
874     LayoutItems(cacheItems_);
875     dVPStartPosBackup_ = viewportStartPos_;
876     totalCountBack_ = getTotalCount_();
877     MarkNeedPredictLayout();
878 }
879 
IsAxisScrollable(AxisDirection direction)880 bool RenderWaterFlow::IsAxisScrollable(AxisDirection direction)
881 {
882     bool ret = true;
883     switch (direction_) {
884         case FlexDirection::COLUMN:
885             if ((direction == AxisDirection::UP && reachHead_) ||
886                 (direction == AxisDirection::DOWN && reachTail_)) {
887                 ret = false;
888             }
889             break;
890         case FlexDirection::ROW:
891             if ((direction == AxisDirection::LEFT && reachHead_) ||
892                 (direction == AxisDirection::RIGHT && reachTail_)) {
893                 ret = false;
894             }
895             break;
896         case FlexDirection::COLUMN_REVERSE:
897             if ((direction == AxisDirection::DOWN && reachHead_) ||
898                 (direction == AxisDirection::UP && reachTail_)) {
899                 ret = false;
900             }
901             break;
902         case FlexDirection::ROW_REVERSE:
903             if ((direction == AxisDirection::RIGHT && reachHead_) ||
904                 (direction == AxisDirection::LEFT && reachTail_)) {
905                 ret = false;
906             }
907             break;
908         default:
909             ret = false;
910             break;
911     }
912     if (direction == AxisDirection::NONE) {
913         ret = false;
914     }
915     return ret;
916 }
917 
HandleAxisEvent(const AxisEvent & event)918 void RenderWaterFlow::HandleAxisEvent(const AxisEvent& event)
919 {
920     double degree = 0.0;
921     if (!NearZero(event.horizontalAxis)) {
922         degree = event.horizontalAxis;
923     } else if (!NearZero(event.verticalAxis)) {
924         degree = event.verticalAxis;
925     }
926     double offset = SystemProperties::Vp2Px(DP_PER_LINE_DESKTOP * LINE_NUMBER_DESKTOP * degree / MOUSE_WHEEL_DEGREES);
927     UpdateScrollPosition(-offset, SCROLL_FROM_ROTATE);
928 }
929 
CheckAxisNode()930 WeakPtr<RenderNode> RenderWaterFlow::CheckAxisNode()
931 {
932     return AceType::WeakClaim<RenderNode>(this);
933 }
934 
OnChildAdded(const RefPtr<RenderNode> & renderNode)935 void RenderWaterFlow::OnChildAdded(const RefPtr<RenderNode>& renderNode)
936 {
937     Offset offset;
938     switch (direction_) {
939         case FlexDirection::COLUMN:
940             offset.SetX(crossSize_ / CENTER_POINT);
941             offset.SetY(mainSize_ + cacheSize_);
942             break;
943         case FlexDirection::ROW:
944             offset.SetX(mainSize_ + cacheSize_);
945             offset.SetY(crossSize_ / CENTER_POINT);
946             break;
947         case FlexDirection::COLUMN_REVERSE:
948             offset.SetX(crossSize_ / CENTER_POINT);
949             offset.SetY(0.0 - cacheSize_);
950             break;
951         case FlexDirection::ROW_REVERSE:
952             offset.SetX(0.0 - cacheSize_);
953             offset.SetY(crossSize_ / CENTER_POINT);
954             break;
955         default:
956             break;
957     }
958     // set default position for animateTo(covering animation)
959     renderNode->SetPosition(offset);
960     RenderNode::OnChildAdded(renderNode);
961 }
962 
IsUseOnly()963 bool RenderWaterFlow::IsUseOnly()
964 {
965     return true;
966 }
967 
GetFlowItemByChild(const RefPtr<RenderNode> & child)968 RefPtr<RenderWaterFlowItem> RenderWaterFlow::GetFlowItemByChild(const RefPtr<RenderNode>& child)
969 {
970     int32_t depth = DEFAULT_DEPTH;
971     auto item = child;
972     auto flowItem = AceType::DynamicCast<RenderWaterFlowItem>(item);
973     while (!flowItem && depth > 0) {
974         if (!item || item->GetChildren().empty()) {
975             return nullptr;
976         }
977         item = item->GetChildren().front();
978         flowItem = AceType::DynamicCast<RenderWaterFlowItem>(item);
979         --depth;
980     }
981     return flowItem;
982 }
983 
OutputMatrix()984 void RenderWaterFlow::OutputMatrix()
985 {
986     for (auto it = flowMatrix_.begin(); it != flowMatrix_.end();) {
987         LOGD("%{public}s: [%{public}zu] Pos[%{public}f, %{public}f] Size[%{public}f, %{public}f]", __PRETTY_FUNCTION__,
988             it->first, it->second.crossPos, it->second.mainPos, it->second.crossSize, it->second.mainSize);
989         it++;
990     }
991 }
992 
RequestWaterFlowFooter()993 void RenderWaterFlow::RequestWaterFlowFooter()
994 {
995     auto generator = itemGenerator_.Upgrade();
996     footer_ = generator ? generator->RequestWaterFlowFooter() : RefPtr<RenderNode>();
997     if (footer_) {
998         AddChild(footer_);
999         footer_->Layout(GetLayoutParam());
1000         footer_->SetVisible(false);
1001         auto mainSize = GetMainSize(footer_);
1002         auto crossSize = GetCrossSize(footer_);
1003         if (NonPositive(mainSize) || NonPositive(crossSize)) {
1004             RemoveChild(footer_);
1005             footer_ = nullptr;
1006         } else {
1007             GetFooterSize(mainSize, crossSize);
1008         }
1009     }
1010 }
1011 
GetLastSupplyedIndex()1012 size_t RenderWaterFlow::GetLastSupplyedIndex()
1013 {
1014     return flowMatrix_.empty() ? 0 : (--flowMatrix_.end())->first;
1015 }
1016 
GetNextSupplyedIndex()1017 size_t RenderWaterFlow::GetNextSupplyedIndex()
1018 {
1019     size_t index = 0;
1020     if (!flowMatrix_.empty()) {
1021         index = (--flowMatrix_.end())->first;
1022         index++;
1023     }
1024     return index;
1025 }
1026 
GetLastSupplyedMainSize()1027 double RenderWaterFlow::GetLastSupplyedMainSize()
1028 {
1029     double result = 0.0;
1030     if (flowMatrix_.empty()) {
1031         return result;
1032     }
1033     size_t index = GetLastSupplyedIndex();
1034     auto iter = flowMatrix_.find(index);
1035     if (iter != flowMatrix_.end()) {
1036         result = iter->second.mainSize + iter->second.mainPos;
1037     }
1038     return result;
1039 }
1040 
GetLastMainBlankPos()1041 Offset RenderWaterFlow::GetLastMainBlankPos()
1042 {
1043     Offset pos;
1044     size_t crossIndex = 0;
1045     if (mainSideEndPos_.empty() || mainSideEndPos_.size() != crossSideSize_.size()) {
1046         return pos;
1047     }
1048     pos.SetY(mainSideEndPos_.at(0));
1049     for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1050         if (LessNotEqual(mainSideEndPos_.at(i), pos.GetY())) {
1051             pos.SetY(mainSideEndPos_.at(i));
1052             crossIndex = i;
1053         }
1054     }
1055     pos.SetX(GetCrossEndPos(crossIndex));
1056     return pos;
1057 }
1058 
GetLastMainBlankCross()1059 size_t RenderWaterFlow::GetLastMainBlankCross()
1060 {
1061     double pos = 0.0;
1062     size_t crossIndex = 0;
1063     if (mainSideEndPos_.empty()) {
1064         return crossIndex;
1065     }
1066     pos = mainSideEndPos_.at(0);
1067     for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1068         if (LessNotEqual(mainSideEndPos_.at(i), pos)) {
1069             pos = mainSideEndPos_.at(i);
1070             crossIndex = i;
1071         }
1072     }
1073     return crossIndex;
1074 }
1075 
GetLastMainPos()1076 Offset RenderWaterFlow::GetLastMainPos()
1077 {
1078     Offset pos(0.0, 0.0);
1079     size_t crossIndex = 0;
1080     if (mainSideEndPos_.empty() || mainSideEndPos_.size() != crossSideSize_.size()) {
1081         return pos;
1082     }
1083     double tempMainSidePos = mainSideEndPos_.at(0);
1084     for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1085         if (GreatNotEqual(mainSideEndPos_.at(i), tempMainSidePos)) {
1086             tempMainSidePos = mainSideEndPos_.at(i);
1087             crossIndex = i;
1088         }
1089     }
1090     pos.SetY(mainSideEndPos_.at(crossIndex) - mainGap_);
1091     pos.SetX(GetCrossEndPos(crossIndex));
1092     return pos;
1093 }
1094 
GetCrossEndPos(size_t crossIndex)1095 double RenderWaterFlow::GetCrossEndPos(size_t crossIndex)
1096 {
1097     double pos = 0.0;
1098     if (crossIndex >= crossSideSize_.size()) {
1099         return pos;
1100     }
1101     for (size_t i = 0; i < crossIndex; i++) {
1102         pos += crossSideSize_[i];
1103     }
1104     if (crossIndex > 0) {
1105         pos += crossIndex * crossGap_;
1106     }
1107 
1108     return pos;
1109 }
1110 
GetMainSize(const RefPtr<RenderNode> & item) const1111 double RenderWaterFlow::GetMainSize(const RefPtr<RenderNode>& item) const
1112 {
1113     double size = 0.0;
1114     if (!item) {
1115         return size;
1116     }
1117     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
1118         size = item->GetLayoutSize().Height();
1119     } else {
1120         size = item->GetLayoutSize().Width();
1121     }
1122 
1123     return size;
1124 }
1125 
GetCrossSize(const RefPtr<RenderNode> & item) const1126 double RenderWaterFlow::GetCrossSize(const RefPtr<RenderNode>& item) const
1127 {
1128     double size = 0.0;
1129     if (!item) {
1130         return size;
1131     }
1132 
1133     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
1134         size = item->GetLayoutSize().Width();
1135     } else {
1136         size = item->GetLayoutSize().Height();
1137     }
1138 
1139     return size;
1140 }
1141 
ConstraintItemSize(FlowStyle item,size_t crossIndex)1142 FlowStyle RenderWaterFlow::ConstraintItemSize(FlowStyle item, size_t crossIndex)
1143 {
1144     FlowStyle result = item;
1145     if (GreatNotEqual(result.mainSize, itemConstraintSize_.maxMainSize)) {
1146         result.mainSize = itemConstraintSize_.maxMainSize;
1147     }
1148     if (LessNotEqual(result.mainSize, itemConstraintSize_.minMainSize)) {
1149         result.mainSize = itemConstraintSize_.minMainSize;
1150     }
1151     if (crossIndex < crossSideSize_.size()) {
1152         result.crossSize = crossSideSize_[crossIndex];
1153     }
1154     return result;
1155 }
1156 
CheckReachHead()1157 bool RenderWaterFlow::CheckReachHead()
1158 {
1159     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1160         return LessOrEqual(viewportStartPos_, 0.0);
1161     }
1162     return LessOrEqual(0.0, viewportStartPos_);
1163 }
1164 
CheckReachTail()1165 bool RenderWaterFlow::CheckReachTail()
1166 {
1167     double tailPos = GetTailPos();
1168     double footerOffset = 0.0;
1169     if (footer_) {
1170         switch (direction_) {
1171             case FlexDirection::COLUMN:
1172             case FlexDirection::COLUMN_REVERSE:
1173                 footerOffset = footerMaxSize_.Height();
1174                 break;
1175             case FlexDirection::ROW:
1176             case FlexDirection::ROW_REVERSE:
1177                 footerOffset = footerMaxSize_.Width();
1178                 break;
1179             default:
1180                 break;
1181         }
1182     }
1183     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1184         return (GreatOrEqual((viewportStartPos_) + mainSize_, tailPos + footerOffset));
1185     }
1186     return (GreatOrEqual(tailPos - footerOffset, viewportStartPos_));
1187 }
1188 
AdjustViewPort()1189 void RenderWaterFlow::AdjustViewPort()
1190 {
1191     double tailPos = GetTailPos();
1192     double footerOffset = 0.0;
1193     if (footer_) {
1194         switch (direction_) {
1195             case FlexDirection::COLUMN:
1196             case FlexDirection::COLUMN_REVERSE:
1197                 footerOffset = footerMaxSize_.Height();
1198                 break;
1199             case FlexDirection::ROW:
1200             case FlexDirection::ROW_REVERSE:
1201                 footerOffset = footerMaxSize_.Width();
1202                 break;
1203             default:
1204                 break;
1205         }
1206     }
1207 
1208     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1209         // Correct the position of view port to avoid oversize offset from scroller
1210         viewportStartPos_ = std::max(viewportStartPos_, 0.0);
1211         if (GreatOrEqual((viewportStartPos_) + mainSize_, tailPos + footerOffset)) {
1212             viewportStartPos_ = std::max((tailPos + footerOffset - mainSize_), 0.0);
1213         }
1214     } else {
1215         // Correct the position of view port to avoid oversize offset from scroller
1216         viewportStartPos_ = std::min(viewportStartPos_, 0.0);
1217         if (GreatOrEqual(tailPos - footerOffset, viewportStartPos_)) {
1218             viewportStartPos_ = std::min(tailPos - footerOffset, 0.0);
1219         }
1220     }
1221 }
1222 
GetTailPos()1223 double RenderWaterFlow::GetTailPos()
1224 {
1225     double result = 0.0;
1226     if (!getTotalCount_) {
1227         return result;
1228     }
1229 
1230     if (flowMatrix_.empty()) {
1231         if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1232             return result;
1233         }
1234         return mainSize_;
1235     }
1236 
1237     if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1238         result = DBL_MAX;
1239     } else {
1240         result = -DBL_MAX;
1241     }
1242 
1243     totalCount_ = getTotalCount_();
1244     auto iter = flowMatrix_.find(totalCount_ - 1);
1245     if (iter != flowMatrix_.end()) {
1246         if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1247             result = GetLastMainPos().GetY();
1248         } else {
1249             result = mainSize_ - GetLastMainPos().GetY();
1250         }
1251     }
1252     return result;
1253 }
1254 
GetTargetPos()1255 double RenderWaterFlow::GetTargetPos()
1256 {
1257     double result = 0.0;
1258     // valid targetIndex_
1259     if (targetIndex_ >= 0) {
1260         auto iter = flowMatrix_.find(targetIndex_);
1261         if (iter != flowMatrix_.end()) {
1262             result = iter->second.mainPos;
1263         } else {
1264             result = DBL_MAX;
1265         }
1266     } else {
1267         if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1268             result = viewportStartPos_ + mainSize_;
1269         } else {
1270             result = -viewportStartPos_ + mainSize_;
1271         }
1272     }
1273     return result;
1274 }
1275 
GetCacheTargetPos() const1276 double RenderWaterFlow::GetCacheTargetPos() const
1277 {
1278     return viewportStartPos_ + mainSize_ + cacheSize_;
1279 }
1280 
AnimateToPos(const double & position,int32_t duration,const RefPtr<Curve> & curve)1281 void RenderWaterFlow::AnimateToPos(const double& position, int32_t duration, const RefPtr<Curve>& curve)
1282 {
1283     if (!animator_->IsStopped()) {
1284         animator_->Stop();
1285     }
1286     animator_->ClearInterpolators();
1287     auto animation = AceType::MakeRefPtr<CurveAnimation<double>>(viewportStartPos_, position, curve);
1288     animation->AddListener([weakScroll = AceType::WeakClaim(this)](double value) {
1289         auto scroll = weakScroll.Upgrade();
1290         if (scroll) {
1291             scroll->DoJump(value, SCROLL_FROM_ANIMATION);
1292         }
1293     });
1294     animator_->AddInterpolator(animation);
1295     animator_->SetDuration(duration);
1296     animator_->ClearStopListeners();
1297     animator_->Play();
1298 }
1299 
ClearFlowMatrix(size_t index,bool clearAll)1300 void RenderWaterFlow::ClearFlowMatrix(size_t index, bool clearAll)
1301 {
1302     if (!clearAll) {
1303         for (auto it = flowMatrix_.begin(); it != flowMatrix_.end();) {
1304             if (it->first >= index) {
1305                 flowMatrix_.erase(it++);
1306             } else {
1307                 it++;
1308             }
1309         }
1310     } else {
1311         flowMatrix_.clear();
1312     }
1313 }
1314 
ClearItemsByCrossIndex(size_t index,bool clearAll)1315 void RenderWaterFlow::ClearItemsByCrossIndex(size_t index, bool clearAll)
1316 {
1317     if (!clearAll) {
1318         for (auto& cross : itemsByCrossIndex_) {
1319             for (auto item = cross.begin(); item != cross.end();) {
1320                 if (*item >= index) {
1321                     item = cross.erase(item);
1322                 } else {
1323                     item++;
1324                 }
1325             }
1326         }
1327     } else {
1328         itemsByCrossIndex_.clear();
1329         std::vector<size_t> item;
1330         for (size_t i = 0; i < crossCount_; i++) {
1331             itemsByCrossIndex_.emplace_back(item);
1332         }
1333     }
1334 }
1335 
UpdateMainSideEndPos()1336 void RenderWaterFlow::UpdateMainSideEndPos()
1337 {
1338     if (mainSideEndPos_.size() != itemsByCrossIndex_.size()) {
1339         return;
1340     }
1341 
1342     for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1343         int32_t maxIndex = -1;
1344         for (size_t j : itemsByCrossIndex_[i]) {
1345             maxIndex = std::max(maxIndex, static_cast<int32_t>(j));
1346         }
1347         auto iter = flowMatrix_.find(maxIndex);
1348         if (iter != flowMatrix_.end()) {
1349             mainSideEndPos_.at(i) = iter->second.mainPos + iter->second.mainSize + mainGap_;
1350         } else {
1351             mainSideEndPos_.at(i) = 0.0;
1352         }
1353     }
1354 }
1355 
InitMainSideEndPos()1356 void RenderWaterFlow::InitMainSideEndPos()
1357 {
1358     mainSideEndPos_.clear();
1359     for (size_t i = 0; i < crossCount_; i++) {
1360         mainSideEndPos_.emplace_back(0.0);
1361     }
1362 }
1363 
RemoveAllChild()1364 void RenderWaterFlow::RemoveAllChild()
1365 {
1366     items_.clear();
1367     ClearChildren();
1368 }
1369 
NeedPredictLayout()1370 bool RenderWaterFlow::NeedPredictLayout()
1371 {
1372     return !(updateFlag_ || (NearEqual(dVPStartPosBackup_, viewportStartPos_) &&
1373        (totalCountBack_ == getTotalCount_())));
1374 }
1375 
PreParseArgs(const std::string & args)1376 std::string RenderWaterFlow::PreParseArgs(const std::string& args)
1377 {
1378     if (args.empty() || args.find(UNIT_AUTO) == std::string::npos) {
1379         return args;
1380     }
1381     std::string rowsArgs;
1382     std::vector<std::string> strs;
1383     StringUtils::StringSplitter(args, ' ', strs);
1384     std::string current;
1385     size_t rowArgSize = strs.size();
1386     for (size_t i = 0; i < rowArgSize; ++i) {
1387         current = strs[i];
1388         // "auto" means 1fr in waterflow
1389         if (strs[i] == std::string(UNIT_AUTO)) {
1390             current = "1fr";
1391         }
1392         rowsArgs += ' ' + current;
1393     }
1394     return rowsArgs;
1395 }
1396 
HandleScrollEvent()1397 void RenderWaterFlow::HandleScrollEvent()
1398 {
1399     for (auto& event : waterflowEventFlags_) {
1400         switch (event.first) {
1401             case WaterFlowEvents::REACH_START:
1402                 if (event.second) {
1403                     ResumeEventCallback(component_, &WaterFlowComponent::GetOnReachStart);
1404                     LOGD("waterflow event REACH_START triggered.");
1405                     event.second = false;
1406                 }
1407                 break;
1408             case WaterFlowEvents::REACH_END:
1409                 if (event.second) {
1410                     ResumeEventCallback(component_, &WaterFlowComponent::GetOnReachEnd);
1411                     LOGD("waterflow event REACH_END triggered.");
1412                     event.second = false;
1413                 }
1414                 break;
1415             default:
1416                 LOGW("This event does not handle in here, please check. event number: %{public}d", event.first);
1417                 break;
1418         }
1419     }
1420 }
1421 } // namespace OHOS::Ace::V2
1422