[cairo-commit] 14 commits - src/cairo-analysis-surface.c src/cairoint.h src/cairo-paginated-private.h src/cairo-paginated-surface.c src/cairo-pattern.c src/cairo-pdf-operators.c src/cairo-pdf-operators-private.h src/cairo-pdf-surface.c src/cairo-pdf-surface-private.h src/cairo-surface.c src/cairo-types-private.h src/Makefile.am

Adrian Johnson ajohnson at kemper.freedesktop.org
Mon Jan 7 03:11:43 PST 2008


 src/Makefile.am                   |    1 
 src/cairo-analysis-surface.c      |   11 
 src/cairo-paginated-private.h     |   22 
 src/cairo-paginated-surface.c     |    4 
 src/cairo-pattern.c               |   28 
 src/cairo-pdf-operators-private.h |  106 +
 src/cairo-pdf-operators.c         |  531 +++++++++
 src/cairo-pdf-surface-private.h   |   69 -
 src/cairo-pdf-surface.c           | 2214 ++++++++++++++------------------------
 src/cairo-surface.c               |   84 -
 src/cairo-types-private.h         |    3 
 src/cairoint.h                    |    4 
 12 files changed, 1601 insertions(+), 1476 deletions(-)

New commits:
commit 25f24e79f84e0c04a8c6944cc6e018e9eb2df997
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Jan 7 21:19:35 2008 +1030

    PDF: Update the PDF page structure comment

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 614d655..40edb22 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -88,37 +88,6 @@
  * that fallback images do not composite with any content under the
  * fallback images.
  *
- * The group containing the supported operations (content_group_list
- * in the example below) does not do any drawing directly. Instead it
- * paints groups containing the drawing operations and performs
- * clipping. The reason for this is that clipping operations performed
- * in a group do not affect the parent group.
- *
- * Example PDF Page Structure:
- *
- *   Page Content
- *   ------------
- *     /knockout_group Do
- *
- *   knockout_group
- *   --------------
- *     /content_group_list Do
- *     /fallback_image_1 Do
- *     /fallback_image_2 Do
- *     ...
- *
- *   content_group_list
- *   ------------------
- *     q
- *     /content_group_1 Do
- *     /content_group_2 Do
- *     10 10 m 10 20 l 20 20 l 20 10 l h W  # clip
- *     /content_group_3 Do
- *     Q q                                  # reset clip
- *     /content_group_4 Do
- *     Q
- *
- *
  * Streams:
  *
  * This PDF surface has three types of streams:
@@ -139,42 +108,21 @@
  *
  * Content Stream:
  *   The Content Stream is opened and closed with the following functions:
- *     _cairo_pdf_surface_start_content_stream ()
- *     _cairo_pdf_surface_stop_content_stream ()
- *
- *   The Content Stream is written to content_group_n groups (as shown
- *   in the page structure example). The Content Stream may be paused
- *   and resumed with the following functions:
- *     _cairo_pdf_surface_pause_content_stream ()
- *     _cairo_pdf_surface_resume_content_stream ()
- *
- *   When the Content Stream is paused, a PDF Stream or Group Stream
- *   may be opened. After closing the PDF Stream or Group Stream the
- *   Content Stream may be resumed.
+ *     _cairo_pdf_surface_open_content_stream ()
+ *     _cairo_pdf_surface_close_content_stream ()
  *
- *   The Content Stream contains the text and graphics operators. When
- *   a pattern is required the Content Stream is paused, a PDF Stream
- *   is opened, the pattern is written to a PDF Stream, the PDF Stream
- *   is closed, then the Content Stream is resumed.
- *
- *   Each group comprising the Content Stream is stored in memory
- *   until the stream is closed or the maximum group size is
- *   exceeded. This is due to the need to list all resources used in
- *   the group in the group's stream dictionary.
+ *   The Content Stream contains the text and graphics operators.
  *
  * Group Stream:
  *   A Group Stream may be opened and closed with the following functions:
  *     _cairo_pdf_surface_open_group ()
  *     _cairo_pdf_surface_close_group ()
  *
- *   A Group Stream is written to a separate group in the PDF file
- *   that is not part of the Content Stream. Group Streams are also
- *   stored in memory until the stream is closed due to the need to
- *   list the resources used in the group in the group's stream
- *   dictionary.
- *
- *   Group Streams are used for short sequences of graphics operations
- *   that need to be in a separate group from the Content Stream.
+ *   A Group Stream is a Form XObject. It is used for short sequences
+ *   of operators. As the content is very short the group is stored in
+ *   memory until it is closed. This allows some optimization such as
+ *   including the Resource dictionary and stream length inside the
+ *   XObject instead of using an indirect object.
  */
 
 typedef struct _cairo_pdf_object {
commit 21f842f0dfd5dd3cc1fd3b56db034fc4e209adaa
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Jan 7 21:17:26 2008 +1030

    PDF: Remove copy_page
    
    Now that the content stream is no longer split into multiple streams
    it is not possible to implement a copy_page function that shares the
    common content between pages.
    
    Remove this function so the paginated surface will rewrite the
    content from the meta surface.

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index c018764..614d655 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -2687,19 +2687,6 @@ _cairo_pdf_surface_unselect_pattern (cairo_pdf_surface_t *surface)
 }
 
 static cairo_int_status_t
-_cairo_pdf_surface_copy_page (void *abstract_surface)
-{
-    cairo_pdf_surface_t *surface = abstract_surface;
-    cairo_int_status_t status;
-
-    status = _cairo_pdf_surface_close_content_stream (surface);
-    if (status)
-	return status;
-
-    return _cairo_pdf_surface_write_page (surface);
-}
-
-static cairo_int_status_t
 _cairo_pdf_surface_show_page (void *abstract_surface)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
@@ -4577,7 +4564,7 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
-    _cairo_pdf_surface_copy_page,
+    NULL,  /* _cairo_pdf_surface_copy_page */
     _cairo_pdf_surface_show_page,
     NULL, /* set_clip_region */
     _cairo_pdf_surface_intersect_clip_path,
commit e2adb921f8b7619410db971d1524cbeab2dd6102
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Jan 7 21:15:18 2008 +1030

    PDF: Put each fallback image in a separate group
    
    Each fallback image needs to be in a separate group in the knockout
    group. Otherwise transparent edges of adjacent fallback images will
    composite with each other creating visible seams between the images.

diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index 5e6ac82..233b01d 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -110,6 +110,7 @@ struct _cairo_pdf_surface {
     cairo_array_t alpha_linear_functions;
     cairo_array_t patterns;
     cairo_array_t smask_groups;
+    cairo_array_t knockout_group;
 
     cairo_scaled_font_subsets_t *font_subsets;
     cairo_array_t fonts;
@@ -120,7 +121,6 @@ struct _cairo_pdf_surface {
     cairo_bool_t compress_content;
 
     cairo_pdf_resource_t content;
-    cairo_pdf_resource_t fallback_content;
     cairo_pdf_resource_t content_resources;
     cairo_pdf_group_resources_t resources;
     cairo_bool_t has_fallback_images;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index a4243d0..c018764 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -311,6 +311,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
     _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
     _cairo_array_init (&surface->patterns, sizeof (cairo_pdf_pattern_t));
     _cairo_array_init (&surface->smask_groups, sizeof (cairo_pdf_smask_group_t *));
+    _cairo_array_init (&surface->knockout_group, sizeof (cairo_pdf_resource_t));
 
     _cairo_pdf_group_resources_init (&surface->resources);
 
@@ -540,6 +541,7 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
 	_cairo_pdf_smask_group_destroy (group);
     }
     _cairo_array_truncate (&surface->smask_groups, 0);
+    _cairo_array_truncate (&surface->knockout_group, 0);
 }
 
 static void
@@ -1250,6 +1252,7 @@ _cairo_pdf_surface_finish (void *abstract_surface)
     _cairo_array_fini (&surface->patterns);
     _cairo_array_fini (&surface->smask_groups);
     _cairo_array_fini (&surface->fonts);
+    _cairo_array_fini (&surface->knockout_group);
 
     if (surface->font_subsets) {
 	_cairo_scaled_font_subsets_destroy (surface->font_subsets);
@@ -4005,8 +4008,9 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface
 static cairo_status_t
 _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
 {
-    cairo_pdf_resource_t page, knockout;
+    cairo_pdf_resource_t page, knockout, res;
     cairo_status_t status;
+    int i, len;
 
     _cairo_pdf_group_resources_clear (&surface->resources);
     if (surface->has_fallback_images) {
@@ -4014,13 +4018,19 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
 	if (status)
 	    return status;
 
+	len = _cairo_array_num_elements (&surface->knockout_group);
+	for (i = 0; i < len; i++) {
+	    _cairo_array_copy_element (&surface->knockout_group, i, &res);
+	    _cairo_output_stream_printf (surface->output,
+					 "/x%d Do\r\n",
+					 res.id);
+	    _cairo_pdf_surface_add_xobject (surface, res);
+	}
 	_cairo_output_stream_printf (surface->output,
-				     "/x%d Do\r\n"
 				     "/x%d Do\r\n",
-				     surface->content.id,
-				     surface->fallback_content.id);
+				     surface->content.id);
 	_cairo_pdf_surface_add_xobject (surface, surface->content);
-	_cairo_pdf_surface_add_xobject (surface, surface->fallback_content);
+
 	status = _cairo_pdf_surface_close_group (surface, &knockout);
 	if (status)
 	    return status;
@@ -4204,10 +4214,14 @@ _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
     if (status)
 	return status;
 
+    status = _cairo_array_append (&surface->knockout_group, &surface->content);
+    if (status)
+	return status;
+
     surface->has_fallback_images = TRUE;
     _cairo_pdf_group_resources_clear (&surface->resources);
     return _cairo_pdf_surface_open_content_stream (surface,
-						   &surface->fallback_content,
+						   &surface->content,
 						   TRUE);
 }
 
commit d6a84302a07d2b7e67584029fdb7a882ad246a09
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Jan 7 21:11:46 2008 +1030

    Fix analysis of transformed meta surfaces

diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index b6f09f8..29b74f3 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -70,7 +70,7 @@ _cairo_analysis_surface_analyze_meta_surface_pattern (cairo_analysis_surface_t *
     cairo_surface_pattern_t *surface_pattern;
     cairo_status_t status;
     cairo_bool_t old_has_ctm;
-    cairo_matrix_t old_ctm;
+    cairo_matrix_t old_ctm, p2d;
 
     assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
     surface_pattern = (cairo_surface_pattern_t *) pattern;
@@ -78,7 +78,12 @@ _cairo_analysis_surface_analyze_meta_surface_pattern (cairo_analysis_surface_t *
 
     old_ctm = surface->ctm;
     old_has_ctm = surface->has_ctm;
-    cairo_matrix_multiply (&surface->ctm, &pattern->matrix, &surface->ctm);
+    p2d = pattern->matrix;
+    status = cairo_matrix_invert (&p2d);
+    /* _cairo_pattern_set_matrix guarantees invertibility */
+    assert (status == CAIRO_STATUS_SUCCESS);
+
+    cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm);
     surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
 
     status = _cairo_meta_surface_replay_and_create_regions (surface_pattern->surface,
@@ -114,7 +119,7 @@ _cairo_analysis_surface_add_operation  (cairo_analysis_surface_t *surface,
 					      &x1, &y1, &x2, &y2,
 					      NULL);
 	rect->x = floor (x1);
-	rect->y = floor (x2);
+	rect->y = floor (y1);
 
 	x2 = ceil (x2) - rect->x;
 	y2 = ceil (y2) - rect->y;
commit 3c725d50db43b848b4ad8f35bcabd5b1d0395924
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Jan 7 21:09:04 2008 +1030

    PDF: Make _SOURCE operator work inside meta surface patterns

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index a99267c..a4243d0 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1595,6 +1595,7 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
 {
     double old_width, old_height;
     cairo_matrix_t old_cairo_to_pdf;
+    cairo_paginated_mode_t old_paginated_mode;
     cairo_rectangle_int16_t meta_extents;
     cairo_status_t status;
     int alpha = 0;
@@ -1606,8 +1607,14 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
     old_width = surface->width;
     old_height = surface->height;
     old_cairo_to_pdf = surface->cairo_to_pdf;
+    old_paginated_mode = surface->paginated_mode;
     surface->width = meta_extents.width;
     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);
@@ -1641,6 +1648,7 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *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);
@@ -4157,15 +4165,17 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t  *surface,
     if (! _pattern_supported (pattern))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    if (op == CAIRO_OPERATOR_OVER) {
+    if (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_SOURCE) {
 	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;
+		return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
 	}
-	return CAIRO_STATUS_SUCCESS;
     }
 
+    if (op == CAIRO_OPERATOR_OVER)
+	return CAIRO_STATUS_SUCCESS;
+
     /* The SOURCE operator is only if there is nothing painted
      * underneath. */
     if (op == CAIRO_OPERATOR_SOURCE)
commit 6d6b74ac4ce3a9bcab45c338fc31e5a83823cde6
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Jan 7 21:08:09 2008 +1030

    PDF: Support _OPERATOR_SOURCE when nothing under the operation
    
    CAIRO_OPERATOR_SOURCE operations on the PDF backend are now natively
    supported when there is nothing already underneath the operation.

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index c437ce4..a99267c 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -4166,10 +4166,10 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t  *surface,
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    /* The SOURCE operator is only supported for the fallback images. */
-    if (op == CAIRO_OPERATOR_SOURCE &&
-	surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK)
-	return CAIRO_STATUS_SUCCESS;
+    /* The SOURCE operator is only if there is nothing painted
+     * underneath. */
+    if (op == CAIRO_OPERATOR_SOURCE)
+	return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
 
     return CAIRO_INT_STATUS_UNSUPPORTED;
 }
@@ -4186,27 +4186,19 @@ _cairo_pdf_surface_operation_supported (cairo_pdf_surface_t  *surface,
 }
 
 static cairo_int_status_t
-_cairo_pdf_surface_set_operator (cairo_pdf_surface_t *surface,
-				 cairo_operator_t op)
+_cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
 {
     cairo_status_t status;
 
-    if (op == CAIRO_OPERATOR_OVER)
-	return CAIRO_STATUS_SUCCESS;
-
-    if (op == CAIRO_OPERATOR_SOURCE) {
-	status = _cairo_pdf_surface_close_content_stream (surface);
-	if (status)
-	    return status;
-
-	surface->has_fallback_images = TRUE;
-	_cairo_pdf_group_resources_clear (&surface->resources);
-	return _cairo_pdf_surface_open_content_stream (surface,
-						       &surface->fallback_content,
-						       TRUE);
-    }
+    status = _cairo_pdf_surface_close_content_stream (surface);
+    if (status)
+	return status;
 
-    return CAIRO_INT_STATUS_UNSUPPORTED;
+    surface->has_fallback_images = TRUE;
+    _cairo_pdf_group_resources_clear (&surface->resources);
+    return _cairo_pdf_surface_open_content_stream (surface,
+						   &surface->fallback_content,
+						   TRUE);
 }
 
 static cairo_int_status_t
@@ -4219,15 +4211,16 @@ _cairo_pdf_surface_paint (void			*abstract_surface,
     cairo_pdf_smask_group_t *group;
     cairo_pdf_resource_t pattern_res, gstate_res;
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
 	return _cairo_pdf_surface_analyze_operation (surface, op, source);
+    } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
+	status = _cairo_pdf_surface_start_fallback (surface);
+	if (status)
+	    return status;
+    }
 
     assert (_cairo_pdf_surface_operation_supported (surface, op, source));
 
-    status = _cairo_pdf_surface_set_operator (surface, op);
-    if (status)
-	return status;
-
     pattern_res.id = 0;
     gstate_res.id = 0;
     status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res);
@@ -4291,15 +4284,15 @@ _cairo_pdf_surface_mask	(void			*abstract_surface,
 	    return status2;
 
 	return status;
+    } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
+	status = _cairo_pdf_surface_start_fallback (surface);
+	if (status)
+	    return status;
     }
 
     assert (_cairo_pdf_surface_operation_supported (surface, op, source));
     assert (_cairo_pdf_surface_operation_supported (surface, op, mask));
 
-    status = _cairo_pdf_surface_set_operator (surface, op);
-    if (status)
-	return status;
-
     group = _cairo_pdf_surface_create_smask_group (surface);
     if (group == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
@@ -4414,15 +4407,16 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
     cairo_pdf_smask_group_t *group;
     cairo_pdf_resource_t pattern_res, gstate_res;
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
 	return _cairo_pdf_surface_analyze_operation (surface, op, source);
+    } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
+	status = _cairo_pdf_surface_start_fallback (surface);
+	if (status)
+	    return status;
+    }
 
     assert (_cairo_pdf_surface_operation_supported (surface, op, source));
 
-    status = _cairo_pdf_surface_set_operator (surface, op);
-    if (status)
-	return status;
-
     pattern_res.id = 0;
     gstate_res.id = 0;
     status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res);
commit e195cb551caa40f309127ac7a39e4a17653966c8
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Jan 7 21:05:36 2008 +1030

    Add FALLBACK mode to paginated surface
    
    The PDF surface needs to know when the fallback images start so it can
    close off the content stream and create a knockout transparency group
    for the fallback images. Currently it does this by looking for
    operations with CAIRO_OPERATOR_SOURCE. PDF returns unsupported for
    _SOURCE during the analysis phase so _SOURCE will never appear during
    native operations. However this prevents the PDF surface from
    supporting _SOURCE operations that can be natively supported. For
    example a _SOURCE operation with nothing painting under it can be
    converted to _OVER and natively supported.
    
    A third mode, CAIRO_PAGINATED_MODE_FALLBACK, has been added. The
    paginated surface will set this mode before it paints finer-grained
    fallback images.

