new beta-0.90.0
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-boxes.c
blob63b68ddfb90867d47b8ec7f6209b5ecf9b045c23
1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2009 Intel Corporation
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
28 * The Original Code is the cairo graphics library.
30 * Contributor(s):
31 * Chris Wilson <chris@chris-wilson.co.uk>
34 #include "cairoint.h"
36 #include "cairo-box-inline.h"
37 #include "cairo-boxes-private.h"
38 #include "cairo-error-private.h"
40 void
41 _cairo_boxes_init (cairo_boxes_t *boxes)
43 boxes->status = CAIRO_STATUS_SUCCESS;
44 boxes->num_limits = 0;
45 boxes->num_boxes = 0;
47 boxes->tail = &boxes->chunks;
48 boxes->chunks.next = NULL;
49 boxes->chunks.base = boxes->boxes_embedded;
50 boxes->chunks.size = ARRAY_LENGTH (boxes->boxes_embedded);
51 boxes->chunks.count = 0;
53 boxes->is_pixel_aligned = TRUE;
56 void
57 _cairo_boxes_init_from_rectangle (cairo_boxes_t *boxes,
58 int x, int y, int w, int h)
60 _cairo_boxes_init (boxes);
62 _cairo_box_from_integers (&boxes->chunks.base[0], x, y, w, h);
63 boxes->num_boxes = 1;
66 void
67 _cairo_boxes_init_with_clip (cairo_boxes_t *boxes,
68 cairo_clip_t *clip)
70 _cairo_boxes_init (boxes);
71 if (clip)
72 _cairo_boxes_limit (boxes, clip->boxes, clip->num_boxes);
75 void
76 _cairo_boxes_init_for_array (cairo_boxes_t *boxes,
77 cairo_box_t *array,
78 int num_boxes)
80 int n;
82 boxes->status = CAIRO_STATUS_SUCCESS;
83 boxes->num_limits = 0;
84 boxes->num_boxes = num_boxes;
86 boxes->tail = &boxes->chunks;
87 boxes->chunks.next = NULL;
88 boxes->chunks.base = array;
89 boxes->chunks.size = num_boxes;
90 boxes->chunks.count = num_boxes;
92 for (n = 0; n < num_boxes; n++) {
93 if (! _cairo_fixed_is_integer (array[n].p1.x) ||
94 ! _cairo_fixed_is_integer (array[n].p1.y) ||
95 ! _cairo_fixed_is_integer (array[n].p2.x) ||
96 ! _cairo_fixed_is_integer (array[n].p2.y))
98 break;
102 boxes->is_pixel_aligned = n == num_boxes;
105 void
106 _cairo_boxes_limit (cairo_boxes_t *boxes,
107 const cairo_box_t *limits,
108 int num_limits)
110 int n;
112 boxes->limits = limits;
113 boxes->num_limits = num_limits;
115 if (boxes->num_limits) {
116 boxes->limit = limits[0];
117 for (n = 1; n < num_limits; n++) {
118 if (limits[n].p1.x < boxes->limit.p1.x)
119 boxes->limit.p1.x = limits[n].p1.x;
121 if (limits[n].p1.y < boxes->limit.p1.y)
122 boxes->limit.p1.y = limits[n].p1.y;
124 if (limits[n].p2.x > boxes->limit.p2.x)
125 boxes->limit.p2.x = limits[n].p2.x;
127 if (limits[n].p2.y > boxes->limit.p2.y)
128 boxes->limit.p2.y = limits[n].p2.y;
133 static void
134 _cairo_boxes_add_internal (cairo_boxes_t *boxes,
135 const cairo_box_t *box)
137 struct _cairo_boxes_chunk *chunk;
139 if (unlikely (boxes->status))
140 return;
142 chunk = boxes->tail;
143 if (unlikely (chunk->count == chunk->size)) {
144 int size;
146 size = chunk->size * 2;
147 chunk->next = _cairo_malloc_ab_plus_c (size,
148 sizeof (cairo_box_t),
149 sizeof (struct _cairo_boxes_chunk));
151 if (unlikely (chunk->next == NULL)) {
152 boxes->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
153 return;
156 chunk = chunk->next;
157 boxes->tail = chunk;
159 chunk->next = NULL;
160 chunk->count = 0;
161 chunk->size = size;
162 chunk->base = (cairo_box_t *) (chunk + 1);
165 chunk->base[chunk->count++] = *box;
166 boxes->num_boxes++;
168 if (boxes->is_pixel_aligned)
169 boxes->is_pixel_aligned = _cairo_box_is_pixel_aligned (box);
172 cairo_status_t
173 _cairo_boxes_add (cairo_boxes_t *boxes,
174 cairo_antialias_t antialias,
175 const cairo_box_t *box)
177 cairo_box_t b;
179 if (antialias == CAIRO_ANTIALIAS_NONE) {
180 b.p1.x = _cairo_fixed_round_down (box->p1.x);
181 b.p1.y = _cairo_fixed_round_down (box->p1.y);
182 b.p2.x = _cairo_fixed_round_down (box->p2.x);
183 b.p2.y = _cairo_fixed_round_down (box->p2.y);
184 box = &b;
187 if (box->p1.y == box->p2.y)
188 return CAIRO_STATUS_SUCCESS;
190 if (box->p1.x == box->p2.x)
191 return CAIRO_STATUS_SUCCESS;
193 if (boxes->num_limits) {
194 cairo_point_t p1, p2;
195 cairo_bool_t reversed = FALSE;
196 int n;
198 /* support counter-clockwise winding for rectangular tessellation */
199 if (box->p1.x < box->p2.x) {
200 p1.x = box->p1.x;
201 p2.x = box->p2.x;
202 } else {
203 p2.x = box->p1.x;
204 p1.x = box->p2.x;
205 reversed = ! reversed;
208 if (p1.x >= boxes->limit.p2.x || p2.x <= boxes->limit.p1.x)
209 return CAIRO_STATUS_SUCCESS;
211 if (box->p1.y < box->p2.y) {
212 p1.y = box->p1.y;
213 p2.y = box->p2.y;
214 } else {
215 p2.y = box->p1.y;
216 p1.y = box->p2.y;
217 reversed = ! reversed;
220 if (p1.y >= boxes->limit.p2.y || p2.y <= boxes->limit.p1.y)
221 return CAIRO_STATUS_SUCCESS;
223 for (n = 0; n < boxes->num_limits; n++) {
224 const cairo_box_t *limits = &boxes->limits[n];
225 cairo_box_t _box;
226 cairo_point_t _p1, _p2;
228 if (p1.x >= limits->p2.x || p2.x <= limits->p1.x)
229 continue;
230 if (p1.y >= limits->p2.y || p2.y <= limits->p1.y)
231 continue;
233 /* Otherwise, clip the box to the limits. */
234 _p1 = p1;
235 if (_p1.x < limits->p1.x)
236 _p1.x = limits->p1.x;
237 if (_p1.y < limits->p1.y)
238 _p1.y = limits->p1.y;
240 _p2 = p2;
241 if (_p2.x > limits->p2.x)
242 _p2.x = limits->p2.x;
243 if (_p2.y > limits->p2.y)
244 _p2.y = limits->p2.y;
246 if (_p2.y <= _p1.y || _p2.x <= _p1.x)
247 continue;
249 _box.p1.y = _p1.y;
250 _box.p2.y = _p2.y;
251 if (reversed) {
252 _box.p1.x = _p2.x;
253 _box.p2.x = _p1.x;
254 } else {
255 _box.p1.x = _p1.x;
256 _box.p2.x = _p2.x;
259 _cairo_boxes_add_internal (boxes, &_box);
261 } else {
262 _cairo_boxes_add_internal (boxes, box);
265 return boxes->status;
268 void
269 _cairo_boxes_extents (const cairo_boxes_t *boxes,
270 cairo_box_t *box)
272 const struct _cairo_boxes_chunk *chunk;
273 cairo_box_t b;
274 int i;
276 if (boxes->num_boxes == 0) {
277 box->p1.x = box->p1.y = box->p2.x = box->p2.y = 0;
278 return;
281 b = boxes->chunks.base[0];
282 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
283 for (i = 0; i < chunk->count; i++) {
284 if (chunk->base[i].p1.x < b.p1.x)
285 b.p1.x = chunk->base[i].p1.x;
287 if (chunk->base[i].p1.y < b.p1.y)
288 b.p1.y = chunk->base[i].p1.y;
290 if (chunk->base[i].p2.x > b.p2.x)
291 b.p2.x = chunk->base[i].p2.x;
293 if (chunk->base[i].p2.y > b.p2.y)
294 b.p2.y = chunk->base[i].p2.y;
297 *box = b;
300 void
301 _cairo_boxes_clear (cairo_boxes_t *boxes)
303 struct _cairo_boxes_chunk *chunk, *next;
305 for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) {
306 next = chunk->next;
307 free (chunk);
310 boxes->tail = &boxes->chunks;
311 boxes->chunks.next = 0;
312 boxes->chunks.count = 0;
313 boxes->chunks.base = boxes->boxes_embedded;
314 boxes->chunks.size = ARRAY_LENGTH (boxes->boxes_embedded);
315 boxes->num_boxes = 0;
317 boxes->is_pixel_aligned = TRUE;
320 cairo_box_t *
321 _cairo_boxes_to_array (const cairo_boxes_t *boxes,
322 int *num_boxes,
323 cairo_bool_t force_allocation)
325 const struct _cairo_boxes_chunk *chunk;
326 cairo_box_t *box;
327 int i, j;
329 *num_boxes = boxes->num_boxes;
330 if (boxes->chunks.next == NULL && ! force_allocation)
331 return boxes->chunks.base;
333 box = _cairo_malloc_ab (boxes->num_boxes, sizeof (cairo_box_t));
334 if (box == NULL) {
335 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
336 return NULL;
339 j = 0;
340 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
341 for (i = 0; i < chunk->count; i++)
342 box[j++] = chunk->base[i];
345 return box;
348 void
349 _cairo_boxes_fini (cairo_boxes_t *boxes)
351 struct _cairo_boxes_chunk *chunk, *next;
353 for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) {
354 next = chunk->next;
355 free (chunk);
359 cairo_bool_t
360 _cairo_boxes_for_each_box (cairo_boxes_t *boxes,
361 cairo_bool_t (*func) (cairo_box_t *box, void *data),
362 void *data)
364 struct _cairo_boxes_chunk *chunk;
365 int i;
367 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
368 for (i = 0; i < chunk->count; i++)
369 if (! func (&chunk->base[i], data))
370 return FALSE;
373 return TRUE;
376 struct cairo_box_renderer {
377 cairo_span_renderer_t base;
378 cairo_boxes_t *boxes;
381 static cairo_status_t
382 span_to_boxes (void *abstract_renderer, int y, int h,
383 const cairo_half_open_span_t *spans, unsigned num_spans)
385 struct cairo_box_renderer *r = abstract_renderer;
386 cairo_status_t status = CAIRO_STATUS_SUCCESS;
387 cairo_box_t box;
389 if (num_spans == 0)
390 return CAIRO_STATUS_SUCCESS;
392 box.p1.y = _cairo_fixed_from_int (y);
393 box.p2.y = _cairo_fixed_from_int (y + h);
394 do {
395 if (spans[0].coverage) {
396 box.p1.x = _cairo_fixed_from_int(spans[0].x);
397 box.p2.x = _cairo_fixed_from_int(spans[1].x);
398 status = _cairo_boxes_add (r->boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
400 spans++;
401 } while (--num_spans > 1 && status == CAIRO_STATUS_SUCCESS);
403 return status;
406 cairo_status_t
407 _cairo_rasterise_polygon_to_boxes (cairo_polygon_t *polygon,
408 cairo_fill_rule_t fill_rule,
409 cairo_boxes_t *boxes)
411 struct cairo_box_renderer renderer;
412 cairo_scan_converter_t *converter;
413 cairo_int_status_t status;
414 cairo_rectangle_int_t r;
416 TRACE ((stderr, "%s: fill_rule=%d\n", __FUNCTION__, fill_rule));
418 _cairo_box_round_to_rectangle (&polygon->extents, &r);
419 converter = _cairo_mono_scan_converter_create (r.x, r.y,
420 r.x + r.width,
421 r.y + r.height,
422 fill_rule);
423 status = _cairo_mono_scan_converter_add_polygon (converter, polygon);
424 if (unlikely (status))
425 goto cleanup_converter;
427 renderer.boxes = boxes;
428 renderer.base.render_rows = span_to_boxes;
430 status = converter->generate (converter, &renderer.base);
431 cleanup_converter:
432 converter->destroy (converter);
433 return status;
436 void
437 _cairo_debug_print_boxes (FILE *stream, const cairo_boxes_t *boxes)
439 const struct _cairo_boxes_chunk *chunk;
440 cairo_box_t extents;
441 int i;
443 _cairo_boxes_extents (boxes, &extents);
444 fprintf (stream, "boxes x %d: (%f, %f) x (%f, %f)\n",
445 boxes->num_boxes,
446 _cairo_fixed_to_double (extents.p1.x),
447 _cairo_fixed_to_double (extents.p1.y),
448 _cairo_fixed_to_double (extents.p2.x),
449 _cairo_fixed_to_double (extents.p2.y));
451 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
452 for (i = 0; i < chunk->count; i++) {
453 fprintf (stderr, " box[%d]: (%f, %f), (%f, %f)\n", i,
454 _cairo_fixed_to_double (chunk->base[i].p1.x),
455 _cairo_fixed_to_double (chunk->base[i].p1.y),
456 _cairo_fixed_to_double (chunk->base[i].p2.x),
457 _cairo_fixed_to_double (chunk->base[i].p2.y));