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