1 /*
2 * Copyright (c) 2021-2023 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/custom_paint/rosen_render_custom_paint.h"
17
18 #include <cmath>
19
20 #include "flutter/lib/ui/text/font_collection.h"
21 #include "flutter/third_party/txt/src/txt/paragraph_builder.h"
22 #include "flutter/third_party/txt/src/txt/paragraph_style.h"
23 #include "flutter/third_party/txt/src/txt/paragraph_txt.h"
24 #include "render_service_client/core/ui/rs_node.h"
25 #include "third_party/bounds_checking_function/include/securec.h"
26 #include "third_party/skia/include/core/SkBlendMode.h"
27 #include "third_party/skia/include/core/SkCanvas.h"
28 #include "third_party/skia/include/core/SkColor.h"
29 #include "third_party/skia/include/core/SkImage.h"
30 #include "third_party/skia/include/core/SkMaskFilter.h"
31 #include "third_party/skia/include/core/SkPoint.h"
32 #include "third_party/skia/include/core/SkSurface.h"
33 #include "third_party/skia/include/effects/SkDashPathEffect.h"
34 #include "third_party/skia/include/effects/SkGradientShader.h"
35 #include "third_party/skia/include/encode/SkJpegEncoder.h"
36 #include "third_party/skia/include/encode/SkPngEncoder.h"
37 #include "third_party/skia/include/encode/SkWebpEncoder.h"
38 #include "third_party/skia/include/utils/SkBase64.h"
39 #include "third_party/skia/include/utils/SkParsePath.h"
40
41 #include "base/geometry/dimension.h"
42 #include "base/i18n/localization.h"
43 #include "base/image/pixel_map.h"
44 #include "base/json/json_util.h"
45 #include "base/log/ace_trace.h"
46 #include "base/utils/linear_map.h"
47 #include "base/utils/measure_util.h"
48 #include "base/utils/string_utils.h"
49 #include "base/utils/utils.h"
50 #include "bridge/common/utils/utils.h"
51 #include "core/components/calendar/rosen_render_calendar.h"
52 #include "core/components/common/painter/rosen_decoration_painter.h"
53 #include "core/components/font/constants_converter.h"
54 #include "core/components/font/rosen_font_collection.h"
55 #include "core/components/text/text_theme.h"
56 #include "core/image/flutter_image_cache.h"
57 #include "core/image/image_cache.h"
58 #include "core/image/image_provider.h"
59 #include "core/pipeline/base/rosen_render_context.h"
60
61 #ifdef CANVAS_USE_GPU
62 #include "core/common/graphic/environment_gl.h"
63 #endif
64
65 namespace OHOS::Ace {
66 namespace {
67
68 constexpr double HANGING_PERCENT = 0.8;
69 constexpr double HALF_CIRCLE_ANGLE = 180.0;
70 constexpr double FULL_CIRCLE_ANGLE = 360.0;
71 constexpr int32_t IMAGE_CACHE_COUNT = 50;
72 #ifdef CANVAS_USE_GPU
73 constexpr int32_t UNREF_OBJECT_DELAY = 100;
74 #endif
75
76 constexpr double DEFAULT_QUALITY = 0.92;
77 constexpr int32_t MAX_LENGTH = 2048 * 2048;
78 const std::string UNSUPPORTED = "data:image/png";
79 const std::string URL_PREFIX = "data:";
80 const std::string URL_SYMBOL = ";base64,";
81 const std::string IMAGE_PNG = "image/png";
82 const std::string IMAGE_JPEG = "image/jpeg";
83 const std::string IMAGE_WEBP = "image/webp";
84 const std::u16string ELLIPSIS = u"\u2026";
85
86 // If args is empty or invalid format, use default: image/png
GetMimeType(const std::string & args)87 std::string GetMimeType(const std::string& args)
88 {
89 // Args example: ["image/png"]
90 std::vector<std::string> values;
91 StringUtils::StringSplitter(args, '"', values);
92 if (values.size() < 3) {
93 return IMAGE_PNG;
94 } else {
95 // Convert to lowercase string.
96 for (size_t i = 0; i < values[1].size(); ++i) {
97 values[1][i] = static_cast<uint8_t>(tolower(values[1][i]));
98 }
99 return values[1];
100 }
101 }
102
103 // Quality need between 0.0 and 1.0 for MimeType jpeg and webp
GetQuality(const std::string & args)104 double GetQuality(const std::string& args)
105 {
106 // Args example: ["image/jpeg", 0.8]
107 std::vector<std::string> values;
108 StringUtils::StringSplitter(args, ',', values);
109 if (values.size() < 2) {
110 return DEFAULT_QUALITY;
111 }
112 auto mimeType = GetMimeType(args);
113 if (mimeType != IMAGE_JPEG && mimeType != IMAGE_WEBP) {
114 return DEFAULT_QUALITY;
115 }
116 double quality = StringUtils::StringToDouble(values[1]);
117 if (quality < 0.0 || quality > 1.0) {
118 return DEFAULT_QUALITY;
119 }
120 return quality;
121 }
122
123 template<typename T, typename N>
ConvertEnumToSkEnum(T key,const LinearEnumMapNode<T,N> * map,size_t length,N defaultValue)124 N ConvertEnumToSkEnum(T key, const LinearEnumMapNode<T, N>* map, size_t length, N defaultValue)
125 {
126 int64_t index = BinarySearchFindIndex(map, length, key);
127 return index != -1 ? map[index].value : defaultValue;
128 }
129
130 const LinearEnumMapNode<CompositeOperation, SkBlendMode> SK_BLEND_MODE_TABLE[] = {
131 { CompositeOperation::SOURCE_OVER, SkBlendMode::kSrcOver },
132 { CompositeOperation::SOURCE_ATOP, SkBlendMode::kSrcATop },
133 { CompositeOperation::SOURCE_IN, SkBlendMode::kSrcIn },
134 { CompositeOperation::SOURCE_OUT, SkBlendMode::kSrcOut },
135 { CompositeOperation::DESTINATION_OVER, SkBlendMode::kDstOver },
136 { CompositeOperation::DESTINATION_ATOP, SkBlendMode::kDstATop },
137 { CompositeOperation::DESTINATION_IN, SkBlendMode::kDstIn },
138 { CompositeOperation::DESTINATION_OUT, SkBlendMode::kDstOut },
139 { CompositeOperation::LIGHTER, SkBlendMode::kLighten },
140 { CompositeOperation::COPY, SkBlendMode::kSrc },
141 { CompositeOperation::XOR, SkBlendMode::kXor },
142 };
143 constexpr size_t BLEND_MODE_SIZE = ArraySize(SK_BLEND_MODE_TABLE);
144
145 } // namespace
146
RosenRenderCustomPaint()147 RosenRenderCustomPaint::RosenRenderCustomPaint()
148 {
149 auto currentDartState = flutter::UIDartState::Current();
150 if (!currentDartState) {
151 return;
152 }
153
154 renderTaskHolder_ = MakeRefPtr<FlutterRenderTaskHolder>(currentDartState->GetSkiaUnrefQueue(),
155 currentDartState->GetIOManager(), currentDartState->GetTaskRunners().GetIOTaskRunner());
156
157 InitImageCallbacks();
158 }
159
~RosenRenderCustomPaint()160 RosenRenderCustomPaint::~RosenRenderCustomPaint()
161 {
162 #ifdef CANVAS_USE_GPU
163 auto pipeline = context_.Upgrade();
164 if (!pipeline) {
165 return;
166 }
167 pipeline->PostTaskToRT([this]() { environment_ = nullptr; });
168 #endif
169 }
170
171 #ifdef CANVAS_USE_GPU
InitializeEglContext()172 void RosenRenderCustomPaint::InitializeEglContext()
173 {
174 ACE_SCOPED_TRACE("InitializeEglContext");
175 if (environment_) {
176 return;
177 }
178 environment_ = EnvironmentGL::GetCurrent();
179 if (environment_) {
180 return;
181 }
182 auto pipeline = context_.Upgrade();
183 if (!pipeline) {
184 return;
185 }
186 pipeline->PostTaskToRT([this]() { environment_ = EnvironmentGL::MakeSharedGLContext(); });
187 if (!environment_) {
188 LOGE("Make shared GLContext failed.");
189 return;
190 }
191 environment_->MakeCurrent();
192 environment_->MakeGrContext();
193 }
194 #endif
195
CreateSurface(double viewScale)196 bool RosenRenderCustomPaint::CreateSurface(double viewScale)
197 {
198 #ifdef CANVAS_USE_GPU
199 InitializeEglContext();
200 if (!environment_) {
201 return false;
202 }
203 auto grContext = environment_->GetGrContext();
204 if (!grContext) {
205 LOGE("grContext_ is nullptr.");
206 return false;
207 }
208 auto imageInfo = SkImageInfo::MakeN32(GetLayoutSize().Width() * viewScale, GetLayoutSize().Height() * viewScale,
209 kOpaque_SkAlphaType, SkColorSpace::MakeSRGB());
210
211 const SkSurfaceProps surfaceProps(SkSurfaceProps::InitType::kLegacyFontHost_InitType);
212 surface_ = SkSurface::MakeRenderTarget(
213 grContext.get(), SkBudgeted::kNo, imageInfo, 0, kBottomLeft_GrSurfaceOrigin, &surfaceProps);
214 if (!surface_) {
215 LOGE("surface_ is nullptr");
216 return false;
217 }
218 skCanvas_ = std::unique_ptr<SkCanvas>(surface_->getCanvas());
219 lastLayoutSize_ = GetLayoutSize();
220 skCanvas_->drawColor(0x0);
221
222 auto imageInfo = SkImageInfo::Make(GetLayoutSize().Width() * viewScale, GetLayoutSize().Height() * viewScale,
223 SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kUnpremul_SkAlphaType);
224 cacheBitmap_.reset();
225 cacheBitmap_.allocPixels(imageInfo);
226 cacheBitmap_.eraseColor(SK_ColorTRANSPARENT);
227 cacheCanvas_ = std::make_unique<SkCanvas>(cacheBitmap_);
228 return true;
229 #else
230 return false;
231 #endif
232 }
233
CreateBitmap(double viewScale)234 void RosenRenderCustomPaint::CreateBitmap(double viewScale)
235 {
236 auto imageInfo = SkImageInfo::Make(GetLayoutSize().Width() * viewScale, GetLayoutSize().Height() * viewScale,
237 SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kUnpremul_SkAlphaType);
238 canvasCache_.reset();
239 cacheBitmap_.reset();
240 canvasCache_.allocPixels(imageInfo);
241 cacheBitmap_.allocPixels(imageInfo);
242 canvasCache_.eraseColor(SK_ColorTRANSPARENT);
243 cacheBitmap_.eraseColor(SK_ColorTRANSPARENT);
244 skCanvas_ = std::make_unique<SkCanvas>(canvasCache_);
245 cacheCanvas_ = std::make_unique<SkCanvas>(cacheBitmap_);
246 }
247
Paint(RenderContext & context,const Offset & offset)248 void RosenRenderCustomPaint::Paint(RenderContext& context, const Offset& offset)
249 {
250 ACE_SCOPED_TRACE("RosenRenderCustomPaint::Paint");
251 auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas();
252 if (auto rsNode = static_cast<RosenRenderContext*>(&context)->GetRSNode()) {
253 rsNode->SetClipToFrame(true);
254 }
255 if (!canvas) {
256 return;
257 }
258 auto pipeline = context_.Upgrade();
259 if (!pipeline) {
260 return;
261 }
262 // use physical pixel to store bitmap
263 double viewScale = pipeline->GetViewScale();
264 if (lastLayoutSize_ != GetLayoutSize()) {
265 if (GetLayoutSize().IsInfinite()) {
266 return;
267 }
268 if (!CreateSurface(viewScale)) {
269 CreateBitmap(viewScale);
270 }
271 lastLayoutSize_ = GetLayoutSize();
272 }
273 if (!skCanvas_) {
274 LOGE("skCanvas_ is null");
275 return;
276 }
277 skCanvas_->scale(viewScale, viewScale);
278 TriggerOnReadyEvent();
279
280 for (const auto& task : tasks_) {
281 task(*this, offset);
282 }
283 skCanvas_->scale(1.0 / viewScale, 1.0 / viewScale);
284 tasks_.clear();
285
286 canvas->save();
287 canvas->scale(1.0 / viewScale, 1.0 / viewScale);
288 #ifdef CANVAS_USE_GPU
289 if (surface_) {
290 ACE_SCOPED_TRACE("surface draw");
291 surface_->flush(SkSurface::BackendSurfaceAccess::kNoAccess, { .fFlags = kSyncCpu_GrFlushFlag });
292 auto image = surface_->makeImageSnapshot();
293 if (!image) {
294 return;
295 }
296 canvas->drawImage(image, 0, 0, nullptr);
297 pipeline->GetTaskExecutor()->PostDelayedTask([image] {}, TaskExecutor::TaskType::UI, UNREF_OBJECT_DELAY);
298 } else {
299 canvas->drawBitmap(canvasCache_, 0.0f, 0.0f);
300 }
301 #else
302 canvas->drawBitmap(canvasCache_, 0.0f, 0.0f);
303 #endif
304 canvas->restore();
305 }
306
GetStrokePaint()307 SkPaint RosenRenderCustomPaint::GetStrokePaint()
308 {
309 static const LinearEnumMapNode<LineJoinStyle, SkPaint::Join> skLineJoinTable[] = {
310 { LineJoinStyle::MITER, SkPaint::Join::kMiter_Join },
311 { LineJoinStyle::ROUND, SkPaint::Join::kRound_Join },
312 { LineJoinStyle::BEVEL, SkPaint::Join::kBevel_Join },
313 };
314 static const LinearEnumMapNode<LineCapStyle, SkPaint::Cap> skLineCapTable[] = {
315 { LineCapStyle::BUTT, SkPaint::Cap::kButt_Cap },
316 { LineCapStyle::ROUND, SkPaint::Cap::kRound_Cap },
317 { LineCapStyle::SQUARE, SkPaint::Cap::kSquare_Cap },
318 };
319 SkPaint paint;
320 paint.setColor(strokeState_.GetColor().GetValue());
321 paint.setStyle(SkPaint::Style::kStroke_Style);
322 paint.setStrokeJoin(ConvertEnumToSkEnum(
323 strokeState_.GetLineJoin(), skLineJoinTable, ArraySize(skLineJoinTable), SkPaint::Join::kMiter_Join));
324 paint.setStrokeCap(ConvertEnumToSkEnum(
325 strokeState_.GetLineCap(), skLineCapTable, ArraySize(skLineCapTable), SkPaint::Cap::kButt_Cap));
326 paint.setStrokeWidth(static_cast<SkScalar>(strokeState_.GetLineWidth()));
327 paint.setStrokeMiter(static_cast<SkScalar>(strokeState_.GetMiterLimit()));
328
329 // set line Dash
330 UpdateLineDash(paint);
331
332 // set global alpha
333 if (globalState_.HasGlobalAlpha()) {
334 paint.setAlphaf(globalState_.GetAlpha());
335 }
336 return paint;
337 }
338
ToDataURL(const std::string & args)339 std::string RosenRenderCustomPaint::ToDataURL(const std::string& args)
340 {
341 std::string mimeType = GetMimeType(args);
342 double quality = GetQuality(args);
343 double width = GetLayoutSize().Width();
344 double height = GetLayoutSize().Height();
345 SkBitmap tempCache;
346 tempCache.allocPixels(SkImageInfo::Make(width, height, SkColorType::kBGRA_8888_SkColorType,
347 (mimeType == IMAGE_JPEG) ? SkAlphaType::kOpaque_SkAlphaType : SkAlphaType::kUnpremul_SkAlphaType));
348 bool isGpuEnable = false;
349 bool success = false;
350 #ifdef CANVAS_USE_GPU
351 if (surface_) {
352 isGpuEnable = true;
353 auto pipeline = context_.Upgrade();
354 if (!pipeline) {
355 return UNSUPPORTED;
356 }
357 double viewScale = pipeline->GetViewScale();
358 SkBitmap bitmap;
359 auto imageInfo = SkImageInfo::Make(lastLayoutSize_.Width() * viewScale, lastLayoutSize_.Height() * viewScale,
360 SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kUnpremul_SkAlphaType);
361 bitmap.allocPixels(imageInfo);
362 if (!surface_->readPixels(bitmap, 0, 0)) {
363 LOGE("surface readPixels failed when ToDataURL.");
364 return UNSUPPORTED;
365 }
366 success = bitmap.pixmap().scalePixels(tempCache.pixmap(), SkFilterQuality::kHigh_SkFilterQuality);
367 if (!success) {
368 LOGE("scalePixels failed when ToDataURL.");
369 return UNSUPPORTED;
370 }
371 }
372 #endif
373 if (!isGpuEnable) {
374 if (canvasCache_.empty()) {
375 LOGE("Bitmap is empty");
376 return UNSUPPORTED;
377 }
378
379 success = canvasCache_.pixmap().scalePixels(tempCache.pixmap(), SkFilterQuality::kHigh_SkFilterQuality);
380 if (!success) {
381 LOGE("scalePixels failed when ToDataURL.");
382 return UNSUPPORTED;
383 }
384 }
385 SkPixmap src = tempCache.pixmap();
386 SkDynamicMemoryWStream dst;
387 if (mimeType == IMAGE_JPEG) {
388 SkJpegEncoder::Options options;
389 options.fQuality = quality * 100;
390 success = SkJpegEncoder::Encode(&dst, src, options);
391 } else if (mimeType == IMAGE_WEBP) {
392 SkWebpEncoder::Options options;
393 options.fQuality = quality * 100.0;
394 success = SkWebpEncoder::Encode(&dst, src, options);
395 } else {
396 mimeType = IMAGE_PNG;
397 SkPngEncoder::Options options;
398 success = SkPngEncoder::Encode(&dst, src, options);
399 }
400 if (!success) {
401 LOGE("Encode failed when ToDataURL.");
402 return UNSUPPORTED;
403 }
404 auto result = dst.detachAsData();
405 if (result == nullptr) {
406 LOGE("DetachAsData failed when ToDataURL.");
407 return UNSUPPORTED;
408 }
409 size_t len = SkBase64::Encode(result->data(), result->size(), nullptr);
410 if (len > MAX_LENGTH) {
411 LOGE("ToDataURL failed, image too large.");
412 return UNSUPPORTED;
413 }
414 SkString info(len);
415 SkBase64::Encode(result->data(), result->size(), info.writable_str());
416 return std::string(URL_PREFIX).append(mimeType).append(URL_SYMBOL).append(info.c_str());
417 }
418
SetAntiAlias(bool isEnabled)419 void RosenRenderCustomPaint::SetAntiAlias(bool isEnabled)
420 {
421 antiAlias_ = isEnabled;
422 }
423
TransferFromImageBitmap(const RefPtr<OffscreenCanvas> & offscreenCanvas)424 void RosenRenderCustomPaint::TransferFromImageBitmap(const RefPtr<OffscreenCanvas>& offscreenCanvas)
425 {
426 std::unique_ptr<ImageData> imageData =
427 offscreenCanvas->GetImageData(0, 0, offscreenCanvas->GetWidth(), offscreenCanvas->GetHeight());
428 ImageData* imageDataPtr = imageData.get();
429 if (imageData != nullptr) {
430 PutImageData(Offset(0, 0), *imageDataPtr);
431 }
432 }
433
FillRect(const Offset & offset,const Rect & rect)434 void RosenRenderCustomPaint::FillRect(const Offset& offset, const Rect& rect)
435 {
436 SkPaint paint;
437 paint.setAntiAlias(antiAlias_);
438 paint.setColor(fillState_.GetColor().GetValue());
439 paint.setStyle(SkPaint::Style::kFill_Style);
440 SkRect skRect = SkRect::MakeLTRB(rect.Left() + offset.GetX(), rect.Top() + offset.GetY(),
441 rect.Right() + offset.GetX(), offset.GetY() + rect.Bottom());
442 if (HasShadow()) {
443 SkPath path;
444 path.addRect(skRect);
445 RosenDecorationPainter::PaintShadow(path, shadow_, skCanvas_.get());
446 }
447 if (fillState_.GetGradient().IsValid()) {
448 UpdatePaintShader(offset, paint, fillState_.GetGradient());
449 }
450 if (fillState_.GetPattern().IsValid()) {
451 UpdatePaintShader(fillState_.GetPattern(), paint);
452 }
453 if (globalState_.HasGlobalAlpha()) {
454 paint.setAlphaf(globalState_.GetAlpha()); // update the global alpha after setting the color
455 }
456 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
457 skCanvas_->drawRect(skRect, paint);
458 } else {
459 InitPaintBlend(cachePaint_);
460 cacheCanvas_->drawRect(skRect, paint);
461 skCanvas_->drawBitmap(cacheBitmap_, 0, 0, &cachePaint_);
462 cacheBitmap_.eraseColor(0);
463 }
464 }
465
StrokeRect(const Offset & offset,const Rect & rect)466 void RosenRenderCustomPaint::StrokeRect(const Offset& offset, const Rect& rect)
467 {
468 SkPaint paint = GetStrokePaint();
469 paint.setAntiAlias(antiAlias_);
470 SkRect skRect = SkRect::MakeLTRB(rect.Left() + offset.GetX(), rect.Top() + offset.GetY(),
471 rect.Right() + offset.GetX(), offset.GetY() + rect.Bottom());
472 if (HasShadow()) {
473 SkPath path;
474 path.addRect(skRect);
475 RosenDecorationPainter::PaintShadow(path, shadow_, skCanvas_.get());
476 }
477 if (strokeState_.GetGradient().IsValid()) {
478 UpdatePaintShader(offset, paint, strokeState_.GetGradient());
479 }
480 if (strokeState_.GetPattern().IsValid()) {
481 UpdatePaintShader(strokeState_.GetPattern(), paint);
482 }
483 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
484 skCanvas_->drawRect(skRect, paint);
485 } else {
486 InitPaintBlend(cachePaint_);
487 cacheCanvas_->drawRect(skRect, paint);
488 skCanvas_->drawBitmap(cacheBitmap_, 0, 0, &cachePaint_);
489 cacheBitmap_.eraseColor(0);
490 }
491 }
492
ClearRect(const Offset & offset,const Rect & rect)493 void RosenRenderCustomPaint::ClearRect(const Offset& offset, const Rect& rect)
494 {
495 SkPaint paint;
496 paint.setAntiAlias(antiAlias_);
497 paint.setBlendMode(SkBlendMode::kClear);
498 auto skRect = SkRect::MakeLTRB(rect.Left() + offset.GetX(), rect.Top() + offset.GetY(),
499 rect.Right() + offset.GetX(), rect.Bottom() + offset.GetY());
500 skCanvas_->drawRect(skRect, paint);
501 }
502
FillText(const Offset & offset,const std::string & text,double x,double y)503 void RosenRenderCustomPaint::FillText(const Offset& offset, const std::string& text, double x, double y)
504 {
505 if (!UpdateParagraph(offset, text, false, HasShadow())) {
506 return;
507 }
508 PaintText(offset, x, y, false, HasShadow());
509 }
510
StrokeText(const Offset & offset,const std::string & text,double x,double y)511 void RosenRenderCustomPaint::StrokeText(const Offset& offset, const std::string& text, double x, double y)
512 {
513 if (HasShadow()) {
514 if (!UpdateParagraph(offset, text, true, true)) {
515 return;
516 }
517 PaintText(offset, x, y, true, true);
518 }
519
520 if (!UpdateParagraph(offset, text, true)) {
521 return;
522 }
523 PaintText(offset, x, y, true);
524 }
525
MeasureTextInner(const MeasureContext & context)526 double RosenRenderCustomPaint::MeasureTextInner(const MeasureContext& context)
527 {
528 using namespace Constants;
529 txt::ParagraphStyle style;
530 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
531 if (!fontCollection) {
532 LOGW("fontCollection is null");
533 return 0.0;
534 }
535 std::unique_ptr<txt::ParagraphBuilder> builder = txt::ParagraphBuilder::CreateTxtBuilder(style, fontCollection);
536 txt::TextStyle txtStyle;
537 std::vector<std::string> fontFamilies;
538 if (context.fontSize) {
539 txtStyle.font_size = context.fontSize.value().ConvertToPx();
540 } else {
541 auto context = PipelineBase::GetCurrentContext();
542 auto textTheme = context->GetTheme<TextTheme>();
543 txtStyle.font_size = textTheme->GetTextStyle().GetFontSize().ConvertToPx();
544 }
545 txtStyle.font_style = ConvertTxtFontStyle(context.fontStyle);
546 FontWeight fontWeightStr = StringUtils::StringToFontWeight(context.fontWeight);
547 txtStyle.font_weight = ConvertTxtFontWeight(fontWeightStr);
548 StringUtils::StringSplitter(context.fontFamily, ',', fontFamilies);
549 txtStyle.font_families = fontFamilies;
550 if (context.letterSpacing.has_value()) {
551 txtStyle.letter_spacing = context.letterSpacing.value().ConvertToPx();
552 }
553
554 builder->PushStyle(txtStyle);
555 builder->AddText(StringUtils::Str8ToStr16(context.textContent));
556 auto paragraph = builder->Build();
557 if (!paragraph) {
558 return 0.0;
559 }
560 paragraph->Layout(Size::INFINITE_SIZE);
561 return std::ceil(paragraph->GetLongestLine());
562 }
563
MeasureTextSizeInner(const MeasureContext & context)564 Size RosenRenderCustomPaint::MeasureTextSizeInner(const MeasureContext& context)
565 {
566 using namespace Constants;
567 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
568 if (!fontCollection) {
569 LOGW("fontCollection is null");
570 return Size(0.0, 0.0);
571 }
572 txt::ParagraphStyle style;
573 style.text_align = ConvertTxtTextAlign(context.textAlign);
574 if (context.textOverlayFlow == TextOverflow::ELLIPSIS) {
575 style.ellipsis = ELLIPSIS;
576 }
577 if (GreatNotEqual(context.maxlines, 0.0)) {
578 style.max_lines = context.maxlines;
579 }
580
581 std::unique_ptr<txt::ParagraphBuilder> builder = txt::ParagraphBuilder::CreateTxtBuilder(style, fontCollection);
582 txt::TextStyle txtStyle;
583 std::vector<std::string> fontFamilies;
584 if (context.fontSize.has_value()) {
585 txtStyle.font_size = context.fontSize.value().ConvertToPx();
586 } else {
587 auto context = PipelineBase::GetCurrentContext();
588 auto textTheme = context->GetTheme<TextTheme>();
589 txtStyle.font_size = textTheme->GetTextStyle().GetFontSize().ConvertToPx();
590 }
591 txtStyle.font_style = ConvertTxtFontStyle(context.fontStyle);
592 FontWeight fontWeightStr = StringUtils::StringToFontWeight(context.fontWeight);
593 txtStyle.font_weight = ConvertTxtFontWeight(fontWeightStr);
594 StringUtils::StringSplitter(context.fontFamily, ',', fontFamilies);
595 txtStyle.font_families = fontFamilies;
596 if (context.letterSpacing.has_value()) {
597 txtStyle.letter_spacing = context.letterSpacing.value().ConvertToPx();
598 }
599 if (context.lineHeight.has_value()) {
600 if (context.lineHeight->Unit() == DimensionUnit::PERCENT) {
601 txtStyle.has_height_override = true;
602 txtStyle.height = context.lineHeight->Value();
603 } else {
604 auto lineHeight = context.lineHeight.value().ConvertToPx();
605 if (!NearEqual(lineHeight, txtStyle.font_size) && (lineHeight > 0.0) && (!NearZero(txtStyle.font_size))) {
606 txtStyle.height = lineHeight / txtStyle.font_size;
607 txtStyle.has_height_override = true;
608 }
609 }
610 }
611 builder->PushStyle(txtStyle);
612 std::string content = context.textContent;
613 StringUtils::TransformStrCase(content, static_cast<int32_t>(context.textCase));
614 builder->AddText(StringUtils::Str8ToStr16(content));
615 auto paragraph = builder->Build();
616 if (!paragraph) {
617 return Size(0.0, 0.0);
618 }
619 if (context.constraintWidth.has_value()) {
620 paragraph->Layout(context.constraintWidth.value().ConvertToPx());
621 } else {
622 paragraph->Layout(Size::INFINITE_SIZE);
623 }
624 double textWidth = 0.0;
625 auto* paragraphTxt = static_cast<txt::ParagraphTxt*>(paragraph.get());
626 if (paragraphTxt->GetLineCount() == 1) {
627 textWidth = std::max(paragraph->GetLongestLine(), paragraph->GetMaxIntrinsicWidth());
628 } else {
629 textWidth = paragraph->GetLongestLine();
630 }
631 auto sizeWidth = std::min(paragraph->GetMaxWidth(), textWidth);
632 sizeWidth =
633 context.constraintWidth.has_value() ? context.constraintWidth.value().ConvertToPx() : std::ceil(sizeWidth);
634
635 float baselineOffset = 0.0;
636 if (context.baselineOffset.has_value()) {
637 baselineOffset = static_cast<float>(context.baselineOffset.value().ConvertToPx());
638 }
639 float heightFinal = static_cast<float>(paragraph->GetHeight()) + std::fabs(baselineOffset);
640
641 return Size(sizeWidth, heightFinal);
642 }
643
MeasureText(const std::string & text,const PaintState & state)644 double RosenRenderCustomPaint::MeasureText(const std::string& text, const PaintState& state)
645 {
646 using namespace Constants;
647 txt::ParagraphStyle style;
648 style.text_align = ConvertTxtTextAlign(state.GetTextAlign());
649 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
650 if (!fontCollection) {
651 LOGW("MeasureText: fontCollection is null");
652 return 0.0;
653 }
654 std::unique_ptr<txt::ParagraphBuilder> builder = txt::ParagraphBuilder::CreateTxtBuilder(style, fontCollection);
655 txt::TextStyle txtStyle;
656 ConvertTxtStyle(state.GetTextStyle(), context_, txtStyle);
657 txtStyle.font_size = state.GetTextStyle().GetFontSize().Value();
658 builder->PushStyle(txtStyle);
659 builder->AddText(StringUtils::Str8ToStr16(text));
660 auto paragraph = builder->Build();
661 paragraph->Layout(Size::INFINITE_SIZE);
662 return paragraph->GetMaxIntrinsicWidth();
663 }
664
MeasureTextHeight(const std::string & text,const PaintState & state)665 double RosenRenderCustomPaint::MeasureTextHeight(const std::string& text, const PaintState& state)
666 {
667 using namespace Constants;
668 txt::ParagraphStyle style;
669 style.text_align = ConvertTxtTextAlign(state.GetTextAlign());
670 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
671 if (!fontCollection) {
672 LOGW("MeasureText: fontCollection is null");
673 return 0.0;
674 }
675 std::unique_ptr<txt::ParagraphBuilder> builder = txt::ParagraphBuilder::CreateTxtBuilder(style, fontCollection);
676 txt::TextStyle txtStyle;
677 ConvertTxtStyle(state.GetTextStyle(), context_, txtStyle);
678 txtStyle.font_size = state.GetTextStyle().GetFontSize().Value();
679 builder->PushStyle(txtStyle);
680 builder->AddText(StringUtils::Str8ToStr16(text));
681 auto paragraph = builder->Build();
682 paragraph->Layout(Size::INFINITE_SIZE);
683 return paragraph->GetHeight();
684 }
685
MeasureTextMetrics(const std::string & text,const PaintState & state)686 TextMetrics RosenRenderCustomPaint::MeasureTextMetrics(const std::string& text, const PaintState& state)
687 {
688 using namespace Constants;
689 txt::ParagraphStyle style;
690 style.text_align = ConvertTxtTextAlign(state.GetTextAlign());
691 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
692 if (!fontCollection) {
693 LOGW("MeasureText: fontCollection is null");
694 return { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
695 }
696 std::unique_ptr<txt::ParagraphBuilder> builder = txt::ParagraphBuilder::CreateTxtBuilder(style, fontCollection);
697 txt::TextStyle txtStyle;
698 ConvertTxtStyle(state.GetTextStyle(), context_, txtStyle);
699 txtStyle.font_size = state.GetTextStyle().GetFontSize().Value();
700 builder->PushStyle(txtStyle);
701 builder->AddText(StringUtils::Str8ToStr16(text));
702 auto paragraph = builder->Build();
703 paragraph->Layout(Size::INFINITE_SIZE);
704
705 auto textAlign = state.GetTextAlign();
706 auto textBaseLine = state.GetTextStyle().GetTextBaseline();
707
708 auto width = paragraph->GetMaxIntrinsicWidth();
709 auto height = paragraph->GetHeight();
710
711 auto actualBoundingBoxLeft = -GetAlignOffset(textAlign, paragraph);
712 auto actualBoundingBoxRight = width - actualBoundingBoxLeft;
713 auto actualBoundingBoxAscent = -GetBaselineOffset(textBaseLine, paragraph);
714 auto actualBoundingBoxDescent = height - actualBoundingBoxAscent;
715
716 return { width, height, actualBoundingBoxLeft, actualBoundingBoxRight, actualBoundingBoxAscent,
717 actualBoundingBoxDescent };
718 }
719
PaintText(const Offset & offset,double x,double y,bool isStroke,bool hasShadow)720 void RosenRenderCustomPaint::PaintText(const Offset& offset, double x, double y, bool isStroke, bool hasShadow)
721 {
722 paragraph_->Layout(GetLayoutSize().Width());
723 if (GetLayoutSize().Width() > paragraph_->GetMaxIntrinsicWidth()) {
724 paragraph_->Layout(std::ceil(paragraph_->GetMaxIntrinsicWidth()));
725 }
726 auto align = isStroke ? strokeState_.GetTextAlign() : fillState_.GetTextAlign();
727 double dx = offset.GetX() + x + GetAlignOffset(align, paragraph_);
728 auto baseline =
729 isStroke ? strokeState_.GetTextStyle().GetTextBaseline() : fillState_.GetTextStyle().GetTextBaseline();
730 double dy = offset.GetY() + y + GetBaselineOffset(baseline, paragraph_);
731
732 if (hasShadow) {
733 skCanvas_->save();
734 auto shadowOffsetX = shadow_.GetOffset().GetX();
735 auto shadowOffsetY = shadow_.GetOffset().GetY();
736 paragraph_->Paint(skCanvas_.get(), dx + shadowOffsetX, dy + shadowOffsetY);
737 skCanvas_->restore();
738 return;
739 }
740
741 paragraph_->Paint(skCanvas_.get(), dx, dy);
742 }
743
GetAlignOffset(TextAlign align,std::unique_ptr<txt::Paragraph> & paragraph)744 double RosenRenderCustomPaint::GetAlignOffset(TextAlign align, std::unique_ptr<txt::Paragraph>& paragraph)
745 {
746 double x = 0.0;
747 switch (align) {
748 case TextAlign::LEFT:
749 x = 0.0;
750 break;
751 case TextAlign::START:
752 x = (GetTextDirection() == TextDirection::LTR) ? 0.0 : -paragraph->GetMaxIntrinsicWidth();
753 break;
754 case TextAlign::RIGHT:
755 x = -paragraph->GetMaxIntrinsicWidth();
756 break;
757 case TextAlign::END:
758 x = (GetTextDirection() == TextDirection::LTR) ? -paragraph->GetMaxIntrinsicWidth() : 0.0;
759 break;
760 case TextAlign::CENTER:
761 x = -paragraph->GetMaxIntrinsicWidth() / 2;
762 break;
763 default:
764 x = 0.0;
765 break;
766 }
767 return x;
768 }
769
GetBaselineOffset(TextBaseline baseline,std::unique_ptr<txt::Paragraph> & paragraph)770 double RosenRenderCustomPaint::GetBaselineOffset(TextBaseline baseline, std::unique_ptr<txt::Paragraph>& paragraph)
771 {
772 double y = 0.0;
773 switch (baseline) {
774 case TextBaseline::ALPHABETIC:
775 y = -paragraph->GetAlphabeticBaseline();
776 break;
777 case TextBaseline::IDEOGRAPHIC:
778 y = -paragraph->GetIdeographicBaseline();
779 break;
780 case TextBaseline::BOTTOM:
781 y = -paragraph->GetHeight();
782 break;
783 case TextBaseline::TOP:
784 y = 0.0;
785 break;
786 case TextBaseline::MIDDLE:
787 y = -paragraph->GetHeight() / 2;
788 break;
789 case TextBaseline::HANGING:
790 y = -HANGING_PERCENT * (paragraph->GetHeight() - paragraph->GetAlphabeticBaseline());
791 break;
792 default:
793 y = -paragraph->GetAlphabeticBaseline();
794 break;
795 }
796 return y;
797 }
798
MoveTo(const Offset & offset,double x,double y)799 void RosenRenderCustomPaint::MoveTo(const Offset& offset, double x, double y)
800 {
801 skPath_.moveTo(SkDoubleToScalar(x + offset.GetX()), SkDoubleToScalar(y + offset.GetY()));
802 }
803
LineTo(const Offset & offset,double x,double y)804 void RosenRenderCustomPaint::LineTo(const Offset& offset, double x, double y)
805 {
806 skPath_.lineTo(SkDoubleToScalar(x + offset.GetX()), SkDoubleToScalar(y + offset.GetY()));
807 }
808
BezierCurveTo(const Offset & offset,const BezierCurveParam & param)809 void RosenRenderCustomPaint::BezierCurveTo(const Offset& offset, const BezierCurveParam& param)
810 {
811 skPath_.cubicTo(SkDoubleToScalar(param.cp1x + offset.GetX()), SkDoubleToScalar(param.cp1y + offset.GetY()),
812 SkDoubleToScalar(param.cp2x + offset.GetX()), SkDoubleToScalar(param.cp2y + offset.GetY()),
813 SkDoubleToScalar(param.x + offset.GetX()), SkDoubleToScalar(param.y + offset.GetY()));
814 }
815
QuadraticCurveTo(const Offset & offset,const QuadraticCurveParam & param)816 void RosenRenderCustomPaint::QuadraticCurveTo(const Offset& offset, const QuadraticCurveParam& param)
817 {
818 skPath_.quadTo(SkDoubleToScalar(param.cpx + offset.GetX()), SkDoubleToScalar(param.cpy + offset.GetY()),
819 SkDoubleToScalar(param.x + offset.GetX()), SkDoubleToScalar(param.y + offset.GetY()));
820 }
821
Arc(const Offset & offset,const ArcParam & param)822 void RosenRenderCustomPaint::Arc(const Offset& offset, const ArcParam& param)
823 {
824 double left = param.x - param.radius + offset.GetX();
825 double top = param.y - param.radius + offset.GetY();
826 double right = param.x + param.radius + offset.GetX();
827 double bottom = param.y + param.radius + offset.GetY();
828 double startAngle = param.startAngle * HALF_CIRCLE_ANGLE / M_PI;
829 double endAngle = param.endAngle * HALF_CIRCLE_ANGLE / M_PI;
830 double sweepAngle = endAngle - startAngle;
831 if (param.anticlockwise) {
832 sweepAngle =
833 endAngle > startAngle ? (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) - FULL_CIRCLE_ANGLE) : sweepAngle;
834 } else {
835 sweepAngle =
836 endAngle > startAngle ? sweepAngle : (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) + FULL_CIRCLE_ANGLE);
837 }
838 auto rect = SkRect::MakeLTRB(left, top, right, bottom);
839 if (NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && !NearEqual(startAngle, endAngle)) {
840 // draw circle
841 double half = GreatNotEqual(sweepAngle, 0.0) ? HALF_CIRCLE_ANGLE : -HALF_CIRCLE_ANGLE;
842 skPath_.arcTo(rect, SkDoubleToScalar(startAngle), SkDoubleToScalar(half), false);
843 skPath_.arcTo(rect, SkDoubleToScalar(half + startAngle), SkDoubleToScalar(half), false);
844 } else if (!NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && abs(sweepAngle) > FULL_CIRCLE_ANGLE) {
845 double half = GreatNotEqual(sweepAngle, 0.0) ? HALF_CIRCLE_ANGLE : -HALF_CIRCLE_ANGLE;
846 skPath_.arcTo(rect, SkDoubleToScalar(startAngle), SkDoubleToScalar(half), false);
847 skPath_.arcTo(rect, SkDoubleToScalar(half + startAngle), SkDoubleToScalar(half), false);
848 skPath_.arcTo(rect, SkDoubleToScalar(half + half + startAngle), SkDoubleToScalar(sweepAngle), false);
849 } else {
850 skPath_.arcTo(rect, SkDoubleToScalar(startAngle), SkDoubleToScalar(sweepAngle), false);
851 }
852 }
853
ArcTo(const Offset & offset,const ArcToParam & param)854 void RosenRenderCustomPaint::ArcTo(const Offset& offset, const ArcToParam& param)
855 {
856 double x1 = param.x1 + offset.GetX();
857 double y1 = param.y1 + offset.GetY();
858 double x2 = param.x2 + offset.GetX();
859 double y2 = param.y2 + offset.GetY();
860 double radius = param.radius;
861 skPath_.arcTo(SkDoubleToScalar(x1), SkDoubleToScalar(y1), SkDoubleToScalar(x2), SkDoubleToScalar(y2),
862 SkDoubleToScalar(radius));
863 }
864
Ellipse(const Offset & offset,const EllipseParam & param)865 void RosenRenderCustomPaint::Ellipse(const Offset& offset, const EllipseParam& param)
866 {
867 // Init the start and end angle, then calculated the sweepAngle.
868 double startAngle = std::fmod(param.startAngle, M_PI * 2.0);
869 double endAngle = std::fmod(param.endAngle, M_PI * 2.0);
870 startAngle = (startAngle < 0.0 ? startAngle + M_PI * 2.0 : startAngle) * HALF_CIRCLE_ANGLE / M_PI;
871 endAngle = (endAngle < 0.0 ? endAngle + M_PI * 2.0 : endAngle) * HALF_CIRCLE_ANGLE / M_PI;
872 if (NearEqual(param.startAngle, param.endAngle)) {
873 return; // Just return when startAngle is same as endAngle.
874 }
875 double rotation = param.rotation * HALF_CIRCLE_ANGLE / M_PI;
876 double sweepAngle = endAngle - startAngle;
877 if (param.anticlockwise) {
878 if (sweepAngle > 0.0) { // Make sure the sweepAngle is negative when anticlockwise.
879 sweepAngle -= FULL_CIRCLE_ANGLE;
880 }
881 } else {
882 if (sweepAngle < 0.0) { // Make sure the sweepAngle is positive when clockwise.
883 sweepAngle += FULL_CIRCLE_ANGLE;
884 }
885 }
886
887 // Init the oval Rect(left, top, right, bottom).
888 double left = param.x - param.radiusX + offset.GetX();
889 double top = param.y - param.radiusY + offset.GetY();
890 double right = param.x + param.radiusX + offset.GetX();
891 double bottom = param.y + param.radiusY + offset.GetY();
892 auto rect = SkRect::MakeLTRB(left, top, right, bottom);
893 if (!NearZero(rotation)) {
894 SkMatrix matrix;
895 matrix.setRotate(-rotation, param.x + offset.GetX(), param.y + offset.GetY());
896 skPath_.transform(matrix);
897 }
898 if (NearZero(sweepAngle) && !NearZero(param.endAngle - param.startAngle)) {
899 // The entire ellipse needs to be drawn with two arcTo.
900 skPath_.arcTo(rect, startAngle, HALF_CIRCLE_ANGLE, false);
901 skPath_.arcTo(rect, startAngle + HALF_CIRCLE_ANGLE, HALF_CIRCLE_ANGLE, false);
902 } else {
903 skPath_.arcTo(rect, startAngle, sweepAngle, false);
904 }
905 if (!NearZero(rotation)) {
906 SkMatrix matrix;
907 matrix.setRotate(rotation, param.x + offset.GetX(), param.y + offset.GetY());
908 skPath_.transform(matrix);
909 }
910 }
911
AddRect(const Offset & offset,const Rect & rect)912 void RosenRenderCustomPaint::AddRect(const Offset& offset, const Rect& rect)
913 {
914 SkRect skRect = SkRect::MakeLTRB(rect.Left() + offset.GetX(), rect.Top() + offset.GetY(),
915 rect.Right() + offset.GetX(), offset.GetY() + rect.Bottom());
916 skPath_.addRect(skRect);
917 }
918
SetFillRuleForPath(const CanvasFillRule & rule)919 void RosenRenderCustomPaint::SetFillRuleForPath(const CanvasFillRule& rule)
920 {
921 if (rule == CanvasFillRule::NONZERO) {
922 skPath_.setFillType(SkPath::FillType::kWinding_FillType);
923 } else if (rule == CanvasFillRule::EVENODD) {
924 skPath_.setFillType(SkPath::FillType::kEvenOdd_FillType);
925 }
926 }
927
SetFillRuleForPath2D(const CanvasFillRule & rule)928 void RosenRenderCustomPaint::SetFillRuleForPath2D(const CanvasFillRule& rule)
929 {
930 if (rule == CanvasFillRule::NONZERO) {
931 skPath2d_.setFillType(SkPath::FillType::kWinding_FillType);
932 } else if (rule == CanvasFillRule::EVENODD) {
933 skPath2d_.setFillType(SkPath::FillType::kEvenOdd_FillType);
934 }
935 }
936
ParsePath2D(const Offset & offset,const RefPtr<CanvasPath2D> & path)937 void RosenRenderCustomPaint::ParsePath2D(const Offset& offset, const RefPtr<CanvasPath2D>& path)
938 {
939 for (const auto& [cmd, args] : path->GetCaches()) {
940 switch (cmd) {
941 case PathCmd::CMDS: {
942 Path2DAddPath(offset, args);
943 break;
944 }
945 case PathCmd::TRANSFORM: {
946 Path2DSetTransform(offset, args);
947 break;
948 }
949 case PathCmd::MOVE_TO: {
950 Path2DMoveTo(offset, args);
951 break;
952 }
953 case PathCmd::LINE_TO: {
954 Path2DLineTo(offset, args);
955 break;
956 }
957 case PathCmd::ARC: {
958 Path2DArc(offset, args);
959 break;
960 }
961 case PathCmd::ARC_TO: {
962 Path2DArcTo(offset, args);
963 break;
964 }
965 case PathCmd::QUADRATIC_CURVE_TO: {
966 Path2DQuadraticCurveTo(offset, args);
967 break;
968 }
969 case PathCmd::BEZIER_CURVE_TO: {
970 Path2DBezierCurveTo(offset, args);
971 break;
972 }
973 case PathCmd::ELLIPSE: {
974 Path2DEllipse(offset, args);
975 break;
976 }
977 case PathCmd::RECT: {
978 Path2DRect(offset, args);
979 break;
980 }
981 case PathCmd::CLOSE_PATH: {
982 Path2DClosePath(offset, args);
983 break;
984 }
985 default: {
986 break;
987 }
988 }
989 }
990 }
991
Fill(const Offset & offset)992 void RosenRenderCustomPaint::Fill(const Offset& offset)
993 {
994 SkPaint paint;
995 paint.setAntiAlias(antiAlias_);
996 paint.setColor(fillState_.GetColor().GetValue());
997 paint.setStyle(SkPaint::Style::kFill_Style);
998 if (HasShadow()) {
999 RosenDecorationPainter::PaintShadow(skPath_, shadow_, skCanvas_.get());
1000 }
1001 if (fillState_.GetGradient().IsValid()) {
1002 UpdatePaintShader(offset, paint, fillState_.GetGradient());
1003 }
1004 if (fillState_.GetPattern().IsValid()) {
1005 UpdatePaintShader(fillState_.GetPattern(), paint);
1006 }
1007 if (globalState_.HasGlobalAlpha()) {
1008 paint.setAlphaf(globalState_.GetAlpha());
1009 }
1010 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
1011 skCanvas_->drawPath(skPath_, paint);
1012 } else {
1013 InitPaintBlend(cachePaint_);
1014 cacheCanvas_->drawPath(skPath_, paint);
1015 skCanvas_->drawBitmap(cacheBitmap_, 0, 0, &cachePaint_);
1016 cacheBitmap_.eraseColor(0);
1017 }
1018 }
1019
Fill(const Offset & offset,const RefPtr<CanvasPath2D> & path)1020 void RosenRenderCustomPaint::Fill(const Offset& offset, const RefPtr<CanvasPath2D>& path)
1021 {
1022 if (path == nullptr) {
1023 LOGE("Fill failed, target path is null.");
1024 return;
1025 }
1026 ParsePath2D(offset, path);
1027 Path2DFill(offset);
1028 skPath2d_.reset();
1029 }
1030
Stroke(const Offset & offset)1031 void RosenRenderCustomPaint::Stroke(const Offset& offset)
1032 {
1033 SkPaint paint = GetStrokePaint();
1034 paint.setAntiAlias(antiAlias_);
1035 if (HasShadow()) {
1036 RosenDecorationPainter::PaintShadow(skPath_, shadow_, skCanvas_.get());
1037 }
1038 if (strokeState_.GetGradient().IsValid()) {
1039 UpdatePaintShader(offset, paint, strokeState_.GetGradient());
1040 }
1041 if (strokeState_.GetPattern().IsValid()) {
1042 UpdatePaintShader(strokeState_.GetPattern(), paint);
1043 }
1044 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
1045 skCanvas_->drawPath(skPath_, paint);
1046 } else {
1047 InitPaintBlend(cachePaint_);
1048 cacheCanvas_->drawPath(skPath_, paint);
1049 skCanvas_->drawBitmap(cacheBitmap_, 0, 0, &cachePaint_);
1050 cacheBitmap_.eraseColor(0);
1051 }
1052 }
1053
Stroke(const Offset & offset,const RefPtr<CanvasPath2D> & path)1054 void RosenRenderCustomPaint::Stroke(const Offset& offset, const RefPtr<CanvasPath2D>& path)
1055 {
1056 if (path == nullptr) {
1057 LOGE("Stroke failed, target path is null.");
1058 return;
1059 }
1060 ParsePath2D(offset, path);
1061 Path2DStroke(offset);
1062 skPath2d_.reset();
1063 }
1064
Path2DAddPath(const Offset & offset,const PathArgs & args)1065 void RosenRenderCustomPaint::Path2DAddPath(const Offset& offset, const PathArgs& args)
1066 {
1067 SkPath out;
1068 SkParsePath::FromSVGString(args.cmds.c_str(), &out);
1069 skPath2d_.addPath(out);
1070 }
1071
Path2DSetTransform(const Offset & offset,const PathArgs & args)1072 void RosenRenderCustomPaint::Path2DSetTransform(const Offset& offset, const PathArgs& args)
1073 {
1074 SkMatrix skMatrix;
1075 double scaleX = args.para1;
1076 double skewX = args.para2;
1077 double skewY = args.para3;
1078 double scaleY = args.para4;
1079 double translateX = args.para5;
1080 double translateY = args.para6;
1081 skMatrix.setAll(scaleX, skewY, translateX, skewX, scaleY, translateY, 0, 0, 1);
1082 skPath2d_.transform(skMatrix);
1083 }
1084
Path2DMoveTo(const Offset & offset,const PathArgs & args)1085 void RosenRenderCustomPaint::Path2DMoveTo(const Offset& offset, const PathArgs& args)
1086 {
1087 double x = args.para1 + offset.GetX();
1088 double y = args.para2 + offset.GetY();
1089 skPath2d_.moveTo(x, y);
1090 }
1091
Path2DLineTo(const Offset & offset,const PathArgs & args)1092 void RosenRenderCustomPaint::Path2DLineTo(const Offset& offset, const PathArgs& args)
1093 {
1094 double x = args.para1 + offset.GetX();
1095 double y = args.para2 + offset.GetY();
1096 skPath2d_.lineTo(x, y);
1097 }
1098
Path2DArc(const Offset & offset,const PathArgs & args)1099 void RosenRenderCustomPaint::Path2DArc(const Offset& offset, const PathArgs& args)
1100 {
1101 double x = args.para1;
1102 double y = args.para2;
1103 double r = args.para3;
1104 auto rect =
1105 SkRect::MakeLTRB(x - r + offset.GetX(), y - r + offset.GetY(), x + r + offset.GetX(), y + r + offset.GetY());
1106 double startAngle = args.para4 * HALF_CIRCLE_ANGLE / M_PI;
1107 double endAngle = args.para5 * HALF_CIRCLE_ANGLE / M_PI;
1108 double sweepAngle = endAngle - startAngle;
1109 if (!NearZero(args.para6)) {
1110 sweepAngle =
1111 endAngle > startAngle ? (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) - FULL_CIRCLE_ANGLE) : sweepAngle;
1112 } else {
1113 sweepAngle =
1114 endAngle > startAngle ? sweepAngle : (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) + FULL_CIRCLE_ANGLE);
1115 }
1116 if (NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && !NearEqual(startAngle, endAngle)) {
1117 skPath2d_.arcTo(rect, startAngle, HALF_CIRCLE_ANGLE, false);
1118 skPath2d_.arcTo(rect, startAngle + HALF_CIRCLE_ANGLE, HALF_CIRCLE_ANGLE, false);
1119 } else if (!NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && abs(sweepAngle) > FULL_CIRCLE_ANGLE) {
1120 skPath2d_.arcTo(rect, startAngle, HALF_CIRCLE_ANGLE, false);
1121 skPath2d_.arcTo(rect, startAngle + HALF_CIRCLE_ANGLE, HALF_CIRCLE_ANGLE, false);
1122 skPath2d_.arcTo(rect, startAngle + HALF_CIRCLE_ANGLE + HALF_CIRCLE_ANGLE, sweepAngle, false);
1123 } else {
1124 skPath2d_.arcTo(rect, startAngle, sweepAngle, false);
1125 }
1126 }
1127
Path2DArcTo(const Offset & offset,const PathArgs & args)1128 void RosenRenderCustomPaint::Path2DArcTo(const Offset& offset, const PathArgs& args)
1129 {
1130 double x1 = args.para1 + offset.GetX();
1131 double y1 = args.para2 + offset.GetY();
1132 double x2 = args.para3 + offset.GetX();
1133 double y2 = args.para4 + offset.GetY();
1134 double r = args.para5;
1135 skPath2d_.arcTo(x1, y1, x2, y2, r);
1136 }
1137
Path2DQuadraticCurveTo(const Offset & offset,const PathArgs & args)1138 void RosenRenderCustomPaint::Path2DQuadraticCurveTo(const Offset& offset, const PathArgs& args)
1139 {
1140 double cpx = args.para1 + offset.GetX();
1141 double cpy = args.para2 + offset.GetY();
1142 double x = args.para3 + offset.GetX();
1143 double y = args.para4 + offset.GetY();
1144 skPath2d_.quadTo(cpx, cpy, x, y);
1145 }
1146
Path2DBezierCurveTo(const Offset & offset,const PathArgs & args)1147 void RosenRenderCustomPaint::Path2DBezierCurveTo(const Offset& offset, const PathArgs& args)
1148 {
1149 double cp1x = args.para1 + offset.GetX();
1150 double cp1y = args.para2 + offset.GetY();
1151 double cp2x = args.para3 + offset.GetX();
1152 double cp2y = args.para4 + offset.GetY();
1153 double x = args.para5 + offset.GetX();
1154 double y = args.para6 + offset.GetY();
1155 skPath2d_.cubicTo(cp1x, cp1y, cp2x, cp2y, x, y);
1156 }
1157
Path2DEllipse(const Offset & offset,const PathArgs & args)1158 void RosenRenderCustomPaint::Path2DEllipse(const Offset& offset, const PathArgs& args)
1159 {
1160 if (NearEqual(args.para6, args.para7)) {
1161 return; // Just return when startAngle is same as endAngle.
1162 }
1163
1164 double x = args.para1;
1165 double y = args.para2;
1166 double rx = args.para3;
1167 double ry = args.para4;
1168 double rotation = args.para5 * HALF_CIRCLE_ANGLE / M_PI;
1169 double startAngle = std::fmod(args.para6, M_PI * 2.0);
1170 double endAngle = std::fmod(args.para7, M_PI * 2.0);
1171 bool anticlockwise = NearZero(args.para8) ? false : true;
1172 startAngle = (startAngle < 0.0 ? startAngle + M_PI * 2.0 : startAngle) * HALF_CIRCLE_ANGLE / M_PI;
1173 endAngle = (endAngle < 0.0 ? endAngle + M_PI * 2.0 : endAngle) * HALF_CIRCLE_ANGLE / M_PI;
1174 double sweepAngle = endAngle - startAngle;
1175 if (anticlockwise) {
1176 if (sweepAngle > 0.0) { // Make sure the sweepAngle is negative when anticlockwise.
1177 sweepAngle -= FULL_CIRCLE_ANGLE;
1178 }
1179 } else {
1180 if (sweepAngle < 0.0) { // Make sure the sweepAngle is positive when clockwise.
1181 sweepAngle += FULL_CIRCLE_ANGLE;
1182 }
1183 }
1184 auto rect = SkRect::MakeLTRB(
1185 x - rx + offset.GetX(), y - ry + offset.GetY(), x + rx + offset.GetX(), y + ry + offset.GetY());
1186
1187 if (!NearZero(rotation)) {
1188 SkMatrix matrix;
1189 matrix.setRotate(-rotation, x + offset.GetX(), y + offset.GetY());
1190 skPath2d_.transform(matrix);
1191 }
1192 if (NearZero(sweepAngle) && !NearZero(args.para6 - args.para7)) {
1193 // The entire ellipse needs to be drawn with two arcTo.
1194 skPath2d_.arcTo(rect, startAngle, HALF_CIRCLE_ANGLE, false);
1195 skPath2d_.arcTo(rect, startAngle + HALF_CIRCLE_ANGLE, HALF_CIRCLE_ANGLE, false);
1196 } else {
1197 skPath2d_.arcTo(rect, startAngle, sweepAngle, false);
1198 }
1199 if (!NearZero(rotation)) {
1200 SkMatrix matrix;
1201 matrix.setRotate(rotation, x + offset.GetX(), y + offset.GetY());
1202 skPath2d_.transform(matrix);
1203 }
1204 }
1205
Path2DRect(const Offset & offset,const PathArgs & args)1206 void RosenRenderCustomPaint::Path2DRect(const Offset& offset, const PathArgs& args)
1207 {
1208 double left = args.para1 + offset.GetX();
1209 double top = args.para2 + offset.GetY();
1210 double right = args.para3 + args.para1 + offset.GetX();
1211 double bottom = args.para4 + args.para2 + offset.GetY();
1212 skPath2d_.addRect(SkRect::MakeLTRB(left, top, right, bottom));
1213 }
1214
Path2DClosePath(const Offset & offset,const PathArgs & args)1215 void RosenRenderCustomPaint::Path2DClosePath(const Offset& offset, const PathArgs& args)
1216 {
1217 skPath2d_.close();
1218 }
1219
Path2DStroke(const Offset & offset)1220 void RosenRenderCustomPaint::Path2DStroke(const Offset& offset)
1221 {
1222 SkPaint paint = GetStrokePaint();
1223 paint.setAntiAlias(antiAlias_);
1224 if (HasShadow()) {
1225 RosenDecorationPainter::PaintShadow(skPath2d_, shadow_, skCanvas_.get());
1226 }
1227 if (strokeState_.GetGradient().IsValid()) {
1228 UpdatePaintShader(offset, paint, strokeState_.GetGradient());
1229 }
1230 if (strokeState_.GetPattern().IsValid()) {
1231 UpdatePaintShader(strokeState_.GetPattern(), paint);
1232 }
1233 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
1234 skCanvas_->drawPath(skPath2d_, paint);
1235 } else {
1236 InitPaintBlend(cachePaint_);
1237 cacheCanvas_->drawPath(skPath2d_, paint);
1238 skCanvas_->drawBitmap(cacheBitmap_, 0, 0, &cachePaint_);
1239 cacheBitmap_.eraseColor(0);
1240 }
1241 }
1242
Path2DFill(const Offset & offset)1243 void RosenRenderCustomPaint::Path2DFill(const Offset& offset)
1244 {
1245 SkPaint paint;
1246 paint.setAntiAlias(antiAlias_);
1247 paint.setColor(fillState_.GetColor().GetValue());
1248 paint.setStyle(SkPaint::Style::kFill_Style);
1249 if (HasShadow()) {
1250 RosenDecorationPainter::PaintShadow(skPath2d_, shadow_, skCanvas_.get());
1251 }
1252 if (fillState_.GetGradient().IsValid()) {
1253 UpdatePaintShader(offset, paint, fillState_.GetGradient());
1254 }
1255 if (fillState_.GetPattern().IsValid()) {
1256 UpdatePaintShader(fillState_.GetPattern(), paint);
1257 }
1258 if (globalState_.HasGlobalAlpha()) {
1259 paint.setAlphaf(globalState_.GetAlpha());
1260 }
1261 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
1262 skCanvas_->drawPath(skPath2d_, paint);
1263 } else {
1264 InitPaintBlend(cachePaint_);
1265 cacheCanvas_->drawPath(skPath2d_, paint);
1266 skCanvas_->drawBitmap(cacheBitmap_, 0, 0, &cachePaint_);
1267 cacheBitmap_.eraseColor(0);
1268 }
1269 }
1270
Path2DClip()1271 void RosenRenderCustomPaint::Path2DClip()
1272 {
1273 skCanvas_->clipPath(skPath2d_);
1274 }
1275
Clip()1276 void RosenRenderCustomPaint::Clip()
1277 {
1278 skCanvas_->clipPath(skPath_);
1279 }
1280
Clip(const RefPtr<CanvasPath2D> & path)1281 void RosenRenderCustomPaint::Clip(const RefPtr<CanvasPath2D>& path)
1282 {
1283 if (path == nullptr) {
1284 LOGE("Fill failed, target path is null.");
1285 return;
1286 }
1287 auto offset = Offset(0, 0);
1288 ParsePath2D(offset, path);
1289 Path2DClip();
1290 skPath2d_.reset();
1291 }
1292
BeginPath()1293 void RosenRenderCustomPaint::BeginPath()
1294 {
1295 skPath_.reset();
1296 }
1297
ResetTransform()1298 void RosenRenderCustomPaint::ResetTransform()
1299 {
1300 skCanvas_->resetMatrix();
1301 }
1302
ClosePath()1303 void RosenRenderCustomPaint::ClosePath()
1304 {
1305 skPath_.close();
1306 }
1307
Save()1308 void RosenRenderCustomPaint::Save()
1309 {
1310 SaveStates();
1311 skCanvas_->save();
1312 }
1313
Restore()1314 void RosenRenderCustomPaint::Restore()
1315 {
1316 RestoreStates();
1317 skCanvas_->restore();
1318 }
1319
InitImagePaint()1320 void RosenRenderCustomPaint::InitImagePaint()
1321 {
1322 if (smoothingEnabled_) {
1323 if (smoothingQuality_ == "low") {
1324 imagePaint_.setFilterQuality(SkFilterQuality::kLow_SkFilterQuality);
1325 } else if (smoothingQuality_ == "medium") {
1326 imagePaint_.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality);
1327 } else if (smoothingQuality_ == "high") {
1328 imagePaint_.setFilterQuality(SkFilterQuality::kHigh_SkFilterQuality);
1329 } else {
1330 LOGE("Unsupported Quality type:%{public}s", smoothingQuality_.c_str());
1331 }
1332 } else {
1333 imagePaint_.setFilterQuality(SkFilterQuality::kNone_SkFilterQuality);
1334 }
1335 }
1336
InitPaintBlend(SkPaint & paint)1337 void RosenRenderCustomPaint::InitPaintBlend(SkPaint& paint)
1338 {
1339 paint.setBlendMode(
1340 ConvertEnumToSkEnum(globalState_.GetType(), SK_BLEND_MODE_TABLE, BLEND_MODE_SIZE, SkBlendMode::kSrcOver));
1341 }
1342
UpdateParagraph(const Offset & offset,const std::string & text,bool isStroke,bool hasShadow)1343 bool RosenRenderCustomPaint::UpdateParagraph(
1344 const Offset& offset, const std::string& text, bool isStroke, bool hasShadow)
1345 {
1346 using namespace Constants;
1347 txt::ParagraphStyle style;
1348 if (isStroke) {
1349 style.text_align = ConvertTxtTextAlign(strokeState_.GetTextAlign());
1350 } else {
1351 style.text_align = ConvertTxtTextAlign(fillState_.GetTextAlign());
1352 }
1353 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
1354 if (!fontCollection) {
1355 LOGW("UpdateParagraph: fontCollection is null");
1356 return false;
1357 }
1358 std::unique_ptr<txt::ParagraphBuilder> builder = txt::ParagraphBuilder::CreateTxtBuilder(style, fontCollection);
1359 txt::TextStyle txtStyle;
1360 if (!isStroke && hasShadow) {
1361 txt::TextShadow txtShadow;
1362 txtShadow.color = shadow_.GetColor().GetValue();
1363 txtShadow.offset.fX = shadow_.GetOffset().GetX();
1364 txtShadow.offset.fY = shadow_.GetOffset().GetY();
1365 txtShadow.blur_radius = shadow_.GetBlurRadius();
1366 txtStyle.text_shadows.emplace_back(txtShadow);
1367 }
1368 txtStyle.locale = Localization::GetInstance()->GetFontLocale();
1369 UpdateTextStyleForeground(offset, isStroke, txtStyle, hasShadow);
1370 builder->PushStyle(txtStyle);
1371 builder->AddText(StringUtils::Str8ToStr16(text));
1372 paragraph_ = builder->Build();
1373 return true;
1374 }
1375
UpdateTextStyleForeground(const Offset & offset,bool isStroke,txt::TextStyle & txtStyle,bool hasShadow)1376 void RosenRenderCustomPaint::UpdateTextStyleForeground(
1377 const Offset& offset, bool isStroke, txt::TextStyle& txtStyle, bool hasShadow)
1378 {
1379 using namespace Constants;
1380 if (!isStroke) {
1381 txtStyle.color = ConvertSkColor(fillState_.GetColor());
1382 txtStyle.font_size = fillState_.GetTextStyle().GetFontSize().Value();
1383 ConvertTxtStyle(fillState_.GetTextStyle(), context_, txtStyle);
1384 if (fillState_.GetGradient().IsValid()) {
1385 SkPaint paint;
1386 paint.setStyle(SkPaint::Style::kFill_Style);
1387 UpdatePaintShader(offset, paint, fillState_.GetGradient());
1388 txtStyle.foreground = paint;
1389 txtStyle.has_foreground = true;
1390 }
1391 if (globalState_.HasGlobalAlpha()) {
1392 if (txtStyle.has_foreground) {
1393 txtStyle.foreground.setColor(fillState_.GetColor().GetValue());
1394 txtStyle.foreground.setAlphaf(globalState_.GetAlpha()); // set alpha after color
1395 } else {
1396 SkPaint paint;
1397 paint.setColor(fillState_.GetColor().GetValue());
1398 paint.setAlphaf(globalState_.GetAlpha()); // set alpha after color
1399 InitPaintBlend(paint);
1400 txtStyle.foreground = paint;
1401 txtStyle.has_foreground = true;
1402 }
1403 }
1404 } else {
1405 // use foreground to draw stroke
1406 SkPaint paint = GetStrokePaint();
1407 InitPaintBlend(paint);
1408 ConvertTxtStyle(strokeState_.GetTextStyle(), context_, txtStyle);
1409 txtStyle.font_size = strokeState_.GetTextStyle().GetFontSize().Value();
1410 if (strokeState_.GetGradient().IsValid()) {
1411 UpdatePaintShader(offset, paint, strokeState_.GetGradient());
1412 }
1413 if (hasShadow) {
1414 paint.setColor(shadow_.GetColor().GetValue());
1415 paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle,
1416 RosenDecorationPainter::ConvertRadiusToSigma(shadow_.GetBlurRadius())));
1417 }
1418 txtStyle.foreground = paint;
1419 txtStyle.has_foreground = true;
1420 }
1421 }
1422
HasShadow() const1423 bool RosenRenderCustomPaint::HasShadow() const
1424 {
1425 return !(NearZero(shadow_.GetOffset().GetX()) && NearZero(shadow_.GetOffset().GetY()) &&
1426 NearZero(shadow_.GetBlurRadius()));
1427 }
1428
UpdatePaintShader(const Offset & offset,SkPaint & paint,const Gradient & gradient)1429 void RosenRenderCustomPaint::UpdatePaintShader(const Offset& offset, SkPaint& paint, const Gradient& gradient)
1430 {
1431 SkPoint beginPoint = SkPoint::Make(SkDoubleToScalar(gradient.GetBeginOffset().GetX() + offset.GetX()),
1432 SkDoubleToScalar(gradient.GetBeginOffset().GetY() + offset.GetY()));
1433 SkPoint endPoint = SkPoint::Make(SkDoubleToScalar(gradient.GetEndOffset().GetX() + offset.GetX()),
1434 SkDoubleToScalar(gradient.GetEndOffset().GetY() + offset.GetY()));
1435 SkPoint pts[2] = { beginPoint, endPoint };
1436 std::vector<GradientColor> gradientColors = gradient.GetColors();
1437 std::stable_sort(gradientColors.begin(), gradientColors.end(),
1438 [](auto& colorA, auto& colorB) { return colorA.GetDimension() < colorB.GetDimension(); });
1439 uint32_t colorsSize = gradientColors.size();
1440 SkColor colors[gradientColors.size()];
1441 float pos[gradientColors.size()];
1442 for (uint32_t i = 0; i < colorsSize; ++i) {
1443 const auto& gradientColor = gradientColors[i];
1444 colors[i] = gradientColor.GetColor().GetValue();
1445 pos[i] = gradientColor.GetDimension().Value();
1446 }
1447
1448 #ifdef USE_SYSTEM_SKIA
1449 auto mode = SkShader::kClamp_TileMode;
1450 #else
1451 auto mode = SkTileMode::kClamp;
1452 #endif
1453
1454 sk_sp<SkShader> skShader = nullptr;
1455 if (gradient.GetType() == GradientType::LINEAR) {
1456 skShader = SkGradientShader::MakeLinear(pts, colors, pos, gradientColors.size(), mode);
1457 } else {
1458 if (gradient.GetInnerRadius() <= 0.0 && beginPoint == endPoint) {
1459 skShader = SkGradientShader::MakeRadial(
1460 endPoint, gradient.GetOuterRadius(), colors, pos, gradientColors.size(), mode);
1461 } else {
1462 skShader = SkGradientShader::MakeTwoPointConical(beginPoint, gradient.GetInnerRadius(), endPoint,
1463 gradient.GetOuterRadius(), colors, pos, gradientColors.size(), mode);
1464 }
1465 }
1466 paint.setShader(skShader);
1467 }
1468
Rotate(double angle)1469 void RosenRenderCustomPaint::Rotate(double angle)
1470 {
1471 skCanvas_->rotate(angle * 180 / M_PI);
1472 }
1473
Scale(double x,double y)1474 void RosenRenderCustomPaint::Scale(double x, double y)
1475 {
1476 skCanvas_->scale(x, y);
1477 }
1478
SetTransform(const TransformParam & param)1479 void RosenRenderCustomPaint::SetTransform(const TransformParam& param)
1480 {
1481 auto pipeline = context_.Upgrade();
1482 if (!pipeline) {
1483 return;
1484 }
1485 // use physical pixel to store bitmap
1486 double viewScale = pipeline->GetViewScale();
1487 SkMatrix skMatrix;
1488 skMatrix.setAll(param.scaleX * viewScale, param.skewY * viewScale, param.translateX * viewScale,
1489 param.skewX * viewScale, param.scaleY * viewScale, param.translateY * viewScale, 0, 0, 1);
1490 skCanvas_->setMatrix(skMatrix);
1491 }
1492
Transform(const TransformParam & param)1493 void RosenRenderCustomPaint::Transform(const TransformParam& param)
1494 {
1495 SkMatrix skMatrix;
1496 skMatrix.setAll(param.scaleX, param.skewY, param.translateX, param.skewX, param.scaleY, param.translateY, 0, 0, 1);
1497 skCanvas_->concat(skMatrix);
1498 }
1499
Translate(double x,double y)1500 void RosenRenderCustomPaint::Translate(double x, double y)
1501 {
1502 skCanvas_->translate(x, y);
1503 }
1504
UpdateLineDash(SkPaint & paint)1505 void RosenRenderCustomPaint::UpdateLineDash(SkPaint& paint)
1506 {
1507 if (!strokeState_.GetLineDash().lineDash.empty()) {
1508 auto lineDashState = strokeState_.GetLineDash().lineDash;
1509 SkScalar intervals[lineDashState.size()];
1510 for (size_t i = 0; i < lineDashState.size(); ++i) {
1511 intervals[i] = SkDoubleToScalar(lineDashState[i]);
1512 }
1513 SkScalar phase = SkDoubleToScalar(strokeState_.GetLineDash().dashOffset);
1514 paint.setPathEffect(SkDashPathEffect::Make(intervals, lineDashState.size(), phase));
1515 }
1516 }
1517
InitImageCallbacks()1518 void RosenRenderCustomPaint::InitImageCallbacks()
1519 {
1520 imageObjSuccessCallback_ = [weak = AceType::WeakClaim(this)](
1521 ImageSourceInfo info, const RefPtr<ImageObject>& imageObj) {
1522 auto render = weak.Upgrade();
1523 if (render->loadingSource_ == info) {
1524 render->ImageObjReady(imageObj);
1525 return;
1526 } else {
1527 LOGE("image sourceInfo_ check error, : %{public}s vs %{public}s",
1528 render->loadingSource_.ToString().c_str(), info.ToString().c_str());
1529 }
1530 };
1531
1532 failedCallback_ = [weak = AceType::WeakClaim(this)](ImageSourceInfo info, const std::string& errorMsg = "") {
1533 auto render = weak.Upgrade();
1534 LOGE("tkh failedCallback_");
1535 render->ImageObjFailed();
1536 };
1537
1538 uploadSuccessCallback_ = [weak = AceType::WeakClaim(this)](
1539 ImageSourceInfo sourceInfo, const fml::RefPtr<flutter::CanvasImage>& image) {};
1540
1541 onPostBackgroundTask_ = [weak = AceType::WeakClaim(this)](CancelableTask task) {};
1542 }
1543
ImageObjReady(const RefPtr<ImageObject> & imageObj)1544 void RosenRenderCustomPaint::ImageObjReady(const RefPtr<ImageObject>& imageObj)
1545 {
1546 imageObj_ = imageObj;
1547 if (imageObj_->IsSvg()) {
1548 skiaDom_ = AceType::DynamicCast<SvgSkiaImageObject>(imageObj_)->GetSkiaDom();
1549 currentSource_ = loadingSource_;
1550 CanvasImage canvasImage = canvasImage_;
1551 TaskFunc func = [canvasImage](RenderCustomPaint& iface, const Offset& offset) {
1552 iface.DrawImage(offset, canvasImage, 0, 0);
1553 };
1554 tasks_.emplace_back(func);
1555 MarkNeedRender();
1556 } else {
1557 LOGE("image is not svg");
1558 }
1559 }
1560
ImageObjFailed()1561 void RosenRenderCustomPaint::ImageObjFailed()
1562 {
1563 imageObj_ = nullptr;
1564 skiaDom_ = nullptr;
1565 }
1566
DrawSvgImage(const Offset & offset,const CanvasImage & canvasImage)1567 void RosenRenderCustomPaint::DrawSvgImage(const Offset& offset, const CanvasImage& canvasImage)
1568 {
1569 const auto skCanvas = skCanvas_.get();
1570 // Make the ImageSourceInfo
1571 canvasImage_ = canvasImage;
1572 loadingSource_ = ImageSourceInfo(canvasImage.src);
1573 // get the ImageObject
1574 if (currentSource_ != loadingSource_) {
1575 ImageProvider::FetchImageObject(loadingSource_, imageObjSuccessCallback_, uploadSuccessCallback_,
1576 failedCallback_, GetContext(), true, true, true, renderTaskHolder_, onPostBackgroundTask_);
1577 }
1578
1579 // draw the svg
1580 if (skiaDom_) {
1581 SkRect srcRect;
1582 SkRect dstRect;
1583 Offset startPoint;
1584 double scaleX = 1.0f;
1585 double scaleY = 1.0f;
1586 switch (canvasImage.flag) {
1587 case 0:
1588 srcRect = SkRect::MakeXYWH(0, 0, skiaDom_->containerSize().width(), skiaDom_->containerSize().height());
1589 dstRect = SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy,
1590 skiaDom_->containerSize().width(), skiaDom_->containerSize().height());
1591 break;
1592 case 1: {
1593 srcRect = SkRect::MakeXYWH(0, 0, skiaDom_->containerSize().width(), skiaDom_->containerSize().height());
1594 dstRect = SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy, canvasImage.dWidth, canvasImage.dHeight);
1595 break;
1596 }
1597 case 2: {
1598 srcRect = SkRect::MakeXYWH(canvasImage.sx, canvasImage.sy, canvasImage.sWidth, canvasImage.sHeight);
1599 dstRect = SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy, canvasImage.dWidth, canvasImage.dHeight);
1600 break;
1601 }
1602 default:
1603 break;
1604 }
1605 scaleX = dstRect.width() / srcRect.width();
1606 scaleY = dstRect.height() / srcRect.height();
1607 startPoint = offset + Offset(dstRect.left(), dstRect.top())
1608 - Offset(srcRect.left() * scaleX, srcRect.top() * scaleY);
1609
1610 skCanvas->save();
1611 skCanvas->clipRect(dstRect);
1612 skCanvas->translate(startPoint.GetX(), startPoint.GetY());
1613 skCanvas->scale(scaleX, scaleY);
1614 skiaDom_->render(skCanvas);
1615 skCanvas->restore();
1616 }
1617 }
1618
DrawImage(const Offset & offset,const CanvasImage & canvasImage,double width,double height)1619 void RosenRenderCustomPaint::DrawImage(
1620 const Offset& offset, const CanvasImage& canvasImage, double width, double height)
1621 {
1622 if (!flutter::UIDartState::Current()) {
1623 return;
1624 }
1625
1626 std::string::size_type tmp = canvasImage.src.find(".svg");
1627 if (tmp != std::string::npos) {
1628 DrawSvgImage(offset, canvasImage);
1629 return;
1630 }
1631
1632 auto image = GetImage(canvasImage.src);
1633
1634 if (!image) {
1635 LOGE("image is null");
1636 return;
1637 }
1638 InitImagePaint();
1639 InitPaintBlend(imagePaint_);
1640
1641 switch (canvasImage.flag) {
1642 case 0:
1643 skCanvas_->drawImage(image, canvasImage.dx, canvasImage.dy);
1644 break;
1645 case 1: {
1646 SkRect rect = SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy, canvasImage.dWidth, canvasImage.dHeight);
1647 skCanvas_->drawImageRect(image, rect, &imagePaint_);
1648 break;
1649 }
1650 case 2: {
1651 SkRect dstRect = SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy, canvasImage.dWidth, canvasImage.dHeight);
1652 SkRect srcRect = SkRect::MakeXYWH(canvasImage.sx, canvasImage.sy, canvasImage.sWidth, canvasImage.sHeight);
1653 skCanvas_->drawImageRect(image, srcRect, dstRect, &imagePaint_);
1654 break;
1655 }
1656 default:
1657 break;
1658 }
1659 }
1660
DrawPixelMap(RefPtr<PixelMap> pixelMap,const CanvasImage & canvasImage)1661 void RosenRenderCustomPaint::DrawPixelMap(RefPtr<PixelMap> pixelMap, const CanvasImage& canvasImage)
1662 {
1663 if (!flutter::UIDartState::Current()) {
1664 return;
1665 }
1666
1667 auto context = GetContext().Upgrade();
1668 if (!context) {
1669 return;
1670 }
1671
1672 // get skImage form pixelMap
1673 auto imageInfo = ImageProvider::MakeSkImageInfoFromPixelMap(pixelMap);
1674 SkPixmap imagePixmap(imageInfo, reinterpret_cast<const void*>(pixelMap->GetPixels()), pixelMap->GetRowBytes());
1675
1676 // Step2: Create SkImage and draw it, using gpu or cpu
1677 sk_sp<SkImage> image;
1678 if (!renderTaskHolder_->ioManager) {
1679 image = SkImage::MakeFromRaster(imagePixmap, &PixelMap::ReleaseProc, PixelMap::GetReleaseContext(pixelMap));
1680 } else {
1681 #ifndef GPU_DISABLED
1682 image = SkImage::MakeCrossContextFromPixmap(renderTaskHolder_->ioManager->GetResourceContext().get(),
1683 imagePixmap, true, imagePixmap.colorSpace(), true);
1684 #else
1685 image = SkImage::MakeFromRaster(imagePixmap, &PixelMap::ReleaseProc, PixelMap::GetReleaseContext(pixelMap));
1686 #endif
1687 }
1688 if (!image) {
1689 LOGE("image is null");
1690 return;
1691 }
1692 InitImagePaint();
1693 InitPaintBlend(imagePaint_);
1694 switch (canvasImage.flag) {
1695 case 0:
1696 skCanvas_->drawImage(image, canvasImage.dx, canvasImage.dy);
1697 break;
1698 case 1: {
1699 SkRect rect = SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy, canvasImage.dWidth, canvasImage.dHeight);
1700 skCanvas_->drawImageRect(image, rect, &imagePaint_);
1701 break;
1702 }
1703 case 2: {
1704 SkRect dstRect = SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy, canvasImage.dWidth, canvasImage.dHeight);
1705 SkRect srcRect = SkRect::MakeXYWH(canvasImage.sx, canvasImage.sy, canvasImage.sWidth, canvasImage.sHeight);
1706 skCanvas_->drawImageRect(image, srcRect, dstRect, &imagePaint_);
1707 break;
1708 }
1709 default:
1710 break;
1711 }
1712 }
1713
UpdatePaintShader(const Pattern & pattern,SkPaint & paint)1714 void RosenRenderCustomPaint::UpdatePaintShader(const Pattern& pattern, SkPaint& paint)
1715 {
1716 if (!flutter::UIDartState::Current()) {
1717 return;
1718 }
1719
1720 auto context = GetContext().Upgrade();
1721 if (!context) {
1722 return;
1723 }
1724
1725 auto width = pattern.GetImageWidth();
1726 auto height = pattern.GetImageHeight();
1727 auto image = GreatOrEqual(width, 0) && GreatOrEqual(height, 0)
1728 ? ImageProvider::GetSkImage(pattern.GetImgSrc(), context, Size(width, height))
1729 : ImageProvider::GetSkImage(pattern.GetImgSrc(), context);
1730 if (!image) {
1731 LOGE("image is null");
1732 return;
1733 }
1734 static const LinearMapNode<void (*)(sk_sp<SkImage>, SkPaint&)> staticPattern[] = {
1735 { "no-repeat",
1736 [](sk_sp<SkImage> image, SkPaint& paint) {
1737 #ifdef USE_SYSTEM_SKIA
1738 paint.setShader(image->makeShader(SkShader::kDecal_TileMode, SkShader::kDecal_TileMode, nullptr));
1739 #else
1740 paint.setShader(image->makeShader(SkTileMode::kDecal, SkTileMode::kDecal, nullptr));
1741 #endif
1742 } },
1743 { "repeat",
1744 [](sk_sp<SkImage> image, SkPaint& paint) {
1745 #ifdef USE_SYSTEM_SKIA
1746 paint.setShader(image->makeShader(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, nullptr));
1747 #else
1748 paint.setShader(image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, nullptr));
1749 #endif
1750 } },
1751 { "repeat-x",
1752 [](sk_sp<SkImage> image, SkPaint& paint) {
1753 #ifdef USE_SYSTEM_SKIA
1754 paint.setShader(image->makeShader(SkShader::kRepeat_TileMode, SkShader::kDecal_TileMode, nullptr));
1755 #else
1756 paint.setShader(image->makeShader(SkTileMode::kRepeat, SkTileMode::kDecal, nullptr));
1757 #endif
1758 } },
1759 { "repeat-y",
1760 [](sk_sp<SkImage> image, SkPaint& paint) {
1761 #ifdef USE_SYSTEM_SKIA
1762 paint.setShader(image->makeShader(SkShader::kDecal_TileMode, SkShader::kRepeat_TileMode, nullptr));
1763 #else
1764 paint.setShader(image->makeShader(SkTileMode::kDecal, SkTileMode::kRepeat, nullptr));
1765 #endif
1766 } },
1767 };
1768 auto operatorIter = BinarySearchFindIndex(staticPattern, ArraySize(staticPattern), pattern.GetRepetition().c_str());
1769 if (operatorIter != -1) {
1770 staticPattern[operatorIter].value(image, paint);
1771 }
1772 }
1773
PutImageData(const Offset & offset,const ImageData & imageData)1774 void RosenRenderCustomPaint::PutImageData(const Offset& offset, const ImageData& imageData)
1775 {
1776 if (imageData.data.empty()) {
1777 LOGE("PutImageData failed, image data is empty.");
1778 return;
1779 }
1780 uint32_t* data = new (std::nothrow) uint32_t[imageData.data.size()];
1781 if (data == nullptr) {
1782 LOGE("PutImageData failed, new data is null.");
1783 return;
1784 }
1785
1786 for (uint32_t i = 0; i < imageData.data.size(); ++i) {
1787 data[i] = imageData.data[i].GetValue();
1788 }
1789 SkBitmap skBitmap;
1790 auto imageInfo = SkImageInfo::Make(imageData.dirtyWidth, imageData.dirtyHeight, SkColorType::kBGRA_8888_SkColorType,
1791 SkAlphaType::kOpaque_SkAlphaType);
1792 skBitmap.allocPixels(imageInfo);
1793 skBitmap.setPixels(data);
1794 skCanvas_->drawBitmap(skBitmap, imageData.x, imageData.y);
1795 delete[] data;
1796 }
1797
GetImageData(double left,double top,double width,double height)1798 std::unique_ptr<ImageData> RosenRenderCustomPaint::GetImageData(double left, double top, double width, double height)
1799 {
1800 double viewScale = 1.0;
1801 auto pipeline = context_.Upgrade();
1802 if (pipeline) {
1803 viewScale = pipeline->GetViewScale();
1804 }
1805 // copy the bitmap to tempCanvas
1806 auto imageInfo =
1807 SkImageInfo::Make(width, height, SkColorType::kBGRA_8888_SkColorType, SkAlphaType::kOpaque_SkAlphaType);
1808 SkBitmap tempCache;
1809 double scaledLeft = left * viewScale;
1810 double scaledTop = top * viewScale;
1811 double dirtyWidth = width >= 0 ? width : 0;
1812 double dirtyHeight = height >= 0 ? height : 0;
1813 tempCache.allocPixels(imageInfo);
1814 int32_t size = dirtyWidth * dirtyHeight;
1815 bool isGpuEnable = false;
1816 const uint8_t* pixels = nullptr;
1817 SkCanvas tempCanvas(tempCache);
1818 auto srcRect = SkRect::MakeXYWH(scaledLeft, scaledTop, width * viewScale, height * viewScale);
1819 auto dstRect = SkRect::MakeXYWH(0.0, 0.0, dirtyWidth, dirtyHeight);
1820 #ifdef CANVAS_USE_GPU
1821 if (surface_) {
1822 isGpuEnable = true;
1823 SkBitmap bitmap;
1824 auto imageInfo = SkImageInfo::Make(lastLayoutSize_.Width() * viewScale, lastLayoutSize_.Height() * viewScale,
1825 SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kUnpremul_SkAlphaType);
1826 bitmap.allocPixels(imageInfo);
1827 if (!surface_->readPixels(bitmap, 0, 0)) {
1828 LOGE("surface readPixels failed when GetImageData.");
1829 }
1830 tempCanvas.drawBitmapRect(bitmap, srcRect, dstRect, nullptr);
1831 }
1832 #endif
1833 if (!isGpuEnable) {
1834 tempCanvas.drawBitmapRect(canvasCache_, srcRect, dstRect, nullptr);
1835 }
1836 pixels = tempCache.pixmap().addr8();
1837 if (pixels == nullptr) {
1838 return nullptr;
1839 }
1840 std::unique_ptr<ImageData> imageData = std::make_unique<ImageData>();
1841 imageData->dirtyWidth = dirtyWidth;
1842 imageData->dirtyHeight = dirtyHeight;
1843 // a pixel include 4 data(blue, green, red, alpha)
1844 for (int i = 0; i < size * 4; i += 4) {
1845 auto blue = pixels[i];
1846 auto green = pixels[i + 1];
1847 auto red = pixels[i + 2];
1848 auto alpha = pixels[i + 3];
1849 imageData->data.emplace_back(Color::FromARGB(alpha, red, green, blue));
1850 }
1851 return imageData;
1852 }
1853
GetJsonData(const std::string & path)1854 std::string RosenRenderCustomPaint::GetJsonData(const std::string& path)
1855 {
1856 AssetImageLoader imageLoader;
1857 return imageLoader.LoadJsonData(path, context_.Upgrade());
1858 }
1859
WebGLInit(CanvasRenderContextBase * context)1860 void RosenRenderCustomPaint::WebGLInit(CanvasRenderContextBase* context)
1861 {
1862 webGLContext_ = context;
1863 if (webGLContext_) {
1864 auto pipeline = context_.Upgrade();
1865 if (!pipeline) {
1866 return;
1867 }
1868 double viewScale = pipeline->GetViewScale();
1869 if (!webglBitmap_.readyToDraw()) {
1870 auto imageInfo =
1871 SkImageInfo::Make(GetLayoutSize().Width() * viewScale, GetLayoutSize().Height() * viewScale,
1872 SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kOpaque_SkAlphaType);
1873 webglBitmap_.allocPixels(imageInfo);
1874 #ifdef USE_SYSTEM_SKIA
1875 webglBitmap_.eraseColor(SK_ColorTRANSPARENT);
1876 #endif
1877 }
1878 webGLContext_->SetBitMapPtr(reinterpret_cast<char*>(webglBitmap_.getPixels()),
1879 webglBitmap_.width(), webglBitmap_.height());
1880 }
1881 }
1882
WebGLUpdate()1883 void RosenRenderCustomPaint::WebGLUpdate()
1884 {
1885 LOGD("RosenRenderCustomPaint::WebGLUpdate");
1886 if (skCanvas_ && webglBitmap_.readyToDraw()) {
1887 skCanvas_->save();
1888 /* Do mirror flip */
1889 skCanvas_->setMatrix(SkMatrix::MakeScale(1.0, -1.0));
1890 skCanvas_->drawBitmap(webglBitmap_, 0, -webglBitmap_.height());
1891 skCanvas_->restore();
1892 }
1893 }
1894
DrawBitmapMesh(const RefPtr<OffscreenCanvas> & offscreenCanvas,const std::vector<double> & mesh,int32_t column,int32_t row)1895 void RosenRenderCustomPaint::DrawBitmapMesh(const RefPtr<OffscreenCanvas>& offscreenCanvas,
1896 const std::vector<double>& mesh, int32_t column, int32_t row)
1897 {
1898 std::unique_ptr<ImageData> imageData = offscreenCanvas->GetImageData(0, 0,
1899 offscreenCanvas->GetWidth(), offscreenCanvas->GetHeight());
1900 if (imageData != nullptr) {
1901 if (imageData->data.empty()) {
1902 LOGE("PutImageData failed, image data is empty.");
1903 return;
1904 }
1905 uint32_t* data = new (std::nothrow) uint32_t[imageData->data.size()];
1906 if (data == nullptr) {
1907 LOGE("PutImageData failed, new data is null.");
1908 return;
1909 }
1910
1911 for (uint32_t i = 0; i < imageData->data.size(); ++i) {
1912 data[i] = imageData->data[i].GetValue();
1913 }
1914 SkBitmap skBitmap;
1915 auto imageInfo = SkImageInfo::Make(imageData->dirtyWidth, imageData->dirtyHeight,
1916 SkColorType::kBGRA_8888_SkColorType, SkAlphaType::kOpaque_SkAlphaType);
1917 skBitmap.allocPixels(imageInfo);
1918 skBitmap.setPixels(data);
1919 uint32_t size = mesh.size();
1920 float verts[size];
1921 for (uint32_t i = 0; i < size; i++) {
1922 verts[i] = mesh[i];
1923 }
1924 Mesh(skBitmap, column, row, verts, 0, nullptr);
1925 delete[] data;
1926 }
1927 LOGD("RosenRenderCustomPaint::DrawBitmapMesh");
1928 }
1929
Mesh(SkBitmap & bitmap,int column,int row,const float * vertices,const int * colors,const SkPaint * paint)1930 void RosenRenderCustomPaint::Mesh(SkBitmap& bitmap, int column, int row,
1931 const float* vertices, const int* colors, const SkPaint* paint)
1932 {
1933 const int vertCounts = (column + 1) * (row + 1);
1934 int32_t size = 6;
1935 const int indexCount = column * row * size;
1936 uint32_t flags = SkVertices::kHasTexCoords_BuilderFlag;
1937 if (colors) {
1938 flags |= SkVertices::kHasColors_BuilderFlag;
1939 }
1940 SkVertices::Builder builder(SkVertices::kTriangles_VertexMode, vertCounts, indexCount, flags);
1941 if (memcpy_s(builder.positions(), vertCounts * sizeof(SkPoint), vertices, vertCounts * sizeof(SkPoint)) != EOK) {
1942 return;
1943 }
1944 if (colors) {
1945 if (memcpy_s(builder.colors(), vertCounts * sizeof(SkColor), colors, vertCounts * sizeof(SkColor)) != EOK) {
1946 return;
1947 }
1948 }
1949 SkPoint* texsPoint = builder.texCoords();
1950 uint16_t* indices = builder.indices();
1951 const SkScalar height = SkIntToScalar(bitmap.height());
1952 const SkScalar width = SkIntToScalar(bitmap.width());
1953 if (row == 0) {
1954 LOGE("row is zero");
1955 return;
1956 }
1957 if (column == 0) {
1958 LOGE("column is zero");
1959 return;
1960 }
1961 const SkScalar dy = height / row;
1962 const SkScalar dx = width / column;
1963
1964 SkPoint* texsPit = texsPoint;
1965 SkScalar y = 0;
1966 for (int i = 0; i <= row; i++) {
1967 if (i == row) {
1968 y = height; // to ensure numerically we hit h exactly
1969 }
1970 SkScalar x = 0;
1971 for (int j = 0; j < column; j++) {
1972 texsPit->set(x, y);
1973 texsPit += 1;
1974 x += dx;
1975 }
1976 texsPit->set(width, y);
1977 texsPit += 1;
1978 y += dy;
1979 }
1980
1981 uint16_t* dexs = indices;
1982 int index = 0;
1983 for (int i = 0; i < row; i++) {
1984 for (int j = 0; j < column; j++) {
1985 *dexs++ = index;
1986 *dexs++ = index + column + 1;
1987 *dexs++ = index + column + 2;
1988
1989 *dexs++ = index;
1990 *dexs++ = index + column + 2;
1991 *dexs++ = index + 1;
1992
1993 index += 1;
1994 }
1995 index += 1;
1996 }
1997
1998 SkPaint tempPaint;
1999 if (paint) {
2000 tempPaint = *paint;
2001 }
2002 sk_sp<SkColorFilter> colorFter;
2003 sk_sp<SkShader> shader;
2004 sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
2005 #ifdef USE_SYSTEM_SKIA
2006 shader = image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
2007 #else
2008 shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp);
2009 #endif
2010 if (colorFter) {
2011 shader = shader->makeWithColorFilter(colorFter);
2012 }
2013 tempPaint.setShader(shader);
2014 skCanvas_->drawVertices(builder.detach(), SkBlendMode::kModulate, tempPaint);
2015 }
2016
GetImage(const std::string & src)2017 sk_sp<SkImage> RosenRenderCustomPaint::GetImage(const std::string& src)
2018 {
2019 if (!imageCache_) {
2020 imageCache_ = ImageCache::Create();
2021 imageCache_->SetCapacity(IMAGE_CACHE_COUNT);
2022 }
2023 auto cacheImage = imageCache_->GetCacheImage(src);
2024 if (cacheImage && cacheImage->imagePtr) {
2025 return cacheImage->imagePtr->image();
2026 }
2027
2028 auto context = GetContext().Upgrade();
2029 if (!context) {
2030 return nullptr;
2031 }
2032
2033 auto image = ImageProvider::GetSkImage(src, context);
2034 if (image) {
2035 auto rasterizedImage = image->makeRasterImage();
2036 auto canvasImage = flutter::CanvasImage::Create();
2037 canvasImage->set_image({ rasterizedImage, renderTaskHolder_->unrefQueue });
2038 imageCache_->CacheImage(src, std::make_shared<CachedImage>(canvasImage));
2039 return rasterizedImage;
2040 }
2041
2042 return image;
2043 }
2044 } // namespace OHOS::Ace
2045