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 30 Mar 2005 22:24:44 -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 30 Mar 2005 22:24:45 -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,86 @@ _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) { + /* + * Minimum expansion calculation from cairo_pen.c + */ + double a = gstate->ctm.m[0][0], c = gstate->ctm.m[0][1]; + double b = gstate->ctm.m[1][0], d = gstate->ctm.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; + + double min = gstate->max_dash_length * sqrt (f - sqrt (g*g+h*h)); + + if (min < 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 +1792,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 +1819,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)