beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-contour.c
blob9ad75bdbf8df670e01ca338b8eac0830b4838282
1 /*
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
34 * Contributor(s):
35 * Carl D. Worth <cworth@cworth.org>
36 * Chris Wilson <chris@chris-wilson.co.uk>
39 #include "cairoint.h"
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"
47 void
48 _cairo_contour_init (cairo_contour_t *contour,
49 int direction)
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;
59 cairo_int_status_t
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;
75 next->num_points = 1;
76 next->points = (cairo_point_t *)(next+1);
77 next->next = NULL;
78 tail->next = next;
79 contour->tail = next;
81 next->points[0] = *point;
82 return CAIRO_INT_STATUS_SUCCESS;
85 static void
86 first_inc (cairo_contour_t *contour,
87 cairo_point_t **p,
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];
94 } else
95 ++*p;
98 static void
99 last_dec (cairo_contour_t *contour,
100 cairo_point_t **p,
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)
108 *chain = prev;
109 *p = &(*chain)->points[(*chain)->num_points-1];
110 } else
111 --*p;
114 void
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)
123 return;
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) {
132 cairo_point_t p;
134 p = *first;
135 *first = *last;
136 *last = p;
138 first_inc (contour, &first, &first_chain);
139 last_dec (contour, &last, &last_chain);
143 cairo_int_status_t
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;
149 int i;
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))
155 return 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)
168 return FALSE;
170 iter->point = &iter->chain->points[0];
171 return TRUE;
172 } else {
173 iter->point++;
174 return TRUE;
178 static cairo_bool_t
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;
185 static void
186 iter_init (cairo_contour_iter_t *iter, cairo_contour_t *contour)
188 iter->chain = &contour->chain;
189 iter->point = &contour->chain.points[0];
192 static void
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)
205 return NULL;
207 for (prev = &contour->chain; prev->next != chain; prev = prev->next)
210 return prev;
213 cairo_int_status_t
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;
219 int i;
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))
228 return 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)
247 static cairo_bool_t
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;
253 uint64_t max_error;
254 int x0, y0;
255 int nx, ny;
256 int count;
258 iter = *first;
259 iter_next (&iter);
260 if (iter_equal (&iter, last))
261 return FALSE;
263 x0 = first->point->x;
264 y0 = first->point->y;
265 nx = last->point->y - y0;
266 ny = x0 - last->point->x;
268 count = 0;
269 max_error = 0;
270 do {
271 cairo_point_t *p = iter.point;
272 if (! DELETED(p)) {
273 uint64_t d = (uint64_t)nx * (x0 - p->x) + (uint64_t)ny * (y0 - p->y);
274 if (d * d > max_error) {
275 max_error = d * d;
276 furthest = iter;
278 count++;
280 iter_next (&iter);
281 } while (! iter_equal (&iter, last));
282 if (count == 0)
283 return FALSE;
285 if (max_error > tolerance * ((uint64_t)nx * nx + (uint64_t)ny * ny)) {
286 cairo_bool_t simplified;
288 simplified = FALSE;
289 simplified |= _cairo_contour_simplify_chain (contour, tolerance,
290 first, &furthest);
291 simplified |= _cairo_contour_simplify_chain (contour, tolerance,
292 &furthest, last);
293 return simplified;
294 } else {
295 iter = *first;
296 iter_next (&iter);
297 do {
298 MARK_DELETED (iter.point);
299 iter_next (&iter);
300 } while (! iter_equal (&iter, last));
302 return TRUE;
306 void
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;
313 uint64_t max = 0;
314 int i;
316 if (contour->chain.num_points <= 2)
317 return;
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++) {
325 if (last == NULL ||
326 point_distance_sq (last, &chain->points[i]) > tolerance) {
327 last = &chain->points[i];
328 } else {
329 MARK_DELETED (&chain->points[i]);
334 /* stage2: polygon simplification using Douglas-Peucker */
335 do {
336 last = &contour->chain.points[0];
337 iter_init (&furthest, contour);
338 max = 0;
339 for (chain = &contour->chain; chain; chain = chain->next) {
340 for (i = 0; i < chain->num_points; i++) {
341 uint64_t d;
343 if (DELETED (&chain->points[i]))
344 continue;
346 d = point_distance_sq (last, &chain->points[i]);
347 if (d > max) {
348 furthest.chain = chain;
349 furthest.point = &chain->points[i];
350 max = d;
354 assert (max);
356 simplified = FALSE;
357 iter_init (&iter, contour);
358 simplified |= _cairo_contour_simplify_chain (contour, tolerance,
359 &iter, &furthest);
361 iter_init_last (&iter, contour);
362 if (! iter_equal (&furthest, &iter))
363 simplified |= _cairo_contour_simplify_chain (contour, tolerance,
364 &furthest, &iter);
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++;
376 iter_next (&iter);
381 if (iter.chain) {
382 cairo_contour_chain_t *next;
384 for (chain = iter.chain->next; chain; chain = next) {
385 next = chain->next;
386 free (chain);
389 iter.chain->next = NULL;
390 contour->tail = iter.chain;
394 void
395 _cairo_contour_reset (cairo_contour_t *contour)
397 _cairo_contour_fini (contour);
398 _cairo_contour_init (contour, contour->direction);
401 void
402 _cairo_contour_fini (cairo_contour_t *contour)
404 cairo_contour_chain_t *chain, *next;
406 for (chain = contour->chain.next; chain; chain = next) {
407 next = chain->next;
408 free (chain);
412 void
413 _cairo_debug_print_contour (FILE *file, cairo_contour_t *contour)
415 cairo_contour_chain_t *chain;
416 int num_points, size_points;
417 int i;
419 num_points = 0;
420 size_points = 0;
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);
429 num_points = 0;
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",
433 num_points++,
434 _cairo_fixed_to_double (chain->points[i].x),
435 _cairo_fixed_to_double (chain->points[i].y));
440 void
441 __cairo_contour_remove_last_chain (cairo_contour_t *contour)
443 cairo_contour_chain_t *chain;
445 if (contour->tail == &contour->chain)
446 return;
448 for (chain = &contour->chain; chain->next != contour->tail; chain = chain->next)
450 free (contour->tail);
451 contour->tail = chain;
452 chain->next = NULL;