mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-06-12 08:58:27 +02:00
stroke: Adapt rectilinear stroker to handle separable non-unity scaling
Reported-by: Christos Sotiriou <csotiriou@gmail.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
1e4f385dec
commit
0a778d974f
6 changed files with 84 additions and 79 deletions
|
|
@ -700,21 +700,6 @@ _cairo_matrix_compute_basis_scale_factors (const cairo_matrix_t *matrix,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_matrix_is_identity (const cairo_matrix_t *matrix)
|
||||
{
|
||||
return (matrix->xx == 1.0 && matrix->yx == 0.0 &&
|
||||
matrix->xy == 0.0 && matrix->yy == 1.0 &&
|
||||
matrix->x0 == 0.0 && matrix->y0 == 0.0);
|
||||
}
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_matrix_is_translation (const cairo_matrix_t *matrix)
|
||||
{
|
||||
return (matrix->xx == 1.0 && matrix->yx == 0.0 &&
|
||||
matrix->xy == 0.0 && matrix->yy == 1.0);
|
||||
}
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix,
|
||||
int *itx, int *ity)
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ typedef struct _cairo_rectilinear_stroker {
|
|||
const cairo_matrix_t *ctm;
|
||||
cairo_antialias_t antialias;
|
||||
|
||||
cairo_fixed_t half_line_width;
|
||||
cairo_fixed_t half_line_x, half_line_y;
|
||||
cairo_boxes_t *boxes;
|
||||
cairo_point_t current_point;
|
||||
cairo_point_t first_point;
|
||||
|
|
@ -82,11 +82,11 @@ _cairo_rectilinear_stroker_limit (cairo_rectilinear_stroker_t *stroker,
|
|||
stroker->has_bounds = TRUE;
|
||||
_cairo_boxes_get_extents (boxes, num_boxes, &stroker->bounds);
|
||||
|
||||
stroker->bounds.p1.x -= stroker->half_line_width;
|
||||
stroker->bounds.p2.x += stroker->half_line_width;
|
||||
stroker->bounds.p1.x -= stroker->half_line_x;
|
||||
stroker->bounds.p2.x += stroker->half_line_x;
|
||||
|
||||
stroker->bounds.p1.y -= stroker->half_line_width;
|
||||
stroker->bounds.p2.y += stroker->half_line_width;
|
||||
stroker->bounds.p1.y -= stroker->half_line_y;
|
||||
stroker->bounds.p2.y += stroker->half_line_y;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
|
|
@ -122,15 +122,18 @@ _cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t *stroker,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (! _cairo_matrix_has_unity_scale (ctm))
|
||||
if (! _cairo_matrix_is_scale (ctm))
|
||||
return FALSE;
|
||||
|
||||
stroker->stroke_style = stroke_style;
|
||||
stroker->ctm = ctm;
|
||||
stroker->antialias = antialias;
|
||||
|
||||
stroker->half_line_width =
|
||||
_cairo_fixed_from_double (stroke_style->line_width / 2.0);
|
||||
stroker->half_line_x =
|
||||
_cairo_fixed_from_double (fabs(ctm->xx) * stroke_style->line_width / 2.0);
|
||||
stroker->half_line_y =
|
||||
_cairo_fixed_from_double (fabs(ctm->yy) * stroke_style->line_width / 2.0);
|
||||
|
||||
stroker->open_sub_path = FALSE;
|
||||
stroker->segments = stroker->segments_embedded;
|
||||
stroker->segments_size = ARRAY_LENGTH (stroker->segments_embedded);
|
||||
|
|
@ -197,7 +200,8 @@ static cairo_status_t
|
|||
_cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
|
||||
{
|
||||
cairo_line_cap_t line_cap = stroker->stroke_style->line_cap;
|
||||
cairo_fixed_t half_line_width = stroker->half_line_width;
|
||||
cairo_fixed_t half_line_x = stroker->half_line_x;
|
||||
cairo_fixed_t half_line_y = stroker->half_line_y;
|
||||
cairo_status_t status;
|
||||
int i;
|
||||
|
||||
|
|
@ -238,26 +242,26 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
|
|||
if (a->y == b->y) {
|
||||
if (a->x < b->x) {
|
||||
if (lengthen_initial)
|
||||
a->x -= half_line_width;
|
||||
a->x -= half_line_x;
|
||||
if (lengthen_final)
|
||||
b->x += half_line_width;
|
||||
b->x += half_line_x;
|
||||
} else {
|
||||
if (lengthen_initial)
|
||||
a->x += half_line_width;
|
||||
a->x += half_line_x;
|
||||
if (lengthen_final)
|
||||
b->x -= half_line_width;
|
||||
b->x -= half_line_x;
|
||||
}
|
||||
} else {
|
||||
if (a->y < b->y) {
|
||||
if (lengthen_initial)
|
||||
a->y -= half_line_width;
|
||||
a->y -= half_line_y;
|
||||
if (lengthen_final)
|
||||
b->y += half_line_width;
|
||||
b->y += half_line_y;
|
||||
} else {
|
||||
if (lengthen_initial)
|
||||
a->y += half_line_width;
|
||||
a->y += half_line_y;
|
||||
if (lengthen_final)
|
||||
b->y -= half_line_width;
|
||||
b->y -= half_line_y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -265,11 +269,11 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
|
|||
/* Form the rectangle by expanding by half the line width in
|
||||
* either perpendicular direction. */
|
||||
if (a->y == b->y) {
|
||||
a->y -= half_line_width;
|
||||
b->y += half_line_width;
|
||||
a->y -= half_line_y;
|
||||
b->y += half_line_y;
|
||||
} else {
|
||||
a->x -= half_line_width;
|
||||
b->x += half_line_width;
|
||||
a->x -= half_line_x;
|
||||
b->x += half_line_x;
|
||||
}
|
||||
|
||||
if (a->x < b->x) {
|
||||
|
|
@ -301,7 +305,8 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st
|
|||
{
|
||||
cairo_status_t status;
|
||||
cairo_line_cap_t line_cap = stroker->stroke_style->line_cap;
|
||||
cairo_fixed_t half_line_width = stroker->half_line_width;
|
||||
cairo_fixed_t half_line_x = stroker->half_line_x;
|
||||
cairo_fixed_t half_line_y = stroker->half_line_y;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < stroker->num_segments; i++) {
|
||||
|
|
@ -332,25 +337,25 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st
|
|||
if (is_horizontal) {
|
||||
if (box.p1.x <= box.p2.x) {
|
||||
box.p1.x = box.p2.x;
|
||||
box.p2.x += half_line_width;
|
||||
box.p2.x += half_line_x;
|
||||
} else {
|
||||
box.p1.x = box.p2.x - half_line_width;
|
||||
box.p1.x = box.p2.x - half_line_x;
|
||||
}
|
||||
if (out_slope.dy >= 0)
|
||||
box.p1.y -= half_line_width;
|
||||
box.p1.y -= half_line_x;
|
||||
if (out_slope.dy <= 0)
|
||||
box.p2.y += half_line_width;
|
||||
box.p2.y += half_line_x;
|
||||
} else {
|
||||
if (box.p1.y <= box.p2.y) {
|
||||
box.p1.y = box.p2.y;
|
||||
box.p2.y += half_line_width;
|
||||
box.p2.y += half_line_x;
|
||||
} else {
|
||||
box.p1.y = box.p2.y - half_line_width;
|
||||
box.p1.y = box.p2.y - half_line_x;
|
||||
}
|
||||
if (out_slope.dx >= 0)
|
||||
box.p1.x -= half_line_width;
|
||||
box.p1.x -= half_line_x;
|
||||
if (out_slope.dx <= 0)
|
||||
box.p2.x += half_line_width;
|
||||
box.p2.x += half_line_x;
|
||||
}
|
||||
|
||||
status = _cairo_boxes_add (stroker->boxes, stroker->antialias, &box);
|
||||
|
|
@ -362,29 +367,29 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st
|
|||
if (is_horizontal) {
|
||||
if (line_cap == CAIRO_LINE_CAP_SQUARE) {
|
||||
if (a->x <= b->x) {
|
||||
a->x -= half_line_width;
|
||||
b->x += half_line_width;
|
||||
a->x -= half_line_x;
|
||||
b->x += half_line_x;
|
||||
} else {
|
||||
a->x += half_line_width;
|
||||
b->x -= half_line_width;
|
||||
a->x += half_line_x;
|
||||
b->x -= half_line_x;
|
||||
}
|
||||
}
|
||||
|
||||
a->y += half_line_width;
|
||||
b->y -= half_line_width;
|
||||
a->y += half_line_y;
|
||||
b->y -= half_line_y;
|
||||
} else {
|
||||
if (line_cap == CAIRO_LINE_CAP_SQUARE) {
|
||||
if (a->y <= b->y) {
|
||||
a->y -= half_line_width;
|
||||
b->y += half_line_width;
|
||||
a->y -= half_line_y;
|
||||
b->y += half_line_y;
|
||||
} else {
|
||||
a->y += half_line_width;
|
||||
b->y -= half_line_width;
|
||||
a->y += half_line_y;
|
||||
b->y -= half_line_y;
|
||||
}
|
||||
}
|
||||
|
||||
a->x += half_line_width;
|
||||
b->x -= half_line_width;
|
||||
a->x += half_line_x;
|
||||
b->x -= half_line_x;
|
||||
}
|
||||
|
||||
if (a->x == b->x && a->y == b->y)
|
||||
|
|
@ -621,40 +626,40 @@ _cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path,
|
|||
if (! rectilinear_stroker.dash.dashed &&
|
||||
_cairo_path_fixed_is_stroke_box (path, &box) &&
|
||||
/* if the segments overlap we need to feed them into the tessellator */
|
||||
box.p2.x - box.p1.x > 2* rectilinear_stroker.half_line_width &&
|
||||
box.p2.y - box.p1.y > 2* rectilinear_stroker.half_line_width)
|
||||
box.p2.x - box.p1.x > 2* rectilinear_stroker.half_line_x &&
|
||||
box.p2.y - box.p1.y > 2* rectilinear_stroker.half_line_y)
|
||||
{
|
||||
cairo_box_t b;
|
||||
|
||||
/* top */
|
||||
b.p1.x = box.p1.x - rectilinear_stroker.half_line_width;
|
||||
b.p2.x = box.p2.x + rectilinear_stroker.half_line_width;
|
||||
b.p1.y = box.p1.y - rectilinear_stroker.half_line_width;
|
||||
b.p2.y = box.p1.y + rectilinear_stroker.half_line_width;
|
||||
b.p1.x = box.p1.x - rectilinear_stroker.half_line_x;
|
||||
b.p2.x = box.p2.x + rectilinear_stroker.half_line_x;
|
||||
b.p1.y = box.p1.y - rectilinear_stroker.half_line_y;
|
||||
b.p2.y = box.p1.y + rectilinear_stroker.half_line_y;
|
||||
status = _cairo_boxes_add (boxes, antialias, &b);
|
||||
assert (status == CAIRO_INT_STATUS_SUCCESS);
|
||||
|
||||
/* left (excluding top/bottom) */
|
||||
b.p1.x = box.p1.x - rectilinear_stroker.half_line_width;
|
||||
b.p2.x = box.p1.x + rectilinear_stroker.half_line_width;
|
||||
b.p1.y = box.p1.y + rectilinear_stroker.half_line_width;
|
||||
b.p2.y = box.p2.y - rectilinear_stroker.half_line_width;
|
||||
b.p1.x = box.p1.x - rectilinear_stroker.half_line_x;
|
||||
b.p2.x = box.p1.x + rectilinear_stroker.half_line_x;
|
||||
b.p1.y = box.p1.y + rectilinear_stroker.half_line_y;
|
||||
b.p2.y = box.p2.y - rectilinear_stroker.half_line_y;
|
||||
status = _cairo_boxes_add (boxes, antialias, &b);
|
||||
assert (status == CAIRO_INT_STATUS_SUCCESS);
|
||||
|
||||
/* right (excluding top/bottom) */
|
||||
b.p1.x = box.p2.x - rectilinear_stroker.half_line_width;
|
||||
b.p2.x = box.p2.x + rectilinear_stroker.half_line_width;
|
||||
b.p1.y = box.p1.y + rectilinear_stroker.half_line_width;
|
||||
b.p2.y = box.p2.y - rectilinear_stroker.half_line_width;
|
||||
b.p1.x = box.p2.x - rectilinear_stroker.half_line_x;
|
||||
b.p2.x = box.p2.x + rectilinear_stroker.half_line_x;
|
||||
b.p1.y = box.p1.y + rectilinear_stroker.half_line_y;
|
||||
b.p2.y = box.p2.y - rectilinear_stroker.half_line_y;
|
||||
status = _cairo_boxes_add (boxes, antialias, &b);
|
||||
assert (status == CAIRO_INT_STATUS_SUCCESS);
|
||||
|
||||
/* bottom */
|
||||
b.p1.x = box.p1.x - rectilinear_stroker.half_line_width;
|
||||
b.p2.x = box.p2.x + rectilinear_stroker.half_line_width;
|
||||
b.p1.y = box.p2.y - rectilinear_stroker.half_line_width;
|
||||
b.p2.y = box.p2.y + rectilinear_stroker.half_line_width;
|
||||
b.p1.x = box.p1.x - rectilinear_stroker.half_line_x;
|
||||
b.p2.x = box.p2.x + rectilinear_stroker.half_line_x;
|
||||
b.p1.y = box.p2.y - rectilinear_stroker.half_line_y;
|
||||
b.p2.y = box.p2.y + rectilinear_stroker.half_line_y;
|
||||
status = _cairo_boxes_add (boxes, antialias, &b);
|
||||
assert (status == CAIRO_INT_STATUS_SUCCESS);
|
||||
|
||||
|
|
|
|||
|
|
@ -1657,11 +1657,26 @@ cairo_private cairo_status_t
|
|||
_cairo_matrix_compute_basis_scale_factors (const cairo_matrix_t *matrix,
|
||||
double *sx, double *sy, int x_major);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_matrix_is_identity (const cairo_matrix_t *matrix) cairo_pure;
|
||||
static inline cairo_bool_t
|
||||
_cairo_matrix_is_identity (const cairo_matrix_t *matrix)
|
||||
{
|
||||
return (matrix->xx == 1.0 && matrix->yx == 0.0 &&
|
||||
matrix->xy == 0.0 && matrix->yy == 1.0 &&
|
||||
matrix->x0 == 0.0 && matrix->y0 == 0.0);
|
||||
}
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_matrix_is_translation (const cairo_matrix_t *matrix) cairo_pure;
|
||||
static inline cairo_bool_t
|
||||
_cairo_matrix_is_translation (const cairo_matrix_t *matrix)
|
||||
{
|
||||
return (matrix->xx == 1.0 && matrix->yx == 0.0 &&
|
||||
matrix->xy == 0.0 && matrix->yy == 1.0);
|
||||
}
|
||||
|
||||
static inline cairo_bool_t
|
||||
_cairo_matrix_is_scale (const cairo_matrix_t *matrix)
|
||||
{
|
||||
return matrix->yx == 0.0 && matrix->xy == 0.0;
|
||||
}
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_matrix_is_integer_translation(const cairo_matrix_t *matrix,
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
Loading…
Add table
Reference in a new issue