From 8aa306caac99ebe074a6cde8b424b1780cafefee Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Thu, 29 Jun 2006 05:13:37 +0200 Subject: [PATCH] PS: Fix for dash-zero-length --- src/cairo-ps-surface.c | 79 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index d72c3c011..b45e6f918 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -1805,15 +1805,82 @@ _cairo_ps_surface_stroke (void *abstract_surface, cairo_ps_surface_t *surface = abstract_surface; cairo_output_stream_t *stream = surface->stream; cairo_int_status_t status; + double *dash = style->dash; + int num_dashes = style->num_dashes; + double dash_offset = style->dash_offset; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _analyze_operation (surface, op, source); assert (operation_supported (surface, op, source)); + _cairo_output_stream_printf (stream, "%% _cairo_ps_surface_stroke\n"); + /* PostScript has "special needs" when it comes to zero-length + * dash segments with butt caps. It apparently (at least + * according to ghostscript) draws hairlines for this + * case. That's not what the cairo semantics want, so we first + * touch up the array to eliminate any 0.0 values that will + * result in "on" segments. + */ + if (num_dashes && style->line_cap == CAIRO_LINE_CAP_BUTT) { + int i; + + /* If there's an odd number of dash values they will each get + * interpreted as both on and off. So we first explicitly + * expand the array to remove the duplicate usage so that we + * can modify some of the values. + */ + if (num_dashes % 2) { + dash = malloc (2 * num_dashes * sizeof (double)); + if (dash == NULL) + return CAIRO_STATUS_NO_MEMORY; + + memcpy (dash, style->dash, num_dashes * sizeof (double)); + memcpy (dash + num_dashes, style->dash, num_dashes * sizeof (double)); + + num_dashes *= 2; + } + + for (i = 0; i < num_dashes; i += 2) { + if (dash[i] == 0.0) { + /* If we're at the front of the list, we first rotate + * two elements from the end of the list to the front + * of the list before folding away the 0.0. Or, if + * there are only two dash elements, then there is + * nothing at all to draw. + */ + if (i == 0) { + double last_two[2]; + + if (num_dashes == 2) { + if (dash != style->dash) + free (dash); + return CAIRO_STATUS_SUCCESS; + } + /* The cases of num_dashes == 0, 1, or 3 elements + * cannot exist, so the rotation of 2 elements + * will always be safe */ + memcpy (last_two, dash + num_dashes - 2, sizeof (last_two)); + memmove (dash + 2, dash, (num_dashes - 2) * sizeof (double)); + memcpy (dash, last_two, sizeof (last_two)); + dash_offset += dash[0] + dash[1]; + i = 2; + } + dash[i-1] += dash[i+1]; + num_dashes -= 2; + memmove (dash + i, dash + i + 2, (num_dashes - i) * sizeof (double)); + /* If we might have just rotated, it's possible that + * we rotated a 0.0 value to the front of the list. + * Set i to -2 so it will get incremented to 0. */ + if (i == 2) + i = -2; + } + } + } + emit_pattern (surface, source); _cairo_output_stream_printf (stream, @@ -1836,14 +1903,18 @@ _cairo_ps_surface_stroke (void *abstract_surface, _cairo_output_stream_printf (stream, "%d setlinejoin\n", _cairo_ps_line_join (style->line_join)); /* dashes */ - if (style->num_dashes) { + if (num_dashes) { int d; + _cairo_output_stream_printf (stream, "["); - for (d = 0; d < style->num_dashes; d++) - _cairo_output_stream_printf (stream, " %f", style->dash[d]); + for (d = 0; d < num_dashes; d++) + _cairo_output_stream_printf (stream, " %f", dash[d]); _cairo_output_stream_printf (stream, "] %f setdash\n", - style->dash_offset); + dash_offset); } + if (dash != style->dash) + free (dash); + /* miter limit */ _cairo_output_stream_printf (stream, "%f setmiterlimit\n", style->miter_limit);