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.
34 * Carl D. Worth <cworth@redhat.com>
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
{
47 cairo_point_t current_point
;
51 _cpc_move_to (void *closure
, cairo_point_t
*point
)
57 cpc
->current_point
= *point
;
59 return CAIRO_STATUS_SUCCESS
;
63 _cpc_line_to (void *closure
, cairo_point_t
*point
)
69 cpc
->current_point
= *point
;
71 return CAIRO_STATUS_SUCCESS
;
75 _cpc_curve_to (void *closure
,
84 cpc
->current_point
= *p3
;
86 return CAIRO_STATUS_SUCCESS
;
90 _cpc_close_path (void *closure
)
96 return CAIRO_STATUS_SUCCESS
;
100 _cairo_path_count (cairo_path_t
*path
,
101 cairo_path_fixed_t
*path_fixed
,
103 cairo_bool_t flatten
)
105 cairo_status_t status
;
109 cpc
.current_point
.x
= 0;
110 cpc
.current_point
.y
= 0;
113 status
= _cairo_path_fixed_interpret_flat (path_fixed
,
114 CAIRO_DIRECTION_FORWARD
,
121 status
= _cairo_path_fixed_interpret (path_fixed
,
122 CAIRO_DIRECTION_FORWARD
,
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
;
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
;
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 */
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
;
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 */
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
,
201 cpp_t
*cpp
= closure
;
202 cairo_path_data_t
*data
= cpp
->data
;
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
;
262 cpp
.data
= path
->data
;
264 cpp
.current_point
.x
= 0;
265 cpp
.current_point
.y
= 0;
268 double tolerance
= _cairo_gstate_get_tolerance (gstate
);
269 status
= _cairo_path_fixed_interpret_flat (path_fixed
,
270 CAIRO_DIRECTION_FORWARD
,
277 status
= _cairo_path_fixed_interpret (path_fixed
,
278 CAIRO_DIRECTION_FORWARD
,
289 /* Sanity check the count */
290 assert (cpp
.data
- path
->data
== path
->num_data
);
292 return CAIRO_STATUS_SUCCESS
;
296 _cairo_path_create_in_error (cairo_status_t status
)
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
));
306 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
307 return (cairo_path_t
*) &_cairo_path_nil
;
312 path
->status
= status
;
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
)
324 path
= malloc (sizeof (cairo_path_t
));
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
),
333 if (path
->num_data
< 0) {
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
) {
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
,
351 path
->status
= CAIRO_STATUS_SUCCESS
;
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
372 cairo_path_destroy (cairo_path_t
*path
)
374 if (path
== NULL
|| path
== &_cairo_path_nil
)
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
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
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
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.
437 _cairo_path_append_to_context (const cairo_path_t
*path
,
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
) {
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
);
451 p
[1].point
.x
, p
[1].point
.y
);
453 case CAIRO_PATH_LINE_TO
:
454 if (p
->header
.length
< 2)
455 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA
);
457 p
[1].point
.x
, p
[1].point
.y
);
459 case CAIRO_PATH_CURVE_TO
:
460 if (p
->header
.length
< 4)
461 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA
);
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
);
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
);
473 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA
);
476 status
= cairo_status (cr
);
481 return CAIRO_STATUS_SUCCESS
;