1 /*
2 * Copyright (c) 2022 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_ng/svg/svg_dom.h"
17
18 #include "include/core/SkClipOp.h"
19
20 #include "base/utils/utils.h"
21 #include "core/components_ng/svg/parse/svg_fe_blend.h"
22 #include "core/components_ng/svg/parse/svg_fe_flood.h"
23 #include "core/components_ng/svg/svg_context.h"
24 #include "frameworks/core/components_ng/render/adapter/image_painter_utils.h"
25 #include "frameworks/core/components_ng/render/drawing.h"
26 #include "frameworks/core/components_ng/svg/parse/svg_animation.h"
27 #include "frameworks/core/components_ng/svg/parse/svg_circle.h"
28 #include "frameworks/core/components_ng/svg/parse/svg_clip_path.h"
29 #include "frameworks/core/components_ng/svg/parse/svg_defs.h"
30 #include "frameworks/core/components_ng/svg/parse/svg_ellipse.h"
31 #include "frameworks/core/components_ng/svg/parse/svg_fe_color_matrix.h"
32 #include "frameworks/core/components_ng/svg/parse/svg_fe_composite.h"
33 #include "frameworks/core/components_ng/svg/parse/svg_fe_gaussian_blur.h"
34 #include "frameworks/core/components_ng/svg/parse/svg_fe_offset.h"
35 #include "frameworks/core/components_ng/svg/parse/svg_filter.h"
36 #include "frameworks/core/components_ng/svg/parse/svg_g.h"
37 #include "frameworks/core/components_ng/svg/parse/svg_gradient.h"
38 #include "frameworks/core/components_ng/svg/parse/svg_image.h"
39 #include "frameworks/core/components_ng/svg/parse/svg_line.h"
40 #include "frameworks/core/components_ng/svg/parse/svg_mask.h"
41 #include "frameworks/core/components_ng/svg/parse/svg_path.h"
42 #include "frameworks/core/components_ng/svg/parse/svg_pattern.h"
43 #include "frameworks/core/components_ng/svg/parse/svg_polygon.h"
44 #include "frameworks/core/components_ng/svg/parse/svg_rect.h"
45 #include "frameworks/core/components_ng/svg/parse/svg_stop.h"
46 #include "frameworks/core/components_ng/svg/parse/svg_svg.h"
47 #include "frameworks/core/components_ng/svg/parse/svg_use.h"
48 #include "frameworks/core/components_ng/svg/svg_fit_convertor.h"
49 #include "frameworks/core/components_ng/svg/svg_ulils.h"
50
51 namespace OHOS::Ace::NG {
52 namespace {
53
54 const char DOM_SVG_STYLE[] = "style";
55 const char DOM_SVG_CLASS[] = "class";
56 } // namespace
57
58 static const LinearMapNode<RefPtr<SvgNode> (*)()> TAG_FACTORIES[] = {
__anonfe503baf0202() 59 { "animate", []() -> RefPtr<SvgNode> { return SvgAnimation::Create(); } },
__anonfe503baf0302() 60 { "animateMotion", []() -> RefPtr<SvgNode> { return SvgAnimation::CreateAnimateMotion(); } },
__anonfe503baf0402() 61 { "animateTransform", []() -> RefPtr<SvgNode> { return SvgAnimation::CreateAnimateTransform(); } },
__anonfe503baf0502() 62 { "circle", []() -> RefPtr<SvgNode> { return SvgCircle::Create(); } },
__anonfe503baf0602() 63 { "clipPath", []() -> RefPtr<SvgNode> { return SvgClipPath::Create(); } },
__anonfe503baf0702() 64 { "defs", []() -> RefPtr<SvgNode> { return SvgDefs::Create(); } },
__anonfe503baf0802() 65 { "ellipse", []() -> RefPtr<SvgNode> { return SvgEllipse::Create(); } },
__anonfe503baf0902() 66 { "feBlend", []() -> RefPtr<SvgNode> { return SvgFeBlend::Create(); } },
__anonfe503baf0a02() 67 { "feColorMatrix", []() -> RefPtr<SvgNode> { return SvgFeColorMatrix::Create(); } },
__anonfe503baf0b02() 68 { "feComposite", []() -> RefPtr<SvgNode> { return SvgFeComposite::Create(); } },
__anonfe503baf0c02() 69 { "feFlood", []() -> RefPtr<SvgNode> { return SvgFeFlood::Create(); } },
__anonfe503baf0d02() 70 { "feGaussianBlur", []() -> RefPtr<SvgNode> { return SvgFeGaussianBlur::Create(); } },
__anonfe503baf0e02() 71 { "feOffset", []() -> RefPtr<SvgNode> { return SvgFeOffset::Create(); } },
__anonfe503baf0f02() 72 { "filter", []() -> RefPtr<SvgNode> { return SvgFilter::Create(); } },
__anonfe503baf1002() 73 { "g", []() -> RefPtr<SvgNode> { return SvgG::Create(); } },
__anonfe503baf1102() 74 { "image", []() -> RefPtr<SvgNode> { return SvgImage::Create(); } },
__anonfe503baf1202() 75 { "line", []() -> RefPtr<SvgNode> { return SvgLine::Create(); } },
__anonfe503baf1302() 76 { "linearGradient", []() -> RefPtr<SvgNode> { return SvgGradient::CreateLinearGradient(); } },
__anonfe503baf1402() 77 { "mask", []() -> RefPtr<SvgNode> { return SvgMask::Create(); } },
__anonfe503baf1502() 78 { "path", []() -> RefPtr<SvgNode> { return SvgPath::Create(); } },
__anonfe503baf1602() 79 { "pattern", []() -> RefPtr<SvgNode> { return SvgPattern::Create(); } },
__anonfe503baf1702() 80 { "polygon", []() -> RefPtr<SvgNode> { return SvgPolygon::CreatePolygon(); } },
__anonfe503baf1802() 81 { "polyline", []() -> RefPtr<SvgNode> { return SvgPolygon::CreatePolyline(); } },
__anonfe503baf1902() 82 { "radialGradient", []() -> RefPtr<SvgNode> { return SvgGradient::CreateRadialGradient(); } },
__anonfe503baf1a02() 83 { "rect", []() -> RefPtr<SvgNode> { return SvgRect::Create(); } },
__anonfe503baf1b02() 84 { "stop", []() -> RefPtr<SvgNode> { return SvgStop::Create(); } },
__anonfe503baf1c02() 85 { "style", []() -> RefPtr<SvgNode> { return SvgStyle::Create(); } },
__anonfe503baf1d02() 86 { "svg", []() -> RefPtr<SvgNode> { return SvgSvg::Create(); } },
__anonfe503baf1e02() 87 { "use", []() -> RefPtr<SvgNode> { return SvgUse::Create(); } },
88 };
89
SvgDom()90 SvgDom::SvgDom()
91 {
92 svgContext_ = AceType::MakeRefPtr<SvgContext>();
93 attrCallback_ = [weakSvgDom = AceType::WeakClaim(this)](
94 const std::string& styleName, const std::pair<std::string, std::string>& attrPair) {
95 auto svgDom = weakSvgDom.Upgrade();
96 CHECK_NULL_VOID(svgDom);
97 if (svgDom->svgContext_) {
98 svgDom->svgContext_->PushStyle(styleName, attrPair);
99 }
100 };
101 }
102
~SvgDom()103 SvgDom::~SvgDom() {}
104
CreateSvgDom(SkStream & svgStream,const ImageSourceInfo & src)105 RefPtr<SvgDom> SvgDom::CreateSvgDom(SkStream& svgStream, const ImageSourceInfo& src)
106 {
107 RefPtr<SvgDom> svgDom = AceType::MakeRefPtr<SvgDom>();
108 svgDom->fillColor_ = src.GetFillColor();
109 svgDom->path_ = src.GetSrc();
110 bool ret = svgDom->ParseSvg(svgStream);
111 if (ret) {
112 return svgDom;
113 }
114 TAG_LOGW(AceLogTag::ACE_IMAGE, "CreateSvgDom Failed(Reason:Svg parse error).");
115 return nullptr;
116 }
117
ParseSvg(SkStream & svgStream)118 bool SvgDom::ParseSvg(SkStream& svgStream)
119 {
120 SkDOM xmlDom;
121 CHECK_NULL_RETURN(svgContext_, false);
122 if (!xmlDom.build(svgStream)) {
123 LOGE("Failed to parse xml file.");
124 return false;
125 }
126 root_ = TranslateSvgNode(xmlDom, xmlDom.getRootNode(), nullptr);
127 CHECK_NULL_RETURN(root_, false);
128 auto svg = AceType::DynamicCast<SvgSvg>(root_);
129 CHECK_NULL_RETURN(svg, false);
130 svgSize_ = svg->GetSize();
131 viewBox_ = svg->GetViewBox();
132 svgContext_->SetRootViewBox(viewBox_);
133 return true;
134 }
135
TranslateSvgNode(const SkDOM & dom,const SkDOM::Node * xmlNode,const RefPtr<SvgNode> & parent)136 RefPtr<SvgNode> SvgDom::TranslateSvgNode(const SkDOM& dom, const SkDOM::Node* xmlNode, const RefPtr<SvgNode>& parent)
137 {
138 const char* element = dom.getName(xmlNode);
139 if (dom.getType(xmlNode) == SkDOM::kText_Type) {
140 CHECK_NULL_RETURN(parent, nullptr);
141 if (AceType::InstanceOf<SvgStyle>(parent)) {
142 SvgStyle::ParseCssStyle(element, attrCallback_);
143 }
144 }
145
146 auto elementIter = BinarySearchFindIndex(TAG_FACTORIES, ArraySize(TAG_FACTORIES), element);
147 if (elementIter == -1) {
148 return nullptr;
149 }
150 RefPtr<SvgNode> node = TAG_FACTORIES[elementIter].value();
151 CHECK_NULL_RETURN(node, nullptr);
152 if (AceType::InstanceOf<SvgAnimation>(node)) {
153 isStatic_.store(false);
154 }
155 node->SetContext(svgContext_);
156 node->SetImagePath(path_);
157 ParseAttrs(dom, xmlNode, node);
158 for (auto* child = dom.getFirstChild(xmlNode, nullptr); child; child = dom.getNextSibling(child)) {
159 const auto& childNode = TranslateSvgNode(dom, child, node);
160 if (childNode) {
161 node->AppendChild(childNode);
162 }
163 }
164 return node;
165 }
166
ParseAttrs(const SkDOM & xmlDom,const SkDOM::Node * xmlNode,const RefPtr<SvgNode> & svgNode)167 void SvgDom::ParseAttrs(const SkDOM& xmlDom, const SkDOM::Node* xmlNode, const RefPtr<SvgNode>& svgNode)
168 {
169 const char* name = nullptr;
170 const char* value = nullptr;
171 SkDOM::AttrIter attrIter(xmlDom, xmlNode);
172 while ((name = attrIter.next(&value))) {
173 SetAttrValue(name, value, svgNode);
174 }
175 }
176
ParseIdAttr(const WeakPtr<SvgNode> & weakSvgNode,const std::string & value)177 void SvgDom::ParseIdAttr(const WeakPtr<SvgNode>& weakSvgNode, const std::string& value)
178 {
179 auto svgNode = weakSvgNode.Upgrade();
180 CHECK_NULL_VOID(svgNode);
181 svgNode->SetNodeId(value);
182 svgNode->SetAttr(DOM_ID, value);
183 svgContext_->Push(value, svgNode);
184 }
185
ParseFillAttr(const WeakPtr<SvgNode> & weakSvgNode,const std::string & value)186 void SvgDom::ParseFillAttr(const WeakPtr<SvgNode>& weakSvgNode, const std::string& value)
187 {
188 auto svgNode = weakSvgNode.Upgrade();
189 CHECK_NULL_VOID(svgNode);
190 if (fillColor_) {
191 std::stringstream stream;
192 stream << std::hex << fillColor_.value().GetValue();
193 std::string newValue(stream.str());
194 svgNode->SetAttr(DOM_SVG_FILL, "#" + newValue);
195 } else {
196 svgNode->SetAttr(DOM_SVG_FILL, value);
197 }
198 }
199
ParseClassAttr(const WeakPtr<SvgNode> & weakSvgNode,const std::string & value)200 void SvgDom::ParseClassAttr(const WeakPtr<SvgNode>& weakSvgNode, const std::string& value)
201 {
202 auto svgNode = weakSvgNode.Upgrade();
203 CHECK_NULL_VOID(svgNode);
204 std::vector<std::string> styleNameVector;
205 StringUtils::SplitStr(value, " ", styleNameVector);
206 for (const auto& styleName : styleNameVector) {
207 auto attrMap = svgContext_->GetAttrMap(styleName);
208 if (attrMap.empty()) {
209 continue;
210 }
211 for (const auto& attr : attrMap) {
212 svgNode->SetAttr(attr.first, attr.second);
213 }
214 }
215 }
216
ParseStyleAttr(const WeakPtr<SvgNode> & weakSvgNode,const std::string & value)217 void SvgDom::ParseStyleAttr(const WeakPtr<SvgNode>& weakSvgNode, const std::string& value)
218 {
219 auto svgNode = weakSvgNode.Upgrade();
220 CHECK_NULL_VOID(svgNode);
221 std::vector<std::string> attrPairVector;
222 StringUtils::SplitStr(value, ";", attrPairVector);
223 for (const auto& attrPair : attrPairVector) {
224 std::vector<std::string> attrVector;
225 StringUtils::SplitStr(attrPair, ":", attrVector);
226 if (attrVector.size() == 2) {
227 svgNode->SetAttr(attrVector[0], attrVector[1]);
228 }
229 }
230 }
231
SetAttrValue(const std::string & name,const std::string & value,const RefPtr<SvgNode> & svgNode)232 void SvgDom::SetAttrValue(const std::string& name, const std::string& value, const RefPtr<SvgNode>& svgNode)
233 {
234 static const LinearMapNode<void (*)(const std::string&, const WeakPtr<SvgNode>&, SvgDom&)> attrs[] = {
235 { DOM_SVG_CLASS, [](const std::string& val, const WeakPtr<SvgNode>& svgNode,
236 SvgDom& svgDom) { svgDom.ParseClassAttr(svgNode, val); } },
237 { DOM_SVG_FILL, [](const std::string& val, const WeakPtr<SvgNode>& svgNode,
238 SvgDom& svgDom) { svgDom.ParseFillAttr(svgNode, val); } },
239 { DOM_ID, [](const std::string& val, const WeakPtr<SvgNode>& svgNode,
240 SvgDom& svgDom) { svgDom.ParseIdAttr(svgNode, val); } },
241 { DOM_SVG_STYLE, [](const std::string& val, const WeakPtr<SvgNode>& svgNode,
242 SvgDom& svgDom) { svgDom.ParseStyleAttr(svgNode, val); } },
243 };
244 if (value.empty()) {
245 return;
246 }
247 auto attrIter = BinarySearchFindIndex(attrs, ArraySize(attrs), name.c_str());
248 if (attrIter != -1) {
249 attrs[attrIter].value(value, svgNode, *this);
250 return;
251 }
252 svgNode->SetAttr(name, value);
253 }
254
SetFuncNormalizeToPx(FuncNormalizeToPx && funcNormalizeToPx)255 void SvgDom::SetFuncNormalizeToPx(FuncNormalizeToPx&& funcNormalizeToPx)
256 {
257 CHECK_NULL_VOID(svgContext_);
258 svgContext_->SetFuncNormalizeToPx(funcNormalizeToPx);
259 }
260
SetAnimationCallback(FuncAnimateFlush && funcAnimateFlush,const WeakPtr<CanvasImage> & imagePtr)261 void SvgDom::SetAnimationCallback(FuncAnimateFlush&& funcAnimateFlush, const WeakPtr<CanvasImage>& imagePtr)
262 {
263 CHECK_NULL_VOID(svgContext_);
264 svgContext_->SetFuncAnimateFlush(std::move(funcAnimateFlush), imagePtr);
265 }
266
ControlAnimation(bool play)267 void SvgDom::ControlAnimation(bool play)
268 {
269 CHECK_NULL_VOID(svgContext_);
270 svgContext_->ControlAnimators(play);
271 }
272
IsStatic()273 bool SvgDom::IsStatic()
274 {
275 return isStatic_;
276 }
277
SetAnimationOnFinishCallback(const std::function<void ()> & onFinishCallback)278 void SvgDom::SetAnimationOnFinishCallback(const std::function<void()>& onFinishCallback)
279 {
280 CHECK_NULL_VOID(svgContext_);
281 svgContext_->SetOnAnimationFinished(onFinishCallback);
282 }
283
GetDumpInfo()284 std::string SvgDom::GetDumpInfo()
285 {
286 if (svgContext_) {
287 return svgContext_->GetDumpInfo().ToString();
288 }
289 return "";
290 }
291
InitStyles()292 void SvgDom::InitStyles()
293 {
294 CHECK_NULL_VOID(root_);
295 if (!isStyleInited_) {
296 isStyleInited_ = true;
297 root_->InitStyle(SvgBaseAttribute());
298 }
299 }
300
DrawImage(RSCanvas & canvas,const ImageFit & imageFit,const Size & layout)301 void SvgDom::DrawImage(
302 RSCanvas& canvas, const ImageFit& imageFit, const Size& layout)
303 {
304 if (!root_ || !svgContext_) {
305 TAG_LOGW(AceLogTag::ACE_IMAGE, "Svg DrawImage. root:%{public}d svgContext_:%{public}d",
306 !!root_, !!svgContext_);
307 return;
308 }
309 root_->SetIsRootNode(true);
310 InitStyles();
311 canvas.Save();
312 // viewBox scale and imageFit scale
313 FitImage(canvas, imageFit, layout);
314 FitViewPort(layout);
315 svgContext_->CreateDumpInfo(SvgDumpInfo(svgContext_->GetContentSize(),
316 svgContext_->GetCurrentTimeString()));
317 // draw svg tree
318 if (GreatNotEqual(smoothEdge_, 0.0f)) {
319 root_->SetSmoothEdge(smoothEdge_);
320 }
321 root_->SetColorFilter(colorFilter_);
322 root_->Draw(canvas, svgContext_->GetViewPort(), fillColor_);
323 canvas.Restore();
324 }
325
FitImage(RSCanvas & canvas,const ImageFit & imageFit,const Size & layout)326 void SvgDom::FitImage(RSCanvas& canvas, const ImageFit& imageFit, const Size& layout)
327 {
328 // scale svg to layout_ with ImageFit applied
329 if (!layout.IsEmpty()) {
330 layout_ = layout;
331 }
332 RSRect clipRect(0.0f, 0.0f, layout_.Width(), layout_.Height());
333 if (radius_) {
334 ImagePainterUtils::ClipRRect(canvas, clipRect, *radius_);
335 } else {
336 canvas.ClipRect(clipRect, RSClipOp::INTERSECT);
337 }
338 if (!layout_.IsEmpty()) {
339 Size svgContentSize;
340 SvgUtils::CalculateSvgConentSize(svgContentSize, layout_, svgSize_, viewBox_);
341 SvgFitConvertor::ApplyFit(imageFit, canvas, layout_, svgContentSize);
342 if (svgContext_) {
343 svgContext_->SetContentSize(svgContentSize);
344 }
345 }
346 }
347
FitViewPort(const Size & layout)348 void SvgDom::FitViewPort(const Size& layout)
349 {
350 // 设置svg内置视口,用于路径遍历
351 auto viewPort = (svgSize_.IsValid() && !svgSize_.IsInfinite()) ? svgSize_ : layout;
352 if (svgContext_) {
353 svgContext_->SetViewPort(viewPort);
354 }
355 }
356
GetContainerSize() const357 SizeF SvgDom::GetContainerSize() const
358 {
359 return { static_cast<float>(svgSize_.Width()), static_cast<float>(svgSize_.Height()) };
360 }
361
SetFillColor(const std::optional<Color> & color)362 void SvgDom::SetFillColor(const std::optional<Color>& color)
363 {
364 fillColor_ = color;
365 }
366
SetSmoothEdge(float value)367 void SvgDom::SetSmoothEdge(float value)
368 {
369 smoothEdge_ = value;
370 }
371
SetColorFilter(const std::optional<ImageColorFilter> & colorFilter)372 void SvgDom::SetColorFilter(const std::optional<ImageColorFilter>& colorFilter)
373 {
374 colorFilter_ = colorFilter;
375 }
376 } // namespace OHOS::Ace::NG
377