• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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