Implemented patterns in AdgStyle
[adg.git] / cpml / cpml-path.c
blob1aa1d9d431c9e5a4a6eecfbf7f7c2eac98485e21
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"
23 #include <string.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);
31 /**
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
47 cairo_bool_t
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);
58 /**
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
69 * is left untouched.
71 * Return value: 1 on success, 0 on errors
73 cairo_bool_t
74 cpml_path_from_cairo_explicit(CpmlPath *path, const cairo_path_t *src,
75 const CpmlPair *org)
77 if (src->status != CAIRO_STATUS_SUCCESS)
78 return 0;
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 */
87 return 0;
88 } else if (org) {
89 /* Use the provided org */
90 cpml_pair_copy(&path->org, org);
93 return 1;
96 /**
97 * cpml_path_copy:
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 *
107 cpml_path_copy(CpmlPath *path, const CpmlPath *src)
109 if (path == NULL || src == NULL)
110 return 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
126 cairo_bool_t
127 cpml_segment_from_path(CpmlPath *segment, const CpmlPath *path, int index)
129 CpmlPath residue, result;
130 int i;
132 if (!cpml_path_copy(&residue, path))
133 return 0;
135 i = 0;
137 do {
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;
143 ++i;
145 if (index == CPML_LAST) {
146 cpml_path_copy(segment, &result);
147 continue;
149 } while (i < index);
151 cpml_path_copy(segment, &result);
152 return 1;
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
166 cairo_bool_t
167 cpml_primitive_from_path(CpmlPath *primitive, const CpmlPath *path, int index)
169 CpmlPath residue, result;
170 int i;
172 if (!cpml_path_copy(&residue, path))
173 return 0;
175 i = 0;
177 do {
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;
183 ++i;
185 if (index == CPML_LAST) {
186 cpml_path_copy(primitive, &result);
187 continue;
189 } while (i < index);
191 cpml_path_copy(primitive, &result);
192 return 1;
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
205 cairo_bool_t
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)
211 return 0;
213 pair->x = data[index].point.x;
214 pair->y = data[index].point.y;
215 return 1;
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
228 cairo_bool_t
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)
234 return 0;
236 data[index].point.x = pair->x;
237 data[index].point.y = pair->y;
238 return 1;
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
251 cairo_bool_t
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)
259 return 0;
261 /* Common cases */
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);
269 /* TODO */
270 return 0;
274 * cpml_primitive_reverse:
275 * @primitive: an allocated #CpmlPath struct
277 * Reverses a primitive.
279 * Return value: 1 on success, 0 on errors
281 cairo_bool_t
282 cpml_primitive_reverse(CpmlPath *primitive)
284 CpmlPair tmp;
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);
291 break;
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);
303 break;
304 default:
305 return 0;
308 return 1;
312 * strip_leadings:
313 * @path: a #CpmlPath
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)
321 static cairo_bool_t
322 strip_leadings(CpmlPath *path)
324 if (path->cairo_path.data[0].header.type != CAIRO_PATH_MOVE_TO)
325 return 0;
327 do {
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;
336 return 0;
338 } while (path->cairo_path.data->header.type == CAIRO_PATH_MOVE_TO);
340 return 1;
344 * path_to_segment:
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
352 static cairo_bool_t
353 path_to_segment(CpmlPath *segment, const CpmlPath *path)
355 cairo_path_data_t *path_data;
356 int i;
358 if (segment != path)
359 cpml_path_copy(segment, path);
361 if (!strip_leadings(segment) &&
362 segment->cairo_path.status != CAIRO_STATUS_SUCCESS)
363 return 0;
365 path_data = segment->cairo_path.data;
366 i = 0;
368 do {
369 if (path_data->header.type == CAIRO_PATH_MOVE_TO) {
370 --i;
371 break;
372 } else if (path_data->header.type == CAIRO_PATH_CLOSE_PATH) {
373 break;
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;
380 return 1;
384 * path_to_primitive:
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
392 static cairo_bool_t
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)
402 return 0;
404 primitive->cairo_path.num_data = 1;
405 return 1;