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