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_offscreen_canvas.h"
17
18 #include <cmath>
19 #include <sstream>
20
21 #include "txt/paragraph_builder.h"
22 #include "txt/paragraph_style.h"
23 #ifndef USE_ROSEN_DRAWING
24 #include "include/core/SkBlendMode.h"
25 #include "include/core/SkColor.h"
26 #include "include/core/SkMaskFilter.h"
27 #include "include/core/SkPoint.h"
28 #ifndef NEW_SKIA
29 #include "include/effects/SkBlurImageFilter.h"
30 #else
31 #include "include/core/SkColorFilter.h"
32 #include "include/effects/SkImageFilters.h"
33 #endif
34 #endif
35 #include "include/effects/SkDashPathEffect.h"
36 #include "include/effects/SkGradientShader.h"
37 #include "include/encode/SkJpegEncoder.h"
38 #include "include/encode/SkPngEncoder.h"
39 #include "include/encode/SkWebpEncoder.h"
40 #include "include/utils/SkBase64.h"
41 #include "include/utils/SkParsePath.h"
42
43 #include "base/i18n/localization.h"
44 #include "base/image/pixel_map.h"
45 #include "base/log/log.h"
46 #include "base/utils/string_utils.h"
47 #ifndef NEW_SKIA
48 #include "core/components/common/painter/flutter_decoration_painter.h"
49 #else
50 #include "core/components/common/painter/rosen_decoration_painter.h"
51 #endif
52 #include "core/components/font/constants_converter.h"
53 #ifndef NEW_SKIA
54 #include "core/components/font/flutter_font_collection.h"
55 #else
56 #include "core/components/font/rosen_font_collection.h"
57 #endif
58 #ifdef USE_ROSEN_DRAWING
59 #include "core/components_ng/render/drawing.h"
60 #endif
61 #include "core/image/image_provider.h"
62
63 namespace OHOS::Ace {
64 namespace {
65 constexpr double HANGING_PERCENT = 0.8;
66 #ifndef USE_ROSEN_DRAWING
67 template<typename T, typename N>
ConvertEnumToSkEnum(T key,const LinearEnumMapNode<T,N> * map,size_t length,N defaultValue)68 N ConvertEnumToSkEnum(T key, const LinearEnumMapNode<T, N>* map, size_t length, N defaultValue)
69 {
70 int64_t index = BinarySearchFindIndex(map, length, key);
71 return index != -1 ? map[index].value : defaultValue;
72 }
73 #else
74 template<typename T, typename N>
ConvertEnumToDrawingEnum(T key,const LinearEnumMapNode<T,N> * map,size_t length,N defaultValue)75 N ConvertEnumToDrawingEnum(T key, const LinearEnumMapNode<T, N>* map, size_t length, N defaultValue)
76 {
77 int64_t index = BinarySearchFindIndex(map, length, key);
78 return index != -1 ? map[index].value : defaultValue;
79 }
80 #endif
81
82 constexpr double DEFAULT_QUALITY = 0.92;
83 constexpr int32_t MAX_LENGTH = 2048 * 2048;
84 const std::string UNSUPPORTED = "data:image/png";
85 const std::string URL_PREFIX = "data:";
86 const std::string URL_SYMBOL = ";base64,";
87 const std::string IMAGE_PNG = "image/png";
88 const std::string IMAGE_JPEG = "image/jpeg";
89 const std::string IMAGE_WEBP = "image/webp";
90 constexpr double HALF_CIRCLE_ANGLE = 180.0;
91 constexpr double FULL_CIRCLE_ANGLE = 360.0;
92
93 // If args is empty or invalid format, use default: image/png
GetMimeType(const std::string & args)94 std::string GetMimeType(const std::string& args)
95 {
96 std::string type = args;
97 for (size_t i = 0; i < type.size(); ++i) {
98 type[i] = static_cast<uint8_t>(tolower(type[i]));
99 }
100 return type;
101 }
102
103 // Quality need between 0.0 and 1.0 for MimeType jpeg and webp
GetQuality(const std::string & args,const double quality)104 double GetQuality(const std::string& args, const double quality)
105 {
106 std::string type = args;
107 auto mimeType = GetMimeType(type);
108 if (mimeType != IMAGE_JPEG && mimeType != IMAGE_WEBP) {
109 return DEFAULT_QUALITY;
110 }
111 if (quality < 0.0 || quality > 1.0) {
112 return DEFAULT_QUALITY;
113 }
114 return quality;
115 }
116
117 #ifndef USE_ROSEN_DRAWING
118 const LinearEnumMapNode<CompositeOperation, SkBlendMode> SK_BLEND_MODE_TABLE[] = {
119 { CompositeOperation::SOURCE_OVER, SkBlendMode::kSrcOver },
120 { CompositeOperation::SOURCE_ATOP, SkBlendMode::kSrcATop },
121 { CompositeOperation::SOURCE_IN, SkBlendMode::kSrcIn },
122 { CompositeOperation::SOURCE_OUT, SkBlendMode::kSrcOut },
123 { CompositeOperation::DESTINATION_OVER, SkBlendMode::kDstOver },
124 { CompositeOperation::DESTINATION_ATOP, SkBlendMode::kDstATop },
125 { CompositeOperation::DESTINATION_IN, SkBlendMode::kDstIn },
126 { CompositeOperation::DESTINATION_OUT, SkBlendMode::kDstOut },
127 { CompositeOperation::LIGHTER, SkBlendMode::kLighten },
128 { CompositeOperation::COPY, SkBlendMode::kSrc },
129 { CompositeOperation::XOR, SkBlendMode::kXor },
130 };
131 constexpr size_t BLEND_MODE_SIZE = ArraySize(SK_BLEND_MODE_TABLE);
132 #else
133 const LinearEnumMapNode<CompositeOperation, RSBlendMode> DRAWING_BLEND_MODE_TABLE[] = {
134 { CompositeOperation::SOURCE_OVER, RSBlendMode::SRC_OVER },
135 { CompositeOperation::SOURCE_ATOP, RSBlendMode::SRC_ATOP },
136 { CompositeOperation::SOURCE_IN, RSBlendMode::SRC_IN },
137 { CompositeOperation::SOURCE_OUT, RSBlendMode::SRC_OUT },
138 { CompositeOperation::DESTINATION_OVER, RSBlendMode::DST_OVER },
139 { CompositeOperation::DESTINATION_ATOP, RSBlendMode::DST_ATOP },
140 { CompositeOperation::DESTINATION_IN, RSBlendMode::DST_IN },
141 { CompositeOperation::DESTINATION_OUT, RSBlendMode::DST_OUT },
142 { CompositeOperation::LIGHTER, RSBlendMode::LIGHTEN },
143 { CompositeOperation::COPY, RSBlendMode::SRC },
144 { CompositeOperation::XOR, RSBlendMode::XOR },
145 };
146 constexpr size_t BLEND_MODE_SIZE = ArraySize(DRAWING_BLEND_MODE_TABLE);
147 #endif
148 } // namespace
149
RosenRenderOffscreenCanvas(const WeakPtr<PipelineBase> & context,int32_t width,int32_t height)150 RosenRenderOffscreenCanvas::RosenRenderOffscreenCanvas(const WeakPtr<PipelineBase>& context,
151 int32_t width, int32_t height)
152 {
153 pipelineContext_ = context;
154 width_ = width;
155 height_ = height;
156 #ifndef USE_ROSEN_DRAWING
157 auto imageInfo = SkImageInfo::Make(width, height, SkColorType::kRGBA_8888_SkColorType,
158 SkAlphaType::kOpaque_SkAlphaType);
159 skBitmap_.allocPixels(imageInfo);
160 cacheBitmap_.allocPixels(imageInfo);
161 skBitmap_.eraseColor(SK_ColorTRANSPARENT);
162 cacheBitmap_.eraseColor(SK_ColorTRANSPARENT);
163 skCanvas_ = std::make_unique<SkCanvas>(skBitmap_);
164 cacheCanvas_ = std::make_unique<SkCanvas>(cacheBitmap_);
165 #else
166 RSBitmapFormat format { RSColorType::COLORTYPE_RGBA_8888,
167 RSAlphaType::ALPHATYPE_OPAQUE };
168 bitmap_.Build(width, height, format);
169 cacheBitmap_.Build(width, height, format);
170 bitmap_.ClearWithColor(RSColor::COLOR_TRANSPARENT);
171 cacheBitmap_.ClearWithColor(RSColor::COLOR_TRANSPARENT);
172 canvas_->Bind(bitmap_);
173 cacheCanvas_->Bind(cacheBitmap_);
174 #endif
175 InitFilterFunc();
176 InitImageCallbacks();
177 }
AddRect(const Rect & rect)178 void RosenRenderOffscreenCanvas::AddRect(const Rect& rect)
179 {
180 #ifndef USE_ROSEN_DRAWING
181 SkRect skRect = SkRect::MakeLTRB(rect.Left(), rect.Top(),
182 rect.Right(), rect.Bottom());
183 skPath_.addRect(skRect);
184 #else
185 RSRect drawingRect(rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
186 path_.AddRect(drawingRect);
187 #endif
188 }
189
SetFillRuleForPath(const CanvasFillRule & rule)190 void RosenRenderOffscreenCanvas::SetFillRuleForPath(const CanvasFillRule& rule)
191 {
192 if (rule == CanvasFillRule::NONZERO) {
193 #ifndef USE_ROSEN_DRAWING
194 #ifndef NEW_SKIA
195 skPath_.setFillType(SkPath::FillType::kWinding_FillType);
196 #else
197 skPath_.setFillType(SkPathFillType::kWinding);
198 #endif
199 } else if (rule == CanvasFillRule::EVENODD) {
200 #ifndef NEW_SKIA
201 skPath_.setFillType(SkPath::FillType::kEvenOdd_FillType);
202 #else
203 skPath_.setFillType(SkPathFillType::kEvenOdd);
204 #endif
205 #else
206 if (rule == CanvasFillRule::NONZERO) {
207 path_.SetFillStyle(RSPathFillType::WINDING);
208 } else if (rule == CanvasFillRule::EVENODD) {
209 path_.SetFillStyle(RSPathFillType::EVENTODD);
210 }
211 #endif
212 }
213 }
214
SetFillRuleForPath2D(const CanvasFillRule & rule)215 void RosenRenderOffscreenCanvas::SetFillRuleForPath2D(const CanvasFillRule& rule)
216 {
217 #ifndef USE_ROSEN_DRAWING
218 if (rule == CanvasFillRule::NONZERO) {
219 #ifndef NEW_SKIA
220 skPath2d_.setFillType(SkPath::FillType::kWinding_FillType);
221 #else
222 skPath2d_.setFillType(SkPathFillType::kWinding);
223 #endif
224 } else if (rule == CanvasFillRule::EVENODD) {
225 #ifndef NEW_SKIA
226 skPath2d_.setFillType(SkPath::FillType::kEvenOdd_FillType);
227 #else
228 skPath2d_.setFillType(SkPathFillType::kEvenOdd);
229 #endif
230 }
231 #else
232 if (rule == CanvasFillRule::NONZERO) {
233 path2d_.SetFillStyle(RSPathFillType::WINDING);
234 } else if (rule == CanvasFillRule::EVENODD) {
235 path2d_.SetFillStyle(RSPathFillType::EVENTODD);
236 }
237 #endif
238 }
239
ParsePath2D(const RefPtr<CanvasPath2D> & path)240 void RosenRenderOffscreenCanvas::ParsePath2D(const RefPtr<CanvasPath2D>& path)
241 {
242 for (const auto& [cmd, args] : path->GetCaches()) {
243 switch (cmd) {
244 case PathCmd::CMDS: {
245 Path2DAddPath(args);
246 break;
247 }
248 case PathCmd::TRANSFORM: {
249 Path2DSetTransform(args);
250 break;
251 }
252 case PathCmd::MOVE_TO: {
253 Path2DMoveTo(args);
254 break;
255 }
256 case PathCmd::LINE_TO: {
257 Path2DLineTo(args);
258 break;
259 }
260 case PathCmd::ARC: {
261 Path2DArc(args);
262 break;
263 }
264 case PathCmd::ARC_TO: {
265 Path2DArcTo(args);
266 break;
267 }
268 case PathCmd::QUADRATIC_CURVE_TO: {
269 Path2DQuadraticCurveTo(args);
270 break;
271 }
272 case PathCmd::BEZIER_CURVE_TO: {
273 Path2DBezierCurveTo(args);
274 break;
275 }
276 case PathCmd::ELLIPSE: {
277 Path2DEllipse(args);
278 break;
279 }
280 case PathCmd::RECT: {
281 Path2DRect(args);
282 break;
283 }
284 case PathCmd::CLOSE_PATH: {
285 Path2DClosePath(args);
286 break;
287 }
288 default: {
289 break;
290 }
291 }
292 }
293 }
294
Fill()295 void RosenRenderOffscreenCanvas::Fill()
296 {
297 #ifndef USE_ROSEN_DRAWING
298 SkPaint paint;
299 paint.setAntiAlias(antiAlias_);
300 paint.setColor(fillState_.GetColor().GetValue());
301 paint.setStyle(SkPaint::Style::kFill_Style);
302 if (HasShadow()) {
303 #ifndef NEW_SKIA
304 FlutterDecorationPainter::PaintShadow(skPath_, shadow_, skCanvas_.get());
305 #else
306 RosenDecorationPainter::PaintShadow(skPath_, shadow_, skCanvas_.get());
307 #endif
308 }
309 if (fillState_.GetGradient().IsValid()) {
310 UpdatePaintShader(paint, fillState_.GetGradient());
311 }
312 if (fillState_.GetPattern().IsValid()) {
313 UpdatePaintShader(fillState_.GetPattern(), paint);
314 }
315 if (globalState_.HasGlobalAlpha()) {
316 paint.setAlphaf(globalState_.GetAlpha());
317 }
318 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
319 skCanvas_->drawPath(skPath_, paint);
320 } else {
321 InitCachePaint();
322 cacheCanvas_->drawPath(skPath_, paint);
323 #ifndef NEW_SKIA
324 skCanvas_->drawBitmap(cacheBitmap_, 0, 0, &cachePaint_);
325 #else
326 skCanvas_->drawImage(cacheBitmap_.asImage(), 0, 0, SkSamplingOptions(), &cachePaint_);
327 #endif
328 cacheBitmap_.eraseColor(0);
329 }
330 #else
331 RSBrush brush;
332 brush.SetAntiAlias(antiAlias_);
333 brush.SetColor(fillState_.GetColor().GetValue());
334 if (HasShadow()) {
335 RosenDecorationPainter::PaintShadow(path_, shadow_, canvas_.get());
336 }
337 if (fillState_.GetGradient().IsValid()) {
338 UpdatePaintShader(nullptr, &brush, fillState_.GetGradient());
339 }
340 if (fillState_.GetPattern().IsValid()) {
341 UpdatePaintShader(fillState_.GetPattern(), nullptr, &brush);
342 }
343 if (globalState_.HasGlobalAlpha()) {
344 brush.SetAlphaF(globalState_.GetAlpha());
345 }
346 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
347 canvas_->AttachBrush(brush);
348 canvas_->DrawPath(path_);
349 canvas_->DetachBrush();
350 } else {
351 InitCachePaint();
352 cacheCanvas_->AttachBrush(brush);
353 cacheCanvas_->DrawPath(path_);
354 cacheCanvas_->DetachBrush();
355 canvas_->AttachBrush(cacheBrush_);
356 canvas_->DrawBitmap(cacheBitmap_, 0, 0);
357 canvas_->DetachBrush();
358 cacheBitmap_.ClearWithColor(RSColor::COLOR_TRANSPARENT);
359 }
360 #endif
361 }
362
Fill(const RefPtr<CanvasPath2D> & path)363 void RosenRenderOffscreenCanvas::Fill(const RefPtr<CanvasPath2D>& path)
364 {
365 if (path == nullptr) {
366 LOGE("Fill failed in offscreenCanvas, target path is null.");
367 return;
368 }
369 ParsePath2D(path);
370 Path2DFill();
371 #ifndef USE_ROSEN_DRAWING
372 skPath2d_.reset();
373 #else
374 path2d_.Reset();
375 #endif
376 }
377
Clip()378 void RosenRenderOffscreenCanvas::Clip()
379 {
380 #ifndef USE_ROSEN_DRAWING
381 skCanvas_->clipPath(skPath_);
382 #else
383 canvas_->ClipPath(path_, RSClipOp::INTERSECT, false);
384 #endif
385 }
386
Clip(const RefPtr<CanvasPath2D> & path)387 void RosenRenderOffscreenCanvas::Clip(const RefPtr<CanvasPath2D>& path)
388 {
389 if (path == nullptr) {
390 LOGE("Clip failed in offscreenCanvas, target path is null.");
391 return;
392 }
393 ParsePath2D(path);
394 Path2DClip();
395 #ifndef USE_ROSEN_DRAWING
396 skPath2d_.reset();
397 #else
398 path2d_.Reset();
399 #endif
400 }
401
FillRect(Rect rect)402 void RosenRenderOffscreenCanvas::FillRect(Rect rect)
403 {
404 #ifndef USE_ROSEN_DRAWING
405 SkPaint paint;
406 paint.setAntiAlias(antiAlias_);
407 paint.setColor(fillState_.GetColor().GetValue());
408 paint.setStyle(SkPaint::Style::kFill_Style);
409 SkRect skRect = SkRect::MakeLTRB(rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
410 if (HasShadow()) {
411 SkPath path;
412 path.addRect(skRect);
413 #ifndef NEW_SKIA
414 FlutterDecorationPainter::PaintShadow(path, shadow_, skCanvas_.get());
415 #else
416 RosenDecorationPainter::PaintShadow(path, shadow_, skCanvas_.get());
417 #endif
418 }
419 if (fillState_.GetGradient().IsValid()) {
420 UpdatePaintShader(paint, fillState_.GetGradient());
421 }
422 if (fillState_.GetPattern().IsValid()) {
423 UpdatePaintShader(fillState_.GetPattern(), paint);
424 }
425 if (globalState_.HasGlobalAlpha()) {
426 paint.setAlphaf(globalState_.GetAlpha()); // update the global alpha after setting the color
427 }
428 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
429 skCanvas_->drawRect(skRect, paint);
430 } else {
431 InitCachePaint();
432 cacheCanvas_->drawRect(skRect, paint);
433 #ifndef NEW_SKIA
434 skCanvas_->drawBitmap(cacheBitmap_, 0, 0, &cachePaint_);
435 #else
436 skCanvas_->drawImage(cacheBitmap_.asImage(), 0, 0, SkSamplingOptions(), &cachePaint_);
437 #endif
438 cacheBitmap_.eraseColor(0);
439 }
440 #else
441 RSBrush brush;
442 brush.SetAntiAlias(antiAlias_);
443 brush.SetColor(fillState_.GetColor().GetValue());
444 RSRect drawingRect(rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
445 if (HasShadow()) {
446 RSRecordingPath path;
447 path.AddRect(drawingRect);
448 RosenDecorationPainter::PaintShadow(path, shadow_, canvas_.get());
449 }
450 if (fillState_.GetGradient().IsValid()) {
451 UpdatePaintShader(nullptr, &brush, fillState_.GetGradient());
452 }
453 if (fillState_.GetPattern().IsValid()) {
454 UpdatePaintShader(fillState_.GetPattern(), nullptr, &brush);
455 }
456 if (globalState_.HasGlobalAlpha()) {
457 brush.SetAlphaF(globalState_.GetAlpha()); // update the global alpha after setting the color
458 }
459 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
460 canvas_->AttachBrush(brush);
461 canvas_->DrawRect(drawingRect);
462 canvas_->DetachBrush();
463 } else {
464 InitCachePaint();
465 cacheCanvas_->AttachBrush(brush);
466 cacheCanvas_->DrawRect(drawingRect);
467 cacheCanvas_->DetachBrush();
468 canvas_->AttachBrush(cacheBrush_);
469 canvas_->DrawBitmap(cacheBitmap_, 0, 0);
470 canvas_->DetachBrush();
471 cacheBitmap_.ClearWithColor(RSColor::COLOR_TRANSPARENT);
472 }
473 #endif
474 }
475
PutImageData(const ImageData & imageData)476 void RosenRenderOffscreenCanvas::PutImageData(const ImageData& imageData)
477 {
478 if (imageData.data.empty()) {
479 return;
480 }
481 uint32_t* data = new (std::nothrow)uint32_t[imageData.data.size()];
482 if (data == nullptr) {
483 return;
484 }
485
486 for (uint32_t i = 0; i < imageData.data.size(); ++i) {
487 data[i] = imageData.data[i].GetValue();
488 }
489 #ifndef USE_ROSEN_DRAWING
490 SkBitmap skBitmap;
491 auto imageInfo = SkImageInfo::Make(imageData.dirtyWidth, imageData.dirtyHeight, SkColorType::kBGRA_8888_SkColorType,
492 SkAlphaType::kOpaque_SkAlphaType);
493 skBitmap.allocPixels(imageInfo);
494 skBitmap.setPixels(data);
495 #ifndef NEW_SKIA
496 skCanvas_->drawBitmap(skBitmap, imageData.x, imageData.y);
497 #else
498 skCanvas_->drawImage(skBitmap.asImage(), imageData.x, imageData.y, SkSamplingOptions());
499 #endif
500 #else
501 RSBitmap bitmap;
502 RSBitmapFormat format { RSColorType::COLORTYPE_BGRA_8888,
503 RSAlphaType::ALPHATYPE_OPAQUE };
504 bitmap.Build(imageData.dirtyWidth, imageData.dirtyHeight, format);
505 bitmap.SetPixels(data);
506 canvas_->DrawBitmap(bitmap, imageData.x, imageData.y);
507 #endif
508 delete[] data;
509 }
510
SetPaintImage()511 void RosenRenderOffscreenCanvas::SetPaintImage()
512 {
513 float matrix[20] = {0};
514 matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.0f;
515 #ifndef USE_ROSEN_DRAWING
516 #ifdef USE_SYSTEM_SKIA
517 imagePaint_.setColorFilter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
518 #else
519 imagePaint_.setColorFilter(SkColorFilters::Matrix(matrix));
520 #endif
521
522 imagePaint_.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, 0));
523 #ifndef NEW_SKIA
524 imagePaint_.setImageFilter(SkBlurImageFilter::Make(0, 0, nullptr));
525 #else
526 imagePaint_.setImageFilter(SkImageFilters::Blur(0, 0, nullptr));
527 #endif
528 #else
529 auto filter = imageBrush_.GetFilter();
530 RSColorMatrix colorMatrix;
531 colorMatrix.SetArray(matrix);
532 filter.SetColorFilter(RSColorFilter::CreateMatrixColorFilter(colorMatrix));
533 filter.SetMaskFilter(RSMaskFilter::CreateBlurMaskFilter(RSBlurType::NORMAL, 0));
534 filter.SetImageFilter(RSImageFilter::CreateBlurImageFilter(0, 0, RSTileMode::DECAL, nullptr));
535 imageBrush_.SetFilter(filter);
536 #endif
537
538 SetDropShadowFilter("0px 0px 0px black");
539 std::string filterType, filterParam;
540 if (!GetFilterType(filterType, filterParam)) {
541 return;
542 }
543 if (filterFunc_.find(filterType) != filterFunc_.end()) {
544 filterFunc_[filterType](filterParam);
545 }
546 }
547
InitImagePaint()548 void RosenRenderOffscreenCanvas::InitImagePaint()
549 {
550 #ifndef USE_ROSEN_DRAWING
551 #ifndef NEW_SKIA
552 if (smoothingEnabled_) {
553 if (smoothingQuality_ == "low") {
554 imagePaint_.setFilterQuality(SkFilterQuality::kLow_SkFilterQuality);
555 } else if (smoothingQuality_ == "medium") {
556 imagePaint_.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality);
557 } else if (smoothingQuality_ == "high") {
558 imagePaint_.setFilterQuality(SkFilterQuality::kHigh_SkFilterQuality);
559 } else {
560 LOGE("Unsupported Quality type:%{public}s", smoothingQuality_.c_str());
561 }
562 } else {
563 imagePaint_.setFilterQuality(SkFilterQuality::kNone_SkFilterQuality);
564 }
565 #else
566 if (smoothingEnabled_) {
567 if (smoothingQuality_ == "low") {
568 options_ = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone);
569 } else if (smoothingQuality_ == "medium") {
570 options_ = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
571 } else if (smoothingQuality_ == "high") {
572 options_ = SkSamplingOptions(SkCubicResampler { 1 / 3.0f, 1 / 3.0f });
573 } else {
574 LOGE("Unsupported Quality type:%{public}s", smoothingQuality_.c_str());
575 }
576 } else {
577 options_ = SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone);
578 }
579 #endif
580 #else
581 auto filter = imageBrush_.GetFilter();
582 if (smoothingEnabled_) {
583 if (smoothingQuality_ == "low") {
584 options_ = RSSamplingOptions(RSFilterMode::LINEAR, RSMipmapMode::NONE);
585 filter.SetFilterQuality(RSFilter::FilterQuality::LOW);
586 imageBrush_.SetFilter(filter);
587 } else if (smoothingQuality_ == "medium") {
588 options_ = RSSamplingOptions(RSFilterMode::LINEAR, RSMipmapMode::LINEAR);
589 filter.SetFilterQuality(RSFilter::FilterQuality::MEDIUM);
590 imageBrush_.SetFilter(filter);
591 } else if (smoothingQuality_ == "high") {
592 options_ = RSSamplingOptions(RSCubicResampler::Mitchell());
593 filter.SetFilterQuality(RSFilter::FilterQuality::HIGH);
594 imageBrush_.SetFilter(filter);
595 } else {
596 LOGE("Unsupported Quality type:%{public}s", smoothingQuality_.c_str());
597 }
598 } else {
599 options_ = RSSamplingOptions(RSFilterMode::NEAREST, RSMipmapMode::NONE);
600 filter.SetFilterQuality(RSFilter::FilterQuality::NONE);
601 imageBrush_.SetFilter(filter);
602 }
603 #endif
604 SetPaintImage();
605 }
606
InitImageCallbacks()607 void RosenRenderOffscreenCanvas::InitImageCallbacks()
608 {
609 imageObjSuccessCallback_ = [weak = AceType::WeakClaim(this)](
610 ImageSourceInfo info, const RefPtr<ImageObject>& imageObj) {
611 auto render = weak.Upgrade();
612 if (render->loadingSource_ == info) {
613 render->ImageObjReady(imageObj);
614 return;
615 } else {
616 LOGE("image sourceInfo_ check error, : %{public}s vs %{public}s",
617 render->loadingSource_.ToString().c_str(), info.ToString().c_str());
618 }
619 };
620
621 failedCallback_ = [weak = AceType::WeakClaim(this)](ImageSourceInfo info, const std::string& errorMsg = "") {
622 auto render = weak.Upgrade();
623 LOGE("failedCallback_");
624 render->ImageObjFailed();
625 };
626 uploadSuccessCallback_ = [weak = AceType::WeakClaim(this)](
627 ImageSourceInfo sourceInfo, const RefPtr<NG::CanvasImage>& image) {};
628
629 onPostBackgroundTask_ = [weak = AceType::WeakClaim(this)](CancelableTask task) {};
630 }
631
ImageObjReady(const RefPtr<ImageObject> & imageObj)632 void RosenRenderOffscreenCanvas::ImageObjReady(const RefPtr<ImageObject>& imageObj)
633 {
634 if (imageObj->IsSvg()) {
635 skiaDom_ = AceType::DynamicCast<SvgSkiaImageObject>(imageObj)->GetSkiaDom();
636 currentSource_ = loadingSource_;
637 } else {
638 LOGE("image is not svg");
639 }
640 }
641
ImageObjFailed()642 void RosenRenderOffscreenCanvas::ImageObjFailed()
643 {
644 loadingSource_.SetSrc("");
645 currentSource_.SetSrc("");
646 skiaDom_ = nullptr;
647 }
648
DrawSvgImage(const CanvasImage & canvasImage)649 void RosenRenderOffscreenCanvas::DrawSvgImage(const CanvasImage& canvasImage)
650 {
651 #ifndef USE_ROSEN_DRAWING
652 const auto skCanvas =
653 globalState_.GetType() == CompositeOperation::SOURCE_OVER ? skCanvas_.get() : cacheCanvas_.get();
654 #else
655 const auto drawingCanvas =
656 globalState_.GetType() == CompositeOperation::SOURCE_OVER ? canvas_.get() : cacheCanvas_.get();
657 #endif
658
659 // Make the ImageSourceInfo
660 canvasImage_ = canvasImage;
661 loadingSource_ = ImageSourceInfo(canvasImage.src);
662
663 // get the ImageObject
664 if (currentSource_ != loadingSource_) {
665 ImageProvider::FetchImageObject(loadingSource_, imageObjSuccessCallback_, uploadSuccessCallback_,
666 failedCallback_, pipelineContext_, true, true, true, onPostBackgroundTask_);
667 }
668
669 // draw the svg
670 #ifndef USE_ROSEN_DRAWING
671 if (skiaDom_) {
672 SkRect srcRect;
673 SkRect dstRect;
674 Offset startPoint;
675 double scaleX = 1.0f;
676 double scaleY = 1.0f;
677 switch (canvasImage.flag) {
678 case 0:
679 srcRect = SkRect::MakeXYWH(0, 0, skiaDom_->containerSize().width(), skiaDom_->containerSize().height());
680 dstRect = SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy,
681 skiaDom_->containerSize().width(), skiaDom_->containerSize().height());
682 break;
683 case 1: {
684 srcRect = SkRect::MakeXYWH(0, 0, skiaDom_->containerSize().width(), skiaDom_->containerSize().height());
685 dstRect = SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy, canvasImage.dWidth, canvasImage.dHeight);
686 break;
687 }
688 case 2: {
689 srcRect = SkRect::MakeXYWH(canvasImage.sx, canvasImage.sy, canvasImage.sWidth, canvasImage.sHeight);
690 dstRect = SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy, canvasImage.dWidth, canvasImage.dHeight);
691 break;
692 }
693 default:
694 break;
695 }
696 scaleX = dstRect.width() / srcRect.width();
697 scaleY = dstRect.height() / srcRect.height();
698 startPoint = Offset(dstRect.left(), dstRect.top())
699 - Offset(srcRect.left() * scaleX, srcRect.top() * scaleY);
700
701 skCanvas->save();
702 skCanvas->clipRect(dstRect);
703 skCanvas->translate(startPoint.GetX(), startPoint.GetY());
704 skCanvas->scale(scaleX, scaleY);
705 skiaDom_->render(skCanvas);
706 skCanvas->restore();
707 }
708 #else
709 if (skiaDom_) {
710 RSRect srcRect;
711 RSRect dstRect;
712 Offset startPoint;
713 double scaleX = 1.0f;
714 double scaleY = 1.0f;
715 switch (canvasImage.flag) {
716 case 0:
717 srcRect = RSRect(0, 0, skiaDom_->containerSize().width(), skiaDom_->containerSize().height());
718 dstRect = RSRect(canvasImage.dx, canvasImage.dy, skiaDom_->containerSize().width() + canvasImage.dx,
719 skiaDom_->containerSize().height() + canvasImage.dy);
720 break;
721 case 1: {
722 srcRect = RSRect(0, 0, skiaDom_->containerSize().width(), skiaDom_->containerSize().height());
723 dstRect = RSRect(canvasImage.dx, canvasImage.dy,
724 canvasImage.dWidth + canvasImage.dx, canvasImage.dHeight + canvasImage.dy);
725 break;
726 }
727 case 2: {
728 srcRect = RSRect(canvasImage.sx, canvasImage.sy,
729 canvasImage.sWidth + canvasImage.sx, canvasImage.sHeight + canvasImage.sy);
730 dstRect = RSRect(canvasImage.dx, canvasImage.dy,
731 canvasImage.dWidth + canvasImage.dx, canvasImage.dHeight + canvasImage.dy);
732 break;
733 }
734 default:
735 break;
736 }
737 scaleX = dstRect.GetWidth() / srcRect.GetWidth();
738 scaleY = dstRect.GetHeight() / srcRect.GetHeight();
739 startPoint =
740 Offset(dstRect.GetLeft(), dstRect.GetTop()) - Offset(srcRect.GetLeft() * scaleX, srcRect.GetTop() * scaleY);
741
742 drawingCanvas->Save();
743 drawingCanvas->ClipRect(dstRect, RSClipOp::INTERSECT, false);
744 drawingCanvas->Translate(startPoint.GetX(), startPoint.GetY());
745 drawingCanvas->Scale(scaleX, scaleY);
746 drawingCanvas->DrawSVGDOM(skiaDom_);
747 drawingCanvas->Restore();
748 }
749 #endif
750 }
751
DrawImage(const CanvasImage & canvasImage,double width,double height)752 void RosenRenderOffscreenCanvas::DrawImage(const CanvasImage& canvasImage, double width, double height)
753 {
754 auto context = pipelineContext_.Upgrade();
755 if (!context) {
756 return;
757 }
758
759 std::string::size_type tmp = canvasImage.src.find(".svg");
760 if (tmp != std::string::npos) {
761 DrawSvgImage(canvasImage);
762 return;
763 }
764
765 #ifndef USE_ROSEN_DRAWING
766 auto image = GreatOrEqual(width, 0) && GreatOrEqual(height, 0)
767 ? ImageProvider::GetSkImage(canvasImage.src, context, Size(width, height))
768 : ImageProvider::GetSkImage(canvasImage.src, context);
769 if (!image) {
770 LOGE("image is null");
771 return;
772 }
773 InitCachePaint();
774 const auto skCanvas =
775 globalState_.GetType() == CompositeOperation::SOURCE_OVER ? skCanvas_.get() : cacheCanvas_.get();
776 InitImagePaint();
777 if (HasImageShadow()) {
778 SkRect skRect = SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy, canvasImage.dWidth, canvasImage.dHeight);
779 SkPath path;
780 path.addRect(skRect);
781 #ifndef NEW_SKIA
782 FlutterDecorationPainter::PaintShadow(path, imageShadow_, skCanvas);
783 #else
784 RosenDecorationPainter::PaintShadow(path, imageShadow_, skCanvas);
785 #endif
786 }
787 switch (canvasImage.flag) {
788 case 0:
789 skCanvas->drawImage(image, canvasImage.dx, canvasImage.dy);
790 break;
791 case 1: {
792 SkRect rect = SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy, canvasImage.dWidth, canvasImage.dHeight);
793 #ifndef NEW_SKIA
794 skCanvas->drawImageRect(image, rect, &imagePaint_);
795 #else
796 skCanvas->drawImageRect(image, rect, options_, &imagePaint_);
797 #endif
798 break;
799 }
800 case 2: {
801 SkRect dstRect =
802 SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy, canvasImage.dWidth, canvasImage.dHeight);
803 SkRect srcRect =
804 SkRect::MakeXYWH(canvasImage.sx, canvasImage.sy, canvasImage.sWidth, canvasImage.sHeight);
805 #ifndef NEW_SKIA
806 skCanvas->drawImageRect(image, srcRect, dstRect, &imagePaint_);
807 #else
808 skCanvas->drawImageRect(image, srcRect, dstRect, options_, &imagePaint_, SkCanvas::kFast_SrcRectConstraint);
809 #endif
810 break;
811 }
812 default:
813 break;
814 }
815 if (globalState_.GetType() != CompositeOperation::SOURCE_OVER) {
816 #ifndef NEW_SKIA
817 skCanvas_->drawBitmap(cacheBitmap_, 0, 0, &cachePaint_);
818 #else
819 skCanvas_->drawImage(cacheBitmap_.asImage(), 0, 0, SkSamplingOptions(), &cachePaint_);
820 #endif
821 cacheBitmap_.eraseColor(0);
822 }
823 #else
824 auto image = GreatOrEqual(width, 0) && GreatOrEqual(height, 0)
825 ? ImageProvider::GetDrawingImage(canvasImage.src, context, Size(width, height))
826 : ImageProvider::GetDrawingImage(canvasImage.src, context);
827 if (!image) {
828 LOGE("image is null");
829 return;
830 }
831 InitCachePaint();
832 const auto canvas =
833 globalState_.GetType() == CompositeOperation::SOURCE_OVER ? canvas_.get() : cacheCanvas_.get();
834 InitImagePaint();
835 if (HasImageShadow()) {
836 RSRect drawingRect = RSRect(canvasImage.dx, canvasImage.dy,
837 canvasImage.dWidth + canvasImage.dx, canvasImage.dHeight + canvasImage.dy);
838 RSRecordingPath path;
839 path.AddRect(drawingRect);
840 RosenDecorationPainter::PaintShadow(path, imageShadow_, canvas);
841 }
842
843 switch (canvasImage.flag) {
844 case 0:
845 canvas->DrawImage(*image, canvasImage.dx, canvasImage.dy, RSSamplingOptions());
846 break;
847 case 1: {
848 RSRect rect =
849 RSRect(canvasImage.dx, canvasImage.dy,
850 canvasImage.dWidth + canvasImage.dx, canvasImage.dHeight + canvasImage.dy);
851 canvas->AttachBrush(imageBrush_);
852 canvas->DrawImageRect(*image, rect, options_);
853 canvas->DetachBrush();
854 break;
855 }
856 case 2: {
857 RSRect dstRect = RSRect(canvasImage.dx, canvasImage.dy,
858 canvasImage.dWidth + canvasImage.dx, canvasImage.dHeight + canvasImage.dy);
859 RSRect srcRect = RSRect(canvasImage.sx, canvasImage.sy,
860 canvasImage.sWidth + canvasImage.sx, canvasImage.sHeight + canvasImage.sy);
861 canvas->AttachBrush(imageBrush_);
862 canvas->DrawImageRect(*image, srcRect, dstRect, options_, RSSrcRectConstraint::FAST_SRC_RECT_CONSTRAINT);
863 canvas->DetachBrush();
864 break;
865 }
866 default:
867 break;
868 }
869 if (globalState_.GetType() != CompositeOperation::SOURCE_OVER) {
870 canvas_->AttachBrush(cacheBrush_);
871 canvas_->DrawBitmap(cacheBitmap_, 0, 0);
872 canvas_->DetachBrush();
873 cacheBitmap_.ClearWithColor(RSColor::COLOR_TRANSPARENT);
874 }
875 #endif
876 }
877
DrawPixelMap(RefPtr<PixelMap> pixelMap,const CanvasImage & canvasImage)878 void RosenRenderOffscreenCanvas::DrawPixelMap(RefPtr<PixelMap> pixelMap, const CanvasImage& canvasImage)
879 {
880 auto context = pipelineContext_.Upgrade();
881 if (!context) {
882 return;
883 }
884
885 #ifndef USE_ROSEN_DRAWING
886 // get skImage form pixelMap
887 auto imageInfo = ImageProvider::MakeSkImageInfoFromPixelMap(pixelMap);
888 SkPixmap imagePixmap(imageInfo, reinterpret_cast<const void*>(pixelMap->GetPixels()), pixelMap->GetRowBytes());
889
890 // Step2: Create SkImage and draw it, using gpu or cpu
891 sk_sp<SkImage> image;
892
893 image = SkImage::MakeFromRaster(imagePixmap, &PixelMap::ReleaseProc, PixelMap::GetReleaseContext(pixelMap));
894 if (!image) {
895 LOGE("image is null");
896 return;
897 }
898
899 InitCachePaint();
900 const auto skCanvas =
901 globalState_.GetType() == CompositeOperation::SOURCE_OVER ? skCanvas_.get() : cacheCanvas_.get();
902 InitImagePaint();
903 switch (canvasImage.flag) {
904 case 0:
905 skCanvas->drawImage(image, canvasImage.dx, canvasImage.dy);
906 break;
907 case 1: {
908 SkRect rect = SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy, canvasImage.dWidth, canvasImage.dHeight);
909 #ifndef NEW_SKIA
910 skCanvas->drawImageRect(image, rect, &imagePaint_);
911 #else
912 skCanvas->drawImageRect(image, rect, options_, &imagePaint_);
913 #endif
914 break;
915 }
916 case 2: {
917 SkRect dstRect =
918 SkRect::MakeXYWH(canvasImage.dx, canvasImage.dy, canvasImage.dWidth, canvasImage.dHeight);
919 SkRect srcRect =
920 SkRect::MakeXYWH(canvasImage.sx, canvasImage.sy, canvasImage.sWidth, canvasImage.sHeight);
921 #ifndef NEW_SKIA
922 skCanvas->drawImageRect(image, srcRect, dstRect, &imagePaint_);
923 #else
924 skCanvas->drawImageRect(image, srcRect, dstRect, options_, &imagePaint_, SkCanvas::kFast_SrcRectConstraint);
925 #endif
926 break;
927 }
928 default:
929 break;
930 }
931 if (globalState_.GetType() != CompositeOperation::SOURCE_OVER) {
932 #ifndef NEW_SKIA
933 skCanvas_->drawBitmap(cacheBitmap_, 0, 0, &cachePaint_);
934 #else
935 skCanvas_->drawImage(cacheBitmap_.asImage(), 0, 0, SkSamplingOptions(), &cachePaint_);
936 #endif
937 cacheBitmap_.eraseColor(0);
938 }
939 #else
940 // get Image form pixelMap
941 auto rsBitmapFormat = ImageProvider::MakeRSBitmapFormatFromPixelMap(pixelMap);
942 auto rsBitmap = std::make_shared<RSBitmap>();
943 rsBitmap->Build(pixelMap->GetWidth(), pixelMap->GetHeight(), rsBitmapFormat);
944 rsBitmap->SetPixels(const_cast<void*>(reinterpret_cast<const void*>(pixelMap->GetPixels())));
945
946 // Step2: Create Image and draw it, using gpu or cpu
947 auto image = std::make_shared<RSImage>();
948 if (!image->BuildFromBitmap(*rsBitmap)) {
949 LOGE("image is null");
950 return;
951 }
952
953 InitCachePaint();
954 const auto drawingCanvas =
955 globalState_.GetType() == CompositeOperation::SOURCE_OVER ? canvas_.get() : cacheCanvas_.get();
956 InitImagePaint();
957 switch (canvasImage.flag) {
958 case 0:
959 drawingCanvas->DrawImage(*image, canvasImage.dx, canvasImage.dy, RSSamplingOptions());
960 break;
961 case 1: {
962 RSRect rect = RSRect(canvasImage.dx, canvasImage.dy,
963 canvasImage.dWidth + canvasImage.dx, canvasImage.dHeight + canvasImage.dy);
964 drawingCanvas->AttachBrush(imageBrush_);
965 drawingCanvas->DrawImageRect(*image, rect, options_);
966 drawingCanvas->DetachBrush();
967 break;
968 }
969 case 2: {
970 RSRect dstRect = RSRect(canvasImage.dx, canvasImage.dy,
971 canvasImage.dWidth + canvasImage.dx, canvasImage.dHeight + canvasImage.dy);
972 RSRect srcRect = RSRect(canvasImage.sx, canvasImage.sy,
973 canvasImage.sWidth + canvasImage.sx, canvasImage.sHeight + canvasImage.sy);
974 drawingCanvas->AttachBrush(imageBrush_);
975 drawingCanvas->DrawImageRect(*image, srcRect, dstRect, options_,
976 RSSrcRectConstraint::FAST_SRC_RECT_CONSTRAINT);
977 drawingCanvas->DetachBrush();
978 break;
979 }
980 default:
981 break;
982 }
983 if (globalState_.GetType() != CompositeOperation::SOURCE_OVER) {
984 canvas_->AttachBrush(cacheBrush_);
985 canvas_->DrawBitmap(cacheBitmap_, 0, 0);
986 canvas_->DetachBrush();
987 cacheBitmap_.ClearWithColor(RSColor::COLOR_TRANSPARENT);
988 }
989 #endif
990 }
991
GetImageData(double left,double top,double width,double height)992 std::unique_ptr<ImageData> RosenRenderOffscreenCanvas::GetImageData(double left, double top,
993 double width, double height)
994 {
995 double viewScale = 1.0;
996 auto pipeline = pipelineContext_.Upgrade();
997 if (pipeline) {
998 viewScale = pipeline->GetViewScale();
999 }
1000 // copy the bitmap to tempCanvas
1001 #ifndef USE_ROSEN_DRAWING
1002 auto imageInfo =
1003 SkImageInfo::Make(width, height, SkColorType::kBGRA_8888_SkColorType, SkAlphaType::kOpaque_SkAlphaType);
1004 double scaledLeft = left * viewScale;
1005 double scaledTop = top * viewScale;
1006 double dirtyWidth = width >= 0 ? width : 0;
1007 double dirtyHeight = height >= 0 ? height : 0;
1008 int32_t size = dirtyWidth * dirtyHeight;
1009 auto srcRect = SkRect::MakeXYWH(scaledLeft, scaledTop, width * viewScale, height * viewScale);
1010 auto dstRect = SkRect::MakeXYWH(0.0, 0.0, dirtyWidth, dirtyHeight);
1011 SkBitmap tempCache;
1012 tempCache.allocPixels(imageInfo);
1013 SkCanvas tempCanvas(tempCache);
1014 #if defined (USE_SYSTEM_SKIA_S) || defined (NEW_SKIA)
1015 tempCanvas.drawImageRect(
1016 skBitmap_.asImage(), srcRect, dstRect, options_, nullptr, SkCanvas::kFast_SrcRectConstraint);
1017 #else
1018 tempCanvas.drawBitmapRect(skBitmap_, srcRect, dstRect, nullptr);
1019 #endif
1020 // write color
1021 std::unique_ptr<uint8_t[]> pixels = std::make_unique<uint8_t[]>(size * 4);
1022 tempCanvas.readPixels(imageInfo, pixels.get(), dirtyWidth * imageInfo.bytesPerPixel(), 0, 0);
1023 #else
1024 RSBitmapFormat format { RSColorType::COLORTYPE_BGRA_8888, RSAlphaType::ALPHATYPE_OPAQUE };
1025 double scaledLeft = left * viewScale;
1026 double scaledTop = top * viewScale;
1027 double dirtyWidth = width >= 0 ? width : 0;
1028 double dirtyHeight = height >= 0 ? height : 0;
1029 int32_t size = dirtyWidth * dirtyHeight;
1030 auto srcRect = RSRect(scaledLeft, scaledTop, width * viewScale + scaledLeft, height * viewScale + scaledTop);
1031 auto dstRect = RSRect(0.0, 0.0, dirtyWidth, dirtyHeight);
1032 RSBitmap tempCache;
1033 tempCache.Build(width, height, format);
1034 RSCanvas tempCanvas;
1035 tempCanvas.Bind(tempCache);
1036 RSImage rsImage;
1037 rsImage.BuildFromBitmap(bitmap_);
1038 tempCanvas.DrawImageRect(rsImage, srcRect, dstRect, options_, RSSrcRectConstraint::FAST_SRC_RECT_CONSTRAINT);
1039 // write color
1040 uint8_t* pixels = static_cast<uint8_t*>(tempCache.GetPixels());
1041 #endif
1042 std::unique_ptr<ImageData> imageData = std::make_unique<ImageData>();
1043 imageData->dirtyWidth = dirtyWidth;
1044 imageData->dirtyHeight = dirtyHeight;
1045 // a pixel include 4 data blue, green, red, alpha
1046 for (int i = 0; i < size * 4; i += 4) {
1047 auto blue = pixels[i];
1048 auto green = pixels[i + 1];
1049 auto red = pixels[i + 2];
1050 auto alpha = pixels[i + 3];
1051 imageData->data.emplace_back(Color::FromARGB(alpha, red, green, blue));
1052 }
1053 return imageData;
1054 }
1055
Save()1056 void RosenRenderOffscreenCanvas::Save()
1057 {
1058 SaveStates();
1059 #ifndef USE_ROSEN_DRAWING
1060 skCanvas_->save();
1061 #else
1062 canvas_->Save();
1063 #endif
1064 }
1065
Restore()1066 void RosenRenderOffscreenCanvas::Restore()
1067 {
1068 RestoreStates();
1069 #ifndef USE_ROSEN_DRAWING
1070 skCanvas_->restore();
1071 #else
1072 canvas_->Restore();
1073 #endif
1074 }
1075
ToDataURL(const std::string & type,const double quality)1076 std::string RosenRenderOffscreenCanvas::ToDataURL(const std::string& type, const double quality)
1077 {
1078 auto pipeline = pipelineContext_.Upgrade();
1079 if (!pipeline) {
1080 return UNSUPPORTED;
1081 }
1082 std::string mimeType = GetMimeType(type);
1083 double qua = GetQuality(type, quality);
1084 #ifndef USE_ROSEN_DRAWING
1085 SkBitmap tempCache;
1086 tempCache.allocPixels(SkImageInfo::Make(width_, height_, SkColorType::kBGRA_8888_SkColorType,
1087 (mimeType == IMAGE_JPEG) ? SkAlphaType::kOpaque_SkAlphaType : SkAlphaType::kUnpremul_SkAlphaType));
1088 SkCanvas tempCanvas(tempCache);
1089 double viewScale = pipeline->GetViewScale();
1090 tempCanvas.clear(SK_ColorTRANSPARENT);
1091 tempCanvas.scale(1.0 / viewScale, 1.0 / viewScale);
1092 #if defined(USE_SYSTEM_SKIA_S) || defined (NEW_SKIA)
1093 //The return value of the dual framework interface has no alpha
1094 tempCanvas.drawImage(skBitmap_.asImage(), 0.0f, 0.0f);
1095 #else
1096 tempCanvas.drawBitmap(skBitmap_, 0.0f, 0.0f);
1097 #endif
1098 SkPixmap src;
1099 bool success = tempCache.peekPixels(&src);
1100 #else
1101 RSBitmap tempCache;
1102 tempCache.Build(width_, height_, { RSColorType::COLORTYPE_BGRA_8888,
1103 (mimeType == IMAGE_JPEG) ? RSAlphaType::ALPHATYPE_OPAQUE : RSAlphaType::ALPHATYPE_UNPREMUL });
1104 RSCanvas tempCanvas;
1105 tempCanvas.Bind(tempCache);
1106 double viewScale = pipeline->GetViewScale();
1107 tempCanvas.Clear(RSColor::COLOR_TRANSPARENT);
1108 tempCanvas.Scale(1.0 / viewScale, 1.0 / viewScale);
1109 tempCanvas.DrawBitmap(bitmap_, 0.0f, 0.0f);
1110
1111 auto& skBitmap = tempCache.GetImpl<Rosen::Drawing::SkiaBitmap>()->ExportSkiaBitmap();
1112 SkPixmap src;
1113 bool success = skBitmap.peekPixels(&src);
1114 #endif
1115 if (!success) {
1116 LOGE("ToDataURL failed,the bitmap does not have access to pixel data");
1117 return UNSUPPORTED;
1118 }
1119 SkDynamicMemoryWStream dst;
1120 if (mimeType == IMAGE_JPEG) {
1121 SkJpegEncoder::Options options;
1122 options.fQuality = qua;
1123 success = SkJpegEncoder::Encode(&dst, src, options);
1124 } else if (mimeType == IMAGE_WEBP) {
1125 SkWebpEncoder::Options options;
1126 options.fQuality = qua * 100.0;
1127 success = SkWebpEncoder::Encode(&dst, src, options);
1128 } else {
1129 mimeType = IMAGE_PNG;
1130 SkPngEncoder::Options options;
1131 success = SkPngEncoder::Encode(&dst, src, options);
1132 }
1133 if (!success) {
1134 LOGE("ToDataURL failed,image encoding failed");
1135 return UNSUPPORTED;
1136 }
1137 auto result = dst.detachAsData();
1138 if (result == nullptr) {
1139 LOGE("DetachAsData failed when ToDataURL.");
1140 return UNSUPPORTED;
1141 }
1142 size_t len = SkBase64::Encode(result->data(), result->size(), nullptr);
1143 if (len > MAX_LENGTH) {
1144 LOGE("ToDataURL failed,The resolution of the image is greater than the maximum allowed resolution");
1145 return UNSUPPORTED;
1146 }
1147 SkString info(len);
1148 SkBase64::Encode(result->data(), result->size(), info.writable_str());
1149 return std::string(URL_PREFIX).append(mimeType).append(URL_SYMBOL).append(info.c_str());
1150 }
1151
1152 #ifndef USE_ROSEN_DRAWING
UpdatePaintShader(SkPaint & paint,const Gradient & gradient)1153 void RosenRenderOffscreenCanvas::UpdatePaintShader(SkPaint& paint, const Gradient& gradient)
1154 {
1155 SkPoint beginPoint = SkPoint::Make(SkDoubleToScalar(gradient.GetBeginOffset().GetX()),
1156 SkDoubleToScalar(gradient.GetBeginOffset().GetY()));
1157 SkPoint endPoint = SkPoint::Make(SkDoubleToScalar(gradient.GetEndOffset().GetX()),
1158 SkDoubleToScalar(gradient.GetEndOffset().GetY()));
1159 SkPoint pts[2] = { beginPoint, endPoint };
1160 std::vector<GradientColor> gradientColors = gradient.GetColors();
1161 std::stable_sort(gradientColors.begin(), gradientColors.end(),
1162 [](auto& colorA, auto& colorB) { return colorA.GetDimension() < colorB.GetDimension(); });
1163 uint32_t colorsSize = gradientColors.size();
1164 SkColor colors[gradientColors.size()];
1165 float pos[gradientColors.size()];
1166 for (uint32_t i = 0; i < colorsSize; ++i) {
1167 const auto& gradientColor = gradientColors[i];
1168 colors[i] = gradientColor.GetColor().GetValue();
1169 pos[i] = gradientColor.GetDimension().Value();
1170 }
1171
1172 #ifdef USE_SYSTEM_SKIA
1173 auto mode = SkShader::kClamp_TileMode;
1174 #else
1175 auto mode = SkTileMode::kClamp;
1176 #endif
1177
1178 sk_sp<SkShader> skShader = nullptr;
1179 if (gradient.GetType() == GradientType::LINEAR) {
1180 skShader = SkGradientShader::MakeLinear(pts, colors, pos, gradientColors.size(), mode);
1181 } else {
1182 if (gradient.GetInnerRadius() <= 0.0 && beginPoint == endPoint) {
1183 skShader = SkGradientShader::MakeRadial(
1184 endPoint, gradient.GetOuterRadius(), colors, pos, gradientColors.size(), mode);
1185 } else {
1186 skShader = SkGradientShader::MakeTwoPointConical(beginPoint, gradient.GetInnerRadius(),
1187 endPoint, gradient.GetOuterRadius(), colors, pos, gradientColors.size(), mode);
1188 }
1189 }
1190 paint.setShader(skShader);
1191 }
1192 #else
UpdatePaintShader(RSPen * pen,RSBrush * brush,const Gradient & gradient)1193 void RosenRenderOffscreenCanvas::UpdatePaintShader(RSPen* pen, RSBrush* brush, const Gradient& gradient)
1194 {
1195 RSPoint beginPoint =
1196 RSPoint(static_cast<RSScalar>(gradient.GetBeginOffset().GetX()),
1197 static_cast<RSScalar>(gradient.GetBeginOffset().GetY()));
1198 RSPoint endPoint =
1199 RSPoint(static_cast<RSScalar>(gradient.GetEndOffset().GetX()),
1200 static_cast<RSScalar>(gradient.GetEndOffset().GetY()));
1201 std::vector<RSPoint> pts = { beginPoint, endPoint };
1202 auto gradientColors = gradient.GetColors();
1203 std::stable_sort(gradientColors.begin(), gradientColors.end(),
1204 [](auto& colorA, auto& colorB) { return colorA.GetDimension() < colorB.GetDimension(); });
1205 uint32_t colorsSize = gradientColors.size();
1206 std::vector<RSColorQuad> colors(gradientColors.size(), 0);
1207 std::vector<RSScalar> pos(gradientColors.size(), 0);
1208 for (uint32_t i = 0; i < colorsSize; ++i) {
1209 const auto& gradientColor = gradientColors[i];
1210 colors.at(i) = gradientColor.GetColor().GetValue();
1211 pos.at(i) = gradientColor.GetDimension().Value();
1212 }
1213
1214 auto mode = RSTileMode::CLAMP;
1215 std::shared_ptr<RSShaderEffect> shaderEffect = nullptr;
1216 if (gradient.GetType() == GradientType::LINEAR) {
1217 shaderEffect = RSShaderEffect::CreateLinearGradient(pts.at(0), pts.at(1), colors, pos, mode);
1218 } else {
1219 if (gradient.GetInnerRadius() <= 0.0 && beginPoint == endPoint) {
1220 shaderEffect = RSShaderEffect::CreateRadialGradient(
1221 pts.at(1), gradient.GetOuterRadius(), colors, pos, mode);
1222 } else {
1223 shaderEffect = RSShaderEffect::CreateTwoPointConical(
1224 pts.at(0), gradient.GetInnerRadius(), pts.at(1), gradient.GetOuterRadius(), colors, pos, mode);
1225 }
1226 }
1227 if (pen) {
1228 pen->SetShaderEffect(shaderEffect);
1229 }
1230 if (brush) {
1231 brush->SetShaderEffect(shaderEffect);
1232 }
1233 }
1234 #endif
1235
BeginPath()1236 void RosenRenderOffscreenCanvas::BeginPath()
1237 {
1238 #ifndef USE_ROSEN_DRAWING
1239 skPath_.reset();
1240 #else
1241 path_.Reset();
1242 #endif
1243 }
1244
ResetTransform()1245 void RosenRenderOffscreenCanvas::ResetTransform()
1246 {
1247 #ifndef USE_ROSEN_DRAWING
1248 skCanvas_->resetMatrix();
1249 #else
1250 canvas_->ResetMatrix();
1251 #endif
1252 }
1253
1254 #ifndef USE_ROSEN_DRAWING
UpdatePaintShader(const Pattern & pattern,SkPaint & paint)1255 void RosenRenderOffscreenCanvas::UpdatePaintShader(const Pattern& pattern, SkPaint& paint)
1256 {
1257 auto context = pipelineContext_.Upgrade();
1258 if (!context) {
1259 return;
1260 }
1261
1262 auto width = pattern.GetImageWidth();
1263 auto height = pattern.GetImageHeight();
1264 auto image = GreatOrEqual(width, 0) && GreatOrEqual(height, 0)
1265 ? ImageProvider::GetSkImage(pattern.GetImgSrc(), context, Size(width, height))
1266 : ImageProvider::GetSkImage(pattern.GetImgSrc(), context);
1267 if (!image) {
1268 LOGE("image is null");
1269 return;
1270 }
1271 static const LinearMapNode<void (*)(sk_sp<SkImage>, SkPaint&)> staticPattern[] = {
1272 { "no-repeat",
1273 [](sk_sp<SkImage> image, SkPaint& paint) {
1274 #ifdef USE_SYSTEM_SKIA
1275 paint.setShader(image->makeShader(SkShader::kDecal_TileMode, SkShader::kDecal_TileMode, nullptr));
1276 #elif defined(NEW_SKIA)
1277 paint.setShader(image->makeShader(SkTileMode::kDecal, SkTileMode::kDecal, SkSamplingOptions(), nullptr));
1278 #else
1279 paint.setShader(image->makeShader(SkTileMode::kDecal, SkTileMode::kDecal, nullptr));
1280 #endif
1281 } },
1282 { "repeat",
1283 [](sk_sp<SkImage> image, SkPaint& paint) {
1284 #ifdef USE_SYSTEM_SKIA
1285 paint.setShader(image->makeShader(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, nullptr));
1286 #elif defined(NEW_SKIA)
1287 paint.setShader(image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkSamplingOptions(), nullptr));
1288 #else
1289 paint.setShader(image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, nullptr));
1290 #endif
1291 } },
1292 { "repeat-x",
1293 [](sk_sp<SkImage> image, SkPaint& paint) {
1294 #ifdef USE_SYSTEM_SKIA
1295 paint.setShader(image->makeShader(SkShader::kRepeat_TileMode, SkShader::kDecal_TileMode, nullptr));
1296 #elif defined(NEW_SKIA)
1297 paint.setShader(image->makeShader(SkTileMode::kRepeat, SkTileMode::kDecal, SkSamplingOptions(), nullptr));
1298 #else
1299 paint.setShader(image->makeShader(SkTileMode::kRepeat, SkTileMode::kDecal, nullptr));
1300 #endif
1301 } },
1302 { "repeat-y",
1303 [](sk_sp<SkImage> image, SkPaint& paint) {
1304 #ifdef USE_SYSTEM_SKIA
1305 paint.setShader(image->makeShader(SkShader::kDecal_TileMode, SkShader::kRepeat_TileMode, nullptr));
1306 #elif defined(NEW_SKIA)
1307 paint.setShader(image->makeShader(SkTileMode::kDecal, SkTileMode::kRepeat, SkSamplingOptions(), nullptr));
1308 #else
1309 paint.setShader(image->makeShader(SkTileMode::kDecal, SkTileMode::kRepeat, nullptr));
1310 #endif
1311 } },
1312 };
1313 auto operatorIter =
1314 BinarySearchFindIndex(staticPattern, ArraySize(staticPattern), pattern.GetRepetition().c_str());
1315 if (operatorIter != -1) {
1316 staticPattern[operatorIter].value(image, paint);
1317 }
1318 }
1319 #else
UpdatePaintShader(const Pattern & pattern,RSPen * pen,RSBrush * brush)1320 void RosenRenderOffscreenCanvas::UpdatePaintShader(const Pattern& pattern, RSPen* pen, RSBrush* brush)
1321 {
1322 auto context = pipelineContext_.Upgrade();
1323 if (!context) {
1324 return;
1325 }
1326
1327 auto width = pattern.GetImageWidth();
1328 auto height = pattern.GetImageHeight();
1329 auto image = GreatOrEqual(width, 0) && GreatOrEqual(height, 0)
1330 ? ImageProvider::GetDrawingImage(pattern.GetImgSrc(), context, Size(width, height))
1331 : ImageProvider::GetDrawingImage(pattern.GetImgSrc(), context);
1332 if (!image) {
1333 LOGE("image is null");
1334 return;
1335 }
1336 static const LinearMapNode<void (*)(std::shared_ptr<RSImage>&, std::shared_ptr<RSShaderEffect>&)>
1337 staticPattern[] = {
1338 { "no-repeat",
1339 [](std::shared_ptr<RSImage>& image, std::shared_ptr<RSShaderEffect>& rsShaderEffect) {
1340 rsShaderEffect = RSShaderEffect::CreateImageShader(*image,
1341 RSTileMode::DECAL, RSTileMode::DECAL, RSSamplingOptions(), RSMatrix());
1342 } },
1343 { "repeat",
1344 [](std::shared_ptr<RSImage>& image, std::shared_ptr<RSShaderEffect>& rsShaderEffect) {
1345 rsShaderEffect = RSShaderEffect::CreateImageShader(*image,
1346 RSTileMode::REPEAT, RSTileMode::REPEAT, RSSamplingOptions(), RSMatrix());
1347 } },
1348 { "repeat-x",
1349 [](std::shared_ptr<RSImage>& image, std::shared_ptr<RSShaderEffect>& rsShaderEffect) {
1350 rsShaderEffect = RSShaderEffect::CreateImageShader(*image,
1351 RSTileMode::REPEAT, RSTileMode::DECAL, RSSamplingOptions(), RSMatrix());
1352 } },
1353 { "repeat-y",
1354 [](std::shared_ptr<RSImage>& image, std::shared_ptr<RSShaderEffect>& rsShaderEffect) {
1355 rsShaderEffect = RSShaderEffect::CreateImageShader(*image,
1356 RSTileMode::DECAL, RSTileMode::REPEAT, RSSamplingOptions(), RSMatrix());
1357 } },
1358 };
1359 auto operatorIter = BinarySearchFindIndex(staticPattern, ArraySize(staticPattern), pattern.GetRepetition().c_str());
1360 if (operatorIter != -1) {
1361 std::shared_ptr<RSShaderEffect> shaderEffect = nullptr;
1362 staticPattern[operatorIter].value(image, shaderEffect);
1363 if (pen) {
1364 pen->SetShaderEffect(shaderEffect);
1365 }
1366 if (brush) {
1367 brush->SetShaderEffect(shaderEffect);
1368 }
1369 }
1370 }
1371 #endif
1372
Arc(const ArcParam & param)1373 void RosenRenderOffscreenCanvas::Arc(const ArcParam& param)
1374 {
1375 double left = param.x - param.radius;
1376 double top = param.y - param.radius;
1377 double right = param.x + param.radius;
1378 double bottom = param.y + param.radius;
1379 double startAngle = param.startAngle * HALF_CIRCLE_ANGLE / M_PI;
1380 double endAngle = param.endAngle * HALF_CIRCLE_ANGLE / M_PI;
1381 double sweepAngle = endAngle - startAngle;
1382 if (param.anticlockwise) {
1383 sweepAngle =
1384 endAngle > startAngle ? (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) - FULL_CIRCLE_ANGLE) : sweepAngle;
1385 } else {
1386 sweepAngle =
1387 endAngle > startAngle ? sweepAngle : (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) + FULL_CIRCLE_ANGLE);
1388 }
1389 #ifndef USE_ROSEN_DRAWING
1390 auto rect = SkRect::MakeLTRB(left, top, right, bottom);
1391 if (NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && !NearEqual(startAngle, endAngle)) {
1392 // draw circle
1393 double half = GreatNotEqual(sweepAngle, 0.0) ? HALF_CIRCLE_ANGLE : -HALF_CIRCLE_ANGLE;
1394 skPath_.arcTo(rect, SkDoubleToScalar(startAngle), SkDoubleToScalar(half), false);
1395 skPath_.arcTo(rect, SkDoubleToScalar(half + startAngle), SkDoubleToScalar(half), false);
1396 } else if (!NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && abs(sweepAngle) > FULL_CIRCLE_ANGLE) {
1397 double half = GreatNotEqual(sweepAngle, 0.0) ? HALF_CIRCLE_ANGLE : -HALF_CIRCLE_ANGLE;
1398 skPath_.arcTo(rect, SkDoubleToScalar(startAngle), SkDoubleToScalar(half), false);
1399 skPath_.arcTo(rect, SkDoubleToScalar(half + startAngle), SkDoubleToScalar(half), false);
1400 skPath_.arcTo(rect, SkDoubleToScalar(half + half + startAngle), SkDoubleToScalar(sweepAngle), false);
1401 } else {
1402 skPath_.arcTo(rect, SkDoubleToScalar(startAngle), SkDoubleToScalar(sweepAngle), false);
1403 }
1404 #else
1405 RSPoint point1(left, top);
1406 RSPoint point2(right, bottom);
1407 if (NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && !NearEqual(startAngle, endAngle)) {
1408 // draw circle
1409 double half = GreatNotEqual(sweepAngle, 0.0) ? HALF_CIRCLE_ANGLE : -HALF_CIRCLE_ANGLE;
1410 path_.ArcTo(point1, point2, static_cast<RSScalar>(startAngle), static_cast<RSScalar>(half));
1411 path_.ArcTo(point1, point2, static_cast<RSScalar>(half + startAngle), static_cast<RSScalar>(half));
1412 } else if (!NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && abs(sweepAngle) > FULL_CIRCLE_ANGLE) {
1413 double half = GreatNotEqual(sweepAngle, 0.0) ? HALF_CIRCLE_ANGLE : -HALF_CIRCLE_ANGLE;
1414 path_.ArcTo(point1, point2, static_cast<RSScalar>(startAngle), static_cast<RSScalar>(half));
1415 path_.ArcTo(point1, point2, static_cast<RSScalar>(half + startAngle), static_cast<RSScalar>(half));
1416 path_.ArcTo(point1, point2, static_cast<RSScalar>(half + half + startAngle), static_cast<RSScalar>(sweepAngle));
1417 } else {
1418 path_.ArcTo(point1, point2, static_cast<RSScalar>(startAngle), static_cast<RSScalar>(sweepAngle));
1419 }
1420 #endif
1421 }
1422
ClearRect(Rect rect)1423 void RosenRenderOffscreenCanvas::ClearRect(Rect rect)
1424 {
1425 #ifndef USE_ROSEN_DRAWING
1426 SkPaint paint;
1427 paint.setAntiAlias(antiAlias_);
1428 paint.setBlendMode(SkBlendMode::kClear);
1429 auto skRect = SkRect::MakeLTRB(rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
1430 skCanvas_->drawRect(skRect, paint);
1431 #else
1432 RSBrush brush;
1433 brush.SetAntiAlias(antiAlias_);
1434 brush.SetBlendMode(RSBlendMode::CLEAR);
1435 auto drawingRect = RSRect(rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
1436 canvas_->AttachBrush(brush);
1437 canvas_->DrawRect(drawingRect);
1438 canvas_->DetachBrush();
1439 #endif
1440 }
1441
StrokeRect(Rect rect)1442 void RosenRenderOffscreenCanvas::StrokeRect(Rect rect)
1443 {
1444 #ifndef USE_ROSEN_DRAWING
1445 SkPaint paint = GetStrokePaint();
1446 paint.setAntiAlias(antiAlias_);
1447 SkRect skRect = SkRect::MakeLTRB(rect.Left(), rect.Top(),
1448 rect.Right(), rect.Bottom());
1449 if (HasShadow()) {
1450 SkPath path;
1451 path.addRect(skRect);
1452 #ifndef NEW_SKIA
1453 FlutterDecorationPainter::PaintShadow(path, shadow_, skCanvas_.get());
1454 #else
1455 RosenDecorationPainter::PaintShadow(path, shadow_, skCanvas_.get());
1456 #endif
1457 }
1458 if (strokeState_.GetGradient().IsValid()) {
1459 UpdatePaintShader(paint, strokeState_.GetGradient());
1460 }
1461 if (strokeState_.GetPattern().IsValid()) {
1462 UpdatePaintShader(strokeState_.GetPattern(), paint);
1463 }
1464 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
1465 skCanvas_->drawRect(skRect, paint);
1466 } else {
1467 InitCachePaint();
1468 cacheCanvas_->drawRect(skRect, paint);
1469 #ifndef NEW_SKIA
1470 skCanvas_->drawBitmap(cacheBitmap_, 0, 0, &cachePaint_);
1471 #else
1472 skCanvas_->drawImage(cacheBitmap_.asImage(), 0, 0, SkSamplingOptions(), &cachePaint_);
1473 #endif
1474 cacheBitmap_.eraseColor(0);
1475 }
1476 #else
1477 auto pen = GetStrokePaint();
1478 pen.SetAntiAlias(antiAlias_);
1479 RSRect drawingRect = RSRect(rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
1480 if (HasShadow()) {
1481 RSRecordingPath path;
1482 path.AddRect(drawingRect);
1483 RosenDecorationPainter::PaintShadow(path, shadow_, canvas_.get());
1484 }
1485 if (strokeState_.GetGradient().IsValid()) {
1486 UpdatePaintShader(&pen, nullptr, strokeState_.GetGradient());
1487 }
1488 if (strokeState_.GetPattern().IsValid()) {
1489 UpdatePaintShader(strokeState_.GetPattern(), &pen, nullptr);
1490 }
1491 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
1492 canvas_->AttachPen(pen);
1493 canvas_->DrawRect(drawingRect);
1494 canvas_->DetachPen();
1495 } else {
1496 InitCachePaint();
1497 cacheCanvas_->AttachPen(pen);
1498 cacheCanvas_->DrawRect(drawingRect);
1499 cacheCanvas_->DetachPen();
1500 canvas_->AttachBrush(cacheBrush_);
1501 canvas_->DrawBitmap(cacheBitmap_, 0, 0);
1502 canvas_->DetachBrush();
1503 cacheBitmap_.ClearWithColor(RSColor::COLOR_TRANSPARENT);
1504 }
1505 #endif
1506 }
1507
Stroke()1508 void RosenRenderOffscreenCanvas::Stroke()
1509 {
1510 #ifndef USE_ROSEN_DRAWING
1511 SkPaint paint = GetStrokePaint();
1512 paint.setAntiAlias(antiAlias_);
1513 if (HasShadow()) {
1514 #ifndef NEW_SKIA
1515 FlutterDecorationPainter::PaintShadow(skPath_, shadow_, skCanvas_.get());
1516 #else
1517 RosenDecorationPainter::PaintShadow(skPath_, shadow_, skCanvas_.get());
1518 #endif
1519 }
1520 if (strokeState_.GetGradient().IsValid()) {
1521 UpdatePaintShader(paint, strokeState_.GetGradient());
1522 }
1523 if (strokeState_.GetPattern().IsValid()) {
1524 UpdatePaintShader(strokeState_.GetPattern(), paint);
1525 }
1526 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
1527 skCanvas_->drawPath(skPath_, paint);
1528 } else {
1529 InitCachePaint();
1530 cacheCanvas_->drawPath(skPath_, paint);
1531 #ifndef NEW_SKIA
1532 skCanvas_->drawBitmap(cacheBitmap_, 0, 0, &cachePaint_);
1533 #else
1534 skCanvas_->drawImage(cacheBitmap_.asImage(), 0, 0, SkSamplingOptions(), &cachePaint_);
1535 #endif
1536 cacheBitmap_.eraseColor(0);
1537 }
1538 #else
1539 auto pen = GetStrokePaint();
1540 pen.SetAntiAlias(antiAlias_);
1541 if (HasShadow()) {
1542 RosenDecorationPainter::PaintShadow(path_, shadow_, canvas_.get());
1543 }
1544 if (strokeState_.GetGradient().IsValid()) {
1545 UpdatePaintShader(&pen, nullptr, strokeState_.GetGradient());
1546 }
1547 if (strokeState_.GetPattern().IsValid()) {
1548 UpdatePaintShader(strokeState_.GetPattern(), &pen, nullptr);
1549 }
1550 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
1551 canvas_->AttachPen(pen);
1552 canvas_->DrawPath(path_);
1553 canvas_->DetachPen();
1554 } else {
1555 InitCachePaint();
1556 cacheCanvas_->AttachPen(pen);
1557 cacheCanvas_->DrawPath(path_);
1558 cacheCanvas_->DetachPen();
1559 canvas_->AttachBrush(cacheBrush_);
1560 canvas_->DrawBitmap(cacheBitmap_, 0, 0);
1561 canvas_->DetachBrush();
1562 cacheBitmap_.ClearWithColor(RSColor::COLOR_TRANSPARENT);
1563 }
1564 #endif
1565 }
1566
Stroke(const RefPtr<CanvasPath2D> & path)1567 void RosenRenderOffscreenCanvas::Stroke(const RefPtr<CanvasPath2D>& path)
1568 {
1569 if (path == nullptr) {
1570 return;
1571 }
1572 ParsePath2D(path);
1573 Path2DStroke();
1574 #ifndef USE_ROSEN_DRAWING
1575 skPath2d_.reset();
1576 #else
1577 path2d_.Reset();
1578 #endif
1579 }
1580
1581 #ifndef USE_ROSEN_DRAWING
GetStrokePaint()1582 SkPaint RosenRenderOffscreenCanvas::GetStrokePaint()
1583 {
1584 static const LinearEnumMapNode<LineJoinStyle, SkPaint::Join> skLineJoinTable[] = {
1585 { LineJoinStyle::MITER, SkPaint::Join::kMiter_Join },
1586 { LineJoinStyle::ROUND, SkPaint::Join::kRound_Join },
1587 { LineJoinStyle::BEVEL, SkPaint::Join::kBevel_Join },
1588 };
1589 static const LinearEnumMapNode<LineCapStyle, SkPaint::Cap> skLineCapTable[] = {
1590 { LineCapStyle::BUTT, SkPaint::Cap::kButt_Cap },
1591 { LineCapStyle::ROUND, SkPaint::Cap::kRound_Cap },
1592 { LineCapStyle::SQUARE, SkPaint::Cap::kSquare_Cap },
1593 };
1594 SkPaint paint;
1595 paint.setColor(strokeState_.GetColor().GetValue());
1596 paint.setStyle(SkPaint::Style::kStroke_Style);
1597 paint.setStrokeJoin(ConvertEnumToSkEnum(
1598 strokeState_.GetLineJoin(), skLineJoinTable, ArraySize(skLineJoinTable), SkPaint::Join::kMiter_Join));
1599 paint.setStrokeCap(ConvertEnumToSkEnum(
1600 strokeState_.GetLineCap(), skLineCapTable, ArraySize(skLineCapTable), SkPaint::Cap::kButt_Cap));
1601 paint.setStrokeWidth(static_cast<SkScalar>(strokeState_.GetLineWidth()));
1602 paint.setStrokeMiter(static_cast<SkScalar>(strokeState_.GetMiterLimit()));
1603
1604 // set line Dash
1605 UpdateLineDash(paint);
1606
1607 // set global alpha
1608 if (globalState_.HasGlobalAlpha()) {
1609 paint.setAlphaf(globalState_.GetAlpha());
1610 }
1611 return paint;
1612 }
1613 #else
GetStrokePaint()1614 RSPen RosenRenderOffscreenCanvas::GetStrokePaint()
1615 {
1616 static const LinearEnumMapNode<LineJoinStyle, RSPen::JoinStyle> skLineJoinTable[] = {
1617 { LineJoinStyle::MITER, RSPen::JoinStyle::MITER_JOIN },
1618 { LineJoinStyle::ROUND, RSPen::JoinStyle::ROUND_JOIN },
1619 { LineJoinStyle::BEVEL, RSPen::JoinStyle::BEVEL_JOIN },
1620 };
1621 static const LinearEnumMapNode<LineCapStyle, RSPen::CapStyle> skLineCapTable[] = {
1622 { LineCapStyle::BUTT, RSPen::CapStyle::FLAT_CAP },
1623 { LineCapStyle::ROUND, RSPen::CapStyle::ROUND_CAP },
1624 { LineCapStyle::SQUARE, RSPen::CapStyle::SQUARE_CAP },
1625 };
1626 RSPen pen;
1627 pen.SetColor(strokeState_.GetColor().GetValue());
1628 pen.SetJoinStyle(ConvertEnumToDrawingEnum(strokeState_.GetLineJoin(),
1629 skLineJoinTable, ArraySize(skLineJoinTable), RSPen::JoinStyle::MITER_JOIN));
1630 pen.SetCapStyle(ConvertEnumToDrawingEnum(
1631 strokeState_.GetLineCap(), skLineCapTable, ArraySize(skLineCapTable), RSPen::CapStyle::FLAT_CAP));
1632 pen.SetWidth(static_cast<RSScalar>(strokeState_.GetLineWidth()));
1633 pen.SetMiterLimit(static_cast<RSScalar>(strokeState_.GetMiterLimit()));
1634
1635 // set line Dash
1636 UpdateLineDash(pen);
1637
1638 // set global alpha
1639 if (globalState_.HasGlobalAlpha()) {
1640 pen.SetAlphaF(globalState_.GetAlpha());
1641 }
1642 return pen;
1643 }
1644 #endif
1645
SetAntiAlias(bool isEnabled)1646 void RosenRenderOffscreenCanvas::SetAntiAlias(bool isEnabled)
1647 {
1648 antiAlias_ = isEnabled;
1649 }
HasShadow() const1650 bool RosenRenderOffscreenCanvas::HasShadow() const
1651 {
1652 return !(NearZero(shadow_.GetOffset().GetX()) && NearZero(shadow_.GetOffset().GetY()) &&
1653 NearZero(shadow_.GetBlurRadius()));
1654 }
1655
HasImageShadow() const1656 bool RosenRenderOffscreenCanvas::HasImageShadow() const
1657 {
1658 return !(NearZero(imageShadow_.GetOffset().GetX()) && NearZero(imageShadow_.GetOffset().GetY()) &&
1659 NearZero(imageShadow_.GetBlurRadius()));
1660 }
1661
Path2DAddPath(const PathArgs & args)1662 void RosenRenderOffscreenCanvas::Path2DAddPath(const PathArgs& args)
1663 {
1664 #ifndef USE_ROSEN_DRAWING
1665 SkPath out;
1666 SkParsePath::FromSVGString(args.cmds.c_str(), &out);
1667 skPath2d_.addPath(out);
1668 #else
1669 RSRecordingPath out;
1670 out.BuildFromSVGString(args.cmds.c_str());
1671 path2d_.AddPath(out);
1672 #endif
1673 }
1674
Path2DSetTransform(const PathArgs & args)1675 void RosenRenderOffscreenCanvas::Path2DSetTransform(const PathArgs& args)
1676 {
1677 #ifndef USE_ROSEN_DRAWING
1678 SkMatrix skMatrix;
1679 double scaleX = args.para1;
1680 double skewX = args.para2;
1681 double skewY = args.para3;
1682 double scaleY = args.para4;
1683 double translateX = args.para5;
1684 double translateY = args.para6;
1685 skMatrix.setAll(scaleX, skewY, translateX, skewX, scaleY, translateY, 0, 0, 1);
1686 skPath2d_.transform(skMatrix);
1687 #else
1688 RSMatrix matrix;
1689 double scaleX = args.para1;
1690 double skewX = args.para2;
1691 double skewY = args.para3;
1692 double scaleY = args.para4;
1693 double translateX = args.para5;
1694 double translateY = args.para6;
1695 matrix.SetMatrix(scaleX, skewY, translateX, skewX, scaleY, translateY, 0, 0, 1);
1696 path2d_.Transform(matrix);
1697 #endif
1698 }
1699
Path2DMoveTo(const PathArgs & args)1700 void RosenRenderOffscreenCanvas::Path2DMoveTo(const PathArgs& args)
1701 {
1702 double x = args.para1;
1703 double y = args.para2;
1704 #ifndef USE_ROSEN_DRAWING
1705 skPath2d_.moveTo(x, y);
1706 #else
1707 path2d_.MoveTo(x, y);
1708 #endif
1709 }
1710
Path2DLineTo(const PathArgs & args)1711 void RosenRenderOffscreenCanvas::Path2DLineTo(const PathArgs& args)
1712 {
1713 double x = args.para1;
1714 double y = args.para2;
1715 #ifndef USE_ROSEN_DRAWING
1716 skPath2d_.lineTo(x, y);
1717 #else
1718 path2d_.LineTo(x, y);
1719 #endif
1720 }
1721
Path2DArc(const PathArgs & args)1722 void RosenRenderOffscreenCanvas::Path2DArc(const PathArgs& args)
1723 {
1724 double x = args.para1;
1725 double y = args.para2;
1726 double r = args.para3;
1727 #ifndef USE_ROSEN_DRAWING
1728 auto rect = SkRect::MakeLTRB(x - r, y - r,
1729 x + r, y + r);
1730 double startAngle = args.para4 * HALF_CIRCLE_ANGLE / M_PI;
1731 double endAngle = args.para5 * HALF_CIRCLE_ANGLE / M_PI;
1732 double sweepAngle = endAngle - startAngle;
1733 if (!NearZero(args.para6)) {
1734 sweepAngle = endAngle > startAngle ?
1735 (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) - FULL_CIRCLE_ANGLE) : sweepAngle;
1736 } else {
1737 sweepAngle = endAngle > startAngle ?
1738 sweepAngle : (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) + FULL_CIRCLE_ANGLE);
1739 }
1740 if (NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && !NearEqual(startAngle, endAngle)) {
1741 skPath2d_.arcTo(rect, startAngle, HALF_CIRCLE_ANGLE, false);
1742 skPath2d_.arcTo(rect, startAngle + HALF_CIRCLE_ANGLE, HALF_CIRCLE_ANGLE, false);
1743 } else if (!NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && abs(sweepAngle) > FULL_CIRCLE_ANGLE) {
1744 skPath2d_.arcTo(rect, startAngle, HALF_CIRCLE_ANGLE, false);
1745 skPath2d_.arcTo(rect, startAngle + HALF_CIRCLE_ANGLE, HALF_CIRCLE_ANGLE, false);
1746 skPath2d_.arcTo(rect, startAngle + HALF_CIRCLE_ANGLE + HALF_CIRCLE_ANGLE, sweepAngle, false);
1747 } else {
1748 skPath2d_.arcTo(rect, startAngle, sweepAngle, false);
1749 }
1750 #else
1751 RSPoint point1(x - r, y - r);
1752 RSPoint point2(x + r, y + r);
1753 double startAngle = args.para4 * HALF_CIRCLE_ANGLE / M_PI;
1754 double endAngle = args.para5 * HALF_CIRCLE_ANGLE / M_PI;
1755 double sweepAngle = endAngle - startAngle;
1756 if (!NearZero(args.para6)) {
1757 sweepAngle = endAngle > startAngle ?
1758 (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) - FULL_CIRCLE_ANGLE) : sweepAngle;
1759 } else {
1760 sweepAngle = endAngle > startAngle ?
1761 sweepAngle : (std::fmod(sweepAngle, FULL_CIRCLE_ANGLE) + FULL_CIRCLE_ANGLE);
1762 }
1763 if (NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && !NearEqual(startAngle, endAngle)) {
1764 path2d_.ArcTo(point1, point2, startAngle, HALF_CIRCLE_ANGLE);
1765 path2d_.ArcTo(point1, point2, startAngle + HALF_CIRCLE_ANGLE, HALF_CIRCLE_ANGLE);
1766 } else if (!NearEqual(std::fmod(sweepAngle, FULL_CIRCLE_ANGLE), 0.0) && abs(sweepAngle) > FULL_CIRCLE_ANGLE) {
1767 path2d_.ArcTo(point1, point2, startAngle, HALF_CIRCLE_ANGLE);
1768 path2d_.ArcTo(point1, point2, startAngle + HALF_CIRCLE_ANGLE, HALF_CIRCLE_ANGLE);
1769 path2d_.ArcTo(point1, point2, startAngle + HALF_CIRCLE_ANGLE + HALF_CIRCLE_ANGLE, sweepAngle);
1770 } else {
1771 path2d_.ArcTo(point1, point2, startAngle, sweepAngle);
1772 }
1773 #endif
1774 }
1775
Path2DArcTo(const PathArgs & args)1776 void RosenRenderOffscreenCanvas::Path2DArcTo(const PathArgs& args)
1777 {
1778 #ifndef USE_ROSEN_DRAWING
1779 double x1 = args.para1;
1780 double y1 = args.para2;
1781 double x2 = args.para3;
1782 double y2 = args.para4;
1783 double r = args.para5;
1784 skPath2d_.arcTo(x1, y1, x2, y2, r);
1785 #else
1786 LOGE("Drawing is not supported");
1787 #endif
1788 }
1789
Path2DQuadraticCurveTo(const PathArgs & args)1790 void RosenRenderOffscreenCanvas::Path2DQuadraticCurveTo(const PathArgs& args)
1791 {
1792 double cpx = args.para1;
1793 double cpy = args.para2;
1794 double x = args.para3;
1795 double y = args.para4;
1796 #ifndef USE_ROSEN_DRAWING
1797 skPath2d_.quadTo(cpx, cpy, x, y);
1798 #else
1799 path2d_.QuadTo(cpx, cpy, x, y);
1800 #endif
1801 }
1802
Path2DBezierCurveTo(const PathArgs & args)1803 void RosenRenderOffscreenCanvas::Path2DBezierCurveTo(const PathArgs& args)
1804 {
1805 double cp1x = args.para1;
1806 double cp1y = args.para2;
1807 double cp2x = args.para3;
1808 double cp2y = args.para4;
1809 double x = args.para5;
1810 double y = args.para6;
1811 #ifndef USE_ROSEN_DRAWING
1812 skPath2d_.cubicTo(cp1x, cp1y, cp2x, cp2y, x, y);
1813 #else
1814 path2d_.CubicTo(cp1x, cp1y, cp2x, cp2y, x, y);
1815 #endif
1816 }
1817
Path2DEllipse(const PathArgs & args)1818 void RosenRenderOffscreenCanvas::Path2DEllipse(const PathArgs& args)
1819 {
1820 if (NearEqual(args.para6, args.para7)) {
1821 return; // Just return when startAngle is same as endAngle.
1822 }
1823
1824 double x = args.para1;
1825 double y = args.para2;
1826 double rx = args.para3;
1827 double ry = args.para4;
1828 double rotation = args.para5 * HALF_CIRCLE_ANGLE / M_PI;
1829 double startAngle = std::fmod(args.para6, M_PI * 2.0);
1830 double endAngle = std::fmod(args.para7, M_PI * 2.0);
1831 bool anticlockwise = NearZero(args.para8) ? false : true;
1832 startAngle = (startAngle < 0.0 ? startAngle + M_PI * 2.0 : startAngle) * HALF_CIRCLE_ANGLE / M_PI;
1833 endAngle = (endAngle < 0.0 ? endAngle + M_PI * 2.0 : endAngle) * HALF_CIRCLE_ANGLE / M_PI;
1834 double sweepAngle = endAngle - startAngle;
1835 if (anticlockwise) {
1836 if (sweepAngle > 0.0) { // Make sure the sweepAngle is negative when anticlockwise.
1837 sweepAngle -= FULL_CIRCLE_ANGLE;
1838 }
1839 } else {
1840 if (sweepAngle < 0.0) { // Make sure the sweepAngle is positive when clockwise.
1841 sweepAngle += FULL_CIRCLE_ANGLE;
1842 }
1843 }
1844 #ifndef USE_ROSEN_DRAWING
1845 auto rect = SkRect::MakeLTRB(x - rx, y - ry,
1846 x + rx, y + ry);
1847
1848 if (!NearZero(rotation)) {
1849 SkMatrix matrix;
1850 matrix.setRotate(-rotation, x, y);
1851 skPath2d_.transform(matrix);
1852 }
1853 if (NearZero(sweepAngle) && !NearZero(args.para6 - args.para7)) {
1854 // The entire ellipse needs to be drawn with two arcTo.
1855 skPath2d_.arcTo(rect, startAngle, HALF_CIRCLE_ANGLE, false);
1856 skPath2d_.arcTo(rect, startAngle + HALF_CIRCLE_ANGLE, HALF_CIRCLE_ANGLE, false);
1857 } else {
1858 skPath2d_.arcTo(rect, startAngle, sweepAngle, false);
1859 }
1860 if (!NearZero(rotation)) {
1861 SkMatrix matrix;
1862 matrix.setRotate(rotation, x, y);
1863 skPath2d_.transform(matrix);
1864 }
1865 #else
1866 RSPoint point1(x - rx, y - ry);
1867 RSPoint point2(x + rx, y + ry);
1868
1869 if (!NearZero(rotation)) {
1870 RSMatrix matrix;
1871 matrix.Rotate(-rotation, x, y);
1872 path2d_.Transform(matrix);
1873 }
1874 if (NearZero(sweepAngle) && !NearZero(args.para6 - args.para7)) {
1875 // The entire ellipse needs to be drawn with two arcTo.
1876 path2d_.ArcTo(point1, point2, startAngle, HALF_CIRCLE_ANGLE);
1877 path2d_.ArcTo(point1, point2, startAngle + HALF_CIRCLE_ANGLE, HALF_CIRCLE_ANGLE);
1878 } else {
1879 path2d_.ArcTo(point1, point2, startAngle, sweepAngle);
1880 }
1881 if (!NearZero(rotation)) {
1882 RSMatrix matrix;
1883 matrix.Rotate(rotation, x, y);
1884 path2d_.Transform(matrix);
1885 }
1886 #endif
1887 }
1888
Path2DRect(const PathArgs & args)1889 void RosenRenderOffscreenCanvas::Path2DRect(const PathArgs& args)
1890 {
1891 double left = args.para1;
1892 double top = args.para2;
1893 double right = args.para3 + args.para1;
1894 double bottom = args.para4 + args.para2;
1895 #ifndef USE_ROSEN_DRAWING
1896 skPath2d_.addRect(SkRect::MakeLTRB(left, top, right, bottom));
1897 #else
1898 path2d_.AddRect(RSRect(left, top, right, bottom));
1899 #endif
1900 }
1901
Path2DClosePath(const PathArgs & args)1902 void RosenRenderOffscreenCanvas::Path2DClosePath(const PathArgs& args)
1903 {
1904 #ifndef USE_ROSEN_DRAWING
1905 skPath2d_.close();
1906 #else
1907 path2d_.Close();
1908 #endif
1909 }
1910
Path2DStroke()1911 void RosenRenderOffscreenCanvas::Path2DStroke()
1912 {
1913 #ifndef USE_ROSEN_DRAWING
1914 SkPaint paint = GetStrokePaint();
1915 paint.setAntiAlias(antiAlias_);
1916 if (HasShadow()) {
1917 #ifndef NEW_SKIA
1918 FlutterDecorationPainter::PaintShadow(skPath2d_, shadow_, skCanvas_.get());
1919 #else
1920 RosenDecorationPainter::PaintShadow(skPath2d_, shadow_, skCanvas_.get());
1921 #endif
1922 }
1923 if (strokeState_.GetGradient().IsValid()) {
1924 UpdatePaintShader(paint, strokeState_.GetGradient());
1925 }
1926 if (strokeState_.GetPattern().IsValid()) {
1927 UpdatePaintShader(strokeState_.GetPattern(), paint);
1928 }
1929 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
1930 skCanvas_->drawPath(skPath2d_, paint);
1931 } else {
1932 InitCachePaint();
1933 cacheCanvas_->drawPath(skPath2d_, paint);
1934 #ifndef NEW_SKIA
1935 skCanvas_->drawBitmap(cacheBitmap_, 0, 0, &cachePaint_);
1936 #else
1937 skCanvas_->drawImage(cacheBitmap_.asImage(), 0, 0, SkSamplingOptions(), &cachePaint_);
1938 #endif
1939 cacheBitmap_.eraseColor(0);
1940 }
1941 #else
1942 RSPen pen = GetStrokePaint();
1943 pen.SetAntiAlias(antiAlias_);
1944 if (HasShadow()) {
1945 RosenDecorationPainter::PaintShadow(path2d_, shadow_, canvas_.get());
1946 }
1947 if (strokeState_.GetGradient().IsValid()) {
1948 UpdatePaintShader(&pen, nullptr, strokeState_.GetGradient());
1949 }
1950 if (strokeState_.GetPattern().IsValid()) {
1951 UpdatePaintShader(strokeState_.GetPattern(), &pen, nullptr);
1952 }
1953 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
1954 canvas_->AttachPen(pen);
1955 canvas_->DrawPath(path2d_);
1956 canvas_->DetachPen();
1957 } else {
1958 InitCachePaint();
1959 cacheCanvas_->AttachPen(pen);
1960 cacheCanvas_->DrawPath(path2d_);
1961 cacheCanvas_->DetachPen();
1962 canvas_->AttachBrush(cacheBrush_);
1963 canvas_->DrawBitmap(cacheBitmap_, 0, 0);
1964 canvas_->DetachBrush();
1965 cacheBitmap_.ClearWithColor(RSColor::COLOR_TRANSPARENT);
1966 }
1967 #endif
1968 }
1969
Path2DFill()1970 void RosenRenderOffscreenCanvas::Path2DFill()
1971 {
1972 #ifndef USE_ROSEN_DRAWING
1973 SkPaint paint;
1974 paint.setAntiAlias(antiAlias_);
1975 paint.setColor(fillState_.GetColor().GetValue());
1976 paint.setStyle(SkPaint::Style::kFill_Style);
1977 if (HasShadow()) {
1978 #ifndef NEW_SKIA
1979 FlutterDecorationPainter::PaintShadow(skPath2d_, shadow_, skCanvas_.get());
1980 #else
1981 RosenDecorationPainter::PaintShadow(skPath2d_, shadow_, skCanvas_.get());
1982 #endif
1983 }
1984 if (fillState_.GetGradient().IsValid()) {
1985 UpdatePaintShader(paint, fillState_.GetGradient());
1986 }
1987 if (fillState_.GetPattern().IsValid()) {
1988 UpdatePaintShader(fillState_.GetPattern(), paint);
1989 }
1990 if (globalState_.HasGlobalAlpha()) {
1991 paint.setAlphaf(globalState_.GetAlpha());
1992 }
1993 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
1994 skCanvas_->drawPath(skPath2d_, paint);
1995 } else {
1996 InitCachePaint();
1997 cacheCanvas_->drawPath(skPath2d_, paint);
1998 #ifndef NEW_SKIA
1999 skCanvas_->drawBitmap(cacheBitmap_, 0, 0, &cachePaint_);
2000 #else
2001 skCanvas_->drawImage(cacheBitmap_.asImage(), 0, 0, SkSamplingOptions(), &cachePaint_);
2002 #endif
2003 cacheBitmap_.eraseColor(0);
2004 }
2005 #else
2006 RSBrush brush;
2007 brush.SetAntiAlias(antiAlias_);
2008 brush.SetColor(fillState_.GetColor().GetValue());
2009 if (HasShadow()) {
2010 RosenDecorationPainter::PaintShadow(path2d_, shadow_, canvas_.get());
2011 }
2012 if (fillState_.GetGradient().IsValid()) {
2013 UpdatePaintShader(nullptr, &brush, fillState_.GetGradient());
2014 }
2015 if (fillState_.GetPattern().IsValid()) {
2016 UpdatePaintShader(fillState_.GetPattern(), nullptr, &brush);
2017 }
2018 if (globalState_.HasGlobalAlpha()) {
2019 brush.SetAlphaF(globalState_.GetAlpha());
2020 }
2021 if (globalState_.GetType() == CompositeOperation::SOURCE_OVER) {
2022 canvas_->AttachBrush(brush);
2023 canvas_->DrawPath(path2d_);
2024 canvas_->DetachBrush();
2025 } else {
2026 InitCachePaint();
2027 cacheCanvas_->AttachBrush(brush);
2028 cacheCanvas_->DrawPath(path2d_);
2029 cacheCanvas_->DetachBrush();
2030 canvas_->AttachBrush(cacheBrush_);
2031 canvas_->DrawBitmap(cacheBitmap_, 0, 0);
2032 canvas_->DetachBrush();
2033 cacheBitmap_.ClearWithColor(RSColor::COLOR_TRANSPARENT);
2034 }
2035 #endif
2036 }
2037
Path2DClip()2038 void RosenRenderOffscreenCanvas::Path2DClip()
2039 {
2040 #ifndef USE_ROSEN_DRAWING
2041 skCanvas_->clipPath(skPath2d_);
2042 #else
2043 canvas_->ClipPath(path2d_, RSClipOp::INTERSECT);
2044 #endif
2045 }
2046
2047 #ifndef USE_ROSEN_DRAWING
UpdateLineDash(SkPaint & paint)2048 void RosenRenderOffscreenCanvas::UpdateLineDash(SkPaint& paint)
2049 {
2050 if (!strokeState_.GetLineDash().lineDash.empty()) {
2051 auto lineDashState = strokeState_.GetLineDash().lineDash;
2052 SkScalar intervals[lineDashState.size()];
2053 for (size_t i = 0; i < lineDashState.size(); ++i) {
2054 intervals[i] = SkDoubleToScalar(lineDashState[i]);
2055 }
2056 SkScalar phase = SkDoubleToScalar(strokeState_.GetLineDash().dashOffset);
2057 paint.setPathEffect(SkDashPathEffect::Make(intervals, lineDashState.size(), phase));
2058 }
2059 }
2060 #else
UpdateLineDash(RSPen & pen)2061 void RosenRenderOffscreenCanvas::UpdateLineDash(RSPen& pen)
2062 {
2063 if (!strokeState_.GetLineDash().lineDash.empty()) {
2064 auto lineDashState = strokeState_.GetLineDash().lineDash;
2065 RSScalar intervals[lineDashState.size()];
2066 for (size_t i = 0; i < lineDashState.size(); ++i) {
2067 intervals[i] = static_cast<RSScalar>(lineDashState[i]);
2068 }
2069 RSScalar phase = static_cast<RSScalar>(strokeState_.GetLineDash().dashOffset);
2070 pen.SetPathEffect(RSPathEffect::CreateDashPathEffect(intervals, lineDashState.size(), phase));
2071 }
2072 }
2073 #endif
2074
ArcTo(const ArcToParam & param)2075 void RosenRenderOffscreenCanvas::ArcTo(const ArcToParam& param)
2076 {
2077 #ifndef USE_ROSEN_DRAWING
2078 double x1 = param.x1;
2079 double y1 = param.y1;
2080 double x2 = param.x2;
2081 double y2 = param.y2;
2082 double radius = param.radius;
2083 skPath_.arcTo(SkDoubleToScalar(x1), SkDoubleToScalar(y1), SkDoubleToScalar(x2), SkDoubleToScalar(y2),
2084 SkDoubleToScalar(radius));
2085 #else
2086 LOGE("Drawing is not supported");
2087 #endif
2088 }
MoveTo(double x,double y)2089 void RosenRenderOffscreenCanvas::MoveTo(double x, double y)
2090 {
2091 #ifndef USE_ROSEN_DRAWING
2092 skPath_.moveTo(SkDoubleToScalar(x), SkDoubleToScalar(y));
2093 #else
2094 path_.MoveTo(static_cast<RSScalar>(x), static_cast<RSScalar>(y));
2095 #endif
2096 }
ClosePath()2097 void RosenRenderOffscreenCanvas::ClosePath()
2098 {
2099 #ifndef USE_ROSEN_DRAWING
2100 skPath_.close();
2101 #else
2102 path_.Close();
2103 #endif
2104 }
2105
Rotate(double angle)2106 void RosenRenderOffscreenCanvas::Rotate(double angle)
2107 {
2108 #ifndef USE_ROSEN_DRAWING
2109 skCanvas_->rotate(angle * 180 / M_PI);
2110 #else
2111 canvas_->Rotate(angle * 180 / M_PI);
2112 #endif
2113 }
Scale(double x,double y)2114 void RosenRenderOffscreenCanvas::Scale(double x, double y)
2115 {
2116 #ifndef USE_ROSEN_DRAWING
2117 skCanvas_->scale(x, y);
2118 #else
2119 canvas_->Scale(x, y);
2120 #endif
2121 }
2122
FillText(const std::string & text,double x,double y,const PaintState & state)2123 void RosenRenderOffscreenCanvas::FillText(const std::string& text, double x, double y, const PaintState& state)
2124 {
2125 if (!UpdateOffParagraph(text, false, state, HasShadow())) {
2126 return;
2127 }
2128 PaintText(text, x, y, false, HasShadow());
2129 }
2130
StrokeText(const std::string & text,double x,double y,const PaintState & state)2131 void RosenRenderOffscreenCanvas::StrokeText(const std::string& text, double x, double y, const PaintState& state)
2132 {
2133 if (HasShadow()) {
2134 if (!UpdateOffParagraph(text, true, state, true)) {
2135 return;
2136 }
2137 PaintText(text, x, y, true, true);
2138 }
2139
2140 if (!UpdateOffParagraph(text, true, state)) {
2141 return;
2142 }
2143 PaintText(text, x, y, true);
2144 }
2145
MeasureText(const std::string & text,const PaintState & state)2146 double RosenRenderOffscreenCanvas::MeasureText(const std::string& text, const PaintState& state)
2147 {
2148 using namespace Constants;
2149 txt::ParagraphStyle style;
2150 style.text_align = ConvertTxtTextAlign(state.GetTextAlign());
2151 style.text_direction = ConvertTxtTextDirection(state.GetOffTextDirection());
2152 #ifndef USE_ROSEN_DRAWING
2153 #ifndef NEW_SKIA
2154 auto fontCollection = FlutterFontCollection::GetInstance().GetFontCollection();
2155 #else
2156 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
2157 #endif
2158 #else
2159 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
2160 #endif
2161 if (!fontCollection) {
2162 LOGW("MeasureText: fontCollection is null");
2163 return 0.0;
2164 }
2165 std::unique_ptr<txt::ParagraphBuilder> builder = txt::ParagraphBuilder::CreateTxtBuilder(style, fontCollection);
2166 txt::TextStyle txtStyle;
2167 ConvertTxtStyle(state.GetTextStyle(), pipelineContext_, txtStyle);
2168 txtStyle.font_size = state.GetTextStyle().GetFontSize().Value();
2169 builder->PushStyle(txtStyle);
2170 builder->AddText(StringUtils::Str8ToStr16(text));
2171 auto paragraph = builder->Build();
2172 paragraph->Layout(Size::INFINITE_SIZE);
2173 return paragraph->GetMaxIntrinsicWidth();
2174 }
2175
MeasureTextHeight(const std::string & text,const PaintState & state)2176 double RosenRenderOffscreenCanvas::MeasureTextHeight(const std::string& text, const PaintState& state)
2177 {
2178 using namespace Constants;
2179 txt::ParagraphStyle style;
2180 style.text_align = ConvertTxtTextAlign(state.GetTextAlign());
2181 style.text_direction = ConvertTxtTextDirection(state.GetOffTextDirection());
2182 #ifndef USE_ROSEN_DRAWING
2183 #ifndef NEW_SKIA
2184 auto fontCollection = FlutterFontCollection::GetInstance().GetFontCollection();
2185 #else
2186 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
2187 #endif
2188 #else
2189 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
2190 #endif
2191 if (!fontCollection) {
2192 LOGW("MeasureText: fontCollection is null");
2193 return 0.0;
2194 }
2195 std::unique_ptr<txt::ParagraphBuilder> builder = txt::ParagraphBuilder::CreateTxtBuilder(style, fontCollection);
2196 txt::TextStyle txtStyle;
2197 ConvertTxtStyle(state.GetTextStyle(), pipelineContext_, txtStyle);
2198 txtStyle.font_size = state.GetTextStyle().GetFontSize().Value();
2199 builder->PushStyle(txtStyle);
2200 builder->AddText(StringUtils::Str8ToStr16(text));
2201 auto paragraph = builder->Build();
2202 paragraph->Layout(Size::INFINITE_SIZE);
2203 return paragraph->GetHeight();
2204 }
2205
MeasureTextMetrics(const std::string & text,const PaintState & state)2206 TextMetrics RosenRenderOffscreenCanvas::MeasureTextMetrics(const std::string& text, const PaintState& state)
2207 {
2208 using namespace Constants;
2209 txt::ParagraphStyle style;
2210 style.text_align = ConvertTxtTextAlign(state.GetTextAlign());
2211 style.text_direction = ConvertTxtTextDirection(state.GetOffTextDirection());
2212 #ifndef USE_ROSEN_DRAWING
2213 #ifndef NEW_SKIA
2214 auto fontCollection = FlutterFontCollection::GetInstance().GetFontCollection();
2215 #else
2216 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
2217 #endif
2218 #else
2219 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
2220 #endif
2221 if (!fontCollection) {
2222 LOGW("MeasureText: fontCollection is null");
2223 return { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
2224 }
2225 std::unique_ptr<txt::ParagraphBuilder> builder = txt::ParagraphBuilder::CreateTxtBuilder(style, fontCollection);
2226 txt::TextStyle txtStyle;
2227 ConvertTxtStyle(state.GetTextStyle(), pipelineContext_, txtStyle);
2228 txtStyle.font_size = state.GetTextStyle().GetFontSize().Value();
2229 builder->PushStyle(txtStyle);
2230 builder->AddText(StringUtils::Str8ToStr16(text));
2231 auto paragraph = builder->Build();
2232 paragraph->Layout(Size::INFINITE_SIZE);
2233
2234 auto textAlign = state.GetTextAlign();
2235 auto textBaseLine = state.GetTextStyle().GetTextBaseline();
2236
2237 auto width = paragraph->GetMaxIntrinsicWidth();
2238 auto height = paragraph->GetHeight();
2239
2240 auto actualBoundingBoxLeft = -GetAlignOffset(text, textAlign, paragraph);
2241 auto actualBoundingBoxRight = width - actualBoundingBoxLeft;
2242 auto actualBoundingBoxAscent = -GetBaselineOffset(textBaseLine, paragraph);
2243 auto actualBoundingBoxDescent = height - actualBoundingBoxAscent;
2244
2245 return { width, height, actualBoundingBoxLeft, actualBoundingBoxRight, actualBoundingBoxAscent,
2246 actualBoundingBoxDescent };
2247 }
2248
PaintText(const std::string & text,double x,double y,bool isStroke,bool hasShadow)2249 void RosenRenderOffscreenCanvas::PaintText(const std::string& text, double x, double y, bool isStroke, bool hasShadow)
2250 {
2251 paragraph_->Layout(width_);
2252 if (width_ > paragraph_->GetMaxIntrinsicWidth()) {
2253 paragraph_->Layout(std::ceil(paragraph_->GetMaxIntrinsicWidth()));
2254 }
2255 #ifndef USE_ROSEN_DRAWING
2256 auto align = isStroke ? strokeState_.GetTextAlign() : fillState_.GetTextAlign();
2257 double dx = x + GetAlignOffset(text, align, paragraph_);
2258 auto baseline =
2259 isStroke ? strokeState_.GetTextStyle().GetTextBaseline() : fillState_.GetTextStyle().GetTextBaseline();
2260 double dy = y + GetBaselineOffset(baseline, paragraph_);
2261
2262 if (hasShadow) {
2263 skCanvas_->save();
2264 auto shadowOffsetX = shadow_.GetOffset().GetX();
2265 auto shadowOffsetY = shadow_.GetOffset().GetY();
2266 paragraph_->Paint(skCanvas_.get(), dx + shadowOffsetX, dy + shadowOffsetY);
2267 skCanvas_->restore();
2268 return;
2269 }
2270 paragraph_->Paint(skCanvas_.get(), dx, dy);
2271 #else
2272 if (hasShadow) {
2273 canvas_->Save();
2274 LOGE("Drawing is not supported");
2275 canvas_->Restore();
2276 return;
2277 }
2278 LOGE("Drawing is not supported");
2279 #endif
2280 }
2281
GetAlignOffset(const std::string & text,TextAlign align,std::unique_ptr<txt::Paragraph> & paragraph)2282 double RosenRenderOffscreenCanvas::GetAlignOffset(const std::string& text, TextAlign align,
2283 std::unique_ptr<txt::Paragraph>& paragraph)
2284 {
2285 double x = 0.0;
2286 switch (align) {
2287 case TextAlign::LEFT:
2288 x = 0.0;
2289 break;
2290 case TextAlign::START:
2291 x = (GetTextDirection(text) == TextDirection::LTR) ? 0.0 : -paragraph->GetMaxIntrinsicWidth();
2292 break;
2293 case TextAlign::RIGHT:
2294 x = -paragraph->GetMaxIntrinsicWidth();
2295 break;
2296 case TextAlign::END:
2297 x = (GetTextDirection(text) == TextDirection::LTR) ? -paragraph->GetMaxIntrinsicWidth() : 0.0;
2298 break;
2299 case TextAlign::CENTER:
2300 x = -paragraph->GetMaxIntrinsicWidth() / 2;
2301 break;
2302 default:
2303 x = 0.0;
2304 break;
2305 }
2306 return x;
2307 }
2308
GetTextDirection(const std::string & text)2309 TextDirection RosenRenderOffscreenCanvas::GetTextDirection(const std::string& text)
2310 {
2311 auto wstring = StringUtils::ToWstring(text);
2312 // Find first strong direction char.
2313 for (const auto& charInStr : wstring) {
2314 auto direction = u_charDirection(charInStr);
2315 if (direction == UCharDirection::U_LEFT_TO_RIGHT) {
2316 return TextDirection::LTR;
2317 }
2318 if (direction == UCharDirection::U_RIGHT_TO_LEFT || direction == UCharDirection::U_RIGHT_TO_LEFT_ARABIC) {
2319 return TextDirection::RTL;
2320 }
2321 }
2322 return TextDirection::INHERIT;
2323 }
2324
InitCachePaint()2325 void RosenRenderOffscreenCanvas::InitCachePaint()
2326 {
2327 #ifndef USE_ROSEN_DRAWING
2328 cachePaint_.setBlendMode(
2329 ConvertEnumToSkEnum(globalState_.GetType(), SK_BLEND_MODE_TABLE, BLEND_MODE_SIZE, SkBlendMode::kSrcOver));
2330 #else
2331 cacheBrush_.SetBlendMode(ConvertEnumToDrawingEnum(
2332 globalState_.GetType(), DRAWING_BLEND_MODE_TABLE, BLEND_MODE_SIZE, RSBlendMode::SRC_OVER));
2333 #endif
2334 }
2335
UpdateOffParagraph(const std::string & text,bool isStroke,const PaintState & state,bool hasShadow)2336 bool RosenRenderOffscreenCanvas::UpdateOffParagraph(const std::string& text, bool isStroke,
2337 const PaintState& state, bool hasShadow)
2338 {
2339 using namespace Constants;
2340 txt::ParagraphStyle style;
2341 if (isStroke) {
2342 style.text_align = ConvertTxtTextAlign(strokeState_.GetTextAlign());
2343 } else {
2344 style.text_align = ConvertTxtTextAlign(fillState_.GetTextAlign());
2345 }
2346 style.text_direction = ConvertTxtTextDirection(state.GetOffTextDirection());
2347 #ifndef USE_ROSEN_DRAWING
2348 #ifndef NEW_SKIA
2349 auto fontCollection = FlutterFontCollection::GetInstance().GetFontCollection();
2350 #else
2351 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
2352 #endif
2353 #else
2354 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
2355 #endif
2356 if (!fontCollection) {
2357 return false;
2358 }
2359 std::unique_ptr<txt::ParagraphBuilder> builder = txt::ParagraphBuilder::CreateTxtBuilder(style, fontCollection);
2360 txt::TextStyle txtStyle;
2361 if (!isStroke && hasShadow) {
2362 txt::TextShadow txtShadow;
2363 txtShadow.color = shadow_.GetColor().GetValue();
2364 txtShadow.offset.fX = shadow_.GetOffset().GetX();
2365 txtShadow.offset.fY = shadow_.GetOffset().GetY();
2366 #ifndef NEW_SKIA
2367 txtShadow.blur_radius = shadow_.GetBlurRadius();
2368 #else
2369 txtShadow.blur_sigma = shadow_.GetBlurRadius();
2370 #endif
2371 txtStyle.text_shadows.emplace_back(txtShadow);
2372 }
2373 txtStyle.locale = Localization::GetInstance()->GetFontLocale();
2374 UpdateTextStyleForeground(isStroke, txtStyle, hasShadow);
2375 builder->PushStyle(txtStyle);
2376 builder->AddText(StringUtils::Str8ToStr16(text));
2377 paragraph_ = builder->Build();
2378 return true;
2379 }
2380
UpdateTextStyleForeground(bool isStroke,txt::TextStyle & txtStyle,bool hasShadow)2381 void RosenRenderOffscreenCanvas::UpdateTextStyleForeground(
2382 bool isStroke, txt::TextStyle& txtStyle, bool hasShadow)
2383 {
2384 using namespace Constants;
2385 #ifndef USE_ROSEN_DRAWING
2386 if (!isStroke) {
2387 txtStyle.color = ConvertSkColor(fillState_.GetColor());
2388 txtStyle.font_size = fillState_.GetTextStyle().GetFontSize().Value();
2389 ConvertTxtStyle(fillState_.GetTextStyle(), pipelineContext_, txtStyle);
2390 if (fillState_.GetGradient().IsValid()) {
2391 SkPaint paint;
2392 paint.setStyle(SkPaint::Style::kFill_Style);
2393 UpdatePaintShader(paint, fillState_.GetGradient());
2394 txtStyle.foreground = paint;
2395 txtStyle.has_foreground = true;
2396 }
2397 if (globalState_.HasGlobalAlpha()) {
2398 if (txtStyle.has_foreground) {
2399 txtStyle.foreground.setColor(fillState_.GetColor().GetValue());
2400 txtStyle.foreground.setAlphaf(globalState_.GetAlpha()); // set alpha after color
2401 } else {
2402 SkPaint paint;
2403 paint.setColor(fillState_.GetColor().GetValue());
2404 paint.setAlphaf(globalState_.GetAlpha()); // set alpha after color
2405 txtStyle.foreground = paint;
2406 txtStyle.has_foreground = true;
2407 }
2408 }
2409 } else {
2410 // use foreground to draw stroke
2411 SkPaint paint = GetStrokePaint();
2412 ConvertTxtStyle(strokeState_.GetTextStyle(), pipelineContext_, txtStyle);
2413 txtStyle.font_size = strokeState_.GetTextStyle().GetFontSize().Value();
2414 if (strokeState_.GetGradient().IsValid()) {
2415 UpdatePaintShader(paint, strokeState_.GetGradient());
2416 }
2417 if (hasShadow) {
2418 paint.setColor(shadow_.GetColor().GetValue());
2419 #ifndef NEW_SKIA
2420 paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle,
2421 FlutterDecorationPainter::ConvertRadiusToSigma(shadow_.GetBlurRadius())));
2422 #else
2423 paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle,
2424 RosenDecorationPainter::ConvertRadiusToSigma(shadow_.GetBlurRadius())));
2425 #endif
2426 }
2427 txtStyle.foreground = paint;
2428 txtStyle.has_foreground = true;
2429 }
2430 #else
2431 LOGE("Drawing is not supported");
2432 #endif
2433 }
2434
GetBaselineOffset(TextBaseline baseline,std::unique_ptr<txt::Paragraph> & paragraph)2435 double RosenRenderOffscreenCanvas::GetBaselineOffset(TextBaseline baseline,
2436 std::unique_ptr<txt::Paragraph>& paragraph)
2437 {
2438 double y = 0.0;
2439 switch (baseline) {
2440 case TextBaseline::ALPHABETIC:
2441 y = -paragraph->GetAlphabeticBaseline();
2442 break;
2443 case TextBaseline::IDEOGRAPHIC:
2444 y = -paragraph->GetIdeographicBaseline();
2445 break;
2446 case TextBaseline::BOTTOM:
2447 y = -paragraph->GetHeight();
2448 break;
2449 case TextBaseline::TOP:
2450 y = 0.0;
2451 break;
2452 case TextBaseline::MIDDLE:
2453 y = -paragraph->GetHeight() / 2;
2454 break;
2455 case TextBaseline::HANGING:
2456 y = -HANGING_PERCENT * (paragraph->GetHeight() - paragraph->GetAlphabeticBaseline());
2457 break;
2458 default:
2459 y = -paragraph->GetAlphabeticBaseline();
2460 break;
2461 }
2462 return y;
2463 }
LineTo(double x,double y)2464 void RosenRenderOffscreenCanvas::LineTo(double x, double y)
2465 {
2466 #ifndef USE_ROSEN_DRAWING
2467 skPath_.lineTo(SkDoubleToScalar(x), SkDoubleToScalar(y));
2468 #else
2469 path_.LineTo(static_cast<RSScalar>(x), static_cast<RSScalar>(y));
2470 #endif
2471 }
BezierCurveTo(const BezierCurveParam & param)2472 void RosenRenderOffscreenCanvas::BezierCurveTo(const BezierCurveParam& param)
2473 {
2474 #ifndef USE_ROSEN_DRAWING
2475 skPath_.cubicTo(SkDoubleToScalar(param.cp1x), SkDoubleToScalar(param.cp1y),
2476 SkDoubleToScalar(param.cp2x), SkDoubleToScalar(param.cp2y),
2477 SkDoubleToScalar(param.x), SkDoubleToScalar(param.y));
2478 #else
2479 path_.CubicTo(static_cast<RSScalar>(param.cp1x), static_cast<RSScalar>(param.cp1y),
2480 static_cast<RSScalar>(param.cp2x), static_cast<RSScalar>(param.cp2y),
2481 static_cast<RSScalar>(param.x), static_cast<RSScalar>(param.y));
2482 #endif
2483 }
QuadraticCurveTo(const QuadraticCurveParam & param)2484 void RosenRenderOffscreenCanvas::QuadraticCurveTo(const QuadraticCurveParam& param)
2485 {
2486 #ifndef USE_ROSEN_DRAWING
2487 skPath_.quadTo(SkDoubleToScalar(param.cpx), SkDoubleToScalar(param.cpy),
2488 SkDoubleToScalar(param.x), SkDoubleToScalar(param.y));
2489 #else
2490 path_.QuadTo(static_cast<RSScalar>(param.cpx), static_cast<RSScalar>(param.cpy),
2491 static_cast<RSScalar>(param.x), static_cast<RSScalar>(param.y));
2492 #endif
2493 }
Ellipse(const EllipseParam & param)2494 void RosenRenderOffscreenCanvas::Ellipse(const EllipseParam& param)
2495 {
2496 // Init the start and end angle, then calculated the sweepAngle.
2497 double startAngle = std::fmod(param.startAngle, M_PI * 2.0);
2498 double endAngle = std::fmod(param.endAngle, M_PI * 2.0);
2499 startAngle = (startAngle < 0.0 ? startAngle + M_PI * 2.0 : startAngle) * HALF_CIRCLE_ANGLE / M_PI;
2500 endAngle = (endAngle < 0.0 ? endAngle + M_PI * 2.0 : endAngle) * HALF_CIRCLE_ANGLE / M_PI;
2501 if (NearEqual(param.startAngle, param.endAngle)) {
2502 return; // Just return when startAngle is same as endAngle.
2503 }
2504 double rotation = param.rotation * HALF_CIRCLE_ANGLE / M_PI;
2505 double sweepAngle = endAngle - startAngle;
2506 if (param.anticlockwise) {
2507 if (sweepAngle > 0.0) { // Make sure the sweepAngle is negative when anticlockwise.
2508 sweepAngle -= FULL_CIRCLE_ANGLE;
2509 }
2510 } else {
2511 if (sweepAngle < 0.0) { // Make sure the sweepAngle is positive when clockwise.
2512 sweepAngle += FULL_CIRCLE_ANGLE;
2513 }
2514 }
2515
2516 // Init the oval Rect(left, top, right, bottom).
2517 double left = param.x - param.radiusX;
2518 double top = param.y - param.radiusY;
2519 double right = param.x + param.radiusX;
2520 double bottom = param.y + param.radiusY;
2521 #ifndef USE_ROSEN_DRAWING
2522 auto rect = SkRect::MakeLTRB(left, top, right, bottom);
2523 if (!NearZero(rotation)) {
2524 SkMatrix matrix;
2525 matrix.setRotate(-rotation, param.x, param.y);
2526 skPath_.transform(matrix);
2527 }
2528 if (NearZero(sweepAngle) && !NearZero(param.endAngle - param.startAngle)) {
2529 // The entire ellipse needs to be drawn with two arcTo.
2530 skPath_.arcTo(rect, startAngle, HALF_CIRCLE_ANGLE, false);
2531 skPath_.arcTo(rect, startAngle + HALF_CIRCLE_ANGLE, HALF_CIRCLE_ANGLE, false);
2532 } else {
2533 skPath_.arcTo(rect, startAngle, sweepAngle, false);
2534 }
2535 if (!NearZero(rotation)) {
2536 SkMatrix matrix;
2537 matrix.setRotate(rotation, param.x, param.y);
2538 skPath_.transform(matrix);
2539 }
2540 #else
2541 RSPoint point1(left, top);
2542 RSPoint point2(right, bottom);
2543 if (!NearZero(rotation)) {
2544 RSMatrix matrix;
2545 matrix.Rotate(-rotation, param.x, param.y);
2546 path_.Transform(matrix);
2547 }
2548 if (NearZero(sweepAngle) && !NearZero(param.endAngle - param.startAngle)) {
2549 // The entire ellipse needs to be drawn with two arcTo.
2550 path_.ArcTo(point1, point2, startAngle, HALF_CIRCLE_ANGLE);
2551 path_.ArcTo(point1, point2, startAngle + HALF_CIRCLE_ANGLE, HALF_CIRCLE_ANGLE);
2552 } else {
2553 path_.ArcTo(point1, point2, startAngle, sweepAngle);
2554 }
2555 if (!NearZero(rotation)) {
2556 RSMatrix matrix;
2557 matrix.Rotate(rotation, param.x, param.y);
2558 path_.Transform(matrix);
2559 }
2560 #endif
2561 }
SetTransform(const TransformParam & param)2562 void RosenRenderOffscreenCanvas::SetTransform(const TransformParam& param)
2563 {
2564 auto pipeline = pipelineContext_.Upgrade();
2565 if (!pipeline) {
2566 return;
2567 }
2568
2569 // use physical pixel to store bitmap
2570 double viewScale = pipeline->GetViewScale();
2571
2572 #ifndef USE_ROSEN_DRAWING
2573 SkMatrix skMatrix;
2574 skMatrix.setAll(param.scaleX * viewScale, param.skewY * viewScale, param.translateX, param.skewX * viewScale,
2575 param.scaleY * viewScale, param.translateY, 0, 0, 1);
2576 skCanvas_->setMatrix(skMatrix);
2577 #else
2578 RSMatrix matrix;
2579 matrix.SetMatrix(param.scaleX * viewScale, param.skewY * viewScale, param.translateX, param.skewX * viewScale,
2580 param.scaleY * viewScale, param.translateY, 0, 0, 1);
2581 canvas_->SetMatrix(matrix);
2582 #endif
2583 }
Transform(const TransformParam & param)2584 void RosenRenderOffscreenCanvas::Transform(const TransformParam& param)
2585 {
2586 #ifndef USE_ROSEN_DRAWING
2587 SkMatrix skMatrix;
2588 skMatrix.setAll(param.scaleX, param.skewY, param.translateX, param.skewX, param.scaleY, param.translateY, 0, 0, 1);
2589 skCanvas_->concat(skMatrix);
2590 #else
2591 RSMatrix matrix;
2592 matrix.SetMatrix(param.scaleX, param.skewY, param.translateX, param.skewX, param.scaleY, param.translateY, 0, 0, 1);
2593 canvas_->ConcatMatrix(matrix);
2594 #endif
2595 }
Translate(double x,double y)2596 void RosenRenderOffscreenCanvas::Translate(double x, double y)
2597 {
2598 #ifndef USE_ROSEN_DRAWING
2599 skCanvas_->translate(x, y);
2600 #else
2601 canvas_->Translate(x, y);
2602 #endif
2603 }
2604
TranspareCmdToPath(const RefPtr<CanvasPath2D> & path)2605 void RosenRenderOffscreenCanvas::TranspareCmdToPath(const RefPtr<CanvasPath2D>& path)
2606 {
2607 #ifndef USE_ROSEN_DRAWING
2608 skPath2d_.reset();
2609 #else
2610 path2d_.Reset();
2611 #endif
2612 for (const auto& [cmd, args] : path->GetCaches()) {
2613 switch (cmd) {
2614 case PathCmd::CMDS: {
2615 Path2DAddPath(args);
2616 break;
2617 }
2618 case PathCmd::TRANSFORM: {
2619 Path2DSetTransform(args);
2620 break;
2621 }
2622 case PathCmd::MOVE_TO: {
2623 Path2DMoveTo(args);
2624 break;
2625 }
2626 case PathCmd::LINE_TO: {
2627 Path2DLineTo(args);
2628 break;
2629 }
2630 case PathCmd::ARC: {
2631 Path2DArc(args);
2632 break;
2633 }
2634 case PathCmd::ARC_TO: {
2635 Path2DArcTo(args);
2636 break;
2637 }
2638 case PathCmd::QUADRATIC_CURVE_TO: {
2639 Path2DQuadraticCurveTo(args);
2640 break;
2641 }
2642 case PathCmd::BEZIER_CURVE_TO: {
2643 Path2DBezierCurveTo(args);
2644 break;
2645 }
2646 case PathCmd::ELLIPSE: {
2647 Path2DEllipse(args);
2648 break;
2649 }
2650 case PathCmd::RECT: {
2651 Path2DRect(args);
2652 break;
2653 }
2654 case PathCmd::CLOSE_PATH: {
2655 Path2DClosePath(args);
2656 break;
2657 }
2658 default: {
2659 break;
2660 }
2661 }
2662 }
2663 }
2664
2665 #ifndef USE_ROSEN_DRAWING
IsPointInPathByColor(double x,double y,SkPath & path,SkColor colorMatch)2666 bool RosenRenderOffscreenCanvas::IsPointInPathByColor(double x, double y, SkPath& path, SkColor colorMatch)
2667 {
2668 auto imageInfo = SkImageInfo::Make(width_, height_, SkColorType::kRGBA_8888_SkColorType,
2669 SkAlphaType::kOpaque_SkAlphaType);
2670 SkBitmap skBitmap;
2671 skBitmap.allocPixels(imageInfo);
2672 std::unique_ptr<SkCanvas> skCanvas = std::make_unique<SkCanvas>(skBitmap);
2673
2674 SkPaint paint;
2675 paint.setColor(SK_ColorRED);
2676 paint.setStyle(SkPaint::Style::kFill_Style);
2677 skCanvas->drawPath(path, paint);
2678
2679 paint.setColor(SK_ColorBLUE);
2680 paint.setStyle(SkPaint::Style::kStroke_Style);
2681 paint.setStrokeWidth(static_cast<SkScalar>(strokeState_.GetLineWidth()));
2682 skCanvas->drawPath(path, paint);
2683
2684 SkColor color = skBitmap.getColor(x, y);
2685 if (color == colorMatch) {
2686 return true;
2687 }
2688 return false;
2689 }
2690 #else
IsPointInPathByColor(double x,double y,RSPath & path,RSColorQuad colorMatch)2691 bool RosenRenderOffscreenCanvas::IsPointInPathByColor(
2692 double x, double y, RSPath& path, RSColorQuad colorMatch)
2693 {
2694 RSBitmapFormat format { RSColorType::COLORTYPE_RGBA_8888,
2695 RSAlphaType::ALPHATYPE_OPAQUE };
2696
2697 RSBitmap bitmap;
2698 bitmap.Build(width_, height_, format);
2699 std::unique_ptr<RSCanvas> canvas = std::make_unique<RSCanvas>();
2700 canvas->Bind(bitmap);
2701
2702 RSBrush brush;
2703 brush.SetColor(RSColor::COLOR_RED);
2704 canvas->AttachBrush(brush);
2705 canvas->DrawPath(path);
2706 canvas->DetachBrush();
2707
2708 RSPen pen;
2709 pen.SetColor(RSColor::COLOR_BLUE);
2710 pen.SetWidth(static_cast<RSScalar>(strokeState_.GetLineWidth()));
2711 canvas->AttachPen(pen);
2712 canvas->DrawPath(path);
2713 canvas->DetachPen();
2714
2715 RSColorQuad color = bitmap.GetColor(x, y);
2716 if (color == colorMatch) {
2717 return true;
2718 }
2719 return false;
2720 }
2721 #endif
2722
IsPointInPath(double x,double y)2723 bool RosenRenderOffscreenCanvas::IsPointInPath(double x, double y)
2724 {
2725 #ifndef USE_ROSEN_DRAWING
2726 return IsPointInPathByColor(x, y, skPath_, SK_ColorRED);
2727 #else
2728 return IsPointInPathByColor(x, y, path_, RSColor::COLOR_RED);
2729 #endif
2730 }
2731
IsPointInPath(const RefPtr<CanvasPath2D> & path,double x,double y)2732 bool RosenRenderOffscreenCanvas::IsPointInPath(const RefPtr<CanvasPath2D>& path, double x, double y)
2733 {
2734 TranspareCmdToPath(path);
2735 #ifndef USE_ROSEN_DRAWING
2736 return IsPointInPathByColor(x, y, skPath2d_, SK_ColorRED);
2737 #else
2738 return IsPointInPathByColor(x, y, path2d_, RSColor::COLOR_RED);
2739 #endif
2740 }
2741
IsPointInStroke(double x,double y)2742 bool RosenRenderOffscreenCanvas::IsPointInStroke(double x, double y)
2743 {
2744 #ifndef USE_ROSEN_DRAWING
2745 return IsPointInPathByColor(x, y, skPath_, SK_ColorBLUE);
2746 #else
2747 return IsPointInPathByColor(x, y, path_, RSColor::COLOR_BLUE);
2748 #endif
2749 }
2750
IsPointInStroke(const RefPtr<CanvasPath2D> & path,double x,double y)2751 bool RosenRenderOffscreenCanvas::IsPointInStroke(const RefPtr<CanvasPath2D>& path, double x, double y)
2752 {
2753 TranspareCmdToPath(path);
2754 #ifndef USE_ROSEN_DRAWING
2755 return IsPointInPathByColor(x, y, skPath2d_, SK_ColorBLUE);
2756 #else
2757 return IsPointInPathByColor(x, y, path2d_, RSColor::COLOR_BLUE);
2758 #endif
2759 }
2760
InitFilterFunc()2761 void RosenRenderOffscreenCanvas::InitFilterFunc()
2762 {
2763 filterFunc_["grayscale"] = [&](const std::string& percentage) {
2764 SetGrayFilter(percentage);
2765 };
2766 filterFunc_["sepia"] = [&](const std::string& percentage) {
2767 SetSepiaFilter(percentage);
2768 };
2769 filterFunc_["invert"] = [&](const std::string& percentage) {
2770 SetInvertFilter(percentage);
2771 };
2772 filterFunc_["opacity"] = [&](const std::string& percentage) {
2773 SetOpacityFilter(percentage);
2774 };
2775 filterFunc_["brightness"] = [&](const std::string& percentage) {
2776 SetBrightnessFilter(percentage);
2777 };
2778 filterFunc_["contrast"] = [&](const std::string& percentage) {
2779 SetContrastFilter(percentage);
2780 };
2781 filterFunc_["blur"] = [&](const std::string& percentage) {
2782 SetBlurFilter(percentage);
2783 };
2784 filterFunc_["drop-shadow"] = [&](const std::string& percentage) {
2785 SetDropShadowFilter(percentage);
2786 };
2787 filterFunc_["saturate"] = [&](const std::string& percentage) {
2788 SetSaturateFilter(percentage);
2789 };
2790 filterFunc_["hue-rotate"] = [&](const std::string& percentage) {
2791 SetHueRotateFilter(percentage);
2792 };
2793 }
2794
GetFilterType(std::string & filterType,std::string & filterParam)2795 bool RosenRenderOffscreenCanvas::GetFilterType(std::string& filterType, std::string& filterParam)
2796 {
2797 std::string paramData = filterParam_;
2798 size_t index = paramData.find("(");
2799 if (index == std::string::npos) {
2800 return false;
2801 }
2802 filterType = paramData.substr(0, index);
2803 filterParam = paramData.substr(index + 1);
2804 size_t endeIndex = filterParam.find(")");
2805 if (endeIndex == std::string::npos) {
2806 return false;
2807 }
2808 filterParam.erase(endeIndex, 1);
2809 return true;
2810 }
2811
IsPercentStr(std::string & percent)2812 bool RosenRenderOffscreenCanvas::IsPercentStr(std::string& percent)
2813 {
2814 if (percent.find("%") != std::string::npos) {
2815 size_t index = percent.find("%");
2816 percent = percent.substr(0, index);
2817 return true;
2818 }
2819 return false;
2820 }
2821
PxStrToDouble(const std::string & str)2822 double RosenRenderOffscreenCanvas::PxStrToDouble(const std::string& str)
2823 {
2824 double ret = 0;
2825 size_t index = str.find("px");
2826 if (index != std::string::npos) {
2827 std::string result = str.substr(0, index);
2828 std::istringstream iss(result);
2829 iss >> ret;
2830 }
2831 return ret;
2832 }
2833
BlurStrToDouble(const std::string & str)2834 double RosenRenderOffscreenCanvas::BlurStrToDouble(const std::string& str)
2835 {
2836 double ret = 0;
2837 size_t index = str.find("px");
2838 size_t index1 = str.find("rem");
2839 size_t demIndex = std::string::npos;
2840 if (index != std::string::npos) {
2841 demIndex = index;
2842 }
2843 if (index1 != std::string::npos) {
2844 demIndex = index1;
2845 }
2846 if (demIndex != std::string::npos) {
2847 std::string result = str.substr(0, demIndex);
2848 std::istringstream iss(result);
2849 iss >> ret;
2850 }
2851 if (str.find("rem") != std::string::npos) {
2852 return ret * 15;
2853 }
2854 return ret;
2855 }
2856
SetGrayFilter(const std::string & percent)2857 void RosenRenderOffscreenCanvas::SetGrayFilter(const std::string& percent)
2858 {
2859 std::string percentage = percent;
2860 bool hasPercent = IsPercentStr(percentage);
2861 float percentNum = 0.0f;
2862 std::istringstream iss(percentage);
2863 iss >> percentNum;
2864 if (hasPercent) {
2865 percentNum = percentNum / 100;
2866 }
2867 if (percentNum > 1) {
2868 percentNum = 1;
2869 }
2870 float otherColor = percentNum / 3;
2871 float primColor = 1 - 2 * otherColor;
2872 float matrix[20] = {0};
2873 matrix[0] = matrix[6] = matrix[12] = primColor;
2874 matrix[1] = matrix[2] = matrix[5] = matrix[7] = matrix[10] = matrix[11] = otherColor;
2875 matrix[18] = 1.0f;
2876 SetColorFilter(matrix);
2877 }
2878
SetSepiaFilter(const std::string & percent)2879 void RosenRenderOffscreenCanvas::SetSepiaFilter(const std::string& percent)
2880 {
2881 std::string percentage = percent;
2882 bool hasPercent = IsPercentStr(percentage);
2883 float percentNum = 0.0f;
2884 std::istringstream iss(percentage);
2885 iss >> percentNum;
2886 if (hasPercent) {
2887 percentNum = percentNum / 100;
2888 }
2889 if (percentNum > 1) {
2890 percentNum = 1;
2891 }
2892 float matrix[20] = {0};
2893 matrix[0] = 1.0f - percentNum * 0.6412f;
2894 matrix[1] = percentNum * 0.7044f;
2895 matrix[2] = percentNum * 0.1368f;
2896 matrix[5] = percentNum * 0.2990f;
2897 matrix[6] = 1.0f - percentNum * 0.4130f;
2898 matrix[7] = percentNum * 0.1140f;
2899 matrix[10] = percentNum * 0.2392f;
2900 matrix[11] = percentNum * 0.4696f;
2901 matrix[12] = 1.0f - percentNum * 0.9088f;
2902 matrix[18] = 1.0f;
2903 SetColorFilter(matrix);
2904 }
2905
SetInvertFilter(const std::string & filterParam)2906 void RosenRenderOffscreenCanvas::SetInvertFilter(const std::string& filterParam)
2907 {
2908 std::string percent = filterParam;
2909 bool hasPercent = IsPercentStr(percent);
2910 float percentage = 0.0f;
2911 std::istringstream iss(percent);
2912 iss >> percentage;
2913 if (hasPercent) {
2914 percentage = percentage / 100;
2915 }
2916
2917 float matrix[20] = {0};
2918 matrix[0] = matrix[6] = matrix[12] = 1.0 - 2.0 * percentage;
2919 matrix[4] = matrix[9] = matrix[14] = percentage;
2920 matrix[18] = 1.0f;
2921 SetColorFilter(matrix);
2922 }
2923
SetOpacityFilter(const std::string & filterParam)2924 void RosenRenderOffscreenCanvas::SetOpacityFilter(const std::string& filterParam)
2925 {
2926 std::string percent = filterParam;
2927 bool hasPercent = IsPercentStr(percent);
2928 float percentage = 0.0f;
2929 std::istringstream iss(percent);
2930 iss >> percentage;
2931 if (hasPercent) {
2932 percentage = percentage / 100;
2933 }
2934
2935 float matrix[20] = {0};
2936 matrix[0] = matrix[6] = matrix[12] = 1.0f;
2937 matrix[18] = percentage;
2938 SetColorFilter(matrix);
2939 }
2940
SetBrightnessFilter(const std::string & percent)2941 void RosenRenderOffscreenCanvas::SetBrightnessFilter(const std::string& percent)
2942 {
2943 std::string perStr = percent;
2944 bool hasPercent = IsPercentStr(perStr);
2945 float percentage = 0.0f;
2946 std::istringstream iss(perStr);
2947 iss >> percentage;
2948 if (hasPercent) {
2949 percentage = percentage / 100;
2950 }
2951
2952 if (percentage < 0) {
2953 return;
2954 }
2955 float matrix[20] = {0};
2956 matrix[0] = matrix[6] = matrix[12] = percentage;
2957 matrix[18] = 1.0f;
2958 SetColorFilter(matrix);
2959 }
2960
SetContrastFilter(const std::string & percent)2961 void RosenRenderOffscreenCanvas::SetContrastFilter(const std::string& percent)
2962 {
2963 std::string perStr = percent;
2964 float percentage = 0.0f;
2965 bool hasPercent = IsPercentStr(perStr);
2966 std::istringstream iss(perStr);
2967 iss >> percentage;
2968 if (hasPercent) {
2969 percentage = percentage / 100;
2970 }
2971
2972 float matrix[20] = {0};
2973 matrix[0] = matrix[6] = matrix[12] = percentage;
2974 matrix[4] = matrix[9] = matrix[14] = 0.5f * (1 - percentage);
2975 matrix[18] = 1;
2976 SetColorFilter(matrix);
2977 }
2978
SetBlurFilter(const std::string & percent)2979 void RosenRenderOffscreenCanvas::SetBlurFilter(const std::string& percent)
2980 {
2981 #ifndef USE_ROSEN_DRAWING
2982 #ifndef NEW_SKIA
2983 imagePaint_.setImageFilter(SkBlurImageFilter::Make(BlurStrToDouble(percent), BlurStrToDouble(percent), nullptr));
2984 #else
2985 imagePaint_.setImageFilter(SkImageFilters::Blur(BlurStrToDouble(percent), BlurStrToDouble(percent), nullptr));
2986 #endif
2987 #else
2988 auto filter = imageBrush_.GetFilter();
2989 filter.SetImageFilter(RSImageFilter::CreateBlurImageFilter(
2990 BlurStrToDouble(percent), BlurStrToDouble(percent), RSTileMode::DECAL, nullptr));
2991 imageBrush_.SetFilter(filter);
2992 #endif
2993 }
2994
SetDropShadowFilter(const std::string & percent)2995 void RosenRenderOffscreenCanvas::SetDropShadowFilter(const std::string& percent)
2996 {
2997 std::vector<std::string> offsets;
2998 StringUtils::StringSplitter(percent, ' ', offsets);
2999 if (offsets.empty() || offsets.size() != 4) {
3000 return;
3001 }
3002 imageShadow_.SetOffsetX(PxStrToDouble(offsets[0]));
3003 imageShadow_.SetOffsetY(PxStrToDouble(offsets[1]));
3004 imageShadow_.SetBlurRadius(PxStrToDouble(offsets[2]));
3005 imageShadow_.SetColor(Color::FromString(offsets[3]));
3006 }
3007
SetSaturateFilter(const std::string & filterParam)3008 void RosenRenderOffscreenCanvas::SetSaturateFilter(const std::string& filterParam)
3009 {
3010 std::string percent = filterParam;
3011 bool hasPercent = IsPercentStr(percent);
3012 float percentage = 0.0f;
3013 std::istringstream iss(percent);
3014 iss >> percentage;
3015 if (hasPercent) {
3016 percentage = percentage / 100;
3017 }
3018 double N = percentage;
3019 float matrix[20] = {0};
3020 matrix[0] = 0.3086f * (1 - N) + N;
3021 matrix[1] = matrix[11] = 0.6094f * (1 - N);
3022 matrix[2] = matrix[7] = 0.0820f * (1 - N);
3023 matrix[5] = matrix[10] = 0.3086f * (1 - N);
3024 matrix[6] = 0.6094f * (1 - N) + N;
3025 matrix[12] = 0.0820f * (1 - N) + N;
3026 matrix[18] = 1.0f;
3027 SetColorFilter(matrix);
3028 }
3029
SetHueRotateFilter(const std::string & filterParam)3030 void RosenRenderOffscreenCanvas::SetHueRotateFilter(const std::string& filterParam)
3031 {
3032 std::string percent = filterParam;
3033 float degree = 0.0f;
3034 if (percent.find("deg") != std::string::npos) {
3035 size_t index = percent.find("deg");
3036 percent = percent.substr(0, index);
3037 std::istringstream iss(percent);
3038 iss >> degree;
3039 }
3040 if (percent.find("turn") != std::string::npos) {
3041 size_t index = percent.find("turn");
3042 percent = percent.substr(0, index);
3043 std::istringstream iss(percent);
3044 iss >> degree;
3045 degree = degree * 360;
3046 }
3047 if (percent.find("rad") != std::string::npos) {
3048 size_t index = percent.find("rad");
3049 percent = percent.substr(0, index);
3050 std::istringstream iss(percent);
3051 iss >> degree;
3052 degree = degree * 180 / 3.142f;
3053 }
3054
3055 while (GreatOrEqual(degree, 360)) {
3056 degree -= 360;
3057 }
3058
3059 float matrix[20] = {0};
3060 int32_t type = degree / 120;
3061 float N = (degree - 120 * type) / 120;
3062 switch (type) {
3063 case 0:
3064 // degree is in 0-120
3065 matrix[0] = matrix[6] = matrix[12] = 1 - N;
3066 matrix[2] = matrix[5] = matrix[11] = N;
3067 matrix[18] = 1.0f;
3068 break;
3069 case 1:
3070 // degree is in 120-240
3071 matrix[1] = matrix[7] = matrix[10] = N;
3072 matrix[2] = matrix[5] = matrix[11] = 1 - N;
3073 matrix[18] = 1.0f;
3074 break;
3075 case 2:
3076 // degree is in 240-360
3077 matrix[0] = matrix[6] = matrix[11] = N;
3078 matrix[1] = matrix[7] = matrix[10] = 1 - N;
3079 matrix[18] = 1.0f;
3080 break;
3081 default:
3082 break;
3083 }
3084 SetColorFilter(matrix);
3085 }
3086
SetColorFilter(float matrix[20])3087 void RosenRenderOffscreenCanvas::SetColorFilter(float matrix[20])
3088 {
3089 #ifndef USE_ROSEN_DRAWING
3090 #ifdef USE_SYSTEM_SKIA
3091 matrix[4] *= 255;
3092 matrix[9] *= 255;
3093 matrix[14] *= 255;
3094 matrix[19] *= 255;
3095 imagePaint_.setColorFilter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
3096 #else
3097 imagePaint_.setColorFilter(SkColorFilters::Matrix(matrix));
3098 #endif
3099 #else
3100 RSColorMatrix colorMatrix;
3101 matrix[4] *= 255;
3102 matrix[9] *= 255;
3103 matrix[14] *= 255;
3104 matrix[19] *= 255;
3105 colorMatrix.SetArray(matrix);
3106 auto filter = imageBrush_.GetFilter();
3107 filter.SetColorFilter(RSColorFilter::CreateMatrixColorFilter(colorMatrix));
3108 imageBrush_.SetFilter(filter);
3109 #endif
3110 }
3111 } // namespace OHOS::Ace
3112