static int edge_compare_for_y_against_x (const cairo_point_t *p1, const cairo_point_t *p2, cairo_fixed_t y, cairo_fixed_t x) { cairo_fixed_t adx, ady; cairo_fixed_t dx, dy; cairo_int64_t L, R; adx = p2->x - p1->x; dx = x - p1->x; if (adx == 0) return -dx; if ((adx ^ dx) < 0) return adx; dy = y - p1->y; ady = p2->y - p1->y; L = _cairo_int32x32_64_mul (dy, adx); R = _cairo_int32x32_64_mul (dx, ady); return _cairo_int64_cmp (L, R); }
/* * We need to compare the x-coordinate of a line for a particular y wrt to a * given x, without loss of precision. * * The x-coordinate along an edge for a given y is: * X = A_x + (Y - A_y) * A_dx / A_dy * * So the inequality we wish to test is: * A_x + (Y - A_y) * A_dx / A_dy ∘ X * where ∘ is our inequality operator. * * By construction, we know that A_dy (and (Y - A_y)) are * all positive, so we can rearrange it thus without causing a sign change: * (Y - A_y) * A_dx ∘ (X - A_x) * A_dy * * Given the assumption that all the deltas fit within 32 bits, we can compute * this comparison directly using 64 bit arithmetic. * * See the similar discussion for _slope_compare() and * edges_compare_x_for_y_general(). */ static int edge_compare_for_y_against_x (const cairo_bo_edge_t *a, int32_t y, int32_t x) { int32_t adx, ady; int32_t dx, dy; cairo_int64_t L, R; if (x < a->edge.line.p1.x && x < a->edge.line.p2.x) return 1; if (x > a->edge.line.p1.x && x > a->edge.line.p2.x) return -1; adx = a->edge.line.p2.x - a->edge.line.p1.x; dx = x - a->edge.line.p1.x; if (adx == 0) return -dx; if (dx == 0 || (adx ^ dx) < 0) return adx; dy = y - a->edge.line.p1.y; ady = a->edge.line.p2.y - a->edge.line.p1.y; L = _cairo_int32x32_64_mul (dy, adx); R = _cairo_int32x32_64_mul (dx, ady); return _cairo_int64_cmp (L, R); }
int _cairo_time_cmp (const void *a, const void *b) { const cairo_time_t *ta = a, *tb = b; return _cairo_int64_cmp (*ta, *tb); }
static int _cairo_hull_vertex_compare (const void *av, const void *bv) { cairo_hull_t *a = (cairo_hull_t *) av; cairo_hull_t *b = (cairo_hull_t *) bv; int ret; ret = _cairo_slope_compare (&a->slope, &b->slope); /* * In the case of two vertices with identical slope from the * extremal point discard the nearer point. */ if (ret == 0) { int cmp; cmp = _cairo_int64_cmp (_slope_length (&a->slope), _slope_length (&b->slope)); /* * Use the points' ids to ensure a well-defined ordering, * and avoid setting discard on both points. */ if (cmp < 0 || (cmp == 0 && a->id < b->id)) { a->discard = 1; ret = -1; } else { b->discard = 1; ret = 1; } } return ret; }
static int _cairo_hull_vertex_compare (const void *av, const void *bv) { cairo_hull_t *a = (cairo_hull_t *) av; cairo_hull_t *b = (cairo_hull_t *) bv; int ret; /* Some libraries are reported to actually compare identical * pointers and require the result to be 0. This is the crazy world we * have to live in. */ if (a == b) return 0; ret = _cairo_slope_compare (&a->slope, &b->slope); /* * In the case of two vertices with identical slope from the * extremal point discard the nearer point. */ if (ret == 0) { int cmp; cmp = _cairo_int64_cmp (_slope_length (&a->slope), _slope_length (&b->slope)); /* * Use the points' ids to ensure a well-defined ordering, * and avoid setting discard on both points. */ if (cmp < 0 || (cmp == 0 && a->id < b->id)) { a->discard = 1; ret = -1; } else { b->discard = 1; ret = 1; } } return ret; }
/* Compare two slopes. Slope angles begin at 0 in the direction of the positive X axis and increase in the direction of the positive Y axis. This function always compares the slope vectors based on the smaller angular difference between them, (that is based on an angular difference that is strictly less than pi). To break ties when comparing slope vectors with an angular difference of exactly pi, the vector with a positive dx (or positive dy if dx's are zero) is considered to be more positive than the other. Also, all slope vectors with both dx==0 and dy==0 are considered equal and more positive than any non-zero vector. < 0 => a less positive than b == 0 => a equal to b > 0 => a more positive than b */ int _cairo_slope_compare (const cairo_slope_t *a, const cairo_slope_t *b) { cairo_int64_t ady_bdx = _cairo_int32x32_64_mul (a->dy, b->dx); cairo_int64_t bdy_adx = _cairo_int32x32_64_mul (b->dy, a->dx); int cmp; cmp = _cairo_int64_cmp (ady_bdx, bdy_adx); if (cmp) return cmp; /* special-case zero vectors. the intended logic here is: * zero vectors all compare equal, and more positive than any * non-zero vector. */ if (a->dx == 0 && a->dy == 0 && b->dx == 0 && b->dy ==0) return 0; if (a->dx == 0 && a->dy == 0) return 1; if (b->dx == 0 && b->dy ==0) return -1; /* Finally, we're looking at two vectors that are either equal or * that differ by exactly pi. We can identify the "differ by pi" * case by looking for a change in sign in either dx or dy between * a and b. * * And in these cases, we eliminate the ambiguity by reducing the angle * of b by an infinitesimally small amount, (that is, 'a' will * always be considered less than 'b'). */ if ((a->dx ^ b->dx) < 0 || (a->dy ^ b->dy) < 0) { if (a->dx > 0 || (a->dx == 0 && a->dy > 0)) return +1; else return -1; } /* Finally, for identical slopes, we obviously return 0. */ return 0; }
/* Compare the slope of a to the slope of b, returning 1, 0, -1 if the * slope a is respectively greater than, equal to, or less than the * slope of b. * * For each edge, consider the direction vector formed from: * * top -> bottom * * which is: * * (dx, dy) = (line.p2.x - line.p1.x, line.p2.y - line.p1.y) * * We then define the slope of each edge as dx/dy, (which is the * inverse of the slope typically used in math instruction). We never * compute a slope directly as the value approaches infinity, but we * can derive a slope comparison without division as follows, (where * the ? represents our compare operator). * * 1. slope(a) ? slope(b) * 2. adx/ady ? bdx/bdy * 3. (adx * bdy) ? (bdx * ady) * * Note that from step 2 to step 3 there is no change needed in the * sign of the result since both ady and bdy are guaranteed to be * greater than or equal to 0. * * When using this slope comparison to sort edges, some care is needed * when interpreting the results. Since the slope compare operates on * distance vectors from top to bottom it gives a correct left to * right sort for edges that have a common top point, (such as two * edges with start events at the same location). On the other hand, * the sense of the result will be exactly reversed for two edges that * have a common stop point. */ static inline int _slope_compare (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b) { /* XXX: We're assuming here that dx and dy will still fit in 32 * bits. That's not true in general as there could be overflow. We * should prevent that before the tessellation algorithm * begins. */ int32_t adx = a->edge.line.p2.x - a->edge.line.p1.x; int32_t bdx = b->edge.line.p2.x - b->edge.line.p1.x; /* Since the dy's are all positive by construction we can fast * path several common cases. */ /* First check for vertical lines. */ if (adx == 0) return -bdx; if (bdx == 0) return adx; /* Then where the two edges point in different directions wrt x. */ if ((adx ^ bdx) < 0) return adx; /* Finally we actually need to do the general comparison. */ { int32_t ady = a->edge.line.p2.y - a->edge.line.p1.y; int32_t bdy = b->edge.line.p2.y - b->edge.line.p1.y; cairo_int64_t adx_bdy = _cairo_int32x32_64_mul (adx, bdy); cairo_int64_t bdx_ady = _cairo_int32x32_64_mul (bdx, ady); return _cairo_int64_cmp (adx_bdy, bdx_ady); } }
/* * We need to compare the x-coordinates of a pair of lines for a particular y, * without loss of precision. * * The x-coordinate along an edge for a given y is: * X = A_x + (Y - A_y) * A_dx / A_dy * * So the inequality we wish to test is: * A_x + (Y - A_y) * A_dx / A_dy ∘ B_x + (Y - B_y) * B_dx / B_dy, * where ∘ is our inequality operator. * * By construction, we know that A_dy and B_dy (and (Y - A_y), (Y - B_y)) are * all positive, so we can rearrange it thus without causing a sign change: * A_dy * B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx * A_dy * - (Y - A_y) * A_dx * B_dy * * Given the assumption that all the deltas fit within 32 bits, we can compute * this comparison directly using 128 bit arithmetic. For certain, but common, * input we can reduce this down to a single 32 bit compare by inspecting the * deltas. * * (And put the burden of the work on developing fast 128 bit ops, which are * required throughout the tessellator.) * * See the similar discussion for _slope_compare(). */ static int edges_compare_x_for_y_general (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b, int32_t y) { /* XXX: We're assuming here that dx and dy will still fit in 32 * bits. That's not true in general as there could be overflow. We * should prevent that before the tessellation algorithm * begins. */ int32_t dx; int32_t adx, ady; int32_t bdx, bdy; enum { HAVE_NONE = 0x0, HAVE_DX = 0x1, HAVE_ADX = 0x2, HAVE_DX_ADX = HAVE_DX | HAVE_ADX, HAVE_BDX = 0x4, HAVE_DX_BDX = HAVE_DX | HAVE_BDX, HAVE_ADX_BDX = HAVE_ADX | HAVE_BDX, HAVE_ALL = HAVE_DX | HAVE_ADX | HAVE_BDX } have_dx_adx_bdx = HAVE_ALL; /* don't bother solving for abscissa if the edges' bounding boxes * can be used to order them. */ { int32_t amin, amax; int32_t bmin, bmax; if (a->edge.line.p1.x < a->edge.line.p2.x) { amin = a->edge.line.p1.x; amax = a->edge.line.p2.x; } else { amin = a->edge.line.p2.x; amax = a->edge.line.p1.x; } if (b->edge.line.p1.x < b->edge.line.p2.x) { bmin = b->edge.line.p1.x; bmax = b->edge.line.p2.x; } else { bmin = b->edge.line.p2.x; bmax = b->edge.line.p1.x; } if (amax < bmin) return -1; if (amin > bmax) return +1; } ady = a->edge.line.p2.y - a->edge.line.p1.y; adx = a->edge.line.p2.x - a->edge.line.p1.x; if (adx == 0) have_dx_adx_bdx &= ~HAVE_ADX; bdy = b->edge.line.p2.y - b->edge.line.p1.y; bdx = b->edge.line.p2.x - b->edge.line.p1.x; if (bdx == 0) have_dx_adx_bdx &= ~HAVE_BDX; dx = a->edge.line.p1.x - b->edge.line.p1.x; if (dx == 0) have_dx_adx_bdx &= ~HAVE_DX; #define L _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (ady, bdy), dx) #define A _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (adx, bdy), y - a->edge.line.p1.y) #define B _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (bdx, ady), y - b->edge.line.p1.y) switch (have_dx_adx_bdx) { default: case HAVE_NONE: return 0; case HAVE_DX: /* A_dy * B_dy * (A_x - B_x) ∘ 0 */ return dx; /* ady * bdy is positive definite */ case HAVE_ADX: /* 0 ∘ - (Y - A_y) * A_dx * B_dy */ return adx; /* bdy * (y - a->top.y) is positive definite */ case HAVE_BDX: /* 0 ∘ (Y - B_y) * B_dx * A_dy */ return -bdx; /* ady * (y - b->top.y) is positive definite */ case HAVE_ADX_BDX: /* 0 ∘ (Y - B_y) * B_dx * A_dy - (Y - A_y) * A_dx * B_dy */ if ((adx ^ bdx) < 0) { return adx; } else if (a->edge.line.p1.y == b->edge.line.p1.y) { /* common origin */ cairo_int64_t adx_bdy, bdx_ady; /* ∴ A_dx * B_dy ∘ B_dx * A_dy */ adx_bdy = _cairo_int32x32_64_mul (adx, bdy); bdx_ady = _cairo_int32x32_64_mul (bdx, ady); return _cairo_int64_cmp (adx_bdy, bdx_ady); } else return _cairo_int128_cmp (A, B); case HAVE_DX_ADX: /* A_dy * (A_x - B_x) ∘ - (Y - A_y) * A_dx */ if ((-adx ^ dx) < 0) { return dx; } else { cairo_int64_t ady_dx, dy_adx; ady_dx = _cairo_int32x32_64_mul (ady, dx); dy_adx = _cairo_int32x32_64_mul (a->edge.line.p1.y - y, adx); return _cairo_int64_cmp (ady_dx, dy_adx); } case HAVE_DX_BDX: /* B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx */ if ((bdx ^ dx) < 0) { return dx; } else { cairo_int64_t bdy_dx, dy_bdx; bdy_dx = _cairo_int32x32_64_mul (bdy, dx); dy_bdx = _cairo_int32x32_64_mul (y - b->edge.line.p1.y, bdx); return _cairo_int64_cmp (bdy_dx, dy_bdx); } case HAVE_ALL: /* XXX try comparing (a->edge.line.p2.x - b->edge.line.p2.x) et al */ return _cairo_int128_cmp (L, _cairo_int128_sub (B, A)); } #undef B #undef A #undef L }