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