1 /* CPML - Cairo Path Manipulation Library
2 * Copyright (C) 2008, Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 #include "cpml-path.h"
25 static cairo_bool_t
strip_leadings (CpmlPath
*path
);
26 static cairo_bool_t
path_to_segment (CpmlPath
*segment
,
27 const CpmlPath
*path
);
28 static cairo_bool_t
path_to_primitive (CpmlPath
*primitive
,
29 const CpmlPath
*path
);
32 * cpml_path_from_cairo:
33 * @path: an allocated #CpmlPath structure
34 * @src: the source cairo_path_t
35 * @cr: a cairo context
37 * Builds a CpmlPath from a cairo_path_t structure. This operations involves
38 * stripping the leading MOVE_TO data and setting @path->org
40 * @cr is used to get the current point (if needed): it can be %NULL,
41 * in which case (0,0) will be used.
43 * @path and @src can be the same object (a #CpmlPath structure).
45 * Return value: 1 on success, 0 on errors
48 cpml_path_from_cairo(CpmlPath
*path
, const cairo_path_t
*src
, cairo_t
*cr
)
50 CpmlPair org
= {0., 0.};
52 if (cr
&& cairo_has_current_point(cr
))
53 cairo_get_current_point(cr
, &org
.x
, &org
.y
);
55 return cpml_path_from_cairo_explicit(path
, src
, &org
);
59 * cpml_path_from_cairo_explicit:
60 * @path: an allocated #CpmlPath structure
61 * @src: the source cairo_path_t
62 * @org: a specific origin
64 * Similar to cpml_path_from_cairo() but using an explicit origin.
66 * @path and @src can be the same object (a #CpmlPath structure).
68 * @org can be %NULL, in which case the original path->org pair
71 * Return value: 1 on success, 0 on errors
74 cpml_path_from_cairo_explicit(CpmlPath
*path
, const cairo_path_t
*src
,
77 if (src
->status
!= CAIRO_STATUS_SUCCESS
)
80 if (path
!= (CpmlPath
*) src
)
81 memcpy(path
, src
, sizeof(cairo_path_t
));
83 if (strip_leadings(path
)) {
84 /* org taken from leadings MOVE_TO */
85 } else if (path
->cairo_path
.status
!= CAIRO_STATUS_SUCCESS
) {
86 /* Error: probably an empty path provided */
89 /* Use the provided org */
90 cpml_pair_copy(&path
->org
, org
);
98 * @path: an allocated #CpmlPath
99 * @src: the source path to copy
101 * Strips the leading CAIRO_PATH_MOVE_TO primitives, updating the CpmlPath
102 * structure accordling. Also the path org is update.
104 * Return value: @path or %NULL on errors
107 cpml_path_copy(CpmlPath
*path
, const CpmlPath
*src
)
109 if (path
== NULL
|| src
== NULL
)
112 return memcpy(path
, src
, sizeof(CpmlPath
));
116 * cpml_segment_from_path:
117 * @segment: an allocated #CpmlPath struct
118 * @path: the source path
119 * @index: the segment to retrieve (starting from 1);
120 * %CPML_FIRST or %CPML_LAST can be used
122 * Gets a specific segment from a path.
124 * Return value: 1 if a valid segment was found, 0 on errors
127 cpml_segment_from_path(CpmlPath
*segment
, const CpmlPath
*path
, int index
)
129 CpmlPath residue
, result
;
132 if (!cpml_path_copy(&residue
, path
))
138 if (!path_to_segment(&result
, &residue
))
139 return index
== CPML_LAST
&& i
> 0;
141 residue
.cairo_path
.data
+= result
.cairo_path
.num_data
;
142 residue
.cairo_path
.num_data
-= result
.cairo_path
.num_data
;
145 if (index
== CPML_LAST
) {
146 cpml_path_copy(segment
, &result
);
151 cpml_path_copy(segment
, &result
);
156 * cpml_primitive_from_path:
157 * @primitive: an allocated #CpmlPath struct
158 * @path: the source path
159 * @index: the primitive to retrieve (starting from 1);
160 * %CPML_FIRST or %CPML_LAST can be used
162 * Gets a specific primitive from a path.
164 * Return value: 1 if a valid primitive was found, 0 on errors
167 cpml_primitive_from_path(CpmlPath
*primitive
, const CpmlPath
*path
, int index
)
169 CpmlPath residue
, result
;
172 if (!cpml_path_copy(&residue
, path
))
178 if (!path_to_primitive(&result
, &residue
))
179 return index
== CPML_LAST
&& i
> 0;
181 residue
.cairo_path
.data
+= result
.cairo_path
.num_data
;
182 residue
.cairo_path
.num_data
-= result
.cairo_path
.num_data
;
185 if (index
== CPML_LAST
) {
186 cpml_path_copy(primitive
, &result
);
191 cpml_path_copy(primitive
, &result
);
196 * cpml_primitive_get_pair:
197 * @primitive: the source primitive
198 * @pair: the allocated CpmlPair destination
199 * @index: index of the pair to retrieve, starting from 1
201 * Shortcut to get a pair from a primitive.
203 * Return value: 1 on success, 0 on errors
206 cpml_primitive_get_pair(const CpmlPath
*primitive
, CpmlPair
*pair
, int index
)
208 cairo_path_data_t
*data
= primitive
->cairo_path
.data
;
210 if (index
== 0 || index
> data
[0].header
.length
)
213 pair
->x
= data
[index
].point
.x
;
214 pair
->y
= data
[index
].point
.y
;
219 * cpml_primitive_set_pair:
220 * @primitive: an allocated CpmlPath primitive
221 * @pair: the source pair
222 * @index: index of the pair to change, starting from 1
224 * Shortcut to set a pair on a primitive.
226 * Return value: 1 on success, 0 on errors
229 cpml_primitive_set_pair(CpmlPath
*primitive
, const CpmlPair
*pair
, int index
)
231 cairo_path_data_t
*data
= primitive
->cairo_path
.data
;
233 if (index
== 0 || index
> data
[0].header
.length
)
236 data
[index
].point
.x
= pair
->x
;
237 data
[index
].point
.y
= pair
->y
;
242 * cpml_primitive_get_point:
243 * @primitive: the source primitive
244 * @point: the allocated CpmlPair destination
245 * @pos: the position factor, being 0 the starting and 1 the ending point
247 * Gets a point lying on @primitive at a specific percentual position.
249 * Return value: 1 on success, 0 on errors
252 cpml_primitive_get_point(const CpmlPath
*primitive
,
253 CpmlPair
*point
, double pos
)
255 int type
= primitive
->cairo_path
.data
[0].header
.type
;
257 if (type
!= CAIRO_PATH_CLOSE_PATH
&& type
!= CAIRO_PATH_LINE_TO
&&
258 type
!= CAIRO_PATH_CURVE_TO
)
262 if (type
== CAIRO_PATH_CLOSE_PATH
|| pos
== 0.) {
263 return cpml_pair_copy(point
, &primitive
->org
);
264 } else if (pos
== 1.0) {
265 int n
= type
== CAIRO_PATH_LINE_TO
? 1 : 3;
266 return cpml_primitive_get_pair(primitive
, point
, n
);
274 * cpml_primitive_reverse:
275 * @primitive: an allocated #CpmlPath struct
277 * Reverses a primitive.
279 * Return value: 1 on success, 0 on errors
282 cpml_primitive_reverse(CpmlPath
*primitive
)
286 switch (primitive
->cairo_path
.data
[0].header
.type
) {
287 case CAIRO_PATH_LINE_TO
:
288 cpml_pair_copy(&tmp
, &primitive
->org
);
289 cpml_primitive_get_pair(primitive
, &primitive
->org
, 1);
290 cpml_primitive_set_pair(primitive
, &tmp
, 1);
292 case CAIRO_PATH_CURVE_TO
:
293 cpml_pair_copy(&tmp
, &primitive
->org
);
294 cpml_primitive_get_pair(primitive
, &primitive
->org
, 3);
295 cpml_primitive_set_pair(primitive
, &tmp
, 3);
297 cpml_primitive_get_pair(primitive
, &tmp
, 2);
298 primitive
->cairo_path
.data
[2].point
.x
=
299 primitive
->cairo_path
.data
[3].point
.x
;
300 primitive
->cairo_path
.data
[2].point
.y
=
301 primitive
->cairo_path
.data
[3].point
.y
;
302 cpml_primitive_set_pair(primitive
, &tmp
, 3);
315 * Strips the leading CAIRO_PATH_MOVE_TO primitives, updating the CpmlPath
316 * structure accordling. Also the path org is update.
318 * Return value: 1 on success, 0 on no leading MOVE_TOs or on errors
319 * (check for path->cairo_path.status == CAIRO_STATUS_SUCCESS)
322 strip_leadings(CpmlPath
*path
)
324 if (path
->cairo_path
.data
[0].header
.type
!= CAIRO_PATH_MOVE_TO
)
328 ++path
->cairo_path
.data
;
329 path
->org
.x
= path
->cairo_path
.data
->point
.x
;
330 path
->org
.y
= path
->cairo_path
.data
->point
.y
;
331 ++path
->cairo_path
.data
;
332 path
->cairo_path
.num_data
-= 2;
333 if (path
->cairo_path
.num_data
<= 0) {
334 path
->cairo_path
.status
=
335 CAIRO_STATUS_INVALID_PATH_DATA
;
338 } while (path
->cairo_path
.data
->header
.type
== CAIRO_PATH_MOVE_TO
);
345 * @segment: an allocated #CpmlPath struct
346 * @path: the source path
348 * Converts a path to a segment. @segment and @path can be the same struct.
350 * Return value: 1 if a valid segment is found, 0 on errors
353 path_to_segment(CpmlPath
*segment
, const CpmlPath
*path
)
355 cairo_path_data_t
*path_data
;
359 cpml_path_copy(segment
, path
);
361 if (!strip_leadings(segment
) &&
362 segment
->cairo_path
.status
!= CAIRO_STATUS_SUCCESS
)
365 path_data
= segment
->cairo_path
.data
;
369 if (path_data
->header
.type
== CAIRO_PATH_MOVE_TO
) {
372 } else if (path_data
->header
.type
== CAIRO_PATH_CLOSE_PATH
) {
375 i
+= path_data
->header
.length
;
376 path_data
+= path_data
->header
.length
;
377 } while (i
< segment
->cairo_path
.num_data
);
379 segment
->cairo_path
.num_data
= i
;
385 * @primitive: an allocated #CpmlPath struct
386 * @path: the source path
388 * Converts a path to a primitive. @primitive and @path can be the same struct.
390 * Return value: 1 if a valid primitive is found, 0 on errors
393 path_to_primitive(CpmlPath
*primitive
, const CpmlPath
*path
)
395 cairo_path_data_t
*path_data
;
397 if (primitive
!= path
)
398 cpml_path_copy(primitive
, path
);
400 if (!strip_leadings(primitive
) &&
401 primitive
->cairo_path
.status
!= CAIRO_STATUS_SUCCESS
)
404 primitive
->cairo_path
.num_data
= 1;