diff --git a/src/cairo-paginated-private.h b/src/cairo-paginated-private.h
index 1ecb014..7b41191 100644
--- a/src/cairo-paginated-private.h
+++ b/src/cairo-paginated-private.h
@@ -110,18 +110,22 @@ struct _cairo_paginated_surface_backend {
  *
  * 6. Replays a subset of the meta-surface operations to the target surface
  *
- * 7. Replays the remaining operations to an image surface, sets an
+ * 7. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_FALLBACK
+ *
+ * 8. Replays the remaining operations to an image surface, sets an
  *    appropriate clip on the target, then paints the resulting image
  *    surface to the target.
  *
- * So, the target will see drawing operations during two separate
- * stages, (ANALYZE and RENDER). During the ANALYZE phase the target
- * should not actually perform any rendering, (for example, if
- * performing output to a file, no output should be generated during
- * this stage). Instead the drawing functions simply need to return
- * CAIRO_STATUS_SUCCESS or CAIRO_INT_STATUS_UNSUPPORTED to indicate
- * whether rendering would be supported. And it should do this as
- * quickly as possible.
+ * So, the target will see drawing operations during three separate
+ * stages, (ANALYZE, RENDER and FALLBACK). During the ANALYZE phase
+ * the target should not actually perform any rendering, (for example,
+ * if performing output to a file, no output should be generated
+ * during this stage). Instead the drawing functions simply need to
+ * return CAIRO_STATUS_SUCCESS or CAIRO_INT_STATUS_UNSUPPORTED to
+ * indicate whether rendering would be supported. And it should do
+ * this as quickly as possible. The FALLBACK phase allows the surface
+ * to distinguish fallback images from native rendering in case they
+ * need to be handled as a special case.
  *
  * NOTE: The paginated surface layer assumes that the target surface
  * is "blank" by default at the beginning of each page, without any
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 068a60c..d644d87 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -365,7 +365,9 @@ _paint_page (cairo_paginated_surface_t *surface)
         cairo_box_int_t *boxes;
         int num_boxes, i;
 
-	/* Reset clip region before drawing the fall back images */
+	surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_FALLBACK);
+
+    /* Reset clip region before drawing the fall back images */
 	status = _cairo_surface_intersect_clip_path (surface->target,
 						     NULL,
 						     CAIRO_FILL_RULE_WINDING,
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index dae9e94..c437ce4 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -4168,7 +4168,7 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t  *surface,
 
     /* The SOURCE operator is only supported for the fallback images. */
     if (op == CAIRO_OPERATOR_SOURCE &&
-	surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER)
+	surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK)
 	return CAIRO_STATUS_SUCCESS;
 
     return CAIRO_INT_STATUS_UNSUPPORTED;
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index a7af712..3954f13 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -123,7 +123,8 @@ struct _cairo_cache {
 
 typedef enum _cairo_paginated_mode {
     CAIRO_PAGINATED_MODE_ANALYZE,	/* analyze page regions */
-    CAIRO_PAGINATED_MODE_RENDER		/* render page contents */
+    CAIRO_PAGINATED_MODE_RENDER,	/* render page contents */
+    CAIRO_PAGINATED_MODE_FALLBACK 	/* paint fallback images */
 } cairo_paginated_mode_t;
 
 /* Sure wish C had a real enum type so that this would be distinct
commit d2a5d1ace64cb9efabcb065e7fc28667dd8f779d
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Jan 7 21:04:06 2008 +1030

    PDF: Remove the remaining code for splitting the content
    
    across multiple streams. This fixes the problem reported here
    
    http://lists.cairographics.org/archives/cairo/2007-December/012197.html

diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index 7012155..5e6ac82 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -108,8 +108,6 @@ struct _cairo_pdf_surface {
     cairo_array_t pages;
     cairo_array_t rgb_linear_functions;
     cairo_array_t alpha_linear_functions;
-    cairo_array_t knockout_group;
-    cairo_array_t content_group;
     cairo_array_t patterns;
     cairo_array_t smask_groups;
 
@@ -121,6 +119,12 @@ struct _cairo_pdf_surface {
 
     cairo_bool_t compress_content;
 
+    cairo_pdf_resource_t content;
+    cairo_pdf_resource_t fallback_content;
+    cairo_pdf_resource_t content_resources;
+    cairo_pdf_group_resources_t resources;
+    cairo_bool_t has_fallback_images;
+
     struct {
 	cairo_bool_t active;
 	cairo_pdf_resource_t self;
@@ -136,21 +140,9 @@ struct _cairo_pdf_surface {
 	cairo_output_stream_t *mem_stream;
 	cairo_output_stream_t *old_output;
 	cairo_pdf_resource_t   resource;
-	cairo_pdf_group_resources_t resources;
 	cairo_bool_t is_knockout;
-	cairo_pdf_resource_t first_object;
     } group_stream;
 
-    struct {
-	cairo_bool_t active;
-	cairo_output_stream_t *stream;
-	cairo_output_stream_t *mem_stream;
-	cairo_output_stream_t *old_output;
-	cairo_pdf_group_resources_t resources;
-    } content_stream;
-
-    cairo_array_t *current_group;
-    cairo_pdf_group_resources_t *current_resources;
     cairo_pdf_operators_t pdf_operators;
     cairo_paginated_mode_t paginated_mode;
 
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 0722cc5..dae9e94 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -131,7 +131,7 @@
  *
  * PDF Stream:
  *   A PDF Stream may be opened and closed with the following functions:
- *     _cairo_pdf_surface_open_stream ()
+ *     _cairo_pdf_surface_open stream ()
  *     _cairo_pdf_surface_close_stream ()
  *
  *   PDF Streams are written directly to the PDF file. They are used for
@@ -177,11 +177,6 @@
  *   that need to be in a separate group from the Content Stream.
  */
 
-/* The group stream length is checked after each operation. When this
- * limit is exceeded the group is written out to the pdf stream and a
- * new group is created. */
-#define GROUP_STREAM_LIMIT 65536
-
 typedef struct _cairo_pdf_object {
     long offset;
 } cairo_pdf_object_t;
@@ -204,17 +199,6 @@ typedef struct _cairo_pdf_alpha_linear_function {
     double               alpha2;
 } cairo_pdf_alpha_linear_function_t;
 
-typedef enum group_element_type {
-    ELEM_GROUP,
-    ELEM_CLIP
-} group_element_type_t;
-
-typedef struct _cairo_pdf_group_element {
-    group_element_type_t  type;
-    cairo_pdf_resource_t  group;
-} cairo_pdf_group_element_t;
-
-
 static cairo_pdf_resource_t
 _cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface);
 
@@ -325,13 +309,10 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
     _cairo_array_init (&surface->rgb_linear_functions, sizeof (cairo_pdf_rgb_linear_function_t));
     _cairo_array_init (&surface->alpha_linear_functions, sizeof (cairo_pdf_alpha_linear_function_t));
     _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
-    _cairo_array_init (&surface->knockout_group, sizeof (cairo_pdf_group_element_t));
-    _cairo_array_init (&surface->content_group, sizeof (cairo_pdf_group_element_t));
     _cairo_array_init (&surface->patterns, sizeof (cairo_pdf_pattern_t));
     _cairo_array_init (&surface->smask_groups, sizeof (cairo_pdf_smask_group_t *));
 
-    _cairo_pdf_group_resources_init (&surface->group_stream.resources);
-    _cairo_pdf_group_resources_init (&surface->content_stream.resources);
+    _cairo_pdf_group_resources_init (&surface->resources);
 
     surface->font_subsets = _cairo_scaled_font_subsets_create_composite ();
     if (! surface->font_subsets) {
@@ -347,16 +328,10 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
     surface->compress_content = TRUE;
     surface->pdf_stream.active = FALSE;
     surface->pdf_stream.old_output = NULL;
-    surface->content_stream.active = FALSE;
-    surface->content_stream.stream = NULL;
-    surface->content_stream.mem_stream = NULL;
     surface->group_stream.active = FALSE;
     surface->group_stream.stream = NULL;
     surface->group_stream.mem_stream = NULL;
 
-    surface->current_group = NULL;
-    surface->current_resources = NULL;
-
     surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
 
     surface->force_fallbacks = FALSE;
@@ -552,11 +527,6 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
     cairo_pdf_pattern_t *pattern;
     cairo_pdf_smask_group_t *group;
 
-    _cairo_array_truncate (&surface->content_group, 0);
-    _cairo_array_truncate (&surface->knockout_group, 0);
-    _cairo_array_truncate (&surface->content_group, 0);
-    _cairo_array_truncate (&surface->knockout_group, 0);
-
     size = _cairo_array_num_elements (&surface->patterns);
     for (i = 0; i < size; i++) {
 	pattern = (cairo_pdf_pattern_t *) _cairo_array_index (&surface->patterns, i);
@@ -610,7 +580,7 @@ _cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface,
     int num_alphas, i;
     double other;
     cairo_status_t status;
-    cairo_pdf_group_resources_t *res = surface->current_resources;
+    cairo_pdf_group_resources_t *res = &surface->resources;
 
     num_alphas = _cairo_array_num_elements (&res->alphas);
     for (i = 0; i < num_alphas; i++) {
@@ -634,21 +604,21 @@ static cairo_status_t
 _cairo_pdf_surface_add_smask (cairo_pdf_surface_t  *surface,
 			      cairo_pdf_resource_t  smask)
 {
-    return _cairo_array_append (&surface->current_resources->smasks, &smask);
+    return _cairo_array_append (&(surface->resources.smasks), &smask);
 }
 
 static cairo_status_t
 _cairo_pdf_surface_add_pattern (cairo_pdf_surface_t  *surface,
 				cairo_pdf_resource_t  pattern)
 {
-    return _cairo_array_append (&surface->current_resources->patterns, &pattern);
+    return _cairo_array_append (&(surface->resources.patterns), &pattern);
 }
 
 static cairo_status_t
 _cairo_pdf_surface_add_xobject (cairo_pdf_surface_t  *surface,
 				cairo_pdf_resource_t  xobject)
 {
-    return _cairo_array_append (&surface->current_resources->xobjects, &xobject);
+    return _cairo_array_append (&(surface->resources.xobjects), &xobject);
 }
 
 static cairo_status_t
@@ -660,7 +630,7 @@ _cairo_pdf_surface_add_font (unsigned int        font_id,
     cairo_pdf_font_t font;
     int num_fonts, i;
     cairo_status_t status;
-    cairo_pdf_group_resources_t *res = surface->current_resources;
+    cairo_pdf_group_resources_t *res = &surface->resources;
 
     num_fonts = _cairo_array_num_elements (&res->fonts);
     for (i = 0; i < num_fonts; i++) {
@@ -720,36 +690,36 @@ _cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t         *surface,
     cairo_pdf_resource_t *smask, *pattern, *xobject;
     cairo_pdf_font_t *font;
 
-    _cairo_output_stream_printf (surface->output, "   /Resources <<\r\n");
+    _cairo_output_stream_printf (surface->output, "<<\r\n");
 
     num_alphas = _cairo_array_num_elements (&res->alphas);
     num_smasks = _cairo_array_num_elements (&res->smasks);
     if (num_alphas > 0 || num_smasks > 0) {
 	_cairo_output_stream_printf (surface->output,
-				     "      /ExtGState <<\r\n");
+				     "   /ExtGState <<\r\n");
 
 	for (i = 0; i < num_alphas; i++) {
 	    _cairo_array_copy_element (&res->alphas, i, &alpha);
 	    _cairo_output_stream_printf (surface->output,
-					 "         /a%d << /CA %f /ca %f >>\r\n",
+					 "      /a%d << /CA %f /ca %f >>\r\n",
 					 i, alpha, alpha);
 	}
 
 	for (i = 0; i < num_smasks; i++) {
 	    smask = _cairo_array_index (&res->smasks, i);
 	    _cairo_output_stream_printf (surface->output,
-					 "         /s%d %d 0 R\r\n",
+					 "      /s%d %d 0 R\r\n",
 					 smask->id, smask->id);
 	}
 
 	_cairo_output_stream_printf (surface->output,
-				     "      >>\r\n");
+				     "   >>\r\n");
     }
 
     num_resources = _cairo_array_num_elements (&res->patterns);
     if (num_resources > 0) {
 	_cairo_output_stream_printf (surface->output,
-				     "      /Pattern <<");
+				     "   /Pattern <<");
 	for (i = 0; i < num_resources; i++) {
 	    pattern = _cairo_array_index (&res->patterns, i);
 	    _cairo_output_stream_printf (surface->output,
@@ -764,7 +734,7 @@ _cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t         *surface,
     num_resources = _cairo_array_num_elements (&res->xobjects);
     if (num_resources > 0) {
 	_cairo_output_stream_printf (surface->output,
-				     "      /XObject <<");
+				     "   /XObject <<");
 
 	for (i = 0; i < num_resources; i++) {
 	    xobject = _cairo_array_index (&res->xobjects, i);
@@ -779,20 +749,20 @@ _cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t         *surface,
 
     num_resources = _cairo_array_num_elements (&res->fonts);
     if (num_resources > 0) {
-	_cairo_output_stream_printf (surface->output,"      /Font <<\r\n");
+	_cairo_output_stream_printf (surface->output,"   /Font <<\r\n");
 	for (i = 0; i < num_resources; i++) {
 	    font = _cairo_array_index (&res->fonts, i);
 	    _cairo_output_stream_printf (surface->output,
-					 "         /f-%d-%d %d 0 R\r\n",
+					 "      /f-%d-%d %d 0 R\r\n",
 					 font->font_id,
 					 font->subset_id,
 					 font->subset_resource.id);
 	}
-	_cairo_output_stream_printf (surface->output, "      >>\r\n");
+	_cairo_output_stream_printf (surface->output, "   >>\r\n");
     }
 
     _cairo_output_stream_printf (surface->output,
-				 "   >>\r\n");
+				 ">>\r\n");
 }
 
 static cairo_pdf_smask_group_t *
@@ -1024,11 +994,12 @@ _cairo_pdf_surface_write_memory_stream (cairo_pdf_surface_t         *surface,
 				 surface->height);
 
     if (is_knockout_group)
-	_cairo_output_stream_printf (surface->output,
-				     "      /K true\r\n");
+        _cairo_output_stream_printf (surface->output,
+                                     "      /K true\r\n");
 
     _cairo_output_stream_printf (surface->output,
-				 "   >>\r\n");
+				 "   >>\r\n"
+				 "   /Resources\r\n");
     _cairo_pdf_surface_emit_group_resources (surface, resources);
     _cairo_output_stream_printf (surface->output,
 				 ">>\r\n"
@@ -1046,7 +1017,6 @@ _cairo_pdf_surface_open_group (cairo_pdf_surface_t  *surface,
     cairo_status_t status;
 
     assert (surface->pdf_stream.active == FALSE);
-    assert (surface->content_stream.active == FALSE);
     assert (surface->group_stream.active == FALSE);
 
     surface->group_stream.active = TRUE;
@@ -1064,9 +1034,7 @@ _cairo_pdf_surface_open_group (cairo_pdf_surface_t  *surface,
     surface->group_stream.old_output = surface->output;
     surface->output = surface->group_stream.stream;
     _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
-    _cairo_pdf_group_resources_clear (&surface->group_stream.resources);
-    surface->current_resources = &surface->group_stream.resources;
-    surface->group_stream.is_knockout = FALSE;
+    _cairo_pdf_group_resources_clear (&surface->resources);
 
     if (resource) {
 	surface->group_stream.resource = *resource;
@@ -1075,13 +1043,13 @@ _cairo_pdf_surface_open_group (cairo_pdf_surface_t  *surface,
 	if (surface->group_stream.resource.id == 0)
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
+    surface->group_stream.is_knockout = FALSE;
 
     return status;
 }
 
 static cairo_status_t
-_cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t  *surface,
-					cairo_pdf_resource_t *first_object)
+_cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t  *surface)
 {
     cairo_status_t status;
 
@@ -1090,7 +1058,6 @@ _cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t  *surface,
 	return status;
 
     surface->group_stream.is_knockout = TRUE;
-    surface->group_stream.first_object = *first_object;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1119,7 +1086,7 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
     _cairo_pdf_surface_write_memory_stream (surface,
 					    surface->group_stream.mem_stream,
 					    surface->group_stream.resource,
-					    &surface->group_stream.resources,
+					    &surface->resources,
 					    surface->group_stream.is_knockout);
     if (group)
 	*group = surface->group_stream.resource;
@@ -1132,148 +1099,69 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
 }
 
 static cairo_status_t
-_cairo_pdf_surface_write_group_list (cairo_pdf_surface_t  *surface,
-				     cairo_array_t        *group_list)
-{
-    int i, len;
-    cairo_pdf_group_element_t *elem;
-    cairo_status_t status;
-
-    _cairo_output_stream_printf (surface->output, "q\r\n");
-    if (surface->group_stream.is_knockout) {
-	_cairo_output_stream_printf (surface->output,
-				     "/x%d Do\r\n",
-				     surface->group_stream.first_object.id);
-	status = _cairo_pdf_surface_add_xobject (surface, surface->group_stream.first_object);
-	if (status)
-	    return status;
-    }
-    len = _cairo_array_num_elements (group_list);
-    for (i = 0; i < len; i++) {
-	elem = _cairo_array_index (group_list, i);
-	if (elem->type == ELEM_GROUP) {
-	    _cairo_output_stream_printf (surface->output,
-					 "/x%d Do\r\n",
-					 elem->group.id);
-	    status = _cairo_pdf_surface_add_xobject (surface, elem->group);
-	    if (status)
-		return status;
-	}
-    }
-    _cairo_output_stream_printf (surface->output, "Q\r\n");
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_pdf_surface_start_content_stream (cairo_pdf_surface_t *surface)
+_cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t  *surface,
+					cairo_pdf_resource_t *resource,
+					cairo_bool_t          is_form)
 {
-    cairo_status_t status;
-
-    if (surface->content_stream.active)
-        return CAIRO_STATUS_SUCCESS;
-
     assert (surface->pdf_stream.active == FALSE);
-    assert (surface->content_stream.active == FALSE);
     assert (surface->group_stream.active == FALSE);
 
-    surface->content_stream.active = TRUE;
-    surface->content_stream.mem_stream = _cairo_memory_stream_create ();
+    surface->content_resources = _cairo_pdf_surface_new_object (surface);
+    if (surface->content_resources.id == 0)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    if (surface->compress_content) {
-	surface->content_stream.stream =
-	    _cairo_deflate_stream_create (surface->content_stream.mem_stream);
+    if (is_form) {
+	*resource =
+	    _cairo_pdf_surface_open_stream (surface,
+					    NULL,
+					    surface->compress_content,
+					    "   /Type /XObject\r\n"
+					    "   /Subtype /Form\r\n"
+					    "   /BBox [ 0 0 %f %f ]\r\n"
+					    "   /Group <<\r\n"
+					    "      /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);
     } else {
-	surface->content_stream.stream = surface->content_stream.mem_stream;
+	surface->content =
+	    _cairo_pdf_surface_open_stream (surface,
+					    NULL,
+					    surface->compress_content,
+					    NULL);
     }
-    status = _cairo_output_stream_get_status (surface->content_stream.stream);
-
-    surface->content_stream.old_output = surface->output;
-    surface->output = surface->content_stream.stream;
-    _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
-    _cairo_pdf_group_resources_clear (&surface->content_stream.resources);
-    surface->current_resources = &surface->content_stream.resources;
+    if (surface->content.id == 0)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     _cairo_output_stream_printf (surface->output, "q\r\n");
 
-    return status;
-}
-
-static cairo_status_t
-_cairo_pdf_surface_add_group_to_content_stream (cairo_pdf_surface_t   *surface,
-                                                cairo_pdf_resource_t   group)
-{
-    cairo_pdf_group_element_t elem;
-
-    memset (&elem, 0, sizeof elem);
-    elem.type = ELEM_GROUP;
-    elem.group = group;
-
-    return _cairo_array_append (surface->current_group, &elem);
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
-_cairo_pdf_surface_stop_content_stream (cairo_pdf_surface_t *surface)
+_cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface)
 {
-    cairo_pdf_resource_t group;
     cairo_status_t status;
 
-    assert (surface->pdf_stream.active == FALSE);
-    assert (surface->content_stream.active == TRUE);
+    assert (surface->pdf_stream.active == TRUE);
+    assert (surface->group_stream.active == FALSE);
 
     _cairo_output_stream_printf (surface->output, "Q\r\n");
+    status = _cairo_pdf_surface_close_stream (surface);
+    if (status)
+	return status;
 
-    if (surface->compress_content) {
-	status = _cairo_output_stream_destroy (surface->content_stream.stream);
-	surface->content_stream.stream = NULL;
-	if (status)
-	    return status;
-
-	_cairo_output_stream_printf (surface->content_stream.mem_stream,
-				     "\r\n");
-    }
-    surface->output = surface->content_stream.old_output;
-    _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
-    surface->content_stream.active = FALSE;
-    if (_cairo_memory_stream_length (surface->content_stream.mem_stream) > 0) {
-	group = _cairo_pdf_surface_new_object (surface);
-	if (group.id == 0)
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-	_cairo_pdf_surface_write_memory_stream (surface,
-						surface->content_stream.mem_stream,
-						group,
-						&surface->content_stream.resources,
-						FALSE);
-	status = _cairo_pdf_surface_add_group_to_content_stream (surface, group);
-	if (status)
-	    return status;
-    }
-
-    status = _cairo_output_stream_destroy (surface->content_stream.mem_stream);
-    surface->content_stream.mem_stream = NULL;
-    surface->content_stream.stream = NULL;
-
-    return status;
-}
-
-static cairo_status_t
-_cairo_pdf_surface_check_content_stream_size (cairo_pdf_surface_t *surface)
-{
-    cairo_status_t status;
-
-    if (surface->content_stream.active == FALSE)
-	return CAIRO_STATUS_SUCCESS;
-
-    if (_cairo_memory_stream_length (surface->content_stream.mem_stream) > GROUP_STREAM_LIMIT) {
-	status = _cairo_pdf_surface_stop_content_stream (surface);
-	if (status)
-	    return status;
-
-	status = _cairo_pdf_surface_start_content_stream (surface);
-	if (status)
-	    return status;
-    }
+    _cairo_pdf_surface_update_object (surface, surface->content_resources);
+    _cairo_output_stream_printf (surface->output,
+				 "%d 0 obj\r\n",
+				 surface->content_resources.id);
+    _cairo_pdf_surface_emit_group_resources (surface, &surface->resources);
+    _cairo_output_stream_printf (surface->output,
+				 "endobj\r\n");
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1332,16 +1220,6 @@ _cairo_pdf_surface_finish (void *abstract_surface)
     if (status == CAIRO_STATUS_SUCCESS)
 	status = status2;
 
-    if (surface->content_stream.stream != NULL) {
-	status2 = _cairo_output_stream_destroy (surface->content_stream.stream);
-	if (status == CAIRO_STATUS_SUCCESS)
-	    status = status2;
-    }
-    if (surface->content_stream.mem_stream != NULL) {
-	status2 = _cairo_output_stream_destroy (surface->content_stream.mem_stream);
-	if (status == CAIRO_STATUS_SUCCESS)
-	    status = status2;
-    }
     if (surface->group_stream.stream != NULL) {
 	status2 = _cairo_output_stream_destroy (surface->group_stream.stream);
 	if (status == CAIRO_STATUS_SUCCESS)
@@ -1352,8 +1230,8 @@ _cairo_pdf_surface_finish (void *abstract_surface)
 	if (status == CAIRO_STATUS_SUCCESS)
 	    status = status2;
     }
-    if (surface->content_stream.active)
-	surface->output = surface->content_stream.old_output;
+    if (surface->pdf_stream.active)
+	surface->output = surface->pdf_stream.old_output;
     if (surface->group_stream.active)
 	surface->output = surface->group_stream.old_output;
 
@@ -1363,15 +1241,12 @@ _cairo_pdf_surface_finish (void *abstract_surface)
 	status = status2;
 
     _cairo_pdf_surface_clear (surface);
-    _cairo_pdf_group_resources_fini (&surface->group_stream.resources);
-    _cairo_pdf_group_resources_fini (&surface->content_stream.resources);
+    _cairo_pdf_group_resources_fini (&surface->resources);
 
     _cairo_array_fini (&surface->objects);
     _cairo_array_fini (&surface->pages);
     _cairo_array_fini (&surface->rgb_linear_functions);
     _cairo_array_fini (&surface->alpha_linear_functions);
-    _cairo_array_fini (&surface->knockout_group);
-    _cairo_array_fini (&surface->content_group);
     _cairo_array_fini (&surface->patterns);
     _cairo_array_fini (&surface->smask_groups);
     _cairo_array_fini (&surface->fonts);
@@ -1390,12 +1265,12 @@ _cairo_pdf_surface_start_page (void *abstract_surface)
     cairo_status_t status;
     cairo_pdf_surface_t *surface = abstract_surface;
 
-    surface->current_group = &surface->content_group;
-    status = _cairo_pdf_surface_start_content_stream (surface);
+    surface->has_fallback_images = FALSE;
+    _cairo_pdf_group_resources_clear (&surface->resources);
+    status = _cairo_pdf_surface_open_content_stream (surface, &surface->content, TRUE);
     if (status)
 	return status;
 
-
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -1718,8 +1593,6 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
 				      cairo_surface_t      *meta_surface,
 				      cairo_pdf_resource_t *resource)
 {
-    cairo_array_t group;
-    cairo_array_t *old_group;
     double old_width, old_height;
     cairo_matrix_t old_cairo_to_pdf;
     cairo_rectangle_int16_t meta_extents;
@@ -1730,22 +1603,21 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
     if (status)
 	return status;
 
-    _cairo_array_init (&group, sizeof (cairo_pdf_group_element_t));
-    old_group = surface->current_group;
     old_width = surface->width;
     old_height = surface->height;
     old_cairo_to_pdf = surface->cairo_to_pdf;
-    surface->current_group = &group;
     surface->width = meta_extents.width;
     surface->height = meta_extents.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);
 
-    status = _cairo_pdf_surface_start_content_stream (surface);
+    _cairo_pdf_group_resources_clear (&surface->resources);
+    status = _cairo_pdf_surface_open_content_stream (surface, &surface->content, TRUE);
     if (status)
-	goto CLEANUP_GROUP;
+	return status;
 
+    *resource = surface->content;
     if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
 	status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
 	if (status)
@@ -1764,35 +1636,16 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
     if (status)
 	goto CLEANUP_GROUP;
 
-    status = _cairo_pdf_surface_stop_content_stream (surface);
-    if (status)
-	goto CLEANUP_GROUP;
-
-    status = _cairo_pdf_surface_open_group (surface, NULL);
-    if (status)
-	goto CLEANUP_GROUP;
-
-    status = _cairo_pdf_surface_write_group_list (surface, &group);
-    if (status)
-	goto CLEANUP_GROUP;
-
-    status = _cairo_pdf_surface_close_group (surface, resource);
-    if (status)
-	goto CLEANUP_GROUP;
+    status = _cairo_pdf_surface_close_content_stream (surface);
 
  CLEANUP_GROUP:
-    surface->current_group = old_group;
     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);
 
-    _cairo_array_fini (&group);
-    if (status)
-	return status;
-
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
 static cairo_status_t
@@ -2828,7 +2681,7 @@ _cairo_pdf_surface_copy_page (void *abstract_surface)
     cairo_pdf_surface_t *surface = abstract_surface;
     cairo_int_status_t status;
 
-    status = _cairo_pdf_surface_stop_content_stream (surface);
+    status = _cairo_pdf_surface_close_content_stream (surface);
     if (status)
 	return status;
 
@@ -2841,7 +2694,7 @@ _cairo_pdf_surface_show_page (void *abstract_surface)
     cairo_pdf_surface_t *surface = abstract_surface;
     cairo_int_status_t status;
 
-    status = _cairo_pdf_surface_stop_content_stream (surface);
+    status = _cairo_pdf_surface_close_content_stream (surface);
     if (status)
 	return status;
 
@@ -4144,63 +3997,35 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface
 static cairo_status_t
 _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
 {
+    cairo_pdf_resource_t page, knockout;
     cairo_status_t status;
-    cairo_pdf_resource_t page;
-    cairo_pdf_resource_t content_group, knockout_group, page_content;
-    cairo_bool_t has_fallback_images = FALSE;
-
-    if (_cairo_array_num_elements (&surface->knockout_group) > 0)
-	has_fallback_images = TRUE;
 
-    status = _cairo_pdf_surface_open_group (surface, NULL);
-    if (status)
-	return status;
-
-    status = _cairo_pdf_surface_write_group_list (surface, &surface->content_group);
-    if (status)
-	return status;
-
-    status = _cairo_pdf_surface_close_group (surface, &content_group);
-    if (status)
-	return status;
-
-    if (has_fallback_images) {
-	status = _cairo_pdf_surface_open_knockout_group (surface, &content_group);
+    _cairo_pdf_group_resources_clear (&surface->resources);
+    if (surface->has_fallback_images) {
+	status = _cairo_pdf_surface_open_knockout_group (surface);
 	if (status)
 	    return status;
 
-	status = _cairo_pdf_surface_write_group_list (surface, &surface->knockout_group);
+	_cairo_output_stream_printf (surface->output,
+				     "/x%d Do\r\n"
+				     "/x%d Do\r\n",
+				     surface->content.id,
+				     surface->fallback_content.id);
+	_cairo_pdf_surface_add_xobject (surface, surface->content);
+	_cairo_pdf_surface_add_xobject (surface, surface->fallback_content);
+	status = _cairo_pdf_surface_close_group (surface, &knockout);
 	if (status)
 	    return status;
 
-	status = _cairo_pdf_surface_close_group (surface, &knockout_group);
-	if (status)
-	    return status;
+	_cairo_pdf_group_resources_clear (&surface->resources);
+	status = _cairo_pdf_surface_open_content_stream (surface, &surface->content, FALSE);
+	_cairo_output_stream_printf (surface->output,
+				     "/x%d Do\r\n",
+				     knockout.id);
+	_cairo_pdf_surface_add_xobject (surface, knockout);
+	_cairo_pdf_surface_close_content_stream (surface);
     }
 
-    page_content = _cairo_pdf_surface_open_stream (surface,
-						   NULL,
-						   FALSE,
-						   "   /Type /XObject\r\n"
-						   "   /Subtype /Form\r\n"
-						   "   /BBox [ 0 0 %f %f ]\r\n"
-						   "   /Group <<\r\n"
-						   "      /Type /Group\r\n"
-						   "      /S /Transparency\r\n"
-						   "      /CS /DeviceRGB\r\n"
-						   "   >>\r\n",
-						   surface->width,
-						   surface->height);
-    if (page_content.id == 0)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    _cairo_output_stream_printf (surface->output,
-				 "/x%d Do\r\n",
-				 has_fallback_images ? knockout_group.id : content_group.id);
-    status = _cairo_pdf_surface_close_stream (surface);
-    if (status)
-	return status;
-
     page = _cairo_pdf_surface_new_object (surface);
     if (page.id == 0)
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -4210,24 +4035,21 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
 				 "<< /Type /Page\r\n"
 				 "   /Parent %d 0 R\r\n"
 				 "   /MediaBox [ 0 0 %f %f ]\r\n"
-				 "   /Contents [ %d 0 R ]\r\n"
+				 "   /Contents %d 0 R\r\n"
 				 "   /Group <<\r\n"
 				 "      /Type /Group\r\n"
 				 "      /S /Transparency\r\n"
 				 "      /CS /DeviceRGB\r\n"
 				 "   >>\r\n"
-				 "   /Resources <<\r\n"
-				 "      /XObject << /x%d %d 0 R >>\r\n"
-				 "   >>\r\n"
+				 "   /Resources %d 0 R\r\n"
 				 ">>\r\n"
 				 "endobj\r\n",
 				 page.id,
 				 surface->pages_resource.id,
 				 surface->width,
 				 surface->height,
-				 page_content.id,
-				 has_fallback_images ? knockout_group.id : content_group.id,
-				 has_fallback_images ? knockout_group.id : content_group.id);
+				 surface->content.id,
+				 surface->content_resources.id);
 
     status = _cairo_array_append (&surface->pages, &page);
     if (status)
@@ -4373,16 +4195,15 @@ _cairo_pdf_surface_set_operator (cairo_pdf_surface_t *surface,
 	return CAIRO_STATUS_SUCCESS;
 
     if (op == CAIRO_OPERATOR_SOURCE) {
-	surface->current_group = &surface->knockout_group;
-	status = _cairo_pdf_surface_stop_content_stream (surface);
+	status = _cairo_pdf_surface_close_content_stream (surface);
 	if (status)
 	    return status;
 
-	status = _cairo_pdf_surface_start_content_stream (surface);
-	if (status)
-	    return status;
-
-	return CAIRO_STATUS_SUCCESS;
+	surface->has_fallback_images = TRUE;
+	_cairo_pdf_group_resources_clear (&surface->resources);
+	return _cairo_pdf_surface_open_content_stream (surface,
+						       &surface->fallback_content,
+						       TRUE);
     }
 
     return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -4446,11 +4267,7 @@ _cairo_pdf_surface_paint (void			*abstract_surface,
 	_cairo_pdf_surface_unselect_pattern (surface);
     }
 
-    status = _cairo_output_stream_get_status (surface->output);
-    if (status)
-        return status;
-
-    return _cairo_pdf_surface_check_content_stream_size (surface);
+    return _cairo_output_stream_get_status (surface->output);
 }
 
 static cairo_int_status_t
@@ -4580,11 +4397,7 @@ _cairo_pdf_surface_stroke (void			*abstract_surface,
 	_cairo_pdf_surface_unselect_pattern (surface);
     }
 
-    status = _cairo_output_stream_get_status (surface->output);
-    if (status)
-	return status;
-
-    return _cairo_pdf_surface_check_content_stream_size (surface);
+    return _cairo_output_stream_get_status (surface->output);
 }
 
 static cairo_int_status_t
@@ -4656,11 +4469,7 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
 	_cairo_pdf_surface_unselect_pattern (surface);
     }
 
-    status = _cairo_output_stream_get_status (surface->output);
-    if (status)
-	return status;
-
-    return _cairo_pdf_surface_check_content_stream_size (surface);
+    return _cairo_output_stream_get_status (surface->output);
 }
 
 static cairo_int_status_t
@@ -4726,11 +4535,7 @@ _cairo_pdf_surface_show_glyphs (void			*abstract_surface,
 	_cairo_pdf_surface_unselect_pattern (surface);
     }
 
-    status = _cairo_output_stream_get_status (surface->output);
-    if (status)
-	return status;
-
-    return _cairo_pdf_surface_check_content_stream_size (surface);
+    return _cairo_output_stream_get_status (surface->output);
 }
 
 static void
commit 099810b6c39cc6b5529f740282b64185cf56c8d7
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Jan 7 20:59:22 2008 +1030

    PDF: Perform all clipping in the content stream
    
    Previously this was done in a separate group. Now that the PDF backend
    has been re-organized to not interrupt the content stream the clipping
    can be done in the same stream.

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index b51b787..0722cc5 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -212,8 +212,6 @@ typedef enum group_element_type {
 typedef struct _cairo_pdf_group_element {
     group_element_type_t  type;
     cairo_pdf_resource_t  group;
-    cairo_path_fixed_t   *clip_path;
-    cairo_fill_rule_t     fill_rule;
 } cairo_pdf_group_element_t;
 
 
@@ -221,9 +219,6 @@ static cairo_pdf_resource_t
 _cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface);
 
 static void
-_cairo_pdf_group_element_array_finish (cairo_array_t *array);
-
-static void
 _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
 
 static void
@@ -262,11 +257,6 @@ static long
 _cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface);
 
 static cairo_status_t
-_cairo_pdf_surface_emit_clip (cairo_pdf_surface_t  *surface,
-			      cairo_path_fixed_t   *path,
-			      cairo_fill_rule_t	    fill_rule);
-
-static cairo_status_t
 _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
 
 static cairo_status_t
@@ -562,8 +552,8 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
     cairo_pdf_pattern_t *pattern;
     cairo_pdf_smask_group_t *group;
 
-    _cairo_pdf_group_element_array_finish (&surface->content_group);
-    _cairo_pdf_group_element_array_finish (&surface->knockout_group);
+    _cairo_array_truncate (&surface->content_group, 0);
+    _cairo_array_truncate (&surface->knockout_group, 0);
     _cairo_array_truncate (&surface->content_group, 0);
     _cairo_array_truncate (&surface->knockout_group, 0);
 
@@ -1168,10 +1158,6 @@ _cairo_pdf_surface_write_group_list (cairo_pdf_surface_t  *surface,
 	    status = _cairo_pdf_surface_add_xobject (surface, elem->group);
 	    if (status)
 		return status;
-	} else if (elem->type == ELEM_CLIP) {
-	    status = _cairo_pdf_surface_emit_clip (surface, elem->clip_path, elem->fill_rule);
-	    if (status)
-		return status;
 	}
     }
     _cairo_output_stream_printf (surface->output, "Q\r\n");
