1 /*
2  * Copyright (c) 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_ng/render/adapter/skia_decoration_painter.h"
17 
18 #include <cmath>
19 #include <functional>
20 #include <memory>
21 
22 #include "include/core/SkColor.h"
23 #include "include/core/SkColorFilter.h"
24 #include "include/core/SkImage.h"
25 #include "include/core/SkRRect.h"
26 #include "include/core/SkScalar.h"
27 #include "include/effects/SkGradientShader.h"
28 #include "include/utils/SkParsePath.h"
29 
30 #include "base/geometry/dimension.h"
31 #include "base/geometry/ng/offset_t.h"
32 #include "base/utils/utils.h"
33 #include "core/components_ng/property/calc_length.h"
34 #include "core/components_ng/property/measure_utils.h"
35 #include "core/components_ng/render/drawing_prop_convertor.h"
36 
37 namespace OHOS::Ace::NG {
38 
39 namespace {
40 
41 constexpr int32_t CORNER_NUMS = 4;
42 constexpr uint32_t COLOR_MASK = 0xff000000;
43 constexpr double RIGHT_ANGLE_D = 90.0;
44 constexpr float RIGHT_ANGLE_F = 90.0f;
45 constexpr int32_t STRAIGHT_ANGLE = 180;
46 constexpr double STRAIGHT_ANGLE_D = 180.0;
47 constexpr int32_t REFLEX_ANGLE = 270;
48 constexpr double REFLEX_ANGLE_D = 270.0;
49 constexpr int32_t FULL_ROTATION_F = 360;
50 constexpr double FULL_ROTATION_F = 360.0f;
51 constexpr int32_t MIN_COLOR_STOPS = 2;
52 constexpr int32_t MIN_COLOR_SIZE = 2;
53 
54 template<typename T>
55 class Evaluator : public AceType {
56 public:
57     virtual T Evaluate(const T& begin, const T& end, float fraction) = 0;
58 };
59 
60 template<typename T>
61 class LinearEvaluator : public Evaluator<T> {
62 public:
63     LinearEvaluator() = default;
64 
65     ~LinearEvaluator() override = default;
66 
Evaluate(const T & begin,const T & end,float fraction)67     T Evaluate(const T& begin, const T& end, float fraction) override
68     {
69         return begin + (end - begin) * fraction;
70     }
71 };
72 
73 class GradientShader {
74 public:
75     struct ColorStop {
76         SkColor color { SK_ColorTRANSPARENT };
77         float offset { 0.0f };
78         bool hasValue { false };
79         bool isLength { false };
80     };
81 
GradientShader(const NG::Gradient & gradient)82     explicit GradientShader(const NG::Gradient& gradient)
83     {
84         for (auto& stop : gradient.GetColors()) {
85             ColorStop colorStop;
86             colorStop.color = stop.GetColor().GetValue();
87             colorStop.hasValue = stop.GetHasValue();
88             if (colorStop.hasValue) {
89                 colorStop.isLength = stop.GetDimension().Unit() != DimensionUnit::PERCENT;
90                 if (colorStop.isLength) {
91                     colorStop.offset = static_cast<float>(stop.GetDimension().Value());
92                 } else {
93                     colorStop.offset = static_cast<float>(stop.GetDimension().Value() / 100.0);
94                 }
95             }
96             colorStops_.emplace_back(colorStop);
97         }
98         isRepeat_ = gradient.GetRepeat();
99     }
100     virtual ~GradientShader() = default;
CreateGradientShader()101     virtual sk_sp<SkShader> CreateGradientShader()
102     {
103         return nullptr;
104     }
105 
106 protected:
AddColorStops(float gradientLength)107     void AddColorStops(float gradientLength)
108     {
109         uint32_t colorSize = colorStops_.size();
110         for (uint32_t i = 0; i < colorSize; i++) {
111             auto& colorStop = colorStops_[i];
112             if (colorStop.hasValue) {
113                 if (colorStop.isLength) {
114                     // only support px and percent
115                     colorStop.offset = GreatNotEqual(gradientLength, 0.0) ? colorStop.offset / gradientLength : 0.0f;
116                     colorStop.hasValue = true;
117                 }
118             } else if (i == 0) {
119                 // default: start with 0.0%
120                 colorStop.offset = 0.0f;
121                 colorStop.hasValue = true;
122             } else if (colorSize > 1 && i == colorSize - 1) {
123                 // default: end with 100.0%
124                 colorStop.offset = 1.0f;
125                 colorStop.hasValue = true;
126             }
127             // make sure colors in increasing order
128             if (colorStop.hasValue && i > 0) {
129                 auto prev = static_cast<int32_t>(i - 1);
130                 while (prev >= 0 && !colorStops_[prev].hasValue) {
131                     prev--;
132                 }
133                 if (prev >= 0 && colorStop.offset < colorStops_[prev].offset) {
134                     colorStop.offset = colorStops_[prev].offset;
135                 }
136             }
137         }
138         AdjustNoValueColorStop();
139     }
140 
AdjustNoValueColorStop()141     void AdjustNoValueColorStop()
142     {
143         // deal with not specified color stop
144         uint32_t colorSize = colorStops_.size();
145         if (colorSize <= MIN_COLOR_SIZE) {
146             return;
147         }
148         int32_t noValueStartIndex = 0;
149         bool inUnspecifiedRun = false;
150         for (uint32_t i = 0; i < colorSize; ++i) {
151             if (!colorStops_[i].hasValue && !inUnspecifiedRun) {
152                 noValueStartIndex = static_cast<int32_t>(i);
153                 inUnspecifiedRun = true;
154             } else if (colorStops_[i].hasValue && inUnspecifiedRun) {
155                 auto noValueEndIndex = static_cast<int32_t>(i);
156                 if (noValueStartIndex < noValueEndIndex) {
157                     auto beginValue = colorStops_[noValueStartIndex - 1].offset;
158                     auto endValue = colorStops_[noValueEndIndex].offset;
159                     auto delta = (endValue - beginValue) / static_cast<float>(noValueEndIndex - noValueStartIndex + 1);
160 
161                     for (int32_t j = noValueStartIndex; j < noValueEndIndex; ++j) {
162                         colorStops_[j].offset = (beginValue + static_cast<float>(j - noValueStartIndex + 1) * delta);
163                         colorStops_[j].hasValue = true;
164                     }
165                 }
166                 inUnspecifiedRun = false;
167             }
168         }
169     }
170 
NeedAdjustColorStops() const171     bool NeedAdjustColorStops() const
172     {
173         if (colorStops_.size() < MIN_COLOR_STOPS) {
174             return false;
175         }
176 
177         if (isRepeat_) {
178             return true;
179         }
180         // not in the range of [0, 1]
181         if (colorStops_.front().offset < 0.0f || colorStops_.back().offset > 1.0f) {
182             return true;
183         }
184         return false;
185     }
186 
AdjustColorStops()187     void AdjustColorStops()
188     {
189         const auto firstOffset = colorStops_.front().offset;
190         const auto lastOffset = colorStops_.back().offset;
191         const float span = std::min(std::max(lastOffset - firstOffset, 0.0f), std::numeric_limits<float>::max());
192         if (NearZero(span)) {
193             return;
194         }
195         for (auto& stop : colorStops_) {
196             const auto relativeOffset = std::min(stop.offset - firstOffset, std::numeric_limits<float>::max());
197             const auto adjustOffset = relativeOffset / span;
198             stop.offset = adjustOffset;
199         }
200     }
201 
ToSkColors(std::vector<SkScalar> & pos,std::vector<SkColor> & colors) const202     void ToSkColors(std::vector<SkScalar>& pos, std::vector<SkColor>& colors) const
203     {
204         if (colorStops_.empty()) {
205             pos.push_back(0.0f);
206             colors.push_back(SK_ColorTRANSPARENT);
207         } else if (colorStops_.front().offset > 0.0f) {
208             pos.push_back(0.0f);
209             colors.push_back(SkColor(colorStops_.front().color));
210         }
211 
212         for (const auto& stop : colorStops_) {
213             pos.push_back(stop.offset);
214             colors.push_back(stop.color);
215         }
216 
217         if (pos.back() < 1.0f) {
218             pos.push_back(1.0f);
219             colors.push_back(colors.back());
220         }
221     }
222 
223 protected:
224     std::vector<ColorStop> colorStops_;
225     bool isRepeat_ { false };
226 };
227 
228 class LinearGradientShader final : public GradientShader {
229 public:
LinearGradientShader(const NG::Gradient & gradient,const SkPoint & firstPoint,const SkPoint & secondPoint)230     LinearGradientShader(const NG::Gradient& gradient, const SkPoint& firstPoint, const SkPoint& secondPoint)
231         : GradientShader(gradient), firstPoint_(firstPoint), secondPoint_(secondPoint)
232     {}
233     ~LinearGradientShader() override = default;
234 
CreateGradientShader()235     sk_sp<SkShader> CreateGradientShader() override
236     {
237         AddColorStops((secondPoint_ - firstPoint_).length());
238         if (NeedAdjustColorStops()) {
239             auto startOffset = colorStops_.front().offset;
240             auto endOffset = colorStops_.back().offset;
241             AdjustColorStops();
242             AdjustPoint(startOffset, endOffset);
243         }
244 
245         std::vector<SkScalar> pos;
246         std::vector<SkColor> colors;
247         ToSkColors(pos, colors);
248         SkPoint pts[2] = { firstPoint_, secondPoint_ };
249         SkTileMode tileMode = SkTileMode::kClamp;
250         if (isRepeat_) {
251             tileMode = SkTileMode::kRepeat;
252         }
253         return SkGradientShader::MakeLinear(pts, &colors[0], &pos[0], colors.size(), tileMode);
254     }
255 
CreateLinearGradient(const NG::Gradient & gradient,const SkSize & size)256     static std::unique_ptr<GradientShader> CreateLinearGradient(const NG::Gradient& gradient, const SkSize& size)
257     {
258         auto linearGradient = gradient.GetLinearGradient();
259         CHECK_NULL_RETURN(linearGradient, nullptr);
260         SkPoint firstPoint { 0.0f, 0.0f };
261         SkPoint secondPoint { 0.0f, 0.0f };
262         if (linearGradient->angle) {
263             EndPointsFromAngle(linearGradient->angle.value().Value(), size, firstPoint, secondPoint);
264         } else {
265             if (linearGradient->linearX && linearGradient->linearY) {
266                 float width = size.width();
267                 float height = size.height();
268                 if (linearGradient->linearX == NG::GradientDirection::LEFT) {
269                     height *= -1;
270                 }
271                 if (linearGradient->linearY == NG::GradientDirection::BOTTOM) {
272                     width *= -1;
273                 }
274                 float angle = RIGHT_ANGLE_F - Rad2deg(atan2(width, height));
275                 EndPointsFromAngle(angle, size, firstPoint, secondPoint);
276             } else if (linearGradient->linearX || linearGradient->linearY) {
277                 secondPoint = DirectionToPoint(linearGradient->linearX, linearGradient->linearY, size);
278                 if (linearGradient->linearX) {
279                     firstPoint.fX = size.width() - secondPoint.x();
280                 }
281                 if (linearGradient->linearY) {
282                     firstPoint.fY = size.height() - secondPoint.y();
283                 }
284             } else {
285                 secondPoint.set(0.0f, size.height());
286             }
287         }
288         return std::make_unique<LinearGradientShader>(gradient, firstPoint, secondPoint);
289     }
290 
291 private:
AdjustPoint(float firstOffset,float lastOffset)292     void AdjustPoint(float firstOffset, float lastOffset)
293     {
294         const auto delta = secondPoint_ - firstPoint_;
295         secondPoint_ = firstPoint_ + delta * lastOffset;
296         firstPoint_ = firstPoint_ + delta * firstOffset;
297     }
298 
Deg2rad(float deg)299     static float Deg2rad(float deg)
300     {
301         return static_cast<float>(deg * M_PI / STRAIGHT_ANGLE_D);
302     }
303 
Rad2deg(float rad)304     static float Rad2deg(float rad)
305     {
306         return static_cast<float>(rad * STRAIGHT_ANGLE_D / M_PI);
307     }
308 
EndPointsFromAngle(float angle,const SkSize & size,SkPoint & firstPoint,SkPoint & secondPoint)309     static void EndPointsFromAngle(float angle, const SkSize& size, SkPoint& firstPoint, SkPoint& secondPoint)
310     {
311         angle = fmod(angle, FULL_ROTATION_F);
312         if (LessNotEqual(angle, 0.0)) {
313             angle += FULL_ROTATION_F;
314         }
315 
316         if (NearEqual(angle, 0.0)) {
317             firstPoint.set(0.0f, size.height());
318             secondPoint.set(0.0f, 0.0f);
319             return;
320         } else if (NearEqual(angle, RIGHT_ANGLE_D)) {
321             firstPoint.set(0.0f, 0.0f);
322             secondPoint.set(size.width(), 0.0f);
323             return;
324         } else if (NearEqual(angle, STRAIGHT_ANGLE_D)) {
325             firstPoint.set(0.0f, 0.0f);
326             secondPoint.set(0, size.height());
327             return;
328         } else if (NearEqual(angle, REFLEX_ANGLE_D)) {
329             firstPoint.set(size.width(), 0.0f);
330             secondPoint.set(0.0f, 0.0f);
331             return;
332         }
333         float slope = tan(Deg2rad(RIGHT_ANGLE_F - angle));
334         float perpendicularSlope = -1 / slope;
335 
336         float halfHeight = size.height() / 2;
337         float halfWidth = size.width() / 2;
338         SkPoint cornerPoint { 0.0f, 0.0f };
339         if (angle < RIGHT_ANGLE_D) {
340             cornerPoint.set(halfWidth, halfHeight);
341         } else if (angle < STRAIGHT_ANGLE) {
342             cornerPoint.set(halfWidth, -halfHeight);
343         } else if (angle < REFLEX_ANGLE) {
344             cornerPoint.set(-halfWidth, -halfHeight);
345         } else {
346             cornerPoint.set(-halfWidth, halfHeight);
347         }
348 
349         // Compute b (of y = kx + b) using the corner point.
350         float b = cornerPoint.y() - perpendicularSlope * cornerPoint.x();
351         float endX = b / (slope - perpendicularSlope);
352         float endY = perpendicularSlope * endX + b;
353 
354         secondPoint.set(halfWidth + endX, halfHeight - endY);
355         firstPoint.set(halfWidth - endX, halfHeight + endY);
356     }
357 
DirectionToPoint(const std::optional<GradientDirection> & x,const std::optional<GradientDirection> & y,const SkSize & size)358     static SkPoint DirectionToPoint(
359         const std::optional<GradientDirection>& x, const std::optional<GradientDirection>& y, const SkSize& size)
360     {
361         SkPoint point { 0.0f, 0.0f };
362         if (x) {
363             if (x == GradientDirection::LEFT) {
364                 point.fX = 0.0f;
365             } else {
366                 point.fX = size.width();
367             }
368         }
369 
370         if (y) {
371             if (y == GradientDirection::TOP) {
372                 point.fY = 0.0f;
373             } else {
374                 point.fY = size.height();
375             }
376         }
377 
378         return point;
379     }
380 
381 private:
382     SkPoint firstPoint_ { 0.0f, 0.0f };
383     SkPoint secondPoint_ { 0.0f, 0.0f };
384 };
385 
386 class RadialGradientShader final : public GradientShader {
387 public:
RadialGradientShader(const NG::Gradient & gradient,const SkPoint & center,float radius0,float radius1,float ratio)388     RadialGradientShader(const NG::Gradient& gradient, const SkPoint& center, float radius0, float radius1, float ratio)
389         : GradientShader(gradient), center_(center), radius0_(radius0), radius1_(radius1), ratio_(ratio)
390     {}
391 
392     ~RadialGradientShader() override = default;
393 
CreateGradientShader()394     sk_sp<SkShader> CreateGradientShader() override
395     {
396         SkMatrix matrix = SkMatrix::I();
397         ratio_ = NearZero(ratio_) ? 1.0f : ratio_;
398         if (ratio_ != 1.0f) {
399             matrix.preScale(1.0f, 1 / ratio_, center_.x(), center_.y());
400         }
401         AddColorStops(radius1_);
402         if (NeedAdjustColorStops()) {
403             auto startOffset = colorStops_.front().offset;
404             auto endOffset = colorStops_.back().offset;
405             AdjustColorStops();
406             AdjustRadius(startOffset, endOffset);
407         }
408 
409         SkTileMode tileMode = SkTileMode::kClamp;
410         if (isRepeat_) {
411             ClampNegativeOffsets();
412             tileMode = SkTileMode::kRepeat;
413         }
414         std::vector<SkScalar> pos;
415         std::vector<SkColor> colors;
416         ToSkColors(pos, colors);
417         radius0_ = std::max(radius0_, 0.0f);
418         radius1_ = std::max(radius1_, 0.0f);
419         return SkGradientShader::MakeTwoPointConical(
420             center_, radius0_, center_, radius1_, &colors[0], &pos[0], colors.size(), tileMode, 0, &matrix);
421     }
422 
CreateRadialGradient(const NG::Gradient & gradient,const SkSize & size)423     static std::unique_ptr<GradientShader> CreateRadialGradient(const NG::Gradient& gradient, const SkSize& size)
424     {
425         auto radialGradient = gradient.GetRadialGradient();
426         if (!radialGradient) {
427             return nullptr;
428         }
429         SkPoint center = GetCenter(radialGradient, size);
430         SkSize circleSize = GetCircleSize(radialGradient, size, center);
431         bool isDegenerate = NearZero(circleSize.width()) || NearZero(circleSize.height());
432         float ratio = NearZero(circleSize.height()) ? 1.0f : circleSize.width() / circleSize.height();
433         float radius0 = 0.0f;
434         float radius1 = circleSize.width();
435         if (isDegenerate) {
436             ratio = 1.0f;
437             radius1 = 0.0f;
438         }
439         return std::make_unique<RadialGradientShader>(gradient, center, radius0, radius1, ratio);
440     }
441 
442 private:
AdjustRadius(float firstOffset,float lastOffset)443     void AdjustRadius(float firstOffset, float lastOffset)
444     {
445         float adjustedR0 = radius1_ * firstOffset;
446         float adjustedR1 = radius1_ * lastOffset;
447         if (adjustedR0 < 0.0) {
448             const float radiusSpan = adjustedR1 - adjustedR0;
449             const float shiftToPositive = radiusSpan * ceilf(-adjustedR0 / radiusSpan);
450             adjustedR0 += shiftToPositive;
451             adjustedR1 += shiftToPositive;
452         }
453         radius0_ = adjustedR0;
454         radius1_ = adjustedR1;
455     }
456 
ClampNegativeOffsets()457     void ClampNegativeOffsets()
458     {
459         float lastNegativeOffset = 0.0f;
460         for (uint32_t i = 0; i < colorStops_.size(); ++i) {
461             auto current = colorStops_[i].offset;
462             if (GreatOrEqual(current, 0.0f)) {
463                 if (i > 0) {
464                     float fraction = -lastNegativeOffset / (current - lastNegativeOffset);
465                     LinearEvaluator<Color> evaluator;
466                     Color adjustColor =
467                         evaluator.Evaluate(Color(colorStops_[i - 1].color), Color(colorStops_[i].color), fraction);
468                     colorStops_[i - 1].color = adjustColor.GetValue();
469                 }
470                 break;
471             }
472             colorStops_[i].offset = 0.0f;
473             lastNegativeOffset = current;
474         }
475     }
476 
GetCenter(const std::shared_ptr<NG::RadialGradient> & radialGradient,const SkSize & size)477     static SkPoint GetCenter(const std::shared_ptr<NG::RadialGradient>& radialGradient, const SkSize& size)
478     {
479         SkPoint center = SkPoint::Make(size.width() / 2.0f, size.height() / 2.0f);
480         if (radialGradient->radialCenterX) {
481             const auto& value = radialGradient->radialCenterX.value();
482             center.fX = static_cast<float>(
483                 value.Unit() == DimensionUnit::PERCENT ? value.Value() / 100.0 * size.width() : value.ConvertToPx());
484         }
485         if (radialGradient->radialCenterY) {
486             const auto& value = radialGradient->radialCenterY.value();
487             center.fY = static_cast<float>(
488                 value.Unit() == DimensionUnit::PERCENT ? value.Value() / 100.0 * size.height() : value.ConvertToPx());
489         }
490         return center;
491     }
492 
GetCircleSize(const std::shared_ptr<NG::RadialGradient> & radialGradient,const SkSize & size,const SkPoint & center)493     static SkSize GetCircleSize(
494         const std::shared_ptr<NG::RadialGradient>& radialGradient, const SkSize& size, const SkPoint& center)
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());
501             circleSize.fHeight = circleSize.fWidth;
502             if (radialGradient->radialVerticalSize) {
503                 const auto& wValue = radialGradient->radialVerticalSize.value();
504                 circleSize.fHeight = static_cast<float>(
505                     wValue.Unit() == DimensionUnit::PERCENT ? wValue.Value() * size.height() : wValue.ConvertToPx());
506             }
507         } else {
508             RadialShapeType shape = NG::RadialShapeType::ELLIPSE;
509             if ((radialGradient->radialShape && radialGradient->radialShape.value() == NG::RadialShapeType::CIRCLE) ||
510                 (!radialGradient->radialShape && !radialGradient->radialSizeType &&
511                     radialGradient->radialHorizontalSize && !radialGradient->radialVerticalSize)) {
512                 shape = NG::RadialShapeType::CIRCLE;
513             }
514             auto sizeType =
515                 radialGradient->radialSizeType ? radialGradient->radialSizeType.value() : NG::RadialSizeType::NONE;
516             switch (sizeType) {
517                 case NG::RadialSizeType::CLOSEST_SIDE:
518                     circleSize = RadiusToSide(center, size, shape, std::less<>());
519                     break;
520                 case NG::RadialSizeType::FARTHEST_SIDE:
521                     circleSize = RadiusToSide(center, size, shape, std::greater<>());
522                     break;
523                 case NG::RadialSizeType::CLOSEST_CORNER:
524                     circleSize = RadiusToCorner(center, size, shape, std::less<>());
525                     break;
526                 case NG::RadialSizeType::FARTHEST_CORNER:
527                 case NG::RadialSizeType::NONE:
528                 default:
529                     circleSize = RadiusToCorner(center, size, shape, std::greater<>());
530                     break;
531             }
532         }
533         return circleSize;
534     }
535 
536     using CompareType = std::function<bool(float, float)>;
537 
RadiusToSide(const SkPoint & center,const SkSize & size,NG::RadialShapeType type,const CompareType & compare)538     static SkSize RadiusToSide(
539         const SkPoint& center, const SkSize& size, NG::RadialShapeType type, const CompareType& compare)
540     {
541         auto dx1 = static_cast<float>(std::fabs(center.fX));
542         auto dy1 = static_cast<float>(std::fabs(center.fY));
543         auto dx2 = static_cast<float>(std::fabs(center.fX - size.width()));
544         auto dy2 = static_cast<float>(std::fabs(center.fY - size.height()));
545 
546         auto dx = compare(dx1, dx2) ? dx1 : dx2;
547         auto dy = compare(dy1, dy2) ? dy1 : dy2;
548 
549         if (type == NG::RadialShapeType::CIRCLE) {
550             return compare(dx, dy) ? SkSize::Make(dx, dx) : SkSize::Make(dy, dy);
551         }
552         return SkSize::Make(dx, dy);
553     }
554 
EllipseRadius(const SkPoint & p,float ratio)555     static inline SkSize EllipseRadius(const SkPoint& p, float ratio)
556     {
557         if (NearZero(ratio) || std::isinf(ratio)) {
558             return SkSize { 0.0f, 0.0f };
559         }
560         // x^2/a^2 + y^2/b^2 = 1
561         // a/b = ratio, b = a/ratio
562         // a = sqrt(x^2 + y^2/(1/r^2))
563         float a = sqrtf(p.fX * p.fX + p.fY * p.fY * ratio * ratio);
564         return SkSize::Make(a, a / ratio);
565     }
566 
RadiusToCorner(const SkPoint & center,const SkSize & size,NG::RadialShapeType type,const CompareType & compare)567     static SkSize RadiusToCorner(
568         const SkPoint& center, const SkSize& size, NG::RadialShapeType type, const CompareType& compare)
569     {
570         const SkPoint corners[4] = {
571             SkPoint::Make(0.0f, 0.0f),
572             SkPoint::Make(size.width(), 0.0f),
573             SkPoint::Make(size.width(), size.height()),
574             SkPoint::Make(0.0f, size.height()),
575         };
576 
577         int32_t cornerIndex = 0;
578         float distance = (center - corners[cornerIndex]).length();
579         for (int32_t i = 1; i < CORNER_NUMS; i++) {
580             float newDistance = (center - corners[i]).length();
581             if (compare(newDistance, distance)) {
582                 cornerIndex = i;
583                 distance = newDistance;
584             }
585         }
586 
587         if (type == NG::RadialShapeType::CIRCLE) {
588             return SkSize::Make(distance, distance);
589         }
590 
591         SkSize sideRadius = RadiusToSide(center, size, NG::RadialShapeType::ELLIPSE, compare);
592         return EllipseRadius(corners[cornerIndex] - center,
593             NearZero(sideRadius.height()) ? 1.0f : sideRadius.width() / sideRadius.height());
594     }
595 
596 private:
597     SkPoint center_ { 0.0f, 0.0f };
598     float radius0_ { 0.0f };
599     float radius1_ { 0.0f };
600     float ratio_ { 1.0f };
601 };
602 
603 class SweepGradientShader final : public GradientShader {
604 public:
SweepGradientShader(const NG::Gradient & gradient,const SkPoint & center,float startAngle,float endAngle,float rotation)605     SweepGradientShader(
606         const NG::Gradient& gradient, const SkPoint& center, float startAngle, float endAngle, float rotation)
607         : GradientShader(gradient), center_(center), startAngle_(startAngle), endAngle_(endAngle), rotation_(rotation)
608     {}
609     ~SweepGradientShader() override = default;
610 
CreateGradientShader()611     sk_sp<SkShader> CreateGradientShader() override
612     {
613         AddColorStops(1.0f);
614         if (NeedAdjustColorStops()) {
615             auto startOffset = colorStops_.front().offset;
616             auto endOffset = colorStops_.back().offset;
617             AdjustColorStops();
618             AdjustAngle(startOffset, endOffset);
619         }
620 
621         SkMatrix matrix = SkMatrix::I();
622         if (!NearZero(rotation_)) {
623             matrix.preRotate(rotation_, center_.fX, center_.fY);
624         }
625 
626         std::vector<SkScalar> pos;
627         std::vector<SkColor> colors;
628         ToSkColors(pos, colors);
629         SkTileMode tileMode = SkTileMode::kClamp;
630         if (isRepeat_) {
631             tileMode = SkTileMode::kRepeat;
632         }
633         return SkGradientShader::MakeSweep(
634             center_.fX, center_.fY, &colors[0], &pos[0], colors.size(), tileMode, startAngle_, endAngle_, 0, &matrix);
635     }
636 
CreateSweepGradient(const NG::Gradient & gradient,const SkSize & size)637     static std::unique_ptr<GradientShader> CreateSweepGradient(const NG::Gradient& gradient, const SkSize& size)
638     {
639         auto sweepGradient = gradient.GetSweepGradient();
640         CHECK_NULL_RETURN(sweepGradient, nullptr);
641         SkPoint center = GetCenter(sweepGradient, size);
642         float rotationAngle = 0.0f;
643         if (sweepGradient->rotation) {
644             rotationAngle = fmod(sweepGradient->rotation.value().Value(), FULL_ROTATION_F);
645             if (LessNotEqual(rotationAngle, 0.0f)) {
646                 rotationAngle += FULL_ROTATION_F;
647             }
648         }
649         float startAngle = 0.0f;
650         float endAngle = 0.0f;
651         if (sweepGradient->startAngle.has_value()) {
652             startAngle = sweepGradient->startAngle.value().Value();
653         }
654         if (sweepGradient->endAngle.has_value()) {
655             endAngle = sweepGradient->endAngle.value().Value();
656         }
657         if (startAngle > endAngle) {
658             return nullptr;
659         }
660         return std::make_unique<NG::SweepGradientShader>(gradient, center, startAngle, endAngle, rotationAngle);
661     }
662 
663 private:
GetCenter(const std::shared_ptr<NG::SweepGradient> & sweepGradient,const SkSize & size)664     static SkPoint GetCenter(const std::shared_ptr<NG::SweepGradient>& sweepGradient, const SkSize& size)
665     {
666         SkPoint center = SkPoint::Make(size.width() / 2.0f, size.height() / 2.0f);
667 
668         if (sweepGradient->centerX) {
669             const auto& value = sweepGradient->centerX.value();
670             center.fX = static_cast<float>(
671                 value.Unit() == DimensionUnit::PERCENT ? value.Value() / 100.0f * size.width() : value.ConvertToPx());
672         }
673         if (sweepGradient->centerY) {
674             const auto& value = sweepGradient->centerY.value();
675             center.fY = static_cast<float>(
676                 value.Unit() == DimensionUnit::PERCENT ? value.Value() / 100.0f * size.height() : value.ConvertToPx());
677         }
678         return center;
679     }
680 
AdjustAngle(float firstOffset,float lastOffset)681     void AdjustAngle(float firstOffset, float lastOffset)
682     {
683         const auto delta = endAngle_ - startAngle_;
684         endAngle_ = startAngle_ + delta * lastOffset;
685         startAngle_ = startAngle_ + delta * firstOffset;
686     }
687 
688 private:
689     SkPoint center_ { 0.0f, 0.0f };
690     float startAngle_ { 0.0f };
691     float endAngle_ { 0.0f };
692     float rotation_ { 0.0f };
693 };
694 
695 } // namespace
696 
CreateGradientShader(const NG::Gradient & gradient,const SizeF & frameSize)697 sk_sp<SkShader> SkiaDecorationPainter::CreateGradientShader(const NG::Gradient& gradient, const SizeF& frameSize)
698 {
699     auto ptr = std::make_unique<GradientShader>(gradient);
700     auto size = SkSize::Make(frameSize.Width(), frameSize.Height());
701     switch (gradient.GetType()) {
702         case NG::GradientType::LINEAR:
703             ptr = LinearGradientShader::CreateLinearGradient(gradient, size);
704             break;
705         case NG::GradientType::RADIAL:
706             ptr = RadialGradientShader::CreateRadialGradient(gradient, size);
707             break;
708         case NG::GradientType::SWEEP:
709             ptr = SweepGradientShader::CreateSweepGradient(gradient, size);
710             break;
711         default:
712             LOGE("unsupported gradient type.");
713             break;
714     }
715     if (!ptr) {
716         return nullptr;
717     }
718     return ptr->CreateGradientShader();
719 }
720 
SkiaDimensionToPx(const Dimension & value,const SizeF & size,LengthMode type)721 float SkiaDecorationPainter::SkiaDimensionToPx(const Dimension& value, const SizeF& size, LengthMode type)
722 {
723     if (value.Unit() == DimensionUnit::PERCENT) {
724         switch (type) {
725             case LengthMode::HORIZONTAL:
726                 return ConvertToPx(value, ScaleProperty::CreateScaleProperty(), size.Width()).value();
727             case LengthMode::VERTICAL:
728                 return ConvertToPx(value, ScaleProperty::CreateScaleProperty(), size.Height()).value();
729             case LengthMode::OTHER:
730                 return ConvertToPx(value, ScaleProperty::CreateScaleProperty(), sqrt(size.Width() * size.Height()))
731                     .value();
732             default:
733                 return 0.0f;
734         }
735     } else {
736         return static_cast<float>(value.ConvertToPx());
737     }
738 }
739 
SkiaGetFloatRadiusValue(const Dimension & src,const Dimension & dest,const SizeF & size,LengthMode type)740 float SkiaDecorationPainter::SkiaGetFloatRadiusValue(
741     const Dimension& src, const Dimension& dest, const SizeF& size, LengthMode type)
742 {
743     if (src.Value() < 0.0 && dest.Value() > 0.0) {
744         return SkiaDimensionToPx(dest, size, type);
745     }
746     return SkiaDimensionToPx(src, size, type);
747 }
748 
SkiaCreateSkPath(const RefPtr<BasicShape> & basicShape,const SizeF & size)749 SkPath SkiaDecorationPainter::SkiaCreateSkPath(const RefPtr<BasicShape>& basicShape, const SizeF& size)
750 {
751     OffsetF position;
752     SkPath skPath;
753     if (basicShape == nullptr || basicShape->GetBasicShapeType() == BasicShapeType::NONE) {
754         skPath.addRect(SkRect::MakeXYWH(0.0, 0.0, size.Width(), size.Height()));
755         return skPath;
756     }
757     float offsetX = SkiaDimensionToPx(basicShape->GetPosition().GetX(), size, LengthMode::HORIZONTAL);
758     float offsetY = SkiaDimensionToPx(basicShape->GetPosition().GetY(), size, LengthMode::VERTICAL);
759     position += OffsetF(offsetX, offsetY);
760     switch (basicShape->GetBasicShapeType()) {
761         case BasicShapeType::INSET: {
762             SkiaCreateInset(basicShape, size, position, skPath);
763             break;
764         }
765         case BasicShapeType::CIRCLE: {
766             SkiaCreateCircle(basicShape, size, position, skPath);
767             break;
768         }
769         case BasicShapeType::ELLIPSE: {
770             SkiaCreateEllipse(basicShape, size, position, skPath);
771             break;
772         }
773         case BasicShapeType::POLYGON: {
774             SkiaCreatePolygon(basicShape, size, position, skPath);
775             break;
776         }
777         case BasicShapeType::PATH: {
778             SkiaCreatePath(basicShape, size, position, skPath);
779             break;
780         }
781         case BasicShapeType::RECT: {
782             SkiaCreateRect(basicShape, size, position, skPath);
783             break;
784         }
785         default: {
786             LOGE("invalid BasicShapeType");
787             break;
788         }
789     }
790     return skPath;
791 }
792 
SkiaCreateInset(const RefPtr<BasicShape> & basicShape,const SizeF & size,const OffsetF & position,SkPath & skPath)793 void SkiaDecorationPainter::SkiaCreateInset(
794     const RefPtr<BasicShape>& basicShape, const SizeF& size, const OffsetF& position, SkPath& skPath)
795 {
796     const auto& inset = AceType::DynamicCast<Inset>(basicShape);
797     CHECK_NULL_VOID(inset);
798     double left = SkiaDimensionToPx(inset->GetLeft(), size, LengthMode::HORIZONTAL) + position.GetX();
799     double top = SkiaDimensionToPx(inset->GetTop(), size, LengthMode::VERTICAL) + position.GetY();
800     double right = size.Width() - SkiaDimensionToPx(inset->GetRight(), size, LengthMode::HORIZONTAL) + position.GetX();
801     double bottom = size.Height() - SkiaDimensionToPx(inset->GetBottom(), size, LengthMode::VERTICAL) + position.GetY();
802     SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
803     auto radiusSize = SizeF(std::abs(rect.width()), std::abs(rect.height()));
804     float topLeftRadiusX = SkiaDimensionToPx(inset->GetTopLeftRadius().GetX(), radiusSize, LengthMode::HORIZONTAL);
805     float topLeftRadiusY = SkiaDimensionToPx(inset->GetTopLeftRadius().GetY(), radiusSize, LengthMode::VERTICAL);
806     float topRightRadiusX = SkiaDimensionToPx(inset->GetTopRightRadius().GetX(), radiusSize, LengthMode::HORIZONTAL);
807     float topRightRadiusY = SkiaDimensionToPx(inset->GetTopRightRadius().GetY(), radiusSize, LengthMode::VERTICAL);
808     float bottomRightRadiusX =
809         SkiaDimensionToPx(inset->GetBottomRightRadius().GetX(), radiusSize, LengthMode::HORIZONTAL);
810     float bottomRightRadiusY =
811         SkiaDimensionToPx(inset->GetBottomRightRadius().GetY(), radiusSize, LengthMode::VERTICAL);
812     float bottomLeftRadiusX =
813         SkiaDimensionToPx(inset->GetBottomLeftRadius().GetX(), radiusSize, LengthMode::HORIZONTAL);
814     float bottomLeftRadiusY = SkiaDimensionToPx(inset->GetBottomLeftRadius().GetY(), radiusSize, LengthMode::VERTICAL);
815     const SkVector fRadii[4] = { { topLeftRadiusX, topLeftRadiusY }, { topRightRadiusX, topRightRadiusY },
816         { bottomRightRadiusX, bottomRightRadiusY }, { bottomLeftRadiusX, bottomLeftRadiusY } };
817     SkRRect roundRect;
818     roundRect.setRectRadii(rect, fRadii);
819     skPath.addRRect(roundRect);
820 }
821 
SkiaCreateCircle(const RefPtr<BasicShape> & basicShape,const SizeF & size,const OffsetF & position,SkPath & skPath)822 void SkiaDecorationPainter::SkiaCreateCircle(
823     const RefPtr<BasicShape>& basicShape, const SizeF& size, const OffsetF& position, SkPath& skPath)
824 {
825     const auto& circle = AceType::DynamicCast<Circle>(basicShape);
826     CHECK_NULL_VOID(circle);
827     if (circle->GetRadius().IsValid()) {
828         skPath.addCircle(SkiaDimensionToPx(circle->GetAxisX(), size, LengthMode::HORIZONTAL) + position.GetX(),
829             SkiaDimensionToPx(circle->GetAxisY(), size, LengthMode::VERTICAL) + position.GetY(),
830             SkiaDimensionToPx(circle->GetRadius(), size, LengthMode::OTHER));
831     } else {
832         float width = SkiaDimensionToPx(circle->GetWidth(), size, LengthMode::HORIZONTAL);
833         float height = SkiaDimensionToPx(circle->GetHeight(), size, LengthMode::VERTICAL);
834         float offsetX = SkiaDimensionToPx(circle->GetOffset().GetX(), size, LengthMode::HORIZONTAL) + position.GetX();
835         float offsetY = SkiaDimensionToPx(circle->GetOffset().GetY(), size, LengthMode::VERTICAL) + position.GetY();
836         skPath.addCircle(width * 0.5 + offsetX, height * 0.5 + offsetY, std::min(width, height) * 0.5);
837     }
838 }
839 
SkiaCreateEllipse(const RefPtr<BasicShape> & basicShape,const SizeF & size,const OffsetF & position,SkPath & skPath)840 void SkiaDecorationPainter::SkiaCreateEllipse(
841     const RefPtr<BasicShape>& basicShape, const SizeF& size, const OffsetF& position, SkPath& skPath)
842 {
843     const auto& ellipse = AceType::DynamicCast<Ellipse>(basicShape);
844     CHECK_NULL_VOID(ellipse);
845     if (ellipse->GetRadiusX().IsValid()) {
846         float rx = SkiaDimensionToPx(ellipse->GetRadiusX(), size, LengthMode::HORIZONTAL);
847         float ry = SkiaDimensionToPx(ellipse->GetRadiusY(), size, LengthMode::VERTICAL);
848         double x = SkiaDimensionToPx(ellipse->GetAxisX(), size, LengthMode::HORIZONTAL) + position.GetX() - rx;
849         double y = SkiaDimensionToPx(ellipse->GetAxisY(), size, LengthMode::VERTICAL) + position.GetY() - ry;
850         SkRect rect = SkRect::MakeXYWH(x, y, rx + rx, ry + ry);
851         skPath.addOval(rect);
852     } else {
853         auto width = SkiaDimensionToPx(ellipse->GetWidth(), size, LengthMode::HORIZONTAL);
854         auto height = SkiaDimensionToPx(ellipse->GetHeight(), size, LengthMode::VERTICAL);
855         float x = SkiaDimensionToPx(ellipse->GetOffset().GetX(), size, LengthMode::HORIZONTAL) + position.GetX();
856         float y = SkiaDimensionToPx(ellipse->GetOffset().GetY(), size, LengthMode::VERTICAL) + position.GetY();
857         SkRect rect = SkRect::MakeXYWH(x, y, width, height);
858         skPath.addOval(rect);
859     }
860 }
861 
SkiaCreatePolygon(const RefPtr<BasicShape> & basicShape,const SizeF & size,const OffsetF & position,SkPath & skPath)862 void SkiaDecorationPainter::SkiaCreatePolygon(
863     const RefPtr<BasicShape>& basicShape, const SizeF& size, const OffsetF& position, SkPath& skPath)
864 {
865     const auto& polygon = AceType::DynamicCast<Polygon>(basicShape);
866     CHECK_NULL_VOID(polygon);
867     std::vector<SkPoint> skPoints;
868     for (auto [x, y] : polygon->GetPoints()) {
869         skPoints.emplace_back(SkPoint::Make(SkiaDimensionToPx(x, size, LengthMode::HORIZONTAL) + position.GetX(),
870             SkiaDimensionToPx(y, size, LengthMode::VERTICAL) + position.GetX()));
871     }
872     if (skPoints.empty()) {
873         LOGW("points is null");
874         return;
875     }
876     skPath.addPoly(&skPoints[0], skPoints.size(), true);
877 }
878 
SkiaCreatePath(const RefPtr<BasicShape> & basicShape,const SizeF & size,const OffsetF & position,SkPath & skPath)879 void SkiaDecorationPainter::SkiaCreatePath(
880     const RefPtr<BasicShape>& basicShape, const SizeF& size, const OffsetF& position, SkPath& skPath)
881 {
882     const auto& path = AceType::DynamicCast<Path>(basicShape);
883     CHECK_NULL_VOID(path);
884     if (path->GetValue().empty()) {
885         LOGW("path value is null");
886         return;
887     }
888     SkPath tmpPath;
889     bool ret = SkParsePath::FromSVGString(path->GetValue().c_str(), &tmpPath);
890     if (!ret) {
891         LOGW("path value is invalid");
892         return;
893     }
894     float offsetX = SkiaDimensionToPx(path->GetOffset().GetX(), size, LengthMode::HORIZONTAL) + position.GetX();
895     float offsetY = SkiaDimensionToPx(path->GetOffset().GetY(), size, LengthMode::VERTICAL) + position.GetY();
896     skPath.addPath(tmpPath, offsetX, offsetY);
897 }
898 
SkiaCreateRect(const RefPtr<BasicShape> & basicShape,const SizeF & size,const OffsetF & position,SkPath & skPath)899 void SkiaDecorationPainter::SkiaCreateRect(
900     const RefPtr<BasicShape>& basicShape, const SizeF& size, const OffsetF& position, SkPath& skPath)
901 {
902     const auto& rect = AceType::DynamicCast<ShapeRect>(basicShape);
903     CHECK_NULL_VOID(rect);
904     double left = SkiaDimensionToPx(rect->GetOffset().GetX(), size, LengthMode::HORIZONTAL) + position.GetX();
905     double top = SkiaDimensionToPx(rect->GetOffset().GetY(), size, LengthMode::VERTICAL) + position.GetY();
906     double width = SkiaDimensionToPx(rect->GetWidth(), size, LengthMode::HORIZONTAL);
907     double height = SkiaDimensionToPx(rect->GetHeight(), size, LengthMode::VERTICAL);
908     SkRect skRect = SkRect::MakeXYWH(left, top, width, height);
909     auto radiusSize = SizeF(width, height);
910     float topLeftRadiusX = SkiaGetFloatRadiusValue(
911         rect->GetTopLeftRadius().GetX(), rect->GetTopLeftRadius().GetY(), radiusSize, LengthMode::HORIZONTAL);
912     float topLeftRadiusY = SkiaGetFloatRadiusValue(
913         rect->GetTopLeftRadius().GetY(), rect->GetTopLeftRadius().GetX(), radiusSize, LengthMode::VERTICAL);
914     float topRightRadiusX = SkiaGetFloatRadiusValue(
915         rect->GetTopRightRadius().GetX(), rect->GetTopRightRadius().GetY(), radiusSize, LengthMode::HORIZONTAL);
916     float topRightRadiusY = SkiaGetFloatRadiusValue(
917         rect->GetTopRightRadius().GetY(), rect->GetTopRightRadius().GetX(), radiusSize, LengthMode::VERTICAL);
918     float bottomRightRadiusX = SkiaGetFloatRadiusValue(
919         rect->GetBottomRightRadius().GetX(), rect->GetBottomRightRadius().GetY(), radiusSize, LengthMode::HORIZONTAL);
920     float bottomRightRadiusY = SkiaGetFloatRadiusValue(
921         rect->GetBottomRightRadius().GetY(), rect->GetBottomRightRadius().GetX(), radiusSize, LengthMode::VERTICAL);
922     float bottomLeftRadiusX = SkiaGetFloatRadiusValue(
923         rect->GetBottomLeftRadius().GetX(), rect->GetBottomLeftRadius().GetY(), radiusSize, LengthMode::HORIZONTAL);
924     float bottomLeftRadiusY = SkiaGetFloatRadiusValue(
925         rect->GetBottomLeftRadius().GetY(), rect->GetBottomLeftRadius().GetX(), radiusSize, LengthMode::VERTICAL);
926     const SkVector fRadii[4] = { { topLeftRadiusX, topLeftRadiusY }, { topRightRadiusX, topRightRadiusY },
927         { bottomRightRadiusX, bottomRightRadiusY }, { bottomLeftRadiusX, bottomLeftRadiusY } };
928     SkRRect roundRect;
929     roundRect.setRectRadii(skRect, fRadii);
930     skPath.addRRect(roundRect);
931 }
932 
PaintGrayScale(const SkRRect & rRect,SkCanvas * canvas,float scale)933 void SkiaDecorationPainter::PaintGrayScale(const SkRRect& rRect, SkCanvas* canvas, float scale)
934 {
935     if (GreatNotEqual(scale, 0.0)) {
936         if (canvas) {
937             SkAutoCanvasRestore acr(canvas, true);
938             canvas->clipRRect(rRect, true);
939             SkPaint paint;
940             paint.setAntiAlias(true);
941             float matrix[20] = { 0.0f };
942             matrix[0] = matrix[5] = matrix[10] = 0.2126f * scale;
943             matrix[1] = matrix[6] = matrix[11] = 0.7152f * scale;
944             matrix[2] = matrix[7] = matrix[12] = 0.0722f * scale;
945             matrix[18] = 1.0f * scale;
946             paint.setColorFilter(SkColorFilters::Matrix(matrix));
947             SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
948             canvas->saveLayer(slr);
949         }
950     }
951 }
952 
PaintBrightness(const SkRRect & rRect,SkCanvas * canvas,float bright)953 void SkiaDecorationPainter::PaintBrightness(const SkRRect& rRect, SkCanvas* canvas, float bright)
954 {
955     // brightness range = (0, 2)
956     // skip painting when brightness is normal
957     CHECK_NULL_VOID(!NearEqual(bright, 1.0));
958     if (canvas) {
959         SkAutoCanvasRestore acr(canvas, true);
960         canvas->clipRRect(rRect, true);
961         SkPaint paint;
962         paint.setAntiAlias(true);
963         float matrix[20] = { 0.0f };
964         // shift brightness to (-1, 1)
965         bright = bright - 1;
966         matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.0f;
967         matrix[4] = matrix[9] = matrix[14] = bright;
968         paint.setColorFilter(SkColorFilters::Matrix(matrix));
969         SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
970         canvas->saveLayer(slr);
971     }
972 }
973 
PaintContrast(const SkRRect & rRect,SkCanvas * canvas,float contrasts)974 void SkiaDecorationPainter::PaintContrast(const SkRRect& rRect, SkCanvas* canvas, float contrasts)
975 {
976     // skip painting if contrast is normal
977     CHECK_NULL_VOID(!NearEqual(contrasts, 1.0));
978     if (canvas) {
979         SkAutoCanvasRestore acr(canvas, true);
980         canvas->clipRRect(rRect, true);
981         SkPaint paint;
982         paint.setAntiAlias(true);
983         float matrix[20] = { 0.0f };
984         matrix[0] = matrix[6] = matrix[12] = contrasts;
985         matrix[4] = matrix[9] = matrix[14] = 128 * (1 - contrasts) / 255;
986         matrix[18] = 1.0f;
987         paint.setColorFilter(SkColorFilters::Matrix(matrix));
988         SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
989         canvas->saveLayer(slr);
990     }
991 }
992 
PaintColorBlend(const SkRRect & rRect,SkCanvas * canvas,const Color & colorBlend)993 void SkiaDecorationPainter::PaintColorBlend(const SkRRect& rRect, SkCanvas* canvas, const Color& colorBlend)
994 {
995     if (colorBlend.GetValue() != COLOR_MASK) {
996         if (canvas) {
997             SkAutoCanvasRestore acr(canvas, true);
998             canvas->clipRRect(rRect, true);
999             SkPaint paint;
1000             paint.setAntiAlias(true);
1001             paint.setColorFilter(SkColorFilters::Blend(
1002                 SkColorSetARGB(colorBlend.GetAlpha(), colorBlend.GetRed(), colorBlend.GetGreen(), colorBlend.GetBlue()),
1003                 SkBlendMode::kPlus));
1004             SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
1005             canvas->saveLayer(slr);
1006         }
1007     }
1008 }
1009 
PaintSaturate(const SkRRect & rRect,SkCanvas * canvas,float saturates)1010 void SkiaDecorationPainter::PaintSaturate(const SkRRect& rRect, SkCanvas* canvas, float saturates)
1011 {
1012     if (!NearEqual(saturates, 1.0) && GreatOrEqual(saturates, 0.0)) {
1013         if (canvas) {
1014             SkAutoCanvasRestore acr(canvas, true);
1015             canvas->clipRRect(rRect, true);
1016             SkPaint paint;
1017             paint.setAntiAlias(true);
1018             float matrix[20] = { 0.0f };
1019             matrix[0] = 0.3086f * (1 - saturates) + saturates;
1020             matrix[1] = matrix[11] = 0.6094f * (1 - saturates);
1021             matrix[2] = matrix[7] = 0.0820f * (1 - saturates);
1022             matrix[5] = matrix[10] = 0.3086f * (1 - saturates);
1023             matrix[6] = 0.6094f * (1 - saturates) + saturates;
1024             matrix[12] = 0.0820f * (1 - saturates) + saturates;
1025             matrix[18] = 1.0f;
1026             paint.setColorFilter(SkColorFilters::Matrix(matrix));
1027             SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
1028             canvas->saveLayer(slr);
1029         }
1030     }
1031 }
1032 
PaintSepia(const SkRRect & rRect,SkCanvas * canvas,float sepias)1033 void SkiaDecorationPainter::PaintSepia(const SkRRect& rRect, SkCanvas* canvas, float sepias)
1034 {
1035     if (sepias > 1.0) {
1036         sepias = 1.0;
1037     }
1038     if (GreatNotEqual(sepias, 0.0)) {
1039         if (canvas) {
1040             SkAutoCanvasRestore acr(canvas, true);
1041             canvas->clipRRect(rRect, true);
1042             SkPaint paint;
1043             paint.setAntiAlias(true);
1044             float matrix[20] = { 0.0f };
1045             matrix[0] = 0.393f * sepias;
1046             matrix[1] = 0.769f * sepias;
1047             matrix[2] = 0.189f * sepias;
1048 
1049             matrix[5] = 0.349f * sepias;
1050             matrix[6] = 0.686f * sepias;
1051             matrix[7] = 0.168f * sepias;
1052 
1053             matrix[10] = 0.272f * sepias;
1054             matrix[11] = 0.534f * sepias;
1055             matrix[12] = 0.131f * sepias;
1056             matrix[18] = 1.0f * sepias;
1057             paint.setColorFilter(SkColorFilters::Matrix(matrix));
1058             SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
1059             canvas->saveLayer(slr);
1060         }
1061     }
1062 }
1063 
PaintInvert(const SkRRect & rRect,SkCanvas * canvas,float inverts)1064 void SkiaDecorationPainter::PaintInvert(const SkRRect& rRect, SkCanvas* canvas, float inverts)
1065 {
1066     if (GreatNotEqual(inverts, 0.0)) {
1067         if (canvas) {
1068             SkAutoCanvasRestore acr(canvas, true);
1069             canvas->clipRRect(rRect, true);
1070             SkPaint paint;
1071             paint.setAntiAlias(true);
1072             float matrix[20] = { 0.0f };
1073             if (inverts > 1.0) {
1074                 inverts = 1.0;
1075             }
1076             // complete color invert when dstRGB = 1 - srcRGB
1077             // map (0, 1) to (1, -1)
1078             matrix[0] = matrix[6] = matrix[12] = 1.0 - 2.0 * inverts;
1079             matrix[18] = 1.0f;
1080             // inverts = 0.5 -> RGB = (0.5, 0.5, 0.5) -> image completely gray
1081             matrix[4] = matrix[9] = matrix[14] = inverts;
1082             paint.setColorFilter(SkColorFilters::Matrix(matrix));
1083             SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
1084             canvas->saveLayer(slr);
1085         }
1086     }
1087 }
1088 
PaintHueRotate(const SkRRect & rRect,SkCanvas * canvas,float hueRotate)1089 void SkiaDecorationPainter::PaintHueRotate(const SkRRect& rRect, SkCanvas* canvas, float hueRotate)
1090 {
1091     if (GreatNotEqual(hueRotate, 0.0)) {
1092         if (canvas) {
1093             SkAutoCanvasRestore acr(canvas, true);
1094             canvas->clipRRect(rRect, true);
1095             SkPaint paint;
1096             paint.setAntiAlias(true);
1097             while (GreatOrEqual(hueRotate, FULL_ROTATION)) {
1098                 hueRotate -= FULL_ROTATION;
1099             }
1100             float matrix[20] = { 0.0f };
1101             int32_t type = hueRotate / 120;
1102             float N = (hueRotate - 120 * type) / 120;
1103             switch (type) {
1104                 case 0:
1105                     // color change = R->G, G->B, B->R
1106                     matrix[2] = matrix[5] = matrix[11] = N;
1107                     matrix[0] = matrix[6] = matrix[12] = 1 - N;
1108                     matrix[18] = 1.0f;
1109                     break;
1110                 case 1:
1111                     // compare to original: R->B, G->R, B->G
1112                     matrix[1] = matrix[7] = matrix[10] = N;
1113                     matrix[2] = matrix[5] = matrix[11] = 1 - N;
1114                     matrix[18] = 1.0f;
1115                     break;
1116                 case 2:
1117                     // back to normal color
1118                     matrix[0] = matrix[6] = matrix[12] = N;
1119                     matrix[1] = matrix[7] = matrix[10] = 1 - N;
1120                     matrix[18] = 1.0f;
1121                     break;
1122                 default:
1123                     break;
1124             }
1125             paint.setColorFilter(SkColorFilters::Matrix(matrix));
1126             SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
1127             canvas->saveLayer(slr);
1128         }
1129     }
1130 }
1131 
CreateMaskSkPaint(const RefPtr<BasicShape> & basicShape)1132 SkPaint SkiaDecorationPainter::CreateMaskSkPaint(const RefPtr<BasicShape>& basicShape)
1133 {
1134     SkPaint paint;
1135     paint.setAntiAlias(true);
1136     paint.setStyle(SkPaint::Style::kFill_Style);
1137     paint.setColor(basicShape->GetColor().GetValue());
1138     return paint;
1139 }
1140 
CreateBorderImageGradient(const NG::Gradient & gradient,const SizeF & paintSize)1141 RSImage SkiaDecorationPainter::CreateBorderImageGradient(const NG::Gradient& gradient, const SizeF& paintSize)
1142 {
1143     auto shader = SkiaDecorationPainter::CreateGradientShader(gradient, paintSize);
1144     SkPaint paint;
1145     paint.setAntiAlias(true);
1146     paint.setShader(std::move(shader));
1147 
1148     auto imageInfo = SkImageInfo::Make(paintSize.Width(), paintSize.Height(),
1149         SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kOpaque_SkAlphaType);
1150     SkBitmap skBitmap;
1151     skBitmap.allocPixels(imageInfo);
1152 
1153     std::unique_ptr<SkCanvas> skCanvas = std::make_unique<SkCanvas>(skBitmap);
1154     skCanvas->drawPaint(paint);
1155     auto skImage = SkImage::MakeFromBitmap(skBitmap);
1156     return RSImage(&skImage);
1157 }
1158 
1159 } // namespace OHOS::Ace::NG
1160