1 /*
2 * Copyright (c) 2025 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 "base/utils/string_utils.h"
17 #include "base/utils/linear_map.h"
18 #include "core/components_ng/svg/parse/svg_node.h"
19 #include "core/components_ng/svg/parse/svg_transform.h"
20 #include "core/components_ng/svg/base/svg_length_scale_rule.h"
21
22 namespace OHOS::Ace::NG {
23 namespace {
24
25 const char TRANSFORM_MATRIX[] = "matrix";
26 const char TRANSFORM_ROTATE[] = "rotate";
27 const char TRANSFORM_SCALE[] = "scale";
28 const char TRANSFORM_SKEWX[] = "skewX";
29 const char TRANSFORM_SKEWY[] = "skewY";
30 const char TRANSFORM_TRANSLATE[] = "translate";
31 constexpr int32_t PARAM_COUNT1 = 1;
32 constexpr int32_t PARAM_COUNT2 = 2;
33 constexpr int32_t PARAM_COUNT3 = 3;
34 constexpr int32_t TRANSFORM_MATRIX_PARA_AMOUNT = 6;
35 constexpr int32_t NUM0 = 0;
36 constexpr int32_t NUM1 = 1;
37 constexpr int32_t NUM2 = 2;
38 constexpr int32_t NUM3 = 3;
39 constexpr int32_t NUM4 = 4;
40 constexpr int32_t NUM5 = 5;
41 } // namespace
42
43 using namespace StringUtils;
44
ApplyTransformPivot(const std::string & funcType,const Offset & finalPivot,Matrix4 & matrix)45 void NGSvgTransform::ApplyTransformPivot(const std::string& funcType, const Offset& finalPivot, Matrix4& matrix)
46 {
47 /* move to final pivot to transform.
48 effect = translate(finalPivot) -> transform -> translate(-finalPivot) */
49 double x = finalPivot.GetX();
50 double y = finalPivot.GetY();
51 matrix = Matrix4::CreateTranslate(x, y, 0) * matrix * Matrix4::CreateTranslate(-x, -y, 0);
52 }
53
ObjectBoundingBoxTransform(double srcLength,const SvgLengthScaleRule & rule,SvgLengthType lengthType)54 double NGSvgTransform::ObjectBoundingBoxTransform(double srcLength, const SvgLengthScaleRule& rule,
55 SvgLengthType lengthType)
56 {
57 double length = 0;
58 switch (lengthType) {
59 case SvgLengthType::HORIZONTAL:
60 length = (rule.GetLengthScaleUnit() == SvgLengthScaleUnit::USER_SPACE_ON_USE) ?
61 srcLength :
62 srcLength * rule.GetContainerRect().Width();
63 break;
64 case SvgLengthType::VERTICAL:
65 length = (rule.GetLengthScaleUnit() == SvgLengthScaleUnit::USER_SPACE_ON_USE) ?
66 srcLength :
67 srcLength * rule.GetContainerRect().Height();
68 break;
69 default:
70 break;
71 }
72 return length;
73 }
74
CreateFromTranslate(const std::vector<std::string> & paramVec,Matrix4 & matrix,const SvgLengthScaleRule & lengthRule)75 bool CreateFromTranslate(const std::vector<std::string>& paramVec, Matrix4& matrix,
76 const SvgLengthScaleRule& lengthRule)
77 {
78 double tx = 0.0f;
79 double ty = 0.0f;
80 if (paramVec.size() == PARAM_COUNT1) {
81 tx = StringToDouble(paramVec[NUM0]);
82 } else if (paramVec.size() == PARAM_COUNT2) {
83 tx = StringToDouble(paramVec[NUM0]);
84 ty = StringToDouble(paramVec[NUM1]);
85 } else {
86 return false;
87 }
88 auto x = NGSvgTransform::ObjectBoundingBoxTransform(tx, lengthRule, SvgLengthType::HORIZONTAL);
89 auto y = NGSvgTransform::ObjectBoundingBoxTransform(ty, lengthRule, SvgLengthType::VERTICAL);
90 matrix = Matrix4::CreateTranslate(x, y, 0);
91 return true;
92 }
93
CreateFromScale(const std::vector<std::string> & paramVec,Matrix4 & matrix,const SvgLengthScaleRule & lengthRule)94 bool CreateFromScale(const std::vector<std::string>& paramVec, Matrix4& matrix,
95 const SvgLengthScaleRule& lengthRule)
96 {
97 double sx = 0.0f;
98 double sy = 0.0f;
99 if (paramVec.size() == PARAM_COUNT1) {
100 sx = StringToDouble(paramVec[NUM0]);
101 sy = sx;
102 } else if (paramVec.size() == PARAM_COUNT2) {
103 sx = StringToDouble(paramVec[NUM0]);
104 sy = StringToDouble(paramVec[NUM1]);
105 } else {
106 return false;
107 }
108 auto scaleX = NGSvgTransform::ObjectBoundingBoxTransform(sx, lengthRule, SvgLengthType::HORIZONTAL);
109 auto scaleY = NGSvgTransform::ObjectBoundingBoxTransform(sy, lengthRule, SvgLengthType::VERTICAL);
110 matrix = Matrix4::CreateScale(scaleX, scaleY, 1);
111 return true;
112 }
113
CreateFromRotate(const std::vector<std::string> & paramVec,Matrix4 & matrix,const SvgLengthScaleRule & lengthRule)114 bool CreateFromRotate(const std::vector<std::string>& paramVec, Matrix4& matrix,
115 const SvgLengthScaleRule& lengthRule)
116 {
117 if ((paramVec.size() != PARAM_COUNT1) && (paramVec.size() != PARAM_COUNT3)) {
118 return false;
119 }
120 double rotateAngle = StringToDouble(paramVec[NUM0]);
121 matrix = Matrix4::CreateRotate(rotateAngle, 0, 0, 1);
122 return true;
123 }
124
CreateFromSkewx(const std::vector<std::string> & paramVec,Matrix4 & matrix,const SvgLengthScaleRule & lengthRule)125 bool CreateFromSkewx(const std::vector<std::string>& paramVec, Matrix4& matrix,
126 const SvgLengthScaleRule& lengthRule)
127 {
128 if (paramVec.size() != PARAM_COUNT1) {
129 return false;
130 }
131 double skewAngleAxisX = StringToDouble(paramVec[NUM0]);
132 double skewAngleAxisY = 0.0f;
133 matrix = Matrix4::CreateSkew(skewAngleAxisX, skewAngleAxisY);
134 return true;
135 }
136
CreateFromSkewy(const std::vector<std::string> & paramVec,Matrix4 & matrix,const SvgLengthScaleRule & lengthRule)137 bool CreateFromSkewy(const std::vector<std::string>& paramVec, Matrix4& matrix,
138 const SvgLengthScaleRule& lengthRule)
139 {
140 if (paramVec.size() != PARAM_COUNT1) {
141 return false;
142 }
143 double skewAngleAxisX = 0.0f;
144 double skewAngleAxisY = StringToDouble(paramVec[NUM0]);
145 matrix = Matrix4::CreateSkew(skewAngleAxisX, skewAngleAxisY);
146 return true;
147 }
148
CreateFromMatrix(const std::vector<std::string> & paramVec,Matrix4 & matrix,const SvgLengthScaleRule & lengthRule)149 bool CreateFromMatrix(const std::vector<std::string>& paramVec, Matrix4& matrix,
150 const SvgLengthScaleRule& lengthRule)
151 {
152 if (paramVec.size() != TRANSFORM_MATRIX_PARA_AMOUNT) {
153 return false;
154 }
155 double a = StringToDouble(paramVec[NUM0]);
156 double b = StringToDouble(paramVec[NUM1]);
157 double c = StringToDouble(paramVec[NUM2]);
158 double d = StringToDouble(paramVec[NUM3]);
159 double e = StringToDouble(paramVec[NUM4]);
160 double f = StringToDouble(paramVec[NUM5]);
161 matrix = Matrix4::CreateMatrix2D(a, b, c, d, e, f);
162 return true;
163 }
164
165 using TransformMatrixCreator = bool (*)(const std::vector<std::string>& paramVec, Matrix4& matrix,
166 const SvgLengthScaleRule& lengthRule);
167
UpdateSingleTransform(const std::string & funcType,const std::vector<std::string> & paramVec,Matrix4 & matrix,const SvgLengthScaleRule & lengthRule)168 bool NGSvgTransform::UpdateSingleTransform(
169 const std::string& funcType, const std::vector<std::string>& paramVec, Matrix4& matrix,
170 const SvgLengthScaleRule& lengthRule)
171 {
172 static const LinearMapNode<TransformMatrixCreator> matrix4Creator[] = {
173 { TRANSFORM_MATRIX, CreateFromMatrix },
174 { TRANSFORM_ROTATE, CreateFromRotate },
175 { TRANSFORM_SCALE, CreateFromScale },
176 { TRANSFORM_SKEWX, CreateFromSkewx },
177 { TRANSFORM_SKEWY, CreateFromSkewy },
178 { TRANSFORM_TRANSLATE, CreateFromTranslate },
179 };
180 int64_t index = BinarySearchFindIndex(matrix4Creator, ArraySize(matrix4Creator), funcType.c_str());
181 if (index < 0) {
182 return false;
183 }
184 return matrix4Creator[index].value(paramVec, matrix, lengthRule);
185 }
186
UpdateTransformPivot(const std::string & funcType,const std::vector<std::string> & paramVec,Offset & finalPivot)187 void UpdateTransformPivot(const std::string& funcType, const std::vector<std::string>& paramVec, Offset& finalPivot)
188 {
189 if ((funcType == TRANSFORM_ROTATE) && (paramVec.size() == PARAM_COUNT3)) {
190 Offset localPivot = Offset(StringToDouble(paramVec[NUM1]), StringToDouble(paramVec[NUM2]));
191 finalPivot += localPivot;
192 }
193 }
194
CreateMatrix4(const std::vector<NG::TransformInfo> & transformVec,const Offset & globalPivot,const SvgLengthScaleRule & lengthRule)195 Matrix4 NGSvgTransform::CreateMatrix4(const std::vector<NG::TransformInfo>& transformVec, const Offset& globalPivot,
196 const SvgLengthScaleRule& lengthRule)
197 {
198 Matrix4 retMatrix;
199 for (auto& attr : transformVec) {
200 Matrix4 funcMatrix;
201 Offset finalPivot = globalPivot;
202 bool isUpdated = UpdateSingleTransform(attr.funcType, attr.paramVec, funcMatrix, lengthRule);
203 if (!isUpdated) {
204 TAG_LOGW(AceLogTag::ACE_IMAGE, "CreateMatrix4 failed. funcType:[%{public}s], param cnt:%{public}zu",
205 attr.funcType.c_str(), attr.paramVec.size());
206 return Matrix4();
207 }
208 UpdateTransformPivot(attr.funcType, attr.paramVec, finalPivot);
209 ApplyTransformPivot(attr.funcType, finalPivot, funcMatrix);
210 retMatrix = retMatrix * funcMatrix;
211 }
212 return retMatrix;
213 }
214
CreateTranslate(const std::vector<std::string> & paramVec,RSMatrix & matrix)215 bool NGSvgTransform::CreateTranslate(const std::vector<std::string>& paramVec, RSMatrix& matrix)
216 {
217 if (paramVec.size() > PARAM_COUNT2 || paramVec.size() == 0) {
218 return false;
219 }
220 double tx = 0.0f;
221 double ty = 0.0f;
222 tx = StringToDouble(paramVec[NUM0]);
223 if (paramVec.size() > PARAM_COUNT1) {
224 ty = StringToDouble(paramVec[NUM1]);
225 }
226 matrix.Translate(tx, ty);
227 return true;
228 }
229 } // namespace OHOS::Ace::NG