1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2003 University of Southern California
5 * Copyright © 2005 Red Hat, Inc
6 * Copyright © 2007,2008 Adrian Johnson
8 * This library is free software; you can redistribute it and/or
9 * modify it either under the terms of the GNU Lesser General Public
10 * License version 2.1 as published by the Free Software Foundation
11 * (the "LGPL") or, at your option, under the terms of the Mozilla
12 * Public License Version 1.1 (the "MPL"). If you do not alter this
13 * notice, a recipient may use your version of this file under either
14 * the MPL or the LGPL.
16 * You should have received a copy of the LGPL along with this library
17 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19 * You should have received a copy of the MPL along with this library
20 * in the file COPYING-MPL-1.1
22 * The contents of this file are subject to the Mozilla Public License
23 * Version 1.1 (the "License"); you may not use this file except in
24 * compliance with the License. You may obtain a copy of the License at
25 * http://www.mozilla.org/MPL/
27 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29 * the specific language governing rights and limitations.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is University of Southern
37 * Carl D. Worth <cworth@cworth.org>
38 * Kristian Høgsberg <krh@redhat.com>
39 * Keith Packard <keithp@keithp.com>
40 * Adrian Johnson <ajohnson@redneon.com>
45 * Design of the PS output:
47 * The PS output is harmonised with the PDF operations using PS procedures
48 * to emulate the PDF operators.
50 * This has a number of advantages:
51 * 1. A large chunk of code is shared between the PDF and PS backends.
52 * See cairo-pdf-operators.
53 * 2. Using gs to do PS -> PDF and PDF -> PS will always work well.
56 #define _BSD_SOURCE /* for ctime_r(), snprintf(), strdup() */
60 #include "cairo-ps-surface-private.h"
62 #include "cairo-pdf-operators-private.h"
63 #include "cairo-pdf-shading-private.h"
65 #include "cairo-array-private.h"
66 #include "cairo-composite-rectangles-private.h"
67 #include "cairo-default-context-private.h"
68 #include "cairo-error-private.h"
69 #include "cairo-image-surface-inline.h"
70 #include "cairo-list-inline.h"
71 #include "cairo-scaled-font-subsets-private.h"
72 #include "cairo-paginated-private.h"
73 #include "cairo-recording-surface-private.h"
74 #include "cairo-surface-clipper-private.h"
75 #include "cairo-surface-snapshot-inline.h"
76 #include "cairo-surface-subsurface-private.h"
77 #include "cairo-output-stream-private.h"
78 #include "cairo-type3-glyph-surface-private.h"
79 #include "cairo-image-info-private.h"
90 #define DEBUG_FALLBACK(s) \
91 fprintf (stderr, "%s::%d -- %s\n", __FUNCTION__, __LINE__, (s))
93 #define DEBUG_FALLBACK(s)
97 #define ctime_r(T, BUF) ctime (T)
102 * @Title: PostScript Surfaces
103 * @Short_Description: Rendering PostScript documents
104 * @See_Also: #cairo_surface_t
106 * The PostScript surface is used to render cairo graphics to Adobe
107 * PostScript files and is a multi-page vector surface backend.
111 * CAIRO_HAS_PS_SURFACE:
113 * Defined if the PostScript surface backend is available.
114 * This macro can be used to conditionally compile backend-specific code.
120 CAIRO_PS_COMPRESS_NONE,
121 CAIRO_PS_COMPRESS_LZW,
122 CAIRO_PS_COMPRESS_DEFLATE
123 } cairo_ps_compress_t;
125 static const cairo_surface_backend_t cairo_ps_surface_backend;
126 static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend;
129 _cairo_ps_surface_get_extents (void *abstract_surface,
130 cairo_rectangle_int_t *rectangle);
132 static const cairo_ps_level_t _cairo_ps_levels[] =
138 #define CAIRO_PS_LEVEL_LAST ARRAY_LENGTH (_cairo_ps_levels)
140 static const char * _cairo_ps_level_strings[CAIRO_PS_LEVEL_LAST] =
146 static const char *_cairo_ps_supported_mime_types[] =
148 CAIRO_MIME_TYPE_JPEG,
152 typedef struct _cairo_page_standard_media {
156 } cairo_page_standard_media_t;
158 static const cairo_page_standard_media_t _cairo_page_standard_media[] =
160 { "A0", 2384, 3371 },
161 { "A1", 1685, 2384 },
162 { "A2", 1190, 1684 },
168 { "Letter", 612, 792 },
169 { "Tabloid", 792, 1224 },
170 { "Ledger", 1224, 792 },
171 { "Legal", 612, 1008 },
172 { "Statement", 396, 612 },
173 { "Executive", 540, 720 },
174 { "Folio", 612, 936 },
175 { "Quarto", 610, 780 },
176 { "10x14", 720, 1008 },
179 typedef struct _cairo_page_media {
184 } cairo_page_media_t;
187 _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
194 const char *eps_header = "";
195 cairo_bool_t has_bbox;
197 if (surface->has_creation_date)
198 now = surface->creation_date;
202 if (surface->ps_level_used == CAIRO_PS_LEVEL_2)
208 eps_header = " EPSF-3.0";
210 _cairo_output_stream_printf (surface->final_stream,
211 "%%!PS-Adobe-3.0%s\n"
212 "%%%%Creator: cairo %s (http://cairographics.org)\n"
213 "%%%%CreationDate: %s"
216 cairo_version_string (),
217 ctime_r (&now, ctime_buf),
220 _cairo_output_stream_printf (surface->final_stream,
221 "%%%%DocumentData: Clean7Bit\n"
222 "%%%%LanguageLevel: %d\n",
225 if (!cairo_list_is_empty (&surface->document_media)) {
226 cairo_page_media_t *page;
227 cairo_bool_t first = TRUE;
229 cairo_list_foreach_entry (page, cairo_page_media_t, &surface->document_media, link) {
231 _cairo_output_stream_printf (surface->final_stream,
232 "%%%%DocumentMedia: ");
235 _cairo_output_stream_printf (surface->final_stream,
238 _cairo_output_stream_printf (surface->final_stream,
239 "%s %d %d 0 () ()\n",
247 num_comments = _cairo_array_num_elements (&surface->dsc_header_comments);
248 comments = _cairo_array_index (&surface->dsc_header_comments, 0);
249 if (comments == NULL)
252 for (i = 0; i < num_comments; i++) {
253 _cairo_output_stream_printf (surface->final_stream,
254 "%s\n", comments[i]);
255 if (strncmp (comments[i], "%%BoundingBox:", 14) == 0)
263 _cairo_output_stream_printf (surface->final_stream,
264 "%%%%BoundingBox: %d %d %d %d\n",
271 _cairo_output_stream_printf (surface->final_stream,
272 "%%%%EndComments\n");
274 _cairo_output_stream_printf (surface->final_stream,
275 "%%%%BeginProlog\n");
278 _cairo_output_stream_printf (surface->final_stream,
282 _cairo_output_stream_printf (surface->final_stream,
283 "/languagelevel where\n"
284 "{ pop languagelevel } { 1 } ifelse\n"
285 "%d lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto\n"
286 " (This print job requires a PostScript Language Level %d printer.) show\n"
287 " showpage quit } if\n",
292 _cairo_output_stream_printf (surface->final_stream,
293 "/q { gsave } bind def\n"
294 "/Q { grestore } bind def\n"
295 "/cm { 6 array astore concat } bind def\n"
296 "/w { setlinewidth } bind def\n"
297 "/J { setlinecap } bind def\n"
298 "/j { setlinejoin } bind def\n"
299 "/M { setmiterlimit } bind def\n"
300 "/d { setdash } bind def\n"
301 "/m { moveto } bind def\n"
302 "/l { lineto } bind def\n"
303 "/c { curveto } bind def\n"
304 "/h { closepath } bind def\n"
305 "/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto\n"
306 " 0 exch rlineto 0 rlineto closepath } bind def\n"
307 "/S { stroke } bind def\n"
308 "/f { fill } bind def\n"
309 "/f* { eofill } bind def\n"
310 "/n { newpath } bind def\n"
311 "/W { clip } bind def\n"
312 "/W* { eoclip } bind def\n"
315 "/pdfmark where { pop globaldict /?pdfmark /exec load put }\n"
316 " { globaldict begin /?pdfmark /pop load def /pdfmark\n"
317 " /cleartomark load def end } ifelse\n"
318 "/BDC { mark 3 1 roll /BDC pdfmark } bind def\n"
319 "/EMC { mark /EMC pdfmark } bind def\n"
320 "/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def\n"
321 "/Tj { show currentpoint cairo_store_point } bind def\n"
325 " type /stringtype eq\n"
326 " { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse\n"
328 " currentpoint cairo_store_point\n"
330 "/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore\n"
331 " cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def\n"
332 "/Tf { pop /cairo_font exch def /cairo_font_matrix where\n"
333 " { pop cairo_selectfont } if } bind def\n"
334 "/Td { matrix translate cairo_font_matrix matrix concatmatrix dup\n"
335 " /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point\n"
336 " /cairo_font where { pop cairo_selectfont } if } bind def\n"
337 "/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def\n"
338 " cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def\n"
339 "/g { setgray } bind def\n"
340 "/rg { setrgbcolor } bind def\n"
341 "/d1 { setcachedevice } bind def\n");
343 _cairo_output_stream_printf (surface->final_stream,
346 num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
348 _cairo_output_stream_printf (surface->final_stream,
351 comments = _cairo_array_index (&surface->dsc_setup_comments, 0);
352 for (i = 0; i < num_comments; i++) {
353 _cairo_output_stream_printf (surface->final_stream,
354 "%s\n", comments[i]);
359 _cairo_output_stream_printf (surface->final_stream,
364 static cairo_status_t
365 _cairo_ps_surface_emit_type1_font_subset (cairo_ps_surface_t *surface,
366 cairo_scaled_font_subset_t *font_subset)
370 cairo_type1_subset_t subset;
371 cairo_status_t status;
375 snprintf (name, sizeof name, "f-%d-%d",
376 font_subset->font_id, font_subset->subset_id);
377 status = _cairo_type1_subset_init (&subset, name, font_subset, TRUE);
378 if (unlikely (status))
381 /* FIXME: Figure out document structure convention for fonts */
384 _cairo_output_stream_printf (surface->final_stream,
385 "%% _cairo_ps_surface_emit_type1_font_subset\n");
388 length = subset.header_length + subset.data_length + subset.trailer_length;
389 _cairo_output_stream_write (surface->final_stream, subset.data, length);
391 _cairo_type1_subset_fini (&subset);
393 return CAIRO_STATUS_SUCCESS;
397 static cairo_status_t
398 _cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t *surface,
399 cairo_scaled_font_subset_t *font_subset)
401 cairo_type1_subset_t subset;
402 cairo_status_t status;
406 snprintf (name, sizeof name, "f-%d-%d",
407 font_subset->font_id, font_subset->subset_id);
408 status = _cairo_type1_fallback_init_hex (&subset, name, font_subset);
409 if (unlikely (status))
412 /* FIXME: Figure out document structure convention for fonts */
415 _cairo_output_stream_printf (surface->final_stream,
416 "%% _cairo_ps_surface_emit_type1_font_fallback\n");
419 length = subset.header_length + subset.data_length + subset.trailer_length;
420 _cairo_output_stream_write (surface->final_stream, subset.data, length);
422 _cairo_type1_fallback_fini (&subset);
424 return CAIRO_STATUS_SUCCESS;
427 static cairo_status_t
428 _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface,
429 cairo_scaled_font_subset_t *font_subset)
433 cairo_truetype_subset_t subset;
434 cairo_status_t status;
435 unsigned int i, begin, end;
437 status = _cairo_truetype_subset_init_ps (&subset, font_subset);
438 if (unlikely (status))
441 /* FIXME: Figure out document structure convention for fonts */
444 _cairo_output_stream_printf (surface->final_stream,
445 "%% _cairo_ps_surface_emit_truetype_font_subset\n");
448 _cairo_output_stream_printf (surface->final_stream,
451 "/FontName /%s def\n"
453 "/FontMatrix [ 1 0 0 1 0 0 ] def\n"
454 "/FontBBox [ 0 0 0 0 ] def\n"
455 "/Encoding 256 array def\n"
456 "0 1 255 { Encoding exch /.notdef put } for\n",
459 /* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */
461 if (font_subset->is_latin) {
462 for (i = 1; i < 256; i++) {
463 if (font_subset->latin_to_subset_glyph_index[i] > 0) {
464 if (font_subset->glyph_names != NULL) {
465 _cairo_output_stream_printf (surface->final_stream,
466 "Encoding %d /%s put\n",
467 i, font_subset->glyph_names[font_subset->latin_to_subset_glyph_index[i]]);
469 _cairo_output_stream_printf (surface->final_stream,
470 "Encoding %d /g%ld put\n", i, font_subset->latin_to_subset_glyph_index[i]);
475 for (i = 1; i < font_subset->num_glyphs; i++) {
476 if (font_subset->glyph_names != NULL) {
477 _cairo_output_stream_printf (surface->final_stream,
478 "Encoding %d /%s put\n",
479 i, font_subset->glyph_names[i]);
481 _cairo_output_stream_printf (surface->final_stream,
482 "Encoding %d /g%d put\n", i, i);
487 _cairo_output_stream_printf (surface->final_stream,
488 "/CharStrings %d dict dup begin\n"
490 font_subset->num_glyphs);
492 for (i = 1; i < font_subset->num_glyphs; i++) {
493 if (font_subset->glyph_names != NULL) {
494 _cairo_output_stream_printf (surface->final_stream,
496 font_subset->glyph_names[i], i);
498 _cairo_output_stream_printf (surface->final_stream,
499 "/g%d %d def\n", i, i);
503 _cairo_output_stream_printf (surface->final_stream,
504 "end readonly def\n");
506 _cairo_output_stream_printf (surface->final_stream,
510 for (i = 0; i < subset.num_string_offsets; i++) {
511 end = subset.string_offsets[i];
512 _cairo_output_stream_printf (surface->final_stream,"<");
513 _cairo_output_stream_write_hex_string (surface->final_stream,
514 subset.data + begin, end - begin);
515 _cairo_output_stream_printf (surface->final_stream,"00>\n");
518 if (subset.data_length > end) {
519 _cairo_output_stream_printf (surface->final_stream,"<");
520 _cairo_output_stream_write_hex_string (surface->final_stream,
521 subset.data + end, subset.data_length - end);
522 _cairo_output_stream_printf (surface->final_stream,"00>\n");
525 _cairo_output_stream_printf (surface->final_stream,
527 "/f-%d-%d currentdict end definefont pop\n",
528 font_subset->font_id,
529 font_subset->subset_id);
531 _cairo_truetype_subset_fini (&subset);
533 return CAIRO_STATUS_SUCCESS;
536 static cairo_status_t
537 _cairo_ps_emit_imagemask (cairo_image_surface_t *image,
538 cairo_output_stream_t *stream)
543 /* The only image type supported by Type 3 fonts are 1-bit image
545 assert (image->format == CAIRO_FORMAT_A1);
547 _cairo_output_stream_printf (stream,
552 " /ImageMatrix [%d 0 0 %d 0 %d]\n"
554 " /BitsPerComponent 1\n",
561 _cairo_output_stream_printf (stream,
562 " /DataSource {<\n ");
563 for (row = image->data, rows = image->height; rows; row += image->stride, rows--) {
564 for (byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) {
565 uint8_t output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
566 _cairo_output_stream_printf (stream, "%02x ", output_byte);
568 _cairo_output_stream_printf (stream, "\n ");
570 _cairo_output_stream_printf (stream, ">}\n>>\n");
572 _cairo_output_stream_printf (stream,
575 return _cairo_output_stream_get_status (stream);
578 static cairo_int_status_t
579 _cairo_ps_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset,
582 cairo_ps_surface_t *surface = closure;
583 cairo_status_t status = CAIRO_STATUS_SUCCESS;
585 cairo_surface_t *type3_surface;
587 type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
589 _cairo_ps_emit_imagemask,
590 surface->font_subsets);
592 for (i = 0; i < font_subset->num_glyphs; i++) {
593 status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
594 font_subset->glyphs[i]);
595 if (unlikely (status))
599 cairo_surface_finish (type3_surface);
600 cairo_surface_destroy (type3_surface);
605 static cairo_status_t
606 _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
607 cairo_scaled_font_subset_t *font_subset)
611 cairo_status_t status;
613 cairo_box_t font_bbox = {{0,0},{0,0}};
614 cairo_box_t bbox = {{0,0},{0,0}};
615 cairo_surface_t *type3_surface;
618 if (font_subset->num_glyphs == 0)
619 return CAIRO_STATUS_SUCCESS;
622 _cairo_output_stream_printf (surface->final_stream,
623 "%% _cairo_ps_surface_emit_type3_font_subset\n");
626 _cairo_output_stream_printf (surface->final_stream,
629 "/FontMatrix [1 0 0 1 0 0] def\n"
630 "/Encoding 256 array def\n"
631 "0 1 255 { Encoding exch /.notdef put } for\n");
633 type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
635 _cairo_ps_emit_imagemask,
636 surface->font_subsets);
637 status = type3_surface->status;
638 if (unlikely (status)) {
639 cairo_surface_destroy (type3_surface);
643 for (i = 0; i < font_subset->num_glyphs; i++) {
644 if (font_subset->glyph_names != NULL) {
645 _cairo_output_stream_printf (surface->final_stream,
646 "Encoding %d /%s put\n",
647 i, font_subset->glyph_names[i]);
649 _cairo_output_stream_printf (surface->final_stream,
650 "Encoding %d /g%d put\n", i, i);
654 _cairo_output_stream_printf (surface->final_stream,
657 for (i = 0; i < font_subset->num_glyphs; i++) {
658 _cairo_output_stream_printf (surface->final_stream,
660 status = _cairo_type3_glyph_surface_emit_glyph (type3_surface,
661 surface->final_stream,
662 font_subset->glyphs[i],
665 if (unlikely (status))
668 _cairo_output_stream_printf (surface->final_stream,
671 font_bbox.p1.x = bbox.p1.x;
672 font_bbox.p1.y = bbox.p1.y;
673 font_bbox.p2.x = bbox.p2.x;
674 font_bbox.p2.y = bbox.p2.y;
676 if (bbox.p1.x < font_bbox.p1.x)
677 font_bbox.p1.x = bbox.p1.x;
678 if (bbox.p1.y < font_bbox.p1.y)
679 font_bbox.p1.y = bbox.p1.y;
680 if (bbox.p2.x > font_bbox.p2.x)
681 font_bbox.p2.x = bbox.p2.x;
682 if (bbox.p2.y > font_bbox.p2.y)
683 font_bbox.p2.y = bbox.p2.y;
686 cairo_surface_finish (type3_surface);
687 cairo_surface_destroy (type3_surface);
688 if (unlikely (status))
691 _cairo_output_stream_printf (surface->final_stream,
693 "/FontBBox [%f %f %f %f] def\n"
695 " exch /Glyphs get\n"
697 " 10 dict begin exec end\n"
701 "/f-%d-%d exch definefont pop\n",
702 _cairo_fixed_to_double (font_bbox.p1.x),
703 - _cairo_fixed_to_double (font_bbox.p2.y),
704 _cairo_fixed_to_double (font_bbox.p2.x),
705 - _cairo_fixed_to_double (font_bbox.p1.y),
706 font_subset->font_id,
707 font_subset->subset_id);
709 return CAIRO_STATUS_SUCCESS;
712 static cairo_int_status_t
713 _cairo_ps_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset,
716 cairo_ps_surface_t *surface = closure;
717 cairo_int_status_t status;
719 status = _cairo_scaled_font_subset_create_glyph_names (font_subset);
720 if (_cairo_int_status_is_error (status))
723 status = _cairo_ps_surface_emit_type1_font_subset (surface, font_subset);
724 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
727 status = _cairo_ps_surface_emit_truetype_font_subset (surface, font_subset);
728 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
731 status = _cairo_ps_surface_emit_type1_font_fallback (surface, font_subset);
732 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
736 return CAIRO_STATUS_SUCCESS;
739 static cairo_int_status_t
740 _cairo_ps_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset,
743 cairo_ps_surface_t *surface = closure;
744 cairo_int_status_t status;
746 status = _cairo_scaled_font_subset_create_glyph_names (font_subset);
747 if (_cairo_int_status_is_error (status))
750 status = _cairo_ps_surface_emit_type3_font_subset (surface, font_subset);
751 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
755 return CAIRO_INT_STATUS_SUCCESS;
758 static cairo_status_t
759 _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface)
761 cairo_status_t status;
764 _cairo_output_stream_printf (surface->final_stream,
765 "%% _cairo_ps_surface_emit_font_subsets\n");
768 status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
769 _cairo_ps_surface_analyze_user_font_subset,
771 if (unlikely (status))
774 status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
775 _cairo_ps_surface_emit_unscaled_font_subset,
777 if (unlikely (status))
780 status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
781 _cairo_ps_surface_emit_scaled_font_subset,
783 if (unlikely (status))
786 return _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
787 _cairo_ps_surface_emit_scaled_font_subset,
791 static cairo_status_t
792 _cairo_ps_surface_emit_body (cairo_ps_surface_t *surface)
797 if (ferror (surface->tmpfile) != 0)
798 return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
800 rewind (surface->tmpfile);
801 while ((n = fread (buf, 1, sizeof (buf), surface->tmpfile)) > 0)
802 _cairo_output_stream_write (surface->final_stream, buf, n);
804 if (ferror (surface->tmpfile) != 0)
805 return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
807 return CAIRO_STATUS_SUCCESS;
811 _cairo_ps_surface_emit_footer (cairo_ps_surface_t *surface)
813 _cairo_output_stream_printf (surface->final_stream,
817 _cairo_output_stream_printf (surface->final_stream,
821 _cairo_output_stream_printf (surface->final_stream,
826 _path_covers_bbox (cairo_ps_surface_t *surface,
827 cairo_path_fixed_t *path)
831 if (_cairo_path_fixed_is_box (path, &box)) {
832 cairo_rectangle_int_t rect;
834 _cairo_box_round_to_rectangle (&box, &rect);
836 /* skip trivial whole-page clips */
837 if (_cairo_rectangle_intersect (&rect, &surface->page_bbox)) {
838 if (rect.x == surface->page_bbox.x &&
839 rect.width == surface->page_bbox.width &&
840 rect.y == surface->page_bbox.y &&
841 rect.height == surface->page_bbox.height)
851 static cairo_status_t
852 _cairo_ps_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
853 cairo_path_fixed_t *path,
854 cairo_fill_rule_t fill_rule,
856 cairo_antialias_t antialias)
858 cairo_ps_surface_t *surface = cairo_container_of (clipper,
861 cairo_output_stream_t *stream = surface->stream;
862 cairo_status_t status;
864 assert (surface->paginated_mode != CAIRO_PAGINATED_MODE_ANALYZE);
867 _cairo_output_stream_printf (stream,
868 "%% _cairo_ps_surface_intersect_clip_path\n");
872 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
873 if (unlikely (status))
876 _cairo_output_stream_printf (stream, "Q q\n");
878 surface->current_pattern_is_solid_color = FALSE;
879 _cairo_pdf_operators_reset (&surface->pdf_operators);
881 return CAIRO_STATUS_SUCCESS;
884 if (_path_covers_bbox (surface, path))
885 return CAIRO_STATUS_SUCCESS;
887 return _cairo_pdf_operators_clip (&surface->pdf_operators,
892 /* PLRM specifies a tolerance of 5 points when matching page sizes */
894 _ps_page_dimension_equal (int a, int b)
896 return (abs (a - b) < 5);
900 _cairo_ps_surface_get_page_media (cairo_ps_surface_t *surface)
902 int width, height, i;
904 cairo_page_media_t *page;
905 const char *page_name;
907 width = _cairo_lround (surface->width);
908 height = _cairo_lround (surface->height);
910 /* search previously used page sizes */
911 cairo_list_foreach_entry (page, cairo_page_media_t, &surface->document_media, link) {
912 if (_ps_page_dimension_equal (width, page->width) &&
913 _ps_page_dimension_equal (height, page->height))
917 /* search list of standard page sizes */
919 for (i = 0; i < ARRAY_LENGTH (_cairo_page_standard_media); i++) {
920 if (_ps_page_dimension_equal (width, _cairo_page_standard_media[i].width) &&
921 _ps_page_dimension_equal (height, _cairo_page_standard_media[i].height))
923 page_name = _cairo_page_standard_media[i].name;
924 width = _cairo_page_standard_media[i].width;
925 height = _cairo_page_standard_media[i].height;
930 page = malloc (sizeof (cairo_page_media_t));
931 if (unlikely (page == NULL)) {
932 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
937 page->name = strdup (page_name);
939 snprintf (buf, sizeof (buf), "%dx%dmm",
940 (int) _cairo_lround (surface->width * 25.4/72),
941 (int) _cairo_lround (surface->height * 25.4/72));
942 page->name = strdup (buf);
945 if (unlikely (page->name == NULL)) {
947 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
952 page->height = height;
953 cairo_list_add_tail (&page->link, &surface->document_media);
958 static cairo_surface_t *
959 _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
963 cairo_status_t status, status_ignored;
964 cairo_ps_surface_t *surface;
966 surface = malloc (sizeof (cairo_ps_surface_t));
967 if (unlikely (surface == NULL)) {
968 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
972 _cairo_surface_init (&surface->base,
973 &cairo_ps_surface_backend,
975 CAIRO_CONTENT_COLOR_ALPHA);
977 surface->final_stream = stream;
979 surface->tmpfile = tmpfile ();
980 if (surface->tmpfile == NULL) {
983 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
986 status = _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
989 goto CLEANUP_SURFACE;
992 surface->stream = _cairo_output_stream_create_for_file (surface->tmpfile);
993 status = _cairo_output_stream_get_status (surface->stream);
994 if (unlikely (status))
995 goto CLEANUP_OUTPUT_STREAM;
997 surface->font_subsets = _cairo_scaled_font_subsets_create_simple ();
998 if (unlikely (surface->font_subsets == NULL)) {
999 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1000 goto CLEANUP_OUTPUT_STREAM;
1003 _cairo_scaled_font_subsets_enable_latin_subset (surface->font_subsets, TRUE);
1004 surface->has_creation_date = FALSE;
1005 surface->eps = FALSE;
1006 surface->ps_level = CAIRO_PS_LEVEL_3;
1007 surface->ps_level_used = CAIRO_PS_LEVEL_2;
1008 surface->width = width;
1009 surface->height = height;
1010 cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, height);
1011 surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
1012 surface->force_fallbacks = FALSE;
1013 surface->content = CAIRO_CONTENT_COLOR_ALPHA;
1014 surface->use_string_datasource = FALSE;
1015 surface->current_pattern_is_solid_color = FALSE;
1017 surface->page_bbox.x = 0;
1018 surface->page_bbox.y = 0;
1019 surface->page_bbox.width = width;
1020 surface->page_bbox.height = height;
1022 _cairo_surface_clipper_init (&surface->clipper,
1023 _cairo_ps_surface_clipper_intersect_clip_path);
1025 _cairo_pdf_operators_init (&surface->pdf_operators,
1027 &surface->cairo_to_ps,
1028 surface->font_subsets);
1029 surface->num_pages = 0;
1031 cairo_list_init (&surface->document_media);
1032 _cairo_array_init (&surface->dsc_header_comments, sizeof (char *));
1033 _cairo_array_init (&surface->dsc_setup_comments, sizeof (char *));
1034 _cairo_array_init (&surface->dsc_page_setup_comments, sizeof (char *));
1036 surface->dsc_comment_target = &surface->dsc_header_comments;
1038 surface->paginated_surface = _cairo_paginated_surface_create (
1040 CAIRO_CONTENT_COLOR_ALPHA,
1041 &cairo_ps_surface_paginated_backend);
1042 status = surface->paginated_surface->status;
1043 if (status == CAIRO_STATUS_SUCCESS) {
1044 /* paginated keeps the only reference to surface now, drop ours */
1045 cairo_surface_destroy (&surface->base);
1046 return surface->paginated_surface;
1049 _cairo_scaled_font_subsets_destroy (surface->font_subsets);
1050 CLEANUP_OUTPUT_STREAM:
1051 status_ignored = _cairo_output_stream_destroy (surface->stream);
1052 fclose (surface->tmpfile);
1056 /* destroy stream on behalf of caller */
1057 status_ignored = _cairo_output_stream_destroy (stream);
1059 return _cairo_surface_create_in_error (status);
1063 * cairo_ps_surface_create:
1064 * @filename: a filename for the PS output (must be writable), %NULL may be
1065 * used to specify no output. This will generate a PS surface that
1066 * may be queried and used as a source, without generating a
1068 * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
1069 * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
1071 * Creates a PostScript surface of the specified size in points to be
1072 * written to @filename. See cairo_ps_surface_create_for_stream() for
1073 * a more flexible mechanism for handling the PostScript output than
1074 * simply writing it to a named file.
1076 * Note that the size of individual pages of the PostScript output can
1077 * vary. See cairo_ps_surface_set_size().
1079 * Return value: a pointer to the newly created surface. The caller
1080 * owns the surface and should call cairo_surface_destroy() when done
1083 * This function always returns a valid pointer, but it will return a
1084 * pointer to a "nil" surface if an error such as out of memory
1085 * occurs. You can use cairo_surface_status() to check for this.
1090 cairo_ps_surface_create (const char *filename,
1091 double width_in_points,
1092 double height_in_points)
1094 cairo_output_stream_t *stream;
1096 stream = _cairo_output_stream_create_for_filename (filename);
1097 if (_cairo_output_stream_get_status (stream))
1098 return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream));
1100 return _cairo_ps_surface_create_for_stream_internal (stream,
1106 * cairo_ps_surface_create_for_stream:
1107 * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL
1108 * to indicate a no-op @write_func. With a no-op @write_func,
1109 * the surface may be queried or used as a source without
1110 * generating any temporary files.
1111 * @closure: the closure argument for @write_func
1112 * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
1113 * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
1115 * Creates a PostScript surface of the specified size in points to be
1116 * written incrementally to the stream represented by @write_func and
1117 * @closure. See cairo_ps_surface_create() for a more convenient way
1118 * to simply direct the PostScript output to a named file.
1120 * Note that the size of individual pages of the PostScript
1121 * output can vary. See cairo_ps_surface_set_size().
1123 * Return value: a pointer to the newly created surface. The caller
1124 * owns the surface and should call cairo_surface_destroy() when done
1127 * This function always returns a valid pointer, but it will return a
1128 * pointer to a "nil" surface if an error such as out of memory
1129 * occurs. You can use cairo_surface_status() to check for this.
1134 cairo_ps_surface_create_for_stream (cairo_write_func_t write_func,
1136 double width_in_points,
1137 double height_in_points)
1139 cairo_output_stream_t *stream;
1141 stream = _cairo_output_stream_create (write_func, NULL, closure);
1142 if (_cairo_output_stream_get_status (stream))
1143 return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream));
1145 return _cairo_ps_surface_create_for_stream_internal (stream,
1151 _cairo_surface_is_ps (cairo_surface_t *surface)
1153 return surface->backend == &cairo_ps_surface_backend;
1156 /* If the abstract_surface is a paginated surface, and that paginated
1157 * surface's target is a ps_surface, then set ps_surface to that
1158 * target. Otherwise return FALSE.
1161 _extract_ps_surface (cairo_surface_t *surface,
1162 cairo_bool_t set_error_on_failure,
1163 cairo_ps_surface_t **ps_surface)
1165 cairo_surface_t *target;
1167 if (surface->status)
1169 if (surface->finished) {
1170 if (set_error_on_failure)
1171 _cairo_surface_set_error (surface,
1172 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
1176 if (! _cairo_surface_is_paginated (surface)) {
1177 if (set_error_on_failure)
1178 _cairo_surface_set_error (surface,
1179 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
1183 target = _cairo_paginated_surface_get_target (surface);
1184 if (target->status) {
1185 if (set_error_on_failure)
1186 _cairo_surface_set_error (surface, target->status);
1189 if (target->finished) {
1190 if (set_error_on_failure)
1191 _cairo_surface_set_error (surface,
1192 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
1196 if (! _cairo_surface_is_ps (target)) {
1197 if (set_error_on_failure)
1198 _cairo_surface_set_error (surface,
1199 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
1203 *ps_surface = (cairo_ps_surface_t *) target;
1208 * cairo_ps_surface_restrict_to_level:
1209 * @surface: a PostScript #cairo_surface_t
1210 * @level: PostScript level
1212 * Restricts the generated PostSript file to @level. See
1213 * cairo_ps_get_levels() for a list of available level values that
1216 * This function should only be called before any drawing operations
1217 * have been performed on the given surface. The simplest way to do
1218 * this is to call this function immediately after creating the
1224 cairo_ps_surface_restrict_to_level (cairo_surface_t *surface,
1225 cairo_ps_level_t level)
1227 cairo_ps_surface_t *ps_surface = NULL;
1229 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1232 if (level < CAIRO_PS_LEVEL_LAST)
1233 ps_surface->ps_level = level;
1237 * cairo_ps_get_levels:
1238 * @levels: supported level list
1239 * @num_levels: list length
1241 * Used to retrieve the list of supported levels. See
1242 * cairo_ps_surface_restrict_to_level().
1247 cairo_ps_get_levels (cairo_ps_level_t const **levels,
1251 *levels = _cairo_ps_levels;
1253 if (num_levels != NULL)
1254 *num_levels = CAIRO_PS_LEVEL_LAST;
1258 * cairo_ps_level_to_string:
1259 * @level: a level id
1261 * Get the string representation of the given @level id. This function
1262 * will return %NULL if @level id isn't valid. See cairo_ps_get_levels()
1263 * for a way to get the list of valid level ids.
1265 * Return value: the string associated to given level.
1270 cairo_ps_level_to_string (cairo_ps_level_t level)
1272 if (level >= CAIRO_PS_LEVEL_LAST)
1275 return _cairo_ps_level_strings[level];
1279 * cairo_ps_surface_set_eps:
1280 * @surface: a PostScript #cairo_surface_t
1281 * @eps: %TRUE to output EPS format PostScript
1283 * If @eps is %TRUE, the PostScript surface will output Encapsulated
1286 * This function should only be called before any drawing operations
1287 * have been performed on the current page. The simplest way to do
1288 * this is to call this function immediately after creating the
1289 * surface. An Encapsulated PostScript file should never contain more
1295 cairo_ps_surface_set_eps (cairo_surface_t *surface,
1298 cairo_ps_surface_t *ps_surface = NULL;
1300 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1303 ps_surface->eps = eps;
1307 * cairo_ps_surface_get_eps:
1308 * @surface: a PostScript #cairo_surface_t
1310 * Check whether the PostScript surface will output Encapsulated PostScript.
1312 * Return value: %TRUE if the surface will output Encapsulated PostScript.
1316 cairo_public cairo_bool_t
1317 cairo_ps_surface_get_eps (cairo_surface_t *surface)
1319 cairo_ps_surface_t *ps_surface = NULL;
1321 if (! _extract_ps_surface (surface, FALSE, &ps_surface))
1324 return ps_surface->eps;
1328 * cairo_ps_surface_set_size:
1329 * @surface: a PostScript #cairo_surface_t
1330 * @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
1331 * @height_in_points: new surface height, in points (1 point == 1/72.0 inch)
1333 * Changes the size of a PostScript surface for the current (and
1334 * subsequent) pages.
1336 * This function should only be called before any drawing operations
1337 * have been performed on the current page. The simplest way to do
1338 * this is to call this function immediately after creating the
1339 * surface or immediately after completing a page with either
1340 * cairo_show_page() or cairo_copy_page().
1345 cairo_ps_surface_set_size (cairo_surface_t *surface,
1346 double width_in_points,
1347 double height_in_points)
1349 cairo_ps_surface_t *ps_surface = NULL;
1350 cairo_status_t status;
1352 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1355 ps_surface->width = width_in_points;
1356 ps_surface->height = height_in_points;
1357 cairo_matrix_init (&ps_surface->cairo_to_ps, 1, 0, 0, -1, 0, height_in_points);
1358 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface->pdf_operators,
1359 &ps_surface->cairo_to_ps);
1360 status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface,
1364 status = _cairo_surface_set_error (surface, status);
1368 * cairo_ps_surface_dsc_comment:
1369 * @surface: a PostScript #cairo_surface_t
1370 * @comment: a comment string to be emitted into the PostScript output
1372 * Emit a comment into the PostScript output for the given surface.
1374 * The comment is expected to conform to the PostScript Language
1375 * Document Structuring Conventions (DSC). Please see that manual for
1376 * details on the available comments and their meanings. In
1377 * particular, the \%\%IncludeFeature comment allows a
1378 * device-independent means of controlling printer device features. So
1379 * the PostScript Printer Description Files Specification will also be
1380 * a useful reference.
1382 * The comment string must begin with a percent character (\%) and the
1383 * total length of the string (including any initial percent
1384 * characters) must not exceed 255 characters. Violating either of
1385 * these conditions will place @surface into an error state. But
1386 * beyond these two conditions, this function will not enforce
1387 * conformance of the comment with any particular specification.
1389 * The comment string should not have a trailing newline.
1391 * The DSC specifies different sections in which particular comments
1392 * can appear. This function provides for comments to be emitted
1393 * within three sections: the header, the Setup section, and the
1394 * PageSetup section. Comments appearing in the first two sections
1395 * apply to the entire document while comments in the BeginPageSetup
1396 * section apply only to a single page.
1398 * For comments to appear in the header section, this function should
1399 * be called after the surface is created, but before a call to
1400 * cairo_ps_surface_dsc_begin_setup().
1402 * For comments to appear in the Setup section, this function should
1403 * be called after a call to cairo_ps_surface_dsc_begin_setup() but
1404 * before a call to cairo_ps_surface_dsc_begin_page_setup().
1406 * For comments to appear in the PageSetup section, this function
1407 * should be called after a call to
1408 * cairo_ps_surface_dsc_begin_page_setup().
1410 * Note that it is only necessary to call
1411 * cairo_ps_surface_dsc_begin_page_setup() for the first page of any
1412 * surface. After a call to cairo_show_page() or cairo_copy_page()
1413 * comments are unambiguously directed to the PageSetup section of the
1414 * current page. But it doesn't hurt to call this function at the
1415 * beginning of every page as that consistency may make the calling
1418 * As a final note, cairo automatically generates several comments on
1419 * its own. As such, applications must not manually generate any of
1420 * the following comments:
1422 * Header section: \%!PS-Adobe-3.0, \%\%Creator, \%\%CreationDate, \%\%Pages,
1423 * \%\%BoundingBox, \%\%DocumentData, \%\%LanguageLevel, \%\%EndComments.
1425 * Setup section: \%\%BeginSetup, \%\%EndSetup
1427 * PageSetup section: \%\%BeginPageSetup, \%\%PageBoundingBox, \%\%EndPageSetup.
1429 * Other sections: \%\%BeginProlog, \%\%EndProlog, \%\%Page, \%\%Trailer, \%\%EOF
1431 * Here is an example sequence showing how this function might be used:
1433 * <informalexample><programlisting>
1434 * cairo_surface_t *surface = cairo_ps_surface_create (filename, width, height);
1436 * cairo_ps_surface_dsc_comment (surface, "%%Title: My excellent document");
1437 * cairo_ps_surface_dsc_comment (surface, "%%Copyright: Copyright (C) 2006 Cairo Lover")
1439 * cairo_ps_surface_dsc_begin_setup (surface);
1440 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor White");
1442 * cairo_ps_surface_dsc_begin_page_setup (surface);
1443 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A3");
1444 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *InputSlot LargeCapacity");
1445 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaType Glossy");
1446 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor Blue");
1447 * ... draw to first page here ..
1448 * cairo_show_page (cr);
1450 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A5");
1452 * </programlisting></informalexample>
1457 cairo_ps_surface_dsc_comment (cairo_surface_t *surface,
1458 const char *comment)
1460 cairo_ps_surface_t *ps_surface = NULL;
1461 cairo_status_t status;
1464 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1467 /* A couple of sanity checks on the comment value. */
1468 if (comment == NULL) {
1469 status = _cairo_surface_set_error (surface, CAIRO_STATUS_NULL_POINTER);
1473 if (comment[0] != '%' || strlen (comment) > 255) {
1474 status = _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_DSC_COMMENT);
1478 /* Then, copy the comment and store it in the appropriate array. */
1479 comment_copy = strdup (comment);
1480 if (unlikely (comment_copy == NULL)) {
1481 status = _cairo_surface_set_error (surface, CAIRO_STATUS_NO_MEMORY);
1485 status = _cairo_array_append (ps_surface->dsc_comment_target, &comment_copy);
1486 if (unlikely (status)) {
1487 free (comment_copy);
1488 status = _cairo_surface_set_error (surface, status);
1494 * cairo_ps_surface_dsc_begin_setup:
1495 * @surface: a PostScript #cairo_surface_t
1497 * This function indicates that subsequent calls to
1498 * cairo_ps_surface_dsc_comment() should direct comments to the Setup
1499 * section of the PostScript output.
1501 * This function should be called at most once per surface, and must
1502 * be called before any call to cairo_ps_surface_dsc_begin_page_setup()
1503 * and before any drawing is performed to the surface.
1505 * See cairo_ps_surface_dsc_comment() for more details.
1510 cairo_ps_surface_dsc_begin_setup (cairo_surface_t *surface)
1512 cairo_ps_surface_t *ps_surface = NULL;
1514 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1517 if (ps_surface->dsc_comment_target == &ps_surface->dsc_header_comments)
1518 ps_surface->dsc_comment_target = &ps_surface->dsc_setup_comments;
1522 * cairo_ps_surface_dsc_begin_page_setup:
1523 * @surface: a PostScript #cairo_surface_t
1525 * This function indicates that subsequent calls to
1526 * cairo_ps_surface_dsc_comment() should direct comments to the
1527 * PageSetup section of the PostScript output.
1529 * This function call is only needed for the first page of a
1530 * surface. It should be called after any call to
1531 * cairo_ps_surface_dsc_begin_setup() and before any drawing is
1532 * performed to the surface.
1534 * See cairo_ps_surface_dsc_comment() for more details.
1539 cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface)
1541 cairo_ps_surface_t *ps_surface = NULL;
1543 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1546 if (ps_surface->dsc_comment_target == &ps_surface->dsc_header_comments ||
1547 ps_surface->dsc_comment_target == &ps_surface->dsc_setup_comments)
1549 ps_surface->dsc_comment_target = &ps_surface->dsc_page_setup_comments;
1553 static cairo_status_t
1554 _cairo_ps_surface_finish (void *abstract_surface)
1556 cairo_status_t status, status2;
1557 cairo_ps_surface_t *surface = abstract_surface;
1558 int i, num_comments;
1561 status = surface->base.status;
1562 if (unlikely (status))
1565 _cairo_ps_surface_emit_header (surface);
1567 status = _cairo_ps_surface_emit_font_subsets (surface);
1568 if (unlikely (status))
1571 status = _cairo_ps_surface_emit_body (surface);
1572 if (unlikely (status))
1575 _cairo_ps_surface_emit_footer (surface);
1578 _cairo_scaled_font_subsets_destroy (surface->font_subsets);
1580 status2 = _cairo_output_stream_destroy (surface->stream);
1581 if (status == CAIRO_STATUS_SUCCESS)
1584 fclose (surface->tmpfile);
1586 status2 = _cairo_output_stream_destroy (surface->final_stream);
1587 if (status == CAIRO_STATUS_SUCCESS)
1590 while (! cairo_list_is_empty (&surface->document_media)) {
1591 cairo_page_media_t *page;
1593 page = cairo_list_first_entry (&surface->document_media,
1596 cairo_list_del (&page->link);
1601 num_comments = _cairo_array_num_elements (&surface->dsc_header_comments);
1602 comments = _cairo_array_index (&surface->dsc_header_comments, 0);
1603 if (comments == NULL)
1604 return CAIRO_STATUS_NULL_POINTER;
1606 for (i = 0; i < num_comments; i++)
1608 _cairo_array_fini (&surface->dsc_header_comments);
1610 num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
1611 comments = _cairo_array_index (&surface->dsc_setup_comments, 0);
1612 if (comments == NULL)
1613 return CAIRO_STATUS_NULL_POINTER;
1615 for (i = 0; i < num_comments; i++)
1617 _cairo_array_fini (&surface->dsc_setup_comments);
1619 num_comments = _cairo_array_num_elements (&surface->dsc_page_setup_comments);
1620 comments = _cairo_array_index (&surface->dsc_page_setup_comments, 0);
1621 if (comments == NULL)
1622 return CAIRO_STATUS_NULL_POINTER;
1624 for (i = 0; i < num_comments; i++)
1626 _cairo_array_fini (&surface->dsc_page_setup_comments);
1628 _cairo_surface_clipper_reset (&surface->clipper);
1633 static cairo_int_status_t
1634 _cairo_ps_surface_start_page (void *abstract_surface)
1636 cairo_ps_surface_t *surface = abstract_surface;
1638 /* Increment before print so page numbers start at 1. */
1639 surface->num_pages++;
1641 return CAIRO_STATUS_SUCCESS;
1644 static cairo_int_status_t
1645 _cairo_ps_surface_show_page (void *abstract_surface)
1647 cairo_ps_surface_t *surface = abstract_surface;
1648 cairo_int_status_t status;
1650 if (surface->clipper.clip != NULL)
1651 _cairo_surface_clipper_reset (&surface->clipper);
1653 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
1654 if (unlikely (status))
1657 _cairo_output_stream_printf (surface->stream,
1661 return CAIRO_STATUS_SUCCESS;
1665 color_is_gray (double red, double green, double blue)
1667 const double epsilon = 0.00001;
1669 return (fabs (red - green) < epsilon &&
1670 fabs (red - blue) < epsilon);
1674 * _cairo_ps_surface_acquire_source_surface_from_pattern:
1675 * @surface: the ps surface
1676 * @pattern: A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source
1677 * @extents: extents of the operation that is using this source
1678 * @width: returns width of surface
1679 * @height: returns height of surface
1680 * @x_offset: returns x offset of surface
1681 * @y_offset: returns y offset of surface
1682 * @surface: returns surface of type image surface or recording surface
1683 * @image_extra: returns image extra for image type surface
1685 * Acquire source surface or raster source pattern.
1687 static cairo_status_t
1688 _cairo_ps_surface_acquire_source_surface_from_pattern (cairo_ps_surface_t *surface,
1689 const cairo_pattern_t *pattern,
1690 const cairo_rectangle_int_t *extents,
1695 cairo_surface_t **source_surface,
1698 cairo_status_t status;
1699 cairo_image_surface_t *image;
1701 *x_offset = *y_offset = 0;
1702 switch (pattern->type) {
1703 case CAIRO_PATTERN_TYPE_SURFACE: {
1704 cairo_surface_t *surf = ((cairo_surface_pattern_t *) pattern)->surface;
1706 if (surf->type == CAIRO_SURFACE_TYPE_RECORDING) {
1707 if (surf->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1708 cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surf;
1710 *width = sub->extents.width;
1711 *height = sub->extents.height;
1713 cairo_surface_t *free_me = NULL;
1714 cairo_recording_surface_t *recording_surface;
1716 cairo_rectangle_int_t extents;
1718 recording_surface = (cairo_recording_surface_t *) surf;
1719 if (_cairo_surface_is_snapshot (&recording_surface->base)) {
1720 free_me = _cairo_surface_snapshot_get_target (&recording_surface->base);
1721 recording_surface = (cairo_recording_surface_t *) free_me;
1724 status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
1725 cairo_surface_destroy (free_me);
1726 if (unlikely (status))
1729 _cairo_box_round_to_rectangle (&bbox, &extents);
1730 *width = extents.width;
1731 *height = extents.height;
1733 *source_surface = surf;
1735 return CAIRO_STATUS_SUCCESS;
1737 status = _cairo_surface_acquire_source_image (surf, &image, image_extra);
1738 if (unlikely (status))
1743 case CAIRO_PATTERN_TYPE_RASTER_SOURCE: {
1744 cairo_surface_t *surf;
1746 cairo_rectangle_int_t rect;
1748 /* get the operation extents in pattern space */
1749 _cairo_box_from_rectangle (&box, extents);
1750 _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &box, NULL);
1751 _cairo_box_round_to_rectangle (&box, &rect);
1752 surf = _cairo_raster_source_pattern_acquire (pattern, &surface->base, &rect);
1754 return CAIRO_INT_STATUS_UNSUPPORTED;
1755 assert (_cairo_surface_is_image (surf));
1756 image = (cairo_image_surface_t *) surf;
1759 case CAIRO_PATTERN_TYPE_SOLID:
1760 case CAIRO_PATTERN_TYPE_LINEAR:
1761 case CAIRO_PATTERN_TYPE_RADIAL:
1762 case CAIRO_PATTERN_TYPE_MESH:
1768 *width = image->width;
1769 *height = image->height;
1770 *source_surface = &image->base;
1771 return CAIRO_STATUS_SUCCESS;
1775 _cairo_ps_surface_release_source_surface_from_pattern (cairo_ps_surface_t *surface,
1776 const cairo_pattern_t *pattern,
1777 cairo_surface_t *source,
1780 switch (pattern->type) {
1781 case CAIRO_PATTERN_TYPE_SURFACE: {
1782 cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) pattern;
1783 if (surf_pat->surface->type != CAIRO_SURFACE_TYPE_RECORDING) {
1784 cairo_image_surface_t *image = (cairo_image_surface_t *) source;
1785 _cairo_surface_release_source_image (surf_pat->surface, image, image_extra);
1789 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
1790 _cairo_raster_source_pattern_release (pattern, source);
1793 case CAIRO_PATTERN_TYPE_SOLID:
1794 case CAIRO_PATTERN_TYPE_LINEAR:
1795 case CAIRO_PATTERN_TYPE_RADIAL:
1796 case CAIRO_PATTERN_TYPE_MESH:
1805 * _cairo_ps_surface_create_padded_image_from_image:
1806 * @surface: the ps surface
1807 * @source: The source image
1808 * @extents: extents of the operation that is using this source
1809 * @width: returns width of padded image
1810 * @height: returns height of padded image
1811 * @x_offset: returns x offset of padded image
1812 * @y_offset: returns y offset of padded image
1813 * @image: returns the padded image or NULL if padding not required to fill @extents
1815 * Creates a padded image if the source image does not fill the extents.
1817 static cairo_status_t
1818 _cairo_ps_surface_create_padded_image_from_image (cairo_ps_surface_t *surface,
1819 cairo_image_surface_t *source,
1820 const cairo_matrix_t *source_matrix,
1821 const cairo_rectangle_int_t *extents,
1826 cairo_image_surface_t **image)
1829 cairo_rectangle_int_t rect;
1830 cairo_surface_t *pad_image;
1831 cairo_surface_pattern_t pad_pattern;
1833 cairo_int_status_t status;
1835 /* get the operation extents in pattern space */
1836 _cairo_box_from_rectangle (&box, extents);
1837 _cairo_matrix_transform_bounding_box_fixed (source_matrix, &box, NULL);
1838 _cairo_box_round_to_rectangle (&box, &rect);
1840 /* Check if image needs padding to fill extents. */
1843 if (_cairo_fixed_integer_ceil(box.p1.x) < 0 ||
1844 _cairo_fixed_integer_ceil(box.p1.y) < 0 ||
1845 _cairo_fixed_integer_floor(box.p2.y) > w ||
1846 _cairo_fixed_integer_floor(box.p2.y) > h)
1849 _cairo_image_surface_create_with_pixman_format (NULL,
1850 source->pixman_format,
1851 rect.width, rect.height,
1853 if (pad_image->status) {
1854 status = pad_image->status;
1855 cairo_surface_destroy (pad_image);
1859 _cairo_pattern_init_for_surface (&pad_pattern, &source->base);
1860 cairo_matrix_init_translate (&pad_pattern.base.matrix, rect.x, rect.y);
1861 pad_pattern.base.extend = CAIRO_EXTEND_PAD;
1862 status = _cairo_surface_paint (pad_image,
1863 CAIRO_OPERATOR_SOURCE,
1866 _cairo_pattern_fini (&pad_pattern.base);
1867 *image = (cairo_image_surface_t *) pad_image;
1868 *width = rect.width;
1869 *height = rect.height;
1874 status = CAIRO_STATUS_SUCCESS;
1880 static cairo_int_status_t
1881 _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t *surface,
1882 const cairo_pattern_t *pattern,
1883 const cairo_rectangle_int_t *extents)
1886 double x_offset, y_offset;
1887 cairo_surface_t *source;
1888 cairo_image_surface_t *image;
1890 cairo_int_status_t status;
1891 cairo_image_transparency_t transparency;
1893 status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
1902 if (unlikely (status))
1905 image = (cairo_image_surface_t *) source;
1906 if (image->base.status)
1907 return image->base.status;
1909 transparency = _cairo_image_analyze_transparency (image);
1910 switch (transparency) {
1911 case CAIRO_IMAGE_IS_OPAQUE:
1912 status = CAIRO_STATUS_SUCCESS;
1915 case CAIRO_IMAGE_HAS_BILEVEL_ALPHA:
1916 if (surface->ps_level == CAIRO_PS_LEVEL_2) {
1917 status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1919 surface->ps_level_used = CAIRO_PS_LEVEL_3;
1920 status = CAIRO_STATUS_SUCCESS;
1924 case CAIRO_IMAGE_HAS_ALPHA:
1925 status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1928 case CAIRO_IMAGE_UNKNOWN:
1932 _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
1938 surface_pattern_supported (const cairo_surface_pattern_t *pattern)
1940 if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1943 if (pattern->surface->backend->acquire_source_image == NULL)
1946 /* Does an ALPHA-only source surface even make sense? Maybe, but I
1947 * don't think it's worth the extra code to support it. */
1949 /* XXX: Need to write this function here...
1950 content = pattern->surface->content;
1951 if (content == CAIRO_CONTENT_ALPHA)
1959 _gradient_pattern_supported (cairo_ps_surface_t *surface,
1960 const cairo_pattern_t *pattern)
1962 double min_alpha, max_alpha;
1964 if (surface->ps_level == CAIRO_PS_LEVEL_2)
1967 /* Alpha gradients are only supported (by flattening the alpha)
1968 * if there is no variation in the alpha across the gradient. */
1969 _cairo_pattern_alpha_range (pattern, &min_alpha, &max_alpha);
1970 if (min_alpha != max_alpha)
1973 surface->ps_level_used = CAIRO_PS_LEVEL_3;
1979 pattern_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *pattern)
1981 switch (pattern->type) {
1982 case CAIRO_PATTERN_TYPE_SOLID:
1985 case CAIRO_PATTERN_TYPE_LINEAR:
1986 case CAIRO_PATTERN_TYPE_RADIAL:
1987 case CAIRO_PATTERN_TYPE_MESH:
1988 return _gradient_pattern_supported (surface, pattern);
1990 case CAIRO_PATTERN_TYPE_SURFACE:
1991 return surface_pattern_supported ((cairo_surface_pattern_t *) pattern);
1993 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
2003 mask_supported (cairo_ps_surface_t *surface,
2004 const cairo_pattern_t *mask,
2005 const cairo_rectangle_int_t *extents)
2007 if (surface->ps_level == CAIRO_PS_LEVEL_2)
2010 if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
2011 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
2012 if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
2013 /* check if mask if opaque or bilevel alpha */
2014 if (_cairo_ps_surface_analyze_surface_pattern_transparency (surface, mask, extents) == CAIRO_INT_STATUS_SUCCESS) {
2015 surface->ps_level_used = CAIRO_PS_LEVEL_3;
2024 static cairo_int_status_t
2025 _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
2026 cairo_operator_t op,
2027 const cairo_pattern_t *pattern,
2028 const cairo_pattern_t *mask,
2029 const cairo_rectangle_int_t *extents)
2033 if (surface->force_fallbacks &&
2034 surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
2036 return CAIRO_INT_STATUS_UNSUPPORTED;
2039 if (! pattern_supported (surface, pattern))
2040 return CAIRO_INT_STATUS_UNSUPPORTED;
2042 if (! (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
2043 return CAIRO_INT_STATUS_UNSUPPORTED;
2045 /* Mask is only supported when the mask is an image with opaque or bilevel alpha. */
2046 if (mask && !mask_supported (surface, mask, extents))
2047 return CAIRO_INT_STATUS_UNSUPPORTED;
2049 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
2050 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
2052 if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
2053 if (pattern->extend == CAIRO_EXTEND_PAD) {
2055 cairo_rectangle_int_t rect;
2056 cairo_rectangle_int_t rec_extents;
2058 /* get the operation extents in pattern space */
2059 _cairo_box_from_rectangle (&box, extents);
2060 _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &box, NULL);
2061 _cairo_box_round_to_rectangle (&box, &rect);
2063 /* Check if surface needs padding to fill extents */
2064 if (_cairo_surface_get_extents (surface_pattern->surface, &rec_extents)) {
2065 if (_cairo_fixed_integer_ceil(box.p1.x) < rec_extents.x ||
2066 _cairo_fixed_integer_ceil(box.p1.y) < rec_extents.y ||
2067 _cairo_fixed_integer_floor(box.p2.y) > rec_extents.x + rec_extents.width ||
2068 _cairo_fixed_integer_floor(box.p2.y) > rec_extents.y + rec_extents.height)
2070 return CAIRO_INT_STATUS_UNSUPPORTED;
2074 return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
2078 if (op == CAIRO_OPERATOR_SOURCE) {
2080 return CAIRO_INT_STATUS_UNSUPPORTED;
2082 return CAIRO_STATUS_SUCCESS;
2085 /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
2086 * the pattern contains transparency, we return
2087 * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
2088 * surface. If the analysis surface determines that there is
2089 * anything drawn under this operation, a fallback image will be
2090 * used. Otherwise the operation will be replayed during the
2091 * render stage and we blend the transparency into the white
2092 * background to convert the pattern to opaque.
2094 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE || pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)
2095 return _cairo_ps_surface_analyze_surface_pattern_transparency (surface, pattern, extents);
2097 /* Patterns whose drawn part is opaque are directly supported;
2098 those whose drawn part is partially transparent can be
2099 supported by flattening the alpha. */
2100 _cairo_pattern_alpha_range (pattern, &min_alpha, NULL);
2101 if (CAIRO_ALPHA_IS_OPAQUE (min_alpha))
2102 return CAIRO_STATUS_SUCCESS;
2104 return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
2108 _cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface,
2109 cairo_operator_t op,
2110 const cairo_pattern_t *pattern,
2111 const cairo_pattern_t *mask,
2112 const cairo_rectangle_int_t *extents)
2114 return _cairo_ps_surface_analyze_operation (surface, op, pattern, mask, extents) != CAIRO_INT_STATUS_UNSUPPORTED;
2117 /* The "standard" implementation limit for PostScript string sizes is
2118 * 65535 characters (see PostScript Language Reference, Appendix
2119 * B). We go one short of that because we sometimes need two
2120 * characters in a string to represent a single ASCII85 byte, (for the
2121 * escape sequences "\\", "\(", and "\)") and we must not split these
2122 * across two strings. So we'd be in trouble if we went right to the
2123 * limit and one of these escape sequences just happened to land at
2126 #define STRING_ARRAY_MAX_STRING_SIZE (65535-1)
2127 #define STRING_ARRAY_MAX_COLUMN 72
2129 typedef struct _string_array_stream {
2130 cairo_output_stream_t base;
2131 cairo_output_stream_t *output;
2134 cairo_bool_t use_strings;
2135 } string_array_stream_t;
2137 static cairo_status_t
2138 _string_array_stream_write (cairo_output_stream_t *base,
2139 const unsigned char *data,
2140 unsigned int length)
2142 string_array_stream_t *stream = (string_array_stream_t *) base;
2144 const unsigned char backslash = '\\';
2147 return CAIRO_STATUS_SUCCESS;
2150 if (stream->string_size == 0 && stream->use_strings) {
2151 _cairo_output_stream_printf (stream->output, "(");
2156 if (stream->use_strings) {
2161 _cairo_output_stream_write (stream->output, &backslash, 1);
2163 stream->string_size++;
2167 /* Have to be careful to never split the final ~> sequence. */
2169 _cairo_output_stream_write (stream->output, &c, 1);
2171 stream->string_size++;
2178 _cairo_output_stream_write (stream->output, &c, 1);
2180 stream->string_size++;
2182 if (stream->use_strings &&
2183 stream->string_size >= STRING_ARRAY_MAX_STRING_SIZE)
2185 _cairo_output_stream_printf (stream->output, ")\n");
2186 stream->string_size = 0;
2189 if (stream->column >= STRING_ARRAY_MAX_COLUMN) {
2190 _cairo_output_stream_printf (stream->output, "\n ");
2191 stream->string_size += 2;
2196 return _cairo_output_stream_get_status (stream->output);
2199 static cairo_status_t
2200 _string_array_stream_close (cairo_output_stream_t *base)
2202 cairo_status_t status;
2203 string_array_stream_t *stream = (string_array_stream_t *) base;
2205 if (stream->use_strings)
2206 _cairo_output_stream_printf (stream->output, ")\n");
2208 status = _cairo_output_stream_get_status (stream->output);
2213 /* A string_array_stream wraps an existing output stream. It takes the
2214 * data provided to it and output one or more consecutive string
2215 * objects, each within the standard PostScript implementation limit
2216 * of 65k characters.
2218 * The strings are each separated by a space character for easy
2219 * inclusion within an array object, (but the array delimiters are not
2220 * added by the string_array_stream).
2222 * The string array stream is also careful to wrap the output within
2223 * STRING_ARRAY_MAX_COLUMN columns (+/- 1). The stream also adds
2224 * necessary escaping for special characters within a string,
2225 * (specifically '\', '(', and ')').
2227 static cairo_output_stream_t *
2228 _string_array_stream_create (cairo_output_stream_t *output)
2230 string_array_stream_t *stream;
2232 stream = malloc (sizeof (string_array_stream_t));
2233 if (unlikely (stream == NULL)) {
2234 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
2235 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
2238 _cairo_output_stream_init (&stream->base,
2239 _string_array_stream_write,
2241 _string_array_stream_close);
2242 stream->output = output;
2244 stream->string_size = 0;
2245 stream->use_strings = TRUE;
2247 return &stream->base;
2250 /* A base85_array_stream wraps an existing output stream. It wraps the
2251 * output within STRING_ARRAY_MAX_COLUMN columns (+/- 1). The output
2252 * is not enclosed in strings like string_array_stream.
2254 static cairo_output_stream_t *
2255 _base85_array_stream_create (cairo_output_stream_t *output)
2257 string_array_stream_t *stream;
2259 stream = malloc (sizeof (string_array_stream_t));
2260 if (unlikely (stream == NULL)) {
2261 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
2262 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
2265 _cairo_output_stream_init (&stream->base,
2266 _string_array_stream_write,
2268 _string_array_stream_close);
2269 stream->output = output;
2271 stream->string_size = 0;
2272 stream->use_strings = FALSE;
2274 return &stream->base;
2278 /* PS Output - this section handles output of the parts of the recording
2279 * surface we can render natively in PS. */
2281 static cairo_status_t
2282 _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface,
2283 cairo_image_surface_t *image,
2284 cairo_image_surface_t **opaque_image)
2286 cairo_surface_t *opaque;
2287 cairo_surface_pattern_t pattern;
2288 cairo_status_t status;
2290 opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
2293 if (unlikely (opaque->status)) {
2294 status = opaque->status;
2295 cairo_surface_destroy (opaque);
2299 if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
2300 status = _cairo_surface_paint (opaque,
2301 CAIRO_OPERATOR_SOURCE,
2302 &_cairo_pattern_white.base,
2304 if (unlikely (status)) {
2305 cairo_surface_destroy (opaque);
2310 _cairo_pattern_init_for_surface (&pattern, &image->base);
2311 pattern.base.filter = CAIRO_FILTER_NEAREST;
2312 status = _cairo_surface_paint (opaque, CAIRO_OPERATOR_OVER, &pattern.base, NULL);
2313 _cairo_pattern_fini (&pattern.base);
2314 if (unlikely (status)) {
2315 cairo_surface_destroy (opaque);
2319 *opaque_image = (cairo_image_surface_t *) opaque;
2320 return CAIRO_STATUS_SUCCESS;
2323 static cairo_status_t
2324 _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface,
2325 const unsigned char *data,
2326 unsigned long length,
2327 cairo_ps_compress_t compress,
2328 cairo_bool_t use_strings)
2330 cairo_output_stream_t *base85_stream, *string_array_stream, *deflate_stream;
2331 unsigned char *data_compressed;
2332 unsigned long data_compressed_size;
2333 cairo_status_t status, status2;
2336 string_array_stream = _string_array_stream_create (surface->stream);
2338 string_array_stream = _base85_array_stream_create (surface->stream);
2340 status = _cairo_output_stream_get_status (string_array_stream);
2341 if (unlikely (status))
2342 return _cairo_output_stream_destroy (string_array_stream);
2344 base85_stream = _cairo_base85_stream_create (string_array_stream);
2345 status = _cairo_output_stream_get_status (base85_stream);
2346 if (unlikely (status)) {
2347 status2 = _cairo_output_stream_destroy (string_array_stream);
2348 return _cairo_output_stream_destroy (base85_stream);
2352 case CAIRO_PS_COMPRESS_NONE:
2353 _cairo_output_stream_write (base85_stream, data, length);
2356 case CAIRO_PS_COMPRESS_LZW:
2357 /* XXX: Should fix cairo-lzw to provide a stream-based interface
2359 data_compressed_size = length;
2360 data_compressed = _cairo_lzw_compress ((unsigned char*)data, &data_compressed_size);
2361 if (unlikely (data_compressed == NULL)) {
2362 status = _cairo_output_stream_destroy (string_array_stream);
2363 status = _cairo_output_stream_destroy (base85_stream);
2364 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2366 _cairo_output_stream_write (base85_stream, data_compressed, data_compressed_size);
2367 free (data_compressed);
2370 case CAIRO_PS_COMPRESS_DEFLATE:
2371 deflate_stream = _cairo_deflate_stream_create (base85_stream);
2372 if (_cairo_output_stream_get_status (deflate_stream)) {
2373 return _cairo_output_stream_destroy (deflate_stream);
2375 _cairo_output_stream_write (deflate_stream, data, length);
2376 status = _cairo_output_stream_destroy (deflate_stream);
2377 if (unlikely (status)) {
2378 status2 = _cairo_output_stream_destroy (string_array_stream);
2379 status2 = _cairo_output_stream_destroy (base85_stream);
2380 return _cairo_output_stream_destroy (deflate_stream);
2384 status = _cairo_output_stream_destroy (base85_stream);
2386 /* Mark end of base85 data */
2387 _cairo_output_stream_printf (string_array_stream, "~>");
2388 status2 = _cairo_output_stream_destroy (string_array_stream);
2389 if (status == CAIRO_STATUS_SUCCESS)
2395 static cairo_status_t
2396 _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
2397 cairo_image_surface_t *image_surf,
2398 cairo_operator_t op,
2399 cairo_filter_t filter,
2400 cairo_bool_t stencil_mask)
2402 cairo_status_t status;
2403 unsigned char *data;
2404 unsigned long data_size;
2405 cairo_image_surface_t *ps_image;
2407 cairo_image_transparency_t transparency;
2408 cairo_bool_t use_mask;
2412 cairo_image_color_t color;
2413 const char *interpolate;
2414 cairo_ps_compress_t compress;
2415 const char *compress_filter;
2416 cairo_image_surface_t *image;
2418 if (image_surf->base.status)
2419 return image_surf->base.status;
2422 if (image->format != CAIRO_FORMAT_RGB24 &&
2423 image->format != CAIRO_FORMAT_ARGB32 &&
2424 image->format != CAIRO_FORMAT_A8 &&
2425 image->format != CAIRO_FORMAT_A1)
2427 cairo_surface_t *surf;
2428 cairo_surface_pattern_t pattern;
2430 surf = _cairo_image_surface_create_with_content (image_surf->base.content,
2432 image_surf->height);
2433 image = (cairo_image_surface_t *) surf;
2435 status = surf->status;
2439 _cairo_pattern_init_for_surface (&pattern, &image_surf->base);
2440 status = _cairo_surface_paint (surf,
2441 CAIRO_OPERATOR_SOURCE, &pattern.base,
2443 _cairo_pattern_fini (&pattern.base);
2444 if (unlikely (status))
2451 case CAIRO_FILTER_GOOD:
2452 case CAIRO_FILTER_BEST:
2453 case CAIRO_FILTER_BILINEAR:
2454 interpolate = "true";
2456 case CAIRO_FILTER_FAST:
2457 case CAIRO_FILTER_NEAREST:
2458 case CAIRO_FILTER_GAUSSIAN:
2459 interpolate = "false";
2465 color = CAIRO_IMAGE_IS_MONOCHROME;
2466 transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
2468 transparency = _cairo_image_analyze_transparency (image);
2470 /* PostScript can not represent the alpha channel, so we blend the
2471 current image over a white (or black for CONTENT_COLOR
2472 surfaces) RGB surface to eliminate it. */
2474 if (op == CAIRO_OPERATOR_SOURCE ||
2475 transparency == CAIRO_IMAGE_HAS_ALPHA ||
2476 (transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA &&
2477 surface->ps_level == CAIRO_PS_LEVEL_2))
2479 status = _cairo_ps_surface_flatten_image_transparency (surface,
2482 if (unlikely (status))
2486 } else if (transparency == CAIRO_IMAGE_IS_OPAQUE) {
2488 } else { /* transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA */
2492 color = _cairo_image_analyze_color (ps_image);
2495 /* Type 2 (mask and image interleaved) has the mask and image
2496 * samples interleaved by row. The mask row is first, one bit per
2497 * pixel with (bit 7 first). The row is padded to byte
2498 * boundaries. The image data is 3 bytes per pixel RGB format. */
2501 case CAIRO_IMAGE_UNKNOWN_COLOR:
2503 case CAIRO_IMAGE_IS_COLOR:
2504 data_size = ps_image->width * 3;
2506 case CAIRO_IMAGE_IS_GRAYSCALE:
2507 data_size = ps_image->width;
2509 case CAIRO_IMAGE_IS_MONOCHROME:
2510 data_size = (ps_image->width + 7)/8;
2514 data_size += (ps_image->width + 7)/8;
2515 data_size *= ps_image->height;
2516 data = malloc (data_size);
2517 if (unlikely (data == NULL)) {
2518 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2523 for (y = 0; y < ps_image->height; y++) {
2524 if (stencil_mask || use_mask) {
2526 if (ps_image->format == CAIRO_FORMAT_A1) {
2527 pixel8 = (uint8_t *) (ps_image->data + y * ps_image->stride);
2529 for (x = 0; x < (ps_image->width + 7) / 8; x++, pixel8++) {
2531 a = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (a);
2535 pixel8 = (uint8_t *) (ps_image->data + y * ps_image->stride);
2536 pixel32 = (uint32_t *) (ps_image->data + y * ps_image->stride);
2538 for (x = 0; x < ps_image->width; x++) {
2539 if (ps_image->format == CAIRO_FORMAT_ARGB32) {
2540 a = (*pixel32 & 0xff000000) >> 24;
2547 if (transparency == CAIRO_IMAGE_HAS_ALPHA) {
2549 } else { /* transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA or CAIRO_IMAGE_IS_OPAQUE */
2553 data[i] |= (1 << bit);
2569 pixel32 = (uint32_t *) (ps_image->data + y * ps_image->stride);
2571 for (x = 0; x < ps_image->width; x++, pixel32++) {
2574 if (ps_image->format == CAIRO_FORMAT_ARGB32) {
2575 /* At this point ARGB32 images are either opaque or
2576 * bilevel alpha so we don't need to unpremultiply. */
2577 if (((*pixel32 & 0xff000000) >> 24) == 0) {
2580 r = (*pixel32 & 0x00ff0000) >> 16;
2581 g = (*pixel32 & 0x0000ff00) >> 8;
2582 b = (*pixel32 & 0x000000ff) >> 0;
2584 } else if (ps_image->format == CAIRO_FORMAT_RGB24) {
2585 r = (*pixel32 & 0x00ff0000) >> 16;
2586 g = (*pixel32 & 0x0000ff00) >> 8;
2587 b = (*pixel32 & 0x000000ff) >> 0;
2593 case CAIRO_IMAGE_IS_COLOR:
2594 case CAIRO_IMAGE_UNKNOWN_COLOR:
2600 case CAIRO_IMAGE_IS_GRAYSCALE:
2604 case CAIRO_IMAGE_IS_MONOCHROME:
2608 data[i] |= (1 << bit);
2621 if (surface->ps_level == CAIRO_PS_LEVEL_2) {
2622 compress = CAIRO_PS_COMPRESS_LZW;
2623 compress_filter = "LZWDecode";
2625 compress = CAIRO_PS_COMPRESS_DEFLATE;
2626 compress_filter = "FlateDecode";
2627 surface->ps_level_used = CAIRO_PS_LEVEL_3;
2630 if (surface->use_string_datasource) {
2631 /* Emit the image data as a base85-encoded string which will
2632 * be used as the data source for the image operator later. */
2633 _cairo_output_stream_printf (surface->stream,
2634 "/CairoImageData [\n");
2636 status = _cairo_ps_surface_emit_base85_string (surface,
2641 if (unlikely (status))
2644 _cairo_output_stream_printf (surface->stream,
2646 _cairo_output_stream_printf (surface->stream,
2647 "/CairoImageDataIndex 0 def\n");
2651 _cairo_output_stream_printf (surface->stream,
2652 "%s setcolorspace\n"
2653 "5 dict dup begin\n"
2654 " /ImageType 3 def\n"
2655 " /InterleaveType 2 def\n"
2656 " /DataDict 8 dict def\n"
2658 " /ImageType 1 def\n"
2661 " /Interpolate %s def\n"
2662 " /BitsPerComponent %d def\n"
2663 " /Decode [ %s ] def\n",
2664 color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray",
2668 color == CAIRO_IMAGE_IS_MONOCHROME ? 1 : 8,
2669 color == CAIRO_IMAGE_IS_COLOR ? "0 1 0 1 0 1" : "0 1");
2671 if (surface->use_string_datasource) {
2672 _cairo_output_stream_printf (surface->stream,
2674 " CairoImageData CairoImageDataIndex get\n"
2675 " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2676 " CairoImageDataIndex CairoImageData length 1 sub gt\n"
2677 " { /CairoImageDataIndex 0 def } if\n"
2678 " } /ASCII85Decode filter /%s filter def\n",
2681 _cairo_output_stream_printf (surface->stream,
2682 " /DataSource currentfile /ASCII85Decode filter /%s filter def\n",
2686 _cairo_output_stream_printf (surface->stream,
2687 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2689 " /MaskDict 8 dict def\n"
2691 " /ImageType 1 def\n"
2694 " /Interpolate %s def\n"
2695 " /BitsPerComponent 1 def\n"
2696 " /Decode [ 1 0 ] def\n"
2697 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2707 if (!stencil_mask) {
2708 _cairo_output_stream_printf (surface->stream,
2709 "%s setcolorspace\n",
2710 color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray");
2712 _cairo_output_stream_printf (surface->stream,
2713 "8 dict dup begin\n"
2714 " /ImageType 1 def\n"
2717 " /Interpolate %s def\n"
2718 " /BitsPerComponent %d def\n"
2719 " /Decode [ %s ] def\n",
2723 color == CAIRO_IMAGE_IS_MONOCHROME ? 1 : 8,
2724 stencil_mask ? "1 0" : color == CAIRO_IMAGE_IS_COLOR ? "0 1 0 1 0 1" : "0 1");
2725 if (surface->use_string_datasource) {
2726 _cairo_output_stream_printf (surface->stream,
2728 " CairoImageData CairoImageDataIndex get\n"
2729 " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2730 " CairoImageDataIndex CairoImageData length 1 sub gt\n"
2731 " { /CairoImageDataIndex 0 def } if\n"
2732 " } /ASCII85Decode filter /%s filter def\n",
2735 _cairo_output_stream_printf (surface->stream,
2736 " /DataSource currentfile /ASCII85Decode filter /%s filter def\n",
2740 _cairo_output_stream_printf (surface->stream,
2741 " /Interpolate %s def\n"
2742 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2747 stencil_mask ? "imagemask" : "image");
2750 if (!surface->use_string_datasource) {
2751 /* Emit the image data as a base85-encoded string which will
2752 * be used as the data source for the image operator. */
2753 status = _cairo_ps_surface_emit_base85_string (surface,
2758 _cairo_output_stream_printf (surface->stream, "\n");
2760 status = CAIRO_STATUS_SUCCESS;
2767 if (!use_mask && ps_image != image)
2768 cairo_surface_destroy (&ps_image->base);
2771 if (image != image_surf)
2772 cairo_surface_destroy (&image->base);
2777 static cairo_status_t
2778 _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface,
2779 cairo_surface_t *source,
2783 cairo_status_t status;
2784 const unsigned char *mime_data;
2785 unsigned long mime_data_length;
2786 cairo_image_info_t info;
2787 const char *colorspace;
2790 cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
2791 &mime_data, &mime_data_length);
2792 if (unlikely (source->status))
2793 return source->status;
2794 if (mime_data == NULL)
2795 return CAIRO_INT_STATUS_UNSUPPORTED;
2797 status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length);
2798 if (unlikely (status))
2801 switch (info.num_components) {
2803 colorspace = "/DeviceGray";
2807 colorspace = "/DeviceRGB";
2808 decode = "0 1 0 1 0 1";
2811 colorspace = "/DeviceCMYK";
2812 decode = "0 1 0 1 0 1 0 1";
2815 return CAIRO_INT_STATUS_UNSUPPORTED;
2818 if (surface->use_string_datasource) {
2819 /* Emit the image data as a base85-encoded string which will
2820 * be used as the data source for the image operator later. */
2821 _cairo_output_stream_printf (surface->stream,
2822 "/CairoImageData [\n");
2824 status = _cairo_ps_surface_emit_base85_string (surface,
2827 CAIRO_PS_COMPRESS_NONE,
2829 if (unlikely (status))
2832 _cairo_output_stream_printf (surface->stream,
2834 _cairo_output_stream_printf (surface->stream,
2835 "/CairoImageDataIndex 0 def\n");
2838 _cairo_output_stream_printf (surface->stream,
2839 "%s setcolorspace\n"
2840 "8 dict dup begin\n"
2841 " /ImageType 1 def\n"
2844 " /BitsPerComponent %d def\n"
2845 " /Decode [ %s ] def\n",
2849 info.bits_per_component,
2852 if (surface->use_string_datasource) {
2853 _cairo_output_stream_printf (surface->stream,
2855 " CairoImageData CairoImageDataIndex get\n"
2856 " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2857 " CairoImageDataIndex CairoImageData length 1 sub gt\n"
2858 " { /CairoImageDataIndex 0 def } if\n"
2859 " } /ASCII85Decode filter /DCTDecode filter def\n");
2861 _cairo_output_stream_printf (surface->stream,
2862 " /DataSource currentfile /ASCII85Decode filter /DCTDecode filter def\n");
2865 _cairo_output_stream_printf (surface->stream,
2866 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2871 if (!surface->use_string_datasource) {
2872 /* Emit the image data as a base85-encoded string which will
2873 * be used as the data source for the image operator. */
2874 status = _cairo_ps_surface_emit_base85_string (surface,
2877 CAIRO_PS_COMPRESS_NONE,
2884 static cairo_status_t
2885 _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
2886 cairo_surface_t *recording_surface)
2888 double old_width, old_height;
2889 cairo_matrix_t old_cairo_to_ps;
2890 cairo_content_t old_content;
2891 cairo_rectangle_int_t old_page_bbox;
2892 cairo_surface_t *free_me = NULL;
2893 cairo_surface_clipper_t old_clipper;
2895 cairo_int_status_t status;
2897 old_content = surface->content;
2898 old_width = surface->width;
2899 old_height = surface->height;
2900 old_page_bbox = surface->page_bbox;
2901 old_cairo_to_ps = surface->cairo_to_ps;
2902 old_clipper = surface->clipper;
2903 _cairo_surface_clipper_init (&surface->clipper,
2904 _cairo_ps_surface_clipper_intersect_clip_path);
2906 if (_cairo_surface_is_snapshot (recording_surface))
2907 free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface);
2910 _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
2913 if (unlikely (status))
2917 _cairo_output_stream_printf (surface->stream,
2918 "%% _cairo_ps_surface_emit_recording_surface (%f, %f), (%f, %f)\n",
2919 _cairo_fixed_to_double (bbox.p1.x),
2920 _cairo_fixed_to_double (bbox.p1.y),
2921 _cairo_fixed_to_double (bbox.p2.x),
2922 _cairo_fixed_to_double (bbox.p2.y));
2925 surface->width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
2926 surface->height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
2927 _cairo_box_round_to_rectangle (&bbox, &surface->page_bbox);
2929 surface->current_pattern_is_solid_color = FALSE;
2930 _cairo_pdf_operators_reset (&surface->pdf_operators);
2931 cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
2932 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
2933 &surface->cairo_to_ps);
2934 _cairo_output_stream_printf (surface->stream, " q\n");
2936 if (recording_surface->content == CAIRO_CONTENT_COLOR) {
2937 surface->content = CAIRO_CONTENT_COLOR;
2938 _cairo_output_stream_printf (surface->stream,
2939 " 0 g %d %d %d %d rectfill\n",
2940 surface->page_bbox.x,
2941 surface->page_bbox.y,
2942 surface->page_bbox.width,
2943 surface->page_bbox.height);
2946 status = _cairo_recording_surface_replay_region (recording_surface,
2949 CAIRO_RECORDING_REGION_NATIVE);
2950 assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
2951 if (unlikely (status))
2954 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
2955 if (unlikely (status))
2958 _cairo_output_stream_printf (surface->stream, " Q\n");
2960 _cairo_surface_clipper_reset (&surface->clipper);
2961 surface->clipper = old_clipper;
2962 surface->content = old_content;
2963 surface->width = old_width;
2964 surface->height = old_height;
2965 surface->page_bbox = old_page_bbox;
2966 surface->current_pattern_is_solid_color = FALSE;
2967 _cairo_pdf_operators_reset (&surface->pdf_operators);
2968 surface->cairo_to_ps = old_cairo_to_ps;
2970 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
2971 &surface->cairo_to_ps);
2974 cairo_surface_destroy (free_me);
2978 static cairo_int_status_t
2979 _cairo_ps_surface_emit_recording_subsurface (cairo_ps_surface_t *surface,
2980 cairo_surface_t *recording_surface,
2981 const cairo_rectangle_int_t *extents)
2983 double old_width, old_height;
2984 cairo_matrix_t old_cairo_to_ps;
2985 cairo_content_t old_content;
2986 cairo_rectangle_int_t old_page_bbox;
2987 cairo_surface_clipper_t old_clipper;
2988 cairo_surface_t *free_me = NULL;
2989 cairo_int_status_t status;
2991 old_content = surface->content;
2992 old_width = surface->width;
2993 old_height = surface->height;
2994 old_page_bbox = surface->page_bbox;
2995 old_cairo_to_ps = surface->cairo_to_ps;
2996 old_clipper = surface->clipper;
2997 _cairo_surface_clipper_init (&surface->clipper,
2998 _cairo_ps_surface_clipper_intersect_clip_path);
3001 _cairo_output_stream_printf (surface->stream,
3002 "%% _cairo_ps_surface_emit_recording_subsurface (%d, %d), (%d, %d)\n",
3003 extents->x, extents->y,
3004 extents->width, extents->height);
3007 surface->page_bbox.x = surface->page_bbox.y = 0;
3008 surface->page_bbox.width = surface->width = extents->width;
3009 surface->page_bbox.height = surface->height = extents->height;
3011 surface->current_pattern_is_solid_color = FALSE;
3012 _cairo_pdf_operators_reset (&surface->pdf_operators);
3013 cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
3014 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
3015 &surface->cairo_to_ps);
3016 _cairo_output_stream_printf (surface->stream, " q\n");
3018 if (_cairo_surface_is_snapshot (recording_surface))
3019 free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface);
3021 if (recording_surface->content == CAIRO_CONTENT_COLOR) {
3022 surface->content = CAIRO_CONTENT_COLOR;
3023 _cairo_output_stream_printf (surface->stream,
3024 " 0 g %d %d %d %d rectfill\n",
3025 surface->page_bbox.x,
3026 surface->page_bbox.y,
3027 surface->page_bbox.width,
3028 surface->page_bbox.height);
3031 status = _cairo_recording_surface_replay_region (recording_surface,
3034 CAIRO_RECORDING_REGION_NATIVE);
3035 assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
3036 if (unlikely (status))
3039 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3040 if (unlikely (status))
3043 _cairo_output_stream_printf (surface->stream, " Q\n");
3045 _cairo_surface_clipper_reset (&surface->clipper);
3046 surface->clipper = old_clipper;
3047 surface->content = old_content;
3048 surface->width = old_width;
3049 surface->height = old_height;
3050 surface->page_bbox = old_page_bbox;
3051 surface->current_pattern_is_solid_color = FALSE;
3052 _cairo_pdf_operators_reset (&surface->pdf_operators);
3053 surface->cairo_to_ps = old_cairo_to_ps;
3055 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
3056 &surface->cairo_to_ps);
3059 cairo_surface_destroy (free_me);
3064 _cairo_ps_surface_flatten_transparency (cairo_ps_surface_t *surface,
3065 const cairo_color_t *color,
3071 *green = color->green;
3072 *blue = color->blue;
3074 if (! CAIRO_COLOR_IS_OPAQUE (color)) {
3075 *red *= color->alpha;
3076 *green *= color->alpha;
3077 *blue *= color->alpha;
3078 if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
3079 double one_minus_alpha = 1. - color->alpha;
3080 *red += one_minus_alpha;
3081 *green += one_minus_alpha;
3082 *blue += one_minus_alpha;
3088 _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
3089 cairo_solid_pattern_t *pattern)
3091 double red, green, blue;
3093 _cairo_ps_surface_flatten_transparency (surface, &pattern->color, &red, &green, &blue);
3095 if (color_is_gray (red, green, blue))
3096 _cairo_output_stream_printf (surface->stream,
3100 _cairo_output_stream_printf (surface->stream,
3105 static cairo_status_t
3106 _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
3107 cairo_pattern_t *source_pattern,
3108 cairo_surface_t *source_surface,
3109 cairo_operator_t op,
3112 cairo_bool_t stencil_mask)
3114 cairo_int_status_t status;
3116 if (source_surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
3117 if (source_surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
3118 cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source_surface;
3119 status = _cairo_ps_surface_emit_recording_subsurface (surface, sub->target, &sub->extents);
3121 status = _cairo_ps_surface_emit_recording_surface (surface, source_surface);
3124 cairo_image_surface_t *image = (cairo_image_surface_t *) source_surface;
3125 if (source_pattern->extend != CAIRO_EXTEND_PAD) {
3126 status = _cairo_ps_surface_emit_jpeg_image (surface, source_surface,
3128 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
3132 status = _cairo_ps_surface_emit_image (surface, image,
3133 op, source_pattern->filter, stencil_mask);
3141 _path_fixed_init_rectangle (cairo_path_fixed_t *path,
3142 cairo_rectangle_int_t *rect)
3144 cairo_status_t status;
3146 _cairo_path_fixed_init (path);
3148 status = _cairo_path_fixed_move_to (path,
3149 _cairo_fixed_from_int (rect->x),
3150 _cairo_fixed_from_int (rect->y));
3151 assert (status == CAIRO_STATUS_SUCCESS);
3152 status = _cairo_path_fixed_rel_line_to (path,
3153 _cairo_fixed_from_int (rect->width),
3154 _cairo_fixed_from_int (0));
3155 assert (status == CAIRO_STATUS_SUCCESS);
3156 status = _cairo_path_fixed_rel_line_to (path,
3157 _cairo_fixed_from_int (0),
3158 _cairo_fixed_from_int (rect->height));
3159 assert (status == CAIRO_STATUS_SUCCESS);
3160 status = _cairo_path_fixed_rel_line_to (path,
3161 _cairo_fixed_from_int (-rect->width),
3162 _cairo_fixed_from_int (0));
3163 assert (status == CAIRO_STATUS_SUCCESS);
3165 status = _cairo_path_fixed_close_path (path);
3166 assert (status == CAIRO_STATUS_SUCCESS);
3169 static cairo_status_t
3170 _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
3171 cairo_pattern_t *pattern,
3172 cairo_rectangle_int_t *extents,
3173 cairo_operator_t op,
3174 cairo_bool_t stencil_mask)
3176 cairo_status_t status;
3178 cairo_matrix_t cairo_p2d, ps_p2d;
3179 cairo_path_fixed_t path;
3180 double x_offset, y_offset;
3181 cairo_surface_t *source;
3182 cairo_image_surface_t *image = NULL;
3185 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3186 if (unlikely (status))
3189 status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
3193 &x_offset, &y_offset,
3196 if (unlikely (status))
3199 if (pattern->extend == CAIRO_EXTEND_PAD &&
3200 pattern->type == CAIRO_PATTERN_TYPE_SURFACE &&
3201 ((cairo_surface_pattern_t *)pattern)->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
3202 cairo_image_surface_t *img;
3204 img = (cairo_image_surface_t *) source;
3205 status = _cairo_ps_surface_create_padded_image_from_image (surface,
3210 &x_offset, &y_offset,
3212 if (unlikely (status))
3213 goto release_source;
3216 _path_fixed_init_rectangle (&path, extents);
3217 status = _cairo_pdf_operators_clip (&surface->pdf_operators,
3219 CAIRO_FILL_RULE_WINDING);
3220 _cairo_path_fixed_fini (&path);
3221 if (unlikely (status))
3222 goto release_source;
3224 cairo_p2d = pattern->matrix;
3226 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
3227 double x_scale = cairo_p2d.xx;
3228 double y_scale = cairo_p2d.yy;
3230 _cairo_output_stream_printf (surface->stream,
3231 "%% Fallback Image: x=%f y=%f w=%d h=%d ",
3232 -cairo_p2d.x0/x_scale,
3233 -cairo_p2d.y0/y_scale,
3234 (int)(width/x_scale),
3235 (int)(height/y_scale));
3236 if (x_scale == y_scale) {
3237 _cairo_output_stream_printf (surface->stream,
3241 _cairo_output_stream_printf (surface->stream,
3246 _cairo_output_stream_printf (surface->stream,
3248 (long)width*height*3);
3250 if (op == CAIRO_OPERATOR_SOURCE) {
3251 _cairo_output_stream_printf (surface->stream,
3252 "%d g 0 0 %f %f rectfill\n",
3253 surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
3259 status = cairo_matrix_invert (&cairo_p2d);
3260 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3261 assert (status == CAIRO_STATUS_SUCCESS);
3263 ps_p2d = surface->cairo_to_ps;
3264 cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
3265 cairo_matrix_translate (&ps_p2d, x_offset, y_offset);
3266 cairo_matrix_translate (&ps_p2d, 0.0, height);
3267 cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
3269 if (! _cairo_matrix_is_identity (&ps_p2d)) {
3270 _cairo_output_stream_printf (surface->stream,
3271 "[ %f %f %f %f %f %f ] concat\n",
3272 ps_p2d.xx, ps_p2d.yx,
3273 ps_p2d.xy, ps_p2d.yy,
3274 ps_p2d.x0, ps_p2d.y0);
3277 status = _cairo_ps_surface_emit_surface (surface,
3279 image ? &image->base : source,
3286 cairo_surface_destroy (&image->base);
3288 _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
3293 static cairo_status_t
3294 _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
3295 cairo_pattern_t *pattern,
3296 cairo_rectangle_int_t *extents,
3297 cairo_operator_t op)
3299 cairo_status_t status;
3300 int pattern_width = 0; /* squelch bogus compiler warning */
3301 int pattern_height = 0; /* squelch bogus compiler warning */
3302 double xstep, ystep;
3303 cairo_matrix_t cairo_p2d, ps_p2d;
3304 cairo_bool_t old_use_string_datasource;
3305 double x_offset, y_offset;
3306 cairo_surface_t *source;
3307 cairo_image_surface_t *image = NULL;
3310 cairo_p2d = pattern->matrix;
3311 status = cairo_matrix_invert (&cairo_p2d);
3312 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3313 assert (status == CAIRO_STATUS_SUCCESS);
3315 status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
3318 &pattern_width, &pattern_height,
3319 &x_offset, &y_offset,
3322 if (unlikely (status))
3325 if (pattern->extend == CAIRO_EXTEND_PAD) {
3326 cairo_image_surface_t *img;
3328 assert (source->type == CAIRO_SURFACE_TYPE_IMAGE);
3329 img = (cairo_image_surface_t *) source;
3330 status = _cairo_ps_surface_create_padded_image_from_image (surface,
3334 &pattern_width, &pattern_height,
3335 &x_offset, &y_offset,
3337 if (unlikely (status))
3338 goto release_source;
3341 switch (pattern->extend) {
3342 case CAIRO_EXTEND_PAD:
3343 case CAIRO_EXTEND_NONE:
3345 /* In PS/PDF, (as far as I can tell), all patterns are
3346 * repeating. So we support cairo's EXTEND_NONE semantics
3347 * by setting the repeat step size to a size large enough
3348 * to guarantee that no more than a single occurrence will
3351 * First, map the surface extents into pattern space (since
3352 * xstep and ystep are in pattern space). Then use an upper
3353 * bound on the length of the diagonal of the pattern image
3354 * and the surface as repeat size. This guarantees to never
3357 double x1 = 0.0, y1 = 0.0;
3358 double x2 = surface->width, y2 = surface->height;
3359 _cairo_matrix_transform_bounding_box (&pattern->matrix,
3363 /* Rather than computing precise bounds of the union, just
3364 * add the surface extents unconditionally. We only
3365 * required an answer that's large enough, we don't really
3366 * care if it's not as tight as possible.*/
3367 xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
3368 pattern_width + pattern_height);
3371 case CAIRO_EXTEND_REPEAT:
3372 xstep = pattern_width;
3373 ystep = pattern_height;
3375 case CAIRO_EXTEND_REFLECT:
3376 xstep = pattern_width*2;
3377 ystep = pattern_height*2;
3379 /* All the rest (if any) should have been analyzed away, so these
3380 * cases should be unreachable. */
3387 _cairo_output_stream_printf (surface->stream,
3388 "/CairoPattern {\n");
3390 old_use_string_datasource = surface->use_string_datasource;
3391 surface->use_string_datasource = TRUE;
3392 if (op == CAIRO_OPERATOR_SOURCE) {
3393 _cairo_output_stream_printf (surface->stream,
3394 "%d g 0 0 %f %f rectfill\n",
3395 surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
3398 status = _cairo_ps_surface_emit_surface (surface,
3400 image ? &image->base : source,
3402 pattern_width, pattern_height, FALSE);
3403 if (unlikely (status))
3404 goto release_source;
3406 surface->use_string_datasource = old_use_string_datasource;
3407 _cairo_output_stream_printf (surface->stream,
3410 _cairo_output_stream_printf (surface->stream,
3411 "<< /PatternType 1\n"
3413 " /TilingType 1\n");
3414 _cairo_output_stream_printf (surface->stream,
3415 " /XStep %f /YStep %f\n",
3418 if (pattern->extend == CAIRO_EXTEND_REFLECT) {
3419 _cairo_output_stream_printf (surface->stream,
3420 " /BBox [0 0 %d %d]\n"
3423 " [-1 0 0 1 %d 0] concat CairoPattern\n"
3424 " [ 1 0 0 -1 0 %d] concat CairoPattern\n"
3425 " [-1 0 0 1 %d 0] concat CairoPattern\n"
3428 pattern_width*2, pattern_height*2,
3433 if (op == CAIRO_OPERATOR_SOURCE) {
3434 _cairo_output_stream_printf (surface->stream,
3435 " /BBox [0 0 %f %f]\n",
3438 _cairo_output_stream_printf (surface->stream,
3439 " /BBox [0 0 %d %d]\n",
3440 pattern_width, pattern_height);
3442 _cairo_output_stream_printf (surface->stream,
3443 " /PaintProc { CairoPattern }\n");
3446 _cairo_output_stream_printf (surface->stream,
3449 cairo_p2d = pattern->matrix;
3450 status = cairo_matrix_invert (&cairo_p2d);
3451 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3452 assert (status == CAIRO_STATUS_SUCCESS);
3454 cairo_matrix_init_identity (&ps_p2d);
3455 cairo_matrix_translate (&ps_p2d, 0.0, surface->height);
3456 cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
3457 cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
3458 cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
3459 cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
3461 _cairo_output_stream_printf (surface->stream,
3462 "[ %f %f %f %f %f %f ]\n",
3463 ps_p2d.xx, ps_p2d.yx,
3464 ps_p2d.xy, ps_p2d.yy,
3465 ps_p2d.x0, ps_p2d.y0);
3466 _cairo_output_stream_printf (surface->stream,
3467 "makepattern setpattern\n");
3471 cairo_surface_destroy (&image->base);
3473 _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
3478 typedef struct _cairo_ps_color_stop {
3481 } cairo_ps_color_stop_t;
3484 _cairo_ps_surface_emit_linear_colorgradient (cairo_ps_surface_t *surface,
3485 cairo_ps_color_stop_t *stop1,
3486 cairo_ps_color_stop_t *stop2)
3488 _cairo_output_stream_printf (surface->stream,
3489 " << /FunctionType 2\n"
3490 " /Domain [ 0 1 ]\n"
3491 " /C0 [ %f %f %f ]\n"
3492 " /C1 [ %f %f %f ]\n"
3504 _cairo_ps_surface_emit_stitched_colorgradient (cairo_ps_surface_t *surface,
3505 unsigned int n_stops,
3506 cairo_ps_color_stop_t stops[])
3510 _cairo_output_stream_printf (surface->stream,
3511 "<< /FunctionType 3\n"
3512 " /Domain [ 0 1 ]\n"
3514 for (i = 0; i < n_stops - 1; i++)
3515 _cairo_ps_surface_emit_linear_colorgradient (surface, &stops[i], &stops[i+1]);
3517 _cairo_output_stream_printf (surface->stream, " ]\n");
3519 _cairo_output_stream_printf (surface->stream, " /Bounds [ ");
3520 for (i = 1; i < n_stops-1; i++)
3521 _cairo_output_stream_printf (surface->stream, "%f ", stops[i].offset);
3522 _cairo_output_stream_printf (surface->stream, "]\n");
3524 _cairo_output_stream_printf (surface->stream, " /Encode [ 1 1 %d { pop 0 1 } for ]\n",
3527 _cairo_output_stream_printf (surface->stream, ">>\n");
3531 calc_gradient_color (cairo_ps_color_stop_t *new_stop,
3532 cairo_ps_color_stop_t *stop1,
3533 cairo_ps_color_stop_t *stop2)
3536 double offset = stop1->offset / (stop1->offset + 1.0 - stop2->offset);
3538 for (i = 0; i < 4; i++)
3539 new_stop->color[i] = stop1->color[i] + offset*(stop2->color[i] - stop1->color[i]);
3542 #define COLOR_STOP_EPSILON 1e-6
3544 static cairo_status_t
3545 _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t *surface,
3546 cairo_gradient_pattern_t *pattern)
3548 cairo_ps_color_stop_t *allstops, *stops;
3549 unsigned int i, n_stops;
3551 allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_ps_color_stop_t));
3552 if (unlikely (allstops == NULL))
3553 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3555 stops = &allstops[1];
3556 n_stops = pattern->n_stops;
3558 for (i = 0; i < n_stops; i++) {
3559 cairo_gradient_stop_t *stop = &pattern->stops[i];
3561 stops[i].color[0] = stop->color.red;
3562 stops[i].color[1] = stop->color.green;
3563 stops[i].color[2] = stop->color.blue;
3564 stops[i].color[3] = stop->color.alpha;
3565 stops[i].offset = pattern->stops[i].offset;
3568 if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
3569 pattern->base.extend == CAIRO_EXTEND_REFLECT)
3571 if (stops[0].offset > COLOR_STOP_EPSILON) {
3572 if (pattern->base.extend == CAIRO_EXTEND_REFLECT)
3573 memcpy (allstops, stops, sizeof (cairo_ps_color_stop_t));
3575 calc_gradient_color (&allstops[0], &stops[0], &stops[n_stops-1]);
3579 stops[0].offset = 0.0;
3581 if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
3582 if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
3583 memcpy (&stops[n_stops],
3584 &stops[n_stops - 1],
3585 sizeof (cairo_ps_color_stop_t));
3587 calc_gradient_color (&stops[n_stops], &stops[0], &stops[n_stops-1]);
3591 stops[n_stops-1].offset = 1.0;
3594 for (i = 0; i < n_stops; i++) {
3595 double red, green, blue;
3596 cairo_color_t color;
3598 _cairo_color_init_rgba (&color,
3603 _cairo_ps_surface_flatten_transparency (surface, &color,
3604 &red, &green, &blue);
3605 stops[i].color[0] = red;
3606 stops[i].color[1] = green;
3607 stops[i].color[2] = blue;
3610 _cairo_output_stream_printf (surface->stream,
3611 "/CairoFunction\n");
3612 if (stops[0].offset == stops[n_stops - 1].offset) {
3614 * The first and the last stops have the same offset, but we
3615 * don't want a function with an empty domain, because that
3616 * would provoke underdefined behaviour from rasterisers.
3617 * This can only happen with EXTEND_PAD, because EXTEND_NONE
3618 * is optimised into a clear pattern in cairo-gstate, and
3619 * REFLECT/REPEAT are always transformed to have the first
3620 * stop at t=0 and the last stop at t=1. Thus we want a step
3621 * function going from the first color to the last one.
3623 * This can be accomplished by stitching three functions:
3624 * - a constant first color function,
3625 * - a step from the first color to the last color (with empty domain)
3626 * - a constant last color function
3628 cairo_ps_color_stop_t pad_stops[4];
3630 assert (pattern->base.extend == CAIRO_EXTEND_PAD);
3632 pad_stops[0] = pad_stops[1] = stops[0];
3633 pad_stops[2] = pad_stops[3] = stops[n_stops - 1];
3635 pad_stops[0].offset = 0;
3636 pad_stops[3].offset = 1;
3638 _cairo_ps_surface_emit_stitched_colorgradient (surface, 4, pad_stops);
3639 } else if (n_stops == 2) {
3640 /* no need for stitched function */
3641 _cairo_ps_surface_emit_linear_colorgradient (surface, &stops[0], &stops[1]);
3643 /* multiple stops: stitch. XXX possible optimization: regulary spaced
3644 * stops do not require stitching. XXX */
3645 _cairo_ps_surface_emit_stitched_colorgradient (surface, n_stops, stops);
3647 _cairo_output_stream_printf (surface->stream,
3652 return CAIRO_STATUS_SUCCESS;
3655 static cairo_status_t
3656 _cairo_ps_surface_emit_repeating_function (cairo_ps_surface_t *surface,
3657 cairo_gradient_pattern_t *pattern,
3661 _cairo_output_stream_printf (surface->stream,
3663 "<< /FunctionType 3\n"
3664 " /Domain [ %d %d ]\n"
3665 " /Functions [ %d {CairoFunction} repeat ]\n"
3666 " /Bounds [ %d 1 %d {} for ]\n",
3673 if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
3674 _cairo_output_stream_printf (surface->stream, " /Encode [ %d 1 %d { 2 mod 0 eq {0 1} {1 0} ifelse } for ]\n",
3678 _cairo_output_stream_printf (surface->stream, " /Encode [ %d 1 %d { pop 0 1 } for ]\n",
3683 _cairo_output_stream_printf (surface->stream, ">> def\n");
3685 return CAIRO_STATUS_SUCCESS;
3688 static cairo_status_t
3689 _cairo_ps_surface_emit_gradient (cairo_ps_surface_t *surface,
3690 cairo_gradient_pattern_t *pattern,
3691 cairo_bool_t is_ps_pattern)
3693 cairo_matrix_t pat_to_ps;
3694 cairo_circle_double_t start, end;
3696 cairo_status_t status;
3698 assert (pattern->n_stops != 0);
3700 status = _cairo_ps_surface_emit_pattern_stops (surface, pattern);
3701 if (unlikely (status))
3704 pat_to_ps = pattern->base.matrix;
3705 status = cairo_matrix_invert (&pat_to_ps);
3706 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3707 assert (status == CAIRO_STATUS_SUCCESS);
3708 cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
3710 if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
3711 pattern->base.extend == CAIRO_EXTEND_REFLECT)
3713 double bounds_x1, bounds_x2, bounds_y1, bounds_y2;
3714 double x_scale, y_scale, tolerance;
3716 /* TODO: use tighter extents */
3719 bounds_x2 = surface->width;
3720 bounds_y2 = surface->height;
3721 _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
3722 &bounds_x1, &bounds_y1,
3723 &bounds_x2, &bounds_y2,
3726 x_scale = surface->base.x_resolution / surface->base.x_fallback_resolution;
3727 y_scale = surface->base.y_resolution / surface->base.y_fallback_resolution;
3729 tolerance = fabs (_cairo_matrix_compute_determinant (&pattern->base.matrix));
3730 tolerance /= _cairo_matrix_transformed_circle_major_axis (&pattern->base.matrix, 1);
3731 tolerance *= MIN (x_scale, y_scale);
3733 _cairo_gradient_pattern_box_to_parameter (pattern,
3734 bounds_x1, bounds_y1,
3735 bounds_x2, bounds_y2,
3737 } else if (pattern->stops[0].offset == pattern->stops[pattern->n_stops - 1].offset) {
3739 * If the first and the last stop offset are the same, then
3740 * the color function is a step function.
3741 * _cairo_ps_surface_emit_pattern_stops emits it as a stitched
3742 * function no matter how many stops the pattern has. The
3743 * domain of the stitched function will be [0 1] in this case.
3745 * This is done to avoid emitting degenerate gradients for
3746 * EXTEND_PAD patterns having a step color function.
3751 assert (pattern->base.extend == CAIRO_EXTEND_PAD);
3753 domain[0] = pattern->stops[0].offset;
3754 domain[1] = pattern->stops[pattern->n_stops - 1].offset;
3757 /* PS requires the first and last stop to be the same as the
3758 * extreme coordinates. For repeating patterns this moves the
3759 * extreme coordinates out to the begin/end of the repeating
3760 * function. For non repeating patterns this may move the extreme
3761 * coordinates in if there are not stops at offset 0 and 1. */
3762 _cairo_gradient_pattern_interpolate (pattern, domain[0], &start);
3763 _cairo_gradient_pattern_interpolate (pattern, domain[1], &end);
3765 if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
3766 pattern->base.extend == CAIRO_EXTEND_REFLECT)
3768 int repeat_begin, repeat_end;
3770 repeat_begin = floor (domain[0]);
3771 repeat_end = ceil (domain[1]);
3773 status = _cairo_ps_surface_emit_repeating_function (surface,
3777 if (unlikely (status))
3779 } else if (pattern->n_stops <= 2) {
3780 /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a
3781 * Type 2 function is used by itself without a stitching
3782 * function. Type 2 functions always have the domain [0 1] */
3787 if (is_ps_pattern) {
3788 _cairo_output_stream_printf (surface->stream,
3789 "<< /PatternType 2\n"
3793 if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
3794 _cairo_output_stream_printf (surface->stream,
3795 " << /ShadingType 2\n"
3796 " /ColorSpace /DeviceRGB\n"
3797 " /Coords [ %f %f %f %f ]\n",
3798 start.center.x, start.center.y,
3799 end.center.x, end.center.y);
3801 _cairo_output_stream_printf (surface->stream,
3802 " << /ShadingType 3\n"
3803 " /ColorSpace /DeviceRGB\n"
3804 " /Coords [ %f %f %f %f %f %f ]\n",
3805 start.center.x, start.center.y,
3806 MAX (start.radius, 0),
3807 end.center.x, end.center.y,
3808 MAX (end.radius, 0));
3811 if (pattern->base.extend != CAIRO_EXTEND_NONE) {
3812 _cairo_output_stream_printf (surface->stream,
3813 " /Extend [ true true ]\n");
3815 _cairo_output_stream_printf (surface->stream,
3816 " /Extend [ false false ]\n");
3819 if (domain[0] == 0.0 && domain[1] == 1.0) {
3820 _cairo_output_stream_printf (surface->stream,
3821 " /Function CairoFunction\n");
3823 _cairo_output_stream_printf (surface->stream,
3825 " /FunctionType 3\n"
3826 " /Domain [ 0 1 ]\n"
3828 " /Encode [ %f %f ]\n"
3829 " /Functions [ CairoFunction ]\n"
3831 domain[0], domain[1]);
3834 _cairo_output_stream_printf (surface->stream,
3837 if (is_ps_pattern) {
3838 _cairo_output_stream_printf (surface->stream,
3840 "[ %f %f %f %f %f %f ]\n"
3841 "makepattern setpattern\n",
3842 pat_to_ps.xx, pat_to_ps.yx,
3843 pat_to_ps.xy, pat_to_ps.yy,
3844 pat_to_ps.x0, pat_to_ps.y0);
3846 _cairo_output_stream_printf (surface->stream,
3853 static cairo_status_t
3854 _cairo_ps_surface_emit_mesh_pattern (cairo_ps_surface_t *surface,
3855 cairo_mesh_pattern_t *pattern,
3856 cairo_bool_t is_ps_pattern)
3858 cairo_matrix_t pat_to_ps;
3859 cairo_status_t status;
3860 cairo_pdf_shading_t shading;
3863 if (_cairo_array_num_elements (&pattern->patches) == 0)
3864 return CAIRO_INT_STATUS_NOTHING_TO_DO;
3866 pat_to_ps = pattern->base.matrix;
3867 status = cairo_matrix_invert (&pat_to_ps);
3868 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3869 assert (status == CAIRO_STATUS_SUCCESS);
3871 cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
3873 status = _cairo_pdf_shading_init_color (&shading, pattern);
3874 if (unlikely (status))
3877 _cairo_output_stream_printf (surface->stream,
3879 "/ASCII85Decode filter /FlateDecode filter /ReusableStreamDecode filter\n");
3881 status = _cairo_ps_surface_emit_base85_string (surface,
3883 shading.data_length,
3884 CAIRO_PS_COMPRESS_DEFLATE,
3889 _cairo_output_stream_printf (surface->stream,
3891 "/CairoData exch def\n");
3893 if (is_ps_pattern) {
3894 _cairo_output_stream_printf (surface->stream,
3895 "<< /PatternType 2\n"
3899 _cairo_output_stream_printf (surface->stream,
3900 " << /ShadingType %d\n"
3901 " /ColorSpace /DeviceRGB\n"
3902 " /DataSource CairoData\n"
3903 " /BitsPerCoordinate %d\n"
3904 " /BitsPerComponent %d\n"
3905 " /BitsPerFlag %d\n"
3907 shading.shading_type,
3908 shading.bits_per_coordinate,
3909 shading.bits_per_component,
3910 shading.bits_per_flag);
3912 for (i = 0; i < shading.decode_array_length; i++)
3913 _cairo_output_stream_printf (surface->stream, "%f ", shading.decode_array[i]);
3915 _cairo_output_stream_printf (surface->stream,
3919 if (is_ps_pattern) {
3920 _cairo_output_stream_printf (surface->stream,
3922 "[ %f %f %f %f %f %f ]\n",
3923 pat_to_ps.xx, pat_to_ps.yx,
3924 pat_to_ps.xy, pat_to_ps.yy,
3925 pat_to_ps.x0, pat_to_ps.y0);
3926 _cairo_output_stream_printf (surface->stream,
3930 _cairo_output_stream_printf (surface->stream, "shfill\n");
3933 _cairo_output_stream_printf (surface->stream,
3934 "currentdict /CairoData undef\n");
3936 _cairo_pdf_shading_fini (&shading);
3941 static cairo_status_t
3942 _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
3943 const cairo_pattern_t *pattern,
3944 cairo_rectangle_int_t *extents,
3945 cairo_operator_t op)
3947 cairo_status_t status;
3949 if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
3950 cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
3952 if (surface->current_pattern_is_solid_color == FALSE ||
3953 ! _cairo_color_equal (&surface->current_color, &solid->color))
3955 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3956 if (unlikely (status))
3959 _cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
3961 surface->current_pattern_is_solid_color = TRUE;
3962 surface->current_color = solid->color;
3965 return CAIRO_STATUS_SUCCESS;
3968 surface->current_pattern_is_solid_color = FALSE;
3969 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3970 if (unlikely (status))
3973 switch (pattern->type) {
3974 case CAIRO_PATTERN_TYPE_SOLID:
3976 _cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
3979 case CAIRO_PATTERN_TYPE_SURFACE:
3980 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
3981 status = _cairo_ps_surface_emit_surface_pattern (surface,
3982 (cairo_pattern_t *)pattern,
3985 if (unlikely (status))
3989 case CAIRO_PATTERN_TYPE_LINEAR:
3990 case CAIRO_PATTERN_TYPE_RADIAL:
3991 status = _cairo_ps_surface_emit_gradient (surface,
3992 (cairo_gradient_pattern_t *) pattern,
3994 if (unlikely (status))
3998 case CAIRO_PATTERN_TYPE_MESH:
3999 status = _cairo_ps_surface_emit_mesh_pattern (surface,
4000 (cairo_mesh_pattern_t *) pattern,
4002 if (unlikely (status))
4007 return CAIRO_STATUS_SUCCESS;
4010 static cairo_status_t
4011 _cairo_ps_surface_paint_gradient (cairo_ps_surface_t *surface,
4012 const cairo_pattern_t *source,
4013 const cairo_rectangle_int_t *extents)
4015 cairo_matrix_t pat_to_ps;
4016 cairo_status_t status;
4018 pat_to_ps = source->matrix;
4019 status = cairo_matrix_invert (&pat_to_ps);
4020 /* cairo_pattern_set_matrix ensures the matrix is invertible */
4021 assert (status == CAIRO_STATUS_SUCCESS);
4022 cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
4024 if (! _cairo_matrix_is_identity (&pat_to_ps)) {
4025 _cairo_output_stream_printf (surface->stream,
4026 "[%f %f %f %f %f %f] concat\n",
4027 pat_to_ps.xx, pat_to_ps.yx,
4028 pat_to_ps.xy, pat_to_ps.yy,
4029 pat_to_ps.x0, pat_to_ps.y0);
4032 if (source->type == CAIRO_PATTERN_TYPE_MESH) {
4033 status = _cairo_ps_surface_emit_mesh_pattern (surface,
4034 (cairo_mesh_pattern_t *)source,
4036 if (unlikely (status))
4039 status = _cairo_ps_surface_emit_gradient (surface,
4040 (cairo_gradient_pattern_t *)source,
4042 if (unlikely (status))
4049 static cairo_status_t
4050 _cairo_ps_surface_paint_pattern (cairo_ps_surface_t *surface,
4051 const cairo_pattern_t *source,
4052 cairo_rectangle_int_t *extents,
4053 cairo_operator_t op,
4054 cairo_bool_t stencil_mask)
4056 switch (source->type) {
4057 case CAIRO_PATTERN_TYPE_SURFACE:
4058 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
4059 return _cairo_ps_surface_paint_surface (surface,
4060 (cairo_pattern_t *)source,
4065 case CAIRO_PATTERN_TYPE_LINEAR:
4066 case CAIRO_PATTERN_TYPE_RADIAL:
4067 case CAIRO_PATTERN_TYPE_MESH:
4068 return _cairo_ps_surface_paint_gradient (surface,
4072 case CAIRO_PATTERN_TYPE_SOLID:
4075 return CAIRO_STATUS_SUCCESS;
4080 _can_paint_pattern (const cairo_pattern_t *pattern)
4082 switch (pattern->type) {
4083 case CAIRO_PATTERN_TYPE_SOLID:
4086 case CAIRO_PATTERN_TYPE_SURFACE:
4087 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
4088 return (pattern->extend == CAIRO_EXTEND_NONE ||
4089 pattern->extend == CAIRO_EXTEND_PAD);
4091 case CAIRO_PATTERN_TYPE_LINEAR:
4092 case CAIRO_PATTERN_TYPE_RADIAL:
4093 case CAIRO_PATTERN_TYPE_MESH:
4103 _cairo_ps_surface_get_extents (void *abstract_surface,
4104 cairo_rectangle_int_t *rectangle)
4106 cairo_ps_surface_t *surface = abstract_surface;
4111 /* XXX: The conversion to integers here is pretty bogus, (not to
4112 * mention the aribitray limitation of width to a short(!). We
4113 * may need to come up with a better interface for get_extents.
4115 rectangle->width = ceil (surface->width);
4116 rectangle->height = ceil (surface->height);
4122 _cairo_ps_surface_get_font_options (void *abstract_surface,
4123 cairo_font_options_t *options)
4125 _cairo_font_options_init_default (options);
4127 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
4128 cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
4129 cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
4130 _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_OFF);
4133 static cairo_int_status_t
4134 _cairo_ps_surface_set_clip (cairo_ps_surface_t *surface,
4135 cairo_composite_rectangles_t *composite)
4137 cairo_clip_t *clip = composite->clip;
4139 if (_cairo_composite_rectangles_can_reduce_clip (composite, clip))
4143 if (_cairo_composite_rectangles_can_reduce_clip (composite,
4144 surface->clipper.clip))
4145 return CAIRO_STATUS_SUCCESS;
4148 return _cairo_surface_clipper_set_clip (&surface->clipper, clip);
4151 static cairo_int_status_t
4152 _cairo_ps_surface_paint (void *abstract_surface,
4153 cairo_operator_t op,
4154 const cairo_pattern_t *source,
4155 const cairo_clip_t *clip)
4157 cairo_ps_surface_t *surface = abstract_surface;
4158 cairo_output_stream_t *stream = surface->stream;
4159 cairo_composite_rectangles_t extents;
4160 cairo_status_t status;
4162 status = _cairo_composite_rectangles_init_for_paint (&extents,
4165 if (unlikely (status))
4168 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4169 status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
4170 goto cleanup_composite;
4173 assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
4176 _cairo_output_stream_printf (stream,
4177 "%% _cairo_ps_surface_paint\n");
4180 status = _cairo_ps_surface_set_clip (surface, &extents);
4181 if (unlikely (status))
4182 goto cleanup_composite;
4184 if (_can_paint_pattern (source)) {
4185 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4186 if (unlikely (status))
4187 goto cleanup_composite;
4189 _cairo_output_stream_printf (stream, "q\n");
4190 status = _cairo_ps_surface_paint_pattern (surface,
4192 &extents.bounded, op, FALSE);
4193 if (unlikely (status))
4194 goto cleanup_composite;
4196 _cairo_output_stream_printf (stream, "Q\n");
4198 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4199 if (unlikely (status))
4200 goto cleanup_composite;
4202 _cairo_output_stream_printf (stream, "0 0 %f %f rectfill\n",
4203 surface->width, surface->height);
4207 _cairo_composite_rectangles_fini (&extents);
4211 static cairo_int_status_t
4212 _cairo_ps_surface_mask (void *abstract_surface,
4213 cairo_operator_t op,
4214 const cairo_pattern_t *source,
4215 const cairo_pattern_t *mask,
4216 const cairo_clip_t *clip)
4218 cairo_ps_surface_t *surface = abstract_surface;
4219 cairo_output_stream_t *stream = surface->stream;
4220 cairo_composite_rectangles_t extents;
4221 cairo_status_t status;
4223 status = _cairo_composite_rectangles_init_for_mask (&extents,
4225 op, source, mask, clip);
4226 if (unlikely (status))
4229 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4230 status = _cairo_ps_surface_analyze_operation (surface, op, source, mask, &extents.bounded);
4231 goto cleanup_composite;
4234 assert (_cairo_ps_surface_operation_supported (surface, op, source, mask, &extents.bounded));
4237 _cairo_output_stream_printf (stream,
4238 "%% _cairo_ps_surface_mask\n");
4241 status = _cairo_ps_surface_set_clip (surface, &extents);
4242 if (unlikely (status))
4243 goto cleanup_composite;
4245 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4246 if (unlikely (status))
4247 goto cleanup_composite;
4249 _cairo_output_stream_printf (stream, "q\n");
4250 status = _cairo_ps_surface_paint_pattern (surface,
4252 &extents.bounded, op, TRUE);
4253 if (unlikely (status))
4254 goto cleanup_composite;
4256 _cairo_output_stream_printf (stream, "Q\n");
4259 _cairo_composite_rectangles_fini (&extents);
4263 static cairo_int_status_t
4264 _cairo_ps_surface_stroke (void *abstract_surface,
4265 cairo_operator_t op,
4266 const cairo_pattern_t *source,
4267 const cairo_path_fixed_t *path,
4268 const cairo_stroke_style_t *style,
4269 const cairo_matrix_t *ctm,
4270 const cairo_matrix_t *ctm_inverse,
4272 cairo_antialias_t antialias,
4273 const cairo_clip_t *clip)
4275 cairo_ps_surface_t *surface = abstract_surface;
4276 cairo_composite_rectangles_t extents;
4277 cairo_int_status_t status;
4279 status = _cairo_composite_rectangles_init_for_stroke (&extents,
4284 if (unlikely (status))
4287 /* use the more accurate extents */
4289 cairo_rectangle_int_t r;
4292 status = _cairo_path_fixed_stroke_extents (path, style,
4296 if (unlikely (status))
4297 goto cleanup_composite;
4299 _cairo_box_from_rectangle (&b, &r);
4300 status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b);
4301 if (unlikely (status))
4302 goto cleanup_composite;
4305 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4306 status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
4307 goto cleanup_composite;
4310 assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
4313 _cairo_output_stream_printf (surface->stream,
4314 "%% _cairo_ps_surface_stroke\n");
4317 status = _cairo_ps_surface_set_clip (surface, &extents);
4318 if (unlikely (status))
4319 goto cleanup_composite;
4321 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4322 if (unlikely (status))
4323 goto cleanup_composite;
4325 status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
4332 _cairo_composite_rectangles_fini (&extents);
4336 static cairo_int_status_t
4337 _cairo_ps_surface_fill (void *abstract_surface,
4338 cairo_operator_t op,
4339 const cairo_pattern_t *source,
4340 const cairo_path_fixed_t*path,
4341 cairo_fill_rule_t fill_rule,
4343 cairo_antialias_t antialias,
4344 const cairo_clip_t *clip)
4346 cairo_ps_surface_t *surface = abstract_surface;
4347 cairo_composite_rectangles_t extents;
4348 cairo_int_status_t status;
4350 status = _cairo_composite_rectangles_init_for_fill (&extents,
4354 if (unlikely (status))
4357 /* use the more accurate extents */
4359 cairo_rectangle_int_t r;
4362 _cairo_path_fixed_fill_extents (path,
4367 _cairo_box_from_rectangle (&b, &r);
4368 status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b);
4369 if (unlikely (status))
4370 goto cleanup_composite;
4373 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4374 status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
4375 goto cleanup_composite;
4378 assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
4381 _cairo_output_stream_printf (surface->stream,
4382 "%% _cairo_ps_surface_fill\n");
4385 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4386 if (unlikely (status))
4387 goto cleanup_composite;
4389 status = _cairo_ps_surface_set_clip (surface, &extents);
4390 if (unlikely (status))
4391 goto cleanup_composite;
4393 if (_can_paint_pattern (source)) {
4394 _cairo_output_stream_printf (surface->stream, "q\n");
4396 status = _cairo_pdf_operators_clip (&surface->pdf_operators,
4399 if (unlikely (status))
4400 goto cleanup_composite;
4402 status = _cairo_ps_surface_paint_pattern (surface,
4404 &extents.bounded, op, FALSE);
4405 if (unlikely (status))
4406 goto cleanup_composite;
4408 _cairo_output_stream_printf (surface->stream, "Q\n");
4409 _cairo_pdf_operators_reset (&surface->pdf_operators);
4411 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4412 if (unlikely (status))
4413 goto cleanup_composite;
4415 status = _cairo_pdf_operators_fill (&surface->pdf_operators,
4421 _cairo_composite_rectangles_fini (&extents);
4426 _cairo_ps_surface_has_show_text_glyphs (void *abstract_surface)
4431 static cairo_int_status_t
4432 _cairo_ps_surface_show_text_glyphs (void *abstract_surface,
4433 cairo_operator_t op,
4434 const cairo_pattern_t *source,
4437 cairo_glyph_t *glyphs,
4439 const cairo_text_cluster_t *clusters,
4441 cairo_text_cluster_flags_t cluster_flags,
4442 cairo_scaled_font_t *scaled_font,
4443 const cairo_clip_t *clip)
4445 cairo_ps_surface_t *surface = abstract_surface;
4446 cairo_composite_rectangles_t extents;
4447 cairo_bool_t overlap;
4448 cairo_status_t status;
4450 status = _cairo_composite_rectangles_init_for_glyphs (&extents,
4457 if (unlikely (status))
4460 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4461 status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
4462 goto cleanup_composite;
4465 assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
4468 _cairo_output_stream_printf (surface->stream,
4469 "%% _cairo_ps_surface_show_glyphs\n");
4472 status = _cairo_ps_surface_set_clip (surface, &extents);
4473 if (unlikely (status))
4474 goto cleanup_composite;
4476 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4477 if (unlikely (status))
4478 goto cleanup_composite;
4480 status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
4483 clusters, num_clusters,
4488 _cairo_composite_rectangles_fini (&extents);
4492 static const char **
4493 _cairo_ps_surface_get_supported_mime_types (void *abstract_surface)
4495 return _cairo_ps_supported_mime_types;
4499 _cairo_ps_surface_set_paginated_mode (void *abstract_surface,
4500 cairo_paginated_mode_t paginated_mode)
4502 cairo_ps_surface_t *surface = abstract_surface;
4503 cairo_status_t status;
4505 surface->paginated_mode = paginated_mode;
4507 if (surface->clipper.clip != NULL) {
4508 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4510 _cairo_output_stream_printf (surface->stream, "Q q\n");
4511 _cairo_surface_clipper_reset (&surface->clipper);
4515 static cairo_int_status_t
4516 _cairo_ps_surface_set_bounding_box (void *abstract_surface,
4519 cairo_ps_surface_t *surface = abstract_surface;
4520 int i, num_comments;
4523 cairo_bool_t has_page_media, has_page_bbox;
4524 const char *page_media;
4526 x1 = floor (_cairo_fixed_to_double (bbox->p1.x));
4527 y1 = floor (surface->height - _cairo_fixed_to_double (bbox->p2.y));
4528 x2 = ceil (_cairo_fixed_to_double (bbox->p2.x));
4529 y2 = ceil (surface->height - _cairo_fixed_to_double (bbox->p1.y));
4531 surface->page_bbox.x = x1;
4532 surface->page_bbox.y = y1;
4533 surface->page_bbox.width = x2 - x1;
4534 surface->page_bbox.height = y2 - y1;
4536 _cairo_output_stream_printf (surface->stream,
4537 "%%%%Page: %d %d\n",
4539 surface->num_pages);
4541 _cairo_output_stream_printf (surface->stream,
4542 "%%%%BeginPageSetup\n");
4544 has_page_media = FALSE;
4545 has_page_bbox = FALSE;
4546 num_comments = _cairo_array_num_elements (&surface->dsc_page_setup_comments);
4547 comments = _cairo_array_index (&surface->dsc_page_setup_comments, 0);
4548 if (comments == NULL)
4549 return CAIRO_STATUS_NULL_POINTER;
4551 for (i = 0; i < num_comments; i++) {
4552 _cairo_output_stream_printf (surface->stream,
4553 "%s\n", comments[i]);
4554 if (strncmp (comments[i], "%%PageMedia:", 11) == 0)
4555 has_page_media = TRUE;
4557 if (strncmp (comments[i], "%%PageBoundingBox:", 18) == 0)
4558 has_page_bbox = TRUE;
4563 _cairo_array_truncate (&surface->dsc_page_setup_comments, 0);
4565 if (!has_page_media && !surface->eps) {
4566 page_media = _cairo_ps_surface_get_page_media (surface);
4567 if (unlikely (page_media == NULL))
4568 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4570 _cairo_output_stream_printf (surface->stream,
4571 "%%%%PageMedia: %s\n",
4575 if (!has_page_bbox) {
4576 _cairo_output_stream_printf (surface->stream,
4577 "%%%%PageBoundingBox: %d %d %d %d\n",
4581 _cairo_output_stream_printf (surface->stream,
4582 "%%%%EndPageSetup\n"
4583 "q %d %d %d %d rectclip q\n",
4584 surface->page_bbox.x,
4585 surface->page_bbox.y,
4586 surface->page_bbox.width,
4587 surface->page_bbox.height);
4589 if (surface->num_pages == 1) {
4590 surface->bbox_x1 = x1;
4591 surface->bbox_y1 = y1;
4592 surface->bbox_x2 = x2;
4593 surface->bbox_y2 = y2;
4595 if (x1 < surface->bbox_x1)
4596 surface->bbox_x1 = x1;
4597 if (y1 < surface->bbox_y1)
4598 surface->bbox_y1 = y1;
4599 if (x2 > surface->bbox_x2)
4600 surface->bbox_x2 = x2;
4601 if (y2 > surface->bbox_y2)
4602 surface->bbox_y2 = y2;
4604 surface->current_pattern_is_solid_color = FALSE;
4605 _cairo_pdf_operators_reset (&surface->pdf_operators);
4607 return _cairo_output_stream_get_status (surface->stream);
4611 _cairo_ps_surface_supports_fine_grained_fallbacks (void *abstract_surface)
4616 static const cairo_surface_backend_t cairo_ps_surface_backend = {
4617 CAIRO_SURFACE_TYPE_PS,
4618 _cairo_ps_surface_finish,
4620 _cairo_default_context_create,
4622 NULL, /* create similar: handled by wrapper */
4623 NULL, /* create similar image */
4624 NULL, /* map to image */
4625 NULL, /* unmap image */
4627 _cairo_surface_default_source,
4628 NULL, /* acquire_source_image */
4629 NULL, /* release_source_image */
4630 NULL, /* snapshot */
4632 NULL, /* cairo_ps_surface_copy_page */
4633 _cairo_ps_surface_show_page,
4635 _cairo_ps_surface_get_extents,
4636 _cairo_ps_surface_get_font_options,
4639 NULL, /* mark_dirty_rectangle */
4641 /* Here are the drawing functions */
4643 _cairo_ps_surface_paint, /* paint */
4644 _cairo_ps_surface_mask,
4645 _cairo_ps_surface_stroke,
4646 _cairo_ps_surface_fill,
4647 NULL, /* fill-stroke */
4648 NULL, /* show_glyphs */
4649 _cairo_ps_surface_has_show_text_glyphs,
4650 _cairo_ps_surface_show_text_glyphs,
4651 _cairo_ps_surface_get_supported_mime_types,
4654 static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend = {
4655 _cairo_ps_surface_start_page,
4656 _cairo_ps_surface_set_paginated_mode,
4657 _cairo_ps_surface_set_bounding_box,
4658 NULL, /* _cairo_ps_surface_has_fallback_images, */
4659 _cairo_ps_surface_supports_fine_grained_fallbacks,