| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include "cairoint.h" |
| |
| #include "cairo-line-inline.h" |
| #include "cairo-slope-private.h" |
| |
| static int |
| line_compare_for_y_against_x (const cairo_line_t *a, |
| int32_t y, |
| int32_t x) |
| { |
| int32_t adx, ady; |
| int32_t dx, dy; |
| cairo_int64_t L, R; |
| |
| if (x < a->p1.x && x < a->p2.x) |
| return 1; |
| if (x > a->p1.x && x > a->p2.x) |
| return -1; |
| |
| adx = a->p2.x - a->p1.x; |
| dx = x - a->p1.x; |
| |
| if (adx == 0) |
| return -dx; |
| if (dx == 0 || (adx ^ dx) < 0) |
| return adx; |
| |
| dy = y - a->p1.y; |
| ady = a->p2.y - a->p1.y; |
| |
| L = _cairo_int32x32_64_mul (dy, adx); |
| R = _cairo_int32x32_64_mul (dx, ady); |
| |
| return _cairo_int64_cmp (L, R); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int |
| lines_compare_x_for_y_general (const cairo_line_t *a, |
| const cairo_line_t *b, |
| int32_t y) |
| { |
| |
| |
| |
| |
| |
| int32_t dx = 0; |
| int32_t adx = 0, ady = 0; |
| int32_t bdx = 0, bdy = 0; |
| 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; |
| |
| ady = a->p2.y - a->p1.y; |
| adx = a->p2.x - a->p1.x; |
| if (adx == 0) |
| have_dx_adx_bdx &= ~HAVE_ADX; |
| |
| bdy = b->p2.y - b->p1.y; |
| bdx = b->p2.x - b->p1.x; |
| if (bdx == 0) |
| have_dx_adx_bdx &= ~HAVE_BDX; |
| |
| dx = a->p1.x - b->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->p1.y) |
| #define B _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (bdx, ady), y - b->p1.y) |
| switch (have_dx_adx_bdx) { |
| default: |
| case HAVE_NONE: |
| return 0; |
| case HAVE_DX: |
| |
| return dx; |
| case HAVE_ADX: |
| |
| return adx; |
| case HAVE_BDX: |
| |
| return -bdx; |
| case HAVE_ADX_BDX: |
| |
| if ((adx ^ bdx) < 0) { |
| return adx; |
| } else if (a->p1.y == b->p1.y) { |
| cairo_int64_t adx_bdy, bdx_ady; |
| |
| |
| |
| 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: |
| |
| 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->p1.y - y, adx); |
| |
| return _cairo_int64_cmp (ady_dx, dy_adx); |
| } |
| case HAVE_DX_BDX: |
| |
| 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->p1.y, bdx); |
| |
| return _cairo_int64_cmp (bdy_dx, dy_bdx); |
| } |
| case HAVE_ALL: |
| |
| return _cairo_int128_cmp (L, _cairo_int128_sub (B, A)); |
| } |
| #undef B |
| #undef A |
| #undef L |
| } |
| |
| static int |
| lines_compare_x_for_y (const cairo_line_t *a, |
| const cairo_line_t *b, |
| int32_t y) |
| { |
| |
| |
| |
| |
| |
| enum { |
| HAVE_NEITHER = 0x0, |
| HAVE_AX = 0x1, |
| HAVE_BX = 0x2, |
| HAVE_BOTH = HAVE_AX | HAVE_BX |
| } have_ax_bx = HAVE_BOTH; |
| int32_t ax = 0, bx = 0; |
| |
| if (y == a->p1.y) |
| ax = a->p1.x; |
| else if (y == a->p2.y) |
| ax = a->p2.x; |
| else |
| have_ax_bx &= ~HAVE_AX; |
| |
| if (y == b->p1.y) |
| bx = b->p1.x; |
| else if (y == b->p2.y) |
| bx = b->p2.x; |
| else |
| have_ax_bx &= ~HAVE_BX; |
| |
| switch (have_ax_bx) { |
| default: |
| case HAVE_NEITHER: |
| return lines_compare_x_for_y_general (a, b, y); |
| case HAVE_AX: |
| return -line_compare_for_y_against_x (b, y, ax); |
| case HAVE_BX: |
| return line_compare_for_y_against_x (a, y, bx); |
| case HAVE_BOTH: |
| return ax - bx; |
| } |
| } |
| |
| static int bbox_compare (const cairo_line_t *a, |
| const cairo_line_t *b) |
| { |
| int32_t amin, amax; |
| int32_t bmin, bmax; |
| |
| if (a->p1.x < a->p2.x) { |
| amin = a->p1.x; |
| amax = a->p2.x; |
| } else { |
| amin = a->p2.x; |
| amax = a->p1.x; |
| } |
| |
| if (b->p1.x < b->p2.x) { |
| bmin = b->p1.x; |
| bmax = b->p2.x; |
| } else { |
| bmin = b->p2.x; |
| bmax = b->p1.x; |
| } |
| |
| if (amax < bmin) |
| return -1; |
| |
| if (amin > bmax) |
| return +1; |
| |
| return 0; |
| } |
| |
| int cairo_lines_compare_at_y (const cairo_line_t *a, |
| const cairo_line_t *b, |
| int y) |
| { |
| cairo_slope_t sa, sb; |
| int ret; |
| |
| if (cairo_lines_equal (a, b)) |
| return 0; |
| |
| |
| |
| |
| ret = bbox_compare (a, b); |
| if (ret) |
| return ret; |
| |
| ret = lines_compare_x_for_y (a, b, y); |
| if (ret) |
| return ret; |
| |
| _cairo_slope_init (&sa, &a->p1, &a->p2); |
| _cairo_slope_init (&sb, &b->p1, &b->p2); |
| |
| return _cairo_slope_compare (&sb, &sa); |
| } |