1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2003 University of Southern California
5 * Copyright © 2005 Red Hat, Inc
6 * Copyright © 2007,2008 Adrian Johnson
8 * This library is free software; you can redistribute it and/or
9 * modify it either under the terms of the GNU Lesser General Public
10 * License version 2.1 as published by the Free Software Foundation
11 * (the "LGPL") or, at your option, under the terms of the Mozilla
12 * Public License Version 1.1 (the "MPL"). If you do not alter this
13 * notice, a recipient may use your version of this file under either
14 * the MPL or the LGPL.
16 * You should have received a copy of the LGPL along with this library
17 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19 * You should have received a copy of the MPL along with this library
20 * in the file COPYING-MPL-1.1
22 * The contents of this file are subject to the Mozilla Public License
23 * Version 1.1 (the "License"); you may not use this file except in
24 * compliance with the License. You may obtain a copy of the License at
25 * http://www.mozilla.org/MPL/
27 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29 * the specific language governing rights and limitations.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is University of Southern
37 * Carl D. Worth <cworth@cworth.org>
38 * Kristian Høgsberg <krh@redhat.com>
39 * Keith Packard <keithp@keithp.com>
40 * Adrian Johnson <ajohnson@redneon.com>
45 * Design of the PS output:
47 * The PS output is harmonised with the PDF operations using PS procedures
48 * to emulate the PDF operators.
50 * This has a number of advantages:
51 * 1. A large chunk of code is shared between the PDF and PS backends.
52 * See cairo-pdf-operators.
53 * 2. Using gs to do PS -> PDF and PDF -> PS will always work well.
56 #define _BSD_SOURCE /* for ctime_r(), snprintf(), strdup() */
60 #include "cairo-ps-surface-private.h"
62 #include "cairo-pdf-operators-private.h"
63 #include "cairo-pdf-shading-private.h"
65 #include "cairo-array-private.h"
66 #include "cairo-composite-rectangles-private.h"
67 #include "cairo-default-context-private.h"
68 #include "cairo-error-private.h"
69 #include "cairo-image-surface-inline.h"
70 #include "cairo-list-inline.h"
71 #include "cairo-scaled-font-subsets-private.h"
72 #include "cairo-paginated-private.h"
73 #include "cairo-recording-surface-private.h"
74 #include "cairo-surface-clipper-private.h"
75 #include "cairo-surface-snapshot-inline.h"
76 #include "cairo-surface-subsurface-private.h"
77 #include "cairo-output-stream-private.h"
78 #include "cairo-type3-glyph-surface-private.h"
79 #include "cairo-image-info-private.h"
90 #define DEBUG_FALLBACK(s) \
91 fprintf (stderr, "%s::%d -- %s\n", __FUNCTION__, __LINE__, (s))
93 #define DEBUG_FALLBACK(s)
97 #define ctime_r(T, BUF) ctime (T)
102 * @Title: PostScript Surfaces
103 * @Short_Description: Rendering PostScript documents
104 * @See_Also: #cairo_surface_t
106 * The PostScript surface is used to render cairo graphics to Adobe
107 * PostScript files and is a multi-page vector surface backend.
111 * CAIRO_HAS_PS_SURFACE:
113 * Defined if the PostScript surface backend is available.
114 * This macro can be used to conditionally compile backend-specific code.
120 CAIRO_PS_COMPRESS_NONE
,
121 CAIRO_PS_COMPRESS_LZW
,
122 CAIRO_PS_COMPRESS_DEFLATE
123 } cairo_ps_compress_t
;
125 static const cairo_surface_backend_t cairo_ps_surface_backend
;
126 static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend
;
129 _cairo_ps_surface_get_extents (void *abstract_surface
,
130 cairo_rectangle_int_t
*rectangle
);
132 static const cairo_ps_level_t _cairo_ps_levels
[] =
138 #define CAIRO_PS_LEVEL_LAST ARRAY_LENGTH (_cairo_ps_levels)
140 static const char * _cairo_ps_level_strings
[CAIRO_PS_LEVEL_LAST
] =
146 static const char *_cairo_ps_supported_mime_types
[] =
148 CAIRO_MIME_TYPE_JPEG
,
152 typedef struct _cairo_page_standard_media
{
156 } cairo_page_standard_media_t
;
158 static const cairo_page_standard_media_t _cairo_page_standard_media
[] =
160 { "A0", 2384, 3371 },
161 { "A1", 1685, 2384 },
162 { "A2", 1190, 1684 },
168 { "Letter", 612, 792 },
169 { "Tabloid", 792, 1224 },
170 { "Ledger", 1224, 792 },
171 { "Legal", 612, 1008 },
172 { "Statement", 396, 612 },
173 { "Executive", 540, 720 },
174 { "Folio", 612, 936 },
175 { "Quarto", 610, 780 },
176 { "10x14", 720, 1008 },
179 typedef struct _cairo_page_media
{
184 } cairo_page_media_t
;
187 _cairo_ps_surface_emit_header (cairo_ps_surface_t
*surface
)
194 const char *eps_header
= "";
195 cairo_bool_t has_bbox
;
197 if (surface
->has_creation_date
)
198 now
= surface
->creation_date
;
202 if (surface
->ps_level_used
== CAIRO_PS_LEVEL_2
)
208 eps_header
= " EPSF-3.0";
210 _cairo_output_stream_printf (surface
->final_stream
,
211 "%%!PS-Adobe-3.0%s\n"
212 "%%%%Creator: cairo %s (http://cairographics.org)\n"
213 "%%%%CreationDate: %s"
216 cairo_version_string (),
217 ctime_r (&now
, ctime_buf
),
220 _cairo_output_stream_printf (surface
->final_stream
,
221 "%%%%DocumentData: Clean7Bit\n"
222 "%%%%LanguageLevel: %d\n",
225 if (!cairo_list_is_empty (&surface
->document_media
)) {
226 cairo_page_media_t
*page
;
227 cairo_bool_t first
= TRUE
;
229 cairo_list_foreach_entry (page
, cairo_page_media_t
, &surface
->document_media
, link
) {
231 _cairo_output_stream_printf (surface
->final_stream
,
232 "%%%%DocumentMedia: ");
235 _cairo_output_stream_printf (surface
->final_stream
,
238 _cairo_output_stream_printf (surface
->final_stream
,
239 "%s %d %d 0 () ()\n",
247 num_comments
= _cairo_array_num_elements (&surface
->dsc_header_comments
);
248 comments
= _cairo_array_index (&surface
->dsc_header_comments
, 0);
249 for (i
= 0; i
< num_comments
; i
++) {
250 _cairo_output_stream_printf (surface
->final_stream
,
251 "%s\n", comments
[i
]);
252 if (strncmp (comments
[i
], "%%BoundingBox:", 14) == 0)
260 _cairo_output_stream_printf (surface
->final_stream
,
261 "%%%%BoundingBox: %d %d %d %d\n",
268 _cairo_output_stream_printf (surface
->final_stream
,
269 "%%%%EndComments\n");
271 _cairo_output_stream_printf (surface
->final_stream
,
272 "%%%%BeginProlog\n");
275 _cairo_output_stream_printf (surface
->final_stream
,
279 _cairo_output_stream_printf (surface
->final_stream
,
280 "/languagelevel where\n"
281 "{ pop languagelevel } { 1 } ifelse\n"
282 "%d lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto\n"
283 " (This print job requires a PostScript Language Level %d printer.) show\n"
284 " showpage quit } if\n",
289 _cairo_output_stream_printf (surface
->final_stream
,
290 "/q { gsave } bind def\n"
291 "/Q { grestore } bind def\n"
292 "/cm { 6 array astore concat } bind def\n"
293 "/w { setlinewidth } bind def\n"
294 "/J { setlinecap } bind def\n"
295 "/j { setlinejoin } bind def\n"
296 "/M { setmiterlimit } bind def\n"
297 "/d { setdash } bind def\n"
298 "/m { moveto } bind def\n"
299 "/l { lineto } bind def\n"
300 "/c { curveto } bind def\n"
301 "/h { closepath } bind def\n"
302 "/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto\n"
303 " 0 exch rlineto 0 rlineto closepath } bind def\n"
304 "/S { stroke } bind def\n"
305 "/f { fill } bind def\n"
306 "/f* { eofill } bind def\n"
307 "/n { newpath } bind def\n"
308 "/W { clip } bind def\n"
309 "/W* { eoclip } bind def\n"
312 "/pdfmark where { pop globaldict /?pdfmark /exec load put }\n"
313 " { globaldict begin /?pdfmark /pop load def /pdfmark\n"
314 " /cleartomark load def end } ifelse\n"
315 "/BDC { mark 3 1 roll /BDC pdfmark } bind def\n"
316 "/EMC { mark /EMC pdfmark } bind def\n"
317 "/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def\n"
318 "/Tj { show currentpoint cairo_store_point } bind def\n"
322 " type /stringtype eq\n"
323 " { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse\n"
325 " currentpoint cairo_store_point\n"
327 "/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore\n"
328 " cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def\n"
329 "/Tf { pop /cairo_font exch def /cairo_font_matrix where\n"
330 " { pop cairo_selectfont } if } bind def\n"
331 "/Td { matrix translate cairo_font_matrix matrix concatmatrix dup\n"
332 " /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point\n"
333 " /cairo_font where { pop cairo_selectfont } if } bind def\n"
334 "/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def\n"
335 " cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def\n"
336 "/g { setgray } bind def\n"
337 "/rg { setrgbcolor } bind def\n"
338 "/d1 { setcachedevice } bind def\n");
341 _cairo_output_stream_printf (surface
->final_stream
,
342 "/cairo_set_page_size {\n"
343 " %% Change paper size, but only if different from previous paper size otherwise\n"
344 " %% duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size\n"
345 " %% so we use the same when checking if the size changes.\n"
346 " /setpagedevice where {\n"
347 " pop currentpagedevice\n"
348 " /PageSize known {\n"
350 " currentpagedevice /PageSize get aload pop\n"
362 " /PageSize exch def\n"
363 " /ImagingBBox null def\n"
375 _cairo_output_stream_printf (surface
->final_stream
,
377 _cairo_output_stream_printf (surface
->final_stream
,
380 num_comments
= _cairo_array_num_elements (&surface
->dsc_setup_comments
);
382 comments
= _cairo_array_index (&surface
->dsc_setup_comments
, 0);
383 for (i
= 0; i
< num_comments
; i
++) {
384 _cairo_output_stream_printf (surface
->final_stream
,
385 "%s\n", comments
[i
]);
392 static cairo_status_t
393 _cairo_ps_surface_emit_type1_font_subset (cairo_ps_surface_t
*surface
,
394 cairo_scaled_font_subset_t
*font_subset
)
398 cairo_type1_subset_t subset
;
399 cairo_status_t status
;
403 snprintf (name
, sizeof name
, "f-%d-%d",
404 font_subset
->font_id
, font_subset
->subset_id
);
405 status
= _cairo_type1_subset_init (&subset
, name
, font_subset
, TRUE
);
406 if (unlikely (status
))
409 /* FIXME: Figure out document structure convention for fonts */
412 _cairo_output_stream_printf (surface
->final_stream
,
413 "%% _cairo_ps_surface_emit_type1_font_subset\n");
416 _cairo_output_stream_printf (surface
->final_stream
,
417 "%%%%BeginResource: font %s\n",
419 length
= subset
.header_length
+ subset
.data_length
+ subset
.trailer_length
;
420 _cairo_output_stream_write (surface
->final_stream
, subset
.data
, length
);
421 _cairo_output_stream_printf (surface
->final_stream
,
422 "%%%%EndResource\n");
424 _cairo_type1_subset_fini (&subset
);
426 return CAIRO_STATUS_SUCCESS
;
430 static cairo_status_t
431 _cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t
*surface
,
432 cairo_scaled_font_subset_t
*font_subset
)
434 cairo_type1_subset_t subset
;
435 cairo_status_t status
;
439 snprintf (name
, sizeof name
, "f-%d-%d",
440 font_subset
->font_id
, font_subset
->subset_id
);
441 status
= _cairo_type1_fallback_init_hex (&subset
, name
, font_subset
);
442 if (unlikely (status
))
446 _cairo_output_stream_printf (surface
->final_stream
,
447 "%% _cairo_ps_surface_emit_type1_font_fallback\n");
450 _cairo_output_stream_printf (surface
->final_stream
,
451 "%%%%BeginResource: font %s\n",
453 length
= subset
.header_length
+ subset
.data_length
+ subset
.trailer_length
;
454 _cairo_output_stream_write (surface
->final_stream
, subset
.data
, length
);
455 _cairo_output_stream_printf (surface
->final_stream
,
456 "%%%%EndResource\n");
458 _cairo_type1_fallback_fini (&subset
);
460 return CAIRO_STATUS_SUCCESS
;
463 static cairo_status_t
464 _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t
*surface
,
465 cairo_scaled_font_subset_t
*font_subset
)
469 cairo_truetype_subset_t subset
;
470 cairo_status_t status
;
471 unsigned int i
, begin
, end
;
473 status
= _cairo_truetype_subset_init_ps (&subset
, font_subset
);
474 if (unlikely (status
))
477 /* FIXME: Figure out document structure convention for fonts */
480 _cairo_output_stream_printf (surface
->final_stream
,
481 "%% _cairo_ps_surface_emit_truetype_font_subset\n");
484 _cairo_output_stream_printf (surface
->final_stream
,
485 "%%%%BeginResource: font %s\n",
487 _cairo_output_stream_printf (surface
->final_stream
,
490 "/FontName /%s def\n"
492 "/FontMatrix [ 1 0 0 1 0 0 ] def\n"
493 "/FontBBox [ 0 0 0 0 ] def\n"
494 "/Encoding 256 array def\n"
495 "0 1 255 { Encoding exch /.notdef put } for\n",
498 /* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */
500 if (font_subset
->is_latin
) {
501 for (i
= 1; i
< 256; i
++) {
502 if (font_subset
->latin_to_subset_glyph_index
[i
] > 0) {
503 if (font_subset
->glyph_names
!= NULL
) {
504 _cairo_output_stream_printf (surface
->final_stream
,
505 "Encoding %d /%s put\n",
506 i
, font_subset
->glyph_names
[font_subset
->latin_to_subset_glyph_index
[i
]]);
508 _cairo_output_stream_printf (surface
->final_stream
,
509 "Encoding %d /g%ld put\n", i
, font_subset
->latin_to_subset_glyph_index
[i
]);
514 for (i
= 1; i
< font_subset
->num_glyphs
; i
++) {
515 if (font_subset
->glyph_names
!= NULL
) {
516 _cairo_output_stream_printf (surface
->final_stream
,
517 "Encoding %d /%s put\n",
518 i
, font_subset
->glyph_names
[i
]);
520 _cairo_output_stream_printf (surface
->final_stream
,
521 "Encoding %d /g%d put\n", i
, i
);
526 _cairo_output_stream_printf (surface
->final_stream
,
527 "/CharStrings %d dict dup begin\n"
529 font_subset
->num_glyphs
);
531 for (i
= 1; i
< font_subset
->num_glyphs
; i
++) {
532 if (font_subset
->glyph_names
!= NULL
) {
533 _cairo_output_stream_printf (surface
->final_stream
,
535 font_subset
->glyph_names
[i
], i
);
537 _cairo_output_stream_printf (surface
->final_stream
,
538 "/g%d %d def\n", i
, i
);
542 _cairo_output_stream_printf (surface
->final_stream
,
543 "end readonly def\n");
545 _cairo_output_stream_printf (surface
->final_stream
,
549 for (i
= 0; i
< subset
.num_string_offsets
; i
++) {
550 end
= subset
.string_offsets
[i
];
551 _cairo_output_stream_printf (surface
->final_stream
,"<");
552 _cairo_output_stream_write_hex_string (surface
->final_stream
,
553 subset
.data
+ begin
, end
- begin
);
554 _cairo_output_stream_printf (surface
->final_stream
,"00>\n");
557 if (subset
.data_length
> end
) {
558 _cairo_output_stream_printf (surface
->final_stream
,"<");
559 _cairo_output_stream_write_hex_string (surface
->final_stream
,
560 subset
.data
+ end
, subset
.data_length
- end
);
561 _cairo_output_stream_printf (surface
->final_stream
,"00>\n");
564 _cairo_output_stream_printf (surface
->final_stream
,
566 "/f-%d-%d currentdict end definefont pop\n",
567 font_subset
->font_id
,
568 font_subset
->subset_id
);
569 _cairo_output_stream_printf (surface
->final_stream
,
570 "%%%%EndResource\n");
571 _cairo_truetype_subset_fini (&subset
);
574 return CAIRO_STATUS_SUCCESS
;
577 static cairo_int_status_t
578 _cairo_ps_emit_imagemask (cairo_image_surface_t
*image
,
579 cairo_output_stream_t
*stream
)
584 /* The only image type supported by Type 3 fonts are 1-bit image
586 assert (image
->format
== CAIRO_FORMAT_A1
);
588 _cairo_output_stream_printf (stream
,
593 " /ImageMatrix [%d 0 0 %d 0 %d]\n"
595 " /BitsPerComponent 1\n",
602 _cairo_output_stream_printf (stream
,
603 " /DataSource {<\n ");
604 for (row
= image
->data
, rows
= image
->height
; rows
; row
+= image
->stride
, rows
--) {
605 for (byte
= row
, cols
= (image
->width
+ 7) / 8; cols
; byte
++, cols
--) {
606 uint8_t output_byte
= CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte
);
607 _cairo_output_stream_printf (stream
, "%02x ", output_byte
);
609 _cairo_output_stream_printf (stream
, "\n ");
611 _cairo_output_stream_printf (stream
, ">}\n>>\n");
613 _cairo_output_stream_printf (stream
,
616 return _cairo_output_stream_get_status (stream
);
619 static cairo_int_status_t
620 _cairo_ps_surface_analyze_user_font_subset (cairo_scaled_font_subset_t
*font_subset
,
623 cairo_ps_surface_t
*surface
= closure
;
624 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
626 cairo_surface_t
*type3_surface
;
628 type3_surface
= _cairo_type3_glyph_surface_create (font_subset
->scaled_font
,
630 _cairo_ps_emit_imagemask
,
631 surface
->font_subsets
,
634 for (i
= 0; i
< font_subset
->num_glyphs
; i
++) {
635 status
= _cairo_type3_glyph_surface_analyze_glyph (type3_surface
,
636 font_subset
->glyphs
[i
]);
637 if (unlikely (status
))
641 cairo_surface_finish (type3_surface
);
642 cairo_surface_destroy (type3_surface
);
647 static cairo_status_t
648 _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t
*surface
,
649 cairo_scaled_font_subset_t
*font_subset
)
653 cairo_status_t status
;
655 cairo_box_t font_bbox
= {{0,0},{0,0}};
656 cairo_box_t bbox
= {{0,0},{0,0}};
657 cairo_surface_t
*type3_surface
;
660 if (font_subset
->num_glyphs
== 0)
661 return CAIRO_STATUS_SUCCESS
;
664 _cairo_output_stream_printf (surface
->final_stream
,
665 "%% _cairo_ps_surface_emit_type3_font_subset\n");
668 _cairo_output_stream_printf (surface
->final_stream
,
669 "%%%%BeginResource: font\n");
670 _cairo_output_stream_printf (surface
->final_stream
,
673 "/FontMatrix [1 0 0 1 0 0] def\n"
674 "/Encoding 256 array def\n"
675 "0 1 255 { Encoding exch /.notdef put } for\n");
677 type3_surface
= _cairo_type3_glyph_surface_create (font_subset
->scaled_font
,
679 _cairo_ps_emit_imagemask
,
680 surface
->font_subsets
,
682 status
= type3_surface
->status
;
683 if (unlikely (status
))
686 for (i
= 0; i
< font_subset
->num_glyphs
; i
++) {
687 if (font_subset
->glyph_names
!= NULL
) {
688 _cairo_output_stream_printf (surface
->final_stream
,
689 "Encoding %d /%s put\n",
690 i
, font_subset
->glyph_names
[i
]);
692 _cairo_output_stream_printf (surface
->final_stream
,
693 "Encoding %d /g%d put\n", i
, i
);
697 _cairo_output_stream_printf (surface
->final_stream
,
700 for (i
= 0; i
< font_subset
->num_glyphs
; i
++) {
701 _cairo_output_stream_printf (surface
->final_stream
,
703 status
= _cairo_type3_glyph_surface_emit_glyph (type3_surface
,
704 surface
->final_stream
,
705 font_subset
->glyphs
[i
],
708 if (unlikely (status
))
711 _cairo_output_stream_printf (surface
->final_stream
,
714 font_bbox
.p1
.x
= bbox
.p1
.x
;
715 font_bbox
.p1
.y
= bbox
.p1
.y
;
716 font_bbox
.p2
.x
= bbox
.p2
.x
;
717 font_bbox
.p2
.y
= bbox
.p2
.y
;
719 if (bbox
.p1
.x
< font_bbox
.p1
.x
)
720 font_bbox
.p1
.x
= bbox
.p1
.x
;
721 if (bbox
.p1
.y
< font_bbox
.p1
.y
)
722 font_bbox
.p1
.y
= bbox
.p1
.y
;
723 if (bbox
.p2
.x
> font_bbox
.p2
.x
)
724 font_bbox
.p2
.x
= bbox
.p2
.x
;
725 if (bbox
.p2
.y
> font_bbox
.p2
.y
)
726 font_bbox
.p2
.y
= bbox
.p2
.y
;
729 cairo_surface_finish (type3_surface
);
730 cairo_surface_destroy (type3_surface
);
731 if (unlikely (status
))
734 _cairo_output_stream_printf (surface
->final_stream
,
736 "/FontBBox [%f %f %f %f] def\n"
738 " exch /Glyphs get\n"
740 " 10 dict begin exec end\n"
744 "/f-%d-%d exch definefont pop\n",
745 _cairo_fixed_to_double (font_bbox
.p1
.x
),
746 - _cairo_fixed_to_double (font_bbox
.p2
.y
),
747 _cairo_fixed_to_double (font_bbox
.p2
.x
),
748 - _cairo_fixed_to_double (font_bbox
.p1
.y
),
749 font_subset
->font_id
,
750 font_subset
->subset_id
);
751 _cairo_output_stream_printf (surface
->final_stream
,
752 "%%%%EndResource\n");
754 return CAIRO_STATUS_SUCCESS
;
757 static cairo_int_status_t
758 _cairo_ps_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t
*font_subset
,
761 cairo_ps_surface_t
*surface
= closure
;
762 cairo_int_status_t status
;
764 status
= _cairo_scaled_font_subset_create_glyph_names (font_subset
);
765 if (_cairo_int_status_is_error (status
))
768 status
= _cairo_ps_surface_emit_type1_font_subset (surface
, font_subset
);
769 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
772 status
= _cairo_ps_surface_emit_truetype_font_subset (surface
, font_subset
);
773 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
776 status
= _cairo_ps_surface_emit_type1_font_fallback (surface
, font_subset
);
777 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
781 return CAIRO_STATUS_SUCCESS
;
784 static cairo_int_status_t
785 _cairo_ps_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t
*font_subset
,
788 cairo_ps_surface_t
*surface
= closure
;
789 cairo_int_status_t status
;
791 status
= _cairo_scaled_font_subset_create_glyph_names (font_subset
);
792 if (_cairo_int_status_is_error (status
))
795 status
= _cairo_ps_surface_emit_type3_font_subset (surface
, font_subset
);
796 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
800 return CAIRO_INT_STATUS_SUCCESS
;
803 static cairo_status_t
804 _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t
*surface
)
806 cairo_status_t status
;
809 _cairo_output_stream_printf (surface
->final_stream
,
810 "%% _cairo_ps_surface_emit_font_subsets\n");
813 status
= _cairo_scaled_font_subsets_foreach_user (surface
->font_subsets
,
814 _cairo_ps_surface_analyze_user_font_subset
,
816 if (unlikely (status
))
819 status
= _cairo_scaled_font_subsets_foreach_unscaled (surface
->font_subsets
,
820 _cairo_ps_surface_emit_unscaled_font_subset
,
822 if (unlikely (status
))
825 status
= _cairo_scaled_font_subsets_foreach_scaled (surface
->font_subsets
,
826 _cairo_ps_surface_emit_scaled_font_subset
,
828 if (unlikely (status
))
831 return _cairo_scaled_font_subsets_foreach_user (surface
->font_subsets
,
832 _cairo_ps_surface_emit_scaled_font_subset
,
836 static cairo_status_t
837 _cairo_ps_surface_emit_body (cairo_ps_surface_t
*surface
)
842 if (ferror (surface
->tmpfile
) != 0)
843 return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR
);
845 rewind (surface
->tmpfile
);
846 while ((n
= fread (buf
, 1, sizeof (buf
), surface
->tmpfile
)) > 0)
847 _cairo_output_stream_write (surface
->final_stream
, buf
, n
);
849 if (ferror (surface
->tmpfile
) != 0)
850 return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR
);
852 return CAIRO_STATUS_SUCCESS
;
856 _cairo_ps_surface_emit_footer (cairo_ps_surface_t
*surface
)
858 _cairo_output_stream_printf (surface
->final_stream
,
862 _cairo_output_stream_printf (surface
->final_stream
,
866 _cairo_output_stream_printf (surface
->final_stream
,
871 _path_covers_bbox (cairo_ps_surface_t
*surface
,
872 cairo_path_fixed_t
*path
)
876 if (_cairo_path_fixed_is_box (path
, &box
)) {
877 cairo_rectangle_int_t rect
;
879 _cairo_box_round_to_rectangle (&box
, &rect
);
881 /* skip trivial whole-page clips */
882 if (_cairo_rectangle_intersect (&rect
, &surface
->page_bbox
)) {
883 if (rect
.x
== surface
->page_bbox
.x
&&
884 rect
.width
== surface
->page_bbox
.width
&&
885 rect
.y
== surface
->page_bbox
.y
&&
886 rect
.height
== surface
->page_bbox
.height
)
896 static cairo_status_t
897 _cairo_ps_surface_clipper_intersect_clip_path (cairo_surface_clipper_t
*clipper
,
898 cairo_path_fixed_t
*path
,
899 cairo_fill_rule_t fill_rule
,
901 cairo_antialias_t antialias
)
903 cairo_ps_surface_t
*surface
= cairo_container_of (clipper
,
906 cairo_output_stream_t
*stream
= surface
->stream
;
907 cairo_status_t status
;
909 assert (surface
->paginated_mode
!= CAIRO_PAGINATED_MODE_ANALYZE
);
912 _cairo_output_stream_printf (stream
,
913 "%% _cairo_ps_surface_intersect_clip_path\n");
917 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
918 if (unlikely (status
))
921 _cairo_output_stream_printf (stream
, "Q q\n");
923 surface
->current_pattern_is_solid_color
= FALSE
;
924 _cairo_pdf_operators_reset (&surface
->pdf_operators
);
926 return CAIRO_STATUS_SUCCESS
;
929 if (_path_covers_bbox (surface
, path
))
930 return CAIRO_STATUS_SUCCESS
;
932 return _cairo_pdf_operators_clip (&surface
->pdf_operators
,
937 /* PLRM specifies a tolerance of 5 points when matching page sizes */
939 _ps_page_dimension_equal (int a
, int b
)
941 return (abs (a
- b
) < 5);
945 _cairo_ps_surface_get_page_media (cairo_ps_surface_t
*surface
)
947 int width
, height
, i
;
949 cairo_page_media_t
*page
;
950 const char *page_name
;
952 width
= _cairo_lround (surface
->width
);
953 height
= _cairo_lround (surface
->height
);
955 /* search previously used page sizes */
956 cairo_list_foreach_entry (page
, cairo_page_media_t
, &surface
->document_media
, link
) {
957 if (_ps_page_dimension_equal (width
, page
->width
) &&
958 _ps_page_dimension_equal (height
, page
->height
))
962 /* search list of standard page sizes */
964 for (i
= 0; i
< ARRAY_LENGTH (_cairo_page_standard_media
); i
++) {
965 if (_ps_page_dimension_equal (width
, _cairo_page_standard_media
[i
].width
) &&
966 _ps_page_dimension_equal (height
, _cairo_page_standard_media
[i
].height
))
968 page_name
= _cairo_page_standard_media
[i
].name
;
969 width
= _cairo_page_standard_media
[i
].width
;
970 height
= _cairo_page_standard_media
[i
].height
;
975 page
= malloc (sizeof (cairo_page_media_t
));
976 if (unlikely (page
== NULL
)) {
977 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
982 page
->name
= strdup (page_name
);
984 snprintf (buf
, sizeof (buf
), "%dx%dmm",
985 (int) _cairo_lround (surface
->width
* 25.4/72),
986 (int) _cairo_lround (surface
->height
* 25.4/72));
987 page
->name
= strdup (buf
);
990 if (unlikely (page
->name
== NULL
)) {
992 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
997 page
->height
= height
;
998 cairo_list_add_tail (&page
->link
, &surface
->document_media
);
1003 static cairo_surface_t
*
1004 _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t
*stream
,
1008 cairo_status_t status
, status_ignored
;
1009 cairo_ps_surface_t
*surface
;
1011 surface
= malloc (sizeof (cairo_ps_surface_t
));
1012 if (unlikely (surface
== NULL
)) {
1013 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1017 _cairo_surface_init (&surface
->base
,
1018 &cairo_ps_surface_backend
,
1020 CAIRO_CONTENT_COLOR_ALPHA
);
1022 surface
->final_stream
= stream
;
1024 surface
->tmpfile
= tmpfile ();
1025 if (surface
->tmpfile
== NULL
) {
1028 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1031 status
= _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR
);
1034 goto CLEANUP_SURFACE
;
1037 surface
->stream
= _cairo_output_stream_create_for_file (surface
->tmpfile
);
1038 status
= _cairo_output_stream_get_status (surface
->stream
);
1039 if (unlikely (status
))
1040 goto CLEANUP_OUTPUT_STREAM
;
1042 surface
->font_subsets
= _cairo_scaled_font_subsets_create_simple ();
1043 if (unlikely (surface
->font_subsets
== NULL
)) {
1044 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1045 goto CLEANUP_OUTPUT_STREAM
;
1048 _cairo_scaled_font_subsets_enable_latin_subset (surface
->font_subsets
, TRUE
);
1049 surface
->has_creation_date
= FALSE
;
1050 surface
->eps
= FALSE
;
1051 surface
->ps_level
= CAIRO_PS_LEVEL_3
;
1052 surface
->ps_level_used
= CAIRO_PS_LEVEL_2
;
1053 surface
->width
= width
;
1054 surface
->height
= height
;
1055 cairo_matrix_init (&surface
->cairo_to_ps
, 1, 0, 0, -1, 0, height
);
1056 surface
->paginated_mode
= CAIRO_PAGINATED_MODE_ANALYZE
;
1057 surface
->force_fallbacks
= FALSE
;
1058 surface
->content
= CAIRO_CONTENT_COLOR_ALPHA
;
1059 surface
->use_string_datasource
= FALSE
;
1060 surface
->current_pattern_is_solid_color
= FALSE
;
1062 surface
->page_bbox
.x
= 0;
1063 surface
->page_bbox
.y
= 0;
1064 surface
->page_bbox
.width
= width
;
1065 surface
->page_bbox
.height
= height
;
1067 _cairo_surface_clipper_init (&surface
->clipper
,
1068 _cairo_ps_surface_clipper_intersect_clip_path
);
1070 _cairo_pdf_operators_init (&surface
->pdf_operators
,
1072 &surface
->cairo_to_ps
,
1073 surface
->font_subsets
,
1075 surface
->num_pages
= 0;
1077 cairo_list_init (&surface
->document_media
);
1078 _cairo_array_init (&surface
->dsc_header_comments
, sizeof (char *));
1079 _cairo_array_init (&surface
->dsc_setup_comments
, sizeof (char *));
1080 _cairo_array_init (&surface
->dsc_page_setup_comments
, sizeof (char *));
1082 surface
->dsc_comment_target
= &surface
->dsc_header_comments
;
1084 surface
->paginated_surface
= _cairo_paginated_surface_create (
1086 CAIRO_CONTENT_COLOR_ALPHA
,
1087 &cairo_ps_surface_paginated_backend
);
1088 status
= surface
->paginated_surface
->status
;
1089 if (status
== CAIRO_STATUS_SUCCESS
) {
1090 /* paginated keeps the only reference to surface now, drop ours */
1091 cairo_surface_destroy (&surface
->base
);
1092 return surface
->paginated_surface
;
1095 _cairo_scaled_font_subsets_destroy (surface
->font_subsets
);
1096 CLEANUP_OUTPUT_STREAM
:
1097 status_ignored
= _cairo_output_stream_destroy (surface
->stream
);
1098 fclose (surface
->tmpfile
);
1102 /* destroy stream on behalf of caller */
1103 status_ignored
= _cairo_output_stream_destroy (stream
);
1105 return _cairo_surface_create_in_error (status
);
1109 * cairo_ps_surface_create:
1110 * @filename: a filename for the PS output (must be writable), %NULL may be
1111 * used to specify no output. This will generate a PS surface that
1112 * may be queried and used as a source, without generating a
1114 * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
1115 * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
1117 * Creates a PostScript surface of the specified size in points to be
1118 * written to @filename. See cairo_ps_surface_create_for_stream() for
1119 * a more flexible mechanism for handling the PostScript output than
1120 * simply writing it to a named file.
1122 * Note that the size of individual pages of the PostScript output can
1123 * vary. See cairo_ps_surface_set_size().
1125 * Return value: a pointer to the newly created surface. The caller
1126 * owns the surface and should call cairo_surface_destroy() when done
1129 * This function always returns a valid pointer, but it will return a
1130 * pointer to a "nil" surface if an error such as out of memory
1131 * occurs. You can use cairo_surface_status() to check for this.
1136 cairo_ps_surface_create (const char *filename
,
1137 double width_in_points
,
1138 double height_in_points
)
1140 cairo_output_stream_t
*stream
;
1142 stream
= _cairo_output_stream_create_for_filename (filename
);
1143 if (_cairo_output_stream_get_status (stream
))
1144 return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream
));
1146 return _cairo_ps_surface_create_for_stream_internal (stream
,
1152 * cairo_ps_surface_create_for_stream:
1153 * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL
1154 * to indicate a no-op @write_func. With a no-op @write_func,
1155 * the surface may be queried or used as a source without
1156 * generating any temporary files.
1157 * @closure: the closure argument for @write_func
1158 * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
1159 * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
1161 * Creates a PostScript surface of the specified size in points to be
1162 * written incrementally to the stream represented by @write_func and
1163 * @closure. See cairo_ps_surface_create() for a more convenient way
1164 * to simply direct the PostScript output to a named file.
1166 * Note that the size of individual pages of the PostScript
1167 * output can vary. See cairo_ps_surface_set_size().
1169 * Return value: a pointer to the newly created surface. The caller
1170 * owns the surface and should call cairo_surface_destroy() when done
1173 * This function always returns a valid pointer, but it will return a
1174 * pointer to a "nil" surface if an error such as out of memory
1175 * occurs. You can use cairo_surface_status() to check for this.
1180 cairo_ps_surface_create_for_stream (cairo_write_func_t write_func
,
1182 double width_in_points
,
1183 double height_in_points
)
1185 cairo_output_stream_t
*stream
;
1187 stream
= _cairo_output_stream_create (write_func
, NULL
, closure
);
1188 if (_cairo_output_stream_get_status (stream
))
1189 return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream
));
1191 return _cairo_ps_surface_create_for_stream_internal (stream
,
1197 _cairo_surface_is_ps (cairo_surface_t
*surface
)
1199 return surface
->backend
== &cairo_ps_surface_backend
;
1202 /* If the abstract_surface is a paginated surface, and that paginated
1203 * surface's target is a ps_surface, then set ps_surface to that
1204 * target. Otherwise return FALSE.
1207 _extract_ps_surface (cairo_surface_t
*surface
,
1208 cairo_bool_t set_error_on_failure
,
1209 cairo_ps_surface_t
**ps_surface
)
1211 cairo_surface_t
*target
;
1213 if (surface
->status
)
1215 if (surface
->finished
) {
1216 if (set_error_on_failure
)
1217 _cairo_surface_set_error (surface
,
1218 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED
));
1222 if (! _cairo_surface_is_paginated (surface
)) {
1223 if (set_error_on_failure
)
1224 _cairo_surface_set_error (surface
,
1225 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
));
1229 target
= _cairo_paginated_surface_get_target (surface
);
1230 if (target
->status
) {
1231 if (set_error_on_failure
)
1232 _cairo_surface_set_error (surface
, target
->status
);
1235 if (target
->finished
) {
1236 if (set_error_on_failure
)
1237 _cairo_surface_set_error (surface
,
1238 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED
));
1242 if (! _cairo_surface_is_ps (target
)) {
1243 if (set_error_on_failure
)
1244 _cairo_surface_set_error (surface
,
1245 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
));
1249 *ps_surface
= (cairo_ps_surface_t
*) target
;
1254 * cairo_ps_surface_restrict_to_level:
1255 * @surface: a PostScript #cairo_surface_t
1256 * @level: PostScript level
1258 * Restricts the generated PostSript file to @level. See
1259 * cairo_ps_get_levels() for a list of available level values that
1262 * This function should only be called before any drawing operations
1263 * have been performed on the given surface. The simplest way to do
1264 * this is to call this function immediately after creating the
1270 cairo_ps_surface_restrict_to_level (cairo_surface_t
*surface
,
1271 cairo_ps_level_t level
)
1273 cairo_ps_surface_t
*ps_surface
= NULL
;
1275 if (! _extract_ps_surface (surface
, TRUE
, &ps_surface
))
1278 if (level
< CAIRO_PS_LEVEL_LAST
)
1279 ps_surface
->ps_level
= level
;
1283 * cairo_ps_get_levels:
1284 * @levels: supported level list
1285 * @num_levels: list length
1287 * Used to retrieve the list of supported levels. See
1288 * cairo_ps_surface_restrict_to_level().
1293 cairo_ps_get_levels (cairo_ps_level_t
const **levels
,
1297 *levels
= _cairo_ps_levels
;
1299 if (num_levels
!= NULL
)
1300 *num_levels
= CAIRO_PS_LEVEL_LAST
;
1304 * cairo_ps_level_to_string:
1305 * @level: a level id
1307 * Get the string representation of the given @level id. This function
1308 * will return %NULL if @level id isn't valid. See cairo_ps_get_levels()
1309 * for a way to get the list of valid level ids.
1311 * Return value: the string associated to given level.
1316 cairo_ps_level_to_string (cairo_ps_level_t level
)
1318 if (level
>= CAIRO_PS_LEVEL_LAST
)
1321 return _cairo_ps_level_strings
[level
];
1325 * cairo_ps_surface_set_eps:
1326 * @surface: a PostScript #cairo_surface_t
1327 * @eps: %TRUE to output EPS format PostScript
1329 * If @eps is %TRUE, the PostScript surface will output Encapsulated
1332 * This function should only be called before any drawing operations
1333 * have been performed on the current page. The simplest way to do
1334 * this is to call this function immediately after creating the
1335 * surface. An Encapsulated PostScript file should never contain more
1341 cairo_ps_surface_set_eps (cairo_surface_t
*surface
,
1344 cairo_ps_surface_t
*ps_surface
= NULL
;
1346 if (! _extract_ps_surface (surface
, TRUE
, &ps_surface
))
1349 ps_surface
->eps
= eps
;
1353 * cairo_ps_surface_get_eps:
1354 * @surface: a PostScript #cairo_surface_t
1356 * Check whether the PostScript surface will output Encapsulated PostScript.
1358 * Return value: %TRUE if the surface will output Encapsulated PostScript.
1362 cairo_public cairo_bool_t
1363 cairo_ps_surface_get_eps (cairo_surface_t
*surface
)
1365 cairo_ps_surface_t
*ps_surface
= NULL
;
1367 if (! _extract_ps_surface (surface
, FALSE
, &ps_surface
))
1370 return ps_surface
->eps
;
1374 * cairo_ps_surface_set_size:
1375 * @surface: a PostScript #cairo_surface_t
1376 * @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
1377 * @height_in_points: new surface height, in points (1 point == 1/72.0 inch)
1379 * Changes the size of a PostScript surface for the current (and
1380 * subsequent) pages.
1382 * This function should only be called before any drawing operations
1383 * have been performed on the current page. The simplest way to do
1384 * this is to call this function immediately after creating the
1385 * surface or immediately after completing a page with either
1386 * cairo_show_page() or cairo_copy_page().
1391 cairo_ps_surface_set_size (cairo_surface_t
*surface
,
1392 double width_in_points
,
1393 double height_in_points
)
1395 cairo_ps_surface_t
*ps_surface
= NULL
;
1396 cairo_status_t status
;
1398 if (! _extract_ps_surface (surface
, TRUE
, &ps_surface
))
1401 ps_surface
->width
= width_in_points
;
1402 ps_surface
->height
= height_in_points
;
1403 cairo_matrix_init (&ps_surface
->cairo_to_ps
, 1, 0, 0, -1, 0, height_in_points
);
1404 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface
->pdf_operators
,
1405 &ps_surface
->cairo_to_ps
);
1406 status
= _cairo_paginated_surface_set_size (ps_surface
->paginated_surface
,
1410 status
= _cairo_surface_set_error (surface
, status
);
1414 * cairo_ps_surface_dsc_comment:
1415 * @surface: a PostScript #cairo_surface_t
1416 * @comment: a comment string to be emitted into the PostScript output
1418 * Emit a comment into the PostScript output for the given surface.
1420 * The comment is expected to conform to the PostScript Language
1421 * Document Structuring Conventions (DSC). Please see that manual for
1422 * details on the available comments and their meanings. In
1423 * particular, the \%\%IncludeFeature comment allows a
1424 * device-independent means of controlling printer device features. So
1425 * the PostScript Printer Description Files Specification will also be
1426 * a useful reference.
1428 * The comment string must begin with a percent character (\%) and the
1429 * total length of the string (including any initial percent
1430 * characters) must not exceed 255 characters. Violating either of
1431 * these conditions will place @surface into an error state. But
1432 * beyond these two conditions, this function will not enforce
1433 * conformance of the comment with any particular specification.
1435 * The comment string should not have a trailing newline.
1437 * The DSC specifies different sections in which particular comments
1438 * can appear. This function provides for comments to be emitted
1439 * within three sections: the header, the Setup section, and the
1440 * PageSetup section. Comments appearing in the first two sections
1441 * apply to the entire document while comments in the BeginPageSetup
1442 * section apply only to a single page.
1444 * For comments to appear in the header section, this function should
1445 * be called after the surface is created, but before a call to
1446 * cairo_ps_surface_dsc_begin_setup().
1448 * For comments to appear in the Setup section, this function should
1449 * be called after a call to cairo_ps_surface_dsc_begin_setup() but
1450 * before a call to cairo_ps_surface_dsc_begin_page_setup().
1452 * For comments to appear in the PageSetup section, this function
1453 * should be called after a call to
1454 * cairo_ps_surface_dsc_begin_page_setup().
1456 * Note that it is only necessary to call
1457 * cairo_ps_surface_dsc_begin_page_setup() for the first page of any
1458 * surface. After a call to cairo_show_page() or cairo_copy_page()
1459 * comments are unambiguously directed to the PageSetup section of the
1460 * current page. But it doesn't hurt to call this function at the
1461 * beginning of every page as that consistency may make the calling
1464 * As a final note, cairo automatically generates several comments on
1465 * its own. As such, applications must not manually generate any of
1466 * the following comments:
1468 * Header section: \%!PS-Adobe-3.0, \%\%Creator, \%\%CreationDate, \%\%Pages,
1469 * \%\%BoundingBox, \%\%DocumentData, \%\%LanguageLevel, \%\%EndComments.
1471 * Setup section: \%\%BeginSetup, \%\%EndSetup
1473 * PageSetup section: \%\%BeginPageSetup, \%\%PageBoundingBox, \%\%EndPageSetup.
1475 * Other sections: \%\%BeginProlog, \%\%EndProlog, \%\%Page, \%\%Trailer, \%\%EOF
1477 * Here is an example sequence showing how this function might be used:
1479 * <informalexample><programlisting>
1480 * cairo_surface_t *surface = cairo_ps_surface_create (filename, width, height);
1482 * cairo_ps_surface_dsc_comment (surface, "%%Title: My excellent document");
1483 * cairo_ps_surface_dsc_comment (surface, "%%Copyright: Copyright (C) 2006 Cairo Lover")
1485 * cairo_ps_surface_dsc_begin_setup (surface);
1486 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor White");
1488 * cairo_ps_surface_dsc_begin_page_setup (surface);
1489 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A3");
1490 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *InputSlot LargeCapacity");
1491 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaType Glossy");
1492 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor Blue");
1493 * ... draw to first page here ..
1494 * cairo_show_page (cr);
1496 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A5");
1498 * </programlisting></informalexample>
1503 cairo_ps_surface_dsc_comment (cairo_surface_t
*surface
,
1504 const char *comment
)
1506 cairo_ps_surface_t
*ps_surface
= NULL
;
1507 cairo_status_t status
;
1510 if (! _extract_ps_surface (surface
, TRUE
, &ps_surface
))
1513 /* A couple of sanity checks on the comment value. */
1514 if (comment
== NULL
) {
1515 status
= _cairo_surface_set_error (surface
, CAIRO_STATUS_NULL_POINTER
);
1519 if (comment
[0] != '%' || strlen (comment
) > 255) {
1520 status
= _cairo_surface_set_error (surface
, CAIRO_STATUS_INVALID_DSC_COMMENT
);
1524 /* Then, copy the comment and store it in the appropriate array. */
1525 comment_copy
= strdup (comment
);
1526 if (unlikely (comment_copy
== NULL
)) {
1527 status
= _cairo_surface_set_error (surface
, CAIRO_STATUS_NO_MEMORY
);
1531 status
= _cairo_array_append (ps_surface
->dsc_comment_target
, &comment_copy
);
1532 if (unlikely (status
)) {
1533 free (comment_copy
);
1534 status
= _cairo_surface_set_error (surface
, status
);
1540 * cairo_ps_surface_dsc_begin_setup:
1541 * @surface: a PostScript #cairo_surface_t
1543 * This function indicates that subsequent calls to
1544 * cairo_ps_surface_dsc_comment() should direct comments to the Setup
1545 * section of the PostScript output.
1547 * This function should be called at most once per surface, and must
1548 * be called before any call to cairo_ps_surface_dsc_begin_page_setup()
1549 * and before any drawing is performed to the surface.
1551 * See cairo_ps_surface_dsc_comment() for more details.
1556 cairo_ps_surface_dsc_begin_setup (cairo_surface_t
*surface
)
1558 cairo_ps_surface_t
*ps_surface
= NULL
;
1560 if (! _extract_ps_surface (surface
, TRUE
, &ps_surface
))
1563 if (ps_surface
->dsc_comment_target
== &ps_surface
->dsc_header_comments
)
1564 ps_surface
->dsc_comment_target
= &ps_surface
->dsc_setup_comments
;
1568 * cairo_ps_surface_dsc_begin_page_setup:
1569 * @surface: a PostScript #cairo_surface_t
1571 * This function indicates that subsequent calls to
1572 * cairo_ps_surface_dsc_comment() should direct comments to the
1573 * PageSetup section of the PostScript output.
1575 * This function call is only needed for the first page of a
1576 * surface. It should be called after any call to
1577 * cairo_ps_surface_dsc_begin_setup() and before any drawing is
1578 * performed to the surface.
1580 * See cairo_ps_surface_dsc_comment() for more details.
1585 cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t
*surface
)
1587 cairo_ps_surface_t
*ps_surface
= NULL
;
1589 if (! _extract_ps_surface (surface
, TRUE
, &ps_surface
))
1592 if (ps_surface
->dsc_comment_target
== &ps_surface
->dsc_header_comments
||
1593 ps_surface
->dsc_comment_target
== &ps_surface
->dsc_setup_comments
)
1595 ps_surface
->dsc_comment_target
= &ps_surface
->dsc_page_setup_comments
;
1599 static cairo_status_t
1600 _cairo_ps_surface_finish (void *abstract_surface
)
1602 cairo_status_t status
, status2
;
1603 cairo_ps_surface_t
*surface
= abstract_surface
;
1604 int i
, num_comments
;
1607 status
= surface
->base
.status
;
1608 if (unlikely (status
))
1611 _cairo_ps_surface_emit_header (surface
);
1613 status
= _cairo_ps_surface_emit_font_subsets (surface
);
1614 if (unlikely (status
))
1617 _cairo_output_stream_printf (surface
->final_stream
,
1620 status
= _cairo_ps_surface_emit_body (surface
);
1621 if (unlikely (status
))
1624 _cairo_ps_surface_emit_footer (surface
);
1627 _cairo_scaled_font_subsets_destroy (surface
->font_subsets
);
1629 status2
= _cairo_output_stream_destroy (surface
->stream
);
1630 if (status
== CAIRO_STATUS_SUCCESS
)
1633 fclose (surface
->tmpfile
);
1635 status2
= _cairo_output_stream_destroy (surface
->final_stream
);
1636 if (status
== CAIRO_STATUS_SUCCESS
)
1639 while (! cairo_list_is_empty (&surface
->document_media
)) {
1640 cairo_page_media_t
*page
;
1642 page
= cairo_list_first_entry (&surface
->document_media
,
1645 cairo_list_del (&page
->link
);
1650 num_comments
= _cairo_array_num_elements (&surface
->dsc_header_comments
);
1651 comments
= _cairo_array_index (&surface
->dsc_header_comments
, 0);
1652 for (i
= 0; i
< num_comments
; i
++)
1654 _cairo_array_fini (&surface
->dsc_header_comments
);
1656 num_comments
= _cairo_array_num_elements (&surface
->dsc_setup_comments
);
1657 comments
= _cairo_array_index (&surface
->dsc_setup_comments
, 0);
1658 for (i
= 0; i
< num_comments
; i
++)
1660 _cairo_array_fini (&surface
->dsc_setup_comments
);
1662 num_comments
= _cairo_array_num_elements (&surface
->dsc_page_setup_comments
);
1663 comments
= _cairo_array_index (&surface
->dsc_page_setup_comments
, 0);
1664 for (i
= 0; i
< num_comments
; i
++)
1666 _cairo_array_fini (&surface
->dsc_page_setup_comments
);
1668 _cairo_surface_clipper_reset (&surface
->clipper
);
1673 static cairo_int_status_t
1674 _cairo_ps_surface_start_page (void *abstract_surface
)
1676 cairo_ps_surface_t
*surface
= abstract_surface
;
1678 /* Increment before print so page numbers start at 1. */
1679 surface
->num_pages
++;
1681 return CAIRO_STATUS_SUCCESS
;
1684 static cairo_int_status_t
1685 _cairo_ps_surface_show_page (void *abstract_surface
)
1687 cairo_ps_surface_t
*surface
= abstract_surface
;
1688 cairo_int_status_t status
;
1690 if (surface
->clipper
.clip
!= NULL
)
1691 _cairo_surface_clipper_reset (&surface
->clipper
);
1693 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
1694 if (unlikely (status
))
1697 _cairo_output_stream_printf (surface
->stream
,
1701 return CAIRO_STATUS_SUCCESS
;
1705 color_is_gray (double red
, double green
, double blue
)
1707 const double epsilon
= 0.00001;
1709 return (fabs (red
- green
) < epsilon
&&
1710 fabs (red
- blue
) < epsilon
);
1714 * _cairo_ps_surface_acquire_source_surface_from_pattern:
1715 * @surface: the ps surface
1716 * @pattern: A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source
1717 * @extents: extents of the operation that is using this source
1718 * @width: returns width of surface
1719 * @height: returns height of surface
1720 * @x_offset: returns x offset of surface
1721 * @y_offset: returns y offset of surface
1722 * @surface: returns surface of type image surface or recording surface
1723 * @image_extra: returns image extra for image type surface
1725 * Acquire source surface or raster source pattern.
1727 static cairo_status_t
1728 _cairo_ps_surface_acquire_source_surface_from_pattern (cairo_ps_surface_t
*surface
,
1729 const cairo_pattern_t
*pattern
,
1730 const cairo_rectangle_int_t
*extents
,
1735 cairo_surface_t
**source_surface
,
1738 cairo_status_t status
;
1739 cairo_image_surface_t
*image
;
1741 *x_offset
= *y_offset
= 0;
1742 switch (pattern
->type
) {
1743 case CAIRO_PATTERN_TYPE_SURFACE
: {
1744 cairo_surface_t
*surf
= ((cairo_surface_pattern_t
*) pattern
)->surface
;
1746 if (surf
->type
== CAIRO_SURFACE_TYPE_RECORDING
) {
1747 if (surf
->backend
->type
== CAIRO_SURFACE_TYPE_SUBSURFACE
) {
1748 cairo_surface_subsurface_t
*sub
= (cairo_surface_subsurface_t
*) surf
;
1750 *width
= sub
->extents
.width
;
1751 *height
= sub
->extents
.height
;
1753 cairo_surface_t
*free_me
= NULL
;
1754 cairo_recording_surface_t
*recording_surface
;
1756 cairo_rectangle_int_t extents
;
1758 recording_surface
= (cairo_recording_surface_t
*) surf
;
1759 if (_cairo_surface_is_snapshot (&recording_surface
->base
)) {
1760 free_me
= _cairo_surface_snapshot_get_target (&recording_surface
->base
);
1761 recording_surface
= (cairo_recording_surface_t
*) free_me
;
1764 status
= _cairo_recording_surface_get_bbox (recording_surface
, &bbox
, NULL
);
1765 cairo_surface_destroy (free_me
);
1766 if (unlikely (status
))
1769 _cairo_box_round_to_rectangle (&bbox
, &extents
);
1770 *width
= extents
.width
;
1771 *height
= extents
.height
;
1773 *source_surface
= surf
;
1775 return CAIRO_STATUS_SUCCESS
;
1777 status
= _cairo_surface_acquire_source_image (surf
, &image
, image_extra
);
1778 if (unlikely (status
))
1783 case CAIRO_PATTERN_TYPE_RASTER_SOURCE
: {
1784 cairo_surface_t
*surf
;
1786 cairo_rectangle_int_t rect
;
1788 /* get the operation extents in pattern space */
1789 _cairo_box_from_rectangle (&box
, extents
);
1790 _cairo_matrix_transform_bounding_box_fixed (&pattern
->matrix
, &box
, NULL
);
1791 _cairo_box_round_to_rectangle (&box
, &rect
);
1792 surf
= _cairo_raster_source_pattern_acquire (pattern
, &surface
->base
, &rect
);
1794 return CAIRO_INT_STATUS_UNSUPPORTED
;
1795 assert (_cairo_surface_is_image (surf
));
1796 image
= (cairo_image_surface_t
*) surf
;
1799 case CAIRO_PATTERN_TYPE_SOLID
:
1800 case CAIRO_PATTERN_TYPE_LINEAR
:
1801 case CAIRO_PATTERN_TYPE_RADIAL
:
1802 case CAIRO_PATTERN_TYPE_MESH
:
1808 *width
= image
->width
;
1809 *height
= image
->height
;
1810 *source_surface
= &image
->base
;
1811 return CAIRO_STATUS_SUCCESS
;
1815 _cairo_ps_surface_release_source_surface_from_pattern (cairo_ps_surface_t
*surface
,
1816 const cairo_pattern_t
*pattern
,
1817 cairo_surface_t
*source
,
1820 switch (pattern
->type
) {
1821 case CAIRO_PATTERN_TYPE_SURFACE
: {
1822 cairo_surface_pattern_t
*surf_pat
= (cairo_surface_pattern_t
*) pattern
;
1823 if (surf_pat
->surface
->type
!= CAIRO_SURFACE_TYPE_RECORDING
) {
1824 cairo_image_surface_t
*image
= (cairo_image_surface_t
*) source
;
1825 _cairo_surface_release_source_image (surf_pat
->surface
, image
, image_extra
);
1829 case CAIRO_PATTERN_TYPE_RASTER_SOURCE
:
1830 _cairo_raster_source_pattern_release (pattern
, source
);
1833 case CAIRO_PATTERN_TYPE_SOLID
:
1834 case CAIRO_PATTERN_TYPE_LINEAR
:
1835 case CAIRO_PATTERN_TYPE_RADIAL
:
1836 case CAIRO_PATTERN_TYPE_MESH
:
1845 * _cairo_ps_surface_create_padded_image_from_image:
1846 * @surface: the ps surface
1847 * @source: The source image
1848 * @extents: extents of the operation that is using this source
1849 * @width: returns width of padded image
1850 * @height: returns height of padded image
1851 * @x_offset: returns x offset of padded image
1852 * @y_offset: returns y offset of padded image
1853 * @image: returns the padded image or NULL if padding not required to fill @extents
1855 * Creates a padded image if the source image does not fill the extents.
1857 static cairo_status_t
1858 _cairo_ps_surface_create_padded_image_from_image (cairo_ps_surface_t
*surface
,
1859 cairo_image_surface_t
*source
,
1860 const cairo_matrix_t
*source_matrix
,
1861 const cairo_rectangle_int_t
*extents
,
1866 cairo_image_surface_t
**image
)
1869 cairo_rectangle_int_t rect
;
1870 cairo_surface_t
*pad_image
;
1871 cairo_surface_pattern_t pad_pattern
;
1873 cairo_int_status_t status
;
1875 /* get the operation extents in pattern space */
1876 _cairo_box_from_rectangle (&box
, extents
);
1877 _cairo_matrix_transform_bounding_box_fixed (source_matrix
, &box
, NULL
);
1878 _cairo_box_round_to_rectangle (&box
, &rect
);
1880 /* Check if image needs padding to fill extents. */
1883 if (_cairo_fixed_integer_ceil(box
.p1
.x
) < 0 ||
1884 _cairo_fixed_integer_ceil(box
.p1
.y
) < 0 ||
1885 _cairo_fixed_integer_floor(box
.p2
.y
) > w
||
1886 _cairo_fixed_integer_floor(box
.p2
.y
) > h
)
1889 _cairo_image_surface_create_with_pixman_format (NULL
,
1890 source
->pixman_format
,
1891 rect
.width
, rect
.height
,
1893 if (pad_image
->status
)
1894 return pad_image
->status
;
1896 _cairo_pattern_init_for_surface (&pad_pattern
, &source
->base
);
1897 cairo_matrix_init_translate (&pad_pattern
.base
.matrix
, rect
.x
, rect
.y
);
1898 pad_pattern
.base
.extend
= CAIRO_EXTEND_PAD
;
1899 status
= _cairo_surface_paint (pad_image
,
1900 CAIRO_OPERATOR_SOURCE
,
1903 _cairo_pattern_fini (&pad_pattern
.base
);
1904 *image
= (cairo_image_surface_t
*) pad_image
;
1905 *width
= rect
.width
;
1906 *height
= rect
.height
;
1911 status
= CAIRO_STATUS_SUCCESS
;
1917 static cairo_int_status_t
1918 _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t
*surface
,
1919 const cairo_pattern_t
*pattern
,
1920 const cairo_rectangle_int_t
*extents
)
1923 double x_offset
, y_offset
;
1924 cairo_surface_t
*source
;
1925 cairo_image_surface_t
*image
;
1927 cairo_int_status_t status
;
1928 cairo_image_transparency_t transparency
;
1930 status
= _cairo_ps_surface_acquire_source_surface_from_pattern (surface
,
1939 if (unlikely (status
))
1942 image
= (cairo_image_surface_t
*) source
;
1943 if (image
->base
.status
)
1944 return image
->base
.status
;
1946 transparency
= _cairo_image_analyze_transparency (image
);
1947 switch (transparency
) {
1948 case CAIRO_IMAGE_IS_OPAQUE
:
1949 status
= CAIRO_STATUS_SUCCESS
;
1952 case CAIRO_IMAGE_HAS_BILEVEL_ALPHA
:
1953 if (surface
->ps_level
== CAIRO_PS_LEVEL_2
) {
1954 status
= CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
;
1956 surface
->ps_level_used
= CAIRO_PS_LEVEL_3
;
1957 status
= CAIRO_STATUS_SUCCESS
;
1961 case CAIRO_IMAGE_HAS_ALPHA
:
1962 status
= CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
;
1965 case CAIRO_IMAGE_UNKNOWN
:
1969 _cairo_ps_surface_release_source_surface_from_pattern (surface
, pattern
, source
, image_extra
);
1975 surface_pattern_supported (const cairo_surface_pattern_t
*pattern
)
1977 if (pattern
->surface
->type
== CAIRO_SURFACE_TYPE_RECORDING
)
1980 if (pattern
->surface
->backend
->acquire_source_image
== NULL
)
1983 /* Does an ALPHA-only source surface even make sense? Maybe, but I
1984 * don't think it's worth the extra code to support it. */
1986 /* XXX: Need to write this function here...
1987 content = pattern->surface->content;
1988 if (content == CAIRO_CONTENT_ALPHA)
1996 _gradient_pattern_supported (cairo_ps_surface_t
*surface
,
1997 const cairo_pattern_t
*pattern
)
1999 double min_alpha
, max_alpha
;
2001 if (surface
->ps_level
== CAIRO_PS_LEVEL_2
)
2004 /* Alpha gradients are only supported (by flattening the alpha)
2005 * if there is no variation in the alpha across the gradient. */
2006 _cairo_pattern_alpha_range (pattern
, &min_alpha
, &max_alpha
);
2007 if (min_alpha
!= max_alpha
)
2010 surface
->ps_level_used
= CAIRO_PS_LEVEL_3
;
2016 pattern_supported (cairo_ps_surface_t
*surface
, const cairo_pattern_t
*pattern
)
2018 switch (pattern
->type
) {
2019 case CAIRO_PATTERN_TYPE_SOLID
:
2022 case CAIRO_PATTERN_TYPE_LINEAR
:
2023 case CAIRO_PATTERN_TYPE_RADIAL
:
2024 case CAIRO_PATTERN_TYPE_MESH
:
2025 return _gradient_pattern_supported (surface
, pattern
);
2027 case CAIRO_PATTERN_TYPE_SURFACE
:
2028 return surface_pattern_supported ((cairo_surface_pattern_t
*) pattern
);
2030 case CAIRO_PATTERN_TYPE_RASTER_SOURCE
:
2040 mask_supported (cairo_ps_surface_t
*surface
,
2041 const cairo_pattern_t
*mask
,
2042 const cairo_rectangle_int_t
*extents
)
2044 if (surface
->ps_level
== CAIRO_PS_LEVEL_2
)
2047 if (mask
->type
== CAIRO_PATTERN_TYPE_SURFACE
) {
2048 cairo_surface_pattern_t
*surface_pattern
= (cairo_surface_pattern_t
*) mask
;
2049 if (surface_pattern
->surface
->type
== CAIRO_SURFACE_TYPE_IMAGE
) {
2050 /* check if mask if opaque or bilevel alpha */
2051 if (_cairo_ps_surface_analyze_surface_pattern_transparency (surface
, mask
, extents
) == CAIRO_INT_STATUS_SUCCESS
) {
2052 surface
->ps_level_used
= CAIRO_PS_LEVEL_3
;
2061 static cairo_int_status_t
2062 _cairo_ps_surface_analyze_operation (cairo_ps_surface_t
*surface
,
2063 cairo_operator_t op
,
2064 const cairo_pattern_t
*pattern
,
2065 const cairo_pattern_t
*mask
,
2066 const cairo_rectangle_int_t
*extents
)
2070 if (surface
->force_fallbacks
&&
2071 surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
)
2073 return CAIRO_INT_STATUS_UNSUPPORTED
;
2076 if (! pattern_supported (surface
, pattern
))
2077 return CAIRO_INT_STATUS_UNSUPPORTED
;
2079 if (! (op
== CAIRO_OPERATOR_SOURCE
|| op
== CAIRO_OPERATOR_OVER
))
2080 return CAIRO_INT_STATUS_UNSUPPORTED
;
2082 /* Mask is only supported when the mask is an image with opaque or bilevel alpha. */
2083 if (mask
&& !mask_supported (surface
, mask
, extents
))
2084 return CAIRO_INT_STATUS_UNSUPPORTED
;
2086 if (pattern
->type
== CAIRO_PATTERN_TYPE_SURFACE
) {
2087 cairo_surface_pattern_t
*surface_pattern
= (cairo_surface_pattern_t
*) pattern
;
2089 if (surface_pattern
->surface
->type
== CAIRO_SURFACE_TYPE_RECORDING
) {
2090 if (pattern
->extend
== CAIRO_EXTEND_PAD
) {
2092 cairo_rectangle_int_t rect
;
2093 cairo_rectangle_int_t rec_extents
;
2095 /* get the operation extents in pattern space */
2096 _cairo_box_from_rectangle (&box
, extents
);
2097 _cairo_matrix_transform_bounding_box_fixed (&pattern
->matrix
, &box
, NULL
);
2098 _cairo_box_round_to_rectangle (&box
, &rect
);
2100 /* Check if surface needs padding to fill extents */
2101 if (_cairo_surface_get_extents (surface_pattern
->surface
, &rec_extents
)) {
2102 if (_cairo_fixed_integer_ceil(box
.p1
.x
) < rec_extents
.x
||
2103 _cairo_fixed_integer_ceil(box
.p1
.y
) < rec_extents
.y
||
2104 _cairo_fixed_integer_floor(box
.p2
.y
) > rec_extents
.x
+ rec_extents
.width
||
2105 _cairo_fixed_integer_floor(box
.p2
.y
) > rec_extents
.y
+ rec_extents
.height
)
2107 return CAIRO_INT_STATUS_UNSUPPORTED
;
2111 return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN
;
2115 if (op
== CAIRO_OPERATOR_SOURCE
) {
2117 return CAIRO_INT_STATUS_UNSUPPORTED
;
2119 return CAIRO_STATUS_SUCCESS
;
2122 /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
2123 * the pattern contains transparency, we return
2124 * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
2125 * surface. If the analysis surface determines that there is
2126 * anything drawn under this operation, a fallback image will be
2127 * used. Otherwise the operation will be replayed during the
2128 * render stage and we blend the transparency into the white
2129 * background to convert the pattern to opaque.
2131 if (pattern
->type
== CAIRO_PATTERN_TYPE_SURFACE
|| pattern
->type
== CAIRO_PATTERN_TYPE_RASTER_SOURCE
)
2132 return _cairo_ps_surface_analyze_surface_pattern_transparency (surface
, pattern
, extents
);
2134 /* Patterns whose drawn part is opaque are directly supported;
2135 those whose drawn part is partially transparent can be
2136 supported by flattening the alpha. */
2137 _cairo_pattern_alpha_range (pattern
, &min_alpha
, NULL
);
2138 if (CAIRO_ALPHA_IS_OPAQUE (min_alpha
))
2139 return CAIRO_STATUS_SUCCESS
;
2141 return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
;
2145 _cairo_ps_surface_operation_supported (cairo_ps_surface_t
*surface
,
2146 cairo_operator_t op
,
2147 const cairo_pattern_t
*pattern
,
2148 const cairo_pattern_t
*mask
,
2149 const cairo_rectangle_int_t
*extents
)
2151 return _cairo_ps_surface_analyze_operation (surface
, op
, pattern
, mask
, extents
) != CAIRO_INT_STATUS_UNSUPPORTED
;
2154 /* The "standard" implementation limit for PostScript string sizes is
2155 * 65535 characters (see PostScript Language Reference, Appendix
2156 * B). We go one short of that because we sometimes need two
2157 * characters in a string to represent a single ASCII85 byte, (for the
2158 * escape sequences "\\", "\(", and "\)") and we must not split these
2159 * across two strings. So we'd be in trouble if we went right to the
2160 * limit and one of these escape sequences just happened to land at
2163 #define STRING_ARRAY_MAX_STRING_SIZE (65535-1)
2164 #define STRING_ARRAY_MAX_COLUMN 72
2166 typedef struct _string_array_stream
{
2167 cairo_output_stream_t base
;
2168 cairo_output_stream_t
*output
;
2171 cairo_bool_t use_strings
;
2172 } string_array_stream_t
;
2174 static cairo_status_t
2175 _string_array_stream_write (cairo_output_stream_t
*base
,
2176 const unsigned char *data
,
2177 unsigned int length
)
2179 string_array_stream_t
*stream
= (string_array_stream_t
*) base
;
2181 const unsigned char backslash
= '\\';
2184 return CAIRO_STATUS_SUCCESS
;
2187 if (stream
->string_size
== 0 && stream
->use_strings
) {
2188 _cairo_output_stream_printf (stream
->output
, "(");
2193 if (stream
->use_strings
) {
2198 _cairo_output_stream_write (stream
->output
, &backslash
, 1);
2200 stream
->string_size
++;
2204 /* Have to be careful to never split the final ~> sequence. */
2206 _cairo_output_stream_write (stream
->output
, &c
, 1);
2208 stream
->string_size
++;
2215 _cairo_output_stream_write (stream
->output
, &c
, 1);
2217 stream
->string_size
++;
2219 if (stream
->use_strings
&&
2220 stream
->string_size
>= STRING_ARRAY_MAX_STRING_SIZE
)
2222 _cairo_output_stream_printf (stream
->output
, ")\n");
2223 stream
->string_size
= 0;
2226 if (stream
->column
>= STRING_ARRAY_MAX_COLUMN
) {
2227 _cairo_output_stream_printf (stream
->output
, "\n ");
2228 stream
->string_size
+= 2;
2233 return _cairo_output_stream_get_status (stream
->output
);
2236 static cairo_status_t
2237 _string_array_stream_close (cairo_output_stream_t
*base
)
2239 cairo_status_t status
;
2240 string_array_stream_t
*stream
= (string_array_stream_t
*) base
;
2242 if (stream
->use_strings
)
2243 _cairo_output_stream_printf (stream
->output
, ")\n");
2245 status
= _cairo_output_stream_get_status (stream
->output
);
2250 /* A string_array_stream wraps an existing output stream. It takes the
2251 * data provided to it and output one or more consecutive string
2252 * objects, each within the standard PostScript implementation limit
2253 * of 65k characters.
2255 * The strings are each separated by a space character for easy
2256 * inclusion within an array object, (but the array delimiters are not
2257 * added by the string_array_stream).
2259 * The string array stream is also careful to wrap the output within
2260 * STRING_ARRAY_MAX_COLUMN columns (+/- 1). The stream also adds
2261 * necessary escaping for special characters within a string,
2262 * (specifically '\', '(', and ')').
2264 static cairo_output_stream_t
*
2265 _string_array_stream_create (cairo_output_stream_t
*output
)
2267 string_array_stream_t
*stream
;
2269 stream
= malloc (sizeof (string_array_stream_t
));
2270 if (unlikely (stream
== NULL
)) {
2271 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
2272 return (cairo_output_stream_t
*) &_cairo_output_stream_nil
;
2275 _cairo_output_stream_init (&stream
->base
,
2276 _string_array_stream_write
,
2278 _string_array_stream_close
);
2279 stream
->output
= output
;
2281 stream
->string_size
= 0;
2282 stream
->use_strings
= TRUE
;
2284 return &stream
->base
;
2287 /* A base85_array_stream wraps an existing output stream. It wraps the
2288 * output within STRING_ARRAY_MAX_COLUMN columns (+/- 1). The output
2289 * is not enclosed in strings like string_array_stream.
2291 static cairo_output_stream_t
*
2292 _base85_array_stream_create (cairo_output_stream_t
*output
)
2294 string_array_stream_t
*stream
;
2296 stream
= malloc (sizeof (string_array_stream_t
));
2297 if (unlikely (stream
== NULL
)) {
2298 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
2299 return (cairo_output_stream_t
*) &_cairo_output_stream_nil
;
2302 _cairo_output_stream_init (&stream
->base
,
2303 _string_array_stream_write
,
2305 _string_array_stream_close
);
2306 stream
->output
= output
;
2308 stream
->string_size
= 0;
2309 stream
->use_strings
= FALSE
;
2311 return &stream
->base
;
2315 /* PS Output - this section handles output of the parts of the recording
2316 * surface we can render natively in PS. */
2318 static cairo_status_t
2319 _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t
*surface
,
2320 cairo_image_surface_t
*image
,
2321 cairo_image_surface_t
**opaque_image
)
2323 cairo_surface_t
*opaque
;
2324 cairo_surface_pattern_t pattern
;
2325 cairo_status_t status
;
2327 opaque
= cairo_image_surface_create (CAIRO_FORMAT_RGB24
,
2330 if (unlikely (opaque
->status
))
2331 return opaque
->status
;
2333 if (surface
->content
== CAIRO_CONTENT_COLOR_ALPHA
) {
2334 status
= _cairo_surface_paint (opaque
,
2335 CAIRO_OPERATOR_SOURCE
,
2336 &_cairo_pattern_white
.base
,
2338 if (unlikely (status
)) {
2339 cairo_surface_destroy (opaque
);
2344 _cairo_pattern_init_for_surface (&pattern
, &image
->base
);
2345 pattern
.base
.filter
= CAIRO_FILTER_NEAREST
;
2346 status
= _cairo_surface_paint (opaque
, CAIRO_OPERATOR_OVER
, &pattern
.base
, NULL
);
2347 _cairo_pattern_fini (&pattern
.base
);
2348 if (unlikely (status
)) {
2349 cairo_surface_destroy (opaque
);
2353 *opaque_image
= (cairo_image_surface_t
*) opaque
;
2354 return CAIRO_STATUS_SUCCESS
;
2357 static cairo_status_t
2358 _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t
*surface
,
2359 const unsigned char *data
,
2360 unsigned long length
,
2361 cairo_ps_compress_t compress
,
2362 cairo_bool_t use_strings
)
2364 cairo_output_stream_t
*base85_stream
, *string_array_stream
, *deflate_stream
;
2365 unsigned char *data_compressed
;
2366 unsigned long data_compressed_size
;
2367 cairo_status_t status
, status2
;
2370 string_array_stream
= _string_array_stream_create (surface
->stream
);
2372 string_array_stream
= _base85_array_stream_create (surface
->stream
);
2374 status
= _cairo_output_stream_get_status (string_array_stream
);
2375 if (unlikely (status
))
2376 return _cairo_output_stream_destroy (string_array_stream
);
2378 base85_stream
= _cairo_base85_stream_create (string_array_stream
);
2379 status
= _cairo_output_stream_get_status (base85_stream
);
2380 if (unlikely (status
)) {
2381 status2
= _cairo_output_stream_destroy (string_array_stream
);
2382 return _cairo_output_stream_destroy (base85_stream
);
2386 case CAIRO_PS_COMPRESS_NONE
:
2387 _cairo_output_stream_write (base85_stream
, data
, length
);
2390 case CAIRO_PS_COMPRESS_LZW
:
2391 /* XXX: Should fix cairo-lzw to provide a stream-based interface
2393 data_compressed_size
= length
;
2394 data_compressed
= _cairo_lzw_compress ((unsigned char*)data
, &data_compressed_size
);
2395 if (unlikely (data_compressed
== NULL
)) {
2396 status
= _cairo_output_stream_destroy (string_array_stream
);
2397 status
= _cairo_output_stream_destroy (base85_stream
);
2398 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
2400 _cairo_output_stream_write (base85_stream
, data_compressed
, data_compressed_size
);
2401 free (data_compressed
);
2404 case CAIRO_PS_COMPRESS_DEFLATE
:
2405 deflate_stream
= _cairo_deflate_stream_create (base85_stream
);
2406 if (_cairo_output_stream_get_status (deflate_stream
)) {
2407 return _cairo_output_stream_destroy (deflate_stream
);
2409 _cairo_output_stream_write (deflate_stream
, data
, length
);
2410 status
= _cairo_output_stream_destroy (deflate_stream
);
2411 if (unlikely (status
)) {
2412 status2
= _cairo_output_stream_destroy (string_array_stream
);
2413 status2
= _cairo_output_stream_destroy (base85_stream
);
2414 return _cairo_output_stream_destroy (deflate_stream
);
2418 status
= _cairo_output_stream_destroy (base85_stream
);
2420 /* Mark end of base85 data */
2421 _cairo_output_stream_printf (string_array_stream
, "~>");
2422 status2
= _cairo_output_stream_destroy (string_array_stream
);
2423 if (status
== CAIRO_STATUS_SUCCESS
)
2429 static cairo_status_t
2430 _cairo_ps_surface_emit_image (cairo_ps_surface_t
*surface
,
2431 cairo_image_surface_t
*image_surf
,
2432 cairo_operator_t op
,
2433 cairo_filter_t filter
,
2434 cairo_bool_t stencil_mask
)
2436 cairo_status_t status
;
2437 unsigned char *data
;
2438 unsigned long data_size
;
2439 cairo_image_surface_t
*ps_image
;
2441 cairo_image_transparency_t transparency
;
2442 cairo_bool_t use_mask
;
2446 cairo_image_color_t color
;
2447 const char *interpolate
;
2448 cairo_ps_compress_t compress
;
2449 const char *compress_filter
;
2450 cairo_image_surface_t
*image
;
2452 if (image_surf
->base
.status
)
2453 return image_surf
->base
.status
;
2456 if (image
->format
!= CAIRO_FORMAT_RGB24
&&
2457 image
->format
!= CAIRO_FORMAT_ARGB32
&&
2458 image
->format
!= CAIRO_FORMAT_A8
&&
2459 image
->format
!= CAIRO_FORMAT_A1
)
2461 cairo_surface_t
*surf
;
2462 cairo_surface_pattern_t pattern
;
2464 surf
= _cairo_image_surface_create_with_content (image_surf
->base
.content
,
2466 image_surf
->height
);
2467 image
= (cairo_image_surface_t
*) surf
;
2469 status
= surf
->status
;
2473 _cairo_pattern_init_for_surface (&pattern
, &image_surf
->base
);
2474 status
= _cairo_surface_paint (surf
,
2475 CAIRO_OPERATOR_SOURCE
, &pattern
.base
,
2477 _cairo_pattern_fini (&pattern
.base
);
2478 if (unlikely (status
))
2485 case CAIRO_FILTER_GOOD
:
2486 case CAIRO_FILTER_BEST
:
2487 case CAIRO_FILTER_BILINEAR
:
2488 interpolate
= "true";
2490 case CAIRO_FILTER_FAST
:
2491 case CAIRO_FILTER_NEAREST
:
2492 case CAIRO_FILTER_GAUSSIAN
:
2493 interpolate
= "false";
2499 color
= CAIRO_IMAGE_IS_MONOCHROME
;
2500 transparency
= CAIRO_IMAGE_HAS_BILEVEL_ALPHA
;
2502 transparency
= _cairo_image_analyze_transparency (image
);
2504 /* PostScript can not represent the alpha channel, so we blend the
2505 current image over a white (or black for CONTENT_COLOR
2506 surfaces) RGB surface to eliminate it. */
2508 if (op
== CAIRO_OPERATOR_SOURCE
||
2509 transparency
== CAIRO_IMAGE_HAS_ALPHA
||
2510 (transparency
== CAIRO_IMAGE_HAS_BILEVEL_ALPHA
&&
2511 surface
->ps_level
== CAIRO_PS_LEVEL_2
))
2513 status
= _cairo_ps_surface_flatten_image_transparency (surface
,
2516 if (unlikely (status
))
2520 } else if (transparency
== CAIRO_IMAGE_IS_OPAQUE
) {
2522 } else { /* transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA */
2526 color
= _cairo_image_analyze_color (ps_image
);
2529 /* Type 2 (mask and image interleaved) has the mask and image
2530 * samples interleaved by row. The mask row is first, one bit per
2531 * pixel with (bit 7 first). The row is padded to byte
2532 * boundaries. The image data is 3 bytes per pixel RGB format. */
2535 case CAIRO_IMAGE_UNKNOWN_COLOR
:
2537 case CAIRO_IMAGE_IS_COLOR
:
2538 data_size
= ps_image
->width
* 3;
2540 case CAIRO_IMAGE_IS_GRAYSCALE
:
2541 data_size
= ps_image
->width
;
2543 case CAIRO_IMAGE_IS_MONOCHROME
:
2544 data_size
= (ps_image
->width
+ 7)/8;
2548 data_size
+= (ps_image
->width
+ 7)/8;
2549 data_size
*= ps_image
->height
;
2550 data
= malloc (data_size
);
2551 if (unlikely (data
== NULL
)) {
2552 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
2557 for (y
= 0; y
< ps_image
->height
; y
++) {
2558 if (stencil_mask
|| use_mask
) {
2560 if (ps_image
->format
== CAIRO_FORMAT_A1
) {
2561 pixel8
= (uint8_t *) (ps_image
->data
+ y
* ps_image
->stride
);
2563 for (x
= 0; x
< (ps_image
->width
+ 7) / 8; x
++, pixel8
++) {
2565 a
= CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (a
);
2569 pixel8
= (uint8_t *) (ps_image
->data
+ y
* ps_image
->stride
);
2570 pixel32
= (uint32_t *) (ps_image
->data
+ y
* ps_image
->stride
);
2572 for (x
= 0; x
< ps_image
->width
; x
++) {
2573 if (ps_image
->format
== CAIRO_FORMAT_ARGB32
) {
2574 a
= (*pixel32
& 0xff000000) >> 24;
2581 if (transparency
== CAIRO_IMAGE_HAS_ALPHA
) {
2583 } else { /* transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA or CAIRO_IMAGE_IS_OPAQUE */
2587 data
[i
] |= (1 << bit
);
2603 pixel32
= (uint32_t *) (ps_image
->data
+ y
* ps_image
->stride
);
2605 for (x
= 0; x
< ps_image
->width
; x
++, pixel32
++) {
2608 if (ps_image
->format
== CAIRO_FORMAT_ARGB32
) {
2609 /* At this point ARGB32 images are either opaque or
2610 * bilevel alpha so we don't need to unpremultiply. */
2611 if (((*pixel32
& 0xff000000) >> 24) == 0) {
2614 r
= (*pixel32
& 0x00ff0000) >> 16;
2615 g
= (*pixel32
& 0x0000ff00) >> 8;
2616 b
= (*pixel32
& 0x000000ff) >> 0;
2618 } else if (ps_image
->format
== CAIRO_FORMAT_RGB24
) {
2619 r
= (*pixel32
& 0x00ff0000) >> 16;
2620 g
= (*pixel32
& 0x0000ff00) >> 8;
2621 b
= (*pixel32
& 0x000000ff) >> 0;
2627 case CAIRO_IMAGE_IS_COLOR
:
2628 case CAIRO_IMAGE_UNKNOWN_COLOR
:
2634 case CAIRO_IMAGE_IS_GRAYSCALE
:
2638 case CAIRO_IMAGE_IS_MONOCHROME
:
2642 data
[i
] |= (1 << bit
);
2655 if (surface
->ps_level
== CAIRO_PS_LEVEL_2
) {
2656 compress
= CAIRO_PS_COMPRESS_LZW
;
2657 compress_filter
= "LZWDecode";
2659 compress
= CAIRO_PS_COMPRESS_DEFLATE
;
2660 compress_filter
= "FlateDecode";
2661 surface
->ps_level_used
= CAIRO_PS_LEVEL_3
;
2664 if (surface
->use_string_datasource
) {
2665 /* Emit the image data as a base85-encoded string which will
2666 * be used as the data source for the image operator later. */
2667 _cairo_output_stream_printf (surface
->stream
,
2668 "/CairoImageData [\n");
2670 status
= _cairo_ps_surface_emit_base85_string (surface
,
2675 if (unlikely (status
))
2678 _cairo_output_stream_printf (surface
->stream
,
2680 _cairo_output_stream_printf (surface
->stream
,
2681 "/CairoImageDataIndex 0 def\n");
2685 _cairo_output_stream_printf (surface
->stream
,
2686 "%s setcolorspace\n"
2687 "5 dict dup begin\n"
2688 " /ImageType 3 def\n"
2689 " /InterleaveType 2 def\n"
2690 " /DataDict 8 dict def\n"
2692 " /ImageType 1 def\n"
2695 " /Interpolate %s def\n"
2696 " /BitsPerComponent %d def\n"
2697 " /Decode [ %s ] def\n",
2698 color
== CAIRO_IMAGE_IS_COLOR
? "/DeviceRGB" : "/DeviceGray",
2702 color
== CAIRO_IMAGE_IS_MONOCHROME
? 1 : 8,
2703 color
== CAIRO_IMAGE_IS_COLOR
? "0 1 0 1 0 1" : "0 1");
2705 if (surface
->use_string_datasource
) {
2706 _cairo_output_stream_printf (surface
->stream
,
2708 " CairoImageData CairoImageDataIndex get\n"
2709 " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2710 " CairoImageDataIndex CairoImageData length 1 sub gt\n"
2711 " { /CairoImageDataIndex 0 def } if\n"
2712 " } /ASCII85Decode filter /%s filter def\n",
2715 _cairo_output_stream_printf (surface
->stream
,
2716 " /DataSource currentfile /ASCII85Decode filter /%s filter def\n",
2720 _cairo_output_stream_printf (surface
->stream
,
2721 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2723 " /MaskDict 8 dict def\n"
2725 " /ImageType 1 def\n"
2728 " /Interpolate %s def\n"
2729 " /BitsPerComponent 1 def\n"
2730 " /Decode [ 1 0 ] def\n"
2731 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2741 if (!stencil_mask
) {
2742 _cairo_output_stream_printf (surface
->stream
,
2743 "%s setcolorspace\n",
2744 color
== CAIRO_IMAGE_IS_COLOR
? "/DeviceRGB" : "/DeviceGray");
2746 _cairo_output_stream_printf (surface
->stream
,
2747 "8 dict dup begin\n"
2748 " /ImageType 1 def\n"
2751 " /Interpolate %s def\n"
2752 " /BitsPerComponent %d def\n"
2753 " /Decode [ %s ] def\n",
2757 color
== CAIRO_IMAGE_IS_MONOCHROME
? 1 : 8,
2758 stencil_mask
? "1 0" : color
== CAIRO_IMAGE_IS_COLOR
? "0 1 0 1 0 1" : "0 1");
2759 if (surface
->use_string_datasource
) {
2760 _cairo_output_stream_printf (surface
->stream
,
2762 " CairoImageData CairoImageDataIndex get\n"
2763 " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2764 " CairoImageDataIndex CairoImageData length 1 sub gt\n"
2765 " { /CairoImageDataIndex 0 def } if\n"
2766 " } /ASCII85Decode filter /%s filter def\n",
2769 _cairo_output_stream_printf (surface
->stream
,
2770 " /DataSource currentfile /ASCII85Decode filter /%s filter def\n",
2774 _cairo_output_stream_printf (surface
->stream
,
2775 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2779 stencil_mask
? "imagemask" : "image");
2782 if (!surface
->use_string_datasource
) {
2783 /* Emit the image data as a base85-encoded string which will
2784 * be used as the data source for the image operator. */
2785 status
= _cairo_ps_surface_emit_base85_string (surface
,
2790 _cairo_output_stream_printf (surface
->stream
, "\n");
2792 status
= CAIRO_STATUS_SUCCESS
;
2799 if (!use_mask
&& ps_image
!= image
)
2800 cairo_surface_destroy (&ps_image
->base
);
2803 if (image
!= image_surf
)
2804 cairo_surface_destroy (&image
->base
);
2809 static cairo_status_t
2810 _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t
*surface
,
2811 cairo_surface_t
*source
,
2815 cairo_status_t status
;
2816 const unsigned char *mime_data
;
2817 unsigned long mime_data_length
;
2818 cairo_image_info_t info
;
2819 const char *colorspace
;
2822 cairo_surface_get_mime_data (source
, CAIRO_MIME_TYPE_JPEG
,
2823 &mime_data
, &mime_data_length
);
2824 if (unlikely (source
->status
))
2825 return source
->status
;
2826 if (mime_data
== NULL
)
2827 return CAIRO_INT_STATUS_UNSUPPORTED
;
2829 status
= _cairo_image_info_get_jpeg_info (&info
, mime_data
, mime_data_length
);
2830 if (unlikely (status
))
2833 switch (info
.num_components
) {
2835 colorspace
= "/DeviceGray";
2839 colorspace
= "/DeviceRGB";
2840 decode
= "0 1 0 1 0 1";
2843 colorspace
= "/DeviceCMYK";
2844 decode
= "0 1 0 1 0 1 0 1";
2847 return CAIRO_INT_STATUS_UNSUPPORTED
;
2850 if (surface
->use_string_datasource
) {
2851 /* Emit the image data as a base85-encoded string which will
2852 * be used as the data source for the image operator later. */
2853 _cairo_output_stream_printf (surface
->stream
,
2854 "/CairoImageData [\n");
2856 status
= _cairo_ps_surface_emit_base85_string (surface
,
2859 CAIRO_PS_COMPRESS_NONE
,
2861 if (unlikely (status
))
2864 _cairo_output_stream_printf (surface
->stream
,
2866 _cairo_output_stream_printf (surface
->stream
,
2867 "/CairoImageDataIndex 0 def\n");
2870 _cairo_output_stream_printf (surface
->stream
,
2871 "%s setcolorspace\n"
2872 "8 dict dup begin\n"
2873 " /ImageType 1 def\n"
2876 " /BitsPerComponent %d def\n"
2877 " /Decode [ %s ] def\n",
2881 info
.bits_per_component
,
2884 if (surface
->use_string_datasource
) {
2885 _cairo_output_stream_printf (surface
->stream
,
2887 " CairoImageData CairoImageDataIndex get\n"
2888 " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2889 " CairoImageDataIndex CairoImageData length 1 sub gt\n"
2890 " { /CairoImageDataIndex 0 def } if\n"
2891 " } /ASCII85Decode filter /DCTDecode filter def\n");
2893 _cairo_output_stream_printf (surface
->stream
,
2894 " /DataSource currentfile /ASCII85Decode filter /DCTDecode filter def\n");
2897 _cairo_output_stream_printf (surface
->stream
,
2898 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2903 if (!surface
->use_string_datasource
) {
2904 /* Emit the image data as a base85-encoded string which will
2905 * be used as the data source for the image operator. */
2906 status
= _cairo_ps_surface_emit_base85_string (surface
,
2909 CAIRO_PS_COMPRESS_NONE
,
2916 static cairo_status_t
2917 _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t
*surface
,
2918 cairo_surface_t
*recording_surface
)
2920 double old_width
, old_height
;
2921 cairo_matrix_t old_cairo_to_ps
;
2922 cairo_content_t old_content
;
2923 cairo_rectangle_int_t old_page_bbox
;
2924 cairo_surface_t
*free_me
= NULL
;
2925 cairo_surface_clipper_t old_clipper
;
2927 cairo_int_status_t status
;
2929 old_content
= surface
->content
;
2930 old_width
= surface
->width
;
2931 old_height
= surface
->height
;
2932 old_page_bbox
= surface
->page_bbox
;
2933 old_cairo_to_ps
= surface
->cairo_to_ps
;
2934 old_clipper
= surface
->clipper
;
2935 _cairo_surface_clipper_init (&surface
->clipper
,
2936 _cairo_ps_surface_clipper_intersect_clip_path
);
2938 if (_cairo_surface_is_snapshot (recording_surface
))
2939 free_me
= recording_surface
= _cairo_surface_snapshot_get_target (recording_surface
);
2942 _cairo_recording_surface_get_bbox ((cairo_recording_surface_t
*) recording_surface
,
2945 if (unlikely (status
))
2949 _cairo_output_stream_printf (surface
->stream
,
2950 "%% _cairo_ps_surface_emit_recording_surface (%f, %f), (%f, %f)\n",
2951 _cairo_fixed_to_double (bbox
.p1
.x
),
2952 _cairo_fixed_to_double (bbox
.p1
.y
),
2953 _cairo_fixed_to_double (bbox
.p2
.x
),
2954 _cairo_fixed_to_double (bbox
.p2
.y
));
2957 surface
->width
= _cairo_fixed_to_double (bbox
.p2
.x
- bbox
.p1
.x
);
2958 surface
->height
= _cairo_fixed_to_double (bbox
.p2
.y
- bbox
.p1
.y
);
2959 _cairo_box_round_to_rectangle (&bbox
, &surface
->page_bbox
);
2961 surface
->current_pattern_is_solid_color
= FALSE
;
2962 _cairo_pdf_operators_reset (&surface
->pdf_operators
);
2963 cairo_matrix_init (&surface
->cairo_to_ps
, 1, 0, 0, -1, 0, surface
->height
);
2964 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface
->pdf_operators
,
2965 &surface
->cairo_to_ps
);
2966 _cairo_output_stream_printf (surface
->stream
, " q\n");
2968 if (recording_surface
->content
== CAIRO_CONTENT_COLOR
) {
2969 surface
->content
= CAIRO_CONTENT_COLOR
;
2970 _cairo_output_stream_printf (surface
->stream
,
2971 " 0 g %d %d %d %d rectfill\n",
2972 surface
->page_bbox
.x
,
2973 surface
->page_bbox
.y
,
2974 surface
->page_bbox
.width
,
2975 surface
->page_bbox
.height
);
2978 status
= _cairo_recording_surface_replay_region (recording_surface
,
2981 CAIRO_RECORDING_REGION_NATIVE
);
2982 assert (status
!= CAIRO_INT_STATUS_UNSUPPORTED
);
2983 if (unlikely (status
))
2986 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
2987 if (unlikely (status
))
2990 _cairo_output_stream_printf (surface
->stream
, " Q\n");
2992 _cairo_surface_clipper_reset (&surface
->clipper
);
2993 surface
->clipper
= old_clipper
;
2994 surface
->content
= old_content
;
2995 surface
->width
= old_width
;
2996 surface
->height
= old_height
;
2997 surface
->page_bbox
= old_page_bbox
;
2998 surface
->current_pattern_is_solid_color
= FALSE
;
2999 _cairo_pdf_operators_reset (&surface
->pdf_operators
);
3000 surface
->cairo_to_ps
= old_cairo_to_ps
;
3002 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface
->pdf_operators
,
3003 &surface
->cairo_to_ps
);
3006 cairo_surface_destroy (free_me
);
3010 static cairo_int_status_t
3011 _cairo_ps_surface_emit_recording_subsurface (cairo_ps_surface_t
*surface
,
3012 cairo_surface_t
*recording_surface
,
3013 const cairo_rectangle_int_t
*extents
)
3015 double old_width
, old_height
;
3016 cairo_matrix_t old_cairo_to_ps
;
3017 cairo_content_t old_content
;
3018 cairo_rectangle_int_t old_page_bbox
;
3019 cairo_surface_clipper_t old_clipper
;
3020 cairo_surface_t
*free_me
= NULL
;
3021 cairo_int_status_t status
;
3023 old_content
= surface
->content
;
3024 old_width
= surface
->width
;
3025 old_height
= surface
->height
;
3026 old_page_bbox
= surface
->page_bbox
;
3027 old_cairo_to_ps
= surface
->cairo_to_ps
;
3028 old_clipper
= surface
->clipper
;
3029 _cairo_surface_clipper_init (&surface
->clipper
,
3030 _cairo_ps_surface_clipper_intersect_clip_path
);
3033 _cairo_output_stream_printf (surface
->stream
,
3034 "%% _cairo_ps_surface_emit_recording_subsurface (%d, %d), (%d, %d)\n",
3035 extents
->x
, extents
->y
,
3036 extents
->width
, extents
->height
);
3039 surface
->page_bbox
.x
= surface
->page_bbox
.y
= 0;
3040 surface
->page_bbox
.width
= surface
->width
= extents
->width
;
3041 surface
->page_bbox
.height
= surface
->height
= extents
->height
;
3043 surface
->current_pattern_is_solid_color
= FALSE
;
3044 _cairo_pdf_operators_reset (&surface
->pdf_operators
);
3045 cairo_matrix_init (&surface
->cairo_to_ps
, 1, 0, 0, -1, 0, surface
->height
);
3046 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface
->pdf_operators
,
3047 &surface
->cairo_to_ps
);
3048 _cairo_output_stream_printf (surface
->stream
, " q\n");
3050 if (_cairo_surface_is_snapshot (recording_surface
))
3051 free_me
= recording_surface
= _cairo_surface_snapshot_get_target (recording_surface
);
3053 if (recording_surface
->content
== CAIRO_CONTENT_COLOR
) {
3054 surface
->content
= CAIRO_CONTENT_COLOR
;
3055 _cairo_output_stream_printf (surface
->stream
,
3056 " 0 g %d %d %d %d rectfill\n",
3057 surface
->page_bbox
.x
,
3058 surface
->page_bbox
.y
,
3059 surface
->page_bbox
.width
,
3060 surface
->page_bbox
.height
);
3063 status
= _cairo_recording_surface_replay_region (recording_surface
,
3066 CAIRO_RECORDING_REGION_NATIVE
);
3067 assert (status
!= CAIRO_INT_STATUS_UNSUPPORTED
);
3068 if (unlikely (status
))
3071 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
3072 if (unlikely (status
))
3075 _cairo_output_stream_printf (surface
->stream
, " Q\n");
3077 _cairo_surface_clipper_reset (&surface
->clipper
);
3078 surface
->clipper
= old_clipper
;
3079 surface
->content
= old_content
;
3080 surface
->width
= old_width
;
3081 surface
->height
= old_height
;
3082 surface
->page_bbox
= old_page_bbox
;
3083 surface
->current_pattern_is_solid_color
= FALSE
;
3084 _cairo_pdf_operators_reset (&surface
->pdf_operators
);
3085 surface
->cairo_to_ps
= old_cairo_to_ps
;
3087 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface
->pdf_operators
,
3088 &surface
->cairo_to_ps
);
3091 cairo_surface_destroy (free_me
);
3096 _cairo_ps_surface_flatten_transparency (cairo_ps_surface_t
*surface
,
3097 const cairo_color_t
*color
,
3103 *green
= color
->green
;
3104 *blue
= color
->blue
;
3106 if (! CAIRO_COLOR_IS_OPAQUE (color
)) {
3107 *red
*= color
->alpha
;
3108 *green
*= color
->alpha
;
3109 *blue
*= color
->alpha
;
3110 if (surface
->content
== CAIRO_CONTENT_COLOR_ALPHA
) {
3111 double one_minus_alpha
= 1. - color
->alpha
;
3112 *red
+= one_minus_alpha
;
3113 *green
+= one_minus_alpha
;
3114 *blue
+= one_minus_alpha
;
3120 _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t
*surface
,
3121 cairo_solid_pattern_t
*pattern
)
3123 double red
, green
, blue
;
3125 _cairo_ps_surface_flatten_transparency (surface
, &pattern
->color
, &red
, &green
, &blue
);
3127 if (color_is_gray (red
, green
, blue
))
3128 _cairo_output_stream_printf (surface
->stream
,
3132 _cairo_output_stream_printf (surface
->stream
,
3137 static cairo_status_t
3138 _cairo_ps_surface_emit_surface (cairo_ps_surface_t
*surface
,
3139 cairo_pattern_t
*source_pattern
,
3140 cairo_surface_t
*source_surface
,
3141 cairo_operator_t op
,
3144 cairo_bool_t stencil_mask
)
3146 cairo_int_status_t status
;
3148 if (source_pattern
->type
== CAIRO_PATTERN_TYPE_SURFACE
&&
3149 source_pattern
->extend
!= CAIRO_EXTEND_PAD
)
3151 cairo_surface_t
*surf
= ((cairo_surface_pattern_t
*) source_pattern
)->surface
;
3153 status
= _cairo_ps_surface_emit_jpeg_image (surface
, surf
, width
, height
);
3154 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
3158 if (source_surface
->type
== CAIRO_SURFACE_TYPE_RECORDING
) {
3159 if (source_surface
->backend
->type
== CAIRO_SURFACE_TYPE_SUBSURFACE
) {
3160 cairo_surface_subsurface_t
*sub
= (cairo_surface_subsurface_t
*) source_surface
;
3161 status
= _cairo_ps_surface_emit_recording_subsurface (surface
, sub
->target
, &sub
->extents
);
3163 status
= _cairo_ps_surface_emit_recording_surface (surface
, source_surface
);
3166 cairo_image_surface_t
*image
= (cairo_image_surface_t
*) source_surface
;
3168 status
= _cairo_ps_surface_emit_image (surface
, image
,
3169 op
, source_pattern
->filter
, stencil_mask
);
3177 _path_fixed_init_rectangle (cairo_path_fixed_t
*path
,
3178 cairo_rectangle_int_t
*rect
)
3180 cairo_status_t status
;
3182 _cairo_path_fixed_init (path
);
3184 status
= _cairo_path_fixed_move_to (path
,
3185 _cairo_fixed_from_int (rect
->x
),
3186 _cairo_fixed_from_int (rect
->y
));
3187 assert (status
== CAIRO_STATUS_SUCCESS
);
3188 status
= _cairo_path_fixed_rel_line_to (path
,
3189 _cairo_fixed_from_int (rect
->width
),
3190 _cairo_fixed_from_int (0));
3191 assert (status
== CAIRO_STATUS_SUCCESS
);
3192 status
= _cairo_path_fixed_rel_line_to (path
,
3193 _cairo_fixed_from_int (0),
3194 _cairo_fixed_from_int (rect
->height
));
3195 assert (status
== CAIRO_STATUS_SUCCESS
);
3196 status
= _cairo_path_fixed_rel_line_to (path
,
3197 _cairo_fixed_from_int (-rect
->width
),
3198 _cairo_fixed_from_int (0));
3199 assert (status
== CAIRO_STATUS_SUCCESS
);
3201 status
= _cairo_path_fixed_close_path (path
);
3202 assert (status
== CAIRO_STATUS_SUCCESS
);
3205 static cairo_status_t
3206 _cairo_ps_surface_paint_surface (cairo_ps_surface_t
*surface
,
3207 cairo_pattern_t
*pattern
,
3208 cairo_rectangle_int_t
*extents
,
3209 cairo_operator_t op
,
3210 cairo_bool_t stencil_mask
)
3212 cairo_status_t status
;
3214 cairo_matrix_t cairo_p2d
, ps_p2d
;
3215 cairo_path_fixed_t path
;
3216 double x_offset
, y_offset
;
3217 cairo_surface_t
*source
;
3218 cairo_image_surface_t
*image
= NULL
;
3221 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
3222 if (unlikely (status
))
3225 status
= _cairo_ps_surface_acquire_source_surface_from_pattern (surface
,
3229 &x_offset
, &y_offset
,
3232 if (unlikely (status
))
3235 if (pattern
->extend
== CAIRO_EXTEND_PAD
&&
3236 pattern
->type
== CAIRO_PATTERN_TYPE_SURFACE
&&
3237 ((cairo_surface_pattern_t
*)pattern
)->surface
->type
== CAIRO_SURFACE_TYPE_IMAGE
) {
3238 cairo_image_surface_t
*img
;
3240 img
= (cairo_image_surface_t
*) source
;
3241 status
= _cairo_ps_surface_create_padded_image_from_image (surface
,
3246 &x_offset
, &y_offset
,
3248 if (unlikely (status
))
3249 goto release_source
;
3252 _path_fixed_init_rectangle (&path
, extents
);
3253 status
= _cairo_pdf_operators_clip (&surface
->pdf_operators
,
3255 CAIRO_FILL_RULE_WINDING
);
3256 _cairo_path_fixed_fini (&path
);
3257 if (unlikely (status
))
3258 goto release_source
;
3260 cairo_p2d
= pattern
->matrix
;
3262 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_FALLBACK
) {
3263 double x_scale
= cairo_p2d
.xx
;
3264 double y_scale
= cairo_p2d
.yy
;
3266 _cairo_output_stream_printf (surface
->stream
,
3267 "%% Fallback Image: x=%f y=%f w=%d h=%d ",
3268 -cairo_p2d
.x0
/x_scale
,
3269 -cairo_p2d
.y0
/y_scale
,
3270 (int)(width
/x_scale
),
3271 (int)(height
/y_scale
));
3272 if (x_scale
== y_scale
) {
3273 _cairo_output_stream_printf (surface
->stream
,
3277 _cairo_output_stream_printf (surface
->stream
,
3282 _cairo_output_stream_printf (surface
->stream
,
3284 (long)width
*height
*3);
3286 if (op
== CAIRO_OPERATOR_SOURCE
) {
3287 _cairo_output_stream_printf (surface
->stream
,
3288 "%d g 0 0 %f %f rectfill\n",
3289 surface
->content
== CAIRO_CONTENT_COLOR
? 0 : 1,
3295 status
= cairo_matrix_invert (&cairo_p2d
);
3296 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3297 assert (status
== CAIRO_STATUS_SUCCESS
);
3299 ps_p2d
= surface
->cairo_to_ps
;
3300 cairo_matrix_multiply (&ps_p2d
, &cairo_p2d
, &ps_p2d
);
3301 cairo_matrix_translate (&ps_p2d
, x_offset
, y_offset
);
3302 cairo_matrix_translate (&ps_p2d
, 0.0, height
);
3303 cairo_matrix_scale (&ps_p2d
, 1.0, -1.0);
3305 if (! _cairo_matrix_is_identity (&ps_p2d
)) {
3306 _cairo_output_stream_printf (surface
->stream
, "[ ");
3307 _cairo_output_stream_print_matrix (surface
->stream
, &ps_p2d
);
3308 _cairo_output_stream_printf (surface
->stream
, " ] concat\n");
3311 status
= _cairo_ps_surface_emit_surface (surface
,
3313 image
? &image
->base
: source
,
3320 cairo_surface_destroy (&image
->base
);
3322 _cairo_ps_surface_release_source_surface_from_pattern (surface
, pattern
, source
, image_extra
);
3327 static cairo_status_t
3328 _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t
*surface
,
3329 cairo_pattern_t
*pattern
,
3330 cairo_rectangle_int_t
*extents
,
3331 cairo_operator_t op
)
3333 cairo_status_t status
;
3334 int pattern_width
= 0; /* squelch bogus compiler warning */
3335 int pattern_height
= 0; /* squelch bogus compiler warning */
3336 double xstep
, ystep
;
3337 cairo_matrix_t cairo_p2d
, ps_p2d
;
3338 cairo_bool_t old_use_string_datasource
;
3339 double x_offset
, y_offset
;
3340 cairo_surface_t
*source
;
3341 cairo_image_surface_t
*image
= NULL
;
3344 cairo_p2d
= pattern
->matrix
;
3345 status
= cairo_matrix_invert (&cairo_p2d
);
3346 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3347 assert (status
== CAIRO_STATUS_SUCCESS
);
3349 status
= _cairo_ps_surface_acquire_source_surface_from_pattern (surface
,
3352 &pattern_width
, &pattern_height
,
3353 &x_offset
, &y_offset
,
3356 if (unlikely (status
))
3359 if (pattern
->extend
== CAIRO_EXTEND_PAD
) {
3360 cairo_image_surface_t
*img
;
3362 assert (source
->type
== CAIRO_SURFACE_TYPE_IMAGE
);
3363 img
= (cairo_image_surface_t
*) source
;
3364 status
= _cairo_ps_surface_create_padded_image_from_image (surface
,
3368 &pattern_width
, &pattern_height
,
3369 &x_offset
, &y_offset
,
3371 if (unlikely (status
))
3372 goto release_source
;
3374 if (unlikely (status
))
3375 goto release_source
;
3377 switch (pattern
->extend
) {
3378 case CAIRO_EXTEND_PAD
:
3379 case CAIRO_EXTEND_NONE
:
3381 /* In PS/PDF, (as far as I can tell), all patterns are
3382 * repeating. So we support cairo's EXTEND_NONE semantics
3383 * by setting the repeat step size to a size large enough
3384 * to guarantee that no more than a single occurrence will
3387 * First, map the surface extents into pattern space (since
3388 * xstep and ystep are in pattern space). Then use an upper
3389 * bound on the length of the diagonal of the pattern image
3390 * and the surface as repeat size. This guarantees to never
3393 double x1
= 0.0, y1
= 0.0;
3394 double x2
= surface
->width
, y2
= surface
->height
;
3395 _cairo_matrix_transform_bounding_box (&pattern
->matrix
,
3399 /* Rather than computing precise bounds of the union, just
3400 * add the surface extents unconditionally. We only
3401 * required an answer that's large enough, we don't really
3402 * care if it's not as tight as possible.*/
3403 xstep
= ystep
= ceil ((x2
- x1
) + (y2
- y1
) +
3404 pattern_width
+ pattern_height
);
3407 case CAIRO_EXTEND_REPEAT
:
3408 xstep
= pattern_width
;
3409 ystep
= pattern_height
;
3411 case CAIRO_EXTEND_REFLECT
:
3412 xstep
= pattern_width
*2;
3413 ystep
= pattern_height
*2;
3415 /* All the rest (if any) should have been analyzed away, so these
3416 * cases should be unreachable. */
3423 _cairo_output_stream_printf (surface
->stream
,
3424 "/CairoPattern {\n");
3426 old_use_string_datasource
= surface
->use_string_datasource
;
3427 surface
->use_string_datasource
= TRUE
;
3428 if (op
== CAIRO_OPERATOR_SOURCE
) {
3429 _cairo_output_stream_printf (surface
->stream
,
3430 "%d g 0 0 %f %f rectfill\n",
3431 surface
->content
== CAIRO_CONTENT_COLOR
? 0 : 1,
3434 status
= _cairo_ps_surface_emit_surface (surface
,
3436 image
? &image
->base
: source
,
3438 pattern_width
, pattern_height
, FALSE
);
3439 if (unlikely (status
))
3440 goto release_source
;
3442 surface
->use_string_datasource
= old_use_string_datasource
;
3443 _cairo_output_stream_printf (surface
->stream
,
3446 _cairo_output_stream_printf (surface
->stream
,
3447 "<< /PatternType 1\n"
3449 " /TilingType 1\n");
3450 _cairo_output_stream_printf (surface
->stream
,
3451 " /XStep %f /YStep %f\n",
3454 if (pattern
->extend
== CAIRO_EXTEND_REFLECT
) {
3455 _cairo_output_stream_printf (surface
->stream
,
3456 " /BBox [0 0 %d %d]\n"
3458 " pop CairoPattern\n"
3459 " [-1 0 0 1 %d 0] concat CairoPattern\n"
3460 " [ 1 0 0 -1 0 %d] concat CairoPattern\n"
3461 " [-1 0 0 1 %d 0] concat CairoPattern\n"
3464 pattern_width
*2, pattern_height
*2,
3469 if (op
== CAIRO_OPERATOR_SOURCE
) {
3470 _cairo_output_stream_printf (surface
->stream
,
3471 " /BBox [0 0 %f %f]\n",
3474 _cairo_output_stream_printf (surface
->stream
,
3475 " /BBox [0 0 %d %d]\n",
3476 pattern_width
, pattern_height
);
3478 _cairo_output_stream_printf (surface
->stream
,
3479 " /PaintProc { pop CairoPattern }\n");
3482 _cairo_output_stream_printf (surface
->stream
,
3485 cairo_p2d
= pattern
->matrix
;
3486 status
= cairo_matrix_invert (&cairo_p2d
);
3487 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3488 assert (status
== CAIRO_STATUS_SUCCESS
);
3490 cairo_matrix_init_identity (&ps_p2d
);
3491 cairo_matrix_translate (&ps_p2d
, 0.0, surface
->height
);
3492 cairo_matrix_scale (&ps_p2d
, 1.0, -1.0);
3493 cairo_matrix_multiply (&ps_p2d
, &cairo_p2d
, &ps_p2d
);
3494 cairo_matrix_translate (&ps_p2d
, 0.0, pattern_height
);
3495 cairo_matrix_scale (&ps_p2d
, 1.0, -1.0);
3497 _cairo_output_stream_printf (surface
->stream
, "[ ");
3498 _cairo_output_stream_print_matrix (surface
->stream
, &ps_p2d
);
3499 _cairo_output_stream_printf (surface
->stream
,
3501 "makepattern setpattern\n");
3505 cairo_surface_destroy (&image
->base
);
3507 _cairo_ps_surface_release_source_surface_from_pattern (surface
, pattern
, source
, image_extra
);
3512 typedef struct _cairo_ps_color_stop
{
3515 } cairo_ps_color_stop_t
;
3518 _cairo_ps_surface_emit_linear_colorgradient (cairo_ps_surface_t
*surface
,
3519 cairo_ps_color_stop_t
*stop1
,
3520 cairo_ps_color_stop_t
*stop2
)
3522 _cairo_output_stream_printf (surface
->stream
,
3523 " << /FunctionType 2\n"
3524 " /Domain [ 0 1 ]\n"
3525 " /C0 [ %f %f %f ]\n"
3526 " /C1 [ %f %f %f ]\n"
3538 _cairo_ps_surface_emit_stitched_colorgradient (cairo_ps_surface_t
*surface
,
3539 unsigned int n_stops
,
3540 cairo_ps_color_stop_t stops
[])
3544 _cairo_output_stream_printf (surface
->stream
,
3545 "<< /FunctionType 3\n"
3546 " /Domain [ 0 1 ]\n"
3548 for (i
= 0; i
< n_stops
- 1; i
++)
3549 _cairo_ps_surface_emit_linear_colorgradient (surface
, &stops
[i
], &stops
[i
+1]);
3551 _cairo_output_stream_printf (surface
->stream
, " ]\n");
3553 _cairo_output_stream_printf (surface
->stream
, " /Bounds [ ");
3554 for (i
= 1; i
< n_stops
-1; i
++)
3555 _cairo_output_stream_printf (surface
->stream
, "%f ", stops
[i
].offset
);
3556 _cairo_output_stream_printf (surface
->stream
, "]\n");
3558 _cairo_output_stream_printf (surface
->stream
, " /Encode [ 1 1 %d { pop 0 1 } for ]\n",
3561 _cairo_output_stream_printf (surface
->stream
, ">>\n");
3565 calc_gradient_color (cairo_ps_color_stop_t
*new_stop
,
3566 cairo_ps_color_stop_t
*stop1
,
3567 cairo_ps_color_stop_t
*stop2
)
3570 double offset
= stop1
->offset
/ (stop1
->offset
+ 1.0 - stop2
->offset
);
3572 for (i
= 0; i
< 4; i
++)
3573 new_stop
->color
[i
] = stop1
->color
[i
] + offset
*(stop2
->color
[i
] - stop1
->color
[i
]);
3576 #define COLOR_STOP_EPSILON 1e-6
3578 static cairo_status_t
3579 _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t
*surface
,
3580 cairo_gradient_pattern_t
*pattern
)
3582 cairo_ps_color_stop_t
*allstops
, *stops
;
3583 unsigned int i
, n_stops
;
3585 allstops
= _cairo_malloc_ab ((pattern
->n_stops
+ 2), sizeof (cairo_ps_color_stop_t
));
3586 if (unlikely (allstops
== NULL
))
3587 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
3589 stops
= &allstops
[1];
3590 n_stops
= pattern
->n_stops
;
3592 for (i
= 0; i
< n_stops
; i
++) {
3593 cairo_gradient_stop_t
*stop
= &pattern
->stops
[i
];
3595 stops
[i
].color
[0] = stop
->color
.red
;
3596 stops
[i
].color
[1] = stop
->color
.green
;
3597 stops
[i
].color
[2] = stop
->color
.blue
;
3598 stops
[i
].color
[3] = stop
->color
.alpha
;
3599 stops
[i
].offset
= pattern
->stops
[i
].offset
;
3602 if (pattern
->base
.extend
== CAIRO_EXTEND_REPEAT
||
3603 pattern
->base
.extend
== CAIRO_EXTEND_REFLECT
)
3605 if (stops
[0].offset
> COLOR_STOP_EPSILON
) {
3606 if (pattern
->base
.extend
== CAIRO_EXTEND_REFLECT
)
3607 memcpy (allstops
, stops
, sizeof (cairo_ps_color_stop_t
));
3609 calc_gradient_color (&allstops
[0], &stops
[0], &stops
[n_stops
-1]);
3613 stops
[0].offset
= 0.0;
3615 if (stops
[n_stops
-1].offset
< 1.0 - COLOR_STOP_EPSILON
) {
3616 if (pattern
->base
.extend
== CAIRO_EXTEND_REFLECT
) {
3617 memcpy (&stops
[n_stops
],
3618 &stops
[n_stops
- 1],
3619 sizeof (cairo_ps_color_stop_t
));
3621 calc_gradient_color (&stops
[n_stops
], &stops
[0], &stops
[n_stops
-1]);
3625 stops
[n_stops
-1].offset
= 1.0;
3628 for (i
= 0; i
< n_stops
; i
++) {
3629 double red
, green
, blue
;
3630 cairo_color_t color
;
3632 _cairo_color_init_rgba (&color
,
3637 _cairo_ps_surface_flatten_transparency (surface
, &color
,
3638 &red
, &green
, &blue
);
3639 stops
[i
].color
[0] = red
;
3640 stops
[i
].color
[1] = green
;
3641 stops
[i
].color
[2] = blue
;
3644 _cairo_output_stream_printf (surface
->stream
,
3645 "/CairoFunction\n");
3646 if (stops
[0].offset
== stops
[n_stops
- 1].offset
) {
3648 * The first and the last stops have the same offset, but we
3649 * don't want a function with an empty domain, because that
3650 * would provoke underdefined behaviour from rasterisers.
3651 * This can only happen with EXTEND_PAD, because EXTEND_NONE
3652 * is optimised into a clear pattern in cairo-gstate, and
3653 * REFLECT/REPEAT are always transformed to have the first
3654 * stop at t=0 and the last stop at t=1. Thus we want a step
3655 * function going from the first color to the last one.
3657 * This can be accomplished by stitching three functions:
3658 * - a constant first color function,
3659 * - a step from the first color to the last color (with empty domain)
3660 * - a constant last color function
3662 cairo_ps_color_stop_t pad_stops
[4];
3664 assert (pattern
->base
.extend
== CAIRO_EXTEND_PAD
);
3666 pad_stops
[0] = pad_stops
[1] = stops
[0];
3667 pad_stops
[2] = pad_stops
[3] = stops
[n_stops
- 1];
3669 pad_stops
[0].offset
= 0;
3670 pad_stops
[3].offset
= 1;
3672 _cairo_ps_surface_emit_stitched_colorgradient (surface
, 4, pad_stops
);
3673 } else if (n_stops
== 2) {
3674 /* no need for stitched function */
3675 _cairo_ps_surface_emit_linear_colorgradient (surface
, &stops
[0], &stops
[1]);
3677 /* multiple stops: stitch. XXX possible optimization: regulary spaced
3678 * stops do not require stitching. XXX */
3679 _cairo_ps_surface_emit_stitched_colorgradient (surface
, n_stops
, stops
);
3681 _cairo_output_stream_printf (surface
->stream
,
3686 return CAIRO_STATUS_SUCCESS
;
3689 static cairo_status_t
3690 _cairo_ps_surface_emit_repeating_function (cairo_ps_surface_t
*surface
,
3691 cairo_gradient_pattern_t
*pattern
,
3695 _cairo_output_stream_printf (surface
->stream
,
3697 "<< /FunctionType 3\n"
3698 " /Domain [ %d %d ]\n"
3699 " /Functions [ %d {CairoFunction} repeat ]\n"
3700 " /Bounds [ %d 1 %d {} for ]\n",
3707 if (pattern
->base
.extend
== CAIRO_EXTEND_REFLECT
) {
3708 _cairo_output_stream_printf (surface
->stream
, " /Encode [ %d 1 %d { 2 mod 0 eq {0 1} {1 0} ifelse } for ]\n",
3712 _cairo_output_stream_printf (surface
->stream
, " /Encode [ %d 1 %d { pop 0 1 } for ]\n",
3717 _cairo_output_stream_printf (surface
->stream
, ">> def\n");
3719 return CAIRO_STATUS_SUCCESS
;
3722 static cairo_status_t
3723 _cairo_ps_surface_emit_gradient (cairo_ps_surface_t
*surface
,
3724 cairo_gradient_pattern_t
*pattern
,
3725 cairo_bool_t is_ps_pattern
)
3727 cairo_matrix_t pat_to_ps
;
3728 cairo_circle_double_t start
, end
;
3730 cairo_status_t status
;
3732 assert (pattern
->n_stops
!= 0);
3734 status
= _cairo_ps_surface_emit_pattern_stops (surface
, pattern
);
3735 if (unlikely (status
))
3738 pat_to_ps
= pattern
->base
.matrix
;
3739 status
= cairo_matrix_invert (&pat_to_ps
);
3740 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3741 assert (status
== CAIRO_STATUS_SUCCESS
);
3742 cairo_matrix_multiply (&pat_to_ps
, &pat_to_ps
, &surface
->cairo_to_ps
);
3744 if (pattern
->base
.extend
== CAIRO_EXTEND_REPEAT
||
3745 pattern
->base
.extend
== CAIRO_EXTEND_REFLECT
)
3747 double bounds_x1
, bounds_x2
, bounds_y1
, bounds_y2
;
3748 double x_scale
, y_scale
, tolerance
;
3750 /* TODO: use tighter extents */
3753 bounds_x2
= surface
->width
;
3754 bounds_y2
= surface
->height
;
3755 _cairo_matrix_transform_bounding_box (&pattern
->base
.matrix
,
3756 &bounds_x1
, &bounds_y1
,
3757 &bounds_x2
, &bounds_y2
,
3760 x_scale
= surface
->base
.x_resolution
/ surface
->base
.x_fallback_resolution
;
3761 y_scale
= surface
->base
.y_resolution
/ surface
->base
.y_fallback_resolution
;
3763 tolerance
= fabs (_cairo_matrix_compute_determinant (&pattern
->base
.matrix
));
3764 tolerance
/= _cairo_matrix_transformed_circle_major_axis (&pattern
->base
.matrix
, 1);
3765 tolerance
*= MIN (x_scale
, y_scale
);
3767 _cairo_gradient_pattern_box_to_parameter (pattern
,
3768 bounds_x1
, bounds_y1
,
3769 bounds_x2
, bounds_y2
,
3771 } else if (pattern
->stops
[0].offset
== pattern
->stops
[pattern
->n_stops
- 1].offset
) {
3773 * If the first and the last stop offset are the same, then
3774 * the color function is a step function.
3775 * _cairo_ps_surface_emit_pattern_stops emits it as a stitched
3776 * function no matter how many stops the pattern has. The
3777 * domain of the stitched function will be [0 1] in this case.
3779 * This is done to avoid emitting degenerate gradients for
3780 * EXTEND_PAD patterns having a step color function.
3785 assert (pattern
->base
.extend
== CAIRO_EXTEND_PAD
);
3787 domain
[0] = pattern
->stops
[0].offset
;
3788 domain
[1] = pattern
->stops
[pattern
->n_stops
- 1].offset
;
3791 /* PS requires the first and last stop to be the same as the
3792 * extreme coordinates. For repeating patterns this moves the
3793 * extreme coordinates out to the begin/end of the repeating
3794 * function. For non repeating patterns this may move the extreme
3795 * coordinates in if there are not stops at offset 0 and 1. */
3796 _cairo_gradient_pattern_interpolate (pattern
, domain
[0], &start
);
3797 _cairo_gradient_pattern_interpolate (pattern
, domain
[1], &end
);
3799 if (pattern
->base
.extend
== CAIRO_EXTEND_REPEAT
||
3800 pattern
->base
.extend
== CAIRO_EXTEND_REFLECT
)
3802 int repeat_begin
, repeat_end
;
3804 repeat_begin
= floor (domain
[0]);
3805 repeat_end
= ceil (domain
[1]);
3807 status
= _cairo_ps_surface_emit_repeating_function (surface
,
3811 if (unlikely (status
))
3813 } else if (pattern
->n_stops
<= 2) {
3814 /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a
3815 * Type 2 function is used by itself without a stitching
3816 * function. Type 2 functions always have the domain [0 1] */
3821 if (is_ps_pattern
) {
3822 _cairo_output_stream_printf (surface
->stream
,
3823 "<< /PatternType 2\n"
3827 if (pattern
->base
.type
== CAIRO_PATTERN_TYPE_LINEAR
) {
3828 _cairo_output_stream_printf (surface
->stream
,
3829 " << /ShadingType 2\n"
3830 " /ColorSpace /DeviceRGB\n"
3831 " /Coords [ %f %f %f %f ]\n",
3832 start
.center
.x
, start
.center
.y
,
3833 end
.center
.x
, end
.center
.y
);
3835 _cairo_output_stream_printf (surface
->stream
,
3836 " << /ShadingType 3\n"
3837 " /ColorSpace /DeviceRGB\n"
3838 " /Coords [ %f %f %f %f %f %f ]\n",
3839 start
.center
.x
, start
.center
.y
,
3840 MAX (start
.radius
, 0),
3841 end
.center
.x
, end
.center
.y
,
3842 MAX (end
.radius
, 0));
3845 if (pattern
->base
.extend
!= CAIRO_EXTEND_NONE
) {
3846 _cairo_output_stream_printf (surface
->stream
,
3847 " /Extend [ true true ]\n");
3849 _cairo_output_stream_printf (surface
->stream
,
3850 " /Extend [ false false ]\n");
3853 if (domain
[0] == 0.0 && domain
[1] == 1.0) {
3854 _cairo_output_stream_printf (surface
->stream
,
3855 " /Function CairoFunction\n");
3857 _cairo_output_stream_printf (surface
->stream
,
3859 " /FunctionType 3\n"
3860 " /Domain [ 0 1 ]\n"
3862 " /Encode [ %f %f ]\n"
3863 " /Functions [ CairoFunction ]\n"
3865 domain
[0], domain
[1]);
3868 _cairo_output_stream_printf (surface
->stream
,
3871 if (is_ps_pattern
) {
3872 _cairo_output_stream_printf (surface
->stream
,
3875 _cairo_output_stream_print_matrix (surface
->stream
, &pat_to_ps
);
3876 _cairo_output_stream_printf (surface
->stream
, " ]\n"
3877 "makepattern setpattern\n");
3879 _cairo_output_stream_printf (surface
->stream
,
3886 static cairo_status_t
3887 _cairo_ps_surface_emit_mesh_pattern (cairo_ps_surface_t
*surface
,
3888 cairo_mesh_pattern_t
*pattern
,
3889 cairo_bool_t is_ps_pattern
)
3891 cairo_matrix_t pat_to_ps
;
3892 cairo_status_t status
;
3893 cairo_pdf_shading_t shading
;
3896 if (_cairo_array_num_elements (&pattern
->patches
) == 0)
3897 return CAIRO_INT_STATUS_NOTHING_TO_DO
;
3899 pat_to_ps
= pattern
->base
.matrix
;
3900 status
= cairo_matrix_invert (&pat_to_ps
);
3901 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3902 assert (status
== CAIRO_STATUS_SUCCESS
);
3904 cairo_matrix_multiply (&pat_to_ps
, &pat_to_ps
, &surface
->cairo_to_ps
);
3906 status
= _cairo_pdf_shading_init_color (&shading
, pattern
);
3907 if (unlikely (status
))
3910 _cairo_output_stream_printf (surface
->stream
,
3912 "/ASCII85Decode filter /FlateDecode filter /ReusableStreamDecode filter\n");
3914 status
= _cairo_ps_surface_emit_base85_string (surface
,
3916 shading
.data_length
,
3917 CAIRO_PS_COMPRESS_DEFLATE
,
3922 _cairo_output_stream_printf (surface
->stream
,
3924 "/CairoData exch def\n");
3926 if (is_ps_pattern
) {
3927 _cairo_output_stream_printf (surface
->stream
,
3928 "<< /PatternType 2\n"
3932 _cairo_output_stream_printf (surface
->stream
,
3933 " << /ShadingType %d\n"
3934 " /ColorSpace /DeviceRGB\n"
3935 " /DataSource CairoData\n"
3936 " /BitsPerCoordinate %d\n"
3937 " /BitsPerComponent %d\n"
3938 " /BitsPerFlag %d\n"
3940 shading
.shading_type
,
3941 shading
.bits_per_coordinate
,
3942 shading
.bits_per_component
,
3943 shading
.bits_per_flag
);
3945 for (i
= 0; i
< shading
.decode_array_length
; i
++)
3946 _cairo_output_stream_printf (surface
->stream
, "%f ", shading
.decode_array
[i
]);
3948 _cairo_output_stream_printf (surface
->stream
,
3952 if (is_ps_pattern
) {
3953 _cairo_output_stream_printf (surface
->stream
,
3956 _cairo_output_stream_print_matrix (surface
->stream
, &pat_to_ps
);
3957 _cairo_output_stream_printf (surface
->stream
,
3962 _cairo_output_stream_printf (surface
->stream
, "shfill\n");
3965 _cairo_output_stream_printf (surface
->stream
,
3966 "currentdict /CairoData undef\n");
3968 _cairo_pdf_shading_fini (&shading
);
3973 static cairo_status_t
3974 _cairo_ps_surface_emit_pattern (cairo_ps_surface_t
*surface
,
3975 const cairo_pattern_t
*pattern
,
3976 cairo_rectangle_int_t
*extents
,
3977 cairo_operator_t op
)
3979 cairo_status_t status
;
3981 if (pattern
->type
== CAIRO_PATTERN_TYPE_SOLID
) {
3982 cairo_solid_pattern_t
*solid
= (cairo_solid_pattern_t
*) pattern
;
3984 if (surface
->current_pattern_is_solid_color
== FALSE
||
3985 ! _cairo_color_equal (&surface
->current_color
, &solid
->color
))
3987 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
3988 if (unlikely (status
))
3991 _cairo_ps_surface_emit_solid_pattern (surface
, (cairo_solid_pattern_t
*) pattern
);
3993 surface
->current_pattern_is_solid_color
= TRUE
;
3994 surface
->current_color
= solid
->color
;
3997 return CAIRO_STATUS_SUCCESS
;
4000 surface
->current_pattern_is_solid_color
= FALSE
;
4001 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
4002 if (unlikely (status
))
4005 switch (pattern
->type
) {
4006 case CAIRO_PATTERN_TYPE_SOLID
:
4008 _cairo_ps_surface_emit_solid_pattern (surface
, (cairo_solid_pattern_t
*) pattern
);
4011 case CAIRO_PATTERN_TYPE_SURFACE
:
4012 case CAIRO_PATTERN_TYPE_RASTER_SOURCE
:
4013 status
= _cairo_ps_surface_emit_surface_pattern (surface
,
4014 (cairo_pattern_t
*)pattern
,
4017 if (unlikely (status
))
4021 case CAIRO_PATTERN_TYPE_LINEAR
:
4022 case CAIRO_PATTERN_TYPE_RADIAL
:
4023 status
= _cairo_ps_surface_emit_gradient (surface
,
4024 (cairo_gradient_pattern_t
*) pattern
,
4026 if (unlikely (status
))
4030 case CAIRO_PATTERN_TYPE_MESH
:
4031 status
= _cairo_ps_surface_emit_mesh_pattern (surface
,
4032 (cairo_mesh_pattern_t
*) pattern
,
4034 if (unlikely (status
))
4039 return CAIRO_STATUS_SUCCESS
;
4042 static cairo_status_t
4043 _cairo_ps_surface_paint_gradient (cairo_ps_surface_t
*surface
,
4044 const cairo_pattern_t
*source
,
4045 const cairo_rectangle_int_t
*extents
)
4047 cairo_matrix_t pat_to_ps
;
4048 cairo_status_t status
;
4050 pat_to_ps
= source
->matrix
;
4051 status
= cairo_matrix_invert (&pat_to_ps
);
4052 /* cairo_pattern_set_matrix ensures the matrix is invertible */
4053 assert (status
== CAIRO_STATUS_SUCCESS
);
4054 cairo_matrix_multiply (&pat_to_ps
, &pat_to_ps
, &surface
->cairo_to_ps
);
4056 if (! _cairo_matrix_is_identity (&pat_to_ps
)) {
4057 _cairo_output_stream_printf (surface
->stream
, "[");
4058 _cairo_output_stream_print_matrix (surface
->stream
, &pat_to_ps
);
4059 _cairo_output_stream_printf (surface
->stream
, "] concat\n");
4062 if (source
->type
== CAIRO_PATTERN_TYPE_MESH
) {
4063 status
= _cairo_ps_surface_emit_mesh_pattern (surface
,
4064 (cairo_mesh_pattern_t
*)source
,
4066 if (unlikely (status
))
4069 status
= _cairo_ps_surface_emit_gradient (surface
,
4070 (cairo_gradient_pattern_t
*)source
,
4072 if (unlikely (status
))
4079 static cairo_status_t
4080 _cairo_ps_surface_paint_pattern (cairo_ps_surface_t
*surface
,
4081 const cairo_pattern_t
*source
,
4082 cairo_rectangle_int_t
*extents
,
4083 cairo_operator_t op
,
4084 cairo_bool_t stencil_mask
)
4086 switch (source
->type
) {
4087 case CAIRO_PATTERN_TYPE_SURFACE
:
4088 case CAIRO_PATTERN_TYPE_RASTER_SOURCE
:
4089 return _cairo_ps_surface_paint_surface (surface
,
4090 (cairo_pattern_t
*)source
,
4095 case CAIRO_PATTERN_TYPE_LINEAR
:
4096 case CAIRO_PATTERN_TYPE_RADIAL
:
4097 case CAIRO_PATTERN_TYPE_MESH
:
4098 return _cairo_ps_surface_paint_gradient (surface
,
4102 case CAIRO_PATTERN_TYPE_SOLID
:
4105 return CAIRO_STATUS_SUCCESS
;
4110 _can_paint_pattern (const cairo_pattern_t
*pattern
)
4112 switch (pattern
->type
) {
4113 case CAIRO_PATTERN_TYPE_SOLID
:
4116 case CAIRO_PATTERN_TYPE_SURFACE
:
4117 case CAIRO_PATTERN_TYPE_RASTER_SOURCE
:
4118 return (pattern
->extend
== CAIRO_EXTEND_NONE
||
4119 pattern
->extend
== CAIRO_EXTEND_PAD
);
4121 case CAIRO_PATTERN_TYPE_LINEAR
:
4122 case CAIRO_PATTERN_TYPE_RADIAL
:
4123 case CAIRO_PATTERN_TYPE_MESH
:
4133 _cairo_ps_surface_get_extents (void *abstract_surface
,
4134 cairo_rectangle_int_t
*rectangle
)
4136 cairo_ps_surface_t
*surface
= abstract_surface
;
4141 /* XXX: The conversion to integers here is pretty bogus, (not to
4142 * mention the aribitray limitation of width to a short(!). We
4143 * may need to come up with a better interface for get_extents.
4145 rectangle
->width
= ceil (surface
->width
);
4146 rectangle
->height
= ceil (surface
->height
);
4152 _cairo_ps_surface_get_font_options (void *abstract_surface
,
4153 cairo_font_options_t
*options
)
4155 _cairo_font_options_init_default (options
);
4157 cairo_font_options_set_hint_style (options
, CAIRO_HINT_STYLE_NONE
);
4158 cairo_font_options_set_hint_metrics (options
, CAIRO_HINT_METRICS_OFF
);
4159 cairo_font_options_set_antialias (options
, CAIRO_ANTIALIAS_GRAY
);
4160 _cairo_font_options_set_round_glyph_positions (options
, CAIRO_ROUND_GLYPH_POS_OFF
);
4163 static cairo_int_status_t
4164 _cairo_ps_surface_set_clip (cairo_ps_surface_t
*surface
,
4165 cairo_composite_rectangles_t
*composite
)
4167 cairo_clip_t
*clip
= composite
->clip
;
4169 if (_cairo_composite_rectangles_can_reduce_clip (composite
, clip
))
4173 if (_cairo_composite_rectangles_can_reduce_clip (composite
,
4174 surface
->clipper
.clip
))
4175 return CAIRO_STATUS_SUCCESS
;
4178 return _cairo_surface_clipper_set_clip (&surface
->clipper
, clip
);
4181 static cairo_int_status_t
4182 _cairo_ps_surface_paint (void *abstract_surface
,
4183 cairo_operator_t op
,
4184 const cairo_pattern_t
*source
,
4185 const cairo_clip_t
*clip
)
4187 cairo_ps_surface_t
*surface
= abstract_surface
;
4188 cairo_output_stream_t
*stream
= surface
->stream
;
4189 cairo_composite_rectangles_t extents
;
4190 cairo_status_t status
;
4192 status
= _cairo_composite_rectangles_init_for_paint (&extents
,
4195 if (unlikely (status
))
4198 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
) {
4199 status
= _cairo_ps_surface_analyze_operation (surface
, op
, source
, NULL
, &extents
.bounded
);
4200 goto cleanup_composite
;
4203 assert (_cairo_ps_surface_operation_supported (surface
, op
, source
, NULL
, &extents
.bounded
));
4206 _cairo_output_stream_printf (stream
,
4207 "%% _cairo_ps_surface_paint\n");
4210 status
= _cairo_ps_surface_set_clip (surface
, &extents
);
4211 if (unlikely (status
))
4212 goto cleanup_composite
;
4214 if (_can_paint_pattern (source
)) {
4215 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
4216 if (unlikely (status
))
4217 goto cleanup_composite
;
4219 _cairo_output_stream_printf (stream
, "q\n");
4220 status
= _cairo_ps_surface_paint_pattern (surface
,
4222 &extents
.bounded
, op
, FALSE
);
4223 if (unlikely (status
))
4224 goto cleanup_composite
;
4226 _cairo_output_stream_printf (stream
, "Q\n");
4228 status
= _cairo_ps_surface_emit_pattern (surface
, source
, &extents
.bounded
, op
);
4229 if (unlikely (status
))
4230 goto cleanup_composite
;
4232 _cairo_output_stream_printf (stream
, "0 0 %f %f rectfill\n",
4233 surface
->width
, surface
->height
);
4237 _cairo_composite_rectangles_fini (&extents
);
4241 static cairo_int_status_t
4242 _cairo_ps_surface_mask (void *abstract_surface
,
4243 cairo_operator_t op
,
4244 const cairo_pattern_t
*source
,
4245 const cairo_pattern_t
*mask
,
4246 const cairo_clip_t
*clip
)
4248 cairo_ps_surface_t
*surface
= abstract_surface
;
4249 cairo_output_stream_t
*stream
= surface
->stream
;
4250 cairo_composite_rectangles_t extents
;
4251 cairo_status_t status
;
4253 status
= _cairo_composite_rectangles_init_for_mask (&extents
,
4255 op
, source
, mask
, clip
);
4256 if (unlikely (status
))
4259 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
) {
4260 status
= _cairo_ps_surface_analyze_operation (surface
, op
, source
, mask
, &extents
.bounded
);
4261 goto cleanup_composite
;
4264 assert (_cairo_ps_surface_operation_supported (surface
, op
, source
, mask
, &extents
.bounded
));
4267 _cairo_output_stream_printf (stream
,
4268 "%% _cairo_ps_surface_mask\n");
4271 status
= _cairo_ps_surface_set_clip (surface
, &extents
);
4272 if (unlikely (status
))
4273 goto cleanup_composite
;
4275 status
= _cairo_ps_surface_emit_pattern (surface
, source
, &extents
.bounded
, op
);
4276 if (unlikely (status
))
4277 goto cleanup_composite
;
4279 _cairo_output_stream_printf (stream
, "q\n");
4280 status
= _cairo_ps_surface_paint_pattern (surface
,
4282 &extents
.bounded
, op
, TRUE
);
4283 if (unlikely (status
))
4284 goto cleanup_composite
;
4286 _cairo_output_stream_printf (stream
, "Q\n");
4289 _cairo_composite_rectangles_fini (&extents
);
4293 static cairo_int_status_t
4294 _cairo_ps_surface_stroke (void *abstract_surface
,
4295 cairo_operator_t op
,
4296 const cairo_pattern_t
*source
,
4297 const cairo_path_fixed_t
*path
,
4298 const cairo_stroke_style_t
*style
,
4299 const cairo_matrix_t
*ctm
,
4300 const cairo_matrix_t
*ctm_inverse
,
4302 cairo_antialias_t antialias
,
4303 const cairo_clip_t
*clip
)
4305 cairo_ps_surface_t
*surface
= abstract_surface
;
4306 cairo_composite_rectangles_t extents
;
4307 cairo_int_status_t status
;
4309 status
= _cairo_composite_rectangles_init_for_stroke (&extents
,
4314 if (unlikely (status
))
4317 /* use the more accurate extents */
4319 cairo_rectangle_int_t r
;
4322 status
= _cairo_path_fixed_stroke_extents (path
, style
,
4326 if (unlikely (status
))
4327 goto cleanup_composite
;
4329 _cairo_box_from_rectangle (&b
, &r
);
4330 status
= _cairo_composite_rectangles_intersect_mask_extents (&extents
, &b
);
4331 if (unlikely (status
))
4332 goto cleanup_composite
;
4335 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
) {
4336 status
= _cairo_ps_surface_analyze_operation (surface
, op
, source
, NULL
, &extents
.bounded
);
4337 goto cleanup_composite
;
4340 assert (_cairo_ps_surface_operation_supported (surface
, op
, source
, NULL
, &extents
.bounded
));
4343 _cairo_output_stream_printf (surface
->stream
,
4344 "%% _cairo_ps_surface_stroke\n");
4347 status
= _cairo_ps_surface_set_clip (surface
, &extents
);
4348 if (unlikely (status
))
4349 goto cleanup_composite
;
4351 status
= _cairo_ps_surface_emit_pattern (surface
, source
, &extents
.bounded
, op
);
4352 if (unlikely (status
))
4353 goto cleanup_composite
;
4355 status
= _cairo_pdf_operators_stroke (&surface
->pdf_operators
,
4362 _cairo_composite_rectangles_fini (&extents
);
4366 static cairo_int_status_t
4367 _cairo_ps_surface_fill (void *abstract_surface
,
4368 cairo_operator_t op
,
4369 const cairo_pattern_t
*source
,
4370 const cairo_path_fixed_t
*path
,
4371 cairo_fill_rule_t fill_rule
,
4373 cairo_antialias_t antialias
,
4374 const cairo_clip_t
*clip
)
4376 cairo_ps_surface_t
*surface
= abstract_surface
;
4377 cairo_composite_rectangles_t extents
;
4378 cairo_int_status_t status
;
4380 status
= _cairo_composite_rectangles_init_for_fill (&extents
,
4384 if (unlikely (status
))
4387 /* use the more accurate extents */
4389 cairo_rectangle_int_t r
;
4392 _cairo_path_fixed_fill_extents (path
,
4397 _cairo_box_from_rectangle (&b
, &r
);
4398 status
= _cairo_composite_rectangles_intersect_mask_extents (&extents
, &b
);
4399 if (unlikely (status
))
4400 goto cleanup_composite
;
4403 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
) {
4404 status
= _cairo_ps_surface_analyze_operation (surface
, op
, source
, NULL
, &extents
.bounded
);
4405 goto cleanup_composite
;
4408 assert (_cairo_ps_surface_operation_supported (surface
, op
, source
, NULL
, &extents
.bounded
));
4411 _cairo_output_stream_printf (surface
->stream
,
4412 "%% _cairo_ps_surface_fill\n");
4415 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
4416 if (unlikely (status
))
4417 goto cleanup_composite
;
4419 status
= _cairo_ps_surface_set_clip (surface
, &extents
);
4420 if (unlikely (status
))
4421 goto cleanup_composite
;
4423 if (_can_paint_pattern (source
)) {
4424 _cairo_output_stream_printf (surface
->stream
, "q\n");
4426 status
= _cairo_pdf_operators_clip (&surface
->pdf_operators
,
4429 if (unlikely (status
))
4430 goto cleanup_composite
;
4432 status
= _cairo_ps_surface_paint_pattern (surface
,
4434 &extents
.bounded
, op
, FALSE
);
4435 if (unlikely (status
))
4436 goto cleanup_composite
;
4438 _cairo_output_stream_printf (surface
->stream
, "Q\n");
4439 _cairo_pdf_operators_reset (&surface
->pdf_operators
);
4441 status
= _cairo_ps_surface_emit_pattern (surface
, source
, &extents
.bounded
, op
);
4442 if (unlikely (status
))
4443 goto cleanup_composite
;
4445 status
= _cairo_pdf_operators_fill (&surface
->pdf_operators
,
4451 _cairo_composite_rectangles_fini (&extents
);
4456 _cairo_ps_surface_has_show_text_glyphs (void *abstract_surface
)
4461 static cairo_int_status_t
4462 _cairo_ps_surface_show_text_glyphs (void *abstract_surface
,
4463 cairo_operator_t op
,
4464 const cairo_pattern_t
*source
,
4467 cairo_glyph_t
*glyphs
,
4469 const cairo_text_cluster_t
*clusters
,
4471 cairo_text_cluster_flags_t cluster_flags
,
4472 cairo_scaled_font_t
*scaled_font
,
4473 const cairo_clip_t
*clip
)
4475 cairo_ps_surface_t
*surface
= abstract_surface
;
4476 cairo_composite_rectangles_t extents
;
4477 cairo_bool_t overlap
;
4478 cairo_status_t status
;
4480 status
= _cairo_composite_rectangles_init_for_glyphs (&extents
,
4487 if (unlikely (status
))
4490 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
) {
4491 status
= _cairo_ps_surface_analyze_operation (surface
, op
, source
, NULL
, &extents
.bounded
);
4492 goto cleanup_composite
;
4495 assert (_cairo_ps_surface_operation_supported (surface
, op
, source
, NULL
, &extents
.bounded
));
4498 _cairo_output_stream_printf (surface
->stream
,
4499 "%% _cairo_ps_surface_show_glyphs\n");
4502 status
= _cairo_ps_surface_set_clip (surface
, &extents
);
4503 if (unlikely (status
))
4504 goto cleanup_composite
;
4506 status
= _cairo_ps_surface_emit_pattern (surface
, source
, &extents
.bounded
, op
);
4507 if (unlikely (status
))
4508 goto cleanup_composite
;
4510 status
= _cairo_pdf_operators_show_text_glyphs (&surface
->pdf_operators
,
4513 clusters
, num_clusters
,
4518 _cairo_composite_rectangles_fini (&extents
);
4522 static const char **
4523 _cairo_ps_surface_get_supported_mime_types (void *abstract_surface
)
4525 return _cairo_ps_supported_mime_types
;
4529 _cairo_ps_surface_set_paginated_mode (void *abstract_surface
,
4530 cairo_paginated_mode_t paginated_mode
)
4532 cairo_ps_surface_t
*surface
= abstract_surface
;
4533 cairo_status_t status
;
4535 surface
->paginated_mode
= paginated_mode
;
4537 if (surface
->clipper
.clip
!= NULL
) {
4538 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
4540 _cairo_output_stream_printf (surface
->stream
, "Q q\n");
4541 _cairo_surface_clipper_reset (&surface
->clipper
);
4545 static cairo_int_status_t
4546 _cairo_ps_surface_set_bounding_box (void *abstract_surface
,
4549 cairo_ps_surface_t
*surface
= abstract_surface
;
4550 int i
, num_comments
;
4553 cairo_bool_t has_page_media
, has_page_bbox
;
4554 const char *page_media
;
4556 x1
= floor (_cairo_fixed_to_double (bbox
->p1
.x
));
4557 y1
= floor (surface
->height
- _cairo_fixed_to_double (bbox
->p2
.y
));
4558 x2
= ceil (_cairo_fixed_to_double (bbox
->p2
.x
));
4559 y2
= ceil (surface
->height
- _cairo_fixed_to_double (bbox
->p1
.y
));
4561 surface
->page_bbox
.x
= x1
;
4562 surface
->page_bbox
.y
= y1
;
4563 surface
->page_bbox
.width
= x2
- x1
;
4564 surface
->page_bbox
.height
= y2
- y1
;
4566 _cairo_output_stream_printf (surface
->stream
,
4567 "%%%%Page: %d %d\n",
4569 surface
->num_pages
);
4571 _cairo_output_stream_printf (surface
->stream
,
4572 "%%%%BeginPageSetup\n");
4574 has_page_media
= FALSE
;
4575 has_page_bbox
= FALSE
;
4576 num_comments
= _cairo_array_num_elements (&surface
->dsc_page_setup_comments
);
4577 comments
= _cairo_array_index (&surface
->dsc_page_setup_comments
, 0);
4578 for (i
= 0; i
< num_comments
; i
++) {
4579 _cairo_output_stream_printf (surface
->stream
,
4580 "%s\n", comments
[i
]);
4581 if (strncmp (comments
[i
], "%%PageMedia:", 11) == 0)
4582 has_page_media
= TRUE
;
4584 if (strncmp (comments
[i
], "%%PageBoundingBox:", 18) == 0)
4585 has_page_bbox
= TRUE
;
4590 _cairo_array_truncate (&surface
->dsc_page_setup_comments
, 0);
4592 if (!has_page_media
&& !surface
->eps
) {
4593 page_media
= _cairo_ps_surface_get_page_media (surface
);
4594 if (unlikely (page_media
== NULL
))
4595 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
4597 _cairo_output_stream_printf (surface
->stream
,
4598 "%%%%PageMedia: %s\n",
4602 if (!has_page_bbox
) {
4603 _cairo_output_stream_printf (surface
->stream
,
4604 "%%%%PageBoundingBox: %d %d %d %d\n",
4608 if (!surface
->eps
) {
4609 _cairo_output_stream_printf (surface
->stream
,
4610 "%f %f cairo_set_page_size\n",
4611 ceil(surface
->width
),
4612 ceil(surface
->height
));
4615 _cairo_output_stream_printf (surface
->stream
,
4616 "%%%%EndPageSetup\n"
4617 "q %d %d %d %d rectclip q\n",
4618 surface
->page_bbox
.x
,
4619 surface
->page_bbox
.y
,
4620 surface
->page_bbox
.width
,
4621 surface
->page_bbox
.height
);
4623 if (surface
->num_pages
== 1) {
4624 surface
->bbox_x1
= x1
;
4625 surface
->bbox_y1
= y1
;
4626 surface
->bbox_x2
= x2
;
4627 surface
->bbox_y2
= y2
;
4629 if (x1
< surface
->bbox_x1
)
4630 surface
->bbox_x1
= x1
;
4631 if (y1
< surface
->bbox_y1
)
4632 surface
->bbox_y1
= y1
;
4633 if (x2
> surface
->bbox_x2
)
4634 surface
->bbox_x2
= x2
;
4635 if (y2
> surface
->bbox_y2
)
4636 surface
->bbox_y2
= y2
;
4638 surface
->current_pattern_is_solid_color
= FALSE
;
4639 _cairo_pdf_operators_reset (&surface
->pdf_operators
);
4641 return _cairo_output_stream_get_status (surface
->stream
);
4645 _cairo_ps_surface_supports_fine_grained_fallbacks (void *abstract_surface
)
4650 static const cairo_surface_backend_t cairo_ps_surface_backend
= {
4651 CAIRO_SURFACE_TYPE_PS
,
4652 _cairo_ps_surface_finish
,
4654 _cairo_default_context_create
,
4656 NULL
, /* create similar: handled by wrapper */
4657 NULL
, /* create similar image */
4658 NULL
, /* map to image */
4659 NULL
, /* unmap image */
4661 _cairo_surface_default_source
,
4662 NULL
, /* acquire_source_image */
4663 NULL
, /* release_source_image */
4664 NULL
, /* snapshot */
4666 NULL
, /* cairo_ps_surface_copy_page */
4667 _cairo_ps_surface_show_page
,
4669 _cairo_ps_surface_get_extents
,
4670 _cairo_ps_surface_get_font_options
,
4673 NULL
, /* mark_dirty_rectangle */
4675 /* Here are the drawing functions */
4677 _cairo_ps_surface_paint
, /* paint */
4678 _cairo_ps_surface_mask
,
4679 _cairo_ps_surface_stroke
,
4680 _cairo_ps_surface_fill
,
4681 NULL
, /* fill-stroke */
4682 NULL
, /* show_glyphs */
4683 _cairo_ps_surface_has_show_text_glyphs
,
4684 _cairo_ps_surface_show_text_glyphs
,
4685 _cairo_ps_surface_get_supported_mime_types
,
4688 static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend
= {
4689 _cairo_ps_surface_start_page
,
4690 _cairo_ps_surface_set_paginated_mode
,
4691 _cairo_ps_surface_set_bounding_box
,
4692 NULL
, /* _cairo_ps_surface_has_fallback_images, */
4693 _cairo_ps_surface_supports_fine_grained_fallbacks
,