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