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 "frameworks/core/components/svg/parse/svg_dom.h"
17 
18 #include "frameworks/core/components/svg/parse/svg_animation.h"
19 #include "frameworks/core/components/svg/parse/svg_circle.h"
20 #include "frameworks/core/components/svg/parse/svg_clip_path.h"
21 #include "frameworks/core/components/svg/parse/svg_defs.h"
22 #include "frameworks/core/components/svg/parse/svg_ellipse.h"
23 #include "frameworks/core/components/svg/parse/svg_fe_colormatrix.h"
24 #include "frameworks/core/components/svg/parse/svg_fe_composite.h"
25 #include "frameworks/core/components/svg/parse/svg_fe_gaussianblur.h"
26 #include "frameworks/core/components/svg/parse/svg_fe_offset.h"
27 #include "frameworks/core/components/svg/parse/svg_g.h"
28 #include "frameworks/core/components/svg/parse/svg_gradient.h"
29 #include "frameworks/core/components/svg/parse/svg_line.h"
30 #include "frameworks/core/components/svg/parse/svg_path.h"
31 #include "frameworks/core/components/svg/parse/svg_polygon.h"
32 #include "frameworks/core/components/svg/parse/svg_rect.h"
33 #include "frameworks/core/components/svg/parse/svg_stop.h"
34 #include "frameworks/core/components/svg/parse/svg_svg.h"
35 #include "frameworks/core/components/svg/parse/svg_use.h"
36 #include "frameworks/core/components/transform/transform_component.h"
37 
38 #ifdef ENABLE_ROSEN_BACKEND
39 #include "frameworks/core/components/svg/rosen_render_svg.h"
40 #include "frameworks/core/pipeline/base/rosen_render_context.h"
41 #endif
42 
43 namespace OHOS::Ace {
44 namespace {
45 
46 const char DOM_SVG_STYLE[] = "style";
47 const char DOM_SVG_CLASS[] = "class";
48 
49 } // namespace
50 
51 static const LinearMapNode<RefPtr<SvgNode> (*)()> TAG_FACTORIES[] = {
__anon3de6db050202() 52     { "animate", []() -> RefPtr<SvgNode> { return SvgAnimation::CreateAnimate(); } },
__anon3de6db050302() 53     { "animateMotion", []() -> RefPtr<SvgNode> { return SvgAnimation::CreateAnimateMotion(); } },
__anon3de6db050402() 54     { "animateTransform", []() -> RefPtr<SvgNode> { return SvgAnimation::CreateAnimateTransform(); } },
__anon3de6db050502() 55     { "circle", []() -> RefPtr<SvgNode> { return SvgCircle::Create(); } },
__anon3de6db050602() 56     { "clipPath", []() -> RefPtr<SvgNode> { return SvgClipPath::Create(); } },
__anon3de6db050702() 57     { "defs", []() -> RefPtr<SvgNode> { return SvgDefs::Create(); } },
__anon3de6db050802() 58     { "ellipse", []() -> RefPtr<SvgNode> { return SvgEllipse::Create(); } },
__anon3de6db050902() 59     { "feColorMatrix", []() -> RefPtr<SvgNode> { return SvgFeColorMatrix::Create(); } },
__anon3de6db050a02() 60     { "feComposite", []() -> RefPtr<SvgNode> { return SvgFeComposite::Create(); } },
__anon3de6db050b02() 61     { "feGaussianBlur", []() -> RefPtr<SvgNode> { return SvgFeGaussianBlur::Create(); } },
__anon3de6db050c02() 62     { "feOffset", []() -> RefPtr<SvgNode> { return SvgFeOffset::Create(); } },
__anon3de6db050d02() 63     { "filter", []() -> RefPtr<SvgNode> { return SvgFilter::Create(); } },
__anon3de6db050e02() 64     { "g", []() -> RefPtr<SvgNode> { return SvgG::Create(); } },
__anon3de6db050f02() 65     { "line", []() -> RefPtr<SvgNode> { return SvgLine::Create(); } },
__anon3de6db051002() 66     { "linearGradient", []() -> RefPtr<SvgNode> { return SvgGradient::CreateLinearGradient(); } },
__anon3de6db051102() 67     { "mask", []() -> RefPtr<SvgNode> { return SvgMask::Create(); } },
__anon3de6db051202() 68     { "path", []() -> RefPtr<SvgNode> { return SvgPath::Create(); } },
__anon3de6db051302() 69     { "pattern", []() -> RefPtr<SvgNode> { return SvgPattern::Create(); } },
__anon3de6db051402() 70     { "polygon", []() -> RefPtr<SvgNode> { return SvgPolygon::CreatePolygon(); } },
__anon3de6db051502() 71     { "polyline", []() -> RefPtr<SvgNode> { return SvgPolygon::CreatePolyline(); } },
__anon3de6db051602() 72     { "radialGradient", []() -> RefPtr<SvgNode> { return SvgGradient::CreateRadialGradient(); } },
__anon3de6db051702() 73     { "rect", []() -> RefPtr<SvgNode> { return SvgRect::Create(); } },
__anon3de6db051802() 74     { "stop", []() -> RefPtr<SvgNode> { return SvgStop::Create(); } },
__anon3de6db051902() 75     { "style", []() -> RefPtr<SvgNode> { return SvgStyle::Create(); } },
__anon3de6db051a02() 76     { "svg", []() -> RefPtr<SvgNode> { return SvgSvg::Create(); } },
__anon3de6db051b02() 77     { "use", []() -> RefPtr<SvgNode> { return SvgUse::Create(); } },
78 };
79 
CreateSvgClipBox(const Size & containerSize,const SvgRadius & svgRadius)80 RefPtr<BoxComponent> CreateSvgClipBox(const Size& containerSize, const SvgRadius& svgRadius)
81 {
82     auto clipBox = AceType::MakeRefPtr<BoxComponent>();
83     clipBox->SetWidth(containerSize.Width());
84     clipBox->SetHeight(containerSize.Height());
85     clipBox->SetOverflow(Overflow::FORCE_CLIP);
86     if (svgRadius.IsValid()) {
87         RefPtr<Decoration> decoration = AceType::MakeRefPtr<Decoration>();
88         Border border;
89         border.SetTopLeftRadius(svgRadius.topLeft);
90         border.SetTopRightRadius(svgRadius.topRight);
91         border.SetBottomLeftRadius(svgRadius.bottomLeft);
92         border.SetBottomRightRadius(svgRadius.bottomRight);
93         decoration->SetBorder(border);
94         clipBox->SetBackDecoration(decoration);
95     }
96     return clipBox;
97 }
98 
SvgDom(const WeakPtr<PipelineContext> & context)99 SvgDom::SvgDom(const WeakPtr<PipelineContext>& context) : context_(context)
100 {
101     attrCallback_ = [weakSvgDom = AceType::WeakClaim(this)](
102                         const std::string& styleName, const std::pair<std::string, std::string>& attrPair) {
103         auto svgDom = weakSvgDom.Upgrade();
104         if (!svgDom) {
105             LOGE("svg dom is null");
106             return;
107         }
108         if (svgDom->svgContext_) {
109             if (attrPair.first == "clip-path") {
110                 svgDom->SetHasClipPath(true);
111             }
112             svgDom->svgContext_->PushStyle(styleName, attrPair);
113         }
114     };
115 }
116 
~SvgDom()117 SvgDom::~SvgDom()
118 {
119     if (animatorGroup_) {
120         animatorGroup_->Stop();
121     }
122     root_ = nullptr;
123     renderNode_ = nullptr;
124 }
125 
CreateSvgDom(SkStream & svgStream,const WeakPtr<PipelineContext> & context,const std::optional<Color> & svgThemeColor)126 RefPtr<SvgDom> SvgDom::CreateSvgDom(
127     SkStream& svgStream, const WeakPtr<PipelineContext>& context, const std::optional<Color>& svgThemeColor)
128 {
129     RefPtr<SvgDom> svgDom = AceType::MakeRefPtr<SvgDom>(context);
130     if (svgThemeColor) {
131         svgDom->fillColor_ = svgThemeColor;
132     }
133     bool ret = svgDom->ParseSvg(svgStream);
134     if (ret) {
135         return svgDom;
136     }
137     return nullptr;
138 }
139 
ParseSvg(SkStream & svgStream)140 bool SvgDom::ParseSvg(SkStream& svgStream)
141 {
142     SkDOM xmlDom;
143     if (!xmlDom.build(svgStream)) {
144         return false;
145     }
146     if (svgContext_ == nullptr) {
147         svgContext_ = AceType::MakeRefPtr<SvgContext>();
148     }
149     root_ = TranslateSvgNode(xmlDom, xmlDom.getRootNode(), nullptr);
150     if (root_ == nullptr) {
151         return false;
152     }
153     auto svg = AceType::DynamicCast<SvgSvg>(root_);
154     if (svg == nullptr) {
155         return false;
156     }
157     svg->MarkIsRoot(true);
158     svgSize_ = svg->GetSize();
159     return true;
160 }
161 
TranslateSvgNode(const SkDOM & dom,const SkDOM::Node * xmlNode,const RefPtr<SvgNode> & parent)162 RefPtr<SvgNode> SvgDom::TranslateSvgNode(const SkDOM& dom, const SkDOM::Node* xmlNode, const RefPtr<SvgNode>& parent)
163 {
164     const char* element = dom.getName(xmlNode);
165     if (dom.getType(xmlNode) == SkDOM::kText_Type) {
166         if (parent == nullptr) {
167             return nullptr;
168         }
169         if (AceType::InstanceOf<SvgStyle>(parent)) {
170             SvgStyle::ParseCssStyle(element, attrCallback_);
171         } else {
172             parent->SetText(element);
173         }
174     }
175 
176     auto elementIter = BinarySearchFindIndex(TAG_FACTORIES, ArraySize(TAG_FACTORIES), element);
177     if (elementIter == -1) {
178         return nullptr;
179     }
180     RefPtr<SvgNode> node = TAG_FACTORIES[elementIter].value();
181     if (!node) {
182         return nullptr;
183     }
184     node->SetContext(context_, svgContext_);
185     ParseAttrs(dom, xmlNode, node);
186     for (auto* child = dom.getFirstChild(xmlNode, nullptr); child; child = dom.getNextSibling(child)) {
187         const auto& childNode = TranslateSvgNode(dom, child, node);
188         if (childNode) {
189             node->AppendChild(childNode);
190         }
191     }
192     if (AceType::InstanceOf<SvgAnimation>(node)) {
193         svgAnimate_ = true;
194     }
195     return node;
196 }
197 
ParseAttrs(const SkDOM & xmlDom,const SkDOM::Node * xmlNode,const RefPtr<SvgNode> & svgNode)198 void SvgDom::ParseAttrs(const SkDOM& xmlDom, const SkDOM::Node* xmlNode, const RefPtr<SvgNode>& svgNode)
199 {
200     const char* name = nullptr;
201     const char* value = nullptr;
202     SkDOM::AttrIter attrIter(xmlDom, xmlNode);
203     while ((name = attrIter.next(&value))) {
204         SetAttrValue(name, value, svgNode);
205     }
206 }
207 
ParseIdAttr(const WeakPtr<SvgNode> & weakSvgNode,const std::string & value)208 void SvgDom::ParseIdAttr(const WeakPtr<SvgNode>& weakSvgNode, const std::string& value)
209 {
210     auto svgNode = weakSvgNode.Upgrade();
211     if (!svgNode) {
212         LOGE("ParseIdAttr failed, svgNode is null");
213         return;
214     }
215     svgNode->SetNodeId(value);
216     svgNode->SetAttr(DOM_ID, value);
217     svgContext_->Push(value, svgNode);
218 }
219 
ParseFillAttr(const WeakPtr<SvgNode> & weakSvgNode,const std::string & value)220 void SvgDom::ParseFillAttr(const WeakPtr<SvgNode>& weakSvgNode, const std::string& value)
221 {
222     auto svgNode = weakSvgNode.Upgrade();
223     if (!svgNode) {
224         LOGE("ParseFillAttr failed, svgNode is null");
225         return;
226     }
227     if (fillColor_) {
228         std::stringstream stream;
229         stream << std::hex << fillColor_.value().GetValue();
230         std::string newValue(stream.str());
231         svgNode->SetAttr(DOM_SVG_FILL, "#" + newValue);
232     } else {
233         svgNode->SetAttr(DOM_SVG_FILL, value);
234     }
235 }
236 
ParseClassAttr(const WeakPtr<SvgNode> & weakSvgNode,const std::string & value)237 void SvgDom::ParseClassAttr(const WeakPtr<SvgNode>& weakSvgNode, const std::string& value)
238 {
239     auto svgNode = weakSvgNode.Upgrade();
240     if (!svgNode) {
241         LOGE("ParseClassAttr failed, svgNode is null");
242         return;
243     }
244     std::vector<std::string> styleNameVector;
245     StringUtils::SplitStr(value, " ", styleNameVector);
246     for (const auto& styleName : styleNameVector) {
247         auto attrMap = svgContext_->GetAttrMap(styleName);
248         if (attrMap.empty()) {
249             continue;
250         }
251         for (const auto& attr : attrMap) {
252             svgNode->SetAttr(attr.first, attr.second);
253         }
254     }
255 }
256 
ParseStyleAttr(const WeakPtr<SvgNode> & weakSvgNode,const std::string & value)257 void SvgDom::ParseStyleAttr(const WeakPtr<SvgNode>& weakSvgNode, const std::string& value)
258 {
259     auto svgNode = weakSvgNode.Upgrade();
260     if (!svgNode) {
261         LOGE("ParseStyleAttr failed, svgNode is null");
262         return;
263     }
264     std::vector<std::string> attrPairVector;
265     StringUtils::SplitStr(value, ";", attrPairVector);
266     for (const auto& attrPair : attrPairVector) {
267         std::vector<std::string> attrVector;
268         StringUtils::SplitStr(attrPair, ":", attrVector);
269         if (attrVector.size() == 2) {
270             svgNode->SetAttr(attrVector[0], attrVector[1]);
271         }
272     }
273 }
274 
SetAttrValue(const std::string & name,const std::string & value,const RefPtr<SvgNode> & svgNode)275 void SvgDom::SetAttrValue(const std::string& name, const std::string& value, const RefPtr<SvgNode>& svgNode)
276 {
277     static const LinearMapNode<void (*)(const std::string&, const WeakPtr<SvgNode>&, SvgDom&)> attrs[] = {
278         { DOM_SVG_CLASS, [](const std::string& val, const WeakPtr<SvgNode>& svgNode,
279                              SvgDom& svgDom) { svgDom.ParseClassAttr(svgNode, val); } },
280         { DOM_SVG_FILL, [](const std::string& val, const WeakPtr<SvgNode>& svgNode,
281                             SvgDom& svgDom) { svgDom.ParseFillAttr(svgNode, val); } },
282         { DOM_ID, [](const std::string& val, const WeakPtr<SvgNode>& svgNode,
283                       SvgDom& svgDom) { svgDom.ParseIdAttr(svgNode, val); } },
284         { DOM_SVG_STYLE, [](const std::string& val, const WeakPtr<SvgNode>& svgNode,
285                              SvgDom& svgDom) { svgDom.ParseStyleAttr(svgNode, val); } },
286     };
287     if (value.empty()) {
288         return;
289     }
290     auto attrIter = BinarySearchFindIndex(attrs, ArraySize(attrs), name.c_str());
291     if (attrIter != -1) {
292         attrs[attrIter].value(value, svgNode, *this);
293         return;
294     }
295     svgNode->SetAttr(name, value);
296     if (name == std::string("mask")) {
297         if (value.find("url(") == 0) {
298             auto src = std::regex_replace(value, std::regex(R"(^url\(\s*['"]?\s*#([^()]+?)\s*['"]?\s*\)$)"), "$1");
299             svgContext_->addMaskReferUrl(src);
300         }
301     }
302 }
303 
304 #ifdef ENABLE_ROSEN_BACKEND
305 void SvgDom::PaintDirectly(RenderContext& context, const Offset& offset, ImageFit imageFit, Size layout)
306 {
307     auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas();
308     auto svgRoot = AceType::DynamicCast<RosenRenderSvg>(svgRoot_.Upgrade());
309 
310     if (!canvas) {
311         LOGE("Paint canvas is null");
312         return;
313     }
314     if (svgRoot == nullptr) {
315         return;
316     }
317     double scaleX = 1.0;
318     double scaleY = 1.0;
319     double scaleViewBox = 1.0;
320     double tx = 0.0;
321     double ty = 0.0;
322     double half = 0.5;
323     if (!layout.IsEmpty()) {
324         containerSize_ = layout;
325     }
326     if (!containerSize_.IsEmpty() && (svgSize_.IsValid() && !svgSize_.IsInfinite())) {
327         ApplyImageFit(imageFit, scaleX, scaleY);
328     }
329     auto viewBox = svgRoot->GetViewBox();
330     if (viewBox.IsValid()) {
331         if (svgSize_.IsValid() && !svgSize_.IsInfinite()) {
332             scaleViewBox = std::min(svgSize_.Width() / viewBox.Width(), svgSize_.Height() / viewBox.Height());
333             tx = svgSize_.Width() * half - (viewBox.Width() * half + viewBox.Left()) * scaleViewBox;
334             ty = svgSize_.Height() * half - (viewBox.Height() * half + viewBox.Top()) * scaleViewBox;
335         } else if (!containerSize_.IsEmpty()) {
336             scaleViewBox =
337                 std::min(containerSize_.Width() / viewBox.Width(), containerSize_.Height() / viewBox.Height());
338             tx = containerSize_.Width() * half - (viewBox.Width() * half + viewBox.Left()) * scaleViewBox;
339             ty = containerSize_.Height() * half - (viewBox.Height() * half + viewBox.Top()) * scaleViewBox;
340         } else {
341             LOGW("PaintDirectly containerSize and svgSize is null");
342         }
343     }
344 #ifndef USE_ROSEN_DRAWING
345     canvas->save();
346     canvas->scale(static_cast<float>(scaleX * scaleViewBox), static_cast<float>(scaleY * scaleViewBox));
347     canvas->translate(static_cast<float>(tx), static_cast<float>(ty));
348     svgRoot->PaintDirectly(context, offset);
349     canvas->restore();
350 #else
351     canvas->Save();
352     canvas->Scale(static_cast<float>(scaleX * scaleViewBox), static_cast<float>(scaleY * scaleViewBox));
353     canvas->Translate(static_cast<float>(tx), static_cast<float>(ty));
354     svgRoot->PaintDirectly(context, offset);
355     canvas->Restore();
356 #endif
357 }
358 #endif
359 
360 void SvgDom::CreateRenderNode(ImageFit imageFit, const SvgRadius& svgRadius, bool useBox)
361 {
362     auto svg = AceType::DynamicCast<SvgSvg>(root_);
363     if (svg == nullptr) {
364         return;
365     }
366     Size size = (svgSize_.IsValid() && !svgSize_.IsInfinite()) ? svgSize_ : containerSize_;
367     auto renderSvg = svg->CreateRender(LayoutParam(size, Size(0.0, 0.0)), nullptr, useBox);
368     if (renderSvg) {
369         InitAnimatorGroup(renderSvg);
370         double scaleX = 1.0;
371         double scaleY = 1.0;
372         ApplyImageFit(imageFit, scaleX, scaleY);
373         auto transformComponent = AceType::MakeRefPtr<TransformComponent>();
374         transformComponent->Scale(scaleX, scaleY);
375         auto renderTransform = transformComponent->CreateRenderNode();
376         renderTransform->Attach(context_);
377         SyncRSNode(renderTransform);
378         renderTransform->Update(transformComponent);
379         renderTransform->AddChild(renderSvg);
380         renderTransform->Layout(LayoutParam(containerSize_, Size(0.0, 0.0)));
381         svgRoot_ = renderSvg;
382         transform_ = renderTransform;
383 
384         auto clipBox = CreateSvgClipBox(containerSize_, svgRadius);
385         auto renderBox = clipBox->CreateRenderNode();
386         renderBox->Attach(context_);
387         SyncRSNode(renderBox);
388         renderBox->Update(clipBox);
389         renderBox->AddChild(renderTransform);
390         renderBox->Layout(LayoutParam(containerSize_, Size(0.0, 0.0)));
391         clipBox_ = renderBox;
392 
393         auto boxComponent = AceType::MakeRefPtr<BoxComponent>();
394         boxComponent->SetWidth(containerSize_.Width());
395         boxComponent->SetHeight(containerSize_.Height());
396         renderNode_ = boxComponent->CreateRenderNode();
397         renderNode_->Attach(context_);
398         SyncRSNode(renderNode_);
399         renderNode_->Update(boxComponent);
400         renderNode_->AddChild(renderBox);
401         renderNode_->Layout(LayoutParam(containerSize_, Size(0.0, 0.0)));
402     }
403 }
404 
405 void SvgDom::UpdateLayout(ImageFit imageFit, const SvgRadius& svgRadius, bool useBox)
406 {
407     if (renderNode_) {
408         auto transform = transform_.Upgrade();
409         if (transform) {
410             double scaleX = 1.0;
411             double scaleY = 1.0;
412             ApplyImageFit(imageFit, scaleX, scaleY);
413             auto transformComponent = AceType::MakeRefPtr<TransformComponent>();
414             transformComponent->Scale(scaleX, scaleY);
415             transform->Update(transformComponent);
416         }
417 
418         auto renderClipBox = clipBox_.Upgrade();
419         if (renderClipBox) {
420             auto clipBox = CreateSvgClipBox(containerSize_, svgRadius);
421             renderClipBox->Update(clipBox);
422         }
423 
424         auto boxComponent = AceType::MakeRefPtr<BoxComponent>();
425         boxComponent->SetWidth(containerSize_.Width());
426         boxComponent->SetHeight(containerSize_.Height());
427         renderNode_->Update(boxComponent);
428         renderNode_->Layout(LayoutParam(containerSize_, Size(0.0, 0.0)));
429     }
430 }
431 
432 SvgRenderTree SvgDom::GetSvgRenderTree() const
433 {
434     return { .root = renderNode_,
435         .clipBox = clipBox_.Upgrade(),
436         .transform = transform_.Upgrade(),
437         .svgRoot = svgRoot_.Upgrade(),
438         .svgSize = svgSize_,
439         .containerSize = containerSize_,
440         .svgAnimate = svgAnimate_ };
441 }
442 
443 SvgRenderTree SvgDom::CreateRenderTree(ImageFit imageFit, const SvgRadius& svgRadius, bool useBox)
444 {
445     CreateRenderNode(imageFit, svgRadius, useBox);
446     return GetSvgRenderTree();
447 }
448 
449 void SvgDom::SetSvgRenderTree(const SvgRenderTree& svgRenderTree)
450 {
451     renderNode_ = svgRenderTree.root;
452     clipBox_ = svgRenderTree.clipBox;
453     transform_ = svgRenderTree.transform;
454     svgRoot_ = svgRoot_.Upgrade();
455     svgSize_ = svgRenderTree.svgSize;
456     containerSize_ = svgRenderTree.containerSize;
457     svgAnimate_ = svgRenderTree.svgAnimate;
458 }
459 
460 void SvgDom::ApplyImageFit(ImageFit imageFit, double& scaleX, double& scaleY)
461 {
462     switch (imageFit) {
463         case ImageFit::FILL:
464             ApplyFill(scaleX, scaleY);
465             break;
466         case ImageFit::NONE:
467             break;
468         case ImageFit::COVER:
469             ApplyCover(scaleX, scaleY);
470             break;
471         case ImageFit::CONTAIN:
472             ApplyContain(scaleX, scaleY);
473             break;
474         case ImageFit::SCALE_DOWN:
475             if (svgSize_ > containerSize_ || svgSize_ == containerSize_) {
476                 ApplyContain(scaleX, scaleY);
477             }
478             break;
479         default:
480             break;
481     }
482 }
483 
484 void SvgDom::ApplyFill(double& scaleX, double& scaleY)
485 {
486     if (!svgSize_.IsValid()) {
487         return;
488     }
489     scaleX = containerSize_.Width() / svgSize_.Width();
490     scaleY = containerSize_.Height() / svgSize_.Height();
491 }
492 
493 void SvgDom::ApplyContain(double& scaleX, double& scaleY)
494 {
495     if (!svgSize_.IsValid()) {
496         return;
497     }
498     if (Size::CalcRatio(svgSize_) > Size::CalcRatio(containerSize_)) {
499         scaleX = containerSize_.Width() / svgSize_.Width();
500         scaleY = scaleX;
501     } else {
502         scaleX = containerSize_.Height() / svgSize_.Height();
503         scaleY = scaleX;
504     }
505 }
506 
507 void SvgDom::ApplyCover(double& scaleX, double& scaleY)
508 {
509     if (!svgSize_.IsValid()) {
510         return;
511     }
512     if (Size::CalcRatio(svgSize_) > Size::CalcRatio(containerSize_)) {
513         scaleX = containerSize_.Height() / svgSize_.Height();
514         scaleY = scaleX;
515     } else {
516         scaleX = containerSize_.Width() / svgSize_.Width();
517         scaleY = scaleX;
518     }
519 }
520 
521 void SvgDom::InitAnimatorGroup(const RefPtr<RenderNode>& node)
522 {
523     animatorGroup_ = AceType::MakeRefPtr<AnimatorGroup>();
524     if (!animatorGroup_) {
525         return;
526     }
527     AddToAnimatorGroup(node, animatorGroup_);
528     auto finishEvent = AceAsyncEvent<void()>::Create(finishEvent_, context_);
529     if (finishEvent) {
530         animatorGroup_->AddStopListener([asyncEvent = finishEvent] { asyncEvent(); });
531     }
532     animatorGroup_->Play();
533 }
534 
535 void SvgDom::AddToAnimatorGroup(const RefPtr<RenderNode>& node, RefPtr<AnimatorGroup>& animatorGroup)
536 {
537     if (!animatorGroup) {
538         return;
539     }
540 
541     std::queue<RefPtr<RenderNode>> queue;
542     queue.push(node);
543     while (!queue.empty()) {
544         auto renderNode = queue.front();
545         queue.pop();
546         auto svgBase = AceType::DynamicCast<RenderSvgBase>(renderNode);
547         if (svgBase) {
548             auto animators = svgBase->GetAnimators();
549             for (auto& p : animators) {
550                 animatorGroup->AddAnimator(p.second);
551             }
552         }
553         if (renderNode) {
554             auto children = renderNode->GetChildren();
555             for (auto& child : children) {
556                 queue.push(child);
557             }
558         }
559     }
560 }
561 
562 void SvgDom::SyncRSNode(const RefPtr<RenderNode>& renderNode)
563 {
564     if (!SystemProperties::GetRosenBackendEnabled() || !renderNode) {
565         return;
566     }
567     renderNode->SyncRSNodeBoundary(true, true);
568 }
569 
570 } // namespace OHOS::Ace
571