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