1 /*
2  * Copyright (c) 2021-2023 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/common/painter/rosen_scroll_bar_painter.h"
17 
18 #ifndef USE_ROSEN_DRAWING
19 #include "include/core/SkCanvas.h"
20 #include "include/core/SkPaint.h"
21 #else
22 #include "core/components_ng/render/drawing.h"
23 #endif
24 
25 namespace OHOS::Ace {
26 namespace {
27 
28 constexpr double FULL_ALPHA = 255.0;
29 #ifdef USE_ROSEN_DRAWING
30 constexpr float FLOAT_HALF = 0.5f;
31 #endif
32 
33 } // namespace
34 
35 #ifndef USE_ROSEN_DRAWING
PaintBar(SkCanvas * canvas,const Offset & offset,const Rect & paintRect,const RefPtr<ScrollBar> & scrollBar,const Offset & globalOffset,int32_t alpha)36 void RosenScrollBarPainter::PaintBar(SkCanvas* canvas, const Offset& offset, const Rect& paintRect,
37     const RefPtr<ScrollBar>& scrollBar, const Offset& globalOffset, int32_t alpha)
38 #else
39 void RosenScrollBarPainter::PaintBar(RSCanvas* canvas, const Offset& offset,
40     const Rect& paintRect, const RefPtr<ScrollBar>& scrollBar, const Offset& globalOffset, int32_t alpha)
41 #endif
42 {
43     if ((canvas != nullptr) && scrollBar && scrollBar->NeedScrollBar()) {
44         if (scrollBar->GetShapeMode() == ShapeMode::RECT) {
45             PaintRectBar(canvas, offset, scrollBar, alpha);
46         } else {
47             PaintCircleBar(canvas, globalOffset, paintRect, scrollBar);
48         }
49     }
50 }
51 
52 #ifndef USE_ROSEN_DRAWING
PaintCircleBar(SkCanvas * canvas,const Offset & offset,const Rect & paintRect,const RefPtr<ScrollBar> & scrollBar)53 void RosenScrollBarPainter::PaintCircleBar(
54     SkCanvas* canvas, const Offset& offset, const Rect& paintRect, const RefPtr<ScrollBar>& scrollBar)
55 {
56     if (canvas && scrollBar->GetTrickSweepAngle() > 0.0) {
57         SkPaint paint;
58         paint.setBlendMode(SkBlendMode::kSrcOver);
59         paint.setAntiAlias(true);
60         paint.setStyle(SkPaint::Style::kStroke_Style);
61         paint.setStrokeWidth(scrollBar->GetNormalWidthToPx());
62         paint.setStrokeCap(SkPaint::kRound_Cap);
63 
64         auto rootSize = scrollBar->GetRootSize();
65         // do not draw scrollbar when central is out of scroll viewport
66         if (rootSize.Height() * SK_ScalarHalf < offset.GetY() ||
67             rootSize.Height() * SK_ScalarHalf > offset.GetY() + paintRect.Height()) {
68             return;
69         }
70         double scrollBarWidth = scrollBar->GetNormalWidthToPx();
71         double diameter = rootSize.Width() - scrollBarWidth;
72         SkRect arcRect =
73             SkRect::MakeXYWH(scrollBarWidth * SK_ScalarHalf, scrollBarWidth * SK_ScalarHalf, diameter, diameter);
74         // paint background
75         double deltaAngle = scrollBar->GetBottomAngle() - scrollBar->GetTopAngle();
76         paint.setColor(scrollBar->GetBackgroundColor().GetValue());
77         if (scrollBar->GetPositionMode() == PositionMode::LEFT) {
78             canvas->drawArc(arcRect, deltaAngle * SK_ScalarHalf - STRAIGHT_ANGLE, -deltaAngle, false, paint);
79         } else {
80             canvas->drawArc(arcRect, -deltaAngle * SK_ScalarHalf, deltaAngle, false, paint);
81         }
82 
83         // paint foreground
84         paint.setColor(scrollBar->GetForegroundColor().GetValue());
85         canvas->drawArc(arcRect, scrollBar->GetTrickStartAngle(), scrollBar->GetTrickSweepAngle(), false, paint);
86     }
87 }
88 #else
PaintCircleBar(RSCanvas * canvas,const Offset & offset,const Rect & paintRect,const RefPtr<ScrollBar> & scrollBar)89 void RosenScrollBarPainter::PaintCircleBar(RSCanvas* canvas, const Offset& offset,
90     const Rect& paintRect, const RefPtr<ScrollBar>& scrollBar)
91 {
92     if (canvas && scrollBar->GetTrickSweepAngle() > 0.0) {
93         RSPen pen;
94         pen.SetBlendMode(RSBlendMode::SRC_OVER);
95         pen.SetAntiAlias(true);
96         pen.SetWidth(scrollBar->GetNormalWidthToPx());
97         pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
98 
99         auto rootSize = scrollBar->GetRootSize();
100         // do not draw scrollbar when central is out of scroll viewport
101         if (rootSize.Height() * FLOAT_HALF < offset.GetY() ||
102             rootSize.Height() * FLOAT_HALF > offset.GetY() + paintRect.Height()) {
103             return;
104         }
105         double scrollBarWidth = scrollBar->GetNormalWidthToPx();
106         double diameter = rootSize.Width() - scrollBarWidth;
107         RSRect arcRect = RSRect(
108             scrollBarWidth * FLOAT_HALF,
109             scrollBarWidth * FLOAT_HALF,
110             diameter + scrollBarWidth * FLOAT_HALF,
111             diameter + scrollBarWidth * FLOAT_HALF);
112         // paint background
113         double deltaAngle = scrollBar->GetBottomAngle() - scrollBar->GetTopAngle();
114         pen.SetColor(scrollBar->GetBackgroundColor().GetValue());
115         canvas->AttachPen(pen);
116         if (scrollBar->GetPositionMode() == PositionMode::LEFT) {
117             canvas->DrawArc(arcRect, deltaAngle * FLOAT_HALF - STRAIGHT_ANGLE, -deltaAngle);
118         } else {
119             canvas->DrawArc(arcRect, -deltaAngle * FLOAT_HALF, deltaAngle);
120         }
121         canvas->DetachPen();
122 
123         // paint foreground
124         pen.SetColor(scrollBar->GetForegroundColor().GetValue());
125         canvas->AttachPen(pen);
126         canvas->DrawArc(arcRect, scrollBar->GetTrickStartAngle(), scrollBar->GetTrickSweepAngle());
127         canvas->DetachPen();
128     }
129 }
130 #endif
131 
132 #ifndef USE_ROSEN_DRAWING
PaintRectBar(SkCanvas * canvas,const Offset & offset,const RefPtr<ScrollBar> & scrollBar,int32_t alpha)133 void RosenScrollBarPainter::PaintRectBar(
134     SkCanvas* canvas, const Offset& offset, const RefPtr<ScrollBar>& scrollBar, int32_t alpha)
135 {
136     Rect activeRect = scrollBar->GetActiveRect();
137     Rect barRect = scrollBar->GetBarRect();
138     if (canvas && !NearZero(activeRect.Height()) && !NearZero(barRect.Height())) {
139         SkPaint paint;
140         paint.setBlendMode(SkBlendMode::kSrcOver);
141         paint.setAntiAlias(true);
142         paint.setStyle(SkPaint::Style::kStrokeAndFill_Style);
143         paint.setStrokeCap(SkPaint::kRound_Cap);
144 
145         // paint background
146         SkRect backgroundRect = SkRect::MakeLTRB(barRect.Left(), barRect.Top(), barRect.Right(), barRect.Bottom());
147         paint.setColor(scrollBar->GetBackgroundColor().GetValue());
148         double filletRadius = backgroundRect.width() * SK_ScalarHalf;
149         canvas->drawRoundRect(backgroundRect, filletRadius, filletRadius, paint);
150 
151         // paint foreground
152         paint.setColor(scrollBar->GetForegroundColor().BlendOpacity(alpha / FULL_ALPHA).GetValue());
153         SkRect foregroundRect =
154             SkRect::MakeLTRB(activeRect.Left(), activeRect.Top(), activeRect.Right(), activeRect.Bottom());
155         canvas->drawRoundRect(foregroundRect, filletRadius, filletRadius, paint);
156         RenderScrollBarBoundary(canvas, activeRect.GetOffset(), activeRect.Width(), activeRect.Height());
157     }
158 }
159 #else
PaintRectBar(RSCanvas * canvas,const Offset & offset,const RefPtr<ScrollBar> & scrollBar,int32_t alpha)160 void RosenScrollBarPainter::PaintRectBar(
161     RSCanvas* canvas, const Offset& offset, const RefPtr<ScrollBar>& scrollBar, int32_t alpha)
162 {
163     Rect activeRect = scrollBar->GetActiveRect();
164     Rect barRect = scrollBar->GetBarRect();
165     if (canvas && !NearZero(activeRect.Height()) && !NearZero(barRect.Height())) {
166         RSPen pen;
167         pen.SetBlendMode(RSBlendMode::SRC_OVER);
168         pen.SetAntiAlias(true);
169         pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
170         RSBrush brush;
171         brush.SetBlendMode(RSBlendMode::SRC_OVER);
172         brush.SetAntiAlias(true);
173 
174         // paint background
175         RSRect backgroundRect = RSRect(
176             barRect.Left(), barRect.Top(), barRect.Right(), barRect.Bottom());
177         pen.SetColor(scrollBar->GetBackgroundColor().GetValue());
178         brush.SetColor(scrollBar->GetBackgroundColor().GetValue());
179         double filletRadius = backgroundRect.GetWidth() * FLOAT_HALF;
180         canvas->AttachPen(pen);
181         canvas->AttachBrush(brush);
182         RSRoundRect backRoundRect(backgroundRect, filletRadius, filletRadius);
183         canvas->DrawRoundRect(backRoundRect);
184         canvas->DetachPen();
185         canvas->DetachBrush();
186 
187         // paint foreground
188         pen.SetColor(scrollBar->GetForegroundColor().BlendOpacity(alpha / FULL_ALPHA).GetValue());
189         brush.SetColor(scrollBar->GetForegroundColor().BlendOpacity(alpha / FULL_ALPHA).GetValue());
190         RSRect foregroundRect = RSRect(
191             activeRect.Left(), activeRect.Top(), activeRect.Right(), activeRect.Bottom());
192         RSRoundRect foreRoundRect(foregroundRect, filletRadius, filletRadius);
193         canvas->AttachPen(pen);
194         canvas->AttachBrush(brush);
195         canvas->DrawRoundRect(foreRoundRect);
196         canvas->DetachPen();
197         canvas->DetachBrush();
198         RenderScrollBarBoundary(canvas, activeRect.GetOffset(), activeRect.Width(), activeRect.Height());
199     }
200 }
201 #endif
202 
203 #ifndef USE_ROSEN_DRAWING
RenderScrollBarBoundary(SkCanvas * canvas,const Offset & offset,double width,double height)204 void RosenScrollBarPainter::RenderScrollBarBoundary(SkCanvas* canvas, const Offset& offset, double width, double height)
205 #else
206 void RosenScrollBarPainter::RenderScrollBarBoundary(RSCanvas* canvas, const Offset& offset,
207     double width, double height)
208 #endif
209 {
210     if (SystemProperties::GetDebugBoundaryEnabled()) {
211         if (canvas == nullptr) {
212             LOGE("Paint canvas is null.");
213             return;
214         }
215         Size layoutSize;
216         layoutSize.SetWidth(width);
217         layoutSize.SetHeight(height);
218         DebugBoundaryPainter::PaintDebugBoundary(canvas, offset, layoutSize);
219         DebugBoundaryPainter::PaintDebugCorner(canvas, offset, layoutSize);
220     }
221 }
222 
223 } // namespace OHOS::Ace