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