@@ -1208,6 +1194,8 @@ _cairo_pdf_surface_start_content_stream (cairo_pdf_surface_t *surface)
     _cairo_pdf_group_resources_clear (&surface->content_stream.resources);
     surface->current_resources = &surface->content_stream.resources;
 
+    _cairo_output_stream_printf (surface->output, "q\r\n");
+
     return status;
 }
 
@@ -1233,6 +1221,8 @@ _cairo_pdf_surface_stop_content_stream (cairo_pdf_surface_t *surface)
     assert (surface->pdf_stream.active == FALSE);
     assert (surface->content_stream.active == TRUE);
 
+    _cairo_output_stream_printf (surface->output, "Q\r\n");
+
     if (surface->compress_content) {
 	status = _cairo_output_stream_destroy (surface->content_stream.stream);
 	surface->content_stream.stream = NULL;
@@ -1288,20 +1278,6 @@ _cairo_pdf_surface_check_content_stream_size (cairo_pdf_surface_t *surface)
     return CAIRO_STATUS_SUCCESS;
 }
 
-static void
-_cairo_pdf_group_element_array_finish (cairo_array_t *array)
-{
-    int i, len;
-    cairo_pdf_group_element_t *elem;
-
-    len = _cairo_array_num_elements (array);
-    for (i = 0; i < len; i++) {
-	elem = _cairo_array_index (array, i);
-	if (elem->type == ELEM_CLIP && elem->clip_path)
-	    _cairo_path_fixed_destroy (elem->clip_path);
-    }
-}
-
 static cairo_surface_t *
 _cairo_pdf_surface_create_similar (void			*abstract_surface,
 				   cairo_content_t	 content,
@@ -1812,7 +1788,6 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
 						  surface->cairo_to_pdf);
 
-    _cairo_pdf_group_element_array_finish (&group);
     _cairo_array_fini (&group);
     if (status)
 	return status;
@@ -2898,53 +2873,6 @@ _cairo_pdf_surface_get_extents (void		        *abstract_surface,
     return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
-_cairo_pdf_surface_add_clip (cairo_pdf_surface_t  *surface,
-			     cairo_path_fixed_t	  *path,
-			     cairo_fill_rule_t     fill_rule)
-{
-    cairo_pdf_group_element_t elem;
-    cairo_status_t status;
-
-    memset (&elem, 0, sizeof elem);
-    elem.type = ELEM_CLIP;
-
-    if (path == NULL) {
-	elem.clip_path = NULL;
-    } else {
-	elem.clip_path = _cairo_path_fixed_create ();
-	if (elem.clip_path == NULL)
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-	status = _cairo_path_fixed_init_copy (elem.clip_path, path);
-	if (status) {
-	    _cairo_path_fixed_destroy (elem.clip_path);
-	    return status;
-	}
-    }
-    elem.fill_rule = fill_rule;
-
-    status = _cairo_pdf_surface_stop_content_stream (surface);
-    if (status) {
-	if (elem.clip_path != NULL)
-	    _cairo_path_fixed_destroy (elem.clip_path);
-	return status;
-    }
-
-    status = _cairo_array_append (surface->current_group, &elem);
-    if (status) {
-	if (elem.clip_path != NULL)
-	    _cairo_path_fixed_destroy (elem.clip_path);
-	return status;
-    }
-
-    status = _cairo_pdf_surface_start_content_stream (surface);
-    if (status)
-	return status;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
 static cairo_int_status_t
 _cairo_pdf_surface_intersect_clip_path (void			*abstract_surface,
 					cairo_path_fixed_t	*path,
@@ -2954,7 +2882,12 @@ _cairo_pdf_surface_intersect_clip_path (void			*abstract_surface,
 {
     cairo_pdf_surface_t *surface = abstract_surface;
 
-    return _cairo_pdf_surface_add_clip (surface, path, fill_rule);
+    if (path == NULL) {
+	_cairo_output_stream_printf (surface->output, "Q q\r\n");
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule);
 }
 
 static void
@@ -3979,19 +3912,6 @@ _cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface)
 }
 
 static cairo_status_t
-_cairo_pdf_surface_emit_clip (cairo_pdf_surface_t  *surface,
-			      cairo_path_fixed_t   *path,
-			      cairo_fill_rule_t	    fill_rule)
-{
-    if (path == NULL) {
-	_cairo_output_stream_printf (surface->output, "Q q\r\n");
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule);
-}
-
-static cairo_status_t
 _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t 	*surface,
 				     cairo_pdf_smask_group_t 	*group)
 {
commit 83630b1c70b24035b333ccfbbda8b67bd5fdd32e
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Jan 7 20:55:56 2008 +1030

    PDF: Emit all patterns after content stream
    
    To fix this performance issue
    
    http://lists.cairographics.org/archives/cairo/2007-December/012197.html
    
    the PDF surface needs to avoid starting and stopping the content
    stream every time it emits a pattern. This patch makes the PDF surface
    store a list of all patterns used while the content stream is written
    out then write out all the patterns after the content stream is
    closed.

diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index d4318d6..7012155 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-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 © 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
@@ -45,6 +46,7 @@
 
 #include "cairo-surface-private.h"
 #include "cairo-pdf-operators-private.h"
+#include "cairo-path-fixed-private.h"
 
 typedef struct _cairo_pdf_resource {
     unsigned int id;
@@ -58,6 +60,37 @@ typedef struct _cairo_pdf_group_resources {
     cairo_array_t fonts;
 } cairo_pdf_group_resources_t;
 
+typedef struct _cairo_pdf_pattern {
+    cairo_pattern_t *pattern;
+    cairo_pdf_resource_t pattern_res;
+    cairo_pdf_resource_t gstate_res;
+} cairo_pdf_pattern_t;
+
+typedef enum _cairo_pdf_operation {
+    PDF_PAINT,
+    PDF_MASK,
+    PDF_FILL,
+    PDF_STROKE,
+    PDF_SHOW_GLYPHS
+} cairo_pdf_operation_t;
+
+typedef struct _cairo_pdf_smask_group
+{
+    cairo_pdf_resource_t  group_res;
+    cairo_pdf_operation_t operation;
+    cairo_pattern_t	 *source;
+    cairo_pdf_resource_t  source_res;
+    cairo_pattern_t	 *mask;
+    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_glyph_t	 *glyphs;
+    int			  num_glyphs;
+    cairo_scaled_font_t	 *scaled_font;
+} cairo_pdf_smask_group_t;
+
 typedef struct _cairo_pdf_surface cairo_pdf_surface_t;
 
 struct _cairo_pdf_surface {
@@ -77,6 +110,8 @@ struct _cairo_pdf_surface {
     cairo_array_t alpha_linear_functions;
     cairo_array_t knockout_group;
     cairo_array_t content_group;
+    cairo_array_t patterns;
+    cairo_array_t smask_groups;
 
     cairo_scaled_font_subsets_t *font_subsets;
     cairo_array_t fonts;
@@ -100,6 +135,7 @@ struct _cairo_pdf_surface {
 	cairo_output_stream_t *stream;
 	cairo_output_stream_t *mem_stream;
 	cairo_output_stream_t *old_output;
+	cairo_pdf_resource_t   resource;
 	cairo_pdf_group_resources_t resources;
 	cairo_bool_t is_knockout;
 	cairo_pdf_resource_t first_object;
@@ -113,16 +149,6 @@ struct _cairo_pdf_surface {
 	cairo_pdf_group_resources_t resources;
     } content_stream;
 
-    struct {
-	cairo_pattern_type_t type;
-	double red;
-	double green;
-	double blue;
-	double alpha;
-	cairo_pdf_resource_t smask;
-	cairo_pdf_resource_t pattern;
-    } emitted_pattern;
-
     cairo_array_t *current_group;
     cairo_pdf_group_resources_t *current_resources;
     cairo_pdf_operators_t pdf_operators;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 2e5cd2b..b51b787 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -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 © 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
@@ -225,6 +226,9 @@ _cairo_pdf_group_element_array_finish (cairo_array_t *array);
 static void
 _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
 
+static void
+_cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group);
+
 static cairo_status_t
 _cairo_pdf_surface_add_font (unsigned int        font_id,
 			     unsigned int        subset_id,
@@ -235,9 +239,10 @@ _cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res);
 
 static cairo_pdf_resource_t
 _cairo_pdf_surface_open_stream (cairo_pdf_surface_t	*surface,
+				cairo_pdf_resource_t    *resource,
                                 cairo_bool_t             compressed,
 				const char		*fmt,
-				...) CAIRO_PRINTF_FORMAT(3, 4);
+				...) CAIRO_PRINTF_FORMAT(4, 5);
 static cairo_status_t
 _cairo_pdf_surface_close_stream (cairo_pdf_surface_t	*surface);
 
@@ -321,7 +326,6 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
 			 CAIRO_CONTENT_COLOR_ALPHA);
 
     surface->output = output;
-
     surface->width = width;
     surface->height = height;
     cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, height);
@@ -333,6 +337,8 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
     _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
     _cairo_array_init (&surface->knockout_group, sizeof (cairo_pdf_group_element_t));
     _cairo_array_init (&surface->content_group, sizeof (cairo_pdf_group_element_t));
+    _cairo_array_init (&surface->patterns, sizeof (cairo_pdf_pattern_t));
+    _cairo_array_init (&surface->smask_groups, sizeof (cairo_pdf_smask_group_t *));
 
     _cairo_pdf_group_resources_init (&surface->group_stream.resources);
     _cairo_pdf_group_resources_init (&surface->content_stream.resources);
@@ -552,10 +558,28 @@ cairo_pdf_surface_set_size (cairo_surface_t	*surface,
 static void
 _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
 {
+    int i, size;
+    cairo_pdf_pattern_t *pattern;
+    cairo_pdf_smask_group_t *group;
+
     _cairo_pdf_group_element_array_finish (&surface->content_group);
     _cairo_pdf_group_element_array_finish (&surface->knockout_group);
     _cairo_array_truncate (&surface->content_group, 0);
     _cairo_array_truncate (&surface->knockout_group, 0);
+
+    size = _cairo_array_num_elements (&surface->patterns);
+    for (i = 0; i < size; i++) {
+	pattern = (cairo_pdf_pattern_t *) _cairo_array_index (&surface->patterns, i);
+	cairo_pattern_destroy (pattern->pattern);
+    }
+    _cairo_array_truncate (&surface->patterns, 0);
+
+    size = _cairo_array_num_elements (&surface->smask_groups);
+    for (i = 0; i < size; i++) {
+	_cairo_array_copy_element (&surface->smask_groups, i, &group);
+	_cairo_pdf_smask_group_destroy (group);
+    }
+    _cairo_array_truncate (&surface->smask_groups, 0);
 }
 
 static void
@@ -781,8 +805,100 @@ _cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t         *surface,
 				 "   >>\r\n");
 }
 
+static cairo_pdf_smask_group_t *
+_cairo_pdf_surface_create_smask_group (cairo_pdf_surface_t 	*surface)
+{
+    cairo_pdf_smask_group_t 	*group;
+
+    group = calloc (1, sizeof (cairo_pdf_smask_group_t));
+    if (group == NULL) {
+	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	return NULL;
+    }
+
+    group->group_res = _cairo_pdf_surface_new_object (surface);
+    if (group->group_res.id == 0) {
+	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	free (group);
+	return NULL;
+    }
+
+    return group;
+}
+
+static void
+_cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group)
+{
+    if (group->operation == PDF_FILL ||	group->operation == PDF_STROKE)
+	_cairo_path_fixed_fini (&group->path);
+    if (group->source)
+	cairo_pattern_destroy (group->source);
+    if (group->mask)
+	cairo_pattern_destroy (group->mask);
+    if (group->scaled_font)
+	cairo_scaled_font_destroy (group->scaled_font);
+    free (group);
+}
+
+static cairo_status_t
+_cairo_pdf_surface_add_smask_group (cairo_pdf_surface_t     *surface,
+				    cairo_pdf_smask_group_t *group)
+{
+    return _cairo_array_append (&surface->smask_groups, &group);
+}
+
+static cairo_status_t
+_cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t 	*surface,
+				    cairo_pattern_t     	*pattern,
+				    cairo_pdf_resource_t 	*pattern_res,
+				    cairo_pdf_resource_t 	*gstate_res)
+{
+    cairo_pdf_pattern_t pdf_pattern;
+
+    /* Solid colors are emitted into the content stream */
+    if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
+	pattern_res->id = 0;
+	gstate_res->id = 0;
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    /* Gradients with zero stops do not produce any output */
+    if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
+        pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
+    {
+	cairo_gradient_pattern_t *gradient;
+
+	gradient = (cairo_gradient_pattern_t *) pattern;
+	if (gradient->n_stops == 0)
+	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+    }
+
+    pdf_pattern.pattern = cairo_pattern_reference (pattern);
+    pdf_pattern.pattern_res = _cairo_pdf_surface_new_object (surface);
+    if (pdf_pattern.pattern_res.id == 0)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    pdf_pattern.gstate_res.id = 0;
+
+    /* gradient patterns require an smask object to implement transparency */
+    if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
+        pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
+        if (_cairo_pattern_is_opaque (pattern) == FALSE) {
+            pdf_pattern.gstate_res = _cairo_pdf_surface_new_object (surface);
+            if (pdf_pattern.gstate_res.id == 0)
+                return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+        }
+    }
+
+    *pattern_res = pdf_pattern.pattern_res;
+    *gstate_res = pdf_pattern.gstate_res;
+
+    return _cairo_array_append (&surface->patterns, &pdf_pattern);
+}
+
 static cairo_pdf_resource_t
 _cairo_pdf_surface_open_stream (cairo_pdf_surface_t	*surface,
+				cairo_pdf_resource_t    *resource,
 				cairo_bool_t             compressed,
 				const char		*fmt,
 				...)
@@ -791,9 +907,14 @@ _cairo_pdf_surface_open_stream (cairo_pdf_surface_t	*surface,
     cairo_pdf_resource_t self, length;
     cairo_output_stream_t *output = NULL;
 
-    self = _cairo_pdf_surface_new_object (surface);
-    if (self.id == 0)
-	return self;
+    if (resource) {
+	self = *resource;
+	_cairo_pdf_surface_update_object (surface, self);
+    } else {
+	self = _cairo_pdf_surface_new_object (surface);
+	if (self.id == 0)
+	    return self;
+    }
 
     length = _cairo_pdf_surface_new_object (surface);
     if (length.id == 0)
@@ -881,23 +1002,20 @@ _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
     return status;
 }
 
-static cairo_pdf_resource_t
+static void
 _cairo_pdf_surface_write_memory_stream (cairo_pdf_surface_t         *surface,
 					cairo_output_stream_t       *mem_stream,
+					cairo_pdf_resource_t         resource,
 					cairo_pdf_group_resources_t *resources,
 					cairo_bool_t                 is_knockout_group)
 {
-    cairo_pdf_resource_t group;
-
-    group = _cairo_pdf_surface_new_object (surface);
-    if (group.id == 0)
-	return group;
+    _cairo_pdf_surface_update_object (surface, resource);
 
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "<< /Type /XObject\r\n"
 				 "   /Length %d\r\n",
-				 group.id,
+				 resource.id,
 				 _cairo_memory_stream_length (mem_stream));
 
     if (surface->compress_content) {
@@ -929,12 +1047,11 @@ _cairo_pdf_surface_write_memory_stream (cairo_pdf_surface_t         *surface,
     _cairo_output_stream_printf (surface->output,
 				 "endstream\r\n"
 				 "endobj\r\n");
-
-    return group;
 }
 
 static cairo_status_t
-_cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface)
+_cairo_pdf_surface_open_group (cairo_pdf_surface_t  *surface,
+			       cairo_pdf_resource_t *resource)
 {
     cairo_status_t status;
 
@@ -961,6 +1078,14 @@ _cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface)
     surface->current_resources = &surface->group_stream.resources;
     surface->group_stream.is_knockout = FALSE;
 
+    if (resource) {
+	surface->group_stream.resource = *resource;
+    } else {
+	surface->group_stream.resource = _cairo_pdf_surface_new_object (surface);
+	if (surface->group_stream.resource.id == 0)
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
     return status;
 }
 
@@ -970,7 +1095,7 @@ _cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t  *surface,
 {
     cairo_status_t status;
 
-    status = _cairo_pdf_surface_open_group (surface);
+    status = _cairo_pdf_surface_open_group (surface, NULL);
     if (status)
 	return status;
 
@@ -1001,15 +1126,17 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
     surface->output = surface->group_stream.old_output;
     _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
     surface->group_stream.active = FALSE;
-    *group = _cairo_pdf_surface_write_memory_stream (surface,
-						     surface->group_stream.mem_stream,
-						     &surface->group_stream.resources,
-						     surface->group_stream.is_knockout);
-    if (group->id == 0)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    _cairo_pdf_surface_write_memory_stream (surface,
+					    surface->group_stream.mem_stream,
+					    surface->group_stream.resource,
+					    &surface->group_stream.resources,
+					    surface->group_stream.is_knockout);
+    if (group)
+	*group = surface->group_stream.resource;
 
     status = _cairo_output_stream_destroy (surface->group_stream.mem_stream);
     surface->group_stream.mem_stream = NULL;
+    surface->group_stream.stream = NULL;
 
     return status;
 }
@@ -1097,33 +1224,6 @@ _cairo_pdf_surface_add_group_to_content_stream (cairo_pdf_surface_t   *surface,
     return _cairo_array_append (surface->current_group, &elem);
 }
 
-static void
-_cairo_pdf_surface_pause_content_stream (cairo_pdf_surface_t *surface)
-{
-    assert (surface->pdf_stream.active == FALSE);
-
-    if (surface->content_stream.active == FALSE)
-	return;
-
-    surface->output = surface->content_stream.old_output;
-    _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
-    surface->content_stream.active = FALSE;
-}
-
-static void
-_cairo_pdf_surface_resume_content_stream (cairo_pdf_surface_t *surface)
-{
-    assert (surface->pdf_stream.active == FALSE);
-
-    if (surface->content_stream.active == TRUE)
-	return;
-
-    surface->output = surface->content_stream.stream;
-    _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
-    surface->current_resources = &surface->content_stream.resources;
-    surface->content_stream.active = TRUE;
-}
-
 static cairo_status_t
 _cairo_pdf_surface_stop_content_stream (cairo_pdf_surface_t *surface)
 {
@@ -1146,13 +1246,15 @@ _cairo_pdf_surface_stop_content_stream (cairo_pdf_surface_t *surface)
     _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
     surface->content_stream.active = FALSE;
     if (_cairo_memory_stream_length (surface->content_stream.mem_stream) > 0) {
-	group = _cairo_pdf_surface_write_memory_stream (surface,
-							surface->content_stream.mem_stream,
-							&surface->content_stream.resources,
-							FALSE);
+	group = _cairo_pdf_surface_new_object (surface);
 	if (group.id == 0)
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
+	_cairo_pdf_surface_write_memory_stream (surface,
+						surface->content_stream.mem_stream,
+						group,
+						&surface->content_stream.resources,
+						FALSE);
 	status = _cairo_pdf_surface_add_group_to_content_stream (surface, group);
 	if (status)
 	    return status;
@@ -1160,6 +1262,7 @@ _cairo_pdf_surface_stop_content_stream (cairo_pdf_surface_t *surface)
 
     status = _cairo_output_stream_destroy (surface->content_stream.mem_stream);
     surface->content_stream.mem_stream = NULL;
+    surface->content_stream.stream = NULL;
 
     return status;
 }
@@ -1283,20 +1386,19 @@ _cairo_pdf_surface_finish (void *abstract_surface)
     if (status == CAIRO_STATUS_SUCCESS)
 	status = status2;
 
+    _cairo_pdf_surface_clear (surface);
+    _cairo_pdf_group_resources_fini (&surface->group_stream.resources);
+    _cairo_pdf_group_resources_fini (&surface->content_stream.resources);
+
     _cairo_array_fini (&surface->objects);
     _cairo_array_fini (&surface->pages);
     _cairo_array_fini (&surface->rgb_linear_functions);
     _cairo_array_fini (&surface->alpha_linear_functions);
-    _cairo_array_fini (&surface->fonts);
-
-    _cairo_pdf_group_resources_fini (&surface->group_stream.resources);
-    _cairo_pdf_group_resources_fini (&surface->content_stream.resources);
-
-    _cairo_pdf_group_element_array_finish (&surface->knockout_group);
     _cairo_array_fini (&surface->knockout_group);
-
-    _cairo_pdf_group_element_array_finish (&surface->content_group);
     _cairo_array_fini (&surface->content_group);
+    _cairo_array_fini (&surface->patterns);
+    _cairo_array_fini (&surface->smask_groups);
+    _cairo_array_fini (&surface->fonts);
 
     if (surface->font_subsets) {
 	_cairo_scaled_font_subsets_destroy (surface->font_subsets);
@@ -1438,6 +1540,7 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t	*surface,
     }
 
     *stream_ret = _cairo_pdf_surface_open_stream (surface,
+						  NULL,
                                                   FALSE,
 						  "   /Type /XObject\r\n"
 						  "   /Subtype /Image\r\n"
@@ -1564,6 +1667,7 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t   *surface,
 
     if (need_smask)
 	*image_ret = _cairo_pdf_surface_open_stream (surface,
+						     NULL,
                                                      FALSE,
 						     IMAGE_DICTIONARY
 						     "   /SMask %d 0 R\r\n",
@@ -1571,6 +1675,7 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t   *surface,
 						     smask.id);
     else
 	*image_ret = _cairo_pdf_surface_open_stream (surface,
+						     NULL,
                                                      FALSE,
 						     IMAGE_DICTIONARY,
 						     image->width, image->height);
@@ -1649,11 +1754,6 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
     if (status)
 	return status;
 
-    _cairo_pdf_surface_resume_content_stream (surface);
-    status = _cairo_pdf_surface_stop_content_stream (surface);
-    if (status)
-	return status;
-
     _cairo_array_init (&group, sizeof (cairo_pdf_group_element_t));
     old_group = surface->current_group;
     old_width = surface->width;
@@ -1692,7 +1792,7 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
     if (status)
 	goto CLEANUP_GROUP;
 
-    status = _cairo_pdf_surface_open_group (surface);
+    status = _cairo_pdf_surface_open_group (surface, NULL);
     if (status)
 	goto CLEANUP_GROUP;
 
@@ -1717,33 +1817,14 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
     if (status)
 	return status;
 
-    status = _cairo_pdf_surface_start_content_stream (surface);
-    if (status)
-	return status;
-
-    _cairo_pdf_surface_pause_content_stream (surface);
-
     return CAIRO_STATUS_SUCCESS;
 }
 
-static void
-_cairo_pdf_surface_emit_solid_pattern (cairo_pdf_surface_t   *surface,
-				       cairo_solid_pattern_t *pattern)
-{
-    surface->emitted_pattern.type = CAIRO_PATTERN_TYPE_SOLID;
-    surface->emitted_pattern.red = pattern->color.red;
-    surface->emitted_pattern.green = pattern->color.green;
-    surface->emitted_pattern.blue = pattern->color.blue;
-    surface->emitted_pattern.alpha = pattern->color.alpha;
-    surface->emitted_pattern.smask.id = 0;
-    surface->emitted_pattern.pattern.id = 0;
-}
-
 static cairo_status_t
-_cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	 *surface,
-					 cairo_surface_pattern_t *pattern)
+_cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	*surface,
+					 cairo_pdf_pattern_t 	*pdf_pattern)
 {
-    cairo_pdf_resource_t stream;
+    cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern;
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
     cairo_pdf_resource_t pattern_resource = {0}; /* squelch bogus compiler warning */
     cairo_matrix_t cairo_p2d, pdf_p2d;
@@ -1754,8 +1835,6 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	 *surface,
     int pattern_height = 0; /* squelch bogus compiler warning */
     int bbox_x, bbox_y;
 
-    _cairo_pdf_surface_pause_content_stream (surface);
-
     if (_cairo_surface_is_meta (pattern->surface)) {
 	cairo_surface_t *meta_surface = pattern->surface;
 	cairo_rectangle_int16_t pattern_extents;
@@ -1876,25 +1955,25 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	 *surface,
     cairo_matrix_translate (&pdf_p2d, 0.0, pattern_height);
     cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
 
-    stream = _cairo_pdf_surface_open_stream (surface,
-					     FALSE,
-					     "   /BBox [0 0 %d %d]\r\n"
-					     "   /XStep %f\r\n"
-					     "   /YStep %f\r\n"
-					     "   /PatternType 1\r\n"
-					     "   /TilingType 1\r\n"
-					     "   /PaintType 1\r\n"
-					     "   /Matrix [ %f %f %f %f %f %f ]\r\n"
-					     "   /Resources << /XObject << /x%d %d 0 R >> >>\r\n",
-					     bbox_x, bbox_y,
-					     xstep, ystep,
-					     pdf_p2d.xx, pdf_p2d.yx,
-					     pdf_p2d.xy, pdf_p2d.yy,
-					     pdf_p2d.x0, pdf_p2d.y0,
-					     pattern_resource.id,
-					     pattern_resource.id);
-    if (stream.id == 0)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
+    _cairo_pdf_surface_open_stream (surface,
+				    &pdf_pattern->pattern_res,
+				    FALSE,
+				    "   /PatternType 1\r\n"
+				    "   /BBox [0 0 %d %d]\r\n"
+				    "   /XStep %f\r\n"
+				    "   /YStep %f\r\n"
+				    "   /TilingType 1\r\n"
+				    "   /PaintType 1\r\n"
+				    "   /Matrix [ %f %f %f %f %f %f ]\r\n"
+				    "   /Resources << /XObject << /x%d %d 0 R >> >>\r\n",
+				    bbox_x, bbox_y,
+				    xstep, ystep,
+				    pdf_p2d.xx, pdf_p2d.yx,
+				    pdf_p2d.xy, pdf_p2d.yy,
+				    pdf_p2d.x0, pdf_p2d.y0,
+				    pattern_resource.id,
+				    pattern_resource.id);
 
     if (_cairo_surface_is_meta (pattern->surface)) {
 	if (extend == CAIRO_EXTEND_REFLECT) {
@@ -1927,13 +2006,6 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	 *surface,
     if (status)
 	return status;
 
-    _cairo_pdf_surface_resume_content_stream (surface);
-
-    surface->emitted_pattern.type = CAIRO_PATTERN_TYPE_SURFACE;
-    surface->emitted_pattern.smask.id = 0;
-    surface->emitted_pattern.pattern = stream;
-    surface->emitted_pattern.alpha = 1.0;
-
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -2298,13 +2370,16 @@ _cairo_pdf_surface_emit_repeating_function (cairo_pdf_surface_t      *surface,
     return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_pdf_resource_t
+static cairo_status_t
 cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t  *surface,
-                                           cairo_pdf_resource_t  gradient_mask)
+					   cairo_pdf_resource_t  gstate_resource,
+					   cairo_pdf_resource_t  gradient_mask)
 {
-    cairo_pdf_resource_t xobj_resource, smask_resource, gstate_resource;
+    cairo_pdf_resource_t xobj_resource, smask_resource;
+    cairo_status_t status;
 
     xobj_resource = _cairo_pdf_surface_open_stream (surface,
+						    NULL,
                                                     surface->compress_content,
                                                     "   /Type /XObject\r\n"
                                                     "   /Subtype /Form\r\n"
@@ -2327,7 +2402,7 @@ cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t  *surface,
                                                     gradient_mask.id,
                                                     gradient_mask.id);
     if (xobj_resource.id == 0)
-	return xobj_resource;
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     _cairo_output_stream_printf (surface->output,
                                  "q\r\n"
@@ -2340,14 +2415,13 @@ cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t  *surface,
                                  surface->width,
                                  surface->height);
 
-    if (_cairo_pdf_surface_close_stream (surface)) {
-	smask_resource.id = 0;
-	return smask_resource;
-    }
+     status = _cairo_pdf_surface_close_stream (surface);
+     if (status)
+	return status;
 
     smask_resource = _cairo_pdf_surface_new_object (surface);
     if (smask_resource.id == 0)
-	return smask_resource;
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     _cairo_output_stream_printf (surface->output,
                                  "%d 0 obj\r\n"
@@ -2360,9 +2434,7 @@ cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t  *surface,
                                  xobj_resource.id);
 
     /* Create GState which uses the transparency group as an SMask. */
-    gstate_resource = _cairo_pdf_surface_new_object (surface);
-    if (gstate_resource.id == 0)
-	return gstate_resource;
+    _cairo_pdf_surface_update_object (surface, gstate_resource);
 
     _cairo_output_stream_printf (surface->output,
                                  "%d 0 obj\r\n"
@@ -2376,14 +2448,14 @@ cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t  *surface,
                                  gstate_resource.id,
                                  smask_resource.id);
 
-    return gstate_resource;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
 _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t    *surface,
-                                        cairo_linear_pattern_t *pattern)
+					cairo_pdf_pattern_t    *pdf_pattern)
 {
-    cairo_pdf_resource_t pattern_resource, smask;
+    cairo_linear_pattern_t *pattern = (cairo_linear_pattern_t *) pdf_pattern->pattern;
     cairo_pdf_resource_t color_function, alpha_function;
     double x1, y1, x2, y2;
     double _x1, _y1, _x2, _y2;
@@ -2394,11 +2466,9 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t    *surface,
     double first_stop, last_stop;
     int repeat_begin = 0, repeat_end = 1;
 
-    if (pattern->base.n_stops == 0)
-        return CAIRO_INT_STATUS_NOTHING_TO_DO;
+    assert (pattern->base.n_stops != 0);
 
-    extend = cairo_pattern_get_extend (&pattern->base.base);
-    _cairo_pdf_surface_pause_content_stream (surface);
+    extend = cairo_pattern_get_extend (pdf_pattern->pattern);
 
     pat_to_pdf = pattern->base.base.matrix;
     status = cairo_matrix_invert (&pat_to_pdf);
@@ -2493,10 +2563,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t    *surface,
 	}
     }
 
-    pattern_resource = _cairo_pdf_surface_new_object (surface);
-    if (pattern_resource.id == 0)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
+    _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
     _cairo_output_stream_printf (surface->output,
                                  "%d 0 obj\r\n"
                                  "<< /Type /Pattern\r\n"
@@ -2508,7 +2575,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t    *surface,
                                  "         /Coords [ %f %f %f %f ]\r\n"
                                  "         /Domain [ %f %f ]\r\n"
                                  "         /Function %d 0 R\r\n",
-                                 pattern_resource.id,
+				 pdf_pattern->pattern_res.id,
                                  pat_to_pdf.xx, pat_to_pdf.yx,
                                  pat_to_pdf.xy, pat_to_pdf.yy,
                                  pat_to_pdf.x0, pat_to_pdf.y0,
@@ -2529,10 +2596,10 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t    *surface,
                                  ">>\r\n"
                                  "endobj\r\n");
 
-    if (alpha_function.id == 0) {
-         surface->emitted_pattern.smask.id = 0;
-    } else {
-        cairo_pdf_resource_t mask_resource;
+    if (alpha_function.id != 0) {
+	cairo_pdf_resource_t mask_resource;
+
+	assert (pdf_pattern->gstate_res.id != 0);
 
         /* Create pattern for SMask. */
         mask_resource = _cairo_pdf_surface_new_object (surface);
@@ -2574,38 +2641,27 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t    *surface,
         if (status)
             return status;
 
-        smask = cairo_pdf_surface_emit_transparency_group (surface, mask_resource);
-	if (smask.id == 0)
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-        surface->emitted_pattern.smask = smask;
+	cairo_pdf_surface_emit_transparency_group (surface,
+						   pdf_pattern->gstate_res,
+						   mask_resource);
     }
-
-    surface->emitted_pattern.type = CAIRO_PATTERN_TYPE_LINEAR;
-    surface->emitted_pattern.pattern = pattern_resource;
-    surface->emitted_pattern.alpha = 1.0;
-
-    _cairo_pdf_surface_resume_content_stream (surface);
-
     return status;
 }
 
 static cairo_status_t
 _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t    *surface,
-                                        cairo_radial_pattern_t *pattern)
+					cairo_pdf_pattern_t    *pdf_pattern)
 {
-    cairo_pdf_resource_t pattern_resource, smask;
     cairo_pdf_resource_t color_function, alpha_function;
     double x1, y1, x2, y2, r1, r2;
     cairo_matrix_t pat_to_pdf;
     cairo_extend_t extend;
     cairo_status_t status;
+    cairo_radial_pattern_t *pattern = (cairo_radial_pattern_t *) pdf_pattern->pattern;
 
-    if (pattern->base.n_stops == 0)
-        return CAIRO_INT_STATUS_NOTHING_TO_DO;
+    assert (pattern->base.n_stops != 0);
 
-    extend = cairo_pattern_get_extend (&pattern->base.base);
-    _cairo_pdf_surface_pause_content_stream (surface);
+    extend = cairo_pattern_get_extend (pdf_pattern->pattern);
 
     status = _cairo_pdf_surface_emit_pattern_stops (surface,
                                                     &pattern->base,
@@ -2627,9 +2683,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t    *surface,
     y2 = _cairo_fixed_to_double (pattern->c2.y);
     r2 = _cairo_fixed_to_double (pattern->r2);
 
-    pattern_resource = _cairo_pdf_surface_new_object (surface);
-    if (pattern_resource.id == 0)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
 
     _cairo_output_stream_printf (surface->output,
                                  "%d 0 obj\r\n"
@@ -2641,7 +2695,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t    *surface,
                                  "         /ColorSpace /DeviceRGB\r\n"
                                  "         /Coords [ %f %f %f %f %f %f ]\r\n"
                                  "         /Function %d 0 R\r\n",
-                                 pattern_resource.id,
+				 pdf_pattern->pattern_res.id,
                                  pat_to_pdf.xx, pat_to_pdf.yx,
                                  pat_to_pdf.xy, pat_to_pdf.yy,
                                  pat_to_pdf.x0, pat_to_pdf.y0,
@@ -2661,12 +2715,12 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t    *surface,
                                  ">>\r\n"
                                  "endobj\r\n");
 
-    if (alpha_function.id == 0) {
-        surface->emitted_pattern.smask.id = 0;
-    } else {
-        cairo_pdf_resource_t mask_resource;
+    if (alpha_function.id != 0) {
+	cairo_pdf_resource_t mask_resource;
 
-        /* Create pattern for SMask. */
+	assert (pdf_pattern->gstate_res.id != 0);
+
+	/* Create pattern for SMask. */
         mask_resource = _cairo_pdf_surface_new_object (surface);
 	if (mask_resource.id == 0)
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -2701,38 +2755,30 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t    *surface,
                                      ">>\r\n"
                                      "endobj\r\n");
 
-        smask = cairo_pdf_surface_emit_transparency_group (surface, mask_resource);
-	if (smask.id == 0)
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-        surface->emitted_pattern.smask = smask;
+	cairo_pdf_surface_emit_transparency_group (surface,
+						   pdf_pattern->gstate_res,
+						   mask_resource);
     }
 
-    surface->emitted_pattern.type = CAIRO_PATTERN_TYPE_RADIAL;
-    surface->emitted_pattern.pattern = pattern_resource;
-    surface->emitted_pattern.alpha = 1.0;
-
-     _cairo_pdf_surface_resume_content_stream (surface);
-
-     return status;
+    return status;
 }
 
 static cairo_status_t
-_cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+_cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern_t *pdf_pattern)
 {
-    switch (pattern->type) {
+    switch (pdf_pattern->pattern->type) {
     case CAIRO_PATTERN_TYPE_SOLID:
-	_cairo_pdf_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
-        return CAIRO_STATUS_SUCCESS;
+	ASSERT_NOT_REACHED;
+	break;
 
     case CAIRO_PATTERN_TYPE_SURFACE:
-	return _cairo_pdf_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern);
+	return _cairo_pdf_surface_emit_surface_pattern (surface, pdf_pattern);
 
     case CAIRO_PATTERN_TYPE_LINEAR:
-	return _cairo_pdf_surface_emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
+	return _cairo_pdf_surface_emit_linear_pattern (surface, pdf_pattern);
 
     case CAIRO_PATTERN_TYPE_RADIAL:
-	return _cairo_pdf_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern);
+	return _cairo_pdf_surface_emit_radial_pattern (surface, pdf_pattern);
     }
 
     ASSERT_NOT_REACHED;
@@ -2741,23 +2787,27 @@ _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *
 
 static cairo_status_t
 _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
-                                   cairo_bool_t         is_stroke)
+				   cairo_pattern_t     *pattern,
+				   cairo_pdf_resource_t pattern_res,
+				   cairo_bool_t         is_stroke)
 {
     cairo_status_t status;
     int alpha;
 
-    status = _cairo_pdf_surface_add_alpha (surface, surface->emitted_pattern.alpha, &alpha);
-    if (status)
-	return status;
+    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;
 
-    if (surface->emitted_pattern.type == CAIRO_PATTERN_TYPE_SOLID) {
 	_cairo_output_stream_printf (surface->output,
-                                     "%f %f %f ",
-                                     surface->emitted_pattern.red,
-                                     surface->emitted_pattern.green,
-                                     surface->emitted_pattern.blue);
+				     "q %f %f %f ",
+				     solid_pattern->color.red,
+				     solid_pattern->color.green,
+				     solid_pattern->color.blue);
 
-        if (is_stroke)
+	if (is_stroke)
             _cairo_output_stream_printf (surface->output, "RG ");
         else
             _cairo_output_stream_printf (surface->output, "rg ");
@@ -2766,29 +2816,37 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
                                      "/a%d gs\r\n",
                                      alpha);
     } else {
-        if (is_stroke) {
-            _cairo_output_stream_printf (surface->output,
-                                         "/Pattern CS /p%d SCN ",
-                                         surface->emitted_pattern.pattern.id);
-        } else {
-            _cairo_output_stream_printf (surface->output,
-                                         "/Pattern cs /p%d scn ",
-                                         surface->emitted_pattern.pattern.id);
-        }
-        status = _cairo_pdf_surface_add_pattern (surface, surface->emitted_pattern.pattern);
+	status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
 	if (status)
 	    return status;
 
-        _cairo_output_stream_printf (surface->output,
-                                     "/a%d gs ",
-                                     alpha);
+	status = _cairo_pdf_surface_add_pattern (surface, pattern_res);
+	if (status)
+	    return status;
 
-        _cairo_output_stream_printf (surface->output, "\r\n");
+	if (is_stroke) {
+	    _cairo_output_stream_printf (surface->output,
+					 "q /Pattern CS /p%d SCN ",
+					 pattern_res.id);
+	} else {
+	    _cairo_output_stream_printf (surface->output,
+					 "q /Pattern cs /p%d scn ",
+					 pattern_res.id);
+	}
+	_cairo_output_stream_printf (surface->output,
+				     "/a%d gs\r\n",
+				     alpha);
     }
 
     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");
+}
+
 static cairo_int_status_t
 _cairo_pdf_surface_copy_page (void *abstract_surface)
 {
@@ -2992,8 +3050,9 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t		*surface,
     }
 
     *stream = _cairo_pdf_surface_open_stream (surface,
-					     surface->compress_content,
-					     NULL);
+					      NULL,
+					      surface->compress_content,
+					      NULL);
     if (stream->id == 0)
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
@@ -3588,6 +3647,7 @@ _cairo_pdf_surface_emit_bitmap_glyph (cairo_pdf_surface_t	*surface,
     }
 
     *glyph_ret = _cairo_pdf_surface_open_stream (surface,
+						 NULL,
 						 surface->compress_content,
 						 NULL);
     if (glyph_ret->id == 0) {
@@ -3932,6 +3992,236 @@ _cairo_pdf_surface_emit_clip (cairo_pdf_surface_t  *surface,
 }
 
 static cairo_status_t
+_cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t 	*surface,
+				     cairo_pdf_smask_group_t 	*group)
+{
+    cairo_pdf_resource_t mask_group;
+    cairo_pdf_resource_t smask;
+    cairo_pdf_smask_group_t *smask_group;
+    cairo_pdf_resource_t pattern_res, gstate_res;
+    cairo_status_t status;
+
+    /* Create mask group */
+    status = _cairo_pdf_surface_open_group (surface, NULL);
+    if (status)
+	return status;
+
+    pattern_res.id = 0;
+    gstate_res.id = 0;
+    status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask, &pattern_res, &gstate_res);
+    if (status)
+	return status;
+
+    if (gstate_res.id != 0) {
+	smask_group = _cairo_pdf_surface_create_smask_group (surface);
+	if (smask_group == NULL)
+	    return CAIRO_STATUS_NO_MEMORY;
+
+	smask_group->operation = PDF_PAINT;
+	smask_group->source = cairo_pattern_reference (group->mask);
+	smask_group->source_res = pattern_res;
+	status = _cairo_pdf_surface_add_smask_group (surface, smask_group);
+	if (status)
+	    return status;
+
+	status = _cairo_pdf_surface_add_smask (surface, gstate_res);
+	status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res);
+
+	_cairo_output_stream_printf (surface->output,
+				     "q /s%d gs /x%d Do Q\r\n",
+				     gstate_res.id,
+				     smask_group->group_res.id);
+    } else {
+	status = _cairo_pdf_surface_select_pattern (surface, group->mask, pattern_res, FALSE);
+	if (status)
+	    return status;
+
+	_cairo_output_stream_printf (surface->output,
+				     "0 0 %f %f re f\r\n",
+				     surface->width, surface->height);
+
+	_cairo_pdf_surface_unselect_pattern (surface);
+    }
+
+    status = _cairo_pdf_surface_close_group (surface, &mask_group);
+    if (status)
+	return status;
+
+    /* Create source group */
+    status = _cairo_pdf_surface_open_group (surface, &group->source_res);
+    if (status)
+	return status;
+
+    pattern_res.id = 0;
+    gstate_res.id = 0;
+    status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source, &pattern_res, &gstate_res);
+    if (status)
+	return status;
+
+    if (gstate_res.id != 0) {
+	smask_group = _cairo_pdf_surface_create_smask_group (surface);
+	if (smask_group == NULL)
+	    return CAIRO_STATUS_NO_MEMORY;
+
+	smask_group->operation = PDF_PAINT;
+	smask_group->source = cairo_pattern_reference (group->source);
+	smask_group->source_res = pattern_res;
+	status = _cairo_pdf_surface_add_smask_group (surface, smask_group);
+	if (status)
+	    return status;
+
+	status = _cairo_pdf_surface_add_smask (surface, gstate_res);
+	status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res);
+
+	_cairo_output_stream_printf (surface->output,
+				     "q /s%d gs /x%d Do Q\r\n",
+				     gstate_res.id,
+				     smask_group->group_res.id);
+    } else {
+	status = _cairo_pdf_surface_select_pattern (surface, group->source, pattern_res, FALSE);
+	if (status)
+	    return status;
+
+	_cairo_output_stream_printf (surface->output,
+				     "0 0 %f %f re f\r\n",
+				     surface->width, surface->height);
+
+	_cairo_pdf_surface_unselect_pattern (surface);
+    }
+
+    status = _cairo_pdf_surface_close_group (surface, NULL);
+    if (status)
+	return status;
+
+    /* Create an smask based on the alpha component of mask_group */
+    smask = _cairo_pdf_surface_new_object (surface);
+    if (smask.id == 0)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    _cairo_output_stream_printf (surface->output,
+				 "%d 0 obj\r\n"
+				 "<< /Type /Mask\r\n"
+				 "   /S /Alpha\r\n"
+				 "   /G %d 0 R\r\n"
+				 ">>\r\n"
+				 "endobj\r\n",
+				 smask.id,
+				 mask_group.id);
+
+    /* Create a GState that uses the smask */
+    _cairo_pdf_surface_update_object (surface, group->group_res);
+    _cairo_output_stream_printf (surface->output,
+				 "%d 0 obj\r\n"
+				 "<< /Type /ExtGState\r\n"
+				 "   /SMask %d 0 R\r\n"
+				 "   /ca 1\r\n"
+				 "   /CA 1\r\n"
+				 "   /AIS false\r\n"
+				 ">>\r\n"
+				 "endobj\r\n",
+				 group->group_res.id,
+				 smask.id);
+
+    return _cairo_output_stream_get_status (surface->output);
+}
+
+static cairo_status_t
+_cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t     *surface,
+				      cairo_pdf_smask_group_t *group)
+{
+    cairo_status_t status;
+
+    /* _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)
+	return status;
+
+    status = _cairo_pdf_surface_select_pattern (surface,
+						group->source,
+						group->source_res,
+						group->operation == PDF_STROKE);
+    if (status)
+	return status;
+
+    switch (group->operation) {
+    case PDF_PAINT:
+	_cairo_output_stream_printf (surface->output,
+				     "0 0 %f %f re f\r\n",
+				     surface->width, surface->height);
+	break;
+    case PDF_MASK:
+	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);
+	break;
+    case PDF_SHOW_GLYPHS:
+	status = _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
+						   group->glyphs,
+						   group->num_glyphs,
+						   group->scaled_font);
+	break;
+    }
+    if (status)
+	return status;
+
+    _cairo_pdf_surface_unselect_pattern (surface);
+
+    return _cairo_pdf_surface_close_group (surface, NULL);
+}
+
+static cairo_status_t
+_cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface)
+{
+    cairo_pdf_pattern_t pattern;
+    cairo_pdf_smask_group_t *group;
+    int pattern_index, group_index;
+    cairo_status_t status;
+
+    /* Writing out PDF_MASK groups will cause additional smask groups
+     * to be appended to surface->smask_groups. Additional patterns
+     * may also be appended to surface->patterns.
+     *
+     * Writing meta surface patterns will cause additional patterns
+     * and groups to be appended.
+     */
+    pattern_index = 0;
+    group_index = 0;
+    while ((pattern_index < _cairo_array_num_elements (&surface->patterns)) ||
+	   (group_index < _cairo_array_num_elements (&surface->smask_groups)))
+    {
+	for (; group_index < _cairo_array_num_elements (&surface->smask_groups); group_index++) {
+	    _cairo_array_copy_element (&surface->smask_groups, group_index, &group);
+	    status = _cairo_pdf_surface_write_smask_group (surface, group);
+	    if (status)
+		return status;
+	}
+
+	for (; pattern_index < _cairo_array_num_elements (&surface->patterns); pattern_index++) {
+	    _cairo_array_copy_element (&surface->patterns, pattern_index, &pattern);
+	    status = _cairo_pdf_surface_emit_pattern (surface, &pattern);
+	    if (status)
+		return status;
+	}
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
 _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
 {
     cairo_status_t status;
@@ -3942,7 +4232,7 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
     if (_cairo_array_num_elements (&surface->knockout_group) > 0)
 	has_fallback_images = TRUE;
 
-    status = _cairo_pdf_surface_open_group (surface);
+    status = _cairo_pdf_surface_open_group (surface, NULL);
     if (status)
 	return status;
 
@@ -3969,6 +4259,7 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
     }
 
     page_content = _cairo_pdf_surface_open_stream (surface,
+						   NULL,
 						   FALSE,
 						   "   /Type /XObject\r\n"
 						   "   /Subtype /Form\r\n"
@@ -4022,6 +4313,8 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
     if (status)
 	return status;
 
+    _cairo_pdf_surface_write_patterns_and_smask_groups (surface);
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -4181,60 +4474,56 @@ _cairo_pdf_surface_paint (void			*abstract_surface,
 			  cairo_pattern_t	*source)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
-    cairo_pdf_resource_t smask_group = {0}; /* squelch bogus compiler warning */
     cairo_status_t status;
+    cairo_pdf_smask_group_t *group;
+    cairo_pdf_resource_t pattern_res, gstate_res;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_pdf_surface_analyze_operation (surface, op, source);
 
     assert (_cairo_pdf_surface_operation_supported (surface, op, source));
 
-    status = _cairo_pdf_surface_emit_pattern (surface, source);
-    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
-        return CAIRO_STATUS_SUCCESS;
-
-    if (status)
-	return status;
-
     status = _cairo_pdf_surface_set_operator (surface, op);
     if (status)
 	return status;
 
-    if (surface->emitted_pattern.smask.id != 0) {
-	_cairo_pdf_surface_pause_content_stream (surface);
-	status = _cairo_pdf_surface_open_group (surface);
-	if (status)
-	    return status;
-    } else {
-	_cairo_output_stream_printf (surface->output, "q ");
-    }
-
-    status = _cairo_pdf_surface_select_pattern (surface, FALSE);
+    pattern_res.id = 0;
+    gstate_res.id = 0;
+    status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res);
+    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+	return CAIRO_STATUS_SUCCESS;
     if (status)
 	return status;
 
-    _cairo_output_stream_printf (surface->output,
-				 "0 0 %f %f re f\r\n",
-				 surface->width, surface->height);
+    if (gstate_res.id != 0) {
+	group = _cairo_pdf_surface_create_smask_group (surface);
+	if (group == NULL)
+	    return CAIRO_STATUS_NO_MEMORY;
 
-    if (surface->emitted_pattern.smask.id != 0) {
-	status = _cairo_pdf_surface_close_group (surface, &smask_group);
+	group->operation = PDF_PAINT;
+	group->source = cairo_pattern_reference (source);
+	group->source_res = pattern_res;
+	status = _cairo_pdf_surface_add_smask_group (surface, group);
 	if (status)
 	    return status;
 
-	_cairo_pdf_surface_resume_content_stream (surface);
+	status = _cairo_pdf_surface_add_smask (surface, gstate_res);
+	status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
+
 	_cairo_output_stream_printf (surface->output,
 				     "q /s%d gs /x%d Do Q\r\n",
-				     surface->emitted_pattern.smask,
-				     smask_group.id);
-	status = _cairo_pdf_surface_add_smask (surface, surface->emitted_pattern.smask);
-	if (status)
-	    return status;
-	status = _cairo_pdf_surface_add_xobject (surface, smask_group);
+				     gstate_res.id,
+				     group->group_res.id);
+    } else {
+	status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
 	if (status)
 	    return status;
-    } else {
-	_cairo_output_stream_printf (surface->output, "Q\r\n");
+
+	_cairo_output_stream_printf (surface->output,
+				     "0 0 %f %f re f\r\n",
+				     surface->width, surface->height);
+
+	_cairo_pdf_surface_unselect_pattern (surface);
     }
 
     status = _cairo_output_stream_get_status (surface->output);
@@ -4251,11 +4540,7 @@ _cairo_pdf_surface_mask	(void			*abstract_surface,
 			 cairo_pattern_t	*mask)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
-    cairo_pdf_resource_t mask_group;
-    cairo_pdf_resource_t group = {0}; /* squelch bogus compiler warning */
-    cairo_pdf_resource_t source_group;
-    cairo_pdf_resource_t smask;
-    cairo_pdf_resource_t gstate;
+    cairo_pdf_smask_group_t *group;
     cairo_status_t status, status2;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
@@ -4278,149 +4563,32 @@ _cairo_pdf_surface_mask	(void			*abstract_surface,
     if (status)
 	return status;
 
-    /* Create mask group */
-    status = _cairo_pdf_surface_emit_pattern (surface, mask);
-    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
-        return CAIRO_STATUS_SUCCESS;
+    group = _cairo_pdf_surface_create_smask_group (surface);
+    if (group == NULL)
+	return CAIRO_STATUS_NO_MEMORY;
 
-    if (status)
-	return status;
-
-    _cairo_pdf_surface_pause_content_stream (surface);
-
-    status = _cairo_pdf_surface_open_group (surface);
-    if (status)
-	return status;
-
-    status = _cairo_pdf_surface_select_pattern (surface, FALSE);
-    if (status)
-	return status;
-
-    _cairo_output_stream_printf (surface->output,
-				 "0 0 %f %f re f\r\n",
-				 surface->width, surface->height);
-    status = _cairo_pdf_surface_close_group (surface, &mask_group);
-    if (status)
-	return status;
-
-    if (surface->emitted_pattern.smask.id != 0) {
-	group = mask_group;
-	status = _cairo_pdf_surface_open_group (surface);
-	if (status)
-	    return status;
-
-	_cairo_output_stream_printf (surface->output,
-				     "/s%d gs /x%d Do\r\n",
-				     surface->emitted_pattern.smask,
-				     group.id);
-	status = _cairo_pdf_surface_add_smask (surface, surface->emitted_pattern.smask);
-	if (status)
-	    return status;
-	status = _cairo_pdf_surface_add_xobject (surface, group);
-	if (status)
-	    return status;
-
-	status = _cairo_pdf_surface_close_group (surface, &mask_group);
-	if (status)
-	    return status;
-    }
-
-    /* Create source group */
-    status = _cairo_pdf_surface_emit_pattern (surface, source);
-    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
-        return CAIRO_STATUS_SUCCESS;
-
-    if (status)
-	return status;
-
-    _cairo_pdf_surface_pause_content_stream (surface);
-
-    status = _cairo_pdf_surface_open_group (surface);
-    if (status)
-	return status;
-
-    status = _cairo_pdf_surface_select_pattern (surface, FALSE);
-    if (status)
-	return status;
+    group->operation = PDF_MASK;
+    group->source = cairo_pattern_reference (source);
+    group->mask = cairo_pattern_reference (mask);
+    group->source_res = _cairo_pdf_surface_new_object (surface);
+    if (group->source_res.id == 0)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    _cairo_output_stream_printf (surface->output,
-				 "0 0 %f %f re f\r\n",
-				 surface->width, surface->height);
-    status = _cairo_pdf_surface_close_group (surface, &source_group);
+    status = _cairo_pdf_surface_add_smask_group (surface, group);
     if (status)
 	return status;
 
-    if (surface->emitted_pattern.smask.id != 0) {
-	group = source_group;
-	status = _cairo_pdf_surface_open_group (surface);
-	if (status)
-	    return status;
-
-	_cairo_output_stream_printf (surface->output,
-				     "/s%d gs /x%d Do\r\n",
-				     surface->emitted_pattern.smask,
-				     group.id);
-	status = _cairo_pdf_surface_add_smask (surface, surface->emitted_pattern.smask);
-	if (status)
-	    return status;
-	status = _cairo_pdf_surface_add_xobject (surface, group);
-	if (status)
-	    return status;
-
-	status =_cairo_pdf_surface_close_group (surface, &source_group);
-	if (status)
-	    return status;
-    }
-
-    /* Create an smask based on the alpha component of mask_group */
-    smask = _cairo_pdf_surface_new_object (surface);
-    if (smask.id == 0)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    _cairo_output_stream_printf (surface->output,
-				 "%d 0 obj\r\n"
-				 "<< /Type /Mask\r\n"
-				 "   /S /Alpha\r\n"
-				 "   /G %d 0 R\r\n"
-				 ">>\r\n"
-				 "endobj\r\n",
-				 smask.id,
-				 mask_group.id);
-
-    /* Create a GState that uses the smask */
-    gstate = _cairo_pdf_surface_new_object (surface);
-    if (gstate.id == 0)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    _cairo_output_stream_printf (surface->output,
-				 "%d 0 obj\r\n"
-				 "<< /Type /ExtGState\r\n"
-				 "   /SMask %d 0 R\r\n"
-				 "   /ca 1\r\n"
-				 "   /CA 1\r\n"
-				 "   /AIS false\r\n"
-				 ">>\r\n"
-				 "endobj\r\n",
-				 gstate.id,
-				 smask.id);
+    status = _cairo_pdf_surface_add_smask (surface, group->group_res);
+    status = _cairo_pdf_surface_add_xobject (surface, group->source_res);
 
-    /* Select the GState then draw the source */
-    _cairo_pdf_surface_resume_content_stream (surface);
     _cairo_output_stream_printf (surface->output,
 				 "q /s%d gs /x%d Do Q\r\n",
-				 gstate.id,
-				 source_group.id);
-    status = _cairo_pdf_surface_add_smask (surface, gstate);
-    if (status)
-	return status;
-    status = _cairo_pdf_surface_add_xobject (surface, source_group);
-    if (status)
-	return status;
+				 group->group_res.id,
+				 group->source_res.id);
 
     return _cairo_output_stream_get_status (surface->output);
 }
 
-
 static cairo_int_status_t
 _cairo_pdf_surface_stroke (void			*abstract_surface,
 			   cairo_operator_t	 op,
@@ -4433,60 +4601,63 @@ _cairo_pdf_surface_stroke (void			*abstract_surface,
 			   cairo_antialias_t	 antialias)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
-    cairo_pdf_resource_t smask_group = {0}; /* squelch bogus compiler warning */
     cairo_status_t status;
+    cairo_pdf_smask_group_t *group;
+    cairo_pdf_resource_t pattern_res, gstate_res;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_pdf_surface_analyze_operation (surface, op, source);
 
     assert (_cairo_pdf_surface_operation_supported (surface, op, source));
 
-    status = _cairo_pdf_surface_emit_pattern (surface, source);
+    pattern_res.id = 0;
+    gstate_res.id = 0;
+    status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res);
     if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
-        return CAIRO_STATUS_SUCCESS;
-
+	return CAIRO_STATUS_SUCCESS;
     if (status)
 	return status;
 
-    if (surface->emitted_pattern.smask.id != 0) {
-	_cairo_pdf_surface_pause_content_stream (surface);
-	status = _cairo_pdf_surface_open_group (surface);
+    if (gstate_res.id != 0) {
+	group = _cairo_pdf_surface_create_smask_group (surface);
+	if (group == NULL)
+	    return CAIRO_STATUS_NO_MEMORY;
+
+	group->operation = PDF_STROKE;
+	group->source = cairo_pattern_reference (source);
+	group->source_res = pattern_res;
+	status = _cairo_path_fixed_init_copy (&group->path, path);
 	if (status)
 	    return status;
-    } else {
-	_cairo_output_stream_printf (surface->output, "q ");
-    }
-
-    status = _cairo_pdf_surface_select_pattern (surface, TRUE);
-    if (status)
-	return status;
-
-    status = _cairo_pdf_operator_stroke (&surface->pdf_operators,
-					 path,
-					 style,
-					 ctm,
-					 ctm_inverse);
-    if (status)
-	return status;
 
-    if (surface->emitted_pattern.smask.id != 0) {
-	status = _cairo_pdf_surface_close_group (surface, &smask_group);
+	group->style = style;
+	group->ctm = *ctm;
+	group->ctm_inverse = *ctm_inverse;
+	status = _cairo_pdf_surface_add_smask_group (surface, group);
 	if (status)
 	    return status;
 
-	_cairo_pdf_surface_resume_content_stream (surface);
+	status = _cairo_pdf_surface_add_smask (surface, gstate_res);
+	status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
+
 	_cairo_output_stream_printf (surface->output,
 				     "q /s%d gs /x%d Do Q\r\n",
-				     surface->emitted_pattern.smask,
-				     smask_group.id);
-	status = _cairo_pdf_surface_add_smask (surface, surface->emitted_pattern.smask);
+				     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_surface_add_xobject (surface, smask_group);
+
+	status = _cairo_pdf_operator_stroke (&surface->pdf_operators,
+					     path,
+					     style,
+					     ctm,
+					     ctm_inverse);
 	if (status)
 	    return status;
-    } else {
-	_cairo_output_stream_printf (surface->output, "Q\r\n");
+
+	_cairo_pdf_surface_unselect_pattern (surface);
     }
 
     status = _cairo_output_stream_get_status (surface->output);
@@ -4506,8 +4677,9 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
 			 cairo_antialias_t	 antialias)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
-    cairo_pdf_resource_t smask_group = {0}; /* squelch bogus compiler warning */
     cairo_status_t status;
+    cairo_pdf_smask_group_t *group;
+    cairo_pdf_resource_t pattern_res, gstate_res;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_pdf_surface_analyze_operation (surface, op, source);
@@ -4518,48 +4690,50 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
     if (status)
 	return status;
 
-    status = _cairo_pdf_surface_emit_pattern (surface, source);
+    pattern_res.id = 0;
+    gstate_res.id = 0;
+    status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res);
     if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
-        return CAIRO_STATUS_SUCCESS;
-
+	return CAIRO_STATUS_SUCCESS;
     if (status)
 	return status;
 
-    if (surface->emitted_pattern.smask.id != 0) {
-	_cairo_pdf_surface_pause_content_stream (surface);
-	status = _cairo_pdf_surface_open_group (surface);
+    if (gstate_res.id != 0) {
+	group = _cairo_pdf_surface_create_smask_group (surface);
+	if (group == NULL)
+	    return CAIRO_STATUS_NO_MEMORY;
+
+	group->operation = PDF_FILL;
+	group->source = cairo_pattern_reference (source);
+	group->source_res = pattern_res;
+	status = _cairo_path_fixed_init_copy (&group->path, path);
 	if (status)
 	    return status;
-    } else {
-	_cairo_output_stream_printf (surface->output, "q ");
-    }
 
-    status = _cairo_pdf_surface_select_pattern (surface, FALSE);
-    if (status)
-	return status;
-
-    status = _cairo_pdf_operators_fill (&surface->pdf_operators, path, fill_rule);
-    if (status)
-	return status;
-
-    if (surface->emitted_pattern.smask.id != 0) {
-	status = _cairo_pdf_surface_close_group (surface, &smask_group);
+	group->fill_rule = fill_rule;
+	status = _cairo_pdf_surface_add_smask_group (surface, group);
 	if (status)
 	    return status;
 
-	_cairo_pdf_surface_resume_content_stream (surface);
+	status = _cairo_pdf_surface_add_smask (surface, gstate_res);
+	status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
+
 	_cairo_output_stream_printf (surface->output,
 				     "q /s%d gs /x%d Do Q\r\n",
-				     surface->emitted_pattern.smask,
-				     smask_group.id);
-	status = _cairo_pdf_surface_add_smask (surface, surface->emitted_pattern.smask);
+				     gstate_res.id,
+				     group->group_res.id);
+    } else {
+	status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
 	if (status)
 	    return status;
-	status = _cairo_pdf_surface_add_xobject (surface, smask_group);
+
+	status = _cairo_pdf_operators_fill (&surface->pdf_operators,
+					    path,
+					    fill_rule);
 	if (status)
 	    return status;
-    } else {
-	_cairo_output_stream_printf (surface->output, "Q\r\n");
+
+	_cairo_pdf_surface_unselect_pattern (surface);
     }
 
     status = _cairo_output_stream_get_status (surface->output);
@@ -4578,60 +4752,58 @@ _cairo_pdf_surface_show_glyphs (void			*abstract_surface,
 				cairo_scaled_font_t	*scaled_font)
 {
     cairo_pdf_surface_t *surface = abstract_surface;
-    cairo_pdf_resource_t smask_group = {0}; /* squelch bogus compiler warning */
     cairo_status_t status;
+    cairo_pdf_smask_group_t *group;
+    cairo_pdf_resource_t pattern_res, gstate_res;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_pdf_surface_analyze_operation (surface, op, source);
 
     assert (_cairo_pdf_surface_operation_supported (surface, op, source));
 
-    status = _cairo_pdf_surface_emit_pattern (surface, source);
+    pattern_res.id = 0;
+    gstate_res.id = 0;
+    status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res);
     if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
-        return CAIRO_STATUS_SUCCESS;
-
-    if (status)
-	return status;
-
-    if (surface->emitted_pattern.smask.id != 0) {
-	_cairo_pdf_surface_pause_content_stream (surface);
-	status = _cairo_pdf_surface_open_group (surface);
-	if (status)
-	    return status;
-    } else {
-	_cairo_output_stream_printf (surface->output, "q ");
-    }
-
-    status = _cairo_pdf_surface_select_pattern (surface, FALSE);
-    if (status)
-	return status;
-
-    status = _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
-					       glyphs,
-					       num_glyphs,
-					       scaled_font);
+	return CAIRO_STATUS_SUCCESS;
     if (status)
 	return status;
 
-    if (surface->emitted_pattern.smask.id != 0) {
-	status = _cairo_pdf_surface_close_group (surface, &smask_group);
+    if (gstate_res.id != 0) {
+	group = _cairo_pdf_surface_create_smask_group (surface);
+	if (group == NULL)
+	    return CAIRO_STATUS_NO_MEMORY;
+
+	group->operation = PDF_SHOW_GLYPHS;
+	group->source = cairo_pattern_reference (source);
+	group->source_res = pattern_res;
+	group->glyphs = glyphs;
+	group->num_glyphs = num_glyphs;
+	group->scaled_font = cairo_scaled_font_reference (scaled_font);
+	status = _cairo_pdf_surface_add_smask_group (surface, group);
 	if (status)
 	    return status;
 
-	_cairo_pdf_surface_resume_content_stream (surface);
+	status = _cairo_pdf_surface_add_smask (surface, gstate_res);
+	status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
 
 	_cairo_output_stream_printf (surface->output,
 				     "q /s%d gs /x%d Do Q\r\n",
-				     surface->emitted_pattern.smask,
-				     smask_group.id);
-	status = _cairo_pdf_surface_add_smask (surface, surface->emitted_pattern.smask);
+				     gstate_res.id,
+				     group->group_res.id);
+    } else {
+	status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
 	if (status)
 	    return status;
-	status = _cairo_pdf_surface_add_xobject (surface, smask_group);
+
+	status = _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
+						   glyphs,
+						   num_glyphs,
+						   scaled_font);
 	if (status)
 	    return status;
-    } else {
-	_cairo_output_stream_printf (surface->output, "Q\r\n");
+
+	_cairo_pdf_surface_unselect_pattern (surface);
     }
 
     status = _cairo_output_stream_get_status (surface->output);
