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