[cairo-commit] 11 commits - boilerplate/cairo-boilerplate.c boilerplate/cairo-boilerplate-win32-printing.c boilerplate/cairo-boilerplate-win32-private.h boilerplate/Makefile.am doc/public src/cairo-win32-printing-surface.c src/cairo-win32-private.h

Adrian Johnson ajohnson at kemper.freedesktop.org
Sun Oct 21 07:22:25 PDT 2007


 boilerplate/Makefile.am                        |    2 
 boilerplate/cairo-boilerplate-win32-printing.c |  308 ++++++++++++++
 boilerplate/cairo-boilerplate-win32-private.h  |   15 
 boilerplate/cairo-boilerplate.c                |   11 
 doc/public/cairo-sections.txt                  |    1 
 src/cairo-win32-printing-surface.c             |  532 ++++++++++++++++++++-----
 src/cairo-win32-private.h                      |    3 
 7 files changed, 772 insertions(+), 100 deletions(-)

New commits:
commit fb2bf3e250b39078476d3df4bdbb81201ef00a96
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 21 23:50:57 2007 +0930

    win32-printing: remove unused code

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 21557d4..2dee9eb 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -701,11 +701,6 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surfa
 
     if (!SetWorldTransform (surface->dc, &xform))
 	return _cairo_win32_print_gdi_error ("_win32_printing_surface_paint_linear_pattern:SetWorldTransform2");
-    GetWorldTransform(surface->dc, &xform);
-    p1x = 0.0;
-    p1y = 0.0;
-    p2x = d;
-    p2y = 0;
 
     GetClipBox (surface->dc, &clip);
 
