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