• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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