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