Back to index

lightning-sunbird  0.9+nobinonly
Defines | Functions
cairo-traps.c File Reference
#include "cairoint.h"

Go to the source code of this file.

Defines

#define CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE   0

Functions

static cairo_status_t _cairo_traps_grow_by (cairo_traps_t *traps, int additional)
static cairo_status_t _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom, cairo_line_t *left, cairo_line_t *right)
static cairo_status_t _cairo_traps_add_trap_from_points (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom, cairo_point_t left_p1, cairo_point_t left_p2, cairo_point_t right_p1, cairo_point_t right_p2)
static int _compare_point_fixed_by_y (const void *av, const void *bv)
static int _compare_cairo_edge_by_top (const void *av, const void *bv)
static int _compare_cairo_edge_by_slope (const void *av, const void *bv)
static cairo_fixed_16_16_t _compute_x (cairo_line_t *line, cairo_fixed_t y)
static int _line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret)
void _cairo_traps_init (cairo_traps_t *traps)
void _cairo_traps_fini (cairo_traps_t *traps)
cairo_status_t _cairo_traps_init_box (cairo_traps_t *traps, cairo_box_t *box)
 _cairo_traps_init_box: : a cairo_traps_t : a box that will be converted to a single trapezoid to store in .
void _cairo_traps_translate (cairo_traps_t *traps, int x, int y)
cairo_status_t _cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3])
cairo_status_t _cairo_traps_tessellate_rectangle (cairo_traps_t *traps, cairo_point_t q[4])
static int _compare_cairo_edge_by_current_x_slope (const void *av, const void *bv)
static double _compute_inverse_slope (cairo_line_t *l)
static double _compute_x_intercept (cairo_line_t *l, double inverse_slope)
cairo_status_t _cairo_traps_tessellate_polygon (cairo_traps_t *traps, cairo_polygon_t *poly, cairo_fill_rule_t fill_rule)
static cairo_bool_t _cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
cairo_bool_t _cairo_traps_contain (cairo_traps_t *traps, double x, double y)
void _cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents)
cairo_status_t _cairo_traps_extract_region (cairo_traps_t *traps, pixman_region16_t **region)
 _cairo_traps_extract_region: : a cairo_traps_t : on return, NULL is stored here if the trapezoids aren't exactly representable as a pixman region, otherwise a a pointer to such a region, newly allocated.

Define Documentation

Definition at line 448 of file cairo-traps.c.


Function Documentation

Definition at line 761 of file cairo-traps.c.

