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