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.
34 * Carl D. Worth <cworth@redhat.com>
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"
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.
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
{
62 _cpc_move_to (void *closure
,
63 const cairo_point_t
*point
)
69 return CAIRO_STATUS_SUCCESS
;
73 _cpc_line_to (void *closure
,
74 const cairo_point_t
*point
)
80 return CAIRO_STATUS_SUCCESS
;
84 _cpc_curve_to (void *closure
,
85 const cairo_point_t
*p1
,
86 const cairo_point_t
*p2
,
87 const cairo_point_t
*p3
)
93 return CAIRO_STATUS_SUCCESS
;
97 _cpc_close_path (void *closure
)
103 return CAIRO_STATUS_SUCCESS
;
107 _cairo_path_count (cairo_path_t
*path
,
108 cairo_path_fixed_t
*path_fixed
,
110 cairo_bool_t flatten
)
112 cairo_status_t status
;
118 status
= _cairo_path_fixed_interpret_flat (path_fixed
,
125 status
= _cairo_path_fixed_interpret (path_fixed
,
133 if (unlikely (status
))
139 /* Closure for path interpretation. */
140 typedef struct cairo_path_populate
{
141 cairo_path_data_t
*data
;
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
;
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 */
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
;
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 */
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
;
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
,
255 cairo_bool_t flatten
)
257 cairo_status_t status
;
260 cpp
.data
= path
->data
;
264 status
= _cairo_path_fixed_interpret_flat (path_fixed
,
269 cairo_get_tolerance (cr
));
271 status
= _cairo_path_fixed_interpret (path_fixed
,
279 if (unlikely (status
))
282 /* Sanity check the count */
283 assert (cpp
.data
- path
->data
== path
->num_data
);
285 return CAIRO_STATUS_SUCCESS
;
289 _cairo_path_create_in_error (cairo_status_t status
)
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
;
305 path
->status
= status
;
310 static cairo_path_t
*
311 _cairo_path_create_internal (cairo_path_fixed_t
*path_fixed
,
313 cairo_bool_t flatten
)
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
),
326 if (path
->num_data
< 0) {
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
)) {
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
);
343 path
->status
= CAIRO_STATUS_SUCCESS
;
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
366 cairo_path_destroy (cairo_path_t
*path
)
368 if (path
== NULL
|| path
== &_cairo_path_nil
)
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
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
392 _cairo_path_create (cairo_path_fixed_t
*path
,
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
414 _cairo_path_create_flat (cairo_path_fixed_t
*path
,
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.
431 _cairo_path_append_to_context (const cairo_path_t
*path
,
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
);
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
);
453 case CAIRO_PATH_CURVE_TO
:
454 if (unlikely (p
->header
.length
< 4))
455 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA
);
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
);
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
);
471 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA
);
474 if (unlikely (cr
->status
))
478 return CAIRO_STATUS_SUCCESS
;