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