2 * Copyright © 2004 Carl Worth
3 * Copyright © 2006 Red Hat, Inc.
4 * Copyright © 2008 Chris Wilson
5 * Copyright © 2011 Intel Corporation
7 * This library is free software; you can redistribute it and/or
8 * modify it either under the terms of the GNU Lesser General Public
9 * License version 2.1 as published by the Free Software Foundation
10 * (the "LGPL") or, at your option, under the terms of the Mozilla
11 * Public License Version 1.1 (the "MPL"). If you do not alter this
12 * notice, a recipient may use your version of this file under either
13 * the MPL or the LGPL.
15 * You should have received a copy of the LGPL along with this library
16 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18 * You should have received a copy of the MPL along with this library
19 * in the file COPYING-MPL-1.1
21 * The contents of this file are subject to the Mozilla Public License
22 * Version 1.1 (the "License"); you may not use this file except in
23 * compliance with the License. You may obtain a copy of the License at
24 * http://www.mozilla.org/MPL/
26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28 * the specific language governing rights and limitations.
30 * The Original Code is the cairo graphics library.
32 * The Initial Developer of the Original Code is Carl Worth
35 * Carl D. Worth <cworth@cworth.org>
36 * Chris Wilson <chris@chris-wilson.co.uk>
41 #include "cairo-error-private.h"
42 #include "cairo-freelist-private.h"
43 #include "cairo-combsort-inline.h"
44 #include "cairo-contour-inline.h"
45 #include "cairo-contour-private.h"
48 _cairo_contour_init (cairo_contour_t
*contour
,
51 contour
->direction
= direction
;
52 contour
->chain
.points
= contour
->embedded_points
;
53 contour
->chain
.next
= NULL
;
54 contour
->chain
.num_points
= 0;
55 contour
->chain
.size_points
= ARRAY_LENGTH (contour
->embedded_points
);
56 contour
->tail
= &contour
->chain
;
60 __cairo_contour_add_point (cairo_contour_t
*contour
,
61 const cairo_point_t
*point
)
63 cairo_contour_chain_t
*tail
= contour
->tail
;
64 cairo_contour_chain_t
*next
;
66 assert (tail
->next
== NULL
);
68 next
= _cairo_malloc_ab_plus_c (tail
->size_points
*2,
69 sizeof (cairo_point_t
),
70 sizeof (cairo_contour_chain_t
));
71 if (unlikely (next
== NULL
))
72 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
74 next
->size_points
= tail
->size_points
*2;
76 next
->points
= (cairo_point_t
*)(next
+1);
81 next
->points
[0] = *point
;
82 return CAIRO_INT_STATUS_SUCCESS
;
86 first_inc (cairo_contour_t
*contour
,
88 cairo_contour_chain_t
**chain
)
90 if (*p
== (*chain
)->points
+ (*chain
)->num_points
) {
91 assert ((*chain
)->next
);
92 *chain
= (*chain
)->next
;
93 *p
= &(*chain
)->points
[0];
99 last_dec (cairo_contour_t
*contour
,
101 cairo_contour_chain_t
**chain
)
103 if (*p
== (*chain
)->points
) {
104 cairo_contour_chain_t
*prev
;
105 assert (*chain
!= &contour
->chain
);
106 for (prev
= &contour
->chain
; prev
->next
!= *chain
; prev
= prev
->next
)
109 *p
= &(*chain
)->points
[(*chain
)->num_points
-1];
115 _cairo_contour_reverse (cairo_contour_t
*contour
)
117 cairo_contour_chain_t
*first_chain
, *last_chain
;
118 cairo_point_t
*first
, *last
;
120 contour
->direction
= -contour
->direction
;
122 if (contour
->chain
.num_points
<= 1)
125 first_chain
= &contour
->chain
;
126 last_chain
= contour
->tail
;
128 first
= &first_chain
->points
[0];
129 last
= &last_chain
->points
[last_chain
->num_points
-1];
131 while (first
!= last
) {
138 first_inc (contour
, &first
, &first_chain
);
139 last_dec (contour
, &last
, &last_chain
);
144 _cairo_contour_add (cairo_contour_t
*dst
,
145 const cairo_contour_t
*src
)
147 const cairo_contour_chain_t
*chain
;
148 cairo_int_status_t status
;
151 for (chain
= &src
->chain
; chain
; chain
= chain
->next
) {
152 for (i
= 0; i
< chain
->num_points
; i
++) {
153 status
= _cairo_contour_add_point (dst
, &chain
->points
[i
]);
154 if (unlikely (status
))
159 return CAIRO_INT_STATUS_SUCCESS
;
162 static inline cairo_bool_t
163 iter_next (cairo_contour_iter_t
*iter
)
165 if (iter
->point
== &iter
->chain
->points
[iter
->chain
->size_points
-1]) {
166 iter
->chain
= iter
->chain
->next
;
167 if (iter
->chain
== NULL
)
170 iter
->point
= &iter
->chain
->points
[0];
179 iter_equal (const cairo_contour_iter_t
*i1
,
180 const cairo_contour_iter_t
*i2
)
182 return i1
->chain
== i2
->chain
&& i1
->point
== i2
->point
;
186 iter_init (cairo_contour_iter_t
*iter
, cairo_contour_t
*contour
)
188 iter
->chain
= &contour
->chain
;
189 iter
->point
= &contour
->chain
.points
[0];
193 iter_init_last (cairo_contour_iter_t
*iter
, cairo_contour_t
*contour
)
195 iter
->chain
= contour
->tail
;
196 iter
->point
= &contour
->tail
->points
[contour
->tail
->num_points
-1];
199 static const cairo_contour_chain_t
*prev_const_chain(const cairo_contour_t
*contour
,
200 const cairo_contour_chain_t
*chain
)
202 const cairo_contour_chain_t
*prev
;
204 if (chain
== &contour
->chain
)
207 for (prev
= &contour
->chain
; prev
->next
!= chain
; prev
= prev
->next
)
214 _cairo_contour_add_reversed (cairo_contour_t
*dst
,
215 const cairo_contour_t
*src
)
217 const cairo_contour_chain_t
*last
;
218 cairo_int_status_t status
;
221 if (src
->chain
.num_points
== 0)
222 return CAIRO_INT_STATUS_SUCCESS
;
224 for (last
= src
->tail
; last
; last
= prev_const_chain (src
, last
)) {
225 for (i
= last
->num_points
-1; i
>= 0; i
--) {
226 status
= _cairo_contour_add_point (dst
, &last
->points
[i
]);
227 if (unlikely (status
))
232 return CAIRO_INT_STATUS_SUCCESS
;
235 static cairo_uint64_t
236 point_distance_sq (const cairo_point_t
*p1
,
237 const cairo_point_t
*p2
)
239 int32_t dx
= p1
->x
- p2
->x
;
240 int32_t dy
= p1
->y
- p2
->y
;
241 return _cairo_int32x32_64_mul (dx
, dx
) + _cairo_int32x32_64_mul (dy
, dy
);
244 #define DELETED(p) ((p)->x == INT_MIN && (p)->y == INT_MAX)
245 #define MARK_DELETED(p) ((p)->x = INT_MIN, (p)->y = INT_MAX)
248 _cairo_contour_simplify_chain (cairo_contour_t
*contour
, const double tolerance
,
249 const cairo_contour_iter_t
*first
,
250 const cairo_contour_iter_t
*last
)
252 cairo_contour_iter_t iter
, furthest
;
260 if (iter_equal (&iter
, last
))
263 x0
= first
->point
->x
;
264 y0
= first
->point
->y
;
265 nx
= last
->point
->y
- y0
;
266 ny
= x0
- last
->point
->x
;
271 cairo_point_t
*p
= iter
.point
;
273 uint64_t d
= (uint64_t)nx
* (x0
- p
->x
) + (uint64_t)ny
* (y0
- p
->y
);
274 if (d
* d
> max_error
) {
281 } while (! iter_equal (&iter
, last
));
285 if (max_error
> tolerance
* ((uint64_t)nx
* nx
+ (uint64_t)ny
* ny
)) {
286 cairo_bool_t simplified
;
289 simplified
|= _cairo_contour_simplify_chain (contour
, tolerance
,
291 simplified
|= _cairo_contour_simplify_chain (contour
, tolerance
,
298 MARK_DELETED (iter
.point
);
300 } while (! iter_equal (&iter
, last
));
307 _cairo_contour_simplify (cairo_contour_t
*contour
, double tolerance
)
309 cairo_contour_chain_t
*chain
;
310 cairo_point_t
*last
= NULL
;
311 cairo_contour_iter_t iter
, furthest
;
312 cairo_bool_t simplified
;
316 if (contour
->chain
.num_points
<= 2)
319 tolerance
= tolerance
* CAIRO_FIXED_ONE
;
320 tolerance
*= tolerance
;
322 /* stage 1: vertex reduction */
323 for (chain
= &contour
->chain
; chain
; chain
= chain
->next
) {
324 for (i
= 0; i
< chain
->num_points
; i
++) {
326 point_distance_sq (last
, &chain
->points
[i
]) > tolerance
) {
327 last
= &chain
->points
[i
];
329 MARK_DELETED (&chain
->points
[i
]);
334 /* stage2: polygon simplification using Douglas-Peucker */
336 last
= &contour
->chain
.points
[0];
337 iter_init (&furthest
, contour
);
339 for (chain
= &contour
->chain
; chain
; chain
= chain
->next
) {
340 for (i
= 0; i
< chain
->num_points
; i
++) {
343 if (DELETED (&chain
->points
[i
]))
346 d
= point_distance_sq (last
, &chain
->points
[i
]);
348 furthest
.chain
= chain
;
349 furthest
.point
= &chain
->points
[i
];
357 iter_init (&iter
, contour
);
358 simplified
|= _cairo_contour_simplify_chain (contour
, tolerance
,
361 iter_init_last (&iter
, contour
);
362 if (! iter_equal (&furthest
, &iter
))
363 simplified
|= _cairo_contour_simplify_chain (contour
, tolerance
,
365 } while (simplified
);
367 iter_init (&iter
, contour
);
368 for (chain
= &contour
->chain
; chain
; chain
= chain
->next
) {
369 int num_points
= chain
->num_points
;
370 chain
->num_points
= 0;
371 for (i
= 0; i
< num_points
; i
++) {
372 if (! DELETED(&chain
->points
[i
])) {
373 if (iter
.point
!= &chain
->points
[i
])
374 *iter
.point
= chain
->points
[i
];
375 iter
.chain
->num_points
++;
382 cairo_contour_chain_t
*next
;
384 for (chain
= iter
.chain
->next
; chain
; chain
= next
) {
389 iter
.chain
->next
= NULL
;
390 contour
->tail
= iter
.chain
;
395 _cairo_contour_reset (cairo_contour_t
*contour
)
397 _cairo_contour_fini (contour
);
398 _cairo_contour_init (contour
, contour
->direction
);
402 _cairo_contour_fini (cairo_contour_t
*contour
)
404 cairo_contour_chain_t
*chain
, *next
;
406 for (chain
= contour
->chain
.next
; chain
; chain
= next
) {
413 _cairo_debug_print_contour (FILE *file
, cairo_contour_t
*contour
)
415 cairo_contour_chain_t
*chain
;
416 int num_points
, size_points
;
421 for (chain
= &contour
->chain
; chain
; chain
= chain
->next
) {
422 num_points
+= chain
->num_points
;
423 size_points
+= chain
->size_points
;
426 fprintf (file
, "contour: direction=%d, num_points=%d / %d\n",
427 contour
->direction
, num_points
, size_points
);
430 for (chain
= &contour
->chain
; chain
; chain
= chain
->next
) {
431 for (i
= 0; i
< chain
->num_points
; i
++) {
432 fprintf (file
, " [%d] = (%f, %f)\n",
434 _cairo_fixed_to_double (chain
->points
[i
].x
),
435 _cairo_fixed_to_double (chain
->points
[i
].y
));
441 __cairo_contour_remove_last_chain (cairo_contour_t
*contour
)
443 cairo_contour_chain_t
*chain
;
445 if (contour
->tail
== &contour
->chain
)
448 for (chain
= &contour
->chain
; chain
->next
!= contour
->tail
; chain
= chain
->next
)
450 free (contour
->tail
);
451 contour
->tail
= chain
;