@@ -839,9 +834,6 @@ _cairo_win32_printing_surface_paint_pattern (cairo_win32_surface_t *surface,
 
 typedef struct _win32_print_path_info {
     cairo_win32_surface_t *surface;
-    cairo_line_cap_t       line_cap;
-    cairo_point_t          last_move_to_point;
-    cairo_bool_t           has_sub_path;
 } win32_path_info_t;
 
 static cairo_status_t
@@ -849,9 +841,6 @@ _cairo_win32_printing_surface_path_move_to (void *closure, cairo_point_t *point)
 {
     win32_path_info_t *path_info = closure;
 
-    path_info->last_move_to_point = *point;
-    path_info->has_sub_path = FALSE;
-
     if (path_info->surface->has_ctm) {
 	double x, y;
 
@@ -1293,7 +1282,6 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
     int i;
     cairo_matrix_t old_ctm;
     cairo_bool_t old_has_ctm;
-    XFORM xform;
     cairo_solid_pattern_t clear;
 
     if (op == CAIRO_OPERATOR_CLEAR) {
@@ -1356,11 +1344,6 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
     }
 
     SaveDC (surface->dc);
-
-    xform.eM11 = 1.0f;
-    xform.eM21 = 0.0f;
-    xform.eM12 = 0.0f;
-    xform.eM22 = 1.0f;
     old_ctm = surface->ctm;
     old_has_ctm = surface->has_ctm;
     surface->has_ctm = TRUE;
commit b854d1e1b57680f244939b90b03911a5300f34d6
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 21 23:50:28 2007 +0930

    win32-printing: fix typo in comment

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index ecbc962..21557d4 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -1442,7 +1442,7 @@ _cairo_win32_printing_surface_set_paginated_mode (void *abstract_surface,
  * possible to draw to the surface.
  *
  * The returned surface will be wrapped using the paginated surface to
- * provide correct complex renderinf behaviour; show_page() and
+ * provide correct complex rendering behaviour; show_page() and
  * associated methods must be used for correct output.
  *
  * Return value: the newly created surface
commit 2d68c46b779909b5cc493a62db1228ea504ff52a
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 21 23:49:58 2007 +0930

    win32-printing: fix dash-caps-joins test failure

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index fa07218..ecbc962 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -1137,19 +1137,21 @@ _cairo_win32_printing_surface_stroke (void                 *abstract_surface,
     }
 
     assert (_cairo_win32_printing_surface_operation_supported (surface, op, source));
+    assert (!(style->num_dashes > 0 && style->dash_offset != 0.0));
 
     cairo_matrix_multiply (&mat, stroke_ctm, &surface->ctm);
     _cairo_matrix_factor_out_scale (&mat, &scale);
 
+    pen_style = PS_GEOMETRIC;
     dash_array = NULL;
     if (style->num_dashes) {
-	pen_style = PS_USERSTYLE;
+	pen_style |= PS_USERSTYLE;
 	dash_array = calloc (sizeof (DWORD), style->num_dashes);
 	for (i = 0; i < style->num_dashes; i++) {
 	    dash_array[i] = (DWORD) (scale * style->dash[i]);
 	}
     } else {
-	pen_style = PS_SOLID;
+	pen_style |= PS_SOLID;
     }
 
     SetMiterLimit (surface->dc, (FLOAT) (scale * style->miter_limit), NULL);
@@ -1166,9 +1168,8 @@ _cairo_win32_printing_surface_stroke (void                 *abstract_surface,
     brush.lbStyle = BS_SOLID;
     brush.lbColor = color;
     brush.lbHatch = 0;
-    pen_style = PS_GEOMETRIC |
-	        _cairo_win32_line_cap (style->line_cap) |
-	        _cairo_win32_line_join (style->line_join);
+    pen_style |= _cairo_win32_line_cap (style->line_cap);
+    pen_style |= _cairo_win32_line_join (style->line_join);
     pen = ExtCreatePen(pen_style,
 		       scale * style->line_width,
 		       &brush,
commit 5fa62250456745907dd97fdb9030481bdc91a8dd
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 21 23:49:33 2007 +0930

    win32-printing: Add test boilerplate
    
    Testing win32-printing requires setting the default printer to
    a PostScript level 3 color printer. The PostScript output is
    saved to a file and converted to png using ghostscript.

diff --git a/boilerplate/Makefile.am b/boilerplate/Makefile.am
index ddac552..7dd9c4d 100644
--- a/boilerplate/Makefile.am
+++ b/boilerplate/Makefile.am
@@ -67,7 +67,9 @@ endif
 
 if CAIRO_HAS_WIN32_SURFACE
 libcairoboilerplate_la_SOURCES += cairo-boilerplate-win32.c
+libcairoboilerplate_la_SOURCES += cairo-boilerplate-win32-printing.c
 libcairoboilerplate_la_SOURCES += cairo-boilerplate-win32-private.h
+libcairoboilerplate_la_LIBADD += -lwinspool
 endif
 
 if CAIRO_HAS_XCB_SURFACE
diff --git a/boilerplate/cairo-boilerplate-win32-printing.c b/boilerplate/cairo-boilerplate-win32-printing.c
new file mode 100644
index 0000000..8de176c
--- /dev/null
+++ b/boilerplate/cairo-boilerplate-win32-printing.c
@@ -0,0 +1,308 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/*
+ * Copyright © 2004,2006 Red Hat, Inc.
+ * Copyright © 2007, Adrian Johnson
+ *
+ * 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.
+ *
+ * Authors: Carl D. Worth <cworth at cworth.org>
+ *          Adrian Johnson <ajohnson at redneon.com>
+ */
+
+/* We require Windows 2000 features such as GetDefaultPrinter() */
+#if !defined(WINVER) || (WINVER < 0x0500)
+# define WINVER 0x0500
+#endif
+#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
+# define _WIN32_WINNT 0x0500
+#endif
+
+#include "cairo-boilerplate.h"
+#include "cairo-boilerplate-win32-private.h"
+
+#include <cairo-win32.h>
+#include <cairo-win32-private.h>
+#include <cairo-paginated-surface-private.h>
+
+#include <windows.h>
+
+#if !defined(POSTSCRIPT_IDENTIFY)
+# define POSTSCRIPT_IDENTIFY 0x1015
+#endif
+
+#if !defined(PSIDENT_GDICENTRIC)
+# define PSIDENT_GDICENTRIC 0x0000
+#endif
+
+#if !defined(GET_PS_FEATURESETTING)
+# define GET_PS_FEATURESETTING 0x1019
+#endif
+
+#if !defined(FEATURESETTING_PSLEVEL)
+# define FEATURESETTING_PSLEVEL 0x0002
+#endif
+
+cairo_user_data_key_t win32_closure_key;
+
+typedef struct _win32_target_closure
+{
+    char *filename;
+    int width;
+    int height;
+    cairo_surface_t *target;
+    HDC dc;
+    int left_margin;
+    int bottom_margin;
+} win32_target_closure_t;
+
+static cairo_bool_t
+printer_is_postscript_level_3 (HDC dc)
+{
+    DWORD word;
+    INT ps_feature, ps_level;
+
+    word = PSIDENT_GDICENTRIC;
+    if (ExtEscape (dc, POSTSCRIPT_IDENTIFY, sizeof(DWORD), (char *)&word, 0, (char *)NULL) <= 0)
+	return FALSE;
+
+    ps_feature = FEATURESETTING_PSLEVEL;
+    if (ExtEscape (dc, GET_PS_FEATURESETTING, sizeof(INT),
+		   (char *)&ps_feature, sizeof(INT), (char *)&ps_level) <= 0)
+	return FALSE;
+
+    if (ps_level >= 3)
+	return TRUE;
+
+    return FALSE;
+}
+
+static void
+create_printer_dc (win32_target_closure_t *ptc)
+{
+    char *printer_name;
+    DWORD size;
+    int x_dpi, y_dpi, left_margin, top_margin, page_height, printable_height;
+    XFORM xform;
+
+    ptc->dc = NULL;
+    GetDefaultPrinter (NULL, &size);
+    printer_name = malloc (size);
+
+    if (printer_name == NULL)
+	return;
+
+    if (GetDefaultPrinter (printer_name, &size) == 0) {
+	free (printer_name);
+	return;
+    }
+
+    /* printf("\nPrinting to : %s\n", printer_name); */
+    ptc->dc = CreateDC (NULL, printer_name, NULL, NULL);
+    free (printer_name);
+
+    if (!printer_is_postscript_level_3 (ptc->dc)) {
+	printf("The default printer driver must be a color PostScript level 3 printer\n");
+	ptc->dc = NULL;
+	return;
+    }
+
+    /* The printer device units on win32 are 1 unit == 1 dot and the
+     * origin is the start of the printable area. We transform the
+     * cordinate space to 1 unit is 1 point as expected by the
+     * tests. As the page size is larger than the test surface sizes,
+     * the origin down so that the each test is drawn at the bottom
+     * left corner of the page. This is because the bottom left corner
+     * of the PNG image that ghostscript creates is positioned at
+     * origin of the PS coordinates (ie the bottom left of the page).
+     * The left and bottom margins are stored in win32_target_closure
+     * as size of the PNG image needs to be increased as the test
+     * output is offset from the bottom left by the non printable
+     * margins. After the PNG is created the margins will be chopped
+     * off so the image matches the reference image.
+     */
+    printable_height = GetDeviceCaps (ptc->dc, VERTRES);
+    x_dpi = GetDeviceCaps (ptc->dc, LOGPIXELSX);
+    y_dpi = GetDeviceCaps (ptc->dc, LOGPIXELSY);
+    left_margin = GetDeviceCaps (ptc->dc, PHYSICALOFFSETX);
+    top_margin = GetDeviceCaps (ptc->dc, PHYSICALOFFSETY);
+    page_height = GetDeviceCaps (ptc->dc, PHYSICALHEIGHT);
+
+    SetGraphicsMode (ptc->dc, GM_ADVANCED);
+    xform.eM11 = x_dpi/72.0;
+    xform.eM12 = 0;
+    xform.eM21 = 0;
+    xform.eM22 = y_dpi/72.0;
+    xform.eDx = 0;
+    xform.eDy = printable_height - ptc->height*y_dpi/72.0;
+    if (!SetWorldTransform (ptc->dc, &xform)) {
+	_cairo_win32_print_gdi_error ("cairo-boilerplate-win32-printing:SetWorldTransform");
+	return;
+    }
+
+    ptc->left_margin = 72.0*left_margin/x_dpi;
+    ptc->bottom_margin = 72.0*(page_height - printable_height - top_margin)/y_dpi;
+}
+
+cairo_surface_t *
+_cairo_boilerplate_win32_printing_create_surface (const char              *name,
+						  cairo_content_t          content,
+						  int                      width,
+						  int                      height,
+						  cairo_boilerplate_mode_t mode,
+						  void                   **closure)
+{
+    win32_target_closure_t *ptc;
+    cairo_surface_t *surface;
+    DOCINFO di;
+
+    if (content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
+	content = CAIRO_CONTENT_COLOR_ALPHA;
+
+    *closure = ptc = xmalloc (sizeof (win32_target_closure_t));
+
+    xasprintf (&ptc->filename, "%s-win32-printing-%s-out.ps",
+	       name, cairo_boilerplate_content_name (content));
+    memset (&di, 0, sizeof (DOCINFO));
+    di.cbSize = sizeof (DOCINFO);
+    di.lpszDocName = ptc->filename;
+    di.lpszOutput = ptc->filename;
+
+    ptc->width = width;
+    ptc->height = height;
+
+    create_printer_dc (ptc);
+    if (ptc->dc == NULL) {
+	printf("\nFailed to create printer\n");
+	free (ptc->filename);
+	free (ptc);
+	return NULL;
+    }
+    StartDoc (ptc->dc, &di);
+    StartPage (ptc->dc);
+    surface = cairo_win32_printing_surface_create (ptc->dc);
+    if (cairo_surface_status (surface)) {
+	free (ptc->filename);
+	free (ptc);
+	return NULL;
+    }
+    cairo_surface_set_fallback_resolution (surface, 72., 72.);
+
+    if (content == CAIRO_CONTENT_COLOR) {
+	ptc->target = surface;
+	surface = cairo_surface_create_similar (ptc->target,
+						CAIRO_CONTENT_COLOR,
+						width, height);
+    } else {
+	ptc->target = NULL;
+    }
+
+    if (cairo_surface_set_user_data (surface,
+				     &win32_closure_key,
+				     ptc,
+				     NULL) != CAIRO_STATUS_SUCCESS) {
+	cairo_surface_destroy (surface);
+	if (ptc->target != NULL)
+	    cairo_surface_destroy (ptc->target);
+	free (ptc->filename);
+	free (ptc);
+	return NULL;
+    }
+
+    return surface;
+}
+
+cairo_status_t
+_cairo_boilerplate_win32_printing_surface_write_to_png (cairo_surface_t *surface, const char *filename)
+{
+    win32_target_closure_t *ptc = cairo_surface_get_user_data (surface, &win32_closure_key);
+    char command[4096];
+    cairo_surface_t *src_image, *dst_image;
+    cairo_t *cr;
+    cairo_status_t status;
+
+    /* Both surface and ptc->target were originally created at the
+     * same dimensions. We want a 1:1 copy here, so we first clear any
+     * device offset on surface.
+     *
+     * In a more realistic use case of device offsets, the target of
+     * this copying would be of a different size than the source, and
+     * the offset would be desirable during the copy operation. */
+    cairo_surface_set_device_offset (surface, 0, 0);
+
+    if (ptc->target) {
+	cairo_t *cr;
+	cr = cairo_create (ptc->target);
+	cairo_set_source_surface (cr, surface, 0, 0);
+	cairo_paint (cr);
+	cairo_show_page (cr);
+	cairo_destroy (cr);
+
+	cairo_surface_finish (surface);
+	surface = ptc->target;
+    }
+
+    cairo_surface_finish (surface);
+    EndPage (ptc->dc);
+    EndDoc (ptc->dc);
+    sprintf (command, "gs -q -r72 -g%dx%d -dSAFER -dBATCH -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=%s %s",
+	     ptc->width + ptc->left_margin, ptc->height + ptc->bottom_margin, filename, ptc->filename);
+
+    if (system (command) != 0)
+	return CAIRO_STATUS_WRITE_ERROR;
+
+    /* Create a new image from the ghostscript image that has the
+     * left and bottom margins removed */
+
+    src_image = cairo_image_surface_create_from_png (filename);
+    status = cairo_surface_status (src_image);
+    if (status)
+	return status;
+
+    dst_image = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+					    ptc->width,
+					    ptc->height);
+    cr = cairo_create (dst_image);
+    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+    cairo_set_source_surface (cr, src_image, -ptc->left_margin, 0);
+    cairo_paint (cr);
+    cairo_destroy (cr);
+
+    cairo_surface_write_to_png (dst_image, filename);
+    status = cairo_surface_status (dst_image);
+    if (status)
+	return status;
+
+    cairo_surface_destroy (src_image);
+    cairo_surface_destroy (dst_image);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_boilerplate_win32_printing_cleanup (void *closure)
+{
+    win32_target_closure_t *ptc = closure;
+
+    if (ptc->target)
+	cairo_surface_destroy (ptc->target);
+    free (ptc->filename);
+    free (ptc);
+    DeleteDC (ptc->dc);
+}
diff --git a/boilerplate/cairo-boilerplate-win32-private.h b/boilerplate/cairo-boilerplate-win32-private.h
index 7a6b0c1..e5ef0f6 100644
--- a/boilerplate/cairo-boilerplate-win32-private.h
+++ b/boilerplate/cairo-boilerplate-win32-private.h
@@ -35,4 +35,19 @@ _cairo_boilerplate_win32_create_surface (const char			 *name,
 					 cairo_boilerplate_mode_t	  mode,
 					 void				**closure);
 
+cairo_surface_t *
+_cairo_boilerplate_win32_printing_create_surface (const char 		  *name,
+						  cairo_content_t 	   content,
+						  int 			   width,
+						  int 			   height,
+						  cairo_boilerplate_mode_t mode,
+						  void 			 **closure);
+
+void
+_cairo_boilerplate_win32_printing_cleanup (void *closure);
+
+cairo_status_t
+_cairo_boilerplate_win32_printing_surface_write_to_png (cairo_surface_t *surface,
+							const char      *filename);
+
 #endif
diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index d8a08da..aaf3433 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -222,6 +222,17 @@ static cairo_boilerplate_target_t targets[] =
     { "win32", CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR_ALPHA, 0,
       _cairo_boilerplate_win32_create_surface,
       cairo_surface_write_to_png },
+    { "win32-printing", CAIRO_SURFACE_TYPE_WIN32_PRINTING,
+      CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
+      _cairo_boilerplate_win32_printing_create_surface,
+      _cairo_boilerplate_win32_printing_surface_write_to_png,
+      _cairo_boilerplate_win32_printing_cleanup,
+      NULL, TRUE },
+    { "win32-printing", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
+      _cairo_boilerplate_win32_printing_create_surface,
+      _cairo_boilerplate_win32_printing_surface_write_to_png,
+      _cairo_boilerplate_win32_printing_cleanup,
+      NULL, TRUE },
 #endif
 #if CAIRO_HAS_XCB_SURFACE
     /* Acceleration architectures may make the results differ by a
commit e63b5e5201a79a8af4bd1d5acb524f067b5f2794
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 21 23:47:35 2007 +0930

    win32-printing: Use the surface ctm in show_glyphs
    
    show_glyphs needs to scale the font by the current CTM.

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index a855268..fa07218 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -1334,9 +1334,23 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
     if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32 &&
 	source->type == CAIRO_PATTERN_TYPE_SOLID)
     {
+	cairo_matrix_t ctm;
+
+	if (surface->has_ctm) {
+	    for (i = 0; i < num_glyphs; i++)
+		cairo_matrix_transform_point (&surface->ctm, &glyphs[i].x, &glyphs[i].y);
+	    cairo_matrix_multiply (&ctm, &scaled_font->ctm, &surface->ctm);
+	    scaled_font = cairo_scaled_font_create (scaled_font->font_face,
+						    &scaled_font->font_matrix,
+						    &ctm,
+						    &scaled_font->options);
+	}
 	status = _cairo_win32_surface_show_glyphs (surface, op,
 						   source, glyphs,
 						   num_glyphs, scaled_font);
+	if (surface->has_ctm)
+	    cairo_scaled_font_destroy (scaled_font);
+
 	return status;
     }
 
commit ac9831ea55bd62f0ed427230ad80348768415852
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 21 23:46:52 2007 +0930

    win32-printing: fix stroke rounding problems
    
    The win32 CTM is changed to user space to set the stroke parameters.
    As win32 uses integers for stroke parameters this will cause rounding
    problems depending on the CTM used.
    
    This is fixed by factoring out a scale from the user space CTM so that
    xx, xy, yx, and yy in the CTM are all < 1. This preserves the shape
    of the transformation while ensuring that the CTM does not cause
    rounding problems. The stroke parameters are multiplied by the scale
    value.

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 6be74f2..a855268 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -1080,14 +1080,31 @@ _cairo_win32_line_join (cairo_line_join_t join)
     }
 }
 
+static void
+_cairo_matrix_factor_out_scale (cairo_matrix_t *m, double *scale)
+{
+    double s;
+
+    s = fabs (m->xx);
+    if (fabs (m->xy) > s)
+	s = fabs (m->xy);
+    if (fabs (m->yx) > s)
+	s = fabs (m->yx);
+    if (fabs (m->yy) > s)
+	s = fabs (m->yy);
+    *scale = s;
+    s = 1.0/s;
+    cairo_matrix_scale (m, s, s);
+}
+
 static cairo_int_status_t
 _cairo_win32_printing_surface_stroke (void                 *abstract_surface,
                                       cairo_operator_t	    op,
                                       cairo_pattern_t	   *source,
                                       cairo_path_fixed_t   *path,
                                       cairo_stroke_style_t *style,
-                                      cairo_matrix_t       *ctm,
-                                      cairo_matrix_t       *ctm_inverse,
+                                      cairo_matrix_t       *stroke_ctm,
+                                      cairo_matrix_t       *stroke_ctm_inverse,
                                       double       	    tolerance,
                                       cairo_antialias_t     antialias)
 {
@@ -1102,6 +1119,8 @@ _cairo_win32_printing_surface_stroke (void                 *abstract_surface,
     HGDIOBJ obj;
     unsigned int i;
     cairo_solid_pattern_t clear;
+    cairo_matrix_t mat;
+    double scale;
 
     if (op == CAIRO_OPERATOR_CLEAR) {
 	_cairo_win32_printing_surface_init_clear_color (surface, &clear);
@@ -1119,18 +1138,21 @@ _cairo_win32_printing_surface_stroke (void                 *abstract_surface,
 
     assert (_cairo_win32_printing_surface_operation_supported (surface, op, source));
 
+    cairo_matrix_multiply (&mat, stroke_ctm, &surface->ctm);
+    _cairo_matrix_factor_out_scale (&mat, &scale);
+
     dash_array = NULL;
     if (style->num_dashes) {
 	pen_style = PS_USERSTYLE;
 	dash_array = calloc (sizeof (DWORD), style->num_dashes);
 	for (i = 0; i < style->num_dashes; i++) {
-	    dash_array[i] = (DWORD) style->dash[i];
+	    dash_array[i] = (DWORD) (scale * style->dash[i]);
 	}
     } else {
 	pen_style = PS_SOLID;
     }
 
-    SetMiterLimit (surface->dc, (FLOAT) style->miter_limit, NULL);
+    SetMiterLimit (surface->dc, (FLOAT) (scale * style->miter_limit), NULL);
     if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
 	cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
 
@@ -1148,7 +1170,7 @@ _cairo_win32_printing_surface_stroke (void                 *abstract_surface,
 	        _cairo_win32_line_cap (style->line_cap) |
 	        _cairo_win32_line_join (style->line_join);
     pen = ExtCreatePen(pen_style,
-		       style->line_width < 1.0 ? 1 : _cairo_lround(style->line_width),
+		       scale * style->line_width,
 		       &brush,
 		       style->num_dashes,
 		       dash_array);
@@ -1168,7 +1190,8 @@ _cairo_win32_printing_surface_stroke (void                 *abstract_surface,
      * Switch to user space to set line parameters
      */
     SaveDC (surface->dc);
-    _cairo_matrix_to_win32_xform (ctm, &xform);
+
+    _cairo_matrix_to_win32_xform (&mat, &xform);
     xform.eDx = 0.0f;
     xform.eDy = 0.0f;
 
commit 89fe7b2ff09d19d3bdc84a8ee871e15716ff3539
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 21 23:45:40 2007 +0930

    win32-printing: fix rounding problems when using pattern matrix
    
    When using meta surface patterns, the win32 CTM is changed to the
    inverted pattern matrix then the meta surface is replayed to the
    surface. The problem with this is that win32 uses integer coordinates
    for GDI functions. A pattern matrix that scale the CTM up will cause
    rounding errors in the position of each path in the pattern.
    
    This is fixed by always keeping the win32 CTM set to the identity
    matrix. The CTM is stored in the surface and all coordinates are
    transformed by the CTM before calling GDI functions.

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index c5a5583..6be74f2 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -313,6 +313,22 @@ _cairo_win32_printing_surface_done_solid_brush (cairo_win32_surface_t *surface)
 }
 
 static cairo_status_t
+_cairo_win32_printing_surface_get_ctm_clip_box (cairo_win32_surface_t *surface,
+						RECT                  *clip)
+{
+    XFORM xform;
+
+    _cairo_matrix_to_win32_xform (&surface->ctm, &xform);
+    if (!SetWorldTransform (surface->dc, &xform))
+	return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:SetWorldTransform");
+    GetClipBox (surface->dc, clip);
+    if (!ModifyWorldTransform (surface->dc, &xform, MWT_IDENTITY))
+	return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:ModifyWorldTransform");
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
 _cairo_win32_printing_surface_paint_solid_pattern (cairo_win32_surface_t *surface,
                                                    cairo_pattern_t       *pattern)
 {
@@ -335,6 +351,8 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t   *surfa
 						  cairo_surface_pattern_t *pattern)
 {
     cairo_content_t old_content;
+    cairo_matrix_t old_ctm;
+    cairo_bool_t old_has_ctm;
     cairo_rectangle_int_t meta_extents;
     cairo_status_t status;
     cairo_extend_t extend;
@@ -351,18 +369,21 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t   *surfa
     /* _cairo_pattern_set_matrix guarantees invertibility */
     assert (status == CAIRO_STATUS_SUCCESS);
 
+    old_ctm = surface->ctm;
+    old_has_ctm = surface->has_ctm;
+    cairo_matrix_multiply (&p2d, &p2d, &surface->ctm);
+    surface->ctm = p2d;
     SaveDC (surface->dc);
-    SetGraphicsMode (surface->dc, GM_ADVANCED);
     _cairo_matrix_to_win32_xform (&p2d, &xform);
 
-    if (!SetWorldTransform (surface->dc, &xform))
-	return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint_meta_pattern_set_world_transform_1");
-
     status = _cairo_surface_get_extents (meta_surface, &meta_extents);
     if (status)
 	return status;
 
-    GetClipBox (surface->dc, &clip);
+    status = _cairo_win32_printing_surface_get_ctm_clip_box (surface, &clip);
+    if (status)
+	return status;
+
     if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) {
 	left = (int) floor((double)clip.left/meta_extents.width);
 	right = (int) ceil((double)clip.right/meta_extents.width);
@@ -389,6 +410,7 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t   *surfa
     for (y_tile = top; y_tile < bottom; y_tile++) {
 	for (x_tile = left; x_tile < right; x_tile++) {
 	    cairo_matrix_t m;
+	    double x, y;
 
 	    SaveDC (surface->dc);
 	    m = p2d;
@@ -405,22 +427,47 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t   *surfa
 		    cairo_matrix_scale (&m, 1, -1);
 		}
 	    }
-	    _cairo_matrix_to_win32_xform (&m, &xform);
-	    if (!SetWorldTransform (surface->dc, &xform))
-		return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint_meta_pattern_set_world_transform_2");
+	    surface->ctm = m;
+	    surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
+
+	    /* Set clip path around bbox of the pattern. */
 	    BeginPath (surface->dc);
-	    Rectangle (surface->dc, 0, 0, meta_extents.width, meta_extents.height);
+
+	    x = 0;
+	    y = 0;
+	    cairo_matrix_transform_point (&surface->ctm, &x, &y);
+	    MoveToEx (surface->dc, (int) x, (int) y, NULL);
+
+	    x = meta_extents.width;
+	    y = 0;
+	    cairo_matrix_transform_point (&surface->ctm, &x, &y);
+	    LineTo (surface->dc, (int) x, (int) y);
+
+	    x = meta_extents.width;
+	    y = meta_extents.height;
+	    cairo_matrix_transform_point (&surface->ctm, &x, &y);
+	    LineTo (surface->dc, (int) x, (int) y);
+
+	    x = 0;
+	    y = meta_extents.height;
+	    cairo_matrix_transform_point (&surface->ctm, &x, &y);
+	    LineTo (surface->dc, (int) x, (int) y);
+
+	    CloseFigure (surface->dc);
 	    EndPath (surface->dc);
 	    SelectClipPath (surface->dc, RGN_AND);
+
 	    status = _cairo_meta_surface_replay (meta_surface, &surface->base);
 	    if (status)
 		return status;
+
 	    RestoreDC (surface->dc, -1);
 	}
     }
 
     surface->content = old_content;
-
+    surface->ctm = old_ctm;
+    surface->has_ctm = old_has_ctm;
     RestoreDC (surface->dc, -1);
 
     return status;
@@ -528,8 +575,8 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t   *surf
     /* _cairo_pattern_set_matrix guarantees invertibility */
     assert (status == CAIRO_STATUS_SUCCESS);
 
+    cairo_matrix_multiply (&m, &m, &surface->ctm);
     SaveDC (surface->dc);
-    SetGraphicsMode (surface->dc, GM_ADVANCED);
     _cairo_matrix_to_win32_xform (&m, &xform);
 
     if (!SetWorldTransform (surface->dc, &xform))
@@ -631,6 +678,8 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surfa
     /* _cairo_pattern_set_matrix guarantees invertibility */
     assert (status == CAIRO_STATUS_SUCCESS);
 
+    cairo_matrix_multiply (&mat, &surface->ctm, &mat);
+
     p1x = _cairo_fixed_to_double (pattern->p1.x);
     p1y = _cairo_fixed_to_double (pattern->p1.y);
     p2x = _cairo_fixed_to_double (pattern->p2.x);
@@ -650,7 +699,6 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surfa
 
     _cairo_matrix_to_win32_xform (&mat, &xform);
 
-    SetGraphicsMode (surface->dc, GM_ADVANCED);
     if (!SetWorldTransform (surface->dc, &xform))
 	return _cairo_win32_print_gdi_error ("_win32_printing_surface_paint_linear_pattern:SetWorldTransform2");
     GetWorldTransform(surface->dc, &xform);
@@ -660,6 +708,7 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surfa
     p2y = 0;
 
     GetClipBox (surface->dc, &clip);
+
     if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) {
 	range_start = (int) floor(clip.left/d);
 	range_stop = (int) ceil(clip.right/d);
@@ -803,10 +852,19 @@ _cairo_win32_printing_surface_path_move_to (void *closure, cairo_point_t *point)
     path_info->last_move_to_point = *point;
     path_info->has_sub_path = FALSE;
 
-    MoveToEx (path_info->surface->dc,
-	      _cairo_fixed_integer_part (point->x),
-	      _cairo_fixed_integer_part (point->y),
-	      NULL);
+    if (path_info->surface->has_ctm) {
+	double x, y;
+
+	x = _cairo_fixed_to_double (point->x);
+	y = _cairo_fixed_to_double (point->y);
+	cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
+	MoveToEx (path_info->surface->dc, (int) x, (int) y, NULL);
+    } else {
+	MoveToEx (path_info->surface->dc,
+		  _cairo_fixed_integer_part (point->x),
+		  _cairo_fixed_integer_part (point->y),
+		  NULL);
+    }
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -816,9 +874,18 @@ _cairo_win32_printing_surface_path_line_to (void *closure, cairo_point_t *point)
 {
     win32_path_info_t *path_info = closure;
 
-    LineTo (path_info->surface->dc,
-	    _cairo_fixed_integer_part (point->x),
-	    _cairo_fixed_integer_part (point->y));
+    if (path_info->surface->has_ctm) {
+	double x, y;
+
+	x = _cairo_fixed_to_double (point->x);
+	y = _cairo_fixed_to_double (point->y);
+	cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
+	LineTo (path_info->surface->dc, (int) x, (int) y);
+    } else {
+	LineTo (path_info->surface->dc,
+		_cairo_fixed_integer_part (point->x),
+		_cairo_fixed_integer_part (point->y));
+    }
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -832,12 +899,34 @@ _cairo_win32_printing_surface_path_curve_to (void          *closure,
     win32_path_info_t *path_info = closure;
     POINT points[3];
 
-    points[0].x = _cairo_fixed_integer_part (b->x);
-    points[0].y = _cairo_fixed_integer_part (b->y);
-    points[1].x = _cairo_fixed_integer_part (c->x);
-    points[1].y = _cairo_fixed_integer_part (c->y);
-    points[2].x = _cairo_fixed_integer_part (d->x);
-    points[2].y = _cairo_fixed_integer_part (d->y);
+    if (path_info->surface->has_ctm) {
+	double x, y;
+
+	x = _cairo_fixed_to_double (b->x);
+	y = _cairo_fixed_to_double (b->y);
+	cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
+	points[0].x = (LONG) x;
+	points[0].y = (LONG) y;
+
+	x = _cairo_fixed_to_double (c->x);
+	y = _cairo_fixed_to_double (c->y);
+	cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
+	points[1].x = (LONG) x;
+	points[1].y = (LONG) y;
+
+	x = _cairo_fixed_to_double (d->x);
+	y = _cairo_fixed_to_double (d->y);
+	cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
+	points[2].x = (LONG) x;
+	points[2].y = (LONG) y;
+    } else {
+	points[0].x = _cairo_fixed_integer_part (b->x);
+	points[0].y = _cairo_fixed_integer_part (b->y);
+	points[1].x = _cairo_fixed_integer_part (c->x);
+	points[1].y = _cairo_fixed_integer_part (c->y);
+	points[2].x = _cairo_fixed_integer_part (d->x);
+	points[2].y = _cairo_fixed_integer_part (d->y);
+    }
     PolyBezierTo (path_info->surface->dc, points, 3);
 
     return CAIRO_STATUS_SUCCESS;
@@ -1079,7 +1168,6 @@ _cairo_win32_printing_surface_stroke (void                 *abstract_surface,
      * Switch to user space to set line parameters
      */
     SaveDC (surface->dc);
-    SetGraphicsMode (surface->dc, GM_ADVANCED);
     _cairo_matrix_to_win32_xform (ctm, &xform);
     xform.eDx = 0.0f;
     xform.eDy = 0.0f;
@@ -1179,6 +1267,8 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
     cairo_scaled_glyph_t *scaled_glyph;
     cairo_pattern_t *opaque = NULL;
     int i;
+    cairo_matrix_t old_ctm;
+    cairo_bool_t old_has_ctm;
     XFORM xform;
     cairo_solid_pattern_t clear;
 
@@ -1228,11 +1318,14 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
     }
 
     SaveDC (surface->dc);
-    SetGraphicsMode (surface->dc, GM_ADVANCED);
+
     xform.eM11 = 1.0f;
     xform.eM21 = 0.0f;
     xform.eM12 = 0.0f;
     xform.eM22 = 1.0f;
+    old_ctm = surface->ctm;
+    old_has_ctm = surface->has_ctm;
+    surface->has_ctm = TRUE;
     BeginPath (surface->dc);
     for (i = 0; i < num_glyphs; i++) {
 	status = _cairo_scaled_glyph_lookup (scaled_font,
@@ -1241,13 +1334,13 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
 					     &scaled_glyph);
 	if (status)
 	    break;
-	xform.eDx = (FLOAT) glyphs[i].x;
-	xform.eDy = (FLOAT) glyphs[i].y;
-	if (!SetWorldTransform (surface->dc, &xform))
-	    return _cairo_win32_print_gdi_error ("_win32_surface_print_show_glyphs:SetWorldTransform");
+	surface->ctm = old_ctm;
+	cairo_matrix_translate (&surface->ctm, glyphs[i].x, glyphs[i].y);
 	status = _cairo_win32_printing_surface_emit_path (surface, scaled_glyph->path);
     }
     EndPath (surface->dc);
+    surface->ctm = old_ctm;
+    surface->has_ctm = old_has_ctm;
     if (status == CAIRO_STATUS_SUCCESS) {
 	SelectClipPath (surface->dc, RGN_AND);
 	status = _cairo_win32_printing_surface_paint_pattern (surface, source);
@@ -1273,8 +1366,20 @@ static cairo_int_status_t
 _cairo_win32_printing_surface_start_page (void *abstract_surface)
 {
     cairo_win32_surface_t *surface = abstract_surface;
+    XFORM xform;
 
     SaveDC (surface->dc);
+    SetGraphicsMode (surface->dc, GM_ADVANCED);
+    GetWorldTransform(surface->dc, &xform);
+    surface->ctm.xx = xform.eM11;
+    surface->ctm.xy = xform.eM21;
+    surface->ctm.yx = xform.eM12;
+    surface->ctm.yy = xform.eM22;
+    surface->ctm.x0 = xform.eDx;
+    surface->ctm.y0 = xform.eDy;
+    surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
+    if (!ModifyWorldTransform (surface->dc, NULL, MWT_IDENTITY))
+	return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_start_page:ModifyWorldTransform");
 
     return CAIRO_STATUS_SUCCESS;
 }
diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h
index 8bf3aeb..0eff4d1 100644
--- a/src/cairo-win32-private.h
+++ b/src/cairo-win32-private.h
@@ -83,6 +83,8 @@ typedef struct _cairo_win32_surface {
     /* printing surface bits */
     cairo_paginated_mode_t paginated_mode;
     cairo_content_t content;
+    cairo_bool_t has_ctm;
+    cairo_matrix_t ctm;
     int clip_saved_dc;
     HBRUSH brush, old_brush;
 } cairo_win32_surface_t;
commit af01d9b8fabc2422eb7db144171d52fab95c4387
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 21 23:43:27 2007 +0930

    win32-printing: add meta surface pattern support

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index cde90b2..c5a5583 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -50,6 +50,7 @@
 
 #include "cairo-clip-private.h"
 #include "cairo-win32-private.h"
+#include "cairo-meta-surface-private.h"
 
 #include <windows.h>
 
@@ -150,6 +151,9 @@ surface_pattern_supported (const cairo_surface_pattern_t *pattern)
 {
     cairo_extend_t extend;
 
+    if (_cairo_surface_is_meta (pattern->surface))
+	return TRUE;
+
     if (cairo_surface_get_type (pattern->surface) != CAIRO_SURFACE_TYPE_WIN32 &&
 	pattern->surface->backend->acquire_source_image == NULL)
     {
@@ -217,7 +221,10 @@ _cairo_win32_printing_surface_analyze_operation (cairo_win32_surface_t *surface,
     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
 	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
 
-	return analyze_surface_pattern_transparency (surface_pattern);
+	if ( _cairo_surface_is_meta (surface_pattern->surface))
+	    return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
+	else
+	    return analyze_surface_pattern_transparency (surface_pattern);
     }
 
     if (_cairo_pattern_is_opaque (pattern))
@@ -237,30 +244,56 @@ _cairo_win32_printing_surface_operation_supported (cairo_win32_surface_t *surfac
 	return FALSE;
 }
 
-static cairo_status_t
-_cairo_win32_printing_surface_select_solid_brush (cairo_win32_surface_t *surface,
-                                                  cairo_pattern_t       *source)
+static void
+_cairo_win32_printing_surface_init_clear_color (cairo_win32_surface_t *surface,
+						cairo_solid_pattern_t *color)
 {
-    cairo_solid_pattern_t *pattern = (cairo_solid_pattern_t *) source;
-    cairo_color_t c = pattern->color;
-    COLORREF color;
+    if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
+	_cairo_pattern_init_solid (color, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR);
+    else
+	_cairo_pattern_init_solid (color, CAIRO_COLOR_BLACK, CAIRO_CONTENT_COLOR);
+}
+
+static COLORREF
+_cairo_win32_printing_surface_flatten_transparency (cairo_win32_surface_t *surface,
+						    const cairo_color_t   *color)
+{
+    COLORREF c;
     BYTE red, green, blue;
 
-    red   = c.red_short   >> 8;
-    green = c.green_short >> 8;
-    blue  = c.blue_short  >> 8;
+    red   = color->red_short   >> 8;
+    green = color->green_short >> 8;
+    blue  = color->blue_short  >> 8;
 
-    if (!CAIRO_COLOR_IS_OPAQUE(&c)) {
-	/* Blend into white */
-	uint8_t one_minus_alpha = 255 - (c.alpha_short >> 8);
+    if (!CAIRO_COLOR_IS_OPAQUE(color)) {
+	if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
+	    /* Blend into white */
+	    uint8_t one_minus_alpha = 255 - (color->alpha_short >> 8);
 
-	red   = (c.red_short   >> 8) + one_minus_alpha;
-	green = (c.green_short >> 8) + one_minus_alpha;
-	blue  = (c.blue_short  >> 8) + one_minus_alpha;
+	    red   = (color->red_short   >> 8) + one_minus_alpha;
+	    green = (color->green_short >> 8) + one_minus_alpha;
+	    blue  = (color->blue_short  >> 8) + one_minus_alpha;
+	} else {
+	    /* Blend into black */
+	    red   = (color->red_short   >> 8);
+	    green = (color->green_short >> 8);
+	    blue  = (color->blue_short  >> 8);
+	}
     }
+    c = RGB (red, green, blue);
+
+    return c;
+}
 
-    color = RGB (red, green, blue);
+static cairo_status_t
+_cairo_win32_printing_surface_select_solid_brush (cairo_win32_surface_t *surface,
+                                                  cairo_pattern_t       *source)
+{
+    cairo_solid_pattern_t *pattern = (cairo_solid_pattern_t *) source;
+    COLORREF color;
 
+    color = _cairo_win32_printing_surface_flatten_transparency (surface,
+								&pattern->color);
     surface->brush = CreateSolidBrush (color);
     if (!surface->brush)
 	return _cairo_win32_print_gdi_error ("_cairo_win32_surface_select_solid_brush(CreateSolidBrush)");
@@ -298,8 +331,104 @@ _cairo_win32_printing_surface_paint_solid_pattern (cairo_win32_surface_t *surfac
 }
 
 static cairo_status_t
-_cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t   *surface,
-                                                     cairo_surface_pattern_t *pattern)
+_cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t   *surface,
+						  cairo_surface_pattern_t *pattern)
+{
+    cairo_content_t old_content;
+    cairo_rectangle_int_t meta_extents;
+    cairo_status_t status;
+    cairo_extend_t extend;
+    cairo_matrix_t p2d;
+    XFORM xform;
+    int x_tile, y_tile, left, right, top, bottom;
+    RECT clip;
+    cairo_surface_t *meta_surface = pattern->surface;
+
+    extend = cairo_pattern_get_extend (&pattern->base);
+
+    p2d = pattern->base.matrix;
+    status = cairo_matrix_invert (&p2d);
+    /* _cairo_pattern_set_matrix guarantees invertibility */
+    assert (status == CAIRO_STATUS_SUCCESS);
+
+    SaveDC (surface->dc);
+    SetGraphicsMode (surface->dc, GM_ADVANCED);
+    _cairo_matrix_to_win32_xform (&p2d, &xform);
+
+    if (!SetWorldTransform (surface->dc, &xform))
+	return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint_meta_pattern_set_world_transform_1");
+
+    status = _cairo_surface_get_extents (meta_surface, &meta_extents);
+    if (status)
+	return status;
+
+    GetClipBox (surface->dc, &clip);
+    if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) {
+	left = (int) floor((double)clip.left/meta_extents.width);
+	right = (int) ceil((double)clip.right/meta_extents.width);
+	top = (int) floor((double)clip.top/meta_extents.height);
+	bottom = (int) ceil((double)clip.bottom/meta_extents.height);
+    } else {
+	left = 0;
+	right = 1;
+	top = 0;
+	bottom = 1;
+    }
+
+    old_content = surface->content;
+    if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
+	cairo_pattern_t  *source;
+	cairo_solid_pattern_t black;
+
+	surface->content = CAIRO_CONTENT_COLOR;
+	_cairo_pattern_init_solid (&black, CAIRO_COLOR_BLACK, CAIRO_CONTENT_COLOR);
+	source = (cairo_pattern_t*) &black;
+	_cairo_win32_printing_surface_paint_solid_pattern (surface, source);
+    }
+
+    for (y_tile = top; y_tile < bottom; y_tile++) {
+	for (x_tile = left; x_tile < right; x_tile++) {
+	    cairo_matrix_t m;
+
+	    SaveDC (surface->dc);
+	    m = p2d;
+	    cairo_matrix_translate (&m,
+				    x_tile*meta_extents.width,
+				    y_tile*meta_extents.height);
+	    if (extend == CAIRO_EXTEND_REFLECT) {
+		if (x_tile % 2) {
+		    cairo_matrix_translate (&m, meta_extents.width, 0);
+		    cairo_matrix_scale (&m, -1, 1);
+		}
+		if (y_tile % 2) {
+		    cairo_matrix_translate (&m, 0, meta_extents.height);
+		    cairo_matrix_scale (&m, 1, -1);
+		}
+	    }
+	    _cairo_matrix_to_win32_xform (&m, &xform);
+	    if (!SetWorldTransform (surface->dc, &xform))
+		return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint_meta_pattern_set_world_transform_2");
+	    BeginPath (surface->dc);
+	    Rectangle (surface->dc, 0, 0, meta_extents.width, meta_extents.height);
+	    EndPath (surface->dc);
+	    SelectClipPath (surface->dc, RGN_AND);
+	    status = _cairo_meta_surface_replay (meta_surface, &surface->base);
+	    if (status)
+		return status;
+	    RestoreDC (surface->dc, -1);
+	}
+    }
+
+    surface->content = old_content;
+
+    RestoreDC (surface->dc, -1);
+
+    return status;
+}
+
+static cairo_status_t
+_cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t   *surface,
+						   cairo_surface_pattern_t *pattern)
 {
     cairo_status_t status;
     cairo_extend_t extend;
@@ -316,6 +445,12 @@ _cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t   *su
     XFORM xform;
     int x_tile, y_tile, left, right, top, bottom;
     RECT clip;
+    const cairo_color_t *background_color;
+
+    if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
+	background_color = CAIRO_COLOR_WHITE;
+    else
+	background_color = CAIRO_COLOR_BLACK;
 
     extend = cairo_pattern_get_extend (&pattern->base);
     status = _cairo_pattern_acquire_surface ((cairo_pattern_t *)pattern,
@@ -347,7 +482,7 @@ _cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t   *su
 
 	status = _cairo_surface_fill_rectangle (opaque_surface,
 				                CAIRO_OPERATOR_SOURCE,
-						CAIRO_COLOR_WHITE,
+						background_color,
 						0, 0,
 						image->width, image->height);
 	if (status) {
@@ -447,6 +582,19 @@ FINISH:
     return status;
 }
 
+static cairo_status_t
+_cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t   *surface,
+                                                     cairo_surface_pattern_t *pattern)
+{
+    if (_cairo_surface_is_meta (pattern->surface)) {
+	return _cairo_win32_printing_surface_paint_meta_pattern (surface,
+								 pattern);
+    } else {
+	return _cairo_win32_printing_surface_paint_image_pattern (surface,
+								  pattern);
+    }
+}
+
 static void
 vertex_set_color (TRIVERTEX *vert, cairo_color_t *color)
 {
@@ -795,11 +943,11 @@ _cairo_win32_printing_surface_paint (void             *abstract_surface,
                                      cairo_pattern_t  *source)
 {
     cairo_win32_surface_t *surface = abstract_surface;
-    cairo_solid_pattern_t white;
+    cairo_solid_pattern_t clear;
 
     if (op == CAIRO_OPERATOR_CLEAR) {
-	_cairo_pattern_init_solid (&white, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR);
-	source = (cairo_pattern_t*) &white;
+	_cairo_win32_printing_surface_init_clear_color (surface, &clear);
+	source = (cairo_pattern_t*) &clear;
 	op = CAIRO_OPERATOR_SOURCE;
     }
 
@@ -864,11 +1012,11 @@ _cairo_win32_printing_surface_stroke (void                 *abstract_surface,
     DWORD *dash_array;
     HGDIOBJ obj;
     unsigned int i;
-    cairo_solid_pattern_t white;
+    cairo_solid_pattern_t clear;
 
     if (op == CAIRO_OPERATOR_CLEAR) {
-	_cairo_pattern_init_solid (&white, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR);
-	source = (cairo_pattern_t*) &white;
+	_cairo_win32_printing_surface_init_clear_color (surface, &clear);
+	source = (cairo_pattern_t*) &clear;
 	op = CAIRO_OPERATOR_SOURCE;
     }
 
@@ -896,18 +1044,10 @@ _cairo_win32_printing_surface_stroke (void                 *abstract_surface,
     SetMiterLimit (surface->dc, (FLOAT) style->miter_limit, NULL);
     if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
 	cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
-	cairo_color_t c = solid->color;
 
-	if (!CAIRO_COLOR_IS_OPAQUE(&c)) {
-	    /* Blend into white */
-	    c.red = c.red*c.alpha + 1 - c.alpha;
-	    c.green = c.green*c.alpha + 1 - c.alpha;
-	    c.blue = c.blue*c.alpha + 1 - c.alpha;
-	}
 
-	color = RGB ((BYTE)(c.red*255),
-		     (BYTE)(c.green*255),
-		     (BYTE)(c.blue*255));
+	color = _cairo_win32_printing_surface_flatten_transparency (surface,
+								    &solid->color);
     } else {
 	/* Color not used as the pen will only be used by WidenPath() */
 	color = RGB (0,0,0);
@@ -979,11 +1119,11 @@ _cairo_win32_printing_surface_fill (void		        *abstract_surface,
 {
     cairo_win32_surface_t *surface = abstract_surface;
     cairo_int_status_t status;
-    cairo_solid_pattern_t white;
+    cairo_solid_pattern_t clear;
 
     if (op == CAIRO_OPERATOR_CLEAR) {
-	_cairo_pattern_init_solid (&white, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR);
-	source = (cairo_pattern_t*) &white;
+	_cairo_win32_printing_surface_init_clear_color (surface, &clear);
+	source = (cairo_pattern_t*) &clear;
 	op = CAIRO_OPERATOR_SOURCE;
     }
 
@@ -1040,11 +1180,11 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
     cairo_pattern_t *opaque = NULL;
     int i;
     XFORM xform;
-    cairo_solid_pattern_t white;
+    cairo_solid_pattern_t clear;
 
     if (op == CAIRO_OPERATOR_CLEAR) {
-	_cairo_pattern_init_solid (&white, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR);
-	source = (cairo_pattern_t*) &white;
+	_cairo_win32_printing_surface_init_clear_color (surface, &clear);
+	source = (cairo_pattern_t*) &clear;
 	op = CAIRO_OPERATOR_SOURCE;
     }
 
@@ -1066,16 +1206,13 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
 
     if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
 	cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
-	cairo_color_t c = solid->color;
+	COLORREF color;
 
-	if (!CAIRO_COLOR_IS_OPAQUE(&c)) {
-	    /* Blend into white */
-	    c.red = c.red*c.alpha + 1 - c.alpha;
-	    c.green = c.green*c.alpha + 1 - c.alpha;
-	    c.blue = c.blue*c.alpha + 1 - c.alpha;
-	}
-
-	opaque = cairo_pattern_create_rgb (c.red, c.green, c.blue);
+	color = _cairo_win32_printing_surface_flatten_transparency (surface,
+								    &solid->color);
+	opaque = cairo_pattern_create_rgb (GetRValue (color),
+					   GetGValue (color),
+					   GetBValue (color));
 	if (opaque->status)
 	    return opaque->status;
 	source = opaque;
@@ -1123,6 +1260,15 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
     return status;
 }
 
+static cairo_surface_t *
+_cairo_win32_printing_surface_create_similar (void		*abstract_surface,
+					      cairo_content_t	 content,
+					      int		 width,
+					      int		 height)
+{
+    return _cairo_meta_surface_create (content, width, height);
+}
+
 static cairo_int_status_t
 _cairo_win32_printing_surface_start_page (void *abstract_surface)
 {
@@ -1182,6 +1328,7 @@ cairo_win32_printing_surface_create (HDC hdc)
 
     surface->image = NULL;
     surface->format = CAIRO_FORMAT_RGB24;
+    surface->content = CAIRO_CONTENT_COLOR_ALPHA;
 
     surface->dc = hdc;
     surface->bitmap = NULL;
@@ -1236,7 +1383,7 @@ _cairo_surface_is_win32_printing (cairo_surface_t *surface)
 
 static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
     CAIRO_SURFACE_TYPE_WIN32_PRINTING,
-    _cairo_win32_surface_create_similar,
+    _cairo_win32_printing_surface_create_similar,
     _cairo_win32_surface_finish,
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h
index eddde36..8bf3aeb 100644
--- a/src/cairo-win32-private.h
+++ b/src/cairo-win32-private.h
@@ -82,6 +82,7 @@ typedef struct _cairo_win32_surface {
 
     /* printing surface bits */
     cairo_paginated_mode_t paginated_mode;
+    cairo_content_t content;
     int clip_saved_dc;
     HBRUSH brush, old_brush;
 } cairo_win32_surface_t;
commit dae1b352c60e6a63ec2131f788fec230fd583d3d
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 21 23:42:54 2007 +0930

    update cairo-sections.txt

diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index 5f450e9..4484271 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -76,6 +76,7 @@ cairo_ps_surface_dsc_comment
 cairo_win32_surface_create
 cairo_win32_surface_create_with_dib
 cairo_win32_surface_create_with_ddb
+cairo_win32_printing_surface_create
 cairo_win32_surface_get_dc
 cairo_win32_surface_get_image
 </SECTION>
commit c8da2a7dedb8352bb623954c3ac40244b86eeb24
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 21 23:42:22 2007 +0930

    win32-printing: check if images are opaque
    
    Don't use fallback for argb32 images with all alpha == 255.

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 02cf30c..cde90b2 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -94,6 +94,57 @@ _cairo_win32_printing_surface_init_ps_mode (cairo_win32_surface_t *surface)
 	surface->flags |= CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT;
 }
 
+static cairo_int_status_t
+analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern)
+{
+    cairo_image_surface_t  *image;
+    void		   *image_extra;
+    cairo_int_status_t      status;
+    int x, y;
+
+    status = _cairo_surface_acquire_source_image (pattern->surface,
+						  &image,
+						  &image_extra);
+    if (status)
+	return status;
+
+    if (image->base.status)
+	return image->base.status;
+
+    if (image->format == CAIRO_FORMAT_RGB24) {
+	status = CAIRO_STATUS_SUCCESS;
+	goto RELEASE_SOURCE;
+    }
+
+    if (image->format != CAIRO_FORMAT_ARGB32) {
+	/* If the surface does not support the image format, assume
+	 * that it does have alpha. The image will be converted to
+	 * rgb24 when the surface blends the image into the page
+	 * color to remove the transparency. */
+	status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
+	goto RELEASE_SOURCE;
+    }
+
+    for (y = 0; y < image->height; y++) {
+	int a;
+	uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
+
+	for (x = 0; x < image->width; x++, pixel++) {
+	    a = (*pixel & 0xff000000) >> 24;
+	    if (a != 255) {
+		status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
+		goto RELEASE_SOURCE;
+	    }
+	}
+    }
+    status = CAIRO_STATUS_SUCCESS;
+
+RELEASE_SOURCE:
+    _cairo_surface_release_source_image (pattern->surface, image, image_extra);
+
+    return status;
+}
+
 static cairo_bool_t
 surface_pattern_supported (const cairo_surface_pattern_t *pattern)
 {
@@ -163,6 +214,12 @@ _cairo_win32_printing_surface_analyze_operation (cairo_win32_surface_t *surface,
      * background to convert the pattern to opaque.
      */
 
+    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
+
+	return analyze_surface_pattern_transparency (surface_pattern);
+    }
+
     if (_cairo_pattern_is_opaque (pattern))
 	return CAIRO_STATUS_SUCCESS;
     else
commit 9eb5747755f8c57bd6ba04925e193503fe194462
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 21 23:41:31 2007 +0930

    win32-printing: Add missing struct initializers

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 991249b..02cf30c 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -1209,9 +1209,11 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
     NULL, /* snapshot */
     NULL, /* is_similar */
     NULL, /* reset */
+    NULL, /* fill_stroke */
 };
 
 static const cairo_paginated_surface_backend_t cairo_win32_surface_paginated_backend = {
     _cairo_win32_printing_surface_start_page,
-    _cairo_win32_printing_surface_set_paginated_mode
+    _cairo_win32_printing_surface_set_paginated_mode,
+    NULL, /* set_bounding_box */
 };


More information about the cairo-commit mailing list