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 for (i = 0; i < num_comments; i++) {
250 _cairo_output_stream_printf (surface->final_stream,
251 "%s\n", comments[i]);
252 if (strncmp (comments[i], "%%BoundingBox:", 14) == 0)
260 _cairo_output_stream_printf (surface->final_stream,
261 "%%%%BoundingBox: %d %d %d %d\n",
268 _cairo_output_stream_printf (surface->final_stream,
269 "%%%%EndComments\n");
271 _cairo_output_stream_printf (surface->final_stream,
272 "%%%%BeginProlog\n");
275 _cairo_output_stream_printf (surface->final_stream,
279 _cairo_output_stream_printf (surface->final_stream,
280 "/languagelevel where\n"
281 "{ pop languagelevel } { 1 } ifelse\n"
282 "%d lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto\n"
283 " (This print job requires a PostScript Language Level %d printer.) show\n"
284 " showpage quit } if\n",
289 _cairo_output_stream_printf (surface->final_stream,
290 "/q { gsave } bind def\n"
291 "/Q { grestore } bind def\n"
292 "/cm { 6 array astore concat } bind def\n"
293 "/w { setlinewidth } bind def\n"
294 "/J { setlinecap } bind def\n"
295 "/j { setlinejoin } bind def\n"
296 "/M { setmiterlimit } bind def\n"
297 "/d { setdash } bind def\n"
298 "/m { moveto } bind def\n"
299 "/l { lineto } bind def\n"
300 "/c { curveto } bind def\n"
301 "/h { closepath } bind def\n"
302 "/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto\n"
303 " 0 exch rlineto 0 rlineto closepath } bind def\n"
304 "/S { stroke } bind def\n"
305 "/f { fill } bind def\n"
306 "/f* { eofill } bind def\n"
307 "/n { newpath } bind def\n"
308 "/W { clip } bind def\n"
309 "/W* { eoclip } bind def\n"
312 "/pdfmark where { pop globaldict /?pdfmark /exec load put }\n"
313 " { globaldict begin /?pdfmark /pop load def /pdfmark\n"
314 " /cleartomark load def end } ifelse\n"
315 "/BDC { mark 3 1 roll /BDC pdfmark } bind def\n"
316 "/EMC { mark /EMC pdfmark } bind def\n"
317 "/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def\n"
318 "/Tj { show currentpoint cairo_store_point } bind def\n"
322 " type /stringtype eq\n"
323 " { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse\n"
325 " currentpoint cairo_store_point\n"
327 "/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore\n"
328 " cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def\n"
329 "/Tf { pop /cairo_font exch def /cairo_font_matrix where\n"
330 " { pop cairo_selectfont } if } bind def\n"
331 "/Td { matrix translate cairo_font_matrix matrix concatmatrix dup\n"
332 " /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point\n"
333 " /cairo_font where { pop cairo_selectfont } if } bind def\n"
334 "/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def\n"
335 " cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def\n"
336 "/g { setgray } bind def\n"
337 "/rg { setrgbcolor } bind def\n"
338 "/d1 { setcachedevice } bind def\n");
340 _cairo_output_stream_printf (surface->final_stream,
343 num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
345 _cairo_output_stream_printf (surface->final_stream,
348 comments = _cairo_array_index (&surface->dsc_setup_comments, 0);
349 for (i = 0; i < num_comments; i++) {
350 _cairo_output_stream_printf (surface->final_stream,
351 "%s\n", comments[i]);
356 _cairo_output_stream_printf (surface->final_stream,
361 static cairo_status_t
362 _cairo_ps_surface_emit_type1_font_subset (cairo_ps_surface_t *surface,
363 cairo_scaled_font_subset_t *font_subset)
367 cairo_type1_subset_t subset;
368 cairo_status_t status;
372 snprintf (name, sizeof name, "f-%d-%d",
373 font_subset->font_id, font_subset->subset_id);
374 status = _cairo_type1_subset_init (&subset, name, font_subset, TRUE);
375 if (unlikely (status))
378 /* FIXME: Figure out document structure convention for fonts */
381 _cairo_output_stream_printf (surface->final_stream,
382 "%% _cairo_ps_surface_emit_type1_font_subset\n");
385 length = subset.header_length + subset.data_length + subset.trailer_length;
386 _cairo_output_stream_write (surface->final_stream, subset.data, length);
388 _cairo_type1_subset_fini (&subset);
390 return CAIRO_STATUS_SUCCESS;
394 static cairo_status_t
395 _cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t *surface,
396 cairo_scaled_font_subset_t *font_subset)
398 cairo_type1_subset_t subset;
399 cairo_status_t status;
403 snprintf (name, sizeof name, "f-%d-%d",
404 font_subset->font_id, font_subset->subset_id);
405 status = _cairo_type1_fallback_init_hex (&subset, name, font_subset);
406 if (unlikely (status))
409 /* FIXME: Figure out document structure convention for fonts */
412 _cairo_output_stream_printf (surface->final_stream,
413 "%% _cairo_ps_surface_emit_type1_font_fallback\n");
416 length = subset.header_length + subset.data_length + subset.trailer_length;
417 _cairo_output_stream_write (surface->final_stream, subset.data, length);
419 _cairo_type1_fallback_fini (&subset);
421 return CAIRO_STATUS_SUCCESS;
424 static cairo_status_t
425 _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface,
426 cairo_scaled_font_subset_t *font_subset)
430 cairo_truetype_subset_t subset;
431 cairo_status_t status;
432 unsigned int i, begin, end;
434 status = _cairo_truetype_subset_init_ps (&subset, font_subset);
435 if (unlikely (status))
438 /* FIXME: Figure out document structure convention for fonts */
441 _cairo_output_stream_printf (surface->final_stream,
442 "%% _cairo_ps_surface_emit_truetype_font_subset\n");
445 _cairo_output_stream_printf (surface->final_stream,
448 "/FontName /%s def\n"
450 "/FontMatrix [ 1 0 0 1 0 0 ] def\n"
451 "/FontBBox [ 0 0 0 0 ] def\n"
452 "/Encoding 256 array def\n"
453 "0 1 255 { Encoding exch /.notdef put } for\n",
456 /* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */
458 if (font_subset->is_latin) {
459 for (i = 1; i < 256; i++) {
460 if (font_subset->latin_to_subset_glyph_index[i] > 0) {
461 if (font_subset->glyph_names != NULL) {
462 _cairo_output_stream_printf (surface->final_stream,
463 "Encoding %d /%s put\n",
464 i, font_subset->glyph_names[font_subset->latin_to_subset_glyph_index[i]]);
466 _cairo_output_stream_printf (surface->final_stream,
467 "Encoding %d /g%ld put\n", i, font_subset->latin_to_subset_glyph_index[i]);
472 for (i = 1; i < font_subset->num_glyphs; i++) {
473 if (font_subset->glyph_names != NULL) {
474 _cairo_output_stream_printf (surface->final_stream,
475 "Encoding %d /%s put\n",
476 i, font_subset->glyph_names[i]);
478 _cairo_output_stream_printf (surface->final_stream,
479 "Encoding %d /g%d put\n", i, i);
484 _cairo_output_stream_printf (surface->final_stream,
485 "/CharStrings %d dict dup begin\n"
487 font_subset->num_glyphs);
489 for (i = 1; i < font_subset->num_glyphs; i++) {
490 if (font_subset->glyph_names != NULL) {
491 _cairo_output_stream_printf (surface->final_stream,
493 font_subset->glyph_names[i], i);
495 _cairo_output_stream_printf (surface->final_stream,
496 "/g%d %d def\n", i, i);
500 _cairo_output_stream_printf (surface->final_stream,
501 "end readonly def\n");
503 _cairo_output_stream_printf (surface->final_stream,
507 for (i = 0; i < subset.num_string_offsets; i++) {
508 end = subset.string_offsets[i];
509 _cairo_output_stream_printf (surface->final_stream,"<");
510 _cairo_output_stream_write_hex_string (surface->final_stream,
511 subset.data + begin, end - begin);
512 _cairo_output_stream_printf (surface->final_stream,"00>\n");
515 if (subset.data_length > end) {
516 _cairo_output_stream_printf (surface->final_stream,"<");
517 _cairo_output_stream_write_hex_string (surface->final_stream,
518 subset.data + end, subset.data_length - end);
519 _cairo_output_stream_printf (surface->final_stream,"00>\n");
522 _cairo_output_stream_printf (surface->final_stream,
524 "/f-%d-%d currentdict end definefont pop\n",
525 font_subset->font_id,
526 font_subset->subset_id);
528 _cairo_truetype_subset_fini (&subset);
530 return CAIRO_STATUS_SUCCESS;
533 static cairo_status_t
534 _cairo_ps_emit_imagemask (cairo_image_surface_t *image,
535 cairo_output_stream_t *stream)
540 /* The only image type supported by Type 3 fonts are 1-bit image
542 assert (image->format == CAIRO_FORMAT_A1);
544 _cairo_output_stream_printf (stream,
549 " /ImageMatrix [%d 0 0 %d 0 %d]\n"
551 " /BitsPerComponent 1\n",
558 _cairo_output_stream_printf (stream,
559 " /DataSource {<\n ");
560 for (row = image->data, rows = image->height; rows; row += image->stride, rows--) {
561 for (byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) {
562 uint8_t output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
563 _cairo_output_stream_printf (stream, "%02x ", output_byte);
565 _cairo_output_stream_printf (stream, "\n ");
567 _cairo_output_stream_printf (stream, ">}\n>>\n");
569 _cairo_output_stream_printf (stream,
572 return _cairo_output_stream_get_status (stream);
575 static cairo_int_status_t
576 _cairo_ps_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset,
579 cairo_ps_surface_t *surface = closure;
580 cairo_status_t status = CAIRO_STATUS_SUCCESS;
582 cairo_surface_t *type3_surface;
584 type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
586 _cairo_ps_emit_imagemask,
587 surface->font_subsets);
589 for (i = 0; i < font_subset->num_glyphs; i++) {
590 status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
591 font_subset->glyphs[i]);
592 if (unlikely (status))
596 cairo_surface_finish (type3_surface);
597 cairo_surface_destroy (type3_surface);
602 static cairo_status_t
603 _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
604 cairo_scaled_font_subset_t *font_subset)
608 cairo_status_t status;
610 cairo_box_t font_bbox = {{0,0},{0,0}};
611 cairo_box_t bbox = {{0,0},{0,0}};
612 cairo_surface_t *type3_surface;
615 if (font_subset->num_glyphs == 0)
616 return CAIRO_STATUS_SUCCESS;
619 _cairo_output_stream_printf (surface->final_stream,
620 "%% _cairo_ps_surface_emit_type3_font_subset\n");
623 _cairo_output_stream_printf (surface->final_stream,
626 "/FontMatrix [1 0 0 1 0 0] def\n"
627 "/Encoding 256 array def\n"
628 "0 1 255 { Encoding exch /.notdef put } for\n");
630 type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
632 _cairo_ps_emit_imagemask,
633 surface->font_subsets);
634 status = type3_surface->status;
635 if (unlikely (status))
638 for (i = 0; i < font_subset->num_glyphs; i++) {
639 if (font_subset->glyph_names != NULL) {
640 _cairo_output_stream_printf (surface->final_stream,
641 "Encoding %d /%s put\n",
642 i, font_subset->glyph_names[i]);
644 _cairo_output_stream_printf (surface->final_stream,
645 "Encoding %d /g%d put\n", i, i);
649 _cairo_output_stream_printf (surface->final_stream,
652 for (i = 0; i < font_subset->num_glyphs; i++) {
653 _cairo_output_stream_printf (surface->final_stream,
655 status = _cairo_type3_glyph_surface_emit_glyph (type3_surface,
656 surface->final_stream,
657 font_subset->glyphs[i],
660 if (unlikely (status))
663 _cairo_output_stream_printf (surface->final_stream,
666 font_bbox.p1.x = bbox.p1.x;
667 font_bbox.p1.y = bbox.p1.y;
668 font_bbox.p2.x = bbox.p2.x;
669 font_bbox.p2.y = bbox.p2.y;
671 if (bbox.p1.x < font_bbox.p1.x)
672 font_bbox.p1.x = bbox.p1.x;
673 if (bbox.p1.y < font_bbox.p1.y)
674 font_bbox.p1.y = bbox.p1.y;
675 if (bbox.p2.x > font_bbox.p2.x)
676 font_bbox.p2.x = bbox.p2.x;
677 if (bbox.p2.y > font_bbox.p2.y)
678 font_bbox.p2.y = bbox.p2.y;
681 cairo_surface_finish (type3_surface);
682 cairo_surface_destroy (type3_surface);
683 if (unlikely (status))
686 _cairo_output_stream_printf (surface->final_stream,
688 "/FontBBox [%f %f %f %f] def\n"
690 " exch /Glyphs get\n"
692 " 10 dict begin exec end\n"
696 "/f-%d-%d exch definefont pop\n",
697 _cairo_fixed_to_double (font_bbox.p1.x),
698 - _cairo_fixed_to_double (font_bbox.p2.y),
699 _cairo_fixed_to_double (font_bbox.p2.x),
700 - _cairo_fixed_to_double (font_bbox.p1.y),
701 font_subset->font_id,
702 font_subset->subset_id);
704 return CAIRO_STATUS_SUCCESS;
707 static cairo_int_status_t
708 _cairo_ps_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset,
711 cairo_ps_surface_t *surface = closure;
712 cairo_int_status_t status;
714 status = _cairo_scaled_font_subset_create_glyph_names (font_subset);
715 if (_cairo_int_status_is_error (status))
718 status = _cairo_ps_surface_emit_type1_font_subset (surface, font_subset);
719 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
722 status = _cairo_ps_surface_emit_truetype_font_subset (surface, font_subset);
723 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
726 status = _cairo_ps_surface_emit_type1_font_fallback (surface, font_subset);
727 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
731 return CAIRO_STATUS_SUCCESS;
734 static cairo_int_status_t
735 _cairo_ps_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset,
738 cairo_ps_surface_t *surface = closure;
739 cairo_int_status_t status;
741 status = _cairo_scaled_font_subset_create_glyph_names (font_subset);
742 if (_cairo_int_status_is_error (status))
745 status = _cairo_ps_surface_emit_type3_font_subset (surface, font_subset);
746 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
750 return CAIRO_INT_STATUS_SUCCESS;
753 static cairo_status_t
754 _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface)
756 cairo_status_t status;
759 _cairo_output_stream_printf (surface->final_stream,
760 "%% _cairo_ps_surface_emit_font_subsets\n");
763 status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
764 _cairo_ps_surface_analyze_user_font_subset,
766 if (unlikely (status))
769 status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
770 _cairo_ps_surface_emit_unscaled_font_subset,
772 if (unlikely (status))
775 status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
776 _cairo_ps_surface_emit_scaled_font_subset,
778 if (unlikely (status))
781 return _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
782 _cairo_ps_surface_emit_scaled_font_subset,
786 static cairo_status_t
787 _cairo_ps_surface_emit_body (cairo_ps_surface_t *surface)
792 if (ferror (surface->tmpfile) != 0)
793 return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
795 rewind (surface->tmpfile);
796 while ((n = fread (buf, 1, sizeof (buf), surface->tmpfile)) > 0)
797 _cairo_output_stream_write (surface->final_stream, buf, n);
799 if (ferror (surface->tmpfile) != 0)
800 return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
802 return CAIRO_STATUS_SUCCESS;
806 _cairo_ps_surface_emit_footer (cairo_ps_surface_t *surface)
808 _cairo_output_stream_printf (surface->final_stream,
812 _cairo_output_stream_printf (surface->final_stream,
816 _cairo_output_stream_printf (surface->final_stream,
821 _path_covers_bbox (cairo_ps_surface_t *surface,
822 cairo_path_fixed_t *path)
826 if (_cairo_path_fixed_is_box (path, &box)) {
827 cairo_rectangle_int_t rect;
829 _cairo_box_round_to_rectangle (&box, &rect);
831 /* skip trivial whole-page clips */
832 if (_cairo_rectangle_intersect (&rect, &surface->page_bbox)) {
833 if (rect.x == surface->page_bbox.x &&
834 rect.width == surface->page_bbox.width &&
835 rect.y == surface->page_bbox.y &&
836 rect.height == surface->page_bbox.height)
846 static cairo_status_t
847 _cairo_ps_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
848 cairo_path_fixed_t *path,
849 cairo_fill_rule_t fill_rule,
851 cairo_antialias_t antialias)
853 cairo_ps_surface_t *surface = cairo_container_of (clipper,
856 cairo_output_stream_t *stream = surface->stream;
857 cairo_status_t status;
859 assert (surface->paginated_mode != CAIRO_PAGINATED_MODE_ANALYZE);
862 _cairo_output_stream_printf (stream,
863 "%% _cairo_ps_surface_intersect_clip_path\n");
867 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
868 if (unlikely (status))
871 _cairo_output_stream_printf (stream, "Q q\n");
873 surface->current_pattern_is_solid_color = FALSE;
874 _cairo_pdf_operators_reset (&surface->pdf_operators);
876 return CAIRO_STATUS_SUCCESS;
879 if (_path_covers_bbox (surface, path))
880 return CAIRO_STATUS_SUCCESS;
882 return _cairo_pdf_operators_clip (&surface->pdf_operators,
887 /* PLRM specifies a tolerance of 5 points when matching page sizes */
889 _ps_page_dimension_equal (int a, int b)
891 return (abs (a - b) < 5);
895 _cairo_ps_surface_get_page_media (cairo_ps_surface_t *surface)
897 int width, height, i;
899 cairo_page_media_t *page;
900 const char *page_name;
902 width = _cairo_lround (surface->width);
903 height = _cairo_lround (surface->height);
905 /* search previously used page sizes */
906 cairo_list_foreach_entry (page, cairo_page_media_t, &surface->document_media, link) {
907 if (_ps_page_dimension_equal (width, page->width) &&
908 _ps_page_dimension_equal (height, page->height))
912 /* search list of standard page sizes */
914 for (i = 0; i < ARRAY_LENGTH (_cairo_page_standard_media); i++) {
915 if (_ps_page_dimension_equal (width, _cairo_page_standard_media[i].width) &&
916 _ps_page_dimension_equal (height, _cairo_page_standard_media[i].height))
918 page_name = _cairo_page_standard_media[i].name;
919 width = _cairo_page_standard_media[i].width;
920 height = _cairo_page_standard_media[i].height;
925 page = malloc (sizeof (cairo_page_media_t));
926 if (unlikely (page == NULL)) {
927 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
932 page->name = strdup (page_name);
934 snprintf (buf, sizeof (buf), "%dx%dmm",
935 (int) _cairo_lround (surface->width * 25.4/72),
936 (int) _cairo_lround (surface->height * 25.4/72));
937 page->name = strdup (buf);
940 if (unlikely (page->name == NULL)) {
942 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
947 page->height = height;
948 cairo_list_add_tail (&page->link, &surface->document_media);
953 static cairo_surface_t *
954 _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
958 cairo_status_t status, status_ignored;
959 cairo_ps_surface_t *surface;
961 surface = malloc (sizeof (cairo_ps_surface_t));
962 if (unlikely (surface == NULL)) {
963 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
967 _cairo_surface_init (&surface->base,
968 &cairo_ps_surface_backend,
970 CAIRO_CONTENT_COLOR_ALPHA);
972 surface->final_stream = stream;
974 surface->tmpfile = tmpfile ();
975 if (surface->tmpfile == NULL) {
978 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
981 status = _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
984 goto CLEANUP_SURFACE;
987 surface->stream = _cairo_output_stream_create_for_file (surface->tmpfile);
988 status = _cairo_output_stream_get_status (surface->stream);
989 if (unlikely (status))
990 goto CLEANUP_OUTPUT_STREAM;
992 surface->font_subsets = _cairo_scaled_font_subsets_create_simple ();
993 if (unlikely (surface->font_subsets == NULL)) {
994 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
995 goto CLEANUP_OUTPUT_STREAM;
998 _cairo_scaled_font_subsets_enable_latin_subset (surface->font_subsets, TRUE);
999 surface->has_creation_date = FALSE;
1000 surface->eps = FALSE;
1001 surface->ps_level = CAIRO_PS_LEVEL_3;
1002 surface->ps_level_used = CAIRO_PS_LEVEL_2;
1003 surface->width = width;
1004 surface->height = height;
1005 cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, height);
1006 surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
1007 surface->force_fallbacks = FALSE;
1008 surface->content = CAIRO_CONTENT_COLOR_ALPHA;
1009 surface->use_string_datasource = FALSE;
1010 surface->current_pattern_is_solid_color = FALSE;
1012 surface->page_bbox.x = 0;
1013 surface->page_bbox.y = 0;
1014 surface->page_bbox.width = width;
1015 surface->page_bbox.height = height;
1017 _cairo_surface_clipper_init (&surface->clipper,
1018 _cairo_ps_surface_clipper_intersect_clip_path);
1020 _cairo_pdf_operators_init (&surface->pdf_operators,
1022 &surface->cairo_to_ps,
1023 surface->font_subsets);
1024 surface->num_pages = 0;
1026 cairo_list_init (&surface->document_media);
1027 _cairo_array_init (&surface->dsc_header_comments, sizeof (char *));
1028 _cairo_array_init (&surface->dsc_setup_comments, sizeof (char *));
1029 _cairo_array_init (&surface->dsc_page_setup_comments, sizeof (char *));
1031 surface->dsc_comment_target = &surface->dsc_header_comments;
1033 surface->paginated_surface = _cairo_paginated_surface_create (
1035 CAIRO_CONTENT_COLOR_ALPHA,
1036 &cairo_ps_surface_paginated_backend);
1037 status = surface->paginated_surface->status;
1038 if (status == CAIRO_STATUS_SUCCESS) {
1039 /* paginated keeps the only reference to surface now, drop ours */
1040 cairo_surface_destroy (&surface->base);
1041 return surface->paginated_surface;
1044 _cairo_scaled_font_subsets_destroy (surface->font_subsets);
1045 CLEANUP_OUTPUT_STREAM:
1046 status_ignored = _cairo_output_stream_destroy (surface->stream);
1047 fclose (surface->tmpfile);
1051 /* destroy stream on behalf of caller */
1052 status_ignored = _cairo_output_stream_destroy (stream);
1054 return _cairo_surface_create_in_error (status);
1058 * cairo_ps_surface_create:
1059 * @filename: a filename for the PS output (must be writable), %NULL may be
1060 * used to specify no output. This will generate a PS surface that
1061 * may be queried and used as a source, without generating a
1063 * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
1064 * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
1066 * Creates a PostScript surface of the specified size in points to be
1067 * written to @filename. See cairo_ps_surface_create_for_stream() for
1068 * a more flexible mechanism for handling the PostScript output than
1069 * simply writing it to a named file.
1071 * Note that the size of individual pages of the PostScript output can
1072 * vary. See cairo_ps_surface_set_size().
1074 * Return value: a pointer to the newly created surface. The caller
1075 * owns the surface and should call cairo_surface_destroy() when done
1078 * This function always returns a valid pointer, but it will return a
1079 * pointer to a "nil" surface if an error such as out of memory
1080 * occurs. You can use cairo_surface_status() to check for this.
1085 cairo_ps_surface_create (const char *filename,
1086 double width_in_points,
1087 double height_in_points)
1089 cairo_output_stream_t *stream;
1091 stream = _cairo_output_stream_create_for_filename (filename);
1092 if (_cairo_output_stream_get_status (stream))
1093 return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream));
1095 return _cairo_ps_surface_create_for_stream_internal (stream,
1101 * cairo_ps_surface_create_for_stream:
1102 * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL
1103 * to indicate a no-op @write_func. With a no-op @write_func,
1104 * the surface may be queried or used as a source without
1105 * generating any temporary files.
1106 * @closure: the closure argument for @write_func
1107 * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
1108 * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
1110 * Creates a PostScript surface of the specified size in points to be
1111 * written incrementally to the stream represented by @write_func and
1112 * @closure. See cairo_ps_surface_create() for a more convenient way
1113 * to simply direct the PostScript output to a named file.
1115 * Note that the size of individual pages of the PostScript
1116 * output can vary. See cairo_ps_surface_set_size().
1118 * Return value: a pointer to the newly created surface. The caller
1119 * owns the surface and should call cairo_surface_destroy() when done
1122 * This function always returns a valid pointer, but it will return a
1123 * pointer to a "nil" surface if an error such as out of memory
1124 * occurs. You can use cairo_surface_status() to check for this.
1129 cairo_ps_surface_create_for_stream (cairo_write_func_t write_func,
1131 double width_in_points,
1132 double height_in_points)
1134 cairo_output_stream_t *stream;
1136 stream = _cairo_output_stream_create (write_func, NULL, closure);
1137 if (_cairo_output_stream_get_status (stream))
1138 return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream));
1140 return _cairo_ps_surface_create_for_stream_internal (stream,
1146 _cairo_surface_is_ps (cairo_surface_t *surface)
1148 return surface->backend == &cairo_ps_surface_backend;
1151 /* If the abstract_surface is a paginated surface, and that paginated
1152 * surface's target is a ps_surface, then set ps_surface to that
1153 * target. Otherwise return FALSE.
1156 _extract_ps_surface (cairo_surface_t *surface,
1157 cairo_bool_t set_error_on_failure,
1158 cairo_ps_surface_t **ps_surface)
1160 cairo_surface_t *target;
1162 if (surface->status)
1164 if (surface->finished) {
1165 if (set_error_on_failure)
1166 _cairo_surface_set_error (surface,
1167 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
1171 if (! _cairo_surface_is_paginated (surface)) {
1172 if (set_error_on_failure)
1173 _cairo_surface_set_error (surface,
1174 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
1178 target = _cairo_paginated_surface_get_target (surface);
1179 if (target->status) {
1180 if (set_error_on_failure)
1181 _cairo_surface_set_error (surface, target->status);
1184 if (target->finished) {
1185 if (set_error_on_failure)
1186 _cairo_surface_set_error (surface,
1187 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
1191 if (! _cairo_surface_is_ps (target)) {
1192 if (set_error_on_failure)
1193 _cairo_surface_set_error (surface,
1194 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
1198 *ps_surface = (cairo_ps_surface_t *) target;
1203 * cairo_ps_surface_restrict_to_level:
1204 * @surface: a PostScript #cairo_surface_t
1205 * @level: PostScript level
1207 * Restricts the generated PostSript file to @level. See
1208 * cairo_ps_get_levels() for a list of available level values that
1211 * This function should only be called before any drawing operations
1212 * have been performed on the given surface. The simplest way to do
1213 * this is to call this function immediately after creating the
1219 cairo_ps_surface_restrict_to_level (cairo_surface_t *surface,
1220 cairo_ps_level_t level)
1222 cairo_ps_surface_t *ps_surface = NULL;
1224 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1227 if (level < CAIRO_PS_LEVEL_LAST)
1228 ps_surface->ps_level = level;
1232 * cairo_ps_get_levels:
1233 * @levels: supported level list
1234 * @num_levels: list length
1236 * Used to retrieve the list of supported levels. See
1237 * cairo_ps_surface_restrict_to_level().
1242 cairo_ps_get_levels (cairo_ps_level_t const **levels,
1246 *levels = _cairo_ps_levels;
1248 if (num_levels != NULL)
1249 *num_levels = CAIRO_PS_LEVEL_LAST;
1253 * cairo_ps_level_to_string:
1254 * @level: a level id
1256 * Get the string representation of the given @level id. This function
1257 * will return %NULL if @level id isn't valid. See cairo_ps_get_levels()
1258 * for a way to get the list of valid level ids.
1260 * Return value: the string associated to given level.
1265 cairo_ps_level_to_string (cairo_ps_level_t level)
1267 if (level >= CAIRO_PS_LEVEL_LAST)
1270 return _cairo_ps_level_strings[level];
1274 * cairo_ps_surface_set_eps:
1275 * @surface: a PostScript #cairo_surface_t
1276 * @eps: %TRUE to output EPS format PostScript
1278 * If @eps is %TRUE, the PostScript surface will output Encapsulated
1281 * This function should only be called before any drawing operations
1282 * have been performed on the current page. The simplest way to do
1283 * this is to call this function immediately after creating the
1284 * surface. An Encapsulated PostScript file should never contain more
1290 cairo_ps_surface_set_eps (cairo_surface_t *surface,
1293 cairo_ps_surface_t *ps_surface = NULL;
1295 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1298 ps_surface->eps = eps;
1302 * cairo_ps_surface_get_eps:
1303 * @surface: a PostScript #cairo_surface_t
1305 * Check whether the PostScript surface will output Encapsulated PostScript.
1307 * Return value: %TRUE if the surface will output Encapsulated PostScript.
1311 cairo_public cairo_bool_t
1312 cairo_ps_surface_get_eps (cairo_surface_t *surface)
1314 cairo_ps_surface_t *ps_surface = NULL;
1316 if (! _extract_ps_surface (surface, FALSE, &ps_surface))
1319 return ps_surface->eps;
1323 * cairo_ps_surface_set_size:
1324 * @surface: a PostScript #cairo_surface_t
1325 * @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
1326 * @height_in_points: new surface height, in points (1 point == 1/72.0 inch)
1328 * Changes the size of a PostScript surface for the current (and
1329 * subsequent) pages.
1331 * This function should only be called before any drawing operations
1332 * have been performed on the current page. The simplest way to do
1333 * this is to call this function immediately after creating the
1334 * surface or immediately after completing a page with either
1335 * cairo_show_page() or cairo_copy_page().
1340 cairo_ps_surface_set_size (cairo_surface_t *surface,
1341 double width_in_points,
1342 double height_in_points)
1344 cairo_ps_surface_t *ps_surface = NULL;
1345 cairo_status_t status;
1347 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1350 ps_surface->width = width_in_points;
1351 ps_surface->height = height_in_points;
1352 cairo_matrix_init (&ps_surface->cairo_to_ps, 1, 0, 0, -1, 0, height_in_points);
1353 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface->pdf_operators,
1354 &ps_surface->cairo_to_ps);
1355 status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface,
1359 status = _cairo_surface_set_error (surface, status);
1363 * cairo_ps_surface_dsc_comment:
1364 * @surface: a PostScript #cairo_surface_t
1365 * @comment: a comment string to be emitted into the PostScript output
1367 * Emit a comment into the PostScript output for the given surface.
1369 * The comment is expected to conform to the PostScript Language
1370 * Document Structuring Conventions (DSC). Please see that manual for
1371 * details on the available comments and their meanings. In
1372 * particular, the \%\%IncludeFeature comment allows a
1373 * device-independent means of controlling printer device features. So
1374 * the PostScript Printer Description Files Specification will also be
1375 * a useful reference.
1377 * The comment string must begin with a percent character (\%) and the
1378 * total length of the string (including any initial percent
1379 * characters) must not exceed 255 characters. Violating either of
1380 * these conditions will place @surface into an error state. But
1381 * beyond these two conditions, this function will not enforce
1382 * conformance of the comment with any particular specification.
1384 * The comment string should not have a trailing newline.
1386 * The DSC specifies different sections in which particular comments
1387 * can appear. This function provides for comments to be emitted
1388 * within three sections: the header, the Setup section, and the
1389 * PageSetup section. Comments appearing in the first two sections
1390 * apply to the entire document while comments in the BeginPageSetup
1391 * section apply only to a single page.
1393 * For comments to appear in the header section, this function should
1394 * be called after the surface is created, but before a call to
1395 * cairo_ps_surface_dsc_begin_setup().
1397 * For comments to appear in the Setup section, this function should
1398 * be called after a call to cairo_ps_surface_dsc_begin_setup() but
1399 * before a call to cairo_ps_surface_dsc_begin_page_setup().
1401 * For comments to appear in the PageSetup section, this function
1402 * should be called after a call to
1403 * cairo_ps_surface_dsc_begin_page_setup().
1405 * Note that it is only necessary to call
1406 * cairo_ps_surface_dsc_begin_page_setup() for the first page of any
1407 * surface. After a call to cairo_show_page() or cairo_copy_page()
1408 * comments are unambiguously directed to the PageSetup section of the
1409 * current page. But it doesn't hurt to call this function at the
1410 * beginning of every page as that consistency may make the calling
1413 * As a final note, cairo automatically generates several comments on
1414 * its own. As such, applications must not manually generate any of
1415 * the following comments:
1417 * Header section: \%!PS-Adobe-3.0, \%\%Creator, \%\%CreationDate, \%\%Pages,
1418 * \%\%BoundingBox, \%\%DocumentData, \%\%LanguageLevel, \%\%EndComments.
1420 * Setup section: \%\%BeginSetup, \%\%EndSetup
1422 * PageSetup section: \%\%BeginPageSetup, \%\%PageBoundingBox, \%\%EndPageSetup.
1424 * Other sections: \%\%BeginProlog, \%\%EndProlog, \%\%Page, \%\%Trailer, \%\%EOF
1426 * Here is an example sequence showing how this function might be used:
1428 * <informalexample><programlisting>
1429 * cairo_surface_t *surface = cairo_ps_surface_create (filename, width, height);
1431 * cairo_ps_surface_dsc_comment (surface, "%%Title: My excellent document");
1432 * cairo_ps_surface_dsc_comment (surface, "%%Copyright: Copyright (C) 2006 Cairo Lover")
1434 * cairo_ps_surface_dsc_begin_setup (surface);
1435 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor White");
1437 * cairo_ps_surface_dsc_begin_page_setup (surface);
1438 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A3");
1439 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *InputSlot LargeCapacity");
1440 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaType Glossy");
1441 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor Blue");
1442 * ... draw to first page here ..
1443 * cairo_show_page (cr);
1445 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A5");
1447 * </programlisting></informalexample>
1452 cairo_ps_surface_dsc_comment (cairo_surface_t *surface,
1453 const char *comment)
1455 cairo_ps_surface_t *ps_surface = NULL;
1456 cairo_status_t status;
1459 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1462 /* A couple of sanity checks on the comment value. */
1463 if (comment == NULL) {
1464 status = _cairo_surface_set_error (surface, CAIRO_STATUS_NULL_POINTER);
1468 if (comment[0] != '%' || strlen (comment) > 255) {
1469 status = _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_DSC_COMMENT);
1473 /* Then, copy the comment and store it in the appropriate array. */
1474 comment_copy = strdup (comment);
1475 if (unlikely (comment_copy == NULL)) {
1476 status = _cairo_surface_set_error (surface, CAIRO_STATUS_NO_MEMORY);
1480 status = _cairo_array_append (ps_surface->dsc_comment_target, &comment_copy);
1481 if (unlikely (status)) {
1482 free (comment_copy);
1483 status = _cairo_surface_set_error (surface, status);
1489 * cairo_ps_surface_dsc_begin_setup:
1490 * @surface: a PostScript #cairo_surface_t
1492 * This function indicates that subsequent calls to
1493 * cairo_ps_surface_dsc_comment() should direct comments to the Setup
1494 * section of the PostScript output.
1496 * This function should be called at most once per surface, and must
1497 * be called before any call to cairo_ps_surface_dsc_begin_page_setup()
1498 * and before any drawing is performed to the surface.
1500 * See cairo_ps_surface_dsc_comment() for more details.
1505 cairo_ps_surface_dsc_begin_setup (cairo_surface_t *surface)
1507 cairo_ps_surface_t *ps_surface = NULL;
1509 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1512 if (ps_surface->dsc_comment_target == &ps_surface->dsc_header_comments)
1513 ps_surface->dsc_comment_target = &ps_surface->dsc_setup_comments;
1517 * cairo_ps_surface_dsc_begin_page_setup:
1518 * @surface: a PostScript #cairo_surface_t
1520 * This function indicates that subsequent calls to
1521 * cairo_ps_surface_dsc_comment() should direct comments to the
1522 * PageSetup section of the PostScript output.
1524 * This function call is only needed for the first page of a
1525 * surface. It should be called after any call to
1526 * cairo_ps_surface_dsc_begin_setup() and before any drawing is
1527 * performed to the surface.
1529 * See cairo_ps_surface_dsc_comment() for more details.
1534 cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface)
1536 cairo_ps_surface_t *ps_surface = NULL;
1538 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1541 if (ps_surface->dsc_comment_target == &ps_surface->dsc_header_comments ||
1542 ps_surface->dsc_comment_target == &ps_surface->dsc_setup_comments)
1544 ps_surface->dsc_comment_target = &ps_surface->dsc_page_setup_comments;
1548 static cairo_status_t
1549 _cairo_ps_surface_finish (void *abstract_surface)
1551 cairo_status_t status, status2;
1552 cairo_ps_surface_t *surface = abstract_surface;
1553 int i, num_comments;
1556 status = surface->base.status;
1557 if (unlikely (status))
1560 _cairo_ps_surface_emit_header (surface);
1562 status = _cairo_ps_surface_emit_font_subsets (surface);
1563 if (unlikely (status))
1566 status = _cairo_ps_surface_emit_body (surface);
1567 if (unlikely (status))
1570 _cairo_ps_surface_emit_footer (surface);
1573 _cairo_scaled_font_subsets_destroy (surface->font_subsets);
1575 status2 = _cairo_output_stream_destroy (surface->stream);
1576 if (status == CAIRO_STATUS_SUCCESS)
1579 fclose (surface->tmpfile);
1581 status2 = _cairo_output_stream_destroy (surface->final_stream);
1582 if (status == CAIRO_STATUS_SUCCESS)
1585 while (! cairo_list_is_empty (&surface->document_media)) {
1586 cairo_page_media_t *page;
1588 page = cairo_list_first_entry (&surface->document_media,
1591 cairo_list_del (&page->link);
1596 num_comments = _cairo_array_num_elements (&surface->dsc_header_comments);
1597 comments = _cairo_array_index (&surface->dsc_header_comments, 0);
1598 for (i = 0; i < num_comments; i++)
1600 _cairo_array_fini (&surface->dsc_header_comments);
1602 num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
1603 comments = _cairo_array_index (&surface->dsc_setup_comments, 0);
1604 for (i = 0; i < num_comments; i++)
1606 _cairo_array_fini (&surface->dsc_setup_comments);
1608 num_comments = _cairo_array_num_elements (&surface->dsc_page_setup_comments);
1609 comments = _cairo_array_index (&surface->dsc_page_setup_comments, 0);
1610 for (i = 0; i < num_comments; i++)
1612 _cairo_array_fini (&surface->dsc_page_setup_comments);
1614 _cairo_surface_clipper_reset (&surface->clipper);
1619 static cairo_int_status_t
1620 _cairo_ps_surface_start_page (void *abstract_surface)
1622 cairo_ps_surface_t *surface = abstract_surface;
1624 /* Increment before print so page numbers start at 1. */
1625 surface->num_pages++;
1627 return CAIRO_STATUS_SUCCESS;
1630 static cairo_int_status_t
1631 _cairo_ps_surface_show_page (void *abstract_surface)
1633 cairo_ps_surface_t *surface = abstract_surface;
1634 cairo_int_status_t status;
1636 if (surface->clipper.clip != NULL)
1637 _cairo_surface_clipper_reset (&surface->clipper);
1639 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
1640 if (unlikely (status))
1643 _cairo_output_stream_printf (surface->stream,
1647 return CAIRO_STATUS_SUCCESS;
1651 color_is_gray (double red, double green, double blue)
1653 const double epsilon = 0.00001;
1655 return (fabs (red - green) < epsilon &&
1656 fabs (red - blue) < epsilon);
1660 * _cairo_ps_surface_acquire_source_surface_from_pattern:
1661 * @surface: the ps surface
1662 * @pattern: A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source
1663 * @extents: extents of the operation that is using this source
1664 * @width: returns width of surface
1665 * @height: returns height of surface
1666 * @x_offset: returns x offset of surface
1667 * @y_offset: returns y offset of surface
1668 * @surface: returns surface of type image surface or recording surface
1669 * @image_extra: returns image extra for image type surface
1671 * Acquire source surface or raster source pattern.
1673 static cairo_status_t
1674 _cairo_ps_surface_acquire_source_surface_from_pattern (cairo_ps_surface_t *surface,
1675 const cairo_pattern_t *pattern,
1676 const cairo_rectangle_int_t *extents,
1681 cairo_surface_t **source_surface,
1684 cairo_status_t status;
1685 cairo_image_surface_t *image;
1687 *x_offset = *y_offset = 0;
1688 switch (pattern->type) {
1689 case CAIRO_PATTERN_TYPE_SURFACE: {
1690 cairo_surface_t *surf = ((cairo_surface_pattern_t *) pattern)->surface;
1692 if (surf->type == CAIRO_SURFACE_TYPE_RECORDING) {
1693 if (surf->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1694 cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surf;
1696 *width = sub->extents.width;
1697 *height = sub->extents.height;
1699 cairo_surface_t *free_me = NULL;
1700 cairo_recording_surface_t *recording_surface;
1702 cairo_rectangle_int_t extents;
1704 recording_surface = (cairo_recording_surface_t *) surf;
1705 if (_cairo_surface_is_snapshot (&recording_surface->base)) {
1706 free_me = _cairo_surface_snapshot_get_target (&recording_surface->base);
1707 recording_surface = (cairo_recording_surface_t *) free_me;
1710 status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
1711 cairo_surface_destroy (free_me);
1712 if (unlikely (status))
1715 _cairo_box_round_to_rectangle (&bbox, &extents);
1716 *width = extents.width;
1717 *height = extents.height;
1719 *source_surface = surf;
1721 return CAIRO_STATUS_SUCCESS;
1723 status = _cairo_surface_acquire_source_image (surf, &image, image_extra);
1724 if (unlikely (status))
1729 case CAIRO_PATTERN_TYPE_RASTER_SOURCE: {
1730 cairo_surface_t *surf;
1732 cairo_rectangle_int_t rect;
1734 /* get the operation extents in pattern space */
1735 _cairo_box_from_rectangle (&box, extents);
1736 _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &box, NULL);
1737 _cairo_box_round_to_rectangle (&box, &rect);
1738 surf = _cairo_raster_source_pattern_acquire (pattern, &surface->base, &rect);
1740 return CAIRO_INT_STATUS_UNSUPPORTED;
1741 assert (_cairo_surface_is_image (surf));
1742 image = (cairo_image_surface_t *) surf;
1745 case CAIRO_PATTERN_TYPE_SOLID:
1746 case CAIRO_PATTERN_TYPE_LINEAR:
1747 case CAIRO_PATTERN_TYPE_RADIAL:
1748 case CAIRO_PATTERN_TYPE_MESH:
1754 *width = image->width;
1755 *height = image->height;
1756 *source_surface = &image->base;
1757 return CAIRO_STATUS_SUCCESS;
1761 _cairo_ps_surface_release_source_surface_from_pattern (cairo_ps_surface_t *surface,
1762 const cairo_pattern_t *pattern,
1763 cairo_surface_t *source,
1766 switch (pattern->type) {
1767 case CAIRO_PATTERN_TYPE_SURFACE: {
1768 cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) pattern;
1769 if (surf_pat->surface->type != CAIRO_SURFACE_TYPE_RECORDING) {
1770 cairo_image_surface_t *image = (cairo_image_surface_t *) source;
1771 _cairo_surface_release_source_image (surf_pat->surface, image, image_extra);
1775 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
1776 _cairo_raster_source_pattern_release (pattern, source);
1779 case CAIRO_PATTERN_TYPE_SOLID:
1780 case CAIRO_PATTERN_TYPE_LINEAR:
1781 case CAIRO_PATTERN_TYPE_RADIAL:
1782 case CAIRO_PATTERN_TYPE_MESH:
1791 * _cairo_ps_surface_create_padded_image_from_image:
1792 * @surface: the ps surface
1793 * @source: The source image
1794 * @extents: extents of the operation that is using this source
1795 * @width: returns width of padded image
1796 * @height: returns height of padded image
1797 * @x_offset: returns x offset of padded image
1798 * @y_offset: returns y offset of padded image
1799 * @image: returns the padded image or NULL if padding not required to fill @extents
1801 * Creates a padded image if the source image does not fill the extents.
1803 static cairo_status_t
1804 _cairo_ps_surface_create_padded_image_from_image (cairo_ps_surface_t *surface,
1805 cairo_image_surface_t *source,
1806 const cairo_matrix_t *source_matrix,
1807 const cairo_rectangle_int_t *extents,
1812 cairo_image_surface_t **image)
1815 cairo_rectangle_int_t rect;
1816 cairo_surface_t *pad_image;
1817 cairo_surface_pattern_t pad_pattern;
1819 cairo_int_status_t status;
1821 /* get the operation extents in pattern space */
1822 _cairo_box_from_rectangle (&box, extents);
1823 _cairo_matrix_transform_bounding_box_fixed (source_matrix, &box, NULL);
1824 _cairo_box_round_to_rectangle (&box, &rect);
1826 /* Check if image needs padding to fill extents. */
1829 if (_cairo_fixed_integer_ceil(box.p1.x) < 0 ||
1830 _cairo_fixed_integer_ceil(box.p1.y) < 0 ||
1831 _cairo_fixed_integer_floor(box.p2.y) > w ||
1832 _cairo_fixed_integer_floor(box.p2.y) > h)
1835 _cairo_image_surface_create_with_pixman_format (NULL,
1836 source->pixman_format,
1837 rect.width, rect.height,
1839 if (pad_image->status)
1840 return pad_image->status;
1842 _cairo_pattern_init_for_surface (&pad_pattern, &source->base);
1843 cairo_matrix_init_translate (&pad_pattern.base.matrix, rect.x, rect.y);
1844 pad_pattern.base.extend = CAIRO_EXTEND_PAD;
1845 status = _cairo_surface_paint (pad_image,
1846 CAIRO_OPERATOR_SOURCE,
1849 _cairo_pattern_fini (&pad_pattern.base);
1850 *image = (cairo_image_surface_t *) pad_image;
1851 *width = rect.width;
1852 *height = rect.height;
1857 status = CAIRO_STATUS_SUCCESS;
1863 static cairo_int_status_t
1864 _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t *surface,
1865 const cairo_pattern_t *pattern,
1866 const cairo_rectangle_int_t *extents)
1869 double x_offset, y_offset;
1870 cairo_surface_t *source;
1871 cairo_image_surface_t *image;
1873 cairo_int_status_t status;
1874 cairo_image_transparency_t transparency;
1876 status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
1885 if (unlikely (status))
1888 image = (cairo_image_surface_t *) source;
1889 if (image->base.status)
1890 return image->base.status;
1892 transparency = _cairo_image_analyze_transparency (image);
1893 switch (transparency) {
1894 case CAIRO_IMAGE_IS_OPAQUE:
1895 status = CAIRO_STATUS_SUCCESS;
1898 case CAIRO_IMAGE_HAS_BILEVEL_ALPHA:
1899 if (surface->ps_level == CAIRO_PS_LEVEL_2) {
1900 status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1902 surface->ps_level_used = CAIRO_PS_LEVEL_3;
1903 status = CAIRO_STATUS_SUCCESS;
1907 case CAIRO_IMAGE_HAS_ALPHA:
1908 status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1911 case CAIRO_IMAGE_UNKNOWN:
1915 _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
1921 surface_pattern_supported (const cairo_surface_pattern_t *pattern)
1923 if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1926 if (pattern->surface->backend->acquire_source_image == NULL)
1929 /* Does an ALPHA-only source surface even make sense? Maybe, but I
1930 * don't think it's worth the extra code to support it. */
1932 /* XXX: Need to write this function here...
1933 content = pattern->surface->content;
1934 if (content == CAIRO_CONTENT_ALPHA)
1942 _gradient_pattern_supported (cairo_ps_surface_t *surface,
1943 const cairo_pattern_t *pattern)
1945 double min_alpha, max_alpha;
1947 if (surface->ps_level == CAIRO_PS_LEVEL_2)
1950 /* Alpha gradients are only supported (by flattening the alpha)
1951 * if there is no variation in the alpha across the gradient. */
1952 _cairo_pattern_alpha_range (pattern, &min_alpha, &max_alpha);
1953 if (min_alpha != max_alpha)
1956 surface->ps_level_used = CAIRO_PS_LEVEL_3;
1962 pattern_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *pattern)
1964 switch (pattern->type) {
1965 case CAIRO_PATTERN_TYPE_SOLID:
1968 case CAIRO_PATTERN_TYPE_LINEAR:
1969 case CAIRO_PATTERN_TYPE_RADIAL:
1970 case CAIRO_PATTERN_TYPE_MESH:
1971 return _gradient_pattern_supported (surface, pattern);
1973 case CAIRO_PATTERN_TYPE_SURFACE:
1974 return surface_pattern_supported ((cairo_surface_pattern_t *) pattern);
1976 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
1986 mask_supported (cairo_ps_surface_t *surface,
1987 const cairo_pattern_t *mask,
1988 const cairo_rectangle_int_t *extents)
1990 if (surface->ps_level == CAIRO_PS_LEVEL_2)
1993 if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
1994 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
1995 if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
1996 /* check if mask if opaque or bilevel alpha */
1997 if (_cairo_ps_surface_analyze_surface_pattern_transparency (surface, mask, extents) == CAIRO_INT_STATUS_SUCCESS) {
1998 surface->ps_level_used = CAIRO_PS_LEVEL_3;
2007 static cairo_int_status_t
2008 _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
2009 cairo_operator_t op,
2010 const cairo_pattern_t *pattern,
2011 const cairo_pattern_t *mask,
2012 const cairo_rectangle_int_t *extents)
2016 if (surface->force_fallbacks &&
2017 surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
2019 return CAIRO_INT_STATUS_UNSUPPORTED;
2022 if (! pattern_supported (surface, pattern))
2023 return CAIRO_INT_STATUS_UNSUPPORTED;
2025 if (! (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
2026 return CAIRO_INT_STATUS_UNSUPPORTED;
2028 /* Mask is only supported when the mask is an image with opaque or bilevel alpha. */
2029 if (mask && !mask_supported (surface, mask, extents))
2030 return CAIRO_INT_STATUS_UNSUPPORTED;
2032 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
2033 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
2035 if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
2036 if (pattern->extend == CAIRO_EXTEND_PAD) {
2038 cairo_rectangle_int_t rect;
2039 cairo_rectangle_int_t rec_extents;
2041 /* get the operation extents in pattern space */
2042 _cairo_box_from_rectangle (&box, extents);
2043 _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &box, NULL);
2044 _cairo_box_round_to_rectangle (&box, &rect);
2046 /* Check if surface needs padding to fill extents */
2047 if (_cairo_surface_get_extents (surface_pattern->surface, &rec_extents)) {
2048 if (_cairo_fixed_integer_ceil(box.p1.x) < rec_extents.x ||
2049 _cairo_fixed_integer_ceil(box.p1.y) < rec_extents.y ||
2050 _cairo_fixed_integer_floor(box.p2.y) > rec_extents.x + rec_extents.width ||
2051 _cairo_fixed_integer_floor(box.p2.y) > rec_extents.y + rec_extents.height)
2053 return CAIRO_INT_STATUS_UNSUPPORTED;
2057 return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
2061 if (op == CAIRO_OPERATOR_SOURCE) {
2063 return CAIRO_INT_STATUS_UNSUPPORTED;
2065 return CAIRO_STATUS_SUCCESS;
2068 /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
2069 * the pattern contains transparency, we return
2070 * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
2071 * surface. If the analysis surface determines that there is
2072 * anything drawn under this operation, a fallback image will be
2073 * used. Otherwise the operation will be replayed during the
2074 * render stage and we blend the transparency into the white
2075 * background to convert the pattern to opaque.
2077 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE || pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)
2078 return _cairo_ps_surface_analyze_surface_pattern_transparency (surface, pattern, extents);
2080 /* Patterns whose drawn part is opaque are directly supported;
2081 those whose drawn part is partially transparent can be
2082 supported by flattening the alpha. */
2083 _cairo_pattern_alpha_range (pattern, &min_alpha, NULL);
2084 if (CAIRO_ALPHA_IS_OPAQUE (min_alpha))
2085 return CAIRO_STATUS_SUCCESS;
2087 return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
2091 _cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface,
2092 cairo_operator_t op,
2093 const cairo_pattern_t *pattern,
2094 const cairo_pattern_t *mask,
2095 const cairo_rectangle_int_t *extents)
2097 return _cairo_ps_surface_analyze_operation (surface, op, pattern, mask, extents) != CAIRO_INT_STATUS_UNSUPPORTED;
2100 /* The "standard" implementation limit for PostScript string sizes is
2101 * 65535 characters (see PostScript Language Reference, Appendix
2102 * B). We go one short of that because we sometimes need two
2103 * characters in a string to represent a single ASCII85 byte, (for the
2104 * escape sequences "\\", "\(", and "\)") and we must not split these
2105 * across two strings. So we'd be in trouble if we went right to the
2106 * limit and one of these escape sequences just happened to land at
2109 #define STRING_ARRAY_MAX_STRING_SIZE (65535-1)
2110 #define STRING_ARRAY_MAX_COLUMN 72
2112 typedef struct _string_array_stream {
2113 cairo_output_stream_t base;
2114 cairo_output_stream_t *output;
2117 cairo_bool_t use_strings;
2118 } string_array_stream_t;
2120 static cairo_status_t
2121 _string_array_stream_write (cairo_output_stream_t *base,
2122 const unsigned char *data,
2123 unsigned int length)
2125 string_array_stream_t *stream = (string_array_stream_t *) base;
2127 const unsigned char backslash = '\\';
2130 return CAIRO_STATUS_SUCCESS;
2133 if (stream->string_size == 0 && stream->use_strings) {
2134 _cairo_output_stream_printf (stream->output, "(");
2139 if (stream->use_strings) {
2144 _cairo_output_stream_write (stream->output, &backslash, 1);
2146 stream->string_size++;
2150 /* Have to be careful to never split the final ~> sequence. */
2152 _cairo_output_stream_write (stream->output, &c, 1);
2154 stream->string_size++;
2161 _cairo_output_stream_write (stream->output, &c, 1);
2163 stream->string_size++;
2165 if (stream->use_strings &&
2166 stream->string_size >= STRING_ARRAY_MAX_STRING_SIZE)
2168 _cairo_output_stream_printf (stream->output, ")\n");
2169 stream->string_size = 0;
2172 if (stream->column >= STRING_ARRAY_MAX_COLUMN) {
2173 _cairo_output_stream_printf (stream->output, "\n ");
2174 stream->string_size += 2;
2179 return _cairo_output_stream_get_status (stream->output);
2182 static cairo_status_t
2183 _string_array_stream_close (cairo_output_stream_t *base)
2185 cairo_status_t status;
2186 string_array_stream_t *stream = (string_array_stream_t *) base;
2188 if (stream->use_strings)
2189 _cairo_output_stream_printf (stream->output, ")\n");
2191 status = _cairo_output_stream_get_status (stream->output);
2196 /* A string_array_stream wraps an existing output stream. It takes the
2197 * data provided to it and output one or more consecutive string
2198 * objects, each within the standard PostScript implementation limit
2199 * of 65k characters.
2201 * The strings are each separated by a space character for easy
2202 * inclusion within an array object, (but the array delimiters are not
2203 * added by the string_array_stream).
2205 * The string array stream is also careful to wrap the output within
2206 * STRING_ARRAY_MAX_COLUMN columns (+/- 1). The stream also adds
2207 * necessary escaping for special characters within a string,
2208 * (specifically '\', '(', and ')').
2210 static cairo_output_stream_t *
2211 _string_array_stream_create (cairo_output_stream_t *output)
2213 string_array_stream_t *stream;
2215 stream = malloc (sizeof (string_array_stream_t));
2216 if (unlikely (stream == NULL)) {
2217 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
2218 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
2221 _cairo_output_stream_init (&stream->base,
2222 _string_array_stream_write,
2224 _string_array_stream_close);
2225 stream->output = output;
2227 stream->string_size = 0;
2228 stream->use_strings = TRUE;
2230 return &stream->base;
2233 /* A base85_array_stream wraps an existing output stream. It wraps the
2234 * output within STRING_ARRAY_MAX_COLUMN columns (+/- 1). The output
2235 * is not enclosed in strings like string_array_stream.
2237 static cairo_output_stream_t *
2238 _base85_array_stream_create (cairo_output_stream_t *output)
2240 string_array_stream_t *stream;
2242 stream = malloc (sizeof (string_array_stream_t));
2243 if (unlikely (stream == NULL)) {
2244 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
2245 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
2248 _cairo_output_stream_init (&stream->base,
2249 _string_array_stream_write,
2251 _string_array_stream_close);
2252 stream->output = output;
2254 stream->string_size = 0;
2255 stream->use_strings = FALSE;
2257 return &stream->base;
2261 /* PS Output - this section handles output of the parts of the recording
2262 * surface we can render natively in PS. */
2264 static cairo_status_t
2265 _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface,
2266 cairo_image_surface_t *image,
2267 cairo_image_surface_t **opaque_image)
2269 cairo_surface_t *opaque;
2270 cairo_surface_pattern_t pattern;
2271 cairo_status_t status;
2273 opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
2276 if (unlikely (opaque->status))
2277 return opaque->status;
2279 if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
2280 status = _cairo_surface_paint (opaque,
2281 CAIRO_OPERATOR_SOURCE,
2282 &_cairo_pattern_white.base,
2284 if (unlikely (status)) {
2285 cairo_surface_destroy (opaque);
2290 _cairo_pattern_init_for_surface (&pattern, &image->base);
2291 pattern.base.filter = CAIRO_FILTER_NEAREST;
2292 status = _cairo_surface_paint (opaque, CAIRO_OPERATOR_OVER, &pattern.base, NULL);
2293 _cairo_pattern_fini (&pattern.base);
2294 if (unlikely (status)) {
2295 cairo_surface_destroy (opaque);
2299 *opaque_image = (cairo_image_surface_t *) opaque;
2300 return CAIRO_STATUS_SUCCESS;
2303 static cairo_status_t
2304 _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface,
2305 const unsigned char *data,
2306 unsigned long length,
2307 cairo_ps_compress_t compress,
2308 cairo_bool_t use_strings)
2310 cairo_output_stream_t *base85_stream, *string_array_stream, *deflate_stream;
2311 unsigned char *data_compressed;
2312 unsigned long data_compressed_size;
2313 cairo_status_t status, status2;
2316 string_array_stream = _string_array_stream_create (surface->stream);
2318 string_array_stream = _base85_array_stream_create (surface->stream);
2320 status = _cairo_output_stream_get_status (string_array_stream);
2321 if (unlikely (status))
2322 return _cairo_output_stream_destroy (string_array_stream);
2324 base85_stream = _cairo_base85_stream_create (string_array_stream);
2325 status = _cairo_output_stream_get_status (base85_stream);
2326 if (unlikely (status)) {
2327 status2 = _cairo_output_stream_destroy (string_array_stream);
2328 return _cairo_output_stream_destroy (base85_stream);
2332 case CAIRO_PS_COMPRESS_NONE:
2333 _cairo_output_stream_write (base85_stream, data, length);
2336 case CAIRO_PS_COMPRESS_LZW:
2337 /* XXX: Should fix cairo-lzw to provide a stream-based interface
2339 data_compressed_size = length;
2340 data_compressed = _cairo_lzw_compress ((unsigned char*)data, &data_compressed_size);
2341 if (unlikely (data_compressed == NULL)) {
2342 status = _cairo_output_stream_destroy (string_array_stream);
2343 status = _cairo_output_stream_destroy (base85_stream);
2344 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2346 _cairo_output_stream_write (base85_stream, data_compressed, data_compressed_size);
2347 free (data_compressed);
2350 case CAIRO_PS_COMPRESS_DEFLATE:
2351 deflate_stream = _cairo_deflate_stream_create (base85_stream);
2352 if (_cairo_output_stream_get_status (deflate_stream)) {
2353 return _cairo_output_stream_destroy (deflate_stream);
2355 _cairo_output_stream_write (deflate_stream, data, length);
2356 status = _cairo_output_stream_destroy (deflate_stream);
2357 if (unlikely (status)) {
2358 status2 = _cairo_output_stream_destroy (string_array_stream);
2359 status2 = _cairo_output_stream_destroy (base85_stream);
2360 return _cairo_output_stream_destroy (deflate_stream);
2364 status = _cairo_output_stream_destroy (base85_stream);
2366 /* Mark end of base85 data */
2367 _cairo_output_stream_printf (string_array_stream, "~>");
2368 status2 = _cairo_output_stream_destroy (string_array_stream);
2369 if (status == CAIRO_STATUS_SUCCESS)
2375 static cairo_status_t
2376 _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
2377 cairo_image_surface_t *image_surf,
2378 cairo_operator_t op,
2379 cairo_filter_t filter,
2380 cairo_bool_t stencil_mask)
2382 cairo_status_t status;
2383 unsigned char *data;
2384 unsigned long data_size;
2385 cairo_image_surface_t *ps_image;
2387 cairo_image_transparency_t transparency;
2388 cairo_bool_t use_mask;
2392 cairo_image_color_t color;
2393 const char *interpolate;
2394 cairo_ps_compress_t compress;
2395 const char *compress_filter;
2396 cairo_image_surface_t *image;
2398 if (image_surf->base.status)
2399 return image_surf->base.status;
2402 if (image->format != CAIRO_FORMAT_RGB24 &&
2403 image->format != CAIRO_FORMAT_ARGB32 &&
2404 image->format != CAIRO_FORMAT_A8 &&
2405 image->format != CAIRO_FORMAT_A1)
2407 cairo_surface_t *surf;
2408 cairo_surface_pattern_t pattern;
2410 surf = _cairo_image_surface_create_with_content (image_surf->base.content,
2412 image_surf->height);
2413 image = (cairo_image_surface_t *) surf;
2415 status = surf->status;
2419 _cairo_pattern_init_for_surface (&pattern, &image_surf->base);
2420 status = _cairo_surface_paint (surf,
2421 CAIRO_OPERATOR_SOURCE, &pattern.base,
2423 _cairo_pattern_fini (&pattern.base);
2424 if (unlikely (status))
2431 case CAIRO_FILTER_GOOD:
2432 case CAIRO_FILTER_BEST:
2433 case CAIRO_FILTER_BILINEAR:
2434 interpolate = "true";
2436 case CAIRO_FILTER_FAST:
2437 case CAIRO_FILTER_NEAREST:
2438 case CAIRO_FILTER_GAUSSIAN:
2439 interpolate = "false";
2445 color = CAIRO_IMAGE_IS_MONOCHROME;
2446 transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
2448 transparency = _cairo_image_analyze_transparency (image);
2450 /* PostScript can not represent the alpha channel, so we blend the
2451 current image over a white (or black for CONTENT_COLOR
2452 surfaces) RGB surface to eliminate it. */
2454 if (op == CAIRO_OPERATOR_SOURCE ||
2455 transparency == CAIRO_IMAGE_HAS_ALPHA ||
2456 (transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA &&
2457 surface->ps_level == CAIRO_PS_LEVEL_2))
2459 status = _cairo_ps_surface_flatten_image_transparency (surface,
2462 if (unlikely (status))
2466 } else if (transparency == CAIRO_IMAGE_IS_OPAQUE) {
2468 } else { /* transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA */
2472 color = _cairo_image_analyze_color (ps_image);
2475 /* Type 2 (mask and image interleaved) has the mask and image
2476 * samples interleaved by row. The mask row is first, one bit per
2477 * pixel with (bit 7 first). The row is padded to byte
2478 * boundaries. The image data is 3 bytes per pixel RGB format. */
2481 case CAIRO_IMAGE_UNKNOWN_COLOR:
2483 case CAIRO_IMAGE_IS_COLOR:
2484 data_size = ps_image->width * 3;
2486 case CAIRO_IMAGE_IS_GRAYSCALE:
2487 data_size = ps_image->width;
2489 case CAIRO_IMAGE_IS_MONOCHROME:
2490 data_size = (ps_image->width + 7)/8;
2494 data_size += (ps_image->width + 7)/8;
2495 data_size *= ps_image->height;
2496 data = malloc (data_size);
2497 if (unlikely (data == NULL)) {
2498 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2503 for (y = 0; y < ps_image->height; y++) {
2504 if (stencil_mask || use_mask) {
2506 if (ps_image->format == CAIRO_FORMAT_A1) {
2507 pixel8 = (uint8_t *) (ps_image->data + y * ps_image->stride);
2509 for (x = 0; x < (ps_image->width + 7) / 8; x++, pixel8++) {
2511 a = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (a);
2515 pixel8 = (uint8_t *) (ps_image->data + y * ps_image->stride);
2516 pixel32 = (uint32_t *) (ps_image->data + y * ps_image->stride);
2518 for (x = 0; x < ps_image->width; x++) {
2519 if (ps_image->format == CAIRO_FORMAT_ARGB32) {
2520 a = (*pixel32 & 0xff000000) >> 24;
2527 if (transparency == CAIRO_IMAGE_HAS_ALPHA) {
2529 } else { /* transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA or CAIRO_IMAGE_IS_OPAQUE */
2533 data[i] |= (1 << bit);
2549 pixel32 = (uint32_t *) (ps_image->data + y * ps_image->stride);
2551 for (x = 0; x < ps_image->width; x++, pixel32++) {
2554 if (ps_image->format == CAIRO_FORMAT_ARGB32) {
2555 /* At this point ARGB32 images are either opaque or
2556 * bilevel alpha so we don't need to unpremultiply. */
2557 if (((*pixel32 & 0xff000000) >> 24) == 0) {
2560 r = (*pixel32 & 0x00ff0000) >> 16;
2561 g = (*pixel32 & 0x0000ff00) >> 8;
2562 b = (*pixel32 & 0x000000ff) >> 0;
2564 } else if (ps_image->format == CAIRO_FORMAT_RGB24) {
2565 r = (*pixel32 & 0x00ff0000) >> 16;
2566 g = (*pixel32 & 0x0000ff00) >> 8;
2567 b = (*pixel32 & 0x000000ff) >> 0;
2573 case CAIRO_IMAGE_IS_COLOR:
2574 case CAIRO_IMAGE_UNKNOWN_COLOR:
2580 case CAIRO_IMAGE_IS_GRAYSCALE:
2584 case CAIRO_IMAGE_IS_MONOCHROME:
2588 data[i] |= (1 << bit);
2601 if (surface->ps_level == CAIRO_PS_LEVEL_2) {
2602 compress = CAIRO_PS_COMPRESS_LZW;
2603 compress_filter = "LZWDecode";
2605 compress = CAIRO_PS_COMPRESS_DEFLATE;
2606 compress_filter = "FlateDecode";
2607 surface->ps_level_used = CAIRO_PS_LEVEL_3;
2610 if (surface->use_string_datasource) {
2611 /* Emit the image data as a base85-encoded string which will
2612 * be used as the data source for the image operator later. */
2613 _cairo_output_stream_printf (surface->stream,
2614 "/CairoImageData [\n");
2616 status = _cairo_ps_surface_emit_base85_string (surface,
2621 if (unlikely (status))
2624 _cairo_output_stream_printf (surface->stream,
2626 _cairo_output_stream_printf (surface->stream,
2627 "/CairoImageDataIndex 0 def\n");
2631 _cairo_output_stream_printf (surface->stream,
2632 "%s setcolorspace\n"
2633 "5 dict dup begin\n"
2634 " /ImageType 3 def\n"
2635 " /InterleaveType 2 def\n"
2636 " /DataDict 8 dict def\n"
2638 " /ImageType 1 def\n"
2641 " /Interpolate %s def\n"
2642 " /BitsPerComponent %d def\n"
2643 " /Decode [ %s ] def\n",
2644 color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray",
2648 color == CAIRO_IMAGE_IS_MONOCHROME ? 1 : 8,
2649 color == CAIRO_IMAGE_IS_COLOR ? "0 1 0 1 0 1" : "0 1");
2651 if (surface->use_string_datasource) {
2652 _cairo_output_stream_printf (surface->stream,
2654 " CairoImageData CairoImageDataIndex get\n"
2655 " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2656 " CairoImageDataIndex CairoImageData length 1 sub gt\n"
2657 " { /CairoImageDataIndex 0 def } if\n"
2658 " } /ASCII85Decode filter /%s filter def\n",
2661 _cairo_output_stream_printf (surface->stream,
2662 " /DataSource currentfile /ASCII85Decode filter /%s filter def\n",
2666 _cairo_output_stream_printf (surface->stream,
2667 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2669 " /MaskDict 8 dict def\n"
2671 " /ImageType 1 def\n"
2674 " /Interpolate %s def\n"
2675 " /BitsPerComponent 1 def\n"
2676 " /Decode [ 1 0 ] def\n"
2677 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2687 if (!stencil_mask) {
2688 _cairo_output_stream_printf (surface->stream,
2689 "%s setcolorspace\n",
2690 color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray");
2692 _cairo_output_stream_printf (surface->stream,
2693 "8 dict dup begin\n"
2694 " /ImageType 1 def\n"
2697 " /Interpolate %s def\n"
2698 " /BitsPerComponent %d def\n"
2699 " /Decode [ %s ] def\n",
2703 color == CAIRO_IMAGE_IS_MONOCHROME ? 1 : 8,
2704 stencil_mask ? "1 0" : color == CAIRO_IMAGE_IS_COLOR ? "0 1 0 1 0 1" : "0 1");
2705 if (surface->use_string_datasource) {
2706 _cairo_output_stream_printf (surface->stream,
2708 " CairoImageData CairoImageDataIndex get\n"
2709 " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2710 " CairoImageDataIndex CairoImageData length 1 sub gt\n"
2711 " { /CairoImageDataIndex 0 def } if\n"
2712 " } /ASCII85Decode filter /%s filter def\n",
2715 _cairo_output_stream_printf (surface->stream,
2716 " /DataSource currentfile /ASCII85Decode filter /%s filter def\n",
2720 _cairo_output_stream_printf (surface->stream,
2721 " /Interpolate %s def\n"
2722 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2727 stencil_mask ? "imagemask" : "image");
2730 if (!surface->use_string_datasource) {
2731 /* Emit the image data as a base85-encoded string which will
2732 * be used as the data source for the image operator. */
2733 status = _cairo_ps_surface_emit_base85_string (surface,
2738 _cairo_output_stream_printf (surface->stream, "\n");
2740 status = CAIRO_STATUS_SUCCESS;
2747 if (!use_mask && ps_image != image)
2748 cairo_surface_destroy (&ps_image->base);
2751 if (image != image_surf)
2752 cairo_surface_destroy (&image->base);
2757 static cairo_status_t
2758 _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface,
2759 cairo_surface_t *source,
2763 cairo_status_t status;
2764 const unsigned char *mime_data;
2765 unsigned long mime_data_length;
2766 cairo_image_info_t info;
2767 const char *colorspace;
2770 cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
2771 &mime_data, &mime_data_length);
2772 if (unlikely (source->status))
2773 return source->status;
2774 if (mime_data == NULL)
2775 return CAIRO_INT_STATUS_UNSUPPORTED;
2777 status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length);
2778 if (unlikely (status))
2781 switch (info.num_components) {
2783 colorspace = "/DeviceGray";
2787 colorspace = "/DeviceRGB";
2788 decode = "0 1 0 1 0 1";
2791 colorspace = "/DeviceCMYK";
2792 decode = "0 1 0 1 0 1 0 1";
2795 return CAIRO_INT_STATUS_UNSUPPORTED;
2798 if (surface->use_string_datasource) {
2799 /* Emit the image data as a base85-encoded string which will
2800 * be used as the data source for the image operator later. */
2801 _cairo_output_stream_printf (surface->stream,
2802 "/CairoImageData [\n");
2804 status = _cairo_ps_surface_emit_base85_string (surface,
2807 CAIRO_PS_COMPRESS_NONE,
2809 if (unlikely (status))
2812 _cairo_output_stream_printf (surface->stream,
2814 _cairo_output_stream_printf (surface->stream,
2815 "/CairoImageDataIndex 0 def\n");
2818 _cairo_output_stream_printf (surface->stream,
2819 "%s setcolorspace\n"
2820 "8 dict dup begin\n"
2821 " /ImageType 1 def\n"
2824 " /BitsPerComponent %d def\n"
2825 " /Decode [ %s ] def\n",
2829 info.bits_per_component,
2832 if (surface->use_string_datasource) {
2833 _cairo_output_stream_printf (surface->stream,
2835 " CairoImageData CairoImageDataIndex get\n"
2836 " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2837 " CairoImageDataIndex CairoImageData length 1 sub gt\n"
2838 " { /CairoImageDataIndex 0 def } if\n"
2839 " } /ASCII85Decode filter /DCTDecode filter def\n");
2841 _cairo_output_stream_printf (surface->stream,
2842 " /DataSource currentfile /ASCII85Decode filter /DCTDecode filter def\n");
2845 _cairo_output_stream_printf (surface->stream,
2846 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2851 if (!surface->use_string_datasource) {
2852 /* Emit the image data as a base85-encoded string which will
2853 * be used as the data source for the image operator. */
2854 status = _cairo_ps_surface_emit_base85_string (surface,
2857 CAIRO_PS_COMPRESS_NONE,
2864 static cairo_status_t
2865 _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
2866 cairo_surface_t *recording_surface)
2868 double old_width, old_height;
2869 cairo_matrix_t old_cairo_to_ps;
2870 cairo_content_t old_content;
2871 cairo_rectangle_int_t old_page_bbox;
2872 cairo_surface_t *free_me = NULL;
2873 cairo_surface_clipper_t old_clipper;
2875 cairo_int_status_t status;
2877 old_content = surface->content;
2878 old_width = surface->width;
2879 old_height = surface->height;
2880 old_page_bbox = surface->page_bbox;
2881 old_cairo_to_ps = surface->cairo_to_ps;
2882 old_clipper = surface->clipper;
2883 _cairo_surface_clipper_init (&surface->clipper,
2884 _cairo_ps_surface_clipper_intersect_clip_path);
2886 if (_cairo_surface_is_snapshot (recording_surface))
2887 free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface);
2890 _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
2893 if (unlikely (status))
2897 _cairo_output_stream_printf (surface->stream,
2898 "%% _cairo_ps_surface_emit_recording_surface (%f, %f), (%f, %f)\n",
2899 _cairo_fixed_to_double (bbox.p1.x),
2900 _cairo_fixed_to_double (bbox.p1.y),
2901 _cairo_fixed_to_double (bbox.p2.x),
2902 _cairo_fixed_to_double (bbox.p2.y));
2905 surface->width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
2906 surface->height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
2907 _cairo_box_round_to_rectangle (&bbox, &surface->page_bbox);
2909 surface->current_pattern_is_solid_color = FALSE;
2910 _cairo_pdf_operators_reset (&surface->pdf_operators);
2911 cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
2912 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
2913 &surface->cairo_to_ps);
2914 _cairo_output_stream_printf (surface->stream, " q\n");
2916 if (recording_surface->content == CAIRO_CONTENT_COLOR) {
2917 surface->content = CAIRO_CONTENT_COLOR;
2918 _cairo_output_stream_printf (surface->stream,
2919 " 0 g %d %d %d %d rectfill\n",
2920 surface->page_bbox.x,
2921 surface->page_bbox.y,
2922 surface->page_bbox.width,
2923 surface->page_bbox.height);
2926 status = _cairo_recording_surface_replay_region (recording_surface,
2929 CAIRO_RECORDING_REGION_NATIVE);
2930 assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
2931 if (unlikely (status))
2934 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
2935 if (unlikely (status))
2938 _cairo_output_stream_printf (surface->stream, " Q\n");
2940 _cairo_surface_clipper_reset (&surface->clipper);
2941 surface->clipper = old_clipper;
2942 surface->content = old_content;
2943 surface->width = old_width;
2944 surface->height = old_height;
2945 surface->page_bbox = old_page_bbox;
2946 surface->current_pattern_is_solid_color = FALSE;
2947 _cairo_pdf_operators_reset (&surface->pdf_operators);
2948 surface->cairo_to_ps = old_cairo_to_ps;
2950 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
2951 &surface->cairo_to_ps);
2954 cairo_surface_destroy (free_me);
2958 static cairo_int_status_t
2959 _cairo_ps_surface_emit_recording_subsurface (cairo_ps_surface_t *surface,
2960 cairo_surface_t *recording_surface,
2961 const cairo_rectangle_int_t *extents)
2963 double old_width, old_height;
2964 cairo_matrix_t old_cairo_to_ps;
2965 cairo_content_t old_content;
2966 cairo_rectangle_int_t old_page_bbox;
2967 cairo_surface_clipper_t old_clipper;
2968 cairo_surface_t *free_me = NULL;
2969 cairo_int_status_t status;
2971 old_content = surface->content;
2972 old_width = surface->width;
2973 old_height = surface->height;
2974 old_page_bbox = surface->page_bbox;
2975 old_cairo_to_ps = surface->cairo_to_ps;
2976 old_clipper = surface->clipper;
2977 _cairo_surface_clipper_init (&surface->clipper,
2978 _cairo_ps_surface_clipper_intersect_clip_path);
2981 _cairo_output_stream_printf (surface->stream,
2982 "%% _cairo_ps_surface_emit_recording_subsurface (%d, %d), (%d, %d)\n",
2983 extents->x, extents->y,
2984 extents->width, extents->height);
2987 surface->page_bbox.x = surface->page_bbox.y = 0;
2988 surface->page_bbox.width = surface->width = extents->width;
2989 surface->page_bbox.height = surface->height = extents->height;
2991 surface->current_pattern_is_solid_color = FALSE;
2992 _cairo_pdf_operators_reset (&surface->pdf_operators);
2993 cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
2994 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
2995 &surface->cairo_to_ps);
2996 _cairo_output_stream_printf (surface->stream, " q\n");
2998 if (_cairo_surface_is_snapshot (recording_surface))
2999 free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface);
3001 if (recording_surface->content == CAIRO_CONTENT_COLOR) {
3002 surface->content = CAIRO_CONTENT_COLOR;
3003 _cairo_output_stream_printf (surface->stream,
3004 " 0 g %d %d %d %d rectfill\n",
3005 surface->page_bbox.x,
3006 surface->page_bbox.y,
3007 surface->page_bbox.width,
3008 surface->page_bbox.height);
3011 status = _cairo_recording_surface_replay_region (recording_surface,
3014 CAIRO_RECORDING_REGION_NATIVE);
3015 assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
3016 if (unlikely (status))
3019 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3020 if (unlikely (status))
3023 _cairo_output_stream_printf (surface->stream, " Q\n");
3025 _cairo_surface_clipper_reset (&surface->clipper);
3026 surface->clipper = old_clipper;
3027 surface->content = old_content;
3028 surface->width = old_width;
3029 surface->height = old_height;
3030 surface->page_bbox = old_page_bbox;
3031 surface->current_pattern_is_solid_color = FALSE;
3032 _cairo_pdf_operators_reset (&surface->pdf_operators);
3033 surface->cairo_to_ps = old_cairo_to_ps;
3035 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
3036 &surface->cairo_to_ps);
3039 cairo_surface_destroy (free_me);
3044 _cairo_ps_surface_flatten_transparency (cairo_ps_surface_t *surface,
3045 const cairo_color_t *color,
3051 *green = color->green;
3052 *blue = color->blue;
3054 if (! CAIRO_COLOR_IS_OPAQUE (color)) {
3055 *red *= color->alpha;
3056 *green *= color->alpha;
3057 *blue *= color->alpha;
3058 if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
3059 double one_minus_alpha = 1. - color->alpha;
3060 *red += one_minus_alpha;
3061 *green += one_minus_alpha;
3062 *blue += one_minus_alpha;
3068 _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
3069 cairo_solid_pattern_t *pattern)
3071 double red, green, blue;
3073 _cairo_ps_surface_flatten_transparency (surface, &pattern->color, &red, &green, &blue);
3075 if (color_is_gray (red, green, blue))
3076 _cairo_output_stream_printf (surface->stream,
3080 _cairo_output_stream_printf (surface->stream,
3085 static cairo_status_t
3086 _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
3087 cairo_pattern_t *source_pattern,
3088 cairo_surface_t *source_surface,
3089 cairo_operator_t op,
3092 cairo_bool_t stencil_mask)
3094 cairo_int_status_t status;
3096 if (source_surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
3097 if (source_surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
3098 cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source_surface;
3099 status = _cairo_ps_surface_emit_recording_subsurface (surface, sub->target, &sub->extents);
3101 status = _cairo_ps_surface_emit_recording_surface (surface, source_surface);
3104 cairo_image_surface_t *image = (cairo_image_surface_t *) source_surface;
3105 if (source_pattern->extend != CAIRO_EXTEND_PAD) {
3106 status = _cairo_ps_surface_emit_jpeg_image (surface, source_surface,
3108 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
3112 status = _cairo_ps_surface_emit_image (surface, image,
3113 op, source_pattern->filter, stencil_mask);
3121 _path_fixed_init_rectangle (cairo_path_fixed_t *path,
3122 cairo_rectangle_int_t *rect)
3124 cairo_status_t status;
3126 _cairo_path_fixed_init (path);
3128 status = _cairo_path_fixed_move_to (path,
3129 _cairo_fixed_from_int (rect->x),
3130 _cairo_fixed_from_int (rect->y));
3131 assert (status == CAIRO_STATUS_SUCCESS);
3132 status = _cairo_path_fixed_rel_line_to (path,
3133 _cairo_fixed_from_int (rect->width),
3134 _cairo_fixed_from_int (0));
3135 assert (status == CAIRO_STATUS_SUCCESS);
3136 status = _cairo_path_fixed_rel_line_to (path,
3137 _cairo_fixed_from_int (0),
3138 _cairo_fixed_from_int (rect->height));
3139 assert (status == CAIRO_STATUS_SUCCESS);
3140 status = _cairo_path_fixed_rel_line_to (path,
3141 _cairo_fixed_from_int (-rect->width),
3142 _cairo_fixed_from_int (0));
3143 assert (status == CAIRO_STATUS_SUCCESS);
3145 status = _cairo_path_fixed_close_path (path);
3146 assert (status == CAIRO_STATUS_SUCCESS);
3149 static cairo_status_t
3150 _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
3151 cairo_pattern_t *pattern,
3152 cairo_rectangle_int_t *extents,
3153 cairo_operator_t op,
3154 cairo_bool_t stencil_mask)
3156 cairo_status_t status;
3158 cairo_matrix_t cairo_p2d, ps_p2d;
3159 cairo_path_fixed_t path;
3160 double x_offset, y_offset;
3161 cairo_surface_t *source;
3162 cairo_image_surface_t *image = NULL;
3165 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3166 if (unlikely (status))
3169 status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
3173 &x_offset, &y_offset,
3176 if (unlikely (status))
3179 if (pattern->extend == CAIRO_EXTEND_PAD &&
3180 pattern->type == CAIRO_PATTERN_TYPE_SURFACE &&
3181 ((cairo_surface_pattern_t *)pattern)->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
3182 cairo_image_surface_t *img;
3184 img = (cairo_image_surface_t *) source;
3185 status = _cairo_ps_surface_create_padded_image_from_image (surface,
3190 &x_offset, &y_offset,
3192 if (unlikely (status))
3193 goto release_source;
3196 _path_fixed_init_rectangle (&path, extents);
3197 status = _cairo_pdf_operators_clip (&surface->pdf_operators,
3199 CAIRO_FILL_RULE_WINDING);
3200 _cairo_path_fixed_fini (&path);
3201 if (unlikely (status))
3202 goto release_source;
3204 cairo_p2d = pattern->matrix;
3206 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
3207 double x_scale = cairo_p2d.xx;
3208 double y_scale = cairo_p2d.yy;
3210 _cairo_output_stream_printf (surface->stream,
3211 "%% Fallback Image: x=%f y=%f w=%d h=%d ",
3212 -cairo_p2d.x0/x_scale,
3213 -cairo_p2d.y0/y_scale,
3214 (int)(width/x_scale),
3215 (int)(height/y_scale));
3216 if (x_scale == y_scale) {
3217 _cairo_output_stream_printf (surface->stream,
3221 _cairo_output_stream_printf (surface->stream,
3226 _cairo_output_stream_printf (surface->stream,
3228 (long)width*height*3);
3230 if (op == CAIRO_OPERATOR_SOURCE) {
3231 _cairo_output_stream_printf (surface->stream,
3232 "%d g 0 0 %f %f rectfill\n",
3233 surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
3239 status = cairo_matrix_invert (&cairo_p2d);
3240 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3241 assert (status == CAIRO_STATUS_SUCCESS);
3243 ps_p2d = surface->cairo_to_ps;
3244 cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
3245 cairo_matrix_translate (&ps_p2d, x_offset, y_offset);
3246 cairo_matrix_translate (&ps_p2d, 0.0, height);
3247 cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
3249 if (! _cairo_matrix_is_identity (&ps_p2d)) {
3250 _cairo_output_stream_printf (surface->stream,
3251 "[ %f %f %f %f %f %f ] concat\n",
3252 ps_p2d.xx, ps_p2d.yx,
3253 ps_p2d.xy, ps_p2d.yy,
3254 ps_p2d.x0, ps_p2d.y0);
3257 status = _cairo_ps_surface_emit_surface (surface,
3259 image ? &image->base : source,
3266 cairo_surface_destroy (&image->base);
3268 _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
3273 static cairo_status_t
3274 _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
3275 cairo_pattern_t *pattern,
3276 cairo_rectangle_int_t *extents,
3277 cairo_operator_t op)
3279 cairo_status_t status;
3280 int pattern_width = 0; /* squelch bogus compiler warning */
3281 int pattern_height = 0; /* squelch bogus compiler warning */
3282 double xstep, ystep;
3283 cairo_matrix_t cairo_p2d, ps_p2d;
3284 cairo_bool_t old_use_string_datasource;
3285 double x_offset, y_offset;
3286 cairo_surface_t *source;
3287 cairo_image_surface_t *image = NULL;
3290 cairo_p2d = pattern->matrix;
3291 status = cairo_matrix_invert (&cairo_p2d);
3292 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3293 assert (status == CAIRO_STATUS_SUCCESS);
3295 status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
3298 &pattern_width, &pattern_height,
3299 &x_offset, &y_offset,
3302 if (unlikely (status))
3305 if (pattern->extend == CAIRO_EXTEND_PAD) {
3306 cairo_image_surface_t *img;
3308 assert (source->type == CAIRO_SURFACE_TYPE_IMAGE);
3309 img = (cairo_image_surface_t *) source;
3310 status = _cairo_ps_surface_create_padded_image_from_image (surface,
3314 &pattern_width, &pattern_height,
3315 &x_offset, &y_offset,
3317 if (unlikely (status))
3318 goto release_source;
3320 if (unlikely (status))
3321 goto release_source;
3323 switch (pattern->extend) {
3324 case CAIRO_EXTEND_PAD:
3325 case CAIRO_EXTEND_NONE:
3327 /* In PS/PDF, (as far as I can tell), all patterns are
3328 * repeating. So we support cairo's EXTEND_NONE semantics
3329 * by setting the repeat step size to a size large enough
3330 * to guarantee that no more than a single occurrence will
3333 * First, map the surface extents into pattern space (since
3334 * xstep and ystep are in pattern space). Then use an upper
3335 * bound on the length of the diagonal of the pattern image
3336 * and the surface as repeat size. This guarantees to never
3339 double x1 = 0.0, y1 = 0.0;
3340 double x2 = surface->width, y2 = surface->height;
3341 _cairo_matrix_transform_bounding_box (&pattern->matrix,
3345 /* Rather than computing precise bounds of the union, just
3346 * add the surface extents unconditionally. We only
3347 * required an answer that's large enough, we don't really
3348 * care if it's not as tight as possible.*/
3349 xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
3350 pattern_width + pattern_height);
3353 case CAIRO_EXTEND_REPEAT:
3354 xstep = pattern_width;
3355 ystep = pattern_height;
3357 case CAIRO_EXTEND_REFLECT:
3358 xstep = pattern_width*2;
3359 ystep = pattern_height*2;
3361 /* All the rest (if any) should have been analyzed away, so these
3362 * cases should be unreachable. */
3369 _cairo_output_stream_printf (surface->stream,
3370 "/CairoPattern {\n");
3372 old_use_string_datasource = surface->use_string_datasource;
3373 surface->use_string_datasource = TRUE;
3374 if (op == CAIRO_OPERATOR_SOURCE) {
3375 _cairo_output_stream_printf (surface->stream,
3376 "%d g 0 0 %f %f rectfill\n",
3377 surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
3380 status = _cairo_ps_surface_emit_surface (surface,
3382 image ? &image->base : source,
3384 pattern_width, pattern_height, FALSE);
3385 if (unlikely (status))
3386 goto release_source;
3388 surface->use_string_datasource = old_use_string_datasource;
3389 _cairo_output_stream_printf (surface->stream,
3392 _cairo_output_stream_printf (surface->stream,
3393 "<< /PatternType 1\n"
3395 " /TilingType 1\n");
3396 _cairo_output_stream_printf (surface->stream,
3397 " /XStep %f /YStep %f\n",
3400 if (pattern->extend == CAIRO_EXTEND_REFLECT) {
3401 _cairo_output_stream_printf (surface->stream,
3402 " /BBox [0 0 %d %d]\n"
3405 " [-1 0 0 1 %d 0] concat CairoPattern\n"
3406 " [ 1 0 0 -1 0 %d] concat CairoPattern\n"
3407 " [-1 0 0 1 %d 0] concat CairoPattern\n"
3410 pattern_width*2, pattern_height*2,
3415 if (op == CAIRO_OPERATOR_SOURCE) {
3416 _cairo_output_stream_printf (surface->stream,
3417 " /BBox [0 0 %f %f]\n",
3420 _cairo_output_stream_printf (surface->stream,
3421 " /BBox [0 0 %d %d]\n",
3422 pattern_width, pattern_height);
3424 _cairo_output_stream_printf (surface->stream,
3425 " /PaintProc { CairoPattern }\n");
3428 _cairo_output_stream_printf (surface->stream,
3431 cairo_p2d = pattern->matrix;
3432 status = cairo_matrix_invert (&cairo_p2d);
3433 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3434 assert (status == CAIRO_STATUS_SUCCESS);
3436 cairo_matrix_init_identity (&ps_p2d);
3437 cairo_matrix_translate (&ps_p2d, 0.0, surface->height);
3438 cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
3439 cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
3440 cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
3441 cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
3443 _cairo_output_stream_printf (surface->stream,
3444 "[ %f %f %f %f %f %f ]\n",
3445 ps_p2d.xx, ps_p2d.yx,
3446 ps_p2d.xy, ps_p2d.yy,
3447 ps_p2d.x0, ps_p2d.y0);
3448 _cairo_output_stream_printf (surface->stream,
3449 "makepattern setpattern\n");
3453 cairo_surface_destroy (&image->base);
3455 _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
3460 typedef struct _cairo_ps_color_stop {
3463 } cairo_ps_color_stop_t;
3466 _cairo_ps_surface_emit_linear_colorgradient (cairo_ps_surface_t *surface,
3467 cairo_ps_color_stop_t *stop1,
3468 cairo_ps_color_stop_t *stop2)
3470 _cairo_output_stream_printf (surface->stream,
3471 " << /FunctionType 2\n"
3472 " /Domain [ 0 1 ]\n"
3473 " /C0 [ %f %f %f ]\n"
3474 " /C1 [ %f %f %f ]\n"
3486 _cairo_ps_surface_emit_stitched_colorgradient (cairo_ps_surface_t *surface,
3487 unsigned int n_stops,
3488 cairo_ps_color_stop_t stops[])
3492 _cairo_output_stream_printf (surface->stream,
3493 "<< /FunctionType 3\n"
3494 " /Domain [ 0 1 ]\n"
3496 for (i = 0; i < n_stops - 1; i++)
3497 _cairo_ps_surface_emit_linear_colorgradient (surface, &stops[i], &stops[i+1]);
3499 _cairo_output_stream_printf (surface->stream, " ]\n");
3501 _cairo_output_stream_printf (surface->stream, " /Bounds [ ");
3502 for (i = 1; i < n_stops-1; i++)
3503 _cairo_output_stream_printf (surface->stream, "%f ", stops[i].offset);
3504 _cairo_output_stream_printf (surface->stream, "]\n");
3506 _cairo_output_stream_printf (surface->stream, " /Encode [ 1 1 %d { pop 0 1 } for ]\n",
3509 _cairo_output_stream_printf (surface->stream, ">>\n");
3513 calc_gradient_color (cairo_ps_color_stop_t *new_stop,
3514 cairo_ps_color_stop_t *stop1,
3515 cairo_ps_color_stop_t *stop2)
3518 double offset = stop1->offset / (stop1->offset + 1.0 - stop2->offset);
3520 for (i = 0; i < 4; i++)
3521 new_stop->color[i] = stop1->color[i] + offset*(stop2->color[i] - stop1->color[i]);
3524 #define COLOR_STOP_EPSILON 1e-6
3526 static cairo_status_t
3527 _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t *surface,
3528 cairo_gradient_pattern_t *pattern)
3530 cairo_ps_color_stop_t *allstops, *stops;
3531 unsigned int i, n_stops;
3533 allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_ps_color_stop_t));
3534 if (unlikely (allstops == NULL))
3535 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3537 stops = &allstops[1];
3538 n_stops = pattern->n_stops;
3540 for (i = 0; i < n_stops; i++) {
3541 cairo_gradient_stop_t *stop = &pattern->stops[i];
3543 stops[i].color[0] = stop->color.red;
3544 stops[i].color[1] = stop->color.green;
3545 stops[i].color[2] = stop->color.blue;
3546 stops[i].color[3] = stop->color.alpha;
3547 stops[i].offset = pattern->stops[i].offset;
3550 if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
3551 pattern->base.extend == CAIRO_EXTEND_REFLECT)
3553 if (stops[0].offset > COLOR_STOP_EPSILON) {
3554 if (pattern->base.extend == CAIRO_EXTEND_REFLECT)
3555 memcpy (allstops, stops, sizeof (cairo_ps_color_stop_t));
3557 calc_gradient_color (&allstops[0], &stops[0], &stops[n_stops-1]);
3561 stops[0].offset = 0.0;
3563 if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
3564 if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
3565 memcpy (&stops[n_stops],
3566 &stops[n_stops - 1],
3567 sizeof (cairo_ps_color_stop_t));
3569 calc_gradient_color (&stops[n_stops], &stops[0], &stops[n_stops-1]);
3573 stops[n_stops-1].offset = 1.0;
3576 for (i = 0; i < n_stops; i++) {
3577 double red, green, blue;
3578 cairo_color_t color;
3580 _cairo_color_init_rgba (&color,
3585 _cairo_ps_surface_flatten_transparency (surface, &color,
3586 &red, &green, &blue);
3587 stops[i].color[0] = red;
3588 stops[i].color[1] = green;
3589 stops[i].color[2] = blue;
3592 _cairo_output_stream_printf (surface->stream,
3593 "/CairoFunction\n");
3594 if (stops[0].offset == stops[n_stops - 1].offset) {
3596 * The first and the last stops have the same offset, but we
3597 * don't want a function with an empty domain, because that
3598 * would provoke underdefined behaviour from rasterisers.
3599 * This can only happen with EXTEND_PAD, because EXTEND_NONE
3600 * is optimised into a clear pattern in cairo-gstate, and
3601 * REFLECT/REPEAT are always transformed to have the first
3602 * stop at t=0 and the last stop at t=1. Thus we want a step
3603 * function going from the first color to the last one.
3605 * This can be accomplished by stitching three functions:
3606 * - a constant first color function,
3607 * - a step from the first color to the last color (with empty domain)
3608 * - a constant last color function
3610 cairo_ps_color_stop_t pad_stops[4];
3612 assert (pattern->base.extend == CAIRO_EXTEND_PAD);
3614 pad_stops[0] = pad_stops[1] = stops[0];
3615 pad_stops[2] = pad_stops[3] = stops[n_stops - 1];
3617 pad_stops[0].offset = 0;
3618 pad_stops[3].offset = 1;
3620 _cairo_ps_surface_emit_stitched_colorgradient (surface, 4, pad_stops);
3621 } else if (n_stops == 2) {
3622 /* no need for stitched function */
3623 _cairo_ps_surface_emit_linear_colorgradient (surface, &stops[0], &stops[1]);
3625 /* multiple stops: stitch. XXX possible optimization: regulary spaced
3626 * stops do not require stitching. XXX */
3627 _cairo_ps_surface_emit_stitched_colorgradient (surface, n_stops, stops);
3629 _cairo_output_stream_printf (surface->stream,
3634 return CAIRO_STATUS_SUCCESS;
3637 static cairo_status_t
3638 _cairo_ps_surface_emit_repeating_function (cairo_ps_surface_t *surface,
3639 cairo_gradient_pattern_t *pattern,
3643 _cairo_output_stream_printf (surface->stream,
3645 "<< /FunctionType 3\n"
3646 " /Domain [ %d %d ]\n"
3647 " /Functions [ %d {CairoFunction} repeat ]\n"
3648 " /Bounds [ %d 1 %d {} for ]\n",
3655 if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
3656 _cairo_output_stream_printf (surface->stream, " /Encode [ %d 1 %d { 2 mod 0 eq {0 1} {1 0} ifelse } for ]\n",
3660 _cairo_output_stream_printf (surface->stream, " /Encode [ %d 1 %d { pop 0 1 } for ]\n",
3665 _cairo_output_stream_printf (surface->stream, ">> def\n");
3667 return CAIRO_STATUS_SUCCESS;
3670 static cairo_status_t
3671 _cairo_ps_surface_emit_gradient (cairo_ps_surface_t *surface,
3672 cairo_gradient_pattern_t *pattern,
3673 cairo_bool_t is_ps_pattern)
3675 cairo_matrix_t pat_to_ps;
3676 cairo_circle_double_t start, end;
3678 cairo_status_t status;
3680 assert (pattern->n_stops != 0);
3682 status = _cairo_ps_surface_emit_pattern_stops (surface, pattern);
3683 if (unlikely (status))
3686 pat_to_ps = pattern->base.matrix;
3687 status = cairo_matrix_invert (&pat_to_ps);
3688 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3689 assert (status == CAIRO_STATUS_SUCCESS);
3690 cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
3692 if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
3693 pattern->base.extend == CAIRO_EXTEND_REFLECT)
3695 double bounds_x1, bounds_x2, bounds_y1, bounds_y2;
3696 double x_scale, y_scale, tolerance;
3698 /* TODO: use tighter extents */
3701 bounds_x2 = surface->width;
3702 bounds_y2 = surface->height;
3703 _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
3704 &bounds_x1, &bounds_y1,
3705 &bounds_x2, &bounds_y2,
3708 x_scale = surface->base.x_resolution / surface->base.x_fallback_resolution;
3709 y_scale = surface->base.y_resolution / surface->base.y_fallback_resolution;
3711 tolerance = fabs (_cairo_matrix_compute_determinant (&pattern->base.matrix));
3712 tolerance /= _cairo_matrix_transformed_circle_major_axis (&pattern->base.matrix, 1);
3713 tolerance *= MIN (x_scale, y_scale);
3715 _cairo_gradient_pattern_box_to_parameter (pattern,
3716 bounds_x1, bounds_y1,
3717 bounds_x2, bounds_y2,
3719 } else if (pattern->stops[0].offset == pattern->stops[pattern->n_stops - 1].offset) {
3721 * If the first and the last stop offset are the same, then
3722 * the color function is a step function.
3723 * _cairo_ps_surface_emit_pattern_stops emits it as a stitched
3724 * function no matter how many stops the pattern has. The
3725 * domain of the stitched function will be [0 1] in this case.
3727 * This is done to avoid emitting degenerate gradients for
3728 * EXTEND_PAD patterns having a step color function.
3733 assert (pattern->base.extend == CAIRO_EXTEND_PAD);
3735 domain[0] = pattern->stops[0].offset;
3736 domain[1] = pattern->stops[pattern->n_stops - 1].offset;
3739 /* PS requires the first and last stop to be the same as the
3740 * extreme coordinates. For repeating patterns this moves the
3741 * extreme coordinates out to the begin/end of the repeating
3742 * function. For non repeating patterns this may move the extreme
3743 * coordinates in if there are not stops at offset 0 and 1. */
3744 _cairo_gradient_pattern_interpolate (pattern, domain[0], &start);
3745 _cairo_gradient_pattern_interpolate (pattern, domain[1], &end);
3747 if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
3748 pattern->base.extend == CAIRO_EXTEND_REFLECT)
3750 int repeat_begin, repeat_end;
3752 repeat_begin = floor (domain[0]);
3753 repeat_end = ceil (domain[1]);
3755 status = _cairo_ps_surface_emit_repeating_function (surface,
3759 if (unlikely (status))
3761 } else if (pattern->n_stops <= 2) {
3762 /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a
3763 * Type 2 function is used by itself without a stitching
3764 * function. Type 2 functions always have the domain [0 1] */
3769 if (is_ps_pattern) {
3770 _cairo_output_stream_printf (surface->stream,
3771 "<< /PatternType 2\n"
3775 if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
3776 _cairo_output_stream_printf (surface->stream,
3777 " << /ShadingType 2\n"
3778 " /ColorSpace /DeviceRGB\n"
3779 " /Coords [ %f %f %f %f ]\n",
3780 start.center.x, start.center.y,
3781 end.center.x, end.center.y);
3783 _cairo_output_stream_printf (surface->stream,
3784 " << /ShadingType 3\n"
3785 " /ColorSpace /DeviceRGB\n"
3786 " /Coords [ %f %f %f %f %f %f ]\n",
3787 start.center.x, start.center.y,
3788 MAX (start.radius, 0),
3789 end.center.x, end.center.y,
3790 MAX (end.radius, 0));
3793 if (pattern->base.extend != CAIRO_EXTEND_NONE) {
3794 _cairo_output_stream_printf (surface->stream,
3795 " /Extend [ true true ]\n");
3797 _cairo_output_stream_printf (surface->stream,
3798 " /Extend [ false false ]\n");
3801 if (domain[0] == 0.0 && domain[1] == 1.0) {
3802 _cairo_output_stream_printf (surface->stream,
3803 " /Function CairoFunction\n");
3805 _cairo_output_stream_printf (surface->stream,
3807 " /FunctionType 3\n"
3808 " /Domain [ 0 1 ]\n"
3810 " /Encode [ %f %f ]\n"
3811 " /Functions [ CairoFunction ]\n"
3813 domain[0], domain[1]);
3816 _cairo_output_stream_printf (surface->stream,
3819 if (is_ps_pattern) {
3820 _cairo_output_stream_printf (surface->stream,
3822 "[ %f %f %f %f %f %f ]\n"
3823 "makepattern setpattern\n",
3824 pat_to_ps.xx, pat_to_ps.yx,
3825 pat_to_ps.xy, pat_to_ps.yy,
3826 pat_to_ps.x0, pat_to_ps.y0);
3828 _cairo_output_stream_printf (surface->stream,
3835 static cairo_status_t
3836 _cairo_ps_surface_emit_mesh_pattern (cairo_ps_surface_t *surface,
3837 cairo_mesh_pattern_t *pattern,
3838 cairo_bool_t is_ps_pattern)
3840 cairo_matrix_t pat_to_ps;
3841 cairo_status_t status;
3842 cairo_pdf_shading_t shading;
3845 if (_cairo_array_num_elements (&pattern->patches) == 0)
3846 return CAIRO_INT_STATUS_NOTHING_TO_DO;
3848 pat_to_ps = pattern->base.matrix;
3849 status = cairo_matrix_invert (&pat_to_ps);
3850 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3851 assert (status == CAIRO_STATUS_SUCCESS);
3853 cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
3855 status = _cairo_pdf_shading_init_color (&shading, pattern);
3856 if (unlikely (status))
3859 _cairo_output_stream_printf (surface->stream,
3861 "/ASCII85Decode filter /FlateDecode filter /ReusableStreamDecode filter\n");
3863 status = _cairo_ps_surface_emit_base85_string (surface,
3865 shading.data_length,
3866 CAIRO_PS_COMPRESS_DEFLATE,
3871 _cairo_output_stream_printf (surface->stream,
3873 "/CairoData exch def\n");
3875 if (is_ps_pattern) {
3876 _cairo_output_stream_printf (surface->stream,
3877 "<< /PatternType 2\n"
3881 _cairo_output_stream_printf (surface->stream,
3882 " << /ShadingType %d\n"
3883 " /ColorSpace /DeviceRGB\n"
3884 " /DataSource CairoData\n"
3885 " /BitsPerCoordinate %d\n"
3886 " /BitsPerComponent %d\n"
3887 " /BitsPerFlag %d\n"
3889 shading.shading_type,
3890 shading.bits_per_coordinate,
3891 shading.bits_per_component,
3892 shading.bits_per_flag);
3894 for (i = 0; i < shading.decode_array_length; i++)
3895 _cairo_output_stream_printf (surface->stream, "%f ", shading.decode_array[i]);
3897 _cairo_output_stream_printf (surface->stream,
3901 if (is_ps_pattern) {
3902 _cairo_output_stream_printf (surface->stream,
3904 "[ %f %f %f %f %f %f ]\n",
3905 pat_to_ps.xx, pat_to_ps.yx,
3906 pat_to_ps.xy, pat_to_ps.yy,
3907 pat_to_ps.x0, pat_to_ps.y0);
3908 _cairo_output_stream_printf (surface->stream,
3912 _cairo_output_stream_printf (surface->stream, "shfill\n");
3915 _cairo_output_stream_printf (surface->stream,
3916 "currentdict /CairoData undef\n");
3918 _cairo_pdf_shading_fini (&shading);
3923 static cairo_status_t
3924 _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
3925 const cairo_pattern_t *pattern,
3926 cairo_rectangle_int_t *extents,
3927 cairo_operator_t op)
3929 cairo_status_t status;
3931 if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
3932 cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
3934 if (surface->current_pattern_is_solid_color == FALSE ||
3935 ! _cairo_color_equal (&surface->current_color, &solid->color))
3937 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3938 if (unlikely (status))
3941 _cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
3943 surface->current_pattern_is_solid_color = TRUE;
3944 surface->current_color = solid->color;
3947 return CAIRO_STATUS_SUCCESS;
3950 surface->current_pattern_is_solid_color = FALSE;
3951 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3952 if (unlikely (status))
3955 switch (pattern->type) {
3956 case CAIRO_PATTERN_TYPE_SOLID:
3958 _cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
3961 case CAIRO_PATTERN_TYPE_SURFACE:
3962 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
3963 status = _cairo_ps_surface_emit_surface_pattern (surface,
3964 (cairo_pattern_t *)pattern,
3967 if (unlikely (status))
3971 case CAIRO_PATTERN_TYPE_LINEAR:
3972 case CAIRO_PATTERN_TYPE_RADIAL:
3973 status = _cairo_ps_surface_emit_gradient (surface,
3974 (cairo_gradient_pattern_t *) pattern,
3976 if (unlikely (status))
3980 case CAIRO_PATTERN_TYPE_MESH:
3981 status = _cairo_ps_surface_emit_mesh_pattern (surface,
3982 (cairo_mesh_pattern_t *) pattern,
3984 if (unlikely (status))
3989 return CAIRO_STATUS_SUCCESS;
3992 static cairo_status_t
3993 _cairo_ps_surface_paint_gradient (cairo_ps_surface_t *surface,
3994 const cairo_pattern_t *source,
3995 const cairo_rectangle_int_t *extents)
3997 cairo_matrix_t pat_to_ps;
3998 cairo_status_t status;
4000 pat_to_ps = source->matrix;
4001 status = cairo_matrix_invert (&pat_to_ps);
4002 /* cairo_pattern_set_matrix ensures the matrix is invertible */
4003 assert (status == CAIRO_STATUS_SUCCESS);
4004 cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
4006 if (! _cairo_matrix_is_identity (&pat_to_ps)) {
4007 _cairo_output_stream_printf (surface->stream,
4008 "[%f %f %f %f %f %f] concat\n",
4009 pat_to_ps.xx, pat_to_ps.yx,
4010 pat_to_ps.xy, pat_to_ps.yy,
4011 pat_to_ps.x0, pat_to_ps.y0);
4014 if (source->type == CAIRO_PATTERN_TYPE_MESH) {
4015 status = _cairo_ps_surface_emit_mesh_pattern (surface,
4016 (cairo_mesh_pattern_t *)source,
4018 if (unlikely (status))
4021 status = _cairo_ps_surface_emit_gradient (surface,
4022 (cairo_gradient_pattern_t *)source,
4024 if (unlikely (status))
4031 static cairo_status_t
4032 _cairo_ps_surface_paint_pattern (cairo_ps_surface_t *surface,
4033 const cairo_pattern_t *source,
4034 cairo_rectangle_int_t *extents,
4035 cairo_operator_t op,
4036 cairo_bool_t stencil_mask)
4038 switch (source->type) {
4039 case CAIRO_PATTERN_TYPE_SURFACE:
4040 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
4041 return _cairo_ps_surface_paint_surface (surface,
4042 (cairo_pattern_t *)source,
4047 case CAIRO_PATTERN_TYPE_LINEAR:
4048 case CAIRO_PATTERN_TYPE_RADIAL:
4049 case CAIRO_PATTERN_TYPE_MESH:
4050 return _cairo_ps_surface_paint_gradient (surface,
4054 case CAIRO_PATTERN_TYPE_SOLID:
4057 return CAIRO_STATUS_SUCCESS;
4062 _can_paint_pattern (const cairo_pattern_t *pattern)
4064 switch (pattern->type) {
4065 case CAIRO_PATTERN_TYPE_SOLID:
4068 case CAIRO_PATTERN_TYPE_SURFACE:
4069 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
4070 return (pattern->extend == CAIRO_EXTEND_NONE ||
4071 pattern->extend == CAIRO_EXTEND_PAD);
4073 case CAIRO_PATTERN_TYPE_LINEAR:
4074 case CAIRO_PATTERN_TYPE_RADIAL:
4075 case CAIRO_PATTERN_TYPE_MESH:
4085 _cairo_ps_surface_get_extents (void *abstract_surface,
4086 cairo_rectangle_int_t *rectangle)
4088 cairo_ps_surface_t *surface = abstract_surface;
4093 /* XXX: The conversion to integers here is pretty bogus, (not to
4094 * mention the aribitray limitation of width to a short(!). We
4095 * may need to come up with a better interface for get_extents.
4097 rectangle->width = ceil (surface->width);
4098 rectangle->height = ceil (surface->height);
4104 _cairo_ps_surface_get_font_options (void *abstract_surface,
4105 cairo_font_options_t *options)
4107 _cairo_font_options_init_default (options);
4109 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
4110 cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
4111 cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
4112 _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_OFF);
4115 static cairo_int_status_t
4116 _cairo_ps_surface_set_clip (cairo_ps_surface_t *surface,
4117 cairo_composite_rectangles_t *composite)
4119 cairo_clip_t *clip = composite->clip;
4121 if (_cairo_composite_rectangles_can_reduce_clip (composite, clip))
4125 if (_cairo_composite_rectangles_can_reduce_clip (composite,
4126 surface->clipper.clip))
4127 return CAIRO_STATUS_SUCCESS;
4130 return _cairo_surface_clipper_set_clip (&surface->clipper, clip);
4133 static cairo_int_status_t
4134 _cairo_ps_surface_paint (void *abstract_surface,
4135 cairo_operator_t op,
4136 const cairo_pattern_t *source,
4137 const cairo_clip_t *clip)
4139 cairo_ps_surface_t *surface = abstract_surface;
4140 cairo_output_stream_t *stream = surface->stream;
4141 cairo_composite_rectangles_t extents;
4142 cairo_status_t status;
4144 status = _cairo_composite_rectangles_init_for_paint (&extents,
4147 if (unlikely (status))
4150 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4151 status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
4152 goto cleanup_composite;
4155 assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
4158 _cairo_output_stream_printf (stream,
4159 "%% _cairo_ps_surface_paint\n");
4162 status = _cairo_ps_surface_set_clip (surface, &extents);
4163 if (unlikely (status))
4164 goto cleanup_composite;
4166 if (_can_paint_pattern (source)) {
4167 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4168 if (unlikely (status))
4169 goto cleanup_composite;
4171 _cairo_output_stream_printf (stream, "q\n");
4172 status = _cairo_ps_surface_paint_pattern (surface,
4174 &extents.bounded, op, FALSE);
4175 if (unlikely (status))
4176 goto cleanup_composite;
4178 _cairo_output_stream_printf (stream, "Q\n");
4180 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4181 if (unlikely (status))
4182 goto cleanup_composite;
4184 _cairo_output_stream_printf (stream, "0 0 %f %f rectfill\n",
4185 surface->width, surface->height);
4189 _cairo_composite_rectangles_fini (&extents);
4193 static cairo_int_status_t
4194 _cairo_ps_surface_mask (void *abstract_surface,
4195 cairo_operator_t op,
4196 const cairo_pattern_t *source,
4197 const cairo_pattern_t *mask,
4198 const cairo_clip_t *clip)
4200 cairo_ps_surface_t *surface = abstract_surface;
4201 cairo_output_stream_t *stream = surface->stream;
4202 cairo_composite_rectangles_t extents;
4203 cairo_status_t status;
4205 status = _cairo_composite_rectangles_init_for_mask (&extents,
4207 op, source, mask, clip);
4208 if (unlikely (status))
4211 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4212 status = _cairo_ps_surface_analyze_operation (surface, op, source, mask, &extents.bounded);
4213 goto cleanup_composite;
4216 assert (_cairo_ps_surface_operation_supported (surface, op, source, mask, &extents.bounded));
4219 _cairo_output_stream_printf (stream,
4220 "%% _cairo_ps_surface_mask\n");
4223 status = _cairo_ps_surface_set_clip (surface, &extents);
4224 if (unlikely (status))
4225 goto cleanup_composite;
4227 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4228 if (unlikely (status))
4229 goto cleanup_composite;
4231 _cairo_output_stream_printf (stream, "q\n");
4232 status = _cairo_ps_surface_paint_pattern (surface,
4234 &extents.bounded, op, TRUE);
4235 if (unlikely (status))
4236 goto cleanup_composite;
4238 _cairo_output_stream_printf (stream, "Q\n");
4241 _cairo_composite_rectangles_fini (&extents);
4245 static cairo_int_status_t
4246 _cairo_ps_surface_stroke (void *abstract_surface,
4247 cairo_operator_t op,
4248 const cairo_pattern_t *source,
4249 const cairo_path_fixed_t *path,
4250 const cairo_stroke_style_t *style,
4251 const cairo_matrix_t *ctm,
4252 const cairo_matrix_t *ctm_inverse,
4254 cairo_antialias_t antialias,
4255 const cairo_clip_t *clip)
4257 cairo_ps_surface_t *surface = abstract_surface;
4258 cairo_composite_rectangles_t extents;
4259 cairo_int_status_t status;
4261 status = _cairo_composite_rectangles_init_for_stroke (&extents,
4266 if (unlikely (status))
4269 /* use the more accurate extents */
4271 cairo_rectangle_int_t r;
4274 status = _cairo_path_fixed_stroke_extents (path, style,
4278 if (unlikely (status))
4279 goto cleanup_composite;
4281 _cairo_box_from_rectangle (&b, &r);
4282 status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b);
4283 if (unlikely (status))
4284 goto cleanup_composite;
4287 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4288 status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
4289 goto cleanup_composite;
4292 assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
4295 _cairo_output_stream_printf (surface->stream,
4296 "%% _cairo_ps_surface_stroke\n");
4299 status = _cairo_ps_surface_set_clip (surface, &extents);
4300 if (unlikely (status))
4301 goto cleanup_composite;
4303 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4304 if (unlikely (status))
4305 goto cleanup_composite;
4307 status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
4314 _cairo_composite_rectangles_fini (&extents);
4318 static cairo_int_status_t
4319 _cairo_ps_surface_fill (void *abstract_surface,
4320 cairo_operator_t op,
4321 const cairo_pattern_t *source,
4322 const cairo_path_fixed_t*path,
4323 cairo_fill_rule_t fill_rule,
4325 cairo_antialias_t antialias,
4326 const cairo_clip_t *clip)
4328 cairo_ps_surface_t *surface = abstract_surface;
4329 cairo_composite_rectangles_t extents;
4330 cairo_int_status_t status;
4332 status = _cairo_composite_rectangles_init_for_fill (&extents,
4336 if (unlikely (status))
4339 /* use the more accurate extents */
4341 cairo_rectangle_int_t r;
4344 _cairo_path_fixed_fill_extents (path,
4349 _cairo_box_from_rectangle (&b, &r);
4350 status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b);
4351 if (unlikely (status))
4352 goto cleanup_composite;
4355 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4356 status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
4357 goto cleanup_composite;
4360 assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
4363 _cairo_output_stream_printf (surface->stream,
4364 "%% _cairo_ps_surface_fill\n");
4367 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4368 if (unlikely (status))
4369 goto cleanup_composite;
4371 status = _cairo_ps_surface_set_clip (surface, &extents);
4372 if (unlikely (status))
4373 goto cleanup_composite;
4375 if (_can_paint_pattern (source)) {
4376 _cairo_output_stream_printf (surface->stream, "q\n");
4378 status = _cairo_pdf_operators_clip (&surface->pdf_operators,
4381 if (unlikely (status))
4382 goto cleanup_composite;
4384 status = _cairo_ps_surface_paint_pattern (surface,
4386 &extents.bounded, op, FALSE);
4387 if (unlikely (status))
4388 goto cleanup_composite;
4390 _cairo_output_stream_printf (surface->stream, "Q\n");
4391 _cairo_pdf_operators_reset (&surface->pdf_operators);
4393 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4394 if (unlikely (status))
4395 goto cleanup_composite;
4397 status = _cairo_pdf_operators_fill (&surface->pdf_operators,
4403 _cairo_composite_rectangles_fini (&extents);
4408 _cairo_ps_surface_has_show_text_glyphs (void *abstract_surface)
4413 static cairo_int_status_t
4414 _cairo_ps_surface_show_text_glyphs (void *abstract_surface,
4415 cairo_operator_t op,
4416 const cairo_pattern_t *source,
4419 cairo_glyph_t *glyphs,
4421 const cairo_text_cluster_t *clusters,
4423 cairo_text_cluster_flags_t cluster_flags,
4424 cairo_scaled_font_t *scaled_font,
4425 const cairo_clip_t *clip)
4427 cairo_ps_surface_t *surface = abstract_surface;
4428 cairo_composite_rectangles_t extents;
4429 cairo_bool_t overlap;
4430 cairo_status_t status;
4432 status = _cairo_composite_rectangles_init_for_glyphs (&extents,
4439 if (unlikely (status))
4442 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4443 status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
4444 goto cleanup_composite;
4447 assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
4450 _cairo_output_stream_printf (surface->stream,
4451 "%% _cairo_ps_surface_show_glyphs\n");
4454 status = _cairo_ps_surface_set_clip (surface, &extents);
4455 if (unlikely (status))
4456 goto cleanup_composite;
4458 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4459 if (unlikely (status))
4460 goto cleanup_composite;
4462 status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
4465 clusters, num_clusters,
4470 _cairo_composite_rectangles_fini (&extents);
4474 static const char **
4475 _cairo_ps_surface_get_supported_mime_types (void *abstract_surface)
4477 return _cairo_ps_supported_mime_types;
4481 _cairo_ps_surface_set_paginated_mode (void *abstract_surface,
4482 cairo_paginated_mode_t paginated_mode)
4484 cairo_ps_surface_t *surface = abstract_surface;
4485 cairo_status_t status;
4487 surface->paginated_mode = paginated_mode;
4489 if (surface->clipper.clip != NULL) {
4490 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4492 _cairo_output_stream_printf (surface->stream, "Q q\n");
4493 _cairo_surface_clipper_reset (&surface->clipper);
4497 static cairo_int_status_t
4498 _cairo_ps_surface_set_bounding_box (void *abstract_surface,
4501 cairo_ps_surface_t *surface = abstract_surface;
4502 int i, num_comments;
4505 cairo_bool_t has_page_media, has_page_bbox;
4506 const char *page_media;
4508 x1 = floor (_cairo_fixed_to_double (bbox->p1.x));
4509 y1 = floor (surface->height - _cairo_fixed_to_double (bbox->p2.y));
4510 x2 = ceil (_cairo_fixed_to_double (bbox->p2.x));
4511 y2 = ceil (surface->height - _cairo_fixed_to_double (bbox->p1.y));
4513 surface->page_bbox.x = x1;
4514 surface->page_bbox.y = y1;
4515 surface->page_bbox.width = x2 - x1;
4516 surface->page_bbox.height = y2 - y1;
4518 _cairo_output_stream_printf (surface->stream,
4519 "%%%%Page: %d %d\n",
4521 surface->num_pages);
4523 _cairo_output_stream_printf (surface->stream,
4524 "%%%%BeginPageSetup\n");
4526 has_page_media = FALSE;
4527 has_page_bbox = FALSE;
4528 num_comments = _cairo_array_num_elements (&surface->dsc_page_setup_comments);
4529 comments = _cairo_array_index (&surface->dsc_page_setup_comments, 0);
4530 for (i = 0; i < num_comments; i++) {
4531 _cairo_output_stream_printf (surface->stream,
4532 "%s\n", comments[i]);
4533 if (strncmp (comments[i], "%%PageMedia:", 11) == 0)
4534 has_page_media = TRUE;
4536 if (strncmp (comments[i], "%%PageBoundingBox:", 18) == 0)
4537 has_page_bbox = TRUE;
4542 _cairo_array_truncate (&surface->dsc_page_setup_comments, 0);
4544 if (!has_page_media && !surface->eps) {
4545 page_media = _cairo_ps_surface_get_page_media (surface);
4546 if (unlikely (page_media == NULL))
4547 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4549 _cairo_output_stream_printf (surface->stream,
4550 "%%%%PageMedia: %s\n",
4554 if (!has_page_bbox) {
4555 _cairo_output_stream_printf (surface->stream,
4556 "%%%%PageBoundingBox: %d %d %d %d\n",
4560 _cairo_output_stream_printf (surface->stream,
4561 "%%%%EndPageSetup\n"
4562 "q %d %d %d %d rectclip q\n",
4563 surface->page_bbox.x,
4564 surface->page_bbox.y,
4565 surface->page_bbox.width,
4566 surface->page_bbox.height);
4568 if (surface->num_pages == 1) {
4569 surface->bbox_x1 = x1;
4570 surface->bbox_y1 = y1;
4571 surface->bbox_x2 = x2;
4572 surface->bbox_y2 = y2;
4574 if (x1 < surface->bbox_x1)
4575 surface->bbox_x1 = x1;
4576 if (y1 < surface->bbox_y1)
4577 surface->bbox_y1 = y1;
4578 if (x2 > surface->bbox_x2)
4579 surface->bbox_x2 = x2;
4580 if (y2 > surface->bbox_y2)
4581 surface->bbox_y2 = y2;
4583 surface->current_pattern_is_solid_color = FALSE;
4584 _cairo_pdf_operators_reset (&surface->pdf_operators);
4586 return _cairo_output_stream_get_status (surface->stream);
4590 _cairo_ps_surface_supports_fine_grained_fallbacks (void *abstract_surface)
4595 static const cairo_surface_backend_t cairo_ps_surface_backend = {
4596 CAIRO_SURFACE_TYPE_PS,
4597 _cairo_ps_surface_finish,
4599 _cairo_default_context_create,
4601 NULL, /* create similar: handled by wrapper */
4602 NULL, /* create similar image */
4603 NULL, /* map to image */
4604 NULL, /* unmap image */
4606 _cairo_surface_default_source,
4607 NULL, /* acquire_source_image */
4608 NULL, /* release_source_image */
4609 NULL, /* snapshot */
4611 NULL, /* cairo_ps_surface_copy_page */
4612 _cairo_ps_surface_show_page,
4614 _cairo_ps_surface_get_extents,
4615 _cairo_ps_surface_get_font_options,
4618 NULL, /* mark_dirty_rectangle */
4620 /* Here are the drawing functions */
4622 _cairo_ps_surface_paint, /* paint */
4623 _cairo_ps_surface_mask,
4624 _cairo_ps_surface_stroke,
4625 _cairo_ps_surface_fill,
4626 NULL, /* fill-stroke */
4627 NULL, /* show_glyphs */
4628 _cairo_ps_surface_has_show_text_glyphs,
4629 _cairo_ps_surface_show_text_glyphs,
4630 _cairo_ps_surface_get_supported_mime_types,
4633 static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend = {
4634 _cairo_ps_surface_start_page,
4635 _cairo_ps_surface_set_paginated_mode,
4636 _cairo_ps_surface_set_bounding_box,
4637 NULL, /* _cairo_ps_surface_has_fallback_images, */
4638 _cairo_ps_surface_supports_fine_grained_fallbacks,