/work/workdir/UnpackedTarball/cairo/src/cairo-boxes.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* cairo - a vector graphics library with display and print output |
2 | | * |
3 | | * Copyright © 2009 Intel Corporation |
4 | | * |
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. |
12 | | * |
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 |
18 | | * |
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/ |
23 | | * |
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. |
27 | | * |
28 | | * The Original Code is the cairo graphics library. |
29 | | * |
30 | | * Contributor(s): |
31 | | * Chris Wilson <chris@chris-wilson.co.uk> |
32 | | */ |
33 | | |
34 | | #include "cairoint.h" |
35 | | |
36 | | #include "cairo-box-inline.h" |
37 | | #include "cairo-boxes-private.h" |
38 | | #include "cairo-error-private.h" |
39 | | |
40 | | void |
41 | | _cairo_boxes_init (cairo_boxes_t *boxes) |
42 | 534k | { |
43 | 534k | boxes->status = CAIRO_STATUS_SUCCESS; |
44 | 534k | boxes->limits = NULL; |
45 | 534k | boxes->num_limits = 0; |
46 | 534k | boxes->num_boxes = 0; |
47 | | |
48 | 534k | boxes->tail = &boxes->chunks; |
49 | 534k | boxes->chunks.next = NULL; |
50 | 534k | boxes->chunks.base = boxes->boxes_embedded; |
51 | 534k | boxes->chunks.size = ARRAY_LENGTH (boxes->boxes_embedded); |
52 | 534k | boxes->chunks.count = 0; |
53 | | |
54 | 534k | boxes->is_pixel_aligned = TRUE; |
55 | 534k | } |
56 | | |
57 | | void |
58 | | _cairo_boxes_init_from_rectangle (cairo_boxes_t *boxes, |
59 | | int x, int y, int w, int h) |
60 | 0 | { |
61 | 0 | _cairo_boxes_init (boxes); |
62 | |
|
63 | 0 | _cairo_box_from_integers (&boxes->chunks.base[0], x, y, w, h); |
64 | 0 | boxes->num_boxes = 1; |
65 | 0 | } |
66 | | |
67 | | void |
68 | | _cairo_boxes_init_with_clip (cairo_boxes_t *boxes, |
69 | | cairo_clip_t *clip) |
70 | 0 | { |
71 | 0 | _cairo_boxes_init (boxes); |
72 | 0 | if (clip) |
73 | 0 | _cairo_boxes_limit (boxes, clip->boxes, clip->num_boxes); |
74 | 0 | } |
75 | | |
76 | | void |
77 | | _cairo_boxes_init_for_array (cairo_boxes_t *boxes, |
78 | | cairo_box_t *array, |
79 | | int num_boxes) |
80 | 686k | { |
81 | 686k | int n; |
82 | | |
83 | 686k | boxes->status = CAIRO_STATUS_SUCCESS; |
84 | 686k | boxes->num_limits = 0; |
85 | 686k | boxes->num_boxes = num_boxes; |
86 | | |
87 | 686k | boxes->tail = &boxes->chunks; |
88 | 686k | boxes->chunks.next = NULL; |
89 | 686k | boxes->chunks.base = array; |
90 | 686k | boxes->chunks.size = num_boxes; |
91 | 686k | boxes->chunks.count = num_boxes; |
92 | | |
93 | 1.37M | for (n = 0; n < num_boxes; n++) { |
94 | 686k | if (! _cairo_fixed_is_integer (array[n].p1.x) || |
95 | 686k | ! _cairo_fixed_is_integer (array[n].p1.y) || |
96 | 686k | ! _cairo_fixed_is_integer (array[n].p2.x) || |
97 | 686k | ! _cairo_fixed_is_integer (array[n].p2.y)) |
98 | 0 | { |
99 | 0 | break; |
100 | 0 | } |
101 | 686k | } |
102 | | |
103 | 686k | boxes->is_pixel_aligned = n == num_boxes; |
104 | 686k | } |
105 | | |
106 | | /** _cairo_boxes_limit: |
107 | | * |
108 | | * Computes the minimum bounding box of the given list of boxes and assign |
109 | | * it to the given boxes set. It also assigns that list as the list of |
110 | | * limiting boxes in the box set. |
111 | | * |
112 | | * @param boxes the box set to be filled (return buffer) |
113 | | * @param limits array of the limiting boxes to compute the bounding |
114 | | * box from |
115 | | * @param num_limits length of the limits array |
116 | | */ |
117 | | void |
118 | | _cairo_boxes_limit (cairo_boxes_t *boxes, |
119 | | const cairo_box_t *limits, |
120 | | int num_limits) |
121 | 20.5k | { |
122 | 20.5k | int n; |
123 | | |
124 | 20.5k | boxes->limits = limits; |
125 | 20.5k | boxes->num_limits = num_limits; |
126 | | |
127 | 20.5k | if (boxes->num_limits) { |
128 | 20.5k | boxes->limit = limits[0]; |
129 | 20.5k | for (n = 1; n < num_limits; n++) { |
130 | 0 | if (limits[n].p1.x < boxes->limit.p1.x) |
131 | 0 | boxes->limit.p1.x = limits[n].p1.x; |
132 | |
|
133 | 0 | if (limits[n].p1.y < boxes->limit.p1.y) |
134 | 0 | boxes->limit.p1.y = limits[n].p1.y; |
135 | |
|
136 | 0 | if (limits[n].p2.x > boxes->limit.p2.x) |
137 | 0 | boxes->limit.p2.x = limits[n].p2.x; |
138 | |
|
139 | 0 | if (limits[n].p2.y > boxes->limit.p2.y) |
140 | 0 | boxes->limit.p2.y = limits[n].p2.y; |
141 | 0 | } |
142 | 20.5k | } |
143 | 20.5k | } |
144 | | |
145 | | static void |
146 | | _cairo_boxes_add_internal (cairo_boxes_t *boxes, |
147 | | const cairo_box_t *box) |
148 | 563k | { |
149 | 563k | struct _cairo_boxes_chunk *chunk; |
150 | | |
151 | 563k | if (unlikely (boxes->status)) |
152 | 0 | return; |
153 | | |
154 | 563k | chunk = boxes->tail; |
155 | 563k | if (unlikely (chunk->count == chunk->size)) { |
156 | 53 | int size; |
157 | | |
158 | 53 | size = chunk->size * 2; |
159 | 53 | chunk->next = _cairo_malloc_ab_plus_c (size, |
160 | 53 | sizeof (cairo_box_t), |
161 | 53 | sizeof (struct _cairo_boxes_chunk)); |
162 | | |
163 | 53 | if (unlikely (chunk->next == NULL)) { |
164 | 0 | boxes->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
165 | 0 | return; |
166 | 0 | } |
167 | | |
168 | 53 | chunk = chunk->next; |
169 | 53 | boxes->tail = chunk; |
170 | | |
171 | 53 | chunk->next = NULL; |
172 | 53 | chunk->count = 0; |
173 | 53 | chunk->size = size; |
174 | 53 | chunk->base = (cairo_box_t *) (chunk + 1); |
175 | 53 | } |
176 | | |
177 | 563k | chunk->base[chunk->count++] = *box; |
178 | 563k | boxes->num_boxes++; |
179 | | |
180 | 563k | if (boxes->is_pixel_aligned) |
181 | 562k | boxes->is_pixel_aligned = _cairo_box_is_pixel_aligned (box); |
182 | 563k | } |
183 | | |
184 | | cairo_status_t |
185 | | _cairo_boxes_add (cairo_boxes_t *boxes, |
186 | | cairo_antialias_t antialias, |
187 | | const cairo_box_t *box) |
188 | 723k | { |
189 | 723k | cairo_box_t b; |
190 | | |
191 | 723k | if (antialias == CAIRO_ANTIALIAS_NONE) { |
192 | 705k | b.p1.x = _cairo_fixed_round_down (box->p1.x); |
193 | 705k | b.p1.y = _cairo_fixed_round_down (box->p1.y); |
194 | 705k | b.p2.x = _cairo_fixed_round_down (box->p2.x); |
195 | 705k | b.p2.y = _cairo_fixed_round_down (box->p2.y); |
196 | 705k | box = &b; |
197 | 705k | } |
198 | | |
199 | 723k | if (box->p1.y == box->p2.y) |
200 | 161 | return CAIRO_STATUS_SUCCESS; |
201 | | |
202 | 723k | if (box->p1.x == box->p2.x) |
203 | 978 | return CAIRO_STATUS_SUCCESS; |
204 | | |
205 | 722k | if (boxes->num_limits) { |
206 | 207k | cairo_point_t p1, p2; |
207 | 207k | cairo_bool_t reversed = FALSE; |
208 | 207k | int n; |
209 | | |
210 | | /* support counter-clockwise winding for rectangular tessellation */ |
211 | 207k | if (box->p1.x < box->p2.x) { |
212 | 203k | p1.x = box->p1.x; |
213 | 203k | p2.x = box->p2.x; |
214 | 203k | } else { |
215 | 3.81k | p2.x = box->p1.x; |
216 | 3.81k | p1.x = box->p2.x; |
217 | 3.81k | reversed = ! reversed; |
218 | 3.81k | } |
219 | | |
220 | 207k | if (p1.x >= boxes->limit.p2.x || p2.x <= boxes->limit.p1.x) |
221 | 150k | return CAIRO_STATUS_SUCCESS; |
222 | | |
223 | 56.9k | if (box->p1.y < box->p2.y) { |
224 | 56.9k | p1.y = box->p1.y; |
225 | 56.9k | p2.y = box->p2.y; |
226 | 56.9k | } else { |
227 | 0 | p2.y = box->p1.y; |
228 | 0 | p1.y = box->p2.y; |
229 | 0 | reversed = ! reversed; |
230 | 0 | } |
231 | | |
232 | 56.9k | if (p1.y >= boxes->limit.p2.y || p2.y <= boxes->limit.p1.y) |
233 | 8.61k | return CAIRO_STATUS_SUCCESS; |
234 | | |
235 | 96.6k | for (n = 0; n < boxes->num_limits; n++) { |
236 | 48.3k | const cairo_box_t *limits = &boxes->limits[n]; |
237 | 48.3k | cairo_box_t _box; |
238 | 48.3k | cairo_point_t _p1, _p2; |
239 | | |
240 | 48.3k | if (p1.x >= limits->p2.x || p2.x <= limits->p1.x) |
241 | 0 | continue; |
242 | 48.3k | if (p1.y >= limits->p2.y || p2.y <= limits->p1.y) |
243 | 0 | continue; |
244 | | |
245 | | /* Otherwise, clip the box to the limits. */ |
246 | 48.3k | _p1 = p1; |
247 | 48.3k | if (_p1.x < limits->p1.x) |
248 | 8.66k | _p1.x = limits->p1.x; |
249 | 48.3k | if (_p1.y < limits->p1.y) |
250 | 8.54k | _p1.y = limits->p1.y; |
251 | | |
252 | 48.3k | _p2 = p2; |
253 | 48.3k | if (_p2.x > limits->p2.x) |
254 | 18.0k | _p2.x = limits->p2.x; |
255 | 48.3k | if (_p2.y > limits->p2.y) |
256 | 21.3k | _p2.y = limits->p2.y; |
257 | | |
258 | 48.3k | if (_p2.y <= _p1.y || _p2.x <= _p1.x) |
259 | 0 | continue; |
260 | | |
261 | 48.3k | _box.p1.y = _p1.y; |
262 | 48.3k | _box.p2.y = _p2.y; |
263 | 48.3k | if (reversed) { |
264 | 2.19k | _box.p1.x = _p2.x; |
265 | 2.19k | _box.p2.x = _p1.x; |
266 | 46.1k | } else { |
267 | 46.1k | _box.p1.x = _p1.x; |
268 | 46.1k | _box.p2.x = _p2.x; |
269 | 46.1k | } |
270 | | |
271 | 48.3k | _cairo_boxes_add_internal (boxes, &_box); |
272 | 48.3k | } |
273 | 515k | } else { |
274 | 515k | _cairo_boxes_add_internal (boxes, box); |
275 | 515k | } |
276 | | |
277 | 563k | return boxes->status; |
278 | 722k | } |
279 | | |
280 | | /** _cairo_boxes_extents: |
281 | | * |
282 | | * Computes the minimum bounding box of the given box set and stores |
283 | | * it in the given box. |
284 | | * |
285 | | * @param boxes The box set whose minimum bounding is computed. |
286 | | * @param box Return buffer for the computed result. |
287 | | */ |
288 | | void |
289 | | _cairo_boxes_extents (const cairo_boxes_t *boxes, |
290 | | cairo_box_t *box) |
291 | 1.22M | { |
292 | 1.22M | const struct _cairo_boxes_chunk *chunk; |
293 | 1.22M | cairo_box_t b; |
294 | 1.22M | int i; |
295 | | |
296 | 1.22M | if (boxes->num_boxes == 0) { |
297 | 10.2k | box->p1.x = box->p1.y = box->p2.x = box->p2.y = 0; |
298 | 10.2k | return; |
299 | 10.2k | } |
300 | | |
301 | 1.21M | b = boxes->chunks.base[0]; |
302 | 2.42M | for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { |
303 | 2.42M | for (i = 0; i < chunk->count; i++) { |
304 | 1.21M | if (chunk->base[i].p1.x < b.p1.x) |
305 | 5 | b.p1.x = chunk->base[i].p1.x; |
306 | | |
307 | 1.21M | if (chunk->base[i].p1.y < b.p1.y) |
308 | 0 | b.p1.y = chunk->base[i].p1.y; |
309 | | |
310 | 1.21M | if (chunk->base[i].p2.x > b.p2.x) |
311 | 1.25k | b.p2.x = chunk->base[i].p2.x; |
312 | | |
313 | 1.21M | if (chunk->base[i].p2.y > b.p2.y) |
314 | 1.48k | b.p2.y = chunk->base[i].p2.y; |
315 | 1.21M | } |
316 | 1.21M | } |
317 | 1.21M | *box = b; |
318 | 1.21M | } |
319 | | |
320 | | void |
321 | | _cairo_boxes_clear (cairo_boxes_t *boxes) |
322 | 25.8k | { |
323 | 25.8k | struct _cairo_boxes_chunk *chunk, *next; |
324 | | |
325 | 25.9k | for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) { |
326 | 53 | next = chunk->next; |
327 | 53 | free (chunk); |
328 | 53 | } |
329 | | |
330 | 25.8k | boxes->tail = &boxes->chunks; |
331 | 25.8k | boxes->chunks.next = 0; |
332 | 25.8k | boxes->chunks.count = 0; |
333 | 25.8k | boxes->chunks.base = boxes->boxes_embedded; |
334 | 25.8k | boxes->chunks.size = ARRAY_LENGTH (boxes->boxes_embedded); |
335 | 25.8k | boxes->num_boxes = 0; |
336 | | |
337 | 25.8k | boxes->is_pixel_aligned = TRUE; |
338 | 25.8k | } |
339 | | |
340 | | /** _cairo_boxes_to_array: |
341 | | * |
342 | | * Linearize a box set of possibly multiple chunks into one big chunk |
343 | | * and returns an array of boxes |
344 | | * |
345 | | * @param boxes The box set to be converted. |
346 | | * @param num_boxes Return buffer for the number of boxes (array count). |
347 | | * @return Pointer to the newly allocated array of boxes |
348 | | * (the number o elements is given in num_boxes). |
349 | | */ |
350 | | cairo_box_t * |
351 | | _cairo_boxes_to_array (const cairo_boxes_t *boxes, |
352 | | int *num_boxes) |
353 | 1.26k | { |
354 | 1.26k | const struct _cairo_boxes_chunk *chunk; |
355 | 1.26k | cairo_box_t *box; |
356 | 1.26k | int i, j; |
357 | | |
358 | 1.26k | *num_boxes = boxes->num_boxes; |
359 | | |
360 | 1.26k | box = _cairo_malloc_ab (boxes->num_boxes, sizeof (cairo_box_t)); |
361 | 1.26k | if (box == NULL) { |
362 | 0 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
363 | 0 | return NULL; |
364 | 0 | } |
365 | | |
366 | 1.26k | j = 0; |
367 | 2.53k | for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { |
368 | 3.80k | for (i = 0; i < chunk->count; i++) |
369 | 2.53k | box[j++] = chunk->base[i]; |
370 | 1.26k | } |
371 | | |
372 | 1.26k | return box; |
373 | 1.26k | } |
374 | | |
375 | | void |
376 | | _cairo_boxes_fini (cairo_boxes_t *boxes) |
377 | 534k | { |
378 | 534k | struct _cairo_boxes_chunk *chunk, *next; |
379 | | |
380 | 534k | for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) { |
381 | 0 | next = chunk->next; |
382 | 0 | free (chunk); |
383 | 0 | } |
384 | 534k | } |
385 | | |
386 | | cairo_bool_t |
387 | | _cairo_boxes_for_each_box (cairo_boxes_t *boxes, |
388 | | cairo_bool_t (*func) (cairo_box_t *box, void *data), |
389 | | void *data) |
390 | 0 | { |
391 | 0 | struct _cairo_boxes_chunk *chunk; |
392 | 0 | int i; |
393 | |
|
394 | 0 | for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { |
395 | 0 | for (i = 0; i < chunk->count; i++) |
396 | 0 | if (! func (&chunk->base[i], data)) |
397 | 0 | return FALSE; |
398 | 0 | } |
399 | | |
400 | 0 | return TRUE; |
401 | 0 | } |
402 | | |
403 | | struct cairo_box_renderer { |
404 | | cairo_span_renderer_t base; |
405 | | cairo_boxes_t *boxes; |
406 | | }; |
407 | | |
408 | | static cairo_status_t |
409 | | span_to_boxes (void *abstract_renderer, int y, int h, |
410 | | const cairo_half_open_span_t *spans, unsigned num_spans) |
411 | 0 | { |
412 | 0 | struct cairo_box_renderer *r = abstract_renderer; |
413 | 0 | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
414 | 0 | cairo_box_t box; |
415 | |
|
416 | 0 | if (num_spans == 0) |
417 | 0 | return CAIRO_STATUS_SUCCESS; |
418 | | |
419 | 0 | box.p1.y = _cairo_fixed_from_int (y); |
420 | 0 | box.p2.y = _cairo_fixed_from_int (y + h); |
421 | 0 | do { |
422 | 0 | if (spans[0].coverage) { |
423 | 0 | box.p1.x = _cairo_fixed_from_int(spans[0].x); |
424 | 0 | box.p2.x = _cairo_fixed_from_int(spans[1].x); |
425 | 0 | status = _cairo_boxes_add (r->boxes, CAIRO_ANTIALIAS_DEFAULT, &box); |
426 | 0 | } |
427 | 0 | spans++; |
428 | 0 | } while (--num_spans > 1 && status == CAIRO_STATUS_SUCCESS); |
429 | |
|
430 | 0 | return status; |
431 | 0 | } |
432 | | |
433 | | cairo_status_t |
434 | | _cairo_rasterise_polygon_to_boxes (cairo_polygon_t *polygon, |
435 | | cairo_fill_rule_t fill_rule, |
436 | | cairo_boxes_t *boxes) |
437 | 0 | { |
438 | 0 | struct cairo_box_renderer renderer; |
439 | 0 | cairo_scan_converter_t *converter; |
440 | 0 | cairo_int_status_t status; |
441 | 0 | cairo_rectangle_int_t r; |
442 | |
|
443 | 0 | TRACE ((stderr, "%s: fill_rule=%d\n", __FUNCTION__, fill_rule)); |
444 | |
|
445 | 0 | _cairo_box_round_to_rectangle (&polygon->extents, &r); |
446 | 0 | converter = _cairo_mono_scan_converter_create (r.x, r.y, |
447 | 0 | r.x + r.width, |
448 | 0 | r.y + r.height, |
449 | 0 | fill_rule); |
450 | 0 | status = _cairo_mono_scan_converter_add_polygon (converter, polygon); |
451 | 0 | if (unlikely (status)) |
452 | 0 | goto cleanup_converter; |
453 | | |
454 | 0 | renderer.boxes = boxes; |
455 | 0 | renderer.base.render_rows = span_to_boxes; |
456 | |
|
457 | 0 | status = converter->generate (converter, &renderer.base); |
458 | 0 | cleanup_converter: |
459 | 0 | converter->destroy (converter); |
460 | 0 | return status; |
461 | 0 | } |
462 | | |
463 | | void |
464 | | _cairo_debug_print_boxes (FILE *stream, const cairo_boxes_t *boxes) |
465 | 0 | { |
466 | 0 | const struct _cairo_boxes_chunk *chunk; |
467 | 0 | cairo_box_t extents; |
468 | 0 | int i; |
469 | |
|
470 | 0 | _cairo_boxes_extents (boxes, &extents); |
471 | 0 | fprintf (stream, "boxes x %d: (%f, %f) x (%f, %f)\n", |
472 | 0 | boxes->num_boxes, |
473 | 0 | _cairo_fixed_to_double (extents.p1.x), |
474 | 0 | _cairo_fixed_to_double (extents.p1.y), |
475 | 0 | _cairo_fixed_to_double (extents.p2.x), |
476 | 0 | _cairo_fixed_to_double (extents.p2.y)); |
477 | |
|
478 | 0 | for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { |
479 | 0 | for (i = 0; i < chunk->count; i++) { |
480 | 0 | fprintf (stderr, " box[%d]: (%f, %f), (%f, %f)\n", i, |
481 | 0 | _cairo_fixed_to_double (chunk->base[i].p1.x), |
482 | 0 | _cairo_fixed_to_double (chunk->base[i].p1.y), |
483 | 0 | _cairo_fixed_to_double (chunk->base[i].p2.x), |
484 | 0 | _cairo_fixed_to_double (chunk->base[i].p2.y)); |
485 | 0 | } |
486 | 0 | } |
487 | 0 | } |