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