1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components/common/painter/flutter_decoration_painter.h"
17
18 #include <cmath>
19 #include <functional>
20
21 #include "flutter/common/task_runners.h"
22 #include "include/core/SkColor.h"
23 #include "include/core/SkMaskFilter.h"
24 #include "include/effects/Sk1DPathEffect.h"
25 #ifndef NEW_SKIA
26 #include "include/effects/SkBlurImageFilter.h"
27 #else
28 #include "include/effects/SkImageFilters.h"
29 #endif
30 #include "include/effects/SkDashPathEffect.h"
31 #include "include/effects/SkGradientShader.h"
32 #include "include/utils/SkShadowUtils.h"
33
34 #include "core/components/common/painter/border_image_painter.h"
35 #include "core/components/common/properties/color.h"
36 #include "core/pipeline/base/flutter_render_context.h"
37 #include "core/pipeline/base/render_node.h"
38 #include "core/pipeline/pipeline_context.h"
39
40 namespace OHOS::Ace {
41 namespace {
42
43 constexpr int32_t DOUBLE_WIDTH = 2;
44 constexpr int32_t DASHED_LINE_LENGTH = 3;
45 constexpr float TOP_START = 225.0f;
46 constexpr float TOP_END = 270.0f;
47 constexpr float RIGHT_START = 315.0f;
48 constexpr float RIGHT_END = 0.0f;
49 constexpr float BOTTOM_START = 45.0f;
50 constexpr float BOTTOM_END = 90.0f;
51 constexpr float LEFT_START = 135.0f;
52 constexpr float LEFT_END = 180.0f;
53 constexpr float SWEEP_ANGLE = 45.0f;
54 constexpr float EXTEND = 1024.0f;
55 constexpr uint32_t COLOR_MASK = 0xff000000;
56
57 class GradientShader {
58 public:
59 struct ColorStop {
60 SkColor color { SK_ColorTRANSPARENT };
61 float offset { 0.0f };
62 bool hasValue { false };
63 bool isLength { false };
64 };
65
GradientShader(const Gradient & gradient)66 explicit GradientShader(const Gradient& gradient)
67 {
68 for (auto& stop : gradient.GetColors()) {
69 ColorStop colorStop;
70 colorStop.color = stop.GetColor().GetValue();
71 colorStop.hasValue = stop.GetHasValue();
72 if (colorStop.hasValue) {
73 colorStop.isLength = stop.GetDimension().Unit() != DimensionUnit::PERCENT;
74 if (colorStop.isLength) {
75 colorStop.offset = static_cast<float>(stop.GetDimension().Value());
76 } else {
77 colorStop.offset = static_cast<float>(stop.GetDimension().Value() / 100.0);
78 }
79 }
80 colorStops_.emplace_back(colorStop);
81 }
82 isRepeat_ = gradient.GetRepeat();
83 }
84 virtual ~GradientShader() = default;
CreateGradientShader()85 virtual sk_sp<SkShader> CreateGradientShader()
86 {
87 return nullptr;
88 }
89
90 protected:
AddColorStops(float gradientLength)91 void AddColorStops(float gradientLength)
92 {
93 uint32_t colorSize = colorStops_.size();
94 for (uint32_t i = 0; i < colorSize; i++) {
95 auto& colorStop = colorStops_[i];
96 if (colorStop.hasValue) {
97 if (colorStop.isLength) {
98 // only support px and percent
99 colorStop.offset = GreatNotEqual(gradientLength, 0.0) ? colorStop.offset / gradientLength : 0.0f;
100 colorStop.hasValue = true;
101 }
102 } else if (i == 0) {
103 // default: start with 0.0%
104 colorStop.offset = 0.0f;
105 colorStop.hasValue = true;
106 } else if (colorSize > 1 && i == colorSize - 1) {
107 // default: end with 100.0%
108 colorStop.offset = 1.0f;
109 colorStop.hasValue = true;
110 }
111 // make sure colors in increasing order
112 if (colorStop.hasValue && i > 0) {
113 auto prev = static_cast<int32_t>(i - 1);
114 while (prev >= 0 && !colorStops_[prev].hasValue) {
115 prev--;
116 }
117 if (prev >= 0 && colorStop.offset < colorStops_[prev].offset) {
118 colorStop.offset = colorStops_[prev].offset;
119 }
120 }
121 }
122 AdjustNoValueColorStop();
123 }
124
AdjustNoValueColorStop()125 void AdjustNoValueColorStop()
126 {
127 // deal with not specified color stop
128 uint32_t colorSize = colorStops_.size();
129 if (colorSize <= 2) {
130 return;
131 }
132 int32_t noValueStartIndex = 0;
133 bool inUnspecifiedRun = false;
134 for (uint32_t i = 0; i < colorSize; ++i) {
135 if (!colorStops_[i].hasValue && !inUnspecifiedRun) {
136 noValueStartIndex = static_cast<int32_t>(i);
137 inUnspecifiedRun = true;
138 } else if (colorStops_[i].hasValue && inUnspecifiedRun) {
139 auto noValueEndIndex = static_cast<int32_t>(i);
140 if (noValueStartIndex > 0 && noValueStartIndex < noValueEndIndex) {
141 auto beginValue = colorStops_[noValueStartIndex - 1].offset;
142 auto endValue = colorStops_[noValueEndIndex].offset;
143 auto delta = (endValue - beginValue) / static_cast<float>(noValueEndIndex - noValueStartIndex + 1);
144
145 for (int32_t j = noValueStartIndex; j < noValueEndIndex; ++j) {
146 colorStops_[j].offset = (beginValue + static_cast<float>(j - noValueStartIndex + 1) * delta);
147 colorStops_[j].hasValue = true;
148 }
149 }
150 inUnspecifiedRun = false;
151 }
152 }
153 }
154
NeedAdjustColorStops() const155 bool NeedAdjustColorStops() const
156 {
157 if (colorStops_.size() < 2) {
158 return false;
159 }
160
161 if (isRepeat_) {
162 return true;
163 }
164 // not in the range of [0, 1]
165 if (colorStops_.front().offset < 0.0f || colorStops_.back().offset > 1.0f) {
166 return true;
167 }
168 return false;
169 }
170
AdjustColorStops()171 void AdjustColorStops()
172 {
173 const auto firstOffset = colorStops_.front().offset;
174 const auto lastOffset = colorStops_.back().offset;
175 const float span = std::min(std::max(lastOffset - firstOffset, 0.0f), std::numeric_limits<float>::max());
176
177 if (NearZero(span)) {
178 return;
179 }
180 for (auto& stop : colorStops_) {
181 const auto relativeOffset = std::min(stop.offset - firstOffset, std::numeric_limits<float>::max());
182 const auto adjustOffset = relativeOffset / span;
183 stop.offset = adjustOffset;
184 }
185 }
186
ToSkColors(std::vector<SkScalar> & pos,std::vector<SkColor> & colors) const187 void ToSkColors(std::vector<SkScalar>& pos, std::vector<SkColor>& colors) const
188 {
189 if (colorStops_.empty()) {
190 pos.push_back(0.0f);
191 colors.push_back(SK_ColorTRANSPARENT);
192 } else if (colorStops_.front().offset > 0.0f) {
193 pos.push_back(0.0f);
194 colors.push_back(SkColor(colorStops_.front().color));
195 }
196
197 for (const auto& stop : colorStops_) {
198 pos.push_back(stop.offset);
199 colors.push_back(stop.color);
200 }
201
202 if (pos.back() < 1.0f) {
203 pos.push_back(1.0f);
204 colors.push_back(colors.back());
205 }
206 }
207
208 protected:
209 std::vector<ColorStop> colorStops_;
210 bool isRepeat_ { false };
211 };
212
213 class LinearGradientShader final : public GradientShader {
214
215 public:
LinearGradientShader(const Gradient & gradient,const SkPoint & firstPoint,const SkPoint & secondPoint)216 LinearGradientShader(const Gradient& gradient, const SkPoint& firstPoint, const SkPoint& secondPoint)
217 : GradientShader(gradient), firstPoint_(firstPoint), secondPoint_(secondPoint)
218 {}
219 ~LinearGradientShader() = default;
220
CreateGradientShader()221 sk_sp<SkShader> CreateGradientShader() override
222 {
223 AddColorStops((secondPoint_ - firstPoint_).length());
224 if (NeedAdjustColorStops()) {
225 auto startOffset = colorStops_.front().offset;
226 auto endOffset = colorStops_.back().offset;
227 AdjustColorStops();
228 AdjustPoint(startOffset, endOffset);
229 }
230
231 std::vector<SkScalar> pos;
232 std::vector<SkColor> colors;
233 ToSkColors(pos, colors);
234 SkPoint pts[2] = { firstPoint_, secondPoint_ };
235 #ifdef USE_SYSTEM_SKIA
236 SkShader::TileMode tileMode = SkShader::kClamp_TileMode;
237 #else
238 SkTileMode tileMode = SkTileMode::kClamp;
239 #endif
240 if (isRepeat_) {
241 #ifdef USE_SYSTEM_SKIA
242 tileMode = SkShader::kRepeat_TileMode;
243 #else
244 tileMode = SkTileMode::kRepeat;
245 #endif
246 }
247 return SkGradientShader::MakeLinear(pts, &colors[0], &pos[0], colors.size(), tileMode);
248 }
249
CreateLinearGradient(const Gradient & gradient,const SkSize & size)250 static std::unique_ptr<GradientShader> CreateLinearGradient(const Gradient& gradient, const SkSize& size)
251 {
252 auto linearGradient = gradient.GetLinearGradient();
253 SkPoint firstPoint { 0.0f, 0.0f };
254 SkPoint secondPoint { 0.0f, 0.0f };
255 if (linearGradient.angle) {
256 EndPointsFromAngle(linearGradient.angle.value().Value(), size, firstPoint, secondPoint);
257 } else {
258 if (linearGradient.linearX && linearGradient.linearY) {
259 float width = size.width();
260 float height = size.height();
261 if (linearGradient.linearX == GradientDirection::LEFT) {
262 height *= -1;
263 }
264 if (linearGradient.linearY == GradientDirection::BOTTOM) {
265 width *= -1;
266 }
267 float angle = 90.0f - Rad2deg(atan2(width, height));
268 EndPointsFromAngle(angle, size, firstPoint, secondPoint);
269 } else if (linearGradient.linearX || linearGradient.linearY) {
270 secondPoint = DirectionToPoint(linearGradient.linearX, linearGradient.linearY, size);
271 if (linearGradient.linearX) {
272 firstPoint.fX = size.width() - secondPoint.x();
273 }
274 if (linearGradient.linearY) {
275 firstPoint.fY = size.height() - secondPoint.y();
276 }
277 } else {
278 secondPoint.set(0.0f, size.height());
279 }
280 }
281 return std::make_unique<LinearGradientShader>(gradient, firstPoint, secondPoint);
282 }
283
284 private:
AdjustPoint(float firstOffset,float lastOffset)285 void AdjustPoint(float firstOffset, float lastOffset)
286 {
287 const auto delta = secondPoint_ - firstPoint_;
288 secondPoint_ = firstPoint_ + delta * lastOffset;
289 firstPoint_ = firstPoint_ + delta * firstOffset;
290 }
291
Deg2rad(float deg)292 static float Deg2rad(float deg)
293 {
294 return static_cast<float>(deg * M_PI / 180.0);
295 }
296
Rad2deg(float rad)297 static float Rad2deg(float rad)
298 {
299 return static_cast<float>(rad * 180.0 / M_PI);
300 }
301
EndPointsFromAngle(float angle,const SkSize & size,SkPoint & firstPoint,SkPoint & secondPoint)302 static void EndPointsFromAngle(float angle, const SkSize& size, SkPoint& firstPoint, SkPoint& secondPoint)
303 {
304 angle = fmod(angle, 360.0f);
305 if (LessNotEqual(angle, 0.0)) {
306 angle += 360.0f;
307 }
308
309 if (NearEqual(angle, 0.0)) {
310 firstPoint.set(0.0f, size.height());
311 secondPoint.set(0.0f, 0.0f);
312 return;
313 } else if (NearEqual(angle, 90.0)) {
314 firstPoint.set(0.0f, 0.0f);
315 secondPoint.set(size.width(), 0.0f);
316 return;
317 } else if (NearEqual(angle, 180.0)) {
318 firstPoint.set(0.0f, 0.0f);
319 secondPoint.set(0, size.height());
320 return;
321 } else if (NearEqual(angle, 270.0)) {
322 firstPoint.set(size.width(), 0.0f);
323 secondPoint.set(0.0f, 0.0f);
324 return;
325 }
326 float slope = tan(Deg2rad(90.0f - angle));
327 float perpendicularSlope = -1 / slope;
328
329 float halfHeight = size.height() / 2;
330 float halfWidth = size.width() / 2;
331 SkPoint cornerPoint { 0.0f, 0.0f };
332 if (angle < 90.0) {
333 cornerPoint.set(halfWidth, halfHeight);
334 } else if (angle < 180) {
335 cornerPoint.set(halfWidth, -halfHeight);
336 } else if (angle < 270) {
337 cornerPoint.set(-halfWidth, -halfHeight);
338 } else {
339 cornerPoint.set(-halfWidth, halfHeight);
340 }
341
342 // Compute b (of y = kx + b) using the corner point.
343 float b = cornerPoint.y() - perpendicularSlope * cornerPoint.x();
344 float endX = b / (slope - perpendicularSlope);
345 float endY = perpendicularSlope * endX + b;
346
347 secondPoint.set(halfWidth + endX, halfHeight - endY);
348 firstPoint.set(halfWidth - endX, halfHeight + endY);
349 }
350
DirectionToPoint(const std::optional<GradientDirection> & x,const std::optional<GradientDirection> & y,const SkSize & size)351 static SkPoint DirectionToPoint(
352 const std::optional<GradientDirection>& x, const std::optional<GradientDirection>& y, const SkSize& size)
353 {
354 SkPoint point { 0.0f, 0.0f };
355 if (x) {
356 if (x == GradientDirection::LEFT) {
357 point.fX = 0.0f;
358 } else {
359 point.fX = size.width();
360 }
361 }
362
363 if (y) {
364 if (y == GradientDirection::TOP) {
365 point.fY = 0.0f;
366 } else {
367 point.fY = size.height();
368 }
369 }
370
371 return point;
372 }
373
374 private:
375 SkPoint firstPoint_ { 0.0f, 0.0f };
376 SkPoint secondPoint_ { 0.0f, 0.0f };
377 };
378
379 class RadialGradientShader final : public GradientShader {
380 public:
RadialGradientShader(const Gradient & gradient,const SkPoint & center,float radius0,float radius1,float ratio)381 RadialGradientShader(const Gradient& gradient, const SkPoint& center, float radius0, float radius1, float ratio)
382 : GradientShader(gradient), center_(center), radius0_(radius0), radius1_(radius1), ratio_(ratio)
383 {}
384
385 ~RadialGradientShader() = default;
386
CreateGradientShader()387 sk_sp<SkShader> CreateGradientShader() override
388 {
389 SkMatrix matrix = SkMatrix::I();
390 ratio_ = NearZero(ratio_) ? 1.0f : ratio_;
391 if (ratio_ != 1.0f) {
392 matrix.preScale(1.0f, 1 / ratio_, center_.x(), center_.y());
393 }
394 AddColorStops(radius1_);
395 if (NeedAdjustColorStops()) {
396 auto startOffset = colorStops_.front().offset;
397 auto endOffset = colorStops_.back().offset;
398 AdjustColorStops();
399 AdjustRadius(startOffset, endOffset);
400 }
401
402 #ifdef USE_SYSTEM_SKIA
403 SkShader::TileMode tileMode = SkShader::kClamp_TileMode;
404 #else
405 SkTileMode tileMode = SkTileMode::kClamp;
406 #endif
407 if (isRepeat_) {
408 ClampNegativeOffsets();
409 #ifdef USE_SYSTEM_SKIA
410 tileMode = SkShader::kRepeat_TileMode;
411 #else
412 tileMode = SkTileMode::kRepeat;
413 #endif
414 }
415 std::vector<SkScalar> pos;
416 std::vector<SkColor> colors;
417 ToSkColors(pos, colors);
418 radius0_ = std::max(radius0_, 0.0f);
419 radius1_ = std::max(radius1_, 0.0f);
420 return SkGradientShader::MakeTwoPointConical(
421 center_, radius0_, center_, radius1_, &colors[0], &pos[0], colors.size(), tileMode, 0, &matrix);
422 }
423
CreateRadialGradient(const Gradient & gradient,const SkSize & size,float dipScale)424 static std::unique_ptr<GradientShader> CreateRadialGradient(
425 const Gradient& gradient, const SkSize& size, float dipScale)
426 {
427 auto radialGradient = gradient.GetRadialGradient();
428 SkPoint center = GetCenter(radialGradient, size, dipScale);
429 SkSize circleSize = GetCircleSize(radialGradient, size, center, dipScale);
430 bool isDegenerate = NearZero(circleSize.width()) || NearZero(circleSize.height());
431 float ratio = NearZero(circleSize.height()) ? 1.0f : circleSize.width() / circleSize.height();
432 float radius0 = 0.0f;
433 float radius1 = circleSize.width();
434 if (isDegenerate) {
435 ratio = 1.0f;
436 radius1 = 0.0f;
437 }
438 return std::make_unique<RadialGradientShader>(gradient, center, radius0, radius1, ratio);
439 }
440
441 private:
AdjustRadius(float firstOffset,float lastOffset)442 void AdjustRadius(float firstOffset, float lastOffset)
443 {
444 float adjustedR0 = radius1_ * firstOffset;
445 float adjustedR1 = radius1_ * lastOffset;
446 if (adjustedR0 < 0.0) {
447 const float radiusSpan = adjustedR1 - adjustedR0;
448 const float shiftToPositive = radiusSpan * ceilf(-adjustedR0 / radiusSpan);
449 adjustedR0 += shiftToPositive;
450 adjustedR1 += shiftToPositive;
451 }
452 radius0_ = adjustedR0;
453 radius1_ = adjustedR1;
454 }
455
ClampNegativeOffsets()456 void ClampNegativeOffsets()
457 {
458 float lastNegativeOffset = 0.0f;
459 for (uint32_t i = 0; i < colorStops_.size(); ++i) {
460 auto current = colorStops_[i].offset;
461 if (GreatOrEqual(current, 0.0f)) {
462 if (i > 0) {
463 float fraction = -lastNegativeOffset / (current - lastNegativeOffset);
464 LinearEvaluator<Color> evaluator;
465 Color adjustColor =
466 evaluator.Evaluate(Color(colorStops_[i - 1].color), Color(colorStops_[i].color), fraction);
467 colorStops_[i - 1].color = adjustColor.GetValue();
468 }
469 break;
470 }
471 colorStops_[i].offset = 0.0f;
472 lastNegativeOffset = current;
473 }
474 }
475
GetCenter(const RadialGradient & radialGradient,const SkSize & size,float dipScale)476 static SkPoint GetCenter(const RadialGradient& radialGradient, const SkSize& size, float dipScale)
477 {
478 SkPoint center = SkPoint::Make(size.width() / 2.0f, size.height() / 2.0f);
479 if (radialGradient.radialCenterX) {
480 const auto& value = radialGradient.radialCenterX.value();
481 center.fX = static_cast<float>(value.Unit() == DimensionUnit::PERCENT ? value.Value() / 100.0 * size.width()
482 : value.ConvertToPx(dipScale));
483 }
484 if (radialGradient.radialCenterY) {
485 const auto& value = radialGradient.radialCenterY.value();
486 center.fY =
487 static_cast<float>(value.Unit() == DimensionUnit::PERCENT ? value.Value() / 100.0 * size.height()
488 : value.ConvertToPx(dipScale));
489 }
490 return center;
491 }
492
GetCircleSize(const RadialGradient & radialGradient,const SkSize & size,const SkPoint & center,float dipScale)493 static SkSize GetCircleSize(
494 const RadialGradient& radialGradient, const SkSize& size, const SkPoint& center, float dipScale)
495 {
496 SkSize circleSize { 0.0f, 0.0f };
497 if (radialGradient.radialHorizontalSize) {
498 const auto& hValue = radialGradient.radialHorizontalSize.value();
499 circleSize.fWidth = static_cast<float>(
500 hValue.Unit() == DimensionUnit::PERCENT ? hValue.Value() * size.width() : hValue.ConvertToPx(dipScale));
501 circleSize.fHeight = circleSize.fWidth;
502 if (radialGradient.radialVerticalSize) {
503 const auto& wValue = radialGradient.radialVerticalSize.value();
504 circleSize.fHeight =
505 static_cast<float>(wValue.Unit() == DimensionUnit::PERCENT ? wValue.Value() * size.height()
506 : wValue.ConvertToPx(dipScale));
507 }
508 } else {
509 RadialShapeType shape = RadialShapeType::ELLIPSE;
510 if ((radialGradient.radialShape && radialGradient.radialShape.value() == RadialShapeType::CIRCLE) ||
511 (!radialGradient.radialShape && !radialGradient.radialSizeType && radialGradient.radialHorizontalSize &&
512 !radialGradient.radialVerticalSize)) {
513 shape = RadialShapeType::CIRCLE;
514 }
515 auto sizeType =
516 radialGradient.radialSizeType ? radialGradient.radialSizeType.value() : RadialSizeType::NONE;
517 switch (sizeType) {
518 case RadialSizeType::CLOSEST_SIDE:
519 circleSize = RadiusToSide(center, size, shape, std::less<>());
520 break;
521 case RadialSizeType::FARTHEST_SIDE:
522 circleSize = RadiusToSide(center, size, shape, std::greater<>());
523 break;
524 case RadialSizeType::CLOSEST_CORNER:
525 circleSize = RadiusToCorner(center, size, shape, std::less<>());
526 break;
527 case RadialSizeType::FARTHEST_CORNER:
528 case RadialSizeType::NONE:
529 default:
530 circleSize = RadiusToCorner(center, size, shape, std::greater<>());
531 break;
532 }
533 }
534 return circleSize;
535 }
536
537 using CompareType = std::function<bool(float, float)>;
538
RadiusToSide(const SkPoint & center,const SkSize & size,RadialShapeType type,const CompareType & compare)539 static SkSize RadiusToSide(
540 const SkPoint& center, const SkSize& size, RadialShapeType type, const CompareType& compare)
541 {
542 auto dx1 = static_cast<float>(std::fabs(center.fX));
543 auto dy1 = static_cast<float>(std::fabs(center.fY));
544 auto dx2 = static_cast<float>(std::fabs(center.fX - size.width()));
545 auto dy2 = static_cast<float>(std::fabs(center.fY - size.height()));
546
547 auto dx = compare(dx1, dx2) ? dx1 : dx2;
548 auto dy = compare(dy1, dy2) ? dy1 : dy2;
549
550 if (type == RadialShapeType::CIRCLE) {
551 return compare(dx, dy) ? SkSize::Make(dx, dx) : SkSize::Make(dy, dy);
552 }
553 return SkSize::Make(dx, dy);
554 }
555
EllipseRadius(const SkPoint & p,float ratio)556 static inline SkSize EllipseRadius(const SkPoint& p, float ratio)
557 {
558 if (NearZero(ratio) || std::isinf(ratio)) {
559 return SkSize { 0.0f, 0.0f };
560 }
561 // x^2/a^2 + y^2/b^2 = 1
562 // a/b = ratio, b = a/ratio
563 // a = sqrt(x^2 + y^2/(1/r^2))
564 float a = sqrtf(p.fX * p.fX + p.fY * p.fY * ratio * ratio);
565 return SkSize::Make(a, a / ratio);
566 }
567
RadiusToCorner(const SkPoint & center,const SkSize & size,RadialShapeType type,const CompareType & compare)568 static SkSize RadiusToCorner(
569 const SkPoint& center, const SkSize& size, RadialShapeType type, const CompareType& compare)
570 {
571 const SkPoint corners[4] = {
572 SkPoint::Make(0.0f, 0.0f),
573 SkPoint::Make(size.width(), 0.0f),
574 SkPoint::Make(size.width(), size.height()),
575 SkPoint::Make(0.0f, size.height()),
576 };
577
578 int32_t cornerIndex = 0;
579 float distance = (center - corners[cornerIndex]).length();
580 for (int32_t i = 1; i < 4; i++) {
581 float newDistance = (center - corners[i]).length();
582 if (compare(newDistance, distance)) {
583 cornerIndex = i;
584 distance = newDistance;
585 }
586 }
587
588 if (type == RadialShapeType::CIRCLE) {
589 return SkSize::Make(distance, distance);
590 }
591
592 SkSize sideRadius = RadiusToSide(center, size, RadialShapeType::ELLIPSE, compare);
593 return EllipseRadius(corners[cornerIndex] - center,
594 NearZero(sideRadius.height()) ? 1.0f : sideRadius.width() / sideRadius.height());
595 }
596
597 private:
598 SkPoint center_ { 0.0f, 0.0f };
599 float radius0_ { 0.0f };
600 float radius1_ { 0.0f };
601 float ratio_ { 1.0f };
602 };
603
604 class SweepGradientShader final : public GradientShader {
605 public:
SweepGradientShader(const Gradient & gradient,const SkPoint & center,float startAngle,float endAngle,float rotation)606 SweepGradientShader(
607 const Gradient& gradient, const SkPoint& center, float startAngle, float endAngle, float rotation)
608 : GradientShader(gradient), center_(center), startAngle_(startAngle), endAngle_(endAngle), rotation_(rotation)
609 {}
610 ~SweepGradientShader() = default;
611
CreateGradientShader()612 sk_sp<SkShader> CreateGradientShader() override
613 {
614 AddColorStops(1.0f);
615 if (NeedAdjustColorStops()) {
616 auto startOffset = colorStops_.front().offset;
617 auto endOffset = colorStops_.back().offset;
618 AdjustColorStops();
619 AdjustAngle(startOffset, endOffset);
620 }
621
622 SkMatrix matrix = SkMatrix::I();
623 if (!NearZero(rotation_)) {
624 matrix.preRotate(rotation_, center_.fX, center_.fY);
625 }
626
627 std::vector<SkScalar> pos;
628 std::vector<SkColor> colors;
629 ToSkColors(pos, colors);
630 #ifdef USE_SYSTEM_SKIA
631 SkShader::TileMode tileMode = SkShader::kClamp_TileMode;
632 #else
633 SkTileMode tileMode = SkTileMode::kClamp;
634 #endif
635 if (isRepeat_) {
636 #ifdef USE_SYSTEM_SKIA
637 tileMode = SkShader::kRepeat_TileMode;
638 #else
639 tileMode = SkTileMode::kRepeat;
640 #endif
641 }
642 return SkGradientShader::MakeSweep(
643 center_.fX, center_.fY, &colors[0], &pos[0], colors.size(), tileMode, startAngle_, endAngle_, 0, &matrix);
644 }
645
CreateSweepGradient(const Gradient & gradient,const SkSize & size,float dipScale)646 static std::unique_ptr<GradientShader> CreateSweepGradient(
647 const Gradient& gradient, const SkSize& size, float dipScale)
648 {
649 auto sweepGradient = gradient.GetSweepGradient();
650 SkPoint center = GetCenter(sweepGradient, size, dipScale);
651 float rotationAngle = 0.0f;
652 if (sweepGradient.rotation) {
653 rotationAngle = fmod(sweepGradient.rotation.value().Value(), 360.0f);
654 if (LessNotEqual(rotationAngle, 0.0f)) {
655 rotationAngle += 360.0f;
656 }
657 }
658 float startAngle = 0.0f;
659 float endAngle = 0.0f;
660 if (sweepGradient.startAngle.has_value()) {
661 startAngle = sweepGradient.startAngle.value().Value();
662 }
663 if (sweepGradient.endAngle.has_value()) {
664 endAngle = sweepGradient.endAngle.value().Value();
665 }
666 return std::make_unique<SweepGradientShader>(gradient, center, startAngle, endAngle, rotationAngle);
667 }
668
669 private:
GetCenter(const SweepGradient & sweepGradient,const SkSize & size,float dipScale)670 static SkPoint GetCenter(const SweepGradient& sweepGradient, const SkSize& size, float dipScale)
671 {
672 SkPoint center = SkPoint::Make(size.width() / 2.0f, size.height() / 2.0f);
673
674 if (sweepGradient.centerX) {
675 const auto& value = sweepGradient.centerX.value();
676 center.fX =
677 static_cast<float>(value.Unit() == DimensionUnit::PERCENT ? value.Value() / 100.0f * size.width()
678 : value.ConvertToPx(dipScale));
679 }
680 if (sweepGradient.centerY) {
681 const auto& value = sweepGradient.centerY.value();
682 center.fY =
683 static_cast<float>(value.Unit() == DimensionUnit::PERCENT ? value.Value() / 100.0f * size.height()
684 : value.ConvertToPx(dipScale));
685 }
686 return center;
687 }
688
AdjustAngle(float firstOffset,float lastOffset)689 void AdjustAngle(float firstOffset, float lastOffset)
690 {
691 const auto delta = endAngle_ - startAngle_;
692 endAngle_ = startAngle_ + delta * lastOffset;
693 startAngle_ = startAngle_ + delta * firstOffset;
694 }
695
696 private:
697 SkPoint center_ { 0.0f, 0.0f };
698 float startAngle_ { 0.0f };
699 float endAngle_ { 0.0f };
700 float rotation_ { 0.0f };
701 };
702
703 } // namespace
704
FlutterDecorationPainter(const RefPtr<Decoration> & decoration,const Rect & paintRect,const Size & paintSize,double dipScale)705 FlutterDecorationPainter::FlutterDecorationPainter(
706 const RefPtr<Decoration>& decoration, const Rect& paintRect, const Size& paintSize, double dipScale)
707 : dipScale_(dipScale), paintRect_(paintRect), decoration_(decoration), paintSize_(paintSize)
708 {}
709
PaintDecoration(const Offset & offset,SkCanvas * canvas,RenderContext & context)710 void FlutterDecorationPainter::PaintDecoration(const Offset& offset, SkCanvas* canvas, RenderContext& context)
711 {
712 if (!canvas) {
713 LOGE("PaintDecoration failed, canvas is null.");
714 return;
715 }
716 if (decoration_ && paintSize_.IsValid()) {
717 canvas->save();
718 SkPaint paint;
719
720 if (opacity_ != UINT8_MAX) {
721 paint.setAlpha(opacity_);
722 }
723
724 Border border = decoration_->GetBorder();
725 flutter::RRect outerRRect = GetOuterRRect(offset + margin_.GetOffsetInPx(scale_), border);
726 flutter::RRect innerRRect = GetInnerRRect(offset + margin_.GetOffsetInPx(scale_), border);
727 flutter::RRect clipRRect = GetClipRRect(offset + margin_.GetOffsetInPx(scale_), border);
728 if (clipLayer_) {
729 // If you want to clip the rounded edges, you need to set a Cliplayer first.
730 clipLayer_->SetClipRRect(outerRRect);
731 }
732 PaintBoxShadows(outerRRect.sk_rrect, decoration_->GetShadows(), canvas);
733 canvas->clipRRect(CanUseInnerRRect(border) ? innerRRect.sk_rrect : outerRRect.sk_rrect, true);
734 PaintColorAndImage(offset, canvas, paint, context);
735 canvas->restore();
736 if (border.HasValue()) {
737 paint.setAntiAlias(true);
738 AdjustBorderStyle(border);
739 if (CanUseFourLine(border)) {
740 PaintBorderWithLine(offset + margin_.GetOffsetInPx(scale_), border, canvas, paint);
741 } else if (CanUseFillStyle(border, paint)) {
742 canvas->drawDRRect(outerRRect.sk_rrect, innerRRect.sk_rrect, paint);
743 } else if (CanUsePathRRect(border, paint)) {
744 SkPath borderPath;
745 borderPath.addRRect(clipRRect.sk_rrect);
746 canvas->drawPath(borderPath, paint);
747 } else {
748 canvas->save();
749 canvas->clipRRect(outerRRect.sk_rrect, SkClipOp::kIntersect, true);
750 canvas->clipRRect(innerRRect.sk_rrect, SkClipOp::kDifference, true);
751 PaintBorderWithPath(offset + margin_.GetOffsetInPx(scale_), border, canvas, paint);
752 canvas->restore();
753 }
754 }
755 }
756 }
757
PaintBorderImage(SkPaint & paint,const Offset & offset,SkCanvas * canvas,const sk_sp<SkImage> & image)758 void FlutterDecorationPainter::PaintBorderImage(SkPaint& paint, const Offset& offset, SkCanvas* canvas,
759 const sk_sp<SkImage>& image)
760 {
761 paint.setAntiAlias(true);
762 if (decoration_->GetHasBorderImageSource()) {
763 if (!image) {
764 return;
765 }
766 canvas->save();
767
768 BorderImagePainter borderImagePainter(paintSize_, decoration_, image, dipScale_);
769 borderImagePainter.InitPainter();
770 borderImagePainter.PaintBorderImage(offset + margin_.GetOffsetInPx(dipScale_), canvas, paint);
771 canvas->restore();
772 }
773 if (decoration_->GetHasBorderImageGradient()) {
774 Gradient gradient = decoration_->GetBorderImageGradient();
775 if (!gradient.IsValid()) {
776 LOGE("Gradient not valid");
777 return;
778 }
779 if (NearZero(paintSize_.Width()) || NearZero(paintSize_.Height())) {
780 return;
781 }
782 canvas->save();
783 #ifndef NEW_SKIA
784 SkSize skPaintSize = SkSize::Make(SkDoubleToMScalar(paintSize_.Width()),
785 SkDoubleToMScalar(paintSize_.Height()));
786 #else
787 SkSize skPaintSize = SkSize::Make(paintSize_.Width(),
788 paintSize_.Height());
789 #endif
790 auto shader = CreateGradientShader(gradient, skPaintSize);
791 paint.setShader(std::move(shader));
792
793 auto imageInfo = SkImageInfo::Make(paintSize_.Width(), paintSize_.Height(),
794 SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kOpaque_SkAlphaType);
795 SkBitmap skBitmap_;
796 skBitmap_.allocPixels(imageInfo);
797 std::unique_ptr<SkCanvas> skCanvas_ = std::make_unique<SkCanvas>(skBitmap_);
798 skCanvas_->drawPaint(paint);
799 sk_sp<SkImage> skImage_ = SkImage::MakeFromBitmap(skBitmap_);
800 BorderImagePainter borderImagePainter(paintSize_, decoration_, skImage_, dipScale_);
801 borderImagePainter.InitPainter();
802 borderImagePainter.PaintBorderImage(offset + margin_.GetOffsetInPx(dipScale_), canvas, paint);
803 paint.setShader(nullptr);
804 canvas->restore();
805 }
806 }
807
PaintDecoration(const Offset & offset,SkCanvas * canvas,RenderContext & context,const sk_sp<SkImage> & image,bool paintBorder)808 void FlutterDecorationPainter::PaintDecoration(const Offset& offset, SkCanvas* canvas,
809 RenderContext& context, const sk_sp<SkImage>& image, bool paintBorder)
810 {
811 if (!canvas) {
812 LOGE("PaintDecoration failed, canvas is null.");
813 return;
814 }
815 if (decoration_) {
816 canvas->save();
817 SkPaint paint;
818
819 if (opacity_ != UINT8_MAX) {
820 paint.setAlpha(opacity_);
821 }
822 Border border = decoration_->GetBorder();
823 flutter::RRect outerRRect = GetOuterRRect(offset + margin_.GetOffsetInPx(scale_), border);
824 flutter::RRect innerRRect = GetInnerRRect(offset + margin_.GetOffsetInPx(scale_), border);
825
826 if (clipLayer_) {
827 // If you want to clip the rounded edges, you need to set a Cliplayer first.
828 clipLayer_->SetClipRRect(outerRRect);
829 }
830 PaintBoxShadows(outerRRect.sk_rrect, decoration_->GetShadows(), canvas);
831 canvas->clipRRect(CanUseInnerRRect(border) ? innerRRect.sk_rrect : outerRRect.sk_rrect, true);
832 PaintColorAndImage(offset, canvas, paint, context);
833 canvas->restore();
834 if (decoration_->GetHasBorderImageSource() || decoration_->GetHasBorderImageGradient()) {
835 PaintBorderImage(paint, offset, canvas, image);
836 return;
837 }
838 if (paintBorder) {
839 PaintBorder(offset, canvas);
840 }
841 }
842 }
843
PaintGrayScale(const flutter::RRect & outerRRect,SkCanvas * canvas,const Dimension & grayscale,const Color & color)844 void FlutterDecorationPainter::PaintGrayScale(const flutter::RRect& outerRRect, SkCanvas* canvas,
845 const Dimension& grayscale, const Color& color)
846 {
847 double scale = grayscale.Value();
848 if (GreatNotEqual(scale, 0.0)) {
849 if (canvas) {
850 SkAutoCanvasRestore acr(canvas, true);
851 canvas->clipRRect(outerRRect.sk_rrect, true);
852 SkPaint paint;
853 paint.setAntiAlias(true);
854 float matrix[20] = { 0 };
855 matrix[0] = matrix[5] = matrix[10] = 0.2126f * scale;
856 matrix[1] = matrix[6] = matrix[11] = 0.7152f * scale;
857 matrix[2] = matrix[7] = matrix[12] = 0.0722f * scale;
858 matrix[18] = 1.0f * scale;
859 #ifdef USE_SYSTEM_SKIA
860 auto filter = SkColorFilter::MakeMatrixFilterRowMajor255(matrix);
861 paint.setColorFilter(filter);
862 #else
863 paint.setColorFilter(SkColorFilters::Matrix(matrix));
864 #endif
865 SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
866 canvas->saveLayer(slr);
867 }
868 }
869 }
870
PaintBrightness(const flutter::RRect & outerRRect,SkCanvas * canvas,const Dimension & brightness,const Color & color)871 void FlutterDecorationPainter::PaintBrightness(const flutter::RRect& outerRRect, SkCanvas* canvas,
872 const Dimension& brightness, const Color& color)
873 {
874 double bright = brightness.Value();
875 // brightness range (0, 2), 1 is normal brightness
876 // skip painting when brightness is 1
877 if (NearEqual(bright, 1.0)) {
878 return;
879 }
880 if (canvas) {
881 SkAutoCanvasRestore acr(canvas, true);
882 canvas->clipRRect(outerRRect.sk_rrect, true);
883 SkPaint paint;
884 paint.setAntiAlias(true);
885 float matrix[20] = { 0 };
886 // brightness range in Skia: (-1, 1), convert from range (0, 2)
887 bright--;
888 matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.0f;
889 matrix[4] = matrix[9] = matrix[14] = bright;
890 #ifdef USE_SYSTEM_SKIA
891 auto filter = SkColorFilter::MakeMatrixFilterRowMajor255(matrix);
892 paint.setColorFilter(filter);
893 #else
894 paint.setColorFilter(SkColorFilters::Matrix(matrix));
895 #endif
896 SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
897 canvas->saveLayer(slr);
898 }
899 }
900
PaintContrast(const flutter::RRect & outerRRect,SkCanvas * canvas,const Dimension & contrast,const Color & color)901 void FlutterDecorationPainter::PaintContrast(const flutter::RRect& outerRRect, SkCanvas* canvas,
902 const Dimension& contrast, const Color& color)
903 {
904 double contrasts = contrast.Value();
905 // skip painting if contrast is normal
906 if (NearEqual(contrasts, 1.0)) {
907 return;
908 }
909 if (canvas) {
910 SkAutoCanvasRestore acr(canvas, true);
911 canvas->clipRRect(outerRRect.sk_rrect, true);
912 SkPaint paint;
913 paint.setAntiAlias(true);
914 float matrix[20] = { 0 };
915 matrix[0] = matrix[6] = matrix[12] = contrasts;
916 matrix[4] = matrix[9] = matrix[14] = 128 * (1 - contrasts) / 255;
917 matrix[18] = 1.0f;
918 #ifdef USE_SYSTEM_SKIA
919 auto filter = SkColorFilter::MakeMatrixFilterRowMajor255(matrix);
920 paint.setColorFilter(filter);
921 #else
922 paint.setColorFilter(SkColorFilters::Matrix(matrix));
923 #endif
924 SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
925 canvas->saveLayer(slr);
926 }
927 }
928
PaintColorBlend(const flutter::RRect & outerRRect,SkCanvas * canvas,const Color & colorBlend,const Color & color)929 void FlutterDecorationPainter::PaintColorBlend(const flutter::RRect& outerRRect, SkCanvas* canvas,
930 const Color& colorBlend, const Color& color)
931 {
932 if (colorBlend.GetValue() != COLOR_MASK) {
933 if (canvas) {
934 SkAutoCanvasRestore acr(canvas, true);
935 canvas->clipRRect(outerRRect.sk_rrect, true);
936 SkPaint paint;
937 paint.setAntiAlias(true);
938 #ifdef USE_SYSTEM_SKIA
939 paint.setColorFilter(SkColorFilter::MakeModeFilter(
940 SkColorSetARGB(colorBlend.GetAlpha(), colorBlend.GetRed(), colorBlend.GetGreen(), colorBlend.GetBlue()),
941 SkBlendMode::kPlus));
942 #else
943 paint.setColorFilter(SkColorFilters::Blend(
944 SkColorSetARGB(colorBlend.GetAlpha(), colorBlend.GetRed(), colorBlend.GetGreen(), colorBlend.GetBlue()),
945 SkBlendMode::kPlus));
946 #endif
947 SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
948 canvas->saveLayer(slr);
949 }
950 }
951 }
952
PaintSaturate(const flutter::RRect & outerRRect,SkCanvas * canvas,const Dimension & saturate,const Color & color)953 void FlutterDecorationPainter::PaintSaturate(const flutter::RRect& outerRRect, SkCanvas* canvas,
954 const Dimension& saturate, const Color& color)
955 {
956 double saturates = saturate.Value();
957 if (!NearEqual(saturates, 1.0) && GreatOrEqual(saturates, 0.0)) {
958 if (canvas) {
959 SkAutoCanvasRestore acr(canvas, true);
960 canvas->clipRRect(outerRRect.sk_rrect, true);
961 SkPaint paint;
962 paint.setAntiAlias(true);
963 float matrix[20] = { 0 };
964 matrix[0] = 0.3086f * (1 - saturates) + saturates;
965 matrix[1] = matrix[11] = 0.6094f * (1 - saturates);
966 matrix[2] = matrix[7] = 0.0820f * (1 - saturates);
967 matrix[5] = matrix[10] = 0.3086f * (1 - saturates);
968 matrix[6] = 0.6094f * (1 - saturates) + saturates;
969 matrix[12] = 0.0820f * (1 - saturates) + saturates;
970 matrix[18] = 1.0f;
971 #ifdef USE_SYSTEM_SKIA
972 auto filter = SkColorFilter::MakeMatrixFilterRowMajor255(matrix);
973 paint.setColorFilter(filter);
974 #else
975 paint.setColorFilter(SkColorFilters::Matrix(matrix));
976 #endif
977 SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
978 canvas->saveLayer(slr);
979 }
980 }
981 }
982
PaintSepia(const flutter::RRect & outerRRect,SkCanvas * canvas,const Dimension & sepia,const Color & color)983 void FlutterDecorationPainter::PaintSepia(const flutter::RRect& outerRRect, SkCanvas* canvas,
984 const Dimension& sepia, const Color& color)
985 {
986 double sepias = sepia.Value();
987 if (sepias > 1.0) {
988 sepias = 1.0;
989 }
990 if (GreatNotEqual(sepias, 0.0)) {
991 if (canvas) {
992 SkAutoCanvasRestore acr(canvas, true);
993 canvas->clipRRect(outerRRect.sk_rrect, true);
994 SkPaint paint;
995 paint.setAntiAlias(true);
996 float matrix[20] = { 0 };
997 matrix[0] = 0.393f * sepias;
998 matrix[1] = 0.769f * sepias;
999 matrix[2] = 0.189f * sepias;
1000
1001 matrix[5] = 0.349f * sepias;
1002 matrix[6] = 0.686f * sepias;
1003 matrix[7] = 0.168f * sepias;
1004
1005 matrix[10] = 0.272f * sepias;
1006 matrix[11] = 0.534f * sepias;
1007 matrix[12] = 0.131f * sepias;
1008 matrix[18] = 1.0f * sepias;
1009 #ifdef USE_SYSTEM_SKIA
1010 auto filter = SkColorFilter::MakeMatrixFilterRowMajor255(matrix);
1011 paint.setColorFilter(filter);
1012 #else
1013 paint.setColorFilter(SkColorFilters::Matrix(matrix));
1014 #endif
1015 SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
1016 canvas->saveLayer(slr);
1017 }
1018 }
1019 }
1020
PaintInvert(const flutter::RRect & outerRRect,SkCanvas * canvas,const Dimension & invert,const Color & color)1021 void FlutterDecorationPainter::PaintInvert(const flutter::RRect& outerRRect, SkCanvas* canvas,
1022 const Dimension& invert, const Color& color)
1023 {
1024 double inverts = invert.Value();
1025 // normal invert = 0, no effect
1026 if (GreatNotEqual(inverts, 0.0)) {
1027 if (canvas) {
1028 SkAutoCanvasRestore acr(canvas, true);
1029 canvas->clipRRect(outerRRect.sk_rrect, true);
1030 SkPaint paint;
1031 paint.setAntiAlias(true);
1032 float matrix[20] = { 0 };
1033 if (inverts > 1.0) {
1034 inverts = 1.0;
1035 }
1036 // complete color invert when dstRGB = 1 - srcRGB
1037 // map (0, 1) to (1, -1)
1038 matrix[0] = matrix[6] = matrix[12] = 1.0 - 2.0 * inverts;
1039 matrix[18] = 1.0f;
1040 // inverts = 0.5 -> RGB = (0.5, 0.5, 0.5) -> image completely gray
1041 matrix[4] = matrix[9] = matrix[14] = inverts;
1042 #ifdef USE_SYSTEM_SKIA
1043 auto filter = SkColorFilter::MakeMatrixFilterRowMajor255(matrix);
1044 paint.setColorFilter(filter);
1045 #else
1046 paint.setColorFilter(SkColorFilters::Matrix(matrix));
1047 #endif
1048 SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
1049 canvas->saveLayer(slr);
1050 }
1051 }
1052 }
1053
PaintHueRotate(const flutter::RRect & outerRRect,SkCanvas * canvas,const float & hueRotate,const Color & color)1054 void FlutterDecorationPainter::PaintHueRotate(const flutter::RRect& outerRRect, SkCanvas* canvas,
1055 const float& hueRotate, const Color& color)
1056 {
1057 float hueRotates = hueRotate;
1058 if (GreatNotEqual(hueRotates, 0.0)) {
1059 if (canvas) {
1060 SkAutoCanvasRestore acr(canvas, true);
1061 canvas->clipRRect(outerRRect.sk_rrect, true);
1062 SkPaint paint;
1063 paint.setAntiAlias(true);
1064 while (GreatOrEqual(hueRotates, 360)) {
1065 hueRotates -= 360;
1066 }
1067 float matrix[20] = { 0 };
1068 int32_t type = hueRotates / 120;
1069 float N = (hueRotates - 120 * type) / 120;
1070 switch (type) {
1071 case 0:
1072 // color change = R->G, G->B, B->R
1073 matrix[2] = matrix[5] = matrix[11] = N;
1074 matrix[0] = matrix[6] = matrix[12] = 1 - N;
1075 matrix[18] = 1.0f;
1076 break;
1077 case 1:
1078 // compare to original: R->B, G->R, B->G
1079 matrix[1] = matrix[7] = matrix[10] = N;
1080 matrix[2] = matrix[5] = matrix[11] = 1 - N;
1081 matrix[18] = 1.0f;
1082 break;
1083 case 2:
1084 // back to normal color
1085 matrix[0] = matrix[6] = matrix[12] = N;
1086 matrix[1] = matrix[7] = matrix[10] = 1 - N;
1087 matrix[18] = 1.0f;
1088 break;
1089 default:
1090 break;
1091 }
1092 #ifdef USE_SYSTEM_SKIA
1093 auto filter = SkColorFilter::MakeMatrixFilterRowMajor255(matrix);
1094 paint.setColorFilter(filter);
1095 #else
1096 paint.setColorFilter(SkColorFilters::Matrix(matrix));
1097 #endif
1098 SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
1099 canvas->saveLayer(slr);
1100 }
1101 }
1102 }
1103
PaintBlur(const flutter::RRect & outerRRect,SkCanvas * canvas,const Dimension & blurRadius,const Color & color)1104 void FlutterDecorationPainter::PaintBlur(
1105 const flutter::RRect& outerRRect, SkCanvas* canvas, const Dimension& blurRadius, const Color& color)
1106 {
1107 auto radius = ConvertRadiusToSigma(NormalizeToPx(blurRadius));
1108 if (GreatNotEqual(radius, 0.0)) {
1109 if (canvas) {
1110 SkAutoCanvasRestore acr(canvas, true);
1111 canvas->clipRRect(outerRRect.sk_rrect, true);
1112 SkPaint paint;
1113 paint.setAntiAlias(true);
1114 #ifdef USE_SYSTEM_SKIA
1115 paint.setColorFilter(SkColorFilter::MakeModeFilter(color.GetValue(), SkBlendMode::kDstOver));
1116 #else
1117 paint.setColorFilter(SkColorFilters::Blend(color.GetValue(), SkBlendMode::kDstOver));
1118 #endif
1119 #ifndef NEW_SKIA
1120 paint.setImageFilter(SkBlurImageFilter::Make(radius, radius, nullptr));
1121 #else
1122 paint.setImageFilter(SkImageFilters::Blur(radius, radius, nullptr));
1123 #endif
1124 SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
1125 canvas->saveLayer(slr);
1126 }
1127 }
1128 }
1129
GetBoxOuterRRect(const Offset & offset)1130 flutter::RRect FlutterDecorationPainter::GetBoxOuterRRect(const Offset& offset)
1131 {
1132 flutter::RRect outerRRect;
1133 if (decoration_) {
1134 Border border = decoration_->GetBorder();
1135 outerRRect = GetBoxRRect(offset + margin_.GetOffsetInPx(scale_), border, 0.0, true);
1136 }
1137 outerRRect.is_null = false;
1138 return outerRRect;
1139 }
1140
PaintColorAndImage(const Offset & offset,SkCanvas * canvas,SkPaint & paint,RenderContext & renderContext)1141 void FlutterDecorationPainter::PaintColorAndImage(
1142 const Offset& offset, SkCanvas* canvas, SkPaint& paint, RenderContext& renderContext)
1143 {
1144 if (!decoration_) {
1145 return;
1146 }
1147
1148 // paint backColor
1149 bool paintBgColor = false;
1150 paint.setStyle(SkPaint::Style::kFill_Style);
1151 Color backColor = decoration_->GetBackgroundColor();
1152 Color animationColor = decoration_->GetAnimationColor();
1153 if (backColor != Color::TRANSPARENT) {
1154 paint.setColor(backColor.GetValue());
1155 if (opacity_ != UINT8_MAX) {
1156 paint.setAlpha(opacity_);
1157 }
1158 canvas->drawRect(
1159 SkRect::MakeXYWH(offset.GetX() + NormalizeToPx(margin_.Left()),
1160 offset.GetY() + NormalizeToPx(margin_.Top()), GetLayoutSize().Width() - NormalizeToPx(margin_.Right()),
1161 GetLayoutSize().Height() - NormalizeToPx(margin_.Bottom())),
1162 paint);
1163 paintBgColor = true;
1164 }
1165 if (animationColor != Color::TRANSPARENT) {
1166 paint.setColor(animationColor.GetValue());
1167 if (opacity_ != UINT8_MAX) {
1168 paint.setAlpha(opacity_);
1169 }
1170 canvas->drawRect(
1171 SkRect::MakeXYWH(offset.GetX() + NormalizeToPx(margin_.Left()),
1172 offset.GetY() + NormalizeToPx(margin_.Top()), GetLayoutSize().Width() - NormalizeToPx(margin_.Right()),
1173 GetLayoutSize().Height() - NormalizeToPx(margin_.Bottom())),
1174 paint);
1175 }
1176
1177 // paint background image.
1178 RefPtr<ArcBackground> arcBG = decoration_->GetArcBackground();
1179 if (arcBG) {
1180 Color arcColor = arcBG->GetColor();
1181 if (arcColor != Color::TRANSPARENT) {
1182 paint.setColor(arcColor.GetValue());
1183 canvas->drawCircle(arcBG->GetCenter().GetX(), arcBG->GetCenter().GetY(), arcBG->GetRadius(), paint);
1184 paintBgColor = true;
1185 }
1186 }
1187 if (paintBgColor) {
1188 return;
1189 }
1190 // paint background image.
1191 if (decoration_->GetImage()) {
1192 PaintImage(offset, renderContext);
1193 return;
1194 }
1195 // paint Gradient color.
1196 if (decoration_->GetGradient().IsValid()) {
1197 PaintGradient(offset, canvas, paint);
1198 }
1199 }
1200
GetOuterRRect(const Offset & offset,const Border & border)1201 flutter::RRect FlutterDecorationPainter::GetOuterRRect(const Offset& offset, const Border& border)
1202 {
1203 flutter::RRect rrect = flutter::RRect();
1204 float topLeftRadiusX = NormalizeToPx(border.TopLeftRadius().GetX());
1205 float topLeftRadiusY = NormalizeToPx(border.TopLeftRadius().GetY());
1206 float topRightRadiusX = NormalizeToPx(border.TopRightRadius().GetX());
1207 float topRightRadiusY = NormalizeToPx(border.TopRightRadius().GetY());
1208 float bottomRightRadiusX = NormalizeToPx(border.BottomRightRadius().GetX());
1209 float bottomRightRadiusY = NormalizeToPx(border.BottomRightRadius().GetY());
1210 float bottomLeftRadiusX = NormalizeToPx(border.BottomLeftRadius().GetX());
1211 float bottomLeftRadiusY = NormalizeToPx(border.BottomLeftRadius().GetY());
1212 SkRect outerRect = SkRect::MakeXYWH(offset.GetX(), offset.GetY(), paintSize_.Width(), paintSize_.Height());
1213 const SkVector outerRadii[] = {
1214 SkVector::Make(topLeftRadiusX, topLeftRadiusY),
1215 SkVector::Make(topRightRadiusX, topRightRadiusY),
1216 SkVector::Make(bottomRightRadiusX, bottomRightRadiusY),
1217 SkVector::Make(bottomLeftRadiusX, bottomLeftRadiusY)
1218 };
1219 rrect.sk_rrect.setRectRadii(outerRect, outerRadii);
1220 return rrect;
1221 }
1222
GetInnerRRect(const Offset & offset,const Border & border)1223 flutter::RRect FlutterDecorationPainter::GetInnerRRect(const Offset& offset, const Border& border)
1224 {
1225 flutter::RRect rrect = flutter::RRect();
1226 float x = offset.GetX();
1227 float y = offset.GetY();
1228 float w = paintSize_.Width();
1229 float h = paintSize_.Height();
1230 float leftW = NormalizeToPx(border.Left().GetWidth());
1231 float topW = NormalizeToPx(border.Top().GetWidth());
1232 float rightW = NormalizeToPx(border.Right().GetWidth());
1233 float bottomW = NormalizeToPx(border.Bottom().GetWidth());
1234 float tlX = NormalizeToPx(border.TopLeftRadius().GetX());
1235 float tlY = NormalizeToPx(border.TopLeftRadius().GetY());
1236 float trX = NormalizeToPx(border.TopRightRadius().GetX());
1237 float trY = NormalizeToPx(border.TopRightRadius().GetY());
1238 float brX = NormalizeToPx(border.BottomRightRadius().GetX());
1239 float brY = NormalizeToPx(border.BottomRightRadius().GetY());
1240 float blX = NormalizeToPx(border.BottomLeftRadius().GetX());
1241 float blY = NormalizeToPx(border.BottomLeftRadius().GetY());
1242 SkRect innerRect = SkRect::MakeXYWH(x + leftW, y + topW, w - rightW - leftW, h - bottomW - topW);
1243 const SkVector innerRadii[] = {
1244 SkVector::Make(std::max(0.0f, tlX - leftW), std::max(0.0f, tlY - topW)),
1245 SkVector::Make(std::max(0.0f, trX - rightW), std::max(0.0f, trY - topW)),
1246 SkVector::Make(std::max(0.0f, brX - rightW), std::max(0.0f, brY - bottomW)),
1247 SkVector::Make(std::max(0.0f, blX - leftW), std::max(0.0f, blY - bottomW))
1248 };
1249 rrect.sk_rrect.setRectRadii(innerRect, innerRadii);
1250 return rrect;
1251 }
1252
GetClipRRect(const Offset & offset,const Border & border)1253 flutter::RRect FlutterDecorationPainter::GetClipRRect(const Offset& offset, const Border& border)
1254 {
1255 flutter::RRect rrect = flutter::RRect();
1256 float bottomRightRadiusX = NormalizeToPx(border.BottomRightRadius().GetX());
1257 float bottomRightRadiusY = NormalizeToPx(border.BottomRightRadius().GetY());
1258 float bottomLeftRadiusX = NormalizeToPx(border.BottomLeftRadius().GetX());
1259 float bottomLeftRadiusY = NormalizeToPx(border.BottomLeftRadius().GetY());
1260 float topLeftRadiusX = NormalizeToPx(border.TopLeftRadius().GetX());
1261 float topLeftRadiusY = NormalizeToPx(border.TopLeftRadius().GetY());
1262 float topRightRadiusX = NormalizeToPx(border.TopRightRadius().GetX());
1263 float topRightRadiusY = NormalizeToPx(border.TopRightRadius().GetY());
1264 const SkVector outerRadii[] = {
1265 SkVector::Make(topLeftRadiusX, topLeftRadiusY),
1266 SkVector::Make(topRightRadiusX, topRightRadiusY),
1267 SkVector::Make(bottomRightRadiusX, bottomRightRadiusY),
1268 SkVector::Make(bottomLeftRadiusX, bottomLeftRadiusY)
1269 };
1270 float leftW = NormalizeToPx(border.Left().GetWidth());
1271 float topW = NormalizeToPx(border.Top().GetWidth());
1272 float rightW = NormalizeToPx(border.Right().GetWidth());
1273 float bottomW = NormalizeToPx(border.Bottom().GetWidth());
1274 float x = offset.GetX() + leftW / 2.0f;
1275 float y = offset.GetY() + topW / 2.0f;
1276 float w = paintSize_.Width() - (leftW + rightW) / 2.0f;
1277 float h = paintSize_.Height() - (topW + bottomW) / 2.0f;
1278 rrect.sk_rrect.setRectRadii(SkRect::MakeXYWH(x, y, w, h), outerRadii);
1279 return rrect;
1280 }
1281
CanUseFillStyle(const Border & border,SkPaint & paint)1282 bool FlutterDecorationPainter::CanUseFillStyle(const Border& border, SkPaint& paint)
1283 {
1284 if (border.Top().GetBorderStyle() != BorderStyle::SOLID ||
1285 border.Right().GetBorderStyle() != BorderStyle::SOLID ||
1286 border.Bottom().GetBorderStyle() != BorderStyle::SOLID ||
1287 border.Left().GetBorderStyle() != BorderStyle::SOLID) {
1288 return false;
1289 }
1290 if (border.Left().GetColor() != border.Top().GetColor() ||
1291 border.Left().GetColor() != border.Right().GetColor() ||
1292 border.Left().GetColor() != border.Bottom().GetColor()) {
1293 return false;
1294 }
1295 paint.setStyle(SkPaint::Style::kFill_Style);
1296 paint.setColor(border.Left().GetColor().GetValue());
1297 return true;
1298 }
1299
CanUsePathRRect(const Border & border,SkPaint & paint)1300 bool FlutterDecorationPainter::CanUsePathRRect(const Border& border, SkPaint& paint)
1301 {
1302 if (border.Left().GetBorderStyle() != border.Top().GetBorderStyle() ||
1303 border.Left().GetBorderStyle() != border.Right().GetBorderStyle() ||
1304 border.Left().GetBorderStyle() != border.Bottom().GetBorderStyle()) {
1305 return false;
1306 }
1307 if (border.Left().GetWidth() != border.Top().GetWidth() ||
1308 border.Left().GetWidth() != border.Right().GetWidth() ||
1309 border.Left().GetWidth() != border.Bottom().GetWidth()) {
1310 return false;
1311 }
1312 if (border.Left().GetColor() != border.Top().GetColor() ||
1313 border.Left().GetColor() != border.Right().GetColor() ||
1314 border.Left().GetColor() != border.Bottom().GetColor()) {
1315 return false;
1316 }
1317 SetBorderStyle(border.Left(), paint, false);
1318 return true;
1319 }
1320
CanUseFourLine(const Border & border)1321 bool FlutterDecorationPainter::CanUseFourLine(const Border& border)
1322 {
1323 if (border.Left().GetBorderStyle() != border.Top().GetBorderStyle() ||
1324 border.Left().GetBorderStyle() != border.Right().GetBorderStyle() ||
1325 border.Left().GetBorderStyle() != border.Bottom().GetBorderStyle()) {
1326 return false;
1327 }
1328 if (border.Left().GetColor() != border.Top().GetColor() ||
1329 border.Left().GetColor() != border.Right().GetColor() ||
1330 border.Left().GetColor() != border.Bottom().GetColor()) {
1331 return false;
1332 }
1333 if (border.TopLeftRadius().IsValid() || border.TopRightRadius().IsValid() ||
1334 border.BottomLeftRadius().IsValid() || border.BottomRightRadius().IsValid()) {
1335 return false;
1336 }
1337 return true;
1338 }
1339
CanUseInnerRRect(const Border & border)1340 bool FlutterDecorationPainter::CanUseInnerRRect(const Border& border)
1341 {
1342 if (!border.HasValue()) {
1343 return false;
1344 }
1345 if (border.Top().GetBorderStyle() != BorderStyle::SOLID ||
1346 border.Right().GetBorderStyle() != BorderStyle::SOLID ||
1347 border.Bottom().GetBorderStyle() != BorderStyle::SOLID ||
1348 border.Left().GetBorderStyle() != BorderStyle::SOLID) {
1349 return false;
1350 }
1351 return true;
1352 }
1353
GetBoxRRect(const Offset & offset,const Border & border,double shrinkFactor,bool isRound)1354 flutter::RRect FlutterDecorationPainter::GetBoxRRect(
1355 const Offset& offset, const Border& border, double shrinkFactor, bool isRound)
1356 {
1357 flutter::RRect rrect = flutter::RRect();
1358 SkRect skRect {};
1359 SkVector fRadii[4] = { { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 } };
1360 if (CheckBorderEdgeForRRect(border)) {
1361 BorderEdge borderEdge = border.Left();
1362 double borderWidth = NormalizeToPx(borderEdge.GetWidth());
1363 skRect.setXYWH(SkDoubleToScalar(offset.GetX() + shrinkFactor * borderWidth),
1364 SkDoubleToScalar(offset.GetY() + shrinkFactor * borderWidth),
1365 SkDoubleToScalar(paintSize_.Width() - shrinkFactor * DOUBLE_WIDTH * borderWidth),
1366 SkDoubleToScalar(paintSize_.Height() - shrinkFactor * DOUBLE_WIDTH * borderWidth));
1367 if (isRound) {
1368 fRadii[SkRRect::kUpperLeft_Corner].set(
1369 SkDoubleToScalar(
1370 std::max(NormalizeToPx(border.TopLeftRadius().GetX()) - shrinkFactor * borderWidth, 0.0)),
1371 SkDoubleToScalar(
1372 std::max(NormalizeToPx(border.TopLeftRadius().GetY()) - shrinkFactor * borderWidth, 0.0)));
1373 fRadii[SkRRect::kUpperRight_Corner].set(
1374 SkDoubleToScalar(
1375 std::max(NormalizeToPx(border.TopRightRadius().GetX()) - shrinkFactor * borderWidth, 0.0)),
1376 SkDoubleToScalar(
1377 std::max(NormalizeToPx(border.TopRightRadius().GetY()) - shrinkFactor * borderWidth, 0.0)));
1378 fRadii[SkRRect::kLowerRight_Corner].set(
1379 SkDoubleToScalar(
1380 std::max(NormalizeToPx(border.BottomRightRadius().GetX()) - shrinkFactor * borderWidth, 0.0)),
1381 SkDoubleToScalar(
1382 std::max(NormalizeToPx(border.BottomRightRadius().GetY()) - shrinkFactor * borderWidth, 0.0)));
1383 fRadii[SkRRect::kLowerLeft_Corner].set(
1384 SkDoubleToScalar(
1385 std::max(NormalizeToPx(border.BottomLeftRadius().GetX()) - shrinkFactor * borderWidth, 0.0)),
1386 SkDoubleToScalar(
1387 std::max(NormalizeToPx(border.BottomLeftRadius().GetY()) - shrinkFactor * borderWidth, 0.0)));
1388 }
1389 } else {
1390 skRect.setXYWH(SkDoubleToScalar(offset.GetX() + shrinkFactor * NormalizeToPx(border.Left().GetWidth())),
1391 SkDoubleToScalar(offset.GetY() + shrinkFactor * NormalizeToPx(border.Top().GetWidth())),
1392 SkDoubleToScalar(
1393 paintSize_.Width() - shrinkFactor * DOUBLE_WIDTH * NormalizeToPx(border.Right().GetWidth())),
1394 SkDoubleToScalar(paintSize_.Height() - shrinkFactor * (NormalizeToPx(border.Bottom().GetWidth()) +
1395 NormalizeToPx(border.Top().GetWidth()))));
1396 }
1397 rrect.sk_rrect.setRectRadii(skRect, fRadii);
1398 return rrect;
1399 }
1400
SetBorderStyle(const BorderEdge & borderEdge,SkPaint & paint,bool useDefaultColor,double spaceBetweenDot,double borderLength)1401 void FlutterDecorationPainter::SetBorderStyle(const BorderEdge& borderEdge, SkPaint& paint,
1402 bool useDefaultColor, double spaceBetweenDot, double borderLength)
1403 {
1404 if (borderEdge.HasValue()) {
1405 double width = NormalizeToPx(borderEdge.GetWidth());
1406 uint32_t color = useDefaultColor ? Color::BLACK.GetValue() : borderEdge.GetColor().GetValue();
1407 paint.setStrokeWidth(width);
1408 paint.setColor(color);
1409 paint.setStyle(SkPaint::Style::kStroke_Style);
1410 if (borderEdge.GetBorderStyle() == BorderStyle::DOTTED) {
1411 SkPath dotPath;
1412 if (NearZero(spaceBetweenDot)) {
1413 spaceBetweenDot = width * 2.0;
1414 }
1415 dotPath.addCircle(0.0f, 0.0f, SkDoubleToScalar(width / 2.0));
1416 paint.setPathEffect(
1417 SkPath1DPathEffect::Make(dotPath, spaceBetweenDot, 0.0, SkPath1DPathEffect::kRotate_Style));
1418 } else if (borderEdge.GetBorderStyle() == BorderStyle::DASHED) {
1419 double addLen = 0.0; // When left < 2 * gap, splits left to gaps.
1420 double delLen = 0.0; // When left > 2 * gap, add one dash and shortening them.
1421 if (!NearZero(borderLength)) {
1422 double count = borderLength / width;
1423 double leftLen = fmod((count - DASHED_LINE_LENGTH), (DASHED_LINE_LENGTH + 1));
1424 if (leftLen > DASHED_LINE_LENGTH - 1) {
1425 delLen = (DASHED_LINE_LENGTH + 1 - leftLen) * width /
1426 (int32_t)((count - DASHED_LINE_LENGTH) / (DASHED_LINE_LENGTH + 1) + 2);
1427 } else {
1428 addLen = leftLen * width / (int32_t)((count - DASHED_LINE_LENGTH) / (DASHED_LINE_LENGTH + 1));
1429 }
1430 }
1431 const float intervals[] = { width * DASHED_LINE_LENGTH - delLen, width + addLen };
1432 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0.0));
1433 } else {
1434 paint.setPathEffect(nullptr);
1435 }
1436 }
1437 }
1438
PaintBorder(const Offset & offset,SkCanvas * canvas)1439 void FlutterDecorationPainter::PaintBorder(const Offset& offset, SkCanvas* canvas)
1440 {
1441 if (!decoration_) {
1442 return;
1443 }
1444
1445 if (decoration_->GetHasBorderImageSource() || decoration_->GetHasBorderImageGradient()) {
1446 return;
1447 }
1448
1449 Border border = decoration_->GetBorder();
1450 if (!border.HasValue()) {
1451 return;
1452 }
1453
1454 SkPaint paint;
1455 if (opacity_ != UINT8_MAX) {
1456 paint.setAlpha(opacity_);
1457 }
1458 paint.setAntiAlias(true);
1459 paint.setStyle(SkPaint::Style::kFill_Style);
1460 flutter::RRect outerRRect = GetOuterRRect(offset + margin_.GetOffsetInPx(scale_), border);
1461 flutter::RRect innerRRect = GetInnerRRect(offset + margin_.GetOffsetInPx(scale_), border);
1462 flutter::RRect clipRRect = GetClipRRect(offset + margin_.GetOffsetInPx(scale_), border);
1463
1464 AdjustBorderStyle(border);
1465 if (CanUseFourLine(border)) {
1466 PaintBorderWithLine(offset + margin_.GetOffsetInPx(scale_), border, canvas, paint);
1467 } else if (CanUseFillStyle(border, paint)) {
1468 canvas->drawDRRect(outerRRect.sk_rrect, innerRRect.sk_rrect, paint);
1469 } else if (CanUsePathRRect(border, paint)) {
1470 SkPath borderPath;
1471 borderPath.addRRect(clipRRect.sk_rrect);
1472 canvas->drawPath(borderPath, paint);
1473 } else {
1474 canvas->save();
1475 canvas->clipRRect(outerRRect.sk_rrect, SkClipOp::kIntersect, true);
1476 canvas->clipRRect(innerRRect.sk_rrect, SkClipOp::kDifference, true);
1477 PaintBorderWithPath(offset + margin_.GetOffsetInPx(scale_), border, canvas, paint);
1478 canvas->restore();
1479 }
1480 }
1481
PaintBorderWithPath(const Offset & offset,const Border & border,SkCanvas * canvas,SkPaint & paint)1482 void FlutterDecorationPainter::PaintBorderWithPath(const Offset& offset, const Border& border, SkCanvas* canvas, SkPaint& paint)
1483 {
1484 float offsetX = offset.GetX();
1485 float offsetY = offset.GetY();
1486 float width = paintSize_.Width();
1487 float height = paintSize_.Height();
1488 float leftW = NormalizeToPx(border.Left().GetWidth());
1489 float topW = NormalizeToPx(border.Top().GetWidth());
1490 float rightW = NormalizeToPx(border.Right().GetWidth());
1491 float bottomW = NormalizeToPx(border.Bottom().GetWidth());
1492 float maxW = std::max(std::max(leftW, topW), std::max(rightW, bottomW));
1493 float x = offset.GetX() + leftW / 2.0f;
1494 float y = offset.GetY() + topW / 2.0f;
1495 float w = std::max(0.0, paintSize_.Width() - (leftW + rightW) / 2.0f);
1496 float h = std::max(0.0, paintSize_.Height() - (topW + bottomW) / 2.0f);
1497 float tlX = std::max(0.0, NormalizeToPx(border.TopLeftRadius().GetX()) - (topW + leftW) / 4.0f);
1498 float tlY = std::max(0.0, NormalizeToPx(border.TopLeftRadius().GetY()) - (topW + leftW) / 4.0f);
1499 float trX = std::max(0.0, NormalizeToPx(border.TopRightRadius().GetX()) - (topW + rightW) / 4.0f);
1500 float trY = std::max(0.0, NormalizeToPx(border.TopRightRadius().GetY()) - (topW + rightW) / 4.0f);
1501 float brX = std::max(0.0, NormalizeToPx(border.BottomRightRadius().GetX()) - (bottomW + rightW) / 4.0f);
1502 float brY = std::max(0.0, NormalizeToPx(border.BottomRightRadius().GetY()) - (bottomW + rightW) / 4.0f);
1503 float blX = std::max(0.0, NormalizeToPx(border.BottomLeftRadius().GetX()) - (bottomW + leftW) / 4.0f);
1504 float blY = std::max(0.0, NormalizeToPx(border.BottomLeftRadius().GetY()) - (bottomW + leftW) / 4.0f);
1505 if (border.Top().HasValue() && !NearZero(topW)) {
1506 // Draw Top Border
1507 SetBorderStyle(border.Top(), paint, false);
1508 auto rectStart = SkRect::MakeXYWH(x, y, tlX * 2.0f, tlY * 2.0f);
1509 auto rectEnd = SkRect::MakeXYWH(x + w - trX * 2.0f, y, trX * 2.0f, trY * 2.0f);
1510 SkPath topBorder;
1511 paint.setStrokeWidth(maxW);
1512 if (border.Top().GetBorderStyle() != BorderStyle::DOTTED) {
1513 paint.setStrokeWidth(maxW);
1514 }
1515 if (NearZero(tlX) || NearZero(tlY) || NearZero(trX) || NearZero(trY)) {
1516 canvas->save();
1517 }
1518 if (NearZero(tlX) && !NearZero(leftW)) {
1519 topBorder.moveTo(offsetX, y);
1520 topBorder.lineTo(x, y);
1521 SkPath topClipPath;
1522 topClipPath.moveTo(offsetX - leftW, offsetY - topW);
1523 topClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + topW * EXTEND);
1524 topClipPath.lineTo(offsetX, offsetY + topW * EXTEND);
1525 topClipPath.close();
1526 canvas->clipPath(topClipPath, SkClipOp::kDifference, true);
1527 }
1528 topBorder.arcTo(rectStart, TOP_START, SWEEP_ANGLE, false);
1529 topBorder.arcTo(rectEnd, TOP_END, SWEEP_ANGLE + 0.5f, false);
1530 if (NearZero(trX) && !NearZero(rightW)) {
1531 topBorder.lineTo(offsetX + width, y);
1532 SkPath topClipPath;
1533 topClipPath.moveTo(offsetX + width + rightW, offsetY - topW);
1534 topClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + topW * EXTEND);
1535 topClipPath.lineTo(offsetX + width, offsetY + topW * EXTEND);
1536 topClipPath.close();
1537 canvas->clipPath(topClipPath, SkClipOp::kDifference, true);
1538 }
1539 canvas->drawPath(topBorder, paint);
1540 if (NearZero(tlX) || NearZero(tlY) || NearZero(trX) || NearZero(trY)) {
1541 canvas->restore();
1542 }
1543 }
1544 if (border.Right().HasValue() && !NearZero(rightW)) {
1545 // Draw Right Border
1546 SetBorderStyle(border.Right(), paint, false);
1547 auto rectStart = SkRect::MakeXYWH(x + w - trX * 2.0f, y, trX * 2.0f, trY * 2.0f);
1548 auto rectEnd = SkRect::MakeXYWH(x + w - brX * 2.0f, y + h - brY * 2.0f, brX * 2.0f, brY * 2.0f);
1549 SkPath rightBorder;
1550 paint.setStrokeWidth(maxW);
1551 if (border.Right().GetBorderStyle() != BorderStyle::DOTTED) {
1552 paint.setStrokeWidth(maxW);
1553 }
1554 if (NearZero(trX) || NearZero(trY) || NearZero(brX) || NearZero(brY)) {
1555 canvas->save();
1556 }
1557 if (NearZero(trX) && !NearZero(topW)) {
1558 rightBorder.moveTo(offsetX + width - rightW / 2.0f, offsetY);
1559 rightBorder.lineTo(x + w - trX * 2.0f, y);
1560 SkPath rightClipPath;
1561 rightClipPath.moveTo(offsetX + width + rightW, offsetY - topW);
1562 rightClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + topW * EXTEND);
1563 rightClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY);
1564 rightClipPath.close();
1565 canvas->clipPath(rightClipPath, SkClipOp::kDifference, true);
1566 }
1567 rightBorder.arcTo(rectStart, RIGHT_START, SWEEP_ANGLE, false);
1568 rightBorder.arcTo(rectEnd, RIGHT_END, SWEEP_ANGLE + 0.5f, false);
1569 if (NearZero(brX) && !NearZero(bottomW)) {
1570 rightBorder.lineTo(offsetX + width - rightW / 2.0f,
1571 offsetY + height);
1572 SkPath rightClipPath;
1573 rightClipPath.moveTo(offsetX + width + rightW, offsetY + height + bottomW);
1574 rightClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + height - bottomW * EXTEND);
1575 rightClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + height);
1576 rightClipPath.close();
1577 canvas->clipPath(rightClipPath, SkClipOp::kDifference, true);
1578 }
1579 canvas->drawPath(rightBorder, paint);
1580 if (NearZero(trX) || NearZero(trY) || NearZero(brX) || NearZero(brY)) {
1581 canvas->restore();
1582 }
1583 }
1584 if (border.Bottom().HasValue() && !NearZero(bottomW)) {
1585 // Draw Bottom Border
1586 SetBorderStyle(border.Bottom(), paint, false);
1587 auto rectStart = SkRect::MakeXYWH(x + w - brX * 2.0f, y + h - brY * 2.0f, brX * 2.0f, brY * 2.0f);
1588 auto rectEnd = SkRect::MakeXYWH(x, y + h - blY * 2.0f, blX * 2.0f, blY * 2.0f);
1589 SkPath bottomBorder;
1590 if (border.Bottom().GetBorderStyle() != BorderStyle::DOTTED) {
1591 paint.setStrokeWidth(maxW);
1592 }
1593 if (NearZero(brX) || NearZero(brY) || NearZero(blX) || NearZero(blY)) {
1594 canvas->save();
1595 }
1596 if (NearZero(brX) && !NearZero(rightW)) {
1597 bottomBorder.moveTo(offsetX + width,
1598 offsetY + height - bottomW / 2.0f);
1599 bottomBorder.lineTo(x + w - brX * 2.0f, y + h - brY * 2.0f);
1600 SkPath bottomClipPath;
1601 bottomClipPath.moveTo(offsetX + width + rightW, offsetY + height + bottomW);
1602 bottomClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + height - bottomW * EXTEND);
1603 bottomClipPath.lineTo(offsetX + width, offsetY + height - bottomW * EXTEND);
1604 bottomClipPath.close();
1605 canvas->clipPath(bottomClipPath, SkClipOp::kDifference, true);
1606 }
1607 bottomBorder.arcTo(rectStart, BOTTOM_START, SWEEP_ANGLE, false);
1608 bottomBorder.arcTo(rectEnd, BOTTOM_END, SWEEP_ANGLE + 0.5f, false);
1609 if (NearZero(blX) && !NearZero(leftW)) {
1610 bottomBorder.lineTo(offsetX, offsetY + height - bottomW / 2.0f);
1611 SkPath bottomClipPath;
1612 bottomClipPath.moveTo(offsetX - leftW, offsetY + height + bottomW);
1613 bottomClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + height - bottomW * EXTEND);
1614 bottomClipPath.lineTo(offsetX, offsetY + height - bottomW * EXTEND);
1615 bottomClipPath.close();
1616 canvas->clipPath(bottomClipPath, SkClipOp::kDifference, true);
1617 }
1618 canvas->drawPath(bottomBorder, paint);
1619 if (NearZero(brX) || NearZero(brY) || NearZero(blX) || NearZero(blY)) {
1620 canvas->restore();
1621 }
1622 }
1623 if (border.Left().HasValue() && !NearZero(leftW)) {
1624 // Draw Left Border
1625 SetBorderStyle(border.Left(), paint, false);
1626 auto rectStart = SkRect::MakeXYWH(x, y + h - blY * 2.0f, blX * 2.0f, blY * 2.0f);
1627 auto rectEnd = SkRect::MakeXYWH(x, y, tlX * 2.0f, tlY * 2.0f);
1628 SkPath leftBorder;
1629 if (border.Left().GetBorderStyle() != BorderStyle::DOTTED) {
1630 paint.setStrokeWidth(maxW);
1631 }
1632 if (NearZero(blX) || NearZero(blY) || NearZero(tlX) || NearZero(tlY)) {
1633 canvas->save();
1634 }
1635 if (NearZero(blX) && !NearZero(bottomW)) {
1636 leftBorder.moveTo(offsetX + leftW / 2.0f, offsetY + height);
1637 leftBorder.lineTo(x, y + h - blY * 2.0f);
1638 SkPath leftClipPath;
1639 leftClipPath.moveTo(offsetX - leftW, offsetY + height + bottomW);
1640 leftClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + height - bottomW * EXTEND);
1641 leftClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + height);
1642 leftClipPath.close();
1643 canvas->clipPath(leftClipPath, SkClipOp::kDifference, true);
1644 }
1645 leftBorder.arcTo(rectStart, LEFT_START, SWEEP_ANGLE, false);
1646 leftBorder.arcTo(rectEnd, LEFT_END, SWEEP_ANGLE + 0.5f, false);
1647 if (NearZero(tlX) && !NearZero(topW)) {
1648 leftBorder.lineTo(offsetX + leftW / 2.0f, offsetY);
1649 SkPath topClipPath;
1650 topClipPath.moveTo(offsetX - leftW, offsetY - topW);
1651 topClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + topW * EXTEND);
1652 topClipPath.lineTo(offsetX + leftW * EXTEND, offsetY);
1653 topClipPath.close();
1654 canvas->clipPath(topClipPath, SkClipOp::kDifference, true);
1655 }
1656 canvas->drawPath(leftBorder, paint);
1657 if (NearZero(blX) || NearZero(blY) || NearZero(tlX) || NearZero(tlY)) {
1658 canvas->restore();
1659 }
1660 }
1661 }
1662
PaintBorderWithLine(const Offset & offset,const Border & border,SkCanvas * canvas,SkPaint & paint)1663 void FlutterDecorationPainter::PaintBorderWithLine(const Offset& offset,
1664 const Border& border, SkCanvas* canvas, SkPaint& paint)
1665 {
1666 double addLen = 0.5;
1667 if (border.Left().GetBorderStyle() != BorderStyle::DOTTED) {
1668 addLen = 0.0;
1669 }
1670 // paint left border edge.
1671 BorderEdge left = border.Left();
1672 if (left.HasValue()) {
1673 if (NearZero(NormalizeToPx(left.GetWidth()))) {
1674 LOGI("left border width is zero");
1675 return;
1676 }
1677 auto borderLength = paintSize_.Height() - NormalizeToPx(left.GetWidth()) * addLen * 2.0;
1678 int32_t rawNumber = borderLength / (2 * NormalizeToPx(left.GetWidth()));
1679 if (NearZero(rawNumber)) {
1680 LOGI("number of dot is zero");
1681 return;
1682 }
1683 SetBorderStyle(left, paint, false, borderLength / rawNumber, borderLength);
1684 canvas->drawLine(offset.GetX() + SK_ScalarHalf * NormalizeToPx(left.GetWidth()),
1685 offset.GetY() + addLen * NormalizeToPx(left.GetWidth()),
1686 offset.GetX() + SK_ScalarHalf * NormalizeToPx(left.GetWidth()), offset.GetY() + paintSize_.Height(), paint);
1687 }
1688
1689 // paint bottom border edge.
1690 BorderEdge bottom = border.Bottom();
1691 if (bottom.HasValue()) {
1692 if (NearZero(NormalizeToPx(bottom.GetWidth()))) {
1693 LOGI("bottom border width is zero");
1694 return;
1695 }
1696 auto borderLength = paintSize_.Width() - NormalizeToPx(bottom.GetWidth()) * addLen * 2.0;
1697 int32_t rawNumber = borderLength / (2 * NormalizeToPx(bottom.GetWidth()));
1698 if (NearZero(rawNumber)) {
1699 LOGI("number of dot is zero");
1700 return;
1701 }
1702 SetBorderStyle(bottom, paint, false, borderLength / rawNumber, borderLength);
1703 canvas->drawLine(offset.GetX() + addLen * NormalizeToPx(bottom.GetWidth()),
1704 offset.GetY() + paintSize_.Height() - SK_ScalarHalf * NormalizeToPx(bottom.GetWidth()),
1705 offset.GetX() + paintSize_.Width(),
1706 offset.GetY() + paintSize_.Height() - SK_ScalarHalf * NormalizeToPx(bottom.GetWidth()), paint);
1707 }
1708 // paint right border edge.
1709 BorderEdge right = border.Right();
1710 if (right.HasValue()) {
1711 if (NearZero(NormalizeToPx(right.GetWidth()))) {
1712 LOGI("right border width is zero");
1713 return;
1714 }
1715 auto borderLength = paintSize_.Height() - NormalizeToPx(right.GetWidth()) * addLen * 2.0;
1716 int32_t rawNumber = borderLength / (2 * NormalizeToPx(right.GetWidth()));
1717 if (NearZero(rawNumber)) {
1718 LOGI("number of dot is zero");
1719 return;
1720 }
1721 SetBorderStyle(right, paint, false, borderLength / rawNumber, borderLength);
1722 canvas->drawLine(offset.GetX() + paintSize_.Width() - SK_ScalarHalf * NormalizeToPx(right.GetWidth()),
1723 offset.GetY() + paintSize_.Height() - addLen * NormalizeToPx(right.GetWidth()),
1724 offset.GetX() + paintSize_.Width() - SK_ScalarHalf * NormalizeToPx(right.GetWidth()), offset.GetY(), paint);
1725 }
1726 // paint top border edge.
1727 BorderEdge top = border.Top();
1728 if (top.HasValue()) {
1729 if (NearZero(NormalizeToPx(top.GetWidth()))) {
1730 LOGI("top border width is zero");
1731 return;
1732 }
1733 auto borderLength = paintSize_.Width() - NormalizeToPx(top.GetWidth()) * addLen * 2.0;
1734 int32_t rawNumber = borderLength / (2 * NormalizeToPx(top.GetWidth()));
1735 if (NearZero(rawNumber)) {
1736 LOGI("number of dot is zero");
1737 return;
1738 }
1739 SetBorderStyle(top, paint, false, borderLength / rawNumber, borderLength);
1740 canvas->drawLine(offset.GetX() + addLen * NormalizeToPx(top.GetWidth()),
1741 offset.GetY() + SK_ScalarHalf * NormalizeToPx(top.GetWidth()), offset.GetX() + paintSize_.Width(),
1742 offset.GetY() + SK_ScalarHalf * NormalizeToPx(top.GetWidth()), paint);
1743 }
1744 }
1745
1746 // Add for box-shadow, otherwise using PaintShadow().
PaintBoxShadows(const SkRRect & rrect,const std::vector<Shadow> & shadows,SkCanvas * canvas)1747 void FlutterDecorationPainter::PaintBoxShadows(
1748 const SkRRect& rrect, const std::vector<Shadow>& shadows, SkCanvas* canvas)
1749 {
1750 if (!canvas) {
1751 LOGE("PaintBoxShadows failed, canvas is null.");
1752 return;
1753 }
1754 canvas->save();
1755 // The location of the component itself does not draw a shadow
1756 canvas->clipRRect(rrect, SkClipOp::kDifference, true);
1757
1758 if (!shadows.empty()) {
1759 for (const auto& shadow : shadows) {
1760 if (!shadow.IsValid()) {
1761 LOGW("The current shadow is not drawn if the shadow is invalid.");
1762 continue;
1763 }
1764 if (shadow.GetHardwareAcceleration()) {
1765 // Do not support blurRadius and spreadRadius to paint shadow, use elevation.
1766 PaintShadow(SkPath().addRRect(rrect), shadow, canvas);
1767 } else {
1768 SkRRect shadowRRect = rrect;
1769 // Keep the original rounded corners.
1770 SkVector fRadii[4] = { rrect.radii(SkRRect::kUpperLeft_Corner),
1771 rrect.radii(SkRRect::kUpperRight_Corner), rrect.radii(SkRRect::kLowerRight_Corner),
1772 rrect.radii(SkRRect::kLowerLeft_Corner) };
1773
1774 SkScalar left = rrect.rect().left();
1775 SkScalar top = rrect.rect().top();
1776 auto width = rrect.width() + DOUBLE_WIDTH * shadow.GetSpreadRadius();
1777 auto height = rrect.height() + DOUBLE_WIDTH * shadow.GetSpreadRadius();
1778 SkRect skRect {};
1779 skRect.setXYWH(left + SkDoubleToScalar(shadow.GetOffset().GetX() - shadow.GetSpreadRadius()),
1780 top + SkDoubleToScalar(shadow.GetOffset().GetY() - shadow.GetSpreadRadius()),
1781 SkDoubleToScalar(width > 0.0 ? width : 0.0), SkDoubleToScalar(height > 0.0 ? height : 0.0));
1782 shadowRRect.setRectRadii(skRect, fRadii);
1783 SkPaint paint;
1784 paint.setColor(shadow.GetColor().GetValue());
1785 paint.setAntiAlias(true);
1786 paint.setMaskFilter(SkMaskFilter::MakeBlur(
1787 SkBlurStyle::kNormal_SkBlurStyle, ConvertRadiusToSigma(shadow.GetBlurRadius())));
1788 canvas->drawRRect(shadowRRect, paint);
1789 }
1790 }
1791 }
1792 canvas->restore();
1793 }
1794
PaintShadow(const SkPath & path,const Shadow & shadow,SkCanvas * canvas)1795 void FlutterDecorationPainter::PaintShadow(const SkPath& path, const Shadow& shadow, SkCanvas* canvas)
1796 {
1797 if (!canvas) {
1798 LOGE("PaintShadow failed, canvas is null.");
1799 return;
1800 }
1801 if (!shadow.IsValid()) {
1802 LOGW("The current shadow is not drawn if the shadow is invalid.");
1803 return;
1804 }
1805
1806 canvas->save();
1807 SkPath skPath = path;
1808 skPath.offset(shadow.GetOffset().GetX(), shadow.GetOffset().GetY());
1809 SkColor spotColor = shadow.GetColor().GetValue();
1810 if (shadow.GetHardwareAcceleration()) {
1811 // PlaneParams represents the coordinates of the component, and here we only need to focus on the elevation
1812 // of the component.
1813 SkPoint3 planeParams = { 0.0f, 0.0f, shadow.GetElevation() };
1814
1815 // LightPos is the location of a spot light source, which is by default located directly above the center
1816 // of the component.
1817 SkPoint3 lightPos = { skPath.getBounds().centerX(), skPath.getBounds().centerY(), shadow.GetLightHeight() };
1818
1819 // Current ambient color is not available.
1820 SkColor ambientColor = SkColorSetARGB(0, 0, 0, 0);
1821 SkShadowUtils::DrawShadow(canvas, skPath, planeParams, lightPos, shadow.GetLightRadius(), ambientColor,
1822 spotColor, SkShadowFlags::kTransparentOccluder_ShadowFlag);
1823 } else {
1824 SkPaint paint;
1825 paint.setColor(spotColor);
1826 paint.setAntiAlias(true);
1827 paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, ConvertRadiusToSigma(shadow.GetBlurRadius())));
1828 canvas->drawPath(skPath, paint);
1829 }
1830 canvas->restore();
1831 }
1832
PaintImage(const Offset & offset,RenderContext & context)1833 void FlutterDecorationPainter::PaintImage(const Offset& offset, RenderContext& context)
1834 {
1835 if (decoration_) {
1836 RefPtr<BackgroundImage> backgroundImage = decoration_->GetImage();
1837 if (backgroundImage && renderImage_) {
1838 renderImage_->RenderWithContext(context, offset);
1839 }
1840 }
1841 }
1842
GetGradientPaint(SkPaint & paint)1843 bool FlutterDecorationPainter::GetGradientPaint(SkPaint& paint)
1844 {
1845 Gradient gradient = decoration_->GetGradient();
1846 if (NearZero(paintSize_.Width()) || NearZero(paintSize_.Height()) || !gradient.IsValid()) {
1847 return false;
1848 }
1849 #ifndef NEW_SKIA
1850 SkSize skPaintSize = SkSize::Make(SkDoubleToMScalar(paintSize_.Width()), SkDoubleToMScalar(paintSize_.Height()));
1851 #else
1852 SkSize skPaintSize = SkSize::Make(paintSize_.Width(), paintSize_.Height());
1853 #endif
1854 auto shader = CreateGradientShader(gradient, skPaintSize);
1855 paint.setShader(std::move(shader));
1856 return true;
1857 }
1858
PaintGradient(const Offset & offset,SkCanvas * canvas,SkPaint & paint)1859 void FlutterDecorationPainter::PaintGradient(const Offset& offset, SkCanvas* canvas, SkPaint& paint)
1860 {
1861 Gradient gradient = decoration_->GetGradient();
1862 if (NearZero(paintSize_.Width()) || NearZero(paintSize_.Height())) {
1863 return;
1864 }
1865 if (!gradient.IsValid()) {
1866 return;
1867 }
1868
1869 #ifndef NEW_SKIA
1870 SkSize skPaintSize = SkSize::Make(SkDoubleToMScalar(paintSize_.Width()), SkDoubleToMScalar(paintSize_.Height()));
1871 #else
1872 SkSize skPaintSize = SkSize::Make(paintSize_.Width(), paintSize_.Height());
1873 #endif
1874 SkAutoCanvasRestore restore(canvas, true);
1875 auto shader = CreateGradientShader(gradient, skPaintSize);
1876 paint.setShader(std::move(shader));
1877 #ifndef NEW_SKIA
1878 canvas->translate(SkDoubleToMScalar(offset.GetX() + NormalizeToPx(margin_.Left())),
1879 SkDoubleToMScalar(offset.GetY() + NormalizeToPx(margin_.Top())));
1880 canvas->drawRect(
1881 SkRect::MakeXYWH(0.0f, 0.0f, SkDoubleToMScalar(paintSize_.Width()), SkDoubleToMScalar(paintSize_.Height())),
1882 paint);
1883 #else
1884 canvas->translate(offset.GetX() + NormalizeToPx(margin_.Left()),
1885 offset.GetY() + NormalizeToPx(margin_.Top()));
1886 canvas->drawRect(
1887 SkRect::MakeXYWH(0.0f, 0.0f, paintSize_.Width(), paintSize_.Height()),
1888 paint);
1889 #endif
1890 // reset shader;
1891 paint.setShader(nullptr);
1892 }
1893
CreateGradientShader(const Gradient & gradient,const SkSize & size)1894 sk_sp<SkShader> FlutterDecorationPainter::CreateGradientShader(const Gradient& gradient, const SkSize& size)
1895 {
1896 auto ptr = std::make_unique<GradientShader>(gradient);
1897 switch (gradient.GetType()) {
1898 case GradientType::LINEAR:
1899 ptr = LinearGradientShader::CreateLinearGradient(gradient, size);
1900 break;
1901 case GradientType::RADIAL:
1902 ptr = RadialGradientShader::CreateRadialGradient(gradient, size, dipScale_);
1903 break;
1904 case GradientType::SWEEP:
1905 ptr = SweepGradientShader::CreateSweepGradient(gradient, size, dipScale_);
1906 break;
1907 default:
1908 LOGE("unsupported gradient type.");
1909 break;
1910 }
1911 return ptr->CreateGradientShader();
1912 }
1913
CheckBorderEdgeForRRect(const Border & border)1914 bool FlutterDecorationPainter::CheckBorderEdgeForRRect(const Border& border)
1915 {
1916 double leftWidth = NormalizeToPx(border.Left().GetWidth());
1917 if (NearEqual(leftWidth, NormalizeToPx(border.Top().GetWidth())) &&
1918 NearEqual(leftWidth, NormalizeToPx(border.Right().GetWidth())) &&
1919 NearEqual(leftWidth, NormalizeToPx(border.Bottom().GetWidth()))) {
1920 BorderStyle leftStyle = border.Left().GetBorderStyle();
1921 return leftStyle == border.Top().GetBorderStyle() && leftStyle == border.Right().GetBorderStyle() &&
1922 leftStyle == border.Bottom().GetBorderStyle();
1923 }
1924 return false;
1925 }
1926
AdjustBorderStyle(Border & border)1927 void FlutterDecorationPainter::AdjustBorderStyle(Border& border)
1928 {
1929 // if not set border style use default border style solid
1930 if (border.Left().IsValid() && border.Left().GetBorderStyle() == BorderStyle::NONE) {
1931 border.SetLeftStyle(BorderStyle::SOLID);
1932 }
1933
1934 if (border.Top().IsValid() && border.Top().GetBorderStyle() == BorderStyle::NONE) {
1935 border.SetTopStyle(BorderStyle::SOLID);
1936 }
1937
1938 if (border.Right().IsValid() && border.Right().GetBorderStyle() == BorderStyle::NONE) {
1939 border.SetRightStyle(BorderStyle::SOLID);
1940 }
1941
1942 if (border.Bottom().IsValid() && border.Bottom().GetBorderStyle() == BorderStyle::NONE) {
1943 border.SetBottomStyle(BorderStyle::SOLID);
1944 }
1945 }
1946
NormalizeToPx(const Dimension & dimension) const1947 double FlutterDecorationPainter::NormalizeToPx(const Dimension& dimension) const
1948 {
1949 if ((dimension.Unit() == DimensionUnit::VP) || (dimension.Unit() == DimensionUnit::FP)) {
1950 return (dimension.Value() * dipScale_);
1951 }
1952 return dimension.Value();
1953 }
1954
SliceNormalizePercentToPx(const Dimension & dimension,bool isVertical) const1955 double FlutterDecorationPainter::SliceNormalizePercentToPx(const Dimension& dimension, bool isVertical) const
1956 {
1957 if (dimension.Unit() != DimensionUnit::PERCENT) {
1958 return NormalizeToPx(dimension);
1959 }
1960 auto limit = isVertical ? image_->width() : image_->height();
1961 return limit * dimension.Value();
1962 }
1963
WidthNormalizePercentToPx(const Dimension & dimension,bool isVertical) const1964 double FlutterDecorationPainter::WidthNormalizePercentToPx(const Dimension& dimension, bool isVertical) const
1965 {
1966 if (dimension.Unit() != DimensionUnit::PERCENT) {
1967 return NormalizeToPx(dimension);
1968 }
1969 auto limit = isVertical ? paintSize_.Width() : paintSize_.Height();
1970 return limit * dimension.Value();
1971 }
1972
OutsetNormalizePercentToPx(const Dimension & dimension,bool isVertical) const1973 double FlutterDecorationPainter::OutsetNormalizePercentToPx(const Dimension& dimension, bool isVertical) const
1974 {
1975 if (dimension.Unit() != DimensionUnit::PERCENT) {
1976 return NormalizeToPx(dimension);
1977 }
1978 auto limit = isVertical ? paintSize_.Width() : paintSize_.Height();
1979 return limit * dimension.Value();
1980 }
1981
1982 } // namespace OHOS::Ace
1983