1 /*
2 * Copyright (c) 2021-2022 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/flutter_svg_painter.h"
17
18 #include "include/core/SkColor.h"
19 #include "include/core/SkPathMeasure.h"
20 #include "include/core/SkRSXform.h"
21 #include "include/core/SkTextBlob.h"
22 #include "include/effects/SkDashPathEffect.h"
23 #include "include/effects/SkLumaColorFilter.h"
24 #include "include/utils/SkParsePath.h"
25 #include "include/effects/SkGradientShader.h"
26
27 #include "frameworks/core/components/svg/flutter_render_svg_pattern.h"
28 #include "frameworks/core/components/transform/flutter_render_transform.h"
29
30 namespace OHOS::Ace {
31
32 namespace {
33
34 constexpr int32_t COL_INDEX = 2;
35 constexpr int32_t ROW_INDEX = 3;
36 constexpr float ROTATE_VALUE = 0.0005f;
37 constexpr float FLAT_ANGLE = 180.0f;
38 const char ROTATE_TYPE_AUTO[] = "auto";
39 const char ROTATE_TYPE_REVERSE[] = "auto-reverse";
40
41 } // namespace
42
43 #if !defined(PREVIEW)
44 const char FONT_TYPE_HWCHINESE[] = "/system/fonts/DroidSansChinese.ttf";
45 const char FONT_TYPE_DROIDSANS[] = "/system/fonts/DroidSans.ttf";
46 sk_sp<SkTypeface> FlutterSvgPainter::fontTypeChinese_ = SkTypeface::MakeFromFile(FONT_TYPE_HWCHINESE);
47 sk_sp<SkTypeface> FlutterSvgPainter::fontTypeNormal_ = SkTypeface::MakeFromFile(FONT_TYPE_DROIDSANS);
48 #else
49 sk_sp<SkTypeface> FlutterSvgPainter::fontTypeChinese_;
50 sk_sp<SkTypeface> FlutterSvgPainter::fontTypeNormal_;
51 #endif
52
SetMask(SkCanvas * canvas)53 void FlutterSvgPainter::SetMask(SkCanvas* canvas)
54 {
55 SkPaint mask_filter;
56 #ifdef USE_SYSTEM_SKIA
57 auto outerFilter = SkLumaColorFilter::Make();
58 auto innerFilter = SkColorFilter::MakeSRGBToLinearGamma();
59 auto filter = SkColorFilter::MakeComposeFilter(outerFilter, std::move(innerFilter));
60 mask_filter.setColorFilter(filter);
61 #else
62 auto outerFilter = SkLumaColorFilter::Make();
63 auto innerFilter = SkColorFilters::SRGBToLinearGamma();
64 auto filter = SkColorFilters::Compose(outerFilter, std::move(innerFilter));
65 mask_filter.setColorFilter(filter);
66 #endif
67 canvas->saveLayer(nullptr, &mask_filter);
68 }
69
SetFillStyle(SkPaint & skPaint,const FillState & fillState,uint8_t opacity,bool antiAlias)70 void FlutterSvgPainter::SetFillStyle(SkPaint& skPaint, const FillState& fillState, uint8_t opacity, bool antiAlias)
71 {
72 double curOpacity = fillState.GetOpacity().GetValue() * opacity * (1.0f / UINT8_MAX);
73 skPaint.setStyle(SkPaint::Style::kFill_Style);
74 skPaint.setAntiAlias(antiAlias);
75 if (fillState.GetGradient()) {
76 SetGradientStyle(skPaint, fillState, curOpacity);
77 } else {
78 skPaint.setColor(fillState.GetColor().BlendOpacity(curOpacity).GetValue());
79 }
80 }
81
SetFillStyle(SkCanvas * skCanvas,const SkPath & skPath,const FillState & fillState,uint8_t opacity,bool antiAlias)82 void FlutterSvgPainter::SetFillStyle(
83 SkCanvas* skCanvas, const SkPath& skPath, const FillState& fillState, uint8_t opacity, bool antiAlias)
84 {
85 if (fillState.GetColor() == Color::TRANSPARENT && !fillState.GetGradient()) {
86 return;
87 }
88 SkPaint paint;
89 SetFillStyle(paint, fillState, opacity, antiAlias);
90 skCanvas->drawPath(skPath, paint);
91 }
92
SetGradientStyle(SkPaint & skPaint,const FillState & fillState,double opacity)93 void FlutterSvgPainter::SetGradientStyle(SkPaint& skPaint, const FillState& fillState, double opacity)
94 {
95 auto gradient = fillState.GetGradient();
96 if (!gradient) {
97 return;
98 }
99 auto gradientColors = gradient->GetColors();
100 if (gradientColors.empty()) {
101 return;
102 }
103 std::vector<SkScalar> pos;
104 std::vector<SkColor> colors;
105 for (const auto& gradientColor : gradientColors) {
106 pos.push_back(gradientColor.GetDimension().Value());
107 colors.push_back(
108 gradientColor.GetColor().BlendOpacity(gradientColor.GetOpacity()).BlendOpacity(opacity).GetValue());
109 }
110 if (gradient->GetType() == GradientType::LINEAR) {
111 auto info = gradient->GetLinearGradientInfo();
112 SkPoint pts[2] = { SkPoint::Make(info.x1, info.y1), SkPoint::Make(info.x2, info.y2) };
113 #ifdef USE_SYSTEM_SKIA
114 skPaint.setShader(SkGradientShader::MakeLinear(pts, &colors[0], &pos[0], gradientColors.size(),
115 static_cast<SkShader::TileMode>(gradient->GetSpreadMethod()), 0, nullptr));
116 #else
117 skPaint.setShader(SkGradientShader::MakeLinear(pts, &colors[0], &pos[0], gradientColors.size(),
118 static_cast<SkTileMode>(gradient->GetSpreadMethod()), 0, nullptr));
119 #endif
120 }
121 if (gradient->GetType() == GradientType::RADIAL) {
122 auto info = gradient->GetRadialGradientInfo();
123 auto center = SkPoint::Make(info.cx, info.cy);
124 auto focal = SkPoint::Make(info.fx, info.fx);
125 #ifdef USE_SYSTEM_SKIA
126 return center == focal ? skPaint.setShader(SkGradientShader::MakeRadial(center, info.r, &colors[0], &pos[0],
127 gradientColors.size(),
128 static_cast<SkShader::TileMode>(gradient->GetSpreadMethod()), 0, nullptr))
129 : skPaint.setShader(SkGradientShader::MakeTwoPointConical(focal, 0, center, info.r,
130 &colors[0], &pos[0], gradientColors.size(),
131 static_cast<SkShader::TileMode>(gradient->GetSpreadMethod()), 0, nullptr));
132 #else
133 return center == focal
134 ? skPaint.setShader(SkGradientShader::MakeRadial(center, info.r, &colors[0], &pos[0],
135 gradientColors.size(), static_cast<SkTileMode>(gradient->GetSpreadMethod()), 0, nullptr))
136 : skPaint.setShader(
137 SkGradientShader::MakeTwoPointConical(focal, 0, center, info.r, &colors[0], &pos[0],
138 gradientColors.size(), static_cast<SkTileMode>(gradient->GetSpreadMethod()), 0, nullptr));
139 #endif
140 }
141 }
142
SetFillStyle(SkCanvas * canvas,const SkPath & skPath,const FillState & fillState,RenderInfo & renderInfo)143 void FlutterSvgPainter::SetFillStyle(
144 SkCanvas* canvas, const SkPath& skPath, const FillState& fillState, RenderInfo& renderInfo)
145 {
146 const auto& fillHref = fillState.GetHref();
147 if (fillHref.empty() || fillState.GetGradient() || !renderInfo.node) {
148 return SetFillStyle(canvas, skPath, fillState, renderInfo.opacity, renderInfo.antiAlias);
149 }
150
151 SkPaint skPaint;
152 skPaint.reset();
153 auto pattern = AceType::DynamicCast<FlutterRenderSvgPattern>(renderInfo.node->GetPatternFromRoot(fillHref));
154 if (!pattern) {
155 return;
156 }
157 if (!pattern->OnAsPaint(renderInfo.offset, renderInfo.node->GetPaintBounds(renderInfo.offset), skPaint)) {
158 return;
159 }
160 skPaint.setAlphaf(fillState.GetOpacity().GetValue() * renderInfo.opacity * (1.0f / UINT8_MAX));
161 skPaint.setAntiAlias(renderInfo.antiAlias);
162 canvas->drawPath(skPath, skPaint);
163 }
164
SetStrokeStyle(SkPaint & skPaint,const StrokeState & strokeState,uint8_t opacity,bool antiAlias)165 void FlutterSvgPainter::SetStrokeStyle(SkPaint& skPaint, const StrokeState& strokeState, uint8_t opacity,
166 bool antiAlias)
167 {
168 skPaint.setStyle(SkPaint::Style::kStroke_Style);
169 double curOpacity = strokeState.GetOpacity().GetValue() * opacity * (1.0f / UINT8_MAX);
170 skPaint.setColor(strokeState.GetColor().BlendOpacity(curOpacity).GetValue());
171 if (strokeState.GetLineCap() == LineCapStyle::ROUND) {
172 skPaint.setStrokeCap(SkPaint::Cap::kRound_Cap);
173 } else if (strokeState.GetLineCap() == LineCapStyle::SQUARE) {
174 skPaint.setStrokeCap(SkPaint::Cap::kSquare_Cap);
175 } else {
176 skPaint.setStrokeCap(SkPaint::Cap::kButt_Cap);
177 }
178 if (strokeState.GetLineJoin() == LineJoinStyle::ROUND) {
179 skPaint.setStrokeJoin(SkPaint::Join::kRound_Join);
180 } else if (strokeState.GetLineJoin() == LineJoinStyle::BEVEL) {
181 skPaint.setStrokeJoin(SkPaint::Join::kBevel_Join);
182 } else {
183 skPaint.setStrokeJoin(SkPaint::Join::kMiter_Join);
184 }
185 skPaint.setStrokeWidth(static_cast<SkScalar>(strokeState.GetLineWidth().Value()));
186 skPaint.setStrokeMiter(static_cast<SkScalar>(strokeState.GetMiterLimit()));
187 skPaint.setAntiAlias(antiAlias);
188 UpdateLineDash(skPaint, strokeState);
189 }
190
SetStrokeStyle(SkCanvas * skCanvas,const SkPath & skPath,const StrokeState & strokeState,uint8_t opacity,bool antiAlias)191 void FlutterSvgPainter::SetStrokeStyle(
192 SkCanvas* skCanvas, const SkPath& skPath, const StrokeState& strokeState, uint8_t opacity, bool antiAlias)
193 {
194 if (strokeState.GetColor() == Color::TRANSPARENT) {
195 return;
196 }
197 if (GreatNotEqual(strokeState.GetLineWidth().Value(), 0.0)) {
198 SkPaint paint;
199 SetStrokeStyle(paint, strokeState, opacity, antiAlias);
200 skCanvas->drawPath(skPath, paint);
201 }
202 }
203
SetStrokeStyle(SkCanvas * skCanvas,const SkPath & skPath,const StrokeState & strokeState,RenderInfo & renderInfo)204 void FlutterSvgPainter::SetStrokeStyle(
205 SkCanvas* skCanvas, const SkPath& skPath, const StrokeState& strokeState, RenderInfo& renderInfo)
206 {
207 const auto& strokeHref = strokeState.GetHref();
208 if (strokeHref.empty() || !renderInfo.node) {
209 return SetStrokeStyle(skCanvas, skPath, strokeState, renderInfo.opacity, renderInfo.antiAlias);
210 }
211
212 if (GreatNotEqual(strokeState.GetLineWidth().Value(), 0.0)) {
213 SkPaint paint;
214 SetStrokeStyle(paint, strokeState, renderInfo.opacity, renderInfo.antiAlias);
215 auto pattern = AceType::DynamicCast<FlutterRenderSvgPattern>(renderInfo.node->GetPatternFromRoot(strokeHref));
216 if (!pattern) {
217 return;
218 }
219 if (!pattern->OnAsPaint(renderInfo.offset, renderInfo.node->GetPaintBounds(renderInfo.offset), paint)) {
220 return;
221 }
222 skCanvas->drawPath(skPath, paint);
223 }
224 }
225
UpdateLineDash(SkPaint & paint,const StrokeState & strokeState)226 void FlutterSvgPainter::UpdateLineDash(SkPaint& paint, const StrokeState& strokeState)
227 {
228 if (!strokeState.GetLineDash().lineDash.empty()) {
229 auto lineDashState = strokeState.GetLineDash().lineDash;
230 SkScalar intervals[lineDashState.size()];
231 for (size_t i = 0; i < lineDashState.size(); ++i) {
232 intervals[i] = SkDoubleToScalar(lineDashState[i]);
233 }
234 SkScalar phase = SkDoubleToScalar(strokeState.GetLineDash().dashOffset);
235 paint.setPathEffect(SkDashPathEffect::Make(intervals, lineDashState.size(), phase));
236 }
237 }
238
CheckFontType()239 void FlutterSvgPainter::CheckFontType()
240 {
241 if (!fontTypeChinese_) {
242 LOGW("can't load HwChinese-Medium.ttf");
243 }
244 if (!fontTypeNormal_) {
245 LOGW("can't load DroidSans.ttf");
246 }
247 }
248
GetPathLength(const std::string & path)249 double FlutterSvgPainter::GetPathLength(const std::string& path)
250 {
251 SkPath skPath;
252 SkParsePath::FromSVGString(path.c_str(), &skPath);
253 SkPathMeasure pathMeasure(skPath, false);
254 SkScalar length = pathMeasure.getLength();
255 return length;
256 }
257
GetPathOffset(const std::string & path,double current)258 Offset FlutterSvgPainter::GetPathOffset(const std::string& path, double current)
259 {
260 SkPath skPath;
261 SkParsePath::FromSVGString(path.c_str(), &skPath);
262 SkPathMeasure pathMeasure(skPath, false);
263 SkPoint position;
264 if (!pathMeasure.getPosTan(current, &position, nullptr)) {
265 return Offset(0.0, 0.0);
266 }
267 return Offset(position.fX, position.fY);
268 }
269
GetMotionPathPosition(const std::string & path,double percent,MotionPathPosition & result)270 bool FlutterSvgPainter::GetMotionPathPosition(const std::string& path, double percent, MotionPathPosition& result)
271 {
272 if (path.empty()) {
273 return false;
274 }
275 SkPath motion;
276 SkParsePath::FromSVGString(path.c_str(), &motion);
277 SkPathMeasure pathMeasure(motion, false);
278 SkPoint position;
279 SkVector tangent;
280 bool ret = pathMeasure.getPosTan(pathMeasure.getLength() * percent, &position, &tangent);
281 if (!ret) {
282 return false;
283 }
284 result.rotate = SkRadiansToDegrees(std::atan2(tangent.y(), tangent.x()));
285 result.offset.SetX(position.x());
286 result.offset.SetY(position.y());
287 return true;
288 }
289
UpdateText(SkCanvas * canvas,const SvgTextInfo & svgTextInfo,const TextDrawInfo & textDrawInfo)290 Offset FlutterSvgPainter::UpdateText(SkCanvas* canvas, const SvgTextInfo& svgTextInfo, const TextDrawInfo& textDrawInfo)
291 {
292 Offset offset = textDrawInfo.offset;
293 if (!canvas) {
294 LOGE("Paint skCanvas is null");
295 return offset;
296 }
297
298 SkFont font;
299
300 font.setSize(svgTextInfo.textStyle.GetFontSize().Value());
301 font.setScaleX(1.0);
302 double space = 0.0;
303 SkScalar x = SkDoubleToScalar(offset.GetX());
304 SkScalar y = SkDoubleToScalar(offset.GetY());
305 std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
306
307 SkPaint paint;
308 SkPaint strokePaint;
309 FlutterSvgPainter::SetFillStyle(paint, svgTextInfo.fillState, svgTextInfo.opacity);
310 FlutterSvgPainter::SetStrokeStyle(strokePaint, svgTextInfo.strokeState, svgTextInfo.opacity);
311
312 for (int i = 0; i < (int)data.size(); i++) {
313 wchar_t temp = data[i];
314 if (temp >= 0x4e00 && temp <= 0x9fa5) {
315 // range of chinese
316 font.setTypeface(fontTypeChinese_);
317 } else {
318 font.setTypeface(fontTypeNormal_);
319 }
320 auto blob = SkTextBlob::MakeFromText(&temp, sizeof(temp), font, SkTextEncoding::kUTF16);
321 auto width = font.measureText(&temp, sizeof(temp), SkTextEncoding::kUTF16);
322 canvas->save();
323 canvas->rotate(textDrawInfo.rotate, x, y);
324 canvas->drawTextBlob(blob.get(), x, y, paint);
325 if (svgTextInfo.strokeState.HasStroke() && !NearZero(svgTextInfo.strokeState.GetLineWidth().Value())) {
326 canvas->drawTextBlob(blob.get(), x, y, strokePaint);
327 }
328 canvas->restore();
329 x = x + width + space;
330 }
331
332 return Offset(x, y);
333 }
334
UpdateTextPath(SkCanvas * canvas,const SvgTextInfo & svgTextInfo,const PathDrawInfo & pathDrawInfo)335 double FlutterSvgPainter::UpdateTextPath(
336 SkCanvas* canvas, const SvgTextInfo& svgTextInfo, const PathDrawInfo& pathDrawInfo)
337 {
338 double offset = pathDrawInfo.offset;
339 if (!canvas) {
340 LOGE("Paint skCanvas is null");
341 return offset;
342 }
343
344 SkFont font;
345 font.setSize(svgTextInfo.textStyle.GetFontSize().Value());
346 font.setScaleX(1.0);
347 double space = 0.0;
348 std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
349
350 SkPaint paint;
351 SkPaint strokePaint;
352 FlutterSvgPainter::SetFillStyle(paint, svgTextInfo.fillState, svgTextInfo.opacity);
353 FlutterSvgPainter::SetStrokeStyle(strokePaint, svgTextInfo.strokeState, svgTextInfo.opacity);
354
355 SkPath path;
356 SkParsePath::FromSVGString(pathDrawInfo.path.c_str(), &path);
357 SkPathMeasure pathMeasure(path, false);
358 SkScalar length = pathMeasure.getLength();
359
360 for (int i = 0; i < (int)data.size(); i++) {
361 wchar_t temp = data[i];
362 if (temp >= 0x4e00 && temp <= 0x9fa5) {
363 font.setTypeface(fontTypeChinese_);
364 } else {
365 font.setTypeface(fontTypeNormal_);
366 }
367 auto width = font.measureText(&temp, sizeof(wchar_t), SkTextEncoding::kUTF16);
368 if (length < offset + width + space) {
369 LOGD("path length is not enough, length:%{public}lf, next offset:%{public}lf",
370 length, offset + width + space);
371 break;
372 }
373 if (offset < 0) {
374 offset += (width + space);
375 continue;
376 }
377
378 SkPoint position;
379 SkVector tangent;
380 if (!pathMeasure.getPosTan(offset + width / 2.0, &position, &tangent)) {
381 break;
382 }
383 if (!pathMeasure.getPosTan(offset, &position, nullptr)) {
384 break;
385 }
386 SkRSXform rsxForm = SkRSXform::Make(tangent.fX, tangent.fY, position.fX, position.fY);
387 auto blob = SkTextBlob::MakeFromRSXform(&temp, sizeof(wchar_t), &rsxForm, font, SkTextEncoding::kUTF16);
388
389 canvas->save();
390 canvas->rotate(pathDrawInfo.rotate, position.fX, position.fY);
391 canvas->drawTextBlob(blob.get(), 0.0, 0.0, paint);
392 if (svgTextInfo.strokeState.HasStroke() && !NearZero(svgTextInfo.strokeState.GetLineWidth().Value())) {
393 canvas->drawTextBlob(blob.get(), 0.0, 0.0, strokePaint);
394 }
395 canvas->restore();
396 offset = offset + width + space;
397 }
398
399 return offset;
400 }
401
MeasureTextBounds(const SvgTextInfo & svgTextInfo,const TextDrawInfo & textDrawInfo,Rect & bounds)402 Offset FlutterSvgPainter::MeasureTextBounds(
403 const SvgTextInfo& svgTextInfo, const TextDrawInfo& textDrawInfo, Rect& bounds)
404 {
405 Offset offset = textDrawInfo.offset;
406 SkFont font;
407
408 font.setSize(svgTextInfo.textStyle.GetFontSize().Value());
409 font.setScaleX(1.0);
410 double space = 0.0;
411 SkScalar x = SkDoubleToScalar(offset.GetX());
412 SkScalar y = SkDoubleToScalar(offset.GetY());
413 std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
414
415 for (int i = 0; i < (int)data.size(); i++) {
416 wchar_t temp = data[i];
417 if (temp >= 0x4e00 && temp <= 0x9fa5) {
418 // range of chinese
419 font.setTypeface(fontTypeChinese_);
420 } else {
421 font.setTypeface(fontTypeNormal_);
422 }
423 auto width = font.measureText(&temp, sizeof(temp), SkTextEncoding::kUTF16);
424 x = x + width + space;
425 }
426 bounds.SetWidth(fmax(x, bounds.Width()));
427 bounds.SetHeight(fmax(y, bounds.Height()));
428
429 return Offset(x, y);
430 }
431
MeasureTextPathBounds(const SvgTextInfo & svgTextInfo,const PathDrawInfo & pathDrawInfo,Rect & bounds)432 double FlutterSvgPainter::MeasureTextPathBounds(
433 const SvgTextInfo& svgTextInfo, const PathDrawInfo& pathDrawInfo, Rect& bounds)
434 {
435 double offset = pathDrawInfo.offset;
436
437 SkFont font;
438 font.setSize(svgTextInfo.textStyle.GetFontSize().Value());
439 font.setScaleX(1.0);
440 double space = 0.0;
441 std::wstring data = StringUtils::ToWstring(svgTextInfo.data);
442
443 SkPath path;
444 SkParsePath::FromSVGString(pathDrawInfo.path.c_str(), &path);
445 SkPathMeasure pathMeasure(path, false);
446 SkScalar length = pathMeasure.getLength();
447
448 for (int i = 0; i < (int)data.size(); i++) {
449 wchar_t temp = data[i];
450 if (temp >= 0x4e00 && temp <= 0x9fa5) {
451 font.setTypeface(fontTypeChinese_);
452 } else {
453 font.setTypeface(fontTypeNormal_);
454 }
455 auto width = font.measureText(&temp, sizeof(temp), SkTextEncoding::kUTF16);
456 if (length < offset + width + space) {
457 LOGD("path length is not enough, length:%{public}lf, next offset:%{public}lf",
458 length, offset + width + space);
459 break;
460 }
461 offset = offset + width + space;
462 }
463
464 auto& pathBounds = path.getBounds();
465 bounds.SetWidth(fmax(pathBounds.right(), bounds.Width()));
466 bounds.SetHeight(fmax(pathBounds.bottom(), bounds.Height()));
467 return offset;
468 }
469
SkipSpace(const char str[])470 static const char* SkipSpace(const char str[])
471 {
472 if (!str) {
473 return nullptr;
474 }
475 while (isspace(*str)) {
476 str++;
477 }
478 return str;
479 }
480
SkipSep(const char str[])481 static const char* SkipSep(const char str[])
482 {
483 if (!str) {
484 return nullptr;
485 }
486 while (isspace(*str) || *str == ',') {
487 str++;
488 }
489 return str;
490 }
491
FindDoubleValue(const char str[],double & value)492 static const char* FindDoubleValue(const char str[], double& value)
493 {
494 str = SkipSpace(str);
495 if (!str) {
496 return nullptr;
497 }
498 char* stop = nullptr;
499 float v = std::strtod(str, &stop);
500 if (str == stop || errno == ERANGE) {
501 return nullptr;
502 }
503 value = v;
504 return stop;
505 }
506
StringToPoints(const char str[],std::vector<SkPoint> & points)507 void FlutterSvgPainter::StringToPoints(const char str[], std::vector<SkPoint>& points)
508 {
509 for (;;) {
510 double x = 0.0;
511 str = FindDoubleValue(str, x);
512 if (str == nullptr) {
513 break;
514 }
515 str = SkipSep(str);
516 double y = 0.0;
517 str = FindDoubleValue(str, y);
518 if (str == nullptr) {
519 break;
520 }
521 points.emplace_back(SkPoint::Make(x, y));
522 }
523 }
524
CreateMotionMatrix(const std::string & path,const std::string & rotate,double percent,bool & isSuccess)525 Matrix4 FlutterSvgPainter::CreateMotionMatrix(const std::string& path, const std::string& rotate,
526 double percent, bool& isSuccess)
527 {
528 if (path.empty()) {
529 isSuccess = false;
530 return Matrix4::CreateIdentity();
531 }
532 SkPath motion;
533 SkParsePath::FromSVGString(path.c_str(), &motion);
534 SkPathMeasure pathMeasure(motion, false);
535 SkPoint position;
536 SkVector tangent;
537 bool ret = pathMeasure.getPosTan(pathMeasure.getLength() * percent, &position, &tangent);
538 if (!ret) {
539 isSuccess = false;
540 return Matrix4::CreateIdentity();
541 }
542 float degrees = 0.0f;
543 if (rotate == ROTATE_TYPE_AUTO) {
544 degrees = SkRadiansToDegrees(std::atan2(tangent.y(), tangent.x()));
545 } else if (rotate == ROTATE_TYPE_REVERSE) {
546 degrees = SkRadiansToDegrees(std::atan2(tangent.y(), tangent.x())) + FLAT_ANGLE;
547 } else {
548 degrees = StringUtils::StringToDouble(rotate);
549 }
550 auto transform = Matrix4::CreateTranslate(position.x(), position.y(), 0.0);
551 Matrix4 rotateMatrix;
552 rotateMatrix.SetEntry(ROW_INDEX, COL_INDEX, ROTATE_VALUE);
553 rotateMatrix.Rotate(degrees, 0.0f, 0.0f, 1.0f);
554 transform = rotateMatrix * transform;
555 isSuccess = true;
556 return FlutterRenderTransform::GetTransformByOffset(transform, Offset(position.x(), position.y()));
557 }
558
ToSkMatrix(const Matrix4 & matrix4)559 SkMatrix FlutterSvgPainter::ToSkMatrix(const Matrix4& matrix4)
560 {
561 // Mappings from SkMatrix-index to input-index.
562 static const int32_t K_SK_MATRIX_INDEX_TO_MATRIX4_INDEX[] = {
563 0,
564 4,
565 12,
566 1,
567 5,
568 13,
569 3,
570 7,
571 15,
572 };
573
574 SkMatrix skMatrix;
575 for (std::size_t i = 0; i < ArraySize(K_SK_MATRIX_INDEX_TO_MATRIX4_INDEX); ++i) {
576 int32_t matrixIndex = K_SK_MATRIX_INDEX_TO_MATRIX4_INDEX[i];
577 if (matrixIndex < matrix4.Count())
578 skMatrix[i] = matrix4[matrixIndex];
579 else
580 skMatrix[i] = 0.0;
581 }
582 return skMatrix;
583 }
584
585 } // namespace OHOS::Ace