commit b4e0864b960887fd71de85d514cb3e855c276080
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Jan 7 20:42:15 2008 +1030

    Use _cairo_pattern_create_copy() in cairo-surface.c
    
    Use _cairo_pattern_create_copy()/cairo_pattern_destroy() instead of
    _cairo_pattern_init_copy()/_cairo_pattern_fini() so the PDF backend
    can reference the patterns and destroy them later.

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index e68880a..f6f26c7 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -86,7 +86,7 @@ DEFINE_NIL_SURFACE(CAIRO_STATUS_WRITE_ERROR, _cairo_surface_nil_write_error);
 static cairo_status_t
 _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
 					     cairo_surface_t *destination,
-					     cairo_pattern_t *pattern_out);
+					     cairo_pattern_t **pattern_out);
 
 /**
  * _cairo_surface_set_error:
@@ -1395,24 +1395,24 @@ _cairo_surface_paint (cairo_surface_t	*surface,
 		      cairo_pattern_t	*source)
 {
     cairo_status_t status;
-    cairo_pattern_union_t dev_source;
+    cairo_pattern_t *dev_source;
 
     assert (! surface->is_snapshot);
 
-    status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
+    status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source);
     if (status)
 	return _cairo_surface_set_error (surface, status);
 
     if (surface->backend->paint) {
-	status = surface->backend->paint (surface, op, &dev_source.base);
+	status = surface->backend->paint (surface, op, dev_source);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
             goto FINISH;
     }
 
-    status = _cairo_surface_fallback_paint (surface, op, &dev_source.base);
+    status = _cairo_surface_fallback_paint (surface, op, dev_source);
 
  FINISH:
-    _cairo_pattern_fini (&dev_source.base);
+    cairo_pattern_destroy (dev_source);
 
     return _cairo_surface_set_error (surface, status);
 }
@@ -1424,31 +1424,31 @@ _cairo_surface_mask (cairo_surface_t	*surface,
 		     cairo_pattern_t	*mask)
 {
     cairo_status_t status;
-    cairo_pattern_union_t dev_source;
-    cairo_pattern_union_t dev_mask;
+    cairo_pattern_t *dev_source;
+    cairo_pattern_t *dev_mask;
 
     assert (! surface->is_snapshot);
 
-    status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
+    status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source);
     if (status)
 	goto FINISH;
 
-    status = _cairo_surface_copy_pattern_for_destination (mask, surface, &dev_mask.base);
+    status = _cairo_surface_copy_pattern_for_destination (mask, surface, &dev_mask);
     if (status)
 	goto CLEANUP_SOURCE;
 
     if (surface->backend->mask) {
-	status = surface->backend->mask (surface, op, &dev_source.base, &dev_mask.base);
+	status = surface->backend->mask (surface, op, dev_source, dev_mask);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
             goto CLEANUP_MASK;
     }
 
-    status = _cairo_surface_fallback_mask (surface, op, &dev_source.base, &dev_mask.base);
+    status = _cairo_surface_fallback_mask (surface, op, dev_source, dev_mask);
 
  CLEANUP_MASK:
-    _cairo_pattern_fini (&dev_mask.base);
+    cairo_pattern_destroy (dev_mask);
  CLEANUP_SOURCE:
-    _cairo_pattern_fini (&dev_source.base);
+    cairo_pattern_destroy (dev_source);
  FINISH:
 
     return _cairo_surface_set_error (surface, status);
@@ -1473,29 +1473,29 @@ _cairo_surface_fill_stroke (cairo_surface_t	    *surface,
     cairo_status_t status;
 
     if (surface->backend->fill_stroke) {
-	cairo_pattern_union_t dev_stroke_source;
-	cairo_pattern_union_t dev_fill_source;
+	cairo_pattern_t *dev_stroke_source;
+	cairo_pattern_t *dev_fill_source;
 	cairo_matrix_t dev_ctm = *stroke_ctm;
 	cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
 
-	status = _cairo_surface_copy_pattern_for_destination (stroke_source, surface, &dev_stroke_source.base);
+	status = _cairo_surface_copy_pattern_for_destination (stroke_source, surface, &dev_stroke_source);
 	if (status)
 	    return _cairo_surface_set_error (surface, status);
 
-	status = _cairo_surface_copy_pattern_for_destination (fill_source, surface, &dev_fill_source.base);
+	status = _cairo_surface_copy_pattern_for_destination (fill_source, surface, &dev_fill_source);
 	if (status) {
-	    _cairo_pattern_fini (&dev_stroke_source.base);
+	    cairo_pattern_destroy (dev_stroke_source);
 	    return _cairo_surface_set_error (surface, status);
 	}
 
-	status = surface->backend->fill_stroke (surface, fill_op, &dev_fill_source.base,
+	status = surface->backend->fill_stroke (surface, fill_op, dev_fill_source,
 						fill_rule, fill_tolerance, fill_antialias,
-						path, stroke_op, &dev_stroke_source.base, stroke_style,
+						path, stroke_op, dev_stroke_source, stroke_style,
 						&dev_ctm, &dev_ctm_inverse, stroke_tolerance,
 						stroke_antialias);
 
-	_cairo_pattern_fini (&dev_stroke_source.base);
-	_cairo_pattern_fini (&dev_fill_source.base);
+	cairo_pattern_destroy (dev_stroke_source);
+	cairo_pattern_destroy (dev_fill_source);
 
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return _cairo_surface_set_error (surface, status);
@@ -1527,7 +1527,7 @@ _cairo_surface_stroke (cairo_surface_t		*surface,
 		       cairo_antialias_t	 antialias)
 {
     cairo_status_t status;
-    cairo_pattern_union_t dev_source;
+    cairo_pattern_t *dev_source;
     cairo_path_fixed_t *dev_path = path;
     cairo_path_fixed_t real_dev_path;
     cairo_matrix_t dev_ctm = *ctm;
@@ -1535,12 +1535,12 @@ _cairo_surface_stroke (cairo_surface_t		*surface,
 
     assert (! surface->is_snapshot);
 
-    status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
+    status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source);
     if (status)
 	return _cairo_surface_set_error (surface, status);
 
     if (surface->backend->stroke) {
-	status = surface->backend->stroke (surface, op, &dev_source.base,
+	status = surface->backend->stroke (surface, op, dev_source,
 					   path, stroke_style,
 					   &dev_ctm, &dev_ctm_inverse,
 					   tolerance, antialias);
@@ -1549,7 +1549,7 @@ _cairo_surface_stroke (cairo_surface_t		*surface,
             goto FINISH;
     }
 
-    status = _cairo_surface_fallback_stroke (surface, op, &dev_source.base,
+    status = _cairo_surface_fallback_stroke (surface, op, dev_source,
                                              path, stroke_style,
                                              &dev_ctm, &dev_ctm_inverse,
                                              tolerance, antialias);
@@ -1557,7 +1557,7 @@ _cairo_surface_stroke (cairo_surface_t		*surface,
  FINISH:
     if (dev_path == &real_dev_path)
         _cairo_path_fixed_fini (&real_dev_path);
-    _cairo_pattern_fini (&dev_source.base);
+    cairo_pattern_destroy (dev_source);
 
     return _cairo_surface_set_error (surface, status);
 }
@@ -1572,16 +1572,16 @@ _cairo_surface_fill (cairo_surface_t	*surface,
 		     cairo_antialias_t	 antialias)
 {
     cairo_status_t status;
-    cairo_pattern_union_t dev_source;
+    cairo_pattern_t *dev_source;
 
     assert (! surface->is_snapshot);
 
-    status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
+    status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source);
     if (status)
 	return _cairo_surface_set_error (surface, status);
 
     if (surface->backend->fill) {
-	status = surface->backend->fill (surface, op, &dev_source.base,
+	status = surface->backend->fill (surface, op, dev_source,
 					 path, fill_rule,
 					 tolerance, antialias);
 
@@ -1589,12 +1589,12 @@ _cairo_surface_fill (cairo_surface_t	*surface,
             goto FINISH;
     }
 
-    status = _cairo_surface_fallback_fill (surface, op, &dev_source.base,
+    status = _cairo_surface_fallback_fill (surface, op, dev_source,
                                            path, fill_rule,
                                            tolerance, antialias);
 
  FINISH:
-    _cairo_pattern_fini (&dev_source.base);
+    cairo_pattern_destroy (dev_source);
 
     return _cairo_surface_set_error (surface, status);
 }
@@ -2045,7 +2045,7 @@ _cairo_surface_show_glyphs (cairo_surface_t	*surface,
 {
     cairo_status_t status;
     cairo_scaled_font_t *dev_scaled_font = scaled_font;
-    cairo_pattern_union_t dev_source;
+    cairo_pattern_t *dev_source;
     cairo_matrix_t font_matrix;
 
     assert (! surface->is_snapshot);
@@ -2055,7 +2055,7 @@ _cairo_surface_show_glyphs (cairo_surface_t	*surface,
 
     status = _cairo_surface_copy_pattern_for_destination (source,
 						          surface,
-							  &dev_source.base);
+							  &dev_source);
     if (status)
 	return _cairo_surface_set_error (surface, status);
 
@@ -2080,7 +2080,7 @@ _cairo_surface_show_glyphs (cairo_surface_t	*surface,
     }
     status = cairo_scaled_font_status (dev_scaled_font);
     if (status) {
-	_cairo_pattern_fini (&dev_source.base);
+	cairo_pattern_destroy (dev_source);
 	return _cairo_surface_set_error (surface, status);
     }
 
@@ -2089,12 +2089,12 @@ _cairo_surface_show_glyphs (cairo_surface_t	*surface,
     status = CAIRO_INT_STATUS_UNSUPPORTED;
 
     if (surface->backend->show_glyphs)
-	status = surface->backend->show_glyphs (surface, op, &dev_source.base,
+	status = surface->backend->show_glyphs (surface, op, dev_source,
 						glyphs, num_glyphs,
                                                 dev_scaled_font);
 
     if (status == CAIRO_INT_STATUS_UNSUPPORTED)
-	status = _cairo_surface_fallback_show_glyphs (surface, op, &dev_source.base,
+	status = _cairo_surface_fallback_show_glyphs (surface, op, dev_source,
 						      glyphs, num_glyphs,
 						      dev_scaled_font);
 
@@ -2103,7 +2103,7 @@ _cairo_surface_show_glyphs (cairo_surface_t	*surface,
     if (dev_scaled_font != scaled_font)
 	cairo_scaled_font_destroy (dev_scaled_font);
 
-    _cairo_pattern_fini (&dev_source.base);
+    cairo_pattern_destroy (dev_source);
 
     return _cairo_surface_set_error (surface, status);
 }
@@ -2370,11 +2370,11 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t            *dst,
 static cairo_status_t
 _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
                                              cairo_surface_t *destination,
-                                             cairo_pattern_t *pattern_out)
+                                             cairo_pattern_t **pattern_out)
 {
     cairo_status_t status;
 
-    status = _cairo_pattern_init_copy (pattern_out, pattern);
+    status = _cairo_pattern_create_copy (pattern_out, pattern);
     if (status)
 	return status;
 
@@ -2387,7 +2387,7 @@ _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
 	 * matrix should always be invertible. */
 	assert (status == CAIRO_STATUS_SUCCESS);
 
-	_cairo_pattern_transform (pattern_out, &device_to_surface);
+	_cairo_pattern_transform (*pattern_out, &device_to_surface);
     }
 
     return CAIRO_STATUS_SUCCESS;
commit 6ead8feaf3f87e12e686092386dddcc2faa62b7f
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Jan 7 20:41:43 2008 +1030

    Add _cairo_pattern_create_copy()

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 488177b..f5d17dd 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -213,6 +213,34 @@ _cairo_pattern_fini (cairo_pattern_t *pattern)
     }
 }
 
+cairo_status_t
+_cairo_pattern_create_copy (cairo_pattern_t	  **pattern,
+			    const cairo_pattern_t  *other)
+{
+    if (other->status)
+	return other->status;
+
+    switch (other->type) {
+    case CAIRO_PATTERN_TYPE_SOLID:
+	*pattern = malloc (sizeof (cairo_solid_pattern_t));
+	break;
+    case CAIRO_PATTERN_TYPE_SURFACE:
+	*pattern = malloc (sizeof (cairo_surface_pattern_t));
+	break;
+    case CAIRO_PATTERN_TYPE_LINEAR:
+	*pattern = malloc (sizeof (cairo_linear_pattern_t));
+	break;
+    case CAIRO_PATTERN_TYPE_RADIAL:
+	*pattern = malloc (sizeof (cairo_radial_pattern_t));
+	break;
+    }
+    if (*pattern == NULL)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    return _cairo_pattern_init_copy (*pattern, other);
+}
+
+
 void
 _cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
 			   const cairo_color_t	 *color,
diff --git a/src/cairoint.h b/src/cairoint.h
index 6d5bc2c..19513a7 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2223,6 +2223,10 @@ _cairo_slope_counter_clockwise (cairo_slope_t *a, cairo_slope_t *b);
 /* cairo_pattern.c */
 
 cairo_private cairo_status_t
+_cairo_pattern_create_copy (cairo_pattern_t	  **pattern,
+			    const cairo_pattern_t  *other);
+
+cairo_private cairo_status_t
 _cairo_pattern_init_copy (cairo_pattern_t	*pattern,
 			  const cairo_pattern_t *other);
 
commit 26c6159b1e2f5481fb18f5f06f01063002dd6c98
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Jan 7 20:36:32 2008 +1030

    Move the PDF drawing operators into cairo-pdf-operators.c
    
    By defining PostScript functions the same as the PDF drawing
    operators, this code can be shared by both the PDF and PS backends.

diff --git a/src/Makefile.am b/src/Makefile.am
index e00bcfb..243dc56 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,6 +22,7 @@ endif
 if CAIRO_HAS_PDF_SURFACE
 libcairo_pdf_headers = cairo-pdf.h
 libcairo_pdf_sources = cairo-pdf-surface.c cairo-pdf-surface-private.h \
+	               cairo-pdf-operators.c cairo-pdf-operators-private.h \
 		       cairo-deflate-stream.c
 libcairo_font_subset_sources =	$(font_subset_sources)
 backend_pkgconfigs += cairo-pdf.pc
diff --git a/src/cairo-pdf-operators-private.h b/src/cairo-pdf-operators-private.h
new file mode 100644
index 0000000..835d395
--- /dev/null
+++ b/src/cairo-pdf-operators-private.h
@@ -0,0 +1,106 @@
+/* -*- 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
+ *
+ * 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):
+ *	Kristian Høgsberg <krh at redhat.com>
+ *	Carl Worth <cworth at cworth.org>
+ *	Adrian Johnson <ajohnson at redneon.com>
+ */
+
+#ifndef CAIRO_PDF_OPERATORS_H
+#define CAIRO_PDF_OPERATORS_H
+
+#include "cairoint.h"
+
+typedef cairo_status_t
+(*cairo_pdf_operators_use_font_subset_t) (unsigned int  font_id,
+					  unsigned int  subset_id,
+					  void         *closure);
+
+typedef struct _cairo_pdf_operators {
+    cairo_output_stream_t *stream;
+    cairo_matrix_t cairo_to_pdf;
+    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_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,
+						void				     *closure);
+
+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_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_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_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 */
diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c
new file mode 100644
index 0000000..3c06e72
--- /dev/null
+++ b/src/cairo-pdf-operators.c
@@ -0,0 +1,531 @@
+/* -*- 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
+ *
+ * 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):
+ *	Kristian Høgsberg <krh at redhat.com>
+ *	Carl Worth <cworth at cworth.org>
+ *	Adrian Johnson <ajohnson at redneon.com>
+ */
+
+#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"
+
+void
+_cairo_pdf_operators_init (cairo_pdf_operators_t 	*pdf_operators,
+			   cairo_output_stream_t   	*stream,
+			   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->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)
+{
+}
+
+void
+_cairo_pdf_operators_set_font_subsets_callback (cairo_pdf_operators_t 		     *pdf_operators,
+						cairo_pdf_operators_use_font_subset_t use_font_subset,
+						void				     *closure)
+{
+    pdf_operators->use_font_subset = use_font_subset;
+    pdf_operators->use_font_subset_closure = closure;
+}
+
+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)
+{
+    pdf_operators->cairo_to_pdf = cairo_to_pdf;
+}
+
+typedef struct _pdf_path_info {
+    cairo_output_stream_t   *output;
+    cairo_matrix_t	    *cairo_to_pdf;
+    cairo_matrix_t	    *ctm_inverse;
+} 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);
+
+    _cairo_output_stream_printf (info->output,
+				 "%f %f m ", x, y);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+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);
+
+    _cairo_output_stream_printf (info->output,
+				 "%f %f l ", x, y);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_path_curve_to (void          *closure,
+			  cairo_point_t *b,
+			  cairo_point_t *c,
+			  cairo_point_t *d)
+{
+    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);
+    }
+
+    _cairo_output_stream_printf (info->output,
+				 "%f %f %f %f %f %f c ",
+				 bx, by, cx, cy, dx, dy);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_path_close_path (void *closure)
+{
+    pdf_path_info_t *info = closure;
+
+    _cairo_output_stream_printf (info->output,
+				 "h\r\n");
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+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;
+
+    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);
+	if (status)
+	    return status;
+    }
+
+    switch (fill_rule) {
+    case CAIRO_FILL_RULE_WINDING:
+	pdf_operator = "W";
+	break;
+    case CAIRO_FILL_RULE_EVEN_ODD:
+	pdf_operator = "W*";
+	break;
+    default:
+	ASSERT_NOT_REACHED;
+    }
+
+    _cairo_output_stream_printf (pdf_operators->stream,
+				 "%s n\r\n",
+				 pdf_operator);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static int
+_cairo_pdf_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_pdf_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_pdf_operators_emit_stroke_style (cairo_pdf_operators_t 	*pdf_operators,
+					cairo_stroke_style_t	*style)
+{
+    _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;
+	_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]);
+	_cairo_output_stream_printf (pdf_operators->stream, "] %f d\r\n",
+				     style->dash_offset);
+    } else {
+	_cairo_output_stream_printf (pdf_operators->stream, "[] 0.0 d\r\n");
+    }
+
+    _cairo_output_stream_printf (pdf_operators->stream,
+				 "%f M ",
+				 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)
+{
+    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)
+	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);
+    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);
+    if (status)
+	return status;
+
+    switch (fill_rule) {
+    case CAIRO_FILL_RULE_WINDING:
+	pdf_operator = "f";
+	break;
+    case CAIRO_FILL_RULE_EVEN_ODD:
+	pdf_operator = "f*";
+	break;
+    default:
+	ASSERT_NOT_REACHED;
+    }
+
+    _cairo_output_stream_printf (pdf_operators->stream,
+				 "%s\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;
+
+    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,
+				 "BT\r\n");
+
+    if (scaled_font->scale.xy == 0.0 &&
+        scaled_font->scale.yx == 0.0)
+        diagonal = TRUE;
+    else
+        diagonal = FALSE;
+
+    in_TJ = FALSE;
+    for (i = 0; i < num_glyphs; i++) {
+        status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
+                                                       scaled_font, glyphs[i].index,
+                                                       &subset_glyph);
+	if (status)
+            return status;
+
+        if (subset_glyph.is_composite)
+            hex_width = 4;
+        else
+            hex_width = 2;
+
+        if (subset_glyph.is_scaled == FALSE) {
+            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");
+                in_TJ = FALSE;
+            }
+	    _cairo_output_stream_printf (pdf_operators->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,
+                                         "%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;
+            Tlm_x = glyphs[i].x;
+            Tlm_y = glyphs[i].y;
+            Tm_x = Tlm_x;
+        }
+
+        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,
+                                                     "%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,
+                                                 "[<%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,
+                                                     "> %f <",
+                                                     -1000.0*delta/scaled_font->scale.xx);
+                        Tm_x += delta;
+                    }
+                    _cairo_output_stream_printf (pdf_operators->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,
+                                                     "> %f <",
+                                                     -1000.0*delta/scaled_font->scale.xx);
+                        Tm_x += delta;
+                    }
+                    _cairo_output_stream_printf (pdf_operators->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,
+                                                     "%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,
+                                                 "<%0*x> Tj ",
+                                                 hex_width,
+                                                 subset_glyph.subset_glyph_index);
+                    Tm_x += subset_glyph.x_advance;
+                }
+            }
+        } else {
+            _cairo_output_stream_printf (pdf_operators->stream,
+                                         "<%0*x> Tj\r\n",
+                                         hex_width,
+                                         subset_glyph.subset_glyph_index);
+        }
+    }
+
+    _cairo_output_stream_printf (pdf_operators->stream,
+				 "ET\r\n");
+
+    return _cairo_output_stream_get_status (pdf_operators->stream);
+}
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index 28b6fd1..d4318d6 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -44,6 +44,7 @@
 #include "cairo-pdf.h"
 
 #include "cairo-surface-private.h"
