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