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