Updated: Sudoku no longer crashes
[moon.git] / cairo / src / cairo-path.c
blobc6639f3f4bd85c5a24261d95384fb2ab23808e46
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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-path-private.h"
40 #include "cairo-path-fixed-private.h"
42 static const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
44 /* Closure for path interpretation. */
45 typedef struct cairo_path_count {
46 int count;
47 cairo_point_t current_point;
48 } cpc_t;
50 static cairo_status_t
51 _cpc_move_to (void *closure, cairo_point_t *point)
53 cpc_t *cpc = closure;
55 cpc->count += 2;
57 cpc->current_point = *point;
59 return CAIRO_STATUS_SUCCESS;
62 static cairo_status_t
63 _cpc_line_to (void *closure, cairo_point_t *point)
65 cpc_t *cpc = closure;
67 cpc->count += 2;
69 cpc->current_point = *point;
71 return CAIRO_STATUS_SUCCESS;
74 static cairo_status_t
75 _cpc_curve_to (void *closure,
76 cairo_point_t *p1,
77 cairo_point_t *p2,
78 cairo_point_t *p3)
80 cpc_t *cpc = closure;
82 cpc->count += 4;
84 cpc->current_point = *p3;
86 return CAIRO_STATUS_SUCCESS;
89 static cairo_status_t
90 _cpc_close_path (void *closure)
92 cpc_t *cpc = closure;
94 cpc->count += 1;
96 return CAIRO_STATUS_SUCCESS;
99 static int
100 _cairo_path_count (cairo_path_t *path,
101 cairo_path_fixed_t *path_fixed,
102 double tolerance,
103 cairo_bool_t flatten)
105 cairo_status_t status;
106 cpc_t cpc;
108 cpc.count = 0;
109 cpc.current_point.x = 0;
110 cpc.current_point.y = 0;
112 if (flatten) {
113 status = _cairo_path_fixed_interpret_flat (path_fixed,
114 CAIRO_DIRECTION_FORWARD,
115 _cpc_move_to,
116 _cpc_line_to,
117 _cpc_close_path,
118 &cpc,
119 tolerance);
120 } else {
121 status = _cairo_path_fixed_interpret (path_fixed,
122 CAIRO_DIRECTION_FORWARD,
123 _cpc_move_to,
124 _cpc_line_to,
125 _cpc_curve_to,
126 _cpc_close_path,
127 &cpc);
130 if (status)
131 return -1;
133 return cpc.count;
136 /* Closure for path interpretation. */
137 typedef struct cairo_path_populate {
138 cairo_path_data_t *data;
139 cairo_gstate_t *gstate;
140 cairo_point_t current_point;
141 } cpp_t;
143 static cairo_status_t
144 _cpp_move_to (void *closure, cairo_point_t *point)
146 cpp_t *cpp = closure;
147 cairo_path_data_t *data = cpp->data;
148 double x, y;
150 x = _cairo_fixed_to_double (point->x);
151 y = _cairo_fixed_to_double (point->y);
153 _cairo_gstate_backend_to_user (cpp->gstate, &x, &y);
155 data->header.type = CAIRO_PATH_MOVE_TO;
156 data->header.length = 2;
158 /* We index from 1 to leave room for data->header */
159 data[1].point.x = x;
160 data[1].point.y = y;
162 cpp->data += data->header.length;
164 cpp->current_point = *point;
166 return CAIRO_STATUS_SUCCESS;
169 static cairo_status_t
170 _cpp_line_to (void *closure, cairo_point_t *point)
172 cpp_t *cpp = closure;
173 cairo_path_data_t *data = cpp->data;
174 double x, y;
176 x = _cairo_fixed_to_double (point->x);
177 y = _cairo_fixed_to_double (point->y);
179 _cairo_gstate_backend_to_user (cpp->gstate, &x, &y);
181 data->header.type = CAIRO_PATH_LINE_TO;
182 data->header.length = 2;
184 /* We index from 1 to leave room for data->header */
185 data[1].point.x = x;
186 data[1].point.y = y;
188 cpp->data += data->header.length;
190 cpp->current_point = *point;
192 return CAIRO_STATUS_SUCCESS;
195 static cairo_status_t
196 _cpp_curve_to (void *closure,
197 cairo_point_t *p1,
198 cairo_point_t *p2,
199 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_gstate_backend_to_user (cpp->gstate, &x1, &y1);
211 x2 = _cairo_fixed_to_double (p2->x);
212 y2 = _cairo_fixed_to_double (p2->y);
213 _cairo_gstate_backend_to_user (cpp->gstate, &x2, &y2);
215 x3 = _cairo_fixed_to_double (p3->x);
216 y3 = _cairo_fixed_to_double (p3->y);
217 _cairo_gstate_backend_to_user (cpp->gstate, &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 cpp->current_point = *p3;
236 return CAIRO_STATUS_SUCCESS;
239 static cairo_status_t
240 _cpp_close_path (void *closure)
242 cpp_t *cpp = closure;
243 cairo_path_data_t *data = cpp->data;
245 data->header.type = CAIRO_PATH_CLOSE_PATH;
246 data->header.length = 1;
248 cpp->data += data->header.length;
250 return CAIRO_STATUS_SUCCESS;
253 static cairo_status_t
254 _cairo_path_populate (cairo_path_t *path,
255 cairo_path_fixed_t *path_fixed,
256 cairo_gstate_t *gstate,
257 cairo_bool_t flatten)
259 cairo_status_t status;
260 cpp_t cpp;
262 cpp.data = path->data;
263 cpp.gstate = gstate;
264 cpp.current_point.x = 0;
265 cpp.current_point.y = 0;
267 if (flatten) {
268 double tolerance = _cairo_gstate_get_tolerance (gstate);
269 status = _cairo_path_fixed_interpret_flat (path_fixed,
270 CAIRO_DIRECTION_FORWARD,
271 _cpp_move_to,
272 _cpp_line_to,
273 _cpp_close_path,
274 &cpp,
275 tolerance);
276 } else {
277 status = _cairo_path_fixed_interpret (path_fixed,
278 CAIRO_DIRECTION_FORWARD,
279 _cpp_move_to,
280 _cpp_line_to,
281 _cpp_curve_to,
282 _cpp_close_path,
283 &cpp);
286 if (status)
287 return status;
289 /* Sanity check the count */
290 assert (cpp.data - path->data == path->num_data);
292 return CAIRO_STATUS_SUCCESS;
295 cairo_path_t *
296 _cairo_path_create_in_error (cairo_status_t status)
298 cairo_path_t *path;
300 /* special case NO_MEMORY so as to avoid allocations */
301 if (status == CAIRO_STATUS_NO_MEMORY)
302 return (cairo_path_t*) &_cairo_path_nil;
304 path = malloc (sizeof (cairo_path_t));
305 if (path == NULL) {
306 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
307 return (cairo_path_t*) &_cairo_path_nil;
310 path->num_data = 0;
311 path->data = NULL;
312 path->status = status;
314 return path;
317 static cairo_path_t *
318 _cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
319 cairo_gstate_t *gstate,
320 cairo_bool_t flatten)
322 cairo_path_t *path;
324 path = malloc (sizeof (cairo_path_t));
325 if (path == NULL) {
326 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
327 return (cairo_path_t*) &_cairo_path_nil;
330 path->num_data = _cairo_path_count (path, path_fixed,
331 _cairo_gstate_get_tolerance (gstate),
332 flatten);
333 if (path->num_data < 0) {
334 free (path);
335 return (cairo_path_t*) &_cairo_path_nil;
338 if (path->num_data) {
339 path->data = _cairo_malloc_ab (path->num_data,
340 sizeof (cairo_path_data_t));
341 if (path->data == NULL) {
342 free (path);
343 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
344 return (cairo_path_t*) &_cairo_path_nil;
347 path->status = _cairo_path_populate (path, path_fixed,
348 gstate, flatten);
349 } else {
350 path->data = NULL;
351 path->status = CAIRO_STATUS_SUCCESS;
354 return path;
358 * cairo_path_destroy:
359 * @path: a path previously returned by either cairo_copy_path() or
360 * cairo_copy_path_flat().
362 * Immediately releases all memory associated with @path. After a call
363 * to cairo_path_destroy() the @path pointer is no longer valid and
364 * should not be used further.
366 * Note: cairo_path_destroy() should only be called with a
367 * pointer to a #cairo_path_t returned by a cairo function. Any path
368 * that is created manually (ie. outside of cairo) should be destroyed
369 * manually as well.
371 void
372 cairo_path_destroy (cairo_path_t *path)
374 if (path == NULL || path == &_cairo_path_nil)
375 return;
377 if (path->data)
378 free (path->data);
380 free (path);
384 * _cairo_path_create:
385 * @path: a fixed-point, device-space path to be converted and copied
386 * @gstate: the current graphics state
388 * Creates a user-space #cairo_path_t copy of the given device-space
389 * @path. The @gstate parameter provides the inverse CTM for the
390 * conversion.
392 * Return value: the new copy of the path. If there is insufficient
393 * memory a pointer to a special static nil #cairo_path_t will be
394 * returned instead with status==%CAIRO_STATUS_NO_MEMORY and
395 * data==%NULL.
397 cairo_path_t *
398 _cairo_path_create (cairo_path_fixed_t *path,
399 cairo_gstate_t *gstate)
401 return _cairo_path_create_internal (path, gstate, FALSE);
405 * _cairo_path_create_flat:
406 * @path: a fixed-point, device-space path to be flattened, converted and copied
407 * @gstate: the current graphics state
409 * Creates a flattened, user-space #cairo_path_t copy of the given
410 * device-space @path. The @gstate parameter provide the inverse CTM
411 * for the conversion, as well as the tolerance value to control the
412 * accuracy of the flattening.
414 * Return value: the flattened copy of the path. If there is insufficient
415 * memory a pointer to a special static nil #cairo_path_t will be
416 * returned instead with status==%CAIRO_STATUS_NO_MEMORY and
417 * data==%NULL.
419 cairo_path_t *
420 _cairo_path_create_flat (cairo_path_fixed_t *path,
421 cairo_gstate_t *gstate)
423 return _cairo_path_create_internal (path, gstate, TRUE);
427 * _cairo_path_append_to_context:
428 * @path: the path data to be appended
429 * @cr: a cairo context
431 * Append @path to the current path within @cr.
433 * Return value: %CAIRO_STATUS_INVALID_PATH_DATA if the data in @path
434 * is invalid, and %CAIRO_STATUS_SUCCESS otherwise.
436 cairo_status_t
437 _cairo_path_append_to_context (const cairo_path_t *path,
438 cairo_t *cr)
440 int i;
441 cairo_path_data_t *p;
442 cairo_status_t status;
444 for (i=0; i < path->num_data; i += path->data[i].header.length) {
445 p = &path->data[i];
446 switch (p->header.type) {
447 case CAIRO_PATH_MOVE_TO:
448 if (p->header.length < 2)
449 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
450 cairo_move_to (cr,
451 p[1].point.x, p[1].point.y);
452 break;
453 case CAIRO_PATH_LINE_TO:
454 if (p->header.length < 2)
455 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
456 cairo_line_to (cr,
457 p[1].point.x, p[1].point.y);
458 break;
459 case CAIRO_PATH_CURVE_TO:
460 if (p->header.length < 4)
461 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
462 cairo_curve_to (cr,
463 p[1].point.x, p[1].point.y,
464 p[2].point.x, p[2].point.y,
465 p[3].point.x, p[3].point.y);
466 break;
467 case CAIRO_PATH_CLOSE_PATH:
468 if (p->header.length < 1)
469 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
470 cairo_close_path (cr);
471 break;
472 default:
473 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
476 status = cairo_status (cr);
477 if (status)
478 return status;
481 return CAIRO_STATUS_SUCCESS;