1 /*
2 * Copyright (c) 2021-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 "core/components/common/properties/clip_path.h"
17
18 namespace OHOS::Ace {
19
SetLength(const std::vector<Dimension> & lengths)20 bool Inset::SetLength(const std::vector<Dimension>& lengths)
21 {
22 std::string::size_type size = lengths.size();
23 bool ret = true;
24 switch (size) {
25 case 1:
26 SetLength(lengths.at(0), lengths.at(0), lengths.at(0), lengths.at(0));
27 break;
28 case 2:
29 SetLength(lengths.at(0), lengths.at(1), lengths.at(0), lengths.at(1));
30 break;
31 case 3:
32 SetLength(lengths.at(0), lengths.at(1), lengths.at(2), lengths.at(1));
33 break;
34 case 4:
35 SetLength(lengths.at(0), lengths.at(1), lengths.at(2), lengths.at(3));
36 break;
37 default:
38 LOGE("invalid length value");
39 ret = false;
40 break;
41 }
42 return ret;
43 }
44
SetLength(const Dimension & top,const Dimension & right,const Dimension & bottom,const Dimension & left)45 void Inset::SetLength(const Dimension& top, const Dimension& right, const Dimension& bottom, const Dimension& left)
46 {
47 SetTop(top);
48 SetRight(right);
49 SetBottom(bottom);
50 SetLeft(left);
51 }
52
SetRadius(const std::vector<Dimension> & rounds,bool isX)53 void Inset::SetRadius(const std::vector<Dimension>& rounds, bool isX)
54 {
55 std::string::size_type size = rounds.size();
56 switch (size) {
57 case 1:
58 SetRadius(rounds.at(0), rounds.at(0), rounds.at(0), rounds.at(0), isX);
59 break;
60 case 2:
61 SetRadius(rounds.at(0), rounds.at(1), rounds.at(0), rounds.at(1), isX);
62 break;
63 case 3:
64 SetRadius(rounds.at(0), rounds.at(1), rounds.at(2), rounds.at(1), isX);
65 break;
66 case 4:
67 SetRadius(rounds.at(0), rounds.at(1), rounds.at(2), rounds.at(3), isX);
68 break;
69 default:
70 LOGE("invalid radius value");
71 break;
72 }
73 }
74
SetRadius(const Dimension & top,const Dimension & right,const Dimension & bottom,const Dimension & left,bool isX)75 void Inset::SetRadius(const Dimension& top, const Dimension& right, const Dimension& bottom, const Dimension& left,
76 bool isX)
77 {
78 SetTopLeftRadius(top, isX);
79 SetTopRightRadius(right, isX);
80 SetBottomRightRadius(bottom, isX);
81 SetBottomLeftRadius(left, isX);
82 }
83
GetGeometryBoxType(const std::string & value)84 GeometryBoxType ClipPath::GetGeometryBoxType(const std::string& value)
85 {
86 GeometryBoxType geometryBoxType = GeometryBoxType::NONE;
87 std::string::size_type boxPosition = 0;
88 std::string::size_type tmp = value.find("margin-box");
89 if (tmp != std::string::npos && tmp >= boxPosition) {
90 geometryBoxType = GeometryBoxType::MARGIN_BOX;
91 boxPosition = tmp;
92 }
93 tmp = value.find("border-box");
94 if (tmp != std::string::npos && tmp >= boxPosition) {
95 geometryBoxType = GeometryBoxType::BORDER_BOX;
96 boxPosition = tmp;
97 }
98 tmp = value.find("padding-box");
99 if (tmp != std::string::npos && tmp >= boxPosition) {
100 geometryBoxType = GeometryBoxType::PADDING_BOX;
101 boxPosition = tmp;
102 }
103 tmp = value.find("content-box");
104 if (tmp != std::string::npos && tmp >= boxPosition) {
105 geometryBoxType = GeometryBoxType::CONTENT_BOX;
106 }
107 return geometryBoxType;
108 }
109
GetBasicShapeInfo(const std::string & value,BasicShapeType & basicShapeType,std::string & data)110 void ClipPath::GetBasicShapeInfo(const std::string& value, BasicShapeType& basicShapeType, std::string& data)
111 {
112 std::string::size_type first = 0;
113 std::string::size_type tmp = value.find("inset(");
114 if (tmp != std::string::npos && tmp >= first) {
115 first = tmp + std::strlen("inset(");
116 data = value.substr(first, (value.find_first_of(')', first) - first));
117 basicShapeType = BasicShapeType::INSET;
118 }
119 tmp = value.find("circle(");
120 if (tmp != std::string::npos && tmp >= first) {
121 first = tmp + std::strlen("circle(");
122 data = value.substr(first, (value.find_first_of(')', first) - first));
123 basicShapeType = BasicShapeType::CIRCLE;
124 }
125 tmp = value.find("ellipse(");
126 if (tmp != std::string::npos && tmp >= first) {
127 first = tmp + std::strlen("ellipse(");
128 data = value.substr(first, (value.find_first_of(')', first) - first));
129 basicShapeType = BasicShapeType::ELLIPSE;
130 }
131 tmp = value.find("polygon(");
132 if (tmp != std::string::npos && tmp >= first) {
133 first = tmp + std::strlen("polygon(");
134 data = value.substr(first, (value.find_first_of(')', first) - first));
135 basicShapeType = BasicShapeType::POLYGON;
136 }
137 tmp = value.find("path('");
138 if (tmp != std::string::npos && tmp >= first) {
139 first = tmp + std::strlen("path('");
140 data = value.substr(first, (value.find("')", first) - first));
141 basicShapeType = BasicShapeType::PATH;
142 }
143 tmp = value.find("path(\"");
144 if (tmp != std::string::npos && tmp >= first) {
145 first = tmp + std::strlen("path(\"");
146 data = value.substr(first, (value.find("\")", first) - first));
147 basicShapeType = BasicShapeType::PATH;
148 }
149 }
150
CreateCircle(const std::string & data)151 RefPtr<Circle> ClipPath::CreateCircle(const std::string& data)
152 {
153 std::string::size_type atIndex = data.find("at");
154 if (atIndex == std::string::npos) {
155 Dimension radius = StringUtils::StringToDimension(StringUtils::TrimStr(data));
156 if (!radius.IsValid()) {
157 return nullptr;
158 }
159 auto circle = AceType::MakeRefPtr<Circle>();
160 circle->SetRadius(radius);
161 return circle;
162 }
163 Dimension radius = StringUtils::StringToDimension(StringUtils::TrimStr(data.substr(0, atIndex)));
164 if (!radius.IsValid()) {
165 return nullptr;
166 }
167 auto circle = AceType::MakeRefPtr<Circle>();
168 circle->SetRadius(radius);
169 std::vector<Dimension> axis;
170 StringUtils::SplitStr(StringUtils::TrimStr(data.substr(atIndex + 2)), " ", axis);
171 if (axis.size() == 1) {
172 circle->SetAxisX(axis.at(0));
173 }
174 if (axis.size() >= 2) {
175 circle->SetAxisX(axis.at(0));
176 circle->SetAxisY(axis.at(1));
177 }
178 return circle;
179 }
180
CreateEllipse(const std::string & data)181 RefPtr<Ellipse> ClipPath::CreateEllipse(const std::string& data)
182 {
183 std::string::size_type atIndex = data.find("at");
184 if (atIndex == std::string::npos) {
185 return CreateEllipseSize(data);
186 }
187 auto ellipse = CreateEllipseSize(StringUtils::TrimStr(data.substr(0, atIndex)));
188 if (!ellipse) {
189 return nullptr;
190 }
191 std::vector<Dimension> axis;
192 StringUtils::SplitStr(StringUtils::TrimStr(data.substr(atIndex + 2)), " ", axis);
193 if (axis.size() == 1) {
194 ellipse->SetAxisX(axis.at(0));
195 }
196 if (axis.size() >= 2) {
197 ellipse->SetAxisX(axis.at(0));
198 ellipse->SetAxisY(axis.at(1));
199 }
200 return ellipse;
201 }
202
CreateEllipseSize(const std::string & data)203 RefPtr<Ellipse> ClipPath::CreateEllipseSize(const std::string& data)
204 {
205 std::vector<Dimension> lengths;
206 StringUtils::SplitStr(data, " ", lengths);
207 if (lengths.size() != 2) {
208 return nullptr;
209 }
210 if (!lengths.at(0).IsValid() || !lengths.at(1).IsValid()) {
211 return nullptr;
212 }
213 auto ellipse = AceType::MakeRefPtr<Ellipse>();
214 ellipse->SetRadiusX(lengths.at(0));
215 ellipse->SetRadiusY(lengths.at(1));
216 return ellipse;
217 }
218
CreateInset(const std::string & data)219 RefPtr<Inset> ClipPath::CreateInset(const std::string& data)
220 {
221 std::string::size_type roundIndex = data.find("round");
222 if (roundIndex == std::string::npos) {
223 return CreateInsetSize(data);
224 }
225 auto inset = CreateInsetSize(StringUtils::TrimStr(data.substr(0, roundIndex)));
226 if (!inset) {
227 return nullptr;
228 }
229 std::string roundData = StringUtils::TrimStr(data.substr(roundIndex + 5));
230 std::string::size_type roundDataIndex = roundData.find('/');
231 if (roundDataIndex == std::string::npos) {
232 std::vector<Dimension> rounds;
233 StringUtils::SplitStr(roundData, " ", rounds);
234 if (rounds.empty()) {
235 return inset;
236 }
237 inset->SetRadius(rounds);
238 } else {
239 std::vector<Dimension> rounds1;
240 StringUtils::SplitStr(StringUtils::TrimStr(roundData.substr(0, roundDataIndex)), " ", rounds1);
241 if (!rounds1.empty()) {
242 inset->SetRadius(rounds1, true);
243 }
244 std::vector<Dimension> rounds2;
245 StringUtils::SplitStr(StringUtils::TrimStr(roundData.substr(roundDataIndex + 1)), " ", rounds2);
246 if (!rounds2.empty()) {
247 inset->SetRadius(rounds2, false);
248 }
249 }
250 return inset;
251 }
252
CreateInsetSize(const std::string & data)253 RefPtr<Inset> ClipPath::CreateInsetSize(const std::string& data)
254 {
255 std::vector<Dimension> lengths;
256 StringUtils::SplitStr(data, " ", lengths);
257 if (lengths.empty()) {
258 return nullptr;
259 }
260 auto inset = AceType::MakeRefPtr<Inset>();
261 if (inset->SetLength(lengths)) {
262 return inset;
263 }
264 return nullptr;
265 }
266
CreatePolygon(const std::string & data)267 RefPtr<Polygon> ClipPath::CreatePolygon(const std::string& data)
268 {
269 std::vector<std::string> points;
270 StringUtils::StringSplitter(StringUtils::TrimStr(data), ',', points);
271 if (points.empty()) {
272 return nullptr;
273 }
274 auto polygon = AceType::MakeRefPtr<Polygon>();
275 for (const auto& item : points) {
276 std::vector<Dimension> point;
277 StringUtils::SplitStr(StringUtils::TrimStr(item), " ", point);
278 if (point.size() != 2) {
279 return nullptr;
280 }
281 polygon->PushPoint(point[0], point[1]);
282 }
283 if (polygon->IsValid()) {
284 return polygon;
285 }
286 return nullptr;
287 }
288
CreatePath(const std::string & data)289 RefPtr<Path> ClipPath::CreatePath(const std::string& data)
290 {
291 if (data.empty()) {
292 return nullptr;
293 }
294 auto path = AceType::MakeRefPtr<Path>();
295 path->SetValue(StringUtils::TrimStr(data));
296 return path;
297 }
298
CreateShape(const std::string & value)299 RefPtr<ClipPath> ClipPath::CreateShape(const std::string& value)
300 {
301 BasicShapeType basicShapeType = BasicShapeType::NONE;
302 std::string data;
303 GetBasicShapeInfo(value, basicShapeType, data);
304 if (basicShapeType == BasicShapeType::NONE || data.empty()) {
305 return nullptr;
306 }
307 RefPtr<BasicShape> basicShape = nullptr;
308 switch (basicShapeType) {
309 case BasicShapeType::CIRCLE: {
310 basicShape = CreateCircle(data);
311 break;
312 }
313 case BasicShapeType::ELLIPSE: {
314 basicShape = CreateEllipse(data);
315 break;
316 }
317 case BasicShapeType::INSET: {
318 basicShape = CreateInset(data);
319 break;
320 }
321 case BasicShapeType::PATH: {
322 basicShape = CreatePath(data);
323 break;
324 }
325 case BasicShapeType::POLYGON: {
326 basicShape = CreatePolygon(data);
327 break;
328 }
329 default: {
330 LOGE("basic shape type is none or invalid");
331 break;
332 }
333 }
334 if (basicShape) {
335 return AceType::MakeRefPtr<ClipPath>(basicShape);
336 }
337 return nullptr;
338 }
339
340 } // namespace OHOS::Ace
341