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