[cairo-commit] 5 commits - src/cairo.h src/cairo-image-surface.c src/cairoint.h src/cairo-mutex-type-private.h src/cairo-paginated-surface.c src/cairo-surface.c src/cairo-surface-private.h src/cairo-win32-font.c src/cairo-win32.h src/cairo-win32-printing-surface.c src/cairo-win32-private.h src/cairo-win32-surface.c src/Makefile.am src/Makefile.win32

Vladimir Vukicevic vladimir at kemper.freedesktop.org
Tue Sep 18 12:48:07 PDT 2007


 src/Makefile.am                    |    2 
 src/Makefile.win32                 |    3 
 src/cairo-image-surface.c          |    2 
 src/cairo-mutex-type-private.h     |    6 
 src/cairo-paginated-surface.c      |   41 -
 src/cairo-surface-private.h        |    8 
 src/cairo-surface.c                |   24 
 src/cairo-win32-font.c             |    7 
 src/cairo-win32-printing-surface.c | 1220 +++++++++++++++++++++++++++++++++++++
 src/cairo-win32-private.h          |   66 +-
 src/cairo-win32-surface.c          |   78 +-
 src/cairo-win32.h                  |    3 
 src/cairo.h                        |    4 
 src/cairoint.h                     |    6 
 14 files changed, 1423 insertions(+), 47 deletions(-)

