summaryrefslogtreecommitdiff
path: root/src/cairo-ps-surface.c
diff options
context:
space:
mode:
authorLoïc Minier <lool@dooz.org>2009-04-15 00:04:39 +0200
committerLoïc Minier <lool@dooz.org>2009-04-15 00:04:39 +0200
commitf4713253ccf85d454c2d7ae0322ff63c5144bbc9 (patch)
tree8b2bb39ee4d40ad5e22de698f5ec45393910e867 /src/cairo-ps-surface.c
parent0b7f8018c0813104d5ed151ba3ddebd84a9b42ef (diff)
Imported Upstream version 1.6.4
Diffstat (limited to 'src/cairo-ps-surface.c')
-rw-r--r--src/cairo-ps-surface.c1789
1 files changed, 777 insertions, 1012 deletions
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 65df5a2..f6940bf 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -3,7 +3,7 @@
*
* Copyright © 2003 University of Southern California
* Copyright © 2005 Red Hat, Inc
- * Copyright © 2007 Adrian Johnson
+ * Copyright © 2007,2008 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -40,9 +40,11 @@
* Adrian Johnson <ajohnson@redneon.com>
*/
+#define _BSD_SOURCE /* for ctime_r(), snprintf(), strdup() */
#include "cairoint.h"
#include "cairo-ps.h"
#include "cairo-ps-surface-private.h"
+#include "cairo-pdf-operators-private.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-paginated-private.h"
#include "cairo-meta-surface-private.h"
@@ -60,12 +62,6 @@
#define ctime_r(T, BUF) ctime (T)
#endif
-typedef enum _cairo_image_transparency {
- CAIRO_IMAGE_IS_OPAQUE,
- CAIRO_IMAGE_HAS_BILEVEL_ALPHA,
- CAIRO_IMAGE_HAS_ALPHA
-} cairo_image_transparency_t;
-
static const cairo_surface_backend_t cairo_ps_surface_backend;
static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend;
@@ -83,248 +79,6 @@ static const char * _cairo_ps_level_strings[CAIRO_PS_LEVEL_LAST] =
"PS Level 3"
};
-/* A word wrap stream can be used as a filter to do word wrapping on
- * top of an existing output stream. The word wrapping is quite
- * simple, using isspace to determine characters that separate
- * words. Any word that will cause the column count exceed the given
- * max_column will have a '\n' character emitted before it.
- *
- * The stream is careful to maintain integrity for words that cross
- * the boundary from one call to write to the next.
- *
- * Note: This stream does not guarantee that the output will never
- * exceed max_column. In particular, if a single word is larger than
- * max_column it will not be broken up.
- */
-typedef struct _word_wrap_stream {
- cairo_output_stream_t base;
- cairo_output_stream_t *output;
- int max_column;
- int column;
- cairo_bool_t last_write_was_space;
-} word_wrap_stream_t;
-
-static int
-_count_word_up_to (const unsigned char *s, int length)
-{
- int word = 0;
-
- while (length--) {
- if (! isspace (*s++))
- word++;
- else
- return word;
- }
-
- return word;
-}
-
-static cairo_status_t
-_word_wrap_stream_write (cairo_output_stream_t *base,
- const unsigned char *data,
- unsigned int length)
-{
- word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
- cairo_bool_t newline;
- int word;
-
- while (length) {
- if (isspace (*data)) {
- newline = (*data == '\n' || *data == '\r');
- if (! newline && stream->column >= stream->max_column) {
- _cairo_output_stream_printf (stream->output, "\n");
- stream->column = 0;
- }
- _cairo_output_stream_write (stream->output, data, 1);
- data++;
- length--;
- if (newline)
- stream->column = 0;
- else
- stream->column++;
- stream->last_write_was_space = TRUE;
- } else {
- word = _count_word_up_to (data, length);
- /* Don't wrap if this word is a continuation of a word
- * from a previous call to write. */
- if (stream->column + word >= stream->max_column &&
- stream->last_write_was_space)
- {
- _cairo_output_stream_printf (stream->output, "\n");
- stream->column = 0;
- }
- _cairo_output_stream_write (stream->output, data, word);
- data += word;
- length -= word;
- stream->column += word;
- stream->last_write_was_space = FALSE;
- }
- }
-
- return _cairo_output_stream_get_status (stream->output);
-}
-
-static cairo_status_t
-_word_wrap_stream_close (cairo_output_stream_t *base)
-{
- word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
-
- return _cairo_output_stream_get_status (stream->output);
-}
-
-static cairo_output_stream_t *
-_word_wrap_stream_create (cairo_output_stream_t *output, int max_column)
-{
- word_wrap_stream_t *stream;
-
- if (output->status)
- return _cairo_output_stream_create_in_error (output->status);
-
- stream = malloc (sizeof (word_wrap_stream_t));
- if (stream == NULL) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return (cairo_output_stream_t *) &_cairo_output_stream_nil;
- }
-
- _cairo_output_stream_init (&stream->base,
- _word_wrap_stream_write,
- _word_wrap_stream_close);
- stream->output = output;
- stream->max_column = max_column;
- stream->column = 0;
- stream->last_write_was_space = FALSE;
-
- return &stream->base;
-}
-
-typedef struct _ps_path_info {
- cairo_ps_surface_t *surface;
- cairo_output_stream_t *stream;
- cairo_line_cap_t line_cap;
- cairo_point_t last_move_to_point;
- cairo_bool_t has_sub_path;
-} ps_path_info_t;
-
-static cairo_status_t
-_cairo_ps_surface_path_move_to (void *closure, cairo_point_t *point)
-{
- ps_path_info_t *path_info = closure;
-
- path_info->last_move_to_point = *point;
- path_info->has_sub_path = FALSE;
-
- _cairo_output_stream_printf (path_info->stream,
- "%f %f M ",
- _cairo_fixed_to_double (point->x),
- _cairo_fixed_to_double (point->y));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_line_to (void *closure, cairo_point_t *point)
-{
- ps_path_info_t *path_info = closure;
-
- if (path_info->line_cap != CAIRO_LINE_CAP_ROUND &&
- ! path_info->has_sub_path &&
- point->x == path_info->last_move_to_point.x &&
- point->y == path_info->last_move_to_point.y)
- {
- return CAIRO_STATUS_SUCCESS;
- }
-
- path_info->has_sub_path = TRUE;
-
- _cairo_output_stream_printf (path_info->stream,
- "%f %f L ",
- _cairo_fixed_to_double (point->x),
- _cairo_fixed_to_double (point->y));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d)
-{
- ps_path_info_t *path_info = closure;
-
- path_info->has_sub_path = TRUE;
-
- _cairo_output_stream_printf (path_info->stream,
- "%f %f %f %f %f %f C ",
- _cairo_fixed_to_double (b->x),
- _cairo_fixed_to_double (b->y),
- _cairo_fixed_to_double (c->x),
- _cairo_fixed_to_double (c->y),
- _cairo_fixed_to_double (d->x),
- _cairo_fixed_to_double (d->y));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_close_path (void *closure)
-{
- ps_path_info_t *path_info = closure;
-
- if (path_info->line_cap != CAIRO_LINE_CAP_ROUND &&
- ! path_info->has_sub_path)
- {
- return CAIRO_STATUS_SUCCESS;
- }
-
- _cairo_output_stream_printf (path_info->stream,
- "P\n");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* The line cap value is needed to workaround the fact that PostScript
- * semantics for stroking degenerate sub-paths do not match cairo
- * semantics. (PostScript draws something for any line cap value,
- * while cairo draws something only for round caps).
- *
- * When using this function to emit a path to be filled, rather than
- * stroked, simply pass %CAIRO_LINE_CAP_ROUND which will guarantee that
- * the stroke workaround will not modify the path being emitted.
- */
-static cairo_status_t
-_cairo_ps_surface_emit_path (cairo_ps_surface_t *surface,
- cairo_output_stream_t *stream,
- cairo_path_fixed_t *path,
- cairo_line_cap_t line_cap)
-{
- cairo_output_stream_t *word_wrap;
- cairo_status_t status, status2;
- ps_path_info_t path_info;
-
- word_wrap = _word_wrap_stream_create (stream, 79);
- status = _cairo_output_stream_get_status (word_wrap);
- if (status)
- return _cairo_output_stream_destroy (word_wrap);
-
- path_info.surface = surface;
- path_info.stream = word_wrap;
- path_info.line_cap = line_cap;
- status = _cairo_path_fixed_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_ps_surface_path_move_to,
- _cairo_ps_surface_path_line_to,
- _cairo_ps_surface_path_curve_to,
- _cairo_ps_surface_path_close_path,
- &path_info);
-
- status2 = _cairo_output_stream_destroy (word_wrap);
- if (status == CAIRO_STATUS_SUCCESS)
- status = status2;
-
- return status;
-}
-
static void
_cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
{
@@ -388,26 +142,56 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
"userdict begin\n");
} else {
_cairo_output_stream_printf (surface->final_stream,
- "/languagelevel where{pop languagelevel}{1}ifelse %d lt{/Helvetica\n"
- "findfont 12 scalefont setfont 50 500 moveto\n"
- "(This print job requires a PostScript Language Level %d printer.)show\n"
- "showpage quit}if\n",
+ "/languagelevel where\n"
+ "{ pop languagelevel } { 1 } ifelse\n"
+ "%d lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto\n"
+ " (This print job requires a PostScript Language Level %d printer.) show\n"
+ " showpage quit } if\n",
level,
level);
}
_cairo_output_stream_printf (surface->final_stream,
- "/C{curveto}bind def\n"
- "/F{fill}bind def\n"
- "/G{setgray}bind def\n"
- "/L{lineto}bind def\n"
- "/M{moveto}bind def\n"
- "/P{closepath}bind def\n"
- "/R{setrgbcolor}bind def\n"
- "/S{show}bind def\n"
- "/xS{xshow}bind def\n"
- "/yS{yshow}bind def\n"
- "/xyS{xyshow}bind def\n"
+ "/q { gsave } bind def\n"
+ "/Q { grestore } bind def\n"
+ "/cm { 6 array astore concat } bind def\n"
+ "/w { setlinewidth } bind def\n"
+ "/J { setlinecap } bind def\n"
+ "/j { setlinejoin } bind def\n"
+ "/M { setmiterlimit } bind def\n"
+ "/d { setdash } bind def\n"
+ "/m { moveto } bind def\n"
+ "/l { lineto } bind def\n"
+ "/c { curveto } bind def\n"
+ "/h { closepath } bind def\n"
+ "/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto\n"
+ " 0 exch rlineto 0 rlineto closepath } bind def\n"
+ "/S { stroke } bind def\n"
+ "/f { fill } bind def\n"
+ "/f* { eofill } bind def\n"
+ "/n { newpath } bind def\n"
+ "/W { clip } bind def\n"
+ "/W* { eoclip } bind def\n"
+ "/Tf { pop /cairo_font exch def } bind def\n"
+ "/BT { } bind def\n"
+ "/ET { } bind def\n"
+ "/Tj { show } bind def\n"
+ "/TJ {\n"
+ " {\n"
+ " dup\n"
+ " type /stringtype eq\n"
+ " { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse\n"
+ " } forall\n"
+ "} bind def\n"
+ "/Td { matrix translate cairo_font_matrix matrix concatmatrix aload\n"
+ " /cairo_font_matrix exch def 6 2 roll 0 0 6 array astore\n"
+ " cairo_font exch selectfont moveto } bind def\n"
+ "/Tm { 6 copy 6 array astore /cairo_font_matrix exch def 6 2 roll 0 0\n"
+ " 6 array astore cairo_font exch selectfont moveto } bind def\n"
+ "/g { setgray } bind def\n"
+ "/rg { setrgbcolor } bind def\n");
+
+ _cairo_output_stream_printf (surface->final_stream,
"%%%%EndProlog\n");
num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
@@ -440,7 +224,7 @@ _cairo_ps_surface_emit_type1_font_subset (cairo_ps_surface_t *surface,
int length;
char name[64];
- snprintf (name, sizeof name, "CairoFont-%d-%d",
+ snprintf (name, sizeof name, "f-%d-%d",
font_subset->font_id, font_subset->subset_id);
status = _cairo_type1_subset_init (&subset, name, font_subset, TRUE);
if (status)
@@ -471,7 +255,7 @@ _cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t *surface,
int length;
char name[64];
- snprintf (name, sizeof name, "CairoFont-%d-%d",
+ snprintf (name, sizeof name, "f-%d-%d",
font_subset->font_id, font_subset->subset_id);
status = _cairo_type1_fallback_init_hex (&subset, name, font_subset);
if (status)
@@ -516,7 +300,7 @@ _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface,
_cairo_output_stream_printf (surface->final_stream,
"11 dict begin\n"
"/FontType 42 def\n"
- "/FontName /CairoFont-%d-%d def\n"
+ "/FontName /f-%d-%d def\n"
"/PaintType 0 def\n"
"/FontMatrix [ 1 0 0 1 0 0 ] def\n"
"/FontBBox [ 0 0 0 0 ] def\n"
@@ -586,48 +370,9 @@ _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface,
}
static cairo_int_status_t
-_cairo_ps_surface_emit_outline_glyph_data (cairo_ps_surface_t *surface,
- cairo_scaled_font_t *scaled_font,
- unsigned long glyph_index,
- cairo_box_t *bbox)
-{
- cairo_scaled_glyph_t *scaled_glyph;
- cairo_status_t status;
-
- status = _cairo_scaled_glyph_lookup (scaled_font,
- glyph_index,
- CAIRO_SCALED_GLYPH_INFO_METRICS|
- CAIRO_SCALED_GLYPH_INFO_PATH,
- &scaled_glyph);
- if (status)
- return status;
-
- *bbox = scaled_glyph->bbox;
- _cairo_output_stream_printf (surface->final_stream,
- "0 0 %f %f %f %f setcachedevice\n",
- _cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
- -_cairo_fixed_to_double (scaled_glyph->bbox.p2.y),
- _cairo_fixed_to_double (scaled_glyph->bbox.p2.x),
- -_cairo_fixed_to_double (scaled_glyph->bbox.p1.y));
-
- /* We're filling not stroking, so we pass CAIRO_LINE_CAP_ROUND. */
- status = _cairo_ps_surface_emit_path (surface,
- surface->final_stream,
- scaled_glyph->path,
- CAIRO_LINE_CAP_ROUND);
- if (status)
- return status;
-
- _cairo_output_stream_printf (surface->final_stream,
- "F\n");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
_cairo_ps_surface_emit_bitmap_glyph_data (cairo_ps_surface_t *surface,
cairo_scaled_font_t *scaled_font,
- unsigned long glyph_index,
+ unsigned long glyph_index,
cairo_box_t *bbox)
{
cairo_scaled_glyph_t *scaled_glyph;
@@ -718,15 +463,10 @@ _cairo_ps_surface_emit_glyph (cairo_ps_surface_t *surface,
"\t\t{ %% %d\n", subset_glyph_index);
if (subset_glyph_index != 0) {
- status = _cairo_ps_surface_emit_outline_glyph_data (surface,
- scaled_font,
- scaled_font_glyph_index,
- bbox);
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
- status = _cairo_ps_surface_emit_bitmap_glyph_data (surface,
- scaled_font,
- scaled_font_glyph_index,
- bbox);
+ status = _cairo_ps_surface_emit_bitmap_glyph_data (surface,
+ scaled_font,
+ scaled_font_glyph_index,
+ bbox);
}
_cairo_output_stream_printf (surface->final_stream,
@@ -815,7 +555,7 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
"} bind def\n"
"currentdict\n"
"end\n"
- "/CairoFont-%d-%d exch definefont pop\n",
+ "/f-%d-%d exch definefont pop\n",
_cairo_fixed_to_double (font_bbox.p1.x),
_cairo_fixed_to_double (font_bbox.p1.y),
_cairo_fixed_to_double (font_bbox.p2.x),
@@ -983,10 +723,16 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
surface->ps_level_used = CAIRO_PS_LEVEL_2;
surface->width = width;
surface->height = height;
+ cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, height);
surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
surface->force_fallbacks = FALSE;
surface->content = CAIRO_CONTENT_COLOR_ALPHA;
+ surface->use_string_datasource = FALSE;
+ _cairo_pdf_operators_init (&surface->pdf_operators,
+ surface->stream,
+ &surface->cairo_to_ps,
+ surface->font_subsets);
surface->num_pages = 0;
_cairo_array_init (&surface->dsc_header_comments, sizeof (char *));
@@ -1115,10 +861,15 @@ _extract_ps_surface (cairo_surface_t *surface,
{
cairo_surface_t *target;
+ if (surface->status)
+ return surface->status;
+
if (! _cairo_surface_is_paginated (surface))
return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
target = _cairo_paginated_surface_get_target (surface);
+ if (target->status)
+ return target->status;
if (! _cairo_surface_is_ps (target))
return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
@@ -1293,6 +1044,9 @@ cairo_ps_surface_set_size (cairo_surface_t *surface,
ps_surface->width = width_in_points;
ps_surface->height = height_in_points;
+ cairo_matrix_init (&ps_surface->cairo_to_ps, 1, 0, 0, -1, 0, height_in_points);
+ _cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface->pdf_operators,
+ &ps_surface->cairo_to_ps);
status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface,
width_in_points,
height_in_points);
@@ -1574,7 +1328,7 @@ static void
_cairo_ps_surface_end_page (cairo_ps_surface_t *surface)
{
_cairo_output_stream_printf (surface->stream,
- "grestore grestore\n");
+ "Q\n");
}
static cairo_int_status_t
@@ -1598,45 +1352,6 @@ color_is_gray (double red, double green, double blue)
fabs (red - blue) < epsilon);
}
-static cairo_status_t
-_analyze_image_transparency (cairo_image_surface_t *image,
- cairo_image_transparency_t *transparency)
-{
- int x, y;
-
- if (image->format == CAIRO_FORMAT_RGB24) {
- *transparency = CAIRO_IMAGE_IS_OPAQUE;
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (image->format != CAIRO_FORMAT_ARGB32) {
- /* If the PS surface does not support the image format, assume
- * that it does have alpha. The image will be converted to
- * rgb24 when the PS surface blends the image into the page
- * color to remove the transparency. */
- *transparency = CAIRO_IMAGE_HAS_ALPHA;
- return CAIRO_STATUS_SUCCESS;
- }
-
- *transparency = CAIRO_IMAGE_IS_OPAQUE;
- for (y = 0; y < image->height; y++) {
- int a;
- uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
-
- for (x = 0; x < image->width; x++, pixel++) {
- a = (*pixel & 0xff000000) >> 24;
- if (a > 0 && a < 255) {
- *transparency = CAIRO_IMAGE_HAS_ALPHA;
- return CAIRO_STATUS_SUCCESS;
- } else if (a == 0) {
- *transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
- }
- }
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static cairo_int_status_t
_cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t *surface,
cairo_surface_pattern_t *pattern)
@@ -1655,10 +1370,7 @@ _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t
if (image->base.status)
return image->base.status;
- status = _analyze_image_transparency (image, &transparency);
- if (status)
- goto RELEASE_SOURCE;
-
+ transparency = _cairo_image_analyze_transparency (image);
switch (transparency) {
case CAIRO_IMAGE_IS_OPAQUE:
status = CAIRO_STATUS_SUCCESS;
@@ -1676,9 +1388,11 @@ _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t
case CAIRO_IMAGE_HAS_ALPHA:
status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
break;
+
+ case CAIRO_IMAGE_UNKNOWN:
+ ASSERT_NOT_REACHED;
}
-RELEASE_SOURCE:
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
return status;
@@ -1736,17 +1450,17 @@ _gradient_pattern_supported (cairo_ps_surface_t *surface,
surface->ps_level_used = CAIRO_PS_LEVEL_3;
extend = cairo_pattern_get_extend (pattern);
- if (extend == CAIRO_EXTEND_REPEAT ||
- extend == CAIRO_EXTEND_REFLECT) {
- return FALSE;
- }
-
/* Radial gradients are currently only supported 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);
@@ -1855,6 +1569,7 @@ typedef struct _string_array_stream {
cairo_output_stream_t *output;
int column;
int string_size;
+ cairo_bool_t use_strings;
} string_array_stream_t;
static cairo_status_t
@@ -1870,34 +1585,38 @@ _string_array_stream_write (cairo_output_stream_t *base,
return CAIRO_STATUS_SUCCESS;
while (length--) {
- if (stream->string_size == 0) {
+ if (stream->string_size == 0 && stream->use_strings) {
_cairo_output_stream_printf (stream->output, "(");
stream->column++;
}
c = *data++;
- switch (c) {
- case '\\':
- case '(':
- case ')':
- _cairo_output_stream_write (stream->output, &backslash, 1);
- stream->column++;
- stream->string_size++;
- break;
- /* Have to also be careful to never split the final ~> sequence. */
- case '~':
+ if (stream->use_strings) {
+ switch (c) {
+ case '\\':
+ case '(':
+ case ')':
+ _cairo_output_stream_write (stream->output, &backslash, 1);
+ stream->column++;
+ stream->string_size++;
+ break;
+ }
+ }
+ /* Have to be careful to never split the final ~> sequence. */
+ if (c == '~') {
_cairo_output_stream_write (stream->output, &c, 1);
stream->column++;
stream->string_size++;
length--;
c = *data++;
- break;
}
_cairo_output_stream_write (stream->output, &c, 1);
stream->column++;
stream->string_size++;
- if (stream->string_size >= STRING_ARRAY_MAX_STRING_SIZE) {
+ if (stream->use_strings &&
+ stream->string_size >= STRING_ARRAY_MAX_STRING_SIZE)
+ {
_cairo_output_stream_printf (stream->output, ")\n");
stream->string_size = 0;
stream->column = 0;
@@ -1918,7 +1637,8 @@ _string_array_stream_close (cairo_output_stream_t *base)
cairo_status_t status;
string_array_stream_t *stream = (string_array_stream_t *) base;
- _cairo_output_stream_printf (stream->output, ")\n");
+ if (stream->use_strings)
+ _cairo_output_stream_printf (stream->output, ")\n");
status = _cairo_output_stream_get_status (stream->output);
@@ -1956,10 +1676,38 @@ _string_array_stream_create (cairo_output_stream_t *output)
stream->output = output;
stream->column = 0;
stream->string_size = 0;
+ stream->use_strings = TRUE;
+
+ return &stream->base;
+}
+
+/* A base85_array_stream wraps an existing output stream. It wraps the
+ * output within STRING_ARRAY_MAX_COLUMN columns (+/- 1). The output
+ * is not enclosed in strings like string_array_stream.
+ */
+static cairo_output_stream_t *
+_base85_array_stream_create (cairo_output_stream_t *output)
+{
+ string_array_stream_t *stream;
+
+ stream = malloc (sizeof (string_array_stream_t));
+ if (stream == NULL) {
+ _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+ return (cairo_output_stream_t *) &_cairo_output_stream_nil;
+ }
+
+ _cairo_output_stream_init (&stream->base,
+ _string_array_stream_write,
+ _string_array_stream_close);
+ stream->output = output;
+ stream->column = 0;
+ stream->string_size = 0;
+ stream->use_strings = FALSE;
return &stream->base;
}
+
/* PS Output - this section handles output of the parts of the meta
* surface we can render natively in PS. */
@@ -2021,12 +1769,17 @@ fail:
static cairo_status_t
_cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface,
unsigned char *data,
- unsigned long length)
+ unsigned long length,
+ cairo_bool_t use_strings)
{
cairo_output_stream_t *base85_stream, *string_array_stream;
cairo_status_t status, status2;
- string_array_stream = _string_array_stream_create (surface->stream);
+ if (use_strings)
+ string_array_stream = _string_array_stream_create (surface->stream);
+ else
+ string_array_stream = _base85_array_stream_create (surface->stream);
+
status = _cairo_output_stream_get_status (string_array_stream);
if (status)
return _cairo_output_stream_destroy (string_array_stream);
@@ -2051,25 +1804,22 @@ _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface,
static cairo_status_t
_cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
cairo_image_surface_t *image,
- const char *name,
cairo_operator_t op)
{
cairo_status_t status;
- unsigned char *rgb, *rgb_compressed;
- unsigned long rgb_size, rgb_compressed_size;
- unsigned char *mask = NULL, *mask_compressed = NULL;
- unsigned long mask_size = 0, mask_compressed_size = 0;
+ unsigned char *data, *data_compressed;
+ unsigned long data_size, data_compressed_size;
cairo_image_surface_t *opaque_image = NULL;
int x, y, i;
cairo_image_transparency_t transparency;
cairo_bool_t use_mask;
+ uint32_t *pixel;
+ int bit;
if (image->base.status)
return image->base.status;
- status = _analyze_image_transparency (image, &transparency);
- if (status)
- return status;
+ transparency = _cairo_image_analyze_transparency (image);
/* PostScript can not represent the alpha channel, so we blend the
current image over a white (or black for CONTENT_COLOR
@@ -2094,191 +1844,184 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
use_mask = TRUE;
}
- rgb_size = 3 * image->width * image->height;
- rgb = malloc (rgb_size);
- if (rgb == NULL) {
+ if (use_mask) {
+ /* Type 2 (mask and image interleaved) has the mask and image
+ * samples interleaved by row. The mask row is first, one bit
+ * per pixel with (bit 7 first). The row is padded to byte
+ * boundaries. The image data is 3 bytes per pixel RGB
+ * format. */
+ data_size = image->height * ((image->width + 7)/8 + 3*image->width);
+ } else {
+ data_size = image->height * image->width * 3;
+ }
+ data = malloc (data_size);
+ if (data == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto bail1;
}
if (use_mask) {
- mask_size = ((image->width+7) / 8) * image->height;
- mask = malloc (mask_size);
- if (mask == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto bail2;
- }
- }
-
- if (use_mask) {
- int byte = 0;
- int bit = 7;
i = 0;
for (y = 0; y < image->height; y++) {
- uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
+ /* mask row */
+ pixel = (uint32_t *) (image->data + y * image->stride);
+ bit = 7;
for (x = 0; x < image->width; x++, pixel++) {
if (bit == 7)
- mask[byte] = 0;
+ data[i] = 0;
if (((*pixel & 0xff000000) >> 24) > 0x80)
- mask[byte] |= (1 << bit);
+ data[i] |= (1 << bit);
bit--;
if (bit < 0) {
bit = 7;
- byte++;
+ i++;
}
- rgb[i++] = (*pixel & 0x00ff0000) >> 16;
- rgb[i++] = (*pixel & 0x0000ff00) >> 8;
- rgb[i++] = (*pixel & 0x000000ff) >> 0;
}
+ if (bit != 7)
+ i++;
- if (bit != 7) {
- bit = 7;
- byte++;
+ /* image row*/
+ pixel = (uint32_t *) (image->data + y * image->stride);
+ for (x = 0; x < image->width; x++, pixel++) {
+ data[i++] = (*pixel & 0x00ff0000) >> 16;
+ data[i++] = (*pixel & 0x0000ff00) >> 8;
+ data[i++] = (*pixel & 0x000000ff) >> 0;
}
}
} else {
i = 0;
for (y = 0; y < opaque_image->height; y++) {
- uint32_t *pixel = (uint32_t *) (opaque_image->data + y * opaque_image->stride);
+ pixel = (uint32_t *) (opaque_image->data + y * opaque_image->stride);
for (x = 0; x < opaque_image->width; x++, pixel++) {
- rgb[i++] = (*pixel & 0x00ff0000) >> 16;
- rgb[i++] = (*pixel & 0x0000ff00) >> 8;
- rgb[i++] = (*pixel & 0x000000ff) >> 0;
+ data[i++] = (*pixel & 0x00ff0000) >> 16;
+ data[i++] = (*pixel & 0x0000ff00) >> 8;
+ data[i++] = (*pixel & 0x000000ff) >> 0;
}
}
}
/* XXX: Should fix cairo-lzw to provide a stream-based interface
* instead. */
- rgb_compressed_size = rgb_size;
- rgb_compressed = _cairo_lzw_compress (rgb, &rgb_compressed_size);
- if (rgb_compressed == NULL) {
+ data_compressed_size = data_size;
+ data_compressed = _cairo_lzw_compress (data, &data_compressed_size);
+ if (data_compressed == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto bail3;
+ goto bail2;
}
- /* First emit the image data as a base85-encoded string which will
- * be used as the data source for the image operator later. */
- _cairo_output_stream_printf (surface->stream,
- "/%sData [\n", name);
-
- status = _cairo_ps_surface_emit_base85_string (surface,
- rgb_compressed,
- rgb_compressed_size);
- if (status)
- goto bail4;
-
- _cairo_output_stream_printf (surface->stream,
- "] def\n");
- _cairo_output_stream_printf (surface->stream,
- "/%sDataIndex 0 def\n", name);
-
- /* Emit the mask data as a base85-encoded string which will
- * be used as the mask source for the image operator later. */
- if (mask) {
- mask_compressed_size = mask_size;
- mask_compressed = _cairo_lzw_compress (mask, &mask_compressed_size);
- if (mask_compressed == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto bail4;
- }
-
+ if (surface->use_string_datasource) {
+ /* Emit the image data as a base85-encoded string which will
+ * be used as the data source for the image operator later. */
_cairo_output_stream_printf (surface->stream,
- "/%sMask [\n", name);
+ "/CairoImageData [\n");
status = _cairo_ps_surface_emit_base85_string (surface,
- mask_compressed,
- mask_compressed_size);
+ data_compressed,
+ data_compressed_size,
+ TRUE);
if (status)
- goto bail5;
+ goto bail3;
_cairo_output_stream_printf (surface->stream,
"] def\n");
_cairo_output_stream_printf (surface->stream,
- "/%sMaskIndex 0 def\n", name);
+ "/CairoImageDataIndex 0 def\n");
}
- if (mask) {
+ if (use_mask) {
_cairo_output_stream_printf (surface->stream,
- "/%s {\n"
- " /DeviceRGB setcolorspace\n"
- " <<\n"
- " /ImageType 3\n"
- " /InterleaveType 3\n"
- " /DataDict <<\n"
- " /ImageType 1\n"
- " /Width %d\n"
- " /Height %d\n"
- " /BitsPerComponent 8\n"
- " /Decode [ 0 1 0 1 0 1 ]\n"
- " /DataSource {\n"
- " %sData %sDataIndex get\n"
- " /%sDataIndex %sDataIndex 1 add def\n"
- " %sDataIndex %sData length 1 sub gt { /%sDataIndex 0 def } if\n"
- " } /ASCII85Decode filter /LZWDecode filter\n"
- " /ImageMatrix [ 1 0 0 1 0 0 ]\n"
- " >>\n"
- " /MaskDict <<\n"
- " /ImageType 1\n"
- " /Width %d\n"
- " /Height %d\n"
- " /BitsPerComponent 1\n"
- " /Decode [ 1 0 ]\n"
- " /DataSource {\n"
- " %sMask %sMaskIndex get\n"
- " /%sMaskIndex %sMaskIndex 1 add def\n"
- " %sMaskIndex %sMask length 1 sub gt { /%sMaskIndex 0 def } if\n"
- " } /ASCII85Decode filter /LZWDecode filter\n"
- " /ImageMatrix [ 1 0 0 1 0 0 ]\n"
- " >>\n"
- " >>\n"
- " image\n"
- "} def\n",
- name,
+ "/DeviceRGB setcolorspace\n"
+ "5 dict dup begin\n"
+ " /ImageType 3 def\n"
+ " /InterleaveType 2 def\n"
+ " /DataDict 8 dict def\n"
+ " DataDict begin\n"
+ " /ImageType 1 def\n"
+ " /Width %d def\n"
+ " /Height %d def\n"
+ " /BitsPerComponent 8 def\n"
+ " /Decode [ 0 1 0 1 0 1 ] def\n",
image->width,
+ image->height);
+
+ if (surface->use_string_datasource) {
+ _cairo_output_stream_printf (surface->stream,
+ " /DataSource {\n"
+ " CairoImageData CairoImageDataIndex get\n"
+ " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
+ " CairoImageDataIndex CairoImageData length 1 sub gt\n"
+ " { /CairoImageDataIndex 0 def } if\n"
+ " } /ASCII85Decode filter /LZWDecode filter def\n");
+ } else {
+ _cairo_output_stream_printf (surface->stream,
+ " /DataSource currentfile /ASCII85Decode filter /LZWDecode filter def\n");
+ }
+
+ _cairo_output_stream_printf (surface->stream,
+ " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
+ " end\n"
+ " /MaskDict 8 dict def\n"
+ " MaskDict begin\n"
+ " /ImageType 1 def\n"
+ " /Width %d def\n"
+ " /Height %d def\n"
+ " /BitsPerComponent 1 def\n"
+ " /Decode [ 1 0 ] def\n"
+ " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
+ " end\n"
+ "end\n"
+ "image\n",
image->height,
- name, name, name, name, name, name, name,
image->width,
image->height,
- name, name, name, name, name, name, name);
+ image->height);
} else {
_cairo_output_stream_printf (surface->stream,
- "/%s {\n"
- " /DeviceRGB setcolorspace\n"
- " <<\n"
- " /ImageType 1\n"
- " /Width %d\n"
- " /Height %d\n"
- " /BitsPerComponent 8\n"
- " /Decode [ 0 1 0 1 0 1 ]\n"
- " /DataSource {\n"
- " %sData %sDataIndex get\n"
- " /%sDataIndex %sDataIndex 1 add def\n"
- " %sDataIndex %sData length 1 sub gt { /%sDataIndex 0 def } if\n"
- " } /ASCII85Decode filter /LZWDecode filter\n"
- " /ImageMatrix [ 1 0 0 1 0 0 ]\n"
- " >>\n"
- " image\n"
- "} def\n",
- name,
+ "/DeviceRGB setcolorspace\n"
+ "8 dict dup begin\n"
+ " /ImageType 1 def\n"
+ " /Width %d def\n"
+ " /Height %d def\n"
+ " /BitsPerComponent 8 def\n"
+ " /Decode [ 0 1 0 1 0 1 ] def\n",
opaque_image->width,
- opaque_image->height,
- name, name, name, name, name, name, name);
- }
+ opaque_image->height);
+ if (surface->use_string_datasource) {
+ _cairo_output_stream_printf (surface->stream,
+ " /DataSource {\n"
+ " CairoImageData CairoImageDataIndex get\n"
+ " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
+ " CairoImageDataIndex CairoImageData length 1 sub gt\n"
+ " { /CairoImageDataIndex 0 def } if\n"
+ " } /ASCII85Decode filter /LZWDecode filter def\n");
+ } else {
+ _cairo_output_stream_printf (surface->stream,
+ " /DataSource currentfile /ASCII85Decode filter /LZWDecode filter def\n");
+ }
- status = CAIRO_STATUS_SUCCESS;
+ _cairo_output_stream_printf (surface->stream,
+ " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
+ "end\n"
+ "image\n",
+ opaque_image->height);
+ }
-bail5:
- if (use_mask)
- free (mask_compressed);
-bail4:
- free (rgb_compressed);
+ if (!surface->use_string_datasource) {
+ /* Emit the image data as a base85-encoded string which will
+ * be used as the data source for the image operator. */
+ status = _cairo_ps_surface_emit_base85_string (surface,
+ data_compressed,
+ data_compressed_size,
+ FALSE);
+ } else {
+ status = CAIRO_STATUS_SUCCESS;
+ }
bail3:
- if (use_mask)
- free (mask);
+ free (data_compressed);
+
bail2:
- free (rgb);
+ free (data);
bail1:
if (!use_mask && opaque_image != image)
@@ -2288,41 +2031,13 @@ bail1:
}
static cairo_status_t
-_cairo_ps_surface_emit_image_surface (cairo_ps_surface_t *surface,
- cairo_surface_pattern_t *pattern,
- int *width,
- int *height,
- cairo_operator_t op)
-{
- cairo_image_surface_t *image;
- void *image_extra;
- cairo_status_t status;
-
- status = _cairo_surface_acquire_source_image (pattern->surface,
- &image,
- &image_extra);
- if (status)
- return status;
-
- status = _cairo_ps_surface_emit_image (surface, image, "CairoPattern", op);
- if (status)
- goto fail;
-
- *width = image->width;
- *height = image->height;
-
-fail:
- _cairo_surface_release_source_image (pattern->surface, image, image_extra);
-
- return status;
-}
-
-static cairo_status_t
_cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
cairo_surface_t *meta_surface)
{
double old_width, old_height;
+ cairo_matrix_t old_cairo_to_ps;
cairo_content_t old_content;
+ cairo_clip_t *old_clip;
cairo_rectangle_int_t meta_extents;
cairo_status_t status;
@@ -2333,16 +2048,23 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
old_content = surface->content;
old_width = surface->width;
old_height = surface->height;
+ old_cairo_to_ps = surface->cairo_to_ps;
+ old_clip = _cairo_surface_get_clip (&surface->base);
surface->width = meta_extents.width;
surface->height = meta_extents.height;
+ cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
+ _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
+ &surface->cairo_to_ps);
_cairo_output_stream_printf (surface->stream,
- "/CairoPattern {\n"
- "gsave\n");
+ " q\n"
+ " 0 0 %f %f rectclip\n",
+ surface->width,
+ surface->height);
if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
surface->content = CAIRO_CONTENT_COLOR;
_cairo_output_stream_printf (surface->stream,
- "0 G 0 0 %f %f rectfill\n",
+ " 0 g 0 0 %f %f rectfill\n",
surface->width,
surface->height);
}
@@ -2354,11 +2076,17 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
return status;
_cairo_output_stream_printf (surface->stream,
- "grestore\n"
- "} bind def\n");
+ " Q\n");
surface->content = old_content;
surface->width = old_width;
surface->height = old_height;
+ surface->cairo_to_ps = old_cairo_to_ps;
+ status = _cairo_surface_set_clip (&surface->base, old_clip);
+ if (status)
+ return status;
+
+ _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
+ &surface->cairo_to_ps);
return CAIRO_STATUS_SUCCESS;
}
@@ -2399,54 +2127,167 @@ _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
if (color_is_gray (red, green, blue))
_cairo_output_stream_printf (surface->stream,
- "%f G\n",
+ "%f g\n",
red);
else
_cairo_output_stream_printf (surface->stream,
- "%f %f %f R\n",
+ "%f %f %f rg\n",
red, green, blue);
}
static cairo_status_t
-_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
- cairo_surface_pattern_t *pattern,
- cairo_operator_t op)
+_cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
+ cairo_surface_pattern_t *pattern,
+ int *width,
+ int *height,
+ cairo_operator_t op)
{
- cairo_status_t status;
- int pattern_width = 0; /* squelch bogus compiler warning */
- int pattern_height = 0; /* squelch bogus compiler warning */
- double xstep, ystep;
- cairo_matrix_t inverse = pattern->base.matrix;
-
- status = cairo_matrix_invert (&inverse);
- /* cairo_pattern_set_matrix ensures the matrix is invertible */
- assert (status == CAIRO_STATUS_SUCCESS);
+ cairo_status_t status;
if (_cairo_surface_is_meta (pattern->surface)) {
cairo_surface_t *meta_surface = pattern->surface;
cairo_rectangle_int_t pattern_extents;
- status = _cairo_ps_surface_emit_meta_surface (surface,
- meta_surface);
- if (status)
- return status;
-
status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
if (status)
return status;
- pattern_width = pattern_extents.width;
- pattern_height = pattern_extents.height;
+ *width = pattern_extents.width;
+ *height = pattern_extents.height;
} else {
- status = _cairo_ps_surface_emit_image_surface (surface,
- pattern,
- &pattern_width,
- &pattern_height,
- op);
+ status = _cairo_surface_acquire_source_image (pattern->surface,
+ &surface->image,
+ &surface->image_extra);
if (status)
return status;
+
+ *width = surface->image->width;
+ *height = surface->image->height;
}
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
+ cairo_surface_pattern_t *pattern,
+ cairo_operator_t op)
+{
+ cairo_status_t status;
+
+ if (_cairo_surface_is_meta (pattern->surface)) {
+ cairo_surface_t *meta_surface = pattern->surface;
+
+ status = _cairo_ps_surface_emit_meta_surface (surface,
+ meta_surface);
+ } else {
+ status = _cairo_ps_surface_emit_image (surface, surface->image, op);
+ }
+
+ return status;
+}
+
+static void
+_cairo_ps_surface_release_surface (cairo_ps_surface_t *surface,
+ cairo_surface_pattern_t *pattern)
+{
+ if (!_cairo_surface_is_meta (pattern->surface))
+ _cairo_surface_release_source_image (pattern->surface, surface->image,
+ surface->image_extra);
+}
+
+static cairo_status_t
+_cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
+ cairo_surface_pattern_t *pattern,
+ cairo_operator_t op)
+{
+ cairo_status_t status;
+ int width, height;
+ cairo_matrix_t cairo_p2d, ps_p2d;
+
+ status = _cairo_ps_surface_acquire_surface (surface,
+ pattern,
+ &width,
+ &height,
+ op);
+ if (status)
+ return status;
+
+ cairo_p2d = pattern->base.matrix;
+
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
+ double scale = cairo_p2d.xx;
+
+ _cairo_output_stream_printf (surface->stream,
+ "%% Fallback Image: x=%f, y=%f, w=%d, h=%d res=%fdpi size=%ld\n",
+ -cairo_p2d.x0/scale,
+ -cairo_p2d.y0/scale,
+ (int)(width/scale),
+ (int)(height/scale),
+ scale*72,
+ (long)width*height*3);
+ } else {
+ if (op == CAIRO_OPERATOR_SOURCE) {
+ _cairo_output_stream_printf (surface->stream,
+ "%d g 0 0 %f %f rectfill\n",
+ surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
+ surface->width,
+ surface->height);
+ }
+ }
+
+ status = cairo_matrix_invert (&cairo_p2d);
+ /* cairo_pattern_set_matrix ensures the matrix is invertible */
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ ps_p2d = surface->cairo_to_ps;
+ cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
+ cairo_matrix_translate (&ps_p2d, 0.0, height);
+ cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+
+ _cairo_output_stream_printf (surface->stream,
+ "[ %f %f %f %f %f %f ] concat\n",
+ ps_p2d.xx, ps_p2d.yx,
+ ps_p2d.xy, ps_p2d.yy,
+ ps_p2d.x0, ps_p2d.y0);
+
+ status = _cairo_ps_surface_emit_surface (surface, pattern, op);
+ _cairo_ps_surface_release_surface (surface, pattern);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
+ cairo_surface_pattern_t *pattern,
+ cairo_operator_t op)
+{
+ cairo_status_t status;
+ int pattern_width = 0; /* squelch bogus compiler warning */
+ int pattern_height = 0; /* squelch bogus compiler warning */
+ double xstep, ystep;
+ cairo_matrix_t cairo_p2d, ps_p2d;
+ cairo_rectangle_int_t surface_extents;
+ cairo_bool_t old_use_string_datasource;
+
+ cairo_p2d = pattern->base.matrix;
+ status = cairo_matrix_invert (&cairo_p2d);
+ /* cairo_pattern_set_matrix ensures the matrix is invertible */
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ ps_p2d = surface->cairo_to_ps;
+ cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
+ cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
+ cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+
+ status = _cairo_ps_surface_acquire_surface (surface,
+ pattern,
+ &pattern_width,
+ &pattern_height,
+ op);
+ if (status)
+ return status;
+
switch (pattern->base.extend) {
/* We implement EXTEND_PAD like EXTEND_NONE for now */
case CAIRO_EXTEND_PAD:
@@ -2479,10 +2320,13 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
break;
}
case CAIRO_EXTEND_REPEAT:
- case CAIRO_EXTEND_REFLECT:
xstep = pattern_width;
ystep = pattern_height;
break;
+ case CAIRO_EXTEND_REFLECT:
+ xstep = pattern_width*2;
+ ystep = pattern_height*2;
+ break;
/* All the rest (if any) should have been analyzed away, so these
* cases should be unreachable. */
default:
@@ -2492,23 +2336,84 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
}
_cairo_output_stream_printf (surface->stream,
+ "/CairoPattern {\n");
+
+ old_use_string_datasource = surface->use_string_datasource;
+ surface->use_string_datasource = TRUE;
+ if (op == CAIRO_OPERATOR_SOURCE) {
+ _cairo_output_stream_printf (surface->stream,
+ "%d g 0 0 %f %f rectfill\n",
+ surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
+ xstep, ystep);
+ }
+ status = _cairo_ps_surface_emit_surface (surface, pattern, op);
+ if (status)
+ return status;
+
+ surface->use_string_datasource = old_use_string_datasource;
+ _cairo_output_stream_printf (surface->stream,
+ "} bind def\n");
+
+ _cairo_output_stream_printf (surface->stream,
"<< /PatternType 1\n"
" /PaintType 1\n"
" /TilingType 1\n");
_cairo_output_stream_printf (surface->stream,
- " /BBox [0 0 %d %d]\n",
- pattern_width, pattern_height);
- _cairo_output_stream_printf (surface->stream,
" /XStep %f /YStep %f\n",
xstep, ystep);
+
+ if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
+ _cairo_output_stream_printf (surface->stream,
+ " /BBox [0 0 %d %d]\n"
+ " /PaintProc {\n"
+ " CairoPattern\n"
+ " [-1 0 0 1 %d 0] concat CairoPattern\n"
+ " [ 1 0 0 -1 0 %d] concat CairoPattern\n"
+ " [-1 0 0 1 %d 0] concat CairoPattern\n"
+ " CairoPattern\n"
+ " } bind\n",
+ pattern_width*2, pattern_height*2,
+ pattern_width*2,
+ pattern_height*2,
+ pattern_width*2);
+ } else {
+ if (op == CAIRO_OPERATOR_SOURCE) {
+ _cairo_output_stream_printf (surface->stream,
+ " /BBox [0 0 %f %f]\n",
+ xstep, ystep);
+ } else {
+ _cairo_output_stream_printf (surface->stream,
+ " /BBox [0 0 %d %d]\n",
+ pattern_width, pattern_height);
+ }
+ _cairo_output_stream_printf (surface->stream,
+ " /PaintProc { CairoPattern }\n");
+ }
+
_cairo_output_stream_printf (surface->stream,
- " /PaintProc { CairoPattern } bind\n"
">>\n");
+
+ status = _cairo_surface_get_extents (&surface->base, &surface_extents);
+ if (status)
+ return status;
+
+ cairo_p2d = pattern->base.matrix;
+ status = cairo_matrix_invert (&cairo_p2d);
+ /* cairo_pattern_set_matrix ensures the matrix is invertible */
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ cairo_matrix_init_identity (&ps_p2d);
+ cairo_matrix_translate (&ps_p2d, 0.0, surface_extents.height);
+ cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+ cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
+ cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
+ cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+
_cairo_output_stream_printf (surface->stream,
"[ %f %f %f %f %f %f ]\n",
- inverse.xx, inverse.yx,
- inverse.xy, inverse.yy,
- inverse.x0, inverse.y0);
+ ps_p2d.xx, ps_p2d.yx,
+ ps_p2d.xy, ps_p2d.yy,
+ ps_p2d.x0, ps_p2d.y0);
_cairo_output_stream_printf (surface->stream,
"makepattern setpattern\n");
@@ -2517,7 +2422,7 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
typedef struct _cairo_ps_color_stop {
double offset;
- double color[3];
+ double color[4];
} cairo_ps_color_stop_t;
static void
@@ -2526,12 +2431,12 @@ _cairo_ps_surface_emit_linear_colorgradient (cairo_ps_surface_t *surface,
cairo_ps_color_stop_t *stop2)
{
_cairo_output_stream_printf (surface->stream,
- "<< /FunctionType 2\n"
- " /Domain [ 0 1 ]\n"
- " /C0 [ %f %f %f ]\n"
- " /C1 [ %f %f %f ]\n"
- " /N 1\n"
- ">>\n",
+ " << /FunctionType 2\n"
+ " /Domain [ 0 1 ]\n"
+ " /C0 [ %f %f %f ]\n"
+ " /C1 [ %f %f %f ]\n"
+ " /N 1\n"
+ " >>\n",
stop1->color[0],
stop1->color[1],
stop1->color[2],
@@ -2548,25 +2453,35 @@ _cairo_ps_surface_emit_stitched_colorgradient (cairo_ps_surface_t *surface,
unsigned int i;
_cairo_output_stream_printf (surface->stream,
- " << /FunctionType 3\n"
- " /Domain [ 0 1 ]\n"
- " /Functions [\n");
+ "<< /FunctionType 3\n"
+ " /Domain [ 0 1 ]\n"
+ " /Functions [\n");
for (i = 0; i < n_stops - 1; i++)
_cairo_ps_surface_emit_linear_colorgradient (surface, &stops[i], &stops[i+1]);
- _cairo_output_stream_printf (surface->stream, " ]\n");
+ _cairo_output_stream_printf (surface->stream, " ]\n");
- _cairo_output_stream_printf (surface->stream, " /Bounds [ ");
+ _cairo_output_stream_printf (surface->stream, " /Bounds [ ");
for (i = 1; i < n_stops-1; i++)
_cairo_output_stream_printf (surface->stream, "%f ", stops[i].offset);
_cairo_output_stream_printf (surface->stream, "]\n");
- _cairo_output_stream_printf (surface->stream, " /Encode [ ");
- for (i = 1; i < n_stops; i++)
- _cairo_output_stream_printf (surface->stream, "0 1 ");
- _cairo_output_stream_printf (surface->stream, "]\n");
+ _cairo_output_stream_printf (surface->stream, " /Encode [ 1 1 %d { pop 0 1 } for ]\n",
+ n_stops - 1);
- _cairo_output_stream_printf (surface->stream, " >>\n");
+ _cairo_output_stream_printf (surface->stream, ">>\n");
+}
+
+static void
+calc_gradient_color (cairo_ps_color_stop_t *new_stop,
+ cairo_ps_color_stop_t *stop1,
+ cairo_ps_color_stop_t *stop2)
+{
+ int i;
+ double offset = stop1->offset / (stop1->offset + 1.0 - stop2->offset);
+
+ for (i = 0; i < 4; i++)
+ new_stop->color[i] = stop1->color[i] + offset*(stop2->color[i] - stop1->color[i]);
}
#define COLOR_STOP_EPSILON 1e-6
@@ -2586,33 +2501,58 @@ _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t *surface,
n_stops = pattern->n_stops;
for (i = 0; i < n_stops; i++) {
- double red, green, blue;
+ cairo_gradient_stop_t *stop = &pattern->stops[i];
- _cairo_ps_surface_flatten_transparency (surface,
- &pattern->stops[i].color,
- &red, &green, &blue);
- stops[i].color[0] = red;
- stops[i].color[1] = green;
- stops[i].color[2] = blue;
- stops[i].offset = _cairo_fixed_to_double (pattern->stops[i].x);
+ stops[i].color[0] = stop->color.red;
+ stops[i].color[1] = stop->color.green;
+ stops[i].color[2] = stop->color.blue;
+ stops[i].color[3] = stop->color.alpha;
+ stops[i].offset = pattern->stops[i].offset;
}
- /* make sure first offset is 0.0 and last offset is 1.0 */
- if (stops[0].offset > COLOR_STOP_EPSILON) {
- memcpy (allstops, stops, sizeof (cairo_ps_color_stop_t));
- stops = allstops;
- n_stops++;
+ if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
+ pattern->base.extend == CAIRO_EXTEND_REFLECT) {
+ if (stops[0].offset > COLOR_STOP_EPSILON) {
+ if (pattern->base.extend == CAIRO_EXTEND_REFLECT)
+ memcpy (allstops, stops, sizeof (cairo_ps_color_stop_t));
+ else
+ calc_gradient_color (&allstops[0], &stops[0], &stops[n_stops-1]);
+ stops = allstops;
+ n_stops++;
+ }
+ stops[0].offset = 0.0;
+
+ if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
+ if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
+ memcpy (&stops[n_stops],
+ &stops[n_stops - 1],
+ sizeof (cairo_ps_color_stop_t));
+ } else {
+ calc_gradient_color (&stops[n_stops], &stops[0], &stops[n_stops-1]);
+ }
+ n_stops++;
+ }
+ stops[n_stops-1].offset = 1.0;
}
- stops[0].offset = 0.0;
- if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
- memcpy (&stops[n_stops],
- &stops[n_stops - 1],
- sizeof (cairo_ps_color_stop_t));
- n_stops++;
+ for (i = 0; i < n_stops; i++) {
+ double red, green, blue;
+ cairo_color_t color;
+
+ _cairo_color_init_rgba (&color,
+ stops[i].color[0],
+ stops[i].color[1],
+ stops[i].color[2],
+ stops[i].color[3]);
+ _cairo_ps_surface_flatten_transparency (surface, &color,
+ &red, &green, &blue);
+ stops[i].color[0] = red;
+ stops[i].color[1] = green;
+ stops[i].color[2] = blue;
}
- stops[n_stops-1].offset = 1.0;
+ _cairo_output_stream_printf (surface->stream,
+ "/CairoFunction\n");
if (n_stops == 2) {
/* no need for stitched function */
_cairo_ps_surface_emit_linear_colorgradient (surface, &stops[0], &stops[1]);
@@ -2621,6 +2561,8 @@ _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t *surface,
* stops do not require stitching. XXX */
_cairo_ps_surface_emit_stitched_colorgradient (surface, n_stops,stops);
}
+ _cairo_output_stream_printf (surface->stream,
+ "def\n");
free (allstops);
@@ -2628,40 +2570,146 @@ _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t *surface,
}
static cairo_status_t
+_cairo_ps_surface_emit_repeating_function (cairo_ps_surface_t *surface,
+ cairo_gradient_pattern_t *pattern,
+ int begin,
+ int end)
+{
+ _cairo_output_stream_printf (surface->stream,
+ "/CairoFunction\n"
+ "<< /FunctionType 3\n"
+ " /Domain [ %d %d ]\n"
+ " /Functions [ %d {CairoFunction} repeat ]\n"
+ " /Bounds [ %d 1 %d {} for ]\n",
+ begin,
+ end,
+ end - begin,
+ begin + 1,
+ end - 1);
+
+ if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
+ _cairo_output_stream_printf (surface->stream, " /Encode [ %d 1 %d { 2 mod 0 eq {0 1} {1 0} ifelse } for ]\n",
+ begin,
+ end - 1);
+ } else {
+ _cairo_output_stream_printf (surface->stream, " /Encode [ %d 1 %d { pop 0 1 } for ]\n",
+ begin,
+ end - 1);
+ }
+
+ _cairo_output_stream_printf (surface->stream, ">> def\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
_cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface,
cairo_linear_pattern_t *pattern)
{
double x1, y1, x2, y2;
+ double _x1, _y1, _x2, _y2;
+ cairo_matrix_t pat_to_ps;
cairo_extend_t extend;
cairo_status_t status;
- cairo_matrix_t inverse = pattern->base.base.matrix;
+ cairo_gradient_pattern_t *gradient = &pattern->base;
+ double first_stop, last_stop;
+ int repeat_begin = 0, repeat_end = 1;
if (pattern->base.n_stops == 0)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
extend = cairo_pattern_get_extend (&pattern->base.base);
- status = cairo_matrix_invert (&inverse);
- if (status)
- return status;
+ pat_to_ps = pattern->base.base.matrix;
+ status = cairo_matrix_invert (&pat_to_ps);
+ /* cairo_pattern_set_matrix ensures the matrix is invertible */
+ assert (status == CAIRO_STATUS_SUCCESS);
+ cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
+ 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_ps, &x1, &y1);
+
+ x2 = _cairo_fixed_to_double (pattern->p2.x);
+ y2 = _cairo_fixed_to_double (pattern->p2.y);
+ cairo_matrix_transform_point (&pat_to_ps, &x2, &y2);
+
+ dx = fabs (x2 - x1);
+ dy = fabs (y2 - y1);
+ if (dx > 1e-6)
+ x_rep = (int) ceil (surface->width/dx);
+ if (dy > 1e-6)
+ y_rep = (int) ceil (surface->height/dy);
+
+ repeat_end = MAX (x_rep, y_rep);
+ repeat_begin = -repeat_end;
+ first_stop = repeat_begin;
+ last_stop = repeat_end;
+ }
+
+ /* PS 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;
+ }
+
+ status = _cairo_ps_surface_emit_pattern_stops (surface,
+ &pattern->base);
+ if (status)
+ return status;
+
+ if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
+ pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
+ status = _cairo_ps_surface_emit_repeating_function (surface,
+ &pattern->base,
+ repeat_begin,
+ repeat_end);
+ if (status)
+ return status;
+ }
+
_cairo_output_stream_printf (surface->stream,
"<< /PatternType 2\n"
" /Shading\n"
" << /ShadingType 2\n"
" /ColorSpace /DeviceRGB\n"
" /Coords [ %f %f %f %f ]\n"
- " /Function\n",
- x1, y1, x2, y2);
-
- status = _cairo_ps_surface_emit_pattern_stops (surface, &pattern->base);
- if (status)
- return status;
+ " /Domain [ %f %f ]\r\n"
+ " /Function CairoFunction\n",
+ x1, y1, x2, y2,
+ first_stop, last_stop);
if (extend == CAIRO_EXTEND_PAD) {
_cairo_output_stream_printf (surface->stream,
@@ -2676,9 +2724,9 @@ _cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface,
">>\n");
_cairo_output_stream_printf (surface->stream,
"[ %f %f %f %f %f %f ]\n",
- inverse.xx, inverse.yx,
- inverse.xy, inverse.yy,
- inverse.x0, inverse.y0);
+ pat_to_ps.xx, pat_to_ps.yx,
+ pat_to_ps.xy, pat_to_ps.yy,
+ pat_to_ps.x0, pat_to_ps.y0);
_cairo_output_stream_printf (surface->stream,
"makepattern setpattern\n");
@@ -2690,19 +2738,21 @@ _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface,
cairo_radial_pattern_t *pattern)
{
double x1, y1, x2, y2, r1, r2;
+ cairo_matrix_t pat_to_ps;
cairo_extend_t extend;
cairo_status_t status;
- cairo_matrix_t inverse = pattern->base.base.matrix;
if (pattern->base.n_stops == 0)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
extend = cairo_pattern_get_extend (&pattern->base.base);
- status = cairo_matrix_invert (&inverse);
- if (status)
- return status;
+ pat_to_ps = pattern->base.base.matrix;
+ status = cairo_matrix_invert (&pat_to_ps);
+ /* cairo_pattern_set_matrix ensures the matrix is invertible */
+ assert (status == CAIRO_STATUS_SUCCESS);
+ cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
x1 = _cairo_fixed_to_double (pattern->c1.x);
y1 = _cairo_fixed_to_double (pattern->c1.y);
r1 = _cairo_fixed_to_double (pattern->r1);
@@ -2710,19 +2760,19 @@ _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface,
y2 = _cairo_fixed_to_double (pattern->c2.y);
r2 = _cairo_fixed_to_double (pattern->r2);
- _cairo_output_stream_printf (surface->stream,
+ status = _cairo_ps_surface_emit_pattern_stops (surface, &pattern->base);
+ if (status)
+ return status;
+
+ _cairo_output_stream_printf (surface->stream,
"<< /PatternType 2\n"
" /Shading\n"
" << /ShadingType 3\n"
" /ColorSpace /DeviceRGB\n"
" /Coords [ %f %f %f %f %f %f ]\n"
- " /Function\n",
+ " /Function CairoFunction\n",
x1, y1, r1, x2, y2, r2);
- status = _cairo_ps_surface_emit_pattern_stops (surface, &pattern->base);
- if (status)
- return status;
-
if (extend == CAIRO_EXTEND_PAD) {
_cairo_output_stream_printf (surface->stream,
" /Extend [ true true ]\r\n");
@@ -2734,11 +2784,12 @@ _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface,
_cairo_output_stream_printf (surface->stream,
" >>\n"
">>\n");
+
_cairo_output_stream_printf (surface->stream,
"[ %f %f %f %f %f %f ]\n",
- inverse.xx, inverse.yx,
- inverse.xy, inverse.yy,
- inverse.x0, inverse.y0);
+ pat_to_ps.xx, pat_to_ps.yx,
+ pat_to_ps.xy, pat_to_ps.yy,
+ pat_to_ps.x0, pat_to_ps.y0);
_cairo_output_stream_printf (surface->stream,
"makepattern setpattern\n");
@@ -2795,8 +2846,6 @@ _cairo_ps_surface_intersect_clip_path (void *abstract_surface,
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
- cairo_status_t status;
- const char *ps_operator;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
@@ -2807,30 +2856,13 @@ _cairo_ps_surface_intersect_clip_path (void *abstract_surface,
#endif
if (path == NULL) {
- _cairo_output_stream_printf (stream, "grestore gsave\n");
+ _cairo_output_stream_printf (stream, "Q q\n");
return CAIRO_STATUS_SUCCESS;
}
- /* We're "filling" not stroking, so we pass CAIRO_LINE_CAP_ROUND. */
- status = _cairo_ps_surface_emit_path (surface, stream, path,
- CAIRO_LINE_CAP_ROUND);
-
- switch (fill_rule) {
- case CAIRO_FILL_RULE_WINDING:
- ps_operator = "clip";
- break;
- case CAIRO_FILL_RULE_EVEN_ODD:
- ps_operator = "eoclip";
- break;
- default:
- ASSERT_NOT_REACHED;
- }
-
- _cairo_output_stream_printf (stream,
- "%s newpath\n",
- ps_operator);
-
- return status;
+ return _cairo_pdf_operators_clip (&surface->pdf_operators,
+ path,
+ fill_rule);
}
static cairo_int_status_t
@@ -2870,7 +2902,7 @@ _cairo_ps_surface_paint (void *abstract_surface,
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
- cairo_rectangle_int_t extents, pattern_extents;
+ cairo_rectangle_int_t extents;
cairo_status_t status;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
@@ -2887,65 +2919,35 @@ _cairo_ps_surface_paint (void *abstract_surface,
if (status)
return status;
- status = _cairo_pattern_get_extents (source, &pattern_extents);
- if (status)
- return status;
-
- _cairo_rectangle_intersect (&extents, &pattern_extents);
-
- status = _cairo_ps_surface_emit_pattern (surface, source, op);
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- return CAIRO_STATUS_SUCCESS;
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
+ (source->extend == CAIRO_EXTEND_NONE ||
+ source->extend == CAIRO_EXTEND_PAD))
+ {
+ _cairo_output_stream_printf (stream, "q 0 0 %d %d rectclip\n",
+ extents.width,
+ extents.height);
- if (status)
- return status;
+ status = _cairo_ps_surface_paint_surface (surface,
+ (cairo_surface_pattern_t *) source,
+ op);
+ if (status)
+ return status;
- _cairo_output_stream_printf (stream, "%d %d M\n",
- extents.x, extents.y);
- _cairo_output_stream_printf (stream, "%d %d L\n",
- extents.x + extents.width,
- extents.y);
- _cairo_output_stream_printf (stream, "%d %d L\n",
- extents.x + extents.width,
- extents.y + extents.height);
- _cairo_output_stream_printf (stream, "%d %d L\n",
- extents.x,
- extents.y + extents.height);
- _cairo_output_stream_printf (stream, "P F\n");
+ _cairo_output_stream_printf (stream, "Q\n");
+ } else {
+ status = _cairo_ps_surface_emit_pattern (surface, source, op);
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
- return CAIRO_STATUS_SUCCESS;
-}
+ if (status)
+ return status;
-static int
-_cairo_ps_line_cap (cairo_line_cap_t cap)
-{
- switch (cap) {
- case CAIRO_LINE_CAP_BUTT:
- return 0;
- case CAIRO_LINE_CAP_ROUND:
- return 1;
- case CAIRO_LINE_CAP_SQUARE:
- return 2;
- default:
- ASSERT_NOT_REACHED;
- return 0;
+ _cairo_output_stream_printf (stream, "0 0 %d %d rectfill\n",
+ extents.width,
+ extents.height);
}
-}
-static int
-_cairo_ps_line_join (cairo_line_join_t join)
-{
- switch (join) {
- case CAIRO_LINE_JOIN_MITER:
- return 0;
- case CAIRO_LINE_JOIN_ROUND:
- return 1;
- case CAIRO_LINE_JOIN_BEVEL:
- return 2;
- default:
- ASSERT_NOT_REACHED;
- return 0;
- }
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
@@ -2960,11 +2962,7 @@ _cairo_ps_surface_stroke (void *abstract_surface,
cairo_antialias_t antialias)
{
cairo_ps_surface_t *surface = abstract_surface;
- cairo_output_stream_t *stream = surface->stream;
cairo_int_status_t status;
- double *dash = style->dash;
- int num_dashes = style->num_dashes;
- double dash_offset = style->dash_offset;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_ps_surface_analyze_operation (surface, op, source);
@@ -2972,130 +2970,19 @@ _cairo_ps_surface_stroke (void *abstract_surface,
assert (_cairo_ps_surface_operation_supported (surface, op, source));
#if DEBUG_PS
- _cairo_output_stream_printf (stream,
+ _cairo_output_stream_printf (surface->stream,
"%% _cairo_ps_surface_stroke\n");
#endif
- /* PostScript has "special needs" when it comes to zero-length
- * dash segments with butt caps. It apparently (at least
- * according to ghostscript) draws hairlines for this
- * case. That's not what the cairo semantics want, so we first
- * touch up the array to eliminate any 0.0 values that will
- * result in "on" segments.
- */
- if (num_dashes && style->line_cap == CAIRO_LINE_CAP_BUTT) {
- int i;
-
- /* If there's an odd number of dash values they will each get
- * interpreted as both on and off. So we first explicitly
- * expand the array to remove the duplicate usage so that we
- * can modify some of the values.
- */
- if (num_dashes % 2) {
- dash = _cairo_malloc_abc (num_dashes, 2, sizeof (double));
- if (dash == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- memcpy (dash, style->dash, num_dashes * sizeof (double));
- memcpy (dash + num_dashes, style->dash, num_dashes * sizeof (double));
-
- num_dashes *= 2;
- }
-
- for (i = 0; i < num_dashes; i += 2) {
- if (dash[i] == 0.0) {
- /* If we're at the front of the list, we first rotate
- * two elements from the end of the list to the front
- * of the list before folding away the 0.0. Or, if
- * there are only two dash elements, then there is
- * nothing at all to draw.
- */
- if (i == 0) {
- double last_two[2];
-
- if (num_dashes == 2) {
- if (dash != style->dash)
- free (dash);
- return CAIRO_STATUS_SUCCESS;
- }
- /* The cases of num_dashes == 0, 1, or 3 elements
- * cannot exist, so the rotation of 2 elements
- * will always be safe */
- memcpy (last_two, dash + num_dashes - 2, sizeof (last_two));
- memmove (dash + 2, dash, (num_dashes - 2) * sizeof (double));
- memcpy (dash, last_two, sizeof (last_two));
- dash_offset += dash[0] + dash[1];
- i = 2;
- }
- dash[i-1] += dash[i+1];
- num_dashes -= 2;
- memmove (dash + i, dash + i + 2, (num_dashes - i) * sizeof (double));
- /* If we might have just rotated, it's possible that
- * we rotated a 0.0 value to the front of the list.
- * Set i to -2 so it will get incremented to 0. */
- if (i == 2)
- i = -2;
- }
- }
- }
-
status = _cairo_ps_surface_emit_pattern (surface, source, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
- if (status) {
- if (dash != style->dash)
- free (dash);
- return status;
- }
-
- _cairo_output_stream_printf (stream,
- "gsave\n");
- status = _cairo_ps_surface_emit_path (surface, stream, path,
- style->line_cap);
- if (status) {
- if (dash != style->dash)
- free (dash);
- return status;
- }
-
- /*
- * Switch to user space to set line parameters
- */
- _cairo_output_stream_printf (stream,
- "[%f %f %f %f 0 0] concat\n",
- ctm->xx, ctm->yx, ctm->xy, ctm->yy);
- /* line width */
- _cairo_output_stream_printf (stream, "%f setlinewidth\n",
- style->line_width);
- /* line cap */
- _cairo_output_stream_printf (stream, "%d setlinecap\n",
- _cairo_ps_line_cap (style->line_cap));
- /* line join */
- _cairo_output_stream_printf (stream, "%d setlinejoin\n",
- _cairo_ps_line_join (style->line_join));
- /* dashes */
- if (num_dashes) {
- int d;
-
- _cairo_output_stream_printf (stream, "[");
- for (d = 0; d < num_dashes; d++)
- _cairo_output_stream_printf (stream, " %f", dash[d]);
- _cairo_output_stream_printf (stream, "] %f setdash\n",
- dash_offset);
- }
- if (dash != style->dash)
- free (dash);
-
- /* miter limit */
- _cairo_output_stream_printf (stream, "%f setmiterlimit\n",
- style->miter_limit);
- _cairo_output_stream_printf (stream,
- "stroke\n");
- _cairo_output_stream_printf (stream,
- "grestore\n");
-
- return CAIRO_STATUS_SUCCESS;
+ return _cairo_pdf_operators_stroke (&surface->pdf_operators,
+ path,
+ style,
+ ctm,
+ ctm_inverse);
}
static cairo_int_status_t
@@ -3108,9 +2995,7 @@ _cairo_ps_surface_fill (void *abstract_surface,
cairo_antialias_t antialias)
{
cairo_ps_surface_t *surface = abstract_surface;
- cairo_output_stream_t *stream = surface->stream;
cairo_int_status_t status;
- const char *ps_operator;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_ps_surface_analyze_operation (surface, op, source);
@@ -3118,48 +3003,44 @@ _cairo_ps_surface_fill (void *abstract_surface,
assert (_cairo_ps_surface_operation_supported (surface, op, source));
#if DEBUG_PS
- _cairo_output_stream_printf (stream,
+ _cairo_output_stream_printf (surface->stream,
"%% _cairo_ps_surface_fill\n");
#endif
- status = _cairo_ps_surface_emit_pattern (surface, source, op);
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- return CAIRO_STATUS_SUCCESS;
-
- if (status)
- return status;
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
+ (source->extend == CAIRO_EXTEND_NONE ||
+ source->extend == CAIRO_EXTEND_PAD))
+ {
+ _cairo_output_stream_printf (surface->stream, "q\n");
- /* We're filling not stroking, so we pass CAIRO_LINE_CAP_ROUND. */
- status = _cairo_ps_surface_emit_path (surface, stream, path,
- CAIRO_LINE_CAP_ROUND);
- if (status)
- return status;
+ status = _cairo_pdf_operators_clip (&surface->pdf_operators,
+ path,
+ fill_rule);
+ if (status)
+ return status;
- switch (fill_rule) {
- case CAIRO_FILL_RULE_WINDING:
- ps_operator = "F";
- break;
- case CAIRO_FILL_RULE_EVEN_ODD:
- ps_operator = "eofill";
- break;
- default:
- ASSERT_NOT_REACHED;
- }
+ status = _cairo_ps_surface_paint_surface (surface,
+ (cairo_surface_pattern_t *) source,
+ op);
+ if (status)
+ return status;
- _cairo_output_stream_printf (stream,
- "%s\n", ps_operator);
+ _cairo_output_stream_printf (surface->stream, "Q\n");
+ } else {
+ status = _cairo_ps_surface_emit_pattern (surface, source, op);
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
- return CAIRO_STATUS_SUCCESS;
-}
+ if (status)
+ return status;
-/* This size keeps the length of the hex encoded string of glyphs
- * within 80 columns. */
-#define MAX_GLYPHS_PER_SHOW 36
+ status = _cairo_pdf_operators_fill (&surface->pdf_operators,
+ path,
+ fill_rule);
+ }
-typedef struct _cairo_ps_glyph_id {
- unsigned int subset_id;
- unsigned int glyph_id;
-} cairo_ps_glyph_id_t;
+ return status;
+}
static cairo_int_status_t
_cairo_ps_surface_show_glyphs (void *abstract_surface,
@@ -3170,14 +3051,7 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
cairo_scaled_font_t *scaled_font)
{
cairo_ps_surface_t *surface = abstract_surface;
- cairo_output_stream_t *stream = surface->stream;
- unsigned int current_subset_id = -1;
- cairo_scaled_font_subsets_glyph_t subset_glyph;
- cairo_ps_glyph_id_t *glyph_ids;
cairo_status_t status;
- unsigned int num_glyphs_unsigned, i, j, last, end;
- cairo_bool_t vertical, horizontal;
- cairo_output_stream_t *word_wrap;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_ps_surface_analyze_operation (surface, op, source);
@@ -3185,15 +3059,13 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
assert (_cairo_ps_surface_operation_supported (surface, op, source));
#if DEBUG_PS
- _cairo_output_stream_printf (stream,
+ _cairo_output_stream_printf (surface->stream,
"%% _cairo_ps_surface_show_glyphs\n");
#endif
if (num_glyphs <= 0)
return CAIRO_STATUS_SUCCESS;
- num_glyphs_unsigned = num_glyphs;
-
status = _cairo_ps_surface_emit_pattern (surface, source, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
@@ -3201,116 +3073,10 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
if (status)
return status;
- glyph_ids = _cairo_malloc_ab (num_glyphs_unsigned, sizeof (cairo_ps_glyph_id_t));
- if (glyph_ids == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- for (i = 0; i < num_glyphs_unsigned; i++) {
- status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
- scaled_font, glyphs[i].index,
- &subset_glyph);
- if (status)
- goto fail;
-
- glyph_ids[i].subset_id = subset_glyph.subset_id;
- glyph_ids[i].glyph_id = subset_glyph.subset_glyph_index;
- }
-
- i = 0;
- while (i < num_glyphs_unsigned) {
- if (glyph_ids[i].subset_id != current_subset_id) {
- _cairo_output_stream_printf (surface->stream,
- "/CairoFont-%d-%d "
- "[ %f %f %f %f 0 0 ] selectfont\n",
- subset_glyph.font_id,
- glyph_ids[i].subset_id,
- scaled_font->scale.xx,
- scaled_font->scale.yx,
- -scaled_font->scale.xy,
- -scaled_font->scale.yy);
- current_subset_id = glyph_ids[i].subset_id;
- }
-
- if (i == 0)
- _cairo_output_stream_printf (stream,
- "%f %f M\n",
- glyphs[i].x,
- glyphs[i].y);
-
- horizontal = TRUE;
- vertical = TRUE;
- end = num_glyphs_unsigned;
- if (end - i > MAX_GLYPHS_PER_SHOW)
- end = i + MAX_GLYPHS_PER_SHOW;
- last = end - 1;
- for (j = i; j < end - 1; j++) {
- if ((glyphs[j].y != glyphs[j + 1].y))
- horizontal = FALSE;
- if ((glyphs[j].x != glyphs[j + 1].x))
- vertical = FALSE;
- if (glyph_ids[j].subset_id != glyph_ids[j + 1].subset_id) {
- last = j;
- break;
- }
- }
-
- if (i == last) {
- _cairo_output_stream_printf (surface->stream, "<%02x> S\n", glyph_ids[i].glyph_id);
- } else {
- word_wrap = _word_wrap_stream_create (surface->stream, 79);
- if (_cairo_output_stream_get_status (word_wrap)) {
- status = _cairo_output_stream_destroy (word_wrap);
- goto fail;
- }
-
- _cairo_output_stream_printf (word_wrap, "<");
- for (j = i; j < last+1; j++)
- _cairo_output_stream_printf (word_wrap, "%02x", glyph_ids[j].glyph_id);
- _cairo_output_stream_printf (word_wrap, ">\n[");
-
- if (horizontal) {
- for (j = i; j < last+1; j++) {
- if (j == num_glyphs_unsigned - 1)
- _cairo_output_stream_printf (word_wrap, "0 ");
- else
- _cairo_output_stream_printf (word_wrap,
- "%f ", glyphs[j + 1].x - glyphs[j].x);
- }
- _cairo_output_stream_printf (word_wrap, "] xS\n");
- } else if (vertical) {
- for (j = i; j < last+1; j++) {
- if (j == num_glyphs_unsigned - 1)
- _cairo_output_stream_printf (word_wrap, "0 ");
- else
- _cairo_output_stream_printf (word_wrap,
- "%f ", glyphs[j + 1].y - glyphs[j].y);
- }
- _cairo_output_stream_printf (word_wrap, "] yS\n");
- } else {
- for (j = i; j < last+1; j++) {
- if (j == num_glyphs_unsigned - 1)
- _cairo_output_stream_printf (word_wrap, "0 0 ");
- else
- _cairo_output_stream_printf (word_wrap,
- "%f %f ",
- glyphs[j + 1].x - glyphs[j].x,
- glyphs[j + 1].y - glyphs[j].y);
- }
- _cairo_output_stream_printf (word_wrap, "] xyS\n");
- }
-
- status = _cairo_output_stream_destroy (word_wrap);
- if (status)
- goto fail;
- }
- i = last + 1;
- }
-
- status = _cairo_output_stream_get_status (surface->stream);
-fail:
- free (glyph_ids);
-
- return status;
+ return _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
+ glyphs,
+ num_glyphs,
+ scaled_font);
}
static void
@@ -3362,13 +3128,12 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface,
_cairo_array_truncate (&surface->dsc_page_setup_comments, 0);
_cairo_output_stream_printf (surface->stream,
- "%%%%PageBoundingBox: %d %d %d %d\n"
- "gsave %f %f translate 1.0 -1.0 scale gsave\n",
- x1, y1, x2, y2,
- 0.0, surface->height);
+ "%%%%PageBoundingBox: %d %d %d %d\n",
+ x1, y1, x2, y2);
_cairo_output_stream_printf (surface->stream,
- "%%%%EndPageSetup\n");
+ "%%%%EndPageSetup\n"
+ "q\n");
if (surface->num_pages == 1) {
surface->bbox_x1 = x1;