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