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