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/parse/svg_use.h"
17 
18 #include "base/utils/utils.h"
19 #include "frameworks/core/components/declaration/svg/svg_declaration.h"
20 
21 namespace OHOS::Ace::NG {
22 namespace {
23 const char DOM_SVG_SRC_VIEW_BOX[] = "viewBox";
24 }
25 
SvgUse()26 SvgUse::SvgUse() : SvgGraphic() {}
27 
OnInitStyle()28 void SvgUse::OnInitStyle()
29 {
30     useOffsetX_ = useAttr_.x.Value();
31     useOffsetY_ = useAttr_.y.Value();
32 }
33 
Create()34 RefPtr<SvgNode> SvgUse::Create()
35 {
36     return AceType::MakeRefPtr<SvgUse>();
37 }
38 
AsPath(const Size & viewPort) const39 RSRecordingPath SvgUse::AsPath(const Size& viewPort) const
40 {
41     auto svgContext = svgContext_.Upgrade();
42     CHECK_NULL_RETURN(svgContext, RSRecordingPath());
43     if (attributes_.href.empty()) {
44         LOGE("href is empty");
45         return {};
46     }
47     auto refSvgNode = svgContext->GetSvgNodeById(attributes_.href);
48     CHECK_NULL_RETURN(refSvgNode, RSRecordingPath());
49 
50     AttributeScope scope(refSvgNode);
51     refSvgNode->InheritAttr(attributes_);
52     return refSvgNode->AsPath(viewPort);
53 }
54 
OnDraw(RSCanvas & canvas,const Size & layout,const std::optional<Color> & color)55 void SvgUse::OnDraw(RSCanvas& canvas, const Size& layout, const std::optional<Color>& color)
56 {
57     auto svgContext = svgContext_.Upgrade();
58     CHECK_NULL_VOID(svgContext);
59     if (attributes_.href.empty()) {
60         return;
61     }
62     auto refSvgNode = svgContext->GetSvgNodeById(attributes_.href);
63     CHECK_NULL_VOID(refSvgNode);
64     auto useX = useAttr_.x.Value();
65     if (useAttr_.x.Unit() == DimensionUnit::PERCENT) {
66         useX = useX * layout.Width();
67     }
68     auto useY = useAttr_.y.Value();
69     if (useAttr_.y.Unit() == DimensionUnit::PERCENT) {
70         useY = useY * layout.Height();
71     }
72     if (!NearEqual(useX, 0.0) || !NearEqual(useY, 0.0)) {
73         canvas.Translate(useX, useY);
74     }
75     AttributeScope scope(refSvgNode);
76     refSvgNode->InheritUseAttr(attributes_);
77 
78     refSvgNode->Draw(canvas, layout, color);
79 }
80 
ParseAndSetSpecializedAttr(const std::string & name,const std::string & value)81 bool SvgUse::ParseAndSetSpecializedAttr(const std::string& name, const std::string& value)
82 {
83     static const LinearMapNode<void (*)(const std::string&, SvgAttributes&)> SVG_ATTR_ARRAY[] = {
84         { DOM_SVG_MIRROR,
85             [](const std::string& val, SvgAttributes& attr) {
86                 attr.autoMirror = val == "true";
87             } },
88         { DOM_SVG_HEIGHT,
89             [](const std::string& val, SvgAttributes& attr) {
90                 attr.height = SvgAttributesParser::ParseDimension(val);
91             } },
92         { DOM_SVG_SRC_VIEW_BOX,
93             [](const std::string& val, SvgAttributes& attr) {
94                 if (val.empty()) {
95                     return;
96                 }
97                 std::vector<double> viewBox;
98                 StringUtils::StringSplitter(val, ' ', viewBox);
99                 if (viewBox.size() == 4) {
100                     attr.viewBox = Rect(viewBox[0], viewBox[1], viewBox[2], viewBox[3]);
101                 }
102             } },
103         { DOM_SVG_VIEW_BOX,
104             [](const std::string& val, SvgAttributes& attr) {
105                 if (val.empty()) {
106                     return;
107                 }
108                 std::vector<double> viewBox;
109                 StringUtils::StringSplitter(val, ' ', viewBox);
110                 if (viewBox.size() == 4) {
111                     attr.viewBox = Rect(viewBox[0], viewBox[1], viewBox[2], viewBox[3]);
112                 }
113             } },
114         { DOM_SVG_WIDTH,
115             [](const std::string& val, SvgAttributes& attr) {
116                 attr.width = SvgAttributesParser::ParseDimension(val);
117             } },
118         { DOM_SVG_X,
119             [](const std::string& val, SvgAttributes& attr) {
120                 attr.x = SvgAttributesParser::ParseDimension(val);
121             } },
122         { DOM_SVG_Y,
123             [](const std::string& val, SvgAttributes& attr) {
124                 attr.y = SvgAttributesParser::ParseDimension(val);
125             } },
126     };
127     auto attrIter = BinarySearchFindIndex(SVG_ATTR_ARRAY, ArraySize(SVG_ATTR_ARRAY), name.c_str());
128     if (attrIter != -1) {
129         SVG_ATTR_ARRAY[attrIter].value(value, useAttr_);
130         return true;
131     }
132     return false;
133 }
134 
AttributeScope(const RefPtr<SvgNode> & node)135 SvgUse::AttributeScope::AttributeScope(const RefPtr<SvgNode>& node) : node_(node)
136 {
137     auto nodeAttr = node->GetBaseAttributes();
138     attributes_ = nodeAttr;
139 }
140 
~AttributeScope()141 SvgUse::AttributeScope::~AttributeScope()
142 {
143     auto node = node_.Upgrade();
144     CHECK_NULL_VOID(node);
145     node->SetBaseAttributes(attributes_);
146 }
147 } // namespace OHOS::Ace::NG
148