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
106 CpmlPath
*cpml_path_copy(CpmlPath
*path
, const CpmlPath
*src
)
108 if (path
== NULL
|| src
== NULL
)
111 return memcpy(path
, src
, sizeof(CpmlPath
));
115 * cpml_segment_from_path:
116 * @segment: an allocated #CpmlPath struct
117 * @path: the source path
118 * @index: the segment to retrieve (starting from 1);
119 * %CPML_FIRST or %CPML_LAST can be used
121 * Gets a specific segment from a path.
123 * Return value: 1 if a valid segment was found, 0 on errors
126 cpml_segment_from_path(CpmlPath
*segment
, const CpmlPath
*path
, int index
)
128 CpmlPath residue
, result
;
131 if (!cpml_path_copy(&residue
, path
))
137 if (!path_to_segment(&result
, &residue
))
138 return index
== CPML_LAST
&& i
> 0;
140 residue
.cairo_path
.data
+= result
.cairo_path
.num_data
;
141 residue
.cairo_path
.num_data
-= result
.cairo_path
.num_data
;
144 if (index
== CPML_LAST
) {
145 cpml_path_copy(segment
, &result
);
150 cpml_path_copy(segment
, &result
);
155 * cpml_primitive_from_path:
156 * @primitive: an allocated #CpmlPath struct
157 * @path: the source path
158 * @index: the primitive to retrieve (starting from 1);
159 * %CPML_FIRST or %CPML_LAST can be used
161 * Gets a specific primitive from a path.
163 * Return value: 1 if a valid primitive was found, 0 on errors
166 cpml_primitive_from_path(CpmlPath
*primitive
, const CpmlPath
*path
, int index
)
168 CpmlPath residue
, result
;
171 if (!cpml_path_copy(&residue
, path
))
177 if (!path_to_primitive(&result
, &residue
))
178 return index
== CPML_LAST
&& i
> 0;
180 residue
.cairo_path
.data
+= result
.cairo_path
.num_data
;
181 residue
.cairo_path
.num_data
-= result
.cairo_path
.num_data
;
184 if (index
== CPML_LAST
) {
185 cpml_path_copy(primitive
, &result
);
190 cpml_path_copy(primitive
, &result
);
195 * cpml_primitive_get_pair:
196 * @primitive: the source primitive
197 * @pair: the allocated CpmlPair destination
198 * @index: index of the pair to retrieve, starting from 1
200 * Shortcut to get a pair from a primitive.
202 * Return value: 1 on success, 0 on errors
205 cpml_primitive_get_pair(const CpmlPath
*primitive
, CpmlPair
*pair
, int index
)
207 cairo_path_data_t
*data
= primitive
->cairo_path
.data
;
209 if (index
== 0 || index
> data
[0].header
.length
)
212 pair
->x
= data
[index
].point
.x
;
213 pair
->y
= data
[index
].point
.y
;
218 * cpml_primitive_set_pair:
219 * @primitive: an allocated CpmlPath primitive
220 * @pair: the source pair
221 * @index: index of the pair to change, starting from 1
223 * Shortcut to set a pair on a primitive.
225 * Return value: 1 on success, 0 on errors
228 cpml_primitive_set_pair(CpmlPath
*primitive
, const CpmlPair
*pair
, int index
)
230 cairo_path_data_t
*data
= primitive
->cairo_path
.data
;
232 if (index
== 0 || index
> data
[0].header
.length
)
235 data
[index
].point
.x
= pair
->x
;
236 data
[index
].point
.y
= pair
->y
;
241 * cpml_primitive_get_point:
242 * @primitive: the source primitive
243 * @point: the allocated CpmlPair destination
244 * @pos: the position factor, being 0 the starting and 1 the ending point
246 * Gets a point lying on @primitive at a specific percentual position.
248 * Return value: 1 on success, 0 on errors
251 cpml_primitive_get_point(const CpmlPath
*primitive
, CpmlPair
*point
, double pos
)
253 int type
= primitive
->cairo_path
.data
[0].header
.type
;
255 if (type
!= CAIRO_PATH_CLOSE_PATH
&& type
!= CAIRO_PATH_LINE_TO
&&
256 type
!= CAIRO_PATH_CURVE_TO
)
260 if (type
== CAIRO_PATH_CLOSE_PATH
|| pos
== 0.) {
261 return cpml_pair_copy(point
, &primitive
->org
);
262 } else if (pos
== 1.0) {
263 int n
= type
== CAIRO_PATH_LINE_TO
? 1 : 3;
264 return cpml_primitive_get_pair(primitive
, point
, n
);
272 * cpml_primitive_reverse:
273 * @primitive: an allocated #CpmlPath struct
275 * Reverses a primitive.
277 * Return value: 1 on success, 0 on errors
279 cairo_bool_t
cpml_primitive_reverse(CpmlPath
*primitive
)
283 switch (primitive
->cairo_path
.data
[0].header
.type
) {
284 case CAIRO_PATH_LINE_TO
:
285 cpml_pair_copy(&tmp
, &primitive
->org
);
286 cpml_primitive_get_pair(primitive
, &primitive
->org
, 1);
287 cpml_primitive_set_pair(primitive
, &tmp
, 1);
289 case CAIRO_PATH_CURVE_TO
:
290 cpml_pair_copy(&tmp
, &primitive
->org
);
291 cpml_primitive_get_pair(primitive
, &primitive
->org
, 3);
292 cpml_primitive_set_pair(primitive
, &tmp
, 3);
294 cpml_primitive_get_pair(primitive
, &tmp
, 2);
295 primitive
->cairo_path
.data
[2].point
.x
=
296 primitive
->cairo_path
.data
[3].point
.x
;
297 primitive
->cairo_path
.data
[2].point
.y
=
298 primitive
->cairo_path
.data
[3].point
.y
;
299 cpml_primitive_set_pair(primitive
, &tmp
, 3);
312 * Strips the leading CAIRO_PATH_MOVE_TO primitives, updating the CpmlPath
313 * structure accordling. Also the path org is update.
315 * Return value: 1 on success, 0 on no leading MOVE_TOs or on errors
316 * (check for path->cairo_path.status == CAIRO_STATUS_SUCCESS)
318 static cairo_bool_t
strip_leadings(CpmlPath
*path
)
320 if (path
->cairo_path
.data
[0].header
.type
!= CAIRO_PATH_MOVE_TO
)
324 ++path
->cairo_path
.data
;
325 path
->org
.x
= path
->cairo_path
.data
->point
.x
;
326 path
->org
.y
= path
->cairo_path
.data
->point
.y
;
327 ++path
->cairo_path
.data
;
328 path
->cairo_path
.num_data
-= 2;
329 if (path
->cairo_path
.num_data
<= 0) {
330 path
->cairo_path
.status
= CAIRO_STATUS_INVALID_PATH_DATA
;
333 } while (path
->cairo_path
.data
->header
.type
== CAIRO_PATH_MOVE_TO
);
340 * @segment: an allocated #CpmlPath struct
341 * @path: the source path
343 * Converts a path to a segment. @segment and @path can be the same struct.
345 * Return value: 1 if a valid segment is found, 0 on errors
348 path_to_segment(CpmlPath
*segment
, const CpmlPath
*path
)
350 cairo_path_data_t
*path_data
;
354 cpml_path_copy(segment
, path
);
356 if (!strip_leadings(segment
) &&
357 segment
->cairo_path
.status
!= CAIRO_STATUS_SUCCESS
)
360 path_data
= segment
->cairo_path
.data
;
364 if (path_data
->header
.type
== CAIRO_PATH_MOVE_TO
) {
367 } else if (path_data
->header
.type
== CAIRO_PATH_CLOSE_PATH
) {
370 i
+= path_data
->header
.length
;
371 path_data
+= path_data
->header
.length
;
372 } while (i
< segment
->cairo_path
.num_data
);
374 segment
->cairo_path
.num_data
= i
;
380 * @primitive: an allocated #CpmlPath struct
381 * @path: the source path
383 * Converts a path to a primitive. @primitive and @path can be the same struct.
385 * Return value: 1 if a valid primitive is found, 0 on errors
388 path_to_primitive(CpmlPath
*primitive
, const CpmlPath
*path
)
390 cairo_path_data_t
*path_data
;
392 if (primitive
!= path
)
393 cpml_path_copy(primitive
, path
);
395 if (!strip_leadings(primitive
) &&
396 primitive
->cairo_path
.status
!= CAIRO_STATUS_SUCCESS
)
399 primitive
->cairo_path
.num_data
= 1;