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 "core/components/svg/svg_transform.h"
17
18 #include "base/utils/string_utils.h"
19
20 namespace OHOS::Ace {
21 namespace {
22
23 const char TRANSFORM_MATRIX[] = "matrix";
24 const char TRANSFORM_ROTATE[] = "rotate";
25 const char TRANSFORM_SCALE[] = "scale";
26 const char TRANSFORM_SKEW[] = "skew";
27 const char TRANSFORM_SKEWX[] = "skewX";
28 const char TRANSFORM_SKEWY[] = "skewY";
29 const char TRANSFORM_TRANSLATE[] = "translate";
30
31 } // namespace
32
33 using namespace StringUtils;
34
ApplyRotationPivot(Matrix4 & mat,float x,float y)35 void SvgTransform::ApplyRotationPivot(Matrix4& mat, float x, float y)
36 {
37 // translate matrix to offset rotation center
38 // effect = translate(pivot) -> rotate(angle) -> translate(-pivot)
39 mat = Matrix4::CreateTranslate(x, y, 0) * mat * Matrix4::CreateTranslate(-x, -y, 0);
40 }
41
CreateMatrix4(const std::string & transform)42 Matrix4 SvgTransform::CreateMatrix4(const std::string& transform)
43 {
44 auto retMat = Matrix4::CreateIdentity();
45 std::vector<std::string> attrs;
46 SplitStr(transform, ")", attrs);
47 for (auto& attr : attrs) {
48 std::string type = attr.substr(0, attr.find_first_of("("));
49 std::string values = attr.substr(attr.find_first_of("(") + 1);
50 std::vector<std::string> numVec;
51 std::string tag = (values.find(",") != std::string::npos) ? "," : " ";
52 SplitStr(values, tag, numVec);
53 if (numVec.empty()) {
54 continue;
55 }
56
57 Matrix4 mat = Matrix4::CreateIdentity();
58 TrimStr(attr);
59 if (type == TRANSFORM_TRANSLATE) {
60 if (numVec.size() == 1) {
61 mat = Matrix4::CreateTranslate(StringToFloat(numVec[0].c_str()), 0, 0);
62 } else {
63 mat = Matrix4::CreateTranslate(StringToFloat(numVec[0].c_str()), StringToFloat(numVec[1].c_str()), 0);
64 }
65 } else if (type == TRANSFORM_SCALE) {
66 if (numVec.size() == 1) {
67 mat = Matrix4::CreateScale(StringToFloat(numVec[0].c_str()), StringToFloat(numVec[0].c_str()), 1);
68 } else {
69 mat = Matrix4::CreateScale(StringToFloat(numVec[0].c_str()), StringToFloat(numVec[1].c_str()), 1);
70 }
71 } else if (type == TRANSFORM_ROTATE) {
72 mat = Matrix4::CreateRotate(StringToFloat(numVec[0].c_str()), 0, 0, 1);
73 if (numVec.size() >= 3) {
74 ApplyRotationPivot(mat, StringToFloat(numVec[1]), StringToFloat(numVec[2]));
75 }
76 } else if (type == TRANSFORM_SKEWX) {
77 mat = Matrix4::CreateSkew(StringToFloat(numVec[0].c_str()), 0);
78 } else if (type == TRANSFORM_SKEWY) {
79 mat = Matrix4::CreateSkew(0, StringToFloat(numVec[0].c_str()));
80 } else if (type == TRANSFORM_MATRIX && numVec.size() == 6) {
81 mat = Matrix4::CreateMatrix2D(StringToFloat(numVec[0].c_str()), StringToFloat(numVec[1].c_str()),
82 StringToFloat(numVec[2].c_str()), StringToFloat(numVec[3].c_str()),
83 StringToFloat(numVec[4].c_str()), StringToFloat(numVec[5].c_str()));
84 } else {
85 continue;
86 }
87 retMat = retMat * mat;
88 }
89 return retMat;
90 }
91
CreateInfoFromString(const std::string & transform)92 TransformInfo SvgTransform::CreateInfoFromString(const std::string& transform)
93 {
94 TransformInfo transformInfo;
95 transformInfo.matrix4 = CreateMatrix4(transform);
96 return transformInfo;
97 }
98
CreateMatrixFromMap(const std::map<std::string,std::vector<float>> & transform)99 Matrix4 SvgTransform::CreateMatrixFromMap(const std::map<std::string, std::vector<float>>& transform)
100 {
101 auto retMat = Matrix4::CreateIdentity();
102 auto mat = Matrix4::CreateIdentity();
103 for (auto& [type, values] : transform) {
104 if (values.empty()) {
105 continue;
106 }
107 if (type == TRANSFORM_TRANSLATE && values.size() >= 2) {
108 mat = Matrix4::CreateTranslate(values[0], values[1], 0);
109 } else if (type == TRANSFORM_SCALE && values.size() >= 2) {
110 mat = Matrix4::CreateScale(values[0], values[1], 1);
111 } else if (type == TRANSFORM_ROTATE) {
112 mat = Matrix4::CreateRotate(values[0], 0, 0, 1);
113 if (values.size() >= 3) {
114 ApplyRotationPivot(mat, values[1], values[2]);
115 }
116 } else if (type == TRANSFORM_SKEW && values.size() >= 2) {
117 mat = Matrix4::CreateSkew(values[0], values[1]);
118 } else {
119 continue;
120 }
121 retMat = retMat * mat;
122 }
123 return retMat;
124 }
125
CreateInfoFromMap(const std::map<std::string,std::vector<float>> & transform)126 TransformInfo SvgTransform::CreateInfoFromMap(const std::map<std::string, std::vector<float>>& transform)
127 {
128 TransformInfo transformInfo;
129 transformInfo.matrix4 = CreateMatrixFromMap(transform);
130 return transformInfo;
131 }
132
CreateMap(const std::string & transform)133 std::map<std::string, std::vector<float>> SvgTransform::CreateMap(const std::string& transform)
134 {
135 std::map<std::string, std::vector<float>> mapTrans;
136 std::vector<std::string> attrs;
137 SplitStr(transform, ")", attrs);
138 for (auto& attr : attrs) {
139 std::string type = attr.substr(0, attr.find_first_of("("));
140 std::string values = attr.substr(attr.find_first_of("(") + 1);
141 std::vector<std::string> numVec;
142 std::string tag = (values.find(",") != std::string::npos) ? "," : " ";
143 SplitStr(values, tag, numVec);
144 if (numVec.empty()) {
145 continue;
146 }
147 TrimStr(attr);
148 if (type == TRANSFORM_TRANSLATE) {
149 if (numVec.size() == 1) {
150 mapTrans[TRANSFORM_TRANSLATE] = { StringToFloat(numVec[0].c_str()), 0, 0 };
151 } else {
152 mapTrans[TRANSFORM_TRANSLATE] = {
153 StringToFloat(numVec[0].c_str()), StringToFloat(numVec[1].c_str()), 0
154 };
155 }
156 } else if (type == TRANSFORM_SCALE) {
157 if (numVec.size() == 1) {
158 mapTrans[TRANSFORM_SCALE] = { StringToFloat(numVec[0].c_str()), StringToFloat(numVec[0].c_str()), 1 };
159 } else {
160 mapTrans[TRANSFORM_SCALE] = { StringToFloat(numVec[0].c_str()), StringToFloat(numVec[1].c_str()), 1 };
161 }
162 } else if (type == TRANSFORM_ROTATE) {
163 if (numVec.size() == 1) {
164 mapTrans[TRANSFORM_ROTATE] = { StringToFloat(numVec[0].c_str())};
165 } else if (numVec.size() >= 3) {
166 mapTrans[TRANSFORM_ROTATE] = {
167 StringToFloat(numVec[0].c_str()), StringToFloat(numVec[1].c_str()), StringToFloat(numVec[2].c_str())
168 };
169 }
170 } else if (type == TRANSFORM_SKEWX) {
171 if (mapTrans.find(TRANSFORM_SKEW) != mapTrans.end()) {
172 mapTrans[TRANSFORM_SKEW][0] += StringToFloat(numVec[0].c_str());
173 continue;
174 }
175 mapTrans[TRANSFORM_SKEW] = { StringToFloat(numVec[0].c_str()), 0 };
176 } else if (type == TRANSFORM_SKEWY) {
177 if (mapTrans.find(TRANSFORM_SKEW) != mapTrans.end()) {
178 mapTrans[TRANSFORM_SKEW][1] += StringToFloat(numVec[0].c_str());
179 continue;
180 }
181 mapTrans[TRANSFORM_SKEW] = { 0, StringToFloat(numVec[0].c_str()) };
182 } else if (type == TRANSFORM_MATRIX && numVec.size() >= 6) {
183 mapTrans[TRANSFORM_MATRIX] = {
184 StringToFloat(numVec[0].c_str()), StringToFloat(numVec[1].c_str()), StringToFloat(numVec[2].c_str()),
185 StringToFloat(numVec[3].c_str()), StringToFloat(numVec[4].c_str()), StringToFloat(numVec[5].c_str())
186 };
187 }
188 }
189 return mapTrans;
190 }
191
SetProperty(const std::string & type,const std::vector<float> & from,const std::vector<float> & to,double value,std::map<std::string,std::vector<float>> & transformAttrs)192 bool SvgTransform::SetProperty(const std::string& type, const std::vector<float>& from, const std::vector<float>& to,
193 double value, std::map<std::string, std::vector<float>>& transformAttrs)
194 {
195 if ((type == TRANSFORM_SCALE || type == TRANSFORM_TRANSLATE) && from.size() >= 2 && to.size() >= 2) {
196 float x = from[0] + (to[0] - from[0]) * value;
197 float y = from[1] + (to[1] - from[1]) * value;
198 transformAttrs[type] = { x, y, 1};
199 } else if (type == TRANSFORM_ROTATE && from.size() >= 3 && to.size() >= 3) {
200 float rotate = from[0] + (to[0] - from[0]) * value;
201 float centerX = from[1] + (to[1] - from[1]) * value;
202 float centerY = from[2] + (to[2] - from[2]) * value;
203 transformAttrs[TRANSFORM_ROTATE] = { rotate, centerX, centerY};
204 } else if (type == TRANSFORM_SKEWX && from.size() >= 1 && to.size() >= 1) {
205 float skewX = from[0] + (to[0] - from[0]) * value;
206 if (transformAttrs.find(TRANSFORM_SKEW) != transformAttrs.end()) {
207 transformAttrs[TRANSFORM_SKEW][0] = skewX;
208 } else {
209 transformAttrs[TRANSFORM_SKEW] = { skewX, 0.0f};
210 }
211 } else if (type == TRANSFORM_SKEWY && from.size() >= 1 && to.size() >= 1) {
212 float skewY = from[0] + (to[0] - from[0]) * value;
213 if (transformAttrs.find(TRANSFORM_SKEW) != transformAttrs.end()) {
214 transformAttrs[TRANSFORM_SKEW][1] = skewY;
215 } else {
216 transformAttrs[TRANSFORM_SKEW] = { 0.0f, skewY };
217 }
218 } else {
219 return false;
220 }
221
222 return true;
223 }
224
AlignmentValues(const std::string & type,std::vector<float> & from,std::vector<float> & to)225 bool SvgTransform::AlignmentValues(const std::string& type, std::vector<float>& from, std::vector<float>& to)
226 {
227 auto fromSize = from.size();
228 auto toSize = to.size();
229 if (type == TRANSFORM_SCALE) {
230 if (fromSize == 0) {
231 from = { 0.0f, 0.0f };
232 } else if (fromSize == 1) {
233 from.push_back(from[0]);
234 }
235 if (toSize == 1) {
236 to.push_back(to[0]);
237 }
238 } else if (type == TRANSFORM_SKEWX || type == TRANSFORM_SKEWY) {
239 if (fromSize == 0) {
240 from = { 0.0f };
241 }
242 } else if (type == TRANSFORM_TRANSLATE) {
243 if (fromSize == 0) {
244 from = { 0.0f, 0.0f };
245 } else if (fromSize == 1) {
246 from.push_back(0.0f);
247 }
248 if (toSize == 1) {
249 to.push_back(0.0f);
250 }
251 } else if (type == TRANSFORM_ROTATE) {
252 if (fromSize == 0) {
253 from = { 0.0f, 0.0f, 0.0f };
254 } else if (fromSize < 3) {
255 from = { from[0], 0.0f, 0.0f };
256 }
257 if (toSize < 3) {
258 to = { to[0], 0.0f, 0.0f };
259 }
260 } else {
261 return false;
262 }
263 return true;
264 }
265
AlignmentFrame(const std::string & type,std::vector<float> & frame)266 bool SvgTransform::AlignmentFrame(const std::string& type, std::vector<float>& frame)
267 {
268 auto size = frame.size();
269 if (size == 0) {
270 return false;
271 }
272
273 if (type == TRANSFORM_SCALE) {
274 if (size == 1) {
275 frame.push_back(frame[0]);
276 }
277 } else if (type == TRANSFORM_TRANSLATE) {
278 if (size == 1) {
279 frame.push_back(0.0f);
280 }
281 } else if (type == TRANSFORM_ROTATE) {
282 if (size < 3) {
283 frame = { frame[0], 0.0f, 0.0f };
284 }
285 } else if (type == TRANSFORM_SKEWX || type == TRANSFORM_SKEWY) {
286 } else {
287 return false;
288 }
289 return true;
290 }
291
292 } // namespace OHOS::Ace
293