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/common/painter/rosen_svg_painter.h"
17
18 #include "include/utils/SkParsePath.h"
19 #include "frameworks/core/components/svg/rosen_render_svg_pattern.h"
20
21 namespace OHOS::Ace {
22
23 namespace {
24
25 constexpr float FLAT_ANGLE = 180.0f;
26 const char ROTATE_TYPE_AUTO[] = "auto";
27 const char ROTATE_TYPE_REVERSE[] = "auto-reverse";
28
29 } // namespace
30
31 #ifndef USE_ROSEN_DRAWING
32 #if !defined(PREVIEW)
33 const char FONT_TYPE_HWCHINESE[] = "/system/fonts/HwChinese-Medium.ttf";
34 const char FONT_TYPE_DROIDSANS[] = "/system/fonts/DroidSans.ttf";
35 sk_sp<SkTypeface> RosenSvgPainter::fontTypeChinese_ = SkTypeface::MakeFromFile(FONT_TYPE_HWCHINESE);
36 sk_sp<SkTypeface> RosenSvgPainter::fontTypeNormal_ = SkTypeface::MakeFromFile(FONT_TYPE_DROIDSANS);
37 #else
38 sk_sp<SkTypeface> RosenSvgPainter::fontTypeChinese_;
39 sk_sp<SkTypeface> RosenSvgPainter::fontTypeNormal_;
40 #endif
41 #else
42 #if !defined(PREVIEW)
43 const char FONT_TYPE_HWCHINESE[] = "/system/fonts/HwChinese-Medium.ttf";
44 const char FONT_TYPE_DROIDSANS[] = "/system/fonts/DroidSans.ttf";
45 std::shared_ptr<RSTypeface> RosenSvgPainter::fontTypeChinese_ = RSTypeface::MakeFromFile(FONT_TYPE_HWCHINESE);
46 std::shared_ptr<RSTypeface> RosenSvgPainter::fontTypeNormal_ = RSTypeface::MakeFromFile(FONT_TYPE_DROIDSANS);
47 #else
48 std::shared_ptr<RSTypeface> RosenSvgPainter::fontTypeChinese_;
49 std::shared_ptr<RSTypeface> RosenSvgPainter::fontTypeNormal_;
50 #endif
51 #endif
52
53 #ifndef USE_ROSEN_DRAWING
SetMask(SkCanvas * canvas)54 void RosenSvgPainter::SetMask(SkCanvas* canvas)
55 {
56 SkPaint mask_filter;
57
58 auto outerFilter = SkLumaColorFilter::Make();
59 auto innerFilter = SkColorFilters::SRGBToLinearGamma();
60 auto filter = SkColorFilters::Compose(outerFilter, std::move(innerFilter));
61 mask_filter.setColorFilter(filter);
62 canvas->saveLayer(nullptr, &mask_filter);
63 }
64 #else
SetMask(RSCanvas * canvas)65 void RosenSvgPainter::SetMask(RSCanvas* canvas)
66 {
67 auto outerFilter = RSRecordingColorFilter::CreateLumaColorFilter();
68 auto innerFilter = RSRecordingColorFilter::CreateSrgbGammaToLinear();
69 auto colorFilter = RSRecordingColorFilter::CreateComposeColorFilter(*outerFilter, *innerFilter);
70 RSFilter filter;
71 filter.SetColorFilter(colorFilter);
72 RSBrush mask_filter;
73 mask_filter.SetFilter(filter);
74 RSSaveLayerOps saveLayerRec(nullptr, &mask_filter);
75 canvas->SaveLayer(saveLayerRec);
76 }
77 #endif
78
79 #ifndef USE_ROSEN_DRAWING
SetFillStyle(SkPaint & skPaint,const FillState & fillState,uint8_t opacity,bool antiAlias)80 void RosenSvgPainter::SetFillStyle(SkPaint& skPaint, const FillState& fillState, uint8_t opacity, bool antiAlias)
81 {
82 double curOpacity = fillState.GetOpacity().GetValue() * opacity * (1.0f / UINT8_MAX);
83 skPaint.setStyle(SkPaint::Style::kFill_Style);
84 skPaint.setAntiAlias(antiAlias);
85 if (fillState.GetGradient()) {
86 SetGradientStyle(skPaint, fillState, curOpacity);
87 } else {
88 skPaint.setColor(fillState.GetColor().BlendOpacity(curOpacity).GetValue());
89 }
90 }
91 #else
SetFillStyle(RSBrush & brush,const FillState & fillState,uint8_t opacity,bool antiAlias)92 void RosenSvgPainter::SetFillStyle(RSBrush& brush,
93 const FillState& fillState, uint8_t opacity, bool antiAlias)
94 {
95 double curOpacity = fillState.GetOpacity().GetValue() * opacity * (1.0f / UINT8_MAX);
96 brush.SetAntiAlias(antiAlias);
97 if (fillState.GetGradient()) {
98 SetGradientStyle(brush, fillState, curOpacity);
99 } else {
100 brush.SetColor(fillState.GetColor().BlendOpacity(curOpacity).GetValue());
101 }
102 }
103 #endif
104
105 #ifndef USE_ROSEN_DRAWING
SetFillStyle(SkCanvas * skCanvas,const SkPath & skPath,const FillState & fillState,uint8_t opacity,bool antiAlias)106 void RosenSvgPainter::SetFillStyle(
107 SkCanvas* skCanvas, const SkPath& skPath, const FillState& fillState, uint8_t opacity, bool antiAlias)
108 {
109 if (fillState.GetColor() == Color::TRANSPARENT && !fillState.GetGradient()) {
110 return;
111 }
112 SkPaint paint;
113 SetFillStyle(paint, fillState, opacity, antiAlias);
114 skCanvas->drawPath(skPath, paint);
115 }
116 #else
SetFillStyle(RSCanvas * canvas,const RSPath & path,const FillState & fillState,uint8_t opacity,bool antiAlias)117 void RosenSvgPainter::SetFillStyle(RSCanvas* canvas, const RSPath& path,
118 const FillState& fillState, uint8_t opacity, bool antiAlias)
119 {
120 if (fillState.GetColor() == Color::TRANSPARENT && !fillState.GetGradient()) {
121 return;
122 }
123 RSBrush brush;
124 SetFillStyle(brush, fillState, opacity, antiAlias);
125 canvas->AttachBrush(brush);
126 canvas->DrawPath(path);
127 canvas->DetachBrush();
128 }
129 #endif
130
131 #ifndef USE_ROSEN_DRAWING
SetGradientStyle(SkPaint & skPaint,const FillState & fillState,double opacity)132 void RosenSvgPainter::SetGradientStyle(SkPaint& skPaint, const FillState& fillState, double opacity)
133 {
134 auto gradient = fillState.GetGradient();
135 if (!gradient) {
136 return;
137 }
138 auto gradientColors = gradient->GetColors();
139 if (gradientColors.empty()) {
140 return;
141 }
142 std::vector<SkScalar> pos;
143 std::vector<SkColor> colors;
144 for (const auto& gradientColor : gradientColors) {
145 pos.push_back(gradientColor.GetDimension().Value());
146 colors.push_back(
147 gradientColor.GetColor().BlendOpacity(gradientColor.GetOpacity()).BlendOpacity(opacity).GetValue());
148 }
149 if (gradient->GetType() == GradientType::LINEAR) {
150 auto info = gradient->GetLinearGradientInfo();
151 SkPoint pts[2] = { SkPoint::Make(info.x1, info.y1), SkPoint::Make(info.x2, info.y2) };
152
153 skPaint.setShader(SkGradientShader::MakeLinear(pts, &colors[0], &pos[0], gradientColors.size(),
154 static_cast<SkTileMode>(gradient->GetSpreadMethod()), 0, nullptr));
155 }
156 if (gradient->GetType() == GradientType::RADIAL) {
157 auto info = gradient->GetRadialGradientInfo();
158 auto center = SkPoint::Make(info.cx, info.cy);
159 auto focal = SkPoint::Make(info.fx, info.fx);
160
161 return center == focal
162 ? skPaint.setShader(SkGradientShader::MakeRadial(center, info.r, &colors[0], &pos[0],
163 gradientColors.size(), static_cast<SkTileMode>(gradient->GetSpreadMethod()), 0, nullptr))
164 : skPaint.setShader(
165 SkGradientShader::MakeTwoPointConical(focal, 0, center, info.r, &colors[0], &pos[0],
166 gradientColors.size(), static_cast<SkTileMode>(gradient->GetSpreadMethod()), 0, nullptr));
167 }
168 }
169 #else
SetGradientStyle(RSBrush & brush,const FillState & fillState,double opacity)170 void RosenSvgPainter::SetGradientStyle(RSBrush& brush, const FillState& fillState, double opacity)
171 {
172 auto gradient = fillState.GetGradient();
173 if (!gradient) {
174 return;
175 }
176 auto gradientColors = gradient->GetColors();
177 if (gradientColors.empty()) {
178 return;
179 }
180 std::vector<RSScalar> pos;
181 std::vector<RSColorQuad> colors;
182 for (const auto& gradientColor : gradientColors) {
183 pos.push_back(gradientColor.GetDimension().Value());
184 colors.push_back(
185 gradientColor.GetColor().BlendOpacity(gradientColor.GetOpacity()).BlendOpacity(opacity).GetValue());
186 }
187 if (gradient->GetType() == GradientType::LINEAR) {
188 auto info = gradient->GetLinearGradientInfo();
189 RSPoint startPt = RSPoint(info.x1, info.y1);
190 RSPoint endPt = RSPoint(info.x2, info.y2);
191 brush.SetShaderEffect(RSRecordingShaderEffect::CreateLinearGradient(
192 startPt, endPt, colors, pos, static_cast<RSTileMode>(gradient->GetSpreadMethod())));
193 }
194 if (gradient->GetType() == GradientType::RADIAL) {
195 auto info = gradient->GetRadialGradientInfo();
196 auto center = RSPoint(info.cx, info.cy);
197 auto focal = RSPoint(info.fx, info.fx);
198 RSMatrix matrix;
199 return center == focal ? brush.SetShaderEffect(RSRecordingShaderEffect::CreateRadialGradient(center,
200 info.r, colors, pos, static_cast<RSTileMode>(gradient->GetSpreadMethod())))
201 : brush.SetShaderEffect(RSRecordingShaderEffect::CreateTwoPointConical(focal, 0, center,
202 info.r, colors, pos, static_cast<RSTileMode>(gradient->GetSpreadMethod()), &matrix));
203 }
204 }
205 #endif
206
207 #ifndef USE_ROSEN_DRAWING
SetFillStyle(SkCanvas * canvas,const SkPath & skPath,const FillState & fillState,RenderInfo & renderInfo)208 void RosenSvgPainter::SetFillStyle(
209 SkCanvas* canvas, const SkPath& skPath, const FillState& fillState, RenderInfo& renderInfo)
210 {
211 const auto& fillHref = fillState.GetHref();
212 if (fillHref.empty() || fillState.GetGradient() || !renderInfo.node) {
213 return SetFillStyle(canvas, skPath, fillState, renderInfo.opacity, renderInfo.antiAlias);
214 }
215
216 SkPaint skPaint;
217 skPaint.reset();
218 auto pattern = AceType::DynamicCast<RosenRenderSvgPattern>(renderInfo.node->GetPatternFromRoot(fillHref));
219 if (!pattern) {
220 return;
221 }
222 if (!pattern->OnAsPaint(renderInfo.offset, renderInfo.node->GetPaintBounds(renderInfo.offset), skPaint)) {
223 return;
224 }
225 skPaint.setAlphaf(fillState.GetOpacity().GetValue() * renderInfo.opacity * (1.0f / UINT8_MAX));
226 skPaint.setAntiAlias(renderInfo.antiAlias);
227 canvas->drawPath(skPath, skPaint);
228 }
229 #else
SetFillStyle(RSCanvas * canvas,const RSPath & path,const FillState & fillState,RenderInfo & renderInfo)230 void RosenSvgPainter::SetFillStyle(RSCanvas* canvas,
231 const RSPath& path, const FillState& fillState, RenderInfo& renderInfo)
232 {
233 const auto& fillHref = fillState.GetHref();
234 if (fillHref.empty() || fillState.GetGradient() || !renderInfo.node) {
235 return SetFillStyle(canvas, path, fillState, renderInfo.opacity, renderInfo.antiAlias);
236 }
237
238 RSBrush brush;
239 brush.Reset();
240 auto pattern = AceType::DynamicCast<RosenRenderSvgPattern>(renderInfo.node->GetPatternFromRoot(fillHref));
241 if (!pattern) {
242 return;
243 }
244 if (!pattern->OnAsPaint(renderInfo.offset, renderInfo.node->GetPaintBounds(renderInfo.offset), nullptr, &brush)) {
245 return;
246 }
247 brush.SetAlphaF(fillState.GetOpacity().GetValue() * renderInfo.opacity * (1.0f / UINT8_MAX));
248 brush.SetAntiAlias(renderInfo.antiAlias);
249 canvas->AttachBrush(brush);
250 canvas->DrawPath(path);
251 canvas->DetachBrush();
252 }
253 #endif
254
255 #ifndef USE_ROSEN_DRAWING
SetStrokeStyle(SkPaint & skPaint,const StrokeState & strokeState,uint8_t opacity,bool antiAlias)256 void RosenSvgPainter::SetStrokeStyle(SkPaint& skPaint, const StrokeState& strokeState, uint8_t opacity, bool antiAlias)
257 {
258 skPaint.setStyle(SkPaint::Style::kStroke_Style);
259 double curOpacity = strokeState.GetOpacity().GetValue() * opacity * (1.0f / UINT8_MAX);
260 skPaint.setColor(strokeState.GetColor().BlendOpacity(curOpacity).GetValue());
261 if (strokeState.GetLineCap() == LineCapStyle::ROUND) {
262 skPaint.setStrokeCap(SkPaint::Cap::kRound_Cap);
263 } else if (strokeState.GetLineCap() == LineCapStyle::SQUARE) {
264 skPaint.setStrokeCap(SkPaint::Cap::kSquare_Cap);
265 } else {
266 skPaint.setStrokeCap(SkPaint::Cap::kButt_Cap);
267 }
268 if (strokeState.GetLineJoin() == LineJoinStyle::ROUND) {
269 skPaint.setStrokeJoin(SkPaint::Join::kRound_Join);
270 } else if (strokeState.GetLineJoin() == LineJoinStyle::BEVEL) {
271 skPaint.setStrokeJoin(SkPaint::Join::kBevel_Join);
272 } else {
273 skPaint.setStrokeJoin(SkPaint::Join::kMiter_Join);
274 }
275 skPaint.setStrokeWidth(static_cast<SkScalar>(strokeState.GetLineWidth().Value()));
276 skPaint.setStrokeMiter(static_cast<SkScalar>(strokeState.GetMiterLimit()));
277 skPaint.setAntiAlias(antiAlias);
278 UpdateLineDash(skPaint, strokeState);
279 }
280 #else
SetStrokeStyle(RSPen & pen,const StrokeState & strokeState,uint8_t opacity,bool antiAlias)281 void RosenSvgPainter::SetStrokeStyle(RSPen& pen,
282 const StrokeState& strokeState, uint8_t opacity, bool antiAlias)
283 {
284 double curOpacity = strokeState.GetOpacity().GetValue() * opacity * (1.0f / UINT8_MAX);
285 pen.SetColor(strokeState.GetColor().BlendOpacity(curOpacity).GetValue());
286 if (strokeState.GetLineCap() == LineCapStyle::ROUND) {
287 pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
288 } else if (strokeState.GetLineCap() == LineCapStyle::SQUARE) {
289 pen.SetCapStyle(RSPen::CapStyle::SQUARE_CAP);
290 } else {
291 pen.SetCapStyle(RSPen::CapStyle::FLAT_CAP);
292 }
293 if (strokeState.GetLineJoin() == LineJoinStyle::ROUND) {
294 pen.SetJoinStyle(RSPen::JoinStyle::ROUND_JOIN);
295 } else if (strokeState.GetLineJoin() == LineJoinStyle::BEVEL) {
296 pen.SetJoinStyle(RSPen::JoinStyle::BEVEL_JOIN);
297 } else {
298 pen.SetJoinStyle(RSPen::JoinStyle::MITER_JOIN);
299 }
300 pen.SetWidth(static_cast<RSScalar>(strokeState.GetLineWidth().Value()));
301 pen.SetMiterLimit(static_cast<RSScalar>(strokeState.GetMiterLimit()));
302 pen.SetAntiAlias(antiAlias);
303 UpdateLineDash(pen, strokeState);
304 }
305 #endif
306
307 #ifndef USE_ROSEN_DRAWING
SetStrokeStyle(SkCanvas * skCanvas,const SkPath & skPath,const StrokeState & strokeState,uint8_t opacity,bool antiAlias)308 void RosenSvgPainter::SetStrokeStyle(
309 SkCanvas* skCanvas, const SkPath& skPath, const StrokeState& strokeState, uint8_t opacity, bool antiAlias)
310 {
311 if (strokeState.GetColor() == Color::TRANSPARENT) {
312 return;
313 }
314 if (GreatNotEqual(strokeState.GetLineWidth().Value(), 0.0)) {
315 SkPaint paint;
316 SetStrokeStyle(paint, strokeState, opacity, antiAlias);
317 skCanvas->drawPath(skPath, paint);
318 }
319 }
320 #else
SetStrokeStyle(RSCanvas * canvas,const RSPath & path,const StrokeState & strokeState,uint8_t opacity,bool antiAlias)321 void RosenSvgPainter::SetStrokeStyle(RSCanvas* canvas,
322 const RSPath& path, const StrokeState& strokeState, uint8_t opacity, bool antiAlias)
323 {
324 if (strokeState.GetColor() == Color::TRANSPARENT) {
325 return;
326 }
327 if (GreatNotEqual(strokeState.GetLineWidth().Value(), 0.0)) {
328 RSPen pen;
329 SetStrokeStyle(pen, strokeState, opacity, antiAlias);
330 canvas->AttachPen(pen);
331 canvas->DrawPath(path);
332 canvas->DetachPen();
333 }
334 }
335 #endif
336
337 #ifndef USE_ROSEN_DRAWING
SetStrokeStyle(SkCanvas * skCanvas,const SkPath & skPath,const StrokeState & strokeState,RenderInfo & renderInfo)338 void RosenSvgPainter::SetStrokeStyle(
339 SkCanvas* skCanvas, const SkPath& skPath, const StrokeState& strokeState, RenderInfo& renderInfo)
340 {
341 const auto& strokeHref = strokeState.GetHref();
342 if (strokeHref.empty() || !renderInfo.node) {
343 return SetStrokeStyle(skCanvas, skPath, strokeState, renderInfo.opacity, renderInfo.antiAlias);
344 }
345
346 if (GreatNotEqual(strokeState.GetLineWidth().Value(), 0.0)) {
347 SkPaint paint;
348 SetStrokeStyle(paint, strokeState, renderInfo.opacity, renderInfo.antiAlias);
349 auto pattern = AceType::DynamicCast<RosenRenderSvgPattern>(renderInfo.node->GetPatternFromRoot(strokeHref));
350 if (!pattern) {
351 return;
352 }
353 if (!pattern->OnAsPaint(renderInfo.offset, renderInfo.node->GetPaintBounds(renderInfo.offset), paint)) {
354 return;
355 }
356 skCanvas->drawPath(skPath, paint);
357 }
358 }
359 #else
SetStrokeStyle(RSCanvas * canvas,const RSPath & path,const StrokeState & strokeState,RenderInfo & renderInfo)360 void RosenSvgPainter::SetStrokeStyle(RSCanvas* canvas,
361 const RSPath& path, const StrokeState& strokeState, RenderInfo& renderInfo)
362 {
363 const auto& strokeHref = strokeState.GetHref();
364 if (strokeHref.empty() || !renderInfo.node) {
365 return SetStrokeStyle(canvas, path, strokeState, renderInfo.opacity, renderInfo.antiAlias);
366 }
367
368 if (GreatNotEqual(strokeState.GetLineWidth().Value(), 0.0)) {
369 RSPen pen;
370 SetStrokeStyle(pen, strokeState, renderInfo.opacity, renderInfo.antiAlias);
371 auto pattern = AceType::DynamicCast<RosenRenderSvgPattern>(renderInfo.node->GetPatternFromRoot(strokeHref));
372 if (!pattern) {
373 return;
374 }
375 if (!pattern->OnAsPaint(renderInfo.offset, renderInfo.node->GetPaintBounds(renderInfo.offset), &pen, nullptr)) {
376 return;
377 }
378 canvas->AttachPen(pen);
379 canvas->DrawPath(path);
380 canvas->DetachPen();
381 }
382 }
383 #endif
384
385 #ifndef USE_ROSEN_DRAWING
UpdateLineDash(SkPaint & paint,const StrokeState & strokeState)386 void RosenSvgPainter::UpdateLineDash(SkPaint& paint, const StrokeState& strokeState)
387 {
388 if (!strokeState.GetLineDash().lineDash.empty()) {
389 auto lineDashState = strokeState.GetLineDash().lineDash;
390 SkScalar intervals[lineDashState.size()];
391 for (size_t i = 0; i < lineDashState.size(); ++i) {
392 intervals[i] = SkDoubleToScalar(lineDashState[i]);
393 }
394 SkScalar phase = SkDoubleToScalar(strokeState.GetLineDash().dashOffset);
395 paint.setPathEffect(SkDashPathEffect::Make(intervals, lineDashState.size(), phase));
396 }
397 }
398 #else
UpdateLineDash(RSPen & pen,const StrokeState & strokeState)399 void RosenSvgPainter::UpdateLineDash(RSPen& pen, const StrokeState& strokeState)
400 {
401 if (!strokeState.GetLineDash().lineDash.empty()) {
402 auto lineDashState = strokeState.GetLineDash().lineDash;
403 RSScalar intervals[lineDashState.size()];
404 for (size_t i = 0; i < lineDashState.size(); ++i) {
405 intervals[i] = static_cast<RSScalar>(lineDashState[i]);
406 }
407 RSScalar phase = static_cast<RSScalar>(strokeState.GetLineDash().dashOffset);
408 pen.SetPathEffect(RSRecordingPathEffect::CreateDashPathEffect(intervals, lineDashState.size(), phase));
409 }
410 }
411 #endif
412
CheckFontType()413 void RosenSvgPainter::CheckFontType()
414 {
415 if (!fontTypeChinese_) {
416 LOGW("can't load HwChinese-Medium.ttf");
417 }
418 if (!fontTypeNormal_) {
419 LOGW("can't load DroidSans.ttf");
420 }
421 }
422
423 #ifndef USE_ROSEN_DRAWING
GetPathLength(const std::string & path)424 double RosenSvgPainter::GetPathLength(const std::string& path)
425 {
426 SkPath skPath;
427 SkParsePath::FromSVGString(path.c_str(), &skPath);
428 SkPathMeasure pathMeasure(skPath, false);
429 SkScalar length = pathMeasure.getLength();
430 return length;
431 }
432 #else
GetPathLength(const std::string & path)433 double RosenSvgPainter::GetPathLength(const std::string& path)
434 {
435 RSRecordingPath drawPath;
436 drawPath.BuildFromSVGString(path.c_str());
437 auto length = drawPath.GetLength(false);
438 return length;
439 }
440 #endif
441
442 #ifndef USE_ROSEN_DRAWING
GetPathOffset(const std::string & path,double current)443 Offset RosenSvgPainter::GetPathOffset(const std::string& path, double current)
444 {
445 SkPath skPath;
446 SkParsePath::FromSVGString(path.c_str(), &skPath);
447 SkPathMeasure pathMeasure(skPath, false);
448 SkPoint position;
449 if (!pathMeasure.getPosTan(current, &position, nullptr)) {
450 return Offset(0.0, 0.0);
451 }
452 return Offset(position.fX, position.fY);
453 }
454 #else
GetPathOffset(const std::string & path,double current)455 Offset RosenSvgPainter::GetPathOffset(const std::string& path, double current)
456 {
457 RSRecordingPath drawPath;
458 drawPath.BuildFromSVGString(path.c_str());
459 RSPoint position;
460 RSPoint tangent;
461 if (!drawPath.GetPositionAndTangent(current, position, tangent, false)) {
462 return Offset(0.0, 0.0);
463 }
464 return Offset(position.GetX(), position.GetY());
465 }
466 #endif
467
GetMotionPathPosition(const std::string & path,double percent,MotionPathPosition & result)468 bool RosenSvgPainter::GetMotionPathPosition(const std::string& path, double percent, MotionPathPosition& result)
469 {
470 if (path.empty()) {
471 return false;
472 }
473 #ifndef USE_ROSEN_DRAWING
474 SkPath motion;
475 SkParsePath::FromSVGString(path.c_str(), &motion);
476 SkPathMeasure pathMeasure(motion, false);
477 SkPoint position;
478 SkVector tangent;
479 bool ret = pathMeasure.getPosTan(pathMeasure.getLength() * percent, &position, &tangent);
480 if (!ret) {
481 return false;
482 }
483 result.rotate = SkRadiansToDegrees(std::atan2(tangent.y(), tangent.x()));
484 result.offset.SetX(position.x());
485 result.offset.SetY(position.y());
486 #else
487 RSRecordingPath motion;
488 motion.BuildFromSVGString(path.c_str());
489 RSPoint position;
490 RSPoint tangent;
491 bool ret = motion.GetPositionAndTangent(motion.GetLength(false) * percent, position, tangent, false);
492 if (!ret) {
493 return false;
494 }
495 result.rotate = Rosen::Drawing::ConvertRadiansToDegrees(std::atan2(tangent.GetY(), tangent.GetX()));
496 result.offset.SetX(position.GetX());
497 result.offset.SetY(position.GetY());
498 #endif
499 return true;
500 }
501
502 #ifndef USE_ROSEN_DRAWING
UpdateText(SkCanvas * canvas,const SvgTextInfo & svgTextInfo,const TextDrawInfo & textDrawInfo)503 Offset RosenSvgPainter::UpdateText(SkCanvas* canvas, const SvgTextInfo& svgTextInfo, const TextDrawInfo& textDrawInfo)
504 {
505 Offset offset = textDrawInfo.offset;
506 if (!canvas) {
507 LOGE("Paint skCanvas is null");
508 return offset;
509 }
510
511 SkFont font;
512 font.setSize(svgTextInfo.textStyle.GetFontSize().Value());
513 font.setScaleX(1.0);
514
515 double space = 0.0;
516 SkScalar x = SkDoubleToScalar(offset.GetX());
517 SkScalar y = SkDoubleToScalar(offset.GetY());
518 std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
519
520 SkPaint paint;
521 SkPaint strokePaint;
522 RosenSvgPainter::SetFillStyle(paint, svgTextInfo.fillState, svgTextInfo.opacity);
523 RosenSvgPainter::SetStrokeStyle(strokePaint, svgTextInfo.strokeState, svgTextInfo.opacity);
524
525 for (int i = 0; i < (int)data.size(); i++) {
526 wchar_t temp = data[i];
527 if (temp >= 0x4e00 && temp <= 0x9fa5) {
528 // range of chinese
529 font.setTypeface(fontTypeChinese_);
530 } else {
531 font.setTypeface(fontTypeNormal_);
532 }
533 auto blob = SkTextBlob::MakeFromText(&temp, sizeof(temp), font, SkTextEncoding::kUTF16);
534 #ifdef WINDOWS_PLATFORM
535 auto width = font.measureText(&temp, 4, SkTextEncoding::kUTF16);
536 #else
537 auto width = font.measureText(&temp, sizeof(temp), SkTextEncoding::kUTF16);
538 #endif
539
540 canvas->save();
541 canvas->rotate(textDrawInfo.rotate, x, y);
542 canvas->drawTextBlob(blob.get(), x, y, paint);
543 if (svgTextInfo.strokeState.HasStroke() && !NearZero(svgTextInfo.strokeState.GetLineWidth().Value())) {
544 canvas->drawTextBlob(blob.get(), x, y, strokePaint);
545 }
546 canvas->restore();
547 x = x + width + space;
548 }
549
550 return Offset(x, y);
551 }
552 #else
UpdateText(RSCanvas * canvas,const SvgTextInfo & svgTextInfo,const TextDrawInfo & textDrawInfo)553 Offset RosenSvgPainter::UpdateText(RSCanvas* canvas, const SvgTextInfo& svgTextInfo, const TextDrawInfo& textDrawInfo)
554 {
555 Offset offset = textDrawInfo.offset;
556 if (!canvas) {
557 LOGE("Paint skCanvas is null");
558 return offset;
559 }
560
561 RSFont font;
562 font.SetSize(svgTextInfo.textStyle.GetFontSize().Value());
563 font.SetScaleX(1.0);
564
565 double space = 0.0;
566 SkScalar x = SkDoubleToScalar(offset.GetX());
567 SkScalar y = SkDoubleToScalar(offset.GetY());
568 std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
569
570 RSBrush brush;
571 RSPen strokePen;
572 RosenSvgPainter::SetFillStyle(brush, svgTextInfo.fillState, svgTextInfo.opacity);
573 RosenSvgPainter::SetStrokeStyle(strokePen, svgTextInfo.strokeState, svgTextInfo.opacity);
574
575 for (int i = 0; i < (int)data.size(); i++) {
576 wchar_t temp = data[i];
577 if (temp >= 0x4e00 && temp <= 0x9fa5) {
578 // range of chinese
579 font.SetTypeface(fontTypeChinese_);
580 } else {
581 font.SetTypeface(fontTypeNormal_);
582 }
583 auto blob = RSTextBlob::MakeFromText(&temp, sizeof(temp), font, RSTextEncoding::UTF16);
584 #ifdef WINDOWS_PLATFORM
585 auto width = font.MeasureText(&temp, 4, RSTextEncoding::UTF16);
586 #else
587 auto width = font.MeasureText(&temp, sizeof(temp), RSTextEncoding::UTF16);
588 #endif
589
590 canvas->Save();
591 canvas->Rotate(textDrawInfo.rotate, x, y);
592 canvas->AttachBrush(brush);
593 canvas->DrawTextBlob(blob.get(), x, y);
594 canvas->DetachBrush();
595 if (svgTextInfo.strokeState.HasStroke() && !NearZero(svgTextInfo.strokeState.GetLineWidth().Value())) {
596 canvas->AttachPen(strokePen);
597 canvas->DrawTextBlob(blob.get(), x, y);
598 canvas->DetachPen();
599 }
600 canvas->Restore();
601 x = x + width + space;
602 }
603
604 return Offset(x, y);
605 }
606 #endif
607
608 #ifndef USE_ROSEN_DRAWING
UpdateTextPath(SkCanvas * canvas,const SvgTextInfo & svgTextInfo,const PathDrawInfo & pathDrawInfo)609 double RosenSvgPainter::UpdateTextPath(
610 SkCanvas* canvas, const SvgTextInfo& svgTextInfo, const PathDrawInfo& pathDrawInfo)
611 {
612 double offset = pathDrawInfo.offset;
613 if (!canvas) {
614 LOGE("Paint skCanvas is null");
615 return offset;
616 }
617
618 SkFont font;
619 font.setSize(svgTextInfo.textStyle.GetFontSize().Value());
620 font.setScaleX(1.0);
621 double space = 0.0;
622 std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
623
624 SkPaint paint;
625 SkPaint strokePaint;
626 RosenSvgPainter::SetFillStyle(paint, svgTextInfo.fillState, svgTextInfo.opacity);
627 RosenSvgPainter::SetStrokeStyle(strokePaint, svgTextInfo.strokeState, svgTextInfo.opacity);
628
629 SkPath path;
630 SkParsePath::FromSVGString(pathDrawInfo.path.c_str(), &path);
631 SkPathMeasure pathMeasure(path, false);
632 SkScalar length = pathMeasure.getLength();
633
634 for (int i = 0; i < (int)data.size(); i++) {
635 wchar_t temp = data[i];
636 if (temp >= 0x4e00 && temp <= 0x9fa5) {
637 font.setTypeface(fontTypeChinese_);
638 } else {
639 font.setTypeface(fontTypeNormal_);
640 }
641 #ifdef WINDOWS_PLATFORM
642 auto width = font.measureText(&temp, 4, SkTextEncoding::kUTF16);
643 #else
644 auto width = font.measureText(&temp, sizeof(wchar_t), SkTextEncoding::kUTF16);
645 #endif
646 if (length < offset + width + space) {
647 break;
648 }
649 if (offset < 0) {
650 offset += (width + space);
651 continue;
652 }
653
654 SkPoint position;
655 SkVector tangent;
656 if (!pathMeasure.getPosTan(offset + width / 2.0, &position, &tangent)) {
657 break;
658 }
659 if (!pathMeasure.getPosTan(offset, &position, nullptr)) {
660 break;
661 }
662 SkRSXform rsxForm = SkRSXform::Make(tangent.fX, tangent.fY, position.fX, position.fY);
663 auto blob = SkTextBlob::MakeFromRSXform(&temp, sizeof(wchar_t), &rsxForm, font, SkTextEncoding::kUTF16);
664
665 canvas->save();
666 canvas->rotate(pathDrawInfo.rotate, position.fX, position.fY);
667 canvas->drawTextBlob(blob.get(), 0.0, 0.0, paint);
668 if (svgTextInfo.strokeState.HasStroke() && !NearZero(svgTextInfo.strokeState.GetLineWidth().Value())) {
669 canvas->drawTextBlob(blob.get(), 0.0, 0.0, strokePaint);
670 }
671 canvas->restore();
672 offset = offset + width + space;
673 }
674
675 return offset;
676 }
677 #else
UpdateTextPath(RSCanvas * canvas,const SvgTextInfo & svgTextInfo,const PathDrawInfo & pathDrawInfo)678 double RosenSvgPainter::UpdateTextPath(
679 RSCanvas* canvas, const SvgTextInfo& svgTextInfo, const PathDrawInfo& pathDrawInfo)
680 {
681 double offset = pathDrawInfo.offset;
682 if (!canvas) {
683 LOGE("Paint skCanvas is null");
684 return offset;
685 }
686
687 RSFont font;
688 font.SetSize(svgTextInfo.textStyle.GetFontSize().Value());
689 font.SetScaleX(1.0);
690 double space = 0.0;
691 std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
692
693 RSBrush brush;
694 RSPen strokePen;
695 RosenSvgPainter::SetFillStyle(brush, svgTextInfo.fillState, svgTextInfo.opacity);
696 RosenSvgPainter::SetStrokeStyle(strokePen, svgTextInfo.strokeState, svgTextInfo.opacity);
697
698 RSPath path;
699 path.BuildFromSVGString(pathDrawInfo.path);
700 RSScalar length = path.GetLength(false);
701
702 for (int i = 0; i < (int)data.size(); i++) {
703 wchar_t temp = data[i];
704 if (temp >= 0x4e00 && temp <= 0x9fa5) {
705 font.SetTypeface(fontTypeChinese_);
706 } else {
707 font.SetTypeface(fontTypeNormal_);
708 }
709 #ifdef WINDOWS_PLATFORM
710 auto width = font.MeasureText(&temp, 4, RSTextEncoding::UTF16);
711 #else
712 auto width = font.MeasureText(&temp, sizeof(wchar_t), RSTextEncoding::UTF16);
713 #endif
714 if (length < offset + width + space) {
715 break;
716 }
717 if (offset < 0) {
718 offset += (width + space);
719 continue;
720 }
721
722 RSPoint position;
723 RSPoint tangent;
724 if (!path.GetPositionAndTangent(offset + width / 2.0, position, tangent, false)) {
725 break;
726 }
727 RSPoint tempTangent;
728 if (!path.GetPositionAndTangent(offset, position, tempTangent, false)) {
729 break;
730 }
731 RSXform rsxForm = RSXform::Make(tangent.GetX(), tangent.GetY(), position.GetX(), position.GetY());
732 auto blob = RSTextBlob::MakeFromRSXform(&temp, sizeof(wchar_t), &rsxForm, font, RSTextEncoding::UTF16);
733
734 canvas->Save();
735 canvas->Rotate(pathDrawInfo.rotate, position.GetX(), position.GetY());
736 canvas->AttachBrush(brush);
737 canvas->DrawTextBlob(blob.get(), 0.0, 0.0);
738 canvas->DetachBrush();
739 if (svgTextInfo.strokeState.HasStroke() && !NearZero(svgTextInfo.strokeState.GetLineWidth().Value())) {
740 canvas->AttachPen(strokePen);
741 canvas->DrawTextBlob(blob.get(), 0.0, 0.0);
742 canvas->DetachPen();
743 }
744 canvas->Restore();
745 offset = offset + width + space;
746 }
747
748 return offset;
749 }
750 #endif
751
752 #ifndef USE_ROSEN_DRAWING
MeasureTextBounds(const SvgTextInfo & svgTextInfo,const TextDrawInfo & textDrawInfo,Rect & bounds)753 Offset RosenSvgPainter::MeasureTextBounds(
754 const SvgTextInfo& svgTextInfo, const TextDrawInfo& textDrawInfo, Rect& bounds)
755 {
756 Offset offset = textDrawInfo.offset;
757 SkFont font;
758
759 font.setSize(svgTextInfo.textStyle.GetFontSize().Value());
760 font.setScaleX(1.0);
761 double space = 0.0;
762 SkScalar x = SkDoubleToScalar(offset.GetX());
763 SkScalar y = SkDoubleToScalar(offset.GetY());
764 std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
765
766 for (int i = 0; i < (int)data.size(); i++) {
767 wchar_t temp = data[i];
768 if (temp >= 0x4e00 && temp <= 0x9fa5) {
769 // range of chinese
770 font.setTypeface(fontTypeChinese_);
771 } else {
772 font.setTypeface(fontTypeNormal_);
773 }
774 auto width = font.measureText(&temp, sizeof(temp), SkTextEncoding::kUTF16);
775 x = x + width + space;
776 }
777 bounds.SetWidth(fmax(x, bounds.Width()));
778 bounds.SetHeight(fmax(y, bounds.Height()));
779
780 return Offset(x, y);
781 }
782 #else
MeasureTextBounds(const SvgTextInfo & svgTextInfo,const TextDrawInfo & textDrawInfo,Rect & bounds)783 Offset RosenSvgPainter::MeasureTextBounds(
784 const SvgTextInfo& svgTextInfo, const TextDrawInfo& textDrawInfo, Rect& bounds)
785 {
786 Offset offset = textDrawInfo.offset;
787 RSFont font;
788
789 font.SetSize(svgTextInfo.textStyle.GetFontSize().Value());
790 font.SetScaleX(1.0);
791 double space = 0.0;
792 SkScalar x = SkDoubleToScalar(offset.GetX());
793 SkScalar y = SkDoubleToScalar(offset.GetY());
794 std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
795
796 for (int i = 0; i < (int)data.size(); i++) {
797 wchar_t temp = data[i];
798 if (temp >= 0x4e00 && temp <= 0x9fa5) {
799 // range of chinese
800 font.SetTypeface(fontTypeChinese_);
801 } else {
802 font.SetTypeface(fontTypeNormal_);
803 }
804 auto width = font.MeasureText(&temp, sizeof(temp), RSTextEncoding::UTF16);
805 x = x + width + space;
806 }
807 bounds.SetWidth(fmax(x, bounds.Width()));
808 bounds.SetHeight(fmax(y, bounds.Height()));
809
810 return Offset(x, y);
811 }
812 #endif
813
814 #ifndef USE_ROSEN_DRAWING
MeasureTextPathBounds(const SvgTextInfo & svgTextInfo,const PathDrawInfo & pathDrawInfo,Rect & bounds)815 double RosenSvgPainter::MeasureTextPathBounds(
816 const SvgTextInfo& svgTextInfo, const PathDrawInfo& pathDrawInfo, Rect& bounds)
817 {
818 double offset = pathDrawInfo.offset;
819
820 SkFont font;
821 font.setSize(svgTextInfo.textStyle.GetFontSize().Value());
822 font.setScaleX(1.0);
823 double space = 0.0;
824 std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
825
826 SkPath path;
827 SkParsePath::FromSVGString(pathDrawInfo.path.c_str(), &path);
828 SkPathMeasure pathMeasure(path, false);
829 SkScalar length = pathMeasure.getLength();
830
831 for (int i = 0; i < (int)data.size(); i++) {
832 wchar_t temp = data[i];
833 if (temp >= 0x4e00 && temp <= 0x9fa5) {
834 font.setTypeface(fontTypeChinese_);
835 } else {
836 font.setTypeface(fontTypeNormal_);
837 }
838 auto width = font.measureText(&temp, sizeof(temp), SkTextEncoding::kUTF16);
839 if (length < offset + width + space) {
840 break;
841 }
842 offset = offset + width + space;
843 }
844
845 auto& pathBounds = path.getBounds();
846 bounds.SetWidth(fmax(pathBounds.right(), bounds.Width()));
847 bounds.SetHeight(fmax(pathBounds.bottom(), bounds.Height()));
848 return offset;
849 }
850 #else
MeasureTextPathBounds(const SvgTextInfo & svgTextInfo,const PathDrawInfo & pathDrawInfo,Rect & bounds)851 double RosenSvgPainter::MeasureTextPathBounds(
852 const SvgTextInfo& svgTextInfo, const PathDrawInfo& pathDrawInfo, Rect& bounds)
853 {
854 double offset = pathDrawInfo.offset;
855
856 RSFont font;
857 font.SetSize(svgTextInfo.textStyle.GetFontSize().Value());
858 font.SetScaleX(1.0);
859 double space = 0.0;
860 std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
861
862 SkPath path;
863 SkParsePath::FromSVGString(pathDrawInfo.path.c_str(), &path);
864 SkPathMeasure pathMeasure(path, false);
865 SkScalar length = pathMeasure.getLength();
866
867 for (int i = 0; i < (int)data.size(); i++) {
868 wchar_t temp = data[i];
869 if (temp >= 0x4e00 && temp <= 0x9fa5) {
870 font.SetTypeface(fontTypeChinese_);
871 } else {
872 font.SetTypeface(fontTypeNormal_);
873 }
874 auto width = font.MeasureText(&temp, sizeof(temp), RSTextEncoding::UTF16);
875 if (length < offset + width + space) {
876 break;
877 }
878 offset = offset + width + space;
879 }
880
881 auto& pathBounds = path.getBounds();
882 bounds.SetWidth(fmax(pathBounds.right(), bounds.Width()));
883 bounds.SetHeight(fmax(pathBounds.bottom(), bounds.Height()));
884 return offset;
885 }
886 #endif
887
SkipSpace(const char str[])888 static const char* SkipSpace(const char str[])
889 {
890 if (!str) {
891 return nullptr;
892 }
893 while (isspace(*str)) {
894 str++;
895 }
896 return str;
897 }
898
SkipSep(const char str[])899 static const char* SkipSep(const char str[])
900 {
901 if (!str) {
902 return nullptr;
903 }
904 while (isspace(*str) || *str == ',') {
905 str++;
906 }
907 return str;
908 }
909
FindDoubleValue(const char str[],double & value)910 static const char* FindDoubleValue(const char str[], double& value)
911 {
912 str = SkipSpace(str);
913 if (!str) {
914 return nullptr;
915 }
916 char* stop = nullptr;
917 float v = std::strtod(str, &stop);
918 if (str == stop || errno == ERANGE) {
919 return nullptr;
920 }
921 value = v;
922 return stop;
923 }
924
925 #ifndef USE_ROSEN_DRAWING
StringToPoints(const char str[],std::vector<SkPoint> & points)926 void RosenSvgPainter::StringToPoints(const char str[], std::vector<SkPoint>& points)
927 #else
928 void RosenSvgPainter::StringToPoints(const char str[], std::vector<RSPoint>& points)
929 #endif
930 {
931 for (;;) {
932 double x = 0.0;
933 str = FindDoubleValue(str, x);
934 if (str == nullptr) {
935 break;
936 }
937 str = SkipSep(str);
938 double y = 0.0;
939 str = FindDoubleValue(str, y);
940 if (str == nullptr) {
941 break;
942 }
943 #ifndef USE_ROSEN_DRAWING
944 points.emplace_back(SkPoint::Make(x, y));
945 #else
946 points.emplace_back(RSPoint(x, y));
947 #endif
948 }
949 }
950
UpdateMotionMatrix(const std::shared_ptr<RSNode> & rsNode,const std::string & path,const std::string & rotate,double percent)951 void RosenSvgPainter::UpdateMotionMatrix(
952 const std::shared_ptr<RSNode>& rsNode, const std::string& path, const std::string& rotate, double percent)
953 {
954 if (path.empty() || rsNode == nullptr) {
955 return;
956 }
957 #ifndef USE_ROSEN_DRAWING
958 SkPath motion;
959 SkParsePath::FromSVGString(path.c_str(), &motion);
960 SkPathMeasure pathMeasure(motion, false);
961 SkPoint position;
962 SkVector tangent;
963 bool ret = pathMeasure.getPosTan(pathMeasure.getLength() * percent, &position, &tangent);
964 if (!ret) {
965 return;
966 }
967 float degrees = 0.0f;
968 if (rotate == ROTATE_TYPE_AUTO) {
969 degrees = SkRadiansToDegrees(std::atan2(tangent.y(), tangent.x()));
970 } else if (rotate == ROTATE_TYPE_REVERSE) {
971 degrees = SkRadiansToDegrees(std::atan2(tangent.y(), tangent.x())) + FLAT_ANGLE;
972 } else {
973 degrees = StringUtils::StringToDouble(rotate);
974 }
975 // reset quaternion
976 rsNode->SetRotation({ 0., 0., 0., 1. });
977 rsNode->SetRotation(degrees, 0., 0.);
978 auto frame = rsNode->GetStagingProperties().GetFrame();
979 rsNode->SetPivot(position.x() / frame.x_, position.y() / frame.y_);
980 #else
981 RSRecordingPath motion;
982 motion.BuildFromSVGString(path.c_str());
983 RSPoint position;
984 RSPoint tangent;
985 bool ret = motion.GetPositionAndTangent(motion.GetLength(false) * percent, position, tangent, false);
986 if (!ret) {
987 return;
988 }
989 float degrees = 0.0f;
990 if (rotate == ROTATE_TYPE_AUTO) {
991 degrees = Rosen::Drawing::ConvertRadiansToDegrees(std::atan2(tangent.GetY(), tangent.GetX()));
992 } else if (rotate == ROTATE_TYPE_REVERSE) {
993 degrees = Rosen::Drawing::ConvertRadiansToDegrees(std::atan2(tangent.GetY(), tangent.GetX())) + FLAT_ANGLE;
994 } else {
995 degrees = StringUtils::StringToDouble(rotate);
996 }
997 // reset quaternion
998 rsNode->SetRotation({ 0., 0., 0., 1. });
999 rsNode->SetRotation(degrees, 0., 0.);
1000 auto frame = rsNode->GetStagingProperties().GetFrame();
1001 rsNode->SetPivot(position.GetX() / frame.x_, position.GetY() / frame.y_);
1002 #endif
1003 }
1004
1005 #ifndef USE_ROSEN_DRAWING
ToSkMatrix(const Matrix4 & matrix4)1006 SkMatrix RosenSvgPainter::ToSkMatrix(const Matrix4& matrix4)
1007 {
1008 // Mappings from SkMatrix-index to input-index.
1009 static const int32_t K_SK_MATRIX_INDEX_TO_MATRIX4_INDEX[] = {
1010 0,
1011 4,
1012 12,
1013 1,
1014 5,
1015 13,
1016 3,
1017 7,
1018 15,
1019 };
1020
1021 SkMatrix skMatrix;
1022 for (std::size_t i = 0; i < ArraySize(K_SK_MATRIX_INDEX_TO_MATRIX4_INDEX); ++i) {
1023 int32_t matrixIndex = K_SK_MATRIX_INDEX_TO_MATRIX4_INDEX[i];
1024 if (matrixIndex < matrix4.Count())
1025 skMatrix[i] = matrix4[matrixIndex];
1026 else
1027 skMatrix[i] = 0.0;
1028 }
1029 return skMatrix;
1030 }
1031 #else
ToDrawingMatrix(const Matrix4 & matrix4)1032 RSMatrix RosenSvgPainter::ToDrawingMatrix(const Matrix4& matrix4)
1033 {
1034 // Mappings from DrawingMatrix-index to input-index.
1035 static const int32_t K_DRAWING_MATRIX_INDEX_TO_MATRIX4_INDEX[] = {
1036 0,
1037 4,
1038 12,
1039 1,
1040 5,
1041 13,
1042 3,
1043 7,
1044 15,
1045 };
1046
1047 RSMatrix matrix;
1048 for (std::size_t i = 0; i < ArraySize(K_DRAWING_MATRIX_INDEX_TO_MATRIX4_INDEX); ++i) {
1049 int32_t matrixIndex = K_DRAWING_MATRIX_INDEX_TO_MATRIX4_INDEX[i];
1050 if (matrixIndex < matrix4.Count())
1051 matrix.Set(static_cast<RSMatrix::Index>(i), matrix4[matrixIndex]);
1052 else
1053 matrix.Set(static_cast<RSMatrix::Index>(i), 0.0);
1054 }
1055 return matrix;
1056 }
1057 #endif
1058
1059 } // namespace OHOS::Ace
1060