[cairo] cairo stroke problem with potential patch

Jeff Muizelaar jeff at infidigm.net
Tue Jun 20 10:51:21 PDT 2006


On Tue, Jun 20, 2006 at 07:47:28AM -0400, Keith Wells wrote:
> I have been working on some bugs in the Mozilla SVG arena.  The initial
> stroke-cap is missing from the very first dash-array element drawn in the
> following svg example.   I noticed there was a cairo bug already in the
> system, https://bugs.freedesktop.org/show_bug.cgi?id=4409,  that addressed
> this issue,  or close to it, but apparently still exists on, at least,  the
> Windows XP version of recent builds of firefox.  I don't think this has
> been resolved in the most recent version of cairo-path-stroke.c.
> 
> This is the svg example I have been playing with that shows this problem:
> <?xml version="1.0" ?>
>  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
> <rect  x="20" y="20" width="100" height="100" fill="blue" stroke="red"
> stroke-width="20" stroke-dasharray="0.001,20" stroke-linecap="round"/>
> </svg>
> 
> If you render this in firefox, you will notice that the very first leading
> cap is cutoff.
> 
> Here is a fix for it:
> 
> @@ -720,21 +738,20 @@ _cairo_stroker_line_to_dashed (void *clo
>             if (stroker->has_current_face) {
>                 status = _cairo_stroker_join (stroker,
> &stroker->current_face, &sub_start);
>                 if (status)
>                   return status;
>             } else {
>                 if (!stroker->has_first_face) {
>                   stroker->first_face = sub_start;
>                   stroker->has_first_face = 1;
> -               } else {
> +               }
>                   status = _cairo_stroker_add_leading_cap (stroker,
> &sub_start);
>                   if (status)
>                       return status;
> -               }
>             }
>           }
>           if (remain) {
>             /*
>              * Cap if not at end of segment
>              */
>             status = _cairo_stroker_add_trailing_cap (stroker, &sub_end);
>             if (status)
> 
> The problem  with the above svg example is that the first element in this
> dash-array NEVER invokes _cairo_stroker_add_leading_cap. 

This is not exactly true. The first element of the dash-array is usually
capped by _cairo_stroker_add_caps either by
_cairo_path_fixed_stroke_to_traps or _cairo_stroker_move_to. I haven't
actually looked at the However, it
looks like the problem you are seeing is caused by stroking a closed
dashed path. Basically, what happen is:
  - _cairo_stroker_line_to_dashed adds the first_face expecting it to be
    capped later on
  - when _cairo_stroker_close_path is called it draws that last line
    with _cairo_stroker_line_to_dashed.
  - _cairo_stroker_line_to_dashed returns with stroker->has_current_face
    unset.
  - the test for has_first_face and has_current_face fails correctly
  - close_path then incorrectly discards first_face, causing the bug.

Unconditionally adding the cap in the dashed_line_to is wrong because if
the _cairo_stroker_line_to_dashed returns with has_current_face set the
line needs to be joined and not capped.

This means the fix probably belongs in _cairo_stroker_close_path instead
of _cairo_stroker_line_to_dashed.

Thanks for the bug report and attempted fix, the stroking/dashing code
is a little hairy.

-Jeff


More information about the cairo mailing list