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