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.c1247
1 files changed, 814 insertions, 433 deletions
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 49e5e84..00cc4fb 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -44,6 +44,7 @@
#include "cairo-pdf.h"
#include "cairo-pdf-surface-private.h"
#include "cairo-pdf-operators-private.h"
+#include "cairo-pdf-shading-private.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
@@ -357,6 +358,8 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
goto BAIL1;
}
+ _cairo_scaled_font_subsets_enable_latin_subset (surface->font_subsets, TRUE);
+
surface->next_available_resource.id = 1;
surface->pages_resource = _cairo_pdf_surface_new_object (surface);
if (surface->pages_resource.id == 0) {
@@ -1037,13 +1040,24 @@ _cairo_pdf_source_surface_equal (const void *key_a, const void *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) && (a->interpolate == b->interpolate);
+ if (a->interpolate != b->interpolate)
+ return FALSE;
+
+ if (a->unique_id && b->unique_id && a->unique_id_length == b->unique_id_length)
+ return (memcmp (a->unique_id, b->unique_id, a->unique_id_length) == 0);
+
+ return (a->id == b->id);
}
static void
_cairo_pdf_source_surface_init_key (cairo_pdf_source_surface_entry_t *key)
{
- key->base.hash = key->id;
+ if (key->unique_id && key->unique_id_length > 0) {
+ key->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE,
+ key->unique_id, key->unique_id_length);
+ } else {
+ key->base.hash = key->id;
+ }
}
static cairo_int_status_t
@@ -1135,6 +1149,7 @@ static cairo_status_t
_cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
cairo_surface_t *source,
cairo_filter_t filter,
+ cairo_bool_t mask,
cairo_pdf_resource_t *surface_res,
int *width,
int *height)
@@ -1144,6 +1159,8 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
cairo_pdf_source_surface_entry_t *surface_entry;
cairo_status_t status;
cairo_bool_t interpolate;
+ const unsigned char *unique_id;
+ unsigned long unique_id_length;
switch (filter) {
default:
@@ -1161,6 +1178,9 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
surface_key.id = source->unique_id;
surface_key.interpolate = interpolate;
+ cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_UNIQUE_ID,
+ (const unsigned char **) &surface_key.unique_id,
+ &surface_key.unique_id_length);
_cairo_pdf_source_surface_init_key (&surface_key);
surface_entry = _cairo_hash_table_lookup (surface->all_surfaces, &surface_key.base);
if (surface_entry) {
@@ -1177,6 +1197,23 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
surface_entry->id = surface_key.id;
surface_entry->interpolate = interpolate;
+ surface_entry->mask = mask;
+ cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_UNIQUE_ID,
+ &unique_id, &unique_id_length);
+ if (unique_id && unique_id_length > 0) {
+ surface_entry->unique_id = malloc (unique_id_length);
+ if (surface_entry->unique_id == NULL) {
+ cairo_surface_destroy (source);
+ free (surface_entry);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ surface_entry->unique_id_length = unique_id_length;
+ memcpy (surface_entry->unique_id, unique_id, unique_id_length);
+ } else {
+ surface_entry->unique_id = NULL;
+ surface_entry->unique_id_length = 0;
+ }
_cairo_pdf_source_surface_init_key (surface_entry);
src_surface.hash_entry = surface_entry;
@@ -1251,10 +1288,13 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
/* gradient patterns require an smask object to implement transparency */
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
- pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
+ pattern->type == CAIRO_PATTERN_TYPE_RADIAL ||
+ pattern->type == CAIRO_PATTERN_TYPE_MESH)
{
- cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
- if (! _gradient_stops_are_opaque (gradient)) {
+ double min_alpha;
+
+ _cairo_pattern_alpha_range (pattern, &min_alpha, NULL);
+ if (! CAIRO_ALPHA_IS_OPAQUE (min_alpha)) {
pdf_pattern.gstate_res = _cairo_pdf_surface_new_object (surface);
if (pdf_pattern.gstate_res.id == 0) {
cairo_pattern_destroy (pdf_pattern.pattern);
@@ -1629,6 +1669,9 @@ _cairo_pdf_source_surface_entry_pluck (void *entry, void *closure)
cairo_hash_table_t *patterns = closure;
_cairo_hash_table_remove (patterns, &surface_entry->base);
+ if (surface_entry->unique_id)
+ free (surface_entry->unique_id);
+
free (surface_entry);
}
@@ -1783,6 +1826,46 @@ _cairo_pdf_surface_supports_fine_grained_fallbacks (void *abstract_surface)
return TRUE;
}
+static cairo_status_t
+_cairo_pdf_surface_emit_imagemask (cairo_pdf_surface_t *surface,
+ cairo_image_surface_t *image,
+ cairo_pdf_resource_t *image_res)
+{
+ cairo_status_t status;
+ uint8_t *byte, output_byte;
+ int row, col, num_cols;
+
+
+ /* This is the only image format supported for stencil masking */
+ assert (image->format == CAIRO_FORMAT_A1);
+
+ status = _cairo_pdf_surface_open_stream (surface,
+ image_res,
+ TRUE,
+ " /Type /XObject\n"
+ " /Subtype /Image\n"
+ " /ImageMask true\n"
+ " /Width %d\n"
+ " /Height %d\n"
+ " /BitsPerComponent 1\n",
+ image->width, image->height);
+ if (unlikely (status))
+ return status;
+
+ num_cols = (image->width + 7) / 8;
+ for (row = 0; row < image->height; row++) {
+ byte = image->data + row * image->stride;
+ for (col = 0; col < num_cols; col++) {
+ output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
+ output_byte = ~output_byte;
+ _cairo_output_stream_write (surface->output, &output_byte, 1);
+ byte++;
+ }
+ }
+
+ return _cairo_pdf_surface_close_stream (surface);
+}
+
/* Emit alpha channel from the image into the given data, providing
* an id that can be used to reference the resulting SMask object.
*
@@ -1891,7 +1974,8 @@ static cairo_status_t
_cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
cairo_image_surface_t *image,
cairo_pdf_resource_t *image_res,
- cairo_filter_t filter)
+ cairo_filter_t filter,
+ cairo_bool_t mask)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
char *rgb;
@@ -1912,6 +1996,9 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
image->format == CAIRO_FORMAT_A8 ||
image->format == CAIRO_FORMAT_A1);
+ if (mask)
+ return _cairo_pdf_surface_emit_imagemask (surface, image, image_res);
+
rgb_size = image->height * image->width * 3;
rgb = _cairo_malloc_abc (image->width, image->height, 3);
if (unlikely (rgb == NULL)) {
@@ -2108,7 +2195,8 @@ static cairo_status_t
_cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface,
cairo_surface_t *source,
cairo_pdf_resource_t resource,
- cairo_bool_t interpolate)
+ cairo_bool_t interpolate,
+ cairo_bool_t mask)
{
cairo_image_surface_t *image;
void *image_extra;
@@ -2127,7 +2215,7 @@ _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface,
return status;
status = _cairo_pdf_surface_emit_image (surface, image,
- &resource, interpolate);
+ &resource, interpolate, mask);
if (unlikely (status))
goto BAIL;
@@ -2218,7 +2306,7 @@ _cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t *surface,
}
status = _cairo_pdf_surface_emit_image (surface, (cairo_image_surface_t *)pad_image,
- resource, interpolate);
+ resource, interpolate, FALSE);
if (unlikely (status))
goto BAIL;
@@ -2377,7 +2465,8 @@ _cairo_pdf_surface_emit_surface (cairo_pdf_surface_t *surface,
return _cairo_pdf_surface_emit_image_surface (surface,
src_surface->surface,
src_surface->hash_entry->surface_res,
- src_surface->hash_entry->interpolate);
+ src_surface->hash_entry->interpolate,
+ src_surface->hash_entry->mask);
}
}
@@ -2414,6 +2503,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
status = _cairo_pdf_surface_add_source_surface (surface,
pattern->surface,
pdf_pattern->pattern->filter,
+ FALSE,
&pattern_resource,
&pattern_width,
&pattern_height);
@@ -2827,7 +2917,50 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface,
stops[n_stops-1].offset = 1.0;
}
- if (n_stops <= 2) {
+ if (stops[0].offset == stops[n_stops - 1].offset) {
+ /*
+ * The first and the last stops have the same offset, but we
+ * don't want a function with an empty domain, because that
+ * would provoke underdefined behaviour from rasterisers.
+ * This can only happen with EXTEND_PAD, because EXTEND_NONE
+ * is optimised into a clear pattern in cairo-gstate, and
+ * REFLECT/REPEAT are always transformed to have the first
+ * stop at t=0 and the last stop at t=1. Thus we want a step
+ * function going from the first color to the last one.
+ *
+ * This can be accomplished by stitching three functions:
+ * - a constant first color function,
+ * - a step from the first color to the last color (with empty domain)
+ * - a constant last color function
+ */
+ cairo_pdf_color_stop_t pad_stops[4];
+
+ assert (pattern->base.extend == CAIRO_EXTEND_PAD);
+
+ pad_stops[0] = pad_stops[1] = stops[0];
+ pad_stops[2] = pad_stops[3] = stops[n_stops - 1];
+
+ pad_stops[0].offset = 0;
+ pad_stops[3].offset = 1;
+
+ status = _cairo_pdf_surface_emit_stitched_colorgradient (surface,
+ 4,
+ pad_stops,
+ FALSE,
+ color_function);
+ if (unlikely (status))
+ goto BAIL;
+
+ if (emit_alpha) {
+ status = _cairo_pdf_surface_emit_stitched_colorgradient (surface,
+ 4,
+ pad_stops,
+ TRUE,
+ alpha_function);
+ if (unlikely (status))
+ goto BAIL;
+ }
+ } else if (n_stops == 2) {
/* no need for stitched function */
status = cairo_pdf_surface_emit_rgb_linear_function (surface,
&stops[0],
@@ -3013,101 +3146,159 @@ cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t *surface,
return _cairo_output_stream_get_status (surface->output);
}
+static void
+_cairo_pdf_surface_output_gradient (cairo_pdf_surface_t *surface,
+ const cairo_pdf_pattern_t *pdf_pattern,
+ cairo_pdf_resource_t pattern_resource,
+ const cairo_matrix_t *pat_to_pdf,
+ const cairo_circle_double_t*start,
+ const cairo_circle_double_t*end,
+ const double *domain,
+ const char *colorspace,
+ cairo_pdf_resource_t color_function)
+{
+ _cairo_output_stream_printf (surface->output,
+ "%d 0 obj\n"
+ "<< /Type /Pattern\n"
+ " /PatternType 2\n"
+ " /Matrix [ %f %f %f %f %f %f ]\n"
+ " /Shading\n",
+ pattern_resource.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);
+
+ if (pdf_pattern->pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
+ _cairo_output_stream_printf (surface->output,
+ " << /ShadingType 2\n"
+ " /ColorSpace %s\n"
+ " /Coords [ %f %f %f %f ]\n",
+ colorspace,
+ start->center.x, start->center.y,
+ end->center.x, end->center.y);
+ } else {
+ _cairo_output_stream_printf (surface->output,
+ " << /ShadingType 3\n"
+ " /ColorSpace %s\n"
+ " /Coords [ %f %f %f %f %f %f ]\n",
+ colorspace,
+ start->center.x, start->center.y,
+ MAX (start->radius, 0),
+ end->center.x, end->center.y,
+ MAX (end->radius, 0));
+ }
+
+ _cairo_output_stream_printf (surface->output,
+ " /Domain [ %f %f ]\n",
+ domain[0], domain[1]);
+
+ if (pdf_pattern->pattern->extend != CAIRO_EXTEND_NONE) {
+ _cairo_output_stream_printf (surface->output,
+ " /Extend [ true true ]\n");
+ } else {
+ _cairo_output_stream_printf (surface->output,
+ " /Extend [ false false ]\n");
+ }
+
+ _cairo_output_stream_printf (surface->output,
+ " /Function %d 0 R\n"
+ " >>\n"
+ ">>\n"
+ "endobj\n",
+ color_function.id);
+}
+
static cairo_status_t
-_cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
- cairo_pdf_pattern_t *pdf_pattern)
+_cairo_pdf_surface_emit_gradient (cairo_pdf_surface_t *surface,
+ cairo_pdf_pattern_t *pdf_pattern)
{
- cairo_linear_pattern_t *pattern = (cairo_linear_pattern_t *) pdf_pattern->pattern;
+ cairo_gradient_pattern_t *pattern = (cairo_gradient_pattern_t *) pdf_pattern->pattern;
cairo_pdf_resource_t color_function, alpha_function;
- double x1, y1, x2, y2;
- double _x1, _y1, _x2, _y2;
cairo_matrix_t pat_to_pdf;
- cairo_extend_t extend;
+ cairo_circle_double_t start, end;
+ double domain[2];
cairo_status_t status;
- cairo_gradient_pattern_t *gradient = &pattern->base;
- double first_stop, last_stop;
- int repeat_begin = 0, repeat_end = 1;
- assert (pattern->base.n_stops != 0);
+ assert (pattern->n_stops != 0);
- extend = cairo_pattern_get_extend (pdf_pattern->pattern);
+ status = _cairo_pdf_surface_emit_pattern_stops (surface,
+ pattern,
+ &color_function,
+ &alpha_function);
+ if (unlikely (status))
+ return status;
- pat_to_pdf = pattern->base.base.matrix;
+ pat_to_pdf = pattern->base.matrix;
status = cairo_matrix_invert (&pat_to_pdf);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
-
cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
- first_stop = gradient->stops[0].offset;
- last_stop = gradient->stops[gradient->n_stops - 1].offset;
-
- if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
- pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
- double dx, dy;
- int x_rep = 0, y_rep = 0;
-
- x1 = _cairo_fixed_to_double (pattern->p1.x);
- y1 = _cairo_fixed_to_double (pattern->p1.y);
- cairo_matrix_transform_point (&pat_to_pdf, &x1, &y1);
-
- x2 = _cairo_fixed_to_double (pattern->p2.x);
- y2 = _cairo_fixed_to_double (pattern->p2.y);
- cairo_matrix_transform_point (&pat_to_pdf, &x2, &y2);
-
- dx = fabs (x2 - x1);
- dy = fabs (y2 - y1);
- if (dx > 1e-6)
- x_rep = ceil (surface->width/dx);
- if (dy > 1e-6)
- y_rep = ceil (surface->height/dy);
-
- repeat_end = MAX (x_rep, y_rep);
- repeat_begin = -repeat_end;
- first_stop = repeat_begin;
- last_stop = repeat_end;
- }
-
- /* PDF requires the first and last stop to be the same as the line
- * coordinates. For repeating patterns this moves the line
- * coordinates out to the begin/end of the repeating function. For
- * non repeating patterns this may move the line coordinates in if
- * there are not stops at offset 0 and 1. */
- x1 = _cairo_fixed_to_double (pattern->p1.x);
- y1 = _cairo_fixed_to_double (pattern->p1.y);
- x2 = _cairo_fixed_to_double (pattern->p2.x);
- y2 = _cairo_fixed_to_double (pattern->p2.y);
-
- _x1 = x1 + (x2 - x1)*first_stop;
- _y1 = y1 + (y2 - y1)*first_stop;
- _x2 = x1 + (x2 - x1)*last_stop;
- _y2 = y1 + (y2 - y1)*last_stop;
-
- x1 = _x1;
- x2 = _x2;
- y1 = _y1;
- y2 = _y2;
-
- /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a
- * Type 2 function is used by itself without a stitching
- * function. Type 2 functions always have the domain [0 1] */
- if ((pattern->base.base.extend == CAIRO_EXTEND_NONE ||
- pattern->base.base.extend == CAIRO_EXTEND_PAD) &&
- gradient->n_stops == 2) {
- first_stop = 0.0;
- last_stop = 1.0;
+
+ if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
+ pattern->base.extend == CAIRO_EXTEND_REFLECT)
+ {
+ double bounds_x1, bounds_x2, bounds_y1, bounds_y2;
+ double x_scale, y_scale, tolerance;
+
+ /* TODO: use tighter extents */
+ bounds_x1 = 0;
+ bounds_y1 = 0;
+ bounds_x2 = surface->width;
+ bounds_y2 = surface->height;
+ _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
+ &bounds_x1, &bounds_y1,
+ &bounds_x2, &bounds_y2,
+ NULL);
+
+ x_scale = surface->base.x_resolution / surface->base.x_fallback_resolution;
+ y_scale = surface->base.y_resolution / surface->base.y_fallback_resolution;
+
+ tolerance = fabs (_cairo_matrix_compute_determinant (&pattern->base.matrix));
+ tolerance /= _cairo_matrix_transformed_circle_major_axis (&pattern->base.matrix, 1);
+ tolerance *= MIN (x_scale, y_scale);
+
+ _cairo_gradient_pattern_box_to_parameter (pattern,
+ bounds_x1, bounds_y1,
+ bounds_x2, bounds_y2,
+ tolerance, domain);
+ } else if (pattern->stops[0].offset == pattern->stops[pattern->n_stops - 1].offset) {
+ /*
+ * If the first and the last stop offset are the same, then
+ * the color function is a step function.
+ * _cairo_ps_surface_emit_pattern_stops emits it as a stitched
+ * function no matter how many stops the pattern has. The
+ * domain of the stitched function will be [0 1] in this case.
+ *
+ * This is done to avoid emitting degenerate gradients for
+ * EXTEND_PAD patterns having a step color function.
+ */
+ domain[0] = 0.0;
+ domain[1] = 1.0;
+
+ assert (pattern->base.extend == CAIRO_EXTEND_PAD);
+ } else {
+ domain[0] = pattern->stops[0].offset;
+ domain[1] = pattern->stops[pattern->n_stops - 1].offset;
}
- status = _cairo_pdf_surface_emit_pattern_stops (surface,
- &pattern->base,
- &color_function,
- &alpha_function);
- if (unlikely (status))
- return status;
+ /* PDF requires the first and last stop to be the same as the
+ * extreme coordinates. For repeating patterns this moves the
+ * extreme coordinates out to the begin/end of the repeating
+ * function. For non repeating patterns this may move the extreme
+ * coordinates in if there are not stops at offset 0 and 1. */
+ _cairo_gradient_pattern_interpolate (pattern, domain[0], &start);
+ _cairo_gradient_pattern_interpolate (pattern, domain[1], &end);
+
+ if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
+ pattern->base.extend == CAIRO_EXTEND_REFLECT)
+ {
+ int repeat_begin, repeat_end;
+
+ repeat_begin = floor (domain[0]);
+ repeat_end = ceil (domain[1]);
- if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
- pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
status = _cairo_pdf_surface_emit_repeating_function (surface,
- &pattern->base,
+ pattern,
&color_function,
repeat_begin,
repeat_end);
@@ -3116,47 +3307,26 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
if (alpha_function.id != 0) {
status = _cairo_pdf_surface_emit_repeating_function (surface,
- &pattern->base,
+ pattern,
&alpha_function,
repeat_begin,
repeat_end);
if (unlikely (status))
return status;
}
+ } else if (pattern->n_stops <= 2) {
+ /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a
+ * Type 2 function is used by itself without a stitching
+ * function. Type 2 functions always have the domain [0 1] */
+ domain[0] = 0.0;
+ domain[1] = 1.0;
}
_cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Type /Pattern\n"
- " /PatternType 2\n"
- " /Matrix [ %f %f %f %f %f %f ]\n"
- " /Shading\n"
- " << /ShadingType 2\n"
- " /ColorSpace /DeviceRGB\n"
- " /Coords [ %f %f %f %f ]\n"
- " /Domain [ %f %f ]\n"
- " /Function %d 0 R\n",
- 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,
- x1, y1, x2, y2,
- first_stop, last_stop,
- color_function.id);
-
- if (extend == CAIRO_EXTEND_PAD) {
- _cairo_output_stream_printf (surface->output,
- " /Extend [ true true ]\n");
- } else {
- _cairo_output_stream_printf (surface->output,
- " /Extend [ false false ]\n");
- }
-
- _cairo_output_stream_printf (surface->output,
- " >>\n"
- ">>\n"
- "endobj\n");
+ _cairo_pdf_surface_output_gradient (surface, pdf_pattern,
+ pdf_pattern->pattern_res,
+ &pat_to_pdf, &start, &end, domain,
+ "/DeviceRGB", color_function);
if (alpha_function.id != 0) {
cairo_pdf_resource_t mask_resource;
@@ -3168,37 +3338,11 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
if (mask_resource.id == 0)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Type /Pattern\n"
- " /PatternType 2\n"
- " /Matrix [ %f %f %f %f %f %f ]\n"
- " /Shading\n"
- " << /ShadingType 2\n"
- " /ColorSpace /DeviceGray\n"
- " /Coords [ %f %f %f %f ]\n"
- " /Domain [ %f %f ]\n"
- " /Function %d 0 R\n",
- mask_resource.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,
- x1, y1, x2, y2,
- first_stop, last_stop,
- alpha_function.id);
-
- if (extend == CAIRO_EXTEND_PAD) {
- _cairo_output_stream_printf (surface->output,
- " /Extend [ true true ]\n");
- } else {
- _cairo_output_stream_printf (surface->output,
- " /Extend [ false false ]\n");
- }
+ _cairo_pdf_surface_output_gradient (surface, pdf_pattern,
+ mask_resource,
+ &pat_to_pdf, &start, &end, domain,
+ "/DeviceGray", alpha_function);
- _cairo_output_stream_printf (surface->output,
- " >>\n"
- ">>\n"
- "endobj\n");
status = _cairo_pdf_surface_add_pattern (surface, mask_resource);
if (unlikely (status))
return status;
@@ -3214,111 +3358,138 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
}
static cairo_status_t
-_cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface,
- cairo_pdf_pattern_t *pdf_pattern)
+_cairo_pdf_surface_emit_mesh_pattern (cairo_pdf_surface_t *surface,
+ cairo_pdf_pattern_t *pdf_pattern)
{
- 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;
+ cairo_pattern_t *pattern = pdf_pattern->pattern;
+ cairo_pdf_shading_t shading;
+ int i;
+ cairo_pdf_resource_t res;
- assert (pattern->base.n_stops != 0);
+ pat_to_pdf = pattern->matrix;
+ status = cairo_matrix_invert (&pat_to_pdf);
+ /* cairo_pattern_set_matrix ensures the matrix is invertible */
+ assert (status == CAIRO_STATUS_SUCCESS);
- extend = cairo_pattern_get_extend (pdf_pattern->pattern);
+ cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
- status = _cairo_pdf_surface_emit_pattern_stops (surface,
- &pattern->base,
- &color_function,
- &alpha_function);
+ status = _cairo_pdf_shading_init_color (&shading, (cairo_mesh_pattern_t *) pattern);
if (unlikely (status))
return status;
- pat_to_pdf = pattern->base.base.matrix;
- status = cairo_matrix_invert (&pat_to_pdf);
- /* cairo_pattern_set_matrix ensures the matrix is invertible */
- assert (status == CAIRO_STATUS_SUCCESS);
+ res = _cairo_pdf_surface_new_object (surface);
+ if (unlikely (res.id == 0))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
- x1 = _cairo_fixed_to_double (pattern->c1.x);
- y1 = _cairo_fixed_to_double (pattern->c1.y);
- r1 = _cairo_fixed_to_double (pattern->r1);
- x2 = _cairo_fixed_to_double (pattern->c2.x);
- y2 = _cairo_fixed_to_double (pattern->c2.y);
- r2 = _cairo_fixed_to_double (pattern->r2);
+ _cairo_output_stream_printf (surface->output,
+ "%d 0 obj\n"
+ "<< /ShadingType %d\n"
+ " /ColorSpace /DeviceRGB\n"
+ " /BitsPerCoordinate %d\n"
+ " /BitsPerComponent %d\n"
+ " /BitsPerFlag %d\n"
+ " /Decode [",
+ res.id,
+ shading.shading_type,
+ shading.bits_per_coordinate,
+ shading.bits_per_component,
+ shading.bits_per_flag);
- _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
+ for (i = 0; i < shading.decode_array_length; i++)
+ _cairo_output_stream_printf (surface->output, "%f ", shading.decode_array[i]);
+
+ _cairo_output_stream_printf (surface->output,
+ "]\n"
+ " /Length %ld\n"
+ ">>\n"
+ "stream\n",
+ shading.data_length);
+
+ _cairo_output_stream_write (surface->output, shading.data, shading.data_length);
_cairo_output_stream_printf (surface->output,
+ "\nendstream\n"
+ "endobj\n");
+
+ _cairo_pdf_shading_fini (&shading);
+
+ _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
+ _cairo_output_stream_printf (surface->output,
"%d 0 obj\n"
"<< /Type /Pattern\n"
" /PatternType 2\n"
" /Matrix [ %f %f %f %f %f %f ]\n"
- " /Shading\n"
- " << /ShadingType 3\n"
- " /ColorSpace /DeviceRGB\n"
- " /Coords [ %f %f %f %f %f %f ]\n"
- " /Function %d 0 R\n",
+ " /Shading %d 0 R\n"
+ ">>\n"
+ "endobj\n",
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,
- x1, y1, r1, x2, y2, r2,
- color_function.id);
+ res.id);
- if (extend == CAIRO_EXTEND_PAD) {
- _cairo_output_stream_printf (surface->output,
- " /Extend [ true true ]\n");
- } else {
- _cairo_output_stream_printf (surface->output,
- " /Extend [ false false ]\n");
- }
+ if (pdf_pattern->gstate_res.id != 0) {
+ cairo_pdf_resource_t mask_resource;
- _cairo_output_stream_printf (surface->output,
- " >>\n"
- ">>\n"
- "endobj\n");
+ /* Create pattern for SMask. */
+ res = _cairo_pdf_surface_new_object (surface);
+ if (unlikely (res.id == 0))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- if (alpha_function.id != 0) {
- cairo_pdf_resource_t mask_resource;
+ status = _cairo_pdf_shading_init_alpha (&shading, (cairo_mesh_pattern_t *) pattern);
+ if (unlikely (status))
+ return status;
- assert (pdf_pattern->gstate_res.id != 0);
+ _cairo_output_stream_printf (surface->output,
+ "%d 0 obj\n"
+ "<< /ShadingType %d\n"
+ " /ColorSpace /DeviceGray\n"
+ " /BitsPerCoordinate %d\n"
+ " /BitsPerComponent %d\n"
+ " /BitsPerFlag %d\n"
+ " /Decode [",
+ res.id,
+ shading.shading_type,
+ shading.bits_per_coordinate,
+ shading.bits_per_component,
+ shading.bits_per_flag);
+
+ for (i = 0; i < shading.decode_array_length; i++)
+ _cairo_output_stream_printf (surface->output, "%f ", shading.decode_array[i]);
+
+ _cairo_output_stream_printf (surface->output,
+ "]\n"
+ " /Length %ld\n"
+ ">>\n"
+ "stream\n",
+ shading.data_length);
+
+ _cairo_output_stream_write (surface->output, shading.data, shading.data_length);
+
+ _cairo_output_stream_printf (surface->output,
+ "\nendstream\n"
+ "endobj\n");
+ _cairo_pdf_shading_fini (&shading);
- /* Create pattern for SMask. */
mask_resource = _cairo_pdf_surface_new_object (surface);
- if (mask_resource.id == 0)
+ if (unlikely (mask_resource.id == 0))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Type /Pattern\n"
- " /PatternType 2\n"
- " /Matrix [ %f %f %f %f %f %f ]\n"
- " /Shading\n"
- " << /ShadingType 3\n"
- " /ColorSpace /DeviceGray\n"
- " /Coords [ %f %f %f %f %f %f ]\n"
- " /Function %d 0 R\n",
- mask_resource.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,
- x1, y1, r1, x2, y2, r2,
- alpha_function.id);
-
- if (extend == CAIRO_EXTEND_PAD) {
- _cairo_output_stream_printf (surface->output,
- " /Extend [ true true ]\n");
- } else {
- _cairo_output_stream_printf (surface->output,
- " /Extend [ false false ]\n");
- }
-
- _cairo_output_stream_printf (surface->output,
- " >>\n"
- ">>\n"
- "endobj\n");
+ _cairo_output_stream_printf (surface->output,
+ "%d 0 obj\n"
+ "<< /Type /Pattern\n"
+ " /PatternType 2\n"
+ " /Matrix [ %f %f %f %f %f %f ]\n"
+ " /Shading %d 0 R\n"
+ ">>\n"
+ "endobj\n",
+ mask_resource.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,
+ res.id);
status = cairo_pdf_surface_emit_transparency_group (surface,
pdf_pattern->gstate_res,
@@ -3353,11 +3524,12 @@ _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern
break;
case CAIRO_PATTERN_TYPE_LINEAR:
- status = _cairo_pdf_surface_emit_linear_pattern (surface, pdf_pattern);
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ status = _cairo_pdf_surface_emit_gradient (surface, pdf_pattern);
break;
- case CAIRO_PATTERN_TYPE_RADIAL:
- status = _cairo_pdf_surface_emit_radial_pattern (surface, pdf_pattern);
+ case CAIRO_PATTERN_TYPE_MESH:
+ status = _cairo_pdf_surface_emit_mesh_pattern (surface, pdf_pattern);
break;
default:
@@ -3375,7 +3547,8 @@ _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_surface_pattern_t *source,
+ cairo_bool_t mask)
{
cairo_pdf_resource_t surface_res;
int width, height;
@@ -3386,6 +3559,7 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
status = _cairo_pdf_surface_add_source_surface (surface,
source->surface,
source->base.filter,
+ mask,
&surface_res,
&width,
&height);
@@ -3420,10 +3594,16 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
if (unlikely (status))
return status;
- _cairo_output_stream_printf (surface->output,
- "/a%d gs /x%d Do\n",
- alpha,
- surface_res.id);
+ if (mask) {
+ _cairo_output_stream_printf (surface->output,
+ "/x%d Do\n",
+ surface_res.id);
+ } else {
+ _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);
}
@@ -3616,6 +3796,7 @@ _cairo_pdf_surface_get_font_options (void *abstract_surface,
cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
+ _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_OFF);
}
static cairo_pdf_resource_t
@@ -3790,7 +3971,6 @@ _create_font_subset_tag (cairo_scaled_font_subset_t *font_subset,
static cairo_int_status_t
_cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
cairo_scaled_font_subset_t *font_subset,
- cairo_bool_t is_composite,
cairo_pdf_resource_t *stream)
{
unsigned int i, num_bfchar;
@@ -3818,7 +3998,7 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
"/CMapType 2 def\n"
"1 begincodespacerange\n");
- if (is_composite) {
+ if (font_subset->is_composite && !font_subset->is_latin) {
_cairo_output_stream_printf (surface->output,
"<0000> <ffff>\n");
} else {
@@ -3870,7 +4050,7 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
"%d beginbfchar\n",
num_bfchar - i > 100 ? 100 : num_bfchar - i);
}
- if (is_composite)
+ if (font_subset->is_composite && !font_subset->is_latin)
_cairo_output_stream_printf (surface->output, "<%04x> ", i + 1);
else
_cairo_output_stream_printf (surface->output, "<%02x> ", i + 1);
@@ -3908,7 +4088,7 @@ _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface,
cairo_pdf_resource_t stream, descriptor, cidfont_dict;
cairo_pdf_resource_t subset_resource, to_unicode_stream;
cairo_pdf_font_t font;
- unsigned int i;
+ unsigned int i, last_glyph;
cairo_status_t status;
char tag[10];
@@ -3923,6 +4103,8 @@ _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface,
status = _cairo_pdf_surface_open_stream (surface,
NULL,
TRUE,
+ font_subset->is_latin ?
+ " /Subtype /Type1C\n" :
" /Subtype /CIDFontType0C\n");
if (unlikely (status))
return status;
@@ -3935,7 +4117,7 @@ _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface,
return status;
status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
- font_subset, TRUE,
+ font_subset,
&to_unicode_stream);
if (_cairo_status_is_error (status))
return status;
@@ -3979,58 +4161,106 @@ _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface,
(long)(subset->y_max*PDF_UNITS_PER_EM),
stream.id);
- cidfont_dict = _cairo_pdf_surface_new_object (surface);
- if (cidfont_dict.id == 0)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ if (font_subset->is_latin) {
+ /* find last glyph used */
+ for (i = 255; i >= 32; i--)
+ if (font_subset->latin_to_subset_glyph_index[i] > 0)
+ break;
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Type /Font\n"
- " /Subtype /CIDFontType0\n"
- " /BaseFont /%s+%s\n"
- " /CIDSystemInfo\n"
- " << /Registry (Adobe)\n"
- " /Ordering (Identity)\n"
- " /Supplement 0\n"
- " >>\n"
- " /FontDescriptor %d 0 R\n"
- " /W [0 [",
- cidfont_dict.id,
- tag,
- subset->ps_name,
- descriptor.id);
+ last_glyph = i;
+ _cairo_pdf_surface_update_object (surface, subset_resource);
+ _cairo_output_stream_printf (surface->output,
+ "%d 0 obj\r\n"
+ "<< /Type /Font\n"
+ " /Subtype /Type1\n"
+ " /BaseFont /%s+%s\n"
+ " /FirstChar 32\n"
+ " /LastChar %d\n"
+ " /FontDescriptor %d 0 R\n"
+ " /Encoding /WinAnsiEncoding\n"
+ " /Widths [",
+ subset_resource.id,
+ tag,
+ subset->ps_name,
+ last_glyph,
+ descriptor.id);
+
+ for (i = 32; i < last_glyph + 1; i++) {
+ int glyph = font_subset->latin_to_subset_glyph_index[i];
+ if (glyph > 0) {
+ _cairo_output_stream_printf (surface->output,
+ " %ld",
+ (long)(subset->widths[glyph]*PDF_UNITS_PER_EM));
+ } else {
+ _cairo_output_stream_printf (surface->output, " 0");
+ }
+ }
- for (i = 0; i < font_subset->num_glyphs; i++)
_cairo_output_stream_printf (surface->output,
- " %ld",
- (long)(subset->widths[i]*PDF_UNITS_PER_EM));
+ " ]\n");
- _cairo_output_stream_printf (surface->output,
- " ]]\n"
- ">>\n"
- "endobj\n");
+ if (to_unicode_stream.id != 0)
+ _cairo_output_stream_printf (surface->output,
+ " /ToUnicode %d 0 R\n",
+ to_unicode_stream.id);
- _cairo_pdf_surface_update_object (surface, subset_resource);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Type /Font\n"
- " /Subtype /Type0\n"
- " /BaseFont /%s+%s\n"
- " /Encoding /Identity-H\n"
- " /DescendantFonts [ %d 0 R]\n",
- subset_resource.id,
- tag,
- subset->ps_name,
- cidfont_dict.id);
+ _cairo_output_stream_printf (surface->output,
+ ">>\n"
+ "endobj\n");
+ } else {
+ cidfont_dict = _cairo_pdf_surface_new_object (surface);
+ if (cidfont_dict.id == 0)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- if (to_unicode_stream.id != 0)
- _cairo_output_stream_printf (surface->output,
- " /ToUnicode %d 0 R\n",
- to_unicode_stream.id);
+ _cairo_output_stream_printf (surface->output,
+ "%d 0 obj\n"
+ "<< /Type /Font\n"
+ " /Subtype /CIDFontType0\n"
+ " /BaseFont /%s+%s\n"
+ " /CIDSystemInfo\n"
+ " << /Registry (Adobe)\n"
+ " /Ordering (Identity)\n"
+ " /Supplement 0\n"
+ " >>\n"
+ " /FontDescriptor %d 0 R\n"
+ " /W [0 [",
+ cidfont_dict.id,
+ tag,
+ subset->ps_name,
+ descriptor.id);
+
+ for (i = 0; i < font_subset->num_glyphs; i++)
+ _cairo_output_stream_printf (surface->output,
+ " %ld",
+ (long)(subset->widths[i]*PDF_UNITS_PER_EM));
- _cairo_output_stream_printf (surface->output,
- ">>\n"
- "endobj\n");
+ _cairo_output_stream_printf (surface->output,
+ " ]]\n"
+ ">>\n"
+ "endobj\n");
+
+ _cairo_pdf_surface_update_object (surface, subset_resource);
+ _cairo_output_stream_printf (surface->output,
+ "%d 0 obj\n"
+ "<< /Type /Font\n"
+ " /Subtype /Type0\n"
+ " /BaseFont /%s+%s\n"
+ " /Encoding /Identity-H\n"
+ " /DescendantFonts [ %d 0 R]\n",
+ subset_resource.id,
+ tag,
+ subset->ps_name,
+ cidfont_dict.id);
+
+ if (to_unicode_stream.id != 0)
+ _cairo_output_stream_printf (surface->output,
+ " /ToUnicode %d 0 R\n",
+ to_unicode_stream.id);
+
+ _cairo_output_stream_printf (surface->output,
+ ">>\n"
+ "endobj\n");
+ }
font.font_id = font_subset->font_id;
font.subset_id = font_subset->subset_id;
@@ -4069,6 +4299,11 @@ _cairo_pdf_surface_emit_cff_fallback_font (cairo_pdf_surface_t *surface,
cairo_cff_subset_t subset;
char name[64];
+ /* CFF fallback subsetting does not work with 8-bit glyphs unless
+ * they are a latin subset */
+ if (!font_subset->is_composite && !font_subset->is_latin)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
snprintf (name, sizeof name, "CairoFont-%d-%d",
font_subset->font_id, font_subset->subset_id);
status = _cairo_cff_fallback_init (&subset, name, font_subset);
@@ -4091,7 +4326,7 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface,
cairo_pdf_font_t font;
cairo_status_t status;
unsigned long length;
- unsigned int i;
+ unsigned int i, last_glyph;
char tag[10];
_create_font_subset_tag (font_subset, subset->base_font, tag);
@@ -4122,11 +4357,20 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface,
return status;
status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
- font_subset, FALSE,
+ font_subset,
&to_unicode_stream);
if (_cairo_status_is_error (status))
return status;
+ if (font_subset->is_latin) {
+ /* find last glyph used */
+ for (i = 255; i >= 32; i--)
+ if (font_subset->latin_to_subset_glyph_index[i] > 0)
+ break;
+
+ last_glyph = i;
+ }
+
descriptor = _cairo_pdf_surface_new_object (surface);
if (descriptor.id == 0)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -4135,7 +4379,7 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface,
"%d 0 obj\n"
"<< /Type /FontDescriptor\n"
" /FontName /%s+%s\n"
- " /Flags 4\n"
+ " /Flags %d\n"
" /FontBBox [ %ld %ld %ld %ld ]\n"
" /ItalicAngle 0\n"
" /Ascent %ld\n"
@@ -4149,6 +4393,7 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface,
descriptor.id,
tag,
subset->base_font,
+ font_subset->is_latin ? 32 : 4,
(long)(subset->x_min*PDF_UNITS_PER_EM),
(long)(subset->y_min*PDF_UNITS_PER_EM),
(long)(subset->x_max*PDF_UNITS_PER_EM),
@@ -4164,20 +4409,34 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface,
"<< /Type /Font\n"
" /Subtype /Type1\n"
" /BaseFont /%s+%s\n"
- " /FirstChar 0\n"
+ " /FirstChar %d\n"
" /LastChar %d\n"
" /FontDescriptor %d 0 R\n"
" /Widths [",
subset_resource.id,
tag,
subset->base_font,
- font_subset->num_glyphs - 1,
+ font_subset->is_latin ? 32 : 0,
+ font_subset->is_latin ? last_glyph : font_subset->num_glyphs - 1,
descriptor.id);
- for (i = 0; i < font_subset->num_glyphs; i++)
- _cairo_output_stream_printf (surface->output,
- " %ld",
- (long)(subset->widths[i]*PDF_UNITS_PER_EM));
+ if (font_subset->is_latin) {
+ for (i = 32; i < last_glyph + 1; i++) {
+ int glyph = font_subset->latin_to_subset_glyph_index[i];
+ if (glyph > 0) {
+ _cairo_output_stream_printf (surface->output,
+ " %ld",
+ (long)(subset->widths[glyph]*PDF_UNITS_PER_EM));
+ } else {
+ _cairo_output_stream_printf (surface->output, " 0");
+ }
+ }
+ } else {
+ for (i = 0; i < font_subset->num_glyphs; i++)
+ _cairo_output_stream_printf (surface->output,
+ " %ld",
+ (long)(subset->widths[i]*PDF_UNITS_PER_EM));
+ }
_cairo_output_stream_printf (surface->output,
" ]\n");
@@ -4206,6 +4465,10 @@ _cairo_pdf_surface_emit_type1_font_subset (cairo_pdf_surface_t *surface,
cairo_type1_subset_t subset;
char name[64];
+ /* 16-bit glyphs not compatible with Type 1 fonts */
+ if (font_subset->is_composite && !font_subset->is_latin)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
snprintf (name, sizeof name, "CairoFont-%d-%d",
font_subset->font_id, font_subset->subset_id);
status = _cairo_type1_subset_init (&subset, name, font_subset, FALSE);
@@ -4227,6 +4490,10 @@ _cairo_pdf_surface_emit_type1_fallback_font (cairo_pdf_surface_t *surface,
cairo_type1_subset_t subset;
char name[64];
+ /* 16-bit glyphs not compatible with Type 1 fonts */
+ if (font_subset->is_composite && !font_subset->is_latin)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
snprintf (name, sizeof name, "CairoFont-%d-%d",
font_subset->font_id, font_subset->subset_id);
status = _cairo_type1_fallback_init_binary (&subset, name, font_subset);
@@ -4248,7 +4515,7 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
cairo_status_t status;
cairo_pdf_font_t font;
cairo_truetype_subset_t subset;
- unsigned int i;
+ unsigned int i, last_glyph;
char tag[10];
subset_resource = _cairo_pdf_surface_get_font_resource (surface,
@@ -4257,7 +4524,7 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
if (subset_resource.id == 0)
return CAIRO_STATUS_SUCCESS;
- status = _cairo_truetype_subset_init (&subset, font_subset);
+ status = _cairo_truetype_subset_init_pdf (&subset, font_subset);
if (unlikely (status))
return status;
@@ -4283,7 +4550,7 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
}
status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
- font_subset, TRUE,
+ font_subset,
&to_unicode_stream);
if (_cairo_status_is_error (status)) {
_cairo_truetype_subset_fini (&subset);
@@ -4311,7 +4578,7 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
}
_cairo_output_stream_printf (surface->output,
- " /Flags 4\n"
+ " /Flags %d\n"
" /FontBBox [ %ld %ld %ld %ld ]\n"
" /ItalicAngle 0\n"
" /Ascent %ld\n"
@@ -4322,6 +4589,7 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
" /FontFile2 %u 0 R\n"
">>\n"
"endobj\n",
+ font_subset->is_latin ? 32 : 4,
(long)(subset.x_min*PDF_UNITS_PER_EM),
(long)(subset.y_min*PDF_UNITS_PER_EM),
(long)(subset.x_max*PDF_UNITS_PER_EM),
@@ -4331,60 +4599,108 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
(long)(subset.y_max*PDF_UNITS_PER_EM),
stream.id);
- cidfont_dict = _cairo_pdf_surface_new_object (surface);
- if (cidfont_dict.id == 0) {
- _cairo_truetype_subset_fini (&subset);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
+ if (font_subset->is_latin) {
+ /* find last glyph used */
+ for (i = 255; i >= 32; i--)
+ if (font_subset->latin_to_subset_glyph_index[i] > 0)
+ break;
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Type /Font\n"
- " /Subtype /CIDFontType2\n"
- " /BaseFont /%s+%s\n"
- " /CIDSystemInfo\n"
- " << /Registry (Adobe)\n"
- " /Ordering (Identity)\n"
- " /Supplement 0\n"
- " >>\n"
- " /FontDescriptor %d 0 R\n"
- " /W [0 [",
- cidfont_dict.id,
- tag,
- subset.ps_name,
- descriptor.id);
+ last_glyph = i;
+ _cairo_pdf_surface_update_object (surface, subset_resource);
+ _cairo_output_stream_printf (surface->output,
+ "%d 0 obj\r\n"
+ "<< /Type /Font\n"
+ " /Subtype /TrueType\n"
+ " /BaseFont /%s+%s\n"
+ " /FirstChar 32\n"
+ " /LastChar %d\n"
+ " /FontDescriptor %d 0 R\n"
+ " /Encoding /WinAnsiEncoding\n"
+ " /Widths [",
+ subset_resource.id,
+ tag,
+ subset.ps_name,
+ last_glyph,
+ descriptor.id);
+
+ for (i = 32; i < last_glyph + 1; i++) {
+ int glyph = font_subset->latin_to_subset_glyph_index[i];
+ if (glyph > 0) {
+ _cairo_output_stream_printf (surface->output,
+ " %ld",
+ (long)(subset.widths[glyph]*PDF_UNITS_PER_EM));
+ } else {
+ _cairo_output_stream_printf (surface->output, " 0");
+ }
+ }
- for (i = 0; i < font_subset->num_glyphs; i++)
- _cairo_output_stream_printf (surface->output,
- " %ld",
- (long)(subset.widths[i]*PDF_UNITS_PER_EM));
+ _cairo_output_stream_printf (surface->output,
+ " ]\n");
- _cairo_output_stream_printf (surface->output,
- " ]]\n"
- ">>\n"
- "endobj\n");
+ if (to_unicode_stream.id != 0)
+ _cairo_output_stream_printf (surface->output,
+ " /ToUnicode %d 0 R\n",
+ to_unicode_stream.id);
- _cairo_pdf_surface_update_object (surface, subset_resource);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Type /Font\n"
- " /Subtype /Type0\n"
- " /BaseFont /%s+%s\n"
- " /Encoding /Identity-H\n"
- " /DescendantFonts [ %d 0 R]\n",
- subset_resource.id,
- tag,
- subset.ps_name,
- cidfont_dict.id);
+ _cairo_output_stream_printf (surface->output,
+ ">>\n"
+ "endobj\n");
+ } else {
+ cidfont_dict = _cairo_pdf_surface_new_object (surface);
+ if (cidfont_dict.id == 0) {
+ _cairo_truetype_subset_fini (&subset);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
- if (to_unicode_stream.id != 0)
- _cairo_output_stream_printf (surface->output,
- " /ToUnicode %d 0 R\n",
- to_unicode_stream.id);
+ _cairo_output_stream_printf (surface->output,
+ "%d 0 obj\n"
+ "<< /Type /Font\n"
+ " /Subtype /CIDFontType2\n"
+ " /BaseFont /%s+%s\n"
+ " /CIDSystemInfo\n"
+ " << /Registry (Adobe)\n"
+ " /Ordering (Identity)\n"
+ " /Supplement 0\n"
+ " >>\n"
+ " /FontDescriptor %d 0 R\n"
+ " /W [0 [",
+ cidfont_dict.id,
+ tag,
+ subset.ps_name,
+ descriptor.id);
+
+ for (i = 0; i < font_subset->num_glyphs; i++)
+ _cairo_output_stream_printf (surface->output,
+ " %ld",
+ (long)(subset.widths[i]*PDF_UNITS_PER_EM));
- _cairo_output_stream_printf (surface->output,
- ">>\n"
- "endobj\n");
+ _cairo_output_stream_printf (surface->output,
+ " ]]\n"
+ ">>\n"
+ "endobj\n");
+
+ _cairo_pdf_surface_update_object (surface, subset_resource);
+ _cairo_output_stream_printf (surface->output,
+ "%d 0 obj\n"
+ "<< /Type /Font\n"
+ " /Subtype /Type0\n"
+ " /BaseFont /%s+%s\n"
+ " /Encoding /Identity-H\n"
+ " /DescendantFonts [ %d 0 R]\n",
+ subset_resource.id,
+ tag,
+ subset.ps_name,
+ cidfont_dict.id);
+
+ if (to_unicode_stream.id != 0)
+ _cairo_output_stream_printf (surface->output,
+ " /ToUnicode %d 0 R\n",
+ to_unicode_stream.id);
+
+ _cairo_output_stream_printf (surface->output,
+ ">>\n"
+ "endobj\n");
+ }
font.font_id = font_subset->font_id;
font.subset_id = font_subset->subset_id;
@@ -4607,7 +4923,7 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
free (glyphs);
status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
- font_subset, FALSE,
+ font_subset,
&to_unicode_stream);
if (_cairo_status_is_error (status)) {
free (widths);
@@ -4668,30 +4984,27 @@ _cairo_pdf_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_s
cairo_pdf_surface_t *surface = closure;
cairo_status_t status;
- if (font_subset->is_composite) {
- status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- status = _cairo_pdf_surface_emit_truetype_font_subset (surface, font_subset);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ status = _cairo_pdf_surface_emit_truetype_font_subset (surface, font_subset);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- status = _cairo_pdf_surface_emit_cff_fallback_font (surface, font_subset);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- } else {
#if CAIRO_HAS_FT_FONT
- status = _cairo_pdf_surface_emit_type1_font_subset (surface, font_subset);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ status = _cairo_pdf_surface_emit_type1_font_subset (surface, font_subset);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
#endif
- status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ status = _cairo_pdf_surface_emit_cff_fallback_font (surface, font_subset);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- }
+ status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
ASSERT_NOT_REACHED;
return CAIRO_STATUS_SUCCESS;
@@ -5032,7 +5345,7 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface
cairo_pdf_pattern_t pattern;
cairo_pdf_smask_group_t *group;
cairo_pdf_source_surface_t src_surface;
- int pattern_index, group_index, surface_index;
+ unsigned int pattern_index, group_index, surface_index;
cairo_status_t status;
/* Writing out PDF_MASK groups will cause additional smask groups
@@ -5079,7 +5392,7 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
{
cairo_pdf_resource_t page, knockout, res;
cairo_status_t status;
- int i, len;
+ unsigned int i, len;
_cairo_pdf_group_resources_clear (&surface->resources);
if (surface->has_fallback_images) {
@@ -5226,54 +5539,22 @@ _surface_pattern_supported (cairo_surface_pattern_t *pattern)
}
static cairo_bool_t
-_gradient_pattern_supported (const cairo_pattern_t *pattern)
-{
- cairo_extend_t extend;
-
- extend = cairo_pattern_get_extend ((cairo_pattern_t *) pattern);
-
-
- /* Radial gradients are currently only supported with EXTEND_NONE
- * and EXTEND_PAD and when one circle is inside the other. */
- if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
- double x1, y1, x2, y2, r1, r2, d;
- cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
-
- if (extend == CAIRO_EXTEND_REPEAT ||
- extend == CAIRO_EXTEND_REFLECT) {
- return FALSE;
- }
-
- x1 = _cairo_fixed_to_double (radial->c1.x);
- y1 = _cairo_fixed_to_double (radial->c1.y);
- r1 = _cairo_fixed_to_double (radial->r1);
- x2 = _cairo_fixed_to_double (radial->c2.x);
- y2 = _cairo_fixed_to_double (radial->c2.y);
- r2 = _cairo_fixed_to_double (radial->r2);
-
- d = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
- if (d > fabs(r2 - r1)) {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-static cairo_bool_t
_pattern_supported (const cairo_pattern_t *pattern)
{
- if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ case CAIRO_PATTERN_TYPE_MESH:
return TRUE;
- if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
- pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
- return _gradient_pattern_supported (pattern);
-
- if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
+ case CAIRO_PATTERN_TYPE_SURFACE:
return _surface_pattern_supported ((cairo_surface_pattern_t *) pattern);
- return FALSE;
+ default:
+ ASSERT_NOT_REACHED;
+ return FALSE;
+ }
}
static cairo_bool_t
@@ -5408,6 +5689,68 @@ _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
return _cairo_pdf_surface_open_content_stream (surface, NULL, TRUE);
}
+/* A PDF stencil mask is an A1 mask used with the current color */
+static cairo_int_status_t
+_cairo_pdf_surface_emit_stencil_mask (cairo_pdf_surface_t *surface,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask)
+{
+ cairo_status_t status;
+ cairo_surface_pattern_t *surface_pattern;
+ cairo_image_surface_t *image;
+ void *image_extra;
+ cairo_pdf_resource_t pattern_res = {0};
+
+ if (! (source->type == CAIRO_PATTERN_TYPE_SOLID &&
+ mask->type == CAIRO_PATTERN_TYPE_SURFACE))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ surface_pattern = (cairo_surface_pattern_t *) mask;
+ if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_surface_acquire_source_image (surface_pattern->surface,
+ &image,
+ &image_extra);
+ if (unlikely (status))
+ return status;
+
+ if (image->base.status)
+ return image->base.status;
+
+ if (image->format != CAIRO_FORMAT_A1) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+
+ status = _cairo_pdf_surface_select_pattern (surface, source,
+ pattern_res, FALSE);
+ 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\n");
+ status = _cairo_pdf_surface_paint_surface_pattern (surface,
+ (cairo_surface_pattern_t *) surface_pattern,
+ TRUE);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (surface->output, "Q\n");
+
+ _cairo_surface_release_source_image (surface_pattern->surface, image, image_extra);
+ status = _cairo_output_stream_get_status (surface->output);
+
+cleanup:
+ _cairo_surface_release_source_image (surface_pattern->surface, image, image_extra);
+
+ return status;
+}
+
+
static cairo_int_status_t
_cairo_pdf_surface_paint (void *abstract_surface,
cairo_operator_t op,
@@ -5457,7 +5800,8 @@ _cairo_pdf_surface_paint (void *abstract_surface,
{
_cairo_output_stream_printf (surface->output, "q\n");
status = _cairo_pdf_surface_paint_surface_pattern (surface,
- (cairo_surface_pattern_t *) source);
+ (cairo_surface_pattern_t *) source,
+ FALSE);
if (unlikely (status))
return status;
@@ -5524,7 +5868,7 @@ _cairo_pdf_surface_paint (void *abstract_surface,
}
static cairo_int_status_t
-_cairo_pdf_surface_mask (void *abstract_surface,
+_cairo_pdf_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
@@ -5575,6 +5919,15 @@ _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;
+
+ /* Check if we can use a stencil mask */
+ status = _cairo_pdf_surface_emit_stencil_mask (surface, source, mask);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
group = _cairo_pdf_surface_create_smask_group (surface);
if (unlikely (group == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -5614,10 +5967,6 @@ _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,
@@ -5829,7 +6178,8 @@ _cairo_pdf_surface_fill (void *abstract_surface,
return status;
status = _cairo_pdf_surface_paint_surface_pattern (surface,
- (cairo_surface_pattern_t *) source);
+ (cairo_surface_pattern_t *) source,
+ FALSE);
if (unlikely (status))
return status;
@@ -5927,7 +6277,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
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;
+ cairo_composite_rectangles_t extents;
/* During analysis we return unsupported and let the _fill and
* _stroke functions that are on the fallback path do the analysis
@@ -5959,18 +6309,32 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
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;
+ status = _cairo_composite_rectangles_init_for_fill (&extents,
+ surface->width,
+ surface->height,
+ fill_op, fill_source, path,
+ clip);
+ if (unlikely (status)) {
+ if (status != CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return status;
+ }
+ /* use the more accurate extents */
+ if (extents.is_bounded) {
+ cairo_bool_t is_empty;
+
+ _cairo_path_fixed_fill_extents (path,
+ fill_rule,
+ fill_tolerance,
+ &extents.mask);
+
+ is_empty = ! _cairo_rectangle_intersect (&extents.bounded, &extents.mask);
+ }
fill_pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source,
- &extents,
+ &extents.bounded,
&fill_pattern_res,
&gstate_res);
if (unlikely (status))
@@ -5978,19 +6342,36 @@ _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;
+ status = _cairo_composite_rectangles_init_for_stroke (&extents,
+ surface->width,
+ surface->height,
+ stroke_op, stroke_source,
+ path, stroke_style, stroke_ctm,
+ clip);
+ if (unlikely (status)) {
+ if (status != CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return status;
+ }
+
+ /* use the more accurate extents */
+ if (extents.is_bounded) {
+ cairo_bool_t is_empty;
+
+ status = _cairo_path_fixed_stroke_extents (path, stroke_style,
+ stroke_ctm, stroke_ctm_inverse,
+ stroke_tolerance,
+ &extents.mask);
+ if (unlikely (status))
+ return status;
+
+ is_empty = ! _cairo_rectangle_intersect (&extents.bounded, &extents.mask);
+ }
stroke_pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface,
stroke_source,
- &extents,
+ &extents.bounded,
&stroke_pattern_res,
&gstate_res);
if (unlikely (status))