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