[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-----