1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
3 * Copyright © 2002 Keith Packard
4 * Copyright © 2007 Red Hat, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Keith Packard
34 * Keith R. Packard <keithp@keithp.com>
35 * Carl D. Worth <cworth@cworth.org>
37 * 2002-07-15: Converted from XRenderCompositeDoublePoly to #cairo_trap_t. Carl D. Worth
42 #include "cairo-box-inline.h"
43 #include "cairo-boxes-private.h"
44 #include "cairo-error-private.h"
45 #include "cairo-region-private.h"
46 #include "cairo-slope-private.h"
47 #include "cairo-traps-private.h"
48 #include "cairo-spans-private.h"
50 /* private functions */
53 _cairo_traps_init (cairo_traps_t *traps)
55 VG (VALGRIND_MAKE_MEM_UNDEFINED (traps, sizeof (cairo_traps_t)));
57 traps->status = CAIRO_STATUS_SUCCESS;
59 traps->maybe_region = 1;
60 traps->is_rectilinear = 0;
61 traps->is_rectangular = 0;
65 traps->traps_size = ARRAY_LENGTH (traps->traps_embedded);
66 traps->traps = traps->traps_embedded;
68 traps->num_limits = 0;
69 traps->has_intersections = FALSE;
73 _cairo_traps_limit (cairo_traps_t *traps,
74 const cairo_box_t *limits,
79 traps->limits = limits;
80 traps->num_limits = num_limits;
82 traps->bounds = limits[0];
83 for (i = 1; i < num_limits; i++)
84 _cairo_box_add_box (&traps->bounds, &limits[i]);
88 _cairo_traps_init_with_clip (cairo_traps_t *traps,
89 const cairo_clip_t *clip)
91 _cairo_traps_init (traps);
93 _cairo_traps_limit (traps, clip->boxes, clip->num_boxes);
97 _cairo_traps_clear (cairo_traps_t *traps)
99 traps->status = CAIRO_STATUS_SUCCESS;
101 traps->maybe_region = 1;
102 traps->is_rectilinear = 0;
103 traps->is_rectangular = 0;
105 traps->num_traps = 0;
106 traps->has_intersections = FALSE;
110 _cairo_traps_fini (cairo_traps_t *traps)
112 if (traps->traps != traps->traps_embedded)
115 VG (VALGRIND_MAKE_MEM_NOACCESS (traps, sizeof (cairo_traps_t)));
118 /* make room for at least one more trap */
120 _cairo_traps_grow (cairo_traps_t *traps)
122 cairo_trapezoid_t *new_traps;
123 int new_size = 4 * traps->traps_size;
125 if (CAIRO_INJECT_FAULT ()) {
126 traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
130 if (traps->traps == traps->traps_embedded) {
131 new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t));
132 if (new_traps != NULL)
133 memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded));
135 new_traps = _cairo_realloc_ab (traps->traps,
136 new_size, sizeof (cairo_trapezoid_t));
139 if (unlikely (new_traps == NULL)) {
140 traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
144 traps->traps = new_traps;
145 traps->traps_size = new_size;
150 _cairo_traps_add_trap (cairo_traps_t *traps,
151 cairo_fixed_t top, cairo_fixed_t bottom,
152 cairo_line_t *left, cairo_line_t *right)
154 cairo_trapezoid_t *trap;
156 if (unlikely (traps->num_traps == traps->traps_size)) {
157 if (unlikely (! _cairo_traps_grow (traps)))
161 trap = &traps->traps[traps->num_traps++];
163 trap->bottom = bottom;
165 trap->right = *right;
169 _cairo_traps_add_clipped_trap (cairo_traps_t *traps,
170 cairo_fixed_t _top, cairo_fixed_t _bottom,
171 cairo_line_t *_left, cairo_line_t *_right)
173 /* Note: With the goofy trapezoid specification, (where an
174 * arbitrary two points on the lines can specified for the left
175 * and right edges), these limit checks would not work in
176 * general. For example, one can imagine a trapezoid entirely
177 * within the limits, but with two points used to specify the left
178 * edge entirely to the right of the limits. Fortunately, for our
179 * purposes, cairo will never generate such a crazy
180 * trapezoid. Instead, cairo always uses for its points the
181 * extreme positions of the edge that are visible on at least some
182 * trapezoid. With this constraint, it's impossible for both
183 * points to be outside the limits while the relevant edge is
184 * entirely inside the limits.
186 if (traps->num_limits) {
187 const cairo_box_t *b = &traps->bounds;
188 cairo_fixed_t top = _top, bottom = _bottom;
189 cairo_line_t left = *_left, right = *_right;
191 /* Trivially reject if trapezoid is entirely to the right or
192 * to the left of the limits. */
193 if (left.p1.x >= b->p2.x && left.p2.x >= b->p2.x)
196 if (right.p1.x <= b->p1.x && right.p2.x <= b->p1.x)
199 /* And reject if the trapezoid is entirely above or below */
200 if (top >= b->p2.y || bottom <= b->p1.y)
203 /* Otherwise, clip the trapezoid to the limits. We only clip
204 * where an edge is entirely outside the limits. If we wanted
205 * to be more clever, we could handle cases where a trapezoid
206 * edge intersects the edge of the limits, but that would
207 * require slicing this trapezoid into multiple trapezoids,
208 * and I'm not sure the effort would be worth it. */
212 if (bottom > b->p2.y)
215 if (left.p1.x <= b->p1.x && left.p2.x <= b->p1.x)
216 left.p1.x = left.p2.x = b->p1.x;
218 if (right.p1.x >= b->p2.x && right.p2.x >= b->p2.x)
219 right.p1.x = right.p2.x = b->p2.x;
221 /* Trivial discards for empty trapezoids that are likely to
222 * be produced by our tessellators (most notably convex_quad
223 * when given a simple rectangle).
228 /* cheap colinearity check */
229 if (right.p1.x <= left.p1.x && right.p1.y == left.p1.y &&
230 right.p2.x <= left.p2.x && right.p2.y == left.p2.y)
233 _cairo_traps_add_trap (traps, top, bottom, &left, &right);
235 _cairo_traps_add_trap (traps, _top, _bottom, _left, _right);
239 _compare_point_fixed_by_y (const void *av, const void *bv)
241 const cairo_point_t *a = av, *b = bv;
242 int ret = a->y - b->y;
249 _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps,
250 const cairo_point_t q[4])
254 cairo_slope_t ab, ad;
255 cairo_bool_t b_left_of_d;
259 /* Choose a as a point with minimal y */
261 for (i = 1; i < 4; i++)
262 if (_compare_point_fixed_by_y (&q[i], &q[a]) < 0)
265 /* b and d are adjacent to a, while c is opposite */
270 /* Choose between b and d so that b.y is less than d.y */
271 if (_compare_point_fixed_by_y (&q[d], &q[b]) < 0) {
276 /* Without freedom left to choose anything else, we have four
277 * cases to tessellate.
279 * First, we have to determine the Y-axis sort of the four
280 * vertices, (either abcd or abdc). After that we need to detemine
281 * which edges will be "left" and which will be "right" in the
282 * resulting trapezoids. This can be determined by computing a
283 * slope comparison of ab and ad to determine if b is left of d or
286 * Note that "left of" here is in the sense of which edges should
287 * be the left vs. right edges of the trapezoid. In particular, b
288 * left of d does *not* mean that b.x is less than d.x.
290 * This should hopefully be made clear in the lame ASCII art
291 * below. Since the same slope comparison is used in all cases, we
292 * compute it before testing for the Y-value sort. */
294 /* Note: If a == b then the ab slope doesn't give us any
295 * information. In that case, we can replace it with the ac (or
296 * equivalenly the bc) slope which gives us exactly the same
297 * information we need. At worst the names of the identifiers ab
298 * and b_left_of_d are inaccurate in this case, (would be ac, and
300 if (q[a].x == q[b].x && q[a].y == q[b].y)
301 _cairo_slope_init (&ab, &q[a], &q[c]);
303 _cairo_slope_init (&ab, &q[a], &q[b]);
305 _cairo_slope_init (&ad, &q[a], &q[d]);
307 b_left_of_d = _cairo_slope_compare (&ab, &ad) > 0;
309 if (q[c].y <= q[d].y) {
311 /* Y-sort is abcd and b is left of d, (slope(ab) > slope (ad))
315 * / / /| |\ a.y b.y ab ad
317 * / / | | \ \ b.y c.y bc ad
319 * | / \| \ \ c.y d.y cd ad
322 left.p1 = q[a]; left.p2 = q[b];
323 right.p1 = q[a]; right.p2 = q[d];
324 _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
325 left.p1 = q[b]; left.p2 = q[c];
326 _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
327 left.p1 = q[c]; left.p2 = q[d];
328 _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
330 /* Y-sort is abcd and b is right of d, (slope(ab) <= slope (ad))
333 * /| |\ \ \ a.y b.y ad ab
335 * / / | | \ \ b.y c.y ad bc
337 * / / |/ \ | c.y d.y ad cd
340 left.p1 = q[a]; left.p2 = q[d];
341 right.p1 = q[a]; right.p2 = q[b];
342 _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
343 right.p1 = q[b]; right.p2 = q[c];
344 _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
345 right.p1 = q[c]; right.p2 = q[d];
346 _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
350 /* Y-sort is abdc and b is left of d, (slope (ab) > slope (ad))
353 * // / \ |\ a.y b.y ab ad
355 * / / \ \ \ \ b.y d.y bc ad
357 * // \ / \| d.y c.y bc dc
360 left.p1 = q[a]; left.p2 = q[b];
361 right.p1 = q[a]; right.p2 = q[d];
362 _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
363 left.p1 = q[b]; left.p2 = q[c];
364 _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
365 right.p1 = q[d]; right.p2 = q[c];
366 _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
368 /* Y-sort is abdc and b is right of d, (slope (ab) <= slope (ad))
371 * /| / \ \\ a.y b.y ad ab
373 * / / / / \ \ b.y d.y ad bc
375 * |/ \ / \\ d.y c.y dc bc
378 left.p1 = q[a]; left.p2 = q[d];
379 right.p1 = q[a]; right.p2 = q[b];
380 _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
381 right.p1 = q[b]; right.p2 = q[c];
382 _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
383 left.p1 = q[d]; left.p2 = q[c];
384 _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
389 /* A triangle is simply a degenerate case of a convex
390 * quadrilateral. We would not benefit from having any distinct
391 * implementation of triangle vs. quadrilateral tessellation here. */
393 _cairo_traps_tessellate_triangle (cairo_traps_t *traps,
394 const cairo_point_t t[3])
396 cairo_point_t quad[4];
403 _cairo_traps_tessellate_convex_quad (traps, quad);
408 * _cairo_traps_init_boxes:
409 * @traps: a #cairo_traps_t
410 * @box: an array box that will each be converted to a single trapezoid
411 * to store in @traps.
413 * Initializes a #cairo_traps_t to contain an array of rectangular
417 _cairo_traps_init_boxes (cairo_traps_t *traps,
418 const cairo_boxes_t *boxes)
420 cairo_trapezoid_t *trap;
421 const struct _cairo_boxes_chunk *chunk;
423 _cairo_traps_init (traps);
425 while (traps->traps_size < boxes->num_boxes) {
426 if (unlikely (! _cairo_traps_grow (traps))) {
427 _cairo_traps_fini (traps);
428 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
432 traps->num_traps = boxes->num_boxes;
433 traps->is_rectilinear = TRUE;
434 traps->is_rectangular = TRUE;
435 traps->maybe_region = boxes->is_pixel_aligned;
437 trap = &traps->traps[0];
438 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
439 const cairo_box_t *box;
443 for (i = 0; i < chunk->count; i++) {
444 trap->top = box->p1.y;
445 trap->bottom = box->p2.y;
447 trap->left.p1 = box->p1;
448 trap->left.p2.x = box->p1.x;
449 trap->left.p2.y = box->p2.y;
451 trap->right.p1.x = box->p2.x;
452 trap->right.p1.y = box->p1.y;
453 trap->right.p2 = box->p2;
459 return CAIRO_STATUS_SUCCESS;
463 _cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
464 const cairo_point_t *top_left,
465 const cairo_point_t *bottom_right)
469 cairo_fixed_t top, bottom;
471 if (top_left->y == bottom_right->y)
472 return CAIRO_STATUS_SUCCESS;
474 if (top_left->x == bottom_right->x)
475 return CAIRO_STATUS_SUCCESS;
477 left.p1.x = left.p2.x = top_left->x;
478 left.p1.y = right.p1.y = top_left->y;
479 right.p1.x = right.p2.x = bottom_right->x;
480 left.p2.y = right.p2.y = bottom_right->y;
483 bottom = bottom_right->y;
485 if (traps->num_limits) {
486 cairo_bool_t reversed;
489 if (top >= traps->bounds.p2.y || bottom <= traps->bounds.p1.y)
490 return CAIRO_STATUS_SUCCESS;
492 /* support counter-clockwise winding for rectangular tessellation */
493 reversed = top_left->x > bottom_right->x;
495 right.p1.x = right.p2.x = top_left->x;
496 left.p1.x = left.p2.x = bottom_right->x;
499 if (left.p1.x >= traps->bounds.p2.x || right.p1.x <= traps->bounds.p1.x)
500 return CAIRO_STATUS_SUCCESS;
502 for (n = 0; n < traps->num_limits; n++) {
503 const cairo_box_t *limits = &traps->limits[n];
504 cairo_line_t _left, _right;
505 cairo_fixed_t _top, _bottom;
507 if (top >= limits->p2.y)
509 if (bottom <= limits->p1.y)
512 /* Trivially reject if trapezoid is entirely to the right or
513 * to the left of the limits. */
514 if (left.p1.x >= limits->p2.x)
516 if (right.p1.x <= limits->p1.x)
519 /* Otherwise, clip the trapezoid to the limits. */
521 if (_top < limits->p1.y)
525 if (_bottom > limits->p2.y)
526 _bottom = limits->p2.y;
532 if (_left.p1.x < limits->p1.x) {
533 _left.p1.x = limits->p1.x;
534 _left.p1.y = limits->p1.y;
535 _left.p2.x = limits->p1.x;
536 _left.p2.y = limits->p2.y;
540 if (_right.p1.x > limits->p2.x) {
541 _right.p1.x = limits->p2.x;
542 _right.p1.y = limits->p1.y;
543 _right.p2.x = limits->p2.x;
544 _right.p2.y = limits->p2.y;
547 if (left.p1.x >= right.p1.x)
551 _cairo_traps_add_trap (traps, _top, _bottom, &_right, &_left);
553 _cairo_traps_add_trap (traps, _top, _bottom, &_left, &_right);
556 _cairo_traps_add_trap (traps, top, bottom, &left, &right);
559 return traps->status;
563 _cairo_traps_translate (cairo_traps_t *traps, int x, int y)
565 cairo_fixed_t xoff, yoff;
566 cairo_trapezoid_t *t;
569 /* Ugh. The cairo_composite/(Render) interface doesn't allow
570 an offset for the trapezoids. Need to manually shift all
571 the coordinates to align with the offset origin of the
572 intermediate surface. */
574 xoff = _cairo_fixed_from_int (x);
575 yoff = _cairo_fixed_from_int (y);
577 for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) {
580 t->left.p1.x += xoff;
581 t->left.p1.y += yoff;
582 t->left.p2.x += xoff;
583 t->left.p2.y += yoff;
584 t->right.p1.x += xoff;
585 t->right.p1.y += yoff;
586 t->right.p2.x += xoff;
587 t->right.p2.y += yoff;
592 _cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
593 cairo_trapezoid_t *src_traps,
595 double tx, double ty,
596 double sx, double sy)
599 cairo_fixed_t xoff = _cairo_fixed_from_double (tx);
600 cairo_fixed_t yoff = _cairo_fixed_from_double (ty);
602 if (sx == 1.0 && sy == 1.0) {
603 for (i = 0; i < num_traps; i++) {
604 offset_traps[i].top = src_traps[i].top + yoff;
605 offset_traps[i].bottom = src_traps[i].bottom + yoff;
606 offset_traps[i].left.p1.x = src_traps[i].left.p1.x + xoff;
607 offset_traps[i].left.p1.y = src_traps[i].left.p1.y + yoff;
608 offset_traps[i].left.p2.x = src_traps[i].left.p2.x + xoff;
609 offset_traps[i].left.p2.y = src_traps[i].left.p2.y + yoff;
610 offset_traps[i].right.p1.x = src_traps[i].right.p1.x + xoff;
611 offset_traps[i].right.p1.y = src_traps[i].right.p1.y + yoff;
612 offset_traps[i].right.p2.x = src_traps[i].right.p2.x + xoff;
613 offset_traps[i].right.p2.y = src_traps[i].right.p2.y + yoff;
616 cairo_fixed_t xsc = _cairo_fixed_from_double (sx);
617 cairo_fixed_t ysc = _cairo_fixed_from_double (sy);
619 for (i = 0; i < num_traps; i++) {
620 offset_traps[i].top = _cairo_fixed_mul (src_traps[i].top + yoff, ysc);
621 offset_traps[i].bottom = _cairo_fixed_mul (src_traps[i].bottom + yoff, ysc);
622 offset_traps[i].left.p1.x = _cairo_fixed_mul (src_traps[i].left.p1.x + xoff, xsc);
623 offset_traps[i].left.p1.y = _cairo_fixed_mul (src_traps[i].left.p1.y + yoff, ysc);
624 offset_traps[i].left.p2.x = _cairo_fixed_mul (src_traps[i].left.p2.x + xoff, xsc);
625 offset_traps[i].left.p2.y = _cairo_fixed_mul (src_traps[i].left.p2.y + yoff, ysc);
626 offset_traps[i].right.p1.x = _cairo_fixed_mul (src_traps[i].right.p1.x + xoff, xsc);
627 offset_traps[i].right.p1.y = _cairo_fixed_mul (src_traps[i].right.p1.y + yoff, ysc);
628 offset_traps[i].right.p2.x = _cairo_fixed_mul (src_traps[i].right.p2.x + xoff, xsc);
629 offset_traps[i].right.p2.y = _cairo_fixed_mul (src_traps[i].right.p2.y + yoff, ysc);
635 _cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
637 cairo_slope_t slope_left, slope_pt, slope_right;
641 if (t->bottom < pt->y)
644 _cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
645 _cairo_slope_init (&slope_pt, &t->left.p1, pt);
647 if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
650 _cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
651 _cairo_slope_init (&slope_pt, &t->right.p1, pt);
653 if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
660 _cairo_traps_contain (const cairo_traps_t *traps,
666 point.x = _cairo_fixed_from_double (x);
667 point.y = _cairo_fixed_from_double (y);
669 for (i = 0; i < traps->num_traps; i++) {
670 if (_cairo_trap_contains (&traps->traps[i], &point))
678 _line_compute_intersection_x_for_y (const cairo_line_t *line,
681 return _cairo_edge_compute_intersection_x_for_y (&line->p1, &line->p2, y);
685 _cairo_traps_extents (const cairo_traps_t *traps,
686 cairo_box_t *extents)
690 if (traps->num_traps == 0) {
691 extents->p1.x = extents->p1.y = 0;
692 extents->p2.x = extents->p2.y = 0;
696 extents->p1.x = extents->p1.y = INT32_MAX;
697 extents->p2.x = extents->p2.y = INT32_MIN;
699 for (i = 0; i < traps->num_traps; i++) {
700 const cairo_trapezoid_t *trap = &traps->traps[i];
702 if (trap->top < extents->p1.y)
703 extents->p1.y = trap->top;
704 if (trap->bottom > extents->p2.y)
705 extents->p2.y = trap->bottom;
707 if (trap->left.p1.x < extents->p1.x) {
708 cairo_fixed_t x = trap->left.p1.x;
709 if (trap->top != trap->left.p1.y) {
710 x = _line_compute_intersection_x_for_y (&trap->left,
712 if (x < extents->p1.x)
717 if (trap->left.p2.x < extents->p1.x) {
718 cairo_fixed_t x = trap->left.p2.x;
719 if (trap->bottom != trap->left.p2.y) {
720 x = _line_compute_intersection_x_for_y (&trap->left,
722 if (x < extents->p1.x)
728 if (trap->right.p1.x > extents->p2.x) {
729 cairo_fixed_t x = trap->right.p1.x;
730 if (trap->top != trap->right.p1.y) {
731 x = _line_compute_intersection_x_for_y (&trap->right,
733 if (x > extents->p2.x)
738 if (trap->right.p2.x > extents->p2.x) {
739 cairo_fixed_t x = trap->right.p2.x;
740 if (trap->bottom != trap->right.p2.y) {
741 x = _line_compute_intersection_x_for_y (&trap->right,
743 if (x > extents->p2.x)
752 _mono_edge_is_vertical (const cairo_line_t *line)
754 return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x);
758 _traps_are_pixel_aligned (cairo_traps_t *traps,
759 cairo_antialias_t antialias)
763 if (antialias == CAIRO_ANTIALIAS_NONE) {
764 for (i = 0; i < traps->num_traps; i++) {
765 if (! _mono_edge_is_vertical (&traps->traps[i].left) ||
766 ! _mono_edge_is_vertical (&traps->traps[i].right))
768 traps->maybe_region = FALSE;
773 for (i = 0; i < traps->num_traps; i++) {
774 if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
775 traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
776 ! _cairo_fixed_is_integer (traps->traps[i].top) ||
777 ! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
778 ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
779 ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
781 traps->maybe_region = FALSE;
791 * _cairo_traps_extract_region:
792 * @traps: a #cairo_traps_t
793 * @region: a #cairo_region_t
795 * Determines if a set of trapezoids are exactly representable as a
796 * cairo region. If so, the passed-in region is initialized to
797 * the area representing the given traps. It should be finalized
798 * with cairo_region_fini(). If not, %CAIRO_INT_STATUS_UNSUPPORTED
801 * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED
802 * or %CAIRO_STATUS_NO_MEMORY
805 _cairo_traps_extract_region (cairo_traps_t *traps,
806 cairo_antialias_t antialias,
807 cairo_region_t **region)
809 cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
810 cairo_rectangle_int_t *rects = stack_rects;
811 cairo_int_status_t status;
814 /* we only treat this a hint... */
815 if (antialias != CAIRO_ANTIALIAS_NONE && ! traps->maybe_region)
816 return CAIRO_INT_STATUS_UNSUPPORTED;
818 if (! _traps_are_pixel_aligned (traps, antialias)) {
819 traps->maybe_region = FALSE;
820 return CAIRO_INT_STATUS_UNSUPPORTED;
823 if (traps->num_traps > ARRAY_LENGTH (stack_rects)) {
824 rects = _cairo_malloc_ab (traps->num_traps, sizeof (cairo_rectangle_int_t));
826 if (unlikely (rects == NULL))
827 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
831 for (i = 0; i < traps->num_traps; i++) {
834 if (antialias == CAIRO_ANTIALIAS_NONE) {
835 x1 = _cairo_fixed_integer_round_down (traps->traps[i].left.p1.x);
836 y1 = _cairo_fixed_integer_round_down (traps->traps[i].top);
837 x2 = _cairo_fixed_integer_round_down (traps->traps[i].right.p1.x);
838 y2 = _cairo_fixed_integer_round_down (traps->traps[i].bottom);
840 x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
841 y1 = _cairo_fixed_integer_part (traps->traps[i].top);
842 x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
843 y2 = _cairo_fixed_integer_part (traps->traps[i].bottom);
846 if (x2 > x1 && y2 > y1) {
847 rects[rect_count].x = x1;
848 rects[rect_count].y = y1;
849 rects[rect_count].width = x2 - x1;
850 rects[rect_count].height = y2 - y1;
856 *region = cairo_region_create_rectangles (rects, rect_count);
857 status = (*region)->status;
859 if (rects != stack_rects)
866 _cairo_traps_to_boxes (cairo_traps_t *traps,
867 cairo_antialias_t antialias,
868 cairo_boxes_t *boxes)
872 for (i = 0; i < traps->num_traps; i++) {
873 if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
874 traps->traps[i].right.p1.x != traps->traps[i].right.p2.x)
878 _cairo_boxes_init (boxes);
880 boxes->num_boxes = traps->num_traps;
881 boxes->chunks.base = (cairo_box_t *) traps->traps;
882 boxes->chunks.count = traps->num_traps;
883 boxes->chunks.size = traps->num_traps;
885 if (antialias != CAIRO_ANTIALIAS_NONE) {
886 for (i = 0; i < traps->num_traps; i++) {
887 /* Note the traps and boxes alias so we need to take the local copies first. */
888 cairo_fixed_t x1 = traps->traps[i].left.p1.x;
889 cairo_fixed_t x2 = traps->traps[i].right.p1.x;
890 cairo_fixed_t y1 = traps->traps[i].top;
891 cairo_fixed_t y2 = traps->traps[i].bottom;
893 boxes->chunks.base[i].p1.x = x1;
894 boxes->chunks.base[i].p1.y = y1;
895 boxes->chunks.base[i].p2.x = x2;
896 boxes->chunks.base[i].p2.y = y2;
898 if (boxes->is_pixel_aligned) {
899 boxes->is_pixel_aligned =
900 _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
901 _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
905 boxes->is_pixel_aligned = TRUE;
907 for (i = 0; i < traps->num_traps; i++) {
908 /* Note the traps and boxes alias so we need to take the local copies first. */
909 cairo_fixed_t x1 = traps->traps[i].left.p1.x;
910 cairo_fixed_t x2 = traps->traps[i].right.p1.x;
911 cairo_fixed_t y1 = traps->traps[i].top;
912 cairo_fixed_t y2 = traps->traps[i].bottom;
914 /* round down here to match Pixman's behavior when using traps. */
915 boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
916 boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
917 boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
918 boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
925 /* moves trap points such that they become the actual corners of the trapezoid */
927 _sanitize_trap (cairo_trapezoid_t *t)
929 cairo_trapezoid_t s = *t;
931 #define FIX(lr, tb, p) \
932 if (t->lr.p.y != t->tb) { \
933 t->lr.p.x = s.lr.p2.x + _cairo_fixed_mul_div_floor (s.lr.p1.x - s.lr.p2.x, s.tb - s.lr.p2.y, s.lr.p1.y - s.lr.p2.y); \
937 FIX (left, bottom, p2);
938 FIX (right, top, p1);
939 FIX (right, bottom, p2);
942 cairo_private cairo_status_t
943 _cairo_traps_path (const cairo_traps_t *traps,
944 cairo_path_fixed_t *path)
948 for (i = 0; i < traps->num_traps; i++) {
949 cairo_status_t status;
950 cairo_trapezoid_t trap = traps->traps[i];
952 if (trap.top == trap.bottom)
955 _sanitize_trap (&trap);
957 status = _cairo_path_fixed_move_to (path, trap.left.p1.x, trap.top);
958 if (unlikely (status)) return status;
959 status = _cairo_path_fixed_line_to (path, trap.right.p1.x, trap.top);
960 if (unlikely (status)) return status;
961 status = _cairo_path_fixed_line_to (path, trap.right.p2.x, trap.bottom);
962 if (unlikely (status)) return status;
963 status = _cairo_path_fixed_line_to (path, trap.left.p2.x, trap.bottom);
964 if (unlikely (status)) return status;
965 status = _cairo_path_fixed_close_path (path);
966 if (unlikely (status)) return status;
969 return CAIRO_STATUS_SUCCESS;
973 _cairo_debug_print_traps (FILE *file, const cairo_traps_t *traps)
979 if (traps->has_limits) {
980 printf ("%s: limits=(%d, %d, %d, %d)\n",
982 traps->limits.p1.x, traps->limits.p1.y,
983 traps->limits.p2.x, traps->limits.p2.y);
987 _cairo_traps_extents (traps, &extents);
988 fprintf (file, "extents=(%d, %d, %d, %d)\n",
989 extents.p1.x, extents.p1.y,
990 extents.p2.x, extents.p2.y);
992 for (n = 0; n < traps->num_traps; n++) {
993 fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n",
995 traps->traps[n].bottom,
996 traps->traps[n].left.p1.x,
997 traps->traps[n].left.p1.y,
998 traps->traps[n].left.p2.x,
999 traps->traps[n].left.p2.y,
1000 traps->traps[n].right.p1.x,
1001 traps->traps[n].right.p1.y,
1002 traps->traps[n].right.p2.x,
1003 traps->traps[n].right.p2.y);
1007 struct cairo_trap_renderer {
1008 cairo_span_renderer_t base;
1009 cairo_traps_t *traps;
1012 static cairo_status_t
1013 span_to_traps (void *abstract_renderer, int y, int h,
1014 const cairo_half_open_span_t *spans, unsigned num_spans)
1016 struct cairo_trap_renderer *r = abstract_renderer;
1017 cairo_fixed_t top, bot;
1020 return CAIRO_STATUS_SUCCESS;
1022 top = _cairo_fixed_from_int (y);
1023 bot = _cairo_fixed_from_int (y + h);
1025 if (spans[0].coverage) {
1026 cairo_fixed_t x0 = _cairo_fixed_from_int(spans[0].x);
1027 cairo_fixed_t x1 = _cairo_fixed_from_int(spans[1].x);
1028 cairo_line_t left = { { x0, top }, { x0, bot } },
1029 right = { { x1, top }, { x1, bot } };
1030 _cairo_traps_add_trap (r->traps, top, bot, &left, &right);
1033 } while (--num_spans > 1);
1035 return CAIRO_STATUS_SUCCESS;
1039 _cairo_rasterise_polygon_to_traps (cairo_polygon_t *polygon,
1040 cairo_fill_rule_t fill_rule,
1041 cairo_antialias_t antialias,
1042 cairo_traps_t *traps)
1044 struct cairo_trap_renderer renderer;
1045 cairo_scan_converter_t *converter;
1046 cairo_int_status_t status;
1047 cairo_rectangle_int_t r;
1049 TRACE ((stderr, "%s: fill_rule=%d, antialias=%d\n",
1050 __FUNCTION__, fill_rule, antialias));
1051 assert(antialias == CAIRO_ANTIALIAS_NONE);
1053 renderer.traps = traps;
1054 renderer.base.render_rows = span_to_traps;
1056 _cairo_box_round_to_rectangle (&polygon->extents, &r);
1057 converter = _cairo_mono_scan_converter_create (r.x, r.y,
1061 status = _cairo_mono_scan_converter_add_polygon (converter, polygon);
1062 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
1063 status = converter->generate (converter, &renderer.base);
1064 converter->destroy (converter);