b=418353, sync up cairo to 1.5.8-87-g21049a9 imported patch 418353-cairo-upgrade.patch
authorvladimir@pobox.com
Tue, 19 Feb 2008 14:52:57 -0800
changeset 11886 e316520b1b4416a698d68d93fd44928d13d932a6
parent 11885 2a4550a18d319c7f5088c4aa3a69298e6ba35367
child 11887 41acaef813e4c14fa81300139e47ea13a6d91a7a
push idunknown
push userunknown
push dateunknown
bugs418353
milestone1.9b4pre
b=418353, sync up cairo to 1.5.8-87-g21049a9 imported patch 418353-cairo-upgrade.patch
gfx/cairo/README
gfx/cairo/cairo/src/Makefile.in
gfx/cairo/cairo/src/cairo-debug.c
gfx/cairo/cairo/src/cairo-font-face.c
gfx/cairo/cairo/src/cairo-font-options.c
gfx/cairo/cairo/src/cairo-ft-font.c
gfx/cairo/cairo/src/cairo-gstate.c
gfx/cairo/cairo/src/cairo-meta-surface.c
gfx/cairo/cairo/src/cairo-misc.c
gfx/cairo/cairo/src/cairo-mutex-list-private.h
gfx/cairo/cairo/src/cairo-os2-surface.c
gfx/cairo/cairo/src/cairo-output-stream-private.h
gfx/cairo/cairo/src/cairo-path-stroke.c
gfx/cairo/cairo/src/cairo-pdf-operators-private.h
gfx/cairo/cairo/src/cairo-pdf-operators.c
gfx/cairo/cairo/src/cairo-pdf-surface-private.h
gfx/cairo/cairo/src/cairo-pdf-surface.c
gfx/cairo/cairo/src/cairo-png.c
gfx/cairo/cairo/src/cairo-ps-surface-private.h
gfx/cairo/cairo/src/cairo-ps-surface.c
gfx/cairo/cairo/src/cairo-scaled-font.c
gfx/cairo/cairo/src/cairo-surface.c
gfx/cairo/cairo/src/cairo-win32-font.c
gfx/cairo/cairo/src/cairo-win32-printing-surface.c
gfx/cairo/cairo/src/cairo-xlib-surface.c
gfx/cairo/cairo/src/cairo.c
gfx/cairo/cairo/src/cairo.h
gfx/cairo/cairo/src/cairoint.h
gfx/cairo/libpixman/src/pixman-compose.c
gfx/cairo/libpixman/src/pixman-private.h
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -2,18 +2,18 @@ Snapshots of cairo and glitz for mozilla
 
 We only include the relevant parts of each release (generally, src/*.[ch]),
 as we have Makefile.in's that integrate into the Mozilla build system.  For
 documentation and similar, please see the official tarballs at
 http://www.cairographics.org/.
 
 VERSIONS:
 
-  cairo (1.5.x - 1.5.8-30-g80e11a8)
-  pixman (0.9.x - pixman-0.9.6-34-g787cc57)
+  cairo (1.5.x - 1.5.8-87-g21049a9)
+  pixman (0.9.x - pixman-0.9.6-37-g8d79c48)
   glitz 0.5.2 (cvs - 2006-01-10)
 
 ***** NOTE FOR VISUAL C++ 6.0 *****
 
 VC6 is not supported.  Please upgrade to VC8.
 
 ==== Patches ====
 
--- a/gfx/cairo/cairo/src/Makefile.in
+++ b/gfx/cairo/cairo/src/Makefile.in
@@ -89,16 +89,17 @@ CSRCS   = \
         cairo-freelist.c \
         cairo-gstate.c \
         cairo-hash.c \
         cairo-hull.c \
         cairo-image-surface.c \
         cairo-lzw.c \
         cairo-matrix.c \
         cairo-meta-surface.c \
+	cairo-misc.c \
 	cairo-mutex.c \
         cairo-output-stream.c \
         cairo-paginated-surface.c \
         cairo-path.c \
         cairo-path-bounds.c \
         cairo-path-fill.c \
         cairo-path-fixed.c \
         cairo-path-stroke.c \
--- a/gfx/cairo/cairo/src/cairo-debug.c
+++ b/gfx/cairo/cairo/src/cairo-debug.c
@@ -64,10 +64,12 @@ cairo_debug_reset_static_data (void)
     _cairo_font_reset_static_data ();
 
 #if CAIRO_HAS_FT_FONT
     _cairo_ft_font_reset_static_data ();
 #endif
 
     _cairo_pattern_reset_static_data ();
 
+    _cairo_scaled_font_reset_static_data ();
+
     CAIRO_MUTEX_FINALIZE ();
 }
--- a/gfx/cairo/cairo/src/cairo-font-face.c
+++ b/gfx/cairo/cairo/src/cairo-font-face.c
@@ -471,21 +471,19 @@ static cairo_status_t
 {
     cairo_toy_font_face_t *font_face = abstract_font_face;
     const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT;
     cairo_status_t status;
 
     if (font_face->base.status)
 	return font_face->base.status;
 
-    if (options != NULL) {
-	status = cairo_font_options_status ((cairo_font_options_t *) options);
-	if (status)
-	    return status;
-    }
+    status = cairo_font_options_status ((cairo_font_options_t *) options);
+    if (status)
+	return status;
 
     return _cairo_font_face_set_error (&font_face->base,
 	                               backend->create_toy (font_face,
 				                            font_matrix,
 							    ctm,
 							    options,
 							    scaled_font));
 }
--- a/gfx/cairo/cairo/src/cairo-font-options.c
+++ b/gfx/cairo/cairo/src/cairo-font-options.c
@@ -47,36 +47,30 @@ static const cairo_font_options_t _cairo
  * _cairo_font_options_init_default:
  * @options: a #cairo_font_options_t
  *
  * Initializes all fields of the font options object to default values.
  **/
 void
 _cairo_font_options_init_default (cairo_font_options_t *options)
 {
-    if (cairo_font_options_status (options))
-	return;
-
     options->antialias = CAIRO_ANTIALIAS_DEFAULT;
     options->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
     options->hint_style = CAIRO_HINT_STYLE_DEFAULT;
     options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT;
 }
 
 void
 _cairo_font_options_init_copy (cairo_font_options_t		*options,
 			       const cairo_font_options_t	*other)
 {
-    if (other != NULL) {
-	options->antialias = other->antialias;
-	options->subpixel_order = other->subpixel_order;
-	options->hint_style = other->hint_style;
-	options->hint_metrics = other->hint_metrics;
-    } else
-	_cairo_font_options_init_default (options);
+    options->antialias = other->antialias;
+    options->subpixel_order = other->subpixel_order;
+    options->hint_style = other->hint_style;
+    options->hint_metrics = other->hint_metrics;
 }
 
 /**
  * cairo_font_options_create:
  *
  * Allocates a new font options object with all options initialized
  *  to default values.
  *
@@ -116,21 +110,18 @@ slim_hidden_def (cairo_font_options_crea
  *   error object is returned where all operations on the object do nothing.
  *   You can check for this with cairo_font_options_status().
  **/
 cairo_font_options_t *
 cairo_font_options_copy (const cairo_font_options_t *original)
 {
     cairo_font_options_t *options;
 
-    if (original != NULL &&
-	cairo_font_options_status ((cairo_font_options_t *) original))
-    {
+    if (cairo_font_options_status ((cairo_font_options_t *) original))
 	return (cairo_font_options_t *) &_cairo_font_options_nil;
-    }
 
     options = malloc (sizeof (cairo_font_options_t));
     if (!options) {
 	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
 	return (cairo_font_options_t *) &_cairo_font_options_nil;
     }
 
     _cairo_font_options_init_copy (options, original);
@@ -188,17 +179,16 @@ slim_hidden_def (cairo_font_options_stat
  **/
 void
 cairo_font_options_merge (cairo_font_options_t       *options,
 			  const cairo_font_options_t *other)
 {
     if (cairo_font_options_status (options))
 	return;
 
-    /* A NULL other maps to the defaults and would not overwrite options */
     if (cairo_font_options_status ((cairo_font_options_t *) other))
 	return;
 
     if (other->antialias != CAIRO_ANTIALIAS_DEFAULT)
 	options->antialias = other->antialias;
     if (other->subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT)
 	options->subpixel_order = other->subpixel_order;
     if (other->hint_style != CAIRO_HINT_STYLE_DEFAULT)
@@ -210,26 +200,28 @@ slim_hidden_def (cairo_font_options_merg
 
 /**
  * cairo_font_options_equal:
  * @options: a #cairo_font_options_t
  * @other: another #cairo_font_options_t
  *
  * Compares two font options objects for equality.
  *
- * Return value: %TRUE if all fields of the two font options objects match
+ * Return value: %TRUE if all fields of the two font options objects match.
+ *	Note that this function will return %FALSE if either object is in
+ *	error.
  **/
 cairo_bool_t
 cairo_font_options_equal (const cairo_font_options_t *options,
 			  const cairo_font_options_t *other)
 {
-    if (options == NULL)
-	options = &_cairo_font_options_nil;
-    if (other == NULL)
-	other = &_cairo_font_options_nil;
+    if (cairo_font_options_status ((cairo_font_options_t *) options))
+	return FALSE;
+    if (cairo_font_options_status ((cairo_font_options_t *) other))
+	return FALSE;
 
     if (options == other)
 	return TRUE;
 
     return (options->antialias == other->antialias &&
 	    options->subpixel_order == other->subpixel_order &&
 	    options->hint_style == other->hint_style &&
 	    options->hint_metrics == other->hint_metrics);
@@ -246,18 +238,18 @@ slim_hidden_def (cairo_font_options_equa
  *
  * Return value: the hash value for the font options object.
  *   The return value can be cast to a 32-bit type if a
  *   32-bit hash value is needed.
  **/
 unsigned long
 cairo_font_options_hash (const cairo_font_options_t *options)
 {
-    if (options == NULL)
-	options = &_cairo_font_options_nil;
+    if (cairo_font_options_status ((cairo_font_options_t *) options))
+	options = &_cairo_font_options_nil; /* force default values */
 
     return ((options->antialias) |
 	    (options->subpixel_order << 4) |
 	    (options->hint_style << 8) |
 	    (options->hint_metrics << 16));
 }
 slim_hidden_def (cairo_font_options_hash);
 
--- a/gfx/cairo/cairo/src/cairo-ft-font.c
+++ b/gfx/cairo/cairo/src/cairo-ft-font.c
@@ -940,17 +940,17 @@ static cairo_status_t
     }
 
     *surface = (cairo_image_surface_t *)
 	cairo_image_surface_create_for_data (data,
 					     format,
 					     width, height, stride);
     if ((*surface)->base.status) {
 	free (data);
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return (*surface)->base.status;
     }
 
     if (subpixel)
 	pixman_image_set_component_alpha ((*surface)->pixman_image, TRUE);
 
     _cairo_image_surface_assume_ownership_of_data ((*surface));
 
     return CAIRO_STATUS_SUCCESS;
@@ -1059,19 +1059,18 @@ static cairo_status_t
 	    bitmap.num_grays  = 256;
 	    stride = (width * hmul + 3) & -4;
 	}
 
 	bitmap.pitch = stride;
 	bitmap.width = width * hmul;
 	bitmap.rows = height * vmul;
 	bitmap.buffer = calloc (stride, bitmap.rows);
-	if (bitmap.buffer == NULL) {
+	if (bitmap.buffer == NULL)
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	}
 
 	FT_Outline_Translate (outline, -cbox.xMin*hmul, -cbox.yMin*vmul);
 
 	if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
 	    free (bitmap.buffer);
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	}
 
@@ -1611,16 +1610,21 @@ static cairo_status_t
     FcResult result;
     int fcslant;
     int fcweight;
     cairo_matrix_t scale;
     cairo_status_t status;
     cairo_ft_font_transform_t sf;
     cairo_ft_options_t ft_options;
 
+    cairo_matrix_multiply (&scale, font_matrix, ctm);
+    status = _compute_transform (&sf, &scale);
+    if (status)
+	return status;
+
     pattern = FcPatternCreate ();
     if (!pattern)
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     if (!FcPatternAddString (pattern,
 		             FC_FAMILY, (unsigned char *) toy_face->family))
     {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -1657,34 +1661,29 @@ static cairo_status_t
         break;
     }
 
     if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight)) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	goto FREE_PATTERN;
     }
 
-    cairo_matrix_multiply (&scale, font_matrix, ctm);
-    _compute_transform (&sf, &scale);
-
     if (! FcPatternAddDouble (pattern, FC_PIXEL_SIZE, sf.y_scale)) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	goto FREE_PATTERN;
     }
 
     if (! FcConfigSubstitute (NULL, pattern, FcMatchPattern)) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	goto FREE_PATTERN;
     }
 
-    if (font_options != NULL) {
-	status = _cairo_ft_font_options_substitute (font_options, pattern);
-	if (status)
-	    goto FREE_PATTERN;
-    }
+    status = _cairo_ft_font_options_substitute (font_options, pattern);
+    if (status)
+	goto FREE_PATTERN;
 
     FcDefaultSubstitute (pattern);
 
     resolved = FcFontMatch (NULL, pattern, &result);
     if (!resolved) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	goto FREE_PATTERN;
     }
@@ -2318,17 +2317,17 @@ static cairo_font_face_t *
     for (font_face = unscaled->faces, prev_font_face = &unscaled->faces;
 	 font_face;
 	 prev_font_face = &font_face->next, font_face = font_face->next)
     {
 	if (font_face->ft_options.load_flags == ft_options->load_flags &&
 	    font_face->ft_options.extra_flags == ft_options->extra_flags &&
 	    cairo_font_options_equal (&font_face->ft_options.base, &ft_options->base))
 	{
-	    if (! font_face->base.status)
+	    if (font_face->base.status == CAIRO_STATUS_SUCCESS)
 		return cairo_font_face_reference (&font_face->base);
 
 	    /* The font_face has been left in an error state, abandon it. */
 	    *prev_font_face = font_face->next;
 	    break;
 	}
     }
 
--- a/gfx/cairo/cairo/src/cairo-gstate.c
+++ b/gfx/cairo/cairo/src/cairo-gstate.c
@@ -895,95 +895,16 @@ cairo_status_t
 				   gstate->op,
 				   &pattern.base);
 
     _cairo_pattern_fini (&pattern.base);
 
     return status;
 }
 
-/**
- * _cairo_operator_bounded_by_mask:
- * @op: a #cairo_operator_t
- *
- * A bounded operator is one where mask pixel
- * of zero results in no effect on the destination image.
- *
- * Unbounded operators often require special handling; if you, for
- * example, draw trapezoids with an unbounded operator, the effect
- * extends past the bounding box of the trapezoids.
- *
- * Return value: %TRUE if the operator is bounded by the mask operand
- **/
-cairo_bool_t
-_cairo_operator_bounded_by_mask (cairo_operator_t op)
-{
-    switch (op) {
-    case CAIRO_OPERATOR_CLEAR:
-    case CAIRO_OPERATOR_SOURCE:
-    case CAIRO_OPERATOR_OVER:
-    case CAIRO_OPERATOR_ATOP:
-    case CAIRO_OPERATOR_DEST:
-    case CAIRO_OPERATOR_DEST_OVER:
-    case CAIRO_OPERATOR_DEST_OUT:
-    case CAIRO_OPERATOR_XOR:
-    case CAIRO_OPERATOR_ADD:
-    case CAIRO_OPERATOR_SATURATE:
-	return TRUE;
-    case CAIRO_OPERATOR_OUT:
-    case CAIRO_OPERATOR_IN:
-    case CAIRO_OPERATOR_DEST_IN:
-    case CAIRO_OPERATOR_DEST_ATOP:
-	return FALSE;
-    }
-
-    ASSERT_NOT_REACHED;
-    return FALSE;
-}
-
-/**
- * _cairo_operator_bounded_by_source:
- * @op: a #cairo_operator_t
- *
- * A bounded operator is one where source pixels of zero
- * (in all four components, r, g, b and a) effect no change
- * in the resulting destination image.
- *
- * Unbounded operators often require special handling; if you, for
- * example, copy a surface with the SOURCE operator, the effect
- * extends past the bounding box of the source surface.
- *
- * Return value: %TRUE if the operator is bounded by the source operand
- **/
-cairo_bool_t
-_cairo_operator_bounded_by_source (cairo_operator_t op)
-{
-    switch (op) {
-    case CAIRO_OPERATOR_OVER:
-    case CAIRO_OPERATOR_ATOP:
-    case CAIRO_OPERATOR_DEST:
-    case CAIRO_OPERATOR_DEST_OVER:
-    case CAIRO_OPERATOR_DEST_OUT:
-    case CAIRO_OPERATOR_XOR:
-    case CAIRO_OPERATOR_ADD:
-    case CAIRO_OPERATOR_SATURATE:
-	return TRUE;
-    case CAIRO_OPERATOR_CLEAR:
-    case CAIRO_OPERATOR_SOURCE:
-    case CAIRO_OPERATOR_OUT:
-    case CAIRO_OPERATOR_IN:
-    case CAIRO_OPERATOR_DEST_IN:
-    case CAIRO_OPERATOR_DEST_ATOP:
-	return FALSE;
-    }
-
-    ASSERT_NOT_REACHED;
-    return FALSE;
-}
-
 cairo_status_t
 _cairo_gstate_mask (cairo_gstate_t  *gstate,
 		    cairo_pattern_t *mask)
 {
     cairo_status_t status;
     cairo_pattern_union_t source_pattern, mask_pattern;
 
     if (mask->status)
--- a/gfx/cairo/cairo/src/cairo-meta-surface.c
+++ b/gfx/cairo/cairo/src/cairo-meta-surface.c
@@ -739,17 +739,22 @@ static cairo_status_t
 					    command->stroke.antialias);
 	    break;
 	}
 	case CAIRO_COMMAND_FILL:
 	{
 	    cairo_command_t *stroke_command;
 
 	    stroke_command = (i < num_elements - 1) ? elements[i + 1] : NULL;
-
+	    if (stroke_command != NULL &&
+		type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL)
+	    {
+		if (stroke_command->header.region != region)
+		    stroke_command = NULL;
+	    }
 	    if (stroke_command != NULL &&
 		stroke_command->header.type == CAIRO_COMMAND_STROKE &&
 		_cairo_path_fixed_is_equal (dev_path, _cairo_command_get_path (stroke_command))) {
 		cairo_matrix_t dev_ctm;
 		cairo_matrix_t dev_ctm_inverse;
 		cairo_matrix_t tmp;
 
 		dev_ctm = stroke_command->stroke.ctm;
@@ -773,16 +778,24 @@ static cairo_status_t
 						     stroke_command->stroke.op,
 						     &stroke_command->stroke.source.base,
 						     &stroke_command->stroke.style,
 						     &dev_ctm,
 						     &dev_ctm_inverse,
 						     stroke_command->stroke.tolerance * tolerance_multiplier,
 						     stroke_command->stroke.antialias);
 		i++;
+		if (type == CAIRO_META_CREATE_REGIONS) {
+		    if (status == CAIRO_STATUS_SUCCESS) {
+			stroke_command->header.region = CAIRO_META_REGION_NATIVE;
+		    } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
+			stroke_command->header.region = CAIRO_META_REGION_IMAGE_FALLBACK;
+			status = CAIRO_STATUS_SUCCESS;
+		    }
+		}
 	    } else
 		status = _cairo_surface_fill (target,
 					      command->fill.op,
 					      &command->fill.source.base,
 					      dev_path,
 					      command->fill.fill_rule,
 					      command->fill.tolerance * tolerance_multiplier,
 					      command->fill.antialias);
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/cairo/src/cairo-misc.c
@@ -0,0 +1,407 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * 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 University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Carl D. Worth <cworth@cworth.org>
+ */
+
+#include "cairoint.h"
+
+
+/**
+ * cairo_status_to_string:
+ * @status: a cairo status
+ *
+ * Provides a human-readable description of a #cairo_status_t.
+ *
+ * Returns: a string representation of the status
+ */
+const char *
+cairo_status_to_string (cairo_status_t status)
+{
+    switch (status) {
+    case CAIRO_STATUS_SUCCESS:
+	return "success";
+    case CAIRO_STATUS_NO_MEMORY:
+	return "out of memory";
+    case CAIRO_STATUS_INVALID_RESTORE:
+	return "cairo_restore without matching cairo_save";
+    case CAIRO_STATUS_INVALID_POP_GROUP:
+	return "cairo_pop_group without matching cairo_push_group";
+    case CAIRO_STATUS_NO_CURRENT_POINT:
+	return "no current point defined";
+    case CAIRO_STATUS_INVALID_MATRIX:
+	return "invalid matrix (not invertible)";
+    case CAIRO_STATUS_INVALID_STATUS:
+	return "invalid value for an input cairo_status_t";
+    case CAIRO_STATUS_NULL_POINTER:
+	return "NULL pointer";
+    case CAIRO_STATUS_INVALID_STRING:
+	return "input string not valid UTF-8";
+    case CAIRO_STATUS_INVALID_PATH_DATA:
+	return "input path data not valid";
+    case CAIRO_STATUS_READ_ERROR:
+	return "error while reading from input stream";
+    case CAIRO_STATUS_WRITE_ERROR:
+	return "error while writing to output stream";
+    case CAIRO_STATUS_SURFACE_FINISHED:
+	return "the target surface has been finished";
+    case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
+	return "the surface type is not appropriate for the operation";
+    case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
+	return "the pattern type is not appropriate for the operation";
+    case CAIRO_STATUS_INVALID_CONTENT:
+	return "invalid value for an input cairo_content_t";
+    case CAIRO_STATUS_INVALID_FORMAT:
+	return "invalid value for an input cairo_format_t";
+    case CAIRO_STATUS_INVALID_VISUAL:
+	return "invalid value for an input Visual*";
+    case CAIRO_STATUS_FILE_NOT_FOUND:
+	return "file not found";
+    case CAIRO_STATUS_INVALID_DASH:
+	return "invalid value for a dash setting";
+    case CAIRO_STATUS_INVALID_DSC_COMMENT:
+	return "invalid value for a DSC comment";
+    case CAIRO_STATUS_INVALID_INDEX:
+	return "invalid index passed to getter";
+    case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
+        return "clip region not representable in desired format";
+    case CAIRO_STATUS_TEMP_FILE_ERROR:
+	return "error creating or writing to a temporary file";
+    case CAIRO_STATUS_INVALID_STRIDE:
+	return "invalid value for stride";
+    }
+
+    return "<unknown error status>";
+}
+
+/**
+ * _cairo_operator_bounded_by_mask:
+ * @op: a #cairo_operator_t
+ *
+ * A bounded operator is one where mask pixel
+ * of zero results in no effect on the destination image.
+ *
+ * Unbounded operators often require special handling; if you, for
+ * example, draw trapezoids with an unbounded operator, the effect
+ * extends past the bounding box of the trapezoids.
+ *
+ * Return value: %TRUE if the operator is bounded by the mask operand
+ **/
+cairo_bool_t
+_cairo_operator_bounded_by_mask (cairo_operator_t op)
+{
+    switch (op) {
+    case CAIRO_OPERATOR_CLEAR:
+    case CAIRO_OPERATOR_SOURCE:
+    case CAIRO_OPERATOR_OVER:
+    case CAIRO_OPERATOR_ATOP:
+    case CAIRO_OPERATOR_DEST:
+    case CAIRO_OPERATOR_DEST_OVER:
+    case CAIRO_OPERATOR_DEST_OUT:
+    case CAIRO_OPERATOR_XOR:
+    case CAIRO_OPERATOR_ADD:
+    case CAIRO_OPERATOR_SATURATE:
+	return TRUE;
+    case CAIRO_OPERATOR_OUT:
+    case CAIRO_OPERATOR_IN:
+    case CAIRO_OPERATOR_DEST_IN:
+    case CAIRO_OPERATOR_DEST_ATOP:
+	return FALSE;
+    }
+
+    ASSERT_NOT_REACHED;
+    return FALSE;
+}
+
+/**
+ * _cairo_operator_bounded_by_source:
+ * @op: a #cairo_operator_t
+ *
+ * A bounded operator is one where source pixels of zero
+ * (in all four components, r, g, b and a) effect no change
+ * in the resulting destination image.
+ *
+ * Unbounded operators often require special handling; if you, for
+ * example, copy a surface with the SOURCE operator, the effect
+ * extends past the bounding box of the source surface.
+ *
+ * Return value: %TRUE if the operator is bounded by the source operand
+ **/
+cairo_bool_t
+_cairo_operator_bounded_by_source (cairo_operator_t op)
+{
+    switch (op) {
+    case CAIRO_OPERATOR_OVER:
+    case CAIRO_OPERATOR_ATOP:
+    case CAIRO_OPERATOR_DEST:
+    case CAIRO_OPERATOR_DEST_OVER:
+    case CAIRO_OPERATOR_DEST_OUT:
+    case CAIRO_OPERATOR_XOR:
+    case CAIRO_OPERATOR_ADD:
+    case CAIRO_OPERATOR_SATURATE:
+	return TRUE;
+    case CAIRO_OPERATOR_CLEAR:
+    case CAIRO_OPERATOR_SOURCE:
+    case CAIRO_OPERATOR_OUT:
+    case CAIRO_OPERATOR_IN:
+    case CAIRO_OPERATOR_DEST_IN:
+    case CAIRO_OPERATOR_DEST_ATOP:
+	return FALSE;
+    }
+
+    ASSERT_NOT_REACHED;
+    return FALSE;
+}
+
+
+void
+_cairo_restrict_value (double *value, double min, double max)
+{
+    if (*value < min)
+	*value = min;
+    else if (*value > max)
+	*value = max;
+}
+
+/* This function is identical to the C99 function lround(), except that it
+ * performs arithmetic rounding (instead of away-from-zero rounding) and
+ * has a valid input range of (INT_MIN, INT_MAX] instead of
+ * [INT_MIN, INT_MAX]. It is much faster on both x86 and FPU-less systems
+ * than other commonly used methods for rounding (lround, round, rint, lrint
+ * or float (d + 0.5)).
+ *
+ * The reason why this function is much faster on x86 than other
+ * methods is due to the fact that it avoids the fldcw instruction.
+ * This instruction incurs a large performance penalty on modern Intel
+ * processors due to how it prevents efficient instruction pipelining.
+ *
+ * The reason why this function is much faster on FPU-less systems is for
+ * an entirely different reason. All common rounding methods involve multiple
+ * floating-point operations. Each one of these operations has to be
+ * emulated in software, which adds up to be a large performance penalty.
+ * This function doesn't perform any floating-point calculations, and thus
+ * avoids this penalty.
+  */
+int
+_cairo_lround (double d)
+{
+    uint32_t top, shift_amount, output;
+    union {
+        double d;
+        uint64_t ui64;
+        uint32_t ui32[2];
+    } u;
+
+    u.d = d;
+
+    /* If the integer word order doesn't match the float word order, we swap
+     * the words of the input double. This is needed because we will be
+     * treating the whole double as a 64-bit unsigned integer. Notice that we
+     * use WORDS_BIGENDIAN to detect the integer word order, which isn't
+     * exactly correct because WORDS_BIGENDIAN refers to byte order, not word
+     * order. Thus, we are making the assumption that the byte order is the
+     * same as the integer word order which, on the modern machines that we
+     * care about, is OK.
+     */
+#if ( defined(FLOAT_WORDS_BIGENDIAN) && !defined(WORDS_BIGENDIAN)) || \
+    (!defined(FLOAT_WORDS_BIGENDIAN) &&  defined(WORDS_BIGENDIAN))
+    {
+        uint32_t temp = u.ui32[0];
+        u.ui32[0] = u.ui32[1];
+        u.ui32[1] = temp;
+    }
+#endif
+
+#ifdef WORDS_BIGENDIAN
+    #define MSW (0) /* Most Significant Word */
+    #define LSW (1) /* Least Significant Word */
+#else
+    #define MSW (1)
+    #define LSW (0)
+#endif
+
+    /* By shifting the most significant word of the input double to the
+     * right 20 places, we get the very "top" of the double where the exponent
+     * and sign bit lie.
+     */
+    top = u.ui32[MSW] >> 20;
+
+    /* Here, we calculate how much we have to shift the mantissa to normalize
+     * it to an integer value. We extract the exponent "top" by masking out the
+     * sign bit, then we calculate the shift amount by subtracting the exponent
+     * from the bias. Notice that the correct bias for 64-bit doubles is
+     * actually 1075, but we use 1053 instead for two reasons:
+     *
+     *  1) To perform rounding later on, we will first need the target
+     *     value in a 31.1 fixed-point format. Thus, the bias needs to be one
+     *     less: (1075 - 1: 1074).
+     *
+     *  2) To avoid shifting the mantissa as a full 64-bit integer (which is
+     *     costly on certain architectures), we break the shift into two parts.
+     *     First, the upper and lower parts of the mantissa are shifted
+     *     individually by a constant amount that all valid inputs will require
+     *     at the very least. This amount is chosen to be 21, because this will
+     *     allow the two parts of the mantissa to later be combined into a
+     *     single 32-bit representation, on which the remainder of the shift
+     *     will be performed. Thus, we decrease the bias by an additional 21:
+     *     (1074 - 21: 1053).
+     */
+    shift_amount = 1053 - (top & 0x7FF);
+
+    /* We are done with the exponent portion in "top", so here we shift it off
+     * the end.
+     */
+    top >>= 11;
+
+    /* Before we perform any operations on the mantissa, we need to OR in
+     * the implicit 1 at the top (see the IEEE-754 spec). We needn't mask
+     * off the sign bit nor the exponent bits because these higher bits won't
+     * make a bit of difference in the rest of our calculations.
+     */
+    u.ui32[MSW] |= 0x100000;
+
+    /* If the input double is negative, we have to decrease the mantissa
+     * by a hair. This is an important part of performing arithmetic rounding,
+     * as negative numbers must round towards positive infinity in the
+     * halfwase case of -x.5. Since "top" contains only the sign bit at this
+     * point, we can just decrease the mantissa by the value of "top".
+     */
+    u.ui64 -= top;
+
+    /* By decrementing "top", we create a bitmask with a value of either
+     * 0x0 (if the input was negative) or 0xFFFFFFFF (if the input was positive
+     * and thus the unsigned subtraction underflowed) that we'll use later.
+     */
+    top--;
+
+    /* Here, we shift the mantissa by the constant value as described above.
+     * We can emulate a 64-bit shift right by 21 through shifting the top 32
+     * bits left 11 places and ORing in the bottom 32 bits shifted 21 places
+     * to the right. Both parts of the mantissa are now packed into a single
+     * 32-bit integer. Although we severely truncate the lower part in the
+     * process, we still have enough significant bits to perform the conversion
+     * without error (for all valid inputs).
+     */
+    output = (u.ui32[MSW] << 11) | (u.ui32[LSW] >> 21);
+
+    /* Next, we perform the shift that converts the X.Y fixed-point number
+     * currently found in "output" to the desired 31.1 fixed-point format
+     * needed for the following rounding step. It is important to consider
+     * all possible values for "shift_amount" at this point:
+     *
+     * - {shift_amount < 0} Since shift_amount is an unsigned integer, it
+     *   really can't have a value less than zero. But, if the shift_amount
+     *   calculation above caused underflow (which would happen with
+     *   input > INT_MAX or input <= INT_MIN) then shift_amount will now be
+     *   a very large number, and so this shift will result in complete
+     *   garbage. But that's OK, as the input was out of our range, so our
+     *   output is undefined.
+     *
+     * - {shift_amount > 31} If the magnitude of the input was very small
+     *   (i.e. |input| << 1.0), shift_amount will have a value greater than
+     *   31. Thus, this shift will also result in garbage. After performing
+     *   the shift, we will zero-out "output" if this is the case.
+     *
+     * - {0 <= shift_amount < 32} In this case, the shift will properly convert
+     *   the mantissa into a 31.1 fixed-point number.
+     */
+    output >>= shift_amount;
+
+    /* This is where we perform rounding with the 31.1 fixed-point number.
+     * Since what we're after is arithmetic rounding, we simply add the single
+     * fractional bit into the integer part of "output", and just keep the
+     * integer part.
+     */
+    output = (output >> 1) + (output & 1);
+
+    /* Here, we zero-out the result if the magnitude if the input was very small
+     * (as explained in the section above). Notice that all input out of the
+     * valid range is also caught by this condition, which means we produce 0
+     * for all invalid input, which is a nice side effect.
+     *
+     * The most straightforward way to do this would be:
+     *
+     *      if (shift_amount > 31)
+     *          output = 0;
+     *
+     * But we can use a little trick to avoid the potential branch. The
+     * expression (shift_amount > 31) will be either 1 or 0, which when
+     * decremented will be either 0x0 or 0xFFFFFFFF (unsigned underflow),
+     * which can be used to conditionally mask away all the bits in "output"
+     * (in the 0x0 case), effectively zeroing it out. Certain, compilers would
+     * have done this for us automatically.
+     */
+    output &= ((shift_amount > 31) - 1);
+
+    /* If the input double was a negative number, then we have to negate our
+     * output. The most straightforward way to do this would be:
+     *
+     *      if (!top)
+     *          output = -output;
+     *
+     * as "top" at this point is either 0x0 (if the input was negative) or
+     * 0xFFFFFFFF (if the input was positive). But, we can use a trick to
+     * avoid the branch. Observe that the following snippet of code has the
+     * same effect as the reference snippet above:
+     *
+     *      if (!top)
+     *          output = 0 - output;
+     *      else
+     *          output = output - 0;
+     *
+     * Armed with the bitmask found in "top", we can condense the two statements
+     * into the following:
+     *
+     *      output = (output & top) - (output & ~top);
+     *
+     * where, in the case that the input double was negative, "top" will be 0,
+     * and the statement will be equivalent to:
+     *
+     *      output = (0) - (output);
+     *
+     * and if the input double was positive, "top" will be 0xFFFFFFFF, and the
+     * statement will be equivalent to:
+     *
+     *      output = (output) - (0);
+     *
+     * Which, as pointed out earlier, is equivalent to the original reference
+     * snippet.
+     */
+    output = (output & top) - (output & ~top);
+
+    return output;
+#undef MSW
+#undef LSW
+}
--- a/gfx/cairo/cairo/src/cairo-mutex-list-private.h
+++ b/gfx/cairo/cairo/src/cairo-mutex-list-private.h
@@ -32,16 +32,17 @@
  */
 
 
 CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_pattern_cache_lock);
 CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock);
 
 CAIRO_MUTEX_DECLARE (_cairo_font_face_mutex);
 CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex);
+CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex);
 
 #if CAIRO_HAS_FT_FONT
 CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex);
 #endif
 
 #if CAIRO_HAS_XLIB_SURFACE
 CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex);
 #endif
--- a/gfx/cairo/cairo/src/cairo-os2-surface.c
+++ b/gfx/cairo/cairo/src/cairo-os2-surface.c
@@ -101,18 +101,20 @@ cairo_os2_init (void)
 {
     /* This may initialize some stuffs, like create mutex semaphores etc.. */
 
     cairo_os2_initialization_count++;
     if (cairo_os2_initialization_count > 1) return;
 
     DisableFPUException ();
 
+#if CAIRO_HAS_FT_FONT
     /* Initialize FontConfig */
     FcInit ();
+#endif
 
     CAIRO_MUTEX_INITIALIZE ();
 }
 
 /**
  * cairo_os2_fini:
  *
  * Uninitializes the Cairo library. This function is automatically called if
@@ -129,26 +131,28 @@ cairo_os2_fini (void)
 
     if (cairo_os2_initialization_count <= 0) return;
     cairo_os2_initialization_count--;
     if (cairo_os2_initialization_count > 0) return;
 
     DisableFPUException ();
 
     /* Free allocated memories! */
-    /* (Check cairo_debug_reset_static_date () for an example of this!) */
+    /* (Check cairo_debug_reset_static_data () for an example of this!) */
     _cairo_font_reset_static_data ();
-#ifdef CAIRO_HAS_FT_FONT
+#if CAIRO_HAS_FT_FONT
     _cairo_ft_font_reset_static_data ();
 #endif
 
     CAIRO_MUTEX_FINALIZE ();
 
+#if CAIRO_HAS_FT_FONT
     /* Uninitialize FontConfig */
     FcFini ();
+#endif
 
 #ifdef __WATCOMC__
     /* It can happen that the libraries we use have memory leaks,
      * so there are still memory chunks allocated at this point.
      * In these cases, Watcom might still have a bigger memory chunk,
      * called "the heap" allocated from the OS.
      * As we want to minimize the memory we lose from the point of
      * view of the OS, we call this function to shrink that heap
--- a/gfx/cairo/cairo/src/cairo-output-stream-private.h
+++ b/gfx/cairo/cairo/src/cairo-output-stream-private.h
@@ -110,21 +110,23 @@ cairo_private void
 				       const char *data,
 				       size_t length);
 
 cairo_private void
 _cairo_dtostr (char *buffer, size_t size, double d);
 
 cairo_private void
 _cairo_output_stream_vprintf (cairo_output_stream_t *stream,
-			      const char *fmt, va_list ap);
+			      const char *fmt,
+			      va_list ap) CAIRO_PRINTF_FORMAT ( 2, 0);
 
 cairo_private void
 _cairo_output_stream_printf (cairo_output_stream_t *stream,
-			     const char *fmt, ...);
+			     const char *fmt,
+			     ...) CAIRO_PRINTF_FORMAT (2, 3);
 
 cairo_private long
 _cairo_output_stream_get_position (cairo_output_stream_t *stream);
 
 cairo_private cairo_status_t
 _cairo_output_stream_get_status (cairo_output_stream_t *stream);
 
 /* This function never returns %NULL. If an error occurs (NO_MEMORY or
--- a/gfx/cairo/cairo/src/cairo-path-stroke.c
+++ b/gfx/cairo/cairo/src/cairo-path-stroke.c
@@ -596,23 +596,33 @@ static inline cairo_bool_t
 
     if (dx0 == 0.0 && dy0 == 0.0) {
 	if (mag_out)
 	    *mag_out = 0.0;
 	return FALSE;
     }
 
     if (dx0 == 0.0) {
-	mag = dy0;
 	*dx = 0.0;
-	*dy = 1.0;
+	if (dy0 > 0.0) {
+	    mag = dy0;
+	    *dy = 1.0;
+	} else {
+	    mag = -dy0;
+	    *dy = -1.0;
+	}
     } else if (dy0 == 0.0) {
-	mag = dx0;
-	*dx = 1.0;
 	*dy = 0.0;
+	if (dx0 > 0.0) {
+	    mag = dx0;
+	    *dx = 1.0;
+	} else {
+	    mag = -dx0;
+	    *dx = -1.0;
+	}
     } else {
 	mag = sqrt (dx0 * dx0 + dy0 * dy0);
 	*dx = dx0 / mag;
 	*dy = dy0 / mag;
     }
 
     if (mag_out)
 	*mag_out = mag;
--- a/gfx/cairo/cairo/src/cairo-pdf-operators-private.h
+++ b/gfx/cairo/cairo/src/cairo-pdf-operators-private.h
@@ -55,17 +55,17 @@ typedef struct _cairo_pdf_operators {
     cairo_scaled_font_subsets_t *font_subsets;
     cairo_pdf_operators_use_font_subset_t use_font_subset;
     void *use_font_subset_closure;
 } cairo_pdf_operators_t;
 
 cairo_private void
 _cairo_pdf_operators_init (cairo_pdf_operators_t       *pdf_operators,
 			   cairo_output_stream_t       *stream,
-			   cairo_matrix_t 		cairo_to_pdf,
+			   cairo_matrix_t 	       *cairo_to_pdf,
 			   cairo_scaled_font_subsets_t *font_subsets);
 
 cairo_private void
 _cairo_pdf_operators_fini (cairo_pdf_operators_t       *pdf_operators);
 
 cairo_private void
 _cairo_pdf_operators_set_font_subsets_callback (cairo_pdf_operators_t 		     *pdf_operators,
 						cairo_pdf_operators_use_font_subset_t use_font_subset,
@@ -73,34 +73,42 @@ cairo_private void
 
 cairo_private void
 _cairo_pdf_operators_set_stream (cairo_pdf_operators_t 	 *pdf_operators,
 				 cairo_output_stream_t   *stream);
 
 
 cairo_private void
 _cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators,
-					      cairo_matrix_t 	     cairo_to_pdf);
+					      cairo_matrix_t 	    *cairo_to_pdf);
 
 cairo_private cairo_int_status_t
 _cairo_pdf_operators_clip (cairo_pdf_operators_t 	*pdf_operators,
 			   cairo_path_fixed_t		*path,
 			   cairo_fill_rule_t		 fill_rule);
 
 cairo_private cairo_int_status_t
-_cairo_pdf_operator_stroke (cairo_pdf_operators_t 	*pdf_operators,
-			    cairo_path_fixed_t		*path,
-			    cairo_stroke_style_t	*style,
-			    cairo_matrix_t		*ctm,
-			    cairo_matrix_t		*ctm_inverse);
+_cairo_pdf_operators_stroke (cairo_pdf_operators_t 	*pdf_operators,
+			     cairo_path_fixed_t		*path,
+			     cairo_stroke_style_t	*style,
+			     cairo_matrix_t		*ctm,
+			     cairo_matrix_t		*ctm_inverse);
 
 cairo_private cairo_int_status_t
 _cairo_pdf_operators_fill (cairo_pdf_operators_t 	*pdf_operators,
 			   cairo_path_fixed_t		*path,
 			   cairo_fill_rule_t	 	fill_rule);
 
+cairo_int_status_t
+_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t 	*pdf_operators,
+				  cairo_path_fixed_t		*path,
+				  cairo_fill_rule_t	 	 fill_rule,
+				  cairo_stroke_style_t	        *style,
+				  cairo_matrix_t		*ctm,
+				  cairo_matrix_t		*ctm_inverse);
+
 cairo_private cairo_int_status_t
 _cairo_pdf_operators_show_glyphs (cairo_pdf_operators_t *pdf_operators,
 				  cairo_glyph_t		*glyphs,
 				  int			 num_glyphs,
 				  cairo_scaled_font_t	*scaled_font);
 
 #endif /* CAIRO_PDF_OPERATORS_H */
--- a/gfx/cairo/cairo/src/cairo-pdf-operators.c
+++ b/gfx/cairo/cairo/src/cairo-pdf-operators.c
@@ -1,14 +1,14 @@
 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2004 Red Hat, Inc
  * Copyright © 2006 Red Hat, Inc
- * Copyright © 2007 Adrian Johnson
+ * Copyright © 2007, 2008 Adrian Johnson
  *
  * 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.
@@ -40,24 +40,26 @@
  */
 
 #include "cairoint.h"
 #include "cairo-pdf-operators-private.h"
 #include "cairo-path-fixed-private.h"
 #include "cairo-output-stream-private.h"
 #include "cairo-scaled-font-subsets-private.h"
 
+#include <ctype.h>
+
 void
 _cairo_pdf_operators_init (cairo_pdf_operators_t	*pdf_operators,
 			   cairo_output_stream_t	*stream,
-			   cairo_matrix_t		 cairo_to_pdf,
+			   cairo_matrix_t		*cairo_to_pdf,
 			   cairo_scaled_font_subsets_t  *font_subsets)
 {
     pdf_operators->stream = stream;
-    pdf_operators->cairo_to_pdf = cairo_to_pdf;
+    pdf_operators->cairo_to_pdf = *cairo_to_pdf;
     pdf_operators->font_subsets = font_subsets;
     pdf_operators->use_font_subset = NULL;
     pdf_operators->use_font_subset_closure = NULL;
 }
 
 void
 _cairo_pdf_operators_fini (cairo_pdf_operators_t	*pdf_operators)
 {
@@ -76,57 +78,214 @@ void
 _cairo_pdf_operators_set_stream (cairo_pdf_operators_t	 *pdf_operators,
 				 cairo_output_stream_t   *stream)
 {
     pdf_operators->stream = stream;
 }
 
 void
 _cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators,
-					      cairo_matrix_t	     cairo_to_pdf)
+					      cairo_matrix_t	    *cairo_to_pdf)
+{
+    pdf_operators->cairo_to_pdf = *cairo_to_pdf;
+}
+
+/* A word wrap stream can be used as a filter to do word wrapping on
+ * top of an existing output stream. The word wrapping is quite
+ * simple, using isspace to determine characters that separate
+ * words. Any word that will cause the column count exceed the given
+ * max_column will have a '\n' character emitted before it.
+ *
+ * The stream is careful to maintain integrity for words that cross
+ * the boundary from one call to write to the next.
+ *
+ * Note: This stream does not guarantee that the output will never
+ * exceed max_column. In particular, if a single word is larger than
+ * max_column it will not be broken up.
+ */
+typedef struct _word_wrap_stream {
+    cairo_output_stream_t base;
+    cairo_output_stream_t *output;
+    int max_column;
+    int column;
+    cairo_bool_t last_write_was_space;
+    cairo_bool_t in_hexstring;
+} word_wrap_stream_t;
+
+static int
+_count_word_up_to (const unsigned char *s, int length)
+{
+    int word = 0;
+
+    while (length--) {
+	if (! (isspace (*s) || *s == '<')) {
+	    s++;
+	    word++;
+	} else {
+	    return word;
+	}
+    }
+
+    return word;
+}
+
+
+/* Count up to either the end of the ASCII hexstring or the number
+ * of columns remaining.
+ */
+static int
+_count_hexstring_up_to (const unsigned char *s, int length, int columns)
+{
+    int word = 0;
+
+    while (length-- && columns--) {
+	if (*s++ != '>')
+	    word++;
+	else
+	    return word;
+    }
+
+    return word;
+}
+
+static cairo_status_t
+_word_wrap_stream_write (cairo_output_stream_t  *base,
+			 const unsigned char	*data,
+			 unsigned int		 length)
 {
-    pdf_operators->cairo_to_pdf = cairo_to_pdf;
+    word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
+    cairo_bool_t newline;
+    int word;
+
+    while (length) {
+	if (*data == '<') {
+	    stream->in_hexstring = TRUE;
+	    data++;
+	    length--;
+	    _cairo_output_stream_printf (stream->output, "<");
+	} else if (*data == '>') {
+	    stream->in_hexstring = FALSE;
+	    data++;
+	    length--;
+	    _cairo_output_stream_printf (stream->output, ">");
+	} else if (isspace (*data)) {
+	    newline =  (*data == '\n' || *data == '\r');
+	    if (! newline && stream->column >= stream->max_column) {
+		_cairo_output_stream_printf (stream->output, "\n");
+		stream->column = 0;
+	    }
+	    _cairo_output_stream_write (stream->output, data, 1);
+	    data++;
+	    length--;
+	    if (newline)
+		stream->column = 0;
+	    else
+		stream->column++;
+	    stream->last_write_was_space = TRUE;
+	} else {
+	    if (stream->in_hexstring) {
+		word = _count_hexstring_up_to (data, length,
+					       MAX (stream->max_column - stream->column, 0));
+	    } else {
+		word = _count_word_up_to (data, length);
+	    }
+	    /* Don't wrap if this word is a continuation of a non hex
+	     * string word from a previous call to write. */
+	    if (stream->column + word >= stream->max_column &&
+		(stream->last_write_was_space || stream->in_hexstring))
+	    {
+		_cairo_output_stream_printf (stream->output, "\n");
+		stream->column = 0;
+	    }
+	    _cairo_output_stream_write (stream->output, data, word);
+	    data += word;
+	    length -= word;
+	    stream->column += word;
+	    stream->last_write_was_space = FALSE;
+	}
+    }
+
+    return _cairo_output_stream_get_status (stream->output);
+}
+
+static cairo_status_t
+_word_wrap_stream_close (cairo_output_stream_t *base)
+{
+    word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
+
+    return _cairo_output_stream_get_status (stream->output);
+}
+
+static cairo_output_stream_t *
+_word_wrap_stream_create (cairo_output_stream_t *output, int max_column)
+{
+    word_wrap_stream_t *stream;
+
+    if (output->status)
+	return _cairo_output_stream_create_in_error (output->status);
+
+    stream = malloc (sizeof (word_wrap_stream_t));
+    if (stream == NULL) {
+	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_output_stream_t *) &_cairo_output_stream_nil;
+    }
+
+    _cairo_output_stream_init (&stream->base,
+			       _word_wrap_stream_write,
+			       _word_wrap_stream_close);
+    stream->output = output;
+    stream->max_column = max_column;
+    stream->column = 0;
+    stream->last_write_was_space = FALSE;
+    stream->in_hexstring = FALSE;
+
+    return &stream->base;
 }
 
 typedef struct _pdf_path_info {
     cairo_output_stream_t   *output;
-    cairo_matrix_t	    *cairo_to_pdf;
-    cairo_matrix_t	    *ctm_inverse;
+    cairo_matrix_t	    *path_transform;
+    cairo_line_cap_t         line_cap;
+    cairo_point_t            last_move_to_point;
+    cairo_bool_t             has_sub_path;
 } pdf_path_info_t;
 
 static cairo_status_t
 _cairo_pdf_path_move_to (void *closure, cairo_point_t *point)
 {
     pdf_path_info_t *info = closure;
     double x = _cairo_fixed_to_double (point->x);
     double y = _cairo_fixed_to_double (point->y);
 
-    if (info->cairo_to_pdf)
-        cairo_matrix_transform_point (info->cairo_to_pdf, &x, &y);
-    if (info->ctm_inverse)
-	cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
-
+    info->last_move_to_point = *point;
+    info->has_sub_path = FALSE;
+    cairo_matrix_transform_point (info->path_transform, &x, &y);
     _cairo_output_stream_printf (info->output,
 				 "%f %f m ", x, y);
 
     return _cairo_output_stream_get_status (info->output);
 }
 
 static cairo_status_t
 _cairo_pdf_path_line_to (void *closure, cairo_point_t *point)
 {
     pdf_path_info_t *info = closure;
     double x = _cairo_fixed_to_double (point->x);
     double y = _cairo_fixed_to_double (point->y);
 
-    if (info->cairo_to_pdf)
-        cairo_matrix_transform_point (info->cairo_to_pdf, &x, &y);
-    if (info->ctm_inverse)
-	cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
+    if (info->line_cap != CAIRO_LINE_CAP_ROUND &&
+	! info->has_sub_path &&
+	point->x == info->last_move_to_point.x &&
+	point->y == info->last_move_to_point.y)
+    {
+	return CAIRO_STATUS_SUCCESS;
+    }
 
+    info->has_sub_path = TRUE;
+    cairo_matrix_transform_point (info->path_transform, &x, &y);
     _cairo_output_stream_printf (info->output,
 				 "%f %f l ", x, y);
 
     return _cairo_output_stream_get_status (info->output);
 }
 
 static cairo_status_t
 _cairo_pdf_path_curve_to (void          *closure,
@@ -137,69 +296,101 @@ static cairo_status_t
     pdf_path_info_t *info = closure;
     double bx = _cairo_fixed_to_double (b->x);
     double by = _cairo_fixed_to_double (b->y);
     double cx = _cairo_fixed_to_double (c->x);
     double cy = _cairo_fixed_to_double (c->y);
     double dx = _cairo_fixed_to_double (d->x);
     double dy = _cairo_fixed_to_double (d->y);
 
-    if (info->cairo_to_pdf) {
-        cairo_matrix_transform_point (info->cairo_to_pdf, &bx, &by);
-        cairo_matrix_transform_point (info->cairo_to_pdf, &cx, &cy);
-        cairo_matrix_transform_point (info->cairo_to_pdf, &dx, &dy);
-    }
-    if (info->ctm_inverse) {
-	cairo_matrix_transform_point (info->ctm_inverse, &bx, &by);
-	cairo_matrix_transform_point (info->ctm_inverse, &cx, &cy);
-	cairo_matrix_transform_point (info->ctm_inverse, &dx, &dy);
-    }
-
+    info->has_sub_path = TRUE;
+    cairo_matrix_transform_point (info->path_transform, &bx, &by);
+    cairo_matrix_transform_point (info->path_transform, &cx, &cy);
+    cairo_matrix_transform_point (info->path_transform, &dx, &dy);
     _cairo_output_stream_printf (info->output,
 				 "%f %f %f %f %f %f c ",
 				 bx, by, cx, cy, dx, dy);
     return _cairo_output_stream_get_status (info->output);
 }
 
 static cairo_status_t
 _cairo_pdf_path_close_path (void *closure)
 {
     pdf_path_info_t *info = closure;
 
+    if (info->line_cap != CAIRO_LINE_CAP_ROUND &&
+	! info->has_sub_path)
+    {
+	return CAIRO_STATUS_SUCCESS;
+    }
+
     _cairo_output_stream_printf (info->output,
 				 "h\r\n");
 
     return _cairo_output_stream_get_status (info->output);
 }
 
+/* The line cap value is needed to workaround the fact that PostScript
+ * and PDF semantics for stroking degenerate sub-paths do not match
+ * cairo semantics. (PostScript draws something for any line cap
+ * value, while cairo draws something only for round caps).
+ *
+ * When using this function to emit a path to be filled, rather than
+ * stroked, simply pass %CAIRO_LINE_CAP_ROUND which will guarantee that
+ * the stroke workaround will not modify the path being emitted.
+ */
+static cairo_status_t
+_cairo_pdf_operators_emit_path (cairo_pdf_operators_t 	*pdf_operators,
+				cairo_path_fixed_t      *path,
+				cairo_matrix_t          *path_transform,
+				cairo_line_cap_t         line_cap)
+{
+    cairo_output_stream_t *word_wrap;
+    cairo_status_t status, status2;
+    pdf_path_info_t info;
+
+    word_wrap = _word_wrap_stream_create (pdf_operators->stream, 79);
+    status = _cairo_output_stream_get_status (word_wrap);
+    if (status)
+	return status;
+
+    info.output = word_wrap;
+    info.path_transform = path_transform;
+    info.line_cap = line_cap;
+    status = _cairo_path_fixed_interpret (path,
+					  CAIRO_DIRECTION_FORWARD,
+					  _cairo_pdf_path_move_to,
+					  _cairo_pdf_path_line_to,
+					  _cairo_pdf_path_curve_to,
+					  _cairo_pdf_path_close_path,
+					  &info);
+
+    status2 = _cairo_output_stream_destroy (word_wrap);
+    if (status == CAIRO_STATUS_SUCCESS)
+	status = status2;
+
+    return status;
+}
+
 cairo_int_status_t
 _cairo_pdf_operators_clip (cairo_pdf_operators_t	*pdf_operators,
 			   cairo_path_fixed_t		*path,
 			   cairo_fill_rule_t		 fill_rule)
 {
     const char *pdf_operator;
+    cairo_status_t status;
 
     if (! path->has_current_point) {
 	/* construct an empty path */
 	_cairo_output_stream_printf (pdf_operators->stream, "0 0 m ");
     } else {
-	pdf_path_info_t info;
-	cairo_status_t status;
-
-	info.output = pdf_operators->stream;
-	info.cairo_to_pdf = &pdf_operators->cairo_to_pdf;
-	info.ctm_inverse = NULL;
-
-	status = _cairo_path_fixed_interpret (path,
-					      CAIRO_DIRECTION_FORWARD,
-					      _cairo_pdf_path_move_to,
-					      _cairo_pdf_path_line_to,
-					      _cairo_pdf_path_curve_to,
-					      _cairo_pdf_path_close_path,
-					      &info);
+	status = _cairo_pdf_operators_emit_path (pdf_operators,
+						 path,
+						 &pdf_operators->cairo_to_pdf,
+						 CAIRO_LINE_CAP_ROUND);
 	if (status)
 	    return status;
     }
 
     switch (fill_rule) {
     case CAIRO_FILL_RULE_WINDING:
 	pdf_operator = "W";
 	break;
@@ -248,106 +439,163 @@ static int
 	return 0;
     }
 }
 
 static cairo_int_status_t
 _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t	*pdf_operators,
 					cairo_stroke_style_t	*style)
 {
+    double *dash = style->dash;
+    int num_dashes = style->num_dashes;
+    double dash_offset = style->dash_offset;
+
+    /* PostScript has "special needs" when it comes to zero-length
+     * dash segments with butt caps. It apparently (at least
+     * according to ghostscript) draws hairlines for this
+     * case. That's not what the cairo semantics want, so we first
+     * touch up the array to eliminate any 0.0 values that will
+     * result in "on" segments.
+     */
+    if (num_dashes && style->line_cap == CAIRO_LINE_CAP_BUTT) {
+	int i;
+
+	/* If there's an odd number of dash values they will each get
+	 * interpreted as both on and off. So we first explicitly
+	 * expand the array to remove the duplicate usage so that we
+	 * can modify some of the values.
+	 */
+	if (num_dashes % 2) {
+	    dash = _cairo_malloc_abc (num_dashes, 2, sizeof (double));
+	    if (dash == NULL)
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+	    memcpy (dash, style->dash, num_dashes * sizeof (double));
+	    memcpy (dash + num_dashes, style->dash, num_dashes * sizeof (double));
+
+	    num_dashes *= 2;
+	}
+
+	for (i = 0; i < num_dashes; i += 2) {
+	    if (dash[i] == 0.0) {
+		/* If we're at the front of the list, we first rotate
+		 * two elements from the end of the list to the front
+		 * of the list before folding away the 0.0. Or, if
+		 * there are only two dash elements, then there is
+		 * nothing at all to draw.
+		 */
+		if (i == 0) {
+		    double last_two[2];
+
+		    if (num_dashes == 2) {
+			if (dash != style->dash)
+			    free (dash);
+			return CAIRO_INT_STATUS_NOTHING_TO_DO;
+		    }
+		    /* The cases of num_dashes == 0, 1, or 3 elements
+		     * cannot exist, so the rotation of 2 elements
+		     * will always be safe */
+		    memcpy (last_two, dash + num_dashes - 2, sizeof (last_two));
+		    memmove (dash + 2, dash, (num_dashes - 2) * sizeof (double));
+		    memcpy (dash, last_two, sizeof (last_two));
+		    dash_offset += dash[0] + dash[1];
+		    i = 2;
+		}
+		dash[i-1] += dash[i+1];
+		num_dashes -= 2;
+		memmove (dash + i, dash + i + 2, (num_dashes - i) * sizeof (double));
+		/* If we might have just rotated, it's possible that
+		 * we rotated a 0.0 value to the front of the list.
+		 * Set i to -2 so it will get incremented to 0. */
+		if (i == 2)
+		    i = -2;
+	    }
+	}
+    }
+
     _cairo_output_stream_printf (pdf_operators->stream,
 				 "%f w\r\n",
 				 style->line_width);
 
     _cairo_output_stream_printf (pdf_operators->stream,
 				 "%d J\r\n",
 				 _cairo_pdf_line_cap (style->line_cap));
 
     _cairo_output_stream_printf (pdf_operators->stream,
 				 "%d j\r\n",
 				 _cairo_pdf_line_join (style->line_join));
 
-    if (style->num_dashes) {
-	unsigned int d;
+    if (num_dashes) {
+	int d;
+
 	_cairo_output_stream_printf (pdf_operators->stream, "[");
-	for (d = 0; d < style->num_dashes; d++)
-	    _cairo_output_stream_printf (pdf_operators->stream, " %f", style->dash[d]);
+	for (d = 0; d < num_dashes; d++)
+	    _cairo_output_stream_printf (pdf_operators->stream, " %f", dash[d]);
 	_cairo_output_stream_printf (pdf_operators->stream, "] %f d\r\n",
-				     style->dash_offset);
+				     dash_offset);
     } else {
 	_cairo_output_stream_printf (pdf_operators->stream, "[] 0.0 d\r\n");
     }
+    if (dash != style->dash)
+        free (dash);
 
     _cairo_output_stream_printf (pdf_operators->stream,
 				 "%f M ",
 				 style->miter_limit < 1.0 ? 1.0 : style->miter_limit);
 
     return _cairo_output_stream_get_status (pdf_operators->stream);
 }
 
 
 cairo_int_status_t
-_cairo_pdf_operator_stroke (cairo_pdf_operators_t	*pdf_operators,
-			    cairo_path_fixed_t		*path,
-			    cairo_stroke_style_t	*style,
-			    cairo_matrix_t		*ctm,
-			    cairo_matrix_t		*ctm_inverse)
+_cairo_pdf_operators_stroke (cairo_pdf_operators_t	*pdf_operators,
+			     cairo_path_fixed_t		*path,
+			     cairo_stroke_style_t	*style,
+			     cairo_matrix_t		*ctm,
+			     cairo_matrix_t		*ctm_inverse)
 {
-    pdf_path_info_t info;
     cairo_status_t status;
     cairo_matrix_t m;
 
     status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style);
+    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+	return CAIRO_STATUS_SUCCESS;
     if (status)
 	return status;
 
-    info.output = pdf_operators->stream;
-    info.cairo_to_pdf = NULL;
-    info.ctm_inverse = ctm_inverse;
-
     cairo_matrix_multiply (&m, ctm, &pdf_operators->cairo_to_pdf);
     _cairo_output_stream_printf (pdf_operators->stream,
 				 "q %f %f %f %f %f %f cm\r\n",
 				 m.xx, m.yx, m.xy, m.yy,
 				 m.x0, m.y0);
 
-    status = _cairo_path_fixed_interpret (path,
-					  CAIRO_DIRECTION_FORWARD,
-					  _cairo_pdf_path_move_to,
-					  _cairo_pdf_path_line_to,
-					  _cairo_pdf_path_curve_to,
-					  _cairo_pdf_path_close_path,
-					  &info);
+    status = _cairo_pdf_operators_emit_path (pdf_operators,
+					     path,
+					     ctm_inverse,
+					     style->line_cap);
     if (status)
 	return status;
 
     _cairo_output_stream_printf (pdf_operators->stream, "S Q\r\n");
 
     return _cairo_output_stream_get_status (pdf_operators->stream);
 }
 
 cairo_int_status_t
 _cairo_pdf_operators_fill (cairo_pdf_operators_t	*pdf_operators,
 			   cairo_path_fixed_t		*path,
 			   cairo_fill_rule_t		fill_rule)
 {
     const char *pdf_operator;
     cairo_status_t status;
-    pdf_path_info_t info;
 
-    info.output = pdf_operators->stream;
-    info.cairo_to_pdf = &pdf_operators->cairo_to_pdf;
-    info.ctm_inverse = NULL;
-    status = _cairo_path_fixed_interpret (path,
-					  CAIRO_DIRECTION_FORWARD,
-					  _cairo_pdf_path_move_to,
-					  _cairo_pdf_path_line_to,
-					  _cairo_pdf_path_curve_to,
-					  _cairo_pdf_path_close_path,
-					  &info);
+    status = _cairo_pdf_operators_emit_path (pdf_operators,
+					     path,
+					     &pdf_operators->cairo_to_pdf,
+					     CAIRO_LINE_CAP_ROUND);
     if (status)
 	return status;
 
     switch (fill_rule) {
     case CAIRO_FILL_RULE_WINDING:
 	pdf_operator = "f";
 	break;
     case CAIRO_FILL_RULE_EVEN_ODD:
@@ -359,36 +607,91 @@ cairo_int_status_t
 
     _cairo_output_stream_printf (pdf_operators->stream,
 				 "%s\r\n",
 				 pdf_operator);
 
     return _cairo_output_stream_get_status (pdf_operators->stream);
 }
 
+cairo_int_status_t
+_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t 	*pdf_operators,
+				  cairo_path_fixed_t		*path,
+				  cairo_fill_rule_t	 	 fill_rule,
+				  cairo_stroke_style_t	        *style,
+				  cairo_matrix_t		*ctm,
+				  cairo_matrix_t		*ctm_inverse)
+{
+    const char *pdf_operator;
+    cairo_status_t status;
+    cairo_matrix_t m;
+
+    status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style);
+    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+	return CAIRO_STATUS_SUCCESS;
+    if (status)
+	return status;
+
+    cairo_matrix_multiply (&m, ctm, &pdf_operators->cairo_to_pdf);
+    _cairo_output_stream_printf (pdf_operators->stream,
+				 "q %f %f %f %f %f %f cm\r\n",
+				 m.xx, m.yx, m.xy, m.yy,
+				 m.x0, m.y0);
+
+    status = _cairo_pdf_operators_emit_path (pdf_operators,
+					     path,
+					     ctm_inverse,
+					     style->line_cap);
+    if (status)
+	return status;
+
+    switch (fill_rule) {
+    case CAIRO_FILL_RULE_WINDING:
+	pdf_operator = "B";
+	break;
+    case CAIRO_FILL_RULE_EVEN_ODD:
+	pdf_operator = "B*";
+	break;
+    default:
+	ASSERT_NOT_REACHED;
+    }
+
+    _cairo_output_stream_printf (pdf_operators->stream,
+				 "%s Q\r\n",
+				 pdf_operator);
+
+    return _cairo_output_stream_get_status (pdf_operators->stream);
+}
+
 #define GLYPH_POSITION_TOLERANCE 0.001
 
 cairo_int_status_t
 _cairo_pdf_operators_show_glyphs (cairo_pdf_operators_t		*pdf_operators,
 				  cairo_glyph_t			*glyphs,
 				  int				 num_glyphs,
 				  cairo_scaled_font_t		*scaled_font)
 {
     unsigned int current_subset_id = (unsigned int)-1;
     cairo_scaled_font_subsets_glyph_t subset_glyph;
     cairo_bool_t diagonal, in_TJ;
     cairo_status_t status;
     double Tlm_x = 0, Tlm_y = 0;
     double Tm_x = 0, y;
     int i, hex_width;
+    cairo_output_stream_t *word_wrap_stream;
 
     for (i = 0; i < num_glyphs; i++)
 	cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &glyphs[i].x, &glyphs[i].y);
 