{
    cairo_slope_t slope_left, slope_pt, slope_right;
    
    if (t->top > pt->y)
       return FALSE;
    if (t->bottom < pt->y)
       return FALSE;
    
    _cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
    _cairo_slope_init (&slope_pt, &t->left.p1, pt);

    if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
       return FALSE;

    _cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
    _cairo_slope_init (&slope_pt, &t->right.p1, pt);

    if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
       return FALSE;

    return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static cairo_status_t _cairo_traps_add_trap ( cairo_traps_t traps,
cairo_fixed_t  top,
cairo_fixed_t  bottom,
cairo_line_t left,
cairo_line_t right 
) [static]

Definition at line 129 of file cairo-traps.c.

{
    cairo_status_t status;
    cairo_trapezoid_t *trap;

    if (top == bottom) {
       return CAIRO_STATUS_SUCCESS;
    }

    if (traps->num_traps >= traps->traps_size) {
       int inc = traps->traps_size ? traps->traps_size : 32;
       status = _cairo_traps_grow_by (traps, inc);
       if (status)
           return status;
    }

    trap = &traps->traps[traps->num_traps];
    trap->top = top;
    trap->bottom = bottom;
    trap->left = *left;
    trap->right = *right;

    if (top < traps->extents.p1.y)
       traps->extents.p1.y = top;
    if (bottom > traps->extents.p2.y)
       traps->extents.p2.y = bottom;
    /*
     * This isn't generally accurate, but it is close enough for
     * this purpose.  Assuming that the left and right segments always
     * contain the trapezoid vertical extents, these compares will
     * yield a containing box.  Assuming that the points all come from
     * the same figure which will eventually be completely drawn, then
     * the compares will yield the correct overall extents
     */
    if (left->p1.x < traps->extents.p1.x)
       traps->extents.p1.x = left->p1.x;
    if (left->p2.x < traps->extents.p1.x)
       traps->extents.p1.x = left->p2.x;
    
    if (right->p1.x > traps->extents.p2.x)
       traps->extents.p2.x = right->p1.x;
    if (right->p2.x > traps->extents.p2.x)
       traps->extents.p2.x = right->p2.x;
    
    traps->num_traps++;

    return CAIRO_STATUS_SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static cairo_status_t _cairo_traps_add_trap_from_points ( cairo_traps_t traps,
cairo_fixed_t  top,
cairo_fixed_t  bottom,
cairo_point_t  left_p1,
cairo_point_t  left_p2,
cairo_point_t  right_p1,
cairo_point_t  right_p2 
) [static]

Definition at line 180 of file cairo-traps.c.

{
    cairo_line_t left;
    cairo_line_t right;

    left.p1 = left_p1;
    left.p2 = left_p2;

    right.p1 = right_p1;
    right.p2 = right_p2;

    return _cairo_traps_add_trap (traps, top, bottom, &left, &right);
}

Here is the call graph for this function:

Here is the caller graph for this function:

cairo_bool_t _cairo_traps_contain ( cairo_traps_t traps,
double  x,
double  y 
)

Definition at line 786 of file cairo-traps.c.

{
    int i;
    cairo_point_t point;

    point.x = _cairo_fixed_from_double (x);
    point.y = _cairo_fixed_from_double (y);

    for (i = 0; i < traps->num_traps; i++) {
       if (_cairo_trap_contains (&traps->traps[i], &point))
           return TRUE;
    }

    return FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _cairo_traps_extents ( cairo_traps_t traps,
cairo_box_t extents 
)

Definition at line 803 of file cairo-traps.c.

{
    *extents = traps->extents;
}

Here is the caller graph for this function:

cairo_status_t _cairo_traps_extract_region ( cairo_traps_t traps,
pixman_region16_t **  region 
)

_cairo_traps_extract_region: : a cairo_traps_t : on return, NULL is stored here if the trapezoids aren't exactly representable as a pixman region, otherwise a a pointer to such a region, newly allocated.

     (free with pixman region destroy)

Determines if a set of trapezoids are exactly representable as a pixman region, and if so creates such a region.

Return value: CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY

Definition at line 822 of file cairo-traps.c.

{
    int i;

    for (i = 0; i < traps->num_traps; i++)
       if (!(traps->traps[i].left.p1.x == traps->traps[i].left.p2.x
             && traps->traps[i].right.p1.x == traps->traps[i].right.p2.x
             && _cairo_fixed_is_integer(traps->traps[i].top)
             && _cairo_fixed_is_integer(traps->traps[i].bottom)
             && _cairo_fixed_is_integer(traps->traps[i].left.p1.x)
             && _cairo_fixed_is_integer(traps->traps[i].right.p1.x))) {
           *region = NULL;
           return CAIRO_STATUS_SUCCESS;
       }
    
    *region = pixman_region_create ();

    for (i = 0; i < traps->num_traps; i++) {
       int x = _cairo_fixed_integer_part(traps->traps[i].left.p1.x);
       int y = _cairo_fixed_integer_part(traps->traps[i].top);
       int width = _cairo_fixed_integer_part(traps->traps[i].right.p1.x) - x;
       int height = _cairo_fixed_integer_part(traps->traps[i].bottom) - y;

       /* XXX: Sometimes we get degenerate trapezoids from the tesellator,
        * if we call pixman_region_union_rect(), it bizarrly fails on such
        * an empty rectangle, so skip them.
        */
       if (width == 0 || height == 0)
         continue;
       
       if (pixman_region_union_rect (*region, *region,
                                  x, y, width, height) != PIXMAN_REGION_STATUS_SUCCESS) {
           pixman_region_destroy (*region);
           return CAIRO_STATUS_NO_MEMORY;
       }
    }

    return CAIRO_STATUS_SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 81 of file cairo-traps.c.

{
    if (traps->traps_size) {
       free (traps->traps);
       traps->traps = NULL;
       traps->traps_size = 0;
       traps->num_traps = 0;
    }
}

Here is the caller graph for this function:

static cairo_status_t _cairo_traps_grow_by ( cairo_traps_t traps,
int  additional 
) [static]

Definition at line 197 of file cairo-traps.c.

{
    cairo_trapezoid_t *new_traps;
    int old_size = traps->traps_size;
    int new_size = traps->num_traps + additional;

    if (new_size <= traps->traps_size) {
       return CAIRO_STATUS_SUCCESS;
    }

    traps->traps_size = new_size;
    new_traps = realloc (traps->traps, traps->traps_size * sizeof (cairo_trapezoid_t));

    if (new_traps == NULL) {
       traps->traps_size = old_size;
       return CAIRO_STATUS_NO_MEMORY;
    }

    traps->traps = new_traps;

    return CAIRO_STATUS_SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 70 of file cairo-traps.c.

{
    traps->num_traps = 0;

    traps->traps_size = 0;
    traps->traps = NULL;
    traps->extents.p1.x = traps->extents.p1.y = CAIRO_MAXSHORT << 16;
    traps->extents.p2.x = traps->extents.p2.y = CAIRO_MINSHORT << 16;
}

Here is the caller graph for this function:

_cairo_traps_init_box: : a cairo_traps_t : a box that will be converted to a single trapezoid to store in .

Initializes a cairo_traps_t to contain a single rectangular trapezoid.

Definition at line 101 of file cairo-traps.c.

{
  cairo_status_t status;
  
  _cairo_traps_init (traps);
  
  status = _cairo_traps_grow_by (traps, 1);
  if (status)
    return status;
  
  traps->num_traps = 1;

  traps->traps[0].top = box->p1.y;
  traps->traps[0].bottom = box->p2.y;
  traps->traps[0].left.p1 = box->p1;
  traps->traps[0].left.p2.x = box->p1.x;
  traps->traps[0].left.p2.y = box->p2.y;
  traps->traps[0].right.p1.x = box->p2.x;
  traps->traps[0].right.p1.y = box->p1.y;
  traps->traps[0].right.p2 = box->p2;

  traps->extents = *box;

  return CAIRO_STATUS_SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 682 of file cairo-traps.c.

{
    cairo_status_t   status;
    int              i, active, inactive;
    cairo_fixed_t    y, y_next, intersect;
    int                     in_out, num_edges = poly->num_edges;
    cairo_edge_t     *edges = poly->edges;

    if (num_edges == 0)
       return CAIRO_STATUS_SUCCESS;

    qsort (edges, num_edges, sizeof (cairo_edge_t), _compare_cairo_edge_by_top);
    
    y = edges[0].edge.p1.y;
    active = 0;
    inactive = 0;
    while (active < num_edges) {
       while (inactive < num_edges && edges[inactive].edge.p1.y <= y)
           inactive++;

       for (i = active; i < inactive; i++)
           edges[i].current_x = _compute_x (&edges[i].edge, y);

       qsort (&edges[active], inactive - active,
              sizeof (cairo_edge_t), _compare_cairo_edge_by_current_x_slope);

       /* find next inflection point */
       y_next = edges[active].edge.p2.y;

       for (i = active; i < inactive; i++) {
           if (edges[i].edge.p2.y < y_next)
              y_next = edges[i].edge.p2.y;
           /* check intersect */
           if (i != inactive - 1 && edges[i].current_x != edges[i+1].current_x)
              if (_line_segs_intersect_ceil (&edges[i].edge, &edges[i+1].edge,
                                          &intersect))
                  if (intersect > y && intersect < y_next)
                     y_next = intersect;
       }
       /* check next inactive point */
       if (inactive < num_edges && edges[inactive].edge.p1.y < y_next)
           y_next = edges[inactive].edge.p1.y;

       /* walk the active edges generating trapezoids */
       in_out = 0;
       for (i = active; i < inactive - 1; i++) {
           if (fill_rule == CAIRO_FILL_RULE_WINDING) {
              if (edges[i].clockWise)
                  in_out++;
              else
                  in_out--;
              if (in_out == 0)
                  continue;
           } else {
              in_out++;
              if ((in_out & 1) == 0)
                  continue;
           }
           status = _cairo_traps_add_trap (traps, y, y_next, &edges[i].edge, &edges[i+1].edge);
           if (status)
              return status;
       }

       /* delete inactive edges */
       for (i = active; i < inactive; i++) {
           if (edges[i].edge.p2.y <= y_next) {
              memmove (&edges[active+1], &edges[active], (i - active) * sizeof (cairo_edge_t));
              active++;
           }
       }

       y = y_next;
    }
    return CAIRO_STATUS_SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 325 of file cairo-traps.c.

{
    cairo_status_t status;

    qsort (q, 4, sizeof (cairo_point_t), _compare_point_fixed_by_y);

    if (q[1].x > q[2].x) {
       status = _cairo_traps_add_trap_from_points (traps,
                                              q[0].y, q[1].y, q[0], q[2], q[0], q[1]);
       if (status)
           return status;
       status = _cairo_traps_add_trap_from_points (traps,
                                              q[1].y, q[2].y, q[0], q[2], q[1], q[3]);
       if (status)
           return status;
       status = _cairo_traps_add_trap_from_points (traps,
                                              q[2].y, q[3].y, q[2], q[3], q[1], q[3]);
       if (status)
           return status;
    } else {
       status = _cairo_traps_add_trap_from_points (traps,
                                              q[0].y, q[1].y, q[0], q[1], q[0], q[2]);
       if (status)
           return status;
       status = _cairo_traps_add_trap_from_points (traps,
                                              q[1].y, q[2].y, q[1], q[3], q[0], q[2]);
       if (status)
           return status;
       status = _cairo_traps_add_trap_from_points (traps,
                                              q[2].y, q[3].y, q[1], q[3], q[2], q[3]);
       if (status)
           return status;
    }

    return CAIRO_STATUS_SUCCESS;
}

Here is the call graph for this function:

Definition at line 262 of file cairo-traps.c.

{
    cairo_status_t status;
    cairo_line_t line;
    cairo_fixed_16_16_t intersect;
    cairo_point_t tsort[3];

    memcpy (tsort, t, 3 * sizeof (cairo_point_t));
    qsort (tsort, 3, sizeof (cairo_point_t), _compare_point_fixed_by_y);

    /* horizontal top edge requires special handling */
    if (tsort[0].y == tsort[1].y) {
       if (tsort[0].x < tsort[1].x)
           status = _cairo_traps_add_trap_from_points (traps,
                                                 tsort[1].y, tsort[2].y,
                                                 tsort[0], tsort[2],
                                                 tsort[1], tsort[2]);
       else
           status = _cairo_traps_add_trap_from_points (traps,
                                                 tsort[1].y, tsort[2].y,
                                                 tsort[1], tsort[2],
                                                 tsort[0], tsort[2]);
       return status;
    }

    line.p1 = tsort[0];
    line.p2 = tsort[1];

    intersect = _compute_x (&line, tsort[2].y);

    if (intersect < tsort[2].x) {
       status = _cairo_traps_add_trap_from_points (traps,
                                              tsort[0].y, tsort[1].y,
                                              tsort[0], tsort[1],
                                              tsort[0], tsort[2]);
       if (status)
           return status;
       status = _cairo_traps_add_trap_from_points (traps,
                                              tsort[1].y, tsort[2].y,
                                              tsort[1], tsort[2],
                                              tsort[0], tsort[2]);
       if (status)
           return status;
    } else {
       status = _cairo_traps_add_trap_from_points (traps,
                                              tsort[0].y, tsort[1].y,
                                              tsort[0], tsort[2],
                                              tsort[0], tsort[1]);
       if (status)
           return status;
       status = _cairo_traps_add_trap_from_points (traps,
                                              tsort[1].y, tsort[2].y,
                                              tsort[0], tsort[2],
                                              tsort[1], tsort[2]);
       if (status)
           return status;
    }

    return CAIRO_STATUS_SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _cairo_traps_translate ( cairo_traps_t traps,
int  x,
int  y 
)

Definition at line 233 of file cairo-traps.c.

{
    cairo_fixed_t xoff, yoff;
    cairo_trapezoid_t *t;
    int i;

    /* Ugh. The cairo_composite/(Render) interface doesn't allow
       an offset for the trapezoids. Need to manually shift all
       the coordinates to align with the offset origin of the
       intermediate surface. */

    xoff = _cairo_fixed_from_int (x);
    yoff = _cairo_fixed_from_int (y);

    for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) {
       t->top += yoff;
       t->bottom += yoff;
       t->left.p1.x += xoff;
       t->left.p1.y += yoff;
       t->left.p2.x += xoff;
       t->left.p2.y += yoff;
       t->right.p1.x += xoff;
       t->right.p1.y += yoff;
       t->right.p2.x += xoff;
       t->right.p2.y += yoff;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int _compare_cairo_edge_by_current_x_slope ( const void av,
const void bv 
) [static]

Definition at line 397 of file cairo-traps.c.

{
    const cairo_edge_t *a = av, *b = bv;
    int ret;

    ret = a->current_x - b->current_x;
    if (ret == 0)
       ret = _compare_cairo_edge_by_slope (a, b);
    return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int _compare_cairo_edge_by_slope ( const void av,
const void bv 
) [static]

Definition at line 376 of file cairo-traps.c.

{
    const cairo_edge_t *a = av, *b = bv;
    cairo_fixed_32_32_t d;

    cairo_fixed_48_16_t a_dx = a->edge.p2.x - a->edge.p1.x;
    cairo_fixed_48_16_t a_dy = a->edge.p2.y - a->edge.p1.y;
    cairo_fixed_48_16_t b_dx = b->edge.p2.x - b->edge.p1.x;
    cairo_fixed_48_16_t b_dy = b->edge.p2.y - b->edge.p1.y;

    d = b_dy * a_dx - a_dy * b_dx;

    if (d > 0)
       return 1;
    else if (d == 0)
       return 0;
    else
       return -1;
}

Here is the caller graph for this function:

static int _compare_cairo_edge_by_top ( const void av,
const void bv 
) [static]

Definition at line 363 of file cairo-traps.c.

{
    const cairo_edge_t *a = av, *b = bv;

    return a->edge.p1.y - b->edge.p1.y;
}

Here is the caller graph for this function:

static int _compare_point_fixed_by_y ( const void av,
const void bv 
) [static]

Definition at line 221 of file cairo-traps.c.

{
    const cairo_point_t     *a = av, *b = bv;

    int ret = a->y - b->y;
    if (ret == 0) {
       ret = a->x - b->x;
    }
    return ret;
}

Here is the caller graph for this function:

static double _compute_inverse_slope ( cairo_line_t l) [static]

Definition at line 564 of file cairo-traps.c.

{
    return (_cairo_fixed_to_double (l->p2.x - l->p1.x) / 
           _cairo_fixed_to_double (l->p2.y - l->p1.y));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static cairo_fixed_16_16_t _compute_x ( cairo_line_t line,
cairo_fixed_t  y 
) [static]

Definition at line 553 of file cairo-traps.c.

{
    cairo_fixed_16_16_t dx = line->p2.x - line->p1.x;
    cairo_fixed_32_32_t ex = (cairo_fixed_48_16_t) (y - line->p1.y) * (cairo_fixed_48_16_t) dx;
    cairo_fixed_16_16_t dy = line->p2.y - line->p1.y;

    return line->p1.x + (ex / dy);
}

Here is the caller graph for this function:

static double _compute_x_intercept ( cairo_line_t l,
double  inverse_slope 
) [static]

Definition at line 571 of file cairo-traps.c.

{
    return _cairo_fixed_to_double (l->p1.x) - inverse_slope * _cairo_fixed_to_double (l->p1.y);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int _line_segs_intersect_ceil ( cairo_line_t left,
cairo_line_t right,
cairo_fixed_t y_ret 
) [static]

Definition at line 577 of file cairo-traps.c.

{
    /*
     * x = m1y + b1
     * x = m2y + b2
     * m1y + b1 = m2y + b2
     * y * (m1 - m2) = b2 - b1
     * y = (b2 - b1) / (m1 - m2)
     */
    cairo_fixed_16_16_t y_intersect;
    double  m1 = _compute_inverse_slope (l1);
    double  b1 = _compute_x_intercept (l1, m1);
    double  m2 = _compute_inverse_slope (l2);
    double  b2 = _compute_x_intercept (l2, m2);

    if (m1 == m2)
       return 0;

    y_intersect = _cairo_fixed_from_double ((b2 - b1) / (m1 - m2));

    if (m1 < m2) {
       cairo_line_t *t;
       t = l1;
       l1 = l2;
       l2 = t;
    }

    /* Assuming 56 bits of floating point precision, the intersection
       is accurate within one sub-pixel coordinate. We must ensure
       that we return a value that is at or after the intersection. At
       most, we must increment once. */
    if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
       y_intersect++;
    /* XXX: Hmm... Keith's error calculations said we'd at most be off
       by one sub-pixel. But, I found that the paint-fill-BE-01.svg
       test from the W3C SVG conformance suite definitely requires two
       increments.

       It could be that we need one to overcome the error, and another
       to round up.

       It would be nice to be sure this code is correct, (but we can't
       do the while loop as it will work for way to long on
       exceedingly distant intersections with large errors that we
       really don't care about anyway as they will be ignored by the
       calling function.
    */
    if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
       y_intersect++;
    /* XXX: hmm... now I found "intersection_killer" inside xrspline.c
       that requires 3 increments. Clearly, we haven't characterized
       this completely yet. */
    if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
       y_intersect++;
    /* I think I've found the answer to our problems. The insight is
       that everytime we round we are changing the slopes of the
       relevant lines, so we may be introducing new intersections that
       we miss, so everything breaks apart. John Hobby wrote a paper
       on how to fix this:

       [Hobby93c] John D. Hobby, Practical Segment Intersection with
       Finite Precision Output, Computation Geometry Theory and
       Applications, 13(4), 1999.

       Available online (2003-08017):

       http://cm.bell-labs.com/cm/cs/doc/93/2-27.ps.gz

       Now we just need to go off and implement that.
    */

    *y_ret = y_intersect;

    return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function: