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