-    _cairo_output_stream_printf (pdf_operators->stream,
+    word_wrap_stream = _word_wrap_stream_create (pdf_operators->stream, 79);
+    status = _cairo_output_stream_get_status (word_wrap_stream);
+    if (status)
+	return status;
+
+    _cairo_output_stream_printf (word_wrap_stream,
 				 "BT\r\n");
 
     if (scaled_font->scale.xy == 0.0 &&
         scaled_font->scale.yx == 0.0)
         diagonal = TRUE;
     else
         diagonal = FALSE;
 
@@ -409,34 +712,34 @@ cairo_int_status_t
             y = 0.0;
             cairo_matrix_transform_distance (&scaled_font->scale,
                                              &subset_glyph.x_advance,
                                              &y);
         }
 
 	if (subset_glyph.subset_id != current_subset_id) {
             if (in_TJ) {
-                _cairo_output_stream_printf (pdf_operators->stream, ">] TJ\r\n");
+                _cairo_output_stream_printf (word_wrap_stream, ">] TJ\r\n");
                 in_TJ = FALSE;
             }
-	    _cairo_output_stream_printf (pdf_operators->stream,
+	    _cairo_output_stream_printf (word_wrap_stream,
 					 "/f-%d-%d 1 Tf\r\n",
 					 subset_glyph.font_id,
 					 subset_glyph.subset_id);
 	    if (pdf_operators->use_font_subset) {
 		status = pdf_operators->use_font_subset (subset_glyph.font_id,
 							 subset_glyph.subset_id,
 							 pdf_operators->use_font_subset_closure);
 		if (status)
 		    return status;
 	    }
         }
 
         if (subset_glyph.subset_id != current_subset_id || !diagonal) {
-            _cairo_output_stream_printf (pdf_operators->stream,
+            _cairo_output_stream_printf (word_wrap_stream,
                                          "%f %f %f %f %f %f Tm\r\n",
                                          scaled_font->scale.xx,
                                          -scaled_font->scale.yx,
                                          -scaled_font->scale.xy,
                                          scaled_font->scale.yy,
                                          glyphs[i].x,
                                          glyphs[i].y);
             current_subset_id = subset_glyph.subset_id;
@@ -447,86 +750,90 @@ cairo_int_status_t
 
         if (diagonal) {
             if (i < num_glyphs - 1 &&
                 fabs((glyphs[i].y - glyphs[i+1].y)/scaled_font->scale.yy) < GLYPH_POSITION_TOLERANCE &&
                 fabs((glyphs[i].x - glyphs[i+1].x)/scaled_font->scale.xx) < 10)
             {
                 if (!in_TJ) {
                     if (i != 0) {
-                        _cairo_output_stream_printf (pdf_operators->stream,
+                        _cairo_output_stream_printf (word_wrap_stream,
                                                      "%f %f Td\r\n",
                                                      (glyphs[i].x - Tlm_x)/scaled_font->scale.xx,
                                                      (glyphs[i].y - Tlm_y)/scaled_font->scale.yy);
 
                         Tlm_x = glyphs[i].x;
                         Tlm_y = glyphs[i].y;
                         Tm_x = Tlm_x;
                     }
-                    _cairo_output_stream_printf (pdf_operators->stream,
+                    _cairo_output_stream_printf (word_wrap_stream,
                                                  "[<%0*x",
                                                  hex_width,
                                                  subset_glyph.subset_glyph_index);
                     Tm_x += subset_glyph.x_advance;
                     in_TJ = TRUE;
                 } else {
                     if (fabs((glyphs[i].x - Tm_x)/scaled_font->scale.xx) > GLYPH_POSITION_TOLERANCE) {
                         double delta = glyphs[i].x - Tm_x;
 
-                        _cairo_output_stream_printf (pdf_operators->stream,
+                        _cairo_output_stream_printf (word_wrap_stream,
                                                      "> %f <",
                                                      -1000.0*delta/scaled_font->scale.xx);
                         Tm_x += delta;
                     }
-                    _cairo_output_stream_printf (pdf_operators->stream,
+                    _cairo_output_stream_printf (word_wrap_stream,
                                                  "%0*x",
                                                  hex_width,
                                                  subset_glyph.subset_glyph_index);
                     Tm_x += subset_glyph.x_advance;
                 }
             }
             else
             {
                 if (in_TJ) {
                     if (fabs((glyphs[i].x - Tm_x)/scaled_font->scale.xx) > GLYPH_POSITION_TOLERANCE) {
                         double delta = glyphs[i].x - Tm_x;
 
-                        _cairo_output_stream_printf (pdf_operators->stream,
+                        _cairo_output_stream_printf (word_wrap_stream,
                                                      "> %f <",
                                                      -1000.0*delta/scaled_font->scale.xx);
                         Tm_x += delta;
                     }
-                    _cairo_output_stream_printf (pdf_operators->stream,
+                    _cairo_output_stream_printf (word_wrap_stream,
                                                  "%0*x>] TJ\r\n",
                                                  hex_width,
                                                  subset_glyph.subset_glyph_index);
                     Tm_x += subset_glyph.x_advance;
                     in_TJ = FALSE;
                 } else {
                     if (i != 0) {
-                        _cairo_output_stream_printf (pdf_operators->stream,
+                        _cairo_output_stream_printf (word_wrap_stream,
                                                      "%f %f Td ",
                                                      (glyphs[i].x - Tlm_x)/scaled_font->scale.xx,
                                                      (glyphs[i].y - Tlm_y)/-scaled_font->scale.yy);
                         Tlm_x = glyphs[i].x;
                         Tlm_y = glyphs[i].y;
                         Tm_x = Tlm_x;
                     }
-                    _cairo_output_stream_printf (pdf_operators->stream,
+                    _cairo_output_stream_printf (word_wrap_stream,
                                                  "<%0*x> Tj ",
                                                  hex_width,
                                                  subset_glyph.subset_glyph_index);
                     Tm_x += subset_glyph.x_advance;
                 }
             }
         } else {
-            _cairo_output_stream_printf (pdf_operators->stream,
+            _cairo_output_stream_printf (word_wrap_stream,
                                          "<%0*x> Tj\r\n",
                                          hex_width,
                                          subset_glyph.subset_glyph_index);
         }
     }
 
-    _cairo_output_stream_printf (pdf_operators->stream,
+    _cairo_output_stream_printf (word_wrap_stream,
 				 "ET\r\n");
 
+    status = _cairo_output_stream_destroy (word_wrap_stream);
+    if (status)
+	return status;
+
     return _cairo_output_stream_get_status (pdf_operators->stream);
 }
--- a/gfx/cairo/cairo/src/cairo-pdf-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-pdf-surface-private.h
@@ -144,15 +144,16 @@ struct _cairo_pdf_surface {
 	cairo_output_stream_t *mem_stream;
 	cairo_output_stream_t *old_output;
 	cairo_pdf_resource_t   resource;
 	cairo_bool_t is_knockout;
     } group_stream;
 
     cairo_pdf_operators_t pdf_operators;
     cairo_paginated_mode_t paginated_mode;
+    cairo_bool_t select_pattern_gstate_saved;
 
     cairo_bool_t force_fallbacks;
 
     cairo_surface_t *paginated_surface;
 };
 
 #endif /* CAIRO_PDF_SURFACE_PRIVATE_H */
--- a/gfx/cairo/cairo/src/cairo-pdf-surface.c
+++ b/gfx/cairo/cairo/src/cairo-pdf-surface.c
@@ -52,35 +52,17 @@
 #include <zlib.h>
 
 /* Issues:
  *
  * - We embed an image in the stream each time it's composited.  We
  *   could add generation counters to surfaces and remember the stream
  *   ID for a particular generation for a particular surface.
  *
- * - Images of other formats than 8 bit RGBA.
- *
  * - Backend specific meta data.
- *
- * - Surface patterns.
- *
- * - Should/does cairo support drawing into a scratch surface and then
- *   using that as a fill pattern?  For this backend, that would involve
- *   using a tiling pattern (4.6.2).  How do you create such a scratch
- *   surface?  cairo_surface_create_similar() ?
- *
- * - What if you create a similar surface and does show_page and then
- *   does show_surface on another surface?
- *
- * - Add test case for RGBA images.
- *
- * - Add test case for RGBA gradients.
- *
- * - Coordinate space for create_similar() args?
  */
 
 /*
  * Page Structure of the Generated PDF:
  *
  * Each page requiring fallbacks images contains a knockout group at
  * the top level. The first operation of the knockout group paints a
  * group containing all the supported drawing operations. Fallback
@@ -280,20 +262,21 @@ static cairo_surface_t *
     surface->pdf_stream.old_output = NULL;
     surface->group_stream.active = FALSE;
     surface->group_stream.stream = NULL;
     surface->group_stream.mem_stream = NULL;
 
     surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
 
     surface->force_fallbacks = FALSE;
+    surface->select_pattern_gstate_saved = FALSE;
 
     _cairo_pdf_operators_init (&surface->pdf_operators,
 			       surface->output,
-			       surface->cairo_to_pdf,
+			       &surface->cairo_to_pdf,
 			       surface->font_subsets);
     _cairo_pdf_operators_set_font_subsets_callback (&surface->pdf_operators,
 						    _cairo_pdf_surface_add_font,
 						    surface);
 
     /* Document header */
     _cairo_output_stream_printf (surface->output,
 				 "%%PDF-1.4\r\n");
@@ -452,17 +435,17 @@ cairo_pdf_surface_set_size (cairo_surfac
 	status = _cairo_surface_set_error (surface, status);
 	return;
     }
 
     pdf_surface->width = width_in_points;
     pdf_surface->height = height_in_points;
     cairo_matrix_init (&pdf_surface->cairo_to_pdf, 1, 0, 0, -1, 0, height_in_points);
     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&pdf_surface->pdf_operators,
-						  pdf_surface->cairo_to_pdf);
+						  &pdf_surface->cairo_to_pdf);
     status = _cairo_paginated_surface_set_size (pdf_surface->paginated_surface,
 						width_in_points,
 						height_in_points);
     if (status)
 	status = _cairo_surface_set_error (surface, status);
 }
 
 static void
@@ -1085,27 +1068,25 @@ static cairo_status_t
 					    "      /Type /Group\r\n"
 					    "      /S /Transparency\r\n"
 					    "      /CS /DeviceRGB\r\n"
 					    "   >>\r\n"
 					    "   /Resources %d 0 R\r\n",
 					    surface->width,
 					    surface->height,
 					    surface->content_resources.id);
-	if (status)
-	    return status;
     } else {
 	status =
 	    _cairo_pdf_surface_open_stream (surface,
 					    NULL,
 					    surface->compress_content,
 					    NULL);
-	if (status)
-	    return status;
     }
+    if (status)
+	return status;
 
     surface->content = surface->pdf_stream.self;
 
     _cairo_output_stream_printf (surface->output, "q\r\n");
 
     return _cairo_output_stream_get_status (surface->output);
 }
 
@@ -1239,60 +1220,30 @@ static cairo_int_status_t
     _cairo_pdf_group_resources_clear (&surface->resources);
     status = _cairo_pdf_surface_open_content_stream (surface, TRUE);
     if (status)
 	return status;
 
     return CAIRO_STATUS_SUCCESS;
 }
 
-static void *
-compress_dup (const void *data, unsigned long data_size,
-	      unsigned long *compressed_size)
-{
-    void *compressed;
-    unsigned long additional_size;
-
-    /* Bound calculation taken from zlib. */
-    additional_size = (data_size >> 12) + (data_size >> 14) + 11;
-    if (INT32_MAX - data_size <= additional_size) {
-	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
-	return NULL;
-    }
-
-    *compressed_size = data_size + additional_size;
-    compressed = malloc (*compressed_size);
-    if (compressed == NULL) {
-	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
-	return NULL;
-    }
-
-    if (compress (compressed, compressed_size, data, data_size) != Z_OK) {
-	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
-	free (compressed);
-	compressed = NULL;
-    }
-
-    return compressed;
-}
-
 /* Emit alpha channel from the image into the given data, providing
  * an id that can be used to reference the resulting SMask object.
  *
  * In the case that the alpha channel happens to be all opaque, then
  * no SMask object will be emitted and *id_ret will be set to 0.
  */
 static cairo_status_t
 _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t	*surface,
 			       cairo_image_surface_t	*image,
 			       cairo_pdf_resource_t	*stream_ret)
 {
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
-    char *alpha, *alpha_compressed;
-    unsigned long alpha_size, alpha_compressed_size;
+    char *alpha;
+    unsigned long alpha_size;
     uint32_t *pixel32;
     uint8_t *pixel8;
     int i, x, y;
     cairo_bool_t opaque;
     uint8_t a;
     int src_bit, dst_bit;
 
     /* This is the only image format we support, which simplifies things. */
@@ -1363,71 +1314,55 @@ static cairo_status_t
 	    }
 	}
     }
 
     /* Bail out without emitting smask if it's all opaque. */
     if (opaque)
 	goto CLEANUP_ALPHA;
 
-    alpha_compressed = compress_dup (alpha, alpha_size, &alpha_compressed_size);
-    if (alpha_compressed == NULL) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto CLEANUP_ALPHA;
-    }
-
     status = _cairo_pdf_surface_open_stream (surface,
 					     NULL,
-					     FALSE,
+					     TRUE,
 					     "   /Type /XObject\r\n"
 					     "   /Subtype /Image\r\n"
 					     "   /Width %d\r\n"
 					     "   /Height %d\r\n"
 					     "   /ColorSpace /DeviceGray\r\n"
-					     "   /BitsPerComponent %d\r\n"
-					     "   /Filter /FlateDecode\r\n",
+					     "   /BitsPerComponent %d\r\n",
 					     image->width, image->height,
 					     image->format == CAIRO_FORMAT_A1 ? 1 : 8);
     if (status)
-	goto CLEANUP_ALPHA_COMPRESSED;
+	goto CLEANUP_ALPHA;
 
     *stream_ret = surface->pdf_stream.self;
-
-    _cairo_output_stream_write (surface->output, alpha_compressed, alpha_compressed_size);
-    _cairo_output_stream_printf (surface->output, "\r\n");
+    _cairo_output_stream_write (surface->output, alpha, alpha_size);
     status = _cairo_pdf_surface_close_stream (surface);
 
- CLEANUP_ALPHA_COMPRESSED:
-    free (alpha_compressed);
  CLEANUP_ALPHA:
     free (alpha);
  CLEANUP:
     return status;
 }
 
 /* Emit image data into the given surface, providing a resource that
  * can be used to reference the data in image_ret. */
 static cairo_status_t
 _cairo_pdf_surface_emit_image (cairo_pdf_surface_t   *surface,
                                cairo_image_surface_t *image,
                                cairo_pdf_resource_t  *image_ret)
 {
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
-    char *rgb, *compressed;
-    unsigned long rgb_size, compressed_size;
+    char *rgb;
+    unsigned long rgb_size;
     uint32_t *pixel;
     int i, x, y;
     cairo_pdf_resource_t smask = {0}; /* squelch bogus compiler warning */
     cairo_bool_t need_smask;
 
-    /* XXX: Need to rewrite this as a pdf_surface function with
-     * pause/resume of content_stream, (currently the only caller does
-     * the pause/resume already, but that is expected to change in the
-     * future). */
-
     /* These are the only image formats we currently support, (which
      * makes things a lot simpler here). This is enforced through
      * _cairo_pdf_surface_analyze_operation which only accept source surfaces of
      * CONTENT_COLOR or CONTENT_COLOR_ALPHA.
      */
     assert (image->format == CAIRO_FORMAT_RGB24 ||
 	    image->format == CAIRO_FORMAT_ARGB32 ||
 	    image->format == CAIRO_FORMAT_A8 ||
@@ -1469,69 +1404,58 @@ static cairo_status_t
 	    } else {
 		rgb[i++] = 0;
 		rgb[i++] = 0;
 		rgb[i++] = 0;
 	    }
 	}
     }
 
-    compressed = compress_dup (rgb, rgb_size, &compressed_size);
-    if (compressed == NULL) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto CLEANUP_RGB;
-    }
-
     need_smask = FALSE;
     if (image->format == CAIRO_FORMAT_ARGB32 ||
 	image->format == CAIRO_FORMAT_A8 ||
 	image->format == CAIRO_FORMAT_A1) {
 	status = _cairo_pdf_surface_emit_smask (surface, image, &smask);
 	if (status)
-	    goto CLEANUP_COMPRESSED;
+	    goto CLEANUP_RGB;
 
 	if (smask.id)
 	    need_smask = TRUE;
     }
 
 #define IMAGE_DICTIONARY	"   /Type /XObject\r\n"		\
 				"   /Subtype /Image\r\n"	\
 				"   /Width %d\r\n"		\
 				"   /Height %d\r\n"		\
 				"   /ColorSpace /DeviceRGB\r\n"	\
-				"   /BitsPerComponent 8\r\n"	\
-				"   /Filter /FlateDecode\r\n"
+				"   /BitsPerComponent 8\r\n"
 
     if (need_smask)
 	status = _cairo_pdf_surface_open_stream (surface,
 						 NULL,
-						 FALSE,
+						 TRUE,
 						 IMAGE_DICTIONARY
 						 "   /SMask %d 0 R\r\n",
 						 image->width, image->height,
 						 smask.id);
     else
 	status = _cairo_pdf_surface_open_stream (surface,
 						 NULL,
-						 FALSE,
+						 TRUE,
 						 IMAGE_DICTIONARY,
 						 image->width, image->height);
     if (status)
-	goto CLEANUP_COMPRESSED;
+	goto CLEANUP_RGB;
 
 #undef IMAGE_DICTIONARY
 
     *image_ret = surface->pdf_stream.self;
-
-    _cairo_output_stream_write (surface->output, compressed, compressed_size);
-    _cairo_output_stream_printf (surface->output, "\r\n");
+    _cairo_output_stream_write (surface->output, rgb, rgb_size);
     status = _cairo_pdf_surface_close_stream (surface);
 
-CLEANUP_COMPRESSED:
-    free (compressed);
 CLEANUP_RGB:
     free (rgb);
 CLEANUP:
     return status;
 }
 
 static cairo_status_t
 _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t     *surface,
@@ -1585,17 +1509,17 @@ static cairo_status_t
     surface->height = meta_extents.height;
     /* Patterns are emitted after fallback images. The paginated mode
      * needs to be set to _RENDER while the meta surface is replayed
      * back to this surface.
      */
     surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER;
     cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, surface->height);
     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
-						  surface->cairo_to_pdf);
+						  &surface->cairo_to_pdf);
 
     _cairo_pdf_group_resources_clear (&surface->resources);
     status = _cairo_pdf_surface_open_content_stream (surface, TRUE);
     if (status)
 	return status;
 
     *resource = surface->content;
     if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
@@ -1619,17 +1543,17 @@ static cairo_status_t
     status = _cairo_pdf_surface_close_content_stream (surface);
 
  CLEANUP_GROUP:
     surface->width = old_width;
     surface->height = old_height;
     surface->paginated_mode = old_paginated_mode;
     surface->cairo_to_pdf = old_cairo_to_pdf;
     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
-						  surface->cairo_to_pdf);
+						  &surface->cairo_to_pdf);
 
     return status;
 }
 
 static cairo_status_t
 _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	*surface,
 					 cairo_pdf_pattern_t	*pdf_pattern)
 {
@@ -2640,59 +2564,68 @@ static cairo_status_t
     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
 	cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *) pattern;
 
 	status = _cairo_pdf_surface_add_alpha (surface, solid_pattern->color.alpha, &alpha);
 	if (status)
 	    return status;
 
 	_cairo_output_stream_printf (surface->output,
-				     "q %f %f %f ",
+				     "%f %f %f ",
 				     solid_pattern->color.red,
 				     solid_pattern->color.green,
 				     solid_pattern->color.blue);
 
 	if (is_stroke)
             _cairo_output_stream_printf (surface->output, "RG ");
         else
             _cairo_output_stream_printf (surface->output, "rg ");
 
         _cairo_output_stream_printf (surface->output,
                                      "/a%d gs\r\n",
                                      alpha);
+	surface->select_pattern_gstate_saved = FALSE;
     } else {
 	status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
 	if (status)
 	    return status;
 
 	status = _cairo_pdf_surface_add_pattern (surface, pattern_res);
 	if (status)
 	    return status;
 
+	/* fill-stroke calls select_pattern twice. Don't save if the
+	 * gstate is already saved. */
+	if (!surface->select_pattern_gstate_saved)
+	    _cairo_output_stream_printf (surface->output, "q ");
+
 	if (is_stroke) {
 	    _cairo_output_stream_printf (surface->output,
-					 "q /Pattern CS /p%d SCN ",
+					 "/Pattern CS /p%d SCN ",
 					 pattern_res.id);
 	} else {
 	    _cairo_output_stream_printf (surface->output,
-					 "q /Pattern cs /p%d scn ",
+					 "/Pattern cs /p%d scn ",
 					 pattern_res.id);
 	}
 	_cairo_output_stream_printf (surface->output,
 				     "/a%d gs\r\n",
 				     alpha);
+	surface->select_pattern_gstate_saved = TRUE;
     }
 
     return _cairo_output_stream_get_status (surface->output);
 }
 
 static void
 _cairo_pdf_surface_unselect_pattern (cairo_pdf_surface_t *surface)
 {
-    _cairo_output_stream_printf (surface->output, "Q\r\n");
+    if (surface->select_pattern_gstate_saved)
+	_cairo_output_stream_printf (surface->output, "Q\r\n");
+    surface->select_pattern_gstate_saved = FALSE;
 }
 
 static cairo_int_status_t
 _cairo_pdf_surface_show_page (void *abstract_surface)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
     cairo_int_status_t status;
 
@@ -2877,21 +2810,21 @@ static cairo_int_status_t
         if (i != 0 && i % 100 == 0) {
             _cairo_output_stream_printf (surface->output,
                                          "endbfchar\r\n"
                                          "%d beginbfchar\r\n",
                                          num_bfchar - i > 100 ? 100 : num_bfchar - i);
         }
         if (is_composite) {
             _cairo_output_stream_printf (surface->output,
-                                         "<%04x> <%04x>\r\n",
+                                         "<%04x> <%04lx>\r\n",
                                          i + 1, font_subset->to_unicode[i + 1]);
         } else {
             _cairo_output_stream_printf (surface->output,
-                                         "<%02x> <%04x>\r\n",
+                                         "<%02x> <%04lx>\r\n",
                                          i + 1, font_subset->to_unicode[i + 1]);
         }
     }
     _cairo_output_stream_printf (surface->output,
                                  "endbfchar\r\n");
 
     _cairo_output_stream_printf (surface->output,
                                  "endcmap\r\n"
@@ -2906,52 +2839,38 @@ static cairo_int_status_t
 static cairo_status_t
 _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t		*surface,
                                   cairo_scaled_font_subset_t	*font_subset,
                                   cairo_cff_subset_t            *subset)
 {
     cairo_pdf_resource_t stream, descriptor, cidfont_dict;
     cairo_pdf_resource_t subset_resource, to_unicode_stream;
     cairo_pdf_font_t font;
-    unsigned long compressed_length;
-    char *compressed;
     unsigned int i;
     cairo_status_t status;
 
     subset_resource = _cairo_pdf_surface_get_font_resource (surface,
 							    font_subset->font_id,
 							    font_subset->subset_id);
     if (subset_resource.id == 0)
 	return CAIRO_STATUS_SUCCESS;
 
-    compressed = compress_dup (subset->data, subset->data_length, &compressed_length);
-    if (compressed == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    stream = _cairo_pdf_surface_new_object (surface);
-    if (stream.id == 0) {
-	free (compressed);
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
-
-    _cairo_output_stream_printf (surface->output,
-				 "%d 0 obj\r\n"
-				 "<< /Filter /FlateDecode\r\n"
-				 "   /Length %lu\r\n"
-				 "   /Subtype /CIDFontType0C\r\n"
-				 ">>\r\n"
-				 "stream\r\n",
-				 stream.id,
-				 compressed_length);
-    _cairo_output_stream_write (surface->output, compressed, compressed_length);
-    _cairo_output_stream_printf (surface->output,
-				 "\r\n"
-				 "endstream\r\n"
-				 "endobj\r\n");
-    free (compressed);
+    status = _cairo_pdf_surface_open_stream (surface,
+					     NULL,
+					     TRUE,
+					     "   /Subtype /CIDFontType0C\r\n");
+    if (status)
+	return status;
+
+    stream = surface->pdf_stream.self;
+    _cairo_output_stream_write (surface->output,
+				subset->data, subset->data_length);
+    status = _cairo_pdf_surface_close_stream (surface);
+    if (status)
+	return status;
 
     status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
 	                                                font_subset, TRUE,
 							&to_unicode_stream);
     if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return status;
 
     descriptor = _cairo_pdf_surface_new_object (surface);
@@ -3087,57 +3006,43 @@ static cairo_status_t
 static cairo_status_t
 _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t		*surface,
                                     cairo_scaled_font_subset_t	*font_subset,
                                     cairo_type1_subset_t        *subset)
 {
     cairo_pdf_resource_t stream, descriptor, subset_resource, to_unicode_stream;
     cairo_pdf_font_t font;
     cairo_status_t status;
-    unsigned long length, compressed_length;
-    char *compressed;
+    unsigned long length;
     unsigned int i;
 
     subset_resource = _cairo_pdf_surface_get_font_resource (surface,
 							    font_subset->font_id,
 							    font_subset->subset_id);
     if (subset_resource.id == 0)
 	return CAIRO_STATUS_SUCCESS;
 
     /* We ignore the zero-trailer and set Length3 to 0. */
     length = subset->header_length + subset->data_length;
-    compressed = compress_dup (subset->data, length, &compressed_length);
-    if (compressed == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    stream = _cairo_pdf_surface_new_object (surface);
-    if (stream.id == 0) {
-	free (compressed);
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
-
-    _cairo_output_stream_printf (surface->output,
-				 "%d 0 obj\r\n"
-				 "<< /Filter /FlateDecode\r\n"
-				 "   /Length %lu\r\n"
-				 "   /Length1 %lu\r\n"
-				 "   /Length2 %lu\r\n"
-				 "   /Length3 0\r\n"
-				 ">>\r\n"
-				 "stream\r\n",
-				 stream.id,
-				 compressed_length,
-				 subset->header_length,
-				 subset->data_length);
-    _cairo_output_stream_write (surface->output, compressed, compressed_length);
-    _cairo_output_stream_printf (surface->output,
-				 "\r\n"
-				 "endstream\r\n"
-				 "endobj\r\n");
-    free (compressed);
+    status = _cairo_pdf_surface_open_stream (surface,
+					     NULL,
+					     TRUE,
+					     "   /Length1 %lu\r\n"
+					     "   /Length2 %lu\r\n"
+					     "   /Length3 0\r\n",
+					     subset->header_length,
+					     subset->data_length);
+    if (status)
+	return status;
+
+    stream = surface->pdf_stream.self;
+    _cairo_output_stream_write (surface->output, subset->data, length);
+    status = _cairo_pdf_surface_close_stream (surface);
+    if (status)
+	return status;
 
     status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
 	                                                font_subset, FALSE,
 							&to_unicode_stream);
     if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return status;
 
     descriptor = _cairo_pdf_surface_new_object (surface);
@@ -3255,59 +3160,46 @@ static cairo_status_t
 _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t		*surface,
 					      cairo_scaled_font_subset_t	*font_subset)
 {
     cairo_pdf_resource_t stream, descriptor, cidfont_dict;
     cairo_pdf_resource_t subset_resource, to_unicode_stream;
     cairo_status_t status;
     cairo_pdf_font_t font;
     cairo_truetype_subset_t subset;
-    unsigned long compressed_length;
-    char *compressed;
     unsigned int i;
 
     subset_resource = _cairo_pdf_surface_get_font_resource (surface,
 							    font_subset->font_id,
 							    font_subset->subset_id);
     if (subset_resource.id == 0)
 	return CAIRO_STATUS_SUCCESS;
 
     status = _cairo_truetype_subset_init (&subset, font_subset);
     if (status)
 	return status;
 
-    compressed = compress_dup (subset.data, subset.data_length,
-			       &compressed_length);
-    if (compressed == NULL) {
+    status = _cairo_pdf_surface_open_stream (surface,
+					     NULL,
+					     TRUE,
+					     "   /Length1 %lu\r\n",
+					     subset.data_length);
+    if (status) {
 	_cairo_truetype_subset_fini (&subset);
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
-
-    stream = _cairo_pdf_surface_new_object (surface);
-    if (stream.id == 0) {
-	free (compressed);
-	_cairo_truetype_subset_fini (&subset);
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return status;
     }
-    _cairo_output_stream_printf (surface->output,
-				 "%d 0 obj\r\n"
-				 "<< /Filter /FlateDecode\r\n"
-				 "   /Length %lu\r\n"
-				 "   /Length1 %lu\r\n"
-				 ">>\r\n"
-				 "stream\r\n",
-				 stream.id,
-				 compressed_length,
-				 subset.data_length);
-    _cairo_output_stream_write (surface->output, compressed, compressed_length);
-    _cairo_output_stream_printf (surface->output,
-				 "\r\n"
-				 "endstream\r\n"
-				 "endobj\r\n");
-    free (compressed);
+
+    stream = surface->pdf_stream.self;
+    _cairo_output_stream_write (surface->output,
+				subset.data, subset.data_length);
+    status = _cairo_pdf_surface_close_stream (surface);
+    if (status) {
+	_cairo_truetype_subset_fini (&subset);
+	return status;
+    }
 
     status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
 	                                                font_subset, TRUE,
 							&to_unicode_stream);
     if (status && status != CAIRO_INT_STATUS_UNSUPPORTED) {
 	_cairo_truetype_subset_fini (&subset);
 	return status;
     }
@@ -3938,17 +3830,17 @@ static cairo_status_t
 
     old_width = surface->width;
     old_height = surface->height;
     old_cairo_to_pdf = surface->cairo_to_pdf;
     surface->width = group->width;
     surface->height = group->height;
     cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, surface->height);
     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
-						  surface->cairo_to_pdf);
+						  &surface->cairo_to_pdf);
 
     /* _mask is a special case that requires two groups - source
      * and mask as well as a smask and gstate dictionary */
     if (group->operation == PDF_MASK)
 	return _cairo_pdf_surface_write_mask_group (surface, group);
 
     status = _cairo_pdf_surface_open_group (surface, &group->group_res);
     if (status)
@@ -3971,21 +3863,21 @@ static cairo_status_t
 	ASSERT_NOT_REACHED;
 	break;
     case PDF_FILL:
 	status = _cairo_pdf_operators_fill (&surface->pdf_operators,
 					    &group->path,
 					    group->fill_rule);
 	break;
     case PDF_STROKE:
-	status = _cairo_pdf_operator_stroke (&surface->pdf_operators,
-					     &group->path,
-					     group->style,
-					     &group->ctm,
-					     &group->ctm_inverse);
+	status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
+					      &group->path,
+					      group->style,
+					      &group->ctm,
+					      &group->ctm_inverse);
 	break;
     case PDF_SHOW_GLYPHS:
 	status = _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
 						   group->glyphs,
 						   group->num_glyphs,
 						   group->scaled_font);
 	break;
     }
