• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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/render_svg_base.h"
17 
18 #include "frameworks/core/animation/curve_animation.h"
19 #include "frameworks/core/components/svg/render_svg.h"
20 #include "frameworks/core/components/svg/render_svg_mask.h"
21 #include "frameworks/core/components/transform/render_transform.h"
22 
23 namespace OHOS::Ace {
24 namespace {
25 
26 constexpr int32_t START_VALUE = 0;
27 constexpr int32_t END_VALUE = 1;
28 constexpr Dimension TRANSFORM_ORIGIN_DEFAULT = 0.5_pct;
29 
30 const std::unordered_map<std::string, std::function<Color(RenderSvgBase&)>> COLOR_PROPER_GETTERS = {
__anon67e2cfbc0202() 31     { ATTR_NAME_FILL, [](RenderSvgBase& base) -> Color { return base.GetFillState().GetColor(); } },
__anon67e2cfbc0302() 32     { ATTR_NAME_STROKE, [](RenderSvgBase& base) -> Color { return base.GetStrokeState().GetColor(); } },
33 };
34 
35 const std::unordered_map<std::string, std::function<Dimension(RenderSvgBase&)>> DIMENSION_PROPER_GETTERS = {
__anon67e2cfbc0402() 36     { ATTR_NAME_STROKE_WIDTH, [](RenderSvgBase& base) -> Dimension { return base.GetStrokeState().GetLineWidth(); } },
__anon67e2cfbc0502() 37     { ATTR_NAME_FONT_SIZE, [](RenderSvgBase& base) -> Dimension { return base.GetTextStyle().GetFontSize(); } },
38 };
39 
40 const std::unordered_map<std::string, std::function<double(RenderSvgBase&)>> DOUBLE_PROPER_GETTERS = {
41     { ATTR_NAME_FILL_OPACITY,
__anon67e2cfbc0602() 42         [](RenderSvgBase& base) -> double { return base.GetFillState().GetOpacity().GetValue(); } },
43     { ATTR_NAME_STROKE_OPACITY,
__anon67e2cfbc0702() 44         [](RenderSvgBase& base) -> double { return base.GetStrokeState().GetOpacity().GetValue(); } },
45     { ATTR_NAME_LETTER_SPACING,
__anon67e2cfbc0802() 46         [](RenderSvgBase& base) -> double { return base.NormalizeToPx(base.GetTextStyle().GetLetterSpacing()); } },
__anon67e2cfbc0902() 47     { ATTR_NAME_MITER_LIMIT, [](RenderSvgBase& base) -> double { return base.GetStrokeState().GetMiterLimit(); } },
48     { ATTR_NAME_STROKE_DASH_OFFSET,
__anon67e2cfbc0a02() 49         [](RenderSvgBase& base) -> double { return base.GetStrokeState().GetLineDash().dashOffset; } },
__anon67e2cfbc0b02() 50     { ATTR_NAME_OPACITY, [](RenderSvgBase& base) -> double { return base.GetOpacity() * (1.0 / UINT8_MAX); } },
51 };
52 
53 const char SVG_TRANSFORM_ORIGIN_LEFT_BOTTOM[] = "left_bottom";
54 const char SVG_TRANSFORM_ORIGIN_LEFT_CENTER[] = "left_center";
55 const char SVG_TRANSFORM_ORIGIN_RIGHT_TOP[] = "right_top";
56 const char SVG_TRANSFORM_ORIGIN_RIGHT_CENTER[] = "right_center";
57 const char SVG_TRANSFORM_ORIGIN_RIGHT_BOTTOM[] = "right_bottom";
58 const char SVG_TRANSFORM_ORIGIN_CENTER_LEFT[] = "center_left";
59 const char SVG_TRANSFORM_ORIGIN_CENTER_RIGHT[] = "center_right";
60 const char SVG_TRANSFORM_ORIGIN_CENTER_CENTER[] = "center_center";
61 const char SVG_TRANSFORM_ORIGIN_CENTER_TOP[] = "center_top";
62 const char SVG_TRANSFORM_ORIGIN_CENTER_BOTTOM[] = "center_bottom";
63 const char SVG_TRANSFORM_ORIGIN_TOP_RIGHT[] = "top_right";
64 const char SVG_TRANSFORM_ORIGIN_TOP_CENTER[] = "top_center";
65 const char SVG_TRANSFORM_ORIGIN_BOTTOM_LEFT[] = "bottom_left";
66 const char SVG_TRANSFORM_ORIGIN_BOTTOM_CENTER[] = "bottom_center";
67 const char SVG_TRANSFORM_ORIGIN_BOTTOM_RIGHT[] = "bottom_right";
68 
69 } // namespace
70 
OpacityDoubleToUint8(double opacity)71 uint8_t OpacityDoubleToUint8(double opacity)
72 {
73     return static_cast<uint8_t>(round(opacity * UINT8_MAX));
74 }
75 
FindRootSvgNode(RefPtr<RenderNode> parent,WeakPtr<RenderSvgBase> & rootSvgNode)76 RefPtr<RenderSvg> FindRootSvgNode(RefPtr<RenderNode> parent, WeakPtr<RenderSvgBase>& rootSvgNode)
77 {
78     auto root = AceType::DynamicCast<RenderSvg>(rootSvgNode.Upgrade());
79     if (root != nullptr) {
80         return root;
81     }
82 
83     while (parent != nullptr) {
84         root = AceType::DynamicCast<RenderSvg>(parent);
85         if (root != nullptr && root->IsRoot()) {
86             rootSvgNode = root;
87             break;
88         }
89         parent = parent->GetParent().Upgrade();
90     }
91     return root;
92 }
93 
FindSvgViewBox(RefPtr<RenderNode> parent)94 Rect FindSvgViewBox(RefPtr<RenderNode> parent)
95 {
96     while (parent != nullptr) {
97         auto svg = AceType::DynamicCast<RenderSvg>(parent);
98         if (svg != nullptr) {
99             const auto& viewBox = svg->GetViewBox();
100             if (!NearZero(viewBox.Width()) && !NearZero(viewBox.Height())) {
101                 return viewBox;
102             }
103             if (svg->IsRoot()) {
104                 break;
105             }
106         }
107         parent = parent->GetParent().Upgrade();
108     }
109 
110     return Rect();
111 }
112 
~RenderSvgBase()113 RenderSvgBase::~RenderSvgBase()
114 {
115     std::unordered_map<std::string, RefPtr<Animator>>::iterator it;
116     for (it = animators_.begin(); it != animators_.end(); ++it) {
117         if (!it->second) {
118             LOGE("animator is null");
119             continue;
120         }
121         if (!it->second->IsStopped()) {
122             it->second->Stop();
123         }
124         it->second->ClearInterpolators();
125     }
126     animators_.clear();
127 }
128 
PaintDirectly(RenderContext & context,const Offset & offset)129 void RenderSvgBase::PaintDirectly(RenderContext& context, const Offset& offset)
130 {
131     for (const auto& item: GetChildren()) {
132         auto child = AceType::DynamicCast<RenderSvgBase>(item);
133         if (!child) {
134             // find svg base node from box node child
135             auto boxChild = item->GetFirstChild();
136             while (!child && boxChild) {
137                 child = AceType::DynamicCast<RenderSvgBase>(boxChild);
138                 boxChild = boxChild->GetFirstChild();
139             }
140         }
141         if (child) {
142             Offset current = offset;
143             if (!context.IsIntersectWith(child, current)) {
144                 continue;
145             }
146             // directly use matrix4 in PaintDirectly instead of streansform layer
147             child->PaintDirectly(context, current);
148             child->SetNeedRender(false);
149         }
150     }
151 }
152 
ConvertDimensionToPx(const Dimension & value,double baseValue)153 double RenderSvgBase::ConvertDimensionToPx(const Dimension& value, double baseValue)
154 {
155     if (value.Unit() == DimensionUnit::PERCENT) {
156         return value.Value() * baseValue;
157     } else if (value.Unit() == DimensionUnit::PX) {
158         return value.Value();
159     } else {
160         return NormalizeToPx(value);
161     }
162 }
163 
ConvertDimensionToPx(const Dimension & value,LengthType type,bool isRoot)164 double RenderSvgBase::ConvertDimensionToPx(const Dimension& value, LengthType type, bool isRoot)
165 {
166     switch (value.Unit()) {
167         case DimensionUnit::PERCENT: {
168             Size viewPort = (svgViewPort_.IsValid() && !isRoot) ? svgViewPort_ : GetLayoutSize();
169             if (type == LengthType::HORIZONTAL) {
170                 return value.Value() * viewPort.Width();
171             }
172             if (type == LengthType::VERTICAL) {
173                 return value.Value() * viewPort.Height();
174             }
175             if (type == LengthType::OTHER) {
176                 return value.Value() * sqrt(viewPort.Width() * viewPort.Height());
177             }
178             return 0.0;
179         }
180         case DimensionUnit::PX:
181             return value.Value();
182         default:
183             return NormalizeToPx(value);
184     }
185 }
186 
IsKeyWord(const std::string & value)187 static inline bool IsKeyWord(const std::string& value)
188 {
189     static const std::set<std::string> keyWords = {"left", "right", "top", "bottom", "center"};
190     return keyWords.find(value) != keyWords.end();
191 }
192 
IsValidHorizontalKeyWord(const std::string & value)193 static inline bool IsValidHorizontalKeyWord(const std::string& value)
194 {
195     static const std::set<std::string> keyWords = {"left", "right", "center"};
196     return keyWords.find(value) != keyWords.end();
197 }
198 
IsValidVerticalKeyWord(const std::string & value)199 static inline bool IsValidVerticalKeyWord(const std::string& value)
200 {
201     static const std::set<std::string> keyWords = {"top", "bottom", "center"};
202     return keyWords.find(value) != keyWords.end();
203 }
204 
FindInKeyWordsMap(const std::string & value)205 static std::pair<Dimension, Dimension> FindInKeyWordsMap(const std::string& value)
206 {
207     static const std::map<std::string, std::pair<Dimension, Dimension>> keyWordsMap = {
208         { SVG_TRANSFORM_ORIGIN_LEFT_BOTTOM, { 0.0_pct, 1.0_pct } },
209         { SVG_TRANSFORM_ORIGIN_LEFT_CENTER, { 0.0_pct, 0.5_pct } },
210         { SVG_TRANSFORM_ORIGIN_RIGHT_TOP, { 1.0_pct, 0.0_pct } },
211         { SVG_TRANSFORM_ORIGIN_RIGHT_CENTER, { 1.0_pct, 0.5_pct } },
212         { SVG_TRANSFORM_ORIGIN_RIGHT_BOTTOM, { 1.0_pct, 1.0_pct } },
213         { SVG_TRANSFORM_ORIGIN_CENTER_LEFT, { 0.0_pct, 0.5_pct } },
214         { SVG_TRANSFORM_ORIGIN_CENTER_RIGHT, { 1.0_pct, 0.5_pct } },
215         { SVG_TRANSFORM_ORIGIN_CENTER_CENTER, { 0.5_pct, 0.5_pct } },
216         { SVG_TRANSFORM_ORIGIN_CENTER_TOP, { 0.5_pct, 0.0_pct } },
217         { SVG_TRANSFORM_ORIGIN_CENTER_BOTTOM, { 0.5_pct, 1.0_pct } },
218         { SVG_TRANSFORM_ORIGIN_TOP_RIGHT, { 1.0_pct, 0.0_pct } },
219         { SVG_TRANSFORM_ORIGIN_TOP_CENTER, { 0.5_pct, 0.0_pct } },
220         { SVG_TRANSFORM_ORIGIN_BOTTOM_LEFT, { 0.0_pct, 1.0_pct } },
221         { SVG_TRANSFORM_ORIGIN_BOTTOM_CENTER, { 0.5_pct, 1.0_pct } },
222         { SVG_TRANSFORM_ORIGIN_BOTTOM_RIGHT, { 1.0_pct, 1.0_pct } }
223     };
224 
225     auto iter = keyWordsMap.find(value);
226     if (iter != keyWordsMap.end()) {
227         return iter->second;
228     } else {
229         return std::make_pair(Dimension(), Dimension());
230     }
231 }
232 
CreateTransformOrigin(const std::string & transformOrigin) const233 std::pair<Dimension, Dimension> RenderSvgBase::CreateTransformOrigin(const std::string& transformOrigin) const
234 {
235     static const std::map<std::string, Dimension> keyMap = {
236         {"left", 0.0_pct},
237         {"right", 1.0_pct},
238         {"center", 0.5_pct},
239         {"top", 0.0_pct},
240         {"bottom", 1.0_pct}
241     };
242     Dimension x;
243     Dimension y;
244     std::vector<std::string> values;
245     StringUtils::SplitStr(transformOrigin, " ", values);
246     if (values.size() == 2) {
247         if (IsKeyWord(values[0]) && IsKeyWord(values[1])) {
248             return FindInKeyWordsMap(values[0] + "_" + values[1]);
249         } else if (IsValidHorizontalKeyWord(values[0])) {
250             x = keyMap.at(values[0]);
251             y = StringUtils::StringToDimension(values[1]);
252         } else if (IsValidVerticalKeyWord(values[1])) {
253             x = StringUtils::StringToDimension(values[0]);
254             y = keyMap.at(values[1]);
255         } else {
256             x = StringUtils::StringToDimension(values[0]);
257             y = StringUtils::StringToDimension(values[1]);
258         }
259     } else if (values.size() == 1) {
260         if (IsValidHorizontalKeyWord(values[0])) {
261             x = keyMap.at(values[0]);
262             y = TRANSFORM_ORIGIN_DEFAULT;
263         } else if (IsValidVerticalKeyWord(values[0])) {
264             x = TRANSFORM_ORIGIN_DEFAULT;
265             y = keyMap.at(values[0]);
266         } else {
267             x = StringUtils::StringToDimension(values[0]);
268             y = TRANSFORM_ORIGIN_DEFAULT;
269         }
270     }
271     return std::make_pair(x, y);
272 }
273 
GetTransformOffset(bool isRoot)274 Offset RenderSvgBase::GetTransformOffset(bool isRoot)
275 {
276     double x = ConvertDimensionToPx(transformOrigin_.first, LengthType::HORIZONTAL, isRoot);
277     double y = ConvertDimensionToPx(transformOrigin_.second, LengthType::VERTICAL, isRoot);
278     return Offset(x, y) + GetTransitionGlobalOffset();
279 }
280 
SetPresentationAttrs(const RefPtr<SvgBaseDeclaration> & baseDeclaration)281 void RenderSvgBase::SetPresentationAttrs(const RefPtr<SvgBaseDeclaration>& baseDeclaration)
282 {
283     if (baseDeclaration) {
284         opacity_ = OpacityDoubleToUint8(baseDeclaration->GetOpacity());
285         fillState_ = baseDeclaration->GetFillState();
286         strokeState_ = baseDeclaration->GetStrokeState();
287         textStyle_ = baseDeclaration->GetSvgTextStyle();
288         transform_ = baseDeclaration->GetTransform();
289         if (IsSvgNode()) {
290             transformAttrs_ = SvgTransform::CreateMap(transform_);
291         }
292         transformOrigin_ = CreateTransformOrigin(baseDeclaration->GetTransformOrigin());
293         maskId_ = ParseIdFromUrl(baseDeclaration->GetMaskId());
294         filterId_ = ParseIdFromUrl(baseDeclaration->GetFilterId());
295         id_ = baseDeclaration->GetId();
296     }
297 }
298 
SetPresentationAttrs(const RefPtr<Component> & component,const RefPtr<SvgBaseDeclaration> & baseDeclaration)299 void RenderSvgBase::SetPresentationAttrs(
300     const RefPtr<Component>& component, const RefPtr<SvgBaseDeclaration>& baseDeclaration)
301 {
302     SetPresentationAttrs(baseDeclaration);
303     if (!id_.empty() && component) {
304         // href used by svg tag 'use'
305         AddComponentHrefToRoot(id_, component);
306         if (baseDeclaration) {
307             AddDeclarationHrefToRoot(id_, baseDeclaration);
308         }
309         return;
310     }
311 }
312 
PrepareTransformAnimation(const RefPtr<SvgAnimate> & svgAnimate,double originalValue)313 void RenderSvgBase::PrepareTransformAnimation(const RefPtr<SvgAnimate>& svgAnimate, double originalValue)
314 {
315     if (!svgAnimate->GetValues().empty()) {
316         PrepareTransformFrameAnimation(svgAnimate, originalValue);
317     } else {
318         PrepareTransformValueAnimation(svgAnimate, originalValue);
319     }
320 }
321 
PrepareTransformValueAnimation(const RefPtr<SvgAnimate> & svgAnimate,double originalValue)322 void RenderSvgBase::PrepareTransformValueAnimation(const RefPtr<SvgAnimate>& svgAnimate, double originalValue)
323 {
324     std::vector<float> fromVec;
325     std::vector<float> toVec;
326     std::string type;
327     if (!svgAnimate->GetValuesRange(fromVec, toVec, type)) {
328         LOGE("invalid animate info of type %{public}s", type.c_str());
329         return;
330     }
331 
332     std::function<void(double)> callback;
333     callback = [weak = AceType::WeakClaim(this), type, fromVec, toVec](double value) {
334         auto svgBase = weak.Upgrade();
335         if (!svgBase) {
336             LOGE("svgBase is null");
337             return;
338         }
339         if (!svgBase->SetTransformProperty(type, fromVec, toVec, value)) {
340             LOGE("no the property: %{public}s", type.c_str());
341             return;
342         }
343         svgBase->OnNotifyRender();
344     };
345     CreatePropertyAnimation(svgAnimate, originalValue, std::move(callback));
346 }
347 
PrepareTransformFrameAnimation(const RefPtr<SvgAnimate> & svgAnimate,double originalValue)348 void RenderSvgBase::PrepareTransformFrameAnimation(const RefPtr<SvgAnimate>& svgAnimate, double originalValue)
349 {
350     std::vector<std::vector<float>> frames;
351     std::string type;
352     if (!svgAnimate->GetFrames(frames, type)) {
353         LOGE("invalid animate keys info of type %{public}s", type.c_str());
354         return;
355     }
356     if (frames.size() <= 1) {
357         LOGE("invalid frames numbers %{public}s", type.c_str());
358         return;
359     }
360 
361     // set indices instead of frames
362     std::vector<std::string> indices;
363     uint32_t size = svgAnimate->GetValues().size();
364     for (uint32_t i = 0; i < size; i++) {
365         indices.emplace_back(std::to_string(i));
366     }
367     auto instance = AceType::MakeRefPtr<SvgAnimate>();
368     svgAnimate->Copy(instance);
369     instance->SetValues(indices);
370 
371     std::function<void(double)> callback;
372     callback = [weak = AceType::WeakClaim(this), type, frames](double value) {
373         auto svgBase = weak.Upgrade();
374         if (!svgBase) {
375             LOGE("svgBase is null");
376             return;
377         }
378         // use index and rate to locate frame and position
379         uint32_t index = (uint32_t)value;
380         double rate = value - index;
381         if (index >= frames.size() - 1) {
382             index = frames.size() - 2;
383             rate = 1.0;
384         }
385         if (!svgBase->SetTransformProperty(type, frames[index], frames[index + 1], rate)) {
386             LOGE("no the property: %{public}s", type.c_str());
387             return;
388         }
389         svgBase->OnNotifyRender();
390     };
391     CreatePropertyAnimation(instance, originalValue, std::move(callback));
392 }
393 
394 template<typename T>
PreparePresentationAnimation(const RefPtr<SvgAnimate> & svgAnimate,const T & originalValue)395 void RenderSvgBase::PreparePresentationAnimation(const RefPtr<SvgAnimate>& svgAnimate, const T& originalValue)
396 {
397     std::function<void(T)> callback;
398     callback = [weakRect = AceType::WeakClaim(this), attrName = svgAnimate->GetAttributeName()](T value) {
399         auto svgBase = weakRect.Upgrade();
400         if (!svgBase) {
401             LOGE("svgBase is null");
402             return;
403         }
404         if (!svgBase->SetPresentationProperty(attrName, value)) {
405             LOGE("no the property: %{public}s", attrName.c_str());
406             return;
407         }
408 
409         // notify render node to paint.
410         // if tspan has changed, should notify parent node of text or textpath.
411         svgBase->OnNotifyRender();
412 
413         if (svgBase->IsSvgNode()) {
414             svgBase->ChangeChildInheritValue(svgBase, attrName, value);
415         }
416     };
417     CreatePropertyAnimation(svgAnimate, originalValue, std::move(callback));
418 }
419 
420 template<typename T>
ChangeChildInheritValue(const RefPtr<RenderNode> & svgBase,const std::string & attrName,T value)421 void RenderSvgBase::ChangeChildInheritValue(const RefPtr<RenderNode>& svgBase, const std::string& attrName, T value)
422 {
423     if (!svgBase) {
424         LOGE("ChangeChildInheritValue failed, svgBase is null");
425         return;
426     }
427     auto renderChildren = svgBase->GetChildren();
428     for (const auto& item : renderChildren) {
429         if (!item->GetVisible()) {
430             continue;
431         }
432         auto child = AceType::DynamicCast<RenderSvgBase>(item);
433         if (child && !child->IsSelfValue(attrName) && !child->HasAnimator(attrName)) {
434             if (child->SetPresentationProperty(attrName, value, false)) {
435                 child->MarkNeedRender(true);
436             }
437         }
438         ChangeChildInheritValue(item, attrName, value);
439     }
440 }
441 
PrepareBaseAnimation(const RefPtr<SvgAnimate> & svgAnimate)442 bool RenderSvgBase::PrepareBaseAnimation(const RefPtr<SvgAnimate>& svgAnimate)
443 {
444     auto attrName = svgAnimate->GetAttributeName();
445     if (COLOR_PROPER_GETTERS.find(attrName) != COLOR_PROPER_GETTERS.end()) {
446         Color originalValue = COLOR_PROPER_GETTERS.find(attrName)->second(*this);
447         PreparePresentationAnimation(svgAnimate, originalValue);
448     } else if (DIMENSION_PROPER_GETTERS.find(attrName) != DIMENSION_PROPER_GETTERS.end()) {
449         Dimension originalValue = DIMENSION_PROPER_GETTERS.find(attrName)->second(*this);
450         PreparePresentationAnimation(svgAnimate, originalValue);
451     } else if (DOUBLE_PROPER_GETTERS.find(attrName) != DOUBLE_PROPER_GETTERS.end()) {
452         double originalValue = DOUBLE_PROPER_GETTERS.find(attrName)->second(*this);
453         PreparePresentationAnimation(svgAnimate, originalValue);
454     } else if (attrName.find(TRANSFORM) != std::string::npos) {
455         double originalValue = 0.0;
456         PrepareTransformAnimation(svgAnimate, originalValue);
457     } else {
458         return false;
459     }
460     return true;
461 }
462 
463 template<typename T>
CreatePropertyAnimation(const RefPtr<SvgAnimate> & svgAnimate,const T & originalValue,std::function<void (T)> && callback)464 bool RenderSvgBase::CreatePropertyAnimation(
465     const RefPtr<SvgAnimate>& svgAnimate, const T& originalValue, std::function<void(T)>&& callback)
466 {
467     if (!svgAnimate) {
468         LOGE("create property animation failed, svgAnimate is null");
469         return false;
470     }
471     auto animatorIter = animators_.find(svgAnimate->GetAttributeName());
472     if (animatorIter != animators_.end()) {
473         if (!animatorIter->second->IsStopped()) {
474             animatorIter->second->Stop();
475         }
476         animatorIter->second->ClearInterpolators();
477         auto animator = animatorIter->second;
478         if (!svgAnimate->CreatePropertyAnimate(std::move(callback), originalValue, animator)) {
479             animators_.erase(animatorIter);
480         }
481     } else {
482         auto animator = CREATE_ANIMATOR(context_);
483         if (svgAnimate->CreatePropertyAnimate(std::move(callback), originalValue, animator)) {
484             animators_.emplace(svgAnimate->GetAttributeName(), animator);
485         }
486     }
487     return true;
488 }
489 
PrepareAnimateMotion(const RefPtr<SvgAnimate> & svgAnimate)490 bool RenderSvgBase::PrepareAnimateMotion(const RefPtr<SvgAnimate>& svgAnimate)
491 {
492     if (!svgAnimate || svgAnimate->GetSvgAnimateType() != SvgAnimateType::MOTION) {
493         LOGE("create motion animation failed, svgAnimate is null");
494         return false;
495     }
496     std::function<void(double)> callback;
497     callback = [weak = AceType::WeakClaim(this), path = svgAnimate->GetPath(), rotate = svgAnimate->GetRotate()](
498                    double value) {
499         auto sharp = weak.Upgrade();
500         if (!sharp) {
501             LOGE("sharp is null");
502             return;
503         }
504         sharp->UpdateMotion(path, rotate, value);
505         sharp->MarkNeedRender(true);
506     };
507 
508     auto animatorIter = animators_.find(ANIMATOR_TYPE_MOTION);
509     if (animatorIter != animators_.end()) {
510         if (!animatorIter->second->IsStopped()) {
511             animatorIter->second->Stop();
512         }
513         animatorIter->second->ClearInterpolators();
514         auto animator = animatorIter->second;
515         if (!svgAnimate->CreateMotionAnimate(std::move(callback), animator)) {
516             animators_.erase(animatorIter);
517         }
518     } else {
519         auto animator = CREATE_ANIMATOR(context_);
520         if (svgAnimate->CreateMotionAnimate(std::move(callback), animator)) {
521             animators_.emplace(ANIMATOR_TYPE_MOTION, animator);
522         }
523     }
524     return true;
525 }
526 
PrepareWeightAnimate(const RefPtr<SvgAnimate> & svgAnimate,std::vector<std::string> & valueVector,const std::string & originalValue,bool & isBy)527 void RenderSvgBase::PrepareWeightAnimate(const RefPtr<SvgAnimate>& svgAnimate, std::vector<std::string>& valueVector,
528     const std::string& originalValue, bool& isBy)
529 {
530     if (!svgAnimate->GetValues().empty()) {
531         valueVector = svgAnimate->GetValues();
532         valueVector.insert(valueVector.begin(), originalValue);
533         std::vector<std::string> newValues;
534         uint32_t size = svgAnimate->GetValues().size();
535         for (uint32_t i = 0; i < size; i++) {
536             newValues.emplace_back(std::to_string(i));
537         }
538         svgAnimate->SetValues(newValues);
539     } else {
540         std::string from = svgAnimate->GetFrom().empty() ? originalValue : svgAnimate->GetFrom();
541         if (!svgAnimate->GetTo().empty()) {
542             valueVector.emplace_back(from);
543             valueVector.emplace_back(svgAnimate->GetTo());
544             svgAnimate->SetFrom(std::to_string(START_VALUE));
545             svgAnimate->SetTo(std::to_string(END_VALUE));
546         } else if (!svgAnimate->GetBy().empty()) {
547             valueVector.emplace_back(from);
548             valueVector.emplace_back(svgAnimate->GetBy());
549             svgAnimate->SetFrom(std::to_string(START_VALUE));
550             svgAnimate->SetTo(std::to_string(END_VALUE));
551             isBy = true;
552         } else {
553             if (from == originalValue) {
554                 return;
555             }
556             valueVector.emplace_back(originalValue);
557             valueVector.emplace_back(from);
558             svgAnimate->SetFrom(std::to_string(START_VALUE));
559             svgAnimate->SetTo(std::to_string(END_VALUE));
560         }
561     }
562 }
563 
564 template<typename T>
SetPresentationProperty(const std::string & attrName,const T & val,bool isSelf)565 bool RenderSvgBase::SetPresentationProperty(const std::string& attrName, const T& val, bool isSelf)
566 {
567     return false;
568 }
569 
570 template<>
SetPresentationProperty(const std::string & attrName,const Color & val,bool isSelf)571 bool RenderSvgBase::SetPresentationProperty(const std::string& attrName, const Color& val, bool isSelf)
572 {
573     if (attrName == ATTR_NAME_FILL) {
574         fillState_.SetColor(val, isSelf);
575     } else if (attrName == ATTR_NAME_STROKE) {
576         strokeState_.SetColor(val, isSelf);
577     } else {
578         return false;
579     }
580     return true;
581 }
582 
583 template<>
SetPresentationProperty(const std::string & attrName,const Dimension & val,bool isSelf)584 bool RenderSvgBase::SetPresentationProperty(const std::string& attrName, const Dimension& val, bool isSelf)
585 {
586     if (attrName == ATTR_NAME_STROKE_WIDTH) {
587         strokeState_.SetLineWidth(val, isSelf);
588     } else if (attrName == ATTR_NAME_FONT_SIZE) {
589         textStyle_.SetFontSize(val, isSelf);
590     } else {
591         return false;
592     }
593     return true;
594 }
595 
596 template<>
SetPresentationProperty(const std::string & attrName,const double & val,bool isSelf)597 bool RenderSvgBase::SetPresentationProperty(const std::string& attrName, const double& val, bool isSelf)
598 {
599     if (attrName == ATTR_NAME_FILL_OPACITY) {
600         fillState_.SetOpacity(val, isSelf);
601     } else if (attrName == ATTR_NAME_STROKE_OPACITY) {
602         strokeState_.SetOpacity(val, isSelf);
603     } else if (attrName == ATTR_NAME_LETTER_SPACING) {
604         textStyle_.SetLetterSpacing(Dimension(val), isSelf);
605     } else if (attrName == ATTR_NAME_MITER_LIMIT) {
606         strokeState_.SetMiterLimit(val, isSelf);
607     } else if (attrName == ATTR_NAME_STROKE_DASH_OFFSET) {
608         strokeState_.SetLineDashOffset(val, isSelf);
609     } else if (attrName == ATTR_NAME_OPACITY) {
610         opacity_ = static_cast<uint8_t>(round(val * UINT8_MAX));
611     } else {
612         return false;
613     }
614     return true;
615 }
616 
SetTransformProperty(const std::string & type,const std::vector<float> & from,const std::vector<float> & to,double value)617 bool RenderSvgBase::SetTransformProperty(
618     const std::string& type, const std::vector<float>& from, const std::vector<float>& to, double value)
619 {
620     return SvgTransform::SetProperty(type, from, to, value, animateTransformAttrs_);
621 }
622 
IsSelfValue(const std::string & attrName)623 bool RenderSvgBase::IsSelfValue(const std::string& attrName)
624 {
625     if (attrName == ATTR_NAME_FILL_OPACITY) {
626         return fillState_.HasOpacity();
627     } else if (attrName == ATTR_NAME_STROKE_OPACITY) {
628         return strokeState_.HasOpacity();
629     } else if (attrName == ATTR_NAME_LETTER_SPACING) {
630         return textStyle_.HasLetterSpacing();
631     } else if (attrName == ATTR_NAME_MITER_LIMIT) {
632         return strokeState_.HasMiterLimit();
633     } else if (attrName == ATTR_NAME_STROKE_DASH_OFFSET) {
634         return strokeState_.HasDashOffset();
635     } else if (attrName == ATTR_NAME_STROKE_WIDTH) {
636         return strokeState_.HasLineWidth();
637     } else if (attrName == ATTR_NAME_FONT_SIZE) {
638         return textStyle_.HasFontSize();
639     } else if (attrName == ATTR_NAME_FILL) {
640         return fillState_.HasColor();
641     } else if (attrName == ATTR_NAME_STROKE) {
642         return strokeState_.HasColor();
643     } else {
644         return true;
645     }
646 }
647 
HasAnimator(const std::string & attrName)648 bool RenderSvgBase::HasAnimator(const std::string& attrName)
649 {
650     return !animators_.empty() && animators_.find(attrName) != animators_.end();
651 }
652 
PrepareAnimation(const std::list<RefPtr<Component>> & componentChildren)653 void RenderSvgBase::PrepareAnimation(const std::list<RefPtr<Component>>& componentChildren)
654 {
655     for (const auto& childComponent : componentChildren) {
656         auto svgAnimate = AceType::DynamicCast<SvgAnimate>(childComponent);
657         if (!svgAnimate) {
658             LOGE("animateComponent is null");
659             continue;
660         }
661         if (!PrepareAnimateMotion(svgAnimate)) {
662             PreparePropertyAnimation(svgAnimate);
663         }
664     }
665 }
666 
AddComponentHrefToRoot(const std::string & id,const RefPtr<Component> & component)667 void RenderSvgBase::AddComponentHrefToRoot(const std::string& id, const RefPtr<Component>& component)
668 {
669     if (!id.empty() && component != nullptr) {
670         auto rootSvg = FindRootSvgNode(GetParent().Upgrade(), rootSvgNode_);
671         if (rootSvg != nullptr) {
672             rootSvg->AddHrefComponent(id, component);
673         }
674     }
675 }
676 
AddDeclarationHrefToRoot(const std::string & id,const RefPtr<SvgBaseDeclaration> & declaration)677 void RenderSvgBase::AddDeclarationHrefToRoot(const std::string& id, const RefPtr<SvgBaseDeclaration>& declaration)
678 {
679     if (!id.empty() && declaration != nullptr) {
680         auto rootSvg = FindRootSvgNode(GetParent().Upgrade(), rootSvgNode_);
681         if (rootSvg != nullptr) {
682             rootSvg->AddHrefDeclaration(id, declaration);
683         }
684     }
685 }
686 
AddHrefToRoot(const std::string & id,const RefPtr<RenderSvgBase> & node)687 void RenderSvgBase::AddHrefToRoot(const std::string& id, const RefPtr<RenderSvgBase>& node)
688 {
689     if (!id.empty() && node != nullptr) {
690         auto rootSvg = FindRootSvgNode(GetParent().Upgrade(), rootSvgNode_);
691         if (rootSvg != nullptr) {
692             rootSvg->AddHrefNode(id, node);
693         }
694     }
695 }
696 
AddMaskToRoot(const std::string & id,const RefPtr<RenderSvgBase> & mask)697 void RenderSvgBase::AddMaskToRoot(const std::string& id, const RefPtr<RenderSvgBase>& mask)
698 {
699     return AddHrefToRoot(id, mask);
700 }
701 
AddPatternToRoot(const std::string & id,const RefPtr<RenderSvgBase> & pattern)702 void RenderSvgBase::AddPatternToRoot(const std::string& id, const RefPtr<RenderSvgBase>& pattern)
703 {
704     return AddHrefToRoot(id, pattern);
705 }
706 
AddFilterToRoot(const std::string & id,const RefPtr<RenderSvgBase> & filter)707 void RenderSvgBase::AddFilterToRoot(const std::string& id, const RefPtr<RenderSvgBase>& filter)
708 {
709     return AddHrefToRoot(id, filter);
710 }
711 
GetComponentHrefFromRoot(const std::string & id)712 RefPtr<Component> RenderSvgBase::GetComponentHrefFromRoot(const std::string& id)
713 {
714     if (!id.empty()) {
715         auto rootSvg = FindRootSvgNode(GetParent().Upgrade(), rootSvgNode_);
716         if (rootSvg != nullptr) {
717             return rootSvg->GetHrefComponent(id);
718         }
719     }
720     return nullptr;
721 }
722 
GetDeclarationHrefFromRoot(const std::string & id)723 RefPtr<SvgBaseDeclaration> RenderSvgBase::GetDeclarationHrefFromRoot(const std::string& id)
724 {
725     if (!id.empty()) {
726         auto rootSvg = FindRootSvgNode(GetParent().Upgrade(), rootSvgNode_);
727         if (rootSvg != nullptr) {
728             return rootSvg->GetHrefDeclaration(id);
729         }
730     }
731     return nullptr;
732 }
733 
GetHrefFromRoot(const std::string & id)734 RefPtr<RenderSvgBase> RenderSvgBase::GetHrefFromRoot(const std::string& id)
735 {
736     if (!id.empty()) {
737         auto rootSvg = FindRootSvgNode(GetParent().Upgrade(), rootSvgNode_);
738         if (rootSvg != nullptr) {
739             return rootSvg->GetHrefNode(id);
740         }
741     }
742     return nullptr;
743 }
744 
GetMaskFromRoot(const std::string & id)745 RefPtr<RenderSvgBase> RenderSvgBase::GetMaskFromRoot(const std::string& id)
746 {
747     return GetHrefFromRoot(id);
748 }
749 
GetPatternFromRoot(const std::string & id)750 RefPtr<RenderSvgBase> RenderSvgBase::GetPatternFromRoot(const std::string& id)
751 {
752     return GetHrefFromRoot(id);
753 }
754 
GetFilterFromRoot(const std::string & id)755 RefPtr<RenderSvgBase> RenderSvgBase::GetFilterFromRoot(const std::string& id)
756 {
757     return GetHrefFromRoot(id);
758 }
759 
Inherit(const RefPtr<SvgBaseDeclaration> & parent,const RefPtr<SvgBaseDeclaration> & self)760 void RenderSvgBase::Inherit(const RefPtr<SvgBaseDeclaration>& parent, const RefPtr<SvgBaseDeclaration>& self)
761 {
762     if (!parent || !self) {
763         LOGD("parent or self declaration is null");
764         return;
765     }
766     if (!self->HasOpacity()) {
767         if (parent->HasOpacity()) {
768             opacity_ = OpacityDoubleToUint8(parent->GetOpacity());
769         }
770     }
771     fillState_.Inherit(parent->GetFillState());
772     strokeState_.Inherit(parent->GetStrokeState());
773     textStyle_.Inherit(parent->GetSvgTextStyle());
774     clipState_.Inherit(parent->GetClipState());
775 }
776 
GetViewBoxFromRoot()777 const Rect RenderSvgBase::GetViewBoxFromRoot()
778 {
779     if (svgViewBox_ == std::nullopt) {
780         svgViewBox_ = FindSvgViewBox(GetParent().Upgrade());
781     }
782 
783     if (svgViewBox_ != std::nullopt) {
784         auto viewBox = svgViewBox_.value();
785         if (!NearZero(viewBox.Width()) && !NearZero(viewBox.Height())) {
786             return viewBox;
787         }
788     }
789 
790     // Use svg box bounds instead of view box when it is null.
791     return GetPaintRect();
792 }
793 
PaintMaskLayer(RenderContext & context,const Offset & svg,const Offset & current)794 void RenderSvgBase::PaintMaskLayer(RenderContext& context, const Offset& svg, const Offset& current)
795 {
796     if (!maskId_.empty()) {
797         RefPtr<RenderSvgMask> renderMask = AceType::DynamicCast<RenderSvgMask>(GetMaskFromRoot(maskId_));
798         if (renderMask != nullptr) {
799             renderMask->PaintMaskLayer(context, svg, renderMask->IsDefaultMaskUnits() ?
800                 GetPaintBounds(current) : GetViewBoxFromRoot());
801         }
802     }
803 }
804 
PaintMaskLayer(RenderContext & context,const Offset & svg,const Rect & bounds)805 void RenderSvgBase::PaintMaskLayer(RenderContext& context, const Offset& svg, const Rect& bounds)
806 {
807     if (!maskId_.empty()) {
808         RefPtr<RenderSvgMask> renderMask = AceType::DynamicCast<RenderSvgMask>(GetMaskFromRoot(maskId_));
809         if (renderMask != nullptr) {
810             renderMask->PaintMaskLayer(context, svg, renderMask->IsDefaultMaskUnits() ?
811                 bounds : GetViewBoxFromRoot());
812         }
813     }
814 }
815 
PreparePropertyAnimation(const RefPtr<SvgAnimate> & svgAnimate)816 bool RenderSvgBase::PreparePropertyAnimation(const RefPtr<SvgAnimate>& svgAnimate)
817 {
818     if (svgAnimate->GetSvgAnimateType() != SvgAnimateType::ANIMATE &&
819         svgAnimate->GetSvgAnimateType() != SvgAnimateType::TRANSFORM) {
820         return false;
821     }
822     if (!PrepareSelfAnimation(svgAnimate)) {
823         PrepareBaseAnimation(svgAnimate);
824     }
825     return true;
826 }
827 
GetRawTransformInfo()828 std::tuple<const Matrix4, float, float> RenderSvgBase::GetRawTransformInfo()
829 {
830     transformInfo_ = (!animateTransformAttrs_.empty()) ? SvgTransform::CreateInfoFromMap(animateTransformAttrs_)
831                                                        : SvgTransform::CreateInfoFromString(transform_);
832     float pivotX = 0.5;
833     float pivotY = 0.5;
834     if (transformInfo_->hasRotateCenter && GetLayoutSize().IsValid()) {
835         pivotX = transformInfo_->rotateCenter.GetX() / GetLayoutSize().Width();
836         pivotY = transformInfo_->rotateCenter.GetY() / GetLayoutSize().Height();
837     }
838     return {transformInfo_->matrix4, pivotX, pivotY};
839 }
840 
GetTransformMatrix4()841 const Matrix4 RenderSvgBase::GetTransformMatrix4()
842 {
843     transformInfo_ = (!animateTransformAttrs_.empty()) ? SvgTransform::CreateInfoFromMap(animateTransformAttrs_)
844                                                        : SvgTransform::CreateInfoFromString(transform_);
845     if (transformInfo_->hasRotateCenter) {
846         transformInfo_->matrix4 = RenderTransform::GetTransformByOffset(
847             transformInfo_->matrix4, transformInfo_->rotateCenter);
848     }
849     return RenderTransform::GetTransformByOffset(transformInfo_->matrix4, GetTransformOffset());
850 }
851 
GetTransformMatrix4Raw()852 const Matrix4 RenderSvgBase::GetTransformMatrix4Raw()
853 {
854     transformInfo_ = SvgTransform::CreateInfoFromString(transform_);
855     if (transformInfo_->hasRotateCenter) {
856         transformInfo_->matrix4 = RenderTransform::GetTransformByOffset(
857             transformInfo_->matrix4, transformInfo_->rotateCenter);
858     }
859     return transformInfo_->matrix4;
860 }
861 
UpdateTransformMatrix4()862 const Matrix4 RenderSvgBase::UpdateTransformMatrix4()
863 {
864     if (transformInfo_ != std::nullopt) {
865         return RenderTransform::GetTransformByOffset(transformInfo_->matrix4, GetTransformOffset());
866     } else {
867         return Matrix4::CreateIdentity();
868     }
869 }
870 
UpdateGradient(FillState & fillState)871 void RenderSvgBase::UpdateGradient(FillState& fillState)
872 {
873     auto& gradient = fillState.GetGradient();
874     if (!gradient) {
875         return;
876     }
877     auto bounds = GetPaintBounds(Offset());
878     auto width = bounds.Width();
879     auto height = bounds.Height();
880     if (gradient->GetType() == GradientType::LINEAR) {
881         const auto& linearGradient = gradient->GetLinearGradient();
882         auto gradientInfo = LinearGradientInfo();
883         auto x1 = linearGradient.x1 ? ConvertDimensionToPx(linearGradient.x1.value(), width) : 0.0;
884         gradientInfo.x1 = x1 + bounds.Left();
885         auto y1 = linearGradient.y1 ? ConvertDimensionToPx(linearGradient.y1.value(), height) : 0.0;
886         gradientInfo.y1 = y1 + bounds.Top();
887         auto x2 = ConvertDimensionToPx((linearGradient.x2 ? linearGradient.x2.value() : 1.0_pct), width);
888         gradientInfo.x2 = x2 + bounds.Left();
889         auto y2 = linearGradient.y2 ? ConvertDimensionToPx(linearGradient.y2.value(), height) : 0.0;
890         gradientInfo.y2 = y2 + bounds.Top();
891         gradient->SetLinearGradientInfo(gradientInfo);
892     }
893     if (gradient->GetType() == GradientType::RADIAL) {
894         const auto& radialGradient = gradient->GetRadialGradient();
895         auto gradientInfo = RadialGradientInfo();
896         Dimension radialHorizontalSize = Dimension(
897             radialGradient.radialHorizontalSize.value().Value(), radialGradient.radialHorizontalSize.value().Unit());
898         gradientInfo.r =
899             ConvertDimensionToPx(radialGradient.radialHorizontalSize ? radialHorizontalSize :
900                 0.5_pct, sqrt(width * height));
901         Dimension radialCenterX = Dimension(
902             radialGradient.radialCenterX.value().Value(), radialGradient.radialCenterX.value().Unit());
903         gradientInfo.cx =
904             ConvertDimensionToPx(radialGradient.radialCenterX ? radialCenterX : 0.5_pct, width) + bounds.Left();
905         Dimension radialCenterY = Dimension(
906             radialGradient.radialCenterY.value().Value(), radialGradient.radialCenterY.value().Unit());
907         gradientInfo.cy =
908             ConvertDimensionToPx(radialGradient.radialCenterY ? radialCenterY : 0.5_pct, height) + bounds.Top();
909         if (radialGradient.fRadialCenterX && radialGradient.fRadialCenterX->IsValid()) {
910             gradientInfo.fx = ConvertDimensionToPx(radialGradient.fRadialCenterX.value(), width) + bounds.Left();
911         } else {
912             gradientInfo.fx = gradientInfo.cx;
913         }
914         if (radialGradient.fRadialCenterY && radialGradient.fRadialCenterY->IsValid()) {
915             gradientInfo.fy = ConvertDimensionToPx(radialGradient.fRadialCenterY.value(), height) + bounds.Top();
916         } else {
917             gradientInfo.fy = gradientInfo.cy;
918         }
919         gradient->SetRadialGradientInfo(gradientInfo);
920     }
921 }
922 
ParseIdFromUrl(const std::string & url)923 std::string RenderSvgBase::ParseIdFromUrl(const std::string& url)
924 {
925     if (url.size() > 6) {
926         std::string::size_type start = url.find("url(#");
927         if (start != std::string::npos) {
928             start += std::strlen("url(#");
929             std::string::size_type end = url.find_first_of(')', start);
930             if (end != std::string::npos) {
931                 return url.substr(start, end - start);
932             }
933         }
934     }
935     return "";
936 }
937 
938 template bool RenderSvgBase::CreatePropertyAnimation(
939     const RefPtr<SvgAnimate>& svgAnimate, const Color& originalValue, std::function<void(Color)>&& callback);
940 template bool RenderSvgBase::CreatePropertyAnimation(
941     const RefPtr<SvgAnimate>& svgAnimate, const Dimension& originalValue, std::function<void(Dimension)>&& callback);
942 template bool RenderSvgBase::CreatePropertyAnimation(
943     const RefPtr<SvgAnimate>& svgAnimate, const double& originalValue, std::function<void(double)>&& callback);
944 template void RenderSvgBase::PreparePresentationAnimation(const RefPtr<SvgAnimate>& svgAnimate, const Dimension& value);
945 template void RenderSvgBase::PreparePresentationAnimation(const RefPtr<SvgAnimate>& svgAnimate, const Color& value);
946 template void RenderSvgBase::PreparePresentationAnimation(const RefPtr<SvgAnimate>& svgAnimate, const double& value);
947 
948 } // namespace OHOS::Ace
949