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