• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components/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 #if !defined(PREVIEW) && !defined(CROSS_PLATFORM)
32 const char FONT_TYPE_HWCHINESE[] = "/system/fonts/HwChinese-Medium.ttf";
33 const char FONT_TYPE_DROIDSANS[] = "/system/fonts/DroidSans.ttf";
34 std::shared_ptr<RSTypeface> RosenSvgPainter::fontTypeChinese_ = RSTypeface::MakeFromFile(FONT_TYPE_HWCHINESE);
35 std::shared_ptr<RSTypeface> RosenSvgPainter::fontTypeNormal_ = RSTypeface::MakeFromFile(FONT_TYPE_DROIDSANS);
36 #else
37 std::shared_ptr<RSTypeface> RosenSvgPainter::fontTypeChinese_;
38 std::shared_ptr<RSTypeface> RosenSvgPainter::fontTypeNormal_;
39 #endif
40 
SetMask(RSCanvas * canvas)41 void RosenSvgPainter::SetMask(RSCanvas* canvas)
42 {
43     auto outerFilter = RSRecordingColorFilter::CreateLumaColorFilter();
44     auto innerFilter = RSRecordingColorFilter::CreateSrgbGammaToLinear();
45     auto colorFilter = RSRecordingColorFilter::CreateComposeColorFilter(*outerFilter, *innerFilter);
46     RSFilter filter;
47     filter.SetColorFilter(colorFilter);
48     RSBrush mask_filter;
49     mask_filter.SetFilter(filter);
50     RSSaveLayerOps saveLayerRec(nullptr, &mask_filter);
51     canvas->SaveLayer(saveLayerRec);
52 }
53 
SetFillStyle(RSBrush & brush,const FillState & fillState,uint8_t opacity,bool antiAlias)54 void RosenSvgPainter::SetFillStyle(RSBrush& brush,
55     const FillState& fillState, uint8_t opacity, bool antiAlias)
56 {
57     double curOpacity = fillState.GetOpacity().GetValue() * opacity * (1.0f / UINT8_MAX);
58     brush.SetAntiAlias(antiAlias);
59     if (fillState.GetGradient()) {
60         SetGradientStyle(brush, fillState, curOpacity);
61     } else {
62         brush.SetColor(fillState.GetColor().BlendOpacity(curOpacity).GetValue());
63     }
64 }
65 
SetFillStyle(RSCanvas * canvas,const RSPath & path,const FillState & fillState,uint8_t opacity,bool antiAlias)66 void RosenSvgPainter::SetFillStyle(RSCanvas* canvas, const RSPath& path,
67     const FillState& fillState, uint8_t opacity, bool antiAlias)
68 {
69     if (fillState.GetColor() == Color::TRANSPARENT && !fillState.GetGradient()) {
70         return;
71     }
72     RSBrush brush;
73     SetFillStyle(brush, fillState, opacity, antiAlias);
74     canvas->AttachBrush(brush);
75     canvas->DrawPath(path);
76     canvas->DetachBrush();
77 }
78 
SetGradientStyle(RSBrush & brush,const FillState & fillState,double opacity)79 void RosenSvgPainter::SetGradientStyle(RSBrush& brush, const FillState& fillState, double opacity)
80 {
81     auto gradient = fillState.GetGradient();
82     if (!gradient) {
83         return;
84     }
85     auto gradientColors = gradient->GetColors();
86     if (gradientColors.empty()) {
87         return;
88     }
89     std::vector<RSScalar> pos;
90     std::vector<RSColorQuad> colors;
91     for (const auto& gradientColor : gradientColors) {
92         pos.push_back(gradientColor.GetDimension().Value());
93         colors.push_back(
94             gradientColor.GetColor().BlendOpacity(gradientColor.GetOpacity()).BlendOpacity(opacity).GetValue());
95     }
96     if (gradient->GetType() == GradientType::LINEAR) {
97         auto info = gradient->GetLinearGradientInfo();
98         RSPoint startPt = RSPoint(info.x1, info.y1);
99         RSPoint endPt = RSPoint(info.x2, info.y2);
100         brush.SetShaderEffect(RSRecordingShaderEffect::CreateLinearGradient(
101             startPt, endPt, colors, pos, static_cast<RSTileMode>(gradient->GetSpreadMethod())));
102     }
103     if (gradient->GetType() == GradientType::RADIAL) {
104         auto info = gradient->GetRadialGradientInfo();
105         auto center = RSPoint(info.cx, info.cy);
106         auto focal = RSPoint(info.fx, info.fx);
107         RSMatrix matrix;
108         return center == focal ? brush.SetShaderEffect(RSRecordingShaderEffect::CreateRadialGradient(center,
109             info.r, colors, pos, static_cast<RSTileMode>(gradient->GetSpreadMethod())))
110             : brush.SetShaderEffect(RSRecordingShaderEffect::CreateTwoPointConical(focal, 0, center,
111             info.r, colors, pos, static_cast<RSTileMode>(gradient->GetSpreadMethod()), &matrix));
112     }
113 }
114 
SetFillStyle(RSCanvas * canvas,const RSPath & path,const FillState & fillState,RenderInfo & renderInfo)115 void RosenSvgPainter::SetFillStyle(RSCanvas* canvas,
116     const RSPath& path, const FillState& fillState, RenderInfo& renderInfo)
117 {
118     const auto& fillHref = fillState.GetHref();
119     if (fillHref.empty() || fillState.GetGradient() || !renderInfo.node) {
120         return SetFillStyle(canvas, path, fillState, renderInfo.opacity, renderInfo.antiAlias);
121     }
122 
123     RSBrush brush;
124     brush.Reset();
125     auto pattern = AceType::DynamicCast<RosenRenderSvgPattern>(renderInfo.node->GetPatternFromRoot(fillHref));
126     if (!pattern) {
127         return;
128     }
129     if (!pattern->OnAsPaint(renderInfo.offset, renderInfo.node->GetPaintBounds(renderInfo.offset), nullptr, &brush)) {
130         return;
131     }
132     brush.SetAlphaF(fillState.GetOpacity().GetValue() * renderInfo.opacity * (1.0f / UINT8_MAX));
133     brush.SetAntiAlias(renderInfo.antiAlias);
134     canvas->AttachBrush(brush);
135     canvas->DrawPath(path);
136     canvas->DetachBrush();
137 }
138 
SetStrokeStyle(RSPen & pen,const StrokeState & strokeState,uint8_t opacity,bool antiAlias)139 void RosenSvgPainter::SetStrokeStyle(RSPen& pen,
140     const StrokeState& strokeState, uint8_t opacity, bool antiAlias)
141 {
142     double curOpacity = strokeState.GetOpacity().GetValue() * opacity * (1.0f / UINT8_MAX);
143     pen.SetColor(strokeState.GetColor().BlendOpacity(curOpacity).GetValue());
144     if (strokeState.GetLineCap() == LineCapStyle::ROUND) {
145         pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
146     } else if (strokeState.GetLineCap() == LineCapStyle::SQUARE) {
147         pen.SetCapStyle(RSPen::CapStyle::SQUARE_CAP);
148     } else {
149         pen.SetCapStyle(RSPen::CapStyle::FLAT_CAP);
150     }
151     if (strokeState.GetLineJoin() == LineJoinStyle::ROUND) {
152         pen.SetJoinStyle(RSPen::JoinStyle::ROUND_JOIN);
153     } else if (strokeState.GetLineJoin() == LineJoinStyle::BEVEL) {
154         pen.SetJoinStyle(RSPen::JoinStyle::BEVEL_JOIN);
155     } else {
156         pen.SetJoinStyle(RSPen::JoinStyle::MITER_JOIN);
157     }
158     pen.SetWidth(static_cast<RSScalar>(strokeState.GetLineWidth().Value()));
159     pen.SetMiterLimit(static_cast<RSScalar>(strokeState.GetMiterLimit()));
160     pen.SetAntiAlias(antiAlias);
161     UpdateLineDash(pen, strokeState);
162 }
163 
SetStrokeStyle(RSCanvas * canvas,const RSPath & path,const StrokeState & strokeState,uint8_t opacity,bool antiAlias)164 void RosenSvgPainter::SetStrokeStyle(RSCanvas* canvas,
165     const RSPath& path, const StrokeState& strokeState, uint8_t opacity, bool antiAlias)
166 {
167     if (strokeState.GetColor() == Color::TRANSPARENT) {
168         return;
169     }
170     if (GreatNotEqual(strokeState.GetLineWidth().Value(), 0.0)) {
171         RSPen pen;
172         SetStrokeStyle(pen, strokeState, opacity, antiAlias);
173         canvas->AttachPen(pen);
174         canvas->DrawPath(path);
175         canvas->DetachPen();
176     }
177 }
178 
SetStrokeStyle(RSCanvas * canvas,const RSPath & path,const StrokeState & strokeState,RenderInfo & renderInfo)179 void RosenSvgPainter::SetStrokeStyle(RSCanvas* canvas,
180     const RSPath& path, const StrokeState& strokeState, RenderInfo& renderInfo)
181 {
182     const auto& strokeHref = strokeState.GetHref();
183     if (strokeHref.empty() || !renderInfo.node) {
184         return SetStrokeStyle(canvas, path, strokeState, renderInfo.opacity, renderInfo.antiAlias);
185     }
186 
187     if (GreatNotEqual(strokeState.GetLineWidth().Value(), 0.0)) {
188         RSPen pen;
189         SetStrokeStyle(pen, strokeState, renderInfo.opacity, renderInfo.antiAlias);
190         auto pattern = AceType::DynamicCast<RosenRenderSvgPattern>(renderInfo.node->GetPatternFromRoot(strokeHref));
191         if (!pattern) {
192             return;
193         }
194         if (!pattern->OnAsPaint(renderInfo.offset, renderInfo.node->GetPaintBounds(renderInfo.offset), &pen, nullptr)) {
195             return;
196         }
197         canvas->AttachPen(pen);
198         canvas->DrawPath(path);
199         canvas->DetachPen();
200     }
201 }
202 
UpdateLineDash(RSPen & pen,const StrokeState & strokeState)203 void RosenSvgPainter::UpdateLineDash(RSPen& pen, const StrokeState& strokeState)
204 {
205     if (!strokeState.GetLineDash().lineDash.empty()) {
206         auto lineDashState = strokeState.GetLineDash().lineDash;
207         RSScalar intervals[lineDashState.size()];
208         for (size_t i = 0; i < lineDashState.size(); ++i) {
209             intervals[i] = static_cast<RSScalar>(lineDashState[i]);
210         }
211         RSScalar phase = static_cast<RSScalar>(strokeState.GetLineDash().dashOffset);
212         pen.SetPathEffect(RSRecordingPathEffect::CreateDashPathEffect(intervals, lineDashState.size(), phase));
213     }
214 }
215 
CheckFontType()216 void RosenSvgPainter::CheckFontType()
217 {
218     if (!fontTypeChinese_) {
219         LOGW("can't load HwChinese-Medium.ttf");
220     }
221     if (!fontTypeNormal_) {
222         LOGW("can't load DroidSans.ttf");
223     }
224 }
225 
GetPathLength(const std::string & path)226 double RosenSvgPainter::GetPathLength(const std::string& path)
227 {
228     RSRecordingPath drawPath;
229     drawPath.BuildFromSVGString(path.c_str());
230     auto length = drawPath.GetLength(false);
231     return length;
232 }
233 
GetPathOffset(const std::string & path,double current)234 Offset RosenSvgPainter::GetPathOffset(const std::string& path, double current)
235 {
236     RSRecordingPath drawPath;
237     drawPath.BuildFromSVGString(path.c_str());
238     RSPoint position;
239     RSPoint tangent;
240     if (!drawPath.GetPositionAndTangent(current, position, tangent, false)) {
241         return Offset(0.0, 0.0);
242     }
243     return Offset(position.GetX(), position.GetY());
244 }
245 
GetMotionPathPosition(const std::string & path,double percent,MotionPathPosition & result)246 bool RosenSvgPainter::GetMotionPathPosition(const std::string& path, double percent, MotionPathPosition& result)
247 {
248     if (path.empty()) {
249         return false;
250     }
251     RSRecordingPath motion;
252     motion.BuildFromSVGString(path.c_str());
253     RSPoint position;
254     RSPoint tangent;
255     bool ret = motion.GetPositionAndTangent(motion.GetLength(false) * percent, position, tangent, false);
256     if (!ret) {
257         return false;
258     }
259     result.rotate = Rosen::Drawing::ConvertRadiansToDegrees(std::atan2(tangent.GetY(), tangent.GetX()));
260     result.offset.SetX(position.GetX());
261     result.offset.SetY(position.GetY());
262     return true;
263 }
264 
UpdateText(RSCanvas * canvas,const SvgTextInfo & svgTextInfo,const TextDrawInfo & textDrawInfo)265 Offset RosenSvgPainter::UpdateText(RSCanvas* canvas, const SvgTextInfo& svgTextInfo, const TextDrawInfo& textDrawInfo)
266 {
267     Offset offset = textDrawInfo.offset;
268     if (!canvas) {
269         LOGE("Paint skCanvas is null");
270         return offset;
271     }
272 
273     RSFont font;
274     font.SetSize(svgTextInfo.textStyle.GetFontSize().Value());
275     font.SetScaleX(1.0);
276 
277     double space = 0.0;
278     SkScalar x = SkDoubleToScalar(offset.GetX());
279     SkScalar y = SkDoubleToScalar(offset.GetY());
280     std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
281 
282     RSBrush brush;
283     RSPen strokePen;
284     RosenSvgPainter::SetFillStyle(brush, svgTextInfo.fillState, svgTextInfo.opacity);
285     RosenSvgPainter::SetStrokeStyle(strokePen, svgTextInfo.strokeState, svgTextInfo.opacity);
286 
287     for (int i = 0; i < (int)data.size(); i++) {
288         wchar_t temp = data[i];
289         if (temp >= 0x4e00 && temp <= 0x9fa5) {
290             // range of chinese
291             font.SetTypeface(fontTypeChinese_);
292         } else {
293             font.SetTypeface(fontTypeNormal_);
294         }
295         auto blob = RSTextBlob::MakeFromText(&temp, sizeof(temp), font, RSTextEncoding::UTF16);
296 #ifdef WINDOWS_PLATFORM
297         auto width = font.MeasureText(&temp, 4, RSTextEncoding::UTF16);
298 #else
299         auto width = font.MeasureText(&temp, sizeof(temp), RSTextEncoding::UTF16);
300 #endif
301 
302         canvas->Save();
303         canvas->Rotate(textDrawInfo.rotate, x, y);
304         canvas->AttachBrush(brush);
305         canvas->DrawTextBlob(blob.get(), x, y);
306         canvas->DetachBrush();
307         if (svgTextInfo.strokeState.HasStroke() && !NearZero(svgTextInfo.strokeState.GetLineWidth().Value())) {
308             canvas->AttachPen(strokePen);
309             canvas->DrawTextBlob(blob.get(), x, y);
310             canvas->DetachPen();
311         }
312         canvas->Restore();
313         x = x + width + space;
314     }
315 
316     return Offset(x, y);
317 }
318 
UpdateTextPath(RSCanvas * canvas,const SvgTextInfo & svgTextInfo,const PathDrawInfo & pathDrawInfo)319 double RosenSvgPainter::UpdateTextPath(
320     RSCanvas* canvas, const SvgTextInfo& svgTextInfo, const PathDrawInfo& pathDrawInfo)
321 {
322     double offset = pathDrawInfo.offset;
323     if (!canvas) {
324         LOGE("Paint skCanvas is null");
325         return offset;
326     }
327 
328     RSFont font;
329     font.SetSize(svgTextInfo.textStyle.GetFontSize().Value());
330     font.SetScaleX(1.0);
331     double space = 0.0;
332     std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
333 
334     RSBrush brush;
335     RSPen strokePen;
336     RosenSvgPainter::SetFillStyle(brush, svgTextInfo.fillState, svgTextInfo.opacity);
337     RosenSvgPainter::SetStrokeStyle(strokePen, svgTextInfo.strokeState, svgTextInfo.opacity);
338 
339     RSPath path;
340     path.BuildFromSVGString(pathDrawInfo.path);
341     RSScalar length = path.GetLength(false);
342 
343     for (int i = 0; i < (int)data.size(); i++) {
344         wchar_t temp = data[i];
345         if (temp >= 0x4e00 && temp <= 0x9fa5) {
346             font.SetTypeface(fontTypeChinese_);
347         } else {
348             font.SetTypeface(fontTypeNormal_);
349         }
350 #ifdef WINDOWS_PLATFORM
351         auto width = font.MeasureText(&temp, 4, RSTextEncoding::UTF16);
352 #else
353         auto width = font.MeasureText(&temp, sizeof(wchar_t), RSTextEncoding::UTF16);
354 #endif
355         if (length < offset + width + space) {
356             break;
357         }
358         if (offset < 0) {
359             offset += (width + space);
360             continue;
361         }
362 
363         RSPoint position;
364         RSPoint tangent;
365         if (!path.GetPositionAndTangent(offset + width / 2.0, position, tangent, false)) {
366             break;
367         }
368         RSPoint tempTangent;
369         if (!path.GetPositionAndTangent(offset, position, tempTangent, false)) {
370             break;
371         }
372         RSXform rsxForm = RSXform::Make(tangent.GetX(), tangent.GetY(), position.GetX(), position.GetY());
373         auto blob = RSTextBlob::MakeFromRSXform(&temp, sizeof(wchar_t), &rsxForm, font, RSTextEncoding::UTF16);
374 
375         canvas->Save();
376         canvas->Rotate(pathDrawInfo.rotate, position.GetX(), position.GetY());
377         canvas->AttachBrush(brush);
378         canvas->DrawTextBlob(blob.get(), 0.0, 0.0);
379         canvas->DetachBrush();
380         if (svgTextInfo.strokeState.HasStroke() && !NearZero(svgTextInfo.strokeState.GetLineWidth().Value())) {
381             canvas->AttachPen(strokePen);
382             canvas->DrawTextBlob(blob.get(), 0.0, 0.0);
383             canvas->DetachPen();
384         }
385         canvas->Restore();
386         offset = offset + width + space;
387     }
388 
389     return offset;
390 }
391 
MeasureTextBounds(const SvgTextInfo & svgTextInfo,const TextDrawInfo & textDrawInfo,Rect & bounds)392 Offset RosenSvgPainter::MeasureTextBounds(
393     const SvgTextInfo& svgTextInfo, const TextDrawInfo& textDrawInfo, Rect& bounds)
394 {
395     Offset offset = textDrawInfo.offset;
396     RSFont font;
397 
398     font.SetSize(svgTextInfo.textStyle.GetFontSize().Value());
399     font.SetScaleX(1.0);
400     double space = 0.0;
401     SkScalar x = SkDoubleToScalar(offset.GetX());
402     SkScalar y = SkDoubleToScalar(offset.GetY());
403     std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
404 
405     for (int i = 0; i < (int)data.size(); i++) {
406         wchar_t temp = data[i];
407         if (temp >= 0x4e00 && temp <= 0x9fa5) {
408             // range of chinese
409             font.SetTypeface(fontTypeChinese_);
410         } else {
411             font.SetTypeface(fontTypeNormal_);
412         }
413         auto width = font.MeasureText(&temp, sizeof(temp), RSTextEncoding::UTF16);
414         x = x + width + space;
415     }
416     bounds.SetWidth(fmax(x, bounds.Width()));
417     bounds.SetHeight(fmax(y, bounds.Height()));
418 
419     return Offset(x, y);
420 }
421 
MeasureTextPathBounds(const SvgTextInfo & svgTextInfo,const PathDrawInfo & pathDrawInfo,Rect & bounds)422 double RosenSvgPainter::MeasureTextPathBounds(
423     const SvgTextInfo& svgTextInfo, const PathDrawInfo& pathDrawInfo, Rect& bounds)
424 {
425     double offset = pathDrawInfo.offset;
426 
427     RSFont font;
428     font.SetSize(svgTextInfo.textStyle.GetFontSize().Value());
429     font.SetScaleX(1.0);
430     double space = 0.0;
431     std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
432 
433     SkPath path;
434     SkParsePath::FromSVGString(pathDrawInfo.path.c_str(), &path);
435     SkPathMeasure pathMeasure(path, false);
436     SkScalar length = pathMeasure.getLength();
437 
438     for (int i = 0; i < (int)data.size(); i++) {
439         wchar_t temp = data[i];
440         if (temp >= 0x4e00 && temp <= 0x9fa5) {
441             font.SetTypeface(fontTypeChinese_);
442         } else {
443             font.SetTypeface(fontTypeNormal_);
444         }
445         auto width = font.MeasureText(&temp, sizeof(temp), RSTextEncoding::UTF16);
446         if (length < offset + width + space) {
447             break;
448         }
449         offset = offset + width + space;
450     }
451 
452     auto& pathBounds = path.getBounds();
453     bounds.SetWidth(fmax(pathBounds.right(), bounds.Width()));
454     bounds.SetHeight(fmax(pathBounds.bottom(), bounds.Height()));
455     return offset;
456 }
457 
SkipSpace(const char str[])458 static const char* SkipSpace(const char str[])
459 {
460     if (!str) {
461         return nullptr;
462     }
463     while (isspace(*str)) {
464         str++;
465     }
466     return str;
467 }
468 
SkipSep(const char str[])469 static const char* SkipSep(const char str[])
470 {
471     if (!str) {
472         return nullptr;
473     }
474     while (isspace(*str) || *str == ',') {
475         str++;
476     }
477     return str;
478 }
479 
FindDoubleValue(const char str[],double & value)480 static const char* FindDoubleValue(const char str[], double& value)
481 {
482     str = SkipSpace(str);
483     if (!str) {
484         return nullptr;
485     }
486     char* stop = nullptr;
487     float v = std::strtod(str, &stop);
488     if (str == stop || errno == ERANGE) {
489         return nullptr;
490     }
491     value = v;
492     return stop;
493 }
494 
StringToPoints(const char str[],std::vector<RSPoint> & points)495 void RosenSvgPainter::StringToPoints(const char str[], std::vector<RSPoint>& points)
496 {
497     for (;;) {
498         double x = 0.0;
499         str = FindDoubleValue(str, x);
500         if (str == nullptr) {
501             break;
502         }
503         str = SkipSep(str);
504         double y = 0.0;
505         str = FindDoubleValue(str, y);
506         if (str == nullptr) {
507             break;
508         }
509         points.emplace_back(RSPoint(x, y));
510     }
511 }
512 
UpdateMotionMatrix(const std::shared_ptr<RSNode> & rsNode,const std::string & path,const std::string & rotate,double percent)513 void RosenSvgPainter::UpdateMotionMatrix(
514     const std::shared_ptr<RSNode>& rsNode, const std::string& path, const std::string& rotate, double percent)
515 {
516     if (path.empty() || rsNode == nullptr) {
517         return;
518     }
519     RSRecordingPath motion;
520     motion.BuildFromSVGString(path.c_str());
521     RSPoint position;
522     RSPoint tangent;
523     bool ret = motion.GetPositionAndTangent(motion.GetLength(false) * percent, position, tangent, false);
524     if (!ret) {
525         return;
526     }
527     float degrees = 0.0f;
528     if (rotate == ROTATE_TYPE_AUTO) {
529         degrees = Rosen::Drawing::ConvertRadiansToDegrees(std::atan2(tangent.GetY(), tangent.GetX()));
530     } else if (rotate == ROTATE_TYPE_REVERSE) {
531         degrees = Rosen::Drawing::ConvertRadiansToDegrees(std::atan2(tangent.GetY(), tangent.GetX())) + FLAT_ANGLE;
532     } else {
533         degrees = StringUtils::StringToDouble(rotate);
534     }
535     // reset quaternion
536     rsNode->SetRotation({ 0., 0., 0., 1. });
537     rsNode->SetRotation(degrees, 0., 0.);
538     auto frame = rsNode->GetStagingProperties().GetFrame();
539     rsNode->SetPivot(position.GetX() / frame.x_, position.GetY() / frame.y_);
540 }
541 
ToDrawingMatrix(const Matrix4 & matrix4)542 RSMatrix RosenSvgPainter::ToDrawingMatrix(const Matrix4& matrix4)
543 {
544     // Mappings from DrawingMatrix-index to input-index.
545     static const int32_t K_DRAWING_MATRIX_INDEX_TO_MATRIX4_INDEX[] = {
546         0,
547         4,
548         12,
549         1,
550         5,
551         13,
552         3,
553         7,
554         15,
555     };
556 
557     RSMatrix matrix;
558     for (std::size_t i = 0; i < ArraySize(K_DRAWING_MATRIX_INDEX_TO_MATRIX4_INDEX); ++i) {
559         int32_t matrixIndex = K_DRAWING_MATRIX_INDEX_TO_MATRIX4_INDEX[i];
560         if (matrixIndex < matrix4.Count())
561             matrix.Set(static_cast<RSMatrix::Index>(i), matrix4[matrixIndex]);
562         else
563             matrix.Set(static_cast<RSMatrix::Index>(i), 0.0);
564     }
565     return matrix;
566 }
567 
568 } // namespace OHOS::Ace
569