• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_ng/pattern/scroll_bar/scroll_bar_pattern.h"
17 
18 #include "base/log/dump_log.h"
19 #include "core/components/common/layout/constants.h"
20 #include "core/components_ng/event/event_hub.h"
21 #include "core/components_ng/property/measure_utils.h"
22 #include "core/pipeline_ng/pipeline_context.h"
23 
24 namespace OHOS::Ace::NG {
25 namespace {
26 constexpr int32_t BAR_DISAPPEAR_DELAY_DURATION = 2000; // 2000ms
27 constexpr int32_t BAR_DISAPPEAR_DURATION = 300;        // 300ms
28 constexpr int32_t BAR_APPEAR_DURATION = 100;           // 100ms
29 constexpr int32_t BAR_DISAPPEAR_FRAME_RATE = 15;       // 15fps, the expected frame rate of opacity animation
30 constexpr int32_t BAR_DISAPPEAR_MIN_FRAME_RATE = 0;
31 constexpr int32_t BAR_DISAPPEAR_MAX_FRAME_RATE = 90;
32 constexpr int32_t SCROLL_BAR_LAYOUT_INFO_COUNT = 120;
33 constexpr int32_t LONG_PRESS_PAGE_INTERVAL_MS = 100;
34 constexpr int32_t LONG_PRESS_TIME_THRESHOLD_MS = 500;
35 } // namespace
36 
OnAttachToFrameNode()37 void ScrollBarPattern::OnAttachToFrameNode()
38 {
39     auto host = GetHost();
40     CHECK_NULL_VOID(host);
41 
42     host->GetRenderContext()->SetClipToFrame(true);
43 }
44 
SendAccessibilityEvent(AccessibilityEventType eventType)45 void ScrollBarPattern::SendAccessibilityEvent(AccessibilityEventType eventType)
46 {
47     auto frameNode = GetHost();
48     CHECK_NULL_VOID(frameNode);
49     frameNode->OnAccessibilityEvent(eventType);
50 }
51 
OnModifyDone()52 void ScrollBarPattern::OnModifyDone()
53 {
54     Pattern::OnModifyDone();
55     auto host = GetHost();
56     CHECK_NULL_VOID(host);
57     auto layoutProperty = host->GetLayoutProperty<ScrollBarLayoutProperty>();
58     CHECK_NULL_VOID(layoutProperty);
59 
60     auto oldDisplayMode = displayMode_;
61     displayMode_ = layoutProperty->GetDisplayMode().value_or(DisplayMode::AUTO);
62     if (oldDisplayMode != displayMode_ && scrollBarProxy_) {
63         if (displayMode_ == DisplayMode::ON) {
64             StopDisappearAnimator();
65         } else if (displayMode_ == DisplayMode::AUTO) {
66             StartDisappearAnimator();
67         }
68     }
69     auto axis = layoutProperty->GetAxis().value_or(Axis::VERTICAL);
70     if (axis_ == axis && scrollableEvent_) {
71         return;
72     }
73     axis_ = axis;
74     // scrollPosition callback
75     scrollPositionCallback_ = [weak = WeakClaim(this)](double offset, int32_t source) {
76         auto pattern = weak.Upgrade();
77         CHECK_NULL_RETURN(pattern, false);
78         if (source == SCROLL_FROM_START) {
79             pattern->StopDisappearAnimator();
80             auto scrollBarProxy = pattern->scrollBarProxy_;
81             if (scrollBarProxy) {
82                 scrollBarProxy->NotifyScrollStart();
83             }
84             // AccessibilityEventType::SCROLL_START
85             return true;
86         }
87         return pattern->UpdateCurrentOffset(offset, source);
88     };
89     scrollEndCallback_ = [weak = WeakClaim(this)]() {
90         auto pattern = weak.Upgrade();
91         CHECK_NULL_VOID(pattern);
92         if (pattern->GetDisplayMode() == DisplayMode::AUTO) {
93             pattern->StartDisappearAnimator();
94         }
95         // AccessibilityEventType::SCROLL_END
96     };
97 
98     auto hub = host->GetEventHub<EventHub>();
99     CHECK_NULL_VOID(hub);
100     auto gestureHub = hub->GetOrCreateGestureEventHub();
101     CHECK_NULL_VOID(gestureHub);
102     if (scrollableEvent_) {
103         gestureHub->RemoveScrollableEvent(scrollableEvent_);
104     }
105     scrollableEvent_ = MakeRefPtr<ScrollableEvent>(axis);
106     scrollableEvent_->SetInBarRegionCallback([weak = AceType::WeakClaim(this)]
107         (const PointF& point, SourceType source) {
108             auto scrollBarPattern = weak.Upgrade();
109             CHECK_NULL_RETURN(scrollBarPattern, false);
110             if (!scrollBarPattern->HasChild()
111                 && Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
112                 auto scrollBar = scrollBarPattern->scrollBar_;
113                 CHECK_NULL_RETURN(scrollBar, false);
114                 if (source == SourceType::MOUSE) {
115                     return scrollBar->InBarHoverRegion(Point(point.GetX(), point.GetY()));
116                 }
117                 return scrollBar->InBarTouchRegion(Point(point.GetX(), point.GetY()));
118             } else {
119                 return scrollBarPattern->childRect_.IsInRegion(point);
120             }
121         }
122     );
123     scrollableEvent_->SetBarCollectTouchTargetCallback(
124         [weak = AceType::WeakClaim(this)](const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
125             TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
126             ResponseLinkResult& responseLinkResult) {
127             auto scrollBarPattern = weak.Upgrade();
128             CHECK_NULL_VOID(scrollBarPattern);
129             if (!scrollBarPattern->HasChild()
130                 && Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
131                 auto scrollBar = scrollBarPattern->scrollBar_;
132                 CHECK_NULL_VOID(scrollBar);
133                 scrollBar->OnCollectTouchTarget(
134                     coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
135             } else {
136                 scrollBarPattern->OnCollectTouchTarget(
137                     coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
138             }
139         });
140 
141     SetBarCollectClickAndLongPressTargetCallback();
142     SetInBarRectRegionCallback();
143     gestureHub->AddScrollableEvent(scrollableEvent_);
144     SetAccessibilityAction();
145     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
146         SetScrollBar(DisplayMode::ON);
147     }
148     if (!panRecognizer_) {
149         InitPanRecognizer();
150     }
151     InitMouseEvent();
152     if (!clickRecognizer_) {
153         InitClickEvent();
154     }
155     if (!longPressRecognizer_) {
156         InitLongPressEvent();
157     }
158 }
159 
SetBarCollectClickAndLongPressTargetCallback()160 void ScrollBarPattern::SetBarCollectClickAndLongPressTargetCallback()
161 {
162     CHECK_NULL_VOID(scrollableEvent_);
163     scrollableEvent_->SetBarCollectClickAndLongPressTargetCallback(
164         [weak = AceType::WeakClaim(this)](const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
165             TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
166             ResponseLinkResult& responseLinkResult) {
167             auto scrollBar = weak.Upgrade();
168             CHECK_NULL_VOID(scrollBar);
169             scrollBar->OnCollectClickTarget(
170                 coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
171             scrollBar->OnCollectLongPressTarget(
172                 coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
173         });
174 }
175 
SetInBarRectRegionCallback()176 void ScrollBarPattern::SetInBarRectRegionCallback()
177 {
178     CHECK_NULL_VOID(scrollableEvent_);
179     scrollableEvent_->SetInBarRectRegionCallback(
180         [weak = AceType::WeakClaim(this)](const PointF& point, SourceType source) {
181             auto scrollBar = weak.Upgrade();
182             CHECK_NULL_RETURN(scrollBar, false);
183             return scrollBar->IsInScrollBar();
184         });
185 }
186 
SetScrollBar(DisplayMode displayMode)187 void ScrollBarPattern::SetScrollBar(DisplayMode displayMode)
188 {
189     auto host = GetHost();
190     CHECK_NULL_VOID(host);
191     if (displayMode == DisplayMode::OFF) {
192         if (scrollBar_) {
193             auto gestureHub = GetGestureHub();
194             if (gestureHub) {
195                 gestureHub->RemoveTouchEvent(scrollBar_->GetTouchEvent());
196             }
197             scrollBar_.Reset();
198             if (scrollBarOverlayModifier_) {
199                 scrollBarOverlayModifier_->SetOpacity(0);
200             }
201         }
202         return;
203     }
204     DisplayMode oldDisplayMode = DisplayMode::OFF;
205     if (!scrollBar_) {
206         scrollBar_ = AceType::MakeRefPtr<ScrollBar>();
207         // set the scroll bar style
208         if (GetAxis() == Axis::HORIZONTAL) {
209             scrollBar_->SetPositionMode(PositionMode::BOTTOM);
210             if (scrollBarOverlayModifier_) {
211                 scrollBarOverlayModifier_->SetPositionMode(PositionMode::BOTTOM);
212             }
213         }
214         RegisterScrollBarEventTask();
215         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
216     } else {
217         oldDisplayMode = scrollBar_->GetDisplayMode();
218     }
219 
220     if (oldDisplayMode != displayMode) {
221         scrollBar_->SetDisplayMode(displayMode);
222         if (scrollBarOverlayModifier_ && scrollBar_->IsScrollable()) {
223             scrollBarOverlayModifier_->SetOpacity(UINT8_MAX);
224         }
225         scrollBar_->ScheduleDisappearDelayTask();
226     }
227 }
228 
HandleScrollBarOutBoundary(float scrollBarOutBoundaryExtent)229 void ScrollBarPattern::HandleScrollBarOutBoundary(float scrollBarOutBoundaryExtent)
230 {
231     CHECK_NULL_VOID(scrollBar_ && scrollBar_->NeedScrollBar());
232     scrollBar_->SetOutBoundary(std::abs(scrollBarOutBoundaryExtent));
233 }
234 
UpdateScrollBarOffset()235 void ScrollBarPattern::UpdateScrollBarOffset()
236 {
237     CHECK_NULL_VOID(scrollBar_);
238     auto host = GetHost();
239     CHECK_NULL_VOID(host);
240     auto geometryNode = host->GetGeometryNode();
241     auto viewSize = geometryNode->GetFrameSize();
242 
243     auto layoutProperty = host->GetLayoutProperty<ScrollBarLayoutProperty>();
244     CHECK_NULL_VOID(layoutProperty);
245     auto estimatedHeight = GetControlDistance() + (GetAxis() == Axis::VERTICAL ? viewSize.Height() : viewSize.Width());
246 
247     UpdateScrollBarRegion(scrollableNodeOffset_, estimatedHeight,
248         Size(viewSize.Width(), viewSize.Height()), Offset(0.0f, 0.0f));
249 }
250 
UpdateScrollBarRegion(float offset,float estimatedHeight,Size viewPort,Offset viewOffset)251 void ScrollBarPattern::UpdateScrollBarRegion(float offset, float estimatedHeight, Size viewPort, Offset viewOffset)
252 {
253     // outer scrollbar, viewOffset is padding offset
254     if (scrollBar_) {
255         auto mainSize = axis_ == Axis::VERTICAL ? viewPort.Height() : viewPort.Width();
256         bool scrollable = GreatNotEqual(estimatedHeight, mainSize);
257         if (scrollBar_->IsScrollable() != scrollable) {
258             scrollBar_->SetScrollable(scrollable);
259             if (scrollBarOverlayModifier_) {
260                 scrollBarOverlayModifier_->SetOpacity(scrollable ? UINT8_MAX : 0);
261             }
262             if (scrollable) {
263                 scrollBar_->ScheduleDisappearDelayTask();
264             }
265         }
266         Offset scrollOffset = { offset, offset };
267         scrollBar_->SetReverse(IsReverse());
268         scrollBar_->UpdateScrollBarRegion(viewOffset, viewPort, scrollOffset, estimatedHeight);
269         scrollBar_->MarkNeedRender();
270     }
271 }
272 
RegisterScrollBarEventTask()273 void ScrollBarPattern::RegisterScrollBarEventTask()
274 {
275     CHECK_NULL_VOID(scrollBar_);
276     auto host = GetHost();
277     CHECK_NULL_VOID(host);
278     auto gestureHub = GetGestureHub();
279     auto inputHub = GetInputHub();
280     CHECK_NULL_VOID(gestureHub);
281     CHECK_NULL_VOID(inputHub);
282     scrollBar_->SetGestureEvent();
283     scrollBar_->SetMouseEvent();
284     scrollBar_->SetHoverEvent();
285     scrollBar_->SetMarkNeedRenderFunc([weak = AceType::WeakClaim(AceType::RawPtr(host))]() {
286         auto host = weak.Upgrade();
287         CHECK_NULL_VOID(host);
288         host->MarkNeedRenderOnly();
289     });
290 
291     auto scrollCallback = [weak = WeakClaim(this)](double offset, int32_t source) {
292         auto pattern = weak.Upgrade();
293         CHECK_NULL_RETURN(pattern, false);
294         pattern->scrollBarProxy_->NotifyScrollBarNode(offset, source);
295         if (source == SCROLL_FROM_START) {
296             pattern->scrollPositionCallback_(0.0, SCROLL_FROM_START);
297         }
298         return true;
299     };
300     scrollBar_->SetScrollPositionCallback(std::move(scrollCallback));
301 
302     auto scrollEnd = [weak = WeakClaim(this)]() {
303         auto pattern = weak.Upgrade();
304         CHECK_NULL_VOID(pattern);
305         pattern->scrollBarProxy_->NotifyScrollStop();
306     };
307     scrollBar_->SetScrollEndCallback(std::move(scrollEnd));
308 
309     gestureHub->AddTouchEvent(scrollBar_->GetTouchEvent());
310     inputHub->AddOnMouseEvent(scrollBar_->GetMouseEvent());
311     inputHub->AddOnHoverEvent(scrollBar_->GetHoverEvent());
312 }
313 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)314 bool ScrollBarPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
315 {
316     if (config.skipMeasure && config.skipLayout) {
317         return false;
318     }
319     bool updateFlag = false;
320     if (!HasChild() && Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
321         updateFlag = true;
322     } else {
323         auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
324         CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
325         auto layoutAlgorithm = DynamicCast<ScrollBarLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
326         CHECK_NULL_RETURN(layoutAlgorithm, false);
327         scrollableDistance_ = layoutAlgorithm->GetScrollableDistance();
328     }
329     if (displayMode_ != DisplayMode::OFF) {
330         updateFlag = UpdateScrollBarDisplay() || updateFlag;
331     }
332     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
333         updateFlag = CheckChildState() || updateFlag;
334     }
335     return updateFlag;
336 }
337 
OnColorConfigurationUpdate()338 void ScrollBarPattern::OnColorConfigurationUpdate()
339 {
340     CHECK_NULL_VOID(scrollBar_);
341     auto pipelineContext = GetContext();
342     CHECK_NULL_VOID(pipelineContext);
343     auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
344     CHECK_NULL_VOID(theme);
345     scrollBar_->SetForegroundColor(theme->GetForegroundColor());
346     scrollBar_->SetBackgroundColor(theme->GetBackgroundColor());
347 }
348 
UpdateScrollBarDisplay()349 bool ScrollBarPattern::UpdateScrollBarDisplay()
350 {
351     auto host = GetHost();
352     CHECK_NULL_RETURN(host, false);
353     auto renderContext = host->GetRenderContext();
354     CHECK_NULL_RETURN(renderContext, false);
355     if (controlDistanceChanged_) {
356         controlDistanceChanged_ = false;
357         if (!Positive(controlDistance_)) {
358             SetOpacity(0);
359             return true;
360         }
361         SetOpacity(UINT8_MAX);
362         if (displayMode_ == DisplayMode::AUTO) {
363             StartDisappearAnimator();
364         }
365         return true;
366     }
367     if (!Positive(controlDistance_)) {
368         SetOpacity(0);
369         return true;
370     }
371     return false;
372 }
373 
IsInScrollBar()374 bool ScrollBarPattern::IsInScrollBar()
375 {
376     auto scrollBar = GetHost();
377     CHECK_NULL_RETURN(scrollBar, false);
378     auto scrollBarSize = scrollBar->GetGeometryNode()->GetFrameSize();
379     const bool isInVerticalScrollBar = (locationInfo_.GetX() >= 0 && locationInfo_.GetX() <= scrollBarSize.Width()) &&
380                                        (locationInfo_.GetY() >= 0 && locationInfo_.GetY() <= scrollBarSize.Height());
381 
382     return isInVerticalScrollBar;
383 }
384 
IsAtTop() const385 bool ScrollBarPattern::IsAtTop() const
386 {
387     return LessOrEqual(currentOffset_, 0.0);
388 }
389 
IsAtBottom() const390 bool ScrollBarPattern::IsAtBottom() const
391 {
392     return GreatOrEqual(currentOffset_, scrollableDistance_);
393 }
394 
ValidateOffset()395 void ScrollBarPattern::ValidateOffset()
396 {
397     if (scrollableDistance_ <= 0.0f) {
398         return;
399     }
400     currentOffset_ = std::clamp(currentOffset_, 0.0f, scrollableDistance_);
401 }
402 
UpdateCurrentOffset(float delta,int32_t source)403 bool ScrollBarPattern::UpdateCurrentOffset(float delta, int32_t source)
404 {
405     auto host = GetHost();
406     CHECK_NULL_RETURN(host, false);
407     if (NearZero(delta) || axis_ == Axis::NONE) {
408         return false;
409     }
410 
411     lastOffset_ = currentOffset_;
412     currentOffset_ += delta;
413     if (scrollBarProxy_ && lastOffset_ != currentOffset_) {
414         scrollBarProxy_->NotifyScrollableNode(-delta, source, AceType::WeakClaim(this));
415     }
416     AddScrollBarLayoutInfo();
417     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
418         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
419     } else {
420         host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
421     }
422     return true;
423 }
424 
AddScrollBarLayoutInfo()425 void ScrollBarPattern::AddScrollBarLayoutInfo()
426 {
427     if (outerScrollBarLayoutInfos_.size() >= SCROLL_BAR_LAYOUT_INFO_COUNT) {
428         outerScrollBarLayoutInfos_.pop_front();
429     }
430     outerScrollBarLayoutInfos_.push_back(OuterScrollBarLayoutInfo({
431         .layoutTime_ = GetSysTimestamp(),
432         .currentOffset_ = currentOffset_,
433         .scrollableNodeOffset_ = scrollableNodeOffset_,
434     }));
435 }
436 
GetAxisDumpInfo()437 void ScrollBarPattern::GetAxisDumpInfo()
438 {
439     switch (axis_) {
440         case Axis::NONE: {
441             DumpLog::GetInstance().AddDesc("Axis: NONE");
442             break;
443         }
444         case Axis::VERTICAL: {
445             DumpLog::GetInstance().AddDesc("Axis: VERTICAL");
446             break;
447         }
448         case Axis::HORIZONTAL: {
449             DumpLog::GetInstance().AddDesc("Axis: HORIZONTAL");
450             break;
451         }
452         case Axis::FREE: {
453             DumpLog::GetInstance().AddDesc("Axis: FREE");
454             break;
455         }
456         default: {
457             break;
458         }
459     }
460 }
461 
GetDisplayModeDumpInfo()462 void ScrollBarPattern::GetDisplayModeDumpInfo()
463 {
464     switch (displayMode_) {
465         case DisplayMode::OFF: {
466             DumpLog::GetInstance().AddDesc("outerScrollBarState: OFF");
467             break;
468         }
469         case DisplayMode::AUTO: {
470             DumpLog::GetInstance().AddDesc("outerScrollBarState: AUTO");
471             break;
472         }
473         case DisplayMode::ON: {
474             DumpLog::GetInstance().AddDesc("outerScrollBarState: ON");
475             break;
476         }
477         default: {
478             break;
479         }
480     }
481 }
482 
GetPanDirectionDumpInfo()483 void ScrollBarPattern::GetPanDirectionDumpInfo()
484 {
485     if (panRecognizer_) {
486         switch (panRecognizer_->GetAxisDirection()) {
487             case Axis::NONE: {
488                 DumpLog::GetInstance().AddDesc("panDirection: NONE");
489                 break;
490             }
491             case Axis::VERTICAL: {
492                 DumpLog::GetInstance().AddDesc("panDirection: VERTICAL");
493                 break;
494             }
495             case Axis::HORIZONTAL: {
496                 DumpLog::GetInstance().AddDesc("panDirection: HORIZONTAL");
497                 break;
498             }
499             case Axis::FREE: {
500                 DumpLog::GetInstance().AddDesc("panDirection: FREE");
501                 break;
502             }
503             default: {
504                 break;
505             }
506         }
507     } else {
508         DumpLog::GetInstance().AddDesc("panDirection is null");
509     }
510 }
511 
DumpAdvanceInfo()512 void ScrollBarPattern::DumpAdvanceInfo()
513 {
514     GetAxisDumpInfo();
515     GetDisplayModeDumpInfo();
516     GetPanDirectionDumpInfo();
517     hasChild_ ? DumpLog::GetInstance().AddDesc("hasChild: true") : DumpLog::GetInstance().AddDesc("hasChild: false");
518     preFrameChildState_ ? DumpLog::GetInstance().AddDesc("preFrameChildState: true")
519                         : DumpLog::GetInstance().AddDesc("preFrameChildState: false");
520     enableNestedSorll_ ? DumpLog::GetInstance().AddDesc("enableNestedSorll: true")
521                        : DumpLog::GetInstance().AddDesc("enableNestedSorll: false");
522     if (!hasChild_ && scrollBar_) {
523         scrollBar_->DumpAdvanceInfo();
524     }
525     DumpLog::GetInstance().AddDesc(std::string("childRect: ").append(childRect_.ToString()));
526     DumpLog::GetInstance().AddDesc(std::string("scrollableDistance: ").append(std::to_string(scrollableDistance_)));
527     DumpLog::GetInstance().AddDesc(std::string("controlDistance_: ").append(std::to_string(controlDistance_)));
528     DumpLog::GetInstance().AddDesc("==========================outerScrollBarLayoutInfos==========================");
529     for (const auto& info : outerScrollBarLayoutInfos_) {
530         DumpLog::GetInstance().AddDesc(info.ToString());
531     }
532     DumpLog::GetInstance().AddDesc("==========================outerScrollBarLayoutInfos==========================");
533 }
534 
StartDisappearAnimator()535 void ScrollBarPattern::StartDisappearAnimator()
536 {
537     if (!Positive(controlDistance_)) {
538         return;
539     }
540     if (disapplearDelayTask_) {
541         disapplearDelayTask_.Cancel();
542     }
543     auto context = GetContext();
544     CHECK_NULL_VOID(context);
545     auto taskExecutor = context->GetTaskExecutor();
546     CHECK_NULL_VOID(taskExecutor);
547     SetOpacity(UINT8_MAX);
548     disapplearDelayTask_.Reset([weak = WeakClaim(this)] {
549         auto scrollBar = weak.Upgrade();
550         CHECK_NULL_VOID(scrollBar);
551         AnimationOption option;
552         if (!scrollBar->HasChild()
553             && Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
554             option.SetCurve(Curves::SHARP);
555         } else {
556             option.SetCurve(Curves::FRICTION);
557         }
558         option.SetDuration(BAR_DISAPPEAR_DURATION);
559         option.SetFrameRateRange(AceType::MakeRefPtr<FrameRateRange>(
560             BAR_DISAPPEAR_MIN_FRAME_RATE, BAR_DISAPPEAR_MAX_FRAME_RATE, BAR_DISAPPEAR_FRAME_RATE));
561         auto disappearAnimation = AnimationUtils::StartAnimation(option, [weak]() {
562             auto scrollBar = weak.Upgrade();
563             CHECK_NULL_VOID(scrollBar);
564             scrollBar->SetOpacity(0);
565         });
566         scrollBar->SetDisappearAnimation(disappearAnimation);
567     });
568     taskExecutor->PostDelayedTask(disapplearDelayTask_, TaskExecutor::TaskType::UI, BAR_DISAPPEAR_DELAY_DURATION,
569         "ArkUIScrollBarDisappearAnimation");
570 }
571 
StopDisappearAnimator()572 void ScrollBarPattern::StopDisappearAnimator()
573 {
574     if (!Positive(controlDistance_)) {
575         return;
576     }
577     if (disapplearDelayTask_) {
578         disapplearDelayTask_.Cancel();
579     }
580     if (disappearAnimation_) {
581         AnimationUtils::StopAnimation(disappearAnimation_);
582     }
583     if (!HasChild()
584         && Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
585         AnimationOption option;
586         option.SetCurve(Curves::SHARP);
587         option.SetDuration(BAR_APPEAR_DURATION);
588         option.SetFrameRateRange(AceType::MakeRefPtr<FrameRateRange>(
589         BAR_DISAPPEAR_MIN_FRAME_RATE, BAR_DISAPPEAR_MAX_FRAME_RATE, BAR_DISAPPEAR_FRAME_RATE));
590         AnimationUtils::StartAnimation(option, [weak = WeakClaim(this)]() {
591             auto scrollBar = weak.Upgrade();
592             CHECK_NULL_VOID(scrollBar);
593             scrollBar->SetOpacity(UINT8_MAX);
594         });
595     } else {
596         SetOpacity(UINT8_MAX);
597     }
598 }
599 
SetOpacity(uint8_t value)600 void ScrollBarPattern::SetOpacity(uint8_t value)
601 {
602     auto host = GetHost();
603     CHECK_NULL_VOID(host);
604     auto renderContext = host->GetRenderContext();
605     CHECK_NULL_VOID(renderContext);
606     opacity_ = value;
607     renderContext->UpdateOpacity(static_cast<double>(value) / UINT8_MAX);
608     host->MarkNeedRenderOnly();
609 }
610 
SetAccessibilityAction()611 void ScrollBarPattern::SetAccessibilityAction()
612 {
613     auto host = GetHost();
614     CHECK_NULL_VOID(host);
615     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
616     CHECK_NULL_VOID(accessibilityProperty);
617     accessibilityProperty->SetActionScrollForward([weakPtr = WeakClaim(this)]() {
618         const auto& pattern = weakPtr.Upgrade();
619         CHECK_NULL_VOID(pattern);
620         if (pattern->GetAxis() == Axis::NONE || pattern->GetScrollableDistance() == 0.0f) {
621             return;
622         }
623         pattern->UpdateCurrentOffset(pattern->GetChildOffset(), SCROLL_FROM_BAR);
624         // AccessibilityEventType::SCROLL_END
625     });
626 
627     accessibilityProperty->SetActionScrollBackward([weakPtr = WeakClaim(this)]() {
628         const auto& pattern = weakPtr.Upgrade();
629         CHECK_NULL_VOID(pattern);
630         if (pattern->GetAxis() == Axis::NONE || pattern->GetScrollableDistance() == 0.0f) {
631             return;
632         }
633         pattern->UpdateCurrentOffset(-pattern->GetChildOffset(), SCROLL_FROM_BAR);
634         // AccessibilityEventType::SCROLL_END
635     });
636 }
637 
InitPanRecognizer()638 void ScrollBarPattern::InitPanRecognizer()
639 {
640     PanDirection panDirection;
641     panDirection.type = axis_ == Axis::HORIZONTAL ? PanDirection::HORIZONTAL : PanDirection::VERTICAL;
642     const static int32_t PLATFORM_VERSION_TEN = 10;
643     float distance = DEFAULT_PAN_DISTANCE.Value();
644     auto context = PipelineContext::GetCurrentContext();
645     if (context && (context->GetMinPlatformVersion() >= PLATFORM_VERSION_TEN)) {
646         distance = DEFAULT_PAN_DISTANCE.ConvertToPx();
647     }
648     panRecognizer_ = MakeRefPtr<PanRecognizer>(1, panDirection, distance);
649     panRecognizer_->SetOnActionUpdate([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
650         auto scrollBar = weakBar.Upgrade();
651         if (scrollBar) {
652             scrollBar->HandleDragUpdate(info);
653         }
654     });
655     panRecognizer_->SetOnActionEnd([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
656         auto scrollBar = weakBar.Upgrade();
657         if (scrollBar) {
658             scrollBar->HandleDragEnd(info);
659         }
660     });
661     panRecognizer_->SetOnActionStart([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
662         auto scrollBar = weakBar.Upgrade();
663         if (scrollBar) {
664             scrollBar->HandleDragStart(info);
665         }
666     });
667     panRecognizer_->SetOnActionCancel([weakBar = AceType::WeakClaim(this)]() {
668         auto scrollBar = weakBar.Upgrade();
669         if (scrollBar) {
670             GestureEvent info;
671             scrollBar->HandleDragEnd(info);
672         }
673     });
674 }
675 
HandleDragStart(const GestureEvent & info)676 void ScrollBarPattern::HandleDragStart(const GestureEvent& info)
677 {
678     StopMotion();
679     SetDragStartPosition(GetMainOffset(Offset(info.GetGlobalPoint().GetX(), info.GetGlobalPoint().GetY())));
680     TAG_LOGI(AceLogTag::ACE_SCROLL_BAR, "outer scrollBar drag start");
681     ACE_SCOPED_TRACE("outer scrollBar HandleDragStart");
682     if (scrollPositionCallback_) {
683         if (scrollBarProxy_) {
684             scrollBarProxy_->NotifyScrollStart();
685             scrollBarProxy_->SetScrollSnapTrigger_(true);
686         }
687         scrollPositionCallback_(0, SCROLL_FROM_START);
688     }
689 }
690 
HandleDragUpdate(const GestureEvent & info)691 void ScrollBarPattern::HandleDragUpdate(const GestureEvent& info)
692 {
693     if (scrollPositionCallback_) {
694         auto offset = info.GetMainDelta();
695         if (IsReverse()) {
696             offset = -offset;
697         }
698         // The offset of the mouse wheel and gesture is opposite.
699         if (info.GetInputEventType() == InputEventType::AXIS && !NearZero(controlDistance_)) {
700             offset = - offset * scrollableDistance_ / controlDistance_;
701         }
702         ACE_SCOPED_TRACE("outer scrollBar HandleDragUpdate offset:%f", offset);
703         scrollPositionCallback_(offset, SCROLL_FROM_BAR);
704     }
705 }
706 
HandleDragEnd(const GestureEvent & info)707 void ScrollBarPattern::HandleDragEnd(const GestureEvent& info)
708 {
709     auto velocity = IsReverse() ? -info.GetMainVelocity() : info.GetMainVelocity();
710     TAG_LOGI(AceLogTag::ACE_SCROLL_BAR, "outer scrollBar drag end, velocity is %{public}f", velocity);
711     ACE_SCOPED_TRACE("outer scrollBar HandleDragEnd velocity:%f", velocity);
712     SetDragEndPosition(GetMainOffset(Offset(info.GetGlobalPoint().GetX(), info.GetGlobalPoint().GetY())));
713     if (NearZero(velocity) || info.GetInputEventType() == InputEventType::AXIS) {
714         if (scrollEndCallback_) {
715             if (scrollBarProxy_) {
716                 scrollBarProxy_->NotifyScrollStop();
717                 scrollBarProxy_->SetScrollSnapTrigger_(false);
718             }
719             scrollEndCallback_();
720         }
721         return;
722     }
723     frictionPosition_ = 0.0;
724     if (frictionMotion_) {
725         frictionMotion_->Reset(friction_, 0, velocity);
726     } else {
727         frictionMotion_ = AceType::MakeRefPtr<FrictionMotion>(friction_, 0, velocity);
728         frictionMotion_->AddListener([weakBar = AceType::WeakClaim(this)](double value) {
729             auto scrollBar = weakBar.Upgrade();
730             CHECK_NULL_VOID(scrollBar);
731             scrollBar->ProcessFrictionMotion(value);
732         });
733     }
734     CHECK_NULL_VOID(!scrollBarProxy_ || !scrollBarProxy_->NotifySnapScroll(-(frictionMotion_->GetFinalPosition()),
735         velocity, GetScrollableDistance(), static_cast<float>(GetDragOffset())));
736     scrollBarProxy_->SetScrollSnapTrigger_(false);
737     if (!frictionController_) {
738         frictionController_ = CREATE_ANIMATOR(PipelineContext::GetCurrentContext());
739         frictionController_->AddStopListener([weakBar = AceType::WeakClaim(this)]() {
740             auto scrollBar = weakBar.Upgrade();
741             CHECK_NULL_VOID(scrollBar);
742             scrollBar->ProcessFrictionMotionStop();
743         });
744     }
745     frictionController_->PlayMotion(frictionMotion_);
746 }
747 
ProcessFrictionMotion(double value)748 void ScrollBarPattern::ProcessFrictionMotion(double value)
749 {
750     if (scrollPositionCallback_) {
751         auto offset = value - frictionPosition_;
752         scrollPositionCallback_(offset, SCROLL_FROM_BAR_FLING);
753     }
754     frictionPosition_ = value;
755 }
756 
ProcessFrictionMotionStop()757 void ScrollBarPattern::ProcessFrictionMotionStop()
758 {
759     if (scrollEndCallback_) {
760         if (scrollBarProxy_) {
761             scrollBarProxy_->NotifyScrollStop();
762         }
763         scrollEndCallback_();
764     }
765 }
766 
OnCollectTouchTarget(const OffsetF & coordinateOffset,const GetEventTargetImpl & getEventTargetImpl,TouchTestResult & result,const RefPtr<FrameNode> & frameNode,const RefPtr<TargetComponent> & targetComponent,ResponseLinkResult & responseLinkResult)767 void ScrollBarPattern::OnCollectTouchTarget(const OffsetF& coordinateOffset,
768     const GetEventTargetImpl& getEventTargetImpl, TouchTestResult& result, const RefPtr<FrameNode>& frameNode,
769     const RefPtr<TargetComponent>& targetComponent, ResponseLinkResult& responseLinkResult)
770 {
771     if (panRecognizer_) {
772         panRecognizer_->SetCoordinateOffset(Offset(coordinateOffset.GetX(), coordinateOffset.GetY()));
773         panRecognizer_->SetGetEventTargetImpl(getEventTargetImpl);
774         panRecognizer_->SetNodeId(frameNode->GetId());
775         panRecognizer_->AttachFrameNode(frameNode);
776         panRecognizer_->SetTargetComponent(targetComponent);
777         panRecognizer_->SetIsSystemGesture(true);
778         panRecognizer_->SetRecognizerType(GestureTypeName::PAN_GESTURE);
779         result.emplace_front(panRecognizer_);
780         responseLinkResult.emplace_back(panRecognizer_);
781     }
782 }
783 
IsReverse() const784 bool ScrollBarPattern::IsReverse() const
785 {
786     return isReverse_;
787 }
788 
SetReverse(bool reverse)789 void ScrollBarPattern::SetReverse(bool reverse)
790 {
791     isReverse_ = reverse;
792 }
793 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const794 void ScrollBarPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
795 {
796     /* no fixed attr below, just return */
797     if (filter.IsFastFilter()) {
798         return;
799     }
800 
801     json->PutExtAttr("enableNestedScroll", enableNestedSorll_ ? "true" : "false", filter);
802 }
803 
OnCollectClickTarget(const OffsetF & coordinateOffset,const GetEventTargetImpl & getEventTargetImpl,TouchTestResult & result,const RefPtr<FrameNode> & frameNode,const RefPtr<TargetComponent> & targetComponent,ResponseLinkResult & responseLinkResult)804 void ScrollBarPattern::OnCollectClickTarget(const OffsetF& coordinateOffset,
805     const GetEventTargetImpl& getEventTargetImpl, TouchTestResult& result, const RefPtr<FrameNode>& frameNode,
806     const RefPtr<TargetComponent>& targetComponent, ResponseLinkResult& responseLinkResult)
807 {
808     if (clickRecognizer_) {
809         clickRecognizer_->SetCoordinateOffset(Offset(coordinateOffset.GetX(), coordinateOffset.GetY()));
810         clickRecognizer_->SetGetEventTargetImpl(getEventTargetImpl);
811         clickRecognizer_->SetNodeId(frameNode->GetId());
812         clickRecognizer_->AttachFrameNode(frameNode);
813         clickRecognizer_->SetTargetComponent(targetComponent);
814         clickRecognizer_->SetIsSystemGesture(true);
815         clickRecognizer_->SetRecognizerType(GestureTypeName::CLICK);
816         result.emplace_front(clickRecognizer_);
817         responseLinkResult.emplace_back(clickRecognizer_);
818     }
819 }
820 
OnCollectLongPressTarget(const OffsetF & coordinateOffset,const GetEventTargetImpl & getEventTargetImpl,TouchTestResult & result,const RefPtr<FrameNode> & frameNode,const RefPtr<TargetComponent> & targetComponent,ResponseLinkResult & responseLinkResult)821 void ScrollBarPattern::OnCollectLongPressTarget(const OffsetF& coordinateOffset,
822     const GetEventTargetImpl& getEventTargetImpl, TouchTestResult& result,
823     const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
824     ResponseLinkResult& responseLinkResult)
825 {
826     if (longPressRecognizer_) {
827         longPressRecognizer_->SetCoordinateOffset(Offset(coordinateOffset.GetX(), coordinateOffset.GetY()));
828         longPressRecognizer_->SetGetEventTargetImpl(getEventTargetImpl);
829         longPressRecognizer_->SetNodeId(frameNode->GetId());
830         longPressRecognizer_->AttachFrameNode(frameNode);
831         longPressRecognizer_->SetTargetComponent(targetComponent);
832         longPressRecognizer_->SetIsSystemGesture(true);
833         longPressRecognizer_->SetRecognizerType(GestureTypeName::LONG_PRESS_GESTURE);
834         longPressRecognizer_->SetSysGestureJudge([](const RefPtr<GestureInfo>& gestureInfo,
835                                                      const std::shared_ptr<BaseGestureEvent>&) -> GestureJudgeResult {
836             const auto &inputEventType = gestureInfo->GetInputEventType();
837             TAG_LOGI(AceLogTag::ACE_SCROLL_BAR, "input event type:%{public}d", inputEventType);
838             return inputEventType == InputEventType::MOUSE_BUTTON ? GestureJudgeResult::CONTINUE
839                                                                   : GestureJudgeResult::REJECT;
840         });
841         result.emplace_front(longPressRecognizer_);
842         responseLinkResult.emplace_back(longPressRecognizer_);
843     }
844 }
845 
InitClickEvent()846 void ScrollBarPattern::InitClickEvent()
847 {
848     clickRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>();
849     std::set<SourceTool> allowedTypes = { SourceTool::MOUSE };
850     auto gestureInfo = MakeRefPtr<GestureInfo>(allowedTypes);
851     clickRecognizer_->SetGestureInfo(gestureInfo);
852     clickRecognizer_->SetOnClick([weakBar = AceType::WeakClaim(this)](const ClickInfo&) {
853         auto scrollBar = weakBar.Upgrade();
854         if (scrollBar) {
855             scrollBar->HandleClickEvent();
856         }
857     });
858 }
859 
HandleClickEvent()860 void ScrollBarPattern::HandleClickEvent()
861 {
862     auto host = GetHost();
863     CHECK_NULL_VOID(host);
864     auto infoOffset = OffsetF(locationInfo_.GetX(), locationInfo_.GetY());
865     auto scrollBarTopOffset = OffsetF(childRect_.Left(), childRect_.Top());
866     auto scrollBarBottomOffset = OffsetF(childRect_.Right(), childRect_.Bottom());
867     if (infoOffset.GetMainOffset(axis_) < scrollBarTopOffset.GetMainOffset(axis_)) {
868         scrollBarProxy_->ScrollPage(true, true);
869     } else if (infoOffset.GetMainOffset(axis_) > scrollBarBottomOffset.GetMainOffset(axis_)) {
870         scrollBarProxy_->ScrollPage(false, true);
871     }
872 }
873 
InitLongPressEvent()874 void ScrollBarPattern::InitLongPressEvent()
875 {
876     longPressRecognizer_ = AceType::MakeRefPtr<LongPressRecognizer>(LONG_PRESS_TIME_THRESHOLD_MS, 1, false, false);
877     longPressRecognizer_->SetOnAction([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
878         auto scrollBar = weakBar.Upgrade();
879         if (scrollBar) {
880             scrollBar->HandleLongPress(true);
881         }
882     });
883 }
884 
HandleLongPress(bool smooth)885 void ScrollBarPattern::HandleLongPress(bool smooth)
886 {
887     bool reverse = false;
888     auto infoOffset = OffsetF(locationInfo_.GetX(), locationInfo_.GetY());
889     auto scrollBarTopOffset = OffsetF(childRect_.Left(), childRect_.Top());
890     auto scrollBarBottomOffset = OffsetF(childRect_.Right(), childRect_.Bottom());
891     if (infoOffset.GetMainOffset(axis_) < scrollBarTopOffset.GetMainOffset(axis_)) {
892         reverse = true;
893         if (scrollingDown_) {
894             return;
895         }
896         scrollingUp_ = true;
897         scrollingDown_ = false;
898     } else if (infoOffset.GetMainOffset(axis_) > scrollBarBottomOffset.GetMainOffset(axis_)) {
899         reverse = false;
900         if (scrollingUp_) {
901             return;
902         }
903         scrollingUp_ = false;
904         scrollingDown_ = true;
905     } else {
906         isMousePressed_ = false;
907         scrollingUp_ = false;
908         scrollingDown_ = false;
909     }
910     if (isMousePressed_ && IsInScrollBar()) {
911         scrollBarProxy_->ScrollPage(reverse, smooth);
912         StartLongPressEventTimer();
913     }
914 }
915 
ScheduleCaretLongPress()916 void ScrollBarPattern::ScheduleCaretLongPress()
917 {
918     auto context = OHOS::Ace::PipelineContext::GetCurrentContext();
919     CHECK_NULL_VOID(context);
920     if (!context->GetTaskExecutor()) {
921         return;
922     }
923     auto taskExecutor = context->GetTaskExecutor();
924     CHECK_NULL_VOID(taskExecutor);
925     taskExecutor->PostDelayedTask(
926         [weak = WeakClaim(this)]() {
927             auto pattern = weak.Upgrade();
928             CHECK_NULL_VOID(pattern);
929             pattern->HandleLongPress(true);
930         },
931         TaskExecutor::TaskType::UI, LONG_PRESS_PAGE_INTERVAL_MS, "ArkUIScrollBarHandleLongPress");
932 }
933 
StartLongPressEventTimer()934 void ScrollBarPattern::StartLongPressEventTimer()
935 {
936     auto tmpHost = GetHost();
937     CHECK_NULL_VOID(tmpHost);
938     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
939     ScheduleCaretLongPress();
940 }
941 
InitMouseEvent()942 void ScrollBarPattern::InitMouseEvent()
943 {
944     CHECK_NULL_VOID(!mouseEvent_);
945     auto host = GetHost();
946     CHECK_NULL_VOID(host);
947     auto inputHub = host->GetOrCreateInputEventHub();
948     CHECK_NULL_VOID(inputHub);
949     auto mouseCallback = [weak = WeakClaim(this)](MouseInfo& info) {
950         auto pattern = weak.Upgrade();
951         CHECK_NULL_VOID(pattern);
952         if (info.GetButton() == MouseButton::LEFT_BUTTON && info.GetAction() == MouseAction::PRESS) {
953             pattern->isMousePressed_ = true;
954         } else {
955             pattern->isMousePressed_ = false;
956             pattern->scrollingUp_ = false;
957             pattern->scrollingDown_ = false;
958         }
959         pattern->locationInfo_ = info.GetLocalLocation();
960     };
961     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseCallback));
962     inputHub->AddOnMouseEvent(mouseEvent_);
963 }
964 } // namespace OHOS::Ace::NG
965