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