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/button/rosen_render_button.h"
17 
18 #ifndef USE_ROSEN_DRAWING
19 #include "include/core/SkMaskFilter.h"
20 #include "include/core/SkPath.h"
21 #include "include/core/SkRRect.h"
22 #endif
23 
24 #include "core/components/box/render_box.h"
25 #include "core/pipeline/base/rosen_render_context.h"
26 #ifdef OHOS_PLATFORM
27 #include "core/components/common/painter/rosen_svg_painter.h"
28 #endif
29 
30 namespace OHOS::Ace {
31 namespace {
32 
33 constexpr double HALF = 0.5;
34 
35 // Definition for arc button of watch which intersected by circle and ellipse.
36 constexpr Dimension CIRCLE_DIAMETER = 233.0_vp;
37 constexpr Dimension OVAL_WIDTH = 260.0_vp;
38 constexpr Dimension OVAL_HEIGHT = 98.0_vp;
39 constexpr Dimension OFFSET_X = (OVAL_WIDTH - ARC_BUTTON_WIDTH) / 2.0;
40 constexpr Dimension OFFSET_Y = CIRCLE_DIAMETER - ARC_BUTTON_HEIGHT;
41 constexpr double CIRCLE_START_ANGLE = 0.759;
42 constexpr double CIRCLE_SWEEP_ANGLE = M_PI - CIRCLE_START_ANGLE * 2;
43 constexpr double OVAL_START_ANGLE = 4.0;
44 constexpr double OVAL_SWEEP_ANGLE = M_PI * 3 - OVAL_START_ANGLE * 2;
45 constexpr double RADIAN_TO_DEGREE = 180.0 / M_PI;
46 
47 // Definition for download button in watch
48 constexpr Dimension CIRCLE_PROGRESS_THICKNESS = 2.0_vp;
49 constexpr Dimension WATCH_DOWNLOAD_SIZE_DELTA = 8.0_vp;
50 constexpr double PROGRESS_START_ANGLE = 1.5 * M_PI;
51 
52 // Definition for animation
53 constexpr uint8_t DEFAULT_OPACITY = 255;
54 
55 constexpr Dimension FOCUS_PADDING = 2.0_vp;
56 constexpr Dimension FOCUS_BORDER_WIDTH = 2.0_vp;
57 constexpr uint32_t FOCUS_BORDER_COLOR = 0xFF0A59F7;
58 constexpr uint32_t FOCUS_POPUP_BORDER_COLOR = 0xFFFFFFFF;
59 
60 } // namespace
61 
PerformLayout()62 void RosenRenderButton::PerformLayout()
63 {
64     RenderButton::PerformLayout();
65 
66     UpdateLayer();
67 }
68 
UpdateLayer()69 void RosenRenderButton::UpdateLayer()
70 {
71     float translateX = GetLayoutSize().Width() / 2 * (INIT_SCALE - scale_);
72     // The bottom of the component must be close to the bottom of the circle when the type is arc.
73     // The center point deviates 2 times downward.
74     float translateY = (buttonComponent_->GetType() == ButtonType::ARC)
75                         ? GetLayoutSize().Height() * (INIT_SCALE - scale_) * 2
76                         : GetLayoutSize().Height() / 2 * (1.0 - scale_);
77     Matrix4 translateMatrix = Matrix4::CreateTranslate(translateX, translateY, 0.0);
78     Matrix4 scaleMatrix = Matrix4::CreateScale(scale_, scale_, 1.0);
79     Matrix4 transformMatrix = translateMatrix * scaleMatrix;
80 
81     transformLayer_ = transformMatrix;
82     opacityLayer_ = DEFAULT_OPACITY * opacity_;
83 }
84 
85 #ifndef USE_ROSEN_DRAWING
PaintLayer(SkCanvas * canvas)86 void RosenRenderButton::PaintLayer(SkCanvas* canvas)
87 #else
88 void RosenRenderButton::PaintLayer(RSCanvas* canvas)
89 #endif
90 {
91 #ifdef OHOS_PLATFORM
92 #ifndef USE_ROSEN_DRAWING
93     auto recordingCanvas = static_cast<Rosen::RSRecordingCanvas*>(canvas);
94     recordingCanvas->MultiplyAlpha(opacityLayer_ / 255.0f);
95     recordingCanvas->concat(RosenSvgPainter::ToSkMatrix(transformLayer_));
96 #else
97     auto recordingCanvas = static_cast<RSRecordingCanvas*>(canvas);
98     recordingCanvas->ConcatMatrix(RosenSvgPainter::ToDrawingMatrix(transformLayer_));
99 #endif
100 #endif
101 }
102 
Paint(RenderContext & context,const Offset & offset)103 void RosenRenderButton::Paint(RenderContext& context, const Offset& offset)
104 {
105     if (!buttonComponent_) {
106         return;
107     }
108     if (isHover_) {
109         UpdateLayer();
110         isHover_ = false;
111     }
112     PaintButtonAnimation();
113     auto canvas = static_cast<RosenRenderContext&>(context).GetCanvas();
114     if (canvas == nullptr) {
115         LOGE("Paint canvas is null");
116         return;
117     }
118     PaintLayer(canvas);
119     if (buttonComponent_->GetType() == ButtonType::ICON) {
120         RenderNode::Paint(context, offset);
121         return;
122     }
123     DrawButton(canvas, offset);
124     auto pipeline = context_.Upgrade();
125     if (isFocus_ && (isTablet_ || isPhone_) && pipeline && pipeline->GetIsTabKeyPressed()) {
126         // Need to use PipelineContext::ShowFocusAnimation
127         if (buttonComponent_->IsPopupButton()) {
128             PaintPopupFocus(context);
129         } else {
130             PaintFocus(context, offset);
131         }
132         SyncFocusGeometryProperties();
133     }
134     RenderNode::Paint(context, offset);
135 }
136 
PaintButtonAnimation()137 void RosenRenderButton::PaintButtonAnimation()
138 {
139     if (!animationRunning_) {
140         return;
141     }
142     UpdateLayer();
143     if (isLastFrame_) {
144         animationRunning_ = false;
145         isOpacityAnimation_ = false;
146         isLastFrame_ = false;
147         isTouchAnimation_ = false;
148     }
149 }
150 
Measure()151 Size RosenRenderButton::Measure()
152 {
153     // Layout size need includes border width, the border width is half outside of button,
154     // total width and height needs to add border width defined by user.
155     if (!buttonComponent_) {
156         return Size();
157     }
158     widthDelta_ = NormalizeToPx(buttonComponent_->GetBorderEdge().GetWidth());
159     double delta = widthDelta_ / 2;
160     offsetDelta_ = Offset(delta, delta);
161     if (buttonComponent_->GetType() == ButtonType::ARC) {
162         return buttonSize_ + Size(widthDelta_, widthDelta_);
163     }
164     if (NeedLayoutExtendToParant()) {
165         buttonSize_ = GetLayoutParam().GetMaxSize();
166     }
167     MeasureButtonSize();
168     if (buttonComponent_->GetType() == ButtonType::NORMAL) {
169         if (buttonComponent_->GetDeclarativeFlag()) {
170             ResetBoxRadius();
171         }
172         if (!buttonComponent_->GetRadiusState() && buttonComponent_->IsInputButton()) {
173             rrectRadius_ = buttonSize_.Height() / 2.0;
174         }
175     }
176     return buttonSize_ + Size(widthDelta_, widthDelta_);
177 }
178 
MeasureButtonSize()179 void RosenRenderButton::MeasureButtonSize()
180 {
181     if (buttonComponent_->GetType() == ButtonType::ICON) {
182         return;
183     }
184     if (NearEqual(GetLayoutParam().GetMaxSize().Width(), Size::INFINITE_SIZE) || (!widthDefined_)) {
185         buttonSize_.SetWidth(0.0);
186     }
187     if (buttonComponent_->GetType() == ButtonType::CAPSULE) {
188         MeasureCapsule();
189         return;
190     }
191     if (buttonComponent_->GetType() == ButtonType::CIRCLE) {
192         MeasureCircle();
193         return;
194     }
195     if (isWatch_ && (buttonComponent_->GetType() == ButtonType::DOWNLOAD)) {
196         if (buttonComponent_->GetRadiusState() || widthDefined_ || heightDefined_) {
197             MeasureCircle();
198             progressDiameter_ = rrectRadius_ * 2 - NormalizeToPx(WATCH_DOWNLOAD_SIZE_DELTA);
199         } else {
200             buttonSize_ = Size(progressDiameter_ + NormalizeToPx(WATCH_DOWNLOAD_SIZE_DELTA),
201                 progressDiameter_ + NormalizeToPx(WATCH_DOWNLOAD_SIZE_DELTA));
202         }
203     }
204 }
205 
MeasureCapsule()206 void RosenRenderButton::MeasureCapsule()
207 {
208     if (GreatNotEqual(rrectRadius_, buttonSize_.Height() / 2.0)) {
209         return;
210     }
211     rrectRadius_ = buttonSize_.Height() / 2.0;
212     ResetBoxRadius();
213 }
214 
MeasureCircle()215 void RosenRenderButton::MeasureCircle()
216 {
217     if (!buttonComponent_->GetRadiusState()) {
218         if (widthDefined_ || heightDefined_) {
219             double minSize = std::min(GetLayoutParam().GetMaxSize().Width(), GetLayoutParam().GetMaxSize().Height());
220             if (buttonComponent_->GetDeclarativeFlag()) {
221                 minSize = widthDefined_ ? std::min(buttonSize_.Width(), buttonSize_.Height()) : buttonSize_.Height();
222             }
223             rrectRadius_ = (minSize - widthDelta_) / 2.0;
224         }
225     } else {
226         auto constrainedSize =
227             GetLayoutParam().Constrain(Size(rrectRadius_ * 2.0 + widthDelta_, rrectRadius_ * 2.0 + widthDelta_));
228         rrectRadius_ = (std::min(constrainedSize.Width(), constrainedSize.Height()) - widthDelta_) / 2.0;
229     }
230     buttonSize_.SetWidth(rrectRadius_ * 2.0);
231     buttonSize_.SetHeight(rrectRadius_ * 2.0);
232     ResetBoxRadius();
233 }
234 
ResetBoxRadius()235 void RosenRenderButton::ResetBoxRadius()
236 {
237     if (!buttonComponent_->GetRadiusState() && buttonComponent_->GetDeclarativeFlag()) {
238         return;
239     }
240     auto parent = GetParent().Upgrade();
241     if (!parent) {
242         return;
243     }
244     auto box = AceType::DynamicCast<RenderBox>(parent);
245     if (box) {
246         auto backDecoration = box->GetBackDecoration();
247         if (backDecoration) {
248             auto border = backDecoration->GetBorder();
249             backDecoration->SetBorderRadius(Radius(rrectRadius_ + NormalizeToPx(border.Top().GetWidth())));
250         }
251     }
252 }
253 
254 #ifndef USE_ROSEN_DRAWING
DrawShape(SkCanvas * canvas,const Offset & offset,bool isStroke)255 void RosenRenderButton::DrawShape(SkCanvas* canvas, const Offset& offset, bool isStroke)
256 {
257     SkPaint paint;
258     if (isStroke) {
259         uint32_t focusColorValue = buttonComponent_->GetFocusColor().GetValue();
260         uint32_t borderColorValue = buttonComponent_->GetBorderEdge().GetColor().GetValue();
261         paint.setColor(needFocusColor_ ? focusColorValue : borderColorValue);
262         paint.setStyle(SkPaint::Style::kStroke_Style);
263         paint.setStrokeWidth(NormalizeToPx(borderEdge_.GetWidth()));
264     } else {
265         paint.setColor(GetStateColor());
266         paint.setStyle(SkPaint::Style::kFill_Style);
267     }
268     paint.setAntiAlias(true);
269     SkRRect rRect;
270 
271     if (buttonComponent_->GetType() == ButtonType::CUSTOM) {
272         ConvertToSkVector(buttonComponent_->GetRectRadii(), radii_);
273         rRect.setRectRadii(SkRect::MakeIWH(buttonSize_.Width(), buttonSize_.Height()), radii_);
274     } else {
275         rRect.setRectXY(SkRect::MakeIWH(buttonSize_.Width(), buttonSize_.Height()), rrectRadius_, rrectRadius_);
276     }
277     rRect.offset(offset.GetX(), offset.GetY());
278 
279 #ifdef OHOS_PLATFORM
280     auto recordingCanvas = static_cast<Rosen::RSRecordingCanvas*>(canvas);
281     if (buttonComponent_->GetType() == ButtonType::CAPSULE) {
282         recordingCanvas->DrawAdaptiveRRectScale(0.5f, paint);
283     } else {
284         recordingCanvas->DrawAdaptiveRRect(rRect.getSimpleRadii().x(), paint);
285     }
286 #else
287     canvas->drawRRect(rRect, paint);
288 #endif
289 }
290 #else
DrawShape(RSCanvas * canvas,const Offset & offset,bool isStroke)291 void RosenRenderButton::DrawShape(RSCanvas* canvas, const Offset& offset, bool isStroke)
292 {
293     RSRoundRect rRect;
294 
295     if (isStroke) {
296         RSPen pen;
297         uint32_t focusColorValue = buttonComponent_->GetFocusColor().GetValue();
298         uint32_t borderColorValue = buttonComponent_->GetBorderEdge().GetColor().GetValue();
299         pen.SetColor(needFocusColor_ ? focusColorValue : borderColorValue);
300         pen.SetWidth(NormalizeToPx(borderEdge_.GetWidth()));
301         pen.SetAntiAlias(true);
302 
303         if (buttonComponent_->GetType() == ButtonType::CUSTOM) {
304             ConvertToVector(buttonComponent_->GetRectRadii(), radii_);
305             rRect = RSRoundRect(RSRect(0, 0, static_cast<RSScalar>(buttonSize_.Width()),
306                 static_cast<RSScalar>(buttonSize_.Height())), radii_);
307         } else {
308             rRect = RSRoundRect(RSRect(0, 0, static_cast<RSScalar>(buttonSize_.Width()),
309                 static_cast<RSScalar>(buttonSize_.Height())),
310                 rrectRadius_, rrectRadius_);
311         }
312         rRect.Offset(offset.GetX(), offset.GetY());
313 
314         canvas->AttachPen(pen);
315         canvas->DrawRoundRect(rRect);
316         canvas->DetachPen();
317     } else {
318         RSBrush brush;
319         brush.SetColor(GetStateColor());
320         brush.SetAntiAlias(true);
321 
322         if (buttonComponent_->GetType() == ButtonType::CUSTOM) {
323             ConvertToVector(buttonComponent_->GetRectRadii(), radii_);
324             rRect = RSRoundRect(RSRect(0, 0, static_cast<RSScalar>(buttonSize_.Width()),
325                 static_cast<RSScalar>(buttonSize_.Height())), radii_);
326         } else {
327             rRect = RSRoundRect(RSRect(0, 0, static_cast<RSScalar>(buttonSize_.Width()),
328                 static_cast<RSScalar>(buttonSize_.Height())),
329                 rrectRadius_, rrectRadius_);
330         }
331         rRect.Offset(offset.GetX(), offset.GetY());
332 
333         canvas->AttachBrush(brush);
334         canvas->DrawRoundRect(rRect);
335         canvas->DetachBrush();
336     }
337 }
338 #endif
339 
340 #ifndef USE_ROSEN_DRAWING
DrawArc(SkCanvas * canvas,const Offset & offset)341 void RosenRenderButton::DrawArc(SkCanvas* canvas, const Offset& offset)
342 {
343     double offsetDelta = NormalizeToPx((OVAL_WIDTH - CIRCLE_DIAMETER)) / 2;
344     SkPath arcPath;
345     arcPath.addArc({ 0, NormalizeToPx(OFFSET_Y), NormalizeToPx(OVAL_WIDTH), NormalizeToPx(OVAL_HEIGHT + OFFSET_Y) },
346         OVAL_START_ANGLE * RADIAN_TO_DEGREE, OVAL_SWEEP_ANGLE * RADIAN_TO_DEGREE);
347     arcPath.addArc({ offsetDelta, 0, NormalizeToPx(CIRCLE_DIAMETER) + offsetDelta, NormalizeToPx(CIRCLE_DIAMETER) },
348         CIRCLE_START_ANGLE * RADIAN_TO_DEGREE, CIRCLE_SWEEP_ANGLE * RADIAN_TO_DEGREE);
349     arcPath.offset(offset.GetX() - NormalizeToPx(OFFSET_X), offset.GetY() - NormalizeToPx(OFFSET_Y));
350 
351     SkPaint paint;
352     paint.setColor(GetStateColor());
353     paint.setStyle(SkPaint::Style::kFill_Style);
354     paint.setAntiAlias(true);
355     canvas->drawPath(arcPath, paint);
356 }
357 #else
DrawArc(RSCanvas * canvas,const Offset & offset)358 void RosenRenderButton::DrawArc(RSCanvas* canvas, const Offset& offset)
359 {
360     double offsetDelta = NormalizeToPx((OVAL_WIDTH - CIRCLE_DIAMETER)) / 2;
361     RSRecordingPath arcPath;
362     arcPath.AddArc(
363         RSRect(0, NormalizeToPx(OFFSET_Y), NormalizeToPx(OVAL_WIDTH), NormalizeToPx(OVAL_HEIGHT + OFFSET_Y)),
364         OVAL_START_ANGLE * RADIAN_TO_DEGREE, OVAL_SWEEP_ANGLE * RADIAN_TO_DEGREE);
365     arcPath.AddArc(
366         RSRect(offsetDelta, 0, NormalizeToPx(CIRCLE_DIAMETER) + offsetDelta, NormalizeToPx(CIRCLE_DIAMETER)),
367         CIRCLE_START_ANGLE * RADIAN_TO_DEGREE, CIRCLE_SWEEP_ANGLE * RADIAN_TO_DEGREE);
368     arcPath.Offset(offset.GetX() - NormalizeToPx(OFFSET_X), offset.GetY() - NormalizeToPx(OFFSET_Y));
369 
370     RSBrush brush;
371     brush.SetColor(GetStateColor());
372     brush.SetAntiAlias(true);
373     canvas->AttachBrush(brush);
374     canvas->DrawPath(arcPath);
375     canvas->DetachBrush();
376 }
377 #endif
378 
379 #ifndef USE_ROSEN_DRAWING
DrawLineProgress(SkCanvas * canvas,const Offset & offset)380 void RosenRenderButton::DrawLineProgress(SkCanvas* canvas, const Offset& offset)
381 {
382     SkPaint paint;
383     paint.setColor(needFocusColor_ ? progressFocusColor_.GetValue() : progressColor_.GetValue());
384     paint.setStyle(SkPaint::Style::kFill_Style);
385     paint.setAntiAlias(true);
386     SkRRect rRect;
387     rRect.setRectXY(SkRect::MakeWH(buttonSize_.Width(), buttonSize_.Height()), rrectRadius_, rrectRadius_);
388     rRect.offset(offset.GetX(), offset.GetY());
389     canvas->save();
390     canvas->clipRRect(rRect, true);
391     canvas->drawRect({ offset.GetX(), offset.GetY(), progressWidth_, buttonSize_.Height() }, paint);
392     canvas->restore();
393 }
394 #else
DrawLineProgress(RSCanvas * canvas,const Offset & offset)395 void RosenRenderButton::DrawLineProgress(RSCanvas* canvas, const Offset& offset)
396 {
397     RSBrush brush;
398     brush.SetColor(needFocusColor_ ? progressFocusColor_.GetValue() : progressColor_.GetValue());
399     brush.SetAntiAlias(true);
400     RSRoundRect rRect(
401         RSRect(0, 0, buttonSize_.Width(), buttonSize_.Height()), rrectRadius_, rrectRadius_);
402     rRect.Offset(offset.GetX(), offset.GetY());
403     canvas->Save();
404     canvas->ClipRoundRect(rRect, RSClipOp::INTERSECT, true);
405     canvas->AttachBrush(brush);
406     canvas->DrawRect({ offset.GetX(), offset.GetY(), progressWidth_, buttonSize_.Height() });
407     canvas->DetachBrush();
408     canvas->Restore();
409 }
410 #endif
411 
412 #ifndef USE_ROSEN_DRAWING
DrawLineProgressAnimation(SkCanvas * canvas,const Offset & offset)413 void RosenRenderButton::DrawLineProgressAnimation(SkCanvas* canvas, const Offset& offset)
414 {
415     double offsetX = offset.GetX();
416     double offsetY = offset.GetY();
417     double radius = buttonSize_.Height() / 2.0;
418     SkPath path;
419     path.addArc({ offsetX, offsetY, buttonSize_.Height() + offsetX, buttonSize_.Height() + offsetY }, 90, 180);
420     if (LessNotEqual(progressWidth_, radius)) {
421         path.addArc({ progressWidth_ + offsetX, offsetY, buttonSize_.Height() - progressWidth_ + offsetX,
422                         buttonSize_.Height() + offsetY },
423             270, -180);
424     } else if (GreatNotEqual(progressWidth_, buttonSize_.Width() - radius)) {
425         path.addRect(
426             { radius + offsetX, offsetY, buttonSize_.Width() - radius + offsetX, buttonSize_.Height() + offsetY });
427         path.addArc({ (buttonSize_.Width() - radius) * 2.0 - progressWidth_ + offsetX, offsetY,
428                         progressWidth_ + offsetX, buttonSize_.Height() + offsetY },
429             270, 180);
430     } else {
431         path.addRect({ radius + offsetX, offsetY, progressWidth_ + offsetX, buttonSize_.Height() + offsetY });
432     }
433     SkPaint paint;
434     paint.setColor(progressColor_.GetValue());
435     paint.setStyle(SkPaint::Style::kFill_Style);
436     paint.setAntiAlias(true);
437     canvas->drawPath(path, paint);
438 }
439 #else
DrawLineProgressAnimation(RSCanvas * canvas,const Offset & offset)440 void RosenRenderButton::DrawLineProgressAnimation(RSCanvas* canvas, const Offset& offset)
441 {
442     double offsetX = offset.GetX();
443     double offsetY = offset.GetY();
444     double radius = buttonSize_.Height() / 2.0;
445     RSRecordingPath path;
446     path.AddArc(RSRect(offsetX, offsetY, buttonSize_.Height() + offsetX, buttonSize_.Height() + offsetY),
447         90, 180);
448     if (LessNotEqual(progressWidth_, radius)) {
449         path.AddArc(RSRect(progressWidth_ + offsetX, offsetY,
450             buttonSize_.Height() - progressWidth_ + offsetX, buttonSize_.Height() + offsetY),
451             270, -180);
452     } else if (GreatNotEqual(progressWidth_, buttonSize_.Width() - radius)) {
453         path.AddRect(RSRect(radius + offsetX, offsetY, buttonSize_.Width() - radius + offsetX,
454             buttonSize_.Height() + offsetY),
455             RSPathDirection::CW_DIRECTION);
456         path.AddArc(RSRect((buttonSize_.Width() - radius) * 2.0 - progressWidth_ + offsetX, offsetY,
457             progressWidth_ + offsetX, buttonSize_.Height() + offsetY),
458             270, 180);
459     } else {
460         path.AddRect(
461             RSRect(radius + offsetX, offsetY, progressWidth_ + offsetX, buttonSize_.Height() + offsetY),
462             RSPathDirection::CW_DIRECTION);
463     }
464     RSBrush brush;
465     brush.SetColor(progressColor_.GetValue());
466     brush.SetAntiAlias(true);
467     canvas->AttachBrush(brush);
468     canvas->DrawPath(path);
469     canvas->DetachBrush();
470 }
471 #endif
472 
473 #ifndef USE_ROSEN_DRAWING
DrawCircleProgress(SkCanvas * canvas,const Offset & offset)474 void RosenRenderButton::DrawCircleProgress(SkCanvas* canvas, const Offset& offset)
475 {
476     SkPaint paint;
477     paint.setAntiAlias(true);
478     paint.setColor(progressColor_.GetValue());
479     paint.setStyle(SkPaint::Style::kStroke_Style);
480     paint.setStrokeWidth(NormalizeToPx(CIRCLE_PROGRESS_THICKNESS));
481     paint.setStrokeCap(SkPaint::kRound_Cap);
482     canvas->drawArc(
483         { offset.GetX(), offset.GetY(), progressDiameter_ + offset.GetX(), progressDiameter_ + offset.GetY() },
484         PROGRESS_START_ANGLE * RADIAN_TO_DEGREE, 360 * progressPercent_, false, paint);
485 }
486 #else
DrawCircleProgress(RSCanvas * canvas,const Offset & offset)487 void RosenRenderButton::DrawCircleProgress(RSCanvas* canvas, const Offset& offset)
488 {
489     RSPen pen;
490     pen.SetAntiAlias(true);
491     pen.SetColor(progressColor_.GetValue());
492     pen.SetWidth(NormalizeToPx(CIRCLE_PROGRESS_THICKNESS));
493     pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
494     canvas->AttachPen(pen);
495     canvas->DrawArc(RSRect(offset.GetX(), offset.GetY(),
496         progressDiameter_ + offset.GetX(), progressDiameter_ + offset.GetY()),
497         PROGRESS_START_ANGLE * RADIAN_TO_DEGREE, 360 * progressPercent_);
498     canvas->DetachPen();
499 }
500 #endif
501 
502 #ifndef USE_ROSEN_DRAWING
DrawDownloadButton(SkCanvas * canvas,const Offset & offset)503 void RosenRenderButton::DrawDownloadButton(SkCanvas* canvas, const Offset& offset)
504 #else
505 void RosenRenderButton::DrawDownloadButton(RSCanvas* canvas, const Offset& offset)
506 #endif
507 {
508     if (isWatch_) {
509 #ifndef USE_ROSEN_DRAWING
510         SkPaint paint;
511         paint.setAntiAlias(true);
512         paint.setStyle(SkPaint::Style::kFill_Style);
513         canvas->save();
514         paint.setColor(GetStateColor());
515         canvas->drawCircle(offset.GetX() + buttonSize_.Width() / 2, offset.GetY() + buttonSize_.Height() / 2,
516             (progressDiameter_ + NormalizeToPx(WATCH_DOWNLOAD_SIZE_DELTA)) / 2, paint);
517         canvas->restore();
518 #else
519         RSBrush brush;
520         brush.SetAntiAlias(true);
521         canvas->Save();
522         brush.SetColor(GetStateColor());
523         canvas->AttachBrush(brush);
524         canvas->DrawCircle(
525             RSPoint(offset.GetX() + buttonSize_.Width() / 2, offset.GetY() + buttonSize_.Height() / 2),
526             (progressDiameter_ + NormalizeToPx(WATCH_DOWNLOAD_SIZE_DELTA)) / 2);
527         canvas->DetachBrush();
528         canvas->Restore();
529 #endif
530         if (progressDisplay_) {
531             DrawCircleProgress(canvas, offset + Offset((buttonSize_.Width() - progressDiameter_) / 2,
532                 (buttonSize_.Height() - progressDiameter_) / 2));
533         }
534         return;
535     }
536 
537     DrawShape(canvas, offset);
538     if (isPhone_) {
539         DrawShape(canvas, offset, true);
540         if (progressDisplay_) {
541             if (GreatOrEqual(rrectRadius_, buttonSize_.Height() / 2.0)) {
542                 DrawLineProgressAnimation(canvas, offset);
543             } else {
544                 DrawLineProgress(canvas, offset);
545             }
546         }
547         return;
548     }
549     if (progressDisplay_) {
550         DrawShape(canvas, offset, true);
551         DrawLineProgress(canvas, offset);
552     }
553 }
554 
555 #ifndef USE_ROSEN_DRAWING
DrawButton(SkCanvas * canvas,const Offset & inOffset)556 void RosenRenderButton::DrawButton(SkCanvas* canvas, const Offset& inOffset)
557 #else
558 void RosenRenderButton::DrawButton(RSCanvas* canvas, const Offset& inOffset)
559 #endif
560 {
561     Offset offset = inOffset + offsetDelta_;
562     if (buttonComponent_->GetType() == ButtonType::ARC) {
563         DrawArc(canvas, offset);
564         return;
565     }
566     if (buttonComponent_->GetType() == ButtonType::DOWNLOAD) {
567         DrawDownloadButton(canvas, offset);
568         return;
569     }
570 
571     // Paint button with border
572     if (NormalizeToPx(buttonComponent_->GetBorderEdge().GetWidth()) > 0.0) {
573         DrawShape(canvas, offset);
574         DrawShape(canvas, offset, true);
575         return;
576     }
577     DrawShape(canvas, offset);
578 }
579 
GetStateColor()580 uint32_t RosenRenderButton::GetStateColor()
581 {
582     if (!buttonComponent_) {
583         return Color().GetValue();
584     }
585     if (!buttonComponent_->GetStateEffect()) {
586         return buttonComponent_->GetBackgroundColor().GetValue();
587     }
588     if (needHoverColor_) {
589         return buttonComponent_->GetHoverColor().GetValue();
590     }
591     if (buttonComponent_->GetDisabledState()) {
592         return buttonComponent_->GetDisabledColor().GetValue();
593     }
594     if (needFocusColor_) {
595         return buttonComponent_->GetFocusColor().GetValue();
596     }
597     Color backgroundColor = buttonComponent_->GetBackgroundColor();
598     if (NeedClickedColor(backgroundColor)) {
599         return isClicked_ ? clickedColor_.GetValue() : backgroundColor.GetValue();
600     }
601     if (!isMoveEventValid_) {
602         maskingOpacity_ = 0.0;
603     }
604     uint32_t animationColor;
605     if (isWatch_) {
606         animationColor = backgroundColor.BlendColor(Color::WHITE.ChangeOpacity(maskingOpacity_)).GetValue();
607     } else {
608         animationColor = backgroundColor.BlendColor(Color::BLACK.ChangeOpacity(maskingOpacity_)).GetValue();
609     }
610     return animationColor;
611 }
612 
NeedClickedColor(const Color & backgroundColor)613 bool RosenRenderButton::NeedClickedColor(const Color& backgroundColor)
614 {
615     if (setClickColor_) {
616         return true;
617     }
618     if (clickedColor_ != defaultClickedColor_) {
619         return true;
620     } else {
621         if (backgroundColor == Color::TRANSPARENT) {
622             return true;
623         }
624     }
625     return false;
626 }
627 
HasEffectiveTransform() const628 bool RosenRenderButton::HasEffectiveTransform() const
629 {
630     return scale_ != INIT_SCALE;
631 }
632 
633 #ifndef USE_ROSEN_DRAWING
ConvertToSkVector(const std::array<Radius,4> & radii,SkVector * skRadii)634 void RosenRenderButton::ConvertToSkVector(const std::array<Radius, 4>& radii, SkVector* skRadii)
635 #else
636 void RosenRenderButton::ConvertToVector(const std::array<Radius, 4>& radii, std::vector<RSPoint>& pRadii)
637 #endif
638 {
639     auto context = context_.Upgrade();
640     if (!context) {
641         return;
642     }
643     double dipScale = context->GetDipScale();
644     for (int32_t i = 0; i < 4; ++i) {
645 #ifndef USE_ROSEN_DRAWING
646         skRadii[i].set(SkDoubleToScalar(std::max(radii[i].GetX().ConvertToPx(dipScale), 0.0)),
647             SkDoubleToScalar(std::max(radii[i].GetY().ConvertToPx(dipScale), 0.0)));
648 #else
649         pRadii[i].SetX(static_cast<float>(std::max(radii[i].GetX().ConvertToPx(dipScale), 0.0)));
650         pRadii[i].SetY(static_cast<float>(std::max(radii[i].GetY().ConvertToPx(dipScale), 0.0)));
651 #endif
652     }
653 }
654 
PaintFocus(RenderContext & context,const Offset & offset)655 void RosenRenderButton::PaintFocus(RenderContext& context, const Offset& offset)
656 {
657     auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas();
658     if (!canvas) {
659         LOGE("paint canvas is null");
660         return;
661     }
662     Size canvasSize = GetLayoutSize();
663     double focusBorderHeight = canvasSize.Height() + NormalizeToPx(FOCUS_PADDING * 2 + FOCUS_BORDER_WIDTH);
664     double focusBorderWidth = canvasSize.Width() + NormalizeToPx(FOCUS_PADDING * 2 + FOCUS_BORDER_WIDTH);
665     double focusRadius = focusBorderHeight * HALF;
666     if (!buttonComponent_) {
667         return;
668     }
669     if (buttonComponent_->GetType() == ButtonType::NORMAL) {
670         focusRadius = rrectRadius_ + NormalizeToPx(FOCUS_PADDING);
671     }
672 
673 #ifndef USE_ROSEN_DRAWING
674     SkPaint paint;
675     paint.setColor(FOCUS_BORDER_COLOR);
676     paint.setStyle(SkPaint::Style::kStroke_Style);
677     paint.setStrokeWidth(NormalizeToPx(FOCUS_BORDER_WIDTH));
678     paint.setAntiAlias(true);
679     SkRRect rRect;
680     rRect.setRectXY(SkRect::MakeIWH(focusBorderWidth, focusBorderHeight), focusRadius, focusRadius);
681     rRect.offset(-NormalizeToPx(FOCUS_PADDING + FOCUS_BORDER_WIDTH * HALF),
682         -NormalizeToPx(FOCUS_PADDING + FOCUS_BORDER_WIDTH * HALF));
683     canvas->drawRRect(rRect, paint);
684 #else
685     RSPen pen;
686     pen.SetColor(FOCUS_BORDER_COLOR);
687     pen.SetWidth(NormalizeToPx(FOCUS_BORDER_WIDTH));
688     pen.SetAntiAlias(true);
689     RSRoundRect rRect(RSRect(0, 0, focusBorderWidth, focusBorderHeight), focusRadius, focusRadius);
690     rRect.Offset(-NormalizeToPx(FOCUS_PADDING + FOCUS_BORDER_WIDTH * HALF),
691         -NormalizeToPx(FOCUS_PADDING + FOCUS_BORDER_WIDTH * HALF));
692     canvas->AttachPen(pen);
693     canvas->DrawRoundRect(rRect);
694     canvas->DetachPen();
695 #endif
696 }
697 
698 #ifndef USE_ROSEN_DRAWING
PaintPopupFocus(RenderContext & context)699 void RosenRenderButton::PaintPopupFocus(RenderContext& context)
700 {
701     auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas();
702     if (!canvas) {
703         LOGE("paint canvas is null");
704         return;
705     }
706     Size canvasSize = GetLayoutSize();
707     double focusBorderHeight = canvasSize.Height() - NormalizeToPx(FOCUS_BORDER_WIDTH) / HALF;
708     double focusBorderWidth = canvasSize.Width() - NormalizeToPx(FOCUS_BORDER_WIDTH) / HALF;
709     double focusRadius = focusBorderHeight * HALF;
710     if (!buttonComponent_) {
711         return;
712     }
713 
714     SkPaint paint;
715     paint.setColor(FOCUS_POPUP_BORDER_COLOR);
716     paint.setStyle(SkPaint::Style::kStroke_Style);
717     paint.setStrokeWidth(NormalizeToPx(FOCUS_BORDER_WIDTH));
718     paint.setAntiAlias(true);
719     SkRRect rRect;
720     rRect.setRectXY(SkRect::MakeIWH(focusBorderWidth, focusBorderHeight), focusRadius, focusRadius);
721     rRect.offset(NormalizeToPx(FOCUS_BORDER_WIDTH), NormalizeToPx(FOCUS_BORDER_WIDTH));
722     canvas->drawRRect(rRect, paint);
723 }
724 #else
PaintPopupFocus(RenderContext & context)725 void RosenRenderButton::PaintPopupFocus(RenderContext& context)
726 {
727     auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas();
728     if (!canvas) {
729         LOGE("paint canvas is null");
730         return;
731     }
732     Size canvasSize = GetLayoutSize();
733     double focusBorderHeight = canvasSize.Height() - NormalizeToPx(FOCUS_BORDER_WIDTH) / HALF;
734     double focusBorderWidth = canvasSize.Width() - NormalizeToPx(FOCUS_BORDER_WIDTH) / HALF;
735     double focusRadius = focusBorderHeight * HALF;
736     if (!buttonComponent_) {
737         return;
738     }
739 
740     RSPen pen;
741     pen.SetColor(FOCUS_POPUP_BORDER_COLOR);
742     pen.SetWidth(NormalizeToPx(FOCUS_BORDER_WIDTH));
743     pen.SetAntiAlias(true);
744 
745     RSRoundRect rRect(RSRect(0, 0, focusBorderWidth, focusBorderHeight), focusRadius, focusRadius);
746     rRect.Offset(NormalizeToPx(FOCUS_BORDER_WIDTH), NormalizeToPx(FOCUS_BORDER_WIDTH));
747 
748     canvas->AttachPen(pen);
749     canvas->DrawRoundRect(rRect);
750     canvas->DetachPen();
751 }
752 #endif
753 
SyncFocusGeometryProperties()754 void RosenRenderButton::SyncFocusGeometryProperties()
755 {
756     auto rsNode = GetRSNode();
757     if (!rsNode) {
758         return;
759     }
760     Size boundsSize = GetLayoutSize();
761     double focusBorderHeight = boundsSize.Height() + NormalizeToPx(FOCUS_PADDING * 2 + FOCUS_BORDER_WIDTH);
762     double focusBorderWidth = boundsSize.Width() + NormalizeToPx(FOCUS_PADDING * 2 + FOCUS_BORDER_WIDTH);
763     Offset boundsOffset = GetPaintOffset() + Offset(-NormalizeToPx(FOCUS_PADDING + FOCUS_BORDER_WIDTH * HALF),
764                                                     -NormalizeToPx(FOCUS_PADDING + FOCUS_BORDER_WIDTH * HALF));
765     boundsOffset += Offset(-NormalizeToPx(FOCUS_PADDING), -NormalizeToPx(FOCUS_PADDING));
766     focusBorderWidth += 2 * NormalizeToPx(FOCUS_PADDING);
767     focusBorderHeight += 2 *NormalizeToPx(FOCUS_PADDING);
768     rsNode->SetBounds(boundsOffset.GetX(), boundsOffset.GetY(), focusBorderWidth, focusBorderHeight);
769     if (IsTailRenderNode()) {
770         Offset frameOffset = GetPaintOffset();
771         Size frameSize = GetLayoutSize();
772         rsNode->SetFrame(frameOffset.GetX(), frameOffset.GetY(), frameSize.Width(), frameSize.Height());
773     }
774 }
775 
776 } // namespace OHOS::Ace
777