• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/pattern/canvas/custom_paint_paint_method.h"
17 
18 #include <cmath>
19 #include <unistd.h>
20 
21 #include "base/geometry/ng/offset_t.h"
22 #include "base/i18n/localization.h"
23 #include "base/json/json_util.h"
24 #include "base/log/ace_trace.h"
25 #include "base/utils/linear_map.h"
26 #include "base/utils/string_utils.h"
27 #include "base/utils/utils.h"
28 #include "bridge/common/utils/utils.h"
29 #include "core/components_ng/render/drawing.h"
30 #ifndef ACE_UNITTEST
31 #include "core/components/common/painter/rosen_decoration_painter.h"
32 #include "core/components/font/constants_converter.h"
33 #include "core/components/font/rosen_font_collection.h"
34 #include "core/image/image_provider.h"
35 #include "core/image/image_cache.h"
36 #endif
37 #include "core/pipeline/base/constants.h"
38 
39 namespace OHOS::Ace::NG {
40 namespace {
41 // BT.709
42 constexpr float LUMR = 0.2126f;
43 constexpr float LUMG = 0.7152f;
44 constexpr float LUMB = 0.0722f;
45 constexpr double HALF = 0.5;
46 constexpr double HALF_CIRCLE_ANGLE = 180.0;
47 constexpr double FULL_CIRCLE_ANGLE = 360.0;
48 constexpr double CONIC_START_ANGLE = 0.0;
49 constexpr double CONIC_END_ANGLE = 359.9;
50 constexpr double MAX_GRAYSCALE = 255.0;
51 constexpr double HANGING_PERCENT = 0.8;
52 constexpr Dimension DEFAULT_FONT_SIZE = 14.0_px;
53 const int32_t PX2REM_NUM = 15;
54 
55 #ifndef ACE_UNITTEST
56 constexpr int32_t IMAGE_CACHE_COUNT = 50;
57 #endif
58 
59 const LinearEnumMapNode<CompositeOperation, RSBlendMode> DRAWING_BLEND_MODE_TABLE[] = {
60     { CompositeOperation::SOURCE_OVER, RSBlendMode::SRC_OVER },
61     { CompositeOperation::SOURCE_ATOP, RSBlendMode::SRC_ATOP },
62     { CompositeOperation::SOURCE_IN, RSBlendMode::SRC_IN },
63     { CompositeOperation::SOURCE_OUT, RSBlendMode::SRC_OUT },
64     { CompositeOperation::DESTINATION_OVER, RSBlendMode::DST_OVER },
65     { CompositeOperation::DESTINATION_ATOP, RSBlendMode::DST_ATOP },
66     { CompositeOperation::DESTINATION_IN, RSBlendMode::DST_IN },
67     { CompositeOperation::DESTINATION_OUT, RSBlendMode::DST_OUT },
68     { CompositeOperation::LIGHTER, RSBlendMode::LIGHTEN },
69     { CompositeOperation::COPY, RSBlendMode::SRC },
70     { CompositeOperation::XOR, RSBlendMode::XOR },
71 };
72 constexpr size_t BLEND_MODE_SIZE = ArraySize(DRAWING_BLEND_MODE_TABLE);
73 
74 template<typename T, typename N>
ConvertEnumToDrawingEnum(T key,const LinearEnumMapNode<T,N> * map,size_t length,N defaultValue)75 N ConvertEnumToDrawingEnum(T key, const LinearEnumMapNode<T, N>* map, size_t length, N defaultValue)
76 {
77     int64_t index = BinarySearchFindIndex(map, length, key);
78     return index != -1 ? map[index].value : defaultValue;
79 }
80 
81 template<typename T>
ConvertStrToEnum(const char * key,const LinearMapNode<T> * map,size_t length,T defaultValue)82 inline T ConvertStrToEnum(const char* key, const LinearMapNode<T>* map, size_t length, T defaultValue)
83 {
84     int64_t index = BinarySearchFindIndex(map, length, key);
85     return index != -1 ? map[index].value : defaultValue;
86 }
87 } // namespace
88 
89 const LinearMapNode<void (*)(std::shared_ptr<RSImage>&, std::shared_ptr<RSShaderEffect>&, RSMatrix&)>
90     CustomPaintPaintMethod::staticPattern[] = {
91         { "clamp",
__anonec538c140202() 92             [](std::shared_ptr<RSImage>& image, std::shared_ptr<RSShaderEffect>& shaderEffect, RSMatrix& matrix) {
93                 shaderEffect = RSShaderEffect::CreateImageShader(
94                     *image, RSTileMode::CLAMP, RSTileMode::CLAMP, RSSamplingOptions(), matrix);
95             } },
96         { "mirror",
__anonec538c140302() 97             [](std::shared_ptr<RSImage>& image, std::shared_ptr<RSShaderEffect>& shaderEffect, RSMatrix& matrix) {
98                 shaderEffect = RSShaderEffect::CreateImageShader(
99                     *image, RSTileMode::MIRROR, RSTileMode::MIRROR, RSSamplingOptions(), matrix);
100             } },
101         { "no-repeat",
__anonec538c140402() 102             [](std::shared_ptr<RSImage>& image, std::shared_ptr<RSShaderEffect>& shaderEffect, RSMatrix& matrix) {
103                 shaderEffect = RSShaderEffect::CreateImageShader(
104                     *image, RSTileMode::DECAL, RSTileMode::DECAL, RSSamplingOptions(), matrix);
105             } },
106         { "repeat",
__anonec538c140502() 107             [](std::shared_ptr<RSImage>& image, std::shared_ptr<RSShaderEffect>& shaderEffect, RSMatrix& matrix) {
108                 shaderEffect = RSShaderEffect::CreateImageShader(
109                     *image, RSTileMode::REPEAT, RSTileMode::REPEAT, RSSamplingOptions(), matrix);
110             } },
111         { "repeat-x",
__anonec538c140602() 112             [](std::shared_ptr<RSImage>& image, std::shared_ptr<RSShaderEffect>& shaderEffect, RSMatrix& matrix) {
113                 shaderEffect = RSShaderEffect::CreateImageShader(
114                     *image, RSTileMode::REPEAT, RSTileMode::DECAL, RSSamplingOptions(), matrix);
115             } },
116         { "repeat-y",
__anonec538c140702() 117             [](std::shared_ptr<RSImage>& image, std::shared_ptr<RSShaderEffect>& shaderEffect, RSMatrix& matrix) {
118                 shaderEffect = RSShaderEffect::CreateImageShader(
119                     *image, RSTileMode::DECAL, RSTileMode::REPEAT, RSSamplingOptions(), matrix);
120             } },
121     };
122 
CustomPaintPaintMethod()123 CustomPaintPaintMethod::CustomPaintPaintMethod()
124 {
125     apiVersion_ = Container::GetCurrentApiTargetVersion();
126 }
127 
CheckFilterProperty(FilterType filterType,const std::string & filterParam)128 bool CustomPaintPaintMethod::CheckFilterProperty(FilterType filterType, const std::string& filterParam)
129 {
130     switch (filterType) {
131         case FilterType::GRAYSCALE:
132         case FilterType::SEPIA:
133         case FilterType::SATURATE:
134         case FilterType::INVERT:
135         case FilterType::OPACITY:
136         case FilterType::BRIGHTNESS:
137         case FilterType::CONTRAST: {
138             static const std::regex contrastRegexExpression(R"((?:-?0)|(?:\d+(?:\.\d+)?%?))");
139             return filterParam.empty() ? true : std::regex_match(filterParam, contrastRegexExpression);
140         }
141         case FilterType::BLUR: {
142             static const std::regex blurRegexExpression(R"((?:-?0)|(?:\d+(?:\.\d+)?(?:px|vp|rem)))");
143             return filterParam.empty() ? true : std::regex_match(filterParam, blurRegexExpression);
144         }
145         case FilterType::HUE_ROTATE: {
146             static const std::regex hueRotateRegexExpression(R"((?:-?0)|(?:-?\d+(?:\.\d+)?(?:deg|grad|rad|turn)))");
147             return filterParam.empty() ? true : std::regex_match(filterParam, hueRotateRegexExpression);
148         }
149         default:
150             return false;
151     }
152 }
153 
ParseFilter(std::string & filter,std::vector<FilterProperty> & filters)154 bool CustomPaintPaintMethod::ParseFilter(std::string& filter, std::vector<FilterProperty>& filters)
155 {
156     filter.erase(0, filter.find_first_not_of(' '));
157     size_t index = filter.find_first_of('(');
158     if (index == std::string::npos) {
159         return false;
160     }
161     FilterType filterType = FilterStrToFilterType(filter.substr(0, index));
162     if (filterType == FilterType::NONE) {
163         return false;
164     }
165     std::string filterParam = filter.substr(index + 1);
166     filterParam.erase(0, filterParam.find_first_not_of(' '));
167     filterParam.erase(filterParam.find_last_not_of(' ') + 1);
168     if (!CheckFilterProperty(filterType, filterParam)) {
169         return false;
170     }
171     filters.emplace_back(FilterProperty{filterType, filterParam});
172     return true;
173 }
174 
HasShadow() const175 bool CustomPaintPaintMethod::HasShadow() const
176 {
177     return !(NearZero(state_.shadow.GetOffset().GetX()) && NearZero(state_.shadow.GetOffset().GetY()) &&
178              NearZero(state_.shadow.GetBlurRadius()));
179 }
180 
UpdateLineDash(RSPen & pen)181 void CustomPaintPaintMethod::UpdateLineDash(RSPen& pen)
182 {
183     if (!state_.strokeState.GetLineDash().lineDash.empty()) {
184         auto lineDashState = state_.strokeState.GetLineDash().lineDash;
185         RSScalar intervals[lineDashState.size()];
186         for (size_t i = 0; i < lineDashState.size(); ++i) {
187             intervals[i] = static_cast<RSScalar>(lineDashState[i]);
188         }
189         RSScalar phase = static_cast<RSScalar>(state_.strokeState.GetLineDash().dashOffset);
190         pen.SetPathEffect(RSPathEffect::CreateDashPathEffect(intervals, lineDashState.size(), phase));
191     }
192 }
193 
UpdateFontFamilies()194 void CustomPaintPaintMethod::UpdateFontFamilies()
195 {
196     auto context = context_.Upgrade();
197     if (!context) {
198         context = PipelineBase::GetCurrentContextSafely();
199     }
200     CHECK_NULL_VOID(context);
201     auto fontManager = context->GetFontManager();
202     CHECK_NULL_VOID(fontManager);
203     if (!fontManager->IsUseAppCustomFont()) {
204         return;
205     }
206     auto fontFamilies = Framework::ConvertStrToFontFamilies(fontManager->GetAppCustomFont());
207     if (state_.fillState.GetTextStyle().GetFontFamilies().empty()) {
208         state_.fillState.SetFontFamilies(fontFamilies);
209     }
210     if (state_.strokeState.GetTextStyle().GetFontFamilies().empty()) {
211         state_.strokeState.SetFontFamilies(fontFamilies);
212     }
213 }
214 
MakeConicGradient(const Ace::Gradient & gradient,const std::shared_ptr<RSColorSpace> & colorSpace)215 std::shared_ptr<RSShaderEffect> CustomPaintPaintMethod::MakeConicGradient(
216     const Ace::Gradient& gradient, const std::shared_ptr<RSColorSpace>& colorSpace)
217 {
218     std::shared_ptr<RSShaderEffect> shaderEffect = nullptr;
219     if (gradient.GetType() == Ace::GradientType::CONIC) {
220         if (!gradient.GetConicGradient().centerX.has_value() || !gradient.GetConicGradient().centerY.has_value() ||
221             !gradient.GetConicGradient().startAngle.has_value()) {
222             return nullptr;
223         }
224         RSMatrix matrix;
225         RSScalar centerX = static_cast<RSScalar>(gradient.GetConicGradient().centerX->Value());
226         RSScalar centerY = static_cast<RSScalar>(gradient.GetConicGradient().centerY->Value());
227         auto gradientColors = gradient.GetColors();
228         std::stable_sort(gradientColors.begin(), gradientColors.end(),
229             [](auto& colorA, auto& colorB) { return colorA.GetDimension() < colorB.GetDimension(); });
230         uint32_t colorsSize = gradientColors.size();
231         std::vector<RSColor4f> colors(colorsSize, { 0, 0, 0, 0 });
232         std::vector<RSScalar> pos(colorsSize, 0);
233         double angle = gradient.GetConicGradient().startAngle->Value() / ACE_PI * 180.0;
234         RSScalar startAngle = static_cast<RSScalar>(angle);
235         matrix.PreRotate(startAngle, centerX, centerY);
236         for (uint32_t i = 0; i < colorsSize; ++i) {
237             const auto& gradientColor = gradientColors[i];
238             colors.at(i) = RSColor(gradientColor.GetColor().GetValue()).GetColor4f();
239             pos.at(i) = gradientColor.GetDimension().Value();
240         }
241         auto mode = RSTileMode::CLAMP;
242         shaderEffect = RSShaderEffect::CreateSweepGradient(RSPoint(centerX, centerY), colors, colorSpace, pos, mode,
243             static_cast<RSScalar>(CONIC_START_ANGLE), static_cast<RSScalar>(CONIC_END_ANGLE), &matrix);
244     }
245     return shaderEffect;
246 }
247 
UpdatePaintShader(RSPen * pen,RSBrush * brush,const Ace::Gradient & gradient)248 void CustomPaintPaintMethod::UpdatePaintShader(RSPen* pen, RSBrush* brush, const Ace::Gradient& gradient)
249 {
250     RSPoint beginPoint = RSPoint(static_cast<RSScalar>(gradient.GetBeginOffset().GetX()),
251         static_cast<RSScalar>(gradient.GetBeginOffset().GetY()));
252     RSPoint endPoint = RSPoint(
253         static_cast<RSScalar>(gradient.GetEndOffset().GetX()), static_cast<RSScalar>(gradient.GetEndOffset().GetY()));
254     std::vector<RSPoint> pts = { beginPoint, endPoint };
255     auto gradientColors = gradient.GetColors();
256     std::stable_sort(gradientColors.begin(), gradientColors.end(),
257         [](auto& colorA, auto& colorB) { return colorA.GetDimension() < colorB.GetDimension(); });
258     uint32_t colorsSize = gradientColors.size();
259     std::vector<RSColor4f> colors(colorsSize, { 0, 0, 0, 0 });
260     std::vector<RSScalar> pos(colorsSize, 0);
261     for (uint32_t i = 0; i < colorsSize; ++i) {
262         const auto& gradientColor = gradientColors[i];
263         colors.at(i) = RSColor(gradientColor.GetColor().GetValue()).GetColor4f();
264         pos.at(i) = gradientColor.GetDimension().Value();
265     }
266 
267     auto mode = RSTileMode::CLAMP;
268 
269     std::shared_ptr<RSColorSpace> colorSpace = RSColorSpace::CreateSRGB();
270     ColorSpace colorSpaceType = ColorSpace::SRGB;
271     if (colorsSize > 0) {
272         colorSpaceType = gradientColors.back().GetColor().GetColorSpace();
273     }
274     if (ColorSpace::DISPLAY_P3 == colorSpaceType) {
275         colorSpace = RSColorSpace::CreateRGB(RSCMSTransferFuncType::SRGB, RSCMSMatrixType::DCIP3);
276     }
277     std::shared_ptr<RSShaderEffect> shaderEffect = nullptr;
278     if (gradient.GetType() == Ace::GradientType::LINEAR) {
279         shaderEffect = RSShaderEffect::CreateLinearGradient(pts.at(0), pts.at(1), colors, colorSpace, pos, mode);
280     } else if (gradient.GetType() == Ace::GradientType::CONIC) {
281         shaderEffect = MakeConicGradient(gradient, colorSpace);
282     } else {
283         if (gradient.GetInnerRadius() <= 0.0 && beginPoint == endPoint) {
284             shaderEffect = RSShaderEffect::CreateRadialGradient(
285                 endPoint, gradient.GetOuterRadius(), colors, colorSpace, pos, mode);
286         } else {
287             RSMatrix matrix;
288             shaderEffect = RSShaderEffect::CreateTwoPointConical(beginPoint, gradient.GetInnerRadius(), endPoint,
289                 gradient.GetOuterRadius(), colors, colorSpace, pos, mode, &matrix);
290         }
291     }
292     if (pen != nullptr) {
293         pen->SetShaderEffect(shaderEffect);
294     }
295     if (brush != nullptr) {
296         brush->SetShaderEffect(shaderEffect);
297     }
298 }
299 
GetMatrixFromPattern(const Ace::Pattern & pattern)300 RSMatrix CustomPaintPaintMethod::GetMatrixFromPattern(const Ace::Pattern& pattern)
301 {
302     RSMatrix matrix;
303     matrix.SetMatrix(pattern.GetScaleX(), pattern.GetSkewX(), pattern.GetTranslateX(), pattern.GetSkewY(),
304         pattern.GetScaleY(), pattern.GetTranslateY(), 0.0f, 0.0f, 1.0f);
305     return matrix;
306 }
307 
GetImage(const std::string & src)308 std::shared_ptr<RSImage> CustomPaintPaintMethod::GetImage(const std::string& src)
309 {
310 #ifndef ACE_UNITTEST
311     if (!imageCache_) {
312         imageCache_ = ImageCache::Create();
313         imageCache_->SetCapacity(IMAGE_CACHE_COUNT);
314     }
315     auto cacheImage = imageCache_->GetCacheImage(src);
316     if (cacheImage && cacheImage->imagePtr) {
317         return cacheImage->imagePtr;
318     }
319 
320     auto context = PipelineBase::GetCurrentContext();
321     CHECK_NULL_RETURN(context, nullptr);
322     auto image = Ace::ImageProvider::GetDrawingImage(src, context);
323     CHECK_NULL_RETURN(image, nullptr);
324     imageCache_->CacheImage(src, std::make_shared<Ace::CachedImage>(image));
325     return image;
326 #else
327     return nullptr;
328 #endif
329 }
330 
UpdatePaintShader(const Ace::Pattern & pattern,RSPen * pen,RSBrush * brush)331 void CustomPaintPaintMethod::UpdatePaintShader(const Ace::Pattern& pattern, RSPen* pen, RSBrush* brush)
332 {
333 #ifndef ACE_UNITTEST
334 #if !defined(PREVIEW)
335     auto pixelMap = pattern.GetPixelMap();
336     CHECK_NULL_VOID(pixelMap);
337     auto rsBitmapFormat = Ace::ImageProvider::MakeRSBitmapFormatFromPixelMap(pixelMap);
338     auto rsBitmap = std::make_shared<RSBitmap>();
339     rsBitmap->Build(pixelMap->GetWidth(), pixelMap->GetHeight(), rsBitmapFormat, pixelMap->GetRowStride());
340     rsBitmap->SetPixels(const_cast<void*>(reinterpret_cast<const void*>(pixelMap->GetPixels())));
341     auto image = std::make_shared<RSImage>();
342     CHECK_NULL_VOID(image->BuildFromBitmap(*rsBitmap));
343 #else
344     auto image = GetImage(pattern.GetImgSrc());
345     CHECK_NULL_VOID(image);
346 #endif
347     RSMatrix matrix;
348     if (pattern.IsTransformable()) {
349         matrix = GetMatrixFromPattern(pattern);
350     }
351     auto operatorIter = BinarySearchFindIndex(staticPattern, ArraySize(staticPattern), pattern.GetRepetition().c_str());
352     if (operatorIter != -1) {
353         std::shared_ptr<RSShaderEffect> shaderEffect = nullptr;
354         staticPattern[operatorIter].value(image, shaderEffect, matrix);
355         if (pen) {
356             pen->SetShaderEffect(shaderEffect);
357         }
358         if (brush) {
359             brush->SetShaderEffect(shaderEffect);
360         }
361     }
362 #endif
363 }
364 
InitPaintBlend(RSBrush & brush)365 void CustomPaintPaintMethod::InitPaintBlend(RSBrush& brush)
366 {
367     brush.SetBlendMode(ConvertEnumToDrawingEnum(
368         state_.globalState.GetType(), DRAWING_BLEND_MODE_TABLE, BLEND_MODE_SIZE, RSBlendMode::SRC_OVER));
369 }
370 
InitPaintBlend(RSPen & pen)371 void CustomPaintPaintMethod::InitPaintBlend(RSPen& pen)
372 {
373     pen.SetBlendMode(ConvertEnumToDrawingEnum(
374         state_.globalState.GetType(), DRAWING_BLEND_MODE_TABLE, BLEND_MODE_SIZE, RSBlendMode::SRC_OVER));
375 }
376 
GetFillPaint(RSBrush & brush,RSSamplingOptions & options)377 void CustomPaintPaintMethod::GetFillPaint(RSBrush& brush, RSSamplingOptions& options)
378 {
379     InitImagePaint(nullptr, &brush, options);
380     brush.SetAntiAlias(antiAlias_);
381     if (state_.fillState.GetPaintStyle() == OHOS::Ace::PaintStyle::Color) {
382         brush.SetColor(state_.fillState.GetColor().GetValue());
383     }
384     if (state_.fillState.GetGradient().IsValid() && state_.fillState.GetPaintStyle() == PaintStyle::Gradient) {
385         UpdatePaintShader(nullptr, &brush, state_.fillState.GetGradient());
386     }
387     if (state_.fillState.GetPatternValue().IsValid() && state_.fillState.GetPaintStyle() == PaintStyle::ImagePattern) {
388         UpdatePaintShader(state_.fillState.GetPatternValue(), nullptr, &brush);
389     }
390     if (state_.globalState.HasGlobalAlpha()) {
391         if (state_.fillState.GetPaintStyle() == OHOS::Ace::PaintStyle::Color) {
392             brush.SetAlphaF(state_.globalState.GetAlpha() *
393                             static_cast<double>(state_.fillState.GetColor().GetAlpha()) / MAX_GRAYSCALE);
394         } else {
395             brush.SetAlphaF(state_.globalState.GetAlpha());
396         }
397     }
398 }
399 
GetStrokePaint(RSPen & pen,RSSamplingOptions & options)400 void CustomPaintPaintMethod::GetStrokePaint(RSPen& pen, RSSamplingOptions& options)
401 {
402     static const LinearEnumMapNode<LineJoinStyle, RSPen::JoinStyle> skLineJoinTable[] = {
403         { LineJoinStyle::MITER, RSPen::JoinStyle::MITER_JOIN },
404         { LineJoinStyle::ROUND, RSPen::JoinStyle::ROUND_JOIN },
405         { LineJoinStyle::BEVEL, RSPen::JoinStyle::BEVEL_JOIN },
406     };
407     static const LinearEnumMapNode<LineCapStyle, RSPen::CapStyle> skLineCapTable[] = {
408         { LineCapStyle::BUTT, RSPen::CapStyle::FLAT_CAP },
409         { LineCapStyle::ROUND, RSPen::CapStyle::ROUND_CAP },
410         { LineCapStyle::SQUARE, RSPen::CapStyle::SQUARE_CAP },
411     };
412     InitImagePaint(&pen, nullptr, options);
413     if (state_.strokeState.GetPaintStyle() == PaintStyle::Color) {
414         pen.SetColor(state_.strokeState.GetColor().GetValue());
415     }
416     if (state_.strokeState.GetGradient().IsValid() && state_.strokeState.GetPaintStyle() == PaintStyle::Gradient) {
417         UpdatePaintShader(&pen, nullptr, state_.strokeState.GetGradient());
418     }
419     if (state_.strokeState.GetPatternValue().IsValid() &&
420         state_.strokeState.GetPaintStyle() == PaintStyle::ImagePattern) {
421         UpdatePaintShader(state_.strokeState.GetPatternValue(), &pen, nullptr);
422     }
423     pen.SetAntiAlias(antiAlias_);
424     pen.SetJoinStyle(ConvertEnumToDrawingEnum(
425         state_.strokeState.GetLineJoin(), skLineJoinTable, ArraySize(skLineJoinTable), RSPen::JoinStyle::MITER_JOIN));
426     pen.SetCapStyle(ConvertEnumToDrawingEnum(
427         state_.strokeState.GetLineCap(), skLineCapTable, ArraySize(skLineCapTable), RSPen::CapStyle::FLAT_CAP));
428     pen.SetWidth(static_cast<RSScalar>(state_.strokeState.GetLineWidth()));
429     pen.SetMiterLimit(static_cast<RSScalar>(state_.strokeState.GetMiterLimit()));
430 
431     // set line Dash
432     UpdateLineDash(pen);
433 
434     // set global alpha
435     if (state_.globalState.HasGlobalAlpha()) {
436         if (state_.strokeState.GetPaintStyle() == PaintStyle::Color) {
437             pen.SetAlphaF(state_.globalState.GetAlpha() *
438                           static_cast<double>(state_.strokeState.GetColor().GetAlpha()) / MAX_GRAYSCALE);
439         } else {
440             pen.SetAlphaF(state_.globalState.GetAlpha());
441         }
442     }
443 }
444 
InitImagePaint(RSPen * pen,RSBrush * brush,RSSamplingOptions & options)445 void CustomPaintPaintMethod::InitImagePaint(RSPen* pen, RSBrush* brush, RSSamplingOptions& options)
446 {
447     RSFilter filter;
448     if (smoothingEnabled_) {
449         if (smoothingQuality_ == "low") {
450             options = RSSamplingOptions(RSFilterMode::LINEAR, RSMipmapMode::NONE);
451             filter.SetFilterQuality(RSFilter::FilterQuality::LOW);
452         } else if (smoothingQuality_ == "medium") {
453             options = RSSamplingOptions(RSFilterMode::LINEAR, RSMipmapMode::LINEAR);
454             filter.SetFilterQuality(RSFilter::FilterQuality::MEDIUM);
455         } else if (smoothingQuality_ == "high") {
456             options = RSSamplingOptions(RSCubicResampler::Mitchell());
457             filter.SetFilterQuality(RSFilter::FilterQuality::HIGH);
458         }
459     } else {
460         options = RSSamplingOptions(RSFilterMode::NEAREST, RSMipmapMode::NONE);
461         filter.SetFilterQuality(RSFilter::FilterQuality::NONE);
462     }
463     if (pen) {
464         pen->SetFilter(filter);
465     }
466     if (brush) {
467         brush->SetFilter(filter);
468     }
469     ClearPaintImage(pen, brush);
470     SetPaintImage(pen, brush);
471 }
472 
DrawSvgImage(RefPtr<SvgDomBase> svgDom,const Ace::CanvasImage & canvasImage,const ImageFit & imageFit)473 void CustomPaintPaintMethod::DrawSvgImage(
474     RefPtr<SvgDomBase> svgDom, const Ace::CanvasImage& canvasImage, const ImageFit& imageFit)
475 {
476     CHECK_NULL_VOID(svgDom);
477     RSRect srcRect;
478     RSRect dstRect;
479     switch (canvasImage.flag) {
480         case 0:
481             srcRect = RSRect(0, 0, svgDom->GetContainerSize().Width(), svgDom->GetContainerSize().Height());
482             dstRect = RSRect(canvasImage.dx, canvasImage.dy, svgDom->GetContainerSize().Width() + canvasImage.dx,
483                 svgDom->GetContainerSize().Height() + canvasImage.dy);
484             break;
485         case 1: {
486             srcRect = RSRect(0, 0, svgDom->GetContainerSize().Width(), svgDom->GetContainerSize().Height());
487             dstRect = RSRect(canvasImage.dx, canvasImage.dy, canvasImage.dWidth + canvasImage.dx,
488                 canvasImage.dHeight + canvasImage.dy);
489             break;
490         }
491         case 2: {
492             srcRect = RSRect(canvasImage.sx, canvasImage.sy, canvasImage.sWidth + canvasImage.sx,
493                 canvasImage.sHeight + canvasImage.sy);
494             dstRect = RSRect(canvasImage.dx, canvasImage.dy, canvasImage.dWidth + canvasImage.dx,
495                 canvasImage.dHeight + canvasImage.dy);
496             break;
497         }
498         default:
499             break;
500     }
501     float scaleX = dstRect.GetWidth() / srcRect.GetWidth();
502     float scaleY = dstRect.GetHeight() / srcRect.GetHeight();
503     OffsetF startPoint =
504         OffsetF(dstRect.GetLeft(), dstRect.GetTop()) - OffsetF(srcRect.GetLeft() * scaleX, srcRect.GetTop() * scaleY);
505 
506     CHECK_NULL_VOID(rsCanvas_);
507     rsCanvas_->Save();
508     rsCanvas_->ClipRect(dstRect, RSClipOp::INTERSECT);
509     rsCanvas_->Translate(startPoint.GetX(), startPoint.GetY());
510     rsCanvas_->Scale(scaleX, scaleY);
511     svgDom->DrawImage(*rsCanvas_, imageFit, Size(srcRect.GetWidth(), srcRect.GetHeight()));
512     rsCanvas_->Restore();
513 }
514 
DrawImageInternal(const Ace::CanvasImage & info,const std::shared_ptr<RSImage> & image)515 void CustomPaintPaintMethod::DrawImageInternal(const Ace::CanvasImage& info, const std::shared_ptr<RSImage>& image)
516 {
517     CHECK_NULL_VOID(rsCanvas_);
518     RSBrush compositeOperationpBrush;
519     InitPaintBlend(compositeOperationpBrush);
520     RSSaveLayerOps slo(nullptr, &compositeOperationpBrush);
521     if (state_.globalState.GetType() != CompositeOperation::SOURCE_OVER) {
522         rsCanvas_->SaveLayer(slo);
523     }
524     imageBrush_.SetAntiAlias(antiAlias_);
525     InitImagePaint(nullptr, &imageBrush_, sampleOptions_);
526     if (state_.globalState.HasGlobalAlpha()) {
527         imageBrush_.SetAlphaF(state_.globalState.GetAlpha());
528     }
529     if (HasShadow()) {
530         auto width = info.dx + (info.flag == DrawImageType::THREE_PARAMS ? image->GetWidth() : info.dWidth);
531         auto height = info.dy + (info.flag == DrawImageType::THREE_PARAMS ? image->GetHeight() : info.dHeight);
532         RSRect rsRect = RSRect(info.dx, info.dy, width, height);
533         RSPath path;
534         path.AddRect(rsRect);
535         PaintImageShadow(path, state_.shadow, &imageBrush_, nullptr,
536             (state_.globalState.GetType() != CompositeOperation::SOURCE_OVER) ? &slo : nullptr);
537     }
538     rsCanvas_->AttachBrush(imageBrush_);
539     switch (info.flag) {
540         case DrawImageType::THREE_PARAMS:
541             rsCanvas_->DrawImage(*image, info.dx, info.dy, sampleOptions_);
542             break;
543         case DrawImageType::FIVE_PARAMS: {
544             RSRect rect = RSRect(info.dx, info.dy, info.dWidth + info.dx, info.dHeight + info.dy);
545             rsCanvas_->DrawImageRect(*image, rect, sampleOptions_);
546             break;
547         }
548         case DrawImageType::NINE_PARAMS: {
549             RSRect dstRect = RSRect(info.dx, info.dy, info.dWidth + info.dx, info.dHeight + info.dy);
550             RSRect srcRect = RSRect(info.sx, info.sy, info.sWidth + info.sx, info.sHeight + info.sy);
551             rsCanvas_->DrawImageRect(*image, srcRect, dstRect, sampleOptions_,
552                 RSSrcRectConstraint::FAST_SRC_RECT_CONSTRAINT);
553             break;
554         }
555         default:
556             break;
557     }
558     rsCanvas_->DetachBrush();
559     if (state_.globalState.GetType() != CompositeOperation::SOURCE_OVER) {
560         rsCanvas_->Restore();
561     }
562 }
563 
DrawImage(const Ace::CanvasImage & canvasImage,double width,double height)564 void CustomPaintPaintMethod::DrawImage(const Ace::CanvasImage& canvasImage, double width, double height)
565 {
566 #ifndef ACE_UNITTEST
567     ContainerScope scope(canvasImage.instanceId);
568     auto context = PipelineBase::GetCurrentContext();
569     auto image = std::make_shared<RSImage>();
570     if (canvasImage.imageData != nullptr) {
571         auto imageData = *(canvasImage.imageData);
572         if (imageData.data.empty()) {
573             return;
574         }
575         RSBitmap bitmap;
576         RSBitmapFormat format { RSColorType::COLORTYPE_BGRA_8888, RSAlphaType::ALPHATYPE_PREMUL };
577         bitmap.Build(imageData.dirtyWidth, imageData.dirtyHeight, format);
578         bitmap.SetPixels(const_cast<void*>(reinterpret_cast<const void*>(imageData.data.data())));
579         image->BuildFromBitmap(bitmap);
580     } else {
581         image = Ace::ImageProvider::GetDrawingImage(
582             canvasImage.src, context, Size(std::max(width, 0.0), std::max(height, 0.0)));
583     }
584     CHECK_NULL_VOID(image);
585     DrawImageInternal(canvasImage, image);
586 #endif
587 }
588 
PutImageData(const Ace::ImageData & imageData)589 void CustomPaintPaintMethod::PutImageData(const Ace::ImageData& imageData)
590 {
591     CHECK_NULL_VOID(rsCanvas_);
592     if (imageData.data.empty()) {
593         return;
594     }
595     RSBitmap bitmap;
596     RSBitmapFormat format { RSColorType::COLORTYPE_BGRA_8888, RSAlphaType::ALPHATYPE_PREMUL };
597     bitmap.Build(imageData.dirtyWidth, imageData.dirtyHeight, format);
598     bitmap.SetPixels(const_cast<void*>(reinterpret_cast<const void*>(imageData.data.data())));
599     RSBrush brush;
600     brush.SetBlendMode(RSBlendMode::SRC);
601     rsCanvas_->AttachBrush(brush);
602     rsCanvas_->DrawBitmap(bitmap, imageData.x, imageData.y);
603     rsCanvas_->DetachBrush();
604 }
605 
FillRect(const Rect & rect)606 void CustomPaintPaintMethod::FillRect(const Rect& rect)
607 {
608     CHECK_NULL_VOID(rsCanvas_);
609     RSBrush brush;
610     RSSamplingOptions options;
611     GetFillPaint(brush, options);
612     RSRect rsRect(rect.Left(), rect.Top(), rect.Right(), +rect.Bottom());
613     if (state_.globalState.GetType() == CompositeOperation::SOURCE_OVER) {
614         if (HasShadow()) {
615             RSRecordingPath path;
616             path.AddRect(rsRect);
617             PaintShadow(path, state_.shadow, &brush, nullptr);
618         }
619         rsCanvas_->AttachBrush(brush);
620         rsCanvas_->DrawRect(rsRect);
621         rsCanvas_->DetachBrush();
622     } else {
623         RSBrush compositeOperationpBrush;
624         InitPaintBlend(compositeOperationpBrush);
625         RSSaveLayerOps slo(nullptr, &compositeOperationpBrush);
626         if (HasShadow()) {
627             RSRecordingPath path;
628             path.AddRect(rsRect);
629             PaintShadow(path, state_.shadow, &brush, nullptr, &slo);
630         }
631         rsCanvas_->SaveLayer(slo);
632         rsCanvas_->AttachBrush(brush);
633         rsCanvas_->DrawRect(rsRect);
634         rsCanvas_->DetachBrush();
635         rsCanvas_->Restore();
636     }
637 }
638 
StrokeRect(const Rect & rect)639 void CustomPaintPaintMethod::StrokeRect(const Rect& rect)
640 {
641     CHECK_NULL_VOID(rsCanvas_);
642     RSPen pen;
643     RSSamplingOptions options;
644     GetStrokePaint(pen, options);
645     RSRect rsRect(rect.Left(), rect.Top(), rect.Right(), +rect.Bottom());
646     if (state_.globalState.GetType() == CompositeOperation::SOURCE_OVER) {
647         if (HasShadow()) {
648             RSRecordingPath path;
649             path.AddRect(rsRect);
650             PaintShadow(path, state_.shadow, nullptr, &pen);
651         }
652         rsCanvas_->AttachPen(pen);
653         rsCanvas_->DrawRect(rsRect);
654         rsCanvas_->DetachPen();
655     } else {
656         RSBrush compositeOperationpBrush;
657         InitPaintBlend(compositeOperationpBrush);
658         RSSaveLayerOps slo(nullptr, &compositeOperationpBrush);
659         if (HasShadow()) {
660             RSRecordingPath path;
661             path.AddRect(rsRect);
662             PaintShadow(path, state_.shadow, nullptr, &pen, &slo);
663         }
664         rsCanvas_->SaveLayer(slo);
665         rsCanvas_->AttachPen(pen);
666         rsCanvas_->DrawRect(rsRect);
667         rsCanvas_->DetachPen();
668         rsCanvas_->Restore();
669     }
670 }
671 
ClearRect(const Rect & rect)672 void CustomPaintPaintMethod::ClearRect(const Rect& rect)
673 {
674     CHECK_NULL_VOID(rsCanvas_);
675     RSBrush brush;
676     RSSamplingOptions options;
677     InitImagePaint(nullptr, &brush, options);
678     brush.SetAntiAlias(antiAlias_);
679     brush.SetBlendMode(RSBlendMode::CLEAR);
680     RSRect rsRect(rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
681     rsCanvas_->AttachBrush(brush);
682     rsCanvas_->DrawRect(rsRect);
683     rsCanvas_->DetachBrush();
684 }
685 
SetFillRuleForPath(const CanvasFillRule & rule)686 void CustomPaintPaintMethod::SetFillRuleForPath(const CanvasFillRule& rule)
687 {
688     if (rule == CanvasFillRule::NONZERO) {
689         rsPath_.SetFillStyle(RSPathFillType::WINDING);
690     } else if (rule == CanvasFillRule::EVENODD) {
691         rsPath_.SetFillStyle(RSPathFillType::EVENTODD);
692     }
693 }
694 
SetFillRuleForPath2D(const CanvasFillRule & rule)695 void CustomPaintPaintMethod::SetFillRuleForPath2D(const CanvasFillRule& rule)
696 {
697     if (rule == CanvasFillRule::NONZERO) {
698         rsPath2d_.SetFillStyle(RSPathFillType::WINDING);
699     } else if (rule == CanvasFillRule::EVENODD) {
700         rsPath2d_.SetFillStyle(RSPathFillType::EVENTODD);
701     }
702 }
703 
Fill()704 void CustomPaintPaintMethod::Fill()
705 {
706     CHECK_NULL_VOID(rsCanvas_);
707     RSBrush brush;
708     RSSamplingOptions options;
709     GetFillPaint(brush, options);
710     if (state_.globalState.GetType() == CompositeOperation::SOURCE_OVER) {
711         if (HasShadow()) {
712             PaintShadow(rsPath_, state_.shadow, &brush, nullptr);
713         }
714         rsCanvas_->AttachBrush(brush);
715         rsCanvas_->DrawPath(rsPath_);
716         rsCanvas_->DetachBrush();
717     } else {
718         RSBrush compositeOperationpBrush;
719         InitPaintBlend(compositeOperationpBrush);
720         RSSaveLayerOps slo(nullptr, &compositeOperationpBrush);
721         if (HasShadow()) {
722             PaintShadow(rsPath_, state_.shadow, &brush, nullptr, &slo);
723         }
724         rsCanvas_->SaveLayer(slo);
725         rsCanvas_->AttachBrush(brush);
726         rsCanvas_->DrawPath(rsPath_);
727         rsCanvas_->DetachBrush();
728         rsCanvas_->Restore();
729     }
730 }
731 
Fill(const RefPtr<CanvasPath2D> & path)732 void CustomPaintPaintMethod::Fill(const RefPtr<CanvasPath2D>& path)
733 {
734     CHECK_NULL_VOID(path);
735     ParsePath2D(path);
736     Path2DFill();
737     rsPath2d_.Reset();
738     if (apiVersion_ >= static_cast<int32_t>(PlatformVersion::VERSION_EIGHTEEN)) {
739         isPath2dChanged_ = false;
740     }
741 }
742 
Path2DFill()743 void CustomPaintPaintMethod::Path2DFill()
744 {
745     CHECK_NULL_VOID(rsCanvas_);
746     RSBrush brush;
747     RSSamplingOptions options;
748     GetFillPaint(brush, options);
749     if (state_.globalState.GetType() == CompositeOperation::SOURCE_OVER) {
750         if (HasShadow()) {
751             PaintShadow(rsPath2d_, state_.shadow, &brush, nullptr);
752         }
753         rsCanvas_->AttachBrush(brush);
754         rsCanvas_->DrawPath(rsPath2d_);
755         rsCanvas_->DetachBrush();
756     } else {
757         RSBrush compositeOperationpBrush;
758         InitPaintBlend(compositeOperationpBrush);
759         RSSaveLayerOps slo(nullptr, &compositeOperationpBrush);
760         if (HasShadow()) {
761             PaintShadow(rsPath2d_, state_.shadow, &brush, nullptr, &slo);
762         }
763         rsCanvas_->SaveLayer(slo);
764         rsCanvas_->AttachBrush(brush);
765         rsCanvas_->DrawPath(rsPath2d_);
766         rsCanvas_->DetachBrush();
767         rsCanvas_->Restore();
768     }
769 }
770 
Stroke()771 void CustomPaintPaintMethod::Stroke()
772 {
773     CHECK_NULL_VOID(rsCanvas_);
774     RSPen pen;
775     RSSamplingOptions options;
776     GetStrokePaint(pen, options);
777     if (state_.globalState.GetType() == CompositeOperation::SOURCE_OVER) {
778         if (HasShadow()) {
779             PaintShadow(rsPath_, state_.shadow, nullptr, &pen);
780         }
781         rsCanvas_->AttachPen(pen);
782         rsCanvas_->DrawPath(rsPath_);
783         rsCanvas_->DetachPen();
784     } else {
785         RSBrush compositeOperationpBrush;
786         InitPaintBlend(compositeOperationpBrush);
787         RSSaveLayerOps slo(nullptr, &compositeOperationpBrush);
788         if (HasShadow()) {
789             PaintShadow(rsPath_, state_.shadow, nullptr, &pen, &slo);
790         }
791         rsCanvas_->SaveLayer(slo);
792         rsCanvas_->AttachPen(pen);
793         rsCanvas_->DrawPath(rsPath_);
794         rsCanvas_->DetachPen();
795         rsCanvas_->Restore();
796     }
797 }
798 
Stroke(const RefPtr<CanvasPath2D> & path)799 void CustomPaintPaintMethod::Stroke(const RefPtr<CanvasPath2D>& path)
800 {
801     CHECK_NULL_VOID(path);
802     ParsePath2D(path);
803     Path2DStroke();
804     rsPath2d_.Reset();
805     if (apiVersion_ >= static_cast<int32_t>(PlatformVersion::VERSION_EIGHTEEN)) {
806         isPath2dChanged_ = false;
807     }
808 }
809 
Path2DStroke()810 void CustomPaintPaintMethod::Path2DStroke()
811 {
812     CHECK_NULL_VOID(rsCanvas_);
813     RSPen pen;
814     RSSamplingOptions options;
815     GetStrokePaint(pen, options);
816     if (state_.globalState.GetType() == CompositeOperation::SOURCE_OVER) {
817         if (HasShadow()) {
818             PaintShadow(rsPath2d_, state_.shadow, nullptr, &pen);
819         }
820         rsCanvas_->AttachPen(pen);
821         rsCanvas_->DrawPath(rsPath2d_);
822         rsCanvas_->DetachPen();
823     } else {
824         RSBrush compositeOperationpBrush;
825         InitPaintBlend(compositeOperationpBrush);
826         RSSaveLayerOps slo(nullptr, &compositeOperationpBrush);
827         if (HasShadow()) {
828             PaintShadow(rsPath2d_, state_.shadow, nullptr, &pen, &slo);
829         }
830         rsCanvas_->SaveLayer(slo);
831         rsCanvas_->AttachPen(pen);
832         rsCanvas_->DrawPath(rsPath2d_);
833         rsCanvas_->DetachPen();
834         rsCanvas_->Restore();
835     }
836 }
837 
Clip()838 void CustomPaintPaintMethod::Clip()
839 {
840     CHECK_NULL_VOID(rsCanvas_);
841     rsCanvas_->ClipPath(rsPath_, RSClipOp::INTERSECT, antiAlias_);
842 }
843 
Clip(const RefPtr<CanvasPath2D> & path)844 void CustomPaintPaintMethod::Clip(const RefPtr<CanvasPath2D>& path)
845 {
846     CHECK_NULL_VOID(path);
847     ParsePath2D(path);
848     Path2DClip();
849     rsPath2d_.Reset();
850     if (apiVersion_ >= static_cast<int32_t>(PlatformVersion::VERSION_EIGHTEEN)) {
851         isPath2dChanged_ = false;
852     }
853 }
854 
Path2DClip()855 void CustomPaintPaintMethod::Path2DClip()
856 {
857     CHECK_NULL_VOID(rsCanvas_);
858     rsCanvas_->ClipPath(rsPath2d_, RSClipOp::INTERSECT, antiAlias_);
859 }
860 
BeginPath()861 void CustomPaintPaintMethod::BeginPath()
862 {
863     rsPath_.Reset();
864     if (apiVersion_ >= static_cast<int32_t>(PlatformVersion::VERSION_EIGHTEEN)) {
865         isPathChanged_ = false;
866     }
867 }
868 
ClosePath()869 void CustomPaintPaintMethod::ClosePath()
870 {
871     rsPath_.Close();
872 }
873 
MoveTo(double x,double y)874 void CustomPaintPaintMethod::MoveTo(double x, double y)
875 {
876     rsPath_.MoveTo(static_cast<RSScalar>(x), static_cast<RSScalar>(y));
877     isPathChanged_ = true;
878 }
879 
LineTo(double x,double y)880 void CustomPaintPaintMethod::LineTo(double x, double y)
881 {
882     if (!isPathChanged_) {
883         rsPath_.MoveTo(static_cast<RSScalar>(x), static_cast<RSScalar>(y));
884     }
885     rsPath_.LineTo(static_cast<RSScalar>(x), static_cast<RSScalar>(y));
886     isPathChanged_ = true;
887 }
888 
Arc(const ArcParam & param)889 void CustomPaintPaintMethod::Arc(const ArcParam& param)
890 {
891     double left = param.x - param.radius;
892     double top = param.y - param.radius;
893     double right = param.x + param.radius;
894     double bottom = param.y + param.radius;
895     double startAngle = param.startAngle * HALF_CIRCLE_ANGLE / ACE_PI;
896     double endAngle = param.endAngle * HALF_CIRCLE_ANGLE / ACE_PI;
897     double sweepAngle = endAngle - startAngle;
898     if (param.anticlockwise) {
899         sweepAngle =
900             endAngle > startAngle ? (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) - FULL_CIRCLE_ANGLE) : sweepAngle;
901     } else {
902         sweepAngle =
903             endAngle > startAngle ? sweepAngle : (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) + FULL_CIRCLE_ANGLE);
904     }
905     RSPoint point1(left, top);
906     RSPoint point2(right, bottom);
907     if (!NearEqual(startAngle, endAngle) &&
908         (NearEqual(std::abs(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE)), 0.0) ||
909             NearEqual(std::abs(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE)), FULL_CIRCLE_ANGLE))) {
910         // draw circle
911         double half = GreatNotEqual(sweepAngle, 0.0) ? HALF_CIRCLE_ANGLE : -HALF_CIRCLE_ANGLE;
912         rsPath_.ArcTo(point1, point2, static_cast<RSScalar>(startAngle), static_cast<RSScalar>(half));
913         rsPath_.ArcTo(point1, point2, static_cast<RSScalar>(half + startAngle), static_cast<RSScalar>(half));
914     } else if (!NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && std::abs(sweepAngle) > FULL_CIRCLE_ANGLE) {
915         double half = GreatNotEqual(sweepAngle, 0.0) ? HALF_CIRCLE_ANGLE : -HALF_CIRCLE_ANGLE;
916         rsPath_.ArcTo(point1, point2, static_cast<RSScalar>(startAngle), static_cast<RSScalar>(half));
917         rsPath_.ArcTo(point1, point2, static_cast<RSScalar>(half + startAngle), static_cast<RSScalar>(half));
918         rsPath_.ArcTo(
919             point1, point2, static_cast<RSScalar>(half + half + startAngle), static_cast<RSScalar>(sweepAngle));
920     } else {
921         rsPath_.ArcTo(point1, point2, static_cast<RSScalar>(startAngle), static_cast<RSScalar>(sweepAngle));
922     }
923     isPathChanged_ = true;
924 }
925 
ArcTo(const ArcToParam & param)926 void CustomPaintPaintMethod::ArcTo(const ArcToParam& param)
927 {
928     if (!isPathChanged_) {
929         rsPath_.MoveTo(static_cast<RSScalar>(param.x1), static_cast<RSScalar>(param.y1));
930     }
931     rsPath_.ArcTo(static_cast<RSScalar>(param.x1), static_cast<RSScalar>(param.y1), static_cast<RSScalar>(param.x2),
932         static_cast<RSScalar>(param.y2), static_cast<RSScalar>(param.radius));
933     isPathChanged_ = true;
934 }
935 
AddRect(const Rect & rect)936 void CustomPaintPaintMethod::AddRect(const Rect& rect)
937 {
938     RSRect rsRect(rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
939     rsPath_.AddRect(rsRect);
940     isPathChanged_ = true;
941 }
942 
AddRoundRect(const Rect & rect,const std::vector<double> & radii)943 void CustomPaintPaintMethod::AddRoundRect(const Rect& rect, const std::vector<double>& radii)
944 {
945     if (radii.size() != 4) { // 4: four corners.
946         return;
947     }
948     RSRect rsRect(rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
949     std::vector<RSPoint> radiusXY = {
950         RSPoint(radii[0], radii[0]), RSPoint(radii[1], radii[1]),   // 0: top-left, 1: top-right.
951         RSPoint(radii[2], radii[2]), RSPoint(radii[3], radii[3])    // 2: bottom-right, 3: bottom-left.
952     };
953     RSRoundRect rsRoundRect(rsRect, radiusXY);
954     rsPath_.AddRoundRect(rsRoundRect, RSPathDirection::CCW_DIRECTION);
955     isPathChanged_ = true;
956 }
957 
Ellipse(const EllipseParam & param)958 void CustomPaintPaintMethod::Ellipse(const EllipseParam& param)
959 {
960     // Init the start and end angle, then calculated the sweepAngle.
961     double startAngle = param.startAngle * HALF_CIRCLE_ANGLE / ACE_PI;
962     double endAngle = param.endAngle * HALF_CIRCLE_ANGLE / ACE_PI;
963     if (NearEqual(param.startAngle, param.endAngle)) {
964         return; // Just return when startAngle is same as endAngle.
965     }
966     double rotation = param.rotation * HALF_CIRCLE_ANGLE / ACE_PI;
967     double sweepAngle = endAngle - startAngle;
968     if (param.anticlockwise) {
969         sweepAngle =
970             endAngle > startAngle ? (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) - FULL_CIRCLE_ANGLE) : sweepAngle;
971     } else {
972         sweepAngle =
973             endAngle > startAngle ? sweepAngle : (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) + FULL_CIRCLE_ANGLE);
974     }
975 
976     // Init the oval Rect(left, top, right, bottom).
977     double left = param.x - param.radiusX;
978     double top = param.y - param.radiusY;
979     double right = param.x + param.radiusX;
980     double bottom = param.y + param.radiusY;
981     RSPoint point1(left, top);
982     RSPoint point2(right, bottom);
983     if (!NearZero(rotation)) {
984         RSMatrix matrix;
985         matrix.Rotate(-rotation, param.x, param.y);
986         rsPath_.Transform(matrix);
987     }
988     if (NearEqual(std::abs(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE)), 0.0) ||
989         NearEqual(std::abs(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE)), FULL_CIRCLE_ANGLE)) {
990         double half = GreatNotEqual(sweepAngle, 0.0) ? HALF_CIRCLE_ANGLE : -HALF_CIRCLE_ANGLE;
991         rsPath_.ArcTo(point1, point2, static_cast<RSScalar>(startAngle), static_cast<RSScalar>(half));
992         rsPath_.ArcTo(point1, point2, static_cast<RSScalar>(half + startAngle), static_cast<RSScalar>(half));
993     } else if (!NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && std::abs(sweepAngle) > FULL_CIRCLE_ANGLE) {
994         double half = GreatNotEqual(sweepAngle, 0.0) ? HALF_CIRCLE_ANGLE : -HALF_CIRCLE_ANGLE;
995         rsPath_.ArcTo(point1, point2, static_cast<RSScalar>(startAngle), static_cast<RSScalar>(half));
996         rsPath_.ArcTo(point1, point2, static_cast<RSScalar>(half + startAngle), static_cast<RSScalar>(half));
997         rsPath_.ArcTo(
998             point1, point2, static_cast<RSScalar>(half + half + startAngle), static_cast<RSScalar>(sweepAngle));
999     } else {
1000         rsPath_.ArcTo(point1, point2, static_cast<RSScalar>(startAngle), static_cast<RSScalar>(sweepAngle));
1001     }
1002     if (!NearZero(rotation)) {
1003         RSMatrix matrix;
1004         matrix.Rotate(rotation, param.x, param.y);
1005         rsPath_.Transform(matrix);
1006     }
1007     isPathChanged_ = true;
1008 }
1009 
BezierCurveTo(const BezierCurveParam & param)1010 void CustomPaintPaintMethod::BezierCurveTo(const BezierCurveParam& param)
1011 {
1012     if (!isPathChanged_) {
1013         rsPath_.MoveTo(static_cast<RSScalar>(param.cp1x), static_cast<RSScalar>(param.cp1y));
1014     }
1015     rsPath_.CubicTo(static_cast<RSScalar>(param.cp1x),
1016         static_cast<RSScalar>(param.cp1y), static_cast<RSScalar>(param.cp2x),
1017         static_cast<RSScalar>(param.cp2y), static_cast<RSScalar>(param.x),
1018         static_cast<RSScalar>(param.y));
1019     isPathChanged_ = true;
1020 }
1021 
QuadraticCurveTo(const QuadraticCurveParam & param)1022 void CustomPaintPaintMethod::QuadraticCurveTo(const QuadraticCurveParam& param)
1023 {
1024     if (!isPathChanged_) {
1025         rsPath_.MoveTo(static_cast<RSScalar>(param.cpx), static_cast<RSScalar>(param.cpy));
1026     }
1027     rsPath_.QuadTo(static_cast<RSScalar>(param.cpx), static_cast<RSScalar>(param.cpy),
1028         static_cast<RSScalar>(param.x), static_cast<RSScalar>(param.y));
1029     isPathChanged_ = true;
1030 }
1031 
ParsePath2D(const RefPtr<CanvasPath2D> & path)1032 void CustomPaintPaintMethod::ParsePath2D(const RefPtr<CanvasPath2D>& path)
1033 {
1034     for (const auto& [cmd, args] : path->GetCaches()) {
1035         switch (cmd) {
1036             case PathCmd::CMDS:
1037                 Path2DAddPath(args);
1038                 break;
1039             case PathCmd::TRANSFORM:
1040                 Path2DSetTransform(args);
1041                 break;
1042             case PathCmd::MOVE_TO:
1043                 Path2DMoveTo(args);
1044                 break;
1045             case PathCmd::LINE_TO:
1046                 Path2DLineTo(args);
1047                 break;
1048             case PathCmd::ARC:
1049                 Path2DArc(args);
1050                 break;
1051             case PathCmd::ARC_TO:
1052                 Path2DArcTo(args);
1053                 break;
1054             case PathCmd::QUADRATIC_CURVE_TO:
1055                 Path2DQuadraticCurveTo(args);
1056                 break;
1057             case PathCmd::BEZIER_CURVE_TO:
1058                 Path2DBezierCurveTo(args);
1059                 break;
1060             case PathCmd::ELLIPSE:
1061                 Path2DEllipse(args);
1062                 break;
1063             case PathCmd::RECT:
1064                 Path2DRect(args);
1065                 break;
1066             case PathCmd::ROUND_RECT:
1067                 Path2DRoundRect(args);
1068                 break;
1069             case PathCmd::CLOSE_PATH:
1070                 Path2DClosePath();
1071                 break;
1072             default:
1073                 break;
1074         }
1075     }
1076 }
1077 
Path2DAddPath(const PathArgs & args)1078 void CustomPaintPaintMethod::Path2DAddPath(const PathArgs& args)
1079 {
1080     RSRecordingPath out;
1081     out.BuildFromSVGString(args.cmds);
1082     rsPath2d_.AddPath(out);
1083 }
1084 
Path2DClosePath()1085 void CustomPaintPaintMethod::Path2DClosePath()
1086 {
1087     rsPath2d_.Close();
1088 }
1089 
Path2DMoveTo(const PathArgs & args)1090 void CustomPaintPaintMethod::Path2DMoveTo(const PathArgs& args)
1091 {
1092     rsPath2d_.MoveTo(args.para1, args.para2);
1093     isPath2dChanged_ = true;
1094 }
1095 
Path2DLineTo(const PathArgs & args)1096 void CustomPaintPaintMethod::Path2DLineTo(const PathArgs& args)
1097 {
1098     if (!isPath2dChanged_) {
1099         rsPath2d_.MoveTo(static_cast<RSScalar>(args.para1), static_cast<RSScalar>(args.para2));
1100     }
1101     rsPath2d_.LineTo(args.para1, args.para2);
1102     isPath2dChanged_ = true;
1103 }
1104 
Path2DArc(const PathArgs & args)1105 void CustomPaintPaintMethod::Path2DArc(const PathArgs& args)
1106 {
1107     RSPoint point1(args.para1 - args.para3, args.para2 - args.para3);
1108     RSPoint point2(args.para1 + args.para3, args.para2 + args.para3);
1109     double startAngle = args.para4 * HALF_CIRCLE_ANGLE / ACE_PI;
1110     double endAngle = args.para5 * HALF_CIRCLE_ANGLE / ACE_PI;
1111     double sweepAngle = endAngle - startAngle;
1112     if (!NearZero(args.para6)) {
1113         sweepAngle =
1114             endAngle > startAngle ? (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) - FULL_CIRCLE_ANGLE) : sweepAngle;
1115     } else {
1116         sweepAngle =
1117             endAngle > startAngle ? sweepAngle : (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) + FULL_CIRCLE_ANGLE);
1118     }
1119     if (!NearEqual(startAngle, endAngle) &&
1120         (NearEqual(std::abs(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE)), 0.0) ||
1121          NearEqual(std::abs(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE)), FULL_CIRCLE_ANGLE))) {
1122         double half = GreatNotEqual(sweepAngle, 0.0) ? HALF_CIRCLE_ANGLE : -HALF_CIRCLE_ANGLE;
1123         rsPath2d_.ArcTo(point1, point2, static_cast<RSScalar>(startAngle), static_cast<RSScalar>(half));
1124         rsPath2d_.ArcTo(point1, point2, static_cast<RSScalar>(half + startAngle), static_cast<RSScalar>(half));
1125     } else if (!NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && std::abs(sweepAngle) > FULL_CIRCLE_ANGLE) {
1126         double half = GreatNotEqual(sweepAngle, 0.0) ? HALF_CIRCLE_ANGLE : -HALF_CIRCLE_ANGLE;
1127         rsPath2d_.ArcTo(point1, point2, static_cast<RSScalar>(startAngle), static_cast<RSScalar>(half));
1128         rsPath2d_.ArcTo(point1, point2, static_cast<RSScalar>(half + startAngle), static_cast<RSScalar>(half));
1129         rsPath2d_.ArcTo(
1130             point1, point2, static_cast<RSScalar>(half + half + startAngle), static_cast<RSScalar>(sweepAngle));
1131     } else {
1132         rsPath2d_.ArcTo(point1, point2, startAngle, sweepAngle);
1133     }
1134     isPath2dChanged_ = true;
1135 }
1136 
Path2DArcTo(const PathArgs & args)1137 void CustomPaintPaintMethod::Path2DArcTo(const PathArgs& args)
1138 {
1139     if (!isPath2dChanged_) {
1140         rsPath2d_.MoveTo(static_cast<RSScalar>(args.para1), static_cast<RSScalar>(args.para2));
1141     }
1142     rsPath2d_.ArcTo(static_cast<RSScalar>(args.para1), static_cast<RSScalar>(args.para2),
1143         static_cast<RSScalar>(args.para3), static_cast<RSScalar>(args.para4), static_cast<RSScalar>(args.para5));
1144     isPath2dChanged_ = true;
1145 }
1146 
Path2DEllipse(const PathArgs & args)1147 void CustomPaintPaintMethod::Path2DEllipse(const PathArgs& args)
1148 {
1149     if (NearEqual(args.para6, args.para7)) {
1150         return; // Just return when startAngle is same as endAngle.
1151     }
1152 
1153     double rotation = args.para5 * HALF_CIRCLE_ANGLE / ACE_PI;
1154     double startAngle = args.para6 * HALF_CIRCLE_ANGLE / ACE_PI;
1155     double endAngle = args.para7 * HALF_CIRCLE_ANGLE / ACE_PI;
1156     bool anticlockwise = NearZero(args.para8) ? false : true;
1157     double sweepAngle = endAngle - startAngle;
1158     if (anticlockwise) {
1159         sweepAngle =
1160             endAngle > startAngle ? (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) - FULL_CIRCLE_ANGLE) : sweepAngle;
1161     } else {
1162         sweepAngle =
1163             endAngle > startAngle ? sweepAngle : (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) + FULL_CIRCLE_ANGLE);
1164     }
1165     RSPoint point1(args.para1 - args.para3, args.para2 - args.para4);
1166     RSPoint point2(args.para1 + args.para3, args.para2 + args.para4);
1167 
1168     if (!NearZero(rotation)) {
1169         RSMatrix matrix;
1170         matrix.Rotate(-rotation, args.para1, args.para2);
1171         rsPath2d_.Transform(matrix);
1172     }
1173     if (NearEqual(std::abs(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE)), 0.0) ||
1174         NearEqual(std::abs(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE)), FULL_CIRCLE_ANGLE)) {
1175         double half = GreatNotEqual(sweepAngle, 0.0) ? HALF_CIRCLE_ANGLE : -HALF_CIRCLE_ANGLE;
1176         rsPath2d_.ArcTo(point1, point2, static_cast<RSScalar>(startAngle), static_cast<RSScalar>(half));
1177         rsPath2d_.ArcTo(point1, point2, static_cast<RSScalar>(half + startAngle), static_cast<RSScalar>(half));
1178     } else if (!NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && std::abs(sweepAngle) > FULL_CIRCLE_ANGLE) {
1179         double half = GreatNotEqual(sweepAngle, 0.0) ? HALF_CIRCLE_ANGLE : -HALF_CIRCLE_ANGLE;
1180         rsPath2d_.ArcTo(point1, point2, static_cast<RSScalar>(startAngle), static_cast<RSScalar>(half));
1181         rsPath2d_.ArcTo(point1, point2, static_cast<RSScalar>(half + startAngle), static_cast<RSScalar>(half));
1182         rsPath2d_.ArcTo(
1183             point1, point2, static_cast<RSScalar>(half + half + startAngle), static_cast<RSScalar>(sweepAngle));
1184     } else {
1185         rsPath2d_.ArcTo(point1, point2, startAngle, sweepAngle);
1186     }
1187     if (!NearZero(rotation)) {
1188         RSMatrix matrix;
1189         matrix.Rotate(rotation, args.para1, args.para2);
1190         rsPath2d_.Transform(matrix);
1191     }
1192     isPath2dChanged_ = true;
1193 }
1194 
Path2DBezierCurveTo(const PathArgs & args)1195 void CustomPaintPaintMethod::Path2DBezierCurveTo(const PathArgs& args)
1196 {
1197     if (!isPath2dChanged_) {
1198         rsPath2d_.MoveTo(static_cast<RSScalar>(args.para1), static_cast<RSScalar>(args.para2));
1199     }
1200     rsPath2d_.CubicTo(args.para1, args.para2, args.para3, args.para4, args.para5, args.para6);
1201     isPath2dChanged_ = true;
1202 }
1203 
Path2DQuadraticCurveTo(const PathArgs & args)1204 void CustomPaintPaintMethod::Path2DQuadraticCurveTo(const PathArgs& args)
1205 {
1206     if (!isPath2dChanged_) {
1207         rsPath2d_.MoveTo(static_cast<RSScalar>(args.para1), static_cast<RSScalar>(args.para2));
1208     }
1209     rsPath2d_.QuadTo(args.para1, args.para2, args.para3, args.para4);
1210     isPath2dChanged_ = true;
1211 }
1212 
Path2DSetTransform(const PathArgs & args)1213 void CustomPaintPaintMethod::Path2DSetTransform(const PathArgs& args)
1214 {
1215     RSMatrix matrix;
1216     matrix.SetMatrix(args.para1, args.para3, args.para5, args.para2, args.para4, args.para6, 0, 0, 1);
1217     rsPath2d_.Transform(matrix);
1218 }
1219 
Save()1220 void CustomPaintPaintMethod::Save()
1221 {
1222     CHECK_NULL_VOID(rsCanvas_);
1223     saveStates_.push_back(state_);
1224     saveColorFilter_.push_back(colorFilter_);
1225     saveBlurFilter_.push_back(blurFilter_);
1226     rsCanvas_->Save();
1227 }
1228 
Restore()1229 void CustomPaintPaintMethod::Restore()
1230 {
1231     CHECK_NULL_VOID(rsCanvas_);
1232     if ((rsCanvas_->GetSaveCount() > DEFAULT_SAVE_COUNT) && (!saveStates_.empty()) && (!saveColorFilter_.empty()) &&
1233         (!saveBlurFilter_.empty())) {
1234         state_ = saveStates_.back();
1235         saveStates_.pop_back();
1236         colorFilter_ = saveColorFilter_.back();
1237         saveColorFilter_.pop_back();
1238         blurFilter_ = saveBlurFilter_.back();
1239         saveBlurFilter_.pop_back();
1240         rsCanvas_->Restore();
1241     }
1242 }
1243 
Scale(double x,double y)1244 void CustomPaintPaintMethod::Scale(double x, double y)
1245 {
1246     CHECK_NULL_VOID(rsCanvas_);
1247     rsCanvas_->Scale(x, y);
1248 }
1249 
Rotate(double angle)1250 void CustomPaintPaintMethod::Rotate(double angle)
1251 {
1252     CHECK_NULL_VOID(rsCanvas_);
1253     rsCanvas_->Rotate(angle * 180 / ACE_PI);
1254 }
1255 
ResetTransform()1256 void CustomPaintPaintMethod::ResetTransform()
1257 {
1258     CHECK_NULL_VOID(rsCanvas_);
1259     rsCanvas_->ResetMatrix();
1260 }
1261 
Transform(const TransformParam & param)1262 void CustomPaintPaintMethod::Transform(const TransformParam& param)
1263 {
1264     CHECK_NULL_VOID(rsCanvas_);
1265     RSMatrix matrix;
1266     matrix.SetMatrix(param.scaleX, param.skewY, param.translateX, param.skewX, param.scaleY, param.translateY, 0, 0, 1);
1267     rsCanvas_->ConcatMatrix(matrix);
1268 }
1269 
Translate(double x,double y)1270 void CustomPaintPaintMethod::Translate(double x, double y)
1271 {
1272     CHECK_NULL_VOID(rsCanvas_);
1273     rsCanvas_->Translate(x, y);
1274 }
1275 
FillText(const std::string & text,double x,double y,std::optional<double> maxWidth)1276 void CustomPaintPaintMethod::FillText(const std::string& text, double x, double y, std::optional<double> maxWidth)
1277 {
1278     auto success = UpdateFillParagraph(text);
1279     CHECK_NULL_VOID(success);
1280     PaintText(lastLayoutSize_.Width(), x, y, maxWidth, false);
1281 }
1282 
StrokeText(const std::string & text,double x,double y,std::optional<double> maxWidth)1283 void CustomPaintPaintMethod::StrokeText(const std::string& text, double x, double y, std::optional<double> maxWidth)
1284 {
1285     auto success = UpdateStrokeParagraph(text);
1286     CHECK_NULL_VOID(success);
1287     PaintText(lastLayoutSize_.Width(), x, y, maxWidth, true);
1288 }
1289 
PaintText(const float width,double x,double y,std::optional<double> maxWidth,bool isStroke)1290 void CustomPaintPaintMethod::PaintText(
1291     const float width, double x, double y, std::optional<double> maxWidth, bool isStroke)
1292 {
1293     CHECK_NULL_VOID(rsCanvas_);
1294     CHECK_NULL_VOID(paragraph_);
1295     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TEN)) {
1296         paragraph_->Layout(FLT_MAX);
1297     } else {
1298         paragraph_->Layout(width);
1299     }
1300     if (width > paragraph_->GetMaxIntrinsicWidth()) {
1301         paragraph_->Layout(std::ceil(paragraph_->GetMaxIntrinsicWidth()));
1302     }
1303     auto align = isStroke ? state_.strokeState.GetTextAlign() : state_.fillState.GetTextAlign();
1304     double dx = 0.0;
1305     if (maxWidth.has_value() && (maxWidth.value() < paragraph_->GetMaxIntrinsicWidth())) {
1306         dx = x + GetAlignOffset(align, maxWidth.value());
1307     } else {
1308         dx = x + GetAlignOffset(align, paragraph_->GetMaxIntrinsicWidth());
1309     }
1310     auto baseline = isStroke ? state_.strokeState.GetTextStyle().GetTextBaseline()
1311                              : state_.fillState.GetTextStyle().GetTextBaseline();
1312     double dy = y + GetBaselineOffset(baseline, paragraph_);
1313 
1314     std::optional<double> scale = CalcTextScale(paragraph_->GetMaxIntrinsicWidth(), maxWidth);
1315     RSBrush compositeOperationpBrush;
1316     InitPaintBlend(compositeOperationpBrush);
1317     RSSaveLayerOps slo(nullptr, &compositeOperationpBrush);
1318     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_THIRTEEN)) {
1319         if (state_.globalState.GetType() != CompositeOperation::SOURCE_OVER) {
1320             rsCanvas_->SaveLayer(slo);
1321         }
1322     }
1323     if (isStroke && shadowParagraph_ != nullptr && HasShadow()) {
1324         PaintStrokeTextShadow(width, dx, dy, scale, &slo);
1325     }
1326     if (scale.has_value()) {
1327         if (!NearZero(scale.value())) {
1328             dx /= scale.value();
1329         }
1330         rsCanvas_->Save();
1331         rsCanvas_->Scale(scale.value(), 1.0);
1332         paragraph_->Paint(rsCanvas_.get(), dx, dy);
1333         rsCanvas_->Restore();
1334     } else {
1335         paragraph_->Paint(rsCanvas_.get(), dx, dy);
1336     }
1337     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_THIRTEEN)) {
1338         if (state_.globalState.GetType() != CompositeOperation::SOURCE_OVER) {
1339             rsCanvas_->Restore();
1340         }
1341     }
1342 }
1343 
PaintStrokeTextShadow(const float width,const double dx,const double dy,const std::optional<double> scale,RSSaveLayerOps * slo)1344 void CustomPaintPaintMethod::PaintStrokeTextShadow(
1345     const float width, const double dx, const double dy, const std::optional<double> scale, RSSaveLayerOps* slo)
1346 {
1347     CHECK_NULL_VOID(rsCanvas_);
1348     CHECK_NULL_VOID(shadowParagraph_);
1349     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_THIRTEEN)) {
1350         if (state_.globalState.GetType() != CompositeOperation::SOURCE_OVER) {
1351             rsCanvas_->SaveLayer(*slo);
1352         }
1353     }
1354     double finalDx = dx;
1355     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TEN)) {
1356         shadowParagraph_->Layout(FLT_MAX);
1357     } else {
1358         shadowParagraph_->Layout(width);
1359     }
1360     if (width > shadowParagraph_->GetMaxIntrinsicWidth()) {
1361         shadowParagraph_->Layout(std::ceil(shadowParagraph_->GetMaxIntrinsicWidth()));
1362     }
1363     rsCanvas_->Save();
1364     auto shadowOffsetX = state_.shadow.GetOffset().GetX();
1365     auto shadowOffsetY = state_.shadow.GetOffset().GetY();
1366     if (scale.has_value()) {
1367         if (!NearZero(scale.value())) {
1368             finalDx /= scale.value();
1369             shadowOffsetX /= scale.value();
1370         }
1371         rsCanvas_->Scale(scale.value(), 1.0);
1372     }
1373     shadowParagraph_->Paint(rsCanvas_.get(), finalDx + shadowOffsetX, dy + shadowOffsetY);
1374     rsCanvas_->Restore();
1375     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_THIRTEEN)) {
1376         if (state_.globalState.GetType() != CompositeOperation::SOURCE_OVER) {
1377             rsCanvas_->Restore();
1378         }
1379     }
1380 }
1381 
GetAlignOffset(TextAlign align,double width)1382 double CustomPaintPaintMethod::GetAlignOffset(TextAlign align, double width)
1383 {
1384     double x = 0.0;
1385     TextDirection textDirection = state_.fillState.GetOffTextDirection();
1386     switch (align) {
1387         case TextAlign::LEFT:
1388             x = 0.0;
1389             break;
1390         case TextAlign::START:
1391             x = (textDirection == TextDirection::LTR) ? 0.0 : -width;
1392             break;
1393         case TextAlign::RIGHT:
1394             x = -width;
1395             break;
1396         case TextAlign::END:
1397             x = (textDirection == TextDirection::LTR) ? -width : 0.0;
1398             break;
1399         case TextAlign::CENTER:
1400             x = -width * HALF;
1401             break;
1402         default:
1403             x = 0.0;
1404             break;
1405     }
1406     return x;
1407 }
1408 
GetBaselineOffset(TextBaseline baseline,std::unique_ptr<RSParagraph> & paragraph)1409 double CustomPaintPaintMethod::GetBaselineOffset(TextBaseline baseline, std::unique_ptr<RSParagraph>& paragraph)
1410 {
1411     double y = 0.0;
1412     switch (baseline) {
1413         case TextBaseline::ALPHABETIC:
1414             y = -paragraph->GetAlphabeticBaseline();
1415             break;
1416         case TextBaseline::IDEOGRAPHIC:
1417             y = -paragraph->GetIdeographicBaseline();
1418             break;
1419         case TextBaseline::BOTTOM:
1420             y = -paragraph->GetHeight();
1421             break;
1422         case TextBaseline::TOP:
1423             y = 0.0;
1424             break;
1425         case TextBaseline::MIDDLE:
1426             y = -paragraph->GetHeight() * HALF;
1427             break;
1428         case TextBaseline::HANGING:
1429             y = -HANGING_PERCENT * (paragraph->GetHeight() - paragraph->GetAlphabeticBaseline());
1430             break;
1431         default:
1432             y = -paragraph->GetAlphabeticBaseline();
1433             break;
1434     }
1435     return y;
1436 }
1437 
1438 #ifndef ACE_UNITTEST
GetFontBaseline(const Rosen::Drawing::FontMetrics & fontMetrics,TextBaseline baseline) const1439 double CustomPaintPaintMethod::GetFontBaseline(
1440     const Rosen::Drawing::FontMetrics& fontMetrics, TextBaseline baseline) const
1441 {
1442     switch (baseline) {
1443         case TextBaseline::TOP:
1444             return fontMetrics.fAscent;
1445         case TextBaseline::HANGING:
1446             return fontMetrics.fAscent * HANGING_PERCENT;
1447         case TextBaseline::MIDDLE:
1448             return fontMetrics.fAscent + fontMetrics.fDescent;
1449         case TextBaseline::BOTTOM:
1450         case TextBaseline::IDEOGRAPHIC:
1451             return fontMetrics.fDescent;
1452         case TextBaseline::ALPHABETIC:
1453             return 0;
1454         default:
1455             break;
1456     }
1457     return 0;
1458 }
1459 
GetFontAlign(TextAlign align,std::unique_ptr<RSParagraph> & paragraph) const1460 double CustomPaintPaintMethod::GetFontAlign(TextAlign align, std::unique_ptr<RSParagraph>& paragraph) const
1461 {
1462     TextDirection textDirection = state_.fillState.GetOffTextDirection();
1463     switch (align) {
1464         case TextAlign::LEFT:
1465             return 0;
1466         case TextAlign::START:
1467             return (textDirection == TextDirection::LTR) ? 0.0 : paragraph->GetMaxIntrinsicWidth();
1468         case TextAlign::RIGHT:
1469             return paragraph->GetMaxIntrinsicWidth();
1470         case TextAlign::END:
1471             return (textDirection == TextDirection::LTR) ? paragraph->GetMaxIntrinsicWidth() : 0.0;
1472         case TextAlign::CENTER:
1473             return paragraph->GetMaxIntrinsicWidth() / 2.0;
1474         default:
1475             break;
1476     }
1477     return 0;
1478 }
1479 #endif
1480 
GetEffectiveAlign(RSTextAlign align,RSTextDirection direction) const1481 RSTextAlign CustomPaintPaintMethod::GetEffectiveAlign(RSTextAlign align, RSTextDirection direction) const
1482 {
1483     if (align == RSTextAlign::START) {
1484         return (direction == RSTextDirection::LTR) ? RSTextAlign::LEFT : RSTextAlign::RIGHT;
1485     } else if (align == RSTextAlign::END) {
1486         return (direction == RSTextDirection::LTR) ? RSTextAlign::RIGHT : RSTextAlign::LEFT;
1487     } else {
1488         return align;
1489     }
1490 }
1491 
ClearPaintImage(RSPen * pen,RSBrush * brush)1492 void CustomPaintPaintMethod::ClearPaintImage(RSPen* pen, RSBrush* brush)
1493 {
1494     RSFilter filter;
1495     RSColorMatrix colorMatrix;
1496     filter.SetColorFilter(RSColorFilter::CreateMatrixColorFilter(colorMatrix));
1497     filter.SetMaskFilter(RSMaskFilter::CreateBlurMaskFilter(RSBlurType::NORMAL, 0));
1498     filter.SetImageFilter(RSImageFilter::CreateBlurImageFilter(0, 0, RSTileMode::DECAL, nullptr));
1499     if (pen) {
1500         pen->SetFilter(filter);
1501     }
1502     if (brush) {
1503         brush->SetFilter(filter);
1504     }
1505 }
1506 
SetPaintImage(RSPen * pen,RSBrush * brush)1507 void CustomPaintPaintMethod::SetPaintImage(RSPen* pen, RSBrush* brush)
1508 {
1509     if (pen) {
1510         auto filter = pen->GetFilter();
1511         filter.SetColorFilter(colorFilter_);
1512         filter.SetImageFilter(blurFilter_);
1513         pen->SetFilter(filter);
1514     }
1515     if (brush) {
1516         auto filter = brush->GetFilter();
1517         filter.SetColorFilter(colorFilter_);
1518         filter.SetImageFilter(blurFilter_);
1519         brush->SetFilter(filter);
1520     }
1521 }
1522 
SetFilterParam(const std::string & filterStr)1523 void CustomPaintPaintMethod::SetFilterParam(const std::string& filterStr)
1524 {
1525     std::vector<FilterProperty> filters;
1526     if (!GetFilterType(filterStr, filters)) {
1527         return;
1528     }
1529     colorMatrix_ = RSColorMatrix();
1530     colorFilter_ = RSColorFilter::CreateMatrixColorFilter(colorMatrix_);
1531     blurFilter_ = RSImageFilter::CreateBlurImageFilter(0, 0, RSTileMode::DECAL, nullptr);
1532     for (FilterProperty filter : filters) {
1533         switch (filter.filterType_) {
1534             case FilterType::NONE:
1535                 break;
1536             case FilterType::GRAYSCALE:
1537                 SetGrayFilter(filter.filterParam_);
1538                 break;
1539             case FilterType::SEPIA:
1540                 SetSepiaFilter(filter.filterParam_);
1541                 break;
1542             case FilterType::SATURATE:
1543                 SetSaturateFilter(filter.filterParam_);
1544                 break;
1545             case FilterType::HUE_ROTATE:
1546                 SetHueRotateFilter(filter.filterParam_);
1547                 break;
1548             case FilterType::INVERT:
1549                 SetInvertFilter(filter.filterParam_);
1550                 break;
1551             case FilterType::OPACITY:
1552                 SetOpacityFilter(filter.filterParam_);
1553                 break;
1554             case FilterType::BRIGHTNESS:
1555                 SetBrightnessFilter(filter.filterParam_);
1556                 break;
1557             case FilterType::CONTRAST:
1558                 SetContrastFilter(filter.filterParam_);
1559                 break;
1560             case FilterType::BLUR:
1561                 SetBlurFilter(filter.filterParam_);
1562                 break;
1563             case FilterType::DROP_SHADOW:
1564                 break;
1565             default:
1566                 break;
1567         }
1568     }
1569     colorFilter_ = RSColorFilter::CreateMatrixColorFilter(colorMatrix_);
1570 }
1571 
1572 // https://drafts.fxtf.org/filter-effects/#grayscaleEquivalent
SetGrayFilter(const std::string & percent)1573 void CustomPaintPaintMethod::SetGrayFilter(const std::string& percent)
1574 {
1575     float percentNum = 1.0f;
1576     if (!CheckNumberAndPercentage(percent, true, percentNum)) {
1577         return;
1578     }
1579 
1580     float matrix[20] = { 0.0f };
1581     float value = 1 - percentNum;
1582 
1583     matrix[0] = LUMR + (1 - LUMR) * value;
1584     matrix[5] = LUMR - LUMR * value;
1585     matrix[10] = LUMR - LUMR * value;
1586 
1587     matrix[1] = LUMG - LUMG * value;
1588     matrix[6] = LUMG + (1 - LUMG) * value;
1589     matrix[11] = LUMG - LUMG * value;
1590 
1591     matrix[2] = LUMB - LUMB * value;
1592     matrix[7] = LUMB - LUMB * value;
1593     matrix[12] = LUMB + (1 - LUMB) * value;
1594 
1595     matrix[18] = 1.0f;
1596     RSColorMatrix colorMatrix;
1597     colorMatrix.SetArray(matrix);
1598     colorMatrix_.PostConcat(colorMatrix);
1599 }
1600 
1601 // https://drafts.fxtf.org/filter-effects/#sepiaEquivalent
SetSepiaFilter(const std::string & percent)1602 void CustomPaintPaintMethod::SetSepiaFilter(const std::string& percent)
1603 {
1604     float percentNum = 1.0f;
1605     if (!CheckNumberAndPercentage(percent, true, percentNum)) {
1606         return;
1607     }
1608     float matrix[20] = { 0.0f };
1609     matrix[0] = 1.0f - percentNum * 0.607f;
1610     matrix[1] = percentNum * 0.769f;
1611     matrix[2] = percentNum * 0.189f;
1612 
1613     matrix[5] = percentNum * 0.349f;
1614     matrix[6] = 1.0f - percentNum * 0.314f;
1615     matrix[7] = percentNum * 0.168f;
1616 
1617     matrix[10] = percentNum * 0.272f;
1618     matrix[11] = percentNum * 0.534f;
1619     matrix[12] = 1.0f - percentNum * 0.869f;
1620 
1621     matrix[18] = 1.0f;
1622     RSColorMatrix colorMatrix;
1623     colorMatrix.SetArray(matrix);
1624     colorMatrix_.PostConcat(colorMatrix);
1625 }
1626 
1627 // https://drafts.fxtf.org/filter-effects/#saturateEquivalent
SetSaturateFilter(const std::string & percent)1628 void CustomPaintPaintMethod::SetSaturateFilter(const std::string& percent)
1629 {
1630     float percentNum = 1.0f;
1631     if (!CheckNumberAndPercentage(percent, false, percentNum)) {
1632         return;
1633     }
1634     float matrix[20] = { 0.0f };
1635 
1636     matrix[0] = LUMR + (1 - LUMR) * percentNum;
1637     matrix[5] = LUMR - LUMR * percentNum;
1638     matrix[10] = LUMR - LUMR * percentNum;
1639 
1640     matrix[1] = LUMG - LUMG * percentNum;
1641     matrix[6] = LUMG + (1 - LUMG) * percentNum;
1642     matrix[11] = LUMG - LUMG * percentNum;
1643 
1644     matrix[2] = LUMB - LUMB * percentNum;
1645     matrix[7] = LUMB - LUMB * percentNum;
1646     matrix[12] = LUMB + (1 - LUMB) * percentNum;
1647 
1648     matrix[18] = 1.0f;
1649     RSColorMatrix colorMatrix;
1650     colorMatrix.SetArray(matrix);
1651     colorMatrix_.PostConcat(colorMatrix);
1652 }
1653 
1654 // https://drafts.fxtf.org/filter-effects/#huerotateEquivalent
SetHueRotateFilter(const std::string & filterParam)1655 void CustomPaintPaintMethod::SetHueRotateFilter(const std::string& filterParam)
1656 {
1657     std::string percent = filterParam;
1658     float rad = 0.0f;
1659     size_t index = percent.find("deg");
1660     if (index != std::string::npos) {
1661         percent.resize(index);
1662         rad = StringUtils::StringToFloat(percent);
1663         rad = rad / HALF_CIRCLE_ANGLE * ACE_PI;
1664     } else if ((index = percent.find("turn")) != std::string::npos) {
1665         percent.resize(index);
1666         rad = StringUtils::StringToFloat(percent);
1667         rad = rad * 2 * ACE_PI;
1668     } else if ((index = percent.find("rad")) != std::string::npos) {
1669         percent.resize(index);
1670         rad = StringUtils::StringToFloat(percent);
1671     }
1672 
1673     float cosValue = std::cos(rad);
1674     float sinValue = std::sin(rad);
1675     float matrix[20] = { 0.0f };
1676 
1677     matrix[0] = LUMR + cosValue * (1 - LUMR) + sinValue * (-LUMR);
1678     matrix[5] = LUMR + cosValue * (-LUMR) + sinValue * 0.143f;
1679     matrix[10] = LUMR + cosValue * (-LUMR) + sinValue * (LUMR - 1);
1680 
1681     matrix[1] = LUMG + cosValue * (-LUMG) + sinValue * (-LUMG);
1682     matrix[6] = LUMG + cosValue * (1 - LUMG) + sinValue * 0.140f;
1683     matrix[11] = LUMG + cosValue * (-LUMG) + sinValue * LUMG;
1684 
1685     matrix[2] = LUMB + cosValue * (-LUMB) + sinValue * (1 - LUMB);
1686     matrix[7] = LUMB + cosValue * (-LUMB) + sinValue * (-0.283f);
1687     matrix[12] = LUMB + cosValue * (1 - LUMB) + sinValue * LUMB;
1688 
1689     matrix[18] = 1.0f;
1690     RSColorMatrix colorMatrix;
1691     colorMatrix.SetArray(matrix);
1692     colorMatrix_.PostConcat(colorMatrix);
1693 }
1694 
1695 /*
1696  * https://drafts.fxtf.org/filter-effects/#invertEquivalent
1697  * Example for R in RGB:
1698  * v0 = percentNum, v1 = 1 - percentNum, n = 1
1699  * If 0 <= R < 1,
1700  * k / n <= R < (k + 1) / n => R * n - 1 < k <= R * n => k = 0
1701  * R' = funcR(R) = v0 + (R - k / n) * n * (v1 - v0) = percentNum + (1 - 2 * percentNum) * R
1702  * If R==1, R' = v1 = 1 - percentNum = percentNum + (1 - 2 * percentNum) * R
1703  * so R' = funcR(R) = percentNum + (1 - 2 * percentNum) * R, where 0 <= R <= 1.
1704  */
SetInvertFilter(const std::string & percent)1705 void CustomPaintPaintMethod::SetInvertFilter(const std::string& percent)
1706 {
1707     float percentNum = 1.0f;
1708     if (!CheckNumberAndPercentage(percent, true, percentNum)) {
1709         return;
1710     }
1711     float matrix[20] = { 0.0f };
1712     matrix[0] = matrix[6] = matrix[12] = 1.0 - 2.0 * percentNum;
1713     matrix[4] = matrix[9] = matrix[14] = percentNum;
1714     matrix[18] = 1.0f;
1715     RSColorMatrix colorMatrix;
1716     colorMatrix.SetArray(matrix);
1717     colorMatrix_.PostConcat(colorMatrix);
1718 }
1719 
1720 /*
1721  * https://drafts.fxtf.org/filter-effects/#opacityEquivalent
1722  * A is short for Alpha:
1723  * v0 = 0, v1 = percentNum, n = 1
1724  * If 0 <= A < 1, k = 0. reference:SetInvertFilter.
1725  * A' = funcR(A) = v0 + (A - k / n) * n * (v1 - v0) = percentNum * A
1726  * If A==1, A' = v1 = percentNum = percentNum * A
1727  * so A' = funcR(A) = percentNum * A, where 0 <= A <= 1.
1728  */
SetOpacityFilter(const std::string & percent)1729 void CustomPaintPaintMethod::SetOpacityFilter(const std::string& percent)
1730 {
1731     float percentNum = 1.0f;
1732     if (!CheckNumberAndPercentage(percent, true, percentNum)) {
1733         return;
1734     }
1735     float matrix[20] = { 0.0f };
1736     matrix[0] = matrix[6] = matrix[12] = 1.0f;
1737     matrix[18] = percentNum;
1738     RSColorMatrix colorMatrix;
1739     colorMatrix.SetArray(matrix);
1740     colorMatrix_.PostConcat(colorMatrix);
1741 }
1742 
1743 /*
1744  * https://drafts.fxtf.org/filter-effects/#brightnessEquivalent
1745  * Example for R in RGB:
1746  * R' = funcR(R) = slope * R + intercept
1747  * where: slope = percentNum, intercept = 0
1748  */
SetBrightnessFilter(const std::string & percent)1749 void CustomPaintPaintMethod::SetBrightnessFilter(const std::string& percent)
1750 {
1751     float percentNum = 1.0f;
1752     if (!CheckNumberAndPercentage(percent, false, percentNum)) {
1753         return;
1754     }
1755     float matrix[20] = { 0.0f };
1756     matrix[0] = matrix[6] = matrix[12] = percentNum;
1757     matrix[18] = 1.0f;
1758     RSColorMatrix colorMatrix;
1759     colorMatrix.SetArray(matrix);
1760     colorMatrix_.PostConcat(colorMatrix);
1761 }
1762 
1763 /*
1764  * https://drafts.fxtf.org/filter-effects/#contrastEquivalent
1765  * Example for R in RGB:
1766  * R' = funcR(R) = slope * R + intercept
1767  * where: slope = percentNum, intercept = 0.5 * (1 - percentNum)
1768  */
SetContrastFilter(const std::string & percent)1769 void CustomPaintPaintMethod::SetContrastFilter(const std::string& percent)
1770 {
1771     float percentNum = 1.0f;
1772     if (!CheckNumberAndPercentage(percent, false, percentNum)) {
1773         return;
1774     }
1775     float matrix[20] = { 0.0f };
1776     matrix[0] = matrix[6] = matrix[12] = percentNum;
1777     matrix[4] = matrix[9] = matrix[14] = 0.5f * (1 - percentNum);
1778     matrix[18] = 1;
1779     RSColorMatrix colorMatrix;
1780     colorMatrix.SetArray(matrix);
1781     colorMatrix_.PostConcat(colorMatrix);
1782 }
1783 
1784 // https://drafts.fxtf.org/filter-effects/#blurEquivalent
SetBlurFilter(const std::string & percent)1785 void CustomPaintPaintMethod::SetBlurFilter(const std::string& percent)
1786 {
1787     float blurNum = 0.0f;
1788     blurNum = BlurStrToDouble(percent);
1789     if (Negative(blurNum)) {
1790         return;
1791     }
1792     blurFilter_ =
1793         RSImageFilter::CreateBlurImageFilter(blurNum, blurNum, RSTileMode::DECAL, nullptr);
1794 }
1795 
GetFilterType(const std::string & filterStr,std::vector<FilterProperty> & filters)1796 bool CustomPaintPaintMethod::GetFilterType(const std::string& filterStr, std::vector<FilterProperty>& filters)
1797 {
1798     std::string paramData = filterStr;
1799     std::transform(paramData.begin(), paramData.end(), paramData.begin(), ::tolower);
1800     paramData.erase(paramData.find_last_not_of(' ') + 1);
1801     paramData.erase(0, paramData.find_first_not_of(' '));
1802     if (paramData == "none") {
1803         filters.emplace_back(FilterProperty{FilterType::NONE, ""});
1804         return true;
1805     }
1806 
1807     std::string filter;
1808     for (auto ch : paramData) {
1809         if (ch == ')') {
1810             if (!ParseFilter(filter, filters)) {
1811                 return false;
1812             }
1813             filter.clear();
1814         } else {
1815             filter.push_back(ch);
1816         }
1817     }
1818     if (!filter.empty()) {
1819         if (!ParseFilter(filter, filters)) {
1820             return false;
1821         }
1822     }
1823     return (filters.size() > 0);
1824 }
1825 
IsPercentStr(std::string & percent)1826 bool CustomPaintPaintMethod::IsPercentStr(std::string& percent)
1827 {
1828     size_t index = percent.find("%");
1829     if (index != std::string::npos) {
1830         percent = percent.substr(0, index);
1831         return true;
1832     }
1833     return false;
1834 }
1835 
PxStrToDouble(const std::string & str)1836 double CustomPaintPaintMethod::PxStrToDouble(const std::string& str)
1837 {
1838     double ret = 0;
1839     size_t index = str.find("px");
1840     if (index != std::string::npos) {
1841         std::string result = str.substr(0, index);
1842         ret = StringUtils::StringToDouble(result);
1843     }
1844     return ret;
1845 }
1846 
BlurStrToDouble(const std::string & str)1847 double CustomPaintPaintMethod::BlurStrToDouble(const std::string& str)
1848 {
1849     double ret = 0;
1850 
1851     // check px case
1852     size_t index = str.find("px");
1853     if (index != std::string::npos) {
1854         std::string result = str.substr(0, index);
1855         ret = StringUtils::StringToDouble(result);
1856         return ret;
1857     }
1858 
1859     // check vp case
1860     index = str.find("vp");
1861     if (index != std::string::npos) {
1862         std::string result = str.substr(0, index);
1863         ret = StringUtils::StringToDouble(result);
1864         ret = ret * density_;
1865         return ret;
1866     }
1867 
1868     // check rem case
1869     index = str.find("rem");
1870     if (index != std::string::npos) {
1871         std::string result = str.substr(0, index);
1872         ret = StringUtils::StringToDouble(result);
1873         ret = ret * PX2REM_NUM;
1874         return ret;
1875     }
1876 
1877     ret = StringUtils::StringToDouble(str);
1878     return ret * density_;
1879 }
1880 
PercentStrToFloat(const std::string & percentStr)1881 float CustomPaintPaintMethod::PercentStrToFloat(const std::string& percentStr)
1882 {
1883     std::string percentage = percentStr;
1884     bool hasPercent = IsPercentStr(percentage);
1885     float percentNum = 0.0f;
1886     percentNum = StringUtils::StringToFloat(percentage);
1887     if (hasPercent) {
1888         percentNum = percentNum / 100;
1889     }
1890     return percentNum;
1891 }
1892 
CheckNumberAndPercentage(const std::string & param,bool isClamped,float & result)1893 bool CustomPaintPaintMethod::CheckNumberAndPercentage(const std::string& param, bool isClamped, float& result)
1894 {
1895     // param.size() == 1, param[0] != 0 ~ 9, return false
1896     if (param.size() == 1 && (param[0] < '0' || param[0] > '9')) {
1897         return false;
1898     }
1899     CHECK_EQUAL_RETURN(param.size(), 0, false);
1900     // param.size() > 1, param[i] != (. || 0 ~ 9), return false (except for the last one)
1901     for (auto i = 0U; i < param.size() - 1; i++) {
1902         if (param[i] < '.' || param[i] == '/' || param[i] > '9') {
1903             return false;
1904         }
1905     }
1906     result = PercentStrToFloat(param);
1907     if (Negative(result)) {
1908         return false;
1909     }
1910     if (isClamped && GreatNotEqual(result, 1.0f)) {
1911         result = 1.0f;
1912     }
1913     return true;
1914 }
1915 
FilterStrToFilterType(const std::string & filterStr)1916 FilterType CustomPaintPaintMethod::FilterStrToFilterType(const std::string& filterStr)
1917 {
1918     const LinearMapNode<FilterType> filterTypeTable[] = {
1919         { "blur", FilterType::BLUR },
1920         { "brightness", FilterType::BRIGHTNESS },
1921         { "contrast", FilterType::CONTRAST },
1922         { "drop-shadow", FilterType::DROP_SHADOW },
1923         { "grayscale", FilterType::GRAYSCALE },
1924         { "hue-rotate", FilterType::HUE_ROTATE },
1925         { "invert", FilterType::INVERT },
1926         { "none", FilterType::NONE },
1927         { "opacity", FilterType::OPACITY },
1928         { "saturate", FilterType::SATURATE },
1929         { "sepia", FilterType::SEPIA },
1930     };
1931     return ConvertStrToEnum(filterStr.c_str(), filterTypeTable, ArraySize(filterTypeTable), FilterType::NONE);
1932 }
1933 
CalcTextScale(double maxIntrinsicWidth,std::optional<double> maxWidth)1934 std::optional<double> CustomPaintPaintMethod::CalcTextScale(double maxIntrinsicWidth, std::optional<double> maxWidth)
1935 {
1936     std::optional<double> scale;
1937     if (NearZero(maxIntrinsicWidth) || !maxWidth.has_value()) {
1938         return scale;
1939     }
1940     if (Negative(maxWidth.value())) {
1941         maxWidth = 0.0f;
1942     }
1943     double maxWidthValue = maxWidth.value();
1944     if (GreatNotEqual(maxIntrinsicWidth, maxWidthValue)) {
1945         scale = maxWidthValue / maxIntrinsicWidth;
1946     }
1947     return scale;
1948 }
1949 
GetTransform() const1950 TransformParam CustomPaintPaintMethod::GetTransform() const
1951 {
1952     TransformParam param;
1953     param.scaleX = matrix_.Get(static_cast<int>(RSMatrix::Index::SCALE_X));
1954     param.scaleY = matrix_.Get(static_cast<int>(RSMatrix::Index::SCALE_Y));
1955     param.skewX = matrix_.Get(static_cast<int>(RSMatrix::Index::SKEW_X));
1956     param.skewY = matrix_.Get(static_cast<int>(RSMatrix::Index::SKEW_Y));
1957     param.translateX = matrix_.Get(static_cast<int>(RSMatrix::Index::TRANS_X));
1958     param.translateY = matrix_.Get(static_cast<int>(RSMatrix::Index::TRANS_Y));
1959     return param;
1960 }
1961 
SaveProperties()1962 void CustomPaintPaintMethod::SaveProperties()
1963 {
1964     matrixStates_.push_back(matrix_);
1965     lineDashStates_.push_back(lineDash_);
1966 }
1967 
RestoreProperties()1968 void CustomPaintPaintMethod::RestoreProperties()
1969 {
1970     if (!matrixStates_.empty()) {
1971         matrix_ = matrixStates_.back();
1972         matrixStates_.pop_back();
1973     }
1974     if (!lineDashStates_.empty()) {
1975         lineDash_ = lineDashStates_.back();
1976         lineDashStates_.pop_back();
1977     }
1978 }
1979 
ResetTransformMatrix()1980 void CustomPaintPaintMethod::ResetTransformMatrix()
1981 {
1982     matrix_.Reset();
1983 }
1984 
ResetLineDash()1985 void CustomPaintPaintMethod::ResetLineDash()
1986 {
1987     std::vector<double>().swap(lineDash_.lineDash);
1988     lineDash_.dashOffset = 0.0;
1989 }
1990 
RotateMatrix(double angle)1991 void CustomPaintPaintMethod::RotateMatrix(double angle)
1992 {
1993     RSMatrix matrix;
1994     matrix.Rotate(angle * HALF_CIRCLE_ANGLE / ACE_PI, 0, 0);
1995     matrix_.PreConcat(matrix);
1996 }
1997 
ScaleMatrix(double sx,double sy)1998 void CustomPaintPaintMethod::ScaleMatrix(double sx, double sy)
1999 {
2000     RSMatrix matrix;
2001     matrix.SetScale(sx, sy);
2002     matrix_.PreConcat(matrix);
2003 }
2004 
SetTransformMatrix(const TransformParam & param)2005 void CustomPaintPaintMethod::SetTransformMatrix(const TransformParam& param)
2006 {
2007     matrix_.SetMatrix(
2008         param.scaleX, param.skewX, param.translateX, param.skewY, param.scaleY, param.translateY, 0, 0, 1);
2009 }
2010 
TransformMatrix(const TransformParam & param)2011 void CustomPaintPaintMethod::TransformMatrix(const TransformParam& param)
2012 {
2013     RSMatrix matrix;
2014     matrix.SetMatrix(param.scaleX, param.skewY, param.translateX, param.skewX, param.scaleY, param.translateY, 0, 0, 1);
2015     matrix_.PreConcat(matrix);
2016 }
2017 
TranslateMatrix(double tx,double ty)2018 void CustomPaintPaintMethod::TranslateMatrix(double tx, double ty)
2019 {
2020     if (tx || ty) {
2021         matrix_.PreTranslate(tx, ty);
2022     }
2023 }
2024 
SaveLayer()2025 void CustomPaintPaintMethod::SaveLayer()
2026 {
2027     CHECK_NULL_VOID(rsCanvas_);
2028     RSBrush compositeOperationpBrush;
2029     InitPaintBlend(compositeOperationpBrush);
2030     RSSaveLayerOps slo(nullptr, &compositeOperationpBrush);
2031     rsCanvas_->SaveLayer(slo);
2032 }
2033 
RestoreLayer()2034 void CustomPaintPaintMethod::RestoreLayer()
2035 {
2036     CHECK_NULL_VOID(rsCanvas_);
2037     rsCanvas_->Restore();
2038 }
2039 
ResetStates()2040 void CustomPaintPaintMethod::ResetStates()
2041 {
2042     smoothingEnabled_ = true;
2043     smoothingQuality_ = "low";
2044     state_.fillState = PaintState();
2045     state_.strokeState = StrokePaintState();
2046     state_.globalState = GlobalPaintState();
2047     // Reset Text Direction
2048     state_.fillState.SetOffTextDirection(GetSystemDirection());
2049     // The default value of the font size in canvas is 14px.
2050     SetFontSize(DEFAULT_FONT_SIZE);
2051     state_.shadow = Shadow();
2052     imageBrush_ = RSBrush();
2053     rsPath_.Reset();
2054     rsPath2d_.Reset();
2055     std::vector<PaintHolder>().swap(saveStates_);
2056     std::vector<RSMatrix>().swap(matrixStates_);
2057     std::vector<LineDashParam>().swap(lineDashStates_);
2058     std::vector<std::shared_ptr<RSColorFilter>>().swap(saveColorFilter_);
2059     std::vector<std::shared_ptr<RSImageFilter>>().swap(saveBlurFilter_);
2060     colorMatrix_ = RSColorMatrix();
2061     colorFilter_ = RSColorFilter::CreateMatrixColorFilter(colorMatrix_);
2062     blurFilter_ = RSImageFilter::CreateBlurImageFilter(0, 0, RSTileMode::DECAL, nullptr);
2063     if (apiVersion_ >= static_cast<int32_t>(PlatformVersion::VERSION_EIGHTEEN)) {
2064         isPathChanged_ = false;
2065         isPath2dChanged_ = false;
2066     }
2067 }
2068 
PaintShadow(const RSPath & path,const Shadow & shadow,const RSBrush * brush,const RSPen * pen,RSSaveLayerOps * slo)2069 void CustomPaintPaintMethod::PaintShadow(
2070     const RSPath& path, const Shadow& shadow, const RSBrush* brush, const RSPen* pen, RSSaveLayerOps* slo)
2071 {
2072 #ifndef ACE_UNITTEST
2073     CHECK_NULL_VOID(rsCanvas_);
2074     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) && slo != nullptr) {
2075         rsCanvas_->SaveLayer(*slo);
2076         RosenDecorationPainter::PaintShadow(path, shadow, rsCanvas_.get(), brush, pen);
2077         rsCanvas_->Restore();
2078     } else {
2079         RosenDecorationPainter::PaintShadow(path, shadow, rsCanvas_.get(), brush, pen);
2080     }
2081 #endif
2082 }
2083 
PaintImageShadow(const RSPath & path,const Shadow & shadow,const RSBrush * brush,const RSPen * pen,RSSaveLayerOps * slo)2084 void CustomPaintPaintMethod::PaintImageShadow(
2085     const RSPath& path, const Shadow& shadow, const RSBrush* brush, const RSPen* pen, RSSaveLayerOps* slo)
2086 {
2087 #ifndef ACE_UNITTEST
2088     CHECK_NULL_VOID(rsCanvas_);
2089     RosenDecorationPainter::PaintShadow(path, shadow, rsCanvas_.get(), brush, pen);
2090     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) && slo != nullptr) {
2091         rsCanvas_->Restore();
2092         rsCanvas_->SaveLayer(*slo);
2093     }
2094 #endif
2095 }
2096 
Path2DRect(const PathArgs & args)2097 void CustomPaintPaintMethod::Path2DRect(const PathArgs& args)
2098 {
2099     rsPath2d_.AddRect(RSRect(args.para1, args.para2, args.para3 + args.para1, args.para4 + args.para2));
2100 }
2101 
Path2DRoundRect(const PathArgs & args)2102 void CustomPaintPaintMethod::Path2DRoundRect(const PathArgs& args)
2103 {
2104     RSRect rsRect(args.para1, args.para2, args.para3 + args.para1, args.para4 + args.para2);
2105     std::vector<RSPoint> radiusXY = {
2106         RSPoint(args.para5, args.para5), RSPoint(args.para6, args.para6),
2107         RSPoint(args.para7, args.para7), RSPoint(args.para8, args.para8)
2108     };
2109     RSRoundRect rsRoundRect(rsRect, radiusXY);
2110     rsPath2d_.AddRoundRect(rsRoundRect, RSPathDirection::CCW_DIRECTION);
2111     isPath2dChanged_ = true;
2112 }
2113 
SetTransform(const TransformParam & param)2114 void CustomPaintPaintMethod::SetTransform(const TransformParam& param)
2115 {
2116     CHECK_NULL_VOID(rsCanvas_);
2117     RSMatrix rsMatrix;
2118     rsMatrix.SetMatrix(
2119         param.scaleX, param.skewX, param.translateX, param.skewY, param.scaleY, param.translateY, 0, 0, 1);
2120     rsCanvas_->SetMatrix(rsMatrix);
2121 }
2122 
MeasureTextMetrics(const std::string & text,const PaintState & state)2123 TextMetrics CustomPaintPaintMethod::MeasureTextMetrics(const std::string& text, const PaintState& state)
2124 {
2125 #ifndef ACE_UNITTEST
2126     TextMetrics textMetrics;
2127     RSParagraphStyle style;
2128     style.textAlign = Constants::ConvertTxtTextAlign(state.GetTextAlign());
2129     auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
2130     CHECK_NULL_RETURN(fontCollection, textMetrics);
2131     std::unique_ptr<RSParagraphBuilder> builder = RSParagraphBuilder::Create(style, fontCollection);
2132     RSTextStyle txtStyle;
2133     ConvertTxtStyle(state.GetTextStyle(), txtStyle);
2134     txtStyle.fontSize = state.GetTextStyle().GetFontSize().Value();
2135     builder->PushStyle(txtStyle);
2136     builder->AppendText(StringUtils::Str8ToStr16(text));
2137 
2138     auto paragraph = builder->CreateTypography();
2139     paragraph->Layout(Size::INFINITE_SIZE);
2140     /**
2141      * @brief reference: https://html.spec.whatwg.org/multipage/canvas.html#dom-textmetrics-alphabeticbaseline
2142      *
2143      */
2144     auto fontMetrics = paragraph->MeasureText();
2145     auto glyphsBoundsTop = paragraph->GetGlyphsBoundsTop();
2146     auto glyphsBoundsBottom = paragraph->GetGlyphsBoundsBottom();
2147     auto glyphsBoundsLeft = paragraph->GetGlyphsBoundsLeft();
2148     auto glyphsBoundsRight = paragraph->GetGlyphsBoundsRight();
2149     auto textAlign = state.GetTextAlign();
2150     auto textBaseLine = state.GetTextStyle().GetTextBaseline();
2151     const double baseLineY = GetFontBaseline(fontMetrics, textBaseLine);
2152     const double baseLineX = GetFontAlign(textAlign, paragraph);
2153 
2154     textMetrics.width = paragraph->GetMaxIntrinsicWidth();
2155     textMetrics.height = paragraph->GetHeight();
2156     textMetrics.actualBoundingBoxAscent = baseLineY - glyphsBoundsTop;
2157     textMetrics.actualBoundingBoxDescent = glyphsBoundsBottom - baseLineY;
2158     textMetrics.actualBoundingBoxLeft = baseLineX - glyphsBoundsLeft;
2159     textMetrics.actualBoundingBoxRight = glyphsBoundsRight - baseLineX;
2160     textMetrics.alphabeticBaseline = baseLineY;
2161     textMetrics.ideographicBaseline = baseLineY - fontMetrics.fDescent;
2162     textMetrics.fontBoundingBoxAscent = baseLineY - fontMetrics.fTop;
2163     textMetrics.fontBoundingBoxDescent = fontMetrics.fBottom - baseLineY;
2164     textMetrics.hangingBaseline = baseLineY - (HANGING_PERCENT * fontMetrics.fAscent);
2165     textMetrics.emHeightAscent = baseLineY - fontMetrics.fAscent;
2166     textMetrics.emHeightDescent = fontMetrics.fDescent - baseLineY;
2167     return textMetrics;
2168 #else
2169     return TextMetrics {};
2170 #endif
2171 }
2172 
UpdateFillParagraph(const std::string & text)2173 bool CustomPaintPaintMethod::UpdateFillParagraph(const std::string& text)
2174 {
2175 #ifndef ACE_UNITTEST
2176     RSParagraphStyle style;
2177     TextAlign textAlign = state_.fillState.GetTextAlign();
2178     style.textAlign = Constants::ConvertTxtTextAlign(textAlign);
2179     style.textDirection = Constants::ConvertTxtTextDirection(state_.fillState.GetOffTextDirection());
2180     style.textAlign = GetEffectiveAlign(style.textAlign, style.textDirection);
2181     auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
2182     CHECK_NULL_RETURN(fontCollection, false);
2183     std::unique_ptr<RSParagraphBuilder> builder = RSParagraphBuilder::Create(style, fontCollection);
2184     CHECK_NULL_RETURN(builder, false);
2185     RSTextStyle txtStyle;
2186     if (HasShadow()) {
2187         Rosen::TextShadow txtShadow;
2188         txtShadow.color = state_.shadow.GetColor().GetValue();
2189         txtShadow.offset.SetX(state_.shadow.GetOffset().GetX());
2190         txtShadow.offset.SetY(state_.shadow.GetOffset().GetY());
2191         txtShadow.blurRadius = state_.shadow.GetBlurRadius();
2192         txtStyle.shadows.emplace_back(txtShadow);
2193     }
2194     txtStyle.locale = Localization::GetInstance()->GetFontLocale();
2195     UpdateFontFamilies();
2196     txtStyle.fontSize = state_.fillState.GetTextStyle().GetFontSize().Value();
2197     ConvertTxtStyle(state_.fillState.GetTextStyle(), txtStyle);
2198     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_THIRTEEN)) {
2199         RSBrush brush;
2200         RSSamplingOptions options;
2201         GetFillPaint(brush, options);
2202         InitPaintBlend(brush);
2203         txtStyle.foregroundBrush = brush;
2204     } else {
2205         UpdateFillTxtStyle(txtStyle);
2206     }
2207     builder->PushStyle(txtStyle);
2208     builder->AppendText(StringUtils::Str8ToStr16(text));
2209     paragraph_ = builder->CreateTypography();
2210     return true;
2211 #else
2212     return false;
2213 #endif
2214 }
2215 
UpdateFillTxtStyle(RSTextStyle & txtStyle)2216 void CustomPaintPaintMethod::UpdateFillTxtStyle(RSTextStyle& txtStyle)
2217 {
2218 #ifndef ACE_UNITTEST
2219     txtStyle.color = Constants::ConvertSkColor(state_.fillState.GetColor());
2220     RSBrush brush;
2221     RSSamplingOptions options;
2222     InitImagePaint(nullptr, &brush, options);
2223     if (state_.fillState.GetGradient().IsValid() && state_.fillState.GetPaintStyle() == PaintStyle::Gradient) {
2224         UpdatePaintShader(nullptr, &brush, state_.fillState.GetGradient());
2225         txtStyle.foregroundBrush = brush;
2226     }
2227     if (state_.globalState.HasGlobalAlpha()) {
2228         if (txtStyle.foregroundBrush.has_value()) {
2229             txtStyle.foregroundBrush->SetColor(state_.fillState.GetColor().GetValue());
2230             txtStyle.foregroundBrush->SetAlphaF(state_.globalState.GetAlpha()); // set alpha after color
2231         } else {
2232             brush.SetColor(state_.fillState.GetColor().GetValue());
2233             brush.SetAlphaF(state_.globalState.GetAlpha()); // set alpha after color
2234             InitPaintBlend(brush);
2235             txtStyle.foregroundBrush = brush;
2236         }
2237     }
2238 #endif
2239 }
2240 
UpdateStrokeParagraph(const std::string & text)2241 bool CustomPaintPaintMethod::UpdateStrokeParagraph(const std::string& text)
2242 {
2243 #ifndef ACE_UNITTEST
2244     RSParagraphStyle style;
2245     TextAlign textAlign = state_.strokeState.GetTextAlign();
2246     style.textAlign = Constants::ConvertTxtTextAlign(textAlign);
2247     style.textDirection = Constants::ConvertTxtTextDirection(state_.fillState.GetOffTextDirection());
2248     style.textAlign = GetEffectiveAlign(style.textAlign, style.textDirection);
2249     auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
2250     CHECK_NULL_RETURN(fontCollection, false);
2251     std::unique_ptr<RSParagraphBuilder> builder = RSParagraphBuilder::Create(style, fontCollection);
2252     CHECK_NULL_RETURN(builder, false);
2253     RSTextStyle txtStyle;
2254     txtStyle.locale = Localization::GetInstance()->GetFontLocale();
2255     UpdateFontFamilies();
2256     RSPen pen;
2257     RSSamplingOptions options;
2258     GetStrokePaint(pen, options);
2259     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_THIRTEEN)) {
2260         InitPaintBlend(pen);
2261     }
2262     ConvertTxtStyle(state_.strokeState.GetTextStyle(), txtStyle);
2263     txtStyle.fontSize = state_.strokeState.GetTextStyle().GetFontSize().Value();
2264     txtStyle.foregroundPen = pen;
2265     builder->PushStyle(txtStyle);
2266     builder->AppendText(StringUtils::Str8ToStr16(text));
2267     paragraph_ = builder->CreateTypography();
2268     if (HasShadow()) {
2269         UpdateStrokeShadowParagraph(text, &pen, style);
2270     }
2271     return true;
2272 #else
2273     return false;
2274 #endif
2275 }
2276 
UpdateStrokeShadowParagraph(const std::string & text,const RSPen * pen,const RSParagraphStyle & style)2277 void CustomPaintPaintMethod::UpdateStrokeShadowParagraph(
2278     const std::string& text, const RSPen* pen, const RSParagraphStyle& style)
2279 {
2280 #ifndef ACE_UNITTEST
2281     auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
2282     CHECK_NULL_VOID(fontCollection);
2283     RSTextStyle shadowStyle;
2284     shadowStyle.locale = Localization::GetInstance()->GetFontLocale();
2285     UpdateFontFamilies();
2286     ConvertTxtStyle(state_.strokeState.GetTextStyle(), shadowStyle);
2287     shadowStyle.fontSize = state_.strokeState.GetTextStyle().GetFontSize().Value();
2288     RSPen shadowPen;
2289     shadowPen.SetColor(state_.shadow.GetColor().GetValue());
2290     shadowPen.SetAntiAlias(true);
2291     shadowPen.SetWidth(pen->GetWidth());
2292     shadowPen.SetMiterLimit(pen->GetMiterLimit());
2293     shadowPen.SetCapStyle(pen->GetCapStyle());
2294     shadowPen.SetJoinStyle(pen->GetJoinStyle());
2295     if (state_.globalState.HasGlobalAlpha()) {
2296         shadowPen.SetAlphaF(
2297             state_.globalState.GetAlpha() * static_cast<double>(state_.shadow.GetColor().GetValue()) / MAX_GRAYSCALE);
2298     }
2299     RSFilter filter;
2300     filter.SetMaskFilter(RSMaskFilter::CreateBlurMaskFilter(
2301         RSBlurType::NORMAL, RosenDecorationPainter::ConvertRadiusToSigma(state_.shadow.GetBlurRadius())));
2302     shadowPen.SetFilter(filter);
2303     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_THIRTEEN)) {
2304         InitPaintBlend(shadowPen);
2305     }
2306     shadowStyle.foregroundPen = shadowPen;
2307     std::unique_ptr<RSParagraphBuilder> shadowBuilder = RSParagraphBuilder::Create(style, fontCollection);
2308     CHECK_NULL_VOID(shadowBuilder);
2309     shadowBuilder->PushStyle(shadowStyle);
2310     shadowBuilder->AppendText(StringUtils::Str8ToStr16(text));
2311     shadowParagraph_ = shadowBuilder->CreateTypography();
2312 #endif
2313 }
2314 
SetTransform(std::shared_ptr<Ace::Pattern> pattern,const TransformParam & transform)2315 void CustomPaintPaintMethod::SetTransform(std::shared_ptr<Ace::Pattern> pattern, const TransformParam& transform)
2316 {
2317     pattern->SetScaleX(transform.scaleX);
2318     pattern->SetScaleY(transform.scaleY);
2319     pattern->SetSkewX(transform.skewX);
2320     pattern->SetSkewY(transform.skewY);
2321     pattern->SetTranslateX(transform.translateX);
2322     pattern->SetTranslateY(transform.translateY);
2323 }
2324 } // namespace OHOS::Ace::NG
2325