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