New commits:
diff-tree d8b0de01d67cdf73d8266a73f54ba1ac42fee3c9 (from 4fd9acc1b321d75623a66d37c0ff299ae06fb98b)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Tue Sep 18 09:26:05 2007 -0700

    fix trailing whitespace

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index e8ed668..612d8cf 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -197,8 +197,8 @@ _cairo_surface_init (cairo_surface_t			*
     cairo_matrix_init_identity (&surface->device_transform);
     cairo_matrix_init_identity (&surface->device_transform_inverse);
 
-    surface->x_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT; 
-    surface->y_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT; 
+    surface->x_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT;
+    surface->y_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT;
 
     surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
     surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
diff-tree 4fd9acc1b321d75623a66d37c0ff299ae06fb98b (from e3c16e15e39d98f96e2ce20e397d88214f5a821e)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Tue Sep 4 10:30:08 2007 -0700

    [win32] add new win32 printing surface

diff --git a/src/Makefile.win32 b/src/Makefile.win32
index 037f9c3..fa00083 100644
--- a/src/Makefile.win32
+++ b/src/Makefile.win32
@@ -62,6 +62,7 @@ SOURCES = \
 	cairo-paginated-surface.c \
 	cairo-analysis-surface.c \
 	cairo-base85-stream.c \
+	cairo-win32-printing-surface.c \
 	$(NULL)
 
 STATIC_SOURCES = cairo-win32-surface.c 
@@ -97,7 +98,7 @@ $(DEFFILE):
 	@ ! grep -q cairo_ERROR $@ || ($(RM) $@; false)
 
 cairo.dll: $(OBJECTS) $(SHARED_OBJECTS) $(DEFFILE)
-	$(CC) -MD -Zi -LD -Fe$@ $(PIXMAN_LIBS) $(OBJECTS) $(SHARED_OBJECTS) -link -DEF:$(DEFFILE) user32.lib gdi32.lib libpng.lib zdll.lib
+	$(CC) -MD -Zi -LD -Fe$@ $(PIXMAN_LIBS) $(OBJECTS) $(SHARED_OBJECTS) -link -DEF:$(DEFFILE) user32.lib gdi32.lib libpng.lib zdll.lib msimg32.lib
 
 cairo-static.lib: $(OBJECTS) $(STATIC_OBJECTS)
 	lib -NOLOGO -OUT:$@ $(PIXMAN_LIBS) $(OBJECTS) $(STATIC_OBJECTS)
diff-tree e3c16e15e39d98f96e2ce20e397d88214f5a821e (from ffc16c4be2fb5a0d214cb186dee52e74dbd584cf)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Wed Aug 29 16:30:49 2007 -0700

    Make NO_MUTEX really mean no mutexes

diff --git a/src/cairo-mutex-type-private.h b/src/cairo-mutex-type-private.h
index 59d581a..b9f0fb3 100644
--- a/src/cairo-mutex-type-private.h
+++ b/src/cairo-mutex-type-private.h
@@ -141,13 +141,13 @@ CAIRO_BEGIN_DECLS
 
 #if CAIRO_NO_MUTEX
 
-/* A poor man's mutex */
+/* No mutexes */
 
   typedef int cairo_mutex_t;
 
 # define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP
-# define CAIRO_MUTEX_LOCK(mutex) do { while (mutex) ; (mutex) = 1; } while (0)
-# define CAIRO_MUTEX_UNLOCK(mutex) (mutex) = 0
+# define CAIRO_MUTEX_LOCK(mutex) CAIRO_MUTEX_NOOP1(mutex)
+# define CAIRO_MUTEX_UNLOCK(mutex) CAIRO_MUTEX_NOOP1(mutex)
 # define CAIRO_MUTEX_NIL_INITIALIZER 0
 
 #elif HAVE_PTHREAD_H /*******************************************************/
diff-tree ffc16c4be2fb5a0d214cb186dee52e74dbd584cf (from 284ed91ee4418baf6dd1a437a904980a2156fa48)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Wed Aug 29 16:25:58 2007 -0700

    [win32] Add win32 printing surface
    
    Add win32 surface intended for use with printer DCs; GDI will be used
    as much as possible, and the surface will be a paginated surface
    that supports fine-grained fallback.
    
    (Original work from Adrian Johnson; additional fixes by me.)

diff --git a/src/Makefile.am b/src/Makefile.am
index dd8d66e..ae7cb63 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -81,7 +81,7 @@ endif
 libcairo_win32_sources =
 if CAIRO_HAS_WIN32_SURFACE
 libcairo_win32_headers = cairo-win32.h
-libcairo_win32_sources += cairo-win32-surface.c cairo-win32-private.h
+libcairo_win32_sources += cairo-win32-surface.c cairo-win32-printing-surface.c cairo-win32-private.h
 backend_pkgconfigs += cairo-win32.pc
 endif
 # This is not really a separate conditional.  Is TRUE iff the previous one is.
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index bf4e341..78b7e30 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -300,22 +300,27 @@ _paint_page (cairo_paginated_surface_t *
 	return status;
     }
 
-    /* Finer grained fallbacks are currently only supported for PDF
-     * and PostScript surfaces */
-    if (surface->target->type == CAIRO_SURFACE_TYPE_PDF ||
-	surface->target->type == CAIRO_SURFACE_TYPE_PS) {
-	has_supported = _cairo_analysis_surface_has_supported (analysis);
-	has_page_fallback = FALSE;
-	has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis);
-    } else {
-	if (_cairo_analysis_surface_has_unsupported (analysis)) {
-	    has_supported = FALSE;
-	    has_page_fallback = TRUE;
-	} else {
-	    has_supported = TRUE;
-	    has_page_fallback = FALSE;
-	}
-	has_finegrained_fallback = FALSE;
+    /* Finer grained fallbacks are currently only supported for some
+     * surface types */
+    switch (surface->target->type) {
+        case CAIRO_SURFACE_TYPE_PDF:
+        case CAIRO_SURFACE_TYPE_PS:
+        case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
+            has_supported = _cairo_analysis_surface_has_supported (analysis);
+            has_page_fallback = FALSE;
+            has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis);
+            break;
+
+        default:
+            if (_cairo_analysis_surface_has_unsupported (analysis)) {
+                has_supported = FALSE;
+                has_page_fallback = TRUE;
+            } else {
+                has_supported = TRUE;
+                has_page_fallback = FALSE;
+            }
+            has_finegrained_fallback = FALSE;
+            break;
     }
 
     if (has_supported) {
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 484ca17..81213e7 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -326,12 +326,7 @@ _win32_scaled_font_set_world_transform (
 {
     XFORM xform;
 
-    xform.eM11 = scaled_font->logical_to_device.xx;
-    xform.eM21 = scaled_font->logical_to_device.xy;
-    xform.eM12 = scaled_font->logical_to_device.yx;
-    xform.eM22 = scaled_font->logical_to_device.yy;
-    xform.eDx = scaled_font->logical_to_device.x0;
-    xform.eDy = scaled_font->logical_to_device.y0;
+    _cairo_matrix_to_win32_xform (&scaled_font->logical_to_device, &xform);
 
     if (!SetWorldTransform (hdc, &xform))
 	return _cairo_win32_print_gdi_error ("_win32_scaled_font_set_world_transform");
diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
new file mode 100644
index 0000000..839f3cd
--- /dev/null
+++ b/src/cairo-win32-printing-surface.c
@@ -0,0 +1,1220 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ *      Adrian Johnson <ajohnson at redneon.com>
+ *      Vladimir Vukicevic <vladimir at pobox.com>
+ */
+
+#define WIN32_LEAN_AND_MEAN
+/* We require Windows 2000 features such as ETO_PDY */
+#if !defined(WINVER) || (WINVER < 0x0500)
+# define WINVER 0x0500
+#endif
+#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
+# define _WIN32_WINNT 0x0500
+#endif
+
+#include "cairoint.h"
+
+#include "cairo-paginated-private.h"
+
+#include "cairo-clip-private.h"
+#include "cairo-win32-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
+
+#define PELS_72DPI  ((LONG)(72. / 0.0254))
+#define NIL_SURFACE ((cairo_surface_t*)&_cairo_surface_nil)
+
+static const cairo_surface_backend_t cairo_win32_printing_surface_backend;
+static const cairo_paginated_surface_backend_t cairo_win32_surface_paginated_backend;
+
+static void
+_cairo_win32_printing_surface_init_ps_mode (cairo_win32_surface_t *surface)
+{
+    DWORD word;
+    INT ps_feature, ps_level;
+
+    word = PSIDENT_GDICENTRIC;
+    if (ExtEscape (surface->dc, POSTSCRIPT_IDENTIFY, sizeof(DWORD), (char *)&word, 0, (char *)NULL) <= 0)
+	return;
+
+    ps_feature = FEATURESETTING_PSLEVEL;
+    if (ExtEscape (surface->dc, GET_PS_FEATURESETTING, sizeof(INT),
+		   (char *)&ps_feature, sizeof(INT), (char *)&ps_level) <= 0)
+	return;
+
+    if (ps_level >= 3)
+	surface->flags |= CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT;
+}
+
+static cairo_bool_t
+surface_pattern_supported (const cairo_surface_pattern_t *pattern)
+{
+    cairo_extend_t extend;
+
+    if (cairo_surface_get_type (pattern->surface) != CAIRO_SURFACE_TYPE_WIN32 &&
+	pattern->surface->backend->acquire_source_image == NULL)
+    {
+	return FALSE;
+    }
+
+    extend = cairo_pattern_get_extend ((cairo_pattern_t*)&pattern->base);
+    switch (extend) {
+    case CAIRO_EXTEND_NONE:
+    case CAIRO_EXTEND_REPEAT:
+    case CAIRO_EXTEND_REFLECT:
+    /* There's no point returning FALSE for EXTEND_PAD, as the image
+     * surface does not currently implement it either */
+    case CAIRO_EXTEND_PAD:
+	return TRUE;
+    }
+
+    ASSERT_NOT_REACHED;
+    return FALSE;
+}
+
+static cairo_bool_t
+pattern_supported (cairo_win32_surface_t *surface, const cairo_pattern_t *pattern)
+{
+    if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
+	return TRUE;
+
+    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
+	return surface_pattern_supported ((const cairo_surface_pattern_t *) pattern);
+
+    if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR)
+	return surface->flags & CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT;
+
+    return FALSE;
+}
+
+static cairo_int_status_t
+_cairo_win32_printing_surface_analyze_operation (cairo_win32_surface_t *surface,
+                                                 cairo_operator_t       op,
+                                                 const cairo_pattern_t *pattern)
+{
+    if (! pattern_supported (surface, pattern))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (op == CAIRO_OPERATOR_SOURCE ||
+	op == CAIRO_OPERATOR_CLEAR)
+	return CAIRO_STATUS_SUCCESS;
+
+    /* If IGNORE_OPERATORS was set, then we pretend everything is
+     * OVER/SOURCE.  Otherwise, we go to fallback.
+     */
+    if (!(surface->flags & CAIRO_WIN32_SURFACE_IGNORE_OPERATORS) &&
+	op != CAIRO_OPERATOR_OVER)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
+     * the pattern contains transparency, we return
+     * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
+     * surface. If the analysis surface determines that there is
+     * anything drawn under this operation, a fallback image will be
+     * used. Otherwise the operation will be replayed during the
+     * render stage and we blend the transarency into the white
+     * background to convert the pattern to opaque.
+     */
+
+    if (_cairo_operator_always_opaque (op))
+	return CAIRO_STATUS_SUCCESS;
+
+    if (_cairo_operator_always_translucent (op))
+	return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
+
+    if (_cairo_pattern_is_opaque (pattern))
+	return CAIRO_STATUS_SUCCESS;
+    else
+	return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
+}
+
+static cairo_bool_t
+_cairo_win32_printing_surface_operation_supported (cairo_win32_surface_t *surface,
+                                                   cairo_operator_t       op,
+                                                   const cairo_pattern_t *pattern)
+{
+    if (_cairo_win32_printing_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED)
+	return TRUE;
+    else
+	return FALSE;
+}
+
+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;
+    cairo_color_t c = pattern->color;
+    COLORREF color;
+    BYTE red, green, blue;
+
+    red   = c.red_short   >> 8;
+    green = c.green_short >> 8;
+    blue  = c.blue_short  >> 8;
+
+    if (!CAIRO_COLOR_IS_OPAQUE(&c)) {
+	/* Blend into white */
+	uint8_t one_minus_alpha = 255 - (c.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;
+    }
+
+    color = RGB (red, green, blue);
+
+    surface->brush = CreateSolidBrush (color);
+    if (!surface->brush)
+	return _cairo_win32_print_gdi_error ("_cairo_win32_surface_select_solid_brush(CreateSolidBrush)");
+    surface->old_brush = SelectObject (surface->dc, surface->brush);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_win32_printing_surface_done_solid_brush (cairo_win32_surface_t *surface)
+{
+    if (surface->old_brush) {
+	SelectObject (surface->dc, surface->old_brush);
+	DeleteObject (surface->brush);
+	surface->old_brush = NULL;
+    }
+}
+
+static cairo_status_t
+_cairo_win32_printing_surface_paint_solid_pattern (cairo_win32_surface_t *surface,
+                                                   cairo_pattern_t       *pattern)
+{
+    RECT clip;
+    cairo_status_t status;
+
+    GetClipBox (surface->dc, &clip);
+    status = _cairo_win32_printing_surface_select_solid_brush (surface, pattern);
+    if (status)
+	return status;
+
+    FillRect (surface->dc, &clip, surface->brush);
+    _cairo_win32_printing_surface_done_solid_brush (surface);
+
+    return 0;
+}
+
+static cairo_status_t
+_cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t   *surface,
+                                                     cairo_surface_pattern_t *pattern)
+{
+    cairo_status_t status;
+    cairo_extend_t extend;
+    cairo_surface_t *pat_surface;
+    cairo_surface_attributes_t pat_attr;
+    cairo_image_surface_t *image;
+    void *image_extra;
+    cairo_surface_t *opaque_surface;
+    cairo_pattern_union_t opaque_pattern;
+    cairo_image_surface_t *opaque_image = NULL;
+    BITMAPINFO bi;
+    cairo_matrix_t m;
+    int oldmode;
+    XFORM xform;
+    int x_tile, y_tile, left, right, top, bottom;
+    RECT clip;
+
+    extend = cairo_pattern_get_extend (&pattern->base);
+    status = _cairo_pattern_acquire_surface ((cairo_pattern_t *)pattern,
+					     (cairo_surface_t *)surface,
+					     0, 0, -1, -1,
+					     &pat_surface, &pat_attr);
+    if (status)
+	return status;
+
+    status = _cairo_surface_acquire_source_image (pat_surface, &image, &image_extra);
+    if (status)
+	goto FINISH;
+
+    if (image->base.status) {
+	status = image->base.status;
+	goto FINISH2;
+    }
+
+    if (image->format != CAIRO_FORMAT_RGB24) {
+	opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+						     image->width,
+						     image->height);
+	if (opaque_surface->status) {
+	    status = opaque_surface->status;
+	    goto FINISH3;
+	}
+
+	_cairo_pattern_init_for_surface (&opaque_pattern.surface, &image->base);
+
+	status = _cairo_surface_fill_rectangle (opaque_surface,
+				                CAIRO_OPERATOR_SOURCE,
+						CAIRO_COLOR_WHITE,
+						0, 0,
+						image->width, image->height);
+	if (status) {
+	    _cairo_pattern_fini (&opaque_pattern.base);
+	    goto FINISH3;
+	}
+
+	status = _cairo_surface_composite (CAIRO_OPERATOR_OVER,
+				           &opaque_pattern.base,
+					   NULL,
+					   opaque_surface,
+					   0, 0,
+					   0, 0,
+					   0, 0,
+					   image->width,
+					   image->height);
+	if (status) {
+	    _cairo_pattern_fini (&opaque_pattern.base);
+	    goto FINISH3;
+	}
+
+	_cairo_pattern_fini (&opaque_pattern.base);
+	opaque_image = (cairo_image_surface_t *) opaque_surface;
+    } else {
+	opaque_surface = &image->base;
+	opaque_image = image;
+    }
+
+    bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    bi.bmiHeader.biWidth = opaque_image->width;
+    bi.bmiHeader.biHeight = -opaque_image->height;
+    bi.bmiHeader.biSizeImage = 0;
+    bi.bmiHeader.biXPelsPerMeter = PELS_72DPI;
+    bi.bmiHeader.biYPelsPerMeter = PELS_72DPI;
+    bi.bmiHeader.biPlanes = 1;
+    bi.bmiHeader.biBitCount = 32;
+    bi.bmiHeader.biCompression = BI_RGB;
+    bi.bmiHeader.biClrUsed = 0;
+    bi.bmiHeader.biClrImportant = 0;
+
+    m = pattern->base.matrix;
+    cairo_matrix_invert (&m);
+
+    SaveDC (surface->dc);
+    SetGraphicsMode (surface->dc, GM_ADVANCED);
+    _cairo_matrix_to_win32_xform (&m, &xform);
+
+    if (!SetWorldTransform (surface->dc, &xform))
+	return _cairo_win32_print_gdi_error ("_win32_scaled_font_set_world_transform");
+
+    oldmode = SetStretchBltMode(surface->dc, HALFTONE);
+
+    GetClipBox (surface->dc, &clip);
+    if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) {
+	left = (int) floor((double)clip.left/opaque_image->width);
+	right = (int) ceil((double)clip.right/opaque_image->width);
+	top = (int) floor((double)clip.top/opaque_image->height);
+	bottom = (int) ceil((double)clip.bottom/opaque_image->height);
+    } else {
+	left = 0;
+	right = 1;
+	top = 0;
+	bottom = 1;
+    }
+
+    for (y_tile = top; y_tile < bottom; y_tile++) {
+	for (x_tile = left; x_tile < right; x_tile++) {
+	    if (!StretchDIBits (surface->dc,
+				x_tile*opaque_image->width,
+				y_tile*opaque_image->height,
+				opaque_image->width,
+				opaque_image->height,
+				0,
+				0,
+				opaque_image->width,
+				opaque_image->height,
+				opaque_image->data,
+				&bi,
+				DIB_RGB_COLORS,
+				SRCCOPY))
+		return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint(StretchDIBits)");
+	}
+    }
+    SetStretchBltMode(surface->dc, oldmode);
+    RestoreDC (surface->dc, -1);
+
+FINISH3:
+    if (opaque_image != image)
+	cairo_surface_destroy (opaque_surface);
+FINISH2:
+    _cairo_surface_release_source_image (pat_surface, image, image_extra);
+FINISH:
+    _cairo_pattern_release_surface ((cairo_pattern_t *)pattern, pat_surface, &pat_attr);
+
+    return status;
+}
+
+static void
+vertex_set_color (TRIVERTEX *vert, cairo_color_t *color)
+{
+    vert->Alpha = 0xffff;
+    vert->Red   = color->red_short;
+    vert->Green = color->green_short;
+    vert->Blue  = color->blue_short;
+}
+
+static cairo_int_status_t
+_cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surface,
+                                                    cairo_linear_pattern_t *pattern)
+{
+    TRIVERTEX *vert;
+    GRADIENT_RECT *rect;
+    RECT clip;
+    XFORM xform;
+    int i, num_stops;
+    cairo_matrix_t mat, rot;
+    double p1x, p1y, p2x, p2y, xd, yd, d, sn, cs;
+    cairo_extend_t extend;
+    int range_start, range_stop, num_ranges, num_rects, stop;
+    int total_verts, total_rects;
+
+    extend = cairo_pattern_get_extend (&pattern->base.base);
+    SaveDC (surface->dc);
+
+    mat = pattern->base.base.matrix;
+    cairo_matrix_invert (&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);
+    p2y = _cairo_fixed_to_double (pattern->p2.y);
+    cairo_matrix_translate (&mat, p1x, p1y);
+
+    xd = p2x - p1x;
+    yd = p2y - p1y;
+    d = sqrt (xd*xd + yd*yd);
+    sn = yd/d;
+    cs = xd/d;
+    cairo_matrix_init (&rot,
+		       cs, sn,
+		       -sn, cs,
+		        0, 0);
+    cairo_matrix_multiply (&mat, &rot, &mat);
+
+    _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);
+    p1x = 0.0;
+    p1y = 0.0;
+    p2x = d;
+    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);
+    } else {
+	range_start = 0;
+	range_stop = 1;
+    }
+    num_ranges = range_stop - range_start;
+    num_stops = pattern->base.n_stops;
+    num_rects = num_stops - 1;
+
+    /* Add an extra four points and two rectangles for EXTEND_PAD */
+    vert = malloc (sizeof (TRIVERTEX) * (num_rects*2*num_ranges + 4));
+    rect = malloc (sizeof (GRADIENT_RECT) * (num_rects*num_ranges + 2));
+
+    for (i = 0; i < num_ranges*num_rects; i++) {
+	vert[i*2].y = (LONG) clip.top;
+	if (i%num_rects == 0) {
+	    stop = 0;
+	    if (extend == CAIRO_EXTEND_REFLECT && (range_start+(i/num_rects))%2)
+		stop = num_rects;
+	    vert[i*2].x = (LONG)(d*(range_start + i/num_rects));
+	    vertex_set_color (&vert[i*2], &pattern->base.stops[stop].color);
+	} else {
+	    vert[i*2].x = vert[i*2-1].x;
+	    vert[i*2].Red = vert[i*2-1].Red;
+	    vert[i*2].Green = vert[i*2-1].Green;
+	    vert[i*2].Blue = vert[i*2-1].Blue;
+	    vert[i*2].Alpha = vert[i*2-1].Alpha;
+	}
+
+	stop = i%num_rects + 1;
+	vert[i*2+1].x = (LONG)(d*(range_start + i/num_rects + _cairo_fixed_to_double (pattern->base.stops[stop].x)));
+	vert[i*2+1].y = (LONG) clip.bottom;
+	if (extend == CAIRO_EXTEND_REFLECT && (range_start+(i/num_rects))%2)
+	    stop = num_rects - stop;
+	vertex_set_color (&vert[i*2+1], &pattern->base.stops[stop].color);
+
+	rect[i].UpperLeft = i*2;
+	rect[i].LowerRight = i*2 + 1;
+    }
+    total_verts = 2*num_ranges*num_rects;
+    total_rects = num_ranges*num_rects;
+
+    if (extend == CAIRO_EXTEND_PAD) {
+	vert[i*2].x = vert[i*2-1].x;
+	vert[i*2].y = (LONG) clip.top;
+	vert[i*2].Red = vert[i*2-1].Red;
+	vert[i*2].Green = vert[i*2-1].Green;
+	vert[i*2].Blue = vert[i*2-1].Blue;
+	vert[i*2].Alpha = 0xff00;
+	vert[i*2+1].x = clip.right;
+	vert[i*2+1].y = (LONG) clip.bottom;
+	vert[i*2+1].Red = vert[i*2-1].Red;
+	vert[i*2+1].Green = vert[i*2-1].Green;
+	vert[i*2+1].Blue = vert[i*2-1].Blue;
+	vert[i*2+1].Alpha = 0xff00;
+	rect[i].UpperLeft = i*2;
+	rect[i].LowerRight = i*2 + 1;
+
+	i++;
+
+	vert[i*2].x = clip.left;
+	vert[i*2].y = (LONG) clip.top;
+	vert[i*2].Red = vert[0].Red;
+	vert[i*2].Green = vert[0].Green;
+	vert[i*2].Blue = vert[0].Blue;
+	vert[i*2].Alpha = 0xff00;
+	vert[i*2+1].x = vert[0].x;
+	vert[i*2+1].y = (LONG) clip.bottom;
+	vert[i*2+1].Red = vert[0].Red;
+	vert[i*2+1].Green = vert[0].Green;
+	vert[i*2+1].Blue = vert[0].Blue;
+	vert[i*2+1].Alpha = 0xff00;
+	rect[i].UpperLeft = i*2;
+	rect[i].LowerRight = i*2 + 1;
+
+	total_verts += 4;
+	total_rects += 2;
+    }
+
+    if (!GradientFill (surface->dc,
+		       vert, total_verts,
+		       rect, total_rects,
+		       GRADIENT_FILL_RECT_H))
+	return _cairo_win32_print_gdi_error ("_win32_printing_surface_paint_linear_pattern:GradientFill");
+
+    free (rect);
+    free (vert);
+    RestoreDC (surface->dc, -1);
+
+    return 0;
+}
+
+static cairo_int_status_t
+_cairo_win32_printing_surface_paint_pattern (cairo_win32_surface_t *surface,
+                                             cairo_pattern_t       *pattern)
+{
+    cairo_status_t status;
+
+    switch (pattern->type) {
+    case CAIRO_PATTERN_TYPE_SOLID:
+	status = _cairo_win32_printing_surface_paint_solid_pattern (surface, pattern);
+	if (status)
+	    return status;
+	break;
+
+    case CAIRO_PATTERN_TYPE_SURFACE:
+	status = _cairo_win32_printing_surface_paint_surface_pattern (surface,
+                                                                      (cairo_surface_pattern_t *) pattern);
+	if (status)
+	    return status;
+	break;
+
+    case CAIRO_PATTERN_TYPE_LINEAR:
+	status = _cairo_win32_printing_surface_paint_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
+	if (status)
+	    return status;
+	break;
+
+    case CAIRO_PATTERN_TYPE_RADIAL:
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+	break;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+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
+_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;
+
+    MoveToEx (path_info->surface->dc,
+	      _cairo_fixed_integer_part (point->x),
+	      _cairo_fixed_integer_part (point->y),
+	      NULL);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_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));
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_printing_surface_path_curve_to (void          *closure,
+                                             cairo_point_t *b,
+                                             cairo_point_t *c,
+                                             cairo_point_t *d)
+{
+    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);
+    PolyBezierTo (path_info->surface->dc, points, 3);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_printing_surface_path_close_path (void *closure)
+{
+    win32_path_info_t *path_info = closure;
+
+    CloseFigure (path_info->surface->dc);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_printing_surface_emit_path (cairo_win32_surface_t *surface,
+                                         cairo_path_fixed_t    *path)
+{
+    win32_path_info_t path_info;
+    cairo_status_t status;
+
+    path_info.surface = surface;
+    status = _cairo_path_fixed_interpret (path,
+					  CAIRO_DIRECTION_FORWARD,
+					  _cairo_win32_printing_surface_path_move_to,
+					  _cairo_win32_printing_surface_path_line_to,
+					  _cairo_win32_printing_surface_path_curve_to,
+					  _cairo_win32_printing_surface_path_close_path,
+					  &path_info);
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_win32_printing_surface_show_page (void *abstract_surface)
+{
+    cairo_win32_surface_t *surface = abstract_surface;
+
+    if (surface->clip_saved_dc != 0)
+	RestoreDC (surface->dc, surface->clip_saved_dc);
+    RestoreDC (surface->dc, -1);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_win32_printing_surface_intersect_clip_path (void		      *abstract_surface,
+                                                   cairo_path_fixed_t *path,
+                                                   cairo_fill_rule_t   fill_rule,
+                                                   double	       tolerance,
+                                                   cairo_antialias_t   antialias)
+{
+    cairo_win32_surface_t *surface = abstract_surface;
+    cairo_status_t status;
+
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+	return CAIRO_STATUS_SUCCESS;
+
+    if (path == NULL) {
+	if (surface->clip_saved_dc != 0) {
+	    RestoreDC (surface->dc, surface->clip_saved_dc);
+	    surface->clip_saved_dc = 0;
+	}
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    BeginPath (surface->dc);
+    status = _cairo_win32_printing_surface_emit_path (surface, path);
+    EndPath (surface->dc);
+
+    switch (fill_rule) {
+    case CAIRO_FILL_RULE_WINDING:
+	SetPolyFillMode (surface->dc, WINDING);
+	break;
+    case CAIRO_FILL_RULE_EVEN_ODD:
+	SetPolyFillMode (surface->dc, ALTERNATE);
+	break;
+    default:
+	ASSERT_NOT_REACHED;
+    }
+
+    if (surface->clip_saved_dc == 0)
+	surface->clip_saved_dc = SaveDC (surface->dc);
+    SelectClipPath (surface->dc, RGN_AND);
+
+    return status;
+}
+
+static void
+_cairo_win32_printing_surface_get_font_options (void                  *abstract_surface,
+                                                cairo_font_options_t  *options)
+{
+    _cairo_font_options_init_default (options);
+
+    cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
+    cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
+    cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
+}
+
+static cairo_int_status_t
+_cairo_win32_printing_surface_paint (void             *abstract_surface,
+                                     cairo_operator_t  op,
+                                     cairo_pattern_t  *source)
+{
+    cairo_win32_surface_t *surface = abstract_surface;
+    cairo_solid_pattern_t white;
+
+    if (op == CAIRO_OPERATOR_CLEAR) {
+	_cairo_pattern_init_solid (&white, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR);
+	source = (cairo_pattern_t*) &white;
+	op = CAIRO_OPERATOR_SOURCE;
+    }
+
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+	return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
+
+    assert (_cairo_win32_printing_surface_operation_supported (surface, op, source));
+
+    return _cairo_win32_printing_surface_paint_pattern (surface, source);
+}
+
+static int
+_cairo_win32_line_cap (cairo_line_cap_t cap)
+{
+    switch (cap) {
+    case CAIRO_LINE_CAP_BUTT:
+	return PS_ENDCAP_FLAT;
+    case CAIRO_LINE_CAP_ROUND:
+	return PS_ENDCAP_ROUND;
+    case CAIRO_LINE_CAP_SQUARE:
+	return PS_ENDCAP_SQUARE;
+    default:
+	ASSERT_NOT_REACHED;
+	return 0;
+    }
+}
+
+static int
+_cairo_win32_line_join (cairo_line_join_t join)
+{
+    switch (join) {
+    case CAIRO_LINE_JOIN_MITER:
+	return PS_JOIN_MITER;
+    case CAIRO_LINE_JOIN_ROUND:
+	return PS_JOIN_ROUND;
+    case CAIRO_LINE_JOIN_BEVEL:
+	return PS_JOIN_BEVEL;
+    default:
+	ASSERT_NOT_REACHED;
+	return 0;
+    }
+}
+
+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,
+                                      double       	    tolerance,
+                                      cairo_antialias_t     antialias)
+{
+    cairo_win32_surface_t *surface = abstract_surface;
+    cairo_int_status_t status;
+    HPEN pen;
+    LOGBRUSH brush;
+    COLORREF color;
+    XFORM xform;
+    DWORD pen_style;
+    DWORD *dash_array;
+    HGDIOBJ obj;
+    unsigned int i;
+    cairo_solid_pattern_t white;
+
+    if (op == CAIRO_OPERATOR_CLEAR) {
+	_cairo_pattern_init_solid (&white, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR);
+	source = (cairo_pattern_t*) &white;
+	op = CAIRO_OPERATOR_SOURCE;
+    }
+
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	/* Win32 does not support a dash offset. */
+	if (style->num_dashes > 0 && style->dash_offset != 0.0)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+
+	return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
+    }
+
+    assert (_cairo_win32_printing_surface_operation_supported (surface, op, source));
+
+    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];
+	}
+    } else {
+	pen_style = PS_SOLID;
+    }
+
+    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));
+    } else {
+	/* Color not used as the pen will only be used by WidenPath() */
+	color = RGB (0,0,0);
+    }
+    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 = ExtCreatePen(pen_style,
+		       style->line_width < 1.0 ? 1 : _cairo_lround(style->line_width),
+		       &brush,
+		       style->num_dashes,
+		       dash_array);
+    if (pen == NULL)
+	return _cairo_win32_print_gdi_error ("_win32_surface_stroke:ExtCreatePen");
+    obj = SelectObject (surface->dc, pen);
+    if (obj == NULL)
+	return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectObject");
+
+    BeginPath (surface->dc);
+    status = _cairo_win32_printing_surface_emit_path (surface, path);
+    EndPath (surface->dc);
+    if (status)
+	return status;
+
+    /*
+     * 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;
+
+    if (!SetWorldTransform (surface->dc, &xform))
+	return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SetWorldTransform");
+
+    if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
+	StrokePath (surface->dc);
+    } else {
+	if (!WidenPath (surface->dc))
+	    return _cairo_win32_print_gdi_error ("_win32_surface_stroke:WidenPath");
+	if (!SelectClipPath (surface->dc, RGN_AND))
+	    return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectClipPath");
+
+	/* Return to device space to paint the pattern */
+	if (!ModifyWorldTransform (surface->dc, &xform, MWT_IDENTITY))
+	    return _cairo_win32_print_gdi_error ("_win32_surface_stroke:ModifyWorldTransform");
+	_cairo_win32_printing_surface_paint_pattern (surface, source);
+    }
+    RestoreDC (surface->dc, -1);
+    DeleteObject (pen);
+    if (dash_array)
+	free (dash_array);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_win32_printing_surface_fill (void		        *abstract_surface,
+				    cairo_operator_t	 op,
+				    cairo_pattern_t	*source,
+				    cairo_path_fixed_t	*path,
+				    cairo_fill_rule_t	 fill_rule,
+				    double		 tolerance,
+				    cairo_antialias_t	 antialias)
+{
+    cairo_win32_surface_t *surface = abstract_surface;
+    cairo_int_status_t status;
+    cairo_solid_pattern_t white;
+
+    if (op == CAIRO_OPERATOR_CLEAR) {
+	_cairo_pattern_init_solid (&white, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR);
+	source = (cairo_pattern_t*) &white;
+	op = CAIRO_OPERATOR_SOURCE;
+    }
+
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+	return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
+
+    assert (_cairo_win32_printing_surface_operation_supported (surface, op, source));
+
+    BeginPath (surface->dc);
+    status = _cairo_win32_printing_surface_emit_path (surface, path);
+    EndPath (surface->dc);
+
+    switch (fill_rule) {
+    case CAIRO_FILL_RULE_WINDING:
+	SetPolyFillMode (surface->dc, WINDING);
+	break;
+    case CAIRO_FILL_RULE_EVEN_ODD:
+	SetPolyFillMode (surface->dc, ALTERNATE);
+	break;
+    default:
+	ASSERT_NOT_REACHED;
+    }
+
+    if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
+	_cairo_win32_printing_surface_select_solid_brush (surface, source);
+	FillPath (surface->dc);
+	_cairo_win32_printing_surface_done_solid_brush (surface);
+    } else {
+	SaveDC (surface->dc);
+	SelectClipPath (surface->dc, RGN_AND);
+	_cairo_win32_printing_surface_paint_pattern (surface, source);
+	RestoreDC (surface->dc, -1);
+    }
+
+    fflush(stderr);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_win32_printing_surface_show_glyphs (void                 *abstract_surface,
+                                           cairo_operator_t	 op,
+                                           cairo_pattern_t	*source,
+                                           cairo_glyph_t        *glyphs,
+                                           int			 num_glyphs,
+                                           cairo_scaled_font_t  *scaled_font)
+{
+    cairo_win32_surface_t *surface = abstract_surface;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+    cairo_scaled_glyph_t *scaled_glyph;
+    cairo_pattern_t *opaque = NULL;
+    int i;
+    XFORM xform;
+    cairo_solid_pattern_t white;
+
+    if (op == CAIRO_OPERATOR_CLEAR) {
+	_cairo_pattern_init_solid (&white, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR);
+	source = (cairo_pattern_t*) &white;
+	op = CAIRO_OPERATOR_SOURCE;
+    }
+
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	if (!(cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32 &&
+	      source->type == CAIRO_PATTERN_TYPE_SOLID)) {
+	    for (i = 0; i < num_glyphs; i++) {
+		status = _cairo_scaled_glyph_lookup (scaled_font,
+						     glyphs[i].index,
+						     CAIRO_SCALED_GLYPH_INFO_PATH,
+						     &scaled_glyph);
+		if (status)
+		    return status;
+	    }
+	}
+
+	return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
+    }
+
+    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;
+	}
+
+	opaque = cairo_pattern_create_rgb (c.red, c.green, c.blue);
+	if (opaque->status)
+	    return opaque->status;
+	source = opaque;
+    }
+
+    if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32 &&
+	source->type == CAIRO_PATTERN_TYPE_SOLID)
+    {
+	status = _cairo_win32_surface_show_glyphs (surface, op,
+						   source, glyphs,
+						   num_glyphs, scaled_font);
+	return status;
+    }
+
+    SaveDC (surface->dc);
+    SetGraphicsMode (surface->dc, GM_ADVANCED);
+    xform.eM11 = 1.0f;
+    xform.eM21 = 0.0f;
+    xform.eM12 = 0.0f;
+    xform.eM22 = 1.0f;
+    BeginPath (surface->dc);
+    for (i = 0; i < num_glyphs; i++) {
+	status = _cairo_scaled_glyph_lookup (scaled_font,
+					     glyphs[i].index,
+					     CAIRO_SCALED_GLYPH_INFO_PATH,
+					     &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");
+	status = _cairo_win32_printing_surface_emit_path (surface, scaled_glyph->path);
+    }
+    EndPath (surface->dc);
+    if (status == 0) {
+	SelectClipPath (surface->dc, RGN_AND);
+	_cairo_win32_printing_surface_paint_pattern (surface, source);
+    }
+    RestoreDC (surface->dc, -1);
+
+    if (opaque)
+	cairo_pattern_destroy (opaque);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_win32_printing_surface_start_page (void *abstract_surface)
+{
+    cairo_win32_surface_t *surface = abstract_surface;
+
+    SaveDC (surface->dc);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_win32_printing_surface_set_paginated_mode (void *abstract_surface,
+                                                  cairo_paginated_mode_t paginated_mode)
+{
+    cairo_win32_surface_t *surface = abstract_surface;
+
+    surface->paginated_mode = paginated_mode;
+}
+
+/**
+ * cairo_win32_printing_surface_create:
+ * @hdc: the DC to create a surface for
+ * @ignore_operators: whether operators other than CLEAR and OVER
+ *   should be treated as SOURCE
+ *
+ * Creates a cairo surface that targets the given DC.  The DC will be
+ * queried for its initial clip extents, and this will be used as the
+ * size of the cairo surface.  The DC should be a printing DC;
+ * antialiasing will be ignored, and GDI will be used as much as
+ * 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
+ * associated methods must be used for correct output.
+ *
+ * If ignore_operators is TRUE, the rendering may be incorrect;
+ * however, the chances of hitting fallback code are much reduced.
+ *
+ * Return value: the newly created surface
+ **/
+cairo_surface_t *
+cairo_win32_printing_surface_create (HDC hdc, cairo_bool_t ignore_operators)
+{
+    cairo_win32_surface_t *surface;
+    RECT rect;
+    int xr, yr;
+
+    /* Try to figure out the drawing bounds for the Device context
+     */
+    if (GetClipBox (hdc, &rect) == ERROR) {
+	_cairo_win32_print_gdi_error ("cairo_win32_surface_create");
+	/* XXX: Can we make a more reasonable guess at the error cause here? */
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return NIL_SURFACE;
+    }
+
+    surface = malloc (sizeof (cairo_win32_surface_t));
+    if (surface == NULL) {
+	_cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return NIL_SURFACE;
+    }
+
+    surface->image = NULL;
+    surface->format = CAIRO_FORMAT_RGB24;
+
+    surface->dc = hdc;
+    surface->bitmap = NULL;
+    surface->is_dib = FALSE;
+    surface->saved_dc_bitmap = NULL;
+    surface->brush = NULL;
+    surface->old_brush = NULL;
+
+    surface->clip_rect.x = (int16_t) rect.left;
+    surface->clip_rect.y = (int16_t) rect.top;
+    surface->clip_rect.width = (uint16_t) (rect.right - rect.left);
+    surface->clip_rect.height = (uint16_t) (rect.bottom - rect.top);
+
+    if (surface->clip_rect.width == 0 ||
+	surface->clip_rect.height == 0)
+    {
+	surface->saved_clip = NULL;
+    } else {
+	surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
+	if (GetClipRgn (hdc, surface->saved_clip) == 0) {
+	    DeleteObject(surface->saved_clip);
+	    surface->saved_clip = NULL;
+	}
+    }
+
+    surface->extents = surface->clip_rect;
+
+    surface->flags = _cairo_win32_flags_for_dc (surface->dc);
+    surface->flags |= CAIRO_WIN32_SURFACE_FOR_PRINTING;
+    if (ignore_operators)
+	surface->flags |= CAIRO_WIN32_SURFACE_IGNORE_OPERATORS;
+    surface->clip_saved_dc = 0;
+
+    _cairo_win32_printing_surface_init_ps_mode (surface);
+    _cairo_surface_init (&surface->base, &cairo_win32_printing_surface_backend,
+                         CAIRO_CONTENT_COLOR_ALPHA);
+
+    xr = GetDeviceCaps(hdc, LOGPIXELSX);
+    yr = GetDeviceCaps(hdc, LOGPIXELSY);
+    _cairo_surface_set_resolution (&surface->base, (double) xr, (double) yr);
+
+    return _cairo_paginated_surface_create (&surface->base,
+                                            CAIRO_CONTENT_COLOR_ALPHA,
+                                            rect.right - rect.left,
+                                            rect.bottom - rect.top,
+                                            &cairo_win32_surface_paginated_backend);
+}
+
+cairo_bool_t
+_cairo_surface_is_win32_printing (cairo_surface_t *surface)
+{
+    return surface->backend == &cairo_win32_printing_surface_backend;
+}
+
+static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
+    CAIRO_SURFACE_TYPE_WIN32_PRINTING,
+    _cairo_win32_surface_create_similar,
+    _cairo_win32_surface_finish,
+    NULL, /* acquire_source_image */
+    NULL, /* release_source_image */
+    NULL, /* acquire_dest_image */
+    NULL, /* release_dest_image */
+    _cairo_win32_surface_clone_similar,
+    NULL, /* composite */
+    NULL, /* fill_rectangles */
+    NULL, /* composite_trapezoids */
+    NULL, /* copy_page */
+    _cairo_win32_printing_surface_show_page,
+    NULL, /* set_clip_region */
+    _cairo_win32_printing_surface_intersect_clip_path,
+    _cairo_win32_surface_get_extents,
+    NULL, /* old_show_glyphs */
+    _cairo_win32_printing_surface_get_font_options,
+    NULL, /* flush */
+    NULL, /* mark_dirty_rectangle */
+    NULL, /* scaled_font_fini */
+    NULL, /* scaled_glyph_fini */
+
+    _cairo_win32_printing_surface_paint,
+    NULL, /* mask */
+    _cairo_win32_printing_surface_stroke,
+    _cairo_win32_printing_surface_fill,
+    _cairo_win32_printing_surface_show_glyphs,
+    NULL, /* snapshot */
+    NULL, /* is_similar */
+    NULL, /* reset */
+};
+
+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
+};
diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h
index 5f5d8d0..3410b34 100644
--- a/src/cairo-win32-private.h
+++ b/src/cairo-win32-private.h
@@ -79,10 +79,18 @@ typedef struct _cairo_win32_surface {
 
     /* Surface DC flags */
     uint32_t flags;
+
+    /* printing surface bits */
+    cairo_paginated_mode_t paginated_mode;
+    int clip_saved_dc;
+    HBRUSH brush, old_brush;
 } cairo_win32_surface_t;
 
 /* Surface DC flag values */
 enum {
+    /* If this is a surface created for printing or not */
+    CAIRO_WIN32_SURFACE_FOR_PRINTING = (1<<0),
+
     /* Whether the DC is a display DC or not */
     CAIRO_WIN32_SURFACE_IS_DISPLAY = (1<<1),
 
@@ -96,7 +104,15 @@ enum {
     CAIRO_WIN32_SURFACE_CAN_STRETCHBLT = (1<<4),
 
     /* Whether we can use StretchDIBits with this surface */
-    CAIRO_WIN32_SURFACE_CAN_STRETCHDIB = (1<<5)
+    CAIRO_WIN32_SURFACE_CAN_STRETCHDIB = (1<<5),
+
+    /* Whether we can use GradientFill rectangles with this surface */
+    CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT = (1<<6),
+
+    /* If we should treat all operators other than CLEAR and OVER
+     * like SOURCE to avoid hitting fallback.  Ignored except
+     * for printing. */
+    CAIRO_WIN32_SURFACE_IGNORE_OPERATORS = (1<<7)
 };
 
 cairo_status_t
@@ -105,4 +121,52 @@ _cairo_win32_print_gdi_error (const char
 cairo_bool_t
 _cairo_surface_is_win32 (cairo_surface_t *surface);
 
+cairo_bool_t
+_cairo_surface_is_win32_printing (cairo_surface_t *surface);
+
+cairo_status_t
+_cairo_win32_surface_finish (void *abstract_surface);
+
+cairo_int_status_t
+_cairo_win32_surface_get_extents (void		          *abstract_surface,
+				  cairo_rectangle_int16_t *rectangle);
+
+uint32_t
+_cairo_win32_flags_for_dc (HDC dc);
+
+cairo_int_status_t
+_cairo_win32_surface_show_glyphs (void			*surface,
+				  cairo_operator_t	 op,
+				  cairo_pattern_t	*source,
+				  cairo_glyph_t		*glyphs,
+				  int			 num_glyphs,
+				  cairo_scaled_font_t	*scaled_font);
+
+cairo_surface_t *
+_cairo_win32_surface_create_similar (void	    *abstract_src,
+				     cairo_content_t content,
+				     int	     width,
+				     int	     height);
+
+cairo_status_t
+_cairo_win32_surface_clone_similar (void *abstract_surface,
+				    cairo_surface_t *src,
+				    int src_x,
+				    int src_y,
+				    int width,
+				    int height,
+				    cairo_surface_t **clone_out);
+
+static inline void
+_cairo_matrix_to_win32_xform (const cairo_matrix_t *m,
+                              XFORM *xform)
+{
+    xform->eM11 = (FLOAT) m->xx;
+    xform->eM21 = (FLOAT) m->xy;
+    xform->eM12 = (FLOAT) m->yx;
+    xform->eM22 = (FLOAT) m->yy;
+    xform->eDx = (FLOAT) m->x0;
+    xform->eDy = (FLOAT) m->y0;
+}
+
 #endif /* CAIRO_WIN32_PRIVATE_H */
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 1358670..1b1a2ff 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -108,7 +108,7 @@ _cairo_win32_print_gdi_error (const char
     return CAIRO_STATUS_NO_MEMORY;
 }
 
-static uint32_t
+uint32_t
 _cairo_win32_flags_for_dc (HDC dc)
 {
     uint32_t flags = 0;
@@ -426,7 +426,7 @@ _cairo_win32_surface_create_similar_inte
     return (cairo_surface_t*) new_surf;
 }
 
-static cairo_surface_t *
+cairo_surface_t *
 _cairo_win32_surface_create_similar (void	    *abstract_src,
 				     cairo_content_t content,
 				     int	     width,
@@ -435,7 +435,50 @@ _cairo_win32_surface_create_similar (voi
     return _cairo_win32_surface_create_similar_internal (abstract_src, content, width, height, FALSE);
 }
 
-static cairo_status_t
+cairo_status_t
+_cairo_win32_surface_clone_similar (void *abstract_surface,
+				    cairo_surface_t *src,
+				    int src_x,
+				    int src_y,
+				    int width,
+				    int height,
+				    cairo_surface_t **clone_out)
+{
+    cairo_content_t src_content;
+    cairo_surface_t *new_surface;
+    cairo_status_t status;
+    cairo_pattern_union_t pattern;
+
+    src_content = cairo_surface_get_content(src);
+    new_surface =
+	_cairo_win32_surface_create_similar_internal (abstract_surface, src_content, width, height, FALSE);
+
+    if (cairo_surface_status(new_surface))
+	return cairo_surface_status(new_surface);
+
+    _cairo_pattern_init_for_surface (&pattern.surface, src);
+
+    status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
+				       &pattern.base,
+				       NULL,
+				       new_surface,
+				       src_x, src_y,
+				       0, 0,
+				       0, 0,
+				       width, height);
+
+    _cairo_pattern_fini (&pattern.base);
+
+    if (status == CAIRO_STATUS_SUCCESS)
+	*clone_out = new_surface;
+    else
+	cairo_surface_destroy (new_surface);
+
+    return status;
+}
+
+
+cairo_status_t
 _cairo_win32_surface_finish (void *abstract_surface)
 {
     cairo_win32_surface_t *surface = abstract_surface;
@@ -476,9 +519,7 @@ _cairo_win32_surface_get_subimage (cairo
 
     status = CAIRO_INT_STATUS_UNSUPPORTED;
 
-    /* We are blitting -from- surface, so we need to check if it
-     * supports BitBlt.  I believe any surface can be used as a
-     * BitBlt destination. */
+    /* Only BitBlt if the source surface supports it. */
     if ((surface->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT) &&
 	BitBlt (local->dc,
 		0, 0,
@@ -1474,7 +1515,7 @@ _cairo_win32_surface_set_clip_region (vo
     }
 }
 
-static cairo_int_status_t
+cairo_int_status_t
 _cairo_win32_surface_get_extents (void		          *abstract_surface,
 				  cairo_rectangle_int_t   *rectangle)
 {
@@ -1493,7 +1534,7 @@ _cairo_win32_surface_flush (void *abstra
 
 #define STACK_GLYPH_SIZE 256
 
-static cairo_int_status_t
+cairo_int_status_t
 _cairo_win32_surface_show_glyphs (void			*surface,
 				  cairo_operator_t	 op,
 				  cairo_pattern_t	*source,
@@ -1536,8 +1577,10 @@ _cairo_win32_surface_show_glyphs (void		
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     /* If we have a fallback mask clip set on the dst, we have
-     * to go through the fallback path */
-    if (dst->base.clip &&
+     * to go through the fallback path, but only if we're not
+     * doing this for printing */
+    if (dst->base.clip  &&
+	!(dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) &&
 	(dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
 	 dst->base.clip->surface != NULL))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1692,6 +1735,8 @@ cairo_win32_surface_create (HDC hdc)
     surface->bitmap = NULL;
     surface->is_dib = FALSE;
     surface->saved_dc_bitmap = NULL;
+    surface->brush = NULL;
+    surface->old_brush = NULL;
 
     surface->clip_rect.x = (int16_t) rect.left;
     surface->clip_rect.y = (int16_t) rect.top;
@@ -1713,6 +1758,7 @@ cairo_win32_surface_create (HDC hdc)
     surface->extents = surface->clip_rect;
 
     surface->flags = _cairo_win32_flags_for_dc (surface->dc);
+    surface->clip_saved_dc = 0;
 
     _cairo_surface_init (&surface->base, &cairo_win32_surface_backend,
 			 _cairo_content_from_format (format));
@@ -1807,7 +1853,9 @@ cairo_win32_surface_create_with_ddb (HDC
  * _cairo_surface_is_win32:
  * @surface: a #cairo_surface_t
  *
- * Checks if a surface is an #cairo_win32_surface_t
+ * Checks if a surface is a win32 surface.  This will
+ * return False if this is a win32 printing surface; use
+ * _cairo_surface_is_win32_printing() to check for that.
  *
  * Return value: True if the surface is an win32 surface
  **/
@@ -1833,10 +1881,8 @@ cairo_win32_surface_get_dc (cairo_surfac
 {
     cairo_win32_surface_t *winsurf;
 
-    if (surface == NULL)
-	return NULL;
-
-    if (!_cairo_surface_is_win32(surface))
+    if (!_cairo_surface_is_win32(surface) &&
+	!_cairo_surface_is_win32_printing(surface))
 	return NULL;
 
     winsurf = (cairo_win32_surface_t *) surface;
@@ -1898,7 +1944,7 @@ static const cairo_surface_backend_t cai
     _cairo_win32_surface_release_source_image,
     _cairo_win32_surface_acquire_dest_image,
     _cairo_win32_surface_release_dest_image,
-    NULL, /* clone_similar */
+    _cairo_win32_surface_clone_similar,
     _cairo_win32_surface_composite,
     _cairo_win32_surface_fill_rectangles,
     NULL, /* composite_trapezoids */
diff --git a/src/cairo-win32.h b/src/cairo-win32.h
index 5664386..43ddf12 100644
--- a/src/cairo-win32.h
+++ b/src/cairo-win32.h
@@ -48,6 +48,9 @@ cairo_public cairo_surface_t *
 cairo_win32_surface_create (HDC hdc);
 
 cairo_public cairo_surface_t *
+cairo_win32_printing_surface_create (HDC hdc, cairo_bool_t ignore_operators);
+
+cairo_public cairo_surface_t *
 cairo_win32_surface_create_with_ddb (HDC hdc,
                                      cairo_format_t format,
                                      int width,
diff --git a/src/cairo.h b/src/cairo.h
index 636c417..65d8b36 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1435,6 +1435,7 @@ cairo_surface_status (cairo_surface_t *s
  * @CAIRO_SURFACE_TYPE_DIRECTFB: The surface is of type directfb
  * @CAIRO_SURFACE_TYPE_SVG: The surface is of type svg
  * @CAIRO_SURFACE_TYPE_OS2: The surface is of type os2
+ * @CAIRO_SURFACE_TYPE_WIN32_PRINTING: The surface is a win32 printing surface
  *
  * #cairo_surface_type_t is used to describe the type of a given
  * surface. The surface types are also known as "backends" or "surface
@@ -1471,7 +1472,8 @@ typedef enum _cairo_surface_type {
     CAIRO_SURFACE_TYPE_BEOS,
     CAIRO_SURFACE_TYPE_DIRECTFB,
     CAIRO_SURFACE_TYPE_SVG,
-    CAIRO_SURFACE_TYPE_OS2
+    CAIRO_SURFACE_TYPE_OS2,
+    CAIRO_SURFACE_TYPE_WIN32_PRINTING
 } cairo_surface_type_t;
 
 cairo_public cairo_surface_type_t
diff-tree 284ed91ee4418baf6dd1a437a904980a2156fa48 (from 79d975f84bcc32e91db517d71a7312e2e1d653d4)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Wed Aug 29 15:34:04 2007 -0700

    Let surfaces specify their native resolution, for fallback purposes

diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index ce660d1..04d8452 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -58,6 +58,8 @@ static const cairo_image_surface_t _cair
 	  0.0, 1.0,
 	  0.0, 0.0
 	},				/* device_transform_inverse */
+	0.0,				/* x_resolution */
+	0.0,				/* y_resolution */
 	0.0,				/* x_fallback_resolution */
 	0.0,				/* y_fallback_resolution */
 	NULL,				/* clip */
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 76cf5bb..bf4e341 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -238,8 +238,8 @@ static cairo_int_status_t
 _paint_fallback_image (cairo_paginated_surface_t *surface,
 		       cairo_box_int_t           *box)
 {
-    double x_scale = surface->base.x_fallback_resolution / 72.0;
-    double y_scale = surface->base.y_fallback_resolution / 72.0;
+    double x_scale = surface->base.x_fallback_resolution / surface->base.x_resolution;
+    double y_scale = surface->base.y_fallback_resolution / surface->base.y_resolution;
     cairo_matrix_t matrix;
     int x, y, width, height;
     cairo_status_t status;
diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h
index 6193cf8..a0b50c5 100644
--- a/src/cairo-surface-private.h
+++ b/src/cairo-surface-private.h
@@ -60,6 +60,14 @@ struct _cairo_surface {
     cairo_matrix_t device_transform;
     cairo_matrix_t device_transform_inverse;
 
+    /* The actual resolution of the device, in dots per inch. */
+    double x_resolution;
+    double y_resolution;
+
+    /* The resolution that should be used when generating image-based
+     * fallback; generally only used by the analysis/paginated
+     * surfaces
+     */
     double x_fallback_resolution;
     double y_fallback_resolution;
 
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 2b6553f..e8ed668 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -62,6 +62,8 @@ const cairo_surface_t name = {					\
       0.0, 1.0,							\
       0.0, 0.0							\
     },					/* device_transform_inverse */	\
+    0.0,				/* x_resolution */	\
+    0.0,				/* y_resolution */	\
     0.0,				/* x_fallback_resolution */	\
     0.0,				/* y_fallback_resolution */	\
     NULL,				/* clip */		\
@@ -195,6 +197,9 @@ _cairo_surface_init (cairo_surface_t			*
     cairo_matrix_init_identity (&surface->device_transform);
     cairo_matrix_init_identity (&surface->device_transform_inverse);
 
+    surface->x_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT; 
+    surface->y_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT; 
+
     surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
     surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
 
@@ -2286,5 +2291,24 @@ _cairo_surface_copy_pattern_for_destinat
     return CAIRO_STATUS_SUCCESS;
 }
 
+/**
+ * _cairo_surface_set_resolution
+ * @surface: the surface
+ * @x_res: x resolution, in dpi
+ * @y_res: y resolution, in dpi
+ *
+ * Set the actual surface resolution of @surface to the given x and y DPI.
+ * Mainly used for correctly computing the scale factor when fallback
+ * rendering needs to take place in the paginated surface.
+ */
+void
+_cairo_surface_set_resolution (cairo_surface_t *surface,
+			       double x_res,
+			       double y_res)
+{
+    surface->x_resolution = x_res;
+    surface->y_resolution = y_res;
+}
+
 /*  LocalWords:  rasterized
  */
diff --git a/src/cairoint.h b/src/cairoint.h
index 39cb025..22eb165 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1077,6 +1077,7 @@ typedef struct _cairo_traps {
 #define CAIRO_GSTATE_MITER_LIMIT_DEFAULT	10.0
 #define CAIRO_GSTATE_DEFAULT_FONT_SIZE  10.0
 
+#define CAIRO_SURFACE_RESOLUTION_DEFAULT 72.0
 #define CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT 300.0
 
 typedef struct _cairo_gstate cairo_gstate_t;
@@ -1694,6 +1695,11 @@ cairo_private void
 _cairo_surface_set_error (cairo_surface_t	*surface,
 			  cairo_status_t	 status);
 
+cairo_private void
+_cairo_surface_set_resolution (cairo_surface_t *surface,
+                               double x_res,
+                               double y_res);
+
 cairo_private cairo_surface_t *
 _cairo_surface_create_similar_scratch (cairo_surface_t *other,
 				       cairo_content_t	content,


More information about the cairo-commit mailing list