summaryrefslogtreecommitdiff
path: root/src/cairo-pdf-surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-pdf-surface.c')
-rw-r--r--src/cairo-pdf-surface.c1119
1 files changed, 822 insertions, 297 deletions
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 2918523..896980a 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -50,6 +50,7 @@
#include "cairo-output-stream-private.h"
#include "cairo-paginated-private.h"
#include "cairo-scaled-font-subsets-private.h"
+#include "cairo-surface-clipper-private.h"
#include "cairo-type3-glyph-surface-private.h"
#include <time.h>
@@ -195,7 +196,7 @@ static cairo_status_t
_cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface);
static cairo_bool_t
-_cairo_pdf_pattern_equal (const void *key_a, const void *key_b);
+_cairo_pdf_source_surface_equal (const void *key_a, const void *key_b);
static const cairo_surface_backend_t cairo_pdf_surface_backend;
static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend;
@@ -243,6 +244,50 @@ _cairo_pdf_surface_set_size_internal (cairo_pdf_surface_t *surface,
&surface->cairo_to_pdf);
}
+static cairo_bool_t
+_path_covers_bbox (cairo_pdf_surface_t *surface,
+ cairo_path_fixed_t *path)
+{
+ cairo_box_t box;
+
+ return _cairo_path_fixed_is_box (path, &box) &&
+ box.p1.x <= 0 &&
+ box.p1.y <= 0 &&
+ box.p2.x >= _cairo_fixed_from_double (surface->width) &&
+ box.p2.y >= _cairo_fixed_from_double (surface->height);
+}
+
+static cairo_status_t
+_cairo_pdf_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_pdf_surface_t *surface = cairo_container_of (clipper,
+ cairo_pdf_surface_t,
+ clipper);
+ cairo_int_status_t status;
+
+ status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+ if (unlikely (status))
+ return status;
+
+ if (path == NULL) {
+ _cairo_output_stream_printf (surface->output, "Q q\n");
+
+ surface->current_pattern_is_solid_color = FALSE;
+ _cairo_pdf_operators_reset (&surface->pdf_operators);
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (_path_covers_bbox (surface, path))
+ return CAIRO_STATUS_SUCCESS;
+
+ return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule);
+}
+
static cairo_surface_t *
_cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
double width,
@@ -275,8 +320,9 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
_cairo_array_init (&surface->knockout_group, sizeof (cairo_pdf_resource_t));
_cairo_array_init (&surface->page_patterns, sizeof (cairo_pdf_pattern_t));
- surface->all_patterns = _cairo_hash_table_create (_cairo_pdf_pattern_equal);
- if (unlikely (surface->all_patterns == NULL)) {
+ _cairo_array_init (&surface->page_surfaces, sizeof (cairo_pdf_source_surface_t));
+ surface->all_surfaces = _cairo_hash_table_create (_cairo_pdf_source_surface_equal);
+ if (unlikely (surface->all_surfaces == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL0;
}
@@ -309,8 +355,12 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->force_fallbacks = FALSE;
surface->select_pattern_gstate_saved = FALSE;
surface->current_pattern_is_solid_color = FALSE;
+ surface->current_operator = CAIRO_OPERATOR_OVER;
surface->header_emitted = FALSE;
+ _cairo_surface_clipper_init (&surface->clipper,
+ _cairo_pdf_surface_clipper_intersect_clip_path);
+
_cairo_pdf_operators_init (&surface->pdf_operators,
surface->output,
&surface->cairo_to_pdf,
@@ -323,7 +373,6 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->paginated_surface = _cairo_paginated_surface_create (
&surface->base,
CAIRO_CONTENT_COLOR_ALPHA,
- width, height,
&cairo_pdf_surface_paginated_backend);
status = surface->paginated_surface->status;
@@ -336,7 +385,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
BAIL2:
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
BAIL1:
- _cairo_hash_table_destroy (surface->all_patterns);
+ _cairo_hash_table_destroy (surface->all_surfaces);
BAIL0:
_cairo_array_fini (&surface->objects);
free (surface);
@@ -570,11 +619,6 @@ cairo_pdf_surface_set_size (cairo_surface_t *surface,
_cairo_pdf_surface_set_size_internal (pdf_surface,
width_in_points,
height_in_points);
- status = _cairo_paginated_surface_set_size (pdf_surface->paginated_surface,
- width_in_points,
- height_in_points);
- if (unlikely (status))
- status = _cairo_surface_set_error (surface, status);
}
static void
@@ -582,6 +626,7 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
{
int i, size;
cairo_pdf_pattern_t *pattern;
+ cairo_pdf_source_surface_t *src_surface;
cairo_pdf_smask_group_t *group;
size = _cairo_array_num_elements (&surface->page_patterns);
@@ -591,6 +636,13 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
}
_cairo_array_truncate (&surface->page_patterns, 0);
+ size = _cairo_array_num_elements (&surface->page_surfaces);
+ for (i = 0; i < size; i++) {
+ src_surface = (cairo_pdf_source_surface_t *) _cairo_array_index (&surface->page_surfaces, i);
+ cairo_surface_destroy (src_surface->surface);
+ }
+ _cairo_array_truncate (&surface->page_surfaces, 0);
+
size = _cairo_array_num_elements (&surface->smask_groups);
for (i = 0; i < size; i++) {
_cairo_array_copy_element (&surface->smask_groups, i, &group);
@@ -603,6 +655,11 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
static void
_cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res)
{
+ int i;
+
+ for (i = 0; i < CAIRO_NUM_OPERATORS; i++)
+ res->operators[i] = FALSE;
+
_cairo_array_init (&res->alphas, sizeof (double));
_cairo_array_init (&res->smasks, sizeof (cairo_pdf_resource_t));
_cairo_array_init (&res->patterns, sizeof (cairo_pdf_resource_t));
@@ -623,6 +680,11 @@ _cairo_pdf_group_resources_fini (cairo_pdf_group_resources_t *res)
static void
_cairo_pdf_group_resources_clear (cairo_pdf_group_resources_t *res)
{
+ int i;
+
+ for (i = 0; i < CAIRO_NUM_OPERATORS; i++)
+ res->operators[i] = FALSE;
+
_cairo_array_truncate (&res->alphas, 0);
_cairo_array_truncate (&res->smasks, 0);
_cairo_array_truncate (&res->patterns, 0);
@@ -630,6 +692,15 @@ _cairo_pdf_group_resources_clear (cairo_pdf_group_resources_t *res)
_cairo_array_truncate (&res->fonts, 0);
}
+static void
+_cairo_pdf_surface_add_operator (cairo_pdf_surface_t *surface,
+ cairo_operator_t op)
+{
+ cairo_pdf_group_resources_t *res = &surface->resources;
+
+ res->operators[op] = TRUE;
+}
+
static cairo_status_t
_cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface,
double alpha,
@@ -738,6 +809,47 @@ _cairo_pdf_surface_get_font_resource (cairo_pdf_surface_t *surface,
return font.subset_resource;
}
+static const char *
+_cairo_operator_to_pdf_blend_mode (cairo_operator_t op)
+{
+ switch (op) {
+ /* The extend blend mode operators */
+ case CAIRO_OPERATOR_MULTIPLY: return "Multiply";
+ case CAIRO_OPERATOR_SCREEN: return "Screen";
+ case CAIRO_OPERATOR_OVERLAY: return "Overlay";
+ case CAIRO_OPERATOR_DARKEN: return "Darken";
+ case CAIRO_OPERATOR_LIGHTEN: return "Lighten";
+ case CAIRO_OPERATOR_COLOR_DODGE: return "ColorDodge";
+ case CAIRO_OPERATOR_COLOR_BURN: return "ColorBurn";
+ case CAIRO_OPERATOR_HARD_LIGHT: return "HardLight";
+ case CAIRO_OPERATOR_SOFT_LIGHT: return "SoftLight";
+ case CAIRO_OPERATOR_DIFFERENCE: return "Difference";
+ case CAIRO_OPERATOR_EXCLUSION: return "Exclusion";
+ case CAIRO_OPERATOR_HSL_HUE: return "Hue";
+ case CAIRO_OPERATOR_HSL_SATURATION: return "Saturation";
+ case CAIRO_OPERATOR_HSL_COLOR: return "Color";
+ case CAIRO_OPERATOR_HSL_LUMINOSITY: return "Luminosity";
+
+ default:
+ /* The original Porter-Duff set */
+ case CAIRO_OPERATOR_CLEAR:
+ case CAIRO_OPERATOR_SOURCE:
+ case CAIRO_OPERATOR_OVER:
+ case CAIRO_OPERATOR_IN:
+ case CAIRO_OPERATOR_OUT:
+ case CAIRO_OPERATOR_ATOP:
+ case CAIRO_OPERATOR_DEST:
+ case CAIRO_OPERATOR_DEST_OVER:
+ case CAIRO_OPERATOR_DEST_IN:
+ case CAIRO_OPERATOR_DEST_OUT:
+ case CAIRO_OPERATOR_DEST_ATOP:
+ case CAIRO_OPERATOR_XOR:
+ case CAIRO_OPERATOR_ADD:
+ case CAIRO_OPERATOR_SATURATE:
+ return "Normal";
+ }
+}
+
static void
_cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t *surface,
cairo_pdf_group_resources_t *res)
@@ -755,6 +867,14 @@ _cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t *surface,
_cairo_output_stream_printf (surface->output,
" /ExtGState <<\n");
+ for (i = 0; i < CAIRO_NUM_OPERATORS; i++) {
+ if (res->operators[i]) {
+ _cairo_output_stream_printf (surface->output,
+ " /b%d << /BM /%s >>\n",
+ i, _cairo_operator_to_pdf_blend_mode(i));
+ }
+ }
+
for (i = 0; i < num_alphas; i++) {
_cairo_array_copy_element (&res->alphas, i, &alpha);
_cairo_output_stream_printf (surface->output,
@@ -873,30 +993,180 @@ _cairo_pdf_surface_add_smask_group (cairo_pdf_surface_t *surface,
}
static cairo_bool_t
-_cairo_pdf_pattern_equal (const void *key_a, const void *key_b)
+_cairo_pdf_source_surface_equal (const void *key_a, const void *key_b)
{
- const cairo_pdf_pattern_entry_t *a = key_a;
- const cairo_pdf_pattern_entry_t *b = key_b;
+ const cairo_pdf_source_surface_entry_t *a = key_a;
+ const cairo_pdf_source_surface_entry_t *b = key_b;
- return a->id == b->id;
+ return (a->id == b->id) && (a->interpolate == b->interpolate);
}
static void
-_cairo_pdf_pattern_init_key (cairo_pdf_pattern_entry_t *key)
+_cairo_pdf_source_surface_init_key (cairo_pdf_source_surface_entry_t *key)
{
key->base.hash = key->id;
}
+static cairo_int_status_t
+_get_jpx_image_info (cairo_surface_t *source,
+ cairo_image_info_t *info,
+ const unsigned char **mime_data,
+ unsigned int *mime_data_length)
+{
+ cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JP2,
+ mime_data, mime_data_length);
+ if (*mime_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return _cairo_image_info_get_jpx_info (info, *mime_data, *mime_data_length);
+}
+
+static cairo_int_status_t
+_get_jpeg_image_info (cairo_surface_t *source,
+ cairo_image_info_t *info,
+ const unsigned char **mime_data,
+ unsigned int *mime_data_length)
+{
+ cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
+ mime_data, mime_data_length);
+ if (*mime_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return _cairo_image_info_get_jpeg_info (info, *mime_data, *mime_data_length);
+}
+
+static cairo_status_t
+_get_source_surface_size (cairo_surface_t *source,
+ int *width,
+ int *height)
+{
+ cairo_status_t status;
+ cairo_rectangle_int_t extents;
+ cairo_image_info_t info;
+ const unsigned char *mime_data;
+ unsigned int mime_data_length;
+
+ if (_cairo_surface_is_meta (source)) {
+ cairo_meta_surface_t *meta_surface = (cairo_meta_surface_t *) source;
+ cairo_box_t bbox;
+
+ status = _cairo_meta_surface_get_bbox (meta_surface, &bbox, NULL);
+ if (unlikely (status))
+ return status;
+
+ _cairo_box_round_to_rectangle (&bbox, &extents);
+
+ *width = extents.width;
+ *height = extents.height;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ status = _get_jpx_image_info (source, &info, &mime_data, &mime_data_length);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
+ *width = info.width;
+ *height = info.height;
+ return status;
+ }
+
+ status = _get_jpeg_image_info (source, &info, &mime_data, &mime_data_length);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
+ *width = info.width;
+ *height = info.height;
+ return status;
+ }
+
+ if (! _cairo_surface_get_extents (source, &extents))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ *width = extents.width;
+ *height = extents.height;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
+ cairo_surface_t *source,
+ cairo_filter_t filter,
+ cairo_pdf_resource_t *surface_res,
+ int *width,
+ int *height)
+{
+ cairo_pdf_source_surface_t src_surface;
+ cairo_pdf_source_surface_entry_t surface_key;
+ cairo_pdf_source_surface_entry_t *surface_entry;
+ cairo_status_t status;
+ cairo_bool_t interpolate;
+
+ switch (filter) {
+ default:
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BEST:
+ case CAIRO_FILTER_BILINEAR:
+ interpolate = TRUE;
+ break;
+ case CAIRO_FILTER_FAST:
+ case CAIRO_FILTER_NEAREST:
+ case CAIRO_FILTER_GAUSSIAN:
+ interpolate = FALSE;
+ break;
+ }
+
+ surface_key.id = source->unique_id;
+ surface_key.interpolate = interpolate;
+ _cairo_pdf_source_surface_init_key (&surface_key);
+ surface_entry = _cairo_hash_table_lookup (surface->all_surfaces, &surface_key.base);
+ if (surface_entry) {
+ *surface_res = surface_entry->surface_res;
+ *width = surface_entry->width;
+ *height = surface_entry->height;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ surface_entry = malloc (sizeof (cairo_pdf_source_surface_entry_t));
+ if (surface_entry == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ surface_entry->id = surface_key.id;
+ surface_entry->interpolate = interpolate;
+ _cairo_pdf_source_surface_init_key (surface_entry);
+
+ src_surface.hash_entry = surface_entry;
+ src_surface.surface = cairo_surface_reference (source);
+ surface_entry->surface_res = _cairo_pdf_surface_new_object (surface);
+ if (surface_entry->surface_res.id == 0) {
+ free (surface_entry);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ status = _get_source_surface_size (source, &surface_entry->width,
+ &surface_entry->height);
+
+ status = _cairo_array_append (&surface->page_surfaces, &src_surface);
+ if (unlikely (status)) {
+ free (surface_entry);
+ return status;
+ }
+
+ status = _cairo_hash_table_insert (surface->all_surfaces,
+ &surface_entry->base);
+
+ *surface_res = surface_entry->surface_res;
+ *width = surface_entry->width;
+ *height = surface_entry->height;
+
+ return status;
+}
+
static cairo_status_t
_cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
const cairo_pattern_t *pattern,
- cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *extents,
cairo_pdf_resource_t *pattern_res,
cairo_pdf_resource_t *gstate_res)
{
cairo_pdf_pattern_t pdf_pattern;
- cairo_pdf_pattern_entry_t pdf_pattern_key;
- cairo_pdf_pattern_entry_t *pdf_pattern_entry;
cairo_status_t status;
/* Solid colors are emitted into the content stream */
@@ -906,7 +1176,6 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
- pdf_pattern_key.id = 0;
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
{
@@ -926,50 +1195,24 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
}
}
- if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
- cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern;
-
- pdf_pattern_key.id = surface->surface->unique_id;
- }
-
- _cairo_pdf_pattern_init_key (&pdf_pattern_key);
- if (pdf_pattern_key.base.hash != 0 &&
- (pdf_pattern_entry = _cairo_hash_table_lookup (surface->all_patterns,
- &pdf_pattern_key.base)))
- {
- *pattern_res = pdf_pattern_entry->pattern_res;
- *gstate_res = pdf_pattern_entry->gstate_res;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- pdf_pattern_entry = malloc (sizeof (cairo_pdf_pattern_entry_t));
- if (pdf_pattern_entry == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- pdf_pattern_entry->id = pdf_pattern_key.id;
- _cairo_pdf_pattern_init_key (pdf_pattern_entry);
-
- pdf_pattern.hash_entry = pdf_pattern_entry;
-
status = _cairo_pattern_create_copy (&pdf_pattern.pattern, pattern);
if (unlikely (status))
return status;
- pdf_pattern_entry->pattern_res = _cairo_pdf_surface_new_object (surface);
- if (pdf_pattern_entry->pattern_res.id == 0) {
+ pdf_pattern.pattern_res = _cairo_pdf_surface_new_object (surface);
+ if (pdf_pattern.pattern_res.id == 0) {
cairo_pattern_destroy (pdf_pattern.pattern);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- pdf_pattern_entry->gstate_res.id = 0;
+ 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_entry->gstate_res = _cairo_pdf_surface_new_object (surface);
- if (pdf_pattern_entry->gstate_res.id == 0) {
+ pdf_pattern.gstate_res = _cairo_pdf_surface_new_object (surface);
+ if (pdf_pattern.gstate_res.id == 0) {
cairo_pattern_destroy (pdf_pattern.pattern);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -978,7 +1221,7 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
pdf_pattern.width = surface->width;
pdf_pattern.height = surface->height;
- if (extents) {
+ if (extents != NULL) {
pdf_pattern.extents = *extents;
} else {
pdf_pattern.extents.x = 0;
@@ -987,8 +1230,8 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
pdf_pattern.extents.height = surface->height;
}
- *pattern_res = pdf_pattern_entry->pattern_res;
- *gstate_res = pdf_pattern_entry->gstate_res;
+ *pattern_res = pdf_pattern.pattern_res;
+ *gstate_res = pdf_pattern.gstate_res;
status = _cairo_array_append (&surface->page_patterns, &pdf_pattern);
if (unlikely (status)) {
@@ -996,13 +1239,6 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
return status;
}
- if (pdf_pattern_entry->base.hash != 0) {
- status = _cairo_hash_table_insert (surface->all_patterns,
- &pdf_pattern_entry->base);
- if (unlikely (status))
- return status;
- }
-
return CAIRO_STATUS_SUCCESS;
}
@@ -1041,6 +1277,7 @@ _cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface,
surface->pdf_stream.length = length;
surface->pdf_stream.compressed = compressed;
surface->current_pattern_is_solid_color = FALSE;
+ surface->current_operator = CAIRO_OPERATOR_OVER;
_cairo_pdf_operators_reset (&surface->pdf_operators);
_cairo_output_stream_printf (surface->output,
@@ -1181,6 +1418,7 @@ _cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface,
surface->group_stream.active = TRUE;
surface->current_pattern_is_solid_color = FALSE;
+ surface->current_operator = CAIRO_OPERATOR_OVER;
_cairo_pdf_operators_reset (&surface->pdf_operators);
surface->group_stream.mem_stream = _cairo_memory_stream_create ();
@@ -1267,6 +1505,7 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
static cairo_status_t
_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;
@@ -1281,7 +1520,7 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface,
if (is_form) {
status =
_cairo_pdf_surface_open_stream (surface,
- NULL,
+ resource,
surface->compress_content,
" /Type /XObject\n"
" /Subtype /Form\n"
@@ -1298,7 +1537,7 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface,
} else {
status =
_cairo_pdf_surface_open_stream (surface,
- NULL,
+ resource,
surface->compress_content,
NULL);
}
@@ -1340,23 +1579,14 @@ _cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface)
return _cairo_output_stream_get_status (surface->output);
}
-static cairo_surface_t *
-_cairo_pdf_surface_create_similar (void *abstract_surface,
- cairo_content_t content,
- int width,
- int height)
-{
- return _cairo_meta_surface_create (content, width, height);
-}
-
static void
-_cairo_pdf_pattern_entry_pluck (void *entry, void *closure)
+_cairo_pdf_source_surface_entry_pluck (void *entry, void *closure)
{
- cairo_pdf_pattern_entry_t *pattern_entry = entry;
+ cairo_pdf_source_surface_entry_t *surface_entry = entry;
cairo_hash_table_t *patterns = closure;
- _cairo_hash_table_remove (patterns, &pattern_entry->base);
- free (pattern_entry);
+ _cairo_hash_table_remove (patterns, &surface_entry->base);
+ free (surface_entry);
}
static cairo_status_t
@@ -1439,10 +1669,11 @@ _cairo_pdf_surface_finish (void *abstract_surface)
_cairo_array_fini (&surface->rgb_linear_functions);
_cairo_array_fini (&surface->alpha_linear_functions);
_cairo_array_fini (&surface->page_patterns);
- _cairo_hash_table_foreach (surface->all_patterns,
- _cairo_pdf_pattern_entry_pluck,
- surface->all_patterns);
- _cairo_hash_table_destroy (surface->all_patterns);
+ _cairo_array_fini (&surface->page_surfaces);
+ _cairo_hash_table_foreach (surface->all_surfaces,
+ _cairo_pdf_source_surface_entry_pluck,
+ surface->all_surfaces);
+ _cairo_hash_table_destroy (surface->all_surfaces);
_cairo_array_fini (&surface->smask_groups);
_cairo_array_fini (&surface->fonts);
_cairo_array_fini (&surface->knockout_group);
@@ -1452,6 +1683,8 @@ _cairo_pdf_surface_finish (void *abstract_surface)
surface->font_subsets = NULL;
}
+ _cairo_surface_clipper_reset (&surface->clipper);
+
return status;
}
@@ -1494,7 +1727,7 @@ _cairo_pdf_surface_has_fallback_images (void *abstract_surface,
cairo_pdf_surface_t *surface = abstract_surface;
surface->has_fallback_images = has_fallbacks;
- status = _cairo_pdf_surface_open_content_stream (surface, has_fallbacks);
+ status = _cairo_pdf_surface_open_content_stream (surface, NULL, has_fallbacks);
if (unlikely (status))
return status;
@@ -1614,7 +1847,7 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface,
static cairo_status_t
_cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
cairo_image_surface_t *image,
- cairo_pdf_resource_t *image_ret,
+ cairo_pdf_resource_t *image_res,
cairo_filter_t filter)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
@@ -1712,7 +1945,7 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
if (need_smask)
status = _cairo_pdf_surface_open_stream (surface,
- NULL,
+ image_res,
TRUE,
IMAGE_DICTIONARY
" /SMask %d 0 R\n",
@@ -1721,7 +1954,7 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
smask.id);
else
status = _cairo_pdf_surface_open_stream (surface,
- NULL,
+ image_res,
TRUE,
IMAGE_DICTIONARY,
image->width, image->height,
@@ -1731,7 +1964,6 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
#undef IMAGE_DICTIONARY
- *image_ret = surface->pdf_stream.self;
_cairo_output_stream_write (surface->output, rgb, rgb_size);
status = _cairo_pdf_surface_close_stream (surface);
@@ -1744,9 +1976,7 @@ CLEANUP:
static cairo_int_status_t
_cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface,
cairo_surface_t *source,
- cairo_pdf_resource_t *res,
- int *width,
- int *height)
+ cairo_pdf_resource_t res)
{
cairo_status_t status;
const unsigned char *mime_data;
@@ -1766,7 +1996,7 @@ _cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface,
return status;
status = _cairo_pdf_surface_open_stream (surface,
- NULL,
+ &res,
FALSE,
" /Type /XObject\n"
" /Subtype /Image\n"
@@ -1779,23 +2009,17 @@ _cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface,
if (status)
return status;
- *res = surface->pdf_stream.self;
_cairo_output_stream_write (surface->output, mime_data, mime_data_length);
_cairo_output_stream_printf (surface->output, "\n");
status = _cairo_pdf_surface_close_stream (surface);
- *width = info.width;
- *height = info.height;
-
return status;
}
static cairo_int_status_t
_cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface,
cairo_surface_t *source,
- cairo_pdf_resource_t *res,
- int *width,
- int *height)
+ cairo_pdf_resource_t res)
{
cairo_status_t status;
const unsigned char *mime_data;
@@ -1817,7 +2041,7 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_pdf_surface_open_stream (surface,
- NULL,
+ &res,
FALSE,
" /Type /XObject\n"
" /Subtype /Image\n"
@@ -1833,90 +2057,130 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface,
if (unlikely (status))
return status;
- *res = surface->pdf_stream.self;
_cairo_output_stream_write (surface->output, mime_data, mime_data_length);
_cairo_output_stream_printf (surface->output, "\n");
status = _cairo_pdf_surface_close_stream (surface);
- *width = info.width;
- *height = info.height;
-
return status;
}
static cairo_status_t
_cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface,
- cairo_pdf_pattern_t *pdf_pattern,
- cairo_pdf_resource_t *resource,
- int *width,
- int *height,
- int *origin_x,
- int *origin_y)
+ cairo_surface_t *source,
+ cairo_pdf_resource_t resource,
+ cairo_bool_t interpolate)
{
cairo_image_surface_t *image;
- cairo_surface_t *pad_image;
void *image_extra;
cairo_status_t status;
- cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern;
- int x = 0;
- int y = 0;
- status = _cairo_pdf_surface_emit_jpx_image (surface, pattern->surface,
- resource, width, height);
+ status = _cairo_pdf_surface_emit_jpx_image (surface, source, resource);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
- status = _cairo_pdf_surface_emit_jpeg_image (surface, pattern->surface,
- resource, width, height);
+ status = _cairo_pdf_surface_emit_jpeg_image (surface, source, resource);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
- status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
+ status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
if (unlikely (status))
return status;
+ status = _cairo_pdf_surface_emit_image (surface, image,
+ &resource, interpolate);
+ if (unlikely (status))
+ goto BAIL;
+
+BAIL:
+ _cairo_surface_release_source_image (source, image, image_extra);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t *surface,
+ cairo_pdf_pattern_t *pdf_pattern,
+ cairo_pdf_resource_t *resource,
+ int *width,
+ int *height,
+ int *origin_x,
+ int *origin_y)
+{
+ cairo_image_surface_t *image;
+ cairo_surface_t *pad_image;
+ void *image_extra;
+ cairo_status_t status;
+ cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern;
+ int x = 0;
+ int y = 0;
+ cairo_bool_t interpolate;
+
+ status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
+ if (unlikely (status))
+ return status;
+
pad_image = &image->base;
- if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD) {
- cairo_box_t box;
- cairo_rectangle_int_t rect;
- cairo_surface_pattern_t pad_pattern;
-
- /* get the operation extents in pattern space */
- _cairo_box_from_rectangle (&box, &pdf_pattern->extents);
- _cairo_matrix_transform_bounding_box_fixed (&pattern->base.matrix, &box, NULL);
- _cairo_box_round_to_rectangle (&box, &rect);
- x = -rect.x;
- y = -rect.y;
-
- pad_image = _cairo_image_surface_create_with_content (pattern->surface->content,
- rect.width,
- rect.height);
- if (pad_image->status) {
- status = pad_image->status;
- goto BAIL;
- }
+ if (pattern->base.extend == CAIRO_EXTEND_PAD) {
+ cairo_box_t box;
+ cairo_rectangle_int_t rect;
+ cairo_surface_pattern_t pad_pattern;
+
+ /* get the operation extents in pattern space */
+ _cairo_box_from_rectangle (&box, &pdf_pattern->extents);
+ _cairo_matrix_transform_bounding_box_fixed (&pattern->base.matrix, &box, NULL);
+ _cairo_box_round_to_rectangle (&box, &rect);
+ x = -rect.x;
+ y = -rect.y;
+
+ pad_image = _cairo_image_surface_create_with_content (pattern->surface->content,
+ rect.width,
+ rect.height);
+ if (pad_image->status) {
+ status = pad_image->status;
+ goto BAIL;
+ }
- _cairo_pattern_init_for_surface (&pad_pattern, &image->base);
- cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y);
- pad_pattern.base.extend = CAIRO_EXTEND_PAD;
- status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
- &pad_pattern.base,
- NULL,
- pad_image,
- 0, 0,
- 0, 0,
- 0, 0,
- rect.width,
- rect.height);
- _cairo_pattern_fini (&pad_pattern.base);
- if (unlikely (status))
- goto BAIL;
+ _cairo_pattern_init_for_surface (&pad_pattern, &image->base);
+ cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y);
+ pad_pattern.base.extend = CAIRO_EXTEND_PAD;
+ status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
+ &pad_pattern.base,
+ NULL,
+ pad_image,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ rect.width,
+ rect.height,
+ NULL);
+ _cairo_pattern_fini (&pad_pattern.base);
+ if (unlikely (status))
+ goto BAIL;
+ }
+
+ switch (pdf_pattern->pattern->filter) {
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BEST:
+ case CAIRO_FILTER_BILINEAR:
+ interpolate = TRUE;
+ break;
+ case CAIRO_FILTER_FAST:
+ case CAIRO_FILTER_NEAREST:
+ case CAIRO_FILTER_GAUSSIAN:
+ interpolate = FALSE;
+ break;
+ }
+
+ *resource = _cairo_pdf_surface_new_object (surface);
+ if (resource->id == 0) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL;
}
status = _cairo_pdf_surface_emit_image (surface, (cairo_image_surface_t *)pad_image,
- resource, pattern->base.filter);
+ resource, interpolate);
if (unlikely (status))
- goto BAIL;
+ goto BAIL;
*width = ((cairo_image_surface_t *)pad_image)->width;
*height = ((cairo_image_surface_t *)pad_image)->height;
@@ -1925,33 +2189,33 @@ _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface,
BAIL:
if (pad_image != &image->base)
- cairo_surface_destroy (pad_image);
+ cairo_surface_destroy (pad_image);
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
return status;
}
+
static cairo_status_t
_cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
cairo_surface_t *meta_surface,
- cairo_pdf_resource_t *resource)
+ cairo_pdf_resource_t resource)
{
double old_width, old_height;
cairo_paginated_mode_t old_paginated_mode;
- cairo_clip_t *old_clip;
cairo_rectangle_int_t meta_extents;
+ cairo_bool_t is_bounded;
cairo_status_t status;
int alpha = 0;
- status = _cairo_surface_get_extents (meta_surface, &meta_extents);
- if (unlikely (status))
- return status;
+ is_bounded = _cairo_surface_get_extents (meta_surface, &meta_extents);
+ assert (is_bounded);
old_width = surface->width;
old_height = surface->height;
old_paginated_mode = surface->paginated_mode;
- old_clip = _cairo_surface_get_clip (&surface->base);
+
_cairo_pdf_surface_set_size_internal (surface,
meta_extents.width,
meta_extents.height);
@@ -1961,11 +2225,10 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
*/
surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER;
_cairo_pdf_group_resources_clear (&surface->resources);
- status = _cairo_pdf_surface_open_content_stream (surface, TRUE);
+ status = _cairo_pdf_surface_open_content_stream (surface, &resource, TRUE);
if (unlikely (status))
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 (unlikely (status))
@@ -1984,10 +2247,6 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
if (unlikely (status))
return status;
- status = _cairo_surface_set_clip (&surface->base, old_clip);
- if (unlikely (status))
- return status;
-
status = _cairo_pdf_surface_close_content_stream (surface);
_cairo_pdf_surface_set_size_internal (surface,
@@ -1999,16 +2258,31 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
}
static cairo_status_t
+_cairo_pdf_surface_emit_surface (cairo_pdf_surface_t *surface,
+ cairo_pdf_source_surface_t *src_surface)
+{
+ if (_cairo_surface_is_meta (src_surface->surface)) {
+ return _cairo_pdf_surface_emit_meta_surface (surface,
+ src_surface->surface,
+ src_surface->hash_entry->surface_res);
+ } else {
+ return _cairo_pdf_surface_emit_image_surface (surface,
+ src_surface->surface,
+ src_surface->hash_entry->surface_res,
+ src_surface->hash_entry->interpolate);
+ }
+}
+
+static cairo_status_t
_cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
cairo_pdf_pattern_t *pdf_pattern)
{
cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern;
cairo_status_t status;
- cairo_pdf_resource_t pattern_resource = {0}; /* squelch bogus compiler warning */
+ cairo_pdf_resource_t pattern_resource = {0};
cairo_matrix_t cairo_p2d, pdf_p2d;
cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base);
double xstep, ystep;
- cairo_rectangle_int_t surface_extents;
int pattern_width = 0; /* squelch bogus compiler warning */
int pattern_height = 0; /* squelch bogus compiler warning */
int origin_x = 0; /* squelch bogus compiler warning */
@@ -2016,35 +2290,26 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
int bbox_x, bbox_y;
char draw_surface[200];
- if (_cairo_surface_is_meta (pattern->surface)) {
- cairo_surface_t *meta_surface = pattern->surface;
- cairo_rectangle_int_t pattern_extents;
-
- status = _cairo_pdf_surface_emit_meta_surface (surface,
- meta_surface,
- &pattern_resource);
- if (unlikely (status))
- return status;
-
- status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
- if (unlikely (status))
- return status;
-
- pattern_width = pattern_extents.width;
- pattern_height = pattern_extents.height;
- } else {
- status = _cairo_pdf_surface_emit_image_surface (surface,
- pdf_pattern,
+ if (pattern->base.extend == CAIRO_EXTEND_PAD &&
+ ! _cairo_surface_is_meta (pattern->surface))
+ {
+ status = _cairo_pdf_surface_emit_padded_image_surface (surface,
+ pdf_pattern,
+ &pattern_resource,
+ &pattern_width,
+ &pattern_height,
+ &origin_x,
+ &origin_y);
+ }
+ else
+ {
+ status = _cairo_pdf_surface_add_source_surface (surface,
+ pattern->surface,
+ pdf_pattern->pattern->filter,
&pattern_resource,
&pattern_width,
- &pattern_height,
- &origin_x,
- &origin_y);
- if (unlikely (status))
- return status;
+ &pattern_height);
}
-
- status = _cairo_surface_get_extents (&surface->base, &surface_extents);
if (unlikely (status))
return status;
@@ -2130,17 +2395,14 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
- cairo_matrix_init_identity (&pdf_p2d);
- cairo_matrix_translate (&pdf_p2d, 0.0, surface_extents.height);
- cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
- cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d);
+ cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &surface->cairo_to_pdf);
cairo_matrix_translate (&pdf_p2d, -origin_x, -origin_y);
cairo_matrix_translate (&pdf_p2d, 0.0, pattern_height);
cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
- _cairo_pdf_surface_update_object (surface, pdf_pattern->hash_entry->pattern_res);
+ _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
status = _cairo_pdf_surface_open_stream (surface,
- &pdf_pattern->hash_entry->pattern_res,
+ &pdf_pattern->pattern_res,
FALSE,
" /PatternType 1\n"
" /BBox [0 0 %d %d]\n"
@@ -2687,9 +2949,9 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
dx = fabs (x2 - x1);
dy = fabs (y2 - y1);
if (dx > 1e-6)
- x_rep = (int) ceil (surface->width/dx);
+ x_rep = ceil (surface->width/dx);
if (dy > 1e-6)
- y_rep = (int) ceil (surface->height/dy);
+ y_rep = ceil (surface->height/dy);
repeat_end = MAX (x_rep, y_rep);
repeat_begin = -repeat_end;
@@ -2755,7 +3017,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
}
}
- _cairo_pdf_surface_update_object (surface, pdf_pattern->hash_entry->pattern_res);
+ _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\n"
"<< /Type /Pattern\n"
@@ -2767,7 +3029,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
" /Coords [ %f %f %f %f ]\n"
" /Domain [ %f %f ]\n"
" /Function %d 0 R\n",
- pdf_pattern->hash_entry->pattern_res.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,
@@ -2791,7 +3053,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
if (alpha_function.id != 0) {
cairo_pdf_resource_t mask_resource;
- assert (pdf_pattern->hash_entry->gstate_res.id != 0);
+ assert (pdf_pattern->gstate_res.id != 0);
/* Create pattern for SMask. */
mask_resource = _cairo_pdf_surface_new_object (surface);
@@ -2834,7 +3096,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
return status;
status = cairo_pdf_surface_emit_transparency_group (surface,
- pdf_pattern->hash_entry->gstate_res,
+ pdf_pattern->gstate_res,
mask_resource);
if (unlikely (status))
return status;
@@ -2878,7 +3140,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);
- _cairo_pdf_surface_update_object (surface, pdf_pattern->hash_entry->pattern_res);
+ _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\n"
@@ -2890,7 +3152,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface,
" /ColorSpace /DeviceRGB\n"
" /Coords [ %f %f %f %f %f %f ]\n"
" /Function %d 0 R\n",
- pdf_pattern->hash_entry->pattern_res.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,
@@ -2913,7 +3175,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface,
if (alpha_function.id != 0) {
cairo_pdf_resource_t mask_resource;
- assert (pdf_pattern->hash_entry->gstate_res.id != 0);
+ assert (pdf_pattern->gstate_res.id != 0);
/* Create pattern for SMask. */
mask_resource = _cairo_pdf_surface_new_object (surface);
@@ -2951,7 +3213,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface,
"endobj\n");
status = cairo_pdf_surface_emit_transparency_group (surface,
- pdf_pattern->hash_entry->gstate_res,
+ pdf_pattern->gstate_res,
mask_resource);
if (unlikely (status))
return status;
@@ -3004,6 +3266,82 @@ _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern
}
static cairo_status_t
+_cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
+ cairo_surface_pattern_t *source)
+{
+ cairo_pdf_resource_t surface_res;
+ int width, height;
+ cairo_matrix_t cairo_p2d, pdf_p2d;
+ cairo_status_t status;
+ int alpha;
+
+ status = _cairo_pdf_surface_add_source_surface (surface,
+ source->surface,
+ source->base.filter,
+ &surface_res,
+ &width,
+ &height);
+ if (unlikely (status))
+ return status;
+
+ cairo_p2d = source->base.matrix;
+ status = cairo_matrix_invert (&cairo_p2d);
+ /* cairo_pattern_set_matrix ensures the matrix is invertible */
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ pdf_p2d = surface->cairo_to_pdf;
+ cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d);
+ cairo_matrix_translate (&pdf_p2d, 0.0, height);
+ cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
+ if (! _cairo_surface_is_meta (source->surface))
+ cairo_matrix_scale (&pdf_p2d, width, height);
+
+ status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+ if (unlikely (status))
+ return status;
+
+ if (! _cairo_matrix_is_identity (&pdf_p2d)) {
+ _cairo_output_stream_printf (surface->output,
+ "%f %f %f %f %f %f cm\n",
+ pdf_p2d.xx, pdf_p2d.yx,
+ pdf_p2d.xy, pdf_p2d.yy,
+ pdf_p2d.x0, pdf_p2d.y0);
+ }
+
+ status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (surface->output,
+ "/a%d gs /x%d Do\n",
+ alpha,
+ surface_res.id);
+
+ return _cairo_pdf_surface_add_xobject (surface, surface_res);
+}
+
+static cairo_status_t
+_cairo_pdf_surface_select_operator (cairo_pdf_surface_t *surface,
+ cairo_operator_t op)
+{
+ cairo_status_t status;
+
+ if (op == surface->current_operator)
+ return CAIRO_STATUS_SUCCESS;
+
+ status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (surface->output,
+ "/b%d gs\n", op);
+ surface->current_operator = op;
+ _cairo_pdf_surface_add_operator (surface, op);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
_cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
const cairo_pattern_t *pattern,
cairo_pdf_resource_t pattern_res,
@@ -3148,7 +3486,7 @@ _cairo_pdf_surface_show_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
+static cairo_bool_t
_cairo_pdf_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -3161,35 +3499,10 @@ _cairo_pdf_surface_get_extents (void *abstract_surface,
* mention the arbitrary limitation of width to a short(!). We
* may need to come up with a better interface for get_size.
*/
- rectangle->width = (int) ceil (surface->width);
- rectangle->height = (int) ceil (surface->height);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_pdf_surface_intersect_clip_path (void *abstract_surface,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_pdf_surface_t *surface = abstract_surface;
- cairo_int_status_t status;
-
- if (path == NULL) {
- status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (unlikely (status))
- return status;
-
- _cairo_output_stream_printf (surface->output, "Q q\n");
- surface->current_pattern_is_solid_color = FALSE;
- _cairo_pdf_operators_reset (&surface->pdf_operators);
-
- return CAIRO_STATUS_SUCCESS;
- }
+ rectangle->width = ceil (surface->width);
+ rectangle->height = ceil (surface->height);
- return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule);
+ return TRUE;
}
static void
@@ -3414,37 +3727,62 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
_cairo_output_stream_printf (surface->output,
"endcodespacerange\n");
- num_bfchar = font_subset->num_glyphs - 1;
+ if (font_subset->is_scaled) {
+ /* Type 3 fonts include glyph 0 in the subset */
+ num_bfchar = font_subset->num_glyphs;
- /* The CMap specification has a limit of 100 characters per beginbfchar operator */
- _cairo_output_stream_printf (surface->output,
- "%d beginbfchar\n",
- num_bfchar > 100 ? 100 : num_bfchar);
+ /* The CMap specification has a limit of 100 characters per beginbfchar operator */
+ _cairo_output_stream_printf (surface->output,
+ "%d beginbfchar\n",
+ num_bfchar > 100 ? 100 : num_bfchar);
+
+ for (i = 0; i < num_bfchar; i++) {
+ if (i != 0 && i % 100 == 0) {
+ _cairo_output_stream_printf (surface->output,
+ "endbfchar\n"
+ "%d beginbfchar\n",
+ num_bfchar - i > 100 ? 100 : num_bfchar - i);
+ }
+ _cairo_output_stream_printf (surface->output, "<%02x> ", i);
+ status = _cairo_pdf_surface_emit_unicode_for_glyph (surface,
+ font_subset->utf8[i]);
+ if (unlikely (status))
+ return status;
- for (i = 0; i < num_bfchar; i++) {
- if (i != 0 && i % 100 == 0) {
- _cairo_output_stream_printf (surface->output,
- "endbfchar\n"
- "%d beginbfchar\n",
- num_bfchar - i > 100 ? 100 : num_bfchar - i);
- }
- if (is_composite) {
- _cairo_output_stream_printf (surface->output,
- "<%04x> ",
- i + 1);
- } else {
- _cairo_output_stream_printf (surface->output,
- "<%02x> ",
- i + 1);
- }
- status = _cairo_pdf_surface_emit_unicode_for_glyph (surface,
- font_subset->utf8[i + 1]);
- if (unlikely (status))
- return status;
+ _cairo_output_stream_printf (surface->output,
+ "\n");
+ }
+ } else {
+ /* Other fonts reserve glyph 0 for .notdef. Omit glyph 0 from the /ToUnicode map */
+ num_bfchar = font_subset->num_glyphs - 1;
+ /* The CMap specification has a limit of 100 characters per beginbfchar operator */
_cairo_output_stream_printf (surface->output,
- "\n");
+ "%d beginbfchar\n",
+ num_bfchar > 100 ? 100 : num_bfchar);
+
+ for (i = 0; i < num_bfchar; i++) {
+ if (i != 0 && i % 100 == 0) {
+ _cairo_output_stream_printf (surface->output,
+ "endbfchar\n"
+ "%d beginbfchar\n",
+ num_bfchar - i > 100 ? 100 : num_bfchar - i);
+ }
+ if (is_composite)
+ _cairo_output_stream_printf (surface->output, "<%04x> ", i + 1);
+ else
+ _cairo_output_stream_printf (surface->output, "<%02x> ", i + 1);
+
+ status = _cairo_pdf_surface_emit_unicode_for_glyph (surface,
+ font_subset->utf8[i + 1]);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (surface->output,
+ "\n");
+ }
}
+
_cairo_output_stream_printf (surface->output,
"endbfchar\n");
@@ -4521,8 +4859,10 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface,
group->height);
/* _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);
+ if (group->operation == PDF_MASK) {
+ status = _cairo_pdf_surface_write_mask_group (surface, group);
+ goto RESTORE_SIZE;
+ }
status = _cairo_pdf_surface_open_group (surface, &group->group_res);
if (unlikely (status))
@@ -4574,6 +4914,7 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface,
status = _cairo_pdf_surface_close_group (surface, NULL);
+RESTORE_SIZE:
_cairo_pdf_surface_set_size_internal (surface,
old_width,
old_height);
@@ -4586,7 +4927,8 @@ _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_pdf_source_surface_t src_surface;
+ int pattern_index, group_index, surface_index;
cairo_status_t status;
/* Writing out PDF_MASK groups will cause additional smask groups
@@ -4598,8 +4940,10 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface
*/
pattern_index = 0;
group_index = 0;
+ surface_index = 0;
while ((pattern_index < _cairo_array_num_elements (&surface->page_patterns)) ||
- (group_index < _cairo_array_num_elements (&surface->smask_groups)))
+ (group_index < _cairo_array_num_elements (&surface->smask_groups)) ||
+ (surface_index < _cairo_array_num_elements (&surface->page_surfaces)))
{
for (; group_index < _cairo_array_num_elements (&surface->smask_groups); group_index++) {
_cairo_array_copy_element (&surface->smask_groups, group_index, &group);
@@ -4614,6 +4958,13 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface
if (unlikely (status))
return status;
}
+
+ for (; surface_index < _cairo_array_num_elements (&surface->page_surfaces); surface_index++) {
+ _cairo_array_copy_element (&surface->page_surfaces, surface_index, &src_surface);
+ status = _cairo_pdf_surface_emit_surface (surface, &src_surface);
+ if (unlikely (status))
+ return status;
+ }
}
return CAIRO_STATUS_SUCCESS;
@@ -4654,7 +5005,7 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
return status;
_cairo_pdf_group_resources_clear (&surface->resources);
- status = _cairo_pdf_surface_open_content_stream (surface, FALSE);
+ status = _cairo_pdf_surface_open_content_stream (surface, NULL, FALSE);
if (unlikely (status))
return status;
@@ -4821,6 +5172,46 @@ _pattern_supported (const cairo_pattern_t *pattern)
return FALSE;
}
+static cairo_bool_t
+_pdf_operator_supported (cairo_operator_t op)
+{
+ switch (op) {
+ case CAIRO_OPERATOR_OVER:
+ case CAIRO_OPERATOR_MULTIPLY:
+ case CAIRO_OPERATOR_SCREEN:
+ case CAIRO_OPERATOR_OVERLAY:
+ case CAIRO_OPERATOR_DARKEN:
+ case CAIRO_OPERATOR_LIGHTEN:
+ case CAIRO_OPERATOR_COLOR_DODGE:
+ case CAIRO_OPERATOR_COLOR_BURN:
+ case CAIRO_OPERATOR_HARD_LIGHT:
+ case CAIRO_OPERATOR_SOFT_LIGHT:
+ case CAIRO_OPERATOR_DIFFERENCE:
+ case CAIRO_OPERATOR_EXCLUSION:
+ case CAIRO_OPERATOR_HSL_HUE:
+ case CAIRO_OPERATOR_HSL_SATURATION:
+ case CAIRO_OPERATOR_HSL_COLOR:
+ case CAIRO_OPERATOR_HSL_LUMINOSITY:
+ return TRUE;
+
+ default:
+ case CAIRO_OPERATOR_CLEAR:
+ case CAIRO_OPERATOR_SOURCE:
+ case CAIRO_OPERATOR_IN:
+ case CAIRO_OPERATOR_OUT:
+ case CAIRO_OPERATOR_ATOP:
+ case CAIRO_OPERATOR_DEST:
+ case CAIRO_OPERATOR_DEST_OVER:
+ case CAIRO_OPERATOR_DEST_IN:
+ case CAIRO_OPERATOR_DEST_OUT:
+ case CAIRO_OPERATOR_DEST_ATOP:
+ case CAIRO_OPERATOR_XOR:
+ case CAIRO_OPERATOR_ADD:
+ case CAIRO_OPERATOR_SATURATE:
+ return FALSE;
+ }
+}
+
static cairo_int_status_t
_cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
cairo_operator_t op,
@@ -4835,7 +5226,7 @@ _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 (_pdf_operator_supported (op)) {
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
@@ -4846,10 +5237,10 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
}
}
- }
- if (op == CAIRO_OPERATOR_OVER)
return CAIRO_STATUS_SUCCESS;
+ }
+
/* The SOURCE operator is supported if the pattern is opaque or if
* there is nothing painted underneath. */
@@ -4911,19 +5302,20 @@ _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
return status;
_cairo_pdf_group_resources_clear (&surface->resources);
- return _cairo_pdf_surface_open_content_stream (surface, TRUE);
+ return _cairo_pdf_surface_open_content_stream (surface, NULL, TRUE);
}
static cairo_int_status_t
_cairo_pdf_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
+ cairo_rectangle_int_t extents;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
return _cairo_pdf_surface_analyze_operation (surface, op, source);
@@ -4935,11 +5327,42 @@ _cairo_pdf_surface_paint (void *abstract_surface,
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_pdf_surface_select_operator (surface, op);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+ if (unlikely (status))
+ return status;
+
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
+ source->extend == CAIRO_EXTEND_NONE) {
+
+ _cairo_output_stream_printf (surface->output, "q\n");
+ status = _cairo_pdf_surface_paint_surface_pattern (surface,
+ (cairo_surface_pattern_t *) source);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (surface->output, "Q\n");
+ return _cairo_output_stream_get_status (surface->output);
+ }
+
+ status = _cairo_surface_paint_extents (&surface->base,
+ op, source, clip,
+ &extents);
+ if (unlikely (status))
+ return status;
+
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents,
&pattern_res, &gstate_res);
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
@@ -4970,16 +5393,13 @@ _cairo_pdf_surface_paint (void *abstract_surface,
if (unlikely (status))
return status;
- status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (unlikely (status))
- return status;
-
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
gstate_res.id,
group->group_res.id);
} else {
- status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
+ status = _cairo_pdf_surface_select_pattern (surface, source,
+ pattern_res, FALSE);
if (unlikely (status))
return status;
@@ -5000,7 +5420,7 @@ _cairo_pdf_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_pdf_smask_group_t *group;
@@ -5028,6 +5448,10 @@ _cairo_pdf_surface_mask (void *abstract_surface,
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
assert (_cairo_pdf_surface_operation_supported (surface, op, mask));
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
group = _cairo_pdf_surface_create_smask_group (surface);
if (unlikely (group == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -5067,6 +5491,10 @@ _cairo_pdf_surface_mask (void *abstract_surface,
if (unlikely (status))
return status;
+ status = _cairo_pdf_surface_select_operator (surface, op);
+ if (unlikely (status))
+ return status;
+
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
group->group_res.id,
@@ -5085,27 +5513,44 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
+ cairo_rectangle_int_t extents;
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_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_surface_stroke_extents (&surface->base,
+ op, source, path,
+ style, ctm, ctm_inverse,
+ tolerance, antialias,
+ clip, &extents);
+ if (unlikely (status))
+ return status;
+
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents,
&pattern_res, &gstate_res);
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
+ status = _cairo_pdf_surface_select_operator (surface, op);
+ if (unlikely (status))
+ return status;
+
if (gstate_res.id != 0) {
group = _cairo_pdf_surface_create_smask_group (surface);
if (unlikely (group == NULL))
@@ -5178,12 +5623,13 @@ _cairo_pdf_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
+ cairo_rectangle_int_t extents;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
return _cairo_pdf_surface_analyze_operation (surface, op, source);
@@ -5195,11 +5641,49 @@ _cairo_pdf_surface_fill (void *abstract_surface,
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_pdf_surface_select_operator (surface, op);
+ if (unlikely (status))
+ return status;
+
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
+ source->extend == CAIRO_EXTEND_NONE) {
+
+ status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (surface->output, "q\n");
+ status = _cairo_pdf_operators_clip (&surface->pdf_operators,
+ path,
+ fill_rule);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_pdf_surface_paint_surface_pattern (surface,
+ (cairo_surface_pattern_t *) source);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (surface->output, "Q\n");
+ return _cairo_output_stream_get_status (surface->output);
+ }
+
+ status = _cairo_surface_fill_extents (&surface->base,
+ op, source, path, fill_rule,
+ tolerance, antialias,
+ clip, &extents);
+ if (unlikely (status))
+ return status;
+
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents,
&pattern_res, &gstate_res);
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
@@ -5279,11 +5763,12 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
cairo_pdf_resource_t fill_pattern_res, stroke_pattern_res, gstate_res;
+ cairo_rectangle_int_t extents;
/* During analysis we return unsupported and let the _fill and
* _stroke functions that are on the fallback path do the analysis
@@ -5304,10 +5789,29 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
+ if (fill_op != stroke_op)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_pdf_surface_select_operator (surface, fill_op);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_surface_fill_extents (&surface->base,
+ fill_op, fill_source, path, fill_rule,
+ fill_tolerance, fill_antialias,
+ clip, &extents);
+ if (unlikely (status))
+ return status;
+
+
fill_pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source,
- extents,
+ &extents,
&fill_pattern_res,
&gstate_res);
if (unlikely (status))
@@ -5315,11 +5819,19 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
assert (gstate_res.id == 0);
+ status = _cairo_surface_stroke_extents (&surface->base,
+ stroke_op, stroke_source, path,
+ stroke_style, stroke_ctm, stroke_ctm_inverse,
+ stroke_tolerance, stroke_antialias,
+ clip, &extents);
+ if (unlikely (status))
+ return status;
+
stroke_pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface,
stroke_source,
- extents,
+ &extents,
&stroke_pattern_res,
&gstate_res);
if (unlikely (status))
@@ -5373,27 +5885,43 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
+ cairo_rectangle_int_t extents;
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_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_surface_glyphs_extents (&surface->base, op, source,
+ glyphs, num_glyphs,
+ scaled_font,
+ clip, &extents);
+ if (unlikely (status))
+ return status;
+
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents,
&pattern_res, &gstate_res);
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
+ status = _cairo_pdf_surface_select_operator (surface, op);
+ if (unlikely (status))
+ return status;
+
if (gstate_res.id != 0) {
group = _cairo_pdf_surface_create_smask_group (surface);
if (unlikely (group == NULL))
@@ -5504,7 +6032,7 @@ _cairo_pdf_surface_set_paginated_mode (void *abstract_surface,
static const cairo_surface_backend_t cairo_pdf_surface_backend = {
CAIRO_SURFACE_TYPE_PDF,
- _cairo_pdf_surface_create_similar,
+ NULL, /* create similar: handled by wrapper */
_cairo_pdf_surface_finish,
NULL, /* acquire_source_image */
NULL, /* release_source_image */
@@ -5518,8 +6046,6 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* _cairo_pdf_surface_copy_page */
_cairo_pdf_surface_show_page,
- NULL, /* set_clip_region */
- _cairo_pdf_surface_intersect_clip_path,
_cairo_pdf_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_pdf_surface_get_font_options,
@@ -5538,7 +6064,6 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
NULL, /* snapshot */
NULL, /* is_compatible */
- NULL, /* reset */
_cairo_pdf_surface_fill_stroke,
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */