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