Index: ChangeLog =================================================================== RCS file: /mirrors/freedesktop/cairo/cairo/ChangeLog,v retrieving revision 1.914 diff -u -p -r1.914 ChangeLog --- ChangeLog 19 Aug 2005 14:39:47 -0000 1.914 +++ ChangeLog 19 Aug 2005 17:49:39 -0000 @@ -1,5 +1,25 @@ 2005-08-19 Carl Worth + Fix for bug #2729: + + * src/cairo-gstate.c: (_cairo_gstate_set_dash): Adjust negative + offsets up to their equivalent positive value. Add error checking + for dash values, (must each be non-negative and must not be all + zero). + + * src/cairo.c (cairo_set_dash): Add documentation. + + * src/cairo.h: + * src/cairo.c: (cairo_status_to_string): Add new + CAIRO_STATUS_INVALID_DASH. + + * test/.cvsignore: + * test/Makefile.am: Add dash-offfset-negative test from Owen. + + * doc/public/tmpl/cairo.sgml: churn + +2005-08-19 Carl Worth + Fix for bug #3915: * src/cairo-pattern.c: (_cairo_pattern_nil_for_status): Add new Index: doc/public/tmpl/cairo.sgml =================================================================== RCS file: /mirrors/freedesktop/cairo/cairo/doc/public/tmpl/cairo.sgml,v retrieving revision 1.29 diff -u -p -r1.29 cairo.sgml --- doc/public/tmpl/cairo.sgml 9 Aug 2005 01:35:22 -0000 1.29 +++ doc/public/tmpl/cairo.sgml 19 Aug 2005 17:48:07 -0000 @@ -279,8 +279,10 @@ Drawing contexts. @cr: @dashes: -@ndash: +@num_dashes: @offset: + +@ndash: @@ -1027,6 +1029,7 @@ Drawing contexts. @CAIRO_STATUS_INVALID_FORMAT: @CAIRO_STATUS_INVALID_VISUAL: @CAIRO_STATUS_FILE_NOT_FOUND: +@CAIRO_STATUS_INVALID_DASH: Index: src/cairo-gstate.c =================================================================== RCS file: /mirrors/freedesktop/cairo/cairo/src/cairo-gstate.c,v retrieving revision 1.165 diff -u -p -r1.165 cairo-gstate.c --- src/cairo-gstate.c 18 Aug 2005 22:50:36 -0000 1.165 +++ src/cairo-gstate.c 19 Aug 2005 17:31:08 -0000 @@ -430,21 +430,48 @@ _cairo_gstate_get_line_join (cairo_gstat cairo_status_t _cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset) { - if (gstate->dash) { + int i; + double dash_total; + + if (gstate->dash) free (gstate->dash); - gstate->dash = NULL; - } gstate->num_dashes = num_dashes; - if (gstate->num_dashes) { - gstate->dash = malloc (gstate->num_dashes * sizeof (double)); - if (gstate->dash == NULL) { - gstate->num_dashes = 0; - return CAIRO_STATUS_NO_MEMORY; - } + + if (gstate->num_dashes == 0) { + gstate->dash = NULL; + gstate->dash_offset = 0.0; + return CAIRO_STATUS_SUCCESS; + } + + gstate->dash = malloc (gstate->num_dashes * sizeof (double)); + if (gstate->dash == NULL) { + gstate->num_dashes = 0; + return CAIRO_STATUS_NO_MEMORY; } memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double)); + + dash_total = 0.0; + for (i = 0; i < gstate->num_dashes; i++) { + if (gstate->dash[i] < 0) + return CAIRO_STATUS_INVALID_DASH; + dash_total += gstate->dash[i]; + } + + if (dash_total == 0.0) + return CAIRO_STATUS_INVALID_DASH; + + /* A single dash value indicate symmetric repeating, so the total + * is twice as long. */ + if (gstate->num_dashes == 1) + dash_total *= 2; + + /* The dashing code doesn't like a negative offset, so we compute + * the equivalent positive offset. */ + if (offset < 0) + offset += ceil (-offset / dash_total + 0.5) * dash_total; + gstate->dash_offset = offset; return CAIRO_STATUS_SUCCESS; Index: src/cairo.c =================================================================== RCS file: /mirrors/freedesktop/cairo/cairo/src/cairo.c,v retrieving revision 1.126 diff -u -p -r1.126 cairo.c --- src/cairo.c 19 Aug 2005 06:10:41 -0000 1.126 +++ src/cairo.c 19 Aug 2005 17:48:05 -0000 @@ -62,7 +62,7 @@ static const cairo_t cairo_nil = { * a bit of a pain, but it should be easy to always catch as long as * one adds a new test case to test a trigger of the new status value. */ -#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_FILE_NOT_FOUND +#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_INVALID_DASH /** * _cairo_error: @@ -715,15 +715,42 @@ cairo_set_line_join (cairo_t *cr, cairo_ _cairo_set_error (cr, cr->status); } +/** + * cairo_set_dash: + * @cr: a cairo context + * @dashes: an array specifying alternate lengths of on and off po + * @num_dashes: the length of the dashes array + * @offset: an offset into the dash pattern at which the stroke should start + * + * Sets the dash pattern to be used by cairo_stroke(). A dash pattern + * is specified by @dashes, an array of positive values. Each value + * provides the user-space length of altenate "on" and "off" portions + * of the stroke. The @offset specifies an offset into the pattern at + * which the stroke begins. + * + * If @num_dashes is 0 dashing is disabled. + * + * If @num_dashes is 1 a symmetric pattern is assumed with alternating + * on and off portions of the size specified by the single value in + * @dashes. + * + * If any value in @dashes is negative, or if all values are 0, then + * @cairo_t will be put into an error state with a status of + * #CAIRO_STATUS_INVALID_DASH. + **/ void -cairo_set_dash (cairo_t *cr, double *dashes, int ndash, double offset) +cairo_set_dash (cairo_t *cr, + double *dashes, + int num_dashes, + double offset) { if (cr->status) { _cairo_set_error (cr, cr->status); return; } - cr->status = _cairo_gstate_set_dash (cr->gstate, dashes, ndash, offset); + cr->status = _cairo_gstate_set_dash (cr->gstate, + dashes, num_dashes, offset); if (cr->status) _cairo_set_error (cr, cr->status); } @@ -2483,6 +2510,8 @@ cairo_status_to_string (cairo_status_t s return "invalid value for an input Visual*"; case CAIRO_STATUS_FILE_NOT_FOUND: return "file not found"; + case CAIRO_STATUS_INVALID_DASH: + return "invalid value for a dash setting"; } return ""; Index: src/cairo.h =================================================================== RCS file: /mirrors/freedesktop/cairo/cairo/src/cairo.h,v retrieving revision 1.147 diff -u -p -r1.147 cairo.h --- src/cairo.h 10 Aug 2005 22:58:25 -0000 1.147 +++ src/cairo.h 19 Aug 2005 17:37:45 -0000 @@ -166,6 +166,7 @@ typedef struct _cairo_user_data_key { * @CAIRO_STATUS_INVALID_FORMAT: invalid value for an input cairo_format_t * @CAIRO_STATUS_INVALID_VISUAL: invalid value for an input Visual* * @CAIRO_STATUS_FILE_NOT_FOUND: file not found + * @CAIRO_STATUS_INVALID_DASH: invalid value for a dash setting * * #cairo_status_t is used to indicate errors that can occur when * using Cairo. In some cases it is returned directly by functions. @@ -191,7 +192,8 @@ typedef enum _cairo_status { CAIRO_STATUS_INVALID_CONTENT, CAIRO_STATUS_INVALID_FORMAT, CAIRO_STATUS_INVALID_VISUAL, - CAIRO_STATUS_FILE_NOT_FOUND + CAIRO_STATUS_FILE_NOT_FOUND, + CAIRO_STATUS_INVALID_DASH } cairo_status_t; /** @@ -386,7 +388,10 @@ void cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join); void -cairo_set_dash (cairo_t *cr, double *dashes, int ndash, double offset); +cairo_set_dash (cairo_t *cr, + double *dashes, + int num_dashes, + double offset); void cairo_set_miter_limit (cairo_t *cr, double limit); Index: test/.cvsignore =================================================================== RCS file: /mirrors/freedesktop/cairo/cairo/test/.cvsignore,v retrieving revision 1.46 diff -u -p -r1.46 .cvsignore --- test/.cvsignore 19 Aug 2005 06:10:42 -0000 1.46 +++ test/.cvsignore 19 Aug 2005 14:55:00 -0000 @@ -12,6 +12,7 @@ composite-integer-translate-over-repeat coverage create-from-png create-from-png-stream +dash-offset-negative fill-and-stroke fill-rule filter-nearest-offset Index: test/Makefile.am =================================================================== RCS file: /mirrors/freedesktop/cairo/cairo/test/Makefile.am,v retrieving revision 1.82 diff -u -p -r1.82 Makefile.am --- test/Makefile.am 19 Aug 2005 06:10:42 -0000 1.82 +++ test/Makefile.am 19 Aug 2005 14:54:43 -0000 @@ -9,6 +9,7 @@ composite-integer-translate-over \ composite-integer-translate-over-repeat \ create-from-png \ create-from-png-stream \ +dash-offset-negative \ fill-and-stroke \ fill-rule \ filter-nearest-offset \ @@ -80,6 +81,7 @@ composite-integer-translate-over-ref.png composite-integer-translate-over-repeat-ref.png \ create-from-png-ref.png \ create-from-png-stream-ref.png \ +dash-offset-negative-ref.png \ fill-and-stroke-ref.png \ fill-rule-ref.png \ filter-nearest-offset-ref.png \ @@ -91,6 +93,7 @@ mask-ref.png \ mask-ctm-ref.png \ mask-surface-ctm-ref.png \ move-to-show-surface-ref.png \ +nil-surface-ref.png \ operator-clear-ref.png \ operator-source-ref.png \ paint-ref.png \ @@ -182,6 +185,7 @@ composite_integer_translate_over_LDADD = composite_integer_translate_over_repeat_LDADD = $(LDADDS) create_from_png_LDADD = $(LDADDS) create_from_png_stream_LDADD = $(LDADDS) +dash_offset_negative_LDADD = $(LDADDS) fill_and_stroke_LDADD = $(LDADDS) fill_rule_LDADD = $(LDADDS) filter_nearest_offset_LDADD = $(LDADDS) Index: test/dash-offset-negative-ref.png =================================================================== RCS file: test/dash-offset-negative-ref.png diff -N test/dash-offset-negative-ref.png Binary files /dev/null and dash-offset-negative-ref.png differ Index: test/dash-offset-negative.c =================================================================== RCS file: test/dash-offset-negative.c diff -N test/dash-offset-negative.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ test/dash-offset-negative.c 19 Aug 2005 17:32:46 -0000 @@ -0,0 +1,99 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor + */ + +#include "cairo-test.h" + +#define IMAGE_WIDTH 19 +#define IMAGE_HEIGHT 19 + +/* Basic test of dashed strokes, including a test for the negative + * dash offset bug: + * + * https://bugs.freedesktop.org/show_bug.cgi?id=2729 + */ + +cairo_test_t test = { + "dash-offset-negative", + "Tests cairo_set_dash with a negative offset", + IMAGE_WIDTH, IMAGE_HEIGHT +}; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double dashes[] = { 1 }; + + cairo_set_line_width (cr, 2); + + /* Basic 1-1 dash pattern */ + cairo_set_dash (cr, dashes, 1, 0.); + + cairo_move_to (cr, 1, 2); + cairo_line_to (cr, 18, 2); + cairo_stroke (cr); + + /* Adjust path by 0.5. Ideally this would give a constant 50% + * gray, (but does not due to the location of the regular sample + * grid points. */ + cairo_move_to (cr, 1.5, 5); + cairo_line_to (cr, 18., 5); + cairo_stroke (cr); + + /* Offset dash by 0.5, rather than the path */ + cairo_set_dash (cr, dashes, 1, 0.5); + + cairo_move_to (cr, 1, 8); + cairo_line_to (cr, 18, 8); + cairo_stroke (cr); + + /* Now, similar tests with negative dash offsets. */ + + /* Basic 1-1 dash pattern dashing */ + cairo_set_dash (cr, dashes, 1, -4); + + cairo_move_to (cr, 1, 11); + cairo_line_to (cr, 18, 11); + cairo_stroke (cr); + + /* Adjust path by 0.5 */ + cairo_move_to (cr, 1.5, 14); + cairo_line_to (cr, 18., 14); + cairo_stroke (cr); + + /* Offset dash by 0.5 */ + cairo_set_dash (cr, dashes, 1, -3.5); + + cairo_move_to (cr, 1, 17); + cairo_line_to (cr, 18, 17); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +int +main (void) +{ + return cairo_test (&test, draw); +}