[cairo-commit] 6 commits - src/cairo.c src/cairo-pdf-surface.c src/cairo-svg-surface.c test/dash-scale.c test/dash-scale-ps-argb32-ref.png test/dash-scale-ref.png test/.gitignore test/line-width-scale.c test/line-width-scale-ps-argb32-ref.png test/line-width-scale-ref.png test/Makefile.am

Carl Worth cworth at kemper.freedesktop.org
Tue May 23 12:19:27 PDT 2006


 src/cairo-pdf-surface.c                 |  140 +++++++++++---------------------
 src/cairo-svg-surface.c                 |   63 +++++++++-----
 src/cairo.c                             |   35 +++++---
 test/.gitignore                         |    1 
 test/Makefile.am                        |    2 
 test/dash-scale-ps-argb32-ref.png       |binary
 test/dash-scale-ref.png                 |binary
 test/dash-scale.c                       |  125 ++++++++++++++++++++++++++++
 test/line-width-scale-ps-argb32-ref.png |binary
 test/line-width-scale-ref.png           |binary
 test/line-width-scale.c                 |   30 +++---
 11 files changed, 261 insertions(+), 135 deletions(-)

New commits:
diff-tree 59885c6a122f593b417cb47dbd676eeac0cd8f69 (from 68b41cfd06dd6c798f8045ba1580342669ef5539)
Author: Carl Worth <cworth at cworth.org>
Date:   Tue May 23 12:08:20 2006 -0700

    Clarify the documentation for cairo_set_dash
    
    Note that dash length units are evaluated in the user space
    at the time of the stroke operation, (not the user space at
    the time of cairo_set_dash).

diff --git a/src/cairo.c b/src/cairo.c
index cf87464..e9a0f33 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -897,9 +897,13 @@ cairo_set_line_join (cairo_t *cr, cairo_
  * 
  * 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 alternate "on" and "off" portions
- * of the stroke. The @offset specifies an offset into the pattern at
- * which the stroke begins.
+ * provides the length of alternate "on" and "off" portions of the
+ * stroke. The @offset specifies an offset into the pattern at which
+ * the stroke begins.
+ *
+ * Note: The length values are in user-space units as evaluated at the
+ * time of stroking. This is not necessarily the same as the user
+ * space at the time of cairo_set_dash().
  *
  * If @num_dashes is 0 dashing is disabled.
  *
diff-tree 68b41cfd06dd6c798f8045ba1580342669ef5539 (from 7e5bef2439be93e46583c0922f68ad770179fa1e)
Author: Carl Worth <cworth at cworth.org>
Date:   Tue May 23 11:23:27 2006 -0700

    PDF: Share path callbacks for fill and stroke.

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index a3bc73d..0c063c6 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1324,63 +1324,6 @@ emit_pattern (cairo_pdf_surface_t *surfa
     return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
 }
 
-static cairo_status_t
-_cairo_pdf_path_move_to (void *closure, cairo_point_t *point)
-{
-    cairo_output_stream_t *output = closure;
-
-    _cairo_output_stream_printf (output,
-				 "%f %f m ",
-				 _cairo_fixed_to_double (point->x),
-				 _cairo_fixed_to_double (point->y));
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_pdf_path_line_to (void *closure, cairo_point_t *point)
-{
-    cairo_output_stream_t *output = closure;
-
-    _cairo_output_stream_printf (output,
-				 "%f %f l ",
-				 _cairo_fixed_to_double (point->x),
-				 _cairo_fixed_to_double (point->y));
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_pdf_path_curve_to (void          *closure,
-			  cairo_point_t *b,
-			  cairo_point_t *c,
-			  cairo_point_t *d)
-{
-    cairo_output_stream_t *output = closure;
-
-    _cairo_output_stream_printf (output,
-				 "%f %f %f %f %f %f c ",
-				 _cairo_fixed_to_double (b->x),
-				 _cairo_fixed_to_double (b->y),
-				 _cairo_fixed_to_double (c->x),
-				 _cairo_fixed_to_double (c->y),
-				 _cairo_fixed_to_double (d->x),
-				 _cairo_fixed_to_double (d->y));
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_pdf_path_close_path (void *closure)
-{
-    cairo_output_stream_t *output = closure;
-
-    _cairo_output_stream_printf (output,
-				 "h\r\n");
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
 static cairo_int_status_t
 _cairo_pdf_surface_copy_page (void *abstract_surface)
 {
@@ -1429,13 +1372,14 @@ typedef struct _pdf_path_info {
 } pdf_path_info_t;
 
 static cairo_status_t
-_cairo_pdf_stroke_move_to (void *closure, cairo_point_t *point)
+_cairo_pdf_path_move_to (void *closure, cairo_point_t *point)
 {
     pdf_path_info_t *info = closure;
     double x = _cairo_fixed_to_double (point->x);
     double y = _cairo_fixed_to_double (point->y);
 
-    cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
+    if (info->ctm_inverse)
+	cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
 
     _cairo_output_stream_printf (info->output,
 				 "%f %f m ", x, y);
@@ -1444,13 +1388,14 @@ _cairo_pdf_stroke_move_to (void *closure
 }
 
 static cairo_status_t
-_cairo_pdf_stroke_line_to (void *closure, cairo_point_t *point)
+_cairo_pdf_path_line_to (void *closure, cairo_point_t *point)
 {
     pdf_path_info_t *info = closure;
     double x = _cairo_fixed_to_double (point->x);
     double y = _cairo_fixed_to_double (point->y);
 
-    cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
+    if (info->ctm_inverse)
+	cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
 
     _cairo_output_stream_printf (info->output,
 				 "%f %f l ", x, y);
@@ -1458,10 +1403,10 @@ _cairo_pdf_stroke_line_to (void *closure
 }
 
 static cairo_status_t
-_cairo_pdf_stroke_curve_to (void          *closure,
-			    cairo_point_t *b,
-			    cairo_point_t *c,
-			    cairo_point_t *d)
+_cairo_pdf_path_curve_to (void          *closure,
+			  cairo_point_t *b,
+			  cairo_point_t *c,
+			  cairo_point_t *d)
 {
     pdf_path_info_t *info = closure;
     double bx = _cairo_fixed_to_double (b->x);
@@ -1471,9 +1416,11 @@ _cairo_pdf_stroke_curve_to (void        
     double dx = _cairo_fixed_to_double (d->x);
     double dy = _cairo_fixed_to_double (d->y);
 
-    cairo_matrix_transform_point (info->ctm_inverse, &bx, &by);
-    cairo_matrix_transform_point (info->ctm_inverse, &cx, &cy);
-    cairo_matrix_transform_point (info->ctm_inverse, &dx, &dy);
+    if (info->ctm_inverse) {
+	cairo_matrix_transform_point (info->ctm_inverse, &bx, &by);
+	cairo_matrix_transform_point (info->ctm_inverse, &cx, &cy);
+	cairo_matrix_transform_point (info->ctm_inverse, &dx, &dy);
+    }
 
     _cairo_output_stream_printf (info->output,
 				 "%f %f %f %f %f %f c ",
@@ -1482,7 +1429,7 @@ _cairo_pdf_stroke_curve_to (void        
 }
 
 static cairo_status_t
-_cairo_pdf_stroke_close_path (void *closure)
+_cairo_pdf_path_close_path (void *closure)
 {
     pdf_path_info_t *info = closure;
 
@@ -1502,6 +1449,7 @@ _cairo_pdf_surface_intersect_clip_path (
     cairo_pdf_surface_t *surface = abstract_surface;
     cairo_status_t status;
     const char *pdf_operator;
+    pdf_path_info_t info;
 
     if (path == NULL) {
 	if (surface->has_clip)
@@ -1515,13 +1463,16 @@ _cairo_pdf_surface_intersect_clip_path (
 	surface->has_clip = TRUE;
     }
 
+    info.output = surface->output;
+    info.ctm_inverse = NULL;
+
     status = _cairo_path_fixed_interpret (path,
 					  CAIRO_DIRECTION_FORWARD,
 					  _cairo_pdf_path_move_to,
 					  _cairo_pdf_path_line_to,
 					  _cairo_pdf_path_curve_to,
 					  _cairo_pdf_path_close_path,
-					  surface->output);
+					  &info);
 
     switch (fill_rule) {
     case CAIRO_FILL_RULE_WINDING:
@@ -1672,6 +1623,7 @@ _cairo_pdf_surface_emit_glyph (cairo_pdf
 {
     cairo_scaled_glyph_t *scaled_glyph;
     cairo_status_t status;
+    pdf_path_info_t info;
 
     status = _cairo_scaled_glyph_lookup (scaled_font,
 					 scaled_font_glyph_index,
@@ -1705,13 +1657,16 @@ _cairo_pdf_surface_emit_glyph (cairo_pdf
 				 _cairo_fixed_to_double (scaled_glyph->bbox.p2.x),
 				 -_cairo_fixed_to_double (scaled_glyph->bbox.p1.y));
 
+    info.output = surface->output;
+    info.ctm_inverse = NULL;
+
     status = _cairo_path_fixed_interpret (scaled_glyph->path,
 					  CAIRO_DIRECTION_FORWARD,
 					  _cairo_pdf_path_move_to,
 					  _cairo_pdf_path_line_to,
 					  _cairo_pdf_path_curve_to,
 					  _cairo_pdf_path_close_path,
-					  surface->output);
+					  &info);
 
     _cairo_output_stream_printf (surface->output,
 				 " f");
@@ -2238,12 +2193,13 @@ _cairo_pdf_surface_stroke (void			*abstr
 
     info.output = surface->output;
     info.ctm_inverse = ctm_inverse;
+
     status = _cairo_path_fixed_interpret (path,
 					  CAIRO_DIRECTION_FORWARD,
-					  _cairo_pdf_stroke_move_to,
-					  _cairo_pdf_stroke_line_to,
-					  _cairo_pdf_stroke_curve_to,
-					  _cairo_pdf_stroke_close_path,
+					  _cairo_pdf_path_move_to,
+					  _cairo_pdf_path_line_to,
+					  _cairo_pdf_path_curve_to,
+					  _cairo_pdf_path_close_path,
 					  &info);
 
     _cairo_output_stream_printf (surface->output,
@@ -2273,6 +2229,7 @@ _cairo_pdf_surface_fill (void			*abstrac
     cairo_pdf_surface_t *surface = abstract_surface;
     const char *pdf_operator;
     cairo_status_t status;
+    pdf_path_info_t info;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
 	/* XXX: Does PDF provide a way we can preserve this hint? For now,
@@ -2289,13 +2246,16 @@ _cairo_pdf_surface_fill (void			*abstrac
     if (status)
 	return status;
 
+    info.output = surface->output;
+    info.ctm_inverse = NULL;
+
     status = _cairo_path_fixed_interpret (path,
 					  CAIRO_DIRECTION_FORWARD,
 					  _cairo_pdf_path_move_to,
 					  _cairo_pdf_path_line_to,
 					  _cairo_pdf_path_curve_to,
 					  _cairo_pdf_path_close_path,
-					  surface->output);
+					  &info);
 
     switch (fill_rule) {
     case CAIRO_FILL_RULE_WINDING:
diff-tree 7e5bef2439be93e46583c0922f68ad770179fa1e (from 1b1b59a4a9cdeab0f3c360c09721aff23154015f)
Author: Carl Worth <cworth at cworth.org>
Date:   Tue May 23 11:17:01 2006 -0700

    PDF: Rename pdf_stroke_t to pdf_path_into_t for future sharing with fill

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index ff7c342..a3bc73d 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1423,21 +1423,21 @@ _cairo_pdf_surface_get_extents (void		  
     return CAIRO_STATUS_SUCCESS;
 }
 
-typedef struct _pdf_stroke {
+typedef struct _pdf_path_info {
     cairo_output_stream_t   *output;
     cairo_matrix_t	    *ctm_inverse;
-} pdf_stroke_t;
+} pdf_path_info_t;
 
 static cairo_status_t
 _cairo_pdf_stroke_move_to (void *closure, cairo_point_t *point)
 {
-    pdf_stroke_t *stroke = closure;
+    pdf_path_info_t *info = closure;
     double x = _cairo_fixed_to_double (point->x);
     double y = _cairo_fixed_to_double (point->y);
 
-    cairo_matrix_transform_point (stroke->ctm_inverse, &x, &y);
+    cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
 
-    _cairo_output_stream_printf (stroke->output,
+    _cairo_output_stream_printf (info->output,
 				 "%f %f m ", x, y);
 
     return CAIRO_STATUS_SUCCESS;
@@ -1446,13 +1446,13 @@ _cairo_pdf_stroke_move_to (void *closure
 static cairo_status_t
 _cairo_pdf_stroke_line_to (void *closure, cairo_point_t *point)
 {
-    pdf_stroke_t *stroke = closure;
+    pdf_path_info_t *info = closure;
     double x = _cairo_fixed_to_double (point->x);
     double y = _cairo_fixed_to_double (point->y);
 
-    cairo_matrix_transform_point (stroke->ctm_inverse, &x, &y);
+    cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
 
-    _cairo_output_stream_printf (stroke->output,
+    _cairo_output_stream_printf (info->output,
 				 "%f %f l ", x, y);
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1463,7 +1463,7 @@ _cairo_pdf_stroke_curve_to (void        
 			    cairo_point_t *c,
 			    cairo_point_t *d)
 {
-    pdf_stroke_t *stroke = closure;
+    pdf_path_info_t *info = closure;
     double bx = _cairo_fixed_to_double (b->x);
     double by = _cairo_fixed_to_double (b->y);
     double cx = _cairo_fixed_to_double (c->x);
@@ -1471,11 +1471,11 @@ _cairo_pdf_stroke_curve_to (void        
     double dx = _cairo_fixed_to_double (d->x);
     double dy = _cairo_fixed_to_double (d->y);
 
-    cairo_matrix_transform_point (stroke->ctm_inverse, &bx, &by);
-    cairo_matrix_transform_point (stroke->ctm_inverse, &cx, &cy);
-    cairo_matrix_transform_point (stroke->ctm_inverse, &dx, &dy);
+    cairo_matrix_transform_point (info->ctm_inverse, &bx, &by);
+    cairo_matrix_transform_point (info->ctm_inverse, &cx, &cy);
+    cairo_matrix_transform_point (info->ctm_inverse, &dx, &dy);
 
-    _cairo_output_stream_printf (stroke->output,
+    _cairo_output_stream_printf (info->output,
 				 "%f %f %f %f %f %f c ",
 				 bx, by, cx, cy, dx, dy);
     return CAIRO_STATUS_SUCCESS;
@@ -1484,9 +1484,9 @@ _cairo_pdf_stroke_curve_to (void        
 static cairo_status_t
 _cairo_pdf_stroke_close_path (void *closure)
 {
-    pdf_stroke_t *stroke = closure;
+    pdf_path_info_t *info = closure;
 
-    _cairo_output_stream_printf (stroke->output,
+    _cairo_output_stream_printf (info->output,
 				 "h\r\n");
 
     return CAIRO_STATUS_SUCCESS;
@@ -2218,7 +2218,7 @@ _cairo_pdf_surface_stroke (void			*abstr
 			   cairo_antialias_t	 antialias)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
-    pdf_stroke_t stroke;
+    pdf_path_info_t info;
     cairo_status_t status;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
@@ -2236,15 +2236,15 @@ _cairo_pdf_surface_stroke (void			*abstr
     if (status)
 	return status;
 
-    stroke.output = surface->output;
-    stroke.ctm_inverse = ctm_inverse;
+    info.output = surface->output;
+    info.ctm_inverse = ctm_inverse;
     status = _cairo_path_fixed_interpret (path,
 					  CAIRO_DIRECTION_FORWARD,
 					  _cairo_pdf_stroke_move_to,
 					  _cairo_pdf_stroke_line_to,
 					  _cairo_pdf_stroke_curve_to,
 					  _cairo_pdf_stroke_close_path,
-					  &stroke);
+					  &info);
 
     _cairo_output_stream_printf (surface->output,
 				 "q %f %f %f %f %f %f cm\r\n",
diff-tree 1b1b59a4a9cdeab0f3c360c09721aff23154015f (from 0755a619a101b89f5c5439f12e0544ab5ecac997)
Author: Carl Worth <cworth at cworth.org>
Date:   Tue May 23 11:12:09 2006 -0700

    New test: dash-scale
    
    Tests interactions of cairo_set_dash and cairo_scale, (in particular with a
    non-uniformly scaled pen).

diff --git a/test/.gitignore b/test/.gitignore
index c0881dc..5588698 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -19,6 +19,7 @@ coverage
 create-from-png
 create-from-png-stream
 dash-caps-joins
+dash-scale
 dash-offset-negative
 dash-zero-length
 extend-reflect
diff --git a/test/Makefile.am b/test/Makefile.am
index b7b440a..fde3873 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -16,6 +16,7 @@ composite-integer-translate-over-repeat 
 create-from-png			\
 create-from-png-stream		\
 dash-caps-joins			\
+dash-scale			\
 dash-offset-negative		\
 dash-zero-length		\
 extend-reflect			\
@@ -151,6 +152,7 @@ create-from-png-ref.png					\
 create-from-png-stream-ref.png				\
 dash-caps-joins-ref.png					\
 dash-caps-joins-ps-argb32-ref.png			\
+dash-scale-ref.png					\
 dash-offset-negative-ref.png				\
 dash-offset-negative-ps-argb32-ref.png			\
 dash-zero-length-ref.png				\
diff --git a/test/dash-scale-ps-argb32-ref.png b/test/dash-scale-ps-argb32-ref.png
new file mode 100644
index 0000000..0320a8b
Binary files /dev/null and b/test/dash-scale-ps-argb32-ref.png differ
diff --git a/test/dash-scale-ref.png b/test/dash-scale-ref.png
new file mode 100644
index 0000000..cba93aa
Binary files /dev/null and b/test/dash-scale-ref.png differ
diff --git a/test/dash-scale.c b/test/dash-scale.c
new file mode 100644
index 0000000..3d8a2f7
--- /dev/null
+++ b/test/dash-scale.c
@@ -0,0 +1,125 @@
+/*
+ * 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: Carl D. Worth <cworth at cworth.org>
+ */
+
+#include "cairo-test.h"
+
+#define LINE_WIDTH 	8.
+#define SIZE 		(5 * LINE_WIDTH)
+#define PAD		(2 * LINE_WIDTH)
+
+cairo_test_t test = {
+    "dash-scale",
+    "Test interactions of cairo_set_dash and cairo_scale, (in particular with a non-uniformly scaled pen)",
+    3 * (PAD + SIZE) + PAD,
+    PAD + 5 * SIZE + 2 * (2 * PAD) + PAD
+};
+
+static void
+make_path (cairo_t *cr)
+{
+    cairo_move_to (cr, 0., 0.);
+    cairo_rel_line_to (cr, 0., SIZE);
+    cairo_rel_line_to (cr, SIZE, 0.);
+    cairo_close_path (cr);
+
+    cairo_move_to (cr, 2 * LINE_WIDTH, 0.);
+    cairo_rel_line_to (cr, 3 * LINE_WIDTH, 0.);
+    cairo_rel_line_to (cr, 0., 3 * LINE_WIDTH);
+}
+
+static void
+draw_three_shapes (cairo_t *cr)
+{
+    cairo_save (cr);
+
+    make_path (cr);
+    cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
+    cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL);
+    cairo_stroke (cr);
+
+    cairo_translate (cr, SIZE + PAD, 0.);
+
+    make_path (cr);
+    cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+    cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+    cairo_stroke (cr);
+
+    cairo_translate (cr, SIZE + PAD, 0.);
+
+    make_path (cr);
+    cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
+    cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
+    cairo_stroke (cr);
+
+    cairo_restore (cr);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    double dash[] = {1.5 * LINE_WIDTH};
+
+    /* We draw in the default black, so paint white first. */
+    cairo_save (cr);
+    cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+    cairo_paint (cr);
+    cairo_restore (cr);
+
+    cairo_translate (cr, PAD, PAD);
+
+    cairo_set_dash (cr, dash, sizeof(dash)/sizeof(dash[0]), - 2 * LINE_WIDTH);
+    cairo_set_line_width (cr, LINE_WIDTH);
+    draw_three_shapes (cr);
+
+    cairo_translate (cr, 0, SIZE + 2 * PAD);
+
+    cairo_save (cr);
+    {
+	cairo_set_dash (cr, dash, sizeof(dash)/sizeof(dash[0]), - 2 * LINE_WIDTH);
+	cairo_set_line_width (cr, LINE_WIDTH);
+	cairo_scale (cr, 1, 2);
+	draw_three_shapes (cr);
+    }
+    cairo_restore (cr);
+
+    cairo_translate (cr, 0, 2 * (SIZE + PAD));
+
+    cairo_save (cr);
+    {
+	cairo_scale (cr, 1, 2);
+	cairo_set_dash (cr, dash, sizeof(dash)/sizeof(dash[0]), - 2 * LINE_WIDTH);
+	cairo_set_line_width (cr, LINE_WIDTH);
+	draw_three_shapes (cr);
+    }
+    cairo_restore (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+    return cairo_test (&test, draw);
+}
diff-tree 0755a619a101b89f5c5439f12e0544ab5ecac997 (from b1231e2ef349af1c0b130880603a924ff67b2967)
Author: Carl Worth <cworth at cworth.org>
Date:   Tue May 23 10:54:54 2006 -0700

    SVG: Fix for line-width-scale
    
    Use the same approach as the PDF backend: emit the pen matrix as the
    SVG transform for the stroke, and compensate by first transforming all path
    coordinates by the ctm_inverse.

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 8a0fd97..94e0abc 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -463,6 +463,7 @@ typedef struct
 {
     cairo_svg_document_t *document;
     xmlBufferPtr path;
+    cairo_matrix_t *ctm_inverse;
 } svg_path_info_t;
 
 static cairo_status_t
@@ -471,12 +472,17 @@ _cairo_svg_path_move_to (void *closure, 
     svg_path_info_t *info = closure;
     xmlBufferPtr path = info->path;
     char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
+    double x = _cairo_fixed_to_double (point->x);
+    double y = _cairo_fixed_to_double (point->y);
+
+    if (info->ctm_inverse)
+	cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
 
     xmlBufferCat (path, CC2XML ("M "));
-    _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (point->x));
+    _cairo_dtostr (buffer, sizeof buffer, x);
     xmlBufferCat (path, CC2XML (buffer));
     xmlBufferCat (path, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (point->y));
+    _cairo_dtostr (buffer, sizeof buffer, y);
     xmlBufferCat (path, CC2XML (buffer));
     xmlBufferCat (path, CC2XML (" "));
 
@@ -489,13 +495,18 @@ _cairo_svg_path_line_to (void *closure, 
     svg_path_info_t *info = closure;
     xmlBufferPtr path = info->path;
     char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
+    double x = _cairo_fixed_to_double (point->x);
+    double y = _cairo_fixed_to_double (point->y);
+
+    if (info->ctm_inverse)
+	cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
 
     xmlBufferCat (path, CC2XML ("L "));
 
-    _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (point->x));
+    _cairo_dtostr (buffer, sizeof buffer, x);
     xmlBufferCat (path, CC2XML (buffer));
     xmlBufferCat (path, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (point->y));
+    _cairo_dtostr (buffer, sizeof buffer, y);
     xmlBufferCat (path, CC2XML (buffer));
     xmlBufferCat (path, CC2XML (" "));
 
@@ -511,24 +522,36 @@ _cairo_svg_path_curve_to (void          
     svg_path_info_t *info = closure;
     xmlBufferPtr path = info->path;
     char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
+    double bx = _cairo_fixed_to_double (b->x);
+    double by = _cairo_fixed_to_double (b->y);
+    double cx = _cairo_fixed_to_double (c->x);
+    double cy = _cairo_fixed_to_double (c->y);
+    double dx = _cairo_fixed_to_double (d->x);
+    double dy = _cairo_fixed_to_double (d->y);
+
+    if (info->ctm_inverse) {
+	cairo_matrix_transform_point (info->ctm_inverse, &bx, &by);
+	cairo_matrix_transform_point (info->ctm_inverse, &cx, &cy);
+	cairo_matrix_transform_point (info->ctm_inverse, &dx, &dy);
+    }
 
     xmlBufferCat (path, CC2XML ("C "));
-    _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (b->x));
+    _cairo_dtostr (buffer, sizeof buffer, bx);
     xmlBufferCat (path, CC2XML (buffer));
     xmlBufferCat (path, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (b->y));
+    _cairo_dtostr (buffer, sizeof buffer, by);
     xmlBufferCat (path, CC2XML (buffer));
     xmlBufferCat (path, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (c->x));
+    _cairo_dtostr (buffer, sizeof buffer, cx);
     xmlBufferCat (path, CC2XML (buffer));
     xmlBufferCat (path, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (c->y));
+    _cairo_dtostr (buffer, sizeof buffer, cy);
     xmlBufferCat (path, CC2XML (buffer));
     xmlBufferCat (path, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (d->x));
+    _cairo_dtostr (buffer, sizeof buffer, dx);
     xmlBufferCat (path, CC2XML (buffer));
     xmlBufferCat (path, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (d->y));
+    _cairo_dtostr (buffer, sizeof buffer, dy);
     xmlBufferCat (path, CC2XML (buffer));
     xmlBufferCat (path, CC2XML (" "));
 
@@ -579,6 +602,7 @@ _cairo_svg_document_emit_glyph (cairo_sv
     
     info.document = document;
     info.path = xmlBufferCreate ();
+    info.ctm_inverse = NULL;
 
     status = _cairo_path_fixed_interpret (scaled_glyph->path,
 					  CAIRO_DIRECTION_FORWARD,
@@ -1324,6 +1348,7 @@ _cairo_svg_surface_fill (void			*abstrac
 
     info.document = document;
     info.path = xmlBufferCreate ();
+    info.ctm_inverse = NULL;
     
     style = xmlBufferCreate ();
     emit_pattern (surface, source, style, 0);
@@ -1525,7 +1550,6 @@ _cairo_svg_surface_stroke (void			*abstr
     xmlBufferPtr style;
     xmlNodePtr child;
     svg_path_info_t info;
-    double rx, ry;
     unsigned int i;
     char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
     
@@ -1536,14 +1560,12 @@ _cairo_svg_surface_stroke (void			*abstr
 
     info.document = document;
     info.path = xmlBufferCreate ();
-
-    rx = ry = stroke_style->line_width;
-    cairo_matrix_transform_distance (ctm, &rx, &ry);
+    info.ctm_inverse = ctm_inverse;
 
     style = xmlBufferCreate ();
     emit_pattern (surface, source, style, 1);
     xmlBufferCat (style, CC2XML ("fill: none; stroke-width: "));
-    _cairo_dtostr (buffer, sizeof buffer, sqrt ((rx * rx + ry * ry) / 2.0));
+    _cairo_dtostr (buffer, sizeof buffer, stroke_style->line_width);
     xmlBufferCat (style, C2XML (buffer)); 
     xmlBufferCat (style, CC2XML (";"));
     
@@ -1576,18 +1598,13 @@ _cairo_svg_surface_stroke (void			*abstr
 	for (i = 0; i < stroke_style->num_dashes; i++) {
 	    if (i != 0)
 		xmlBufferCat (style, CC2XML (","));
-	    /* FIXME: Is is really what we want ? */
-	    rx = ry = stroke_style->dash[i];
-	    cairo_matrix_transform_distance (ctm, &rx, &ry);
-	    _cairo_dtostr (buffer, sizeof buffer, sqrt ((rx * rx + ry * ry) / 2.0));
+	    _cairo_dtostr (buffer, sizeof buffer, stroke_style->dash[i]);
 	    xmlBufferCat (style, C2XML (buffer));
 	}
 	xmlBufferCat (style, CC2XML (";"));
 	if (stroke_style->dash_offset != 0.0) {
 	    xmlBufferCat (style, CC2XML (" stroke-dashoffset: "));
-	    rx = ry = stroke_style->dash_offset;
-	    cairo_matrix_transform_distance (ctm, &rx, &ry);
-	    _cairo_dtostr (buffer, sizeof buffer, sqrt ((rx * rx + ry * ry) / 2.0));
+	    _cairo_dtostr (buffer, sizeof buffer, stroke_style->dash_offset);
 	    xmlBufferCat (style, C2XML (buffer));
 	    xmlBufferCat (style, CC2XML (";"));
 	}
@@ -1607,6 +1624,7 @@ _cairo_svg_surface_stroke (void			*abstr
 					  &info);
     
     child = xmlNewChild (surface->xml_node, NULL, CC2XML ("path"), NULL);
+    emit_transform (child, "transform", ctm);
     xmlSetProp (child, CC2XML ("d"), xmlBufferContent (info.path));
     xmlSetProp (child, CC2XML ("style"), xmlBufferContent (style));
     emit_operator (child, surface, op);
@@ -1718,6 +1736,7 @@ _cairo_svg_surface_intersect_clip_path (
     if (path != NULL) {
 	info.document = document;
 	info.path = xmlBufferCreate ();
+	info.ctm_inverse = NULL;
 
 	group = xmlNewChild (surface->xml_node, NULL, CC2XML ("g"), NULL);
 	clip = xmlNewChild (document->xml_node_defs, NULL, CC2XML ("clipPath"), NULL);
diff-tree b1231e2ef349af1c0b130880603a924ff67b2967 (from 0a1ec91977ef05f04e2cc52895fd98a903f1c8eb)
Author: Carl Worth <cworth at cworth.org>
Date:   Tue May 23 10:45:18 2006 -0700

    Codify 1.0 behavior of cairo_set_line_width as a feature, not a bug.
    
    Clarify the documentation of cairo_set_line_width to indicate that the
    value will be interpreted within the user space at the time of the
    stroke.
    
    Also adjust the comments in test/line-width-scale as well as the
    reference images for that test to match.

diff --git a/src/cairo.c b/src/cairo.c
index 8ec603a..cf87464 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -802,16 +802,28 @@ cairo_set_fill_rule (cairo_t *cr, cairo_
 /**
  * cairo_set_line_width:
  * @cr: a #cairo_t
- * @width: a line width, as a user-space value
+ * @width: a line width
  * 
  * Sets the current line width within the cairo context. The line
- * width specifies the diameter of a pen that is circular in
- * user space.
+ * width value specifies the diameter of a pen that is circular in
+ * user space, (though device-space pen may be an ellipse in general
+ * due to scaling/shear/rotation of the CTM).
+ *
+ * Note: When the description above refers to user space and CTM it
+ * refers to the user space and CTM in effect at the time of the
+ * stroking operation, not the user space and CTM in effect at the
+ * time of the call to cairo_set_line_width(). The simplest usage
+ * makes both of these spaces identical. That is, if there is no
+ * change to the CTM between a call to cairo_set_line_with() and the
+ * stroking operation, then one can just pass user-space values to
+ * cairo_set_line_width() and ignore this note.
  *
  * As with the other stroke parameters, the current line width is
  * examined by cairo_stroke(), cairo_stroke_extents(), and
  * cairo_stroke_to_path(), but does not have any effect during path
  * construction.
+ *
+ * The default line width value is 2.0.
  **/
 void
 cairo_set_line_width (cairo_t *cr, double width)
@@ -2591,9 +2603,10 @@ cairo_get_fill_rule (cairo_t *cr)
  * cairo_get_line_width:
  * @cr: a cairo context
  * 
- * Gets the current line width, as set by cairo_set_line_width().
- * 
- * Return value: the current line width, in user-space units.
+ * Return value: the current line width value exactly as set by
+ * cairo_set_line_width(). Note that the value is unchanged even if
+ * the CTM has changed between the calls to cairo_set_line_width() and
+ * cairo_get_line_width().
  **/
 double
 cairo_get_line_width (cairo_t *cr)
diff --git a/test/line-width-scale-ps-argb32-ref.png b/test/line-width-scale-ps-argb32-ref.png
index ab4d552..2f01fc7 100644
Binary files a/test/line-width-scale-ps-argb32-ref.png and b/test/line-width-scale-ps-argb32-ref.png differ
diff --git a/test/line-width-scale-ref.png b/test/line-width-scale-ref.png
index 9f19759..c40bce3 100644
Binary files a/test/line-width-scale-ref.png and b/test/line-width-scale-ref.png differ
diff --git a/test/line-width-scale.c b/test/line-width-scale.c
index ec79a64..c733262 100644
--- a/test/line-width-scale.c
+++ b/test/line-width-scale.c
@@ -26,7 +26,7 @@
 #include "cairo-test.h"
 
 /* This test exercises the various interactions between
- * cairo_set_line_width and cairo_scale. Specifically it show how
+ * cairo_set_line_width and cairo_scale. Specifically it shows how
  * separate transformations can affect the pen for stroking compared
  * to the path itself.
  *
@@ -35,11 +35,14 @@
  *
  *	http://antigrain.com/tips/line_alignment/conv_order.gif
  *
- * It also uncovered a bug in cairo that cairo_set_line_width was not
- * transforing the width according the the current CTM, but instead
- * delaying that transformation until the time of cairo_stroke. See:
- *
- *	http://article.gmane.org/gmane.comp.graphics.agg/2518
+ * It also uncovered some behavior in cairo that I found surprising.
+ * Namely, cairo_set_line_width was not transforming the width
+ * according the the current CTM, but instead delaying that
+ * transformation until the time of cairo_stroke.
+ *
+ * This delayed behavior was released in cairo 1.0 so we're going to
+ * document this as the way cairo_set_line_width works rather than
+ * considering this a bug.
  */
 
 #define LINE_WIDTH 13
@@ -106,12 +109,12 @@ scale_path_and_line_width (cairo_t *cr)
     cairo_restore (cr);
 }
 
-/* This one's the bug.
- *
- * If we set the line width before scaling, then the path should be
- * scaled but the line width should not.
+/* This is the case that was surprising.
  *
- * With the bug, the line_width is also being scaled here.
+ * Setting the line width before scaling doesn't change anything. The
+ * line width will be interpreted under the CTM in effect at the time
+ * of cairo_stroke, so the line width will be scaled as well as the
+ * path here.
  */
 static void
 set_line_width_then_scale_and_stroke (cairo_t *cr)
@@ -122,10 +125,9 @@ set_line_width_then_scale_and_stroke (ca
     cairo_stroke (cr);
 }
 
-/* This is used to verify what should be the results of
- * set_line_width_then_scale_and_stroke (once the bug is fixed).
+/* Here then is the way to achieve the alternate result.
  *
- * It uses save/restore pairs to isolate the scaling of the path and
+ * This uses save/restore pairs to isolate the scaling of the path and
  * line_width and ensures that the path is scaled while the line width
  * is not.
  */


More information about the cairo-commit mailing list