beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-path.c
blob43cd175a3c5235c0d42a28dd89629447b83d1188
1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2005 Red Hat, Inc.
4 * Copyright © 2006 Red Hat, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Red Hat, Inc.
33 * Contributor(s):
34 * Carl D. Worth <cworth@redhat.com>
37 #include "cairoint.h"
39 #include "cairo-private.h"
40 #include "cairo-backend-private.h"
41 #include "cairo-error-private.h"
42 #include "cairo-path-private.h"
43 #include "cairo-path-fixed-private.h"
45 /**
46 * SECTION:cairo-paths
47 * @Title: Paths
48 * @Short_Description: Creating paths and manipulating path data
50 * Paths are the most basic drawing tools and are primarily used to implicitly
51 * generate simple masks.
52 **/
54 static const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
56 /* Closure for path interpretation. */
57 typedef struct cairo_path_count {
58 int count;
59 } cpc_t;
61 static cairo_status_t
62 _cpc_move_to (void *closure,
63 const cairo_point_t *point)
65 cpc_t *cpc = closure;
67 cpc->count += 2;
69 return CAIRO_STATUS_SUCCESS;
72 static cairo_status_t
73 _cpc_line_to (void *closure,
74 const cairo_point_t *point)
76 cpc_t *cpc = closure;
78 cpc->count += 2;
80 return CAIRO_STATUS_SUCCESS;
83 static cairo_status_t
84 _cpc_curve_to (void *closure,
85 const cairo_point_t *p1,
86 const cairo_point_t *p2,
87 const cairo_point_t *p3)
89 cpc_t *cpc = closure;
91 cpc->count += 4;
93 return CAIRO_STATUS_SUCCESS;
96 static cairo_status_t
97 _cpc_close_path (void *closure)
99 cpc_t *cpc = closure;
101 cpc->count += 1;
103 return CAIRO_STATUS_SUCCESS;
106 static int
107 _cairo_path_count (cairo_path_t *path,
108 cairo_path_fixed_t *path_fixed,
109 double tolerance,
110 cairo_bool_t flatten)
112 cairo_status_t status;
113 cpc_t cpc;
115 cpc.count = 0;
117 if (flatten) {
118 status = _cairo_path_fixed_interpret_flat (path_fixed,
119 _cpc_move_to,
120 _cpc_line_to,
121 _cpc_close_path,
122 &cpc,
123 tolerance);
124 } else {
125 status = _cairo_path_fixed_interpret (path_fixed,
126 _cpc_move_to,
127 _cpc_line_to,
128 _cpc_curve_to,
129 _cpc_close_path,
130 &cpc);
133 if (unlikely (status))
134 return -1;
136 return cpc.count;
139 /* Closure for path interpretation. */
140 typedef struct cairo_path_populate {
141 cairo_path_data_t *data;
142 cairo_t *cr;
143 } cpp_t;
145 static cairo_status_t
146 _cpp_move_to (void *closure,
147 const cairo_point_t *point)
149 cpp_t *cpp = closure;
150 cairo_path_data_t *data = cpp->data;
151 double x, y;
153 x = _cairo_fixed_to_double (point->x);
154 y = _cairo_fixed_to_double (point->y);
156 _cairo_backend_to_user (cpp->cr, &x, &y);
158 data->header.type = CAIRO_PATH_MOVE_TO;
159 data->header.length = 2;
161 /* We index from 1 to leave room for data->header */
162 data[1].point.x = x;
163 data[1].point.y = y;
165 cpp->data += data->header.length;
167 return CAIRO_STATUS_SUCCESS;
170 static cairo_status_t
171 _cpp_line_to (void *closure,
172 const cairo_point_t *point)
174 cpp_t *cpp = closure;
175 cairo_path_data_t *data = cpp->data;
176 double x, y;
178 x = _cairo_fixed_to_double (point->x);
179 y = _cairo_fixed_to_double (point->y);
181 _cairo_backend_to_user (cpp->cr, &x, &y);
183 data->header.type = CAIRO_PATH_LINE_TO;
184 data->header.length = 2;
186 /* We index from 1 to leave room for data->header */
187 data[1].point.x = x;
188 data[1].point.y = y;
190 cpp->data += data->header.length;
192 return CAIRO_STATUS_SUCCESS;
195 static cairo_status_t
196 _cpp_curve_to (void *closure,
197 const cairo_point_t *p1,
198 const cairo_point_t *p2,
199 const cairo_point_t *p3)
201 cpp_t *cpp = closure;
202 cairo_path_data_t *data = cpp->data;
203 double x1, y1;
204 double x2, y2;
205 double x3, y3;
207 x1 = _cairo_fixed_to_double (p1->x);
208 y1 = _cairo_fixed_to_double (p1->y);
209 _cairo_backend_to_user (cpp->cr, &x1, &y1);
211 x2 = _cairo_fixed_to_double (p2->x);
212 y2 = _cairo_fixed_to_double (p2->y);
213 _cairo_backend_to_user (cpp->cr, &x2, &y2);
215 x3 = _cairo_fixed_to_double (p3->x);
216 y3 = _cairo_fixed_to_double (p3->y);
217 _cairo_backend_to_user (cpp->cr, &x3, &y3);
219 data->header.type = CAIRO_PATH_CURVE_TO;
220 data->header.length = 4;
222 /* We index from 1 to leave room for data->header */
223 data[1].point.x = x1;
224 data[1].point.y = y1;
226 data[2].point.x = x2;
227 data[2].point.y = y2;
229 data[3].point.x = x3;
230 data[3].point.y = y3;
232 cpp->data += data->header.length;
234 return CAIRO_STATUS_SUCCESS;
237 static cairo_status_t
238 _cpp_close_path (void *closure)
240 cpp_t *cpp = closure;
241 cairo_path_data_t *data = cpp->data;
243 data->header.type = CAIRO_PATH_CLOSE_PATH;
244 data->header.length = 1;
246 cpp->data += data->header.length;
248 return CAIRO_STATUS_SUCCESS;
251 static cairo_status_t
252 _cairo_path_populate (cairo_path_t *path,
253 cairo_path_fixed_t *path_fixed,
254 cairo_t *cr,
255 cairo_bool_t flatten)
257 cairo_status_t status;
258 cpp_t cpp;
260 cpp.data = path->data;
261 cpp.cr = cr;
263 if (flatten) {
264 status = _cairo_path_fixed_interpret_flat (path_fixed,
265 _cpp_move_to,
266 _cpp_line_to,
267 _cpp_close_path,
268 &cpp,
269 cairo_get_tolerance (cr));
270 } else {
271 status = _cairo_path_fixed_interpret (path_fixed,
272 _cpp_move_to,
273 _cpp_line_to,
274 _cpp_curve_to,
275 _cpp_close_path,
276 &cpp);
279 if (unlikely (status))
280 return status;
282 /* Sanity check the count */
283 assert (cpp.data - path->data == path->num_data);
285 return CAIRO_STATUS_SUCCESS;
288 cairo_path_t *
289 _cairo_path_create_in_error (cairo_status_t status)
291 cairo_path_t *path;
293 /* special case NO_MEMORY so as to avoid allocations */
294 if (status == CAIRO_STATUS_NO_MEMORY)
295 return (cairo_path_t*) &_cairo_path_nil;
297 path = malloc (sizeof (cairo_path_t));
298 if (unlikely (path == NULL)) {
299 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
300 return (cairo_path_t*) &_cairo_path_nil;
303 path->num_data = 0;
304 path->data = NULL;
305 path->status = status;
307 return path;
310 static cairo_path_t *
311 _cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
312 cairo_t *cr,
313 cairo_bool_t flatten)
315 cairo_path_t *path;
317 path = malloc (sizeof (cairo_path_t));
318 if (unlikely (path == NULL)) {
319 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
320 return (cairo_path_t*) &_cairo_path_nil;
323 path->num_data = _cairo_path_count (path, path_fixed,
324 cairo_get_tolerance (cr),
325 flatten);
326 if (path->num_data < 0) {
327 free (path);
328 return (cairo_path_t*) &_cairo_path_nil;
331 if (path->num_data) {
332 path->data = _cairo_malloc_ab (path->num_data,
333 sizeof (cairo_path_data_t));
334 if (unlikely (path->data == NULL)) {
335 free (path);
336 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
337 return (cairo_path_t*) &_cairo_path_nil;
340 path->status = _cairo_path_populate (path, path_fixed, cr, flatten);
341 } else {
342 path->data = NULL;
343 path->status = CAIRO_STATUS_SUCCESS;
346 return path;
350 * cairo_path_destroy:
351 * @path: a path previously returned by either cairo_copy_path() or
352 * cairo_copy_path_flat().
354 * Immediately releases all memory associated with @path. After a call
355 * to cairo_path_destroy() the @path pointer is no longer valid and
356 * should not be used further.
358 * Note: cairo_path_destroy() should only be called with a
359 * pointer to a #cairo_path_t returned by a cairo function. Any path
360 * that is created manually (ie. outside of cairo) should be destroyed
361 * manually as well.
363 * Since: 1.0
365 void
366 cairo_path_destroy (cairo_path_t *path)
368 if (path == NULL || path == &_cairo_path_nil)
369 return;
371 free (path->data);
373 free (path);
375 slim_hidden_def (cairo_path_destroy);
378 * _cairo_path_create:
379 * @path: a fixed-point, device-space path to be converted and copied
380 * @cr: the current graphics context
382 * Creates a user-space #cairo_path_t copy of the given device-space
383 * @path. The @cr parameter provides the inverse CTM for the
384 * conversion.
386 * Return value: the new copy of the path. If there is insufficient
387 * memory a pointer to a special static nil #cairo_path_t will be
388 * returned instead with status==%CAIRO_STATUS_NO_MEMORY and
389 * data==%NULL.
391 cairo_path_t *
392 _cairo_path_create (cairo_path_fixed_t *path,
393 cairo_t *cr)
395 return _cairo_path_create_internal (path, cr, FALSE);
399 * _cairo_path_create_flat:
400 * @path: a fixed-point, device-space path to be flattened, converted and copied
401 * @cr: the current graphics context
403 * Creates a flattened, user-space #cairo_path_t copy of the given
404 * device-space @path. The @cr parameter provide the inverse CTM
405 * for the conversion, as well as the tolerance value to control the
406 * accuracy of the flattening.
408 * Return value: the flattened copy of the path. If there is insufficient
409 * memory a pointer to a special static nil #cairo_path_t will be
410 * returned instead with status==%CAIRO_STATUS_NO_MEMORY and
411 * data==%NULL.
413 cairo_path_t *
414 _cairo_path_create_flat (cairo_path_fixed_t *path,
415 cairo_t *cr)
417 return _cairo_path_create_internal (path, cr, TRUE);
421 * _cairo_path_append_to_context:
422 * @path: the path data to be appended
423 * @cr: a cairo context
425 * Append @path to the current path within @cr.
427 * Return value: %CAIRO_STATUS_INVALID_PATH_DATA if the data in @path
428 * is invalid, and %CAIRO_STATUS_SUCCESS otherwise.
430 cairo_status_t
431 _cairo_path_append_to_context (const cairo_path_t *path,
432 cairo_t *cr)
434 const cairo_path_data_t *p, *end;
436 end = &path->data[path->num_data];
437 for (p = &path->data[0]; p < end; p += p->header.length) {
438 switch (p->header.type) {
439 case CAIRO_PATH_MOVE_TO:
440 if (unlikely (p->header.length < 2))
441 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
443 cairo_move_to (cr, p[1].point.x, p[1].point.y);
444 break;
446 case CAIRO_PATH_LINE_TO:
447 if (unlikely (p->header.length < 2))
448 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
450 cairo_line_to (cr, p[1].point.x, p[1].point.y);
451 break;
453 case CAIRO_PATH_CURVE_TO:
454 if (unlikely (p->header.length < 4))
455 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
457 cairo_curve_to (cr,
458 p[1].point.x, p[1].point.y,
459 p[2].point.x, p[2].point.y,
460 p[3].point.x, p[3].point.y);
461 break;
463 case CAIRO_PATH_CLOSE_PATH:
464 if (unlikely (p->header.length < 1))
465 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
467 cairo_close_path (cr);
468 break;
470 default:
471 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
474 if (unlikely (cr->status))
475 return cr->status;
478 return CAIRO_STATUS_SUCCESS;