Index: cairo-gstate-private.h =================================================================== RCS file: /cvs/cairo/cairo/src/cairo-gstate-private.h,v retrieving revision 1.2 diff -u -8 -p -r1.2 cairo-gstate-private.h --- cairo-gstate-private.h 23 Mar 2005 21:52:54 -0000 1.2 +++ cairo-gstate-private.h 31 Mar 2005 19:11:58 -0000 @@ -49,16 +49,18 @@ struct _cairo_gstate { cairo_line_join_t line_join; double miter_limit; cairo_fill_rule_t fill_rule; double *dash; int num_dashes; double dash_offset; + double max_dash_length; + double fraction_dash_lit; char *font_family; /* NULL means CAIRO_FONT_FAMILY_DEFAULT; */ cairo_font_slant_t font_slant; cairo_font_weight_t font_weight; cairo_font_t *font; /* Specific to the current CTM */ cairo_surface_t *surface; Index: cairo-gstate.c =================================================================== RCS file: /cvs/cairo/cairo/src/cairo-gstate.c,v retrieving revision 1.98 diff -u -8 -p -r1.98 cairo-gstate.c --- cairo-gstate.c 30 Mar 2005 17:31:49 -0000 1.98 +++ cairo-gstate.c 31 Mar 2005 19:11:58 -0000 @@ -86,16 +86,18 @@ _cairo_gstate_init (cairo_gstate_t *gsta gstate->line_join = CAIRO_GSTATE_LINE_JOIN_DEFAULT; gstate->miter_limit = CAIRO_GSTATE_MITER_LIMIT_DEFAULT; gstate->fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT; gstate->dash = NULL; gstate->num_dashes = 0; gstate->dash_offset = 0.0; + gstate->max_dash_length = 0.0; + gstate->fraction_dash_lit = 0.0; gstate->font_family = NULL; gstate->font_slant = CAIRO_FONT_SLANT_DEFAULT; gstate->font_weight = CAIRO_FONT_WEIGHT_DEFAULT; gstate->font = NULL; gstate->surface = NULL; @@ -540,28 +542,41 @@ cairo_line_join_t _cairo_gstate_get_line_join (cairo_gstate_t *gstate) { return gstate->line_join; } cairo_status_t _cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset) { + double length = 0.0, lit = 0.0; + int i; + if (gstate->dash) { free (gstate->dash); gstate->dash = NULL; } gstate->num_dashes = num_dashes; if (gstate->num_dashes) { gstate->dash = malloc (gstate->num_dashes * sizeof (double)); if (gstate->dash == NULL) { gstate->num_dashes = 0; return CAIRO_STATUS_NO_MEMORY; } + + gstate->max_dash_length = 0.0; + for (i = 0; i < num_dashes; i++) { + gstate->max_dash_length = MAX(dash[i], gstate->max_dash_length); + + if (!(i & 1)) + lit += dash[i]; + length += dash[i]; + } + gstate->fraction_dash_lit = lit/length; } memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double)); gstate->dash_offset = offset; return CAIRO_STATUS_SUCCESS; } @@ -1359,46 +1374,77 @@ _cairo_gstate_pattern_init_copy (cairo_g cairo_pattern_union_t *pattern, cairo_pattern_t *src) { _cairo_pattern_init_copy (&pattern->base, src); _cairo_gstate_pattern_transform (gstate, &pattern->base); _cairo_pattern_set_alpha (&pattern->base, gstate->alpha); } +static cairo_bool_t +_dashes_invisible (cairo_gstate_t *gstate) +{ + if (gstate->dash) { + double min, max; + + _cairo_matrix_compute_expansion_factors (&gstate->ctm, &min, &max); + + /* Quick and dirty applicaton of Nyquist sampling limit */ + + if (min * gstate->max_dash_length < 0.5f) + return TRUE; + } + + return FALSE; +} + cairo_status_t _cairo_gstate_stroke (cairo_gstate_t *gstate) { cairo_status_t status; cairo_traps_t traps; + double *dash = NULL; + double alpha = 0.0; if (gstate->line_width <= 0.0) return CAIRO_STATUS_SUCCESS; + if (_dashes_invisible(gstate)) { + dash = gstate->dash; + gstate->dash = NULL; + + alpha = gstate->alpha; + gstate->alpha *= gstate->fraction_dash_lit; + } + _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); _cairo_traps_init (&traps); status = _cairo_path_fixed_stroke_to_traps (&gstate->path, gstate, &traps); - if (status) { - _cairo_traps_fini (&traps); - return status; - } + if (status) + goto BAIL; _cairo_gstate_clip_and_composite_trapezoids (gstate, gstate->pattern, gstate->operator, gstate->surface, &traps); + BAIL: _cairo_traps_fini (&traps); _cairo_gstate_new_path (gstate); - return CAIRO_STATUS_SUCCESS; + if (dash) { + gstate->dash = dash; + gstate->alpha = alpha; + } + + return status; } cairo_status_t _cairo_gstate_in_stroke (cairo_gstate_t *gstate, double x, double y, cairo_bool_t *inside_ret) { @@ -1737,16 +1783,22 @@ _cairo_gstate_show_page (cairo_gstate_t cairo_status_t _cairo_gstate_stroke_extents (cairo_gstate_t *gstate, double *x1, double *y1, double *x2, double *y2) { cairo_status_t status; cairo_traps_t traps; cairo_box_t extents; + double *dash = NULL; + + if (_dashes_invisible(gstate)) { + dash = gstate->dash; + gstate->dash = NULL; + } _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); _cairo_traps_init (&traps); status = _cairo_path_fixed_stroke_to_traps (&gstate->path, gstate, &traps); if (status) goto BAIL; @@ -1758,16 +1810,19 @@ _cairo_gstate_stroke_extents (cairo_gsta *x2 = _cairo_fixed_to_double (extents.p2.x); *y2 = _cairo_fixed_to_double (extents.p2.y); _cairo_gstate_backend_to_user (gstate, x1, y1); _cairo_gstate_backend_to_user (gstate, x2, y2); BAIL: _cairo_traps_fini (&traps); + + if (dash) + gstate->dash = dash; return status; } cairo_status_t _cairo_gstate_fill_extents (cairo_gstate_t *gstate, double *x1, double *y1, double *x2, double *y2) Index: cairo-matrix.c =================================================================== RCS file: /cvs/cairo/cairo/src/cairo-matrix.c,v retrieving revision 1.21 diff -u -8 -p -r1.21 cairo-matrix.c --- cairo-matrix.c 21 Mar 2005 07:23:19 -0000 1.21 +++ cairo-matrix.c 31 Mar 2005 19:11:58 -0000 @@ -626,16 +626,39 @@ _cairo_matrix_compute_scale_factors (cai *sx = minor; *sy = major; } } return CAIRO_STATUS_SUCCESS; } +/* Compute the min/max expansion factors. See the comment in + * cairo-pen.c for the derivation */ +cairo_status_t +_cairo_matrix_compute_expansion_factors (cairo_matrix_t *matrix, + double *min, double *max) +{ + double a = matrix->m[0][0], c = matrix->m[0][1]; + double b = matrix->m[1][0], d = matrix->m[1][1]; + + double i = a*a + c*c; + double j = b*b + d*d; + + double f = 0.5 * (i + j); + double g = 0.5 * (i - j); + double h = a*b + c*d; + + *max = sqrt (f + sqrt (g*g+h*h)); + + *min = sqrt (f - sqrt (g*g+h*h)); + + return CAIRO_STATUS_SUCCESS; +} + cairo_bool_t _cairo_matrix_is_integer_translation(cairo_matrix_t *mat, int *itx, int *ity) { double a, b, c, d, tx, ty; int ttx, tty; int ok = 0; cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty); Index: cairo-pen.c =================================================================== RCS file: /cvs/cairo/cairo/src/cairo-pen.c,v retrieving revision 1.22 diff -u -8 -p -r1.22 cairo-pen.c --- cairo-pen.c 23 Mar 2005 21:50:51 -0000 1.22 +++ cairo-pen.c 31 Mar 2005 19:11:58 -0000 @@ -369,42 +369,25 @@ doesn't matter where on the circle the e */ static int _cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *matrix) { - double a = matrix->m[0][0], c = matrix->m[0][1]; - double b = matrix->m[1][0], d = matrix->m[1][1]; + double min, max, major_axis; + int num_vertices; - double i = a*a + c*c; - double j = b*b + d*d; + _cairo_matrix_compute_expansion_factors (matrix, &min, &max); + major_axis = radius * max; - double f = 0.5 * (i + j); - double g = 0.5 * (i - j); - double h = a*b + c*d; - - /* - * compute major and minor axes lengths for - * a pen with the specified radius - */ - - double major_axis = radius * sqrt (f + sqrt (g*g+h*h)); - - /* - * we don't need the minor axis length, which is - * double min = radius * sqrt (f - sqrt (g*g+h*h)); - */ - /* * compute number of vertices needed */ - int num_vertices; /* Where tolerance / M is > 1, we use 4 points */ if (tolerance >= major_axis) { num_vertices = 4; } else { double delta = acos (1 - tolerance / major_axis); num_vertices = ceil (M_PI / delta); Index: cairoint.h =================================================================== RCS file: /cvs/cairo/cairo/src/cairoint.h,v retrieving revision 1.113 diff -u -8 -p -r1.113 cairoint.h --- cairoint.h 29 Mar 2005 19:48:58 -0000 1.113 +++ cairoint.h 31 Mar 2005 19:11:58 -0000 @@ -1600,16 +1600,19 @@ cairo_private cairo_status_t _cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det); cairo_private cairo_status_t _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2); cairo_private cairo_status_t _cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major); +cairo_private cairo_status_t +_cairo_matrix_compute_expansion_factors (cairo_matrix_t *matrix, double *min, double *max); + cairo_private cairo_bool_t _cairo_matrix_is_integer_translation(cairo_matrix_t *matrix, int *itx, int *ity); /* cairo_traps.c */ cairo_private void _cairo_traps_init (cairo_traps_t *traps); cairo_private void