+#include "cairo-pdf-operators-private.h"
 
 typedef struct _cairo_pdf_resource {
     unsigned int id;
@@ -124,7 +125,7 @@ struct _cairo_pdf_surface {
 
     cairo_array_t *current_group;
     cairo_pdf_group_resources_t *current_resources;
-
+    cairo_pdf_operators_t pdf_operators;
     cairo_paginated_mode_t paginated_mode;
 
     cairo_bool_t force_fallbacks;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 75a58d3..2e5cd2b 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -41,9 +41,9 @@
 #include "cairoint.h"
 #include "cairo-pdf.h"
 #include "cairo-pdf-surface-private.h"
+#include "cairo-pdf-operators-private.h"
 #include "cairo-scaled-font-subsets-private.h"
 #include "cairo-paginated-private.h"
-#include "cairo-path-fixed-private.h"
 #include "cairo-output-stream-private.h"
 #include "cairo-meta-surface-private.h"
 
@@ -225,6 +225,11 @@ _cairo_pdf_group_element_array_finish (cairo_array_t *array);
 static void
 _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
 
+static cairo_status_t
+_cairo_pdf_surface_add_font (unsigned int        font_id,
+			     unsigned int        subset_id,
+			     void 		*closure);
+
 static void
 _cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res);
 
@@ -360,6 +365,14 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
 
     surface->force_fallbacks = FALSE;
 
+    _cairo_pdf_operators_init (&surface->pdf_operators,
+			       surface->output,
+			       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");
@@ -527,6 +540,8 @@ cairo_pdf_surface_set_size (cairo_surface_t	*surface,
     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);
     status = _cairo_paginated_surface_set_size (pdf_surface->paginated_surface,
 						width_in_points,
 						height_in_points);
@@ -623,10 +638,11 @@ _cairo_pdf_surface_add_xobject (cairo_pdf_surface_t  *surface,
 }
 
 static cairo_status_t
-_cairo_pdf_surface_add_font (cairo_pdf_surface_t *surface,
-			     unsigned int         font_id,
-			     unsigned int         subset_id)
+_cairo_pdf_surface_add_font (unsigned int        font_id,
+			     unsigned int        subset_id,
+			     void 		*closure)
 {
+    cairo_pdf_surface_t *surface = closure;
     cairo_pdf_font_t font;
     int num_fonts, i;
     cairo_status_t status;
@@ -821,6 +837,7 @@ _cairo_pdf_surface_open_stream (cairo_pdf_surface_t	*surface,
 	assert (surface->pdf_stream.old_output == NULL);
         surface->pdf_stream.old_output = surface->output;
         surface->output = output;
+	_cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
     }
 
     return surface->pdf_stream.self;
@@ -838,6 +855,7 @@ _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
     if (surface->pdf_stream.compressed) {
 	status = _cairo_output_stream_destroy (surface->output);
 	surface->output = surface->pdf_stream.old_output;
+	_cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
 	surface->pdf_stream.old_output = NULL;
 	_cairo_output_stream_printf (surface->output,
 				     "\r\n");
@@ -938,6 +956,7 @@ _cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface)
 
     surface->group_stream.old_output = surface->output;
     surface->output = surface->group_stream.stream;
+    _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
     _cairo_pdf_group_resources_clear (&surface->group_stream.resources);
     surface->current_resources = &surface->group_stream.resources;
     surface->group_stream.is_knockout = FALSE;
@@ -980,6 +999,7 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
 				     "\r\n");
     }
     surface->output = surface->group_stream.old_output;
+    _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
     surface->group_stream.active = FALSE;
     *group = _cairo_pdf_surface_write_memory_stream (surface,
 						     surface->group_stream.mem_stream,
@@ -1057,6 +1077,7 @@ _cairo_pdf_surface_start_content_stream (cairo_pdf_surface_t *surface)
 
     surface->content_stream.old_output = surface->output;
     surface->output = surface->content_stream.stream;
+    _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
     _cairo_pdf_group_resources_clear (&surface->content_stream.resources);
     surface->current_resources = &surface->content_stream.resources;
 
@@ -1085,6 +1106,7 @@ _cairo_pdf_surface_pause_content_stream (cairo_pdf_surface_t *surface)
 	return;
 
     surface->output = surface->content_stream.old_output;
+    _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
     surface->content_stream.active = FALSE;
 }
 
@@ -1097,6 +1119,7 @@ _cairo_pdf_surface_resume_content_stream (cairo_pdf_surface_t *surface)
 	return;
 
     surface->output = surface->content_stream.stream;
+    _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
     surface->current_resources = &surface->content_stream.resources;
     surface->content_stream.active = TRUE;
 }
@@ -1120,6 +1143,7 @@ _cairo_pdf_surface_stop_content_stream (cairo_pdf_surface_t *surface)
 				     "\r\n");
     }
     surface->output = surface->content_stream.old_output;
+    _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
     surface->content_stream.active = FALSE;
     if (_cairo_memory_stream_length (surface->content_stream.mem_stream) > 0) {
 	group = _cairo_pdf_surface_write_memory_stream (surface,
@@ -1222,6 +1246,8 @@ _cairo_pdf_surface_finish (void *abstract_surface)
 				 "%%%%EOF\r\n",
 				 offset);
 
+     _cairo_pdf_operators_fini (&surface->pdf_operators);
+
     /* close any active streams still open due to fatal errors */
     status2 = _cairo_pdf_surface_close_stream (surface);
     if (status == CAIRO_STATUS_SUCCESS)
@@ -1637,6 +1663,8 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
     surface->width = meta_extents.width;
     surface->height = meta_extents.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);
 
     status = _cairo_pdf_surface_start_content_stream (surface);
     if (status)
@@ -1681,6 +1709,8 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
     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);
 
     _cairo_pdf_group_element_array_finish (&group);
     _cairo_array_fini (&group);
@@ -2810,89 +2840,6 @@ _cairo_pdf_surface_get_extents (void		        *abstract_surface,
     return CAIRO_STATUS_SUCCESS;
 }
 
-typedef struct _pdf_path_info {
-    cairo_output_stream_t   *output;
-    cairo_matrix_t	    *cairo_to_pdf;
-    cairo_matrix_t	    *ctm_inverse;
-} 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);
-
-    _cairo_output_stream_printf (info->output,
-				 "%f %f m ", x, y);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-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);
-
-    _cairo_output_stream_printf (info->output,
-				 "%f %f l ", x, y);
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_pdf_path_curve_to (void          *closure,
-			  cairo_point_t *b,
-			  cairo_point_t *c,
-			  cairo_point_t *d)
-{
-    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);
-    }
-
-    _cairo_output_stream_printf (info->output,
-				 "%f %f %f %f %f %f c ",
-				 bx, by, cx, cy, dx, dy);
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_pdf_path_close_path (void *closure)
-{
-    pdf_path_info_t *info = closure;
-
-    _cairo_output_stream_printf (info->output,
-				 "h\r\n");
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
 static cairo_status_t
 _cairo_pdf_surface_add_clip (cairo_pdf_surface_t  *surface,
 			     cairo_path_fixed_t	  *path,
@@ -3976,51 +3923,12 @@ _cairo_pdf_surface_emit_clip (cairo_pdf_surface_t  *surface,
 			      cairo_path_fixed_t   *path,
 			      cairo_fill_rule_t	    fill_rule)
 {
-    const char *pdf_operator;
-
     if (path == NULL) {
 	_cairo_output_stream_printf (surface->output, "Q q\r\n");
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    if (! path->has_current_point) {
-	/* construct an empty path */
-	_cairo_output_stream_printf (surface->output, "0 0 m ");
-    } else {
-	pdf_path_info_t info;
-	cairo_status_t status;
-
-	info.output = surface->output;
-	info.cairo_to_pdf = &surface->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);
-	if (status)
-	    return status;
-    }
-
-    switch (fill_rule) {
-    case CAIRO_FILL_RULE_WINDING:
-	pdf_operator = "W";
-	break;
-    case CAIRO_FILL_RULE_EVEN_ODD:
-	pdf_operator = "W*";
-	break;
-    default:
-	ASSERT_NOT_REACHED;
-    }
-
-    _cairo_output_stream_printf (surface->output,
-				 "%s n\r\n",
-				 pdf_operator);
-
-    return CAIRO_STATUS_SUCCESS;
+    return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule);
 }
 
 static cairo_status_t
@@ -4512,71 +4420,6 @@ _cairo_pdf_surface_mask	(void			*abstract_surface,
     return _cairo_output_stream_get_status (surface->output);
 }
 
-static int
-_cairo_pdf_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_pdf_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_status_t
-_cairo_pdf_surface_emit_stroke_style (cairo_pdf_surface_t	*surface,
-				      cairo_stroke_style_t	*style)
-{
-    _cairo_output_stream_printf (surface->output,
-				 "%f w\r\n",
-				 style->line_width);
-
-    _cairo_output_stream_printf (surface->output,
-				 "%d J\r\n",
-				 _cairo_pdf_line_cap (style->line_cap));
-
-    _cairo_output_stream_printf (surface->output,
-				 "%d j\r\n",
-				 _cairo_pdf_line_join (style->line_join));
-
-    if (style->num_dashes) {
-	unsigned int d;
-	_cairo_output_stream_printf (surface->output, "[");
-	for (d = 0; d < style->num_dashes; d++)
-	    _cairo_output_stream_printf (surface->output, " %f", style->dash[d]);
-	_cairo_output_stream_printf (surface->output, "] %f d\r\n",
-				     style->dash_offset);
-    } else {
-	_cairo_output_stream_printf (surface->output, "[] 0.0 d\r\n");
-    }
-
-    _cairo_output_stream_printf (surface->output,
-				 "%f M ",
-				 style->miter_limit);
-
-    return _cairo_output_stream_get_status (surface->output);
-}
 
 static cairo_int_status_t
 _cairo_pdf_surface_stroke (void			*abstract_surface,
@@ -4591,9 +4434,7 @@ _cairo_pdf_surface_stroke (void			*abstract_surface,
 {
     cairo_pdf_surface_t *surface = abstract_surface;
     cairo_pdf_resource_t smask_group = {0}; /* squelch bogus compiler warning */
-    pdf_path_info_t info;
     cairo_status_t status;
-    cairo_matrix_t m;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_pdf_surface_analyze_operation (surface, op, source);
@@ -4620,33 +4461,14 @@ _cairo_pdf_surface_stroke (void			*abstract_surface,
     if (status)
 	return status;
 
-    status = _cairo_pdf_surface_emit_stroke_style (surface,
-						   style);
-    if (status)
-	return status;
-
-    info.output = surface->output;
-    info.cairo_to_pdf = NULL;
-    info.ctm_inverse = ctm_inverse;
-
-    cairo_matrix_multiply (&m, ctm, &surface->cairo_to_pdf);
-    _cairo_output_stream_printf (surface->output,
-				 "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_operator_stroke (&surface->pdf_operators,
+					 path,
+					 style,
+					 ctm,
+					 ctm_inverse);
     if (status)
 	return status;
 
-    _cairo_output_stream_printf (surface->output, "S Q\r\n");
-
     if (surface->emitted_pattern.smask.id != 0) {
 	status = _cairo_pdf_surface_close_group (surface, &smask_group);
 	if (status)
@@ -4685,9 +4507,7 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
 {
     cairo_pdf_surface_t *surface = abstract_surface;
     cairo_pdf_resource_t smask_group = {0}; /* squelch bogus compiler warning */
-    const char *pdf_operator;
     cairo_status_t status;
-    pdf_path_info_t info;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_pdf_surface_analyze_operation (surface, op, source);
@@ -4718,34 +4538,10 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
     if (status)
 	return status;
 
-    info.output = surface->output;
-    info.cairo_to_pdf = &surface->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_fill (&surface->pdf_operators, path, fill_rule);
     if (status)
 	return status;
 
-    switch (fill_rule) {
-    case CAIRO_FILL_RULE_WINDING:
-	pdf_operator = "f";
-	break;
-    case CAIRO_FILL_RULE_EVEN_ODD:
-	pdf_operator = "f*";
-	break;
-    default:
-	ASSERT_NOT_REACHED;
-    }
-
-    _cairo_output_stream_printf (surface->output,
-				 "%s\r\n",
-				 pdf_operator);
-
     if (surface->emitted_pattern.smask.id != 0) {
 	status = _cairo_pdf_surface_close_group (surface, &smask_group);
 	if (status)
@@ -4773,8 +4569,6 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
     return _cairo_pdf_surface_check_content_stream_size (surface);
 }
 
-#define GLYPH_POSITION_TOLERANCE 0.001
-
 static cairo_int_status_t
 _cairo_pdf_surface_show_glyphs (void			*abstract_surface,
 				cairo_operator_t	 op,
@@ -4785,13 +4579,7 @@ _cairo_pdf_surface_show_glyphs (void			*abstract_surface,
 {
     cairo_pdf_surface_t *surface = abstract_surface;
     cairo_pdf_resource_t smask_group = {0}; /* squelch bogus compiler warning */
-    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;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_pdf_surface_analyze_operation (surface, op, source);
@@ -4818,148 +4606,12 @@ _cairo_pdf_surface_show_glyphs (void			*abstract_surface,
     if (status)
 	return status;
 
-    _cairo_output_stream_printf (surface->output,
-				 "BT\r\n");
-
-    if (scaled_font->scale.xy == 0.0 &&
-        scaled_font->scale.yx == 0.0)
-        diagonal = TRUE;
-    else
-        diagonal = FALSE;
-
-    in_TJ = FALSE;
-    for (i = 0; i < num_glyphs; i++) {
-        status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
-                                                       scaled_font, glyphs[i].index,
-                                                       &subset_glyph);
-	if (status)
-            return status;
-
-        if (subset_glyph.is_composite)
-            hex_width = 4;
-        else
-            hex_width = 2;
-
-        if (subset_glyph.is_scaled == FALSE) {
-            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 (surface->output, ">] TJ\r\n");
-                in_TJ = FALSE;
-            }
-	    _cairo_output_stream_printf (surface->output,
-					 "/f-%d-%d 1 Tf\r\n",
-					 subset_glyph.font_id,
-					 subset_glyph.subset_id);
-	    status = _cairo_pdf_surface_add_font (surface,
-					          subset_glyph.font_id,
-						  subset_glyph.subset_id);
-	    if (status)
-		return status;
-        }
-
-        if (subset_glyph.subset_id != current_subset_id || !diagonal) {
-            _cairo_output_stream_printf (surface->output,
-                                         "%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,
-                                         surface->height - glyphs[i].y);
-            current_subset_id = subset_glyph.subset_id;
-            Tlm_x = glyphs[i].x;
-            Tlm_y = glyphs[i].y;
-            Tm_x = Tlm_x;
-        }
-
-        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 (surface->output,
-                                                     "%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 (surface->output,
-                                                 "[<%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 (surface->output,
-                                                     "> %f <",
-                                                     -1000.0*delta/scaled_font->scale.xx);
-                        Tm_x += delta;
-                    }
-                    _cairo_output_stream_printf (surface->output,
-                                                 "%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 (surface->output,
-                                                     "> %f <",
-                                                     -1000.0*delta/scaled_font->scale.xx);
-                        Tm_x += delta;
-                    }
-                    _cairo_output_stream_printf (surface->output,
-                                                 "%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 (surface->output,
-                                                     "%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 (surface->output,
-                                                 "<%0*x> Tj ",
-                                                 hex_width,
-                                                 subset_glyph.subset_glyph_index);
-                    Tm_x += subset_glyph.x_advance;
-                }
-            }
-        } else {
-            _cairo_output_stream_printf (surface->output,
-                                         "<%0*x> Tj\r\n",
-                                         hex_width,
-                                         subset_glyph.subset_glyph_index);
-        }
-    }
-
-    _cairo_output_stream_printf (surface->output,
-				 "ET\r\n");
+    status = _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
+					       glyphs,
+					       num_glyphs,
+					       scaled_font);
+    if (status)
+	return status;
 
     if (surface->emitted_pattern.smask.id != 0) {
 	status = _cairo_pdf_surface_close_group (surface, &smask_group);
commit a0e0aae32dfe44cca088736d10d208f328d50a34
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Jan 7 20:34:55 2008 +1030

    PDF: Remove the Type 3 outline glyph code
    
    This code is never used because outline glyphs that go through the
    fallback path are always embedded with Type 1 fallback. The only fonts
    that are embedded as Type 3 are bitmap fonts.

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 66959b3..75a58d3 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -3605,60 +3605,6 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t		*surface,
 }
 
 static cairo_int_status_t
-_cairo_pdf_surface_emit_outline_glyph (cairo_pdf_surface_t	*surface,
-				       cairo_scaled_font_t	*scaled_font,
-				       unsigned long		 glyph_index,
-				       cairo_pdf_resource_t	*glyph_ret)
-{
-    cairo_scaled_glyph_t *scaled_glyph;
-    pdf_path_info_t info;
-    cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
-    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;
-
-    *glyph_ret = _cairo_pdf_surface_open_stream (surface,
-						 surface->compress_content,
-						 NULL);
-    if (glyph_ret->id == 0)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    _cairo_output_stream_printf (surface->output,
-				 "0 0 %f %f %f %f d1\r\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));
-
-    info.output = surface->output;
-    info.cairo_to_pdf = &surface->cairo_to_pdf;
-    info.ctm_inverse = NULL;
-
-    status = _cairo_path_fixed_interpret (scaled_glyph->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);
-    if (status) {
-	/* ignore status return as we are on the error path... */
-	_cairo_pdf_surface_close_stream (surface);
-	return status;
-    }
-
-    _cairo_output_stream_printf (surface->output,
-				 " f");
-
-    return _cairo_pdf_surface_close_stream (surface);
-}
-
-static cairo_int_status_t
 _cairo_pdf_surface_emit_bitmap_glyph (cairo_pdf_surface_t	*surface,
 				      cairo_scaled_font_t	*scaled_font,
 				      unsigned long		 glyph_index,
@@ -3748,30 +3694,6 @@ _cairo_pdf_surface_emit_bitmap_glyph (cairo_pdf_surface_t	*surface,
 }
 
 static cairo_status_t
-_cairo_pdf_surface_emit_glyph (cairo_pdf_surface_t	*surface,
-			       cairo_scaled_font_t	*scaled_font,
-			       unsigned long		 glyph_index,
-			       cairo_pdf_resource_t	*glyph_ret,
-                               cairo_box_t              *bbox,
-                               double                   *width)
-{
-    cairo_status_t status;
-
-    status = _cairo_pdf_surface_emit_outline_glyph (surface,
-						    scaled_font,
-						    glyph_index,
-						    glyph_ret);
-    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
-	status = _cairo_pdf_surface_emit_bitmap_glyph (surface,
-						       scaled_font,
-						       glyph_index,
-						       glyph_ret,
-                                                       bbox,
-                                                       width);
-    return status;
-}
-
-static cairo_status_t
 _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t		*surface,
 					   cairo_scaled_font_subset_t	*font_subset)
 {
@@ -3798,12 +3720,12 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t		*surface,
     }
 
     for (i = 0; i < font_subset->num_glyphs; i++) {
-	status = _cairo_pdf_surface_emit_glyph (surface,
-				                font_subset->scaled_font,
-						font_subset->glyphs[i],
-						&glyphs[i],
-						&bbox,
-						&widths[i]);
+        status = _cairo_pdf_surface_emit_bitmap_glyph (surface,
+                                                       font_subset->scaled_font,
+                                                       font_subset->glyphs[i],
+                                                       &glyphs[i],
+                                                       &bbox,
+                                                       &widths[i]);
 	if (status)
 	    break;
 


More information about the cairo-commit mailing list