[cairo-commit] 12 commits - doc/public src/cairo.c src/cairo-clip.c src/cairo-directfb-surface.c src/cairo-ft-font.c src/cairo-glitz-surface.c src/cairo-gstate.c src/cairo.h src/cairoint.h src/cairo-matrix.c src/cairo-paginated-surface.c src/cairo-path.c src/cairo-pdf.h src/cairo-pdf-surface.c src/cairo-ps.h src/cairo-ps-surface.c src/cairo-ps-test.h src/cairo-scaled-font.c src/cairo-surface.c src/cairo-surface-fallback.c src/cairo-svg.h src/cairo-svg-surface.c src/cairo-svg-test.h src/cairo-xlib-surface.c test/cairo-test.c test/fallback-resolution.c test/.gitignore

Carl Worth cworth at kemper.freedesktop.org
Sat Jun 10 10:14:38 PDT 2006


 doc/public/tmpl/cairo-pdf.sgml    |    7 +
 doc/public/tmpl/cairo-ps.sgml     |    7 +
 doc/public/tmpl/cairo-status.sgml |    7 -
 doc/public/tmpl/cairo-svg.sgml    |    7 +
 src/cairo-clip.c                  |   15 +-
 src/cairo-directfb-surface.c      |    5 
 src/cairo-ft-font.c               |   12 -
 src/cairo-glitz-surface.c         |    8 -
 src/cairo-gstate.c                |   13 -
 src/cairo-matrix.c                |    8 +
 src/cairo-paginated-surface.c     |   11 +
 src/cairo-path.c                  |   29 +++-
 src/cairo-pdf-surface.c           |   35 -----
 src/cairo-pdf.h                   |    5 
 src/cairo-ps-surface.c            |   59 +++-----
 src/cairo-ps-test.h               |   54 +++++++
 src/cairo-ps.h                    |    5 
 src/cairo-scaled-font.c           |    5 
 src/cairo-surface-fallback.c      |    3 
 src/cairo-surface.c               |  257 ++++++++++++++++++++++++++++----------
 src/cairo-svg-surface.c           |   62 +++------
 src/cairo-svg-test.h              |   54 +++++++
 src/cairo-svg.h                   |    5 
 src/cairo-xlib-surface.c          |    8 -
 src/cairo.c                       |    4 
 src/cairo.h                       |    8 +
 src/cairoint.h                    |   23 ++-
 test/.gitignore                   |    2 
 test/cairo-test.c                 |    6 
 test/fallback-resolution.c        |  156 ++++++++++++++++++-----
 30 files changed, 602 insertions(+), 278 deletions(-)

