• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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