@@ -3994,17 +3886,17 @@ static cairo_status_t
 
     _cairo_pdf_surface_unselect_pattern (surface);
     status = _cairo_pdf_surface_close_group (surface, NULL);
 
     surface->width = old_width;
     surface->height = old_height;
     surface->cairo_to_pdf = old_cairo_to_pdf;
     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
-						  surface->cairo_to_pdf);
+						  &surface->cairo_to_pdf);
 
     return status;
 }
 
 static cairo_status_t
 _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface)
 {
     cairo_pdf_pattern_t pattern;
@@ -4472,21 +4364,21 @@ static cairo_int_status_t
 				     "q /s%d gs /x%d Do Q\r\n",
 				     gstate_res.id,
 				     group->group_res.id);
     } else {
 	status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, TRUE);
 	if (status)
 	    return status;
 
-	status = _cairo_pdf_operator_stroke (&surface->pdf_operators,
-					     path,
-					     style,
-					     ctm,
-					     ctm_inverse);
+	status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
+					      path,
+					      style,
+					      ctm,
+					      ctm_inverse);
 	if (status)
 	    return status;
 
 	_cairo_pdf_surface_unselect_pattern (surface);
     }
 
     return _cairo_output_stream_get_status (surface->output);
 }
@@ -4569,16 +4461,107 @@ static cairo_int_status_t
 
 	_cairo_pdf_surface_unselect_pattern (surface);
     }
 
     return _cairo_output_stream_get_status (surface->output);
 }
 
 static cairo_int_status_t
+_cairo_pdf_surface_fill_stroke (void		     *abstract_surface,
+				cairo_operator_t      fill_op,
+				cairo_pattern_t	     *fill_source,
+				cairo_fill_rule_t     fill_rule,
+				double		      fill_tolerance,
+				cairo_antialias_t     fill_antialias,
+				cairo_path_fixed_t   *path,
+				cairo_operator_t      stroke_op,
+				cairo_pattern_t	     *stroke_source,
+				cairo_stroke_style_t *stroke_style,
+				cairo_matrix_t	     *stroke_ctm,
+				cairo_matrix_t	     *stroke_ctm_inverse,
+				double		      stroke_tolerance,
+				cairo_antialias_t     stroke_antialias)
+{
+    cairo_pdf_surface_t *surface = abstract_surface;
+    cairo_status_t status;
+    cairo_pdf_resource_t fill_pattern_res, stroke_pattern_res, gstate_res;
+
+    /* During analysis we return unsupported and let the _fill and
+     * _stroke functions that are on the fallback path do the analysis
+     * for us. During render we may still encounter unsupported
+     * combinations of fill/stroke patterns. However we can return
+     * unsupported anytime to let the _fill and _stroke functions take
+     * over.
+     */
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    /* Fill-stroke with patterns requiring an SMask are not currently
+     * implemented. Non opaque stroke patterns are not supported
+     * because the PDF fill-stroke operator does not blend a
+     * transparent stroke with the fill.
+     */
+    if (fill_source->type == CAIRO_PATTERN_TYPE_LINEAR ||
+        fill_source->type == CAIRO_PATTERN_TYPE_RADIAL)
+    {
+        if (!_cairo_pattern_is_opaque (fill_source))
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+    if (!_cairo_pattern_is_opaque (stroke_source))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    fill_pattern_res.id = 0;
+    gstate_res.id = 0;
+    status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source,
+						 &fill_pattern_res,
+						 &gstate_res);
+    if (status)
+	return status;
+
+    assert (gstate_res.id == 0);
+
+    stroke_pattern_res.id = 0;
+    gstate_res.id = 0;
+    status = _cairo_pdf_surface_add_pdf_pattern (surface,
+						 stroke_source,
+						 &stroke_pattern_res,
+						 &gstate_res);
+    if (status)
+	return status;
+
+    assert (gstate_res.id == 0);
+
+    /* As PDF has separate graphics state for fill and stroke we can
+     * select both at the same time */
+    status = _cairo_pdf_surface_select_pattern (surface, fill_source,
+						fill_pattern_res, FALSE);
+    if (status)
+	return status;
+
+    status = _cairo_pdf_surface_select_pattern (surface, stroke_source,
+						stroke_pattern_res, TRUE);
+    if (status)
+	return status;
+
+    status = _cairo_pdf_operators_fill_stroke (&surface->pdf_operators,
+					       path,
+					       fill_rule,
+					       stroke_style,
+					       stroke_ctm,
+					       stroke_ctm_inverse);
+    if (status)
+	return status;
+
+    _cairo_pdf_surface_unselect_pattern (surface);
+
+    return _cairo_output_stream_get_status (surface->output);
+}
+
+static cairo_int_status_t
 _cairo_pdf_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_pdf_surface_t *surface = abstract_surface;
@@ -4685,14 +4668,15 @@ static const cairo_surface_backend_t cai
     _cairo_pdf_surface_mask,
     _cairo_pdf_surface_stroke,
     _cairo_pdf_surface_fill,
     _cairo_pdf_surface_show_glyphs,
     NULL, /* snapshot */
 
     NULL, /* is_compatible */
     NULL, /* reset */
+    _cairo_pdf_surface_fill_stroke,
 };
 
 static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend = {
     _cairo_pdf_surface_start_page,
     _cairo_pdf_surface_set_paginated_mode
 };
--- a/gfx/cairo/cairo/src/cairo-png.c
+++ b/gfx/cairo/cairo/src/cairo-png.c
@@ -127,31 +127,33 @@ write_png (cairo_surface_t	*surface,
     png_color_16 white;
     int png_color_type;
     int depth;
 
     status = _cairo_surface_acquire_source_image (surface,
 						  &image,
 						  &image_extra);
 
-    if (status == CAIRO_STATUS_NO_MEMORY)
-        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    else if (status != CAIRO_STATUS_SUCCESS)
+    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
 	return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+    else if (status)
+        return status;
+
+    /* PNG complains about "Image width or height is zero in IHDR" */
+    if (image->width == 0 || image->height == 0)
+	return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
 
-    if (image->height && image->width) {
-	rows = _cairo_malloc_ab (image->height, sizeof (png_byte*));
-	if (rows == NULL) {
-	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    goto BAIL1;
-	}
+    rows = _cairo_malloc_ab (image->height, sizeof (png_byte*));
+    if (rows == NULL) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto BAIL1;
+    }
 
-	for (i = 0; i < image->height; i++)
-	    rows[i] = (png_byte *) image->data + i * image->stride;
-    }
+    for (i = 0; i < image->height; i++)
+	rows[i] = (png_byte *) image->data + i * image->stride;
 
     png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status,
 	                           png_simple_error_callback,
 	                           png_simple_warning_callback);
     if (png == NULL) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	goto BAIL2;
     }
--- a/gfx/cairo/cairo/src/cairo-ps-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-ps-surface-private.h
@@ -1,8 +1,9 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2003 University of Southern California
  * 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
@@ -38,16 +39,17 @@
  */
 
 #ifndef CAIRO_PS_SURFACE_PRIVATE_H
 #define CAIRO_PS_SURFACE_PRIVATE_H
 
 #include "cairo-ps.h"
 
 #include "cairo-surface-private.h"
