summaryrefslogtreecommitdiff
path: root/src/cairo-stroke-style.c
diff options
context:
space:
mode:
authorAndrea Canciani <ranma42@gmail.com>2010-01-15 10:44:58 +0100
committerAndrea Canciani <ranma42@gmail.com>2010-02-01 09:48:12 +0100
commit45c795a1820e0317b123e7782cefed6ade8996d7 (patch)
treeabd864e101259adeca94f518e4583565839639aa /src/cairo-stroke-style.c
parent8d7841048b079ce2a582ff17c90e82e0081e5f42 (diff)
downloadcairo-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.c56
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];
}