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