New commits:
diff-tree 0662928e4fd7bd432fdd815b95271d5c74eaba70 (from 13ba5316fbc4b9d2aac13da644f4c87069447246)
Author: Carl Worth <cworth at cworth.org>
Date:   Sat Jun 10 09:44:30 2006 -0700

    Clarify that fallback_resolution acts on a per-page granularity.
    
    This explains why the SVG result from the fallback-resolution test
    doesn't actually show multiple resolutions in effect at the same time.

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index ba78c3a..17c2953 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -728,6 +728,11 @@ cairo_surface_get_device_offset (cairo_s
  * still possible, but they are always performed at the native
  * device resolution. So this function has no effect on those
  * backends.
+ *
+ * NOTE: The fallback resolution only takes effect at the time of
+ * completing a page (with cairo_show_page() or cairo_copy_page()) so
+ * there is currently no way to have more than one fallback resolution
+ * in effect on a single page.
  **/
 void
 cairo_surface_set_fallback_resolution (cairo_surface_t	*surface,
diff --git a/test/fallback-resolution.c b/test/fallback-resolution.c
index 407290e..d1e7a63 100644
--- a/test/fallback-resolution.c
+++ b/test/fallback-resolution.c
@@ -125,6 +125,8 @@ main (void)
 
 	    draw (cr, SIZE, SIZE, ppi[page]);
 
+	    cairo_show_page (cr);
+
 	    /* Backend-specific means of "advancing a page" */
 	    switch (backend) {
 	    case PDF:
@@ -132,9 +134,23 @@ main (void)
 		cairo_show_page (cr);
 		break;
 	    case SVG:
+		/* Since the SVG backend doesn't natively support multiple
+		 * pages, we just move further down for each logical
+		 * page, then finally do a show_page at the end. */
 		if (page < num_pages - 1) {
 		    cairo_translate (cr, 0, SIZE);
 		} else {
+		    /* XXX: The goal of this test is to show the
+		     * effect of several different fallback
+		     * resolutions in a single output document. But
+		     * since fallback_resolution only takes effect at
+		     * the time of show_page, we only get once for the
+		     * SVG backend. I'm just re-setting the first one
+		     * here so we actually get legible output.
+		     *
+		     * To fix this properly we'll need some sort of
+		     * multi-page support in the SVG backend I think.
+		     */
 		    cairo_surface_set_fallback_resolution (surface, ppi[0], ppi[0]);
 		    cairo_show_page (cr);
 		}
diff-tree 13ba5316fbc4b9d2aac13da644f4c87069447246 (from 6ca30e108f32862948fa332b31f60fa79b566d77)
Author: Carl Worth <cworth at cworth.org>
Date:   Sat Jun 10 09:15:31 2006 -0700

    Test PS and SVG backends in addition to PDF in test/fallback-resolution.

diff --git a/test/.gitignore b/test/.gitignore
index 729aaef..fb87f06 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -26,6 +26,8 @@ device-offset
 extend-reflect
 fallback-resolution
 fallback-resolution.pdf
+fallback-resolution.ps
+fallback-resolution.svg
 fill-and-stroke
 fill-and-stroke-alpha
 fill-and-stroke-alpha-add
diff --git a/test/fallback-resolution.c b/test/fallback-resolution.c
index d3ab6c7..407290e 100644
--- a/test/fallback-resolution.c
+++ b/test/fallback-resolution.c
@@ -25,9 +25,16 @@
 
 #include <stdio.h>
 #include <cairo.h>
+
 #include <cairo-pdf.h>
 #include <cairo-pdf-test.h>
 
+#include <cairo-ps.h>
+#include <cairo-ps-test.h>
+
+#include <cairo-svg.h>
+#include <cairo-svg-test.h>
+
 #include "cairo-test.h"
 
 /* This test exists to test cairo_surface_set_fallback_resolution
@@ -65,48 +72,91 @@ draw (cairo_t *cr, double width, double 
     cairo_restore (cr);
 }
 
+#define NUM_BACKENDS 3
+typedef enum {
+    PDF, PS, SVG
+} backend_t;
+static const char *backend_filename[NUM_BACKENDS] = {
+    "fallback-resolution.pdf",
+    "fallback-resolution.ps",
+    "fallback-resolution.svg"
+};
+
 int
 main (void)
 {
     cairo_surface_t *surface;
     cairo_t *cr;
     cairo_status_t status;
-    char *filename;
     double ppi[] = { 600., 300., 150., 75., 37.5 };
-    int i;
-
-    printf("\n");
-
-    filename = "fallback-resolution.pdf";
+    backend_t backend;
+    int page, num_pages;
 
-    surface = cairo_pdf_surface_create (filename, SIZE, SIZE);
+    num_pages = sizeof (ppi) / sizeof (ppi[0]);
 
-    cr = cairo_create (surface);
-
-    /* Force image fallbacks before drawing anything. */
-    cairo_pdf_test_force_fallbacks ();
-
-    for (i = 0; i < sizeof(ppi) / sizeof (ppi[0]); i++)
-    {
-	cairo_surface_set_fallback_resolution (surface, ppi[i], ppi[i]);
-
-	draw (cr, SIZE, SIZE, ppi[i]);
-
-	cairo_show_page (cr);
-    }
+    printf("\n");
 
-    status = cairo_status (cr);
+    for (backend=0; backend < NUM_BACKENDS; backend++) {
 
-    cairo_destroy (cr);
-    cairo_surface_destroy (surface);
+	/* Create backend-specific surface and force image fallbacks. */
+	switch (backend) {
+	case PDF:
+	    surface = cairo_pdf_surface_create (backend_filename[backend],
+						SIZE, SIZE);
+	    cairo_pdf_test_force_fallbacks ();
+	    break;
+	case PS:
+	    surface = cairo_ps_surface_create (backend_filename[backend],
+					       SIZE, SIZE);
+	    cairo_ps_test_force_fallbacks ();
+	    break;
+	case SVG:
+	    surface = cairo_svg_surface_create (backend_filename[backend],
+						SIZE, SIZE * num_pages);
+	    cairo_svg_test_force_fallbacks ();
+	    break;
+	}
+
+	cr = cairo_create (surface);
+
+	for (page = 0; page < num_pages; page++)
+	{
+	    cairo_surface_set_fallback_resolution (surface, ppi[page], ppi[page]);
+
+	    draw (cr, SIZE, SIZE, ppi[page]);
+
+	    /* Backend-specific means of "advancing a page" */
+	    switch (backend) {
+	    case PDF:
+	    case PS:
+		cairo_show_page (cr);
+		break;
+	    case SVG:
+		if (page < num_pages - 1) {
+		    cairo_translate (cr, 0, SIZE);
+		} else {
+		    cairo_surface_set_fallback_resolution (surface, ppi[0], ppi[0]);
+		    cairo_show_page (cr);
+		}
+		break;
+	    }
+	}
+
+	status = cairo_status (cr);
+
+	cairo_destroy (cr);
+	cairo_surface_destroy (surface);
+
+	if (status) {
+	    cairo_test_log ("Failed to create pdf surface for file %s: %s\n",
+			    backend_filename[backend],
+			    cairo_status_to_string (status));
+	    return CAIRO_TEST_FAILURE;
+	}
 
-    if (status) {
-	cairo_test_log ("Failed to create pdf surface for file %s: %s\n",
-			filename, cairo_status_to_string (status));
-	return CAIRO_TEST_FAILURE;
+	printf ("fallback-resolution: Please check %s to ensure it looks correct.\n",
+		backend_filename[backend]);
     }
 
-    printf ("fallback-resolution: Please check %s to ensure it looks correct.\n", filename);
-
     return CAIRO_TEST_SUCCESS;
 }
diff-tree 6ca30e108f32862948fa332b31f60fa79b566d77 (from 100b30d1c09cb7fe73414c4d3466032a8c99b088)
Author: Carl Worth <cworth at cworth.org>
Date:   Sat Jun 10 09:14:47 2006 -0700

    Add cairo_{ps,svg}_test_force_fallbacks so tests can force fallbacks.

diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 4e019e1..a621670 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -39,6 +39,7 @@
 
 #include "cairoint.h"
 #include "cairo-ps.h"
+#include "cairo-ps-test.h"
 #include "cairo-scaled-font-subsets-private.h"
 #include "cairo-paginated-surface-private.h"
 #include "cairo-meta-surface-private.h"
@@ -1033,11 +1034,34 @@ pattern_supported (const cairo_pattern_t
     return FALSE;
 }
 
+static cairo_bool_t cairo_ps_force_fallbacks = FALSE;
+
+/**
+ * cairo_ps_test_force_fallbacks
+ *
+ * Force the PS surface backend to use image fallbacks for every
+ * operation.
+ *
+ * <note>
+ * This function is <emphasis>only</emphasis> intended for internal
+ * testing use within the cairo distribution. It is not installed in
+ * any public header file.
+ * </note>
+ **/
+void
+cairo_ps_test_force_fallbacks (void)
+{
+    cairo_ps_force_fallbacks = TRUE;
+}
+
 static cairo_int_status_t
 operation_supported (cairo_ps_surface_t *surface,
 		      cairo_operator_t op,
 		      const cairo_pattern_t *pattern)
 {
+    if (cairo_ps_force_fallbacks)
+	return FALSE;
+
     if (! pattern_supported (pattern))
 	return FALSE;
 
diff --git a/src/cairo-ps-test.h b/src/cairo-ps-test.h
new file mode 100644
index 0000000..724ca46
--- /dev/null
+++ b/src/cairo-ps-test.h
@@ -0,0 +1,54 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2006 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 University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Carl D. Worth <cworth at cworth.org>
+ */
+
+#ifndef CAIRO_PS_TEST_H
+#define CAIRO_PS_TEST_H
+
+#include <cairo.h>
+
+#if CAIRO_HAS_PS_SURFACE
+
+#include <cairo-ps.h>
+
+CAIRO_BEGIN_DECLS
+
+void
+cairo_ps_test_force_fallbacks (void);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_HAS_PS_SURFACE */
+#endif /* CAIRO_PS_TEST_H */
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 73d119b..c1bcd96 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -40,6 +40,7 @@
 
 #include "cairoint.h"
 #include "cairo-svg.h"
+#include "cairo-svg-test.h"
 #include "cairo-path-fixed-private.h"
 #include "cairo-ft-private.h"
 #include "cairo-meta-surface-private.h"
@@ -615,6 +616,26 @@ _cairo_svg_document_emit_font_subsets (c
     document->font_subsets = NULL;
 }
 
+static cairo_bool_t cairo_svg_force_fallbacks = FALSE;
+
+/**
+ * cairo_svg_test_force_fallbacks
+ *
+ * Force the SVG surface backend to use image fallbacks for every
+ * operation.
+ *
+ * <note>
+ * This function is <emphasis>only</emphasis> intended for internal
+ * testing use within the cairo distribution. It is not installed in
+ * any public header file.
+ * </note>
+ **/
+void
+cairo_svg_test_force_fallbacks (void)
+{
+    cairo_svg_force_fallbacks = TRUE;
+}
+
 static cairo_int_status_t
 _operation_supported (cairo_svg_surface_t *surface,
 		      cairo_operator_t op,
@@ -622,6 +643,9 @@ _operation_supported (cairo_svg_surface_
 {
     cairo_svg_document_t *document = surface->document;
 
+    if (cairo_svg_force_fallbacks)
+	return FALSE;
+
     if (document->svg_version < CAIRO_SVG_VERSION_1_2)
 	if (op != CAIRO_OPERATOR_OVER)
 	    return FALSE;
diff --git a/src/cairo-svg-test.h b/src/cairo-svg-test.h
new file mode 100644
index 0000000..c8ed063
--- /dev/null
+++ b/src/cairo-svg-test.h
@@ -0,0 +1,54 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2006 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 University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Carl D. Worth <cworth at cworth.org>
+ */
+
+#ifndef CAIRO_SVG_TEST_H
+#define CAIRO_SVG_TEST_H
+
+#include <cairo.h>
+
+#if CAIRO_HAS_SVG_SURFACE
+
+#include <cairo-svg.h>
+
+CAIRO_BEGIN_DECLS
+
+void
+cairo_svg_test_force_fallbacks (void);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_HAS_SVG_SURFACE */
+#endif /* CAIRO_SVG_TEST_H */
diff-tree 100b30d1c09cb7fe73414c4d3466032a8c99b088 (from 74857181c96c734d7e735cfc9862e22b01599913)
Author: Carl Worth <cworth at cworth.org>
Date:   Sat Jun 10 08:35:01 2006 -0700

    Fix font size when drawing text with a device_scale.
    
    The trick is to create a new scaled_font with the device_transform
    multiplied into the CTM within _cairo_surface_show_glyphs before
    calling into the backend. The fallback-resolution test shows that
    the font size is now correct.

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index e570e50..ba78c3a 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1675,6 +1675,7 @@ _cairo_surface_show_glyphs (cairo_surfac
 {
     cairo_status_t status;
     cairo_glyph_t *dev_glyphs = (cairo_glyph_t*) glyphs;
+    cairo_scaled_font_t *dev_scaled_font = scaled_font;
     cairo_pattern_union_t dev_source;
 
     assert (! surface->is_snapshot);
@@ -1686,11 +1687,20 @@ _cairo_surface_show_glyphs (cairo_surfac
     if (_cairo_surface_has_device_transform (surface))
     {
         int i;
+	cairo_font_options_t *font_options;
+	cairo_matrix_t font_matrix, dev_ctm;
 
         dev_glyphs = malloc (sizeof(cairo_glyph_t) * num_glyphs);
         if (!dev_glyphs)
             return CAIRO_STATUS_NO_MEMORY;
 
+	font_options = cairo_font_options_create ();
+	status = cairo_font_options_status(font_options);
+	if (status) {
+	    free (dev_glyphs);
+	    return status;
+	}
+
         for (i = 0; i < num_glyphs; i++) {
             dev_glyphs[i].index = glyphs[i].index;
             dev_glyphs[i].x = glyphs[i].x;
@@ -1699,24 +1709,37 @@ _cairo_surface_show_glyphs (cairo_surfac
 					  &dev_glyphs[i].x,
 					  &dev_glyphs[i].y);
         }
+
+	cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix),
+	cairo_scaled_font_get_ctm (scaled_font, &dev_ctm);
+	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &surface->device_transform);
+	cairo_scaled_font_get_font_options (scaled_font, font_options);
+	dev_scaled_font = cairo_scaled_font_create (cairo_scaled_font_get_font_face (scaled_font),
+						    &font_matrix,
+						    &dev_ctm,
+						    font_options);
+	cairo_font_options_destroy (font_options);
     }
 
     if (surface->backend->show_glyphs) {
 	status = surface->backend->show_glyphs (surface, op, &dev_source.base,
 						dev_glyphs, num_glyphs,
-                                                scaled_font);
+                                                dev_scaled_font);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
             goto FINISH;
     }
 
     status = _cairo_surface_fallback_show_glyphs (surface, op, &dev_source.base,
                                                   dev_glyphs, num_glyphs,
-                                                  scaled_font);
+                                                  dev_scaled_font);
 
 FINISH:
     if (dev_glyphs != glyphs)
         free (dev_glyphs);
 
+    if (dev_scaled_font != scaled_font)
+	cairo_scaled_font_destroy (dev_scaled_font);
+
     return status;
 }
 
diff-tree 74857181c96c734d7e735cfc9862e22b01599913 (from ebb53b2572cc74f90d2afd03807b7d4f41a4965a)
Author: Carl Worth <cworth at cworth.org>
Date:   Sat Jun 10 08:29:14 2006 -0700

    Fix line width for stroking with a device_scale.
    
    The trick is to simply multiply the device_transform into the CTM
    within _cairo_surface_stroke before passing the CTM down to the
    backend. The fallback-resolution test shows that the stroke width is
    now correct.

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 41ac654..e570e50 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1205,6 +1205,8 @@ _cairo_surface_stroke (cairo_surface_t		
     cairo_pattern_union_t dev_source;
     cairo_path_fixed_t *dev_path = path;
     cairo_path_fixed_t real_dev_path;
+    cairo_matrix_t dev_ctm = *ctm;
+    cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
 
     assert (! surface->is_snapshot);
 
@@ -1212,16 +1214,23 @@ _cairo_surface_stroke (cairo_surface_t		
 
     if (_cairo_surface_has_device_transform (surface))
     {
+	cairo_matrix_t tmp;
         _cairo_path_fixed_init_copy (&real_dev_path, path);
         _cairo_path_fixed_device_transform (&real_dev_path,
 					    &surface->device_transform);
         dev_path = &real_dev_path;
+
+	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &surface->device_transform);
+	tmp = surface->device_transform;
+	status = cairo_matrix_invert (&tmp);
+	assert (status == CAIRO_STATUS_SUCCESS);
+	cairo_matrix_multiply (&dev_ctm_inverse, &tmp, &dev_ctm_inverse);
     }
 
     if (surface->backend->stroke) {
 	status = surface->backend->stroke (surface, op, &dev_source.base,
 					   dev_path, stroke_style,
-					   ctm, ctm_inverse,
+					   &dev_ctm, &dev_ctm_inverse,
 					   tolerance, antialias);
 
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
@@ -1230,7 +1239,7 @@ _cairo_surface_stroke (cairo_surface_t		
 
     status = _cairo_surface_fallback_stroke (surface, op, &dev_source.base,
                                              dev_path, stroke_style,
-                                             ctm, ctm_inverse,
+                                             &dev_ctm, &dev_ctm_inverse,
                                              tolerance, antialias);
 
  FINISH:
diff-tree ebb53b2572cc74f90d2afd03807b7d4f41a4965a (from 6efeb1e19b4c30d6a88bd9248a1d67b791b8df0d)
Author: Carl Worth <cworth at cworth.org>
Date:   Sat Jun 10 08:21:18 2006 -0700

    Add text and stroke to falback-resolution test (showing bugs in each).

diff --git a/test/fallback-resolution.c b/test/fallback-resolution.c
index 421755d..d3ab6c7 100644
--- a/test/fallback-resolution.c
+++ b/test/fallback-resolution.c
@@ -36,6 +36,35 @@
 #define INCHES_TO_POINTS(in) ((in) * 72.0)
 #define SIZE INCHES_TO_POINTS(1)
 
+static void
+draw (cairo_t *cr, double width, double height, double ppi)
+{
+    char message[80];
+
+    cairo_save (cr);
+
+    cairo_new_path (cr);
+
+    cairo_set_line_width (cr, .05 * SIZE / 2.0);
+    cairo_arc (cr, SIZE / 2.0, SIZE / 2.0,
+	       0.75 * SIZE / 2.0,
+	       0, 2.0 * M_PI);
+    cairo_stroke (cr);
+
+    cairo_arc (cr, SIZE / 2.0, SIZE / 2.0,
+	       0.6 * SIZE / 2.0,
+	       0, 2.0 * M_PI);
+    cairo_fill (cr);
+
+    cairo_move_to (cr, .4 * SIZE/2.0, SIZE/2.0);
+    sprintf (message, "Fallback PPI: %g", ppi);
+    cairo_set_source_rgb (cr, 1, 1, 1); /* white */
+    cairo_set_font_size (cr, .1 * SIZE / 2.0);
+    cairo_show_text (cr, message);
+
+    cairo_restore (cr);
+}
+
 int
 main (void)
 {
@@ -43,7 +72,7 @@ main (void)
     cairo_t *cr;
     cairo_status_t status;
     char *filename;
-    double dpi[] = { 37.5, 75., 150., 300., 600. };
+    double ppi[] = { 600., 300., 150., 75., 37.5 };
     int i;
 
     printf("\n");
@@ -57,12 +86,11 @@ main (void)
     /* Force image fallbacks before drawing anything. */
     cairo_pdf_test_force_fallbacks ();
 
-    for (i = 0; i < sizeof(dpi) / sizeof (dpi[0]); i++) {
-	cairo_surface_set_fallback_resolution (surface, dpi[i], dpi[i]);
-	cairo_arc (cr, SIZE / 2.0, SIZE / 2.0,
-		   0.75 * SIZE / 2.0,
-		   0, 2.0 * M_PI);
-	cairo_fill (cr);
+    for (i = 0; i < sizeof(ppi) / sizeof (ppi[0]); i++)
+    {
+	cairo_surface_set_fallback_resolution (surface, ppi[i], ppi[i]);
+
+	draw (cr, SIZE, SIZE, ppi[i]);
 
 	cairo_show_page (cr);
     }
diff-tree 6efeb1e19b4c30d6a88bd9248a1d67b791b8df0d (from b129f747c5c7edc37982f286940d3583c74cfee9)
Author: Carl Worth <cworth at cworth.org>
Date:   Sat Jun 10 08:19:41 2006 -0700

    Hook up device scaling so fallback_resolution starts working.
    
    Add new, private _cairo_surface_set_device_scale for getting at the
    scaling components of device_transform. Use this in paginated surface
    when replaying to an image surface. The fallback-resolution test now
    clearly shows that image fallback resolution can be controlled by the
    user. Hurrah!

diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index f0ed513..4938b38 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -217,13 +217,20 @@ _paint_page (cairo_paginated_surface_t *
 
     if (_cairo_analysis_surface_has_unsupported (analysis))
     {
+	double x_scale = surface->base.x_fallback_resolution / 72.0;
+	double y_scale = surface->base.y_fallback_resolution / 72.0;
+	cairo_matrix_t matrix;
+
 	image = _cairo_image_surface_create_with_content (surface->content,
-							  surface->width,
-							  surface->height);
+							  surface->width * x_scale,
+							  surface->height * y_scale);
+	_cairo_surface_set_device_scale (image, x_scale, y_scale);
 
 	_cairo_meta_surface_replay (surface->meta, image);
 
 	pattern = cairo_pattern_create_for_surface (image);
+	cairo_matrix_init_scale (&matrix, x_scale, y_scale);
+	cairo_pattern_set_matrix (pattern, &matrix);
 
 	_cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, pattern);
 
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index ad0fe50..41ac654 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -612,6 +612,45 @@ cairo_surface_mark_dirty_rectangle (cair
 }
 
 /**
+ * _cairo_surface_set_device_scale:
+ * @surface: a #cairo_surface_t
+ * @sx: a scale factor in the X direction
+ * @sy: a scale factor in the Y direction
+ *
+ * Private function for setting an extra scale factor to affect all
+ * drawing to a surface. This is used, for example, when replaying a
+ * meta surface to an image fallback intended for an eventual
+ * vector-oriented backend. Since the meta surface will record
+ * coordinates in one backend space, but the image fallback uses a
+ * different backend space, (differing by the fallback resolution
+ * scale factors), we need a scale factor correction.
+ *
+ * Caution: There is no guarantee that a surface with both a
+ * device_scale and a device_offset will be treated in consistent
+ * fashion. So, for now, just don't do that. (And we'll need to
+ * examine this issue in more detail if we were to ever want to export
+ * support for device scaling.)
+ **/
+void
+_cairo_surface_set_device_scale (cairo_surface_t *surface,
+				 double		  sx,
+				 double		  sy)
+{
+    assert (! surface->is_snapshot);
+
+    if (surface->status)
+	return;
+
+    if (surface->finished) {
+	_cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
+	return;
+    }
+
+    surface->device_transform.xx = sx;
+    surface->device_transform.yy = sy;
+}
+
+/**
  * cairo_surface_set_device_offset:
  * @surface: a #cairo_surface_t
  * @x_offset: the offset in the X direction, in device units
diff --git a/src/cairoint.h b/src/cairoint.h
index d7c48ee..78062a7 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1855,6 +1855,11 @@ _cairo_surface_composite_shape_fixup_unb
 cairo_private cairo_bool_t
 _cairo_surface_is_opaque (const cairo_surface_t *surface);
 
+cairo_private void
+_cairo_surface_set_device_scale (cairo_surface_t *surface,
+				 double		  sx,
+				 double		  sy);
+
 cairo_private cairo_bool_t
 _cairo_surface_has_device_transform (cairo_surface_t *surface);
 
diff-tree b129f747c5c7edc37982f286940d3583c74cfee9 (from 24da744d03e961078e68691225fb1363e47b2b22)
Author: Carl Worth <cworth at cworth.org>
Date:   Sat Jun 10 00:12:51 2006 -0700

    Change {x,y}_device_offset values to a device_transform matrix.
    
    This is a step toward allowing device scaling in addition to device offsets.
    So far, the scale values are still always 1.0 so only the translation is
    actually being used. But most of the code is in place for doing scaling as
    well and it just needs to be hooked up.
    
    There are some fragile parts in this code, all of which involve using the
    translation without the scale, (so grep for device_transform.x0 or
    device_transform->x0). Some of these are likely bugs that will hopefully
    be obvious once we start using the scale. Others are OK if only because
    we 'know' that we aren't ever setting device scaling on a surface that
    has a device offset (we only set device scaling on surfaces we create
    internally and we don't export device scaling to the user).
    
    All of these fragile parts in the code have been marked with comments of
    the form: XXX: FRAGILE.

diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 70728ea..0a3bd5f 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -435,11 +435,10 @@ _cairo_clip_clip (cairo_clip_t       *cl
     cairo_traps_t traps;
     cairo_path_fixed_t path_transformed;
 
-    if (_cairo_surface_has_device_offset_or_scale (target)) {
+    if (_cairo_surface_has_device_transform (target)) {
 	_cairo_path_fixed_init_copy (&path_transformed, path);
-	_cairo_path_fixed_offset (&path_transformed,
-				  _cairo_fixed_from_double (target->x_device_offset),
-				  _cairo_fixed_from_double (target->y_device_offset));
+	_cairo_path_fixed_device_transform (&path_transformed,
+					    &target->device_transform);
 	path = &path_transformed;
     }
 
@@ -492,8 +491,14 @@ _cairo_clip_translate (cairo_clip_t  *cl
 
     if (clip->path) {
         cairo_clip_path_t *clip_path = clip->path;
+	cairo_matrix_t matrix;
+
+	cairo_matrix_init_translate (&matrix,
+				     _cairo_fixed_to_double (tx),
+				     _cairo_fixed_to_double (ty));
+
         while (clip_path) {
-            _cairo_path_fixed_offset (&clip_path->path, tx, ty);
+            _cairo_path_fixed_device_transform (&clip_path->path, &matrix);
             clip_path = clip_path->prev;
         }
     }
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index 58f4532..5ff117b 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -752,11 +752,12 @@ _cairo_directfb_surface_show_glyphs (cai
     		return CAIRO_INT_STATUS_UNSUPPORTED;
 		}
    /* round glyph locations to the nearest pixel */
+   /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
     x = (int) floor (glyphs[i].x +
-             glyph_img->base.x_device_offset +
+             glyph_img->base.device_transform.x0 +
              0.5);
     y = (int) floor (glyphs[i].y +
-             glyph_img->base.y_device_offset +
+             glyph_img->base.device_transform.y0 +
              0.5);
 	x +=dest_x;
 	y +=dest_y;
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 08a36a2..d4a6e3e 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -1025,9 +1025,9 @@ _render_glyph_outline (FT_Face          
      * Note: the font's coordinate system is upside down from ours, so the
      * Y coordinate of the control box needs to be negated.
      */
-
-    (*surface)->base.x_device_offset = floor ((double) cbox.xMin / 64.0);
-    (*surface)->base.y_device_offset = floor (-(double) cbox.yMax / 64.0);
+    cairo_surface_set_device_offset (&(*surface)->base,
+				     floor ((double) cbox.xMin / 64.0),
+				     floor (-(double) cbox.yMax / 64.0));
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1075,9 +1075,9 @@ _render_glyph_bitmap (FT_Face		      fac
      * Note: the font's coordinate system is upside down from ours, so the
      * Y coordinate of the control box needs to be negated.
      */
-
-    (*surface)->base.x_device_offset = glyphslot->bitmap_left;
-    (*surface)->base.y_device_offset = -glyphslot->bitmap_top;
+    cairo_surface_set_device_offset (&(*surface)->base,
+				     glyphslot->bitmap_left,
+				     -glyphslot->bitmap_top);
 
     return status;
 }
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 5510c51..f25a220 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -1955,8 +1955,8 @@ _cairo_glitz_surface_old_show_glyphs (ca
 
 	    if (glyph_private->area->width)
 	    {
-		x_offset = scaled_glyphs[i]->surface->base.x_device_offset;
-		y_offset = scaled_glyphs[i]->surface->base.y_device_offset;
+		x_offset = scaled_glyphs[i]->surface->base.device_transform.x0;
+		y_offset = scaled_glyphs[i]->surface->base.device_transform.y0;
 
 		x1 = floor (glyphs[i].x + 0.5) + x_offset;
 		y1 = floor (glyphs[i].y + 0.5) + y_offset;
@@ -1992,8 +1992,8 @@ _cairo_glitz_surface_old_show_glyphs (ca
 		glyph_private = scaled_glyphs[i]->surface_private;
 	    }
 
-	    x_offset = scaled_glyphs[i]->surface->base.x_device_offset;
-	    y_offset = scaled_glyphs[i]->surface->base.y_device_offset;
+	    x_offset = scaled_glyphs[i]->surface->base.device_transform.x0;
+	    y_offset = scaled_glyphs[i]->surface->base.device_transform.y0;
 
 	    x1 = floor (glyphs[i].x + 0.5) + x_offset;
 	    y1 = floor (glyphs[i].y + 0.5) + y_offset;
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index a939856..e262630 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -309,8 +309,8 @@ _cairo_gstate_redirect_target (cairo_gst
     /* The clip is in surface backend coordinates for the previous target;
      * translate it into the child's backend coordinates. */
     _cairo_clip_translate (&gstate->clip,
-                           _cairo_fixed_from_double (child->x_device_offset - gstate->parent_target->x_device_offset),
-                           _cairo_fixed_from_double (child->y_device_offset - gstate->parent_target->y_device_offset));
+                           _cairo_fixed_from_double (child->device_transform.x0 - gstate->parent_target->device_transform.x0),
+                           _cairo_fixed_from_double (child->device_transform.y0 - gstate->parent_target->device_transform.y0));
 }
 
 /**
@@ -723,7 +723,6 @@ _cairo_gstate_copy_transformed_pattern (
 {
     cairo_surface_pattern_t *surface_pattern;
     cairo_surface_t *surface;
-    cairo_matrix_t offset_matrix;
 
     _cairo_pattern_init_copy (pattern, original);
     _cairo_pattern_transform (pattern, ctm_inverse);
@@ -731,12 +730,8 @@ _cairo_gstate_copy_transformed_pattern (
     if (cairo_pattern_get_type (original) == CAIRO_PATTERN_TYPE_SURFACE) {
         surface_pattern = (cairo_surface_pattern_t *) original;
         surface = surface_pattern->surface;
-        if (_cairo_surface_has_device_offset_or_scale (surface)) {
-            cairo_matrix_init_translate (&offset_matrix,
-                                         surface->x_device_offset,
-                                         surface->y_device_offset);
-            _cairo_pattern_transform (pattern, &offset_matrix);
-        }
+        if (_cairo_surface_has_device_transform (surface))
+            _cairo_pattern_transform (pattern, &surface->device_transform);
     }
 
 }
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index a3ab6aa..ffaae60 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -529,6 +529,14 @@ _cairo_matrix_compute_scale_factors (con
 }
 
 cairo_bool_t
+_cairo_matrix_is_identity (const cairo_matrix_t *matrix)
+{
+    return (matrix->xx == 1.0 && matrix->yx == 0.0 &&
+	    matrix->xy == 0.0 && matrix->yy == 1.0 &&
+	    matrix->x0 == 0.0 && matrix->y0 == 0.0);
+}
+
+cairo_bool_t
 _cairo_matrix_is_integer_translation(const cairo_matrix_t *m,
 				     int *itx, int *ity)
 {
diff --git a/src/cairo-path.c b/src/cairo-path.c
index 420e217..b0c094e 100644
--- a/src/cairo-path.c
+++ b/src/cairo-path.c
@@ -604,12 +604,29 @@ _cairo_path_fixed_offset_and_scale (cair
     }
 }
 
+
+/**
+ * _cairo_path_fixed_device_transform:
+ * @path: a #cairo_path_fixed_t to be transformed
+ * @device_transform: a matrix with only scaling/translation (no rotation or shear)
+ *
+ * Transform the fixed-point path according to the scaling and
+ * translation of the given matrix. This function assert()s that the
+ * given matrix has no rotation or shear elements, (that is, xy and yx
+ * are 0.0).
+ **/
 void
-_cairo_path_fixed_offset (cairo_path_fixed_t *path,
-			  cairo_fixed_t offx,
-			  cairo_fixed_t offy)
+_cairo_path_fixed_device_transform (cairo_path_fixed_t	*path,
+				    cairo_matrix_t	*device_transform)
 {
-    _cairo_path_fixed_offset_and_scale (path, offx, offy,
-					CAIRO_FIXED_ONE,
-					CAIRO_FIXED_ONE);
+    assert (device_transform->yx == 0.0 && device_transform->xy == 0.0);
+    /* XXX: FRAGILE: I'm not really sure whether we're doing the
+     * "right" thing here if there is both scaling and translation in
+     * the matrix. But for now, the internals guarantee that we won't
+     * really ever have both going on. */
+    _cairo_path_fixed_offset_and_scale (path,
+					_cairo_fixed_from_double (device_transform->x0),
+					_cairo_fixed_from_double (device_transform->y0),
+					_cairo_fixed_from_double (device_transform->xx),
+					_cairo_fixed_from_double (device_transform->yy));
 }
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 4493487..c46e336 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -919,11 +919,12 @@ _cairo_scaled_font_show_glyphs (cairo_sc
 	}
 
 	/* round glyph locations to the nearest pixel */
+	/* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
 	x = (int) floor (glyphs[i].x +
-                         glyph_surface->base.x_device_offset +
+                         glyph_surface->base.device_transform.x0 +
                          0.5);
 	y = (int) floor (glyphs[i].y +
-                         glyph_surface->base.y_device_offset +
+                         glyph_surface->base.device_transform.y0 +
                          0.5);
 
 	_cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base);
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index 04e8096..5f7607a 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -990,8 +990,7 @@ _cairo_surface_fallback_snapshot (cairo_
     _cairo_surface_release_source_image (surface,
 					 image, &image_extra);
 
-    snapshot->x_device_offset = surface->x_device_offset;
-    snapshot->y_device_offset = surface->y_device_offset;
+    snapshot->device_transform = surface->device_transform;
 
     snapshot->is_snapshot = TRUE;
 
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 9ffd88e..ad0fe50 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -53,8 +53,10 @@ const cairo_surface_t _cairo_surface_nil
       0,	/* element_size */
       NULL,	/* elements */
     },					/* user_data */
-    0.0,				/* x_device_offset */
-    0.0,				/* y_device_offset */
+    { 1.0, 0.0,
+      0.0, 1.0,
+      0.0, 0.0
+    },					/* device_transform */
     0.0,				/* x_fallback_resolution */
     0.0,				/* y_fallback_resolution */
     0,					/* next_clip_serial */
@@ -73,8 +75,10 @@ const cairo_surface_t _cairo_surface_nil
       0,	/* element_size */
       NULL,	/* elements */
     },					/* user_data */
-    0.0,				/* x_device_offset */
-    0.0,				/* y_device_offset */
+    { 1.0, 0.0,
+      0.0, 1.0,
+      0.0, 0.0
+    },					/* device_transform */
     0.0,				/* x_fallback_resolution */
     0.0,				/* y_fallback_resolution */
     0,					/* next_clip_serial */
@@ -93,21 +97,20 @@ const cairo_surface_t _cairo_surface_nil
       0,	/* element_size */
       NULL,	/* elements */
     },					/* user_data */
-    0.0,				/* x_device_offset */
-    0.0,				/* y_device_offset */
+    { 1.0, 0.0,
+      0.0, 1.0,
+      0.0, 0.0
+    },					/* device_transform */
     0.0,				/* x_fallback_resolution */
     0.0,				/* y_fallback_resolution */
     0,					/* next_clip_serial */
     0					/* current_clip_serial */
 };
 
-/* Helper macros for transforming surface coords to backend coords */
-#define SURFACE_TO_BACKEND_X(_surf, _sx)  ((_sx)+((_surf)->x_device_offset))
-#define SURFACE_TO_BACKEND_Y(_surf, _sy)  ((_sy)+((_surf)->y_device_offset))
-
-static void _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
-                                                         cairo_surface_t *destination,
-                                                         cairo_pattern_t *pattern_out);
+static void
+_cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
+					     cairo_surface_t *destination,
+					     cairo_pattern_t *pattern_out);
 
 /**
  * _cairo_surface_set_error:
@@ -203,8 +206,7 @@ _cairo_surface_init (cairo_surface_t			*
 
     _cairo_user_data_array_init (&surface->user_data);
 
-    surface->x_device_offset = 0.0;
-    surface->y_device_offset = 0.0;
+    cairo_matrix_init_identity (&surface->device_transform);
 
     surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
     surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
@@ -594,9 +596,14 @@ cairo_surface_mark_dirty_rectangle (cair
     if (surface->backend->mark_dirty_rectangle) {
 	cairo_status_t status;
 
+	/* XXX: FRAGILE: We're ignoring the scaling component of
+	 * device_transform here. I don't know what the right thing to
+	 * do would actually be if there were some scaling here, but
+	 * we avoid this since device_transfom scaling is not exported
+	 * publicly and mark_dirty is not used internally. */
 	status = surface->backend->mark_dirty_rectangle (surface,
-                                                         SURFACE_TO_BACKEND_X(surface, x),
-                                                         SURFACE_TO_BACKEND_Y(surface, y),
+                                                         x + surface->device_transform.x0,
+                                                         y + surface->device_transform.y0,
 							 width, height);
 
 	if (status)
@@ -637,8 +644,8 @@ cairo_surface_set_device_offset (cairo_s
 	return;
     }
 
-    surface->x_device_offset = x_offset;
-    surface->y_device_offset = y_offset;
+    surface->device_transform.x0 = x_offset;
+    surface->device_transform.y0 = y_offset;
 }
 
 /**
@@ -656,8 +663,8 @@ cairo_surface_get_device_offset (cairo_s
 				 double          *x_offset,
 				 double          *y_offset)
 {
-    *x_offset = surface->x_device_offset;
-    *y_offset = surface->y_device_offset;
+    *x_offset = surface->device_transform.x0;
+    *y_offset = surface->device_transform.y0;
 }
 
 /**
@@ -693,10 +700,9 @@ cairo_surface_set_fallback_resolution (c
 }
 
 cairo_bool_t
-_cairo_surface_has_device_offset_or_scale (cairo_surface_t *surface)
+_cairo_surface_has_device_transform (cairo_surface_t *surface)
 {
-    return (surface->x_device_offset != 0.0 ||
-	    surface->y_device_offset != 0.0);
+    return ! _cairo_matrix_is_identity (&surface->device_transform);
 }
 
 /**
@@ -848,10 +854,8 @@ _cairo_surface_clone_similar (cairo_surf
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     status = surface->backend->clone_similar (surface, src, clone_out);
-    if (status == CAIRO_STATUS_SUCCESS) {
-        (*clone_out)->x_device_offset = src->x_device_offset;
-        (*clone_out)->y_device_offset = src->y_device_offset;
-    }
+    if (status == CAIRO_STATUS_SUCCESS)
+        (*clone_out)->device_transform = src->device_transform;
 
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return status;
@@ -861,10 +865,8 @@ _cairo_surface_clone_similar (cairo_surf
 	return status;
 
     status = surface->backend->clone_similar (surface, &image->base, clone_out);
-    if (status == CAIRO_STATUS_SUCCESS) {
-        (*clone_out)->x_device_offset = src->x_device_offset;
-        (*clone_out)->y_device_offset = src->y_device_offset;
-    }
+    if (status == CAIRO_STATUS_SUCCESS)
+        (*clone_out)->device_transform = src->device_transform;
 
     /* If the above failed point, we could implement a full fallback
      * using acquire_dest_image, but that's going to be very
@@ -1113,7 +1115,7 @@ _cairo_surface_paint (cairo_surface_t	*s
 
     status = _cairo_surface_fallback_paint (surface, op, &dev_source.base);
 
-FINISH:
+ FINISH:
     _cairo_pattern_fini (&dev_source.base);
 
     return status;
@@ -1142,9 +1144,9 @@ _cairo_surface_mask (cairo_surface_t	*su
 
     status = _cairo_surface_fallback_mask (surface, op, &dev_source.base, &dev_mask.base);
 
-FINISH:
-    _cairo_pattern_fini (&dev_source.base);
+ FINISH:
     _cairo_pattern_fini (&dev_mask.base);
+    _cairo_pattern_fini (&dev_source.base);
 
     return status;
 }
@@ -1169,12 +1171,11 @@ _cairo_surface_stroke (cairo_surface_t		
 
     _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
 
-    if (_cairo_surface_has_device_offset_or_scale (surface))
+    if (_cairo_surface_has_device_transform (surface))
     {
         _cairo_path_fixed_init_copy (&real_dev_path, path);
-        _cairo_path_fixed_offset (&real_dev_path,
-				  _cairo_fixed_from_double (surface->x_device_offset),
-				  _cairo_fixed_from_double (surface->y_device_offset));
+        _cairo_path_fixed_device_transform (&real_dev_path,
+					    &surface->device_transform);
         dev_path = &real_dev_path;
     }
 
@@ -1193,7 +1194,7 @@ _cairo_surface_stroke (cairo_surface_t		
                                              ctm, ctm_inverse,
                                              tolerance, antialias);
 
-FINISH:
+ FINISH:
     if (dev_path == &real_dev_path)
         _cairo_path_fixed_fini (&real_dev_path);
     _cairo_pattern_fini (&dev_source.base);
@@ -1219,12 +1220,11 @@ _cairo_surface_fill (cairo_surface_t	*su
 
     _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
 
-    if (_cairo_surface_has_device_offset_or_scale (surface))
+    if (_cairo_surface_has_device_transform (surface))
     {
         _cairo_path_fixed_init_copy (&real_dev_path, path);
-        _cairo_path_fixed_offset (&real_dev_path,
-				  _cairo_fixed_from_double (surface->x_device_offset),
-				  _cairo_fixed_from_double (surface->y_device_offset));
+        _cairo_path_fixed_device_transform (&real_dev_path,
+					    &surface->device_transform);
         dev_path = &real_dev_path;
     }
 
@@ -1241,7 +1241,7 @@ _cairo_surface_fill (cairo_surface_t	*su
                                            dev_path, fill_rule,
                                            tolerance, antialias);
 
-FINISH:
+ FINISH:
     if (dev_path == &real_dev_path)
         _cairo_path_fixed_fini (&real_dev_path);
     _cairo_pattern_fini (&dev_source.base);
@@ -1606,10 +1606,13 @@ _cairo_surface_get_extents (cairo_surfac
 
     status = surface->backend->get_extents (surface, rectangle);
 
-    rectangle->x = SURFACE_TO_BACKEND_X(surface, rectangle->x);
-    rectangle->y = SURFACE_TO_BACKEND_Y(surface, rectangle->y);
-    rectangle->width = rectangle->width - surface->x_device_offset;
-    rectangle->height = rectangle->height - surface->y_device_offset;
+    /* XXX: FRAGILE: This code is currently ignoring any scaling in
+     * the device_transform. This will almost certainly need to be
+     * changed for device_transform scaling will work. */
+    rectangle->x = rectangle->x + surface->device_transform.x0;
+    rectangle->y = rectangle->y + surface->device_transform.y0;
+    rectangle->width = rectangle->width - surface->device_transform.x0;
+    rectangle->height = rectangle->height - surface->device_transform.y0;
 
     return status;
 }
@@ -1629,10 +1632,10 @@ _cairo_surface_show_glyphs (cairo_surfac
     assert (! surface->is_snapshot);
 
     _cairo_surface_copy_pattern_for_destination (source,
-                                                 surface,
-                                                 &dev_source.base);
+						 surface,
+						 &dev_source.base);
 
-    if (_cairo_surface_has_device_offset_or_scale (surface))
+    if (_cairo_surface_has_device_transform (surface))
     {
         int i;
 
@@ -1642,9 +1645,11 @@ _cairo_surface_show_glyphs (cairo_surfac
 
         for (i = 0; i < num_glyphs; i++) {
             dev_glyphs[i].index = glyphs[i].index;
-            /* XXX: err, we really should scale the size of the glyphs, no? */
-            dev_glyphs[i].x = SURFACE_TO_BACKEND_X(surface, glyphs[i].x);
-            dev_glyphs[i].y = SURFACE_TO_BACKEND_Y(surface, glyphs[i].y);
+            dev_glyphs[i].x = glyphs[i].x;
+	    dev_glyphs[i].y = glyphs[i].y;
+	    cairo_matrix_transform_point (&surface->device_transform,
+					  &dev_glyphs[i].x,
+					  &dev_glyphs[i].y);
         }
     }
 
@@ -1966,11 +1971,15 @@ _cairo_surface_copy_pattern_for_destinat
 {
     _cairo_pattern_init_copy (pattern_out, pattern);
 
-    if (_cairo_surface_has_device_offset_or_scale (destination)) {
-	cairo_matrix_t device_to_surface;
-	cairo_matrix_init_translate (&device_to_surface,
-				     - destination->x_device_offset,
-				     - destination->y_device_offset);
+    if (_cairo_surface_has_device_transform (destination)) {
+	cairo_matrix_t device_to_surface = destination->device_transform;
+	cairo_status_t status;
+
+	status = cairo_matrix_invert (&device_to_surface);
+	/* We only ever allow for scaling (under the implementation's
+	 * control) or translation (under the user's control). So the
+	 * matrix should always be invertible. */
+	assert (status == CAIRO_STATUS_SUCCESS);
 
 	_cairo_pattern_transform (pattern_out, &device_to_surface);
     }
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index c383da7..5f57229 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -2245,8 +2245,7 @@ _cairo_xlib_surface_add_glyph (Display *
 
 	cairo_destroy (cr);
 
-	tmp_surface->x_device_offset = glyph_surface->base.x_device_offset;
-	tmp_surface->y_device_offset = glyph_surface->base.y_device_offset;
+	tmp_surface->device_transform = glyph_surface->base.device_transform;
 
 	glyph_surface = (cairo_image_surface_t *) tmp_surface;
 
@@ -2290,8 +2289,9 @@ _cairo_xlib_surface_add_glyph (Display *
      *  sitting around for x and y.
      */
 
-    glyph_info.x = - (int) floor(glyph_surface->base.x_device_offset + 0.5);
-    glyph_info.y = - (int) floor(glyph_surface->base.y_device_offset + 0.5);
+    /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
+    glyph_info.x = - (int) floor(glyph_surface->base.device_transform.x0 + 0.5);
+    glyph_info.y = - (int) floor(glyph_surface->base.device_transform.y0 + 0.5);
     glyph_info.width = glyph_surface->width;
     glyph_info.height = glyph_surface->height;
     glyph_info.xOff = 0;
diff --git a/src/cairo.c b/src/cairo.c
index dfdcfb8..e4fa741 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -423,8 +423,8 @@ cairo_push_group_with_content (cairo_t *
      * device offsets, so we want to set our own surface offsets from /that/,
      * and not from the device origin. */
     cairo_surface_set_device_offset (group_surface,
-                                     cr->gstate->target->x_device_offset - extents.x,
-                                     cr->gstate->target->y_device_offset - extents.y);
+                                     cr->gstate->target->device_transform.x0 - extents.x,
+                                     cr->gstate->target->device_transform.y0 - extents.y);
 
     /* create a new gstate for the redirect */
     cairo_save (cr);
diff --git a/src/cairoint.h b/src/cairoint.h
index 60ca612..d7c48ee 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -855,8 +855,7 @@ struct _cairo_surface {
     cairo_bool_t finished;
     cairo_user_data_array_t user_data;
 
-    double x_device_offset;
-    double y_device_offset;
+    cairo_matrix_t device_transform;
 
     double x_fallback_resolution;
     double y_fallback_resolution;
@@ -1504,9 +1503,8 @@ _cairo_path_fixed_bounds (cairo_path_fix
 			  double *x2, double *y2);
 
 cairo_private void
-_cairo_path_fixed_offset (cairo_path_fixed_t *path,
-			  cairo_fixed_t offx,
-			  cairo_fixed_t offy);
+_cairo_path_fixed_device_transform (cairo_path_fixed_t	*path,
+				    cairo_matrix_t	*device_transform);
 
 /* cairo_path_fill.c */
 cairo_private cairo_status_t
@@ -1858,7 +1856,7 @@ cairo_private cairo_bool_t
 _cairo_surface_is_opaque (const cairo_surface_t *surface);
 
 cairo_private cairo_bool_t
-_cairo_surface_has_device_offset_or_scale (cairo_surface_t *surface);
+_cairo_surface_has_device_transform (cairo_surface_t *surface);
 
 /* cairo_image_surface.c */
 
@@ -2017,6 +2015,9 @@ _cairo_matrix_compute_scale_factors (con
 				     double *sx, double *sy, int x_major);
 
 cairo_private cairo_bool_t
+_cairo_matrix_is_identity (const cairo_matrix_t *matrix);
+
+cairo_private cairo_bool_t
 _cairo_matrix_is_integer_translation(const cairo_matrix_t *matrix,
 				     int *itx, int *ity);
 
diff-tree 24da744d03e961078e68691225fb1363e47b2b22 (from 999315cc0ad326d31c66f2e6fa1ae72dfb9bb57e)
Author: Carl Worth <cworth at cworth.org>
Date:   Fri Jun 9 23:59:24 2006 -0700

    doc: SGML template churn

diff --git a/doc/public/tmpl/cairo-pdf.sgml b/doc/public/tmpl/cairo-pdf.sgml
index 4f7dbd7..c427ffe 100644
--- a/doc/public/tmpl/cairo-pdf.sgml
+++ b/doc/public/tmpl/cairo-pdf.sgml
@@ -17,3 +17,10 @@ Rendering PDF documents
 <!-- ##### SECTION Stability_Level ##### -->
 
 
+<!-- ##### MACRO cairo_pdf_surface_set_dpi ##### -->
+<para>
+
+</para>
+
+
+
diff --git a/doc/public/tmpl/cairo-ps.sgml b/doc/public/tmpl/cairo-ps.sgml
index a3d5765..035d37b 100644
--- a/doc/public/tmpl/cairo-ps.sgml
+++ b/doc/public/tmpl/cairo-ps.sgml
@@ -17,3 +17,10 @@ Rendering PostScript documents
 <!-- ##### SECTION Stability_Level ##### -->
 
 
+<!-- ##### MACRO cairo_ps_surface_set_dpi ##### -->
+<para>
+
+</para>
+
+
+
diff --git a/doc/public/tmpl/cairo-status.sgml b/doc/public/tmpl/cairo-status.sgml
index 37ed0db..fc501a7 100644
--- a/doc/public/tmpl/cairo-status.sgml
+++ b/doc/public/tmpl/cairo-status.sgml
@@ -44,10 +44,3 @@ Decoding cairo's status
 @CAIRO_STATUS_INVALID_DASH: 
 @CAIRO_STATUS_INVALID_DSC_COMMENT: 
 
-<!-- ##### FUNCTION cairo_debug_reset_static_data ##### -->
-<para>
-
-</para>
-
-
-
diff --git a/doc/public/tmpl/cairo-svg.sgml b/doc/public/tmpl/cairo-svg.sgml
index 1099d61..7ee16ee 100644
--- a/doc/public/tmpl/cairo-svg.sgml
+++ b/doc/public/tmpl/cairo-svg.sgml
@@ -17,3 +17,10 @@ Rendering SVG documents
 <!-- ##### SECTION Stability_Level ##### -->
 
 
+<!-- ##### MACRO cairo_svg_surface_set_dpi ##### -->
+<para>
+
+</para>
+
+
+
diff-tree 999315cc0ad326d31c66f2e6fa1ae72dfb9bb57e (from 6f6bdb6663fc439387db6b410bf742de6b501015)
Author: Carl Worth <cworth at cworth.org>
Date:   Fri Jun 9 21:12:44 2006 -0700

    Rename device_{x,y}_offset to {x,y}_device_offset for better consitency/grepability

diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 3922913..70728ea 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -438,8 +438,8 @@ _cairo_clip_clip (cairo_clip_t       *cl
     if (_cairo_surface_has_device_offset_or_scale (target)) {
 	_cairo_path_fixed_init_copy (&path_transformed, path);
 	_cairo_path_fixed_offset (&path_transformed,
-				  _cairo_fixed_from_double (target->device_x_offset),
-				  _cairo_fixed_from_double (target->device_y_offset));
+				  _cairo_fixed_from_double (target->x_device_offset),
+				  _cairo_fixed_from_double (target->y_device_offset));
 	path = &path_transformed;
     }
 
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index 825f80f..58f4532 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -753,10 +753,10 @@ _cairo_directfb_surface_show_glyphs (cai
 		}
    /* round glyph locations to the nearest pixel */
     x = (int) floor (glyphs[i].x +
-             glyph_img->base.device_x_offset +
+             glyph_img->base.x_device_offset +
              0.5);
     y = (int) floor (glyphs[i].y +
-             glyph_img->base.device_y_offset +
+             glyph_img->base.y_device_offset +
              0.5);
 	x +=dest_x;
 	y +=dest_y;
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 998c361..08a36a2 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -1026,8 +1026,8 @@ _render_glyph_outline (FT_Face          
      * Y coordinate of the control box needs to be negated.
      */
 
-    (*surface)->base.device_x_offset = floor ((double) cbox.xMin / 64.0);
-    (*surface)->base.device_y_offset = floor (-(double) cbox.yMax / 64.0);
+    (*surface)->base.x_device_offset = floor ((double) cbox.xMin / 64.0);
+    (*surface)->base.y_device_offset = floor (-(double) cbox.yMax / 64.0);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1076,8 +1076,8 @@ _render_glyph_bitmap (FT_Face		      fac
      * Y coordinate of the control box needs to be negated.
      */
 
-    (*surface)->base.device_x_offset = glyphslot->bitmap_left;
-    (*surface)->base.device_y_offset = -glyphslot->bitmap_top;
+    (*surface)->base.x_device_offset = glyphslot->bitmap_left;
+    (*surface)->base.y_device_offset = -glyphslot->bitmap_top;
 
     return status;
 }
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index f58545a..5510c51 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -1955,8 +1955,8 @@ _cairo_glitz_surface_old_show_glyphs (ca
 
 	    if (glyph_private->area->width)
 	    {
-		x_offset = scaled_glyphs[i]->surface->base.device_x_offset;
-		y_offset = scaled_glyphs[i]->surface->base.device_y_offset;
+		x_offset = scaled_glyphs[i]->surface->base.x_device_offset;
+		y_offset = scaled_glyphs[i]->surface->base.y_device_offset;
 
 		x1 = floor (glyphs[i].x + 0.5) + x_offset;
 		y1 = floor (glyphs[i].y + 0.5) + y_offset;
@@ -1992,8 +1992,8 @@ _cairo_glitz_surface_old_show_glyphs (ca
 		glyph_private = scaled_glyphs[i]->surface_private;
 	    }
 
-	    x_offset = scaled_glyphs[i]->surface->base.device_x_offset;
-	    y_offset = scaled_glyphs[i]->surface->base.device_y_offset;
+	    x_offset = scaled_glyphs[i]->surface->base.x_device_offset;
+	    y_offset = scaled_glyphs[i]->surface->base.y_device_offset;
 
 	    x1 = floor (glyphs[i].x + 0.5) + x_offset;
 	    y1 = floor (glyphs[i].y + 0.5) + y_offset;
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index fdecf43..a939856 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -309,8 +309,8 @@ _cairo_gstate_redirect_target (cairo_gst
     /* The clip is in surface backend coordinates for the previous target;
      * translate it into the child's backend coordinates. */
     _cairo_clip_translate (&gstate->clip,
-                           _cairo_fixed_from_double (child->device_x_offset - gstate->parent_target->device_x_offset),
-                           _cairo_fixed_from_double (child->device_y_offset - gstate->parent_target->device_y_offset));
+                           _cairo_fixed_from_double (child->x_device_offset - gstate->parent_target->x_device_offset),
+                           _cairo_fixed_from_double (child->y_device_offset - gstate->parent_target->y_device_offset));
 }
 
 /**
@@ -733,8 +733,8 @@ _cairo_gstate_copy_transformed_pattern (
         surface = surface_pattern->surface;
         if (_cairo_surface_has_device_offset_or_scale (surface)) {
             cairo_matrix_init_translate (&offset_matrix,
-                                         surface->device_x_offset,
-                                         surface->device_y_offset);
+                                         surface->x_device_offset,
+                                         surface->y_device_offset);
             _cairo_pattern_transform (pattern, &offset_matrix);
         }
     }
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 6b34b26..4493487 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -920,10 +920,10 @@ _cairo_scaled_font_show_glyphs (cairo_sc
 
 	/* round glyph locations to the nearest pixel */
 	x = (int) floor (glyphs[i].x +
-                         glyph_surface->base.device_x_offset +
+                         glyph_surface->base.x_device_offset +
                          0.5);
 	y = (int) floor (glyphs[i].y +
-                         glyph_surface->base.device_y_offset +
+                         glyph_surface->base.y_device_offset +
                          0.5);
 
 	_cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base);
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index 6210190..04e8096 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -990,8 +990,8 @@ _cairo_surface_fallback_snapshot (cairo_
     _cairo_surface_release_source_image (surface,
 					 image, &image_extra);
 
-    snapshot->device_x_offset = surface->device_x_offset;
-    snapshot->device_y_offset = surface->device_y_offset;
+    snapshot->x_device_offset = surface->x_device_offset;
+    snapshot->y_device_offset = surface->y_device_offset;
 
     snapshot->is_snapshot = TRUE;
 
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 1f0a6b6..9ffd88e 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -53,8 +53,8 @@ const cairo_surface_t _cairo_surface_nil
       0,	/* element_size */
       NULL,	/* elements */
     },					/* user_data */
-    0.0,				/* device_x_offset */
-    0.0,				/* device_y_offset */
+    0.0,				/* x_device_offset */
+    0.0,				/* y_device_offset */
     0.0,				/* x_fallback_resolution */
     0.0,				/* y_fallback_resolution */
     0,					/* next_clip_serial */
@@ -73,8 +73,8 @@ const cairo_surface_t _cairo_surface_nil
       0,	/* element_size */
       NULL,	/* elements */
     },					/* user_data */
-    0.0,				/* device_x_offset */
-    0.0,				/* device_y_offset */
+    0.0,				/* x_device_offset */
+    0.0,				/* y_device_offset */
     0.0,				/* x_fallback_resolution */
     0.0,				/* y_fallback_resolution */
     0,					/* next_clip_serial */
@@ -93,8 +93,8 @@ const cairo_surface_t _cairo_surface_nil
       0,	/* element_size */
       NULL,	/* elements */
     },					/* user_data */
-    0.0,				/* device_x_offset */
-    0.0,				/* device_y_offset */
+    0.0,				/* x_device_offset */
+    0.0,				/* y_device_offset */
     0.0,				/* x_fallback_resolution */
     0.0,				/* y_fallback_resolution */
     0,					/* next_clip_serial */
@@ -102,8 +102,8 @@ const cairo_surface_t _cairo_surface_nil
 };
 
 /* Helper macros for transforming surface coords to backend coords */
-#define SURFACE_TO_BACKEND_X(_surf, _sx)  ((_sx)+((_surf)->device_x_offset))
-#define SURFACE_TO_BACKEND_Y(_surf, _sy)  ((_sy)+((_surf)->device_y_offset))
+#define SURFACE_TO_BACKEND_X(_surf, _sx)  ((_sx)+((_surf)->x_device_offset))
+#define SURFACE_TO_BACKEND_Y(_surf, _sy)  ((_sy)+((_surf)->y_device_offset))
 
 static void _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
                                                          cairo_surface_t *destination,
@@ -203,8 +203,8 @@ _cairo_surface_init (cairo_surface_t			*
 
     _cairo_user_data_array_init (&surface->user_data);
 
-    surface->device_x_offset = 0.0;
-    surface->device_y_offset = 0.0;
+    surface->x_device_offset = 0.0;
+    surface->y_device_offset = 0.0;
 
     surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
     surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
@@ -637,8 +637,8 @@ cairo_surface_set_device_offset (cairo_s
 	return;
     }
 
-    surface->device_x_offset = x_offset;
-    surface->device_y_offset = y_offset;
+    surface->x_device_offset = x_offset;
+    surface->y_device_offset = y_offset;
 }
 
 /**
@@ -656,8 +656,8 @@ cairo_surface_get_device_offset (cairo_s
 				 double          *x_offset,
 				 double          *y_offset)
 {
-    *x_offset = surface->device_x_offset;
-    *y_offset = surface->device_y_offset;
+    *x_offset = surface->x_device_offset;
+    *y_offset = surface->y_device_offset;
 }
 
 /**
@@ -695,8 +695,8 @@ cairo_surface_set_fallback_resolution (c
 cairo_bool_t
 _cairo_surface_has_device_offset_or_scale (cairo_surface_t *surface)
 {
-    return (surface->device_x_offset != 0.0 ||
-	    surface->device_y_offset != 0.0);
+    return (surface->x_device_offset != 0.0 ||
+	    surface->y_device_offset != 0.0);
 }
 
 /**
@@ -849,8 +849,8 @@ _cairo_surface_clone_similar (cairo_surf
 
     status = surface->backend->clone_similar (surface, src, clone_out);
     if (status == CAIRO_STATUS_SUCCESS) {
-        (*clone_out)->device_x_offset = src->device_x_offset;
-        (*clone_out)->device_y_offset = src->device_y_offset;
+        (*clone_out)->x_device_offset = src->x_device_offset;
+        (*clone_out)->y_device_offset = src->y_device_offset;
     }
 
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
@@ -862,8 +862,8 @@ _cairo_surface_clone_similar (cairo_surf
 
     status = surface->backend->clone_similar (surface, &image->base, clone_out);
     if (status == CAIRO_STATUS_SUCCESS) {
-        (*clone_out)->device_x_offset = src->device_x_offset;
-        (*clone_out)->device_y_offset = src->device_y_offset;
+        (*clone_out)->x_device_offset = src->x_device_offset;
+        (*clone_out)->y_device_offset = src->y_device_offset;
     }
 
     /* If the above failed point, we could implement a full fallback
@@ -1173,8 +1173,8 @@ _cairo_surface_stroke (cairo_surface_t		
     {
         _cairo_path_fixed_init_copy (&real_dev_path, path);
         _cairo_path_fixed_offset (&real_dev_path,
-				  _cairo_fixed_from_double (surface->device_x_offset),
-				  _cairo_fixed_from_double (surface->device_y_offset));
+				  _cairo_fixed_from_double (surface->x_device_offset),
+				  _cairo_fixed_from_double (surface->y_device_offset));
         dev_path = &real_dev_path;
     }
 
@@ -1223,8 +1223,8 @@ _cairo_surface_fill (cairo_surface_t	*su
     {
         _cairo_path_fixed_init_copy (&real_dev_path, path);
         _cairo_path_fixed_offset (&real_dev_path,
-				  _cairo_fixed_from_double (surface->device_x_offset),
-				  _cairo_fixed_from_double (surface->device_y_offset));
+				  _cairo_fixed_from_double (surface->x_device_offset),
+				  _cairo_fixed_from_double (surface->y_device_offset));
         dev_path = &real_dev_path;
     }
 
@@ -1608,8 +1608,8 @@ _cairo_surface_get_extents (cairo_surfac
 
     rectangle->x = SURFACE_TO_BACKEND_X(surface, rectangle->x);
     rectangle->y = SURFACE_TO_BACKEND_Y(surface, rectangle->y);
-    rectangle->width = rectangle->width - surface->device_x_offset;
-    rectangle->height = rectangle->height - surface->device_y_offset;
+    rectangle->width = rectangle->width - surface->x_device_offset;
+    rectangle->height = rectangle->height - surface->y_device_offset;
 
     return status;
 }
@@ -1969,8 +1969,8 @@ _cairo_surface_copy_pattern_for_destinat
     if (_cairo_surface_has_device_offset_or_scale (destination)) {
 	cairo_matrix_t device_to_surface;
 	cairo_matrix_init_translate (&device_to_surface,
-				     - destination->device_x_offset,
-				     - destination->device_y_offset);
+				     - destination->x_device_offset,
+				     - destination->y_device_offset);
 
 	_cairo_pattern_transform (pattern_out, &device_to_surface);
     }
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 6b8748d..c383da7 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -2245,8 +2245,8 @@ _cairo_xlib_surface_add_glyph (Display *
 
 	cairo_destroy (cr);
 
-	tmp_surface->device_x_offset = glyph_surface->base.device_x_offset;
-	tmp_surface->device_y_offset = glyph_surface->base.device_y_offset;
+	tmp_surface->x_device_offset = glyph_surface->base.x_device_offset;
+	tmp_surface->y_device_offset = glyph_surface->base.y_device_offset;
 
 	glyph_surface = (cairo_image_surface_t *) tmp_surface;
 
@@ -2290,8 +2290,8 @@ _cairo_xlib_surface_add_glyph (Display *
      *  sitting around for x and y.
      */
 
-    glyph_info.x = - (int) floor(glyph_surface->base.device_x_offset + 0.5);
-    glyph_info.y = - (int) floor(glyph_surface->base.device_y_offset + 0.5);
+    glyph_info.x = - (int) floor(glyph_surface->base.x_device_offset + 0.5);
+    glyph_info.y = - (int) floor(glyph_surface->base.y_device_offset + 0.5);
     glyph_info.width = glyph_surface->width;
     glyph_info.height = glyph_surface->height;
     glyph_info.xOff = 0;
diff --git a/src/cairo.c b/src/cairo.c
index 9460bf2..dfdcfb8 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -423,8 +423,8 @@ cairo_push_group_with_content (cairo_t *
      * device offsets, so we want to set our own surface offsets from /that/,
      * and not from the device origin. */
     cairo_surface_set_device_offset (group_surface,
-                                     cr->gstate->target->device_x_offset - extents.x,
-                                     cr->gstate->target->device_y_offset - extents.y);
+                                     cr->gstate->target->x_device_offset - extents.x,
+                                     cr->gstate->target->y_device_offset - extents.y);
 
     /* create a new gstate for the redirect */
     cairo_save (cr);
diff --git a/src/cairoint.h b/src/cairoint.h
index c055b34..60ca612 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -855,8 +855,8 @@ struct _cairo_surface {
     cairo_bool_t finished;
     cairo_user_data_array_t user_data;
 
-    double device_x_offset;
-    double device_y_offset;
+    double x_device_offset;
+    double y_device_offset;
 
     double x_fallback_resolution;
     double y_fallback_resolution;
diff-tree 6f6bdb6663fc439387db6b410bf742de6b501015 (from b2f274b3e86983b312ec19e33b3a1231bd3e51d0)
Author: Carl Worth <cworth at cworth.org>
Date:   Fri Jun 9 16:54:09 2006 -0700

    Add REPLACED_BY macros to help porting to new set_fallback_resolution

diff --git a/src/cairo.h b/src/cairo.h
index 61e9fe9..bfd9524 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1622,6 +1622,9 @@ cairo_debug_reset_static_data (void);
 #define cairo_xlib_surface_create_for_window_with_visual	cairo_xlib_surface_create_for_window_with_visual_REPLACED_BY_cairo_xlib_surface_create
 #define cairo_xcb_surface_create_for_pixmap_with_visual	cairo_xcb_surface_create_for_pixmap_with_visual_REPLACED_BY_cairo_xcb_surface_create
 #define cairo_xcb_surface_create_for_window_with_visual	cairo_xcb_surface_create_for_window_with_visual_REPLACED_BY_cairo_xcb_surface_create
+#define cairo_ps_surface_set_dpi	cairo_ps_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
+#define cairo_pdf_surface_set_dpi	cairo_pdf_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
+#define cairo_svg_surface_set_dpi	cairo_svg_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
 
 #define cairo_current_path	     cairo_current_path_DEPRECATED_BY_cairo_copy_path
 #define cairo_current_path_flat	     cairo_current_path_flat_DEPRECATED_BY_cairo_copy_path_flat
diff-tree b2f274b3e86983b312ec19e33b3a1231bd3e51d0 (from a812b3c4908ff296877a648915d5f06696eebe9e)
Author: Carl Worth <cworth at cworth.org>
Date:   Fri Jun 9 16:52:17 2006 -0700

    New API: Replace cairo_{ps,pdf,svg}_set_dpi with new cairo_surface_set_fallback_resolution.
    
    This just provides the mechanics for storing the value and removing the old
    function calls. The new value is still not used anywhere (though nor where
    the old values), so there should be no functional change (other than forcing
    any programs calling the old API to be updated).

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 9237d52..c0586b9 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -110,8 +110,6 @@ typedef struct _cairo_pdf_surface {
 
     double width;
     double height;
-    double x_dpi;
-    double y_dpi;
 
     cairo_array_t objects;
     cairo_array_t pages;
@@ -138,7 +136,6 @@ typedef struct _cairo_pdf_surface {
     cairo_paginated_mode_t paginated_mode;
 } cairo_pdf_surface_t;
 
-#define PDF_SURFACE_DPI_DEFAULT		300
 #define PDF_SURFACE_MAX_GLYPHS_PER_FONT	256
 
 static cairo_pdf_resource_t
@@ -269,8 +266,6 @@ _cairo_pdf_surface_create_for_stream_int
 
     surface->width = width;
     surface->height = height;
-    surface->x_dpi = PDF_SURFACE_DPI_DEFAULT;
-    surface->y_dpi = PDF_SURFACE_DPI_DEFAULT;
 
     _cairo_array_init (&surface->objects, sizeof (cairo_pdf_object_t));
     _cairo_array_init (&surface->pages, sizeof (cairo_pdf_resource_t));
@@ -413,36 +408,6 @@ _extract_pdf_surface (cairo_surface_t		 
 }
 
 /**
- * cairo_pdf_surface_set_dpi:
- * @surface: a PDF cairo_surface_t
- * @x_dpi: horizontal dpi
- * @y_dpi: vertical dpi
- *
- * Set the horizontal and vertical resolution for image fallbacks.
- * When the pdf backend needs to fall back to image overlays, it will
- * use this resolution. These DPI values are not used for any other
- * purpose, (in particular, they do not have any bearing on the size
- * passed to cairo_pdf_surface_create() nor on the CTM).
- **/
-void
-cairo_pdf_surface_set_dpi (cairo_surface_t	*surface,
-			   double		x_dpi,
-			   double		y_dpi)
-{
-    cairo_pdf_surface_t *pdf_surface;
-    cairo_status_t status;
-
-    status = _extract_pdf_surface (surface, &pdf_surface);
-    if (status) {
-	_cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
-	return;
-    }
-
-    pdf_surface->x_dpi = x_dpi;
-    pdf_surface->y_dpi = y_dpi;
-}
-
-/**
  * cairo_pdf_surface_set_size:
  * @surface: a PDF cairo_surface_t
  * @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
diff --git a/src/cairo-pdf.h b/src/cairo-pdf.h
index bbbe9bd..53699d4 100644
--- a/src/cairo-pdf.h
+++ b/src/cairo-pdf.h
@@ -54,11 +54,6 @@ cairo_pdf_surface_create_for_stream (cai
 				     double		width_in_points,
 				     double		height_in_points);
 
-cairo_public void
-cairo_pdf_surface_set_dpi (cairo_surface_t     *surface,
-			   double		x_dpi,
-			   double		y_dpi);
-
 void
 cairo_pdf_surface_set_size (cairo_surface_t	*surface,
 			    double		 width_in_points,
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 2ed12f1..4e019e1 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -67,8 +67,6 @@ typedef struct cairo_ps_surface {
     double height;
     double max_width;
     double max_height;
-    double x_dpi;
-    double y_dpi;
 
     int num_pages;
 
@@ -84,7 +82,6 @@ typedef struct cairo_ps_surface {
 
 } cairo_ps_surface_t;
 
-#define PS_SURFACE_DPI_DEFAULT		300.0
 #define PS_SURFACE_MAX_GLYPHS_PER_FONT	256
 
 static cairo_status_t
@@ -376,8 +373,6 @@ _cairo_ps_surface_create_for_stream_inte
     surface->height = height;
     surface->max_width = width;
     surface->max_height = height;
-    surface->x_dpi = PS_SURFACE_DPI_DEFAULT;
-    surface->y_dpi = PS_SURFACE_DPI_DEFAULT;
     surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
 
     surface->num_pages = 0;
@@ -520,36 +515,6 @@ _extract_ps_surface (cairo_surface_t	 *s
 }
 
 /**
- * cairo_ps_surface_set_dpi:
- * @surface: a PostScript cairo_surface_t
- * @x_dpi: horizontal dpi
- * @y_dpi: vertical dpi
- *
- * Set the horizontal and vertical resolution for image fallbacks.
- * When the ps backend needs to fall back to image overlays, it will
- * use this resolution. These DPI values are not used for any other
- * purpose, (in particular, they do not have any bearing on the size
- * passed to cairo_ps_surface_create() nor on the CTM).
- **/
-void
-cairo_ps_surface_set_dpi (cairo_surface_t *surface,
-			  double	   x_dpi,
-			  double	   y_dpi)
-{
-    cairo_ps_surface_t *ps_surface;
-    cairo_status_t status;
-
-    status = _extract_ps_surface (surface, &ps_surface);
-    if (status) {
-	_cairo_surface_set_error (surface, status);
-	return;
-    }
-
-    ps_surface->x_dpi = x_dpi;
-    ps_surface->y_dpi = y_dpi;
-}
-
-/**
  * cairo_ps_surface_set_size:
  * @surface: a PostScript cairo_surface_t
  * @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
diff --git a/src/cairo-ps.h b/src/cairo-ps.h
index 2e1d988..a61d12d 100644
--- a/src/cairo-ps.h
+++ b/src/cairo-ps.h
@@ -73,11 +73,6 @@ cairo_ps_surface_dsc_begin_setup (cairo_
 cairo_public void
 cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface);
 
-cairo_public void
-cairo_ps_surface_set_dpi (cairo_surface_t      *surface,
-			  double		x_dpi,
-			  double		y_dpi);
-
 CAIRO_END_DECLS
 
 #else  /* CAIRO_HAS_PS_SURFACE */
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 39b018c..1f0a6b6 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -55,6 +55,8 @@ const cairo_surface_t _cairo_surface_nil
     },					/* user_data */
     0.0,				/* device_x_offset */
     0.0,				/* device_y_offset */
+    0.0,				/* x_fallback_resolution */
+    0.0,				/* y_fallback_resolution */
     0,					/* next_clip_serial */
     0					/* current_clip_serial */
 };
@@ -73,6 +75,8 @@ const cairo_surface_t _cairo_surface_nil
     },					/* user_data */
     0.0,				/* device_x_offset */
     0.0,				/* device_y_offset */
+    0.0,				/* x_fallback_resolution */
+    0.0,				/* y_fallback_resolution */
     0,					/* next_clip_serial */
     0					/* current_clip_serial */
 };
@@ -91,6 +95,8 @@ const cairo_surface_t _cairo_surface_nil
     },					/* user_data */
     0.0,				/* device_x_offset */
     0.0,				/* device_y_offset */
+    0.0,				/* x_fallback_resolution */
+    0.0,				/* y_fallback_resolution */
     0,					/* next_clip_serial */
     0					/* current_clip_serial */
 };
@@ -200,6 +206,9 @@ _cairo_surface_init (cairo_surface_t			*
     surface->device_x_offset = 0.0;
     surface->device_y_offset = 0.0;
 
+    surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
+    surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
+
     surface->clip = NULL;
     surface->next_clip_serial = 0;
     surface->current_clip_serial = 0;
@@ -651,6 +660,38 @@ cairo_surface_get_device_offset (cairo_s
     *y_offset = surface->device_y_offset;
 }
 
+/**
+ * cairo_surface_set_fallback_resolution:
+ * @surface: a #cairo_surface_t
+ * @x_pixels_per_inch: horizontal setting for pixels per inch
+ * @y_pixels_per_inch: vertical setting for pixels per inch
+ *
+ * Set the horizontal and vertical resolution for image fallbacks.
+ *
+ * When certain operations aren't supported natively by a backend,
+ * cairo will fallback by rendering operations to an image and then
+ * overlaying that image onto the output. For backends that are
+ * natively vector-oriented, this function can be used to set the
+ * resolution used for these image fallbacks, (larger values will
+ * result in more detailed images, but also larger file sizes).
+ *
+ * Some examples of natively vector-oriented backends are the ps, pdf,
+ * and svg backends.
+ *
+ * For backends that are natively raster-oriented, image fallbacks are
+ * still possible, but they are always performed at the native
+ * device resolution. So this function has no effect on those
+ * backends.
+ **/
+void
+cairo_surface_set_fallback_resolution (cairo_surface_t	*surface,
+				       double		 x_pixels_per_inch,
+				       double		 y_pixels_per_inch)
+{
+    surface->x_fallback_resolution = x_pixels_per_inch;
+    surface->y_fallback_resolution = y_pixels_per_inch;
+}
+
 cairo_bool_t
 _cairo_surface_has_device_offset_or_scale (cairo_surface_t *surface)
 {
@@ -1934,3 +1975,6 @@ _cairo_surface_copy_pattern_for_destinat
 	_cairo_pattern_transform (pattern_out, &device_to_surface);
     }
 }
+
+/*  LocalWords:  rasterized
+ */
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 79575da..73d119b 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -53,8 +53,6 @@
 
 #define CAIRO_SVG_DTOSTR_BUFFER_LEN 30
 
-#define CAIRO_SVG_DEFAULT_DPI 300
-
 typedef struct cairo_svg_document cairo_svg_document_t;
 typedef struct cairo_svg_surface cairo_svg_surface_t;
 
@@ -84,8 +82,6 @@ struct cairo_svg_document {
 
     double width;
     double height;
-    double x_dpi;
-    double y_dpi;
 
     xmlDocPtr	xml_doc;
     xmlNodePtr	xml_node_defs;
@@ -266,38 +262,6 @@ _extract_svg_surface (cairo_surface_t		 
 }
 
 /**
- * cairo_svg_surface_set_dpi:
- * @surface: a svg cairo_surface_t
- * @x_dpi: horizontal dpi
- * @y_dpi: vertical dpi
- *
- * Set the horizontal and vertical resolution for image fallbacks.
- * When the svg backend needs to fall back to image overlays, it will
- * use this resolution. These DPI values are not used for any other
- * purpose (in particular, they do not have any bearing on the size
- * passed to cairo_pdf_surface_create() nor on the CTM).
- **/
-
-void
-cairo_svg_surface_set_dpi (cairo_surface_t	*abstract_surface,
-			   double		x_dpi,
-			   double		y_dpi)
-{
-    cairo_svg_surface_t *surface;
-    cairo_status_t status;
-
-    status = _extract_svg_surface (abstract_surface, &surface);
-    if (status) {
-	_cairo_surface_set_error (abstract_surface,
-				  CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
-	return;
-    }
-
-    surface->document->x_dpi = x_dpi;
-    surface->document->y_dpi = y_dpi;
-}
-
-/**
  * cairo_svg_surface_restrict_to_version:
  * @surface: a SVG #cairo_surface_t
  * @version: SVG version
@@ -1841,8 +1805,6 @@ _cairo_svg_document_create (cairo_output
     document->finished = FALSE;
     document->width = width;
     document->height = height;
-    document->x_dpi = CAIRO_SVG_DEFAULT_DPI;
-    document->y_dpi = CAIRO_SVG_DEFAULT_DPI;
 
     document->surface_id = 0;
     document->linear_pattern_id = 0;
diff --git a/src/cairo-svg.h b/src/cairo-svg.h
index 637231b..d289936 100644
--- a/src/cairo-svg.h
+++ b/src/cairo-svg.h
@@ -56,11 +56,6 @@ cairo_svg_surface_create_for_stream (cai
 				     double		height_in_points);
 
 cairo_public void
-cairo_svg_surface_set_dpi (cairo_surface_t     *surface,
-			   double		x_dpi,
-			   double		y_dpi);
-
-cairo_public void
 cairo_svg_surface_restrict_to_version (cairo_surface_t 		*surface,
 				       cairo_svg_version_t  	 version);
 
diff --git a/src/cairo.h b/src/cairo.h
index 5b2b4ed..61e9fe9 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1317,6 +1317,11 @@ cairo_surface_get_device_offset (cairo_s
 				 double          *x_offset,
 				 double          *y_offset);
 
+cairo_public void
+cairo_surface_set_fallback_resolution (cairo_surface_t	*surface,
+				       double		 x_pixels_per_inch,
+				       double		 y_pixels_per_inch);
+
 /* Image-surface functions */
 
 /**
diff --git a/src/cairoint.h b/src/cairoint.h
index 04d5146..c055b34 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -858,6 +858,9 @@ struct _cairo_surface {
     double device_x_offset;
     double device_y_offset;
 
+    double x_fallback_resolution;
+    double y_fallback_resolution;
+
     cairo_clip_t *clip;
 
     /*
@@ -1033,6 +1036,8 @@ typedef struct _cairo_traps {
 #define CAIRO_GSTATE_MITER_LIMIT_DEFAULT	10.0
 #define CAIRO_GSTATE_DEFAULT_FONT_SIZE  10.0
 
+#define CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT 300.0
+
 typedef struct _cairo_gstate cairo_gstate_t;
 
 typedef struct _cairo_stroke_face {
diff --git a/test/cairo-test.c b/test/cairo-test.c
index 3005638..0103e46 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -1158,7 +1158,7 @@ create_ps_surface (cairo_test_t		 *test,
 	free (ptc);
 	return NULL;
     }
-    cairo_ps_surface_set_dpi (surface, 72., 72.);
+    cairo_surface_set_fallback_resolution (surface, 72., 72.);
 
     if (content == CAIRO_CONTENT_COLOR) {
 	ptc->target = surface;
@@ -1259,7 +1259,7 @@ create_pdf_surface (cairo_test_t	 *test,
 	free (ptc);
 	return NULL;
     }
-    cairo_pdf_surface_set_dpi (surface, 72., 72.);
+    cairo_surface_set_fallback_resolution (surface, 72., 72.);
 
     if (content == CAIRO_CONTENT_COLOR) {
 	ptc->target = surface;
@@ -1369,7 +1369,7 @@ create_svg_surface (cairo_test_t	 *test,
 	free (ptc);
 	return NULL;
     }
-    cairo_svg_surface_set_dpi (surface, 72., 72.);
+    cairo_surface_set_fallback_resolution (surface, 72., 72.);
 
     if (content == CAIRO_CONTENT_COLOR) {
 	ptc->target = surface;
diff --git a/test/fallback-resolution.c b/test/fallback-resolution.c
index 0028301..421755d 100644
--- a/test/fallback-resolution.c
+++ b/test/fallback-resolution.c
@@ -58,7 +58,7 @@ main (void)
     cairo_pdf_test_force_fallbacks ();
 
     for (i = 0; i < sizeof(dpi) / sizeof (dpi[0]); i++) {
-	cairo_pdf_surface_set_dpi (surface, dpi[i], dpi[i]);
+	cairo_surface_set_fallback_resolution (surface, dpi[i], dpi[i]);
 	cairo_arc (cr, SIZE / 2.0, SIZE / 2.0,
 		   0.75 * SIZE / 2.0,
 		   0, 2.0 * M_PI);


More information about the cairo-commit mailing list