+#include "cairo-pdf-operators-private.h"
 
 typedef struct cairo_ps_surface {
     cairo_surface_t base;
 
     /* Here final_stream corresponds to the stream/file passed to
      * cairo_ps_surface_create surface is built. Meanwhile stream is a
      * temporary stream in which the file output is built, (so that
      * the header can be built and inserted into the target stream
@@ -57,16 +59,20 @@ typedef struct cairo_ps_surface {
     FILE *tmpfile;
     cairo_output_stream_t *stream;
 
     cairo_bool_t eps;
     cairo_content_t content;
     double width;
     double height;
     int bbox_x1, bbox_y1, bbox_x2, bbox_y2;
+    cairo_matrix_t cairo_to_ps;
+    cairo_image_surface_t *image;
+    void *image_extra;
+    cairo_bool_t use_string_datasource;
 
     int num_pages;
 
     cairo_paginated_mode_t paginated_mode;
 
     cairo_bool_t force_fallbacks;
 
     cairo_scaled_font_subsets_t *font_subsets;
@@ -75,12 +81,13 @@ typedef struct cairo_ps_surface {
     cairo_array_t dsc_setup_comments;
     cairo_array_t dsc_page_setup_comments;
 
     cairo_array_t *dsc_comment_target;
 
     cairo_ps_level_t ps_level;
     cairo_ps_level_t ps_level_used;
 
+    cairo_pdf_operators_t pdf_operators;
     cairo_surface_t *paginated_surface;
 } cairo_ps_surface_t;
 
 #endif /* CAIRO_PS_SURFACE_PRIVATE_H */
--- a/gfx/cairo/cairo/src/cairo-ps-surface.c
+++ b/gfx/cairo/cairo/src/cairo-ps-surface.c
@@ -1,14 +1,14 @@
 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2003 University of Southern California
  * Copyright © 2005 Red Hat, Inc
- * Copyright © 2007 Adrian Johnson
+ * Copyright © 2007,2008 Adrian Johnson
  *
  * 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.
@@ -38,16 +38,17 @@
  *	Kristian Høgsberg <krh@redhat.com>
  *	Keith Packard <keithp@keithp.com>
  *	Adrian Johnson <ajohnson@redneon.com>
  */
 
 #include "cairoint.h"
 #include "cairo-ps.h"
 #include "cairo-ps-surface-private.h"
+#include "cairo-pdf-operators-private.h"
 #include "cairo-scaled-font-subsets-private.h"
 #include "cairo-paginated-private.h"
 #include "cairo-meta-surface-private.h"
 #include "cairo-output-stream-private.h"
 
 #include <stdio.h>
 #include <ctype.h>
 #include <time.h>
@@ -78,258 +79,16 @@ static const cairo_ps_level_t _cairo_ps_
 #define CAIRO_PS_LEVEL_LAST ARRAY_LENGTH (_cairo_ps_levels)
 
 static const char * _cairo_ps_level_strings[CAIRO_PS_LEVEL_LAST] =
 {
     "PS Level 2",
     "PS Level 3"
 };
 
-/* A word wrap stream can be used as a filter to do word wrapping on
- * top of an existing output stream. The word wrapping is quite
- * simple, using isspace to determine characters that separate
- * words. Any word that will cause the column count exceed the given
- * max_column will have a '\n' character emitted before it.
- *
- * The stream is careful to maintain integrity for words that cross
- * the boundary from one call to write to the next.
- *
- * Note: This stream does not guarantee that the output will never
- * exceed max_column. In particular, if a single word is larger than
- * max_column it will not be broken up.
- */
-typedef struct _word_wrap_stream {
-    cairo_output_stream_t base;
-    cairo_output_stream_t *output;
-    int max_column;
-    int column;
-    cairo_bool_t last_write_was_space;
-} word_wrap_stream_t;
-
-static int
-_count_word_up_to (const unsigned char *s, int length)
-{
-    int word = 0;
-
-    while (length--) {
-	if (! isspace (*s++))
-	    word++;
-	else
-	    return word;
-    }
-
-    return word;
-}
-
-static cairo_status_t
-_word_wrap_stream_write (cairo_output_stream_t  *base,
-			 const unsigned char	*data,
-			 unsigned int		 length)
-{
-    word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
-    cairo_bool_t newline;
-    int word;
-
-    while (length) {
-	if (isspace (*data)) {
-	    newline =  (*data == '\n' || *data == '\r');
-	    if (! newline && stream->column >= stream->max_column) {
-		_cairo_output_stream_printf (stream->output, "\n");
-		stream->column = 0;
-	    }
-	    _cairo_output_stream_write (stream->output, data, 1);
-	    data++;
-	    length--;
-	    if (newline)
-		stream->column = 0;
-	    else
-		stream->column++;
-	    stream->last_write_was_space = TRUE;
-	} else {
-	    word = _count_word_up_to (data, length);
-	    /* Don't wrap if this word is a continuation of a word
-	     * from a previous call to write. */
-	    if (stream->column + word >= stream->max_column &&
-		stream->last_write_was_space)
-	    {
-		_cairo_output_stream_printf (stream->output, "\n");
-		stream->column = 0;
-	    }
-	    _cairo_output_stream_write (stream->output, data, word);
-	    data += word;
-	    length -= word;
-	    stream->column += word;
-	    stream->last_write_was_space = FALSE;
-	}
-    }
-
-    return _cairo_output_stream_get_status (stream->output);
-}
-
-static cairo_status_t
-_word_wrap_stream_close (cairo_output_stream_t *base)
-{
-    word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
-
-    return _cairo_output_stream_get_status (stream->output);
-}
-
-static cairo_output_stream_t *
-_word_wrap_stream_create (cairo_output_stream_t *output, int max_column)
-{
-    word_wrap_stream_t *stream;
-
-    if (output->status)
-	return _cairo_output_stream_create_in_error (output->status);
-
-    stream = malloc (sizeof (word_wrap_stream_t));
-    if (stream == NULL) {
-	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
-	return (cairo_output_stream_t *) &_cairo_output_stream_nil;
-    }
-
-    _cairo_output_stream_init (&stream->base,
-			       _word_wrap_stream_write,
-			       _word_wrap_stream_close);
-    stream->output = output;
-    stream->max_column = max_column;
-    stream->column = 0;
-    stream->last_write_was_space = FALSE;
-
-    return &stream->base;
-}
-
-typedef struct _ps_path_info {
-    cairo_ps_surface_t *surface;
-    cairo_output_stream_t *stream;
-    cairo_line_cap_t line_cap;
-    cairo_point_t last_move_to_point;
-    cairo_bool_t has_sub_path;
-} ps_path_info_t;
-
-static cairo_status_t
-_cairo_ps_surface_path_move_to (void *closure, cairo_point_t *point)
-{
-    ps_path_info_t *path_info = closure;
-
-    path_info->last_move_to_point = *point;
-    path_info->has_sub_path = FALSE;
-
-    _cairo_output_stream_printf (path_info->stream,
-				 "%f %f M ",
-				 _cairo_fixed_to_double (point->x),
-				 _cairo_fixed_to_double (point->y));
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_line_to (void *closure, cairo_point_t *point)
-{
-    ps_path_info_t *path_info = closure;
-
-    if (path_info->line_cap != CAIRO_LINE_CAP_ROUND &&
-	! path_info->has_sub_path &&
-	point->x == path_info->last_move_to_point.x &&
-	point->y == path_info->last_move_to_point.y)
-    {
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    path_info->has_sub_path = TRUE;
-
-    _cairo_output_stream_printf (path_info->stream,
-				 "%f %f L ",
-				 _cairo_fixed_to_double (point->x),
-				 _cairo_fixed_to_double (point->y));
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_curve_to (void          *closure,
-				 cairo_point_t *b,
-				 cairo_point_t *c,
-				 cairo_point_t *d)
-{
-    ps_path_info_t *path_info = closure;
-
-    path_info->has_sub_path = TRUE;
-
-    _cairo_output_stream_printf (path_info->stream,
-				 "%f %f %f %f %f %f C ",
-				 _cairo_fixed_to_double (b->x),
-				 _cairo_fixed_to_double (b->y),
-				 _cairo_fixed_to_double (c->x),
-				 _cairo_fixed_to_double (c->y),
-				 _cairo_fixed_to_double (d->x),
-				 _cairo_fixed_to_double (d->y));
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_close_path (void *closure)
-{
-    ps_path_info_t *path_info = closure;
-
-    if (path_info->line_cap != CAIRO_LINE_CAP_ROUND &&
-	! path_info->has_sub_path)
-    {
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    _cairo_output_stream_printf (path_info->stream,
-				 "P\n");
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-/* The line cap value is needed to workaround the fact that PostScript
- * semantics for stroking degenerate sub-paths do not match cairo
- * semantics. (PostScript draws something for any line cap value,
- * while cairo draws something only for round caps).
- *
- * When using this function to emit a path to be filled, rather than
- * stroked, simply pass %CAIRO_LINE_CAP_ROUND which will guarantee that
- * the stroke workaround will not modify the path being emitted.
- */
-static cairo_status_t
-_cairo_ps_surface_emit_path (cairo_ps_surface_t	   *surface,
-			     cairo_output_stream_t *stream,
-			     cairo_path_fixed_t    *path,
-			     cairo_line_cap_t	    line_cap)
-{
-    cairo_output_stream_t *word_wrap;
-    cairo_status_t status, status2;
-    ps_path_info_t path_info;
-
-    word_wrap = _word_wrap_stream_create (stream, 79);
-    status = _cairo_output_stream_get_status (word_wrap);
-    if (status)
-	return _cairo_output_stream_destroy (word_wrap);
-
-    path_info.surface = surface;
-    path_info.stream = word_wrap;
-    path_info.line_cap = line_cap;
-    status = _cairo_path_fixed_interpret (path,
-					  CAIRO_DIRECTION_FORWARD,
-					  _cairo_ps_surface_path_move_to,
-					  _cairo_ps_surface_path_line_to,
-					  _cairo_ps_surface_path_curve_to,
-					  _cairo_ps_surface_path_close_path,
-					  &path_info);
-
-    status2 = _cairo_output_stream_destroy (word_wrap);
-    if (status == CAIRO_STATUS_SUCCESS)
-	status = status2;
-
-    return status;
-}
-
 static void
 _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
 {
     char ctime_buf[26];
     time_t now;
     char **comments;
     int i, num_comments;
     int level;
@@ -383,36 +142,61 @@ static void
     if (surface->eps) {
 	_cairo_output_stream_printf (surface->final_stream,
 				     "/cairo_eps_state save def\n"
 				     "/dict_count countdictstack def\n"
 				     "/op_count count 1 sub def\n"
 				     "userdict begin\n");
     } else {
 	_cairo_output_stream_printf (surface->final_stream,
-				     "/languagelevel where{pop languagelevel}{1}ifelse %d lt{/Helvetica\n"
-				     "findfont 12 scalefont setfont 50 500 moveto\n"
-				     "(This print job requires a PostScript Language Level %d printer.)show\n"
-				     "showpage quit}if\n",
+				     "/languagelevel where\n"
+				     "{ pop languagelevel } { 1 } ifelse\n"
+				     "%d lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto\n"
+				     "  (This print job requires a PostScript Language Level %d printer.) show\n"
+				     "  showpage quit } if\n",
 				     level,
 				     level);
     }
 
     _cairo_output_stream_printf (surface->final_stream,
-				 "/C{curveto}bind def\n"
-				 "/F{fill}bind def\n"
-				 "/G{setgray}bind def\n"
-				 "/L{lineto}bind def\n"
-				 "/M{moveto}bind def\n"
-				 "/P{closepath}bind def\n"
-				 "/R{setrgbcolor}bind def\n"
-				 "/S{show}bind def\n"
-				 "/xS{xshow}bind def\n"
-				 "/yS{yshow}bind def\n"
-				 "/xyS{xyshow}bind def\n"
+				 "/q { gsave } bind def\n"
+				 "/Q { grestore } bind def\n"
+				 "/cm { 6 array astore concat } bind def\n"
+				 "/w { setlinewidth } bind def\n"
+				 "/J { setlinecap } bind def\n"
+				 "/j { setlinejoin } bind def\n"
+				 "/M { setmiterlimit } bind def\n"
+				 "/d { setdash } bind def\n"
+				 "/m { moveto } bind def\n"
+				 "/l { lineto } bind def\n"
+				 "/c { curveto } bind def\n"
+				 "/h { closepath } bind def\n"
+				 "/S { stroke } bind def\n"
+				 "/f { fill } bind def\n"
+				 "/f* { eofill } bind def\n"
+				 "/n { newpath } bind def\n"
+				 "/W { clip } bind def\n"
+				 "/W* { eoclip } bind def\n"
+				 "/Tf { pop /cairo_font exch def } bind def\n"
+				 "/BT { } bind def\n"
+				 "/ET { } bind def\n"
+				 "/Tj { show } bind def\n"
+				 "/TJ {\n"
+				 "  {\n"
+				 "    dup\n"
+				 "    type /stringtype eq\n"
+				 "    { show } { -0.0001 mul 0 rmoveto } ifelse\n"
+				 "  } forall\n"
+				 "} bind def\n"
+				 "/Td { moveto } bind def\n"
+				 "/Tm { 6 array astore cairo_font exch selectfont 0 0 moveto } bind def\n"
+				 "/g { setgray } bind def\n"
+				 "/rg { setrgbcolor } bind def\n");
+
+    _cairo_output_stream_printf (surface->final_stream,
 				 "%%%%EndProlog\n");
 
     num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
     if (num_comments) {
 	_cairo_output_stream_printf (surface->final_stream,
 				     "%%%%BeginSetup\n");
 
 	comments = _cairo_array_index (&surface->dsc_setup_comments, 0);
@@ -435,17 +219,17 @@ static cairo_status_t
 
 
 {
     cairo_type1_subset_t subset;
     cairo_status_t status;
     int length;
     char name[64];
 
-    snprintf (name, sizeof name, "CairoFont-%d-%d",
+    snprintf (name, sizeof name, "f-%d-%d",
 	      font_subset->font_id, font_subset->subset_id);
     status = _cairo_type1_subset_init (&subset, name, font_subset, TRUE);
     if (status)
 	return status;
 
     /* FIXME: Figure out document structure convention for fonts */
 
 #if DEBUG_PS
@@ -466,17 +250,17 @@ static cairo_status_t
 _cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t		*surface,
                                             cairo_scaled_font_subset_t	*font_subset)
 {
     cairo_type1_subset_t subset;
     cairo_status_t status;
     int length;
     char name[64];
 
-    snprintf (name, sizeof name, "CairoFont-%d-%d",
+    snprintf (name, sizeof name, "f-%d-%d",
 	      font_subset->font_id, font_subset->subset_id);
     status = _cairo_type1_fallback_init_hex (&subset, name, font_subset);
     if (status)
 	return status;
 
     /* FIXME: Figure out document structure convention for fonts */
 
 #if DEBUG_PS
@@ -511,17 +295,17 @@ static cairo_status_t
 #if DEBUG_PS
     _cairo_output_stream_printf (surface->final_stream,
 				 "%% _cairo_ps_surface_emit_truetype_font_subset\n");
 #endif
 
     _cairo_output_stream_printf (surface->final_stream,
 				 "11 dict begin\n"
 				 "/FontType 42 def\n"
-				 "/FontName /CairoFont-%d-%d def\n"
+				 "/FontName /f-%d-%d def\n"
 				 "/PaintType 0 def\n"
 				 "/FontMatrix [ 1 0 0 1 0 0 ] def\n"
 				 "/FontBBox [ 0 0 0 0 ] def\n"
 				 "/Encoding 256 array def\n"
 				 "0 1 255 { Encoding exch /.notdef put } for\n",
 				 font_subset->font_id,
 				 font_subset->subset_id);
 
@@ -581,58 +365,19 @@ static cairo_status_t
 				 "FontName currentdict end definefont pop\n");
 
     _cairo_truetype_subset_fini (&subset);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
-_cairo_ps_surface_emit_outline_glyph_data (cairo_ps_surface_t	*surface,
-					   cairo_scaled_font_t	*scaled_font,
-					   unsigned long	 glyph_index,
-					   cairo_box_t          *bbox)
-{
-    cairo_scaled_glyph_t *scaled_glyph;
-    cairo_status_t status;
-
-    status = _cairo_scaled_glyph_lookup (scaled_font,
-					 glyph_index,
-					 CAIRO_SCALED_GLYPH_INFO_METRICS|
-					 CAIRO_SCALED_GLYPH_INFO_PATH,
-					 &scaled_glyph);
-    if (status)
-	return status;
-
-    *bbox = scaled_glyph->bbox;
-    _cairo_output_stream_printf (surface->final_stream,
-				 "0 0 %f %f %f %f setcachedevice\n",
-				 _cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
-				 -_cairo_fixed_to_double (scaled_glyph->bbox.p2.y),
-				 _cairo_fixed_to_double (scaled_glyph->bbox.p2.x),
-				 -_cairo_fixed_to_double (scaled_glyph->bbox.p1.y));
-
-    /* We're filling not stroking, so we pass CAIRO_LINE_CAP_ROUND. */
-    status = _cairo_ps_surface_emit_path (surface,
-					  surface->final_stream,
-					  scaled_glyph->path,
-					  CAIRO_LINE_CAP_ROUND);
-    if (status)
-	return status;
-
-    _cairo_output_stream_printf (surface->final_stream,
-				 "F\n");
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
 _cairo_ps_surface_emit_bitmap_glyph_data (cairo_ps_surface_t	*surface,
 					  cairo_scaled_font_t	*scaled_font,
-					  unsigned long	 glyph_index,
+					  unsigned long	         glyph_index,
 					  cairo_box_t           *bbox)
 {
     cairo_scaled_glyph_t *scaled_glyph;
     cairo_status_t status;
     cairo_image_surface_t *image;
     unsigned char *row, *byte;
     int rows, cols;
     double x_advance, y_advance;
@@ -713,25 +458,20 @@ static cairo_status_t
 			      cairo_box_t               *bbox)
 {
     cairo_status_t	    status = CAIRO_STATUS_SUCCESS;
 
     _cairo_output_stream_printf (surface->final_stream,
 				 "\t\t{ %% %d\n", subset_glyph_index);
 
     if (subset_glyph_index != 0) {
-	status = _cairo_ps_surface_emit_outline_glyph_data (surface,
-							    scaled_font,
-							    scaled_font_glyph_index,
-							    bbox);
-	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
-	    status = _cairo_ps_surface_emit_bitmap_glyph_data (surface,
-							       scaled_font,
-							       scaled_font_glyph_index,
-							       bbox);
+	status = _cairo_ps_surface_emit_bitmap_glyph_data (surface,
+							   scaled_font,
+							   scaled_font_glyph_index,
+							   bbox);
     }
 
     _cairo_output_stream_printf (surface->final_stream,
 				 "\t\t}\n");
 
     if (status)
 	status = _cairo_surface_set_error (&surface->base, status);
 
@@ -810,17 +550,17 @@ static cairo_status_t
 				 "] def\n"
 				 "/FontBBox [%f %f %f %f] def\n"
 				 "/BuildChar {\n"
 				 "  exch /Glyphs get\n"
 				 "  exch get exec\n"
 				 "} bind def\n"
 				 "currentdict\n"
 				 "end\n"
-				 "/CairoFont-%d-%d exch definefont pop\n",
+				 "/f-%d-%d exch definefont pop\n",
 				 _cairo_fixed_to_double (font_bbox.p1.x),
 				 _cairo_fixed_to_double (font_bbox.p1.y),
 				 _cairo_fixed_to_double (font_bbox.p2.x),
 				 _cairo_fixed_to_double (font_bbox.p2.y),
 				 font_subset->font_id,
 				 font_subset->subset_id);
 
     return CAIRO_STATUS_SUCCESS;
@@ -978,20 +718,26 @@ static cairo_surface_t *
 	goto CLEANUP_OUTPUT_STREAM;
     }
 
     surface->eps = FALSE;
     surface->ps_level = CAIRO_PS_LEVEL_3;
     surface->ps_level_used = CAIRO_PS_LEVEL_2;
     surface->width  = width;
     surface->height = height;
+    cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, height);
     surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
     surface->force_fallbacks = FALSE;
     surface->content = CAIRO_CONTENT_COLOR_ALPHA;
-
+    surface->use_string_datasource = FALSE;
+
+    _cairo_pdf_operators_init (&surface->pdf_operators,
+			       surface->stream,
+			       &surface->cairo_to_ps,
+			       surface->font_subsets);
     surface->num_pages = 0;
 
     _cairo_array_init (&surface->dsc_header_comments, sizeof (char *));
     _cairo_array_init (&surface->dsc_setup_comments, sizeof (char *));
     _cairo_array_init (&surface->dsc_page_setup_comments, sizeof (char *));
 
     surface->dsc_comment_target = &surface->dsc_header_comments;
 
@@ -1288,16 +1034,19 @@ cairo_ps_surface_set_size (cairo_surface
     status = _extract_ps_surface (surface, &ps_surface);
     if (status) {
 	status = _cairo_surface_set_error (surface, status);
 	return;
     }
 
     ps_surface->width = width_in_points;
     ps_surface->height = height_in_points;
+    cairo_matrix_init (&ps_surface->cairo_to_ps, 1, 0, 0, -1, 0, height_in_points);
+    _cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface->pdf_operators,
+						  &ps_surface->cairo_to_ps);
     status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface,
 						width_in_points,
 						height_in_points);
     if (status)
 	status = _cairo_surface_set_error (surface, status);
 }
 
 /**
@@ -1569,17 +1318,17 @@ static cairo_int_status_t
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static void
 _cairo_ps_surface_end_page (cairo_ps_surface_t *surface)
 {
     _cairo_output_stream_printf (surface->stream,
-				 "grestore grestore\n");
+				 "grestore\n");
 }
 
 static cairo_int_status_t
 _cairo_ps_surface_show_page (void *abstract_surface)
 {
     cairo_ps_surface_t *surface = abstract_surface;
 
     _cairo_ps_surface_end_page (surface);
@@ -1593,53 +1342,48 @@ static cairo_bool_t
 color_is_gray (double red, double green, double blue)
 {
     const double epsilon = 0.00001;
 
     return (fabs (red - green) < epsilon &&
 	    fabs (red - blue) < epsilon);
 }
 
-static cairo_status_t
-_analyze_image_transparency (cairo_image_surface_t      *image,
-			     cairo_image_transparency_t *transparency)
+static cairo_image_transparency_t
+_analyze_image_transparency (cairo_image_surface_t      *image)
 {
     int x, y;
-
-    if (image->format == CAIRO_FORMAT_RGB24) {
-	*transparency = CAIRO_IMAGE_IS_OPAQUE;
-	return CAIRO_STATUS_SUCCESS;
-    }
+    cairo_image_transparency_t transparency;
+
+    if (image->format == CAIRO_FORMAT_RGB24)
+	return CAIRO_IMAGE_IS_OPAQUE;
 
     if (image->format != CAIRO_FORMAT_ARGB32) {
 	/* If the PS surface does not support the image format, assume
 	 * that it does have alpha. The image will be converted to
 	 * rgb24 when the PS surface blends the image into the page
 	 * color to remove the transparency. */
-	*transparency = CAIRO_IMAGE_HAS_ALPHA;
-	return CAIRO_STATUS_SUCCESS;
+	return CAIRO_IMAGE_HAS_ALPHA;
     }
 
-    *transparency = CAIRO_IMAGE_IS_OPAQUE;
+    transparency = CAIRO_IMAGE_IS_OPAQUE;
     for (y = 0; y < image->height; y++) {
-	int a;
 	uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
 
 	for (x = 0; x < image->width; x++, pixel++) {
-	    a = (*pixel & 0xff000000) >> 24;
+	    int a = (*pixel & 0xff000000) >> 24;
 	    if (a > 0 && a < 255) {
-		*transparency = CAIRO_IMAGE_HAS_ALPHA;
-		return CAIRO_STATUS_SUCCESS;
+		return CAIRO_IMAGE_HAS_ALPHA;
 	    } else if (a == 0) {
-		*transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
+		transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
 	    }
 	}
     }
 
-    return CAIRO_STATUS_SUCCESS;
+    return transparency;
 }
 
 static cairo_int_status_t
 _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t      *surface,
 						       cairo_surface_pattern_t *pattern)
 {
     cairo_image_surface_t  *image;
     void		   *image_extra;
@@ -1650,20 +1394,17 @@ static cairo_int_status_t
 						  &image,
 						  &image_extra);
     if (status)
 	return status;
 
     if (image->base.status)
 	return image->base.status;
 
-    status = _analyze_image_transparency (image, &transparency);
-    if (status)
-	goto RELEASE_SOURCE;
-
+    transparency = _analyze_image_transparency (image);
     switch (transparency) {
     case CAIRO_IMAGE_IS_OPAQUE:
 	status = CAIRO_STATUS_SUCCESS;
 	break;
 
     case CAIRO_IMAGE_HAS_BILEVEL_ALPHA:
 	if (surface->ps_level == CAIRO_PS_LEVEL_2) {
 	    status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
@@ -1673,17 +1414,16 @@ static cairo_int_status_t
 	}
 	break;
 
     case CAIRO_IMAGE_HAS_ALPHA:
 	status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
 	break;
     }
 
-RELEASE_SOURCE:
     _cairo_surface_release_source_image (pattern->surface, image, image_extra);
 
     return status;
 }
 
 static cairo_bool_t
 surface_pattern_supported (cairo_surface_pattern_t *pattern)
 {
@@ -1850,59 +1590,64 @@ static cairo_bool_t
 #define STRING_ARRAY_MAX_STRING_SIZE (65535-1)
 #define STRING_ARRAY_MAX_COLUMN	     72
 
 typedef struct _string_array_stream {
     cairo_output_stream_t base;
     cairo_output_stream_t *output;
     int column;
     int string_size;
+    cairo_bool_t use_strings;
 } string_array_stream_t;
 
 static cairo_status_t
 _string_array_stream_write (cairo_output_stream_t *base,
 			    const unsigned char   *data,
 			    unsigned int	   length)
 {
     string_array_stream_t *stream = (string_array_stream_t *) base;
     unsigned char c;
     const unsigned char backslash = '\\';
 
     if (length == 0)
 	return CAIRO_STATUS_SUCCESS;
 
     while (length--) {
-	if (stream->string_size == 0) {
+	if (stream->string_size == 0 && stream->use_strings) {
 	    _cairo_output_stream_printf (stream->output, "(");
 	    stream->column++;
 	}
 
 	c = *data++;
-	switch (c) {
-	case '\\':
-	case '(':
-	case ')':
-	    _cairo_output_stream_write (stream->output, &backslash, 1);
-	    stream->column++;
-	    stream->string_size++;
-	    break;
-	/* Have to also be careful to never split the final ~> sequence. */
-	case '~':
-	    _cairo_output_stream_write (stream->output, &c, 1);
-	    stream->column++;
-	    stream->string_size++;
-	    length--;
-	    c = *data++;
-	    break;
+	if (stream->use_strings) {
+	    switch (c) {
+	    case '\\':
+	    case '(':
+	    case ')':
+		_cairo_output_stream_write (stream->output, &backslash, 1);
+		stream->column++;
+		stream->string_size++;
+		break;
+		/* Have to also be careful to never split the final ~> sequence. */
+	    case '~':
+		_cairo_output_stream_write (stream->output, &c, 1);
+		stream->column++;
+		stream->string_size++;
+		length--;
+		c = *data++;
+		break;
+	    }
 	}
 	_cairo_output_stream_write (stream->output, &c, 1);
 	stream->column++;
 	stream->string_size++;
 
-	if (stream->string_size >= STRING_ARRAY_MAX_STRING_SIZE) {
+	if (stream->use_strings &&
+	    stream->string_size >= STRING_ARRAY_MAX_STRING_SIZE)
+	{
 	    _cairo_output_stream_printf (stream->output, ")\n");
 	    stream->string_size = 0;
 	    stream->column = 0;
 	}
 	if (stream->column >= STRING_ARRAY_MAX_COLUMN) {
 	    _cairo_output_stream_printf (stream->output, "\n ");
 	    stream->string_size += 2;
 	    stream->column = 1;
@@ -1913,17 +1658,18 @@ static cairo_status_t
 }
 
 static cairo_status_t
 _string_array_stream_close (cairo_output_stream_t *base)
 {
     cairo_status_t status;
     string_array_stream_t *stream = (string_array_stream_t *) base;
 
-    _cairo_output_stream_printf (stream->output, ")\n");
+    if (stream->use_strings)
+	_cairo_output_stream_printf (stream->output, ")\n");
 
     status = _cairo_output_stream_get_status (stream->output);
 
     return status;
 }
 
 /* A string_array_stream wraps an existing output stream. It takes the
  * data provided to it and output one or more consecutive string
@@ -1951,20 +1697,48 @@ static cairo_output_stream_t *
     }
 
     _cairo_output_stream_init (&stream->base,
 			       _string_array_stream_write,
 			       _string_array_stream_close);
     stream->output = output;
     stream->column = 0;
     stream->string_size = 0;
+    stream->use_strings = TRUE;
 
     return &stream->base;
 }
 
+/* A base85_array_stream wraps an existing output stream. It wraps the
+ * output within STRING_ARRAY_MAX_COLUMN columns (+/- 1). The output
+ * is not enclosed in strings like string_array_stream.
+ */
+static cairo_output_stream_t *
+_base85_array_stream_create (cairo_output_stream_t *output)
+{
+    string_array_stream_t *stream;
+
+    stream = malloc (sizeof (string_array_stream_t));
+    if (stream == NULL) {
+	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_output_stream_t *) &_cairo_output_stream_nil;
+    }
+
+    _cairo_output_stream_init (&stream->base,
+			       _string_array_stream_write,
+			       _string_array_stream_close);
+    stream->output = output;
+    stream->column = 0;
+    stream->string_size = 0;
+    stream->use_strings = FALSE;
+
+    return &stream->base;
+}
+
+
 /* PS Output - this section handles output of the parts of the meta
  * surface we can render natively in PS. */
 
 static cairo_status_t
 _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t    *surface,
 					      cairo_image_surface_t *image,
 					      cairo_image_surface_t **opaque_image)
 {
@@ -2016,22 +1790,27 @@ fail:
     cairo_surface_destroy (opaque);
 
     return status;
 }
 
 static cairo_status_t
 _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t    *surface,
 				      unsigned char	    *data,
-				      unsigned long	     length)
+				      unsigned long	     length,
+				      cairo_bool_t           use_strings)
 {
     cairo_output_stream_t *base85_stream, *string_array_stream;
     cairo_status_t status, status2;
 
-    string_array_stream = _string_array_stream_create (surface->stream);
+    if (use_strings)
+	string_array_stream = _string_array_stream_create (surface->stream);
+    else
+	string_array_stream = _base85_array_stream_create (surface->stream);
+
     status = _cairo_output_stream_get_status (string_array_stream);
     if (status)
 	return _cairo_output_stream_destroy (string_array_stream);
 
     base85_stream = _cairo_base85_stream_create (string_array_stream);
     status = _cairo_output_stream_get_status (base85_stream);
     if (status) {
 	status2 = _cairo_output_stream_destroy (string_array_stream);
@@ -2046,35 +1825,32 @@ static cairo_status_t
 	status = status2;
 
     return status;
 }
 
 static cairo_status_t
 _cairo_ps_surface_emit_image (cairo_ps_surface_t    *surface,
 			      cairo_image_surface_t *image,
-			      const char	    *name,
 			      cairo_operator_t	     op)
 {
     cairo_status_t status;
-    unsigned char *rgb, *rgb_compressed;
-    unsigned long rgb_size, rgb_compressed_size;
-    unsigned char *mask = NULL, *mask_compressed = NULL;
-    unsigned long mask_size = 0, mask_compressed_size = 0;
+    unsigned char *data, *data_compressed;
+    unsigned long data_size, data_compressed_size;
     cairo_image_surface_t *opaque_image = NULL;
     int x, y, i;
     cairo_image_transparency_t transparency;
     cairo_bool_t use_mask;
+    uint32_t *pixel;
+    int bit;
 
     if (image->base.status)
 	return image->base.status;
 
-    status = _analyze_image_transparency (image, &transparency);
-    if (status)
-	return status;
+    transparency = _analyze_image_transparency (image);
 
     /* PostScript can not represent the alpha channel, so we blend the
        current image over a white (or black for CONTENT_COLOR
        surfaces) RGB surface to eliminate it. */
 
     if (op == CAIRO_OPERATOR_SOURCE ||
 	transparency == CAIRO_IMAGE_HAS_ALPHA ||
 	(transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA &&
@@ -2089,284 +1865,253 @@ static cairo_status_t
 	use_mask = FALSE;
     } else if (transparency == CAIRO_IMAGE_IS_OPAQUE) {
 	opaque_image = image;
 	use_mask = FALSE;
     } else {
 	use_mask = TRUE;
     }
 
-    rgb_size = 3 * image->width * image->height;
-    rgb = _cairo_malloc_abc (image->width, image->height, 3);
-    if (rgb == NULL) {
+    if (use_mask) {
+	/* Type 2 (mask and image interleaved) has the mask and image
+	 * samples interleaved by row.  The mask row is first, one bit
+	 * per pixel with (bit 7 first). The row is padded to byte
+	 * boundaries. The image data is 3 bytes per pixel RGB
+	 * format. */
+	data_size = image->height * ((image->width + 7)/8 + 3*image->width);
+    } else {
+	data_size = image->height * image->width * 3;
+    }
+    data = malloc (data_size);
+    if (data == NULL) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	goto bail1;
     }
 
     if (use_mask) {
-	mask_size = ((image->width+7) / 8) * image->height;
-	mask = _cairo_malloc_ab ((image->width+7) / 8, image->height);
-	if (mask == NULL) {
-	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    goto bail2;
-	}
-    }
-
-    if (use_mask) {
-	int byte = 0;
-	int bit = 7;
 	i = 0;
 	for (y = 0; y < image->height; y++) {
-	    uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
+	    /* mask row */
+	    pixel = (uint32_t *) (image->data + y * image->stride);
+	    bit = 7;
 	    for (x = 0; x < image->width; x++, pixel++) {
 		if (bit == 7)
-		    mask[byte] = 0;
+		    data[i] = 0;
 		if (((*pixel & 0xff000000) >> 24) > 0x80)
-		    mask[byte] |= (1 << bit);
+		    data[i] |= (1 << bit);
 		bit--;
 		if (bit < 0) {
 		    bit = 7;
-		    byte++;
+		    i++;
 		}
-		rgb[i++] = (*pixel & 0x00ff0000) >> 16;
-		rgb[i++] = (*pixel & 0x0000ff00) >>  8;
-		rgb[i++] = (*pixel & 0x000000ff) >>  0;
 	    }
-
-	    if (bit != 7) {
-		bit = 7;
-		byte++;
+	    if (bit != 7)
+		i++;
+
+	    /* image row*/
+	    pixel = (uint32_t *) (image->data + y * image->stride);
+	    for (x = 0; x < image->width; x++, pixel++) {
+		data[i++] = (*pixel & 0x00ff0000) >> 16;
+		data[i++] = (*pixel & 0x0000ff00) >>  8;
+		data[i++] = (*pixel & 0x000000ff) >>  0;
 	    }
 	}
     } else {
 	i = 0;
 	for (y = 0; y < opaque_image->height; y++) {
-	    uint32_t *pixel = (uint32_t *) (opaque_image->data + y * opaque_image->stride);
+	    pixel = (uint32_t *) (opaque_image->data + y * opaque_image->stride);
 	    for (x = 0; x < opaque_image->width; x++, pixel++) {
-		rgb[i++] = (*pixel & 0x00ff0000) >> 16;
-		rgb[i++] = (*pixel & 0x0000ff00) >>  8;
-		rgb[i++] = (*pixel & 0x000000ff) >>  0;
+		data[i++] = (*pixel & 0x00ff0000) >> 16;
+		data[i++] = (*pixel & 0x0000ff00) >>  8;
+		data[i++] = (*pixel & 0x000000ff) >>  0;
 	    }
 	}
     }
 
     /* XXX: Should fix cairo-lzw to provide a stream-based interface
      * instead. */
-    rgb_compressed_size = rgb_size;
-    rgb_compressed = _cairo_lzw_compress (rgb, &rgb_compressed_size);
-    if (rgb_compressed == NULL) {
+    data_compressed_size = data_size;
+    data_compressed = _cairo_lzw_compress (data, &data_compressed_size);
+    if (data_compressed == NULL) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto bail3;
+	goto bail2;
     }
 
-    /* First emit the image data as a base85-encoded string which will
-     * be used as the data source for the image operator later. */
-    _cairo_output_stream_printf (surface->stream,
-				 "/%sData [\n", name);
-
-    status = _cairo_ps_surface_emit_base85_string (surface,
-						   rgb_compressed,
-						   rgb_compressed_size);
-    if (status)
-	goto bail4;
-
-    _cairo_output_stream_printf (surface->stream,
-				 "] def\n");
-    _cairo_output_stream_printf (surface->stream,
-				 "/%sDataIndex 0 def\n", name);
-
-    /* Emit the mask data as a base85-encoded string which will
-     * be used as the mask source for the image operator later. */
-    if (mask) {
-	mask_compressed_size = mask_size;
-	mask_compressed = _cairo_lzw_compress (mask, &mask_compressed_size);
-	if (mask_compressed == NULL) {
-	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    goto bail4;
-	}
-
+    if (surface->use_string_datasource) {
+	/* Emit the image data as a base85-encoded string which will
+	 * be used as the data source for the image operator later. */
 	_cairo_output_stream_printf (surface->stream,
-				     "/%sMask [\n", name);
+				     "/CairoImageData [\n");
 
 	status = _cairo_ps_surface_emit_base85_string (surface,
-						       mask_compressed,
-						       mask_compressed_size);
+						       data_compressed,
+						       data_compressed_size,
+						       TRUE);
 	if (status)
-	    goto bail5;
+	    goto bail3;
 
 	_cairo_output_stream_printf (surface->stream,
 				     "] def\n");
 	_cairo_output_stream_printf (surface->stream,
-				     "/%sMaskIndex 0 def\n", name);
+				     "/CairoImageDataIndex 0 def\n");
     }
 
-    if (mask) {
+    if (use_mask) {
 	_cairo_output_stream_printf (surface->stream,
-				     "/%s {\n"
-				     "    /DeviceRGB setcolorspace\n"
-				     "    <<\n"
-				     "	/ImageType 3\n"
-				     "	/InterleaveType 3\n"
-				     "	/DataDict <<\n"
-				     "		/ImageType 1\n"
-				     "		/Width %d\n"
-				     "		/Height %d\n"
-				     "		/BitsPerComponent 8\n"
-				     "		/Decode [ 0 1 0 1 0 1 ]\n"
-				     "		/DataSource {\n"
-				     "	    		%sData %sDataIndex get\n"
-				     "	    		/%sDataIndex %sDataIndex 1 add def\n"
-				     "	    		%sDataIndex %sData length 1 sub gt { /%sDataIndex 0 def } if\n"
-				     "		} /ASCII85Decode filter /LZWDecode filter\n"
-				     "		/ImageMatrix [ 1 0 0 1 0 0 ]\n"
-				     "	>>\n"
-				     "	/MaskDict <<\n"
-				     "		/ImageType 1\n"
-				     "		/Width %d\n"
-				     "		/Height %d\n"
-				     "		/BitsPerComponent 1\n"
-				     "		/Decode [ 1 0 ]\n"
-				     "		/DataSource {\n"
-				     "	    		%sMask %sMaskIndex get\n"
-				     "	    		/%sMaskIndex %sMaskIndex 1 add def\n"
-				     "	    		%sMaskIndex %sMask length 1 sub gt { /%sMaskIndex 0 def } if\n"
-				     "		} /ASCII85Decode filter /LZWDecode filter\n"
-				     "		/ImageMatrix [ 1 0 0 1 0 0 ]\n"
-				     "	>>\n"
-				     "    >>\n"
-				     "    image\n"
-				     "} def\n",
-				     name,
+				     "/DeviceRGB setcolorspace\n"
+				     "5 dict dup begin\n"
+				     "  /ImageType 3 def\n"
+				     "  /InterleaveType 2 def\n"
+				     "  /DataDict 8 dict def\n"
+				     "    DataDict begin\n"
+				     "    /ImageType 1 def\n"
+				     "    /Width %d def\n"
+				     "    /Height %d def\n"
+				     "    /BitsPerComponent 8 def\n"
+				     "    /Decode [ 0 1 0 1 0 1 ] def\n",
+				     image->width,
+				     image->height);
+
+	if (surface->use_string_datasource) {
+	    _cairo_output_stream_printf (surface->stream,
+					 "    /DataSource {\n"
+					 "      CairoImageData CairoImageDataIndex get\n"
+					 "	/CairoImageDataIndex CairoImageDataIndex 1 add def\n"
+					 "	CairoImageDataIndex CairoImageData length 1 sub gt\n"
+					 "       { /CairoImageDataIndex 0 def } if\n"
+					 "    } /ASCII85Decode filter /LZWDecode filter def\n");
+	} else {
+	    _cairo_output_stream_printf (surface->stream,
+					 "    /DataSource currentfile /ASCII85Decode filter /LZWDecode filter def\n");
+	}
+
+	_cairo_output_stream_printf (surface->stream,
+				     "    /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
+				     "  end\n"
+				     "  /MaskDict 8 dict def\n"
+				     "     MaskDict begin\n"
+				     "    /ImageType 1 def\n"
+				     "    /Width %d def\n"
+				     "    /Height %d def\n"
+				     "    /BitsPerComponent 1 def\n"
+				     "    /Decode [ 1 0 ] def\n"
+				     "    /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
+				     "  end\n"
+				     "end\n"
+				     "image\n",
+				     image->height,
 				     image->width,
 				     image->height,
-				     name, name, name, name, name, name, name,
-				     image->width,
-				     image->height,
-				     name, name, name, name, name, name, name);
+				     image->height);
     } else {
 	_cairo_output_stream_printf (surface->stream,
-				     "/%s {\n"
-				     "    /DeviceRGB setcolorspace\n"
-				     "    <<\n"
-				     "	/ImageType 1\n"
-				     "	/Width %d\n"
-				     "	/Height %d\n"
-				     "	/BitsPerComponent 8\n"
-				     "	/Decode [ 0 1 0 1 0 1 ]\n"
-				     "	/DataSource {\n"
-				     "	    %sData %sDataIndex get\n"
-				     "	    /%sDataIndex %sDataIndex 1 add def\n"
-				     "	    %sDataIndex %sData length 1 sub gt { /%sDataIndex 0 def } if\n"
-				     "	} /ASCII85Decode filter /LZWDecode filter\n"
-				     "	/ImageMatrix [ 1 0 0 1 0 0 ]\n"
-				     "    >>\n"
-				     "    image\n"
-				     "} def\n",
-				     name,
+				     "/DeviceRGB setcolorspace\n"
+				     "8 dict dup begin\n"
+				     "  /ImageType 1 def\n"
+				     "  /Width %d def\n"
+				     "  /Height %d def\n"
+				     "  /BitsPerComponent 8 def\n"
+				     "  /Decode [ 0 1 0 1 0 1 ] def\n",
 				     opaque_image->width,
-				     opaque_image->height,
-				     name, name, name, name, name, name, name);
+				     opaque_image->height);
+	if (surface->use_string_datasource) {
+	    _cairo_output_stream_printf (surface->stream,
+					 "  /DataSource {\n"
+					 "    CairoImageData CairoImageDataIndex get\n"
+					 "    /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
+					 "    CairoImageDataIndex CairoImageData length 1 sub gt\n"
+					 "     { /CairoImageDataIndex 0 def } if\n"
+					 "  } /ASCII85Decode filter /LZWDecode filter def\n");
+	} else {
+	    _cairo_output_stream_printf (surface->stream,
+					 "  /DataSource currentfile /ASCII85Decode filter /LZWDecode filter def\n");
+	}
+
+	_cairo_output_stream_printf (surface->stream,
+				     "  /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
+				     "end\n"
+				     "image\n",
+				     opaque_image->height);
     }
 
-    status = CAIRO_STATUS_SUCCESS;
-
-bail5:
-    if (use_mask)
-	free (mask_compressed);
-bail4:
-    free (rgb_compressed);
+    if (!surface->use_string_datasource) {
+	/* Emit the image data as a base85-encoded string which will
+	 * be used as the data source for the image operator. */
+	status = _cairo_ps_surface_emit_base85_string (surface,
+						       data_compressed,
+						       data_compressed_size,
+						       FALSE);
+    } else {
+	status = CAIRO_STATUS_SUCCESS;
+    }
 
 bail3:
-    if (use_mask)
-	free (mask);
+    free (data_compressed);
+
 bail2:
-    free (rgb);
+    free (data);
 
 bail1:
     if (!use_mask && opaque_image != image)
 	cairo_surface_destroy (&opaque_image->base);
 
     return status;
 }
 
 static cairo_status_t
-_cairo_ps_surface_emit_image_surface (cairo_ps_surface_t      *surface,
-				      cairo_surface_pattern_t *pattern,
-				      int                     *width,
-				      int                     *height,
-				      cairo_operator_t	       op)
-{
-    cairo_image_surface_t  *image;
-    void		   *image_extra;
-    cairo_status_t          status;
-
-    status = _cairo_surface_acquire_source_image (pattern->surface,
-						  &image,
-						  &image_extra);
-    if (status)
-	return status;
-
-    status = _cairo_ps_surface_emit_image (surface, image, "CairoPattern", op);
-    if (status)
-	goto fail;
-
-    *width = image->width;
-    *height = image->height;
-
-fail:
-    _cairo_surface_release_source_image (pattern->surface, image, image_extra);
-
-    return status;
-}
-
-static cairo_status_t
 _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t  *surface,
 				     cairo_surface_t      *meta_surface)
 {
     double old_width, old_height;
+    cairo_matrix_t old_cairo_to_ps;
     cairo_content_t old_content;
     cairo_rectangle_int_t meta_extents;
     cairo_status_t status;
 
     status = _cairo_surface_get_extents (meta_surface, &meta_extents);
     if (status)
 	return status;
 
     old_content = surface->content;
     old_width = surface->width;
     old_height = surface->height;
+    old_cairo_to_ps = surface->cairo_to_ps;
     surface->width = meta_extents.width;
     surface->height = meta_extents.height;
+    cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
+    _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
+						  &surface->cairo_to_ps);
     _cairo_output_stream_printf (surface->stream,
-				 "/CairoPattern {\n"
 				 "  gsave\n"
 				 "  0 0 %f %f rectclip\n",
 				 surface->width,
 				 surface->height);
 
     if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
 	surface->content = CAIRO_CONTENT_COLOR;
 	_cairo_output_stream_printf (surface->stream,
-				     "  0 G 0 0 %f %f rectfill\n",
+				     "  0 g 0 0 %f %f rectfill\n",
 				     surface->width,
 				     surface->height);
     }
 
     status = _cairo_meta_surface_replay_region (meta_surface, &surface->base,
 						CAIRO_META_REGION_NATIVE);
     assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
     if (status)
 	return status;
 
     _cairo_output_stream_printf (surface->stream,
-				 "  grestore\n"
-				 "} bind def\n");
+				 "  grestore\n");
     surface->content = old_content;
     surface->width = old_width;
     surface->height = old_height;
+    surface->cairo_to_ps = old_cairo_to_ps;
+    _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
+						  &surface->cairo_to_ps);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static void
 _cairo_ps_surface_flatten_transparency (cairo_ps_surface_t	*surface,
 					const cairo_color_t	*color,
 					double			*red,
@@ -2397,63 +2142,148 @@ static void
 				      cairo_solid_pattern_t *pattern)
 {
     double red, green, blue;
 
     _cairo_ps_surface_flatten_transparency (surface, &pattern->color, &red, &green, &blue);
 
     if (color_is_gray (red, green, blue))
 	_cairo_output_stream_printf (surface->stream,
-				     "%f G\n",
+				     "%f g\n",
 				     red);
     else
 	_cairo_output_stream_printf (surface->stream,
-				     "%f %f %f R\n",
+				     "%f %f %f rg\n",
 				     red, green, blue);
 }
 
 static cairo_status_t
+_cairo_ps_surface_acquire_surface (cairo_ps_surface_t      *surface,
+				   cairo_surface_pattern_t *pattern,
+				   int                     *width,
+				   int                     *height,
+				   cairo_operator_t	    op)
+{
+    cairo_status_t          status;
+
+    if (_cairo_surface_is_meta (pattern->surface)) {
+	cairo_surface_t *meta_surface = pattern->surface;
+	cairo_rectangle_int_t pattern_extents;
+
+	status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
+	*width = pattern_extents.width;
+	*height = pattern_extents.height;
+    } else {
+	status = _cairo_surface_acquire_source_image (pattern->surface,
+						      &surface->image,
+						      &surface->image_extra);
+	*width = surface->image->width;
+	*height = surface->image->height;
+    }
+
+    return status;
+}
+
+static cairo_status_t
+_cairo_ps_surface_emit_surface (cairo_ps_surface_t      *surface,
+				cairo_surface_pattern_t *pattern,
+				cairo_operator_t	 op)
+{
+    cairo_status_t status;
+
+    if (_cairo_surface_is_meta (pattern->surface)) {
+	cairo_surface_t *meta_surface = pattern->surface;
+
+	status = _cairo_ps_surface_emit_meta_surface (surface,
+						      meta_surface);
+    } else {
+	status = _cairo_ps_surface_emit_image (surface, surface->image, op);
+    }
+
+    return status;
+}
+
+static void
+_cairo_ps_surface_release_surface (cairo_ps_surface_t      *surface,
+				   cairo_surface_pattern_t *pattern)
+{
+    if (!_cairo_surface_is_meta (pattern->surface))
+	_cairo_surface_release_source_image (pattern->surface, surface->image,
+					     surface->image_extra);
+}
+
+static cairo_status_t
+_cairo_ps_surface_paint_surface (cairo_ps_surface_t      *surface,
+				 cairo_surface_pattern_t *pattern,
+				 cairo_operator_t	  op)
+{
+    cairo_status_t status;
+    int width, height;
+    cairo_matrix_t cairo_p2d, ps_p2d;
+
+    status = _cairo_ps_surface_acquire_surface (surface,
+						pattern,
+						&width,
+						&height,
+						op);
+    if (status)
+	return status;
+
+    cairo_p2d = pattern->base.matrix;
+    status = cairo_matrix_invert (&cairo_p2d);
+    /* cairo_pattern_set_matrix ensures the matrix is invertible */
+    assert (status == CAIRO_STATUS_SUCCESS);
+
+    ps_p2d = surface->cairo_to_ps;
+    cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
+    cairo_matrix_translate (&ps_p2d, 0.0, height);
+    cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+
+    _cairo_output_stream_printf (surface->stream,
+				 "[ %f %f %f %f %f %f ] concat\n",
+				 ps_p2d.xx, ps_p2d.yx,
+				 ps_p2d.xy, ps_p2d.yy,
+				 ps_p2d.x0, ps_p2d.y0);
+
+    status = _cairo_ps_surface_emit_surface (surface, pattern, op);
+    _cairo_ps_surface_release_surface (surface, pattern);
+
+    return status;
+}
+
+static cairo_status_t
 _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t      *surface,
 					cairo_surface_pattern_t *pattern,
 					cairo_operator_t	 op)
 {
     cairo_status_t status;
     int pattern_width = 0; /* squelch bogus compiler warning */
     int pattern_height = 0; /* squelch bogus compiler warning */
     double xstep, ystep;
-    cairo_matrix_t inverse = pattern->base.matrix;
-
-    status = cairo_matrix_invert (&inverse);
+    cairo_matrix_t cairo_p2d, ps_p2d;
+    cairo_rectangle_int16_t surface_extents;
+    cairo_bool_t old_use_string_datasource;
+
+    cairo_p2d = pattern->base.matrix;
+    status = cairo_matrix_invert (&cairo_p2d);
     /* cairo_pattern_set_matrix ensures the matrix is invertible */
     assert (status == CAIRO_STATUS_SUCCESS);
 
-    if (_cairo_surface_is_meta (pattern->surface)) {
-	cairo_surface_t *meta_surface = pattern->surface;
-	cairo_rectangle_int_t pattern_extents;
-
-	status = _cairo_ps_surface_emit_meta_surface (surface,
-						      meta_surface);
-	if (status)
-	    return status;
-
-	status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
-	if (status)
-	    return status;
-
-	pattern_width = pattern_extents.width;
-	pattern_height = pattern_extents.height;
-    } else {
-	status = _cairo_ps_surface_emit_image_surface (surface,
-						       pattern,
-						       &pattern_width,
-						       &pattern_height,
-						       op);
-	if (status)
-	    return status;
-    }
+    ps_p2d = surface->cairo_to_ps;
+    cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
+    cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
+    cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+
+    status = _cairo_ps_surface_acquire_surface (surface,
+						pattern,
+						&pattern_width,
+						&pattern_height,
+						op);
+    if (status)
+	return status;
 
     switch (pattern->base.extend) {
 	/* We implement EXTEND_PAD like EXTEND_NONE for now */
     case CAIRO_EXTEND_PAD:
     case CAIRO_EXTEND_NONE:
     {
 	/* In PS/PDF, (as far as I can tell), all patterns are
 	 * repeating. So we support cairo's EXTEND_NONE semantics
@@ -2493,16 +2323,29 @@ static cairo_status_t
 	 * cases should be unreachable. */
     default:
 	ASSERT_NOT_REACHED;
 	xstep = 0;
 	ystep = 0;
     }
 
     _cairo_output_stream_printf (surface->stream,
+				 "/CairoPattern {\n");
+
+    old_use_string_datasource = surface->use_string_datasource;
+    surface->use_string_datasource = TRUE;
+    status = _cairo_ps_surface_emit_surface (surface, pattern, op);
+    if (status)
+	return status;
+
+    surface->use_string_datasource = old_use_string_datasource;
+    _cairo_output_stream_printf (surface->stream,
+				 "} bind def\n");
+
+    _cairo_output_stream_printf (surface->stream,
 				 "<< /PatternType 1\n"
 				 "   /PaintType 1\n"
 				 "   /TilingType 1\n");
     _cairo_output_stream_printf (surface->stream,
 				 "   /XStep %f /YStep %f\n",
 				 xstep, ystep);
 
     if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
@@ -2517,28 +2360,44 @@ static cairo_status_t
 				     "   } bind\n",
 				     pattern_width*2, pattern_height*2,
 				     pattern_width*2,
 				     pattern_height*2,
 				     pattern_width*2);
     } else {
 	_cairo_output_stream_printf (surface->stream,
 				     "   /BBox [0 0 %d %d]\n"
-				     "   /PaintProc { CairoPattern } bind\n",
+				     "   /PaintProc { CairoPattern }\n",
 				     pattern_width, pattern_height);
     }
 
     _cairo_output_stream_printf (surface->stream,
 				 ">>\n");
 
+    status = _cairo_surface_get_extents (&surface->base, &surface_extents);
+    if (status)
+	return status;
+
+    cairo_p2d = pattern->base.matrix;
+    status = cairo_matrix_invert (&cairo_p2d);
+    /* cairo_pattern_set_matrix ensures the matrix is invertible */
+    assert (status == CAIRO_STATUS_SUCCESS);
+
+    cairo_matrix_init_identity (&ps_p2d);
+    cairo_matrix_translate (&ps_p2d, 0.0, surface_extents.height);
+    cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+    cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
+    cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
+    cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+
     _cairo_output_stream_printf (surface->stream,
 				 "[ %f %f %f %f %f %f ]\n",
-				 inverse.xx, inverse.yx,
-				 inverse.xy, inverse.yy,
-				 inverse.x0, inverse.y0);
+				 ps_p2d.xx, ps_p2d.yx,
+				 ps_p2d.xy, ps_p2d.yy,
+				 ps_p2d.x0, ps_p2d.y0);
     _cairo_output_stream_printf (surface->stream,
 				 "makepattern setpattern\n");
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 typedef struct _cairo_ps_color_stop {
     double offset;
@@ -2740,16 +2599,17 @@ static cairo_status_t
 
     extend = cairo_pattern_get_extend (&pattern->base.base);
 
     pat_to_ps = pattern->base.base.matrix;
     status = cairo_matrix_invert (&pat_to_ps);
     /* cairo_pattern_set_matrix ensures the matrix is invertible */
     assert (status == CAIRO_STATUS_SUCCESS);
 
+    cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
     first_stop = _cairo_fixed_to_double (gradient->stops[0].x);
     last_stop = _cairo_fixed_to_double (gradient->stops[gradient->n_stops - 1].x);
 
     if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
 	pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
 	double dx, dy;
 	int x_rep = 0, y_rep = 0;
 
@@ -2852,65 +2712,68 @@ static cairo_status_t
     return status;
 }
 
 static cairo_status_t
 _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t     *surface,
 				       cairo_radial_pattern_t *pattern)
 {
     double x1, y1, x2, y2, r1, r2;
+    cairo_matrix_t pat_to_ps;
     cairo_extend_t extend;
     cairo_status_t status;
-    cairo_matrix_t inverse = pattern->base.base.matrix;
 
     if (pattern->base.n_stops == 0)
         return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
     extend = cairo_pattern_get_extend (&pattern->base.base);
 
-    status = cairo_matrix_invert (&inverse);
-    if (status)
-	return status;
-
+    pat_to_ps = pattern->base.base.matrix;
+    status = cairo_matrix_invert (&pat_to_ps);
+    /* cairo_pattern_set_matrix ensures the matrix is invertible */
+    assert (status == CAIRO_STATUS_SUCCESS);
+
+    cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
     x1 = _cairo_fixed_to_double (pattern->c1.x);
     y1 = _cairo_fixed_to_double (pattern->c1.y);
     r1 = _cairo_fixed_to_double (pattern->r1);
     x2 = _cairo_fixed_to_double (pattern->c2.x);
     y2 = _cairo_fixed_to_double (pattern->c2.y);
     r2 = _cairo_fixed_to_double (pattern->r2);
 
-    _cairo_output_stream_printf (surface->stream,
+   status = _cairo_ps_surface_emit_pattern_stops (surface, &pattern->base);
+   if (status)
+      return status;
+
+   _cairo_output_stream_printf (surface->stream,
 				 "<< /PatternType 2\n"
 				 "   /Shading\n"
 				 "   << /ShadingType 3\n"
 				 "      /ColorSpace /DeviceRGB\n"
 				 "      /Coords [ %f %f %f %f %f %f ]\n"
-				 "      /Function\n",
+				 "      /Function CairoFunction\n",
 				 x1, y1, r1, x2, y2, r2);
 
-    status = _cairo_ps_surface_emit_pattern_stops (surface, &pattern->base);
-    if (status)
-	return status;
-
     if (extend == CAIRO_EXTEND_PAD) {
 	_cairo_output_stream_printf (surface->stream,
                                      "      /Extend [ true true ]\r\n");
     } else {
 	_cairo_output_stream_printf (surface->stream,
                                      "      /Extend [ false false ]\r\n");
     }
 
     _cairo_output_stream_printf (surface->stream,
 				 "   >>\n"
 				 ">>\n");
+
     _cairo_output_stream_printf (surface->stream,
 				 "[ %f %f %f %f %f %f ]\n",
-				 inverse.xx, inverse.yx,
-				 inverse.xy, inverse.yy,
-				 inverse.x0, inverse.y0);
+				 pat_to_ps.xx, pat_to_ps.yx,
+                                 pat_to_ps.xy, pat_to_ps.yy,
+                                 pat_to_ps.x0, pat_to_ps.y0);
     _cairo_output_stream_printf (surface->stream,
 				 "makepattern setpattern\n");
 
     return status;
 }
 
 static cairo_status_t
 _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
@@ -2957,52 +2820,33 @@ static cairo_int_status_t
 _cairo_ps_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_ps_surface_t *surface = abstract_surface;
     cairo_output_stream_t *stream = surface->stream;
-    cairo_status_t status;
-    const char *ps_operator;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return CAIRO_STATUS_SUCCESS;
 
 #if DEBUG_PS
     _cairo_output_stream_printf (stream,
 				 "%% _cairo_ps_surface_intersect_clip_path\n");
 #endif
 
     if (path == NULL) {
-	_cairo_output_stream_printf (stream, "grestore gsave\n");
+	_cairo_output_stream_printf (stream, "Q q\n");
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    /* We're "filling" not stroking, so we pass CAIRO_LINE_CAP_ROUND. */
-    status = _cairo_ps_surface_emit_path (surface, stream, path,
-					  CAIRO_LINE_CAP_ROUND);
-
-    switch (fill_rule) {
-    case CAIRO_FILL_RULE_WINDING:
-	ps_operator = "clip";
-	break;
-    case CAIRO_FILL_RULE_EVEN_ODD:
-	ps_operator = "eoclip";
-	break;
-    default:
-	ASSERT_NOT_REACHED;
-    }
-
-    _cairo_output_stream_printf (stream,
-				 "%s newpath\n",
-				 ps_operator);
-
-    return status;
+    return _cairo_pdf_operators_clip (&surface->pdf_operators,
+				      path,
+				      fill_rule);
 }
 
 static cairo_int_status_t
 _cairo_ps_surface_get_extents (void		       *abstract_surface,
 			       cairo_rectangle_int_t   *rectangle)
 {
     cairo_ps_surface_t *surface = abstract_surface;
 
@@ -3032,457 +2876,199 @@ static void
 
 static cairo_int_status_t
 _cairo_ps_surface_paint (void			*abstract_surface,
 			 cairo_operator_t	 op,
 			 cairo_pattern_t	*source)
 {
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_output_stream_t *stream = surface->stream;
-    cairo_rectangle_int_t extents, pattern_extents;
+    cairo_rectangle_int_t extents, surface_extents;
     cairo_status_t status;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_ps_surface_analyze_operation (surface, op, source);
 
     assert (_cairo_ps_surface_operation_supported (surface, op, source));
 
 #if DEBUG_PS
     _cairo_output_stream_printf (stream,
 				 "%% _cairo_ps_surface_paint\n");
 #endif
 
-    status = _cairo_surface_get_extents (&surface->base, &extents);
+    status = _cairo_surface_get_extents (&surface->base, &surface_extents);
     if (status)
 	return status;
 
-    status = _cairo_pattern_get_extents (source, &pattern_extents);
+    status = _cairo_pattern_get_extents (source, &extents);
     if (status)
 	return status;
 
-    _cairo_rectangle_intersect (&extents, &pattern_extents);
-
-    status = _cairo_ps_surface_emit_pattern (surface, source, op);
-    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
-        return CAIRO_STATUS_SUCCESS;
-
-    if (status)
-	return status;
-
-    _cairo_output_stream_printf (stream, "%d %d M\n",
-				 extents.x, extents.y);
-    _cairo_output_stream_printf (stream, "%d %d L\n",
-				 extents.x + extents.width,
-				 extents.y);
-    _cairo_output_stream_printf (stream, "%d %d L\n",
-				 extents.x + extents.width,
-				 extents.y + extents.height);
-    _cairo_output_stream_printf (stream, "%d %d L\n",
-				 extents.x,
-				 extents.y + extents.height);
-    _cairo_output_stream_printf (stream, "P F\n");
+    _cairo_rectangle_intersect (&extents, &surface_extents);
+
+    if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
+	source->extend == CAIRO_EXTEND_NONE)
+    {
+	_cairo_output_stream_printf (stream, "q %d %d %d %d rectclip\n",
+				     extents.x,
+				     surface_extents.height - extents.y - extents.height,
+				     extents.width,
+				     extents.height);
+
+	status = _cairo_ps_surface_paint_surface (surface,
+						 (cairo_surface_pattern_t *) source,
+						 op);
+	if (status)
+	    return status;
+
+	_cairo_output_stream_printf (stream, "Q\n");
+    } else {
+	status = _cairo_ps_surface_emit_pattern (surface, source, op);
+	if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+	    return CAIRO_STATUS_SUCCESS;
+
+	if (status)
+	    return status;
+
+	_cairo_output_stream_printf (stream, "%d %d %d %d rectfill\n",
+				     extents.x,
+				     surface_extents.height - extents.y - extents.height,
+				     extents.width,
+				     extents.height);
+    }
 
     return CAIRO_STATUS_SUCCESS;
 }
 
-static int
-_cairo_ps_line_cap (cairo_line_cap_t cap)
-{
-    switch (cap) {
-    case CAIRO_LINE_CAP_BUTT:
-	return 0;
-    case CAIRO_LINE_CAP_ROUND:
-	return 1;
-    case CAIRO_LINE_CAP_SQUARE:
-	return 2;
-    default:
-	ASSERT_NOT_REACHED;
-	return 0;
-    }
-}
-
-static int
-_cairo_ps_line_join (cairo_line_join_t join)
-{
-    switch (join) {
-    case CAIRO_LINE_JOIN_MITER:
-	return 0;
-    case CAIRO_LINE_JOIN_ROUND:
-	return 1;
-    case CAIRO_LINE_JOIN_BEVEL:
-	return 2;
-    default:
-	ASSERT_NOT_REACHED;
-	return 0;
-    }
-}
-
 static cairo_int_status_t
 _cairo_ps_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_ps_surface_t *surface = abstract_surface;
-    cairo_output_stream_t *stream = surface->stream;
     cairo_int_status_t status;
-    double *dash = style->dash;
-    int num_dashes = style->num_dashes;
-    double dash_offset = style->dash_offset;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_ps_surface_analyze_operation (surface, op, source);
 
     assert (_cairo_ps_surface_operation_supported (surface, op, source));
 
 #if DEBUG_PS
     _cairo_output_stream_printf (stream,
 				 "%% _cairo_ps_surface_stroke\n");
 #endif
 
-    /* PostScript has "special needs" when it comes to zero-length
-     * dash segments with butt caps. It apparently (at least
-     * according to ghostscript) draws hairlines for this
-     * case. That's not what the cairo semantics want, so we first
-     * touch up the array to eliminate any 0.0 values that will
-     * result in "on" segments.
-     */
-    if (num_dashes && style->line_cap == CAIRO_LINE_CAP_BUTT) {
-	int i;
-
-	/* If there's an odd number of dash values they will each get
-	 * interpreted as both on and off. So we first explicitly
-	 * expand the array to remove the duplicate usage so that we
-	 * can modify some of the values.
-	 */
-	if (num_dashes % 2) {
-	    dash = _cairo_malloc_abc (num_dashes, 2, sizeof (double));
-	    if (dash == NULL)
-		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-	    memcpy (dash, style->dash, num_dashes * sizeof (double));
-	    memcpy (dash + num_dashes, style->dash, num_dashes * sizeof (double));
-
-	    num_dashes *= 2;
-	}
-
-	for (i = 0; i < num_dashes; i += 2) {
-	    if (dash[i] == 0.0) {
-		/* If we're at the front of the list, we first rotate
-		 * two elements from the end of the list to the front
-		 * of the list before folding away the 0.0. Or, if
-		 * there are only two dash elements, then there is
-		 * nothing at all to draw.
-		 */
-		if (i == 0) {
-		    double last_two[2];
-
-		    if (num_dashes == 2) {
-			if (dash != style->dash)
-			    free (dash);
-			return CAIRO_STATUS_SUCCESS;
-		    }
-		    /* The cases of num_dashes == 0, 1, or 3 elements
-		     * cannot exist, so the rotation of 2 elements
-		     * will always be safe */
-		    memcpy (last_two, dash + num_dashes - 2, sizeof (last_two));
-		    memmove (dash + 2, dash, (num_dashes - 2) * sizeof (double));
-		    memcpy (dash, last_two, sizeof (last_two));
-		    dash_offset += dash[0] + dash[1];
-		    i = 2;
-		}
-		dash[i-1] += dash[i+1];
-		num_dashes -= 2;
-		memmove (dash + i, dash + i + 2, (num_dashes - i) * sizeof (double));
-		/* If we might have just rotated, it's possible that
-		 * we rotated a 0.0 value to the front of the list.
-		 * Set i to -2 so it will get incremented to 0. */
-		if (i == 2)
-		    i = -2;
-	    }
-	}
-    }
-
     status = _cairo_ps_surface_emit_pattern (surface, source, op);
     if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
         return CAIRO_STATUS_SUCCESS;
 
-    if (status) {
-	if (dash != style->dash)
-	    free (dash);
-	return status;
-    }
-
-    _cairo_output_stream_printf (stream,
-				 "gsave\n");
-    status = _cairo_ps_surface_emit_path (surface, stream, path,
-					  style->line_cap);
-    if (status) {
-	if (dash != style->dash)
-	    free (dash);
-	return status;
-    }
-
-    /*
-     * Switch to user space to set line parameters
-     */
-    _cairo_output_stream_printf (stream,
-				 "[%f %f %f %f 0 0] concat\n",
-				 ctm->xx, ctm->yx, ctm->xy, ctm->yy);
-    /* line width */
-    _cairo_output_stream_printf (stream, "%f setlinewidth\n",
-				 style->line_width);
-    /* line cap */
-    _cairo_output_stream_printf (stream, "%d setlinecap\n",
-				 _cairo_ps_line_cap (style->line_cap));
-    /* line join */
-    _cairo_output_stream_printf (stream, "%d setlinejoin\n",
-				 _cairo_ps_line_join (style->line_join));
-    /* dashes */
-    if (num_dashes) {
-	int d;
-
-	_cairo_output_stream_printf (stream, "[");
-	for (d = 0; d < num_dashes; d++)
-	    _cairo_output_stream_printf (stream, " %f", dash[d]);
-	_cairo_output_stream_printf (stream, "] %f setdash\n",
-				     dash_offset);
-    }
-    if (dash != style->dash)
-	free (dash);
-
-    /* miter limit */
-    _cairo_output_stream_printf (stream, "%f setmiterlimit\n",
-				 style->miter_limit < 1.0 ? 1.0 : style->miter_limit);
-    _cairo_output_stream_printf (stream,
-				 "stroke\n");
-    _cairo_output_stream_printf (stream,
-				 "grestore\n");
-
-    return CAIRO_STATUS_SUCCESS;
+    return _cairo_pdf_operators_stroke (&surface->pdf_operators,
+					path,
+					style,
+					ctm,
+					ctm_inverse);
 }
 
 static cairo_int_status_t
 _cairo_ps_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_ps_surface_t *surface = abstract_surface;
-    cairo_output_stream_t *stream = surface->stream;
     cairo_int_status_t status;
-    const char *ps_operator;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_ps_surface_analyze_operation (surface, op, source);
 
     assert (_cairo_ps_surface_operation_supported (surface, op, source));
 
 #if DEBUG_PS
     _cairo_output_stream_printf (stream,
 				 "%% _cairo_ps_surface_fill\n");
 #endif
 
-    status = _cairo_ps_surface_emit_pattern (surface, source, op);
-    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
-        return CAIRO_STATUS_SUCCESS;
-
-    if (status)
-	return status;
-
-    /* We're filling not stroking, so we pass CAIRO_LINE_CAP_ROUND. */
-    status = _cairo_ps_surface_emit_path (surface, stream, path,
-					  CAIRO_LINE_CAP_ROUND);
-    if (status)
-	return status;
-
-    switch (fill_rule) {
-    case CAIRO_FILL_RULE_WINDING:
-	ps_operator = "F";
-	break;
-    case CAIRO_FILL_RULE_EVEN_ODD:
-	ps_operator = "eofill";
-	break;
-    default:
-	ASSERT_NOT_REACHED;
+    if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
+	source->extend == CAIRO_EXTEND_NONE)
+    {
+	_cairo_output_stream_printf (surface->stream, "q\n");
+
+	status =  _cairo_pdf_operators_clip (&surface->pdf_operators,
+					     path,
+					     fill_rule);
+	if (status)
+	    return status;
+
+	status = _cairo_ps_surface_paint_surface (surface,
+						 (cairo_surface_pattern_t *) source,
+						 op);
+	if (status)
+	    return status;
+
+	_cairo_output_stream_printf (surface->stream, "Q\n");
+    } else {
+	status = _cairo_ps_surface_emit_pattern (surface, source, op);
+	if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+	    return CAIRO_STATUS_SUCCESS;
+
+	if (status)
+	    return status;
+
+	status = _cairo_pdf_operators_fill (&surface->pdf_operators,
+					    path,
+					    fill_rule);
     }
 
-    _cairo_output_stream_printf (stream,
-				 "%s\n", ps_operator);
-
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
-/* This size keeps the length of the hex encoded string of glyphs
- * within 80 columns. */
-#define MAX_GLYPHS_PER_SHOW  36
-
-typedef struct _cairo_ps_glyph_id {
-    unsigned int subset_id;
-    unsigned int glyph_id;
-} cairo_ps_glyph_id_t;
-
 static cairo_int_status_t
 _cairo_ps_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_ps_surface_t *surface = abstract_surface;
-    cairo_output_stream_t *stream = surface->stream;
-    unsigned int current_subset_id = -1;
-    cairo_scaled_font_subsets_glyph_t subset_glyph;
-    cairo_ps_glyph_id_t *glyph_ids;
     cairo_status_t status;
-    unsigned int num_glyphs_unsigned, i, j, last, end;
-    cairo_bool_t vertical, horizontal;
-    cairo_output_stream_t *word_wrap;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_ps_surface_analyze_operation (surface, op, source);
 
     assert (_cairo_ps_surface_operation_supported (surface, op, source));
 
 #if DEBUG_PS
     _cairo_output_stream_printf (stream,
 				 "%% _cairo_ps_surface_show_glyphs\n");
 #endif
 
     if (num_glyphs <= 0)
         return CAIRO_STATUS_SUCCESS;
 
-    num_glyphs_unsigned = num_glyphs;
-
     status = _cairo_ps_surface_emit_pattern (surface, source, op);
     if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
         return CAIRO_STATUS_SUCCESS;
 
     if (status)
 	return status;
 
-    glyph_ids = _cairo_malloc_ab (num_glyphs_unsigned, sizeof (cairo_ps_glyph_id_t));
-    if (glyph_ids == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    for (i = 0; i < num_glyphs_unsigned; i++) {
-        status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
-                                                       scaled_font, glyphs[i].index,
-                                                       &subset_glyph);
-        if (status)
-            goto fail;
-
-        glyph_ids[i].subset_id = subset_glyph.subset_id;
-        glyph_ids[i].glyph_id = subset_glyph.subset_glyph_index;
-    }
-
-    i = 0;
-    while (i < num_glyphs_unsigned) {
-        if (glyph_ids[i].subset_id != current_subset_id) {
-            _cairo_output_stream_printf (surface->stream,
-                                         "/CairoFont-%d-%d "
-                                         "[ %f %f %f %f 0 0 ] selectfont\n",
-                                         subset_glyph.font_id,
-                                         glyph_ids[i].subset_id,
-                                         scaled_font->scale.xx,
-                                         scaled_font->scale.yx,
-                                         -scaled_font->scale.xy,
-                                         -scaled_font->scale.yy);
-            current_subset_id = glyph_ids[i].subset_id;
-        }
-
-        if (i == 0)
-            _cairo_output_stream_printf (stream,
-                                         "%f %f M\n",
-                                         glyphs[i].x,
-                                         glyphs[i].y);
-
-        horizontal = TRUE;
-        vertical = TRUE;
-        end = num_glyphs_unsigned;
-        if (end - i > MAX_GLYPHS_PER_SHOW)
-            end = i + MAX_GLYPHS_PER_SHOW;
-        last = end - 1;
-        for (j = i; j < end - 1; j++) {
-            if ((glyphs[j].y != glyphs[j + 1].y))
-                horizontal = FALSE;
-            if ((glyphs[j].x != glyphs[j + 1].x))
-                vertical = FALSE;
-            if (glyph_ids[j].subset_id != glyph_ids[j + 1].subset_id) {
-                last = j;
-                break;
-            }
-        }
-
-        if (i == last) {
-            _cairo_output_stream_printf (surface->stream, "<%02x> S\n", glyph_ids[i].glyph_id);
-        } else {
-            word_wrap = _word_wrap_stream_create (surface->stream, 79);
-	    if (_cairo_output_stream_get_status (word_wrap)) {
-		status = _cairo_output_stream_destroy (word_wrap);
-		goto fail;
-	    }
-
-            _cairo_output_stream_printf (word_wrap, "<");
-            for (j = i; j < last+1; j++)
-                _cairo_output_stream_printf (word_wrap, "%02x", glyph_ids[j].glyph_id);
-            _cairo_output_stream_printf (word_wrap, ">\n[");
-
-            if (horizontal) {
-                for (j = i; j < last+1; j++) {
-                    if (j == num_glyphs_unsigned - 1)
-                        _cairo_output_stream_printf (word_wrap, "0 ");
-                    else
-                        _cairo_output_stream_printf (word_wrap,
-                                                     "%f ", glyphs[j + 1].x - glyphs[j].x);
-                }
-                _cairo_output_stream_printf (word_wrap, "] xS\n");
-            } else if (vertical) {
-                for (j = i; j < last+1; j++) {
-                    if (j == num_glyphs_unsigned - 1)
-                        _cairo_output_stream_printf (word_wrap, "0 ");
-                    else
-                        _cairo_output_stream_printf (word_wrap,
-                                                     "%f ", glyphs[j + 1].y - glyphs[j].y);
-                }
-                _cairo_output_stream_printf (word_wrap, "] yS\n");
-            } else {
-                for (j = i; j < last+1; j++) {
-                    if (j == num_glyphs_unsigned - 1)
-                        _cairo_output_stream_printf (word_wrap, "0 0 ");
-                    else
-                        _cairo_output_stream_printf (word_wrap,
-                                                     "%f %f ",
-                                                     glyphs[j + 1].x - glyphs[j].x,
-                                                     glyphs[j + 1].y - glyphs[j].y);
-                }
-                _cairo_output_stream_printf (word_wrap, "] xyS\n");
-            }
-
-            status = _cairo_output_stream_destroy (word_wrap);
-            if (status)
-                goto fail;
-        }
-        i = last + 1;
-    }
-
-    status = _cairo_output_stream_get_status (surface->stream);
-fail:
-    free (glyph_ids);
-
-    return status;
+    return _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
+					     glyphs,
+					     num_glyphs,
+					     scaled_font);
 }
 
 static void
 _cairo_ps_surface_set_paginated_mode (void			*abstract_surface,
 				      cairo_paginated_mode_t	 paginated_mode)
 {
     cairo_ps_surface_t *surface = abstract_surface;
 
@@ -3524,23 +3110,22 @@ static cairo_int_status_t
 	_cairo_output_stream_printf (surface->stream,
 				     "%s\n", comments[i]);
 	free (comments[i]);
 	comments[i] = NULL;
     }
     _cairo_array_truncate (&surface->dsc_page_setup_comments, 0);
 
     _cairo_output_stream_printf (surface->stream,
-				 "%%%%PageBoundingBox: %d %d %d %d\n"
-				 "gsave %f %f translate 1.0 -1.0 scale gsave\n",
-				 x1, y1, x2, y2,
-				 0.0, surface->height);
+				 "%%%%PageBoundingBox: %d %d %d %d\n",
+				 x1, y1, x2, y2);
 
     _cairo_output_stream_printf (surface->stream,
-                                 "%%%%EndPageSetup\n");
+                                 "%%%%EndPageSetup\n"
+				 "gsave\n");
 
     if (surface->num_pages == 1) {
 	surface->bbox_x1 = x1;
 	surface->bbox_y1 = y1;
 	surface->bbox_x2 = x2;
 	surface->bbox_y2 = y2;
     } else {
 	if (x1 < surface->bbox_x1)
--- a/gfx/cairo/cairo/src/cairo-scaled-font.c
+++ b/gfx/cairo/cairo/src/cairo-scaled-font.c
@@ -173,17 +173,17 @@ static void
 _cairo_scaled_glyph_destroy (void *abstract_glyph)
 {
     cairo_scaled_glyph_t *scaled_glyph = abstract_glyph;
     _cairo_scaled_glyph_fini (scaled_glyph);
     free (scaled_glyph);
 }
 
 #define ZOMBIE 0
-const cairo_scaled_font_t _cairo_scaled_font_nil = {
+static const cairo_scaled_font_t _cairo_scaled_font_nil = {
     { ZOMBIE },			/* hash_entry */
     CAIRO_STATUS_NO_MEMORY,	/* status */
     CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
     { 0, 0, 0, NULL },		/* user_data */
     NULL,			/* font_face */
     { 1., 0., 0., 1., 0, 0},	/* font_matrix */
     { 1., 0., 0., 1., 0, 0},	/* ctm */
     { CAIRO_ANTIALIAS_DEFAULT,	/* options */
@@ -461,21 +461,19 @@ cairo_status_t
 			 cairo_font_face_t		   *font_face,
 			 const cairo_matrix_t              *font_matrix,
 			 const cairo_matrix_t              *ctm,
 			 const cairo_font_options_t	   *options,
 			 const cairo_scaled_font_backend_t *backend)
 {
     cairo_status_t status;
 
-    if (options != NULL) {
-	status = cairo_font_options_status ((cairo_font_options_t *) options);
-	if (status)
-	    return status;
-    }
+    status = cairo_font_options_status ((cairo_font_options_t *) options);
+    if (status)
+	return status;
 
     _cairo_scaled_font_init_key (scaled_font, font_face,
 				 font_matrix, ctm, options);
 
     cairo_matrix_multiply (&scaled_font->scale,
 			   &scaled_font->font_matrix,
 			   &scaled_font->ctm);
 
@@ -618,30 +616,28 @@ cairo_scaled_font_create (cairo_font_fac
 			  const cairo_matrix_t       *ctm,
 			  const cairo_font_options_t *options)
 {
     cairo_status_t status;
     cairo_scaled_font_map_t *font_map;
     cairo_scaled_font_t key, *scaled_font = NULL;
 
     if (font_face->status)
-	return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
+	return _cairo_scaled_font_create_in_error (font_face->status);
 
-    if (options != NULL &&
-	cairo_font_options_status ((cairo_font_options_t *) options))
-    {
-	return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
-    }
+    status = cairo_font_options_status ((cairo_font_options_t *) options);
+    if (status)
+	return _cairo_scaled_font_create_in_error (status);
 
     /* Note that degenerate ctm or font_matrix *are* allowed.
      * We want to support a font size of 0. */
 
     font_map = _cairo_scaled_font_map_lock ();
     if (font_map == NULL)
-	return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
+	return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
     _cairo_scaled_font_init_key (&key, font_face,
 				 font_matrix, ctm, options);
 
     /* Return existing scaled_font if it exists in the hash table. */
     if (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry,
 				  (cairo_hash_entry_t**) &scaled_font))
     {
@@ -682,36 +678,86 @@ cairo_scaled_font_create (cairo_font_fac
     }
 
     /* Otherwise create it and insert it into the hash table. */
     status = font_face->backend->scaled_font_create (font_face, font_matrix,
 						     ctm, options, &scaled_font);
     if (status) {
 	_cairo_scaled_font_map_unlock ();
 	status = _cairo_font_face_set_error (font_face, status);
-	return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
+	return _cairo_scaled_font_create_in_error (status);
     }
 
     status = _cairo_hash_table_insert (font_map->hash_table,
 				       &scaled_font->hash_entry);
     _cairo_scaled_font_map_unlock ();
 
     if (status) {
 	/* We can't call _cairo_scaled_font_destroy here since it expects
 	 * that the font has already been successfully inserted into the
 	 * hash table. */
 	_cairo_scaled_font_fini (scaled_font);
 	free (scaled_font);
-	return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
+	return _cairo_scaled_font_create_in_error (status);
     }
 
     return scaled_font;
 }
 slim_hidden_def (cairo_scaled_font_create);
 
+static cairo_scaled_font_t *_cairo_scaled_font_nil_objects[CAIRO_STATUS_LAST_STATUS + 1];
+
+/* XXX This should disappear in favour of a common pool of error objects. */
+cairo_scaled_font_t *
+_cairo_scaled_font_create_in_error (cairo_status_t status)
+{
+    cairo_scaled_font_t *scaled_font;
+
+    assert (status != CAIRO_STATUS_SUCCESS);
+
+    if (status == CAIRO_STATUS_NO_MEMORY)
+	return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
+
+    CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
+    scaled_font = _cairo_scaled_font_nil_objects[status];
+    if (scaled_font == NULL) {
+	scaled_font = malloc (sizeof (cairo_scaled_font_t));
+	if (scaled_font == NULL) {
+	    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
+	    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	    return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
+	}
+
+	*scaled_font = _cairo_scaled_font_nil;
+	scaled_font->status = status;
+	_cairo_scaled_font_nil_objects[status] = scaled_font;
+    }
+    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
+
+    return scaled_font;
+}
+
+void
+_cairo_scaled_font_reset_static_data (void)
+{
+    int status;
+
+    CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
+    for (status = CAIRO_STATUS_SUCCESS;
+	 status <= CAIRO_STATUS_LAST_STATUS;
+	 status++)
+    {
+	if (_cairo_scaled_font_nil_objects[status] != NULL) {
+	    free (_cairo_scaled_font_nil_objects[status]);
+	    _cairo_scaled_font_nil_objects[status] = NULL;
+	}
+    }
+    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
+}
+
 /**
  * cairo_scaled_font_reference:
  * @scaled_font: a #cairo_scaled_font_t, (may be %NULL in which case
  * this function does nothing)
  *
  * Increases the reference count on @scaled_font by one. This prevents
  * @scaled_font from being destroyed until a matching call to
  * cairo_scaled_font_destroy() is made.
--- a/gfx/cairo/cairo/src/cairo-surface.c
+++ b/gfx/cairo/cairo/src/cairo-surface.c
@@ -1657,63 +1657,69 @@ cairo_status_t
  * be retained for the next page.  Use cairo_surface_show_page() if you
  * want to get an empty page after the emission.
  *
  * Since: 1.6
  */
 void
 cairo_surface_copy_page (cairo_surface_t *surface)
 {
+    cairo_status_t status_ignored;
+
     assert (! surface->is_snapshot);
 
     if (surface->status)
 	return;
 
     if (surface->finished) {
-	_cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
+	status_ignored = _cairo_surface_set_error (surface,
+		                                 CAIRO_STATUS_SURFACE_FINISHED);
 	return;
     }
 
     /* It's fine if some backends don't implement copy_page */
     if (surface->backend->copy_page == NULL)
 	return;
 
-    _cairo_surface_set_error (surface,
-			      surface->backend->copy_page (surface));
+    status_ignored = _cairo_surface_set_error (surface,
+			                 surface->backend->copy_page (surface));
 }
 slim_hidden_def (cairo_surface_copy_page);
 
 /**
  * cairo_surface_show_page:
  * @surface: a #cairo_Surface_t
  *
  * Emits and clears the current page for backends that support multiple
  * pages.  Use cairo_surface_copy_page() if you don't want to clear the page.
  *
  * Since: 1.6
  **/
 void
 cairo_surface_show_page (cairo_surface_t *surface)
 {
+    cairo_status_t status_ignored;
+
     assert (! surface->is_snapshot);
 
     if (surface->status)
 	return;
 
     if (surface->finished) {
-	_cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
+	status_ignored = _cairo_surface_set_error (surface,
+		                                 CAIRO_STATUS_SURFACE_FINISHED);
 	return;
     }
 
     /* It's fine if some backends don't implement show_page */
     if (surface->backend->show_page == NULL)
 	return;
 
-    _cairo_surface_set_error (surface,
-			      surface->backend->show_page (surface));
+    status_ignored = _cairo_surface_set_error (surface,
+			                 surface->backend->show_page (surface));
 }
 slim_hidden_def (cairo_surface_show_page);
 
 /**
  * _cairo_surface_get_current_clip_serial:
  * @surface: the #cairo_surface_t to return the serial number for
  *
  * Returns: the serial number associated with the current
--- a/gfx/cairo/cairo/src/cairo-win32-font.c
+++ b/gfx/cairo/cairo/src/cairo-win32-font.c
@@ -272,17 +272,17 @@ static cairo_status_t
     /* We don't have any control over the hinting style or subpixel
      * order in the Win32 font API, so we ignore those parts of
      * cairo_font_options_t. We use the 'antialias' field to set
      * the 'quality'.
      *
      * XXX: The other option we could pay attention to, but don't
      *      here is the hint_metrics options.
      */
-    if (options == NULL || options->antialias == CAIRO_ANTIALIAS_DEFAULT)
+    if (options->antialias == CAIRO_ANTIALIAS_DEFAULT)
 	f->quality = _get_system_quality ();
     else {
 	switch (options->antialias) {
 	case CAIRO_ANTIALIAS_NONE:
 	    f->quality = NONANTIALIASED_QUALITY;
 	    break;
 	case CAIRO_ANTIALIAS_GRAY:
 	    f->quality = ANTIALIASED_QUALITY;
@@ -299,17 +299,17 @@ static cairo_status_t
     }
 
     f->em_square = 0;
     f->scaled_hfont = NULL;
     f->unscaled_hfont = NULL;
 
     if (f->quality == logfont->lfQuality ||
         (logfont->lfQuality == DEFAULT_QUALITY &&
-         (options == NULL || options->antialias == CAIRO_ANTIALIAS_DEFAULT))) {
+         options->antialias == CAIRO_ANTIALIAS_DEFAULT)) {
         /* If face_hfont is non-NULL, then we can use it to avoid creating our
          * own --- because the constraints on face_hfont mentioned above
          * guarantee it was created in exactly the same way that
          * _win32_scaled_font_get_scaled_hfont would create it.
          */
         f->scaled_hfont = face_hfont;
     }
     /* don't delete the hfont if we're using the one passed in to us */
--- a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c
+++ b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c
@@ -196,43 +196,46 @@ pattern_supported (cairo_win32_surface_t
 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_OVER ||
+	  op == CAIRO_OPERATOR_CLEAR))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
+
+	if ( _cairo_surface_is_meta (surface_pattern->surface))
+	    return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
+    }
+
     if (op == CAIRO_OPERATOR_SOURCE ||
 	op == CAIRO_OPERATOR_CLEAR)
 	return CAIRO_STATUS_SUCCESS;
 
-    /* If the operation is anything other than CLEAR, SOURCE, or
-     * OVER, we have to go to fallback.
-     */
-    if (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 (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
 	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
 
-	if ( _cairo_surface_is_meta (surface_pattern->surface))
-	    return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
-	else
-	    return analyze_surface_pattern_transparency (surface_pattern);
+	return analyze_surface_pattern_transparency (surface_pattern);
     }
 
     if (_cairo_pattern_is_opaque (pattern))
 	return CAIRO_STATUS_SUCCESS;
     else
 	return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
 }
 
@@ -456,18 +459,19 @@ static cairo_status_t
 	    cairo_matrix_transform_point (&surface->ctm, &x, &y);
 	    LineTo (surface->dc, (int) x, (int) y);
 
 	    CloseFigure (surface->dc);
 	    EndPath (surface->dc);
 	    SelectClipPath (surface->dc, RGN_AND);
 
 	    SaveDC (surface->dc); /* Allow clip path to be reset during replay */
-	    status = _cairo_meta_surface_replay (meta_surface, &surface->base);
-
+	    status = _cairo_meta_surface_replay_region (meta_surface, &surface->base,
+							CAIRO_META_REGION_NATIVE);
+	    assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
 	    /* Restore both the clip save and our earlier path SaveDC */
 	    RestoreDC (surface->dc, -2);
 
 	    if (status)
 		return status;
 	}
     }
 
--- a/gfx/cairo/cairo/src/cairo-xlib-surface.c
+++ b/gfx/cairo/cairo/src/cairo-xlib-surface.c
@@ -1941,16 +1941,18 @@ static cairo_surface_t *
 				     XRenderPictFormat	       *xrender_format,
 				     int			width,
 				     int			height,
 				     int			depth)
 {
     cairo_xlib_surface_t *surface;
     cairo_xlib_screen_info_t *screen_info;
 
+    CAIRO_MUTEX_INITIALIZE ();
+
     screen_info = _cairo_xlib_screen_info_get (dpy, screen);
     if (screen_info == NULL)
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
     surface = malloc (sizeof (cairo_xlib_surface_t));
     if (surface == NULL) {
 	_cairo_xlib_screen_info_destroy (screen_info);
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
@@ -2088,18 +2090,16 @@ cairo_xlib_surface_create (Display     *
 			   int		width,
 			   int		height)
 {
     Screen *screen = _cairo_xlib_screen_from_visual (dpy, visual);
 
     if (screen == NULL)
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
 
-    CAIRO_MUTEX_INITIALIZE ();
-
     return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
 						visual, NULL, width, height, 0);
 }
 
 /**
  * cairo_xlib_surface_create_for_bitmap:
  * @dpy: an X Display
  * @bitmap: an X Drawable, (a depth-1 Pixmap)
@@ -2114,18 +2114,16 @@ cairo_xlib_surface_create (Display     *
  **/
 cairo_surface_t *
 cairo_xlib_surface_create_for_bitmap (Display  *dpy,
 				      Pixmap	bitmap,
 				      Screen   *screen,
 				      int	width,
 				      int	height)
 {
-    CAIRO_MUTEX_INITIALIZE ();
-
     return _cairo_xlib_surface_create_internal (dpy, bitmap, screen,
 						NULL, NULL, width, height, 1);
 }
 
 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
 /**
  * cairo_xlib_surface_create_with_xrender_format:
  * @dpy: an X Display
@@ -2149,18 +2147,16 @@ cairo_xlib_surface_create_for_bitmap (Di
 cairo_surface_t *
 cairo_xlib_surface_create_with_xrender_format (Display		    *dpy,
 					       Drawable		    drawable,
 					       Screen		    *screen,
 					       XRenderPictFormat    *format,
 					       int		    width,
 					       int		    height)
 {
-    CAIRO_MUTEX_INITIALIZE ();
-
     return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
 						NULL, format, width, height, 0);
 }
 slim_hidden_def (cairo_xlib_surface_create_with_xrender_format);
 
 /**
  * cairo_xlib_surface_get_xrender_format:
  * @surface: an xlib surface
--- a/gfx/cairo/cairo/src/cairo.c
+++ b/gfx/cairo/cairo/src/cairo.c
@@ -58,22 +58,16 @@ static const cairo_t _cairo_nil = {
     FALSE,			/* has_current_point */
     FALSE,			/* has_curve_to */
     NULL, {{NULL}}		/* buf_tail, buf_head */
   }}
 };
 
 #include <assert.h>
 
-/* This has to be updated whenever #cairo_status_t is extended.  That's
- * a bit of a pain, but it should be easy to always catch as long as
- * one adds a new test case to test a trigger of the new status value.
- */
-#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_INVALID_STRIDE
-
 /**
  * _cairo_error:
  * @status: a status value indicating an error, (eg. not
  * CAIRO_STATUS_SUCCESS)
  *
  * Checks that status is an error status, but does nothing else.
  *
  * All assignments of an error status to any user-visible object
@@ -2759,22 +2753,20 @@ void
 cairo_set_font_options (cairo_t                    *cr,
 			const cairo_font_options_t *options)
 {
     cairo_status_t status;
 
     if (cr->status)
 	return;
 
-    if (options != NULL) {
-	status = cairo_font_options_status ((cairo_font_options_t *) options);
-	if (status) {
-	    _cairo_set_error (cr, status);
-	    return;
-	}
+    status = cairo_font_options_status ((cairo_font_options_t *) options);
+    if (status) {
+	_cairo_set_error (cr, status);
+	return;
     }
 
     _cairo_gstate_set_font_options (cr->gstate, options);
 }
 
 /**
  * cairo_get_font_options:
  * @cr: a #cairo_t
@@ -2866,22 +2858,22 @@ BAIL:
  **/
 cairo_scaled_font_t *
 cairo_get_scaled_font (cairo_t *cr)
 {
     cairo_status_t status;
     cairo_scaled_font_t *scaled_font;
 
     if (cr->status)
-	return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
+	return _cairo_scaled_font_create_in_error (cr->status);
 
     status = _cairo_gstate_get_scaled_font (cr->gstate, &scaled_font);
     if (status) {
 	_cairo_set_error (cr, status);
-	return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
+	return _cairo_scaled_font_create_in_error (status);
     }
 
     return scaled_font;
 }
 
 /**
  * cairo_text_extents:
  * @cr: a #cairo_t
@@ -3619,295 +3611,8 @@ cairo_append_path (cairo_t		*cr,
  * Returns: the current status of this context, see #cairo_status_t
  **/
 cairo_status_t
 cairo_status (cairo_t *cr)
 {
     return cr->status;
 }
 slim_hidden_def (cairo_status);
-
-/**
- * cairo_status_to_string:
- * @status: a cairo status
- *
- * Provides a human-readable description of a #cairo_status_t.
- *
- * Returns: a string representation of the status
- */
-const char *
-cairo_status_to_string (cairo_status_t status)
-{
-    switch (status) {
-    case CAIRO_STATUS_SUCCESS:
-	return "success";
-    case CAIRO_STATUS_NO_MEMORY:
-	return "out of memory";
-    case CAIRO_STATUS_INVALID_RESTORE:
-	return "cairo_restore without matching cairo_save";
-    case CAIRO_STATUS_INVALID_POP_GROUP:
-	return "cairo_pop_group without matching cairo_push_group";
-    case CAIRO_STATUS_NO_CURRENT_POINT:
-	return "no current point defined";
-    case CAIRO_STATUS_INVALID_MATRIX:
-	return "invalid matrix (not invertible)";
-    case CAIRO_STATUS_INVALID_STATUS:
-	return "invalid value for an input cairo_status_t";
-    case CAIRO_STATUS_NULL_POINTER:
-	return "NULL pointer";
-    case CAIRO_STATUS_INVALID_STRING:
-	return "input string not valid UTF-8";
-    case CAIRO_STATUS_INVALID_PATH_DATA:
-	return "input path data not valid";
-    case CAIRO_STATUS_READ_ERROR:
-	return "error while reading from input stream";
-    case CAIRO_STATUS_WRITE_ERROR:
-	return "error while writing to output stream";
-    case CAIRO_STATUS_SURFACE_FINISHED:
-	return "the target surface has been finished";
-    case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
-	return "the surface type is not appropriate for the operation";
-    case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
-	return "the pattern type is not appropriate for the operation";
-    case CAIRO_STATUS_INVALID_CONTENT:
-	return "invalid value for an input cairo_content_t";
-    case CAIRO_STATUS_INVALID_FORMAT:
-	return "invalid value for an input cairo_format_t";
-    case CAIRO_STATUS_INVALID_VISUAL:
-	return "invalid value for an input Visual*";
-    case CAIRO_STATUS_FILE_NOT_FOUND:
-	return "file not found";
-    case CAIRO_STATUS_INVALID_DASH:
-	return "invalid value for a dash setting";
-    case CAIRO_STATUS_INVALID_DSC_COMMENT:
-	return "invalid value for a DSC comment";
-    case CAIRO_STATUS_INVALID_INDEX:
-	return "invalid index passed to getter";
-    case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
-        return "clip region not representable in desired format";
-    case CAIRO_STATUS_TEMP_FILE_ERROR:
-	return "error creating or writing to a temporary file";
-    case CAIRO_STATUS_INVALID_STRIDE:
-	return "invalid value for stride";
-    }
-
-    return "<unknown error status>";
-}
-
-void
-_cairo_restrict_value (double *value, double min, double max)
-{
-    if (*value < min)
-	*value = min;
-    else if (*value > max)
-	*value = max;
-}
-
-/* This function is identical to the C99 function lround(), except that it
- * performs arithmetic rounding (instead of away-from-zero rounding) and
- * has a valid input range of (INT_MIN, INT_MAX] instead of
- * [INT_MIN, INT_MAX]. It is much faster on both x86 and FPU-less systems
- * than other commonly used methods for rounding (lround, round, rint, lrint
- * or float (d + 0.5)).
- *
- * The reason why this function is much faster on x86 than other
- * methods is due to the fact that it avoids the fldcw instruction.
- * This instruction incurs a large performance penalty on modern Intel
- * processors due to how it prevents efficient instruction pipelining.
- *
- * The reason why this function is much faster on FPU-less systems is for
- * an entirely different reason. All common rounding methods involve multiple
- * floating-point operations. Each one of these operations has to be
- * emulated in software, which adds up to be a large performance penalty.
- * This function doesn't perform any floating-point calculations, and thus
- * avoids this penalty.
-  */
-int
-_cairo_lround (double d)
-{
-    uint32_t top, shift_amount, output;
-    union {
-        double d;
-        uint64_t ui64;
-        uint32_t ui32[2];
-    } u;
-
-    u.d = d;
-
-    /* If the integer word order doesn't match the float word order, we swap
-     * the words of the input double. This is needed because we will be
-     * treating the whole double as a 64-bit unsigned integer. Notice that we
-     * use WORDS_BIGENDIAN to detect the integer word order, which isn't
-     * exactly correct because WORDS_BIGENDIAN refers to byte order, not word
-     * order. Thus, we are making the assumption that the byte order is the
-     * same as the integer word order which, on the modern machines that we
-     * care about, is OK.
-     */
-#if ( defined(FLOAT_WORDS_BIGENDIAN) && !defined(WORDS_BIGENDIAN)) || \
-    (!defined(FLOAT_WORDS_BIGENDIAN) &&  defined(WORDS_BIGENDIAN))
-    {
-        uint32_t temp = u.ui32[0];
-        u.ui32[0] = u.ui32[1];
-        u.ui32[1] = temp;
-    }
-#endif
-
-#ifdef WORDS_BIGENDIAN
-    #define MSW (0) /* Most Significant Word */
-    #define LSW (1) /* Least Significant Word */
-#else
-    #define MSW (1)
-    #define LSW (0)
-#endif
-
-    /* By shifting the most significant word of the input double to the
-     * right 20 places, we get the very "top" of the double where the exponent
-     * and sign bit lie.
-     */
-    top = u.ui32[MSW] >> 20;
-
-    /* Here, we calculate how much we have to shift the mantissa to normalize
-     * it to an integer value. We extract the exponent "top" by masking out the
-     * sign bit, then we calculate the shift amount by subtracting the exponent
-     * from the bias. Notice that the correct bias for 64-bit doubles is
-     * actually 1075, but we use 1053 instead for two reasons:
-     *
-     *  1) To perform rounding later on, we will first need the target
-     *     value in a 31.1 fixed-point format. Thus, the bias needs to be one
-     *     less: (1075 - 1: 1074).
-     *
-     *  2) To avoid shifting the mantissa as a full 64-bit integer (which is
-     *     costly on certain architectures), we break the shift into two parts.
-     *     First, the upper and lower parts of the mantissa are shifted
-     *     individually by a constant amount that all valid inputs will require
-     *     at the very least. This amount is chosen to be 21, because this will
-     *     allow the two parts of the mantissa to later be combined into a
-     *     single 32-bit representation, on which the remainder of the shift
-     *     will be performed. Thus, we decrease the bias by an additional 21:
-     *     (1074 - 21: 1053).
-     */
-    shift_amount = 1053 - (top & 0x7FF);
-
-    /* We are done with the exponent portion in "top", so here we shift it off
-     * the end.
-     */
-    top >>= 11;
-
-    /* Before we perform any operations on the mantissa, we need to OR in
-     * the implicit 1 at the top (see the IEEE-754 spec). We needn't mask
-     * off the sign bit nor the exponent bits because these higher bits won't
-     * make a bit of difference in the rest of our calculations.
-     */
-    u.ui32[MSW] |= 0x100000;
-
-    /* If the input double is negative, we have to decrease the mantissa
-     * by a hair. This is an important part of performing arithmetic rounding,
-     * as negative numbers must round towards positive infinity in the
-     * halfwase case of -x.5. Since "top" contains only the sign bit at this
-     * point, we can just decrease the mantissa by the value of "top".
-     */
-    u.ui64 -= top;
-
-    /* By decrementing "top", we create a bitmask with a value of either
-     * 0x0 (if the input was negative) or 0xFFFFFFFF (if the input was positive
-     * and thus the unsigned subtraction underflowed) that we'll use later.
-     */
-    top--;
-
-    /* Here, we shift the mantissa by the constant value as described above.
-     * We can emulate a 64-bit shift right by 21 through shifting the top 32
-     * bits left 11 places and ORing in the bottom 32 bits shifted 21 places
-     * to the right. Both parts of the mantissa are now packed into a single
-     * 32-bit integer. Although we severely truncate the lower part in the
-     * process, we still have enough significant bits to perform the conversion
-     * without error (for all valid inputs).
-     */
-    output = (u.ui32[MSW] << 11) | (u.ui32[LSW] >> 21);
-
-    /* Next, we perform the shift that converts the X.Y fixed-point number
-     * currently found in "output" to the desired 31.1 fixed-point format
-     * needed for the following rounding step. It is important to consider
-     * all possible values for "shift_amount" at this point:
-     *
-     * - {shift_amount < 0} Since shift_amount is an unsigned integer, it
-     *   really can't have a value less than zero. But, if the shift_amount
-     *   calculation above caused underflow (which would happen with
-     *   input > INT_MAX or input <= INT_MIN) then shift_amount will now be
-     *   a very large number, and so this shift will result in complete
-     *   garbage. But that's OK, as the input was out of our range, so our
-     *   output is undefined.
-     *
-     * - {shift_amount > 31} If the magnitude of the input was very small
-     *   (i.e. |input| << 1.0), shift_amount will have a value greater than
-     *   31. Thus, this shift will also result in garbage. After performing
-     *   the shift, we will zero-out "output" if this is the case.
-     *
-     * - {0 <= shift_amount < 32} In this case, the shift will properly convert
-     *   the mantissa into a 31.1 fixed-point number.
-     */
-    output >>= shift_amount;
-
-    /* This is where we perform rounding with the 31.1 fixed-point number.
-     * Since what we're after is arithmetic rounding, we simply add the single
-     * fractional bit into the integer part of "output", and just keep the
-     * integer part.
-     */
-    output = (output >> 1) + (output & 1);
-
-    /* Here, we zero-out the result if the magnitude if the input was very small
-     * (as explained in the section above). Notice that all input out of the
-     * valid range is also caught by this condition, which means we produce 0
-     * for all invalid input, which is a nice side effect.
-     *
-     * The most straightforward way to do this would be:
-     *
-     *      if (shift_amount > 31)
-     *          output = 0;
-     *
-     * But we can use a little trick to avoid the potential branch. The
-     * expression (shift_amount > 31) will be either 1 or 0, which when
-     * decremented will be either 0x0 or 0xFFFFFFFF (unsigned underflow),
-     * which can be used to conditionally mask away all the bits in "output"
-     * (in the 0x0 case), effectively zeroing it out. Certain, compilers would
-     * have done this for us automatically.
-     */
-    output &= ((shift_amount > 31) - 1);
-
-    /* If the input double was a negative number, then we have to negate our
-     * output. The most straightforward way to do this would be:
-     *
-     *      if (!top)
-     *          output = -output;
-     *
-     * as "top" at this point is either 0x0 (if the input was negative) or
-     * 0xFFFFFFFF (if the input was positive). But, we can use a trick to
-     * avoid the branch. Observe that the following snippet of code has the
-     * same effect as the reference snippet above:
-     *
-     *      if (!top)
-     *          output = 0 - output;
-     *      else
-     *          output = output - 0;
-     *
-     * Armed with the bitmask found in "top", we can condense the two statements
-     * into the following:
-     *
-     *      output = (output & top) - (output & ~top);
-     *
-     * where, in the case that the input double was negative, "top" will be 0,
-     * and the statement will be equivalent to:
-     *
-     *      output = (0) - (output);
-     *
-     * and if the input double was positive, "top" will be 0xFFFFFFFF, and the
-     * statement will be equivalent to:
-     *
-     *      output = (output) - (0);
-     *
-     * Which, as pointed out earlier, is equivalent to the original reference
-     * snippet.
-     */
-    output = (output & top) - (output & ~top);
-
-    return output;
-#undef MSW
-#undef LSW
-}
--- a/gfx/cairo/cairo/src/cairo.h
+++ b/gfx/cairo/cairo/src/cairo.h
@@ -233,17 +233,17 @@ typedef enum _cairo_status {
     CAIRO_STATUS_INVALID_VISUAL,
     CAIRO_STATUS_FILE_NOT_FOUND,
     CAIRO_STATUS_INVALID_DASH,
     CAIRO_STATUS_INVALID_DSC_COMMENT,
     CAIRO_STATUS_INVALID_INDEX,
     CAIRO_STATUS_CLIP_NOT_REPRESENTABLE,
     CAIRO_STATUS_TEMP_FILE_ERROR,
     CAIRO_STATUS_INVALID_STRIDE
-    /* after adding a new error: update CAIRO_STATUS_LAST_STATUS in cairo.c */
+    /* after adding a new error: update CAIRO_STATUS_LAST_STATUS in cairoint.h */
 } cairo_status_t;
 
 /**
  * cairo_content_t:
  * @CAIRO_CONTENT_COLOR: The surface will hold color content only.
  * @CAIRO_CONTENT_ALPHA: The surface will hold alpha content only.
  * @CAIRO_CONTENT_COLOR_ALPHA: The surface will hold color and alpha content.
  *
--- a/gfx/cairo/cairo/src/cairoint.h
+++ b/gfx/cairo/cairo/src/cairoint.h
@@ -107,16 +107,24 @@ cairo_private FILE *
 
 #ifndef M_SQRT1_2
 #define M_SQRT1_2 0.707106781186547524400844362104849039
 #endif
 
 #undef  ARRAY_LENGTH
 #define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0])))
 
+
+/* This has to be updated whenever #cairo_status_t is extended.  That's
+ * a bit of a pain, but it should be easy to always catch as long as
+ * one adds a new test case to test a trigger of the new status value.
+ */
+#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_INVALID_STRIDE
+
+
 /* Size in bytes of buffer to use off the stack per functions.
  * Mostly used by text functions.  For larger allocations, they'll
  * malloc(). */
 #ifndef CAIRO_STACK_BUFFER_SIZE
 #define CAIRO_STACK_BUFFER_SIZE (512 * sizeof (int))
 #endif
 
 #define CAIRO_STACK_ARRAY_LENGTH(T) (CAIRO_STACK_BUFFER_SIZE / sizeof(T))
@@ -1229,18 +1237,23 @@ cairo_private void
 
 cairo_private void
 _cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font);
 
 cairo_private cairo_status_t
 _cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
 			      cairo_status_t status);
 
+cairo_private cairo_scaled_font_t *
+_cairo_scaled_font_create_in_error (cairo_status_t status);
+
+cairo_private void
+_cairo_scaled_font_reset_static_data (void);
+
 extern const cairo_private cairo_font_face_t _cairo_font_face_nil;
-extern const cairo_private cairo_scaled_font_t _cairo_scaled_font_nil;
 
 cairo_private void
 _cairo_font_face_init (cairo_font_face_t               *font_face,
 		       const cairo_font_face_backend_t *backend);
 
 cairo_private cairo_status_t
 _cairo_font_face_set_error (cairo_font_face_t *font_face,
 	                    cairo_status_t     status);
--- a/gfx/cairo/libpixman/src/pixman-compose.c
+++ b/gfx/cairo/libpixman/src/pixman-compose.c
@@ -3673,42 +3673,539 @@ static void pixmanFetchSourcePict(source
                     ry += cy;
                     rz += cz;
                 }
             }
         }
     }
 }
 
-static void fbFetchTransformed(bits_image_t * pict, int x, int y, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits)
+/*
+ * Fetch from region strategies
+ */
+typedef FASTCALL uint32_t (*fetchFromRegionProc)(bits_image_t *pict, int x, int y, uint32_t *buffer, fetchPixelProc fetch, pixman_box16_t *box);
+
+static inline uint32_t
+fbFetchFromNoRegion(bits_image_t *pict, int x, int y, uint32_t *buffer, fetchPixelProc fetch, pixman_box16_t *box)
+{
+    return fetch (pict, x, y);
+}
+
+static uint32_t
+fbFetchFromNRectangles(bits_image_t *pict, int x, int y, uint32_t *buffer, fetchPixelProc fetch, pixman_box16_t *box)
+{
+    pixman_box16_t box2;
+    if (pixman_region_contains_point (pict->common.src_clip, x, y, &box2))
+        return fbFetchFromNoRegion(pict, x, y, buffer, fetch, box);
+    else
+        return 0;
+}
+
+static uint32_t
+fbFetchFromOneRectangle(bits_image_t *pict, int x, int y, uint32_t *buffer, fetchPixelProc fetch, pixman_box16_t *box)
+{
+    pixman_box16_t box2 = *box;
+    return ((x < box2.x1) | (x >= box2.x2) | (y < box2.y1) | (y >= box2.y2)) ?
+        0 : fbFetchFromNoRegion(pict, x, y, buffer, fetch, box);
+}
+
+/*
+ * Fetching Algorithms
+ */
+static void
+fbFetchTransformed_Nearest_Normal(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+    pixman_box16_t* box = NULL;
+    fetchPixelProc   fetch;
+    fetchFromRegionProc fetchFromRegion;
+    int x, y, i;
+
+    /* initialize the two function pointers */
+    fetch = fetchPixelProcForPicture(pict);
+
+    if(pixman_region_n_rects (pict->common.src_clip) == 1)
+        fetchFromRegion = fbFetchFromNoRegion;
+    else
+        fetchFromRegion = fbFetchFromNRectangles;
+
+    for ( i = 0; i < width; ++i)
+    {
+        if (!mask || mask[i] & maskBits)
+        {
+            if (!v.vector[2])
+            {
+                *(buffer + i) = 0;
+            }
+            else
+            {
+                if (!affine)
+                {
+                    y = MOD(DIV(v.vector[1],v.vector[2]), pict->height);
+                    x = MOD(DIV(v.vector[0],v.vector[2]), pict->width);
+                }
+                else
+                {
+                    y = MOD(v.vector[1]>>16, pict->height);
+                    x = MOD(v.vector[0]>>16, pict->width);
+                }
+                *(buffer + i) = fetchFromRegion(pict, x, y, buffer, fetch, box);
+            }
+        }
+
+        v.vector[0] += unit.vector[0];
+        v.vector[1] += unit.vector[1];
+        v.vector[2] += unit.vector[2];
+    }
+}
+
+static void
+fbFetchTransformed_Nearest_Pad(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+    pixman_box16_t *box = NULL;
+    fetchPixelProc   fetch;
+    fetchFromRegionProc fetchFromRegion;
+    int x, y, i;
+
+    /* initialize the two function pointers */
+    fetch = fetchPixelProcForPicture(pict);
+
+    if(pixman_region_n_rects (pict->common.src_clip) == 1)
+        fetchFromRegion = fbFetchFromNoRegion;
+    else
+        fetchFromRegion = fbFetchFromNRectangles;
+
+    for (i = 0; i < width; ++i)
+    {
+        if (!mask || mask[i] & maskBits)
+        {
+            if (!v.vector[2])
+            {
+                *(buffer + i) = 0;
+            }
+            else
+            {
+                if (!affine)
+                {
+                    y = CLIP(DIV(v.vector[1], v.vector[2]), 0, pict->height-1);
+                    x = CLIP(DIV(v.vector[0], v.vector[2]), 0, pict->width-1);
+                }
+                else
+                {
+                    y = CLIP(v.vector[1]>>16, 0, pict->height-1);
+                    x = CLIP(v.vector[0]>>16, 0, pict->width-1);
+                }
+
+                *(buffer + i) = fetchFromRegion(pict, x, y, buffer, fetch, box);
+            }
+        }
+
+        v.vector[0] += unit.vector[0];
+        v.vector[1] += unit.vector[1];
+        v.vector[2] += unit.vector[2];
+    }
+}
+
+static void
+fbFetchTransformed_Nearest_General(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+    pixman_box16_t *box = NULL;
+    fetchPixelProc   fetch;
+    fetchFromRegionProc fetchFromRegion;
+    int x, y, i;
+
+    /* initialize the two function pointers */
+    fetch = fetchPixelProcForPicture(pict);
+
+    if(pixman_region_n_rects (pict->common.src_clip) == 1)
+    {
+        box = &(pict->common.src_clip->extents);
+        fetchFromRegion = fbFetchFromOneRectangle;
+    }
+    else
+    {
+        fetchFromRegion = fbFetchFromNRectangles;
+    }
+
+    for (i = 0; i < width; ++i) {
+        if (!mask || mask[i] & maskBits)
+        {
+            if (!v.vector[2]) {
+                *(buffer + i) = 0;
+            } else {
+                if (!affine) {
+                    y = DIV(v.vector[1],v.vector[2]);
+                    x = DIV(v.vector[0],v.vector[2]);
+                } else {
+                    y = v.vector[1]>>16;
+                    x = v.vector[0]>>16;
+                }
+                *(buffer + i) = fetchFromRegion(pict, x, y, buffer, fetch, box);
+            }
+        }
+        v.vector[0] += unit.vector[0];
+        v.vector[1] += unit.vector[1];
+        v.vector[2] += unit.vector[2];
+    }
+}
+
+static void
+fbFetchTransformed_Bilinear_Normal(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+    pixman_box16_t *box = NULL;
+    fetchPixelProc   fetch;
+    fetchFromRegionProc fetchFromRegion;
+    int i;
+
+    /* initialize the two function pointers */
+    fetch = fetchPixelProcForPicture(pict);
+
+    if(pixman_region_n_rects (pict->common.src_clip) == 1)
+        fetchFromRegion = fbFetchFromNoRegion;
+    else
+        fetchFromRegion = fbFetchFromNRectangles;
+
+    for (i = 0; i < width; ++i) {
+        if (!mask || mask[i] & maskBits)
+        {
+            if (!v.vector[2]) {
+                *(buffer + i) = 0;
+            } else {
+                int x1, x2, y1, y2, distx, idistx, disty, idisty;
+                uint32_t tl, tr, bl, br, r;
+                uint32_t ft, fb;
+
+                if (!affine) {
+                    pixman_fixed_48_16_t div;
+                    div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
+                    x1 = div >> 16;
+                    distx = ((pixman_fixed_t)div >> 8) & 0xff;
+                    div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
+                    y1 = div >> 16;
+                    disty = ((pixman_fixed_t)div >> 8) & 0xff;
+                } else {
+                    x1 = v.vector[0] >> 16;
+                    distx = (v.vector[0] >> 8) & 0xff;
+                    y1 = v.vector[1] >> 16;
+                    disty = (v.vector[1] >> 8) & 0xff;
+                }
+                x2 = x1 + 1;
+                y2 = y1 + 1;
+
+                idistx = 256 - distx;
+                idisty = 256 - disty;
+
+                x1 = MOD (x1, pict->width);
+                x2 = MOD (x2, pict->width);
+                y1 = MOD (y1, pict->height);
+                y2 = MOD (y2, pict->height);
+
+                tl = fetchFromRegion(pict, x1, y1, buffer, fetch, box);
+                tr = fetchFromRegion(pict, x2, y1, buffer, fetch, box);
+                bl = fetchFromRegion(pict, x1, y2, buffer, fetch, box);
+                br = fetchFromRegion(pict, x2, y2, buffer, fetch, box);
+
+                ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
+                fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
+                r = (((ft * idisty + fb * disty) >> 16) & 0xff);
+                ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
+                fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
+                r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
+                ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
+                fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
+                r |= (((ft * idisty + fb * disty)) & 0xff0000);
+                ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
+                fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
+                r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
+                *(buffer + i) = r;
+            }
+        }
+        v.vector[0] += unit.vector[0];
+        v.vector[1] += unit.vector[1];
+        v.vector[2] += unit.vector[2];
+    }
+}
+
+static void
+fbFetchTransformed_Bilinear_Pad(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+    pixman_box16_t *box = NULL;
+    fetchPixelProc   fetch;
+    fetchFromRegionProc fetchFromRegion;
+    int i;
+
+    /* initialize the two function pointers */
+    fetch = fetchPixelProcForPicture(pict);
+
+    if(pixman_region_n_rects (pict->common.src_clip) == 1)
+        fetchFromRegion = fbFetchFromNoRegion;
+    else
+        fetchFromRegion = fbFetchFromNRectangles;
+
+    for (i = 0; i < width; ++i) {
+        if (!mask || mask[i] & maskBits)
+        {
+            if (!v.vector[2]) {
+                *(buffer + i) = 0;
+            } else {
+                int x1, x2, y1, y2, distx, idistx, disty, idisty;
+                uint32_t tl, tr, bl, br, r;
+                uint32_t ft, fb;
+
+                if (!affine) {
+                    pixman_fixed_48_16_t div;
+                    div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
+                    x1 = div >> 16;
+                    distx = ((pixman_fixed_t)div >> 8) & 0xff;
+                    div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
+                    y1 = div >> 16;
+                    disty = ((pixman_fixed_t)div >> 8) & 0xff;
+                } else {
+                    x1 = v.vector[0] >> 16;
+                    distx = (v.vector[0] >> 8) & 0xff;
+                    y1 = v.vector[1] >> 16;
+                    disty = (v.vector[1] >> 8) & 0xff;
+                }
+                x2 = x1 + 1;
+                y2 = y1 + 1;
+
+                idistx = 256 - distx;
+                idisty = 256 - disty;
+
+                x1 = CLIP (x1, 0, pict->width-1);
+                x2 = CLIP (x2, 0, pict->width-1);
+                y1 = CLIP (y1, 0, pict->height-1);
+                y2 = CLIP (y2, 0, pict->height-1);
+
+                tl = fetchFromRegion(pict, x1, y1, buffer, fetch, box);
+                tr = fetchFromRegion(pict, x2, y1, buffer, fetch, box);
+                bl = fetchFromRegion(pict, x1, y2, buffer, fetch, box);
+                br = fetchFromRegion(pict, x2, y2, buffer, fetch, box);
+
+                ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
+                fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
+                r = (((ft * idisty + fb * disty) >> 16) & 0xff);
+                ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
+                fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
+                r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
+                ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
+                fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
+                r |= (((ft * idisty + fb * disty)) & 0xff0000);
+                ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
+                fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
+                r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
+                *(buffer + i) = r;
+            }
+        }
+        v.vector[0] += unit.vector[0];
+        v.vector[1] += unit.vector[1];
+        v.vector[2] += unit.vector[2];
+    }
+}
+
+static void
+fbFetchTransformed_Bilinear_General(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+    pixman_box16_t *box = NULL;
+    fetchPixelProc   fetch;
+    fetchFromRegionProc fetchFromRegion;
+    int i;
+
+    /* initialize the two function pointers */
+    fetch = fetchPixelProcForPicture(pict);
+
+    if(pixman_region_n_rects (pict->common.src_clip) == 1)
+    {
+        box = &(pict->common.src_clip->extents);
+        fetchFromRegion = fbFetchFromOneRectangle;
+    }
+    else
+    {
+        fetchFromRegion = fbFetchFromNRectangles;
+    }
+
+    for (i = 0; i < width; ++i)
+    {
+        if (!mask || mask[i] & maskBits)
+        {
+            if (!v.vector[2]) {
+                *(buffer + i) = 0;
+            } else {
+                int x1, x2, y1, y2, distx, idistx, disty, idisty;
+                uint32_t tl, tr, bl, br, r;
+                uint32_t ft, fb;
+
+                if (!affine) {
+                    pixman_fixed_48_16_t div;
+                    div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
+                    x1 = div >> 16;
+                    distx = ((pixman_fixed_t)div >> 8) & 0xff;
+                    div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
+                    y1 = div >> 16;
+                    disty = ((pixman_fixed_t)div >> 8) & 0xff;
+                } else {
+                    x1 = v.vector[0] >> 16;
+                    distx = (v.vector[0] >> 8) & 0xff;
+                    y1 = v.vector[1] >> 16;
+                    disty = (v.vector[1] >> 8) & 0xff;
+                }
+                x2 = x1 + 1;
+                y2 = y1 + 1;
+
+                idistx = 256 - distx;
+                idisty = 256 - disty;
+
+                tl = fetchFromRegion(pict, x1, y1, buffer, fetch, box);
+                tr = fetchFromRegion(pict, x2, y1, buffer, fetch, box);
+                bl = fetchFromRegion(pict, x1, y2, buffer, fetch, box);
+                br = fetchFromRegion(pict, x2, y2, buffer, fetch, box);
+
+                ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
+                fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
+                r = (((ft * idisty + fb * disty) >> 16) & 0xff);
+                ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
+                fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
+                r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
+                ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
+                fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
+                r |= (((ft * idisty + fb * disty)) & 0xff0000);
+                ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
+                fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
+                r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
+                *(buffer + i) = r;
+            }
+        }
+
+        v.vector[0] += unit.vector[0];
+        v.vector[1] += unit.vector[1];
+        v.vector[2] += unit.vector[2];
+    }
+}
+
+static void
+fbFetchTransformed_Convolution(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+    pixman_box16_t *box = NULL;
+    fetchPixelProc fetch;
+    int i;
+
+    pixman_fixed_t *params = pict->common.filter_params;
+    int32_t cwidth = pixman_fixed_to_int(params[0]);
+    int32_t cheight = pixman_fixed_to_int(params[1]);
+    int xoff = (params[0] - pixman_fixed_1) >> 1;
+    int yoff = (params[1] - pixman_fixed_1) >> 1;
+    fetch = fetchPixelProcForPicture(pict);
+
+    params += 2;
+    for (i = 0; i < width; ++i) {
+        if (!mask || mask[i] & maskBits)
+        {
+            if (!v.vector[2]) {
+                *(buffer + i) = 0;
+            } else {
+                int x1, x2, y1, y2, x, y;
+                int32_t srtot, sgtot, sbtot, satot;
+                pixman_fixed_t *p = params;
+
+                if (!affine) {
+                    pixman_fixed_48_16_t tmp;
+                    tmp = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2] - xoff;
+                    x1 = pixman_fixed_to_int(tmp);
+                    tmp = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2] - yoff;
+                    y1 = pixman_fixed_to_int(tmp);
+                } else {
+                    x1 = pixman_fixed_to_int(v.vector[0] - xoff);
+                    y1 = pixman_fixed_to_int(v.vector[1] - yoff);
+                }
+                x2 = x1 + cwidth;
+                y2 = y1 + cheight;
+
+                srtot = sgtot = sbtot = satot = 0;
+
+                for (y = y1; y < y2; y++) {
+                    int ty;
+                    switch (pict->common.repeat) {
+                        case PIXMAN_REPEAT_NORMAL:
+                            ty = MOD (y, pict->height);
+                            break;
+                        case PIXMAN_REPEAT_PAD:
+                            ty = CLIP (y, 0, pict->height-1);
+                            break;
+                        default:
+                            ty = y;
+                    }
+                    for (x = x1; x < x2; x++) {
+                        if (*p) {
+                            int tx;
+                            switch (pict->common.repeat) {
+                                case PIXMAN_REPEAT_NORMAL:
+                                    tx = MOD (x, pict->width);
+                                    break;
+                                case PIXMAN_REPEAT_PAD:
+                                    tx = CLIP (x, 0, pict->width-1);
+                                    break;
+                                default:
+                                    tx = x;
+                            }
+                            if (pixman_region_contains_point (pict->common.src_clip, tx, ty, box)) {
+                                uint32_t c = fetch(pict, tx, ty);
+
+                                srtot += Red(c) * *p;
+                                sgtot += Green(c) * *p;
+                                sbtot += Blue(c) * *p;
+                                satot += Alpha(c) * *p;
+                            }
+                        }
+                        p++;
+                    }
+                }
+
+                satot >>= 16;
+                srtot >>= 16;
+                sgtot >>= 16;
+                sbtot >>= 16;
+
+                if (satot < 0) satot = 0; else if (satot > 0xff) satot = 0xff;
+                if (srtot < 0) srtot = 0; else if (srtot > 0xff) srtot = 0xff;
+                if (sgtot < 0) sgtot = 0; else if (sgtot > 0xff) sgtot = 0xff;
+                if (sbtot < 0) sbtot = 0; else if (sbtot > 0xff) sbtot = 0xff;
+
+                *(buffer + i) = ((satot << 24) |
+                                 (srtot << 16) |
+                                 (sgtot <<  8) |
+                                 (sbtot       ));
+            }
+        }
+        v.vector[0] += unit.vector[0];
+        v.vector[1] += unit.vector[1];
+        v.vector[2] += unit.vector[2];
+    }
+}
+
+static void
+fbFetchTransformed(bits_image_t * pict, int x, int y, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits)
 {
     uint32_t     *bits;
     int32_t    stride;
-    fetchPixelProc   fetch;
-    pixman_vector_t	v;
-    pixman_vector_t  unit;
-    int         i;
-    pixman_box16_t box;
+    pixman_vector_t v;
+    pixman_vector_t unit;
     pixman_bool_t affine = TRUE;
 
-    fetch = fetchPixelProcForPicture(pict);
-
     bits = pict->bits;
     stride = pict->rowstride;
 
     /* reference point is the center of the pixel */
     v.vector[0] = pixman_int_to_fixed(x) + pixman_fixed_1 / 2 - 1;
     v.vector[1] = pixman_int_to_fixed(y) + pixman_fixed_1 / 2 - 1;
     v.vector[2] = pixman_fixed_1;
 
     /* when using convolution filters one might get here without a transform */
     if (pict->common.transform)
     {
         if (!pixman_transform_point_3d (pict->common.transform, &v))
-	{
+        {
             fbFinishAccess (pict->pDrawable);
             return;
         }
         unit.vector[0] = pict->common.transform->matrix[0][0];
         unit.vector[1] = pict->common.transform->matrix[1][0];
         unit.vector[2] = pict->common.transform->matrix[2][0];
         affine = v.vector[2] == pixman_fixed_1 && unit.vector[2] == 0;
     }
@@ -3716,455 +4213,63 @@ static void fbFetchTransformed(bits_imag
     {
         unit.vector[0] = pixman_fixed_1;
         unit.vector[1] = 0;
         unit.vector[2] = 0;
     }
 
     if (pict->common.filter == PIXMAN_FILTER_NEAREST || pict->common.filter == PIXMAN_FILTER_FAST)
     {
-        if (pict->common.repeat == PIXMAN_REPEAT_NORMAL) {
-            if (pixman_region_n_rects (pict->common.src_clip) == 1) {
-		for (i = 0; i < width; ++i) {
-		    if (!mask || mask[i] & maskBits)
-		    {
-			if (!v.vector[2]) {
-			    *(buffer + i) = 0;
-			} else {
-			    if (!affine) {
-				y = MOD(DIV(v.vector[1],v.vector[2]), pict->height);
-				x = MOD(DIV(v.vector[0],v.vector[2]), pict->width);
-			    } else {
-				y = MOD(v.vector[1]>>16, pict->height);
-				x = MOD(v.vector[0]>>16, pict->width);
-			    }
-			    *(buffer + i) = fetch(pict, x, y);
-			}
-		    }
-
-                    v.vector[0] += unit.vector[0];
-                    v.vector[1] += unit.vector[1];
-                    v.vector[2] += unit.vector[2];
-                }
-            } else {
-                for (i = 0; i < width; ++i) {
-		    if (!mask || mask[i] & maskBits)
-		    {
-			if (!v.vector[2]) {
-			    *(buffer + i) = 0;
-			} else {
-			    if (!affine) {
-				y = MOD(DIV(v.vector[1],v.vector[2]), pict->height);
-				x = MOD(DIV(v.vector[0],v.vector[2]), pict->width);
-			    } else {
-				y = MOD(v.vector[1]>>16, pict->height);
-				x = MOD(v.vector[0]>>16, pict->width);
-			    }
-			    if (pixman_region_contains_point (pict->common.src_clip, x, y, &box))
-				*(buffer + i) = fetch (pict, x, y);
-			    else
-				*(buffer + i) = 0;
-			}
-		    }
-
-                    v.vector[0] += unit.vector[0];
-                    v.vector[1] += unit.vector[1];
-                    v.vector[2] += unit.vector[2];
-                }
-            }
-        } else {
-            if (pixman_region_n_rects(pict->common.src_clip) == 1) {
-                box = pict->common.src_clip->extents;
-                for (i = 0; i < width; ++i) {
-		    if (!mask || mask[i] & maskBits)
-		    {
-			if (!v.vector[2]) {
-			    *(buffer + i) = 0;
-			} else {
-			    if (!affine) {
-				y = DIV(v.vector[1],v.vector[2]);
-				x = DIV(v.vector[0],v.vector[2]);
-			    } else {
-				y = v.vector[1]>>16;
-				x = v.vector[0]>>16;
-			    }
-			    *(buffer + i) = ((x < box.x1) | (x >= box.x2) | (y < box.y1) | (y >= box.y2)) ?
-				0 : fetch(pict, x, y);
-			}
-		    }
-                    v.vector[0] += unit.vector[0];
-                    v.vector[1] += unit.vector[1];
-                    v.vector[2] += unit.vector[2];
-                }
-            } else {
-                for (i = 0; i < width; ++i) {
-                    if (!mask || mask[i] & maskBits)
-		    {
-			if (!v.vector[2]) {
-			    *(buffer + i) = 0;
-			} else {
-			    if (!affine) {
-				y = DIV(v.vector[1],v.vector[2]);
-				x = DIV(v.vector[0],v.vector[2]);
-			    } else {
-				y = v.vector[1]>>16;
-				x = v.vector[0]>>16;
-			    }
-			    if (pixman_region_contains_point (pict->common.src_clip, x, y, &box))
-				*(buffer + i) = fetch(pict, x, y);
-			    else
-				*(buffer + i) = 0;
-			}
-		    }
-                    v.vector[0] += unit.vector[0];
-                    v.vector[1] += unit.vector[1];
-                    v.vector[2] += unit.vector[2];
-                }
-            }
+        if (pict->common.repeat == PIXMAN_REPEAT_NORMAL)
+        {
+            fbFetchTransformed_Nearest_Normal(pict, width, buffer, mask, maskBits, affine, v, unit);
+
+        }
+        else if (pict->common.repeat == PIXMAN_REPEAT_PAD)
+        {
+            fbFetchTransformed_Nearest_Pad(pict, width, buffer, mask, maskBits, affine, v, unit);
+        }
+        else
+        {
+            fbFetchTransformed_Nearest_General(pict, width, buffer, mask, maskBits, affine, v, unit);
         }
     } else if (pict->common.filter == PIXMAN_FILTER_BILINEAR	||
 	       pict->common.filter == PIXMAN_FILTER_GOOD	||
 	       pict->common.filter == PIXMAN_FILTER_BEST)
     {
         /* adjust vector for maximum contribution at 0.5, 0.5 of each texel. */
         v.vector[0] -= v.vector[2] / 2;
         v.vector[1] -= v.vector[2] / 2;
         unit.vector[0] -= unit.vector[2] / 2;
         unit.vector[1] -= unit.vector[2] / 2;
 
-        if (pict->common.repeat == PIXMAN_REPEAT_NORMAL) {
-            if (pixman_region_n_rects(pict->common.src_clip) == 1) {
-                for (i = 0; i < width; ++i) {
-                    if (!mask || mask[i] & maskBits)
-		    {
-			if (!v.vector[2]) {
-			    *(buffer + i) = 0;
-			} else {
-			    int x1, x2, y1, y2, distx, idistx, disty, idisty;
-			    uint32_t tl, tr, bl, br, r;
-			    uint32_t ft, fb;
-
-			    if (!affine) {
-				pixman_fixed_48_16_t div;
-				div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
-				x1 = div >> 16;
-				distx = ((pixman_fixed_t)div >> 8) & 0xff;
-				div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
-				y1 = div >> 16;
-				disty = ((pixman_fixed_t)div >> 8) & 0xff;
-			    } else {
-				x1 = v.vector[0] >> 16;
-				distx = (v.vector[0] >> 8) & 0xff;
-				y1 = v.vector[1] >> 16;
-				disty = (v.vector[1] >> 8) & 0xff;
-			    }
-			    x2 = x1 + 1;
-			    y2 = y1 + 1;
-
-			    idistx = 256 - distx;
-			    idisty = 256 - disty;
-
-			    x1 = MOD (x1, pict->width);
-			    x2 = MOD (x2, pict->width);
-			    y1 = MOD (y1, pict->height);
-			    y2 = MOD (y2, pict->height);
-
-			    tl = fetch(pict, x1, y1);
-			    tr = fetch(pict, x2, y1);
-			    bl = fetch(pict, x1, y2);
-			    br = fetch(pict, x2, y2);
-
-			    ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
-			    fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
-			    r = (((ft * idisty + fb * disty) >> 16) & 0xff);
-			    ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
-			    fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
-			    r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
-			    ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
-			    fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
-			    r |= (((ft * idisty + fb * disty)) & 0xff0000);
-			    ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
-			    fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
-			    r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
-			    *(buffer + i) = r;
-			}
-		    }
-                    v.vector[0] += unit.vector[0];
-                    v.vector[1] += unit.vector[1];
-                    v.vector[2] += unit.vector[2];
-                }
-            } else {
-                for (i = 0; i < width; ++i) {
-		    if (!mask || mask[i] & maskBits)
-		    {
-			if (!v.vector[2]) {
-			    *(buffer + i) = 0;
-			} else {
-			    int x1, x2, y1, y2, distx, idistx, disty, idisty;
-			    uint32_t tl, tr, bl, br, r;
-			    uint32_t ft, fb;
-
-			    if (!affine) {
-				pixman_fixed_48_16_t div;
-				div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
-				x1 = div >> 16;
-				distx = ((pixman_fixed_t)div >> 8) & 0xff;
-				div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
-				y1 = div >> 16;
-				disty = ((pixman_fixed_t)div >> 8) & 0xff;
-			    } else {
-				x1 = v.vector[0] >> 16;
-				distx = (v.vector[0] >> 8) & 0xff;
-				y1 = v.vector[1] >> 16;
-				disty = (v.vector[1] >> 8) & 0xff;
-			    }
-			    x2 = x1 + 1;
-			    y2 = y1 + 1;
-
-			    idistx = 256 - distx;
-			    idisty = 256 - disty;
-
-			    x1 = MOD (x1, pict->width);
-			    x2 = MOD (x2, pict->width);
-			    y1 = MOD (y1, pict->height);
-			    y2 = MOD (y2, pict->height);
-
-			    tl = pixman_region_contains_point(pict->common.src_clip, x1, y1, &box)
-				? fetch(pict, x1, y1) : 0;
-			    tr = pixman_region_contains_point(pict->common.src_clip, x2, y1, &box)
-				? fetch(pict, x2, y1) : 0;
-			    bl = pixman_region_contains_point(pict->common.src_clip, x1, y2, &box)
-				? fetch(pict, x1, y2) : 0;
-			    br = pixman_region_contains_point(pict->common.src_clip, x2, y2, &box)
-				? fetch(pict, x2, y2) : 0;
-
-			    ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
-			    fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
-			    r = (((ft * idisty + fb * disty) >> 16) & 0xff);
-			    ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
-			    fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
-			    r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
-			    ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
-			    fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
-			    r |= (((ft * idisty + fb * disty)) & 0xff0000);
-			    ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
-			    fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
-			    r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
-			    *(buffer + i) = r;
-			}
-		    }
-
-                    v.vector[0] += unit.vector[0];
-                    v.vector[1] += unit.vector[1];
-                    v.vector[2] += unit.vector[2];
-                }
-            }
-        } else {
-            if (pixman_region_n_rects(pict->common.src_clip) == 1) {
-                box = pict->common.src_clip->extents;
-                for (i = 0; i < width; ++i) {
-		    if (!mask || mask[i] & maskBits)
-		    {
-			if (!v.vector[2]) {
-			    *(buffer + i) = 0;
-			} else {
-			    int x1, x2, y1, y2, distx, idistx, disty, idisty;
-			    uint32_t tl, tr, bl, br, r;
-			    pixman_bool_t x1_out, x2_out, y1_out, y2_out;
-			    uint32_t ft, fb;
-
-			    if (!affine) {
-				pixman_fixed_48_16_t div;
-				div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
-				x1 = div >> 16;
-				distx = ((pixman_fixed_t)div >> 8) & 0xff;
-				div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
-				y1 = div >> 16;
-				disty = ((pixman_fixed_t)div >> 8) & 0xff;
-			    } else {
-				x1 = v.vector[0] >> 16;
-				distx = (v.vector[0] >> 8) & 0xff;
-				y1 = v.vector[1] >> 16;
-				disty = (v.vector[1] >> 8) & 0xff;
-			    }
-			    x2 = x1 + 1;
-			    y2 = y1 + 1;
-
-			    idistx = 256 - distx;
-			    idisty = 256 - disty;
-
-			    x1_out = (x1 < box.x1) | (x1 >= box.x2);
-			    x2_out = (x2 < box.x1) | (x2 >= box.x2);
-			    y1_out = (y1 < box.y1) | (y1 >= box.y2);
-			    y2_out = (y2 < box.y1) | (y2 >= box.y2);
-
-			    tl = x1_out|y1_out ? 0 : fetch(pict, x1, y1);
-			    tr = x2_out|y1_out ? 0 : fetch(pict, x2, y1);
-			    bl = x1_out|y2_out ? 0 : fetch(pict, x1, y2);
-			    br = x2_out|y2_out ? 0 : fetch(pict, x2, y2);
-
-			    ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
-			    fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
-			    r = (((ft * idisty + fb * disty) >> 16) & 0xff);
-			    ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
-			    fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
-			    r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
-			    ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
-			    fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
-			    r |= (((ft * idisty + fb * disty)) & 0xff0000);
-			    ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
-			    fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
-			    r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
-			    *(buffer + i) = r;
-			}
-		    }
-
-                    v.vector[0] += unit.vector[0];
-                    v.vector[1] += unit.vector[1];
-                    v.vector[2] += unit.vector[2];
-                }
-            } else {
-                for (i = 0; i < width; ++i) {
-                    if (!mask || mask[i] & maskBits)
-		    {
-			if (!v.vector[2]) {
-			    *(buffer + i) = 0;
-			} else {
-			    int x1, x2, y1, y2, distx, idistx, disty, idisty;
-			    uint32_t tl, tr, bl, br, r;
-			    uint32_t ft, fb;
-
-			    if (!affine) {
-				pixman_fixed_48_16_t div;
-				div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
-				x1 = div >> 16;
-				distx = ((pixman_fixed_t)div >> 8) & 0xff;
-				div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
-				y1 = div >> 16;
-				disty = ((pixman_fixed_t)div >> 8) & 0xff;
-			    } else {
-				x1 = v.vector[0] >> 16;
-				distx = (v.vector[0] >> 8) & 0xff;
-				y1 = v.vector[1] >> 16;
-				disty = (v.vector[1] >> 8) & 0xff;
-			    }
-			    x2 = x1 + 1;
-			    y2 = y1 + 1;
-
-			    idistx = 256 - distx;
-			    idisty = 256 - disty;
-
-			    tl = pixman_region_contains_point(pict->common.src_clip, x1, y1, &box)
-				? fetch(pict, x1, y1) : 0;
-			    tr = pixman_region_contains_point(pict->common.src_clip, x2, y1, &box)
-				? fetch(pict, x2, y1) : 0;
-			    bl = pixman_region_contains_point(pict->common.src_clip, x1, y2, &box)
-				? fetch(pict, x1, y2) : 0;
-			    br = pixman_region_contains_point(pict->common.src_clip, x2, y2, &box)
-				? fetch(pict, x2, y2) : 0;
-
-			    ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
-			    fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
-			    r = (((ft * idisty + fb * disty) >> 16) & 0xff);
-			    ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
-			    fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
-			    r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
-			    ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
-			    fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
-			    r |= (((ft * idisty + fb * disty)) & 0xff0000);
-			    ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
-			    fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
-			    r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
-			    *(buffer + i) = r;
-			}
-		    }
-
-                    v.vector[0] += unit.vector[0];
-                    v.vector[1] += unit.vector[1];
-                    v.vector[2] += unit.vector[2];
-                }
-            }
+        if (pict->common.repeat == PIXMAN_REPEAT_NORMAL)
+        {
+            fbFetchTransformed_Bilinear_Normal(pict, width, buffer, mask, maskBits, affine, v, unit);
+        }
+        else if (pict->common.repeat == PIXMAN_REPEAT_PAD)
+        {
+            fbFetchTransformed_Bilinear_Pad(pict, width, buffer, mask, maskBits, affine, v, unit);
         }
-    } else if (pict->common.filter == PIXMAN_FILTER_CONVOLUTION) {
-        pixman_fixed_t *params = pict->common.filter_params;
-        int32_t cwidth = pixman_fixed_to_int(params[0]);
-        int32_t cheight = pixman_fixed_to_int(params[1]);
-        int xoff = (params[0] - pixman_fixed_1) >> 1;
-	int yoff = (params[1] - pixman_fixed_1) >> 1;
-        params += 2;
-        for (i = 0; i < width; ++i) {
-	    if (!mask || mask[i] & maskBits)
-	    {
-		if (!v.vector[2]) {
-		    *(buffer + i) = 0;
-		} else {
-		    int x1, x2, y1, y2, x, y;
-		    int32_t srtot, sgtot, sbtot, satot;
-		    pixman_fixed_t *p = params;
-
-		    if (!affine) {
-			pixman_fixed_48_16_t tmp;
-			tmp = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2] - xoff;
-			x1 = pixman_fixed_to_int(tmp);
-			tmp = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2] - yoff;
-			y1 = pixman_fixed_to_int(tmp);
-		    } else {
-			x1 = pixman_fixed_to_int(v.vector[0] - xoff);
-			y1 = pixman_fixed_to_int(v.vector[1] - yoff);
-		    }
-		    x2 = x1 + cwidth;
-		    y2 = y1 + cheight;
-
-		    srtot = sgtot = sbtot = satot = 0;
-
-		    for (y = y1; y < y2; y++) {
-			int ty = (pict->common.repeat == PIXMAN_REPEAT_NORMAL) ? MOD (y, pict->height) : y;
-			for (x = x1; x < x2; x++) {
-			    if (*p) {
-				int tx = (pict->common.repeat == PIXMAN_REPEAT_NORMAL) ? MOD (x, pict->width) : x;
-				if (pixman_region_contains_point (pict->common.src_clip, tx, ty, &box)) {
-				    uint32_t c = fetch(pict, tx, ty);
-
-				    srtot += Red(c) * *p;
-				    sgtot += Green(c) * *p;
-				    sbtot += Blue(c) * *p;
-				    satot += Alpha(c) * *p;
-				}
-			    }
-			    p++;
-			}
-		    }
-
-		    satot >>= 16;
-		    srtot >>= 16;
-		    sgtot >>= 16;
-		    sbtot >>= 16;
-
-		    if (satot < 0) satot = 0; else if (satot > 0xff) satot = 0xff;
-		    if (srtot < 0) srtot = 0; else if (srtot > 0xff) srtot = 0xff;
-		    if (sgtot < 0) sgtot = 0; else if (sgtot > 0xff) sgtot = 0xff;
-		    if (sbtot < 0) sbtot = 0; else if (sbtot > 0xff) sbtot = 0xff;
-
-		    *(buffer + i) = ((satot << 24) |
-				     (srtot << 16) |
-				     (sgtot <<  8) |
-				     (sbtot       ));
-		}
-	    }
-            v.vector[0] += unit.vector[0];
-            v.vector[1] += unit.vector[1];
-            v.vector[2] += unit.vector[2];
+        else
+        {
+            fbFetchTransformed_Bilinear_General(pict, width, buffer, mask, maskBits, affine, v, unit);
         }
     }
+    else if (pict->common.filter == PIXMAN_FILTER_CONVOLUTION)
+    {
+        fbFetchTransformed_Convolution(pict, width, buffer, mask, maskBits, affine, v, unit);
+    }
 
     fbFinishAccess (pict->pDrawable);
 }
 
 
-static void fbFetchExternalAlpha(bits_image_t * pict, int x, int y, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits)
+static void
+fbFetchExternalAlpha(bits_image_t * pict, int x, int y, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits)
 {
     int i;
     uint32_t _alpha_buffer[SCANLINE_BUFFER_LENGTH];
     uint32_t *alpha_buffer = _alpha_buffer;
 
     if (!pict->common.alpha_map) {
         fbFetchTransformed (pict, x, y, width, buffer, mask, maskBits);
 	return;
@@ -4186,31 +4291,33 @@ static void fbFetchExternalAlpha(bits_im
 		| (div_255(Blue(*(buffer + i)) * a));
 	}
     }
 
     if (alpha_buffer != _alpha_buffer)
         free(alpha_buffer);
 }
 
-static void fbStore(bits_image_t * pict, int x, int y, int width, uint32_t *buffer)
+static void
+fbStore(bits_image_t * pict, int x, int y, int width, uint32_t *buffer)
 {
     uint32_t *bits;
     int32_t stride;
     storeProc store = storeProcForPicture(pict);
     const pixman_indexed_t * indexed = pict->indexed;
 
     bits = pict->bits;
     stride = pict->rowstride;
     bits += y*stride;
     store((pixman_image_t *)pict, bits, buffer, x, width, indexed);
     fbFinishAccess (pict->pDrawable);
 }
 
-static void fbStoreExternalAlpha(bits_image_t * pict, int x, int y, int width, uint32_t *buffer)
+static void
+fbStoreExternalAlpha(bits_image_t * pict, int x, int y, int width, uint32_t *buffer)
 {
     uint32_t *bits, *alpha_bits;
     int32_t stride, astride;
     int ax, ay;
     storeProc store;
     storeProc astore;
     const pixman_indexed_t * indexed = pict->indexed;
     const pixman_indexed_t * aindexed;
@@ -4279,17 +4386,17 @@ PIXMAN_COMPOSITE_RECT_GENERAL (const FbC
     else
     {
 	bits_image_t *bits = (bits_image_t *)data->src;
 
 	if (bits->common.alpha_map)
 	{
 	    fetchSrc = (scanFetchProc)fbFetchExternalAlpha;
 	}
-	else if (bits->common.repeat == PIXMAN_REPEAT_NORMAL &&
+	else if ((bits->common.repeat == PIXMAN_REPEAT_NORMAL || bits->common.repeat == PIXMAN_REPEAT_PAD) &&
 		 bits->width == 1 &&
 		 bits->height == 1)
 	{
 	    fetchSrc = (scanFetchProc)fbFetchSolid;
 	    srcClass = SOURCE_IMAGE_CLASS_HORIZONTAL;
 	}
 	else if (!bits->common.transform && bits->common.filter != PIXMAN_FILTER_CONVOLUTION)
 	{
@@ -4317,17 +4424,17 @@ PIXMAN_COMPOSITE_RECT_GENERAL (const FbC
 	else
 	{
 	    bits_image_t *bits = (bits_image_t *)data->mask;
 
 	    if (bits->common.alpha_map)
 	    {
 		fetchMask = (scanFetchProc)fbFetchExternalAlpha;
 	    }
-	    else if (bits->common.repeat == PIXMAN_REPEAT_NORMAL &&
+	    else if ((bits->common.repeat == PIXMAN_REPEAT_NORMAL || bits->common.repeat == PIXMAN_REPEAT_PAD) &&
 		     bits->width == 1 && bits->height == 1)
 	    {
 		fetchMask = (scanFetchProc)fbFetchSolid;
 		maskClass = SOURCE_IMAGE_CLASS_HORIZONTAL;
 	    }
 	    else if (!bits->common.transform && bits->common.filter != PIXMAN_FILTER_CONVOLUTION)
 		fetchMask = (scanFetchProc)fbFetch;
 	    else
--- a/gfx/cairo/libpixman/src/pixman-private.h
+++ b/gfx/cairo/libpixman/src/pixman-private.h
@@ -597,16 +597,18 @@ union pixman_image
 
 #define div_255(x) (((x) + 0x80 + (((x) + 0x80) >> 8)) >> 8)
 
 #define MOD(a,b) ((a) < 0 ? ((b) - ((-(a) - 1) % (b))) - 1 : (a) % (b))
 
 #define DIV(a,b) ((((a) < 0) == ((b) < 0)) ? (a) / (b) :		\
 		  ((a) - (b) + 1 - (((b) < 0) << 1)) / (b))
 
+#define CLIP(a,b,c) ((a) < (b) ? (b) : ((a) > (c) ? (c) : (a)))
+
 #if 0
 /* FIXME: the MOD macro above is equivalent, but faster I think */
 #define mod(a,b) ((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
 #endif
 
 /* FIXME: the (void)__read_func hides lots of warnings (which is what they
  * are supposed to do), but some of them are real. For example the one
  * where Fetch4 doesn't have a READ