diff options
author | Andrea Canciani <ranma42@gmail.com> | 2010-01-15 10:44:58 +0100 |
---|---|---|
committer | Andrea Canciani <ranma42@gmail.com> | 2010-02-01 09:48:12 +0100 |
commit | 45c795a1820e0317b123e7782cefed6ade8996d7 (patch) | |
tree | abd864e101259adeca94f518e4583565839639aa /src/cairo-stroke-style.c | |
parent | 8d7841048b079ce2a582ff17c90e82e0081e5f42 (diff) | |
download | cairo-45c795a1820e0317b123e7782cefed6ade8996d7.tar.gz |
Improve dash pattern approximation
Dash pattern approximation was taking the caps style into account
only for coverage computation, but not when computing the new
pattern, thus the computed approximation had a higher coverage if
the caps style was SQUARE or ROUND.
Reviewed-by: M. Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
Diffstat (limited to 'src/cairo-stroke-style.c')
-rw-r--r-- | src/cairo-stroke-style.c | 56 |
1 files changed, 54 insertions, 2 deletions
diff --git a/src/cairo-stroke-style.c b/src/cairo-stroke-style.c index 28dc5ffb7..9a18e740f 100644 --- a/src/cairo-stroke-style.c +++ b/src/cairo-stroke-style.c @@ -251,8 +251,60 @@ _cairo_stroke_style_dash_approximate (const cairo_stroke_style_t *style, *num_dashes = 2; - dashes[0] = scale * coverage; - dashes[1] = scale * (1.0 - coverage); + /* + * We want to create a new dash pattern with the same relative coverage, + * but composed of just 2 elements with total length equal to scale. + * Based on the formula in _cairo_stroke_style_dash_stroked: + * scale * coverage = dashes[0] + cap_scale * MIN (dashes[1], line_width) + * = MIN (dashes[0] + cap_scale * (scale - dashes[0]), + * dashes[0] + cap_scale * line_width) = + * = MIN (dashes[0] * (1 - cap_scale) + cap_scale * scale, + * dashes[0] + cap_scale * line_width) + * + * Solving both cases we get: + * dashes[0] = scale * (coverage - cap_scale) / (1 - cap_scale) + * when scale - dashes[0] <= line_width + * dashes[0] = scale * coverage - cap_scale * line_width + * when scale - dashes[0] > line_width. + * + * Comparing the two cases we get: + * second > first + * second > scale * (coverage - cap_scale) / (1 - cap_scale) + * second - cap_scale * second - scale * coverage + scale * cap_scale > 0 + * (scale * coverage - cap_scale * line_width) - cap_scale * second - scale * coverage + scale * cap_scale > 0 + * - line_width - second + scale > 0 + * scale - second > line_width + * which is the condition for the second solution to be the valid one. + * So when second > first, the second solution is the correct one (i.e. + * the solution is always MAX (first, second). + */ + switch (style->line_cap) { + default: + ASSERT_NOT_REACHED; + dashes[0] = 0.0; + break; + + case CAIRO_LINE_CAP_BUTT: + /* Simplified formula (substituting 0 for cap_scale): */ + dashes[0] = scale * coverage; + break; + + case CAIRO_LINE_CAP_ROUND: + dashes[0] = MAX(scale * (coverage - ROUND_MINSQ_APPROXIMATION) / (1.0 - ROUND_MINSQ_APPROXIMATION), + scale * coverage - ROUND_MINSQ_APPROXIMATION * style->line_width); + break; + + case CAIRO_LINE_CAP_SQUARE: + /* + * Special attention is needed to handle the case cap_scale == 1 (since the first solution + * is either indeterminate or -inf in this case). Since dash lengths are always >=0, using + * 0 as first solution always leads to the correct solution. + */ + dashes[0] = MAX(0.0, scale * coverage - style->line_width); + break; + } + + dashes[1] = scale - dashes[0]; *dash_offset = on ? 0.0 : dashes[0]; } |