[cairo-commit] 4 commits - src/cairo-ps-surface.c test/clip-operator-ps-argb32-ref.png test/operator-clear-ps-argb32-ref.png

Adrian Johnson ajohnson at kemper.freedesktop.org
Sun Feb 3 01:13:50 PST 2008


 src/cairo-ps-surface.c                |  291 ++++++++++++++++++++++++++--------
 test/clip-operator-ps-argb32-ref.png  |binary
 test/operator-clear-ps-argb32-ref.png |binary
 3 files changed, 229 insertions(+), 62 deletions(-)

New commits:
commit a74e6692341daeff9ab266b3b29fcc8b8e917d88
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Feb 3 19:34:53 2008 +1030

    PS: Implement reflected surface patterns
    
    The image/meta-pattern is written once. A PS pattern twice the size of
    the cairo pattern is created and the surface drawn four times in a
    reflect pattern inside the PS pattern.
    
    This fixes the extend-reflect and extend-reflect-similar PS test
    failures.

diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 631e941..3dcca19 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -2337,12 +2337,15 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t  *surface,
     surface->height = meta_extents.height;
     _cairo_output_stream_printf (surface->stream,
 				 "/CairoPattern {\n"
-				 "gsave\n");
+				 "  gsave\n"
+				 "  0 0 %f %f rectclip\n",
+				 surface->width,
+				 surface->height);
 
     if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
 	surface->content = CAIRO_CONTENT_COLOR;
 	_cairo_output_stream_printf (surface->stream,
-				     "0 G 0 0 %f %f rectfill\n",
+				     "  0 G 0 0 %f %f rectfill\n",
 				     surface->width,
 				     surface->height);
     }
@@ -2354,7 +2357,7 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t  *surface,
 	return status;
 
     _cairo_output_stream_printf (surface->stream,
-				 "grestore\n"
+				 "  grestore\n"
 				 "} bind def\n");
     surface->content = old_content;
     surface->width = old_width;
@@ -2479,10 +2482,13 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t      *surface,
 	break;
     }
     case CAIRO_EXTEND_REPEAT:
-    case CAIRO_EXTEND_REFLECT:
 	xstep = pattern_width;
 	ystep = pattern_height;
 	break;
+    case CAIRO_EXTEND_REFLECT:
+	xstep = pattern_width*2;
+	ystep = pattern_height*2;
+	break;
 	/* All the rest (if any) should have been analyzed away, so these
 	 * cases should be unreachable. */
     default:
@@ -2496,14 +2502,33 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t      *surface,
 				 "   /PaintType 1\n"
 				 "   /TilingType 1\n");
     _cairo_output_stream_printf (surface->stream,
-				 "   /BBox [0 0 %d %d]\n",
-				 pattern_width, pattern_height);
-    _cairo_output_stream_printf (surface->stream,
 				 "   /XStep %f /YStep %f\n",
 				 xstep, ystep);
+
+    if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
+	_cairo_output_stream_printf (surface->stream,
+				     "   /BBox [0 0 %d %d]\n"
+				     "   /PaintProc {\n"
+				     "      CairoPattern\n"
+				     "      [-1 0 0  1 %d 0] concat CairoPattern\n"
+				     "      [ 1 0 0 -1 0 %d] concat CairoPattern\n"
+				     "      [-1 0 0  1 %d 0] concat CairoPattern\n"
+				     "      CairoPattern\n"
+				     "   } bind\n",
+				     pattern_width*2, pattern_height*2,
+				     pattern_width*2,
+				     pattern_height*2,
+				     pattern_width*2);
+    } else {
+	_cairo_output_stream_printf (surface->stream,
+				     "   /BBox [0 0 %d %d]\n"
+				     "   /PaintProc { CairoPattern } bind\n",
+				     pattern_width, pattern_height);
+    }
+
     _cairo_output_stream_printf (surface->stream,
-				 "   /PaintProc { CairoPattern } bind\n"
 				 ">>\n");
+
     _cairo_output_stream_printf (surface->stream,
 				 "[ %f %f %f %f %f %f ]\n",
 				 inverse.xx, inverse.yx,
commit 7c5bc5fde819014f62ebb9bac86d4529f056956d
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Feb 3 18:58:02 2008 +1030

    Add operator-clear ps ref image

diff --git a/test/operator-clear-ps-argb32-ref.png b/test/operator-clear-ps-argb32-ref.png
new file mode 100644
index 0000000..7840e9b
Binary files /dev/null and b/test/operator-clear-ps-argb32-ref.png differ
commit 06b2d009ba50a2908fd9c93ff3e467f511b233cf
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Feb 3 18:50:14 2008 +1030

    Update clip-operator ps ref image

diff --git a/test/clip-operator-ps-argb32-ref.png b/test/clip-operator-ps-argb32-ref.png
index 1d49920..c72ee87 100644
Binary files a/test/clip-operator-ps-argb32-ref.png and b/test/clip-operator-ps-argb32-ref.png differ
commit 13663d1d500a6c2254097011e66199d6dd81c62d
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Feb 3 17:10:56 2008 +1030

    PS: Implement linear gradient repeat and reflect

diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 65df5a2..631e941 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1736,17 +1736,17 @@ _gradient_pattern_supported (cairo_ps_surface_t    *surface,
     surface->ps_level_used = CAIRO_PS_LEVEL_3;
     extend = cairo_pattern_get_extend (pattern);
 
-    if (extend == CAIRO_EXTEND_REPEAT ||
-        extend == CAIRO_EXTEND_REFLECT) {
-        return FALSE;
-    }
-
     /* Radial gradients are currently only supported when one circle
      * is inside the other. */
     if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
         double x1, y1, x2, y2, r1, r2, d;
         cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
 
+	if (extend == CAIRO_EXTEND_REPEAT ||
+	    extend == CAIRO_EXTEND_REFLECT) {
+	    return FALSE;
+	}
+
         x1 = _cairo_fixed_to_double (radial->c1.x);
         y1 = _cairo_fixed_to_double (radial->c1.y);
         r1 = _cairo_fixed_to_double (radial->r1);
@@ -2517,7 +2517,7 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t      *surface,
 
 typedef struct _cairo_ps_color_stop {
     double offset;
-    double color[3];
+    double color[4];
 } cairo_ps_color_stop_t;
 
 static void
@@ -2526,12 +2526,12 @@ _cairo_ps_surface_emit_linear_colorgradient (cairo_ps_surface_t     *surface,
 					     cairo_ps_color_stop_t  *stop2)
 {
     _cairo_output_stream_printf (surface->stream,
-				 "<< /FunctionType 2\n"
-				 "   /Domain [ 0 1 ]\n"
-				 "   /C0 [ %f %f %f ]\n"
-				 "   /C1 [ %f %f %f ]\n"
-				 "   /N 1\n"
-				 ">>\n",
+				 "   << /FunctionType 2\n"
+				 "      /Domain [ 0 1 ]\n"
+				 "      /C0 [ %f %f %f ]\n"
+				 "      /C1 [ %f %f %f ]\n"
+				 "      /N 1\n"
+				 "   >>\n",
 				 stop1->color[0],
 				 stop1->color[1],
 				 stop1->color[2],
@@ -2548,25 +2548,35 @@ _cairo_ps_surface_emit_stitched_colorgradient (cairo_ps_surface_t    *surface,
     unsigned int i;
 
     _cairo_output_stream_printf (surface->stream,
-				 "      << /FunctionType 3\n"
-				 "         /Domain [ 0 1 ]\n"
-				 "         /Functions [\n");
+				 "<< /FunctionType 3\n"
+				 "   /Domain [ 0 1 ]\n"
+				 "   /Functions [\n");
     for (i = 0; i < n_stops - 1; i++)
 	_cairo_ps_surface_emit_linear_colorgradient (surface, &stops[i], &stops[i+1]);
 
-    _cairo_output_stream_printf (surface->stream, "         ]\n");
+    _cairo_output_stream_printf (surface->stream, "   ]\n");
 
-    _cairo_output_stream_printf (surface->stream, "         /Bounds [ ");
+    _cairo_output_stream_printf (surface->stream, "   /Bounds [ ");
     for (i = 1; i < n_stops-1; i++)
 	_cairo_output_stream_printf (surface->stream, "%f ", stops[i].offset);
     _cairo_output_stream_printf (surface->stream, "]\n");
 
-    _cairo_output_stream_printf (surface->stream, "         /Encode [ ");
-    for (i = 1; i < n_stops; i++)
-	_cairo_output_stream_printf (surface->stream, "0 1 ");
-    _cairo_output_stream_printf (surface->stream,  "]\n");
+    _cairo_output_stream_printf (surface->stream, "   /Encode [ 1 1 %d { pop 0 1 } for ]\n",
+				 n_stops - 1);
+
+    _cairo_output_stream_printf (surface->stream, ">>\n");
+}
+
+static void
+calc_gradient_color (cairo_ps_color_stop_t *new_stop,
+		     cairo_ps_color_stop_t *stop1,
+		     cairo_ps_color_stop_t *stop2)
+{
+    int i;
+    double offset = stop1->offset / (stop1->offset + 1.0 - stop2->offset);
 
-    _cairo_output_stream_printf (surface->stream, "      >>\n");
+    for (i = 0; i < 4; i++)
+	new_stop->color[i] = stop1->color[i] + offset*(stop2->color[i] - stop1->color[i]);
 }
 
 #define COLOR_STOP_EPSILON 1e-6
@@ -2586,33 +2596,58 @@ _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t       *surface,
     n_stops = pattern->n_stops;
 
     for (i = 0; i < n_stops; i++) {
-	double red, green, blue;
+	cairo_gradient_stop_t *stop = &pattern->stops[i];
 
-	_cairo_ps_surface_flatten_transparency (surface,
-						&pattern->stops[i].color,
-						&red, &green, &blue);
-	stops[i].color[0] = red;
-	stops[i].color[1] = green;
-	stops[i].color[2] = blue;
+	stops[i].color[0] = stop->color.red;
+	stops[i].color[1] = stop->color.green;
+	stops[i].color[2] = stop->color.blue;
+	stops[i].color[3] = stop->color.alpha;
 	stops[i].offset = _cairo_fixed_to_double (pattern->stops[i].x);
     }
 
-    /* make sure first offset is 0.0 and last offset is 1.0 */
-    if (stops[0].offset > COLOR_STOP_EPSILON) {
-	memcpy (allstops, stops, sizeof (cairo_ps_color_stop_t));
-	stops = allstops;
-	n_stops++;
+    if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
+	pattern->base.extend == CAIRO_EXTEND_REFLECT) {
+	if (stops[0].offset > COLOR_STOP_EPSILON) {
+	    if (pattern->base.extend == CAIRO_EXTEND_REFLECT)
+		memcpy (allstops, stops, sizeof (cairo_ps_color_stop_t));
+	    else
+		calc_gradient_color (&allstops[0], &stops[0], &stops[n_stops-1]);
+	    stops = allstops;
+	    n_stops++;
+	}
+	stops[0].offset = 0.0;
+
+	if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
+	    if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
+		memcpy (&stops[n_stops],
+			&stops[n_stops - 1],
+			sizeof (cairo_ps_color_stop_t));
+	    } else {
+		calc_gradient_color (&stops[n_stops], &stops[0], &stops[n_stops-1]);
+	    }
+	    n_stops++;
+	}
+	stops[n_stops-1].offset = 1.0;
     }
-    stops[0].offset = 0.0;
 
-    if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
-	memcpy (&stops[n_stops],
-		&stops[n_stops - 1],
-		sizeof (cairo_ps_color_stop_t));
-	n_stops++;
+    for (i = 0; i < n_stops; i++) {
+	double red, green, blue;
+	cairo_color_t color;
+
+	_cairo_color_init_rgba (&color,
+				stops[i].color[0],
+				stops[i].color[1],
+				stops[i].color[2],
+				stops[i].color[3]);
+	_cairo_ps_surface_flatten_transparency (surface, &color,
+						&red, &green, &blue);
+	stops[i].color[0] = red;
+	stops[i].color[1] = green;
+	stops[i].color[2] = blue;
     }
-    stops[n_stops-1].offset = 1.0;
 
+    _cairo_output_stream_printf (surface->stream,
+				 "/CairoFunction\n");
     if (n_stops == 2) {
 	/* no need for stitched function */
 	_cairo_ps_surface_emit_linear_colorgradient (surface, &stops[0], &stops[1]);
@@ -2621,6 +2656,8 @@ _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t       *surface,
 	 * stops do not require stitching. XXX */
 	_cairo_ps_surface_emit_stitched_colorgradient (surface, n_stops,stops);
     }
+    _cairo_output_stream_printf (surface->stream,
+				 "def\n");
 
     free (allstops);
 
@@ -2628,40 +2665,145 @@ _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t       *surface,
 }
 
 static cairo_status_t
+_cairo_ps_surface_emit_repeating_function (cairo_ps_surface_t       *surface,
+					   cairo_gradient_pattern_t *pattern,
+					   int                       begin,
+					   int                       end)
+{
+    _cairo_output_stream_printf (surface->stream,
+				 "/CairoFunction\n"
+				 "<< /FunctionType 3\n"
+				 "   /Domain [ %d %d ]\n"
+				 "   /Functions [ %d {CairoFunction} repeat ]\n"
+				 "   /Bounds [ %d 1 %d {} for ]\n",
+				 begin,
+                                 end,
+				 end - begin,
+				 begin + 1,
+				 end - 1);
+
+    if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
+	_cairo_output_stream_printf (surface->stream, "   /Encode [ %d 1 %d { 2 mod 0 eq {0 1} {1 0} ifelse } for ]\n",
+				     begin,
+				     end - 1);
+    } else {
+	_cairo_output_stream_printf (surface->stream, "   /Encode [ %d 1 %d { pop 0 1 } for ]\n",
+				     begin,
+				     end - 1);
+    }
+
+    _cairo_output_stream_printf (surface->stream, ">> def\n");
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
 _cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t     *surface,
 				       cairo_linear_pattern_t *pattern)
 {
     double x1, y1, x2, y2;
+    double _x1, _y1, _x2, _y2;
+    cairo_matrix_t pat_to_ps;
     cairo_extend_t extend;
     cairo_status_t status;
-    cairo_matrix_t inverse = pattern->base.base.matrix;
+    cairo_gradient_pattern_t *gradient = &pattern->base;
+    double first_stop, last_stop;
+    int repeat_begin = 0, repeat_end = 1;
 
     if (pattern->base.n_stops == 0)
         return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
     extend = cairo_pattern_get_extend (&pattern->base.base);
 
-    status = cairo_matrix_invert (&inverse);
-    if (status)
-	return status;
+    pat_to_ps = pattern->base.base.matrix;
+    status = cairo_matrix_invert (&pat_to_ps);
+    /* cairo_pattern_set_matrix ensures the matrix is invertible */
+    assert (status == CAIRO_STATUS_SUCCESS);
+
+    first_stop = _cairo_fixed_to_double (gradient->stops[0].x);
+    last_stop = _cairo_fixed_to_double (gradient->stops[gradient->n_stops - 1].x);
 
+    if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
+	pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
+	double dx, dy;
+	int x_rep = 0, y_rep = 0;
+
+	x1 = _cairo_fixed_to_double (pattern->p1.x);
+	y1 = _cairo_fixed_to_double (pattern->p1.y);
+	cairo_matrix_transform_point (&pat_to_ps, &x1, &y1);
+
+	x2 = _cairo_fixed_to_double (pattern->p2.x);
+	y2 = _cairo_fixed_to_double (pattern->p2.y);
+	cairo_matrix_transform_point (&pat_to_ps, &x2, &y2);
+
+	dx = fabs (x2 - x1);
+	dy = fabs (y2 - y1);
+	if (dx > 1e-6)
+	    x_rep = (int) ceil (surface->width/dx);
+	if (dy > 1e-6)
+	    y_rep = (int) ceil (surface->height/dy);
+
+	repeat_end = MAX (x_rep, y_rep);
+	repeat_begin = -repeat_end;
+	first_stop = repeat_begin;
+	last_stop = repeat_end;
+    }
+
+    /* PS requires the first and last stop to be the same as the line
+     * coordinates. For repeating patterns this moves the line
+     * coordinates out to the begin/end of the repeating function. For
+     * non repeating patterns this may move the line coordinates in if
+     * there are not stops at offset 0 and 1. */
     x1 = _cairo_fixed_to_double (pattern->p1.x);
     y1 = _cairo_fixed_to_double (pattern->p1.y);
     x2 = _cairo_fixed_to_double (pattern->p2.x);
     y2 = _cairo_fixed_to_double (pattern->p2.y);
 
+    _x1 = x1 + (x2 - x1)*first_stop;
+    _y1 = y1 + (y2 - y1)*first_stop;
+    _x2 = x1 + (x2 - x1)*last_stop;
+    _y2 = y1 + (y2 - y1)*last_stop;
+
+    x1 = _x1;
+    x2 = _x2;
+    y1 = _y1;
+    y2 = _y2;
+
+    /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a
+     * Type 2 function is used by itself without a stitching
+     * function. Type 2 functions always have the domain [0 1] */
+    if ((pattern->base.base.extend == CAIRO_EXTEND_NONE ||
+	 pattern->base.base.extend == CAIRO_EXTEND_PAD) &&
+	gradient->n_stops == 2) {
+	first_stop = 0.0;
+	last_stop = 1.0;
+    }
+
+    status = _cairo_ps_surface_emit_pattern_stops (surface,
+						   &pattern->base);
+    if (status)
+	return status;
+
+    if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
+	pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
+	status = _cairo_ps_surface_emit_repeating_function (surface,
+							    &pattern->base,
+							    repeat_begin,
+							    repeat_end);
+	if (status)
+	    return status;
+    }
+
     _cairo_output_stream_printf (surface->stream,
 				 "<< /PatternType 2\n"
 				 "   /Shading\n"
 				 "   << /ShadingType 2\n"
 				 "      /ColorSpace /DeviceRGB\n"
 				 "      /Coords [ %f %f %f %f ]\n"
-				 "      /Function\n",
-				 x1, y1, x2, y2);
-
-    status = _cairo_ps_surface_emit_pattern_stops (surface, &pattern->base);
-    if (status)
-	return status;
+                                 "      /Domain [ %f %f ]\r\n"
+				 "      /Function CairoFunction\n",
+				 x1, y1, x2, y2,
+				 first_stop, last_stop);
 
     if (extend == CAIRO_EXTEND_PAD) {
 	_cairo_output_stream_printf (surface->stream,
@@ -2676,9 +2818,9 @@ _cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t     *surface,
 				 ">>\n");
     _cairo_output_stream_printf (surface->stream,
 				 "[ %f %f %f %f %f %f ]\n",
-				 inverse.xx, inverse.yx,
-				 inverse.xy, inverse.yy,
-				 inverse.x0, inverse.y0);
+                                 pat_to_ps.xx, pat_to_ps.yx,
+                                 pat_to_ps.xy, pat_to_ps.yy,
+                                 pat_to_ps.x0, pat_to_ps.y0);
     _cairo_output_stream_printf (surface->stream,
 				 "makepattern setpattern\n");
 


More information about the cairo-commit mailing list