1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2003 University of Southern California
5 * Copyright © 2005 Red Hat, Inc
6 * Copyright © 2007,2008 Adrian Johnson
8 * This library is free software; you can redistribute it and/or
9 * modify it either under the terms of the GNU Lesser General Public
10 * License version 2.1 as published by the Free Software Foundation
11 * (the "LGPL") or, at your option, under the terms of the Mozilla
12 * Public License Version 1.1 (the "MPL"). If you do not alter this
13 * notice, a recipient may use your version of this file under either
14 * the MPL or the LGPL.
16 * You should have received a copy of the LGPL along with this library
17 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19 * You should have received a copy of the MPL along with this library
20 * in the file COPYING-MPL-1.1
22 * The contents of this file are subject to the Mozilla Public License
23 * Version 1.1 (the "License"); you may not use this file except in
24 * compliance with the License. You may obtain a copy of the License at
25 * http://www.mozilla.org/MPL/
27 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29 * the specific language governing rights and limitations.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is University of Southern
37 * Carl D. Worth <cworth@cworth.org>
38 * Kristian Høgsberg <krh@redhat.com>
39 * Keith Packard <keithp@keithp.com>
40 * Adrian Johnson <ajohnson@redneon.com>
45 * Design of the PS output:
47 * The PS output is harmonised with the PDF operations using PS procedures
48 * to emulate the PDF operators.
50 * This has a number of advantages:
51 * 1. A large chunk of code is shared between the PDF and PS backends.
52 * See cairo-pdf-operators.
53 * 2. Using gs to do PS -> PDF and PDF -> PS will always work well.
56 #define _BSD_SOURCE /* for ctime_r(), snprintf(), strdup() */
60 #include "cairo-ps-surface-private.h"
62 #include "cairo-pdf-operators-private.h"
63 #include "cairo-pdf-shading-private.h"
65 #include "cairo-array-private.h"
66 #include "cairo-composite-rectangles-private.h"
67 #include "cairo-default-context-private.h"
68 #include "cairo-error-private.h"
69 #include "cairo-image-surface-inline.h"
70 #include "cairo-list-inline.h"
71 #include "cairo-scaled-font-subsets-private.h"
72 #include "cairo-paginated-private.h"
73 #include "cairo-recording-surface-private.h"
74 #include "cairo-surface-clipper-private.h"
75 #include "cairo-surface-snapshot-inline.h"
76 #include "cairo-surface-subsurface-private.h"
77 #include "cairo-output-stream-private.h"
78 #include "cairo-type3-glyph-surface-private.h"
79 #include "cairo-image-info-private.h"
90 #define DEBUG_FALLBACK(s) \
91 fprintf (stderr, "%s::%d -- %s\n", __FUNCTION__, __LINE__, (s))
93 #define DEBUG_FALLBACK(s)
97 #define ctime_r(T, BUF) ctime (T)
102 * @Title: PostScript Surfaces
103 * @Short_Description: Rendering PostScript documents
104 * @See_Also: #cairo_surface_t
106 * The PostScript surface is used to render cairo graphics to Adobe
107 * PostScript files and is a multi-page vector surface backend.
111 * CAIRO_HAS_PS_SURFACE:
113 * Defined if the PostScript surface backend is available.
114 * This macro can be used to conditionally compile backend-specific code.
120 CAIRO_PS_COMPRESS_NONE,
121 CAIRO_PS_COMPRESS_LZW,
122 CAIRO_PS_COMPRESS_DEFLATE
123 } cairo_ps_compress_t;
125 static const cairo_surface_backend_t cairo_ps_surface_backend;
126 static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend;
129 _cairo_ps_surface_get_extents (void *abstract_surface,
130 cairo_rectangle_int_t *rectangle);
132 static const cairo_ps_level_t _cairo_ps_levels[] =
138 #define CAIRO_PS_LEVEL_LAST ARRAY_LENGTH (_cairo_ps_levels)
140 static const char * _cairo_ps_level_strings[CAIRO_PS_LEVEL_LAST] =
146 static const char *_cairo_ps_supported_mime_types[] =
148 CAIRO_MIME_TYPE_JPEG,
152 typedef struct _cairo_page_standard_media {
156 } cairo_page_standard_media_t;
158 static const cairo_page_standard_media_t _cairo_page_standard_media[] =
160 { "A0", 2384, 3371 },
161 { "A1", 1685, 2384 },
162 { "A2", 1190, 1684 },
168 { "Letter", 612, 792 },
169 { "Tabloid", 792, 1224 },
170 { "Ledger", 1224, 792 },
171 { "Legal", 612, 1008 },
172 { "Statement", 396, 612 },
173 { "Executive", 540, 720 },
174 { "Folio", 612, 936 },
175 { "Quarto", 610, 780 },
176 { "10x14", 720, 1008 },
179 typedef struct _cairo_page_media {
184 } cairo_page_media_t;
187 _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
194 const char *eps_header = "";
195 cairo_bool_t has_bbox;
197 if (surface->has_creation_date)
198 now = surface->creation_date;
202 if (surface->ps_level_used == CAIRO_PS_LEVEL_2)
208 eps_header = " EPSF-3.0";
210 _cairo_output_stream_printf (surface->final_stream,
211 "%%!PS-Adobe-3.0%s\n"
212 "%%%%Creator: cairo %s (http://cairographics.org)\n"
213 "%%%%CreationDate: %s"
216 cairo_version_string (),
217 ctime_r (&now, ctime_buf),
220 _cairo_output_stream_printf (surface->final_stream,
221 "%%%%DocumentData: Clean7Bit\n"
222 "%%%%LanguageLevel: %d\n",
225 if (!cairo_list_is_empty (&surface->document_media)) {
226 cairo_page_media_t *page;
227 cairo_bool_t first = TRUE;
229 cairo_list_foreach_entry (page, cairo_page_media_t, &surface->document_media, link) {
231 _cairo_output_stream_printf (surface->final_stream,
232 "%%%%DocumentMedia: ");
235 _cairo_output_stream_printf (surface->final_stream,
238 _cairo_output_stream_printf (surface->final_stream,
239 "%s %d %d 0 () ()\n",
247 num_comments = _cairo_array_num_elements (&surface->dsc_header_comments);
248 comments = _cairo_array_index (&surface->dsc_header_comments, 0);
249 if (comments == NULL)
252 for (i = 0; i < num_comments; i++) {
253 _cairo_output_stream_printf (surface->final_stream,
254 "%s\n", comments[i]);
255 if (strncmp (comments[i], "%%BoundingBox:", 14) == 0)
263 _cairo_output_stream_printf (surface->final_stream,
264 "%%%%BoundingBox: %d %d %d %d\n",
271 _cairo_output_stream_printf (surface->final_stream,
272 "%%%%EndComments\n");
274 _cairo_output_stream_printf (surface->final_stream,
275 "%%%%BeginProlog\n");
278 _cairo_output_stream_printf (surface->final_stream,
282 _cairo_output_stream_printf (surface->final_stream,
283 "/languagelevel where\n"
284 "{ pop languagelevel } { 1 } ifelse\n"
285 "%d lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto\n"
286 " (This print job requires a PostScript Language Level %d printer.) show\n"
287 " showpage quit } if\n",
292 _cairo_output_stream_printf (surface->final_stream,
293 "/q { gsave } bind def\n"
294 "/Q { grestore } bind def\n"
295 "/cm { 6 array astore concat } bind def\n"
296 "/w { setlinewidth } bind def\n"
297 "/J { setlinecap } bind def\n"
298 "/j { setlinejoin } bind def\n"
299 "/M { setmiterlimit } bind def\n"
300 "/d { setdash } bind def\n"
301 "/m { moveto } bind def\n"
302 "/l { lineto } bind def\n"
303 "/c { curveto } bind def\n"
304 "/h { closepath } bind def\n"
305 "/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto\n"
306 " 0 exch rlineto 0 rlineto closepath } bind def\n"
307 "/S { stroke } bind def\n"
308 "/f { fill } bind def\n"
309 "/f* { eofill } bind def\n"
310 "/n { newpath } bind def\n"
311 "/W { clip } bind def\n"
312 "/W* { eoclip } bind def\n"
315 "/pdfmark where { pop globaldict /?pdfmark /exec load put }\n"
316 " { globaldict begin /?pdfmark /pop load def /pdfmark\n"
317 " /cleartomark load def end } ifelse\n"
318 "/BDC { mark 3 1 roll /BDC pdfmark } bind def\n"
319 "/EMC { mark /EMC pdfmark } bind def\n"
320 "/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def\n"
321 "/Tj { show currentpoint cairo_store_point } bind def\n"
325 " type /stringtype eq\n"
326 " { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse\n"
328 " currentpoint cairo_store_point\n"
330 "/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore\n"
331 " cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def\n"
332 "/Tf { pop /cairo_font exch def /cairo_font_matrix where\n"
333 " { pop cairo_selectfont } if } bind def\n"
334 "/Td { matrix translate cairo_font_matrix matrix concatmatrix dup\n"
335 " /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point\n"
336 " /cairo_font where { pop cairo_selectfont } if } bind def\n"
337 "/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def\n"
338 " cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def\n"
339 "/g { setgray } bind def\n"
340 "/rg { setrgbcolor } bind def\n"
341 "/d1 { setcachedevice } bind def\n");
344 _cairo_output_stream_printf (surface->final_stream,
345 "/cairo_set_page_size {\n"
346 " %% Change paper size, but only if different from previous paper size otherwise\n"
347 " %% duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size\n"
348 " %% so we use the same when checking if the size changes.\n"
349 " /setpagedevice where {\n"
350 " pop currentpagedevice\n"
351 " /PageSize known {\n"
353 " currentpagedevice /PageSize get aload pop\n"
365 " /PageSize exch def\n"
366 " /ImagingBBox null def\n"
378 _cairo_output_stream_printf (surface->final_stream,
380 _cairo_output_stream_printf (surface->final_stream,
383 num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
385 comments = _cairo_array_index (&surface->dsc_setup_comments, 0);
386 for (i = 0; i < num_comments; i++) {
387 _cairo_output_stream_printf (surface->final_stream,
388 "%s\n", comments[i]);
395 static cairo_status_t
396 _cairo_ps_surface_emit_type1_font_subset (cairo_ps_surface_t *surface,
397 cairo_scaled_font_subset_t *font_subset)
401 cairo_type1_subset_t subset;
402 cairo_status_t status;
406 snprintf (name, sizeof name, "f-%d-%d",
407 font_subset->font_id, font_subset->subset_id);
408 status = _cairo_type1_subset_init (&subset, name, font_subset, TRUE);
409 if (unlikely (status))
412 /* FIXME: Figure out document structure convention for fonts */
415 _cairo_output_stream_printf (surface->final_stream,
416 "%% _cairo_ps_surface_emit_type1_font_subset\n");
419 _cairo_output_stream_printf (surface->final_stream,
420 "%%%%BeginResource: font %s\n",
422 length = subset.header_length + subset.data_length + subset.trailer_length;
423 _cairo_output_stream_write (surface->final_stream, subset.data, length);
424 _cairo_output_stream_printf (surface->final_stream,
425 "%%%%EndResource\n");
427 _cairo_type1_subset_fini (&subset);
429 return CAIRO_STATUS_SUCCESS;
433 static cairo_status_t
434 _cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t *surface,
435 cairo_scaled_font_subset_t *font_subset)
437 cairo_type1_subset_t subset;
438 cairo_status_t status;
442 snprintf (name, sizeof name, "f-%d-%d",
443 font_subset->font_id, font_subset->subset_id);
444 status = _cairo_type1_fallback_init_hex (&subset, name, font_subset);
445 if (unlikely (status))
449 _cairo_output_stream_printf (surface->final_stream,
450 "%% _cairo_ps_surface_emit_type1_font_fallback\n");
453 _cairo_output_stream_printf (surface->final_stream,
454 "%%%%BeginResource: font %s\n",
456 length = subset.header_length + subset.data_length + subset.trailer_length;
457 _cairo_output_stream_write (surface->final_stream, subset.data, length);
458 _cairo_output_stream_printf (surface->final_stream,
459 "%%%%EndResource\n");
461 _cairo_type1_fallback_fini (&subset);
463 return CAIRO_STATUS_SUCCESS;
466 static cairo_status_t
467 _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface,
468 cairo_scaled_font_subset_t *font_subset)
472 cairo_truetype_subset_t subset;
473 cairo_status_t status;
474 unsigned int i, begin, end;
476 status = _cairo_truetype_subset_init_ps (&subset, font_subset);
477 if (unlikely (status))
480 /* FIXME: Figure out document structure convention for fonts */
483 _cairo_output_stream_printf (surface->final_stream,
484 "%% _cairo_ps_surface_emit_truetype_font_subset\n");
487 _cairo_output_stream_printf (surface->final_stream,
488 "%%%%BeginResource: font %s\n",
490 _cairo_output_stream_printf (surface->final_stream,
493 "/FontName /%s def\n"
495 "/FontMatrix [ 1 0 0 1 0 0 ] def\n"
496 "/FontBBox [ 0 0 0 0 ] def\n"
497 "/Encoding 256 array def\n"
498 "0 1 255 { Encoding exch /.notdef put } for\n",
501 /* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */
503 if (font_subset->is_latin) {
504 for (i = 1; i < 256; i++) {
505 if (font_subset->latin_to_subset_glyph_index[i] > 0) {
506 if (font_subset->glyph_names != NULL) {
507 _cairo_output_stream_printf (surface->final_stream,
508 "Encoding %d /%s put\n",
509 i, font_subset->glyph_names[font_subset->latin_to_subset_glyph_index[i]]);
511 _cairo_output_stream_printf (surface->final_stream,
512 "Encoding %d /g%ld put\n", i, font_subset->latin_to_subset_glyph_index[i]);
517 for (i = 1; i < font_subset->num_glyphs; i++) {
518 if (font_subset->glyph_names != NULL) {
519 _cairo_output_stream_printf (surface->final_stream,
520 "Encoding %d /%s put\n",
521 i, font_subset->glyph_names[i]);
523 _cairo_output_stream_printf (surface->final_stream,
524 "Encoding %d /g%d put\n", i, i);
529 _cairo_output_stream_printf (surface->final_stream,
530 "/CharStrings %d dict dup begin\n"
532 font_subset->num_glyphs);
534 for (i = 1; i < font_subset->num_glyphs; i++) {
535 if (font_subset->glyph_names != NULL) {
536 _cairo_output_stream_printf (surface->final_stream,
538 font_subset->glyph_names[i], i);
540 _cairo_output_stream_printf (surface->final_stream,
541 "/g%d %d def\n", i, i);
545 _cairo_output_stream_printf (surface->final_stream,
546 "end readonly def\n");
548 _cairo_output_stream_printf (surface->final_stream,
552 for (i = 0; i < subset.num_string_offsets; i++) {
553 end = subset.string_offsets[i];
554 _cairo_output_stream_printf (surface->final_stream,"<");
555 _cairo_output_stream_write_hex_string (surface->final_stream,
556 subset.data + begin, end - begin);
557 _cairo_output_stream_printf (surface->final_stream,"00>\n");
560 if (subset.data_length > end) {
561 _cairo_output_stream_printf (surface->final_stream,"<");
562 _cairo_output_stream_write_hex_string (surface->final_stream,
563 subset.data + end, subset.data_length - end);
564 _cairo_output_stream_printf (surface->final_stream,"00>\n");
567 _cairo_output_stream_printf (surface->final_stream,
569 "/f-%d-%d currentdict end definefont pop\n",
570 font_subset->font_id,
571 font_subset->subset_id);
572 _cairo_output_stream_printf (surface->final_stream,
573 "%%%%EndResource\n");
574 _cairo_truetype_subset_fini (&subset);
577 return CAIRO_STATUS_SUCCESS;
580 static cairo_int_status_t
581 _cairo_ps_emit_imagemask (cairo_image_surface_t *image,
582 cairo_output_stream_t *stream)
587 /* The only image type supported by Type 3 fonts are 1-bit image
589 assert (image->format == CAIRO_FORMAT_A1);
591 _cairo_output_stream_printf (stream,
596 " /ImageMatrix [%d 0 0 %d 0 %d]\n"
598 " /BitsPerComponent 1\n",
605 _cairo_output_stream_printf (stream,
606 " /DataSource {<\n ");
607 for (row = image->data, rows = image->height; rows; row += image->stride, rows--) {
608 for (byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) {
609 uint8_t output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
610 _cairo_output_stream_printf (stream, "%02x ", output_byte);
612 _cairo_output_stream_printf (stream, "\n ");
614 _cairo_output_stream_printf (stream, ">}\n>>\n");
616 _cairo_output_stream_printf (stream,
619 return _cairo_output_stream_get_status (stream);
622 static cairo_int_status_t
623 _cairo_ps_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset,
626 cairo_ps_surface_t *surface = closure;
627 cairo_status_t status = CAIRO_STATUS_SUCCESS;
629 cairo_surface_t *type3_surface;
631 type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
633 _cairo_ps_emit_imagemask,
634 surface->font_subsets,
637 for (i = 0; i < font_subset->num_glyphs; i++) {
638 status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
639 font_subset->glyphs[i]);
640 if (unlikely (status))
644 cairo_surface_finish (type3_surface);
645 cairo_surface_destroy (type3_surface);
650 static cairo_status_t
651 _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
652 cairo_scaled_font_subset_t *font_subset)
656 cairo_status_t status;
658 cairo_box_t font_bbox = {{0,0},{0,0}};
659 cairo_box_t bbox = {{0,0},{0,0}};
660 cairo_surface_t *type3_surface;
663 if (font_subset->num_glyphs == 0)
664 return CAIRO_STATUS_SUCCESS;
667 _cairo_output_stream_printf (surface->final_stream,
668 "%% _cairo_ps_surface_emit_type3_font_subset\n");
671 _cairo_output_stream_printf (surface->final_stream,
672 "%%%%BeginResource: font\n");
673 _cairo_output_stream_printf (surface->final_stream,
676 "/FontMatrix [1 0 0 1 0 0] def\n"
677 "/Encoding 256 array def\n"
678 "0 1 255 { Encoding exch /.notdef put } for\n");
680 type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
682 _cairo_ps_emit_imagemask,
683 surface->font_subsets,
685 status = type3_surface->status;
686 if (unlikely (status)) {
687 cairo_surface_destroy (type3_surface);
691 for (i = 0; i < font_subset->num_glyphs; i++) {
692 if (font_subset->glyph_names != NULL) {
693 _cairo_output_stream_printf (surface->final_stream,
694 "Encoding %d /%s put\n",
695 i, font_subset->glyph_names[i]);
697 _cairo_output_stream_printf (surface->final_stream,
698 "Encoding %d /g%d put\n", i, i);
702 _cairo_output_stream_printf (surface->final_stream,
705 for (i = 0; i < font_subset->num_glyphs; i++) {
706 _cairo_output_stream_printf (surface->final_stream,
708 status = _cairo_type3_glyph_surface_emit_glyph (type3_surface,
709 surface->final_stream,
710 font_subset->glyphs[i],
713 if (unlikely (status))
716 _cairo_output_stream_printf (surface->final_stream,
719 font_bbox.p1.x = bbox.p1.x;
720 font_bbox.p1.y = bbox.p1.y;
721 font_bbox.p2.x = bbox.p2.x;
722 font_bbox.p2.y = bbox.p2.y;
724 if (bbox.p1.x < font_bbox.p1.x)
725 font_bbox.p1.x = bbox.p1.x;
726 if (bbox.p1.y < font_bbox.p1.y)
727 font_bbox.p1.y = bbox.p1.y;
728 if (bbox.p2.x > font_bbox.p2.x)
729 font_bbox.p2.x = bbox.p2.x;
730 if (bbox.p2.y > font_bbox.p2.y)
731 font_bbox.p2.y = bbox.p2.y;
734 cairo_surface_finish (type3_surface);
735 cairo_surface_destroy (type3_surface);
736 if (unlikely (status))
739 _cairo_output_stream_printf (surface->final_stream,
741 "/FontBBox [%f %f %f %f] def\n"
743 " exch /Glyphs get\n"
745 " 10 dict begin exec end\n"
749 "/f-%d-%d exch definefont pop\n",
750 _cairo_fixed_to_double (font_bbox.p1.x),
751 - _cairo_fixed_to_double (font_bbox.p2.y),
752 _cairo_fixed_to_double (font_bbox.p2.x),
753 - _cairo_fixed_to_double (font_bbox.p1.y),
754 font_subset->font_id,
755 font_subset->subset_id);
756 _cairo_output_stream_printf (surface->final_stream,
757 "%%%%EndResource\n");
759 return CAIRO_STATUS_SUCCESS;
762 static cairo_int_status_t
763 _cairo_ps_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset,
766 cairo_ps_surface_t *surface = closure;
767 cairo_int_status_t status;
769 status = _cairo_scaled_font_subset_create_glyph_names (font_subset);
770 if (_cairo_int_status_is_error (status))
773 status = _cairo_ps_surface_emit_type1_font_subset (surface, font_subset);
774 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
777 status = _cairo_ps_surface_emit_truetype_font_subset (surface, font_subset);
778 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
781 status = _cairo_ps_surface_emit_type1_font_fallback (surface, font_subset);
782 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
786 return CAIRO_STATUS_SUCCESS;
789 static cairo_int_status_t
790 _cairo_ps_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset,
793 cairo_ps_surface_t *surface = closure;
794 cairo_int_status_t status;
796 status = _cairo_scaled_font_subset_create_glyph_names (font_subset);
797 if (_cairo_int_status_is_error (status))
800 status = _cairo_ps_surface_emit_type3_font_subset (surface, font_subset);
801 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
805 return CAIRO_INT_STATUS_SUCCESS;
808 static cairo_status_t
809 _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface)
811 cairo_status_t status;
814 _cairo_output_stream_printf (surface->final_stream,
815 "%% _cairo_ps_surface_emit_font_subsets\n");
818 status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
819 _cairo_ps_surface_analyze_user_font_subset,
821 if (unlikely (status))
824 status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
825 _cairo_ps_surface_emit_unscaled_font_subset,
827 if (unlikely (status))
830 status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
831 _cairo_ps_surface_emit_scaled_font_subset,
833 if (unlikely (status))
836 return _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
837 _cairo_ps_surface_emit_scaled_font_subset,
841 static cairo_status_t
842 _cairo_ps_surface_emit_body (cairo_ps_surface_t *surface)
847 if (ferror (surface->tmpfile) != 0)
848 return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
850 rewind (surface->tmpfile);
851 while ((n = fread (buf, 1, sizeof (buf), surface->tmpfile)) > 0)
852 _cairo_output_stream_write (surface->final_stream, buf, n);
854 if (ferror (surface->tmpfile) != 0)
855 return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
857 return CAIRO_STATUS_SUCCESS;
861 _cairo_ps_surface_emit_footer (cairo_ps_surface_t *surface)
863 _cairo_output_stream_printf (surface->final_stream,
867 _cairo_output_stream_printf (surface->final_stream,
871 _cairo_output_stream_printf (surface->final_stream,
876 _path_covers_bbox (cairo_ps_surface_t *surface,
877 cairo_path_fixed_t *path)
881 if (_cairo_path_fixed_is_box (path, &box)) {
882 cairo_rectangle_int_t rect;
884 _cairo_box_round_to_rectangle (&box, &rect);
886 /* skip trivial whole-page clips */
887 if (_cairo_rectangle_intersect (&rect, &surface->page_bbox)) {
888 if (rect.x == surface->page_bbox.x &&
889 rect.width == surface->page_bbox.width &&
890 rect.y == surface->page_bbox.y &&
891 rect.height == surface->page_bbox.height)
901 static cairo_status_t
902 _cairo_ps_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
903 cairo_path_fixed_t *path,
904 cairo_fill_rule_t fill_rule,
906 cairo_antialias_t antialias)
908 cairo_ps_surface_t *surface = cairo_container_of (clipper,
911 cairo_output_stream_t *stream = surface->stream;
912 cairo_status_t status;
914 assert (surface->paginated_mode != CAIRO_PAGINATED_MODE_ANALYZE);
917 _cairo_output_stream_printf (stream,
918 "%% _cairo_ps_surface_intersect_clip_path\n");
922 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
923 if (unlikely (status))
926 _cairo_output_stream_printf (stream, "Q q\n");
928 surface->current_pattern_is_solid_color = FALSE;
929 _cairo_pdf_operators_reset (&surface->pdf_operators);
931 return CAIRO_STATUS_SUCCESS;
934 if (_path_covers_bbox (surface, path))
935 return CAIRO_STATUS_SUCCESS;
937 return _cairo_pdf_operators_clip (&surface->pdf_operators,
942 /* PLRM specifies a tolerance of 5 points when matching page sizes */
944 _ps_page_dimension_equal (int a, int b)
946 return (abs (a - b) < 5);
950 _cairo_ps_surface_get_page_media (cairo_ps_surface_t *surface)
952 int width, height, i;
954 cairo_page_media_t *page;
955 const char *page_name;
957 width = _cairo_lround (surface->width);
958 height = _cairo_lround (surface->height);
960 /* search previously used page sizes */
961 cairo_list_foreach_entry (page, cairo_page_media_t, &surface->document_media, link) {
962 if (_ps_page_dimension_equal (width, page->width) &&
963 _ps_page_dimension_equal (height, page->height))
967 /* search list of standard page sizes */
969 for (i = 0; i < ARRAY_LENGTH (_cairo_page_standard_media); i++) {
970 if (_ps_page_dimension_equal (width, _cairo_page_standard_media[i].width) &&
971 _ps_page_dimension_equal (height, _cairo_page_standard_media[i].height))
973 page_name = _cairo_page_standard_media[i].name;
974 width = _cairo_page_standard_media[i].width;
975 height = _cairo_page_standard_media[i].height;
980 page = malloc (sizeof (cairo_page_media_t));
981 if (unlikely (page == NULL)) {
982 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
987 page->name = strdup (page_name);
989 snprintf (buf, sizeof (buf), "%dx%dmm",
990 (int) _cairo_lround (surface->width * 25.4/72),
991 (int) _cairo_lround (surface->height * 25.4/72));
992 page->name = strdup (buf);
995 if (unlikely (page->name == NULL)) {
997 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
1001 page->width = width;
1002 page->height = height;
1003 cairo_list_add_tail (&page->link, &surface->document_media);
1008 static cairo_surface_t *
1009 _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
1013 cairo_status_t status, status_ignored;
1014 cairo_ps_surface_t *surface;
1016 surface = malloc (sizeof (cairo_ps_surface_t));
1017 if (unlikely (surface == NULL)) {
1018 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1022 _cairo_surface_init (&surface->base,
1023 &cairo_ps_surface_backend,
1025 CAIRO_CONTENT_COLOR_ALPHA);
1027 surface->final_stream = stream;
1029 surface->tmpfile = tmpfile ();
1030 if (surface->tmpfile == NULL) {
1033 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1036 status = _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
1039 goto CLEANUP_SURFACE;
1042 surface->stream = _cairo_output_stream_create_for_file (surface->tmpfile);
1043 status = _cairo_output_stream_get_status (surface->stream);
1044 if (unlikely (status))
1045 goto CLEANUP_OUTPUT_STREAM;
1047 surface->font_subsets = _cairo_scaled_font_subsets_create_simple ();
1048 if (unlikely (surface->font_subsets == NULL)) {
1049 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1050 goto CLEANUP_OUTPUT_STREAM;
1053 _cairo_scaled_font_subsets_enable_latin_subset (surface->font_subsets, TRUE);
1054 surface->has_creation_date = FALSE;
1055 surface->eps = FALSE;
1056 surface->ps_level = CAIRO_PS_LEVEL_3;
1057 surface->ps_level_used = CAIRO_PS_LEVEL_2;
1058 surface->width = width;
1059 surface->height = height;
1060 cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, height);
1061 surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
1062 surface->force_fallbacks = FALSE;
1063 surface->content = CAIRO_CONTENT_COLOR_ALPHA;
1064 surface->use_string_datasource = FALSE;
1065 surface->current_pattern_is_solid_color = FALSE;
1067 surface->page_bbox.x = 0;
1068 surface->page_bbox.y = 0;
1069 surface->page_bbox.width = width;
1070 surface->page_bbox.height = height;
1072 _cairo_surface_clipper_init (&surface->clipper,
1073 _cairo_ps_surface_clipper_intersect_clip_path);
1075 _cairo_pdf_operators_init (&surface->pdf_operators,
1077 &surface->cairo_to_ps,
1078 surface->font_subsets,
1080 surface->num_pages = 0;
1082 cairo_list_init (&surface->document_media);
1083 _cairo_array_init (&surface->dsc_header_comments, sizeof (char *));
1084 _cairo_array_init (&surface->dsc_setup_comments, sizeof (char *));
1085 _cairo_array_init (&surface->dsc_page_setup_comments, sizeof (char *));
1087 surface->dsc_comment_target = &surface->dsc_header_comments;
1089 surface->paginated_surface = _cairo_paginated_surface_create (
1091 CAIRO_CONTENT_COLOR_ALPHA,
1092 &cairo_ps_surface_paginated_backend);
1093 status = surface->paginated_surface->status;
1094 if (status == CAIRO_STATUS_SUCCESS) {
1095 /* paginated keeps the only reference to surface now, drop ours */
1096 cairo_surface_destroy (&surface->base);
1097 return surface->paginated_surface;
1100 _cairo_scaled_font_subsets_destroy (surface->font_subsets);
1101 CLEANUP_OUTPUT_STREAM:
1102 status_ignored = _cairo_output_stream_destroy (surface->stream);
1103 fclose (surface->tmpfile);
1107 /* destroy stream on behalf of caller */
1108 status_ignored = _cairo_output_stream_destroy (stream);
1110 return _cairo_surface_create_in_error (status);
1114 * cairo_ps_surface_create:
1115 * @filename: a filename for the PS output (must be writable), %NULL may be
1116 * used to specify no output. This will generate a PS surface that
1117 * may be queried and used as a source, without generating a
1119 * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
1120 * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
1122 * Creates a PostScript surface of the specified size in points to be
1123 * written to @filename. See cairo_ps_surface_create_for_stream() for
1124 * a more flexible mechanism for handling the PostScript output than
1125 * simply writing it to a named file.
1127 * Note that the size of individual pages of the PostScript output can
1128 * vary. See cairo_ps_surface_set_size().
1130 * Return value: a pointer to the newly created surface. The caller
1131 * owns the surface and should call cairo_surface_destroy() when done
1134 * This function always returns a valid pointer, but it will return a
1135 * pointer to a "nil" surface if an error such as out of memory
1136 * occurs. You can use cairo_surface_status() to check for this.
1141 cairo_ps_surface_create (const char *filename,
1142 double width_in_points,
1143 double height_in_points)
1145 cairo_output_stream_t *stream;
1147 stream = _cairo_output_stream_create_for_filename (filename);
1148 if (_cairo_output_stream_get_status (stream))
1149 return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream));
1151 return _cairo_ps_surface_create_for_stream_internal (stream,
1157 * cairo_ps_surface_create_for_stream:
1158 * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL
1159 * to indicate a no-op @write_func. With a no-op @write_func,
1160 * the surface may be queried or used as a source without
1161 * generating any temporary files.
1162 * @closure: the closure argument for @write_func
1163 * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
1164 * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
1166 * Creates a PostScript surface of the specified size in points to be
1167 * written incrementally to the stream represented by @write_func and
1168 * @closure. See cairo_ps_surface_create() for a more convenient way
1169 * to simply direct the PostScript output to a named file.
1171 * Note that the size of individual pages of the PostScript
1172 * output can vary. See cairo_ps_surface_set_size().
1174 * Return value: a pointer to the newly created surface. The caller
1175 * owns the surface and should call cairo_surface_destroy() when done
1178 * This function always returns a valid pointer, but it will return a
1179 * pointer to a "nil" surface if an error such as out of memory
1180 * occurs. You can use cairo_surface_status() to check for this.
1185 cairo_ps_surface_create_for_stream (cairo_write_func_t write_func,
1187 double width_in_points,
1188 double height_in_points)
1190 cairo_output_stream_t *stream;
1192 stream = _cairo_output_stream_create (write_func, NULL, closure);
1193 if (_cairo_output_stream_get_status (stream))
1194 return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream));
1196 return _cairo_ps_surface_create_for_stream_internal (stream,
1202 _cairo_surface_is_ps (cairo_surface_t *surface)
1204 return surface->backend == &cairo_ps_surface_backend;
1207 /* If the abstract_surface is a paginated surface, and that paginated
1208 * surface's target is a ps_surface, then set ps_surface to that
1209 * target. Otherwise return FALSE.
1212 _extract_ps_surface (cairo_surface_t *surface,
1213 cairo_bool_t set_error_on_failure,
1214 cairo_ps_surface_t **ps_surface)
1216 cairo_surface_t *target;
1218 if (surface->status)
1220 if (surface->finished) {
1221 if (set_error_on_failure)
1222 _cairo_surface_set_error (surface,
1223 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
1227 if (! _cairo_surface_is_paginated (surface)) {
1228 if (set_error_on_failure)
1229 _cairo_surface_set_error (surface,
1230 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
1234 target = _cairo_paginated_surface_get_target (surface);
1235 if (target->status) {
1236 if (set_error_on_failure)
1237 _cairo_surface_set_error (surface, target->status);
1240 if (target->finished) {
1241 if (set_error_on_failure)
1242 _cairo_surface_set_error (surface,
1243 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
1247 if (! _cairo_surface_is_ps (target)) {
1248 if (set_error_on_failure)
1249 _cairo_surface_set_error (surface,
1250 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
1254 *ps_surface = (cairo_ps_surface_t *) target;
1259 * cairo_ps_surface_restrict_to_level:
1260 * @surface: a PostScript #cairo_surface_t
1261 * @level: PostScript level
1263 * Restricts the generated PostSript file to @level. See
1264 * cairo_ps_get_levels() for a list of available level values that
1267 * This function should only be called before any drawing operations
1268 * have been performed on the given surface. The simplest way to do
1269 * this is to call this function immediately after creating the
1275 cairo_ps_surface_restrict_to_level (cairo_surface_t *surface,
1276 cairo_ps_level_t level)
1278 cairo_ps_surface_t *ps_surface = NULL;
1280 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1283 if (level < CAIRO_PS_LEVEL_LAST)
1284 ps_surface->ps_level = level;
1288 * cairo_ps_get_levels:
1289 * @levels: supported level list
1290 * @num_levels: list length
1292 * Used to retrieve the list of supported levels. See
1293 * cairo_ps_surface_restrict_to_level().
1298 cairo_ps_get_levels (cairo_ps_level_t const **levels,
1302 *levels = _cairo_ps_levels;
1304 if (num_levels != NULL)
1305 *num_levels = CAIRO_PS_LEVEL_LAST;
1309 * cairo_ps_level_to_string:
1310 * @level: a level id
1312 * Get the string representation of the given @level id. This function
1313 * will return %NULL if @level id isn't valid. See cairo_ps_get_levels()
1314 * for a way to get the list of valid level ids.
1316 * Return value: the string associated to given level.
1321 cairo_ps_level_to_string (cairo_ps_level_t level)
1323 if (level >= CAIRO_PS_LEVEL_LAST)
1326 return _cairo_ps_level_strings[level];
1330 * cairo_ps_surface_set_eps:
1331 * @surface: a PostScript #cairo_surface_t
1332 * @eps: %TRUE to output EPS format PostScript
1334 * If @eps is %TRUE, the PostScript surface will output Encapsulated
1337 * This function should only be called before any drawing operations
1338 * have been performed on the current page. The simplest way to do
1339 * this is to call this function immediately after creating the
1340 * surface. An Encapsulated PostScript file should never contain more
1346 cairo_ps_surface_set_eps (cairo_surface_t *surface,
1349 cairo_ps_surface_t *ps_surface = NULL;
1351 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1354 ps_surface->eps = eps;
1358 * cairo_ps_surface_get_eps:
1359 * @surface: a PostScript #cairo_surface_t
1361 * Check whether the PostScript surface will output Encapsulated PostScript.
1363 * Return value: %TRUE if the surface will output Encapsulated PostScript.
1367 cairo_public cairo_bool_t
1368 cairo_ps_surface_get_eps (cairo_surface_t *surface)
1370 cairo_ps_surface_t *ps_surface = NULL;
1372 if (! _extract_ps_surface (surface, FALSE, &ps_surface))
1375 return ps_surface->eps;
1379 * cairo_ps_surface_set_size:
1380 * @surface: a PostScript #cairo_surface_t
1381 * @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
1382 * @height_in_points: new surface height, in points (1 point == 1/72.0 inch)
1384 * Changes the size of a PostScript surface for the current (and
1385 * subsequent) pages.
1387 * This function should only be called before any drawing operations
1388 * have been performed on the current page. The simplest way to do
1389 * this is to call this function immediately after creating the
1390 * surface or immediately after completing a page with either
1391 * cairo_show_page() or cairo_copy_page().
1396 cairo_ps_surface_set_size (cairo_surface_t *surface,
1397 double width_in_points,
1398 double height_in_points)
1400 cairo_ps_surface_t *ps_surface = NULL;
1401 cairo_status_t status;
1403 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1406 ps_surface->width = width_in_points;
1407 ps_surface->height = height_in_points;
1408 cairo_matrix_init (&ps_surface->cairo_to_ps, 1, 0, 0, -1, 0, height_in_points);
1409 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface->pdf_operators,
1410 &ps_surface->cairo_to_ps);
1411 status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface,
1415 status = _cairo_surface_set_error (surface, status);
1419 * cairo_ps_surface_dsc_comment:
1420 * @surface: a PostScript #cairo_surface_t
1421 * @comment: a comment string to be emitted into the PostScript output
1423 * Emit a comment into the PostScript output for the given surface.
1425 * The comment is expected to conform to the PostScript Language
1426 * Document Structuring Conventions (DSC). Please see that manual for
1427 * details on the available comments and their meanings. In
1428 * particular, the \%\%IncludeFeature comment allows a
1429 * device-independent means of controlling printer device features. So
1430 * the PostScript Printer Description Files Specification will also be
1431 * a useful reference.
1433 * The comment string must begin with a percent character (\%) and the
1434 * total length of the string (including any initial percent
1435 * characters) must not exceed 255 characters. Violating either of
1436 * these conditions will place @surface into an error state. But
1437 * beyond these two conditions, this function will not enforce
1438 * conformance of the comment with any particular specification.
1440 * The comment string should not have a trailing newline.
1442 * The DSC specifies different sections in which particular comments
1443 * can appear. This function provides for comments to be emitted
1444 * within three sections: the header, the Setup section, and the
1445 * PageSetup section. Comments appearing in the first two sections
1446 * apply to the entire document while comments in the BeginPageSetup
1447 * section apply only to a single page.
1449 * For comments to appear in the header section, this function should
1450 * be called after the surface is created, but before a call to
1451 * cairo_ps_surface_dsc_begin_setup().
1453 * For comments to appear in the Setup section, this function should
1454 * be called after a call to cairo_ps_surface_dsc_begin_setup() but
1455 * before a call to cairo_ps_surface_dsc_begin_page_setup().
1457 * For comments to appear in the PageSetup section, this function
1458 * should be called after a call to
1459 * cairo_ps_surface_dsc_begin_page_setup().
1461 * Note that it is only necessary to call
1462 * cairo_ps_surface_dsc_begin_page_setup() for the first page of any
1463 * surface. After a call to cairo_show_page() or cairo_copy_page()
1464 * comments are unambiguously directed to the PageSetup section of the
1465 * current page. But it doesn't hurt to call this function at the
1466 * beginning of every page as that consistency may make the calling
1469 * As a final note, cairo automatically generates several comments on
1470 * its own. As such, applications must not manually generate any of
1471 * the following comments:
1473 * Header section: \%!PS-Adobe-3.0, \%\%Creator, \%\%CreationDate, \%\%Pages,
1474 * \%\%BoundingBox, \%\%DocumentData, \%\%LanguageLevel, \%\%EndComments.
1476 * Setup section: \%\%BeginSetup, \%\%EndSetup
1478 * PageSetup section: \%\%BeginPageSetup, \%\%PageBoundingBox, \%\%EndPageSetup.
1480 * Other sections: \%\%BeginProlog, \%\%EndProlog, \%\%Page, \%\%Trailer, \%\%EOF
1482 * Here is an example sequence showing how this function might be used:
1484 * <informalexample><programlisting>
1485 * cairo_surface_t *surface = cairo_ps_surface_create (filename, width, height);
1487 * cairo_ps_surface_dsc_comment (surface, "%%Title: My excellent document");
1488 * cairo_ps_surface_dsc_comment (surface, "%%Copyright: Copyright (C) 2006 Cairo Lover")
1490 * cairo_ps_surface_dsc_begin_setup (surface);
1491 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor White");
1493 * cairo_ps_surface_dsc_begin_page_setup (surface);
1494 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A3");
1495 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *InputSlot LargeCapacity");
1496 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaType Glossy");
1497 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor Blue");
1498 * ... draw to first page here ..
1499 * cairo_show_page (cr);
1501 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A5");
1503 * </programlisting></informalexample>
1508 cairo_ps_surface_dsc_comment (cairo_surface_t *surface,
1509 const char *comment)
1511 cairo_ps_surface_t *ps_surface = NULL;
1512 cairo_status_t status;
1515 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1518 /* A couple of sanity checks on the comment value. */
1519 if (comment == NULL) {
1520 status = _cairo_surface_set_error (surface, CAIRO_STATUS_NULL_POINTER);
1524 if (comment[0] != '%' || strlen (comment) > 255) {
1525 status = _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_DSC_COMMENT);
1529 /* Then, copy the comment and store it in the appropriate array. */
1530 comment_copy = strdup (comment);
1531 if (unlikely (comment_copy == NULL)) {
1532 status = _cairo_surface_set_error (surface, CAIRO_STATUS_NO_MEMORY);
1536 status = _cairo_array_append (ps_surface->dsc_comment_target, &comment_copy);
1537 if (unlikely (status)) {
1538 free (comment_copy);
1539 status = _cairo_surface_set_error (surface, status);
1545 * cairo_ps_surface_dsc_begin_setup:
1546 * @surface: a PostScript #cairo_surface_t
1548 * This function indicates that subsequent calls to
1549 * cairo_ps_surface_dsc_comment() should direct comments to the Setup
1550 * section of the PostScript output.
1552 * This function should be called at most once per surface, and must
1553 * be called before any call to cairo_ps_surface_dsc_begin_page_setup()
1554 * and before any drawing is performed to the surface.
1556 * See cairo_ps_surface_dsc_comment() for more details.
1561 cairo_ps_surface_dsc_begin_setup (cairo_surface_t *surface)
1563 cairo_ps_surface_t *ps_surface = NULL;
1565 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1568 if (ps_surface->dsc_comment_target == &ps_surface->dsc_header_comments)
1569 ps_surface->dsc_comment_target = &ps_surface->dsc_setup_comments;
1573 * cairo_ps_surface_dsc_begin_page_setup:
1574 * @surface: a PostScript #cairo_surface_t
1576 * This function indicates that subsequent calls to
1577 * cairo_ps_surface_dsc_comment() should direct comments to the
1578 * PageSetup section of the PostScript output.
1580 * This function call is only needed for the first page of a
1581 * surface. It should be called after any call to
1582 * cairo_ps_surface_dsc_begin_setup() and before any drawing is
1583 * performed to the surface.
1585 * See cairo_ps_surface_dsc_comment() for more details.
1590 cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface)
1592 cairo_ps_surface_t *ps_surface = NULL;
1594 if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1597 if (ps_surface->dsc_comment_target == &ps_surface->dsc_header_comments ||
1598 ps_surface->dsc_comment_target == &ps_surface->dsc_setup_comments)
1600 ps_surface->dsc_comment_target = &ps_surface->dsc_page_setup_comments;
1604 static cairo_status_t
1605 _cairo_ps_surface_finish (void *abstract_surface)
1607 cairo_status_t status, status2;
1608 cairo_ps_surface_t *surface = abstract_surface;
1609 int i, num_comments;
1612 status = surface->base.status;
1613 if (unlikely (status))
1616 _cairo_ps_surface_emit_header (surface);
1618 status = _cairo_ps_surface_emit_font_subsets (surface);
1619 if (unlikely (status))
1622 _cairo_output_stream_printf (surface->final_stream,
1625 status = _cairo_ps_surface_emit_body (surface);
1626 if (unlikely (status))
1629 _cairo_ps_surface_emit_footer (surface);
1632 _cairo_scaled_font_subsets_destroy (surface->font_subsets);
1634 status2 = _cairo_output_stream_destroy (surface->stream);
1635 if (status == CAIRO_STATUS_SUCCESS)
1638 fclose (surface->tmpfile);
1640 status2 = _cairo_output_stream_destroy (surface->final_stream);
1641 if (status == CAIRO_STATUS_SUCCESS)
1644 while (! cairo_list_is_empty (&surface->document_media)) {
1645 cairo_page_media_t *page;
1647 page = cairo_list_first_entry (&surface->document_media,
1650 cairo_list_del (&page->link);
1655 num_comments = _cairo_array_num_elements (&surface->dsc_header_comments);
1656 comments = _cairo_array_index (&surface->dsc_header_comments, 0);
1657 if (comments == NULL)
1658 return CAIRO_STATUS_NULL_POINTER;
1660 for (i = 0; i < num_comments; i++)
1662 _cairo_array_fini (&surface->dsc_header_comments);
1664 num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
1665 comments = _cairo_array_index (&surface->dsc_setup_comments, 0);
1666 if (comments == NULL)
1667 return CAIRO_STATUS_NULL_POINTER;
1669 for (i = 0; i < num_comments; i++)
1671 _cairo_array_fini (&surface->dsc_setup_comments);
1673 num_comments = _cairo_array_num_elements (&surface->dsc_page_setup_comments);
1674 comments = _cairo_array_index (&surface->dsc_page_setup_comments, 0);
1675 if (comments == NULL)
1676 return CAIRO_STATUS_NULL_POINTER;
1678 for (i = 0; i < num_comments; i++)
1680 _cairo_array_fini (&surface->dsc_page_setup_comments);
1682 _cairo_surface_clipper_reset (&surface->clipper);
1687 static cairo_int_status_t
1688 _cairo_ps_surface_start_page (void *abstract_surface)
1690 cairo_ps_surface_t *surface = abstract_surface;
1692 /* Increment before print so page numbers start at 1. */
1693 surface->num_pages++;
1695 return CAIRO_STATUS_SUCCESS;
1698 static cairo_int_status_t
1699 _cairo_ps_surface_show_page (void *abstract_surface)
1701 cairo_ps_surface_t *surface = abstract_surface;
1702 cairo_int_status_t status;
1704 if (surface->clipper.clip != NULL)
1705 _cairo_surface_clipper_reset (&surface->clipper);
1707 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
1708 if (unlikely (status))
1711 _cairo_output_stream_printf (surface->stream,
1715 return CAIRO_STATUS_SUCCESS;
1719 color_is_gray (double red, double green, double blue)
1721 const double epsilon = 0.00001;
1723 return (fabs (red - green) < epsilon &&
1724 fabs (red - blue) < epsilon);
1728 * _cairo_ps_surface_acquire_source_surface_from_pattern:
1729 * @surface: the ps surface
1730 * @pattern: A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source
1731 * @extents: extents of the operation that is using this source
1732 * @width: returns width of surface
1733 * @height: returns height of surface
1734 * @x_offset: returns x offset of surface
1735 * @y_offset: returns y offset of surface
1736 * @surface: returns surface of type image surface or recording surface
1737 * @image_extra: returns image extra for image type surface
1739 * Acquire source surface or raster source pattern.
1741 static cairo_status_t
1742 _cairo_ps_surface_acquire_source_surface_from_pattern (cairo_ps_surface_t *surface,
1743 const cairo_pattern_t *pattern,
1744 const cairo_rectangle_int_t *extents,
1749 cairo_surface_t **source_surface,
1752 cairo_status_t status;
1753 cairo_image_surface_t *image;
1755 *x_offset = *y_offset = 0;
1756 switch (pattern->type) {
1757 case CAIRO_PATTERN_TYPE_SURFACE: {
1758 cairo_surface_t *surf = ((cairo_surface_pattern_t *) pattern)->surface;
1760 if (surf->type == CAIRO_SURFACE_TYPE_RECORDING) {
1761 if (surf->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1762 cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surf;
1764 *width = sub->extents.width;
1765 *height = sub->extents.height;
1767 cairo_surface_t *free_me = NULL;
1768 cairo_recording_surface_t *recording_surface;
1770 cairo_rectangle_int_t extents;
1772 recording_surface = (cairo_recording_surface_t *) surf;
1773 if (_cairo_surface_is_snapshot (&recording_surface->base)) {
1774 free_me = _cairo_surface_snapshot_get_target (&recording_surface->base);
1775 recording_surface = (cairo_recording_surface_t *) free_me;
1778 status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
1779 cairo_surface_destroy (free_me);
1780 if (unlikely (status))
1783 _cairo_box_round_to_rectangle (&bbox, &extents);
1784 *width = extents.width;
1785 *height = extents.height;
1787 *source_surface = surf;
1789 return CAIRO_STATUS_SUCCESS;
1791 status = _cairo_surface_acquire_source_image (surf, &image, image_extra);
1792 if (unlikely (status))
1797 case CAIRO_PATTERN_TYPE_RASTER_SOURCE: {
1798 cairo_surface_t *surf;
1800 cairo_rectangle_int_t rect;
1802 /* get the operation extents in pattern space */
1803 _cairo_box_from_rectangle (&box, extents);
1804 _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &box, NULL);
1805 _cairo_box_round_to_rectangle (&box, &rect);
1806 surf = _cairo_raster_source_pattern_acquire (pattern, &surface->base, &rect);
1808 return CAIRO_INT_STATUS_UNSUPPORTED;
1809 assert (_cairo_surface_is_image (surf));
1810 image = (cairo_image_surface_t *) surf;
1813 case CAIRO_PATTERN_TYPE_SOLID:
1814 case CAIRO_PATTERN_TYPE_LINEAR:
1815 case CAIRO_PATTERN_TYPE_RADIAL:
1816 case CAIRO_PATTERN_TYPE_MESH:
1822 *width = image->width;
1823 *height = image->height;
1824 *source_surface = &image->base;
1825 return CAIRO_STATUS_SUCCESS;
1829 _cairo_ps_surface_release_source_surface_from_pattern (cairo_ps_surface_t *surface,
1830 const cairo_pattern_t *pattern,
1831 cairo_surface_t *source,
1834 switch (pattern->type) {
1835 case CAIRO_PATTERN_TYPE_SURFACE: {
1836 cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) pattern;
1837 if (surf_pat->surface->type != CAIRO_SURFACE_TYPE_RECORDING) {
1838 cairo_image_surface_t *image = (cairo_image_surface_t *) source;
1839 _cairo_surface_release_source_image (surf_pat->surface, image, image_extra);
1843 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
1844 _cairo_raster_source_pattern_release (pattern, source);
1847 case CAIRO_PATTERN_TYPE_SOLID:
1848 case CAIRO_PATTERN_TYPE_LINEAR:
1849 case CAIRO_PATTERN_TYPE_RADIAL:
1850 case CAIRO_PATTERN_TYPE_MESH:
1859 * _cairo_ps_surface_create_padded_image_from_image:
1860 * @surface: the ps surface
1861 * @source: The source image
1862 * @extents: extents of the operation that is using this source
1863 * @width: returns width of padded image
1864 * @height: returns height of padded image
1865 * @x_offset: returns x offset of padded image
1866 * @y_offset: returns y offset of padded image
1867 * @image: returns the padded image or NULL if padding not required to fill @extents
1869 * Creates a padded image if the source image does not fill the extents.
1871 static cairo_status_t
1872 _cairo_ps_surface_create_padded_image_from_image (cairo_ps_surface_t *surface,
1873 cairo_image_surface_t *source,
1874 const cairo_matrix_t *source_matrix,
1875 const cairo_rectangle_int_t *extents,
1880 cairo_image_surface_t **image)
1883 cairo_rectangle_int_t rect;
1884 cairo_surface_t *pad_image;
1885 cairo_surface_pattern_t pad_pattern;
1887 cairo_int_status_t status;
1889 /* get the operation extents in pattern space */
1890 _cairo_box_from_rectangle (&box, extents);
1891 _cairo_matrix_transform_bounding_box_fixed (source_matrix, &box, NULL);
1892 _cairo_box_round_to_rectangle (&box, &rect);
1894 /* Check if image needs padding to fill extents. */
1897 if (_cairo_fixed_integer_ceil(box.p1.x) < 0 ||
1898 _cairo_fixed_integer_ceil(box.p1.y) < 0 ||
1899 _cairo_fixed_integer_floor(box.p2.y) > w ||
1900 _cairo_fixed_integer_floor(box.p2.y) > h)
1903 _cairo_image_surface_create_with_pixman_format (NULL,
1904 source->pixman_format,
1905 rect.width, rect.height,
1907 if (pad_image->status) {
1908 status = pad_image->status;
1909 cairo_surface_destroy (pad_image);
1913 _cairo_pattern_init_for_surface (&pad_pattern, &source->base);
1914 cairo_matrix_init_translate (&pad_pattern.base.matrix, rect.x, rect.y);
1915 pad_pattern.base.extend = CAIRO_EXTEND_PAD;
1916 status = _cairo_surface_paint (pad_image,
1917 CAIRO_OPERATOR_SOURCE,
1920 _cairo_pattern_fini (&pad_pattern.base);
1921 *image = (cairo_image_surface_t *) pad_image;
1922 *width = rect.width;
1923 *height = rect.height;
1928 status = CAIRO_STATUS_SUCCESS;
1934 static cairo_int_status_t
1935 _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t *surface,
1936 const cairo_pattern_t *pattern,
1937 const cairo_rectangle_int_t *extents)
1940 double x_offset, y_offset;
1941 cairo_surface_t *source;
1942 cairo_image_surface_t *image;
1944 cairo_int_status_t status;
1945 cairo_image_transparency_t transparency;
1947 status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
1956 if (unlikely (status))
1959 image = (cairo_image_surface_t *) source;
1960 if (image->base.status)
1961 return image->base.status;
1963 transparency = _cairo_image_analyze_transparency (image);
1964 switch (transparency) {
1965 case CAIRO_IMAGE_IS_OPAQUE:
1966 status = CAIRO_STATUS_SUCCESS;
1969 case CAIRO_IMAGE_HAS_BILEVEL_ALPHA:
1970 if (surface->ps_level == CAIRO_PS_LEVEL_2) {
1971 status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1973 surface->ps_level_used = CAIRO_PS_LEVEL_3;
1974 status = CAIRO_STATUS_SUCCESS;
1978 case CAIRO_IMAGE_HAS_ALPHA:
1979 status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1982 case CAIRO_IMAGE_UNKNOWN:
1986 _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
1992 surface_pattern_supported (const cairo_surface_pattern_t *pattern)
1994 if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1997 if (pattern->surface->backend->acquire_source_image == NULL)
2000 /* Does an ALPHA-only source surface even make sense? Maybe, but I
2001 * don't think it's worth the extra code to support it. */
2003 /* XXX: Need to write this function here...
2004 content = pattern->surface->content;
2005 if (content == CAIRO_CONTENT_ALPHA)
2013 _gradient_pattern_supported (cairo_ps_surface_t *surface,
2014 const cairo_pattern_t *pattern)
2016 double min_alpha, max_alpha;
2018 if (surface->ps_level == CAIRO_PS_LEVEL_2)
2021 /* Alpha gradients are only supported (by flattening the alpha)
2022 * if there is no variation in the alpha across the gradient. */
2023 _cairo_pattern_alpha_range (pattern, &min_alpha, &max_alpha);
2024 if (min_alpha != max_alpha)
2027 surface->ps_level_used = CAIRO_PS_LEVEL_3;
2033 pattern_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *pattern)
2035 switch (pattern->type) {
2036 case CAIRO_PATTERN_TYPE_SOLID:
2039 case CAIRO_PATTERN_TYPE_LINEAR:
2040 case CAIRO_PATTERN_TYPE_RADIAL:
2041 case CAIRO_PATTERN_TYPE_MESH:
2042 return _gradient_pattern_supported (surface, pattern);
2044 case CAIRO_PATTERN_TYPE_SURFACE:
2045 return surface_pattern_supported ((cairo_surface_pattern_t *) pattern);
2047 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
2057 mask_supported (cairo_ps_surface_t *surface,
2058 const cairo_pattern_t *mask,
2059 const cairo_rectangle_int_t *extents)
2061 if (surface->ps_level == CAIRO_PS_LEVEL_2)
2064 if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
2065 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
2066 if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
2067 /* check if mask if opaque or bilevel alpha */
2068 if (_cairo_ps_surface_analyze_surface_pattern_transparency (surface, mask, extents) == CAIRO_INT_STATUS_SUCCESS) {
2069 surface->ps_level_used = CAIRO_PS_LEVEL_3;
2078 static cairo_int_status_t
2079 _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
2080 cairo_operator_t op,
2081 const cairo_pattern_t *pattern,
2082 const cairo_pattern_t *mask,
2083 const cairo_rectangle_int_t *extents)
2087 if (surface->force_fallbacks &&
2088 surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
2090 return CAIRO_INT_STATUS_UNSUPPORTED;
2093 if (! pattern_supported (surface, pattern))
2094 return CAIRO_INT_STATUS_UNSUPPORTED;
2096 if (! (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
2097 return CAIRO_INT_STATUS_UNSUPPORTED;
2099 /* Mask is only supported when the mask is an image with opaque or bilevel alpha. */
2100 if (mask && !mask_supported (surface, mask, extents))
2101 return CAIRO_INT_STATUS_UNSUPPORTED;
2103 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
2104 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
2106 if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
2107 if (pattern->extend == CAIRO_EXTEND_PAD) {
2109 cairo_rectangle_int_t rect;
2110 cairo_rectangle_int_t rec_extents;
2112 /* get the operation extents in pattern space */
2113 _cairo_box_from_rectangle (&box, extents);
2114 _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &box, NULL);
2115 _cairo_box_round_to_rectangle (&box, &rect);
2117 /* Check if surface needs padding to fill extents */
2118 if (_cairo_surface_get_extents (surface_pattern->surface, &rec_extents)) {
2119 if (_cairo_fixed_integer_ceil(box.p1.x) < rec_extents.x ||
2120 _cairo_fixed_integer_ceil(box.p1.y) < rec_extents.y ||
2121 _cairo_fixed_integer_floor(box.p2.y) > rec_extents.x + rec_extents.width ||
2122 _cairo_fixed_integer_floor(box.p2.y) > rec_extents.y + rec_extents.height)
2124 return CAIRO_INT_STATUS_UNSUPPORTED;
2128 return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
2132 if (op == CAIRO_OPERATOR_SOURCE) {
2134 return CAIRO_INT_STATUS_UNSUPPORTED;
2136 return CAIRO_STATUS_SUCCESS;
2139 /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
2140 * the pattern contains transparency, we return
2141 * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
2142 * surface. If the analysis surface determines that there is
2143 * anything drawn under this operation, a fallback image will be
2144 * used. Otherwise the operation will be replayed during the
2145 * render stage and we blend the transparency into the white
2146 * background to convert the pattern to opaque.
2148 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE || pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)
2149 return _cairo_ps_surface_analyze_surface_pattern_transparency (surface, pattern, extents);
2151 /* Patterns whose drawn part is opaque are directly supported;
2152 those whose drawn part is partially transparent can be
2153 supported by flattening the alpha. */
2154 _cairo_pattern_alpha_range (pattern, &min_alpha, NULL);
2155 if (CAIRO_ALPHA_IS_OPAQUE (min_alpha))
2156 return CAIRO_STATUS_SUCCESS;
2158 return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
2162 _cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface,
2163 cairo_operator_t op,
2164 const cairo_pattern_t *pattern,
2165 const cairo_pattern_t *mask,
2166 const cairo_rectangle_int_t *extents)
2168 return _cairo_ps_surface_analyze_operation (surface, op, pattern, mask, extents) != CAIRO_INT_STATUS_UNSUPPORTED;
2171 /* The "standard" implementation limit for PostScript string sizes is
2172 * 65535 characters (see PostScript Language Reference, Appendix
2173 * B). We go one short of that because we sometimes need two
2174 * characters in a string to represent a single ASCII85 byte, (for the
2175 * escape sequences "\\", "\(", and "\)") and we must not split these
2176 * across two strings. So we'd be in trouble if we went right to the
2177 * limit and one of these escape sequences just happened to land at
2180 #define STRING_ARRAY_MAX_STRING_SIZE (65535-1)
2181 #define STRING_ARRAY_MAX_COLUMN 72
2183 typedef struct _string_array_stream {
2184 cairo_output_stream_t base;
2185 cairo_output_stream_t *output;
2188 cairo_bool_t use_strings;
2189 } string_array_stream_t;
2191 static cairo_status_t
2192 _string_array_stream_write (cairo_output_stream_t *base,
2193 const unsigned char *data,
2194 unsigned int length)
2196 string_array_stream_t *stream = (string_array_stream_t *) base;
2198 const unsigned char backslash = '\\';
2201 return CAIRO_STATUS_SUCCESS;
2204 if (stream->string_size == 0 && stream->use_strings) {
2205 _cairo_output_stream_printf (stream->output, "(");
2210 if (stream->use_strings) {
2215 _cairo_output_stream_write (stream->output, &backslash, 1);
2217 stream->string_size++;
2221 /* Have to be careful to never split the final ~> sequence. */
2223 _cairo_output_stream_write (stream->output, &c, 1);
2225 stream->string_size++;
2232 _cairo_output_stream_write (stream->output, &c, 1);
2234 stream->string_size++;
2236 if (stream->use_strings &&
2237 stream->string_size >= STRING_ARRAY_MAX_STRING_SIZE)
2239 _cairo_output_stream_printf (stream->output, ")\n");
2240 stream->string_size = 0;
2243 if (stream->column >= STRING_ARRAY_MAX_COLUMN) {
2244 _cairo_output_stream_printf (stream->output, "\n ");
2245 stream->string_size += 2;
2250 return _cairo_output_stream_get_status (stream->output);
2253 static cairo_status_t
2254 _string_array_stream_close (cairo_output_stream_t *base)
2256 cairo_status_t status;
2257 string_array_stream_t *stream = (string_array_stream_t *) base;
2259 if (stream->use_strings)
2260 _cairo_output_stream_printf (stream->output, ")\n");
2262 status = _cairo_output_stream_get_status (stream->output);
2267 /* A string_array_stream wraps an existing output stream. It takes the
2268 * data provided to it and output one or more consecutive string
2269 * objects, each within the standard PostScript implementation limit
2270 * of 65k characters.
2272 * The strings are each separated by a space character for easy
2273 * inclusion within an array object, (but the array delimiters are not
2274 * added by the string_array_stream).
2276 * The string array stream is also careful to wrap the output within
2277 * STRING_ARRAY_MAX_COLUMN columns (+/- 1). The stream also adds
2278 * necessary escaping for special characters within a string,
2279 * (specifically '\', '(', and ')').
2281 static cairo_output_stream_t *
2282 _string_array_stream_create (cairo_output_stream_t *output)
2284 string_array_stream_t *stream;
2286 stream = malloc (sizeof (string_array_stream_t));
2287 if (unlikely (stream == NULL)) {
2288 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
2289 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
2292 _cairo_output_stream_init (&stream->base,
2293 _string_array_stream_write,
2295 _string_array_stream_close);
2296 stream->output = output;
2298 stream->string_size = 0;
2299 stream->use_strings = TRUE;
2301 return &stream->base;
2304 /* A base85_array_stream wraps an existing output stream. It wraps the
2305 * output within STRING_ARRAY_MAX_COLUMN columns (+/- 1). The output
2306 * is not enclosed in strings like string_array_stream.
2308 static cairo_output_stream_t *
2309 _base85_array_stream_create (cairo_output_stream_t *output)
2311 string_array_stream_t *stream;
2313 stream = malloc (sizeof (string_array_stream_t));
2314 if (unlikely (stream == NULL)) {
2315 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
2316 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
2319 _cairo_output_stream_init (&stream->base,
2320 _string_array_stream_write,
2322 _string_array_stream_close);
2323 stream->output = output;
2325 stream->string_size = 0;
2326 stream->use_strings = FALSE;
2328 return &stream->base;
2332 /* PS Output - this section handles output of the parts of the recording
2333 * surface we can render natively in PS. */
2335 static cairo_status_t
2336 _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface,
2337 cairo_image_surface_t *image,
2338 cairo_image_surface_t **opaque_image)
2340 cairo_surface_t *opaque;
2341 cairo_surface_pattern_t pattern;
2342 cairo_status_t status;
2344 opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
2347 if (unlikely (opaque->status)) {
2348 status = opaque->status;
2349 cairo_surface_destroy (opaque);
2353 if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
2354 status = _cairo_surface_paint (opaque,
2355 CAIRO_OPERATOR_SOURCE,
2356 &_cairo_pattern_white.base,
2358 if (unlikely (status)) {
2359 cairo_surface_destroy (opaque);
2364 _cairo_pattern_init_for_surface (&pattern, &image->base);
2365 pattern.base.filter = CAIRO_FILTER_NEAREST;
2366 status = _cairo_surface_paint (opaque, CAIRO_OPERATOR_OVER, &pattern.base, NULL);
2367 _cairo_pattern_fini (&pattern.base);
2368 if (unlikely (status)) {
2369 cairo_surface_destroy (opaque);
2373 *opaque_image = (cairo_image_surface_t *) opaque;
2374 return CAIRO_STATUS_SUCCESS;
2377 static cairo_status_t
2378 _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface,
2379 const unsigned char *data,
2380 unsigned long length,
2381 cairo_ps_compress_t compress,
2382 cairo_bool_t use_strings)
2384 cairo_output_stream_t *base85_stream, *string_array_stream, *deflate_stream;
2385 unsigned char *data_compressed;
2386 unsigned long data_compressed_size;
2387 cairo_status_t status, status2;
2390 string_array_stream = _string_array_stream_create (surface->stream);
2392 string_array_stream = _base85_array_stream_create (surface->stream);
2394 status = _cairo_output_stream_get_status (string_array_stream);
2395 if (unlikely (status))
2396 return _cairo_output_stream_destroy (string_array_stream);
2398 base85_stream = _cairo_base85_stream_create (string_array_stream);
2399 status = _cairo_output_stream_get_status (base85_stream);
2400 if (unlikely (status)) {
2401 status2 = _cairo_output_stream_destroy (string_array_stream);
2402 return _cairo_output_stream_destroy (base85_stream);
2406 case CAIRO_PS_COMPRESS_NONE:
2407 _cairo_output_stream_write (base85_stream, data, length);
2410 case CAIRO_PS_COMPRESS_LZW:
2411 /* XXX: Should fix cairo-lzw to provide a stream-based interface
2413 data_compressed_size = length;
2414 data_compressed = _cairo_lzw_compress ((unsigned char*)data, &data_compressed_size);
2415 if (unlikely (data_compressed == NULL)) {
2416 status = _cairo_output_stream_destroy (string_array_stream);
2417 status = _cairo_output_stream_destroy (base85_stream);
2418 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2420 _cairo_output_stream_write (base85_stream, data_compressed, data_compressed_size);
2421 free (data_compressed);
2424 case CAIRO_PS_COMPRESS_DEFLATE:
2425 deflate_stream = _cairo_deflate_stream_create (base85_stream);
2426 if (_cairo_output_stream_get_status (deflate_stream)) {
2427 return _cairo_output_stream_destroy (deflate_stream);
2429 _cairo_output_stream_write (deflate_stream, data, length);
2430 status = _cairo_output_stream_destroy (deflate_stream);
2431 if (unlikely (status)) {
2432 status2 = _cairo_output_stream_destroy (string_array_stream);
2433 status2 = _cairo_output_stream_destroy (base85_stream);
2434 return _cairo_output_stream_destroy (deflate_stream);
2438 status = _cairo_output_stream_destroy (base85_stream);
2440 /* Mark end of base85 data */
2441 _cairo_output_stream_printf (string_array_stream, "~>");
2442 status2 = _cairo_output_stream_destroy (string_array_stream);
2443 if (status == CAIRO_STATUS_SUCCESS)
2449 static cairo_status_t
2450 _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
2451 cairo_image_surface_t *image_surf,
2452 cairo_operator_t op,
2453 cairo_filter_t filter,
2454 cairo_bool_t stencil_mask)
2456 cairo_status_t status;
2457 unsigned char *data;
2458 unsigned long data_size;
2459 cairo_image_surface_t *ps_image;
2461 cairo_image_transparency_t transparency;
2462 cairo_bool_t use_mask;
2466 cairo_image_color_t color;
2467 const char *interpolate;
2468 cairo_ps_compress_t compress;
2469 const char *compress_filter;
2470 cairo_image_surface_t *image;
2472 if (image_surf->base.status)
2473 return image_surf->base.status;
2476 if (image->format != CAIRO_FORMAT_RGB24 &&
2477 image->format != CAIRO_FORMAT_ARGB32 &&
2478 image->format != CAIRO_FORMAT_A8 &&
2479 image->format != CAIRO_FORMAT_A1)
2481 cairo_surface_t *surf;
2482 cairo_surface_pattern_t pattern;
2484 surf = _cairo_image_surface_create_with_content (image_surf->base.content,
2486 image_surf->height);
2487 image = (cairo_image_surface_t *) surf;
2489 status = surf->status;
2493 _cairo_pattern_init_for_surface (&pattern, &image_surf->base);
2494 status = _cairo_surface_paint (surf,
2495 CAIRO_OPERATOR_SOURCE, &pattern.base,
2497 _cairo_pattern_fini (&pattern.base);
2498 if (unlikely (status))
2505 case CAIRO_FILTER_GOOD:
2506 case CAIRO_FILTER_BEST:
2507 case CAIRO_FILTER_BILINEAR:
2508 interpolate = "true";
2510 case CAIRO_FILTER_FAST:
2511 case CAIRO_FILTER_NEAREST:
2512 case CAIRO_FILTER_GAUSSIAN:
2513 interpolate = "false";
2519 color = CAIRO_IMAGE_IS_MONOCHROME;
2520 transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
2522 transparency = _cairo_image_analyze_transparency (image);
2524 /* PostScript can not represent the alpha channel, so we blend the
2525 current image over a white (or black for CONTENT_COLOR
2526 surfaces) RGB surface to eliminate it. */
2528 if (op == CAIRO_OPERATOR_SOURCE ||
2529 transparency == CAIRO_IMAGE_HAS_ALPHA ||
2530 (transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA &&
2531 surface->ps_level == CAIRO_PS_LEVEL_2))
2533 status = _cairo_ps_surface_flatten_image_transparency (surface,
2536 if (unlikely (status))
2540 } else if (transparency == CAIRO_IMAGE_IS_OPAQUE) {
2542 } else { /* transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA */
2546 color = _cairo_image_analyze_color (ps_image);
2549 /* Type 2 (mask and image interleaved) has the mask and image
2550 * samples interleaved by row. The mask row is first, one bit per
2551 * pixel with (bit 7 first). The row is padded to byte
2552 * boundaries. The image data is 3 bytes per pixel RGB format. */
2555 case CAIRO_IMAGE_UNKNOWN_COLOR:
2557 case CAIRO_IMAGE_IS_COLOR:
2558 data_size = ps_image->width * 3;
2560 case CAIRO_IMAGE_IS_GRAYSCALE:
2561 data_size = ps_image->width;
2563 case CAIRO_IMAGE_IS_MONOCHROME:
2564 data_size = (ps_image->width + 7)/8;
2568 data_size += (ps_image->width + 7)/8;
2569 data_size *= ps_image->height;
2570 data = malloc (data_size);
2571 if (unlikely (data == NULL)) {
2572 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2577 for (y = 0; y < ps_image->height; y++) {
2578 if (stencil_mask || use_mask) {
2580 if (ps_image->format == CAIRO_FORMAT_A1) {
2581 pixel8 = (uint8_t *) (ps_image->data + y * ps_image->stride);
2583 for (x = 0; x < (ps_image->width + 7) / 8; x++, pixel8++) {
2585 a = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (a);
2589 pixel8 = (uint8_t *) (ps_image->data + y * ps_image->stride);
2590 pixel32 = (uint32_t *) (ps_image->data + y * ps_image->stride);
2592 for (x = 0; x < ps_image->width; x++) {
2593 if (ps_image->format == CAIRO_FORMAT_ARGB32) {
2594 a = (*pixel32 & 0xff000000) >> 24;
2601 if (transparency == CAIRO_IMAGE_HAS_ALPHA) {
2603 } else { /* transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA or CAIRO_IMAGE_IS_OPAQUE */
2607 data[i] |= (1 << bit);
2623 pixel32 = (uint32_t *) (ps_image->data + y * ps_image->stride);
2625 for (x = 0; x < ps_image->width; x++, pixel32++) {
2628 if (ps_image->format == CAIRO_FORMAT_ARGB32) {
2629 /* At this point ARGB32 images are either opaque or
2630 * bilevel alpha so we don't need to unpremultiply. */
2631 if (((*pixel32 & 0xff000000) >> 24) == 0) {
2634 r = (*pixel32 & 0x00ff0000) >> 16;
2635 g = (*pixel32 & 0x0000ff00) >> 8;
2636 b = (*pixel32 & 0x000000ff) >> 0;
2638 } else if (ps_image->format == CAIRO_FORMAT_RGB24) {
2639 r = (*pixel32 & 0x00ff0000) >> 16;
2640 g = (*pixel32 & 0x0000ff00) >> 8;
2641 b = (*pixel32 & 0x000000ff) >> 0;
2647 case CAIRO_IMAGE_IS_COLOR:
2648 case CAIRO_IMAGE_UNKNOWN_COLOR:
2654 case CAIRO_IMAGE_IS_GRAYSCALE:
2658 case CAIRO_IMAGE_IS_MONOCHROME:
2662 data[i] |= (1 << bit);
2675 if (surface->ps_level == CAIRO_PS_LEVEL_2) {
2676 compress = CAIRO_PS_COMPRESS_LZW;
2677 compress_filter = "LZWDecode";
2679 compress = CAIRO_PS_COMPRESS_DEFLATE;
2680 compress_filter = "FlateDecode";
2681 surface->ps_level_used = CAIRO_PS_LEVEL_3;
2684 if (surface->use_string_datasource) {
2685 /* Emit the image data as a base85-encoded string which will
2686 * be used as the data source for the image operator later. */
2687 _cairo_output_stream_printf (surface->stream,
2688 "/CairoImageData [\n");
2690 status = _cairo_ps_surface_emit_base85_string (surface,
2695 if (unlikely (status))
2698 _cairo_output_stream_printf (surface->stream,
2700 _cairo_output_stream_printf (surface->stream,
2701 "/CairoImageDataIndex 0 def\n");
2705 _cairo_output_stream_printf (surface->stream,
2706 "%s setcolorspace\n"
2707 "5 dict dup begin\n"
2708 " /ImageType 3 def\n"
2709 " /InterleaveType 2 def\n"
2710 " /DataDict 8 dict def\n"
2712 " /ImageType 1 def\n"
2715 " /Interpolate %s def\n"
2716 " /BitsPerComponent %d def\n"
2717 " /Decode [ %s ] def\n",
2718 color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray",
2722 color == CAIRO_IMAGE_IS_MONOCHROME ? 1 : 8,
2723 color == CAIRO_IMAGE_IS_COLOR ? "0 1 0 1 0 1" : "0 1");
2725 if (surface->use_string_datasource) {
2726 _cairo_output_stream_printf (surface->stream,
2728 " CairoImageData CairoImageDataIndex get\n"
2729 " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2730 " CairoImageDataIndex CairoImageData length 1 sub gt\n"
2731 " { /CairoImageDataIndex 0 def } if\n"
2732 " } /ASCII85Decode filter /%s filter def\n",
2735 _cairo_output_stream_printf (surface->stream,
2736 " /DataSource currentfile /ASCII85Decode filter /%s filter def\n",
2740 _cairo_output_stream_printf (surface->stream,
2741 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2743 " /MaskDict 8 dict def\n"
2745 " /ImageType 1 def\n"
2748 " /Interpolate %s def\n"
2749 " /BitsPerComponent 1 def\n"
2750 " /Decode [ 1 0 ] def\n"
2751 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2761 if (!stencil_mask) {
2762 _cairo_output_stream_printf (surface->stream,
2763 "%s setcolorspace\n",
2764 color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray");
2766 _cairo_output_stream_printf (surface->stream,
2767 "8 dict dup begin\n"
2768 " /ImageType 1 def\n"
2771 " /Interpolate %s def\n"
2772 " /BitsPerComponent %d def\n"
2773 " /Decode [ %s ] def\n",
2777 color == CAIRO_IMAGE_IS_MONOCHROME ? 1 : 8,
2778 stencil_mask ? "1 0" : color == CAIRO_IMAGE_IS_COLOR ? "0 1 0 1 0 1" : "0 1");
2779 if (surface->use_string_datasource) {
2780 _cairo_output_stream_printf (surface->stream,
2782 " CairoImageData CairoImageDataIndex get\n"
2783 " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2784 " CairoImageDataIndex CairoImageData length 1 sub gt\n"
2785 " { /CairoImageDataIndex 0 def } if\n"
2786 " } /ASCII85Decode filter /%s filter def\n",
2789 _cairo_output_stream_printf (surface->stream,
2790 " /DataSource currentfile /ASCII85Decode filter /%s filter def\n",
2794 _cairo_output_stream_printf (surface->stream,
2795 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2799 stencil_mask ? "imagemask" : "image");
2802 if (!surface->use_string_datasource) {
2803 /* Emit the image data as a base85-encoded string which will
2804 * be used as the data source for the image operator. */
2805 status = _cairo_ps_surface_emit_base85_string (surface,
2810 _cairo_output_stream_printf (surface->stream, "\n");
2812 status = CAIRO_STATUS_SUCCESS;
2819 if (!use_mask && ps_image != image)
2820 cairo_surface_destroy (&ps_image->base);
2823 if (image != image_surf)
2824 cairo_surface_destroy (&image->base);
2829 static cairo_status_t
2830 _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface,
2831 cairo_surface_t *source,
2835 cairo_status_t status;
2836 const unsigned char *mime_data;
2837 unsigned long mime_data_length;
2838 cairo_image_info_t info;
2839 const char *colorspace;
2842 cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
2843 &mime_data, &mime_data_length);
2844 if (unlikely (source->status))
2845 return source->status;
2846 if (mime_data == NULL)
2847 return CAIRO_INT_STATUS_UNSUPPORTED;
2849 status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length);
2850 if (unlikely (status))
2853 switch (info.num_components) {
2855 colorspace = "/DeviceGray";
2859 colorspace = "/DeviceRGB";
2860 decode = "0 1 0 1 0 1";
2863 colorspace = "/DeviceCMYK";
2864 decode = "0 1 0 1 0 1 0 1";
2867 return CAIRO_INT_STATUS_UNSUPPORTED;
2870 if (surface->use_string_datasource) {
2871 /* Emit the image data as a base85-encoded string which will
2872 * be used as the data source for the image operator later. */
2873 _cairo_output_stream_printf (surface->stream,
2874 "/CairoImageData [\n");
2876 status = _cairo_ps_surface_emit_base85_string (surface,
2879 CAIRO_PS_COMPRESS_NONE,
2881 if (unlikely (status))
2884 _cairo_output_stream_printf (surface->stream,
2886 _cairo_output_stream_printf (surface->stream,
2887 "/CairoImageDataIndex 0 def\n");
2890 _cairo_output_stream_printf (surface->stream,
2891 "%s setcolorspace\n"
2892 "8 dict dup begin\n"
2893 " /ImageType 1 def\n"
2896 " /BitsPerComponent %d def\n"
2897 " /Decode [ %s ] def\n",
2901 info.bits_per_component,
2904 if (surface->use_string_datasource) {
2905 _cairo_output_stream_printf (surface->stream,
2907 " CairoImageData CairoImageDataIndex get\n"
2908 " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2909 " CairoImageDataIndex CairoImageData length 1 sub gt\n"
2910 " { /CairoImageDataIndex 0 def } if\n"
2911 " } /ASCII85Decode filter /DCTDecode filter def\n");
2913 _cairo_output_stream_printf (surface->stream,
2914 " /DataSource currentfile /ASCII85Decode filter /DCTDecode filter def\n");
2917 _cairo_output_stream_printf (surface->stream,
2918 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2923 if (!surface->use_string_datasource) {
2924 /* Emit the image data as a base85-encoded string which will
2925 * be used as the data source for the image operator. */
2926 status = _cairo_ps_surface_emit_base85_string (surface,
2929 CAIRO_PS_COMPRESS_NONE,
2936 static cairo_status_t
2937 _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
2938 cairo_surface_t *recording_surface)
2940 double old_width, old_height;
2941 cairo_matrix_t old_cairo_to_ps;
2942 cairo_content_t old_content;
2943 cairo_rectangle_int_t old_page_bbox;
2944 cairo_surface_t *free_me = NULL;
2945 cairo_surface_clipper_t old_clipper;
2947 cairo_int_status_t status;
2949 old_content = surface->content;
2950 old_width = surface->width;
2951 old_height = surface->height;
2952 old_page_bbox = surface->page_bbox;
2953 old_cairo_to_ps = surface->cairo_to_ps;
2954 old_clipper = surface->clipper;
2955 _cairo_surface_clipper_init (&surface->clipper,
2956 _cairo_ps_surface_clipper_intersect_clip_path);
2958 if (_cairo_surface_is_snapshot (recording_surface))
2959 free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface);
2962 _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
2965 if (unlikely (status))
2969 _cairo_output_stream_printf (surface->stream,
2970 "%% _cairo_ps_surface_emit_recording_surface (%f, %f), (%f, %f)\n",
2971 _cairo_fixed_to_double (bbox.p1.x),
2972 _cairo_fixed_to_double (bbox.p1.y),
2973 _cairo_fixed_to_double (bbox.p2.x),
2974 _cairo_fixed_to_double (bbox.p2.y));
2977 surface->width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
2978 surface->height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
2979 _cairo_box_round_to_rectangle (&bbox, &surface->page_bbox);
2981 surface->current_pattern_is_solid_color = FALSE;
2982 _cairo_pdf_operators_reset (&surface->pdf_operators);
2983 cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
2984 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
2985 &surface->cairo_to_ps);
2986 _cairo_output_stream_printf (surface->stream, " q\n");
2988 if (recording_surface->content == CAIRO_CONTENT_COLOR) {
2989 surface->content = CAIRO_CONTENT_COLOR;
2990 _cairo_output_stream_printf (surface->stream,
2991 " 0 g %d %d %d %d rectfill\n",
2992 surface->page_bbox.x,
2993 surface->page_bbox.y,
2994 surface->page_bbox.width,
2995 surface->page_bbox.height);
2998 status = _cairo_recording_surface_replay_region (recording_surface,
3001 CAIRO_RECORDING_REGION_NATIVE);
3002 assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
3003 if (unlikely (status))
3006 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3007 if (unlikely (status))
3010 _cairo_output_stream_printf (surface->stream, " Q\n");
3012 _cairo_surface_clipper_reset (&surface->clipper);
3013 surface->clipper = old_clipper;
3014 surface->content = old_content;
3015 surface->width = old_width;
3016 surface->height = old_height;
3017 surface->page_bbox = old_page_bbox;
3018 surface->current_pattern_is_solid_color = FALSE;
3019 _cairo_pdf_operators_reset (&surface->pdf_operators);
3020 surface->cairo_to_ps = old_cairo_to_ps;
3022 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
3023 &surface->cairo_to_ps);
3026 cairo_surface_destroy (free_me);
3030 static cairo_int_status_t
3031 _cairo_ps_surface_emit_recording_subsurface (cairo_ps_surface_t *surface,
3032 cairo_surface_t *recording_surface,
3033 const cairo_rectangle_int_t *extents)
3035 double old_width, old_height;
3036 cairo_matrix_t old_cairo_to_ps;
3037 cairo_content_t old_content;
3038 cairo_rectangle_int_t old_page_bbox;
3039 cairo_surface_clipper_t old_clipper;
3040 cairo_surface_t *free_me = NULL;
3041 cairo_int_status_t status;
3043 old_content = surface->content;
3044 old_width = surface->width;
3045 old_height = surface->height;
3046 old_page_bbox = surface->page_bbox;
3047 old_cairo_to_ps = surface->cairo_to_ps;
3048 old_clipper = surface->clipper;
3049 _cairo_surface_clipper_init (&surface->clipper,
3050 _cairo_ps_surface_clipper_intersect_clip_path);
3053 _cairo_output_stream_printf (surface->stream,
3054 "%% _cairo_ps_surface_emit_recording_subsurface (%d, %d), (%d, %d)\n",
3055 extents->x, extents->y,
3056 extents->width, extents->height);
3059 surface->page_bbox.x = surface->page_bbox.y = 0;
3060 surface->page_bbox.width = surface->width = extents->width;
3061 surface->page_bbox.height = surface->height = extents->height;
3063 surface->current_pattern_is_solid_color = FALSE;
3064 _cairo_pdf_operators_reset (&surface->pdf_operators);
3065 cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
3066 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
3067 &surface->cairo_to_ps);
3068 _cairo_output_stream_printf (surface->stream, " q\n");
3070 if (_cairo_surface_is_snapshot (recording_surface))
3071 free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface);
3073 if (recording_surface->content == CAIRO_CONTENT_COLOR) {
3074 surface->content = CAIRO_CONTENT_COLOR;
3075 _cairo_output_stream_printf (surface->stream,
3076 " 0 g %d %d %d %d rectfill\n",
3077 surface->page_bbox.x,
3078 surface->page_bbox.y,
3079 surface->page_bbox.width,
3080 surface->page_bbox.height);
3083 status = _cairo_recording_surface_replay_region (recording_surface,
3086 CAIRO_RECORDING_REGION_NATIVE);
3087 assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
3088 if (unlikely (status))
3091 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3092 if (unlikely (status))
3095 _cairo_output_stream_printf (surface->stream, " Q\n");
3097 _cairo_surface_clipper_reset (&surface->clipper);
3098 surface->clipper = old_clipper;
3099 surface->content = old_content;
3100 surface->width = old_width;
3101 surface->height = old_height;
3102 surface->page_bbox = old_page_bbox;
3103 surface->current_pattern_is_solid_color = FALSE;
3104 _cairo_pdf_operators_reset (&surface->pdf_operators);
3105 surface->cairo_to_ps = old_cairo_to_ps;
3107 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
3108 &surface->cairo_to_ps);
3111 cairo_surface_destroy (free_me);
3116 _cairo_ps_surface_flatten_transparency (cairo_ps_surface_t *surface,
3117 const cairo_color_t *color,
3123 *green = color->green;
3124 *blue = color->blue;
3126 if (! CAIRO_COLOR_IS_OPAQUE (color)) {
3127 *red *= color->alpha;
3128 *green *= color->alpha;
3129 *blue *= color->alpha;
3130 if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
3131 double one_minus_alpha = 1. - color->alpha;
3132 *red += one_minus_alpha;
3133 *green += one_minus_alpha;
3134 *blue += one_minus_alpha;
3140 _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
3141 cairo_solid_pattern_t *pattern)
3143 double red, green, blue;
3145 _cairo_ps_surface_flatten_transparency (surface, &pattern->color, &red, &green, &blue);
3147 if (color_is_gray (red, green, blue))
3148 _cairo_output_stream_printf (surface->stream,
3152 _cairo_output_stream_printf (surface->stream,
3157 static cairo_status_t
3158 _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
3159 cairo_pattern_t *source_pattern,
3160 cairo_surface_t *source_surface,
3161 cairo_operator_t op,
3164 cairo_bool_t stencil_mask)
3166 cairo_int_status_t status;
3168 if (source_pattern->type == CAIRO_PATTERN_TYPE_SURFACE &&
3169 source_pattern->extend != CAIRO_EXTEND_PAD)
3171 cairo_surface_t *surf = ((cairo_surface_pattern_t *) source_pattern)->surface;
3173 status = _cairo_ps_surface_emit_jpeg_image (surface, surf, width, height);
3174 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
3178 if (source_surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
3179 if (source_surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
3180 cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source_surface;
3181 status = _cairo_ps_surface_emit_recording_subsurface (surface, sub->target, &sub->extents);
3183 status = _cairo_ps_surface_emit_recording_surface (surface, source_surface);
3186 cairo_image_surface_t *image = (cairo_image_surface_t *) source_surface;
3188 status = _cairo_ps_surface_emit_image (surface, image,
3189 op, source_pattern->filter, stencil_mask);
3197 _path_fixed_init_rectangle (cairo_path_fixed_t *path,
3198 cairo_rectangle_int_t *rect)
3200 cairo_status_t status;
3202 _cairo_path_fixed_init (path);
3204 status = _cairo_path_fixed_move_to (path,
3205 _cairo_fixed_from_int (rect->x),
3206 _cairo_fixed_from_int (rect->y));
3207 assert (status == CAIRO_STATUS_SUCCESS);
3208 status = _cairo_path_fixed_rel_line_to (path,
3209 _cairo_fixed_from_int (rect->width),
3210 _cairo_fixed_from_int (0));
3211 assert (status == CAIRO_STATUS_SUCCESS);
3212 status = _cairo_path_fixed_rel_line_to (path,
3213 _cairo_fixed_from_int (0),
3214 _cairo_fixed_from_int (rect->height));
3215 assert (status == CAIRO_STATUS_SUCCESS);
3216 status = _cairo_path_fixed_rel_line_to (path,
3217 _cairo_fixed_from_int (-rect->width),
3218 _cairo_fixed_from_int (0));
3219 assert (status == CAIRO_STATUS_SUCCESS);
3221 status = _cairo_path_fixed_close_path (path);
3222 assert (status == CAIRO_STATUS_SUCCESS);
3225 static cairo_status_t
3226 _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
3227 cairo_pattern_t *pattern,
3228 cairo_rectangle_int_t *extents,
3229 cairo_operator_t op,
3230 cairo_bool_t stencil_mask)
3232 cairo_status_t status;
3234 cairo_matrix_t cairo_p2d, ps_p2d;
3235 cairo_path_fixed_t path;
3236 double x_offset, y_offset;
3237 cairo_surface_t *source;
3238 cairo_image_surface_t *image = NULL;
3241 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3242 if (unlikely (status))
3245 status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
3249 &x_offset, &y_offset,
3252 if (unlikely (status))
3255 if (pattern->extend == CAIRO_EXTEND_PAD &&
3256 pattern->type == CAIRO_PATTERN_TYPE_SURFACE &&
3257 ((cairo_surface_pattern_t *)pattern)->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
3258 cairo_image_surface_t *img;
3260 img = (cairo_image_surface_t *) source;
3261 status = _cairo_ps_surface_create_padded_image_from_image (surface,
3266 &x_offset, &y_offset,
3268 if (unlikely (status))
3269 goto release_source;
3272 _path_fixed_init_rectangle (&path, extents);
3273 status = _cairo_pdf_operators_clip (&surface->pdf_operators,
3275 CAIRO_FILL_RULE_WINDING);
3276 _cairo_path_fixed_fini (&path);
3277 if (unlikely (status))
3278 goto release_source;
3280 cairo_p2d = pattern->matrix;
3282 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
3283 double x_scale = cairo_p2d.xx;
3284 double y_scale = cairo_p2d.yy;
3286 _cairo_output_stream_printf (surface->stream,
3287 "%% Fallback Image: x=%f y=%f w=%d h=%d ",
3288 -cairo_p2d.x0/x_scale,
3289 -cairo_p2d.y0/y_scale,
3290 (int)(width/x_scale),
3291 (int)(height/y_scale));
3292 if (x_scale == y_scale) {
3293 _cairo_output_stream_printf (surface->stream,
3297 _cairo_output_stream_printf (surface->stream,
3302 _cairo_output_stream_printf (surface->stream,
3304 (long)width*height*3);
3306 if (op == CAIRO_OPERATOR_SOURCE) {
3307 _cairo_output_stream_printf (surface->stream,
3308 "%d g 0 0 %f %f rectfill\n",
3309 surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
3315 status = cairo_matrix_invert (&cairo_p2d);
3316 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3317 assert (status == CAIRO_STATUS_SUCCESS);
3319 ps_p2d = surface->cairo_to_ps;
3320 cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
3321 cairo_matrix_translate (&ps_p2d, x_offset, y_offset);
3322 cairo_matrix_translate (&ps_p2d, 0.0, height);
3323 cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
3325 if (! _cairo_matrix_is_identity (&ps_p2d)) {
3326 _cairo_output_stream_printf (surface->stream, "[ ");
3327 _cairo_output_stream_print_matrix (surface->stream, &ps_p2d);
3328 _cairo_output_stream_printf (surface->stream, " ] concat\n");
3331 status = _cairo_ps_surface_emit_surface (surface,
3333 image ? &image->base : source,
3340 cairo_surface_destroy (&image->base);
3342 _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
3347 static cairo_status_t
3348 _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
3349 cairo_pattern_t *pattern,
3350 cairo_rectangle_int_t *extents,
3351 cairo_operator_t op)
3353 cairo_status_t status;
3354 int pattern_width = 0; /* squelch bogus compiler warning */
3355 int pattern_height = 0; /* squelch bogus compiler warning */
3356 double xstep, ystep;
3357 cairo_matrix_t cairo_p2d, ps_p2d;
3358 cairo_bool_t old_use_string_datasource;
3359 double x_offset, y_offset;
3360 cairo_surface_t *source;
3361 cairo_image_surface_t *image = NULL;
3364 cairo_p2d = pattern->matrix;
3365 status = cairo_matrix_invert (&cairo_p2d);
3366 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3367 assert (status == CAIRO_STATUS_SUCCESS);
3369 status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
3372 &pattern_width, &pattern_height,
3373 &x_offset, &y_offset,
3376 if (unlikely (status))
3379 if (pattern->extend == CAIRO_EXTEND_PAD) {
3380 cairo_image_surface_t *img;
3382 assert (source->type == CAIRO_SURFACE_TYPE_IMAGE);
3383 img = (cairo_image_surface_t *) source;
3384 status = _cairo_ps_surface_create_padded_image_from_image (surface,
3388 &pattern_width, &pattern_height,
3389 &x_offset, &y_offset,
3391 if (unlikely (status))
3392 goto release_source;
3395 switch (pattern->extend) {
3396 case CAIRO_EXTEND_PAD:
3397 case CAIRO_EXTEND_NONE:
3399 /* In PS/PDF, (as far as I can tell), all patterns are
3400 * repeating. So we support cairo's EXTEND_NONE semantics
3401 * by setting the repeat step size to a size large enough
3402 * to guarantee that no more than a single occurrence will
3405 * First, map the surface extents into pattern space (since
3406 * xstep and ystep are in pattern space). Then use an upper
3407 * bound on the length of the diagonal of the pattern image
3408 * and the surface as repeat size. This guarantees to never
3411 double x1 = 0.0, y1 = 0.0;
3412 double x2 = surface->width, y2 = surface->height;
3413 _cairo_matrix_transform_bounding_box (&pattern->matrix,
3417 /* Rather than computing precise bounds of the union, just
3418 * add the surface extents unconditionally. We only
3419 * required an answer that's large enough, we don't really
3420 * care if it's not as tight as possible.*/
3421 xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
3422 pattern_width + pattern_height);
3425 case CAIRO_EXTEND_REPEAT:
3426 xstep = pattern_width;
3427 ystep = pattern_height;
3429 case CAIRO_EXTEND_REFLECT:
3430 xstep = pattern_width*2;
3431 ystep = pattern_height*2;
3433 /* All the rest (if any) should have been analyzed away, so these
3434 * cases should be unreachable. */
3441 _cairo_output_stream_printf (surface->stream,
3442 "/CairoPattern {\n");
3444 old_use_string_datasource = surface->use_string_datasource;
3445 surface->use_string_datasource = TRUE;
3446 if (op == CAIRO_OPERATOR_SOURCE) {
3447 _cairo_output_stream_printf (surface->stream,
3448 "%d g 0 0 %f %f rectfill\n",
3449 surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
3452 status = _cairo_ps_surface_emit_surface (surface,
3454 image ? &image->base : source,
3456 pattern_width, pattern_height, FALSE);
3457 if (unlikely (status))
3458 goto release_source;
3460 surface->use_string_datasource = old_use_string_datasource;
3461 _cairo_output_stream_printf (surface->stream,
3464 _cairo_output_stream_printf (surface->stream,
3465 "<< /PatternType 1\n"
3467 " /TilingType 1\n");
3468 _cairo_output_stream_printf (surface->stream,
3469 " /XStep %f /YStep %f\n",
3472 if (pattern->extend == CAIRO_EXTEND_REFLECT) {
3473 _cairo_output_stream_printf (surface->stream,
3474 " /BBox [0 0 %d %d]\n"
3476 " pop CairoPattern\n"
3477 " [-1 0 0 1 %d 0] concat CairoPattern\n"
3478 " [ 1 0 0 -1 0 %d] concat CairoPattern\n"
3479 " [-1 0 0 1 %d 0] concat CairoPattern\n"
3482 pattern_width*2, pattern_height*2,
3487 if (op == CAIRO_OPERATOR_SOURCE) {
3488 _cairo_output_stream_printf (surface->stream,
3489 " /BBox [0 0 %f %f]\n",
3492 _cairo_output_stream_printf (surface->stream,
3493 " /BBox [0 0 %d %d]\n",
3494 pattern_width, pattern_height);
3496 _cairo_output_stream_printf (surface->stream,
3497 " /PaintProc { pop CairoPattern }\n");
3500 _cairo_output_stream_printf (surface->stream,
3503 cairo_p2d = pattern->matrix;
3504 status = cairo_matrix_invert (&cairo_p2d);
3505 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3506 assert (status == CAIRO_STATUS_SUCCESS);
3508 cairo_matrix_init_identity (&ps_p2d);
3509 cairo_matrix_translate (&ps_p2d, 0.0, surface->height);
3510 cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
3511 cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
3512 cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
3513 cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
3515 _cairo_output_stream_printf (surface->stream, "[ ");
3516 _cairo_output_stream_print_matrix (surface->stream, &ps_p2d);
3517 _cairo_output_stream_printf (surface->stream,
3519 "makepattern setpattern\n");
3523 cairo_surface_destroy (&image->base);
3525 _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
3530 typedef struct _cairo_ps_color_stop {
3533 } cairo_ps_color_stop_t;
3536 _cairo_ps_surface_emit_linear_colorgradient (cairo_ps_surface_t *surface,
3537 cairo_ps_color_stop_t *stop1,
3538 cairo_ps_color_stop_t *stop2)
3540 _cairo_output_stream_printf (surface->stream,
3541 " << /FunctionType 2\n"
3542 " /Domain [ 0 1 ]\n"
3543 " /C0 [ %f %f %f ]\n"
3544 " /C1 [ %f %f %f ]\n"
3556 _cairo_ps_surface_emit_stitched_colorgradient (cairo_ps_surface_t *surface,
3557 unsigned int n_stops,
3558 cairo_ps_color_stop_t stops[])
3562 _cairo_output_stream_printf (surface->stream,
3563 "<< /FunctionType 3\n"
3564 " /Domain [ 0 1 ]\n"
3566 for (i = 0; i < n_stops - 1; i++)
3567 _cairo_ps_surface_emit_linear_colorgradient (surface, &stops[i], &stops[i+1]);
3569 _cairo_output_stream_printf (surface->stream, " ]\n");
3571 _cairo_output_stream_printf (surface->stream, " /Bounds [ ");
3572 for (i = 1; i < n_stops-1; i++)
3573 _cairo_output_stream_printf (surface->stream, "%f ", stops[i].offset);
3574 _cairo_output_stream_printf (surface->stream, "]\n");
3576 _cairo_output_stream_printf (surface->stream, " /Encode [ 1 1 %d { pop 0 1 } for ]\n",
3579 _cairo_output_stream_printf (surface->stream, ">>\n");
3583 calc_gradient_color (cairo_ps_color_stop_t *new_stop,
3584 cairo_ps_color_stop_t *stop1,
3585 cairo_ps_color_stop_t *stop2)
3588 double offset = stop1->offset / (stop1->offset + 1.0 - stop2->offset);
3590 for (i = 0; i < 4; i++)
3591 new_stop->color[i] = stop1->color[i] + offset*(stop2->color[i] - stop1->color[i]);
3594 #define COLOR_STOP_EPSILON 1e-6
3596 static cairo_status_t
3597 _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t *surface,
3598 cairo_gradient_pattern_t *pattern)
3600 cairo_ps_color_stop_t *allstops, *stops;
3601 unsigned int i, n_stops;
3603 allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_ps_color_stop_t));
3604 if (unlikely (allstops == NULL))
3605 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3607 stops = &allstops[1];
3608 n_stops = pattern->n_stops;
3610 for (i = 0; i < n_stops; i++) {
3611 cairo_gradient_stop_t *stop = &pattern->stops[i];
3613 stops[i].color[0] = stop->color.red;
3614 stops[i].color[1] = stop->color.green;
3615 stops[i].color[2] = stop->color.blue;
3616 stops[i].color[3] = stop->color.alpha;
3617 stops[i].offset = pattern->stops[i].offset;
3620 if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
3621 pattern->base.extend == CAIRO_EXTEND_REFLECT)
3623 if (stops[0].offset > COLOR_STOP_EPSILON) {
3624 if (pattern->base.extend == CAIRO_EXTEND_REFLECT)
3625 memcpy (allstops, stops, sizeof (cairo_ps_color_stop_t));
3627 calc_gradient_color (&allstops[0], &stops[0], &stops[n_stops-1]);
3631 stops[0].offset = 0.0;
3633 if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
3634 if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
3635 memcpy (&stops[n_stops],
3636 &stops[n_stops - 1],
3637 sizeof (cairo_ps_color_stop_t));
3639 calc_gradient_color (&stops[n_stops], &stops[0], &stops[n_stops-1]);
3643 stops[n_stops-1].offset = 1.0;
3646 for (i = 0; i < n_stops; i++) {
3647 double red, green, blue;
3648 cairo_color_t color;
3650 _cairo_color_init_rgba (&color,
3655 _cairo_ps_surface_flatten_transparency (surface, &color,
3656 &red, &green, &blue);
3657 stops[i].color[0] = red;
3658 stops[i].color[1] = green;
3659 stops[i].color[2] = blue;
3662 _cairo_output_stream_printf (surface->stream,
3663 "/CairoFunction\n");
3664 if (stops[0].offset == stops[n_stops - 1].offset) {
3666 * The first and the last stops have the same offset, but we
3667 * don't want a function with an empty domain, because that
3668 * would provoke underdefined behaviour from rasterisers.
3669 * This can only happen with EXTEND_PAD, because EXTEND_NONE
3670 * is optimised into a clear pattern in cairo-gstate, and
3671 * REFLECT/REPEAT are always transformed to have the first
3672 * stop at t=0 and the last stop at t=1. Thus we want a step
3673 * function going from the first color to the last one.
3675 * This can be accomplished by stitching three functions:
3676 * - a constant first color function,
3677 * - a step from the first color to the last color (with empty domain)
3678 * - a constant last color function
3680 cairo_ps_color_stop_t pad_stops[4];
3682 assert (pattern->base.extend == CAIRO_EXTEND_PAD);
3684 pad_stops[0] = pad_stops[1] = stops[0];
3685 pad_stops[2] = pad_stops[3] = stops[n_stops - 1];
3687 pad_stops[0].offset = 0;
3688 pad_stops[3].offset = 1;
3690 _cairo_ps_surface_emit_stitched_colorgradient (surface, 4, pad_stops);
3691 } else if (n_stops == 2) {
3692 /* no need for stitched function */
3693 _cairo_ps_surface_emit_linear_colorgradient (surface, &stops[0], &stops[1]);
3695 /* multiple stops: stitch. XXX possible optimization: regulary spaced
3696 * stops do not require stitching. XXX */
3697 _cairo_ps_surface_emit_stitched_colorgradient (surface, n_stops, stops);
3699 _cairo_output_stream_printf (surface->stream,
3704 return CAIRO_STATUS_SUCCESS;
3707 static cairo_status_t
3708 _cairo_ps_surface_emit_repeating_function (cairo_ps_surface_t *surface,
3709 cairo_gradient_pattern_t *pattern,
3713 _cairo_output_stream_printf (surface->stream,
3715 "<< /FunctionType 3\n"
3716 " /Domain [ %d %d ]\n"
3717 " /Functions [ %d {CairoFunction} repeat ]\n"
3718 " /Bounds [ %d 1 %d {} for ]\n",
3725 if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
3726 _cairo_output_stream_printf (surface->stream, " /Encode [ %d 1 %d { 2 mod 0 eq {0 1} {1 0} ifelse } for ]\n",
3730 _cairo_output_stream_printf (surface->stream, " /Encode [ %d 1 %d { pop 0 1 } for ]\n",
3735 _cairo_output_stream_printf (surface->stream, ">> def\n");
3737 return CAIRO_STATUS_SUCCESS;
3740 static cairo_status_t
3741 _cairo_ps_surface_emit_gradient (cairo_ps_surface_t *surface,
3742 cairo_gradient_pattern_t *pattern,
3743 cairo_bool_t is_ps_pattern)
3745 cairo_matrix_t pat_to_ps;
3746 cairo_circle_double_t start, end;
3748 cairo_status_t status;
3750 assert (pattern->n_stops != 0);
3752 status = _cairo_ps_surface_emit_pattern_stops (surface, pattern);
3753 if (unlikely (status))
3756 pat_to_ps = pattern->base.matrix;
3757 status = cairo_matrix_invert (&pat_to_ps);
3758 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3759 assert (status == CAIRO_STATUS_SUCCESS);
3760 cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
3762 if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
3763 pattern->base.extend == CAIRO_EXTEND_REFLECT)
3765 double bounds_x1, bounds_x2, bounds_y1, bounds_y2;
3766 double x_scale, y_scale, tolerance;
3768 /* TODO: use tighter extents */
3771 bounds_x2 = surface->width;
3772 bounds_y2 = surface->height;
3773 _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
3774 &bounds_x1, &bounds_y1,
3775 &bounds_x2, &bounds_y2,
3778 x_scale = surface->base.x_resolution / surface->base.x_fallback_resolution;
3779 y_scale = surface->base.y_resolution / surface->base.y_fallback_resolution;
3781 tolerance = fabs (_cairo_matrix_compute_determinant (&pattern->base.matrix));
3782 tolerance /= _cairo_matrix_transformed_circle_major_axis (&pattern->base.matrix, 1);
3783 tolerance *= MIN (x_scale, y_scale);
3785 _cairo_gradient_pattern_box_to_parameter (pattern,
3786 bounds_x1, bounds_y1,
3787 bounds_x2, bounds_y2,
3789 } else if (pattern->stops[0].offset == pattern->stops[pattern->n_stops - 1].offset) {
3791 * If the first and the last stop offset are the same, then
3792 * the color function is a step function.
3793 * _cairo_ps_surface_emit_pattern_stops emits it as a stitched
3794 * function no matter how many stops the pattern has. The
3795 * domain of the stitched function will be [0 1] in this case.
3797 * This is done to avoid emitting degenerate gradients for
3798 * EXTEND_PAD patterns having a step color function.
3803 assert (pattern->base.extend == CAIRO_EXTEND_PAD);
3805 domain[0] = pattern->stops[0].offset;
3806 domain[1] = pattern->stops[pattern->n_stops - 1].offset;
3809 /* PS requires the first and last stop to be the same as the
3810 * extreme coordinates. For repeating patterns this moves the
3811 * extreme coordinates out to the begin/end of the repeating
3812 * function. For non repeating patterns this may move the extreme
3813 * coordinates in if there are not stops at offset 0 and 1. */
3814 _cairo_gradient_pattern_interpolate (pattern, domain[0], &start);
3815 _cairo_gradient_pattern_interpolate (pattern, domain[1], &end);
3817 if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
3818 pattern->base.extend == CAIRO_EXTEND_REFLECT)
3820 int repeat_begin, repeat_end;
3822 repeat_begin = floor (domain[0]);
3823 repeat_end = ceil (domain[1]);
3825 status = _cairo_ps_surface_emit_repeating_function (surface,
3829 if (unlikely (status))
3831 } else if (pattern->n_stops <= 2) {
3832 /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a
3833 * Type 2 function is used by itself without a stitching
3834 * function. Type 2 functions always have the domain [0 1] */
3839 if (is_ps_pattern) {
3840 _cairo_output_stream_printf (surface->stream,
3841 "<< /PatternType 2\n"
3845 if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
3846 _cairo_output_stream_printf (surface->stream,
3847 " << /ShadingType 2\n"
3848 " /ColorSpace /DeviceRGB\n"
3849 " /Coords [ %f %f %f %f ]\n",
3850 start.center.x, start.center.y,
3851 end.center.x, end.center.y);
3853 _cairo_output_stream_printf (surface->stream,
3854 " << /ShadingType 3\n"
3855 " /ColorSpace /DeviceRGB\n"
3856 " /Coords [ %f %f %f %f %f %f ]\n",
3857 start.center.x, start.center.y,
3858 MAX (start.radius, 0),
3859 end.center.x, end.center.y,
3860 MAX (end.radius, 0));
3863 if (pattern->base.extend != CAIRO_EXTEND_NONE) {
3864 _cairo_output_stream_printf (surface->stream,
3865 " /Extend [ true true ]\n");
3867 _cairo_output_stream_printf (surface->stream,
3868 " /Extend [ false false ]\n");
3871 if (domain[0] == 0.0 && domain[1] == 1.0) {
3872 _cairo_output_stream_printf (surface->stream,
3873 " /Function CairoFunction\n");
3875 _cairo_output_stream_printf (surface->stream,
3877 " /FunctionType 3\n"
3878 " /Domain [ 0 1 ]\n"
3880 " /Encode [ %f %f ]\n"
3881 " /Functions [ CairoFunction ]\n"
3883 domain[0], domain[1]);
3886 _cairo_output_stream_printf (surface->stream,
3889 if (is_ps_pattern) {
3890 _cairo_output_stream_printf (surface->stream,
3893 _cairo_output_stream_print_matrix (surface->stream, &pat_to_ps);
3894 _cairo_output_stream_printf (surface->stream, " ]\n"
3895 "makepattern setpattern\n");
3897 _cairo_output_stream_printf (surface->stream,
3904 static cairo_status_t
3905 _cairo_ps_surface_emit_mesh_pattern (cairo_ps_surface_t *surface,
3906 cairo_mesh_pattern_t *pattern,
3907 cairo_bool_t is_ps_pattern)
3909 cairo_matrix_t pat_to_ps;
3910 cairo_status_t status;
3911 cairo_pdf_shading_t shading;
3914 if (_cairo_array_num_elements (&pattern->patches) == 0)
3915 return CAIRO_INT_STATUS_NOTHING_TO_DO;
3917 pat_to_ps = pattern->base.matrix;
3918 status = cairo_matrix_invert (&pat_to_ps);
3919 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3920 assert (status == CAIRO_STATUS_SUCCESS);
3922 cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
3924 status = _cairo_pdf_shading_init_color (&shading, pattern);
3925 if (unlikely (status))
3928 _cairo_output_stream_printf (surface->stream,
3930 "/ASCII85Decode filter /FlateDecode filter /ReusableStreamDecode filter\n");
3932 status = _cairo_ps_surface_emit_base85_string (surface,
3934 shading.data_length,
3935 CAIRO_PS_COMPRESS_DEFLATE,
3940 _cairo_output_stream_printf (surface->stream,
3942 "/CairoData exch def\n");
3944 if (is_ps_pattern) {
3945 _cairo_output_stream_printf (surface->stream,
3946 "<< /PatternType 2\n"
3950 _cairo_output_stream_printf (surface->stream,
3951 " << /ShadingType %d\n"
3952 " /ColorSpace /DeviceRGB\n"
3953 " /DataSource CairoData\n"
3954 " /BitsPerCoordinate %d\n"
3955 " /BitsPerComponent %d\n"
3956 " /BitsPerFlag %d\n"
3958 shading.shading_type,
3959 shading.bits_per_coordinate,
3960 shading.bits_per_component,
3961 shading.bits_per_flag);
3963 for (i = 0; i < shading.decode_array_length; i++)
3964 _cairo_output_stream_printf (surface->stream, "%f ", shading.decode_array[i]);
3966 _cairo_output_stream_printf (surface->stream,
3970 if (is_ps_pattern) {
3971 _cairo_output_stream_printf (surface->stream,
3974 _cairo_output_stream_print_matrix (surface->stream, &pat_to_ps);
3975 _cairo_output_stream_printf (surface->stream,
3980 _cairo_output_stream_printf (surface->stream, "shfill\n");
3983 _cairo_output_stream_printf (surface->stream,
3984 "currentdict /CairoData undef\n");
3986 _cairo_pdf_shading_fini (&shading);
3991 static cairo_status_t
3992 _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
3993 const cairo_pattern_t *pattern,
3994 cairo_rectangle_int_t *extents,
3995 cairo_operator_t op)
3997 cairo_status_t status;
3999 if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
4000 cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
4002 if (surface->current_pattern_is_solid_color == FALSE ||
4003 ! _cairo_color_equal (&surface->current_color, &solid->color))
4005 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4006 if (unlikely (status))
4009 _cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
4011 surface->current_pattern_is_solid_color = TRUE;
4012 surface->current_color = solid->color;
4015 return CAIRO_STATUS_SUCCESS;
4018 surface->current_pattern_is_solid_color = FALSE;
4019 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4020 if (unlikely (status))
4023 switch (pattern->type) {
4024 case CAIRO_PATTERN_TYPE_SOLID:
4026 _cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
4029 case CAIRO_PATTERN_TYPE_SURFACE:
4030 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
4031 status = _cairo_ps_surface_emit_surface_pattern (surface,
4032 (cairo_pattern_t *)pattern,
4035 if (unlikely (status))
4039 case CAIRO_PATTERN_TYPE_LINEAR:
4040 case CAIRO_PATTERN_TYPE_RADIAL:
4041 status = _cairo_ps_surface_emit_gradient (surface,
4042 (cairo_gradient_pattern_t *) pattern,
4044 if (unlikely (status))
4048 case CAIRO_PATTERN_TYPE_MESH:
4049 status = _cairo_ps_surface_emit_mesh_pattern (surface,
4050 (cairo_mesh_pattern_t *) pattern,
4052 if (unlikely (status))
4057 return CAIRO_STATUS_SUCCESS;
4060 static cairo_status_t
4061 _cairo_ps_surface_paint_gradient (cairo_ps_surface_t *surface,
4062 const cairo_pattern_t *source,
4063 const cairo_rectangle_int_t *extents)
4065 cairo_matrix_t pat_to_ps;
4066 cairo_status_t status;
4068 pat_to_ps = source->matrix;
4069 status = cairo_matrix_invert (&pat_to_ps);
4070 /* cairo_pattern_set_matrix ensures the matrix is invertible */
4071 assert (status == CAIRO_STATUS_SUCCESS);
4072 cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
4074 if (! _cairo_matrix_is_identity (&pat_to_ps)) {
4075 _cairo_output_stream_printf (surface->stream, "[");
4076 _cairo_output_stream_print_matrix (surface->stream, &pat_to_ps);
4077 _cairo_output_stream_printf (surface->stream, "] concat\n");
4080 if (source->type == CAIRO_PATTERN_TYPE_MESH) {
4081 status = _cairo_ps_surface_emit_mesh_pattern (surface,
4082 (cairo_mesh_pattern_t *)source,
4084 if (unlikely (status))
4087 status = _cairo_ps_surface_emit_gradient (surface,
4088 (cairo_gradient_pattern_t *)source,
4090 if (unlikely (status))
4097 static cairo_status_t
4098 _cairo_ps_surface_paint_pattern (cairo_ps_surface_t *surface,
4099 const cairo_pattern_t *source,
4100 cairo_rectangle_int_t *extents,
4101 cairo_operator_t op,
4102 cairo_bool_t stencil_mask)
4104 switch (source->type) {
4105 case CAIRO_PATTERN_TYPE_SURFACE:
4106 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
4107 return _cairo_ps_surface_paint_surface (surface,
4108 (cairo_pattern_t *)source,
4113 case CAIRO_PATTERN_TYPE_LINEAR:
4114 case CAIRO_PATTERN_TYPE_RADIAL:
4115 case CAIRO_PATTERN_TYPE_MESH:
4116 return _cairo_ps_surface_paint_gradient (surface,
4120 case CAIRO_PATTERN_TYPE_SOLID:
4123 return CAIRO_STATUS_SUCCESS;
4128 _can_paint_pattern (const cairo_pattern_t *pattern)
4130 switch (pattern->type) {
4131 case CAIRO_PATTERN_TYPE_SOLID:
4134 case CAIRO_PATTERN_TYPE_SURFACE:
4135 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
4136 return (pattern->extend == CAIRO_EXTEND_NONE ||
4137 pattern->extend == CAIRO_EXTEND_PAD);
4139 case CAIRO_PATTERN_TYPE_LINEAR:
4140 case CAIRO_PATTERN_TYPE_RADIAL:
4141 case CAIRO_PATTERN_TYPE_MESH:
4151 _cairo_ps_surface_get_extents (void *abstract_surface,
4152 cairo_rectangle_int_t *rectangle)
4154 cairo_ps_surface_t *surface = abstract_surface;
4159 /* XXX: The conversion to integers here is pretty bogus, (not to
4160 * mention the aribitray limitation of width to a short(!). We
4161 * may need to come up with a better interface for get_extents.
4163 rectangle->width = ceil (surface->width);
4164 rectangle->height = ceil (surface->height);
4170 _cairo_ps_surface_get_font_options (void *abstract_surface,
4171 cairo_font_options_t *options)
4173 _cairo_font_options_init_default (options);
4175 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
4176 cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
4177 cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
4178 _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_OFF);
4181 static cairo_int_status_t
4182 _cairo_ps_surface_set_clip (cairo_ps_surface_t *surface,
4183 cairo_composite_rectangles_t *composite)
4185 cairo_clip_t *clip = composite->clip;
4187 if (_cairo_composite_rectangles_can_reduce_clip (composite, clip))
4191 if (_cairo_composite_rectangles_can_reduce_clip (composite,
4192 surface->clipper.clip))
4193 return CAIRO_STATUS_SUCCESS;
4196 return _cairo_surface_clipper_set_clip (&surface->clipper, clip);
4199 static cairo_int_status_t
4200 _cairo_ps_surface_paint (void *abstract_surface,
4201 cairo_operator_t op,
4202 const cairo_pattern_t *source,
4203 const cairo_clip_t *clip)
4205 cairo_ps_surface_t *surface = abstract_surface;
4206 cairo_output_stream_t *stream = surface->stream;
4207 cairo_composite_rectangles_t extents;
4208 cairo_status_t status;
4210 status = _cairo_composite_rectangles_init_for_paint (&extents,
4213 if (unlikely (status))
4216 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4217 status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
4218 goto cleanup_composite;
4221 assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
4224 _cairo_output_stream_printf (stream,
4225 "%% _cairo_ps_surface_paint\n");
4228 status = _cairo_ps_surface_set_clip (surface, &extents);
4229 if (unlikely (status))
4230 goto cleanup_composite;
4232 if (_can_paint_pattern (source)) {
4233 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4234 if (unlikely (status))
4235 goto cleanup_composite;
4237 _cairo_output_stream_printf (stream, "q\n");
4238 status = _cairo_ps_surface_paint_pattern (surface,
4240 &extents.bounded, op, FALSE);
4241 if (unlikely (status))
4242 goto cleanup_composite;
4244 _cairo_output_stream_printf (stream, "Q\n");
4246 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4247 if (unlikely (status))
4248 goto cleanup_composite;
4250 _cairo_output_stream_printf (stream, "0 0 %f %f rectfill\n",
4251 surface->width, surface->height);
4255 _cairo_composite_rectangles_fini (&extents);
4259 static cairo_int_status_t
4260 _cairo_ps_surface_mask (void *abstract_surface,
4261 cairo_operator_t op,
4262 const cairo_pattern_t *source,
4263 const cairo_pattern_t *mask,
4264 const cairo_clip_t *clip)
4266 cairo_ps_surface_t *surface = abstract_surface;
4267 cairo_output_stream_t *stream = surface->stream;
4268 cairo_composite_rectangles_t extents;
4269 cairo_status_t status;
4271 status = _cairo_composite_rectangles_init_for_mask (&extents,
4273 op, source, mask, clip);
4274 if (unlikely (status))
4277 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4278 status = _cairo_ps_surface_analyze_operation (surface, op, source, mask, &extents.bounded);
4279 goto cleanup_composite;
4282 assert (_cairo_ps_surface_operation_supported (surface, op, source, mask, &extents.bounded));
4285 _cairo_output_stream_printf (stream,
4286 "%% _cairo_ps_surface_mask\n");
4289 status = _cairo_ps_surface_set_clip (surface, &extents);
4290 if (unlikely (status))
4291 goto cleanup_composite;
4293 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4294 if (unlikely (status))
4295 goto cleanup_composite;
4297 _cairo_output_stream_printf (stream, "q\n");
4298 status = _cairo_ps_surface_paint_pattern (surface,
4300 &extents.bounded, op, TRUE);
4301 if (unlikely (status))
4302 goto cleanup_composite;
4304 _cairo_output_stream_printf (stream, "Q\n");
4307 _cairo_composite_rectangles_fini (&extents);
4311 static cairo_int_status_t
4312 _cairo_ps_surface_stroke (void *abstract_surface,
4313 cairo_operator_t op,
4314 const cairo_pattern_t *source,
4315 const cairo_path_fixed_t *path,
4316 const cairo_stroke_style_t *style,
4317 const cairo_matrix_t *ctm,
4318 const cairo_matrix_t *ctm_inverse,
4320 cairo_antialias_t antialias,
4321 const cairo_clip_t *clip)
4323 cairo_ps_surface_t *surface = abstract_surface;
4324 cairo_composite_rectangles_t extents;
4325 cairo_int_status_t status;
4327 status = _cairo_composite_rectangles_init_for_stroke (&extents,
4332 if (unlikely (status))
4335 /* use the more accurate extents */
4337 cairo_rectangle_int_t r;
4340 status = _cairo_path_fixed_stroke_extents (path, style,
4344 if (unlikely (status))
4345 goto cleanup_composite;
4347 _cairo_box_from_rectangle (&b, &r);
4348 status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b);
4349 if (unlikely (status))
4350 goto cleanup_composite;
4353 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4354 status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
4355 goto cleanup_composite;
4358 assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
4361 _cairo_output_stream_printf (surface->stream,
4362 "%% _cairo_ps_surface_stroke\n");
4365 status = _cairo_ps_surface_set_clip (surface, &extents);
4366 if (unlikely (status))
4367 goto cleanup_composite;
4369 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4370 if (unlikely (status))
4371 goto cleanup_composite;
4373 status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
4380 _cairo_composite_rectangles_fini (&extents);
4384 static cairo_int_status_t
4385 _cairo_ps_surface_fill (void *abstract_surface,
4386 cairo_operator_t op,
4387 const cairo_pattern_t *source,
4388 const cairo_path_fixed_t*path,
4389 cairo_fill_rule_t fill_rule,
4391 cairo_antialias_t antialias,
4392 const cairo_clip_t *clip)
4394 cairo_ps_surface_t *surface = abstract_surface;
4395 cairo_composite_rectangles_t extents;
4396 cairo_int_status_t status;
4398 status = _cairo_composite_rectangles_init_for_fill (&extents,
4402 if (unlikely (status))
4405 /* use the more accurate extents */
4407 cairo_rectangle_int_t r;
4410 _cairo_path_fixed_fill_extents (path,
4415 _cairo_box_from_rectangle (&b, &r);
4416 status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b);
4417 if (unlikely (status))
4418 goto cleanup_composite;
4421 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4422 status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
4423 goto cleanup_composite;
4426 assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
4429 _cairo_output_stream_printf (surface->stream,
4430 "%% _cairo_ps_surface_fill\n");
4433 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4434 if (unlikely (status))
4435 goto cleanup_composite;
4437 status = _cairo_ps_surface_set_clip (surface, &extents);
4438 if (unlikely (status))
4439 goto cleanup_composite;
4441 if (_can_paint_pattern (source)) {
4442 _cairo_output_stream_printf (surface->stream, "q\n");
4444 status = _cairo_pdf_operators_clip (&surface->pdf_operators,
4447 if (unlikely (status))
4448 goto cleanup_composite;
4450 status = _cairo_ps_surface_paint_pattern (surface,
4452 &extents.bounded, op, FALSE);
4453 if (unlikely (status))
4454 goto cleanup_composite;
4456 _cairo_output_stream_printf (surface->stream, "Q\n");
4457 _cairo_pdf_operators_reset (&surface->pdf_operators);
4459 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4460 if (unlikely (status))
4461 goto cleanup_composite;
4463 status = _cairo_pdf_operators_fill (&surface->pdf_operators,
4469 _cairo_composite_rectangles_fini (&extents);
4474 _cairo_ps_surface_has_show_text_glyphs (void *abstract_surface)
4479 static cairo_int_status_t
4480 _cairo_ps_surface_show_text_glyphs (void *abstract_surface,
4481 cairo_operator_t op,
4482 const cairo_pattern_t *source,
4485 cairo_glyph_t *glyphs,
4487 const cairo_text_cluster_t *clusters,
4489 cairo_text_cluster_flags_t cluster_flags,
4490 cairo_scaled_font_t *scaled_font,
4491 const cairo_clip_t *clip)
4493 cairo_ps_surface_t *surface = abstract_surface;
4494 cairo_composite_rectangles_t extents;
4495 cairo_bool_t overlap;
4496 cairo_status_t status;
4498 status = _cairo_composite_rectangles_init_for_glyphs (&extents,
4505 if (unlikely (status))
4508 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
4509 status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
4510 goto cleanup_composite;
4513 assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
4516 _cairo_output_stream_printf (surface->stream,
4517 "%% _cairo_ps_surface_show_glyphs\n");
4520 status = _cairo_ps_surface_set_clip (surface, &extents);
4521 if (unlikely (status))
4522 goto cleanup_composite;
4524 status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
4525 if (unlikely (status))
4526 goto cleanup_composite;
4528 status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
4531 clusters, num_clusters,
4536 _cairo_composite_rectangles_fini (&extents);
4540 static const char **
4541 _cairo_ps_surface_get_supported_mime_types (void *abstract_surface)
4543 return _cairo_ps_supported_mime_types;
4547 _cairo_ps_surface_set_paginated_mode (void *abstract_surface,
4548 cairo_paginated_mode_t paginated_mode)
4550 cairo_ps_surface_t *surface = abstract_surface;
4551 cairo_status_t status;
4553 surface->paginated_mode = paginated_mode;
4555 if (surface->clipper.clip != NULL) {
4556 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4558 _cairo_output_stream_printf (surface->stream, "Q q\n");
4559 _cairo_surface_clipper_reset (&surface->clipper);
4563 static cairo_int_status_t
4564 _cairo_ps_surface_set_bounding_box (void *abstract_surface,
4567 cairo_ps_surface_t *surface = abstract_surface;
4568 int i, num_comments;
4571 cairo_bool_t has_page_media, has_page_bbox;
4572 const char *page_media;
4574 x1 = floor (_cairo_fixed_to_double (bbox->p1.x));
4575 y1 = floor (surface->height - _cairo_fixed_to_double (bbox->p2.y));
4576 x2 = ceil (_cairo_fixed_to_double (bbox->p2.x));
4577 y2 = ceil (surface->height - _cairo_fixed_to_double (bbox->p1.y));
4579 surface->page_bbox.x = x1;
4580 surface->page_bbox.y = y1;
4581 surface->page_bbox.width = x2 - x1;
4582 surface->page_bbox.height = y2 - y1;
4584 _cairo_output_stream_printf (surface->stream,
4585 "%%%%Page: %d %d\n",
4587 surface->num_pages);
4589 _cairo_output_stream_printf (surface->stream,
4590 "%%%%BeginPageSetup\n");
4592 has_page_media = FALSE;
4593 has_page_bbox = FALSE;
4594 num_comments = _cairo_array_num_elements (&surface->dsc_page_setup_comments);
4595 comments = _cairo_array_index (&surface->dsc_page_setup_comments, 0);
4596 if (comments == NULL)
4597 return CAIRO_STATUS_NULL_POINTER;
4599 for (i = 0; i < num_comments; i++) {
4600 _cairo_output_stream_printf (surface->stream,
4601 "%s\n", comments[i]);
4602 if (strncmp (comments[i], "%%PageMedia:", 11) == 0)
4603 has_page_media = TRUE;
4605 if (strncmp (comments[i], "%%PageBoundingBox:", 18) == 0)
4606 has_page_bbox = TRUE;
4611 _cairo_array_truncate (&surface->dsc_page_setup_comments, 0);
4613 if (!has_page_media && !surface->eps) {
4614 page_media = _cairo_ps_surface_get_page_media (surface);
4615 if (unlikely (page_media == NULL))
4616 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4618 _cairo_output_stream_printf (surface->stream,
4619 "%%%%PageMedia: %s\n",
4623 if (!has_page_bbox) {
4624 _cairo_output_stream_printf (surface->stream,
4625 "%%%%PageBoundingBox: %d %d %d %d\n",
4629 if (!surface->eps) {
4630 _cairo_output_stream_printf (surface->stream,
4631 "%f %f cairo_set_page_size\n",
4632 ceil(surface->width),
4633 ceil(surface->height));
4636 _cairo_output_stream_printf (surface->stream,
4637 "%%%%EndPageSetup\n"
4638 "q %d %d %d %d rectclip q\n",
4639 surface->page_bbox.x,
4640 surface->page_bbox.y,
4641 surface->page_bbox.width,
4642 surface->page_bbox.height);
4644 if (surface->num_pages == 1) {
4645 surface->bbox_x1 = x1;
4646 surface->bbox_y1 = y1;
4647 surface->bbox_x2 = x2;
4648 surface->bbox_y2 = y2;
4650 if (x1 < surface->bbox_x1)
4651 surface->bbox_x1 = x1;
4652 if (y1 < surface->bbox_y1)
4653 surface->bbox_y1 = y1;
4654 if (x2 > surface->bbox_x2)
4655 surface->bbox_x2 = x2;
4656 if (y2 > surface->bbox_y2)
4657 surface->bbox_y2 = y2;
4659 surface->current_pattern_is_solid_color = FALSE;
4660 _cairo_pdf_operators_reset (&surface->pdf_operators);
4662 return _cairo_output_stream_get_status (surface->stream);
4666 _cairo_ps_surface_supports_fine_grained_fallbacks (void *abstract_surface)
4671 static const cairo_surface_backend_t cairo_ps_surface_backend = {
4672 CAIRO_SURFACE_TYPE_PS,
4673 _cairo_ps_surface_finish,
4675 _cairo_default_context_create,
4677 NULL, /* create similar: handled by wrapper */
4678 NULL, /* create similar image */
4679 NULL, /* map to image */
4680 NULL, /* unmap image */
4682 _cairo_surface_default_source,
4683 NULL, /* acquire_source_image */
4684 NULL, /* release_source_image */
4685 NULL, /* snapshot */
4687 NULL, /* cairo_ps_surface_copy_page */
4688 _cairo_ps_surface_show_page,
4690 _cairo_ps_surface_get_extents,
4691 _cairo_ps_surface_get_font_options,
4694 NULL, /* mark_dirty_rectangle */
4696 /* Here are the drawing functions */
4698 _cairo_ps_surface_paint, /* paint */
4699 _cairo_ps_surface_mask,
4700 _cairo_ps_surface_stroke,
4701 _cairo_ps_surface_fill,
4702 NULL, /* fill-stroke */
4703 NULL, /* show_glyphs */
4704 _cairo_ps_surface_has_show_text_glyphs,
4705 _cairo_ps_surface_show_text_glyphs,
4706 _cairo_ps_surface_get_supported_mime_types,
4709 static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend = {
4710 _cairo_ps_surface_start_page,
4711 _cairo_ps_surface_set_paginated_mode,
4712 _cairo_ps_surface_set_bounding_box,
4713 NULL, /* _cairo_ps_surface_has_fallback_images, */
4714 _cairo_ps_surface_supports_fine_grained_fallbacks,