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.
31 * Chris Wilson <chris@chris-wilson.co.uk>
36 #include "cairo-box-inline.h"
37 #include "cairo-boxes-private.h"
38 #include "cairo-error-private.h"
41 _cairo_boxes_init (cairo_boxes_t
*boxes
)
43 boxes
->status
= CAIRO_STATUS_SUCCESS
;
44 boxes
->num_limits
= 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
;
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
);
67 _cairo_boxes_init_with_clip (cairo_boxes_t
*boxes
,
70 _cairo_boxes_init (boxes
);
72 _cairo_boxes_limit (boxes
, clip
->boxes
, clip
->num_boxes
);
76 _cairo_boxes_init_for_array (cairo_boxes_t
*boxes
,
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
))
102 boxes
->is_pixel_aligned
= n
== num_boxes
;
106 _cairo_boxes_limit (cairo_boxes_t
*boxes
,
107 const cairo_box_t
*limits
,
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
;
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
))
143 if (unlikely (chunk
->count
== chunk
->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
);
162 chunk
->base
= (cairo_box_t
*) (chunk
+ 1);
165 chunk
->base
[chunk
->count
++] = *box
;
168 if (boxes
->is_pixel_aligned
)
169 boxes
->is_pixel_aligned
= _cairo_box_is_pixel_aligned (box
);
173 _cairo_boxes_add (cairo_boxes_t
*boxes
,
174 cairo_antialias_t antialias
,
175 const cairo_box_t
*box
)
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
);
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
;
198 /* support counter-clockwise winding for rectangular tessellation */
199 if (box
->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
) {
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
];
226 cairo_point_t _p1
, _p2
;
228 if (p1
.x
>= limits
->p2
.x
|| p2
.x
<= limits
->p1
.x
)
230 if (p1
.y
>= limits
->p2
.y
|| p2
.y
<= limits
->p1
.y
)
233 /* Otherwise, clip the box to the limits. */
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
;
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
)
259 _cairo_boxes_add_internal (boxes
, &_box
);
262 _cairo_boxes_add_internal (boxes
, box
);
265 return boxes
->status
;
269 _cairo_boxes_extents (const cairo_boxes_t
*boxes
,
272 const struct _cairo_boxes_chunk
*chunk
;
276 if (boxes
->num_boxes
== 0) {
277 box
->p1
.x
= box
->p1
.y
= box
->p2
.x
= box
->p2
.y
= 0;
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
;
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
) {
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
;
321 _cairo_boxes_to_array (const cairo_boxes_t
*boxes
,
323 cairo_bool_t force_allocation
)
325 const struct _cairo_boxes_chunk
*chunk
;
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
));
335 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
340 for (chunk
= &boxes
->chunks
; chunk
!= NULL
; chunk
= chunk
->next
) {
341 for (i
= 0; i
< chunk
->count
; i
++)
342 box
[j
++] = chunk
->base
[i
];
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
) {
360 _cairo_boxes_for_each_box (cairo_boxes_t
*boxes
,
361 cairo_bool_t (*func
) (cairo_box_t
*box
, void *data
),
364 struct _cairo_boxes_chunk
*chunk
;
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
))
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
;
390 return CAIRO_STATUS_SUCCESS
;
392 box
.p1
.y
= _cairo_fixed_from_int (y
);
393 box
.p2
.y
= _cairo_fixed_from_int (y
+ h
);
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
);
401 } while (--num_spans
> 1 && status
== CAIRO_STATUS_SUCCESS
);
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
,
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
);
432 converter
->destroy (converter
);
437 _cairo_debug_print_boxes (FILE *stream
, const cairo_boxes_t
*boxes
)
439 const struct _cairo_boxes_chunk
*chunk
;
443 _cairo_boxes_extents (boxes
, &extents
);
444 fprintf (stream
, "boxes x %d: (%f, %f) x (%f, %f)\n",
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
));