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.h"
17
18 #include "frameworks/core/components/display/render_display.h"
19 #include "frameworks/core/components/transform/render_transform.h"
20
21 namespace OHOS::Ace {
22
23 namespace {
24
25 const char TRANSFORM_ROTATE[] = "rotate";
26 const char TRANSFORM_SCALE[] = "scale";
27 const char TRANSFORM_SKEW[] = "skew";
28 const char TRANSFORM_TRANSLATE[] = "translate";
29
30 } // namespace
31
~RenderSvg()32 RenderSvg::~RenderSvg()
33 {
34 svgAnimates_.clear();
35 }
36
Update(const RefPtr<Component> & component)37 void RenderSvg::Update(const RefPtr<Component>& component)
38 {
39 const RefPtr<SvgComponent> svgComponent = AceType::DynamicCast<SvgComponent>(component);
40 if (!svgComponent) {
41 LOGW("svg component is null");
42 return;
43 }
44 isSvgNode_ = true;
45 x_ = svgComponent->GetX();
46 y_ = svgComponent->GetY();
47 width_ = svgComponent->GetWidth();
48 height_ = svgComponent->GetHeight();
49 viewBox_ = svgComponent->GetViewBox();
50 isRoot_ = svgComponent->IsRoot();
51 autoMirror_ = svgComponent->GetAutoMirror();
52 RenderSvgBase::SetPresentationAttrs(svgComponent->GetDeclaration());
53 AddSvgAnimations(svgComponent);
54 MarkNeedLayout();
55 }
56
AddSvgAnimations(const RefPtr<SvgComponent> & svgComponent)57 void RenderSvg::AddSvgAnimations(const RefPtr<SvgComponent>& svgComponent)
58 {
59 if (!svgComponent) {
60 LOGW("svg component is null");
61 return;
62 }
63 svgAnimates_.clear();
64 hasUpdated_ = true;
65 const auto& componentChildren = svgComponent->GetChildren();
66 for (const auto& childComponent : componentChildren) {
67 auto svgAnimateComponent = AceType::DynamicCast<SvgAnimate>(childComponent);
68 if (!svgAnimateComponent || svgAnimateComponent->GetSvgAnimateType() == SvgAnimateType::MOTION) {
69 continue;
70 }
71 auto svgAnimate = AceType::MakeRefPtr<SvgAnimate>();
72 svgAnimateComponent->Copy(svgAnimate);
73 svgAnimates_.emplace_back(svgAnimate);
74 }
75 }
76
PrepareAnimations()77 void RenderSvg::PrepareAnimations()
78 {
79 if (!hasUpdated_) {
80 return;
81 }
82 hasUpdated_ = false;
83 for (const auto& svgAnimate : svgAnimates_) {
84 RenderSvgBase::PreparePropertyAnimation(svgAnimate);
85 }
86 }
87
PrepareSelfAnimation(const RefPtr<SvgAnimate> & svgAnimate)88 bool RenderSvg::PrepareSelfAnimation(const RefPtr<SvgAnimate>& svgAnimate)
89 {
90 if (OpacityAnimation(svgAnimate)) {
91 return true;
92 }
93 Dimension originalValue;
94 if (!GetProperty(svgAnimate->GetAttributeName(), originalValue)) {
95 return false;
96 }
97 std::function<void(Dimension)> callback;
98 callback = [weak = AceType::WeakClaim(this), attrName = svgAnimate->GetAttributeName()](Dimension value) {
99 auto svg = weak.Upgrade();
100 if (!svg) {
101 LOGE("svg is null");
102 return;
103 }
104 bool ret = svg->SetProperty(attrName, value);
105 if (ret) {
106 svg->MarkNeedLayout(true);
107 }
108 };
109 CreatePropertyAnimation(svgAnimate, originalValue, std::move(callback));
110 return true;
111 }
112
OpacityAnimation(const RefPtr<SvgAnimate> & svgAnimate)113 bool RenderSvg::OpacityAnimation(const RefPtr<SvgAnimate>& svgAnimate)
114 {
115 if (svgAnimate->GetAttributeName() != ATTR_NAME_OPACITY) {
116 return false;
117 }
118 SetOpacityCallback();
119 if (opacityCallback_) {
120 double originalValue = opacity_ * (1.0 / UINT8_MAX);
121 CreatePropertyAnimation(svgAnimate, originalValue, std::move(opacityCallback_));
122 }
123 return true;
124 }
125
SetOpacityCallback()126 void RenderSvg::SetOpacityCallback()
127 {
128 int32_t nodeId = GetNodeId();
129 auto parent = GetParent().Upgrade();
130 while (parent) {
131 if (parent->GetNodeId() != nodeId) {
132 break;
133 }
134 auto displayRender = AceType::DynamicCast<RenderDisplay>(parent);
135 if (displayRender) {
136 opacityCallback_ = [weak = AceType::WeakClaim(AceType::RawPtr(displayRender))](double value) {
137 auto display = weak.Upgrade();
138 if (!display) {
139 LOGE("display is null");
140 return;
141 }
142 display->UpdateOpacity(static_cast<uint8_t>(round(value * UINT8_MAX)));
143 };
144 break;
145 }
146 parent = parent->GetParent().Upgrade();
147 }
148 }
149
SetProperty(const std::string & attrName,const Dimension & value)150 bool RenderSvg::SetProperty(const std::string& attrName, const Dimension& value)
151 {
152 if (attrName == ATTR_NAME_WIDTH) {
153 width_ = value;
154 } else if (attrName == ATTR_NAME_HEIGHT) {
155 height_ = value;
156 } else {
157 LOGE("invalid attrName");
158 return false;
159 }
160 return true;
161 }
162
GetProperty(const std::string & attrName,Dimension & dimension) const163 bool RenderSvg::GetProperty(const std::string& attrName, Dimension& dimension) const
164 {
165 if (attrName == ATTR_NAME_WIDTH) {
166 dimension = width_;
167 } else if (attrName == ATTR_NAME_HEIGHT) {
168 dimension = height_;
169 } else {
170 LOGE("invalid attrName");
171 return false;
172 }
173 return true;
174 }
175
PerformLayout()176 void RenderSvg::PerformLayout()
177 {
178 auto context = context_.Upgrade();
179 if (!context) {
180 LOGE("context is null");
181 return;
182 }
183 const auto& children = GetChildren();
184 LayoutParam layoutParam = GetLayoutParam();
185 Size layoutSize;
186 if (LessNotEqual(width_.Value(), 0.0)) {
187 if (layoutParam.GetMaxSize().IsWidthInfinite()) {
188 SetLayoutSize(Size(0.0, 0.0));
189 return;
190 }
191 layoutSize.SetWidth(layoutParam.GetMaxSize().Width());
192 } else {
193 if (isFixSize_) {
194 layoutSize.SetWidth(ConvertDimensionToPx(width_, LengthType::HORIZONTAL, isRoot_));
195 } else {
196 layoutSize.SetWidth(std::clamp(ConvertDimensionToPx(width_, LengthType::HORIZONTAL, isRoot_),
197 layoutParam.GetMinSize().Width(), layoutParam.GetMaxSize().Width()));
198 }
199 }
200 if (LessNotEqual(height_.Value(), 0.0)) {
201 if (layoutParam.GetMaxSize().IsHeightInfinite()) {
202 SetLayoutSize(Size(0.0, 0.0));
203 return;
204 }
205 layoutSize.SetHeight(layoutParam.GetMaxSize().Height());
206 } else {
207 if (isFixSize_) {
208 layoutSize.SetHeight(ConvertDimensionToPx(height_, LengthType::VERTICAL, isRoot_));
209 } else {
210 layoutSize.SetHeight(std::clamp(ConvertDimensionToPx(height_, LengthType::VERTICAL, isRoot_),
211 layoutParam.GetMinSize().Height(), layoutParam.GetMaxSize().Height()));
212 }
213 }
214 SetLayoutSize(layoutSize);
215 for (const auto& child : children) {
216 child->Layout(LayoutParam(layoutSize, Size()));
217 }
218 UpdateTransform();
219 PrepareAnimations();
220 }
221
UpdateTransform()222 void RenderSvg::UpdateTransform()
223 {
224 int32_t nodeId = GetNodeId();
225 RefPtr<RenderTransform> transform = nullptr;
226 auto parent = GetParent().Upgrade();
227 while (parent && parent->GetNodeId() == nodeId) {
228 transform = AceType::DynamicCast<RenderTransform>(parent);
229 if (transform) {
230 break;
231 }
232 parent = parent->GetParent().Upgrade();
233 }
234 if (!transform) {
235 return;
236 }
237 if (!isRoot_ && (GreatNotEqual(x_.Value(), 0.0) || GreatNotEqual(y_.Value(), 0.0))) {
238 transform->Translate(Dimension(ConvertDimensionToPx(x_, LengthType::VERTICAL)),
239 Dimension(ConvertDimensionToPx(y_, LengthType::VERTICAL)));
240 }
241 if (isRoot_ && !NearZero(rootRotate_)) {
242 transform->RotateZ(rootRotate_);
243 }
244 auto& transformAttr = (animateTransformAttrs_.empty()) ? transformAttrs_ : animateTransformAttrs_;
245 for (auto& [type, values] : transformAttr) {
246 if (type == TRANSFORM_TRANSLATE && values.size() >= 2) {
247 transform->Translate(Dimension(values[0]), Dimension(values[1]));
248 } else if (type == TRANSFORM_SCALE && values.size() >= 2) {
249 transform->Scale(values[0], values[1]);
250 } else if (type == TRANSFORM_ROTATE && values.size() >= 1) {
251 transform->RotateZ(values[0]);
252 } else if (type == TRANSFORM_SKEW && values.size() >= 2) {
253 transform->Skew(values[0], values[1]);
254 }
255 }
256
257 if (isRoot_ && autoMirror_) {
258 auto context = context_.Upgrade();
259 if (context && context->IsRightToLeft()) {
260 Offset center = GetGlobalOffset() + GetLayoutSize() * 0.5;
261 transform->Mirror(center, GetGlobalOffset());
262 }
263 }
264 }
265
266 } // namespace OHOS::Ace
267