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