[Bisected] Bugs in cairo's "contour" stroking

Carl Worth <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <[email protected]>
A cairo user recently reported to me that cairo is not robust when
stroking wide splines with tight curvature, (and showed me a rather
striking example).

Compare these two images (the first rendered with cairo 1.10, the second
rendered with cairo master) rendered with the attached demo program.

	http://cworth.org/~cworth/tmp/spline-cairo-1.10.png

	http://cworth.org/~cworth/tmp/spline-cairo-1.12.2-97-g185a351.png

I was quite surprised since the original spline stroking algorithm was
designed to be particularly robust in cases like this. Git bisect was
kind enough to identify the recent "contour" stroker as the source of
the bug. It points to this commit as the commit that introduces the bug:

  commit 545f30856aac98199a49cf66c72dbcb66c1f3a4f
  Author: Chris Wilson <[email protected]>
  Date:   Mon Aug 15 09:44:03 2011 +0100

    stroke: Convert the outlines into contour and then into a polygon
    
    In step 1 of speeding up stroking, we introduce contours as a means for
    tracking the connected edges around the stroke. By keeping track of
    these chains, we can analyse the edges as we proceed and eliminate
    redundant vertices speeding up rasterisation.
    
    Coincidentally fixes line-width-tolerance (looks like a combination of
    using spline tangent vectors and tolerance).
    
    Signed-off-by: Chris Wilson <[email protected]>

I would really like to see this bug fixed. I have not yet had a chance
to dive into the new code. But the new code should be able to maintain
the same approach as the old algorithm, (namely, the final contour
should be constructed from translated pieces of the pen or translated
pieces of the path).

The attached code should provide a reasonable test case to be added to
the test suite. I've also (long ago) written an interactive program
which makes it easy to explore "difficult" splines like the one seen
here. That program is available here:

    git clone git://git.cworth.org/git/cairo-spline

Chris, I'll look forward to your thoughts.

-Carl

-- 
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
cairo-spline-image.c (text/x-csrc, 2.5 KB)
/* cc `pkg-config --cflags --libs cairo` cairo-spline-image.c -o cairo-spline-image */

/* Copyright © 2005 Carl Worth
 * Copyright © 2012 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>

#include <cairo.h>

typedef struct pt {
    double x;
    double y;
} pt_t;

typedef struct spline {
    pt_t pt[4];
} spline_t;

static const double DEFAULT_LINE_WIDTH = 160;

/* A spline showing bugs in the "contour-based stroking" in cairo
 * 1.12 */
static const spline_t spline = {
  { { 172.25, 156.185 }, { 177.225, 164.06 }, { 176.5, 157.5 }, { 175.5, 159.5 } }
};

int
main(int argc, char *argv[])
{
    cairo_surface_t *surface;
    cairo_t *cr;
    cairo_status_t status;

    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 300, 300);
    cr = cairo_create(surface);

    cairo_set_source_rgb(cr, 0, 0, 0);

    cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);

    cairo_move_to(cr, spline.pt[0].x, spline.pt[0].y);
    cairo_curve_to(cr,
	      spline.pt[1].x, spline.pt[1].y,
	      spline.pt[2].x, spline.pt[2].y,
	      spline.pt[3].x, spline.pt[3].y);

    cairo_set_line_width (cr, DEFAULT_LINE_WIDTH);
    cairo_stroke (cr);

    status = cairo_status(cr);
    if (status) {
	fprintf(stderr, "Cairo is unhappy: %s\n",
		cairo_status_to_string(status));
    }

    cairo_surface_write_to_png (surface, "spline.png");

    cairo_destroy(cr);
    cairo_surface_destroy (surface);

    return 0;
}
signature.asc (application/pgp-signature, 197 B)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)

iEYEARECAAYFAk/mAfAACgkQ6JDdNq8qSWjszQCbBnFY2o5KM1E68O/sSJRVRW8L
wb8An30geA2mihAACg8EQA2hyAkzCgZ4
=rnbv
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.