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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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() */
59 #include "cairo-ps-surface-private.h"
60 #include "cairo-pdf-operators-private.h"
61 #include "cairo-scaled-font-subsets-private.h"
62 #include "cairo-paginated-private.h"
63 #include "cairo-meta-surface-private.h"
64 #include "cairo-output-stream-private.h"
65 #include "cairo-type3-glyph-surface-private.h"
76 #define ctime_r(T, BUF) ctime (T)
79 static const cairo_surface_backend_t cairo_ps_surface_backend
;
80 static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend
;
82 static const cairo_ps_level_t _cairo_ps_levels
[] =
88 #define CAIRO_PS_LEVEL_LAST ARRAY_LENGTH (_cairo_ps_levels)
90 static const char * _cairo_ps_level_strings
[CAIRO_PS_LEVEL_LAST
] =
97 _cairo_ps_surface_emit_header (cairo_ps_surface_t
*surface
)
104 const char *eps_header
= "";
106 if (surface
->has_creation_date
)
107 now
= surface
->creation_date
;
111 if (surface
->ps_level_used
== CAIRO_PS_LEVEL_2
)
117 eps_header
= " EPSF-3.0";
119 _cairo_output_stream_printf (surface
->final_stream
,
120 "%%!PS-Adobe-3.0%s\n"
121 "%%%%Creator: cairo %s (http://cairographics.org)\n"
122 "%%%%CreationDate: %s"
124 "%%%%BoundingBox: %d %d %d %d\n",
126 cairo_version_string (),
127 ctime_r (&now
, ctime_buf
),
134 _cairo_output_stream_printf (surface
->final_stream
,
135 "%%%%DocumentData: Clean7Bit\n"
136 "%%%%LanguageLevel: %d\n",
139 num_comments
= _cairo_array_num_elements (&surface
->dsc_header_comments
);
140 comments
= _cairo_array_index (&surface
->dsc_header_comments
, 0);
141 for (i
= 0; i
< num_comments
; i
++) {
142 _cairo_output_stream_printf (surface
->final_stream
,
143 "%s\n", comments
[i
]);
148 _cairo_output_stream_printf (surface
->final_stream
,
149 "%%%%EndComments\n");
151 _cairo_output_stream_printf (surface
->final_stream
,
152 "%%%%BeginProlog\n");
155 _cairo_output_stream_printf (surface
->final_stream
,
156 "/cairo_eps_state save def\n"
157 "/dict_count countdictstack def\n"
158 "/op_count count 1 sub def\n"
161 _cairo_output_stream_printf (surface
->final_stream
,
162 "/languagelevel where\n"
163 "{ pop languagelevel } { 1 } ifelse\n"
164 "%d lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto\n"
165 " (This print job requires a PostScript Language Level %d printer.) show\n"
166 " showpage quit } if\n",
171 _cairo_output_stream_printf (surface
->final_stream
,
172 "/q { gsave } bind def\n"
173 "/Q { grestore } bind def\n"
174 "/cm { 6 array astore concat } bind def\n"
175 "/w { setlinewidth } bind def\n"
176 "/J { setlinecap } bind def\n"
177 "/j { setlinejoin } bind def\n"
178 "/M { setmiterlimit } bind def\n"
179 "/d { setdash } bind def\n"
180 "/m { moveto } bind def\n"
181 "/l { lineto } bind def\n"
182 "/c { curveto } bind def\n"
183 "/h { closepath } bind def\n"
184 "/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto\n"
185 " 0 exch rlineto 0 rlineto closepath } bind def\n"
186 "/S { stroke } bind def\n"
187 "/f { fill } bind def\n"
188 "/f* { eofill } bind def\n"
189 "/B { fill stroke } bind def\n"
190 "/B* { eofill stroke } bind def\n"
191 "/n { newpath } bind def\n"
192 "/W { clip } bind def\n"
193 "/W* { eoclip } bind def\n"
196 "/pdfmark where { pop globaldict /?pdfmark /exec load put }\n"
197 " { globaldict begin /?pdfmark /pop load def /pdfmark\n"
198 " /cleartomark load def end } ifelse\n"
199 "/BDC { mark 3 1 roll /BDC pdfmark } bind def\n"
200 "/EMC { mark /EMC pdfmark } bind def\n"
201 "/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def\n"
202 "/Tj { show currentpoint cairo_store_point } bind def\n"
206 " type /stringtype eq\n"
207 " { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse\n"
209 " currentpoint cairo_store_point\n"
211 "/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore\n"
212 " cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def\n"
213 "/Tf { pop /cairo_font exch def /cairo_font_matrix where\n"
214 " { pop cairo_selectfont } if } bind def\n"
215 "/Td { matrix translate cairo_font_matrix matrix concatmatrix dup\n"
216 " /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point\n"
217 " /cairo_font where { pop cairo_selectfont } if } bind def\n"
218 "/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def\n"
219 " cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def\n"
220 "/g { setgray } bind def\n"
221 "/rg { setrgbcolor } bind def\n"
222 "/d1 { setcachedevice } bind def\n");
224 _cairo_output_stream_printf (surface
->final_stream
,
227 num_comments
= _cairo_array_num_elements (&surface
->dsc_setup_comments
);
229 _cairo_output_stream_printf (surface
->final_stream
,
232 comments
= _cairo_array_index (&surface
->dsc_setup_comments
, 0);
233 for (i
= 0; i
< num_comments
; i
++) {
234 _cairo_output_stream_printf (surface
->final_stream
,
235 "%s\n", comments
[i
]);
240 _cairo_output_stream_printf (surface
->final_stream
,
245 #if CAIRO_HAS_FT_FONT
246 static cairo_status_t
247 _cairo_ps_surface_emit_type1_font_subset (cairo_ps_surface_t
*surface
,
248 cairo_scaled_font_subset_t
*font_subset
)
252 cairo_type1_subset_t subset
;
253 cairo_status_t status
;
257 snprintf (name
, sizeof name
, "f-%d-%d",
258 font_subset
->font_id
, font_subset
->subset_id
);
259 status
= _cairo_type1_subset_init (&subset
, name
, font_subset
, TRUE
);
263 /* FIXME: Figure out document structure convention for fonts */
266 _cairo_output_stream_printf (surface
->final_stream
,
267 "%% _cairo_ps_surface_emit_type1_font_subset\n");
270 length
= subset
.header_length
+ subset
.data_length
+ subset
.trailer_length
;
271 _cairo_output_stream_write (surface
->final_stream
, subset
.data
, length
);
273 _cairo_type1_subset_fini (&subset
);
275 return CAIRO_STATUS_SUCCESS
;
279 static cairo_status_t
280 _cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t
*surface
,
281 cairo_scaled_font_subset_t
*font_subset
)
283 cairo_type1_subset_t subset
;
284 cairo_status_t status
;
288 snprintf (name
, sizeof name
, "f-%d-%d",
289 font_subset
->font_id
, font_subset
->subset_id
);
290 status
= _cairo_type1_fallback_init_hex (&subset
, name
, font_subset
);
294 /* FIXME: Figure out document structure convention for fonts */
297 _cairo_output_stream_printf (surface
->final_stream
,
298 "%% _cairo_ps_surface_emit_type1_font_fallback\n");
301 length
= subset
.header_length
+ subset
.data_length
+ subset
.trailer_length
;
302 _cairo_output_stream_write (surface
->final_stream
, subset
.data
, length
);
304 _cairo_type1_fallback_fini (&subset
);
306 return CAIRO_STATUS_SUCCESS
;
309 static cairo_status_t
310 _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t
*surface
,
311 cairo_scaled_font_subset_t
*font_subset
)
315 cairo_truetype_subset_t subset
;
316 cairo_status_t status
;
317 unsigned int i
, begin
, end
;
319 status
= _cairo_truetype_subset_init (&subset
, font_subset
);
323 /* FIXME: Figure out document structure convention for fonts */
326 _cairo_output_stream_printf (surface
->final_stream
,
327 "%% _cairo_ps_surface_emit_truetype_font_subset\n");
330 _cairo_output_stream_printf (surface
->final_stream
,
333 "/FontName /f-%d-%d def\n"
335 "/FontMatrix [ 1 0 0 1 0 0 ] def\n"
336 "/FontBBox [ 0 0 0 0 ] def\n"
337 "/Encoding 256 array def\n"
338 "0 1 255 { Encoding exch /.notdef put } for\n",
339 font_subset
->font_id
,
340 font_subset
->subset_id
);
342 /* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */
344 for (i
= 1; i
< font_subset
->num_glyphs
; i
++) {
345 if (font_subset
->glyph_names
!= NULL
) {
346 _cairo_output_stream_printf (surface
->final_stream
,
347 "Encoding %d /%s put\n",
348 i
, font_subset
->glyph_names
[i
]);
350 _cairo_output_stream_printf (surface
->final_stream
,
351 "Encoding %d /g%d put\n", i
, i
);
355 _cairo_output_stream_printf (surface
->final_stream
,
356 "/CharStrings %d dict dup begin\n"
358 font_subset
->num_glyphs
);
360 for (i
= 1; i
< font_subset
->num_glyphs
; i
++) {
361 if (font_subset
->glyph_names
!= NULL
) {
362 _cairo_output_stream_printf (surface
->final_stream
,
364 font_subset
->glyph_names
[i
], i
);
366 _cairo_output_stream_printf (surface
->final_stream
,
367 "/g%d %d def\n", i
, i
);
371 _cairo_output_stream_printf (surface
->final_stream
,
372 "end readonly def\n");
374 _cairo_output_stream_printf (surface
->final_stream
,
378 for (i
= 0; i
< subset
.num_string_offsets
; i
++) {
379 end
= subset
.string_offsets
[i
];
380 _cairo_output_stream_printf (surface
->final_stream
,"<");
381 _cairo_output_stream_write_hex_string (surface
->final_stream
,
382 subset
.data
+ begin
, end
- begin
);
383 _cairo_output_stream_printf (surface
->final_stream
,"00>\n");
386 if (subset
.data_length
> end
) {
387 _cairo_output_stream_printf (surface
->final_stream
,"<");
388 _cairo_output_stream_write_hex_string (surface
->final_stream
,
389 subset
.data
+ end
, subset
.data_length
- end
);
390 _cairo_output_stream_printf (surface
->final_stream
,"00>\n");
393 _cairo_output_stream_printf (surface
->final_stream
,
395 "FontName currentdict end definefont pop\n");
397 _cairo_truetype_subset_fini (&subset
);
399 return CAIRO_STATUS_SUCCESS
;
402 static cairo_status_t
403 _cairo_ps_emit_imagemask (cairo_image_surface_t
*image
,
404 cairo_output_stream_t
*stream
)
409 /* The only image type supported by Type 3 fonts are 1-bit image
411 assert (image
->format
== CAIRO_FORMAT_A1
);
413 _cairo_output_stream_printf (stream
,
418 " /ImageMatrix [%d 0 0 %d 0 %d]\n"
420 " /BitsPerComponent 1\n",
427 _cairo_output_stream_printf (stream
,
428 " /DataSource {<\n ");
429 for (row
= image
->data
, rows
= image
->height
; rows
; row
+= image
->stride
, rows
--) {
430 for (byte
= row
, cols
= (image
->width
+ 7) / 8; cols
; byte
++, cols
--) {
431 uint8_t output_byte
= CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte
);
432 _cairo_output_stream_printf (stream
, "%02x ", output_byte
);
434 _cairo_output_stream_printf (stream
, "\n ");
436 _cairo_output_stream_printf (stream
, ">}\n>>\n");
438 _cairo_output_stream_printf (stream
,
441 return _cairo_output_stream_get_status (stream
);
444 static cairo_status_t
445 _cairo_ps_surface_analyze_user_font_subset (cairo_scaled_font_subset_t
*font_subset
,
448 cairo_ps_surface_t
*surface
= closure
;
449 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
451 cairo_surface_t
*type3_surface
;
453 type3_surface
= _cairo_type3_glyph_surface_create (font_subset
->scaled_font
,
455 _cairo_ps_emit_imagemask
,
456 surface
->font_subsets
);
458 for (i
= 0; i
< font_subset
->num_glyphs
; i
++) {
459 status
= _cairo_type3_glyph_surface_analyze_glyph (type3_surface
,
460 font_subset
->glyphs
[i
]);
465 cairo_surface_destroy (type3_surface
);
470 static cairo_status_t
471 _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t
*surface
,
472 cairo_scaled_font_subset_t
*font_subset
)
476 cairo_status_t status
;
478 cairo_box_t font_bbox
= {{0,0},{0,0}};
479 cairo_box_t bbox
= {{0,0},{0,0}};
480 cairo_surface_t
*type3_surface
;
483 if (font_subset
->num_glyphs
== 0)
484 return CAIRO_STATUS_SUCCESS
;
487 _cairo_output_stream_printf (surface
->final_stream
,
488 "%% _cairo_ps_surface_emit_type3_font_subset\n");
491 _cairo_output_stream_printf (surface
->final_stream
,
494 "/FontMatrix [1 0 0 1 0 0] def\n"
495 "/Encoding 256 array def\n"
496 "0 1 255 { Encoding exch /.notdef put } for\n");
498 type3_surface
= _cairo_type3_glyph_surface_create (font_subset
->scaled_font
,
500 _cairo_ps_emit_imagemask
,
501 surface
->font_subsets
);
503 for (i
= 0; i
< font_subset
->num_glyphs
; i
++) {
504 if (font_subset
->glyph_names
!= NULL
) {
505 _cairo_output_stream_printf (surface
->final_stream
,
506 "Encoding %d /%s put\n",
507 i
, font_subset
->glyph_names
[i
]);
509 _cairo_output_stream_printf (surface
->final_stream
,
510 "Encoding %d /g%d put\n", i
, i
);
514 _cairo_output_stream_printf (surface
->final_stream
,
517 for (i
= 0; i
< font_subset
->num_glyphs
; i
++) {
518 _cairo_output_stream_printf (surface
->final_stream
,
520 status
= _cairo_type3_glyph_surface_emit_glyph (type3_surface
,
521 surface
->final_stream
,
522 font_subset
->glyphs
[i
],
528 _cairo_output_stream_printf (surface
->final_stream
,
531 font_bbox
.p1
.x
= bbox
.p1
.x
;
532 font_bbox
.p1
.y
= bbox
.p1
.y
;
533 font_bbox
.p2
.x
= bbox
.p2
.x
;
534 font_bbox
.p2
.y
= bbox
.p2
.y
;
536 if (bbox
.p1
.x
< font_bbox
.p1
.x
)
537 font_bbox
.p1
.x
= bbox
.p1
.x
;
538 if (bbox
.p1
.y
< font_bbox
.p1
.y
)
539 font_bbox
.p1
.y
= bbox
.p1
.y
;
540 if (bbox
.p2
.x
> font_bbox
.p2
.x
)
541 font_bbox
.p2
.x
= bbox
.p2
.x
;
542 if (bbox
.p2
.y
> font_bbox
.p2
.y
)
543 font_bbox
.p2
.y
= bbox
.p2
.y
;
546 cairo_surface_destroy (type3_surface
);
550 _cairo_output_stream_printf (surface
->final_stream
,
552 "/FontBBox [%f %f %f %f] def\n"
554 " exch /Glyphs get\n"
556 " 10 dict begin exec end\n"
560 "/f-%d-%d exch definefont pop\n",
561 _cairo_fixed_to_double (font_bbox
.p1
.x
),
562 - _cairo_fixed_to_double (font_bbox
.p2
.y
),
563 _cairo_fixed_to_double (font_bbox
.p2
.x
),
564 - _cairo_fixed_to_double (font_bbox
.p1
.y
),
565 font_subset
->font_id
,
566 font_subset
->subset_id
);
568 return CAIRO_STATUS_SUCCESS
;
571 static cairo_status_t
572 _cairo_ps_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t
*font_subset
,
575 cairo_ps_surface_t
*surface
= closure
;
576 cairo_status_t status
;
579 status
= _cairo_scaled_font_subset_create_glyph_names (font_subset
);
580 if (status
&& status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
583 #if CAIRO_HAS_FT_FONT
584 status
= _cairo_ps_surface_emit_type1_font_subset (surface
, font_subset
);
585 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
589 status
= _cairo_ps_surface_emit_truetype_font_subset (surface
, font_subset
);
590 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
593 status
= _cairo_ps_surface_emit_type1_font_fallback (surface
, font_subset
);
594 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
598 return CAIRO_STATUS_SUCCESS
;
601 static cairo_status_t
602 _cairo_ps_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t
*font_subset
,
605 cairo_ps_surface_t
*surface
= closure
;
606 cairo_status_t status
;
608 status
= _cairo_scaled_font_subset_create_glyph_names (font_subset
);
609 if (status
&& status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
612 status
= _cairo_ps_surface_emit_type3_font_subset (surface
, font_subset
);
613 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
617 return CAIRO_STATUS_SUCCESS
;
620 static cairo_status_t
621 _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t
*surface
)
623 cairo_status_t status
;
626 _cairo_output_stream_printf (surface
->final_stream
,
627 "%% _cairo_ps_surface_emit_font_subsets\n");
630 status
= _cairo_scaled_font_subsets_foreach_user (surface
->font_subsets
,
631 _cairo_ps_surface_analyze_user_font_subset
,
636 status
= _cairo_scaled_font_subsets_foreach_unscaled (surface
->font_subsets
,
637 _cairo_ps_surface_emit_unscaled_font_subset
,
642 status
= _cairo_scaled_font_subsets_foreach_scaled (surface
->font_subsets
,
643 _cairo_ps_surface_emit_scaled_font_subset
,
648 status
= _cairo_scaled_font_subsets_foreach_user (surface
->font_subsets
,
649 _cairo_ps_surface_emit_scaled_font_subset
,
652 _cairo_scaled_font_subsets_destroy (surface
->font_subsets
);
653 surface
->font_subsets
= NULL
;
658 static cairo_status_t
659 _cairo_ps_surface_emit_body (cairo_ps_surface_t
*surface
)
664 if (ferror (surface
->tmpfile
) != 0)
665 return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR
);
667 rewind (surface
->tmpfile
);
668 while ((n
= fread (buf
, 1, sizeof (buf
), surface
->tmpfile
)) > 0)
669 _cairo_output_stream_write (surface
->final_stream
, buf
, n
);
671 if (ferror (surface
->tmpfile
) != 0)
672 return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR
);
674 return CAIRO_STATUS_SUCCESS
;
678 _cairo_ps_surface_emit_footer (cairo_ps_surface_t
*surface
)
680 _cairo_output_stream_printf (surface
->final_stream
,
684 _cairo_output_stream_printf (surface
->final_stream
,
685 "count op_count sub {pop} repeat\n"
686 "countdictstack dict_count sub {end} repeat\n"
687 "cairo_eps_state restore\n");
690 _cairo_output_stream_printf (surface
->final_stream
,
694 static cairo_surface_t
*
695 _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t
*stream
,
699 cairo_status_t status
, status_ignored
;
700 cairo_ps_surface_t
*surface
;
702 surface
= malloc (sizeof (cairo_ps_surface_t
));
703 if (surface
== NULL
) {
704 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
708 _cairo_surface_init (&surface
->base
, &cairo_ps_surface_backend
,
709 CAIRO_CONTENT_COLOR_ALPHA
);
711 surface
->final_stream
= stream
;
713 surface
->tmpfile
= tmpfile ();
714 if (surface
->tmpfile
== NULL
) {
717 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
720 status
= _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR
);
723 goto CLEANUP_SURFACE
;
726 surface
->stream
= _cairo_output_stream_create_for_file (surface
->tmpfile
);
727 status
= _cairo_output_stream_get_status (surface
->stream
);
729 goto CLEANUP_OUTPUT_STREAM
;
731 surface
->font_subsets
= _cairo_scaled_font_subsets_create_simple ();
732 if (surface
->font_subsets
== NULL
) {
733 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
734 goto CLEANUP_OUTPUT_STREAM
;
737 surface
->has_creation_date
= FALSE
;
738 surface
->eps
= FALSE
;
739 surface
->ps_level
= CAIRO_PS_LEVEL_3
;
740 surface
->ps_level_used
= CAIRO_PS_LEVEL_2
;
741 surface
->width
= width
;
742 surface
->height
= height
;
743 cairo_matrix_init (&surface
->cairo_to_ps
, 1, 0, 0, -1, 0, height
);
744 surface
->paginated_mode
= CAIRO_PAGINATED_MODE_ANALYZE
;
745 surface
->force_fallbacks
= FALSE
;
746 surface
->content
= CAIRO_CONTENT_COLOR_ALPHA
;
747 surface
->use_string_datasource
= FALSE
;
748 surface
->current_pattern_is_solid_color
= FALSE
;
750 _cairo_pdf_operators_init (&surface
->pdf_operators
,
752 &surface
->cairo_to_ps
,
753 surface
->font_subsets
);
754 surface
->num_pages
= 0;
756 _cairo_array_init (&surface
->dsc_header_comments
, sizeof (char *));
757 _cairo_array_init (&surface
->dsc_setup_comments
, sizeof (char *));
758 _cairo_array_init (&surface
->dsc_page_setup_comments
, sizeof (char *));
760 surface
->dsc_comment_target
= &surface
->dsc_header_comments
;
762 surface
->paginated_surface
= _cairo_paginated_surface_create (
764 CAIRO_CONTENT_COLOR_ALPHA
,
766 &cairo_ps_surface_paginated_backend
);
767 status
= surface
->paginated_surface
->status
;
768 if (status
== CAIRO_STATUS_SUCCESS
) {
769 /* paginated keeps the only reference to surface now, drop ours */
770 cairo_surface_destroy (&surface
->base
);
771 return surface
->paginated_surface
;
774 _cairo_scaled_font_subsets_destroy (surface
->font_subsets
);
775 CLEANUP_OUTPUT_STREAM
:
776 status_ignored
= _cairo_output_stream_destroy (surface
->stream
);
777 fclose (surface
->tmpfile
);
781 /* destroy stream on behalf of caller */
782 status_ignored
= _cairo_output_stream_destroy (stream
);
784 return _cairo_surface_create_in_error (status
);
788 * cairo_ps_surface_create:
789 * @filename: a filename for the PS output (must be writable), %NULL may be
790 * used to specify no output. This will generate a PS surface that
791 * may be queried and used as a source, without generating a
793 * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
794 * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
796 * Creates a PostScript surface of the specified size in points to be
797 * written to @filename. See cairo_ps_surface_create_for_stream() for
798 * a more flexible mechanism for handling the PostScript output than
799 * simply writing it to a named file.
801 * Note that the size of individual pages of the PostScript output can
802 * vary. See cairo_ps_surface_set_size().
804 * Return value: a pointer to the newly created surface. The caller
805 * owns the surface and should call cairo_surface_destroy() when done
808 * This function always returns a valid pointer, but it will return a
809 * pointer to a "nil" surface if an error such as out of memory
810 * occurs. You can use cairo_surface_status() to check for this.
815 cairo_ps_surface_create (const char *filename
,
816 double width_in_points
,
817 double height_in_points
)
819 cairo_output_stream_t
*stream
;
821 stream
= _cairo_output_stream_create_for_filename (filename
);
822 if (_cairo_output_stream_get_status (stream
))
823 return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream
));
825 return _cairo_ps_surface_create_for_stream_internal (stream
,
831 * cairo_ps_surface_create_for_stream:
832 * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL
833 * to indicate a no-op @write_func. With a no-op @write_func,
834 * the surface may be queried or used as a source without
835 * generating any temporary files.
836 * @closure: the closure argument for @write_func
837 * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
838 * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
840 * Creates a PostScript surface of the specified size in points to be
841 * written incrementally to the stream represented by @write_func and
842 * @closure. See cairo_ps_surface_create() for a more convenient way
843 * to simply direct the PostScript output to a named file.
845 * Note that the size of individual pages of the PostScript
846 * output can vary. See cairo_ps_surface_set_size().
848 * Return value: a pointer to the newly created surface. The caller
849 * owns the surface and should call cairo_surface_destroy() when done
852 * This function always returns a valid pointer, but it will return a
853 * pointer to a "nil" surface if an error such as out of memory
854 * occurs. You can use cairo_surface_status() to check for this.
859 cairo_ps_surface_create_for_stream (cairo_write_func_t write_func
,
861 double width_in_points
,
862 double height_in_points
)
864 cairo_output_stream_t
*stream
;
866 stream
= _cairo_output_stream_create (write_func
, NULL
, closure
);
867 if (_cairo_output_stream_get_status (stream
))
868 return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream
));
870 return _cairo_ps_surface_create_for_stream_internal (stream
,
876 _cairo_surface_is_ps (cairo_surface_t
*surface
)
878 return surface
->backend
== &cairo_ps_surface_backend
;
881 /* If the abstract_surface is a paginated surface, and that paginated
882 * surface's target is a ps_surface, then set ps_surface to that
883 * target. Otherwise return %CAIRO_STATUS_SURFACE_TYPE_MISMATCH.
885 static cairo_status_t
886 _extract_ps_surface (cairo_surface_t
*surface
,
887 cairo_ps_surface_t
**ps_surface
)
889 cairo_surface_t
*target
;
892 return surface
->status
;
894 if (! _cairo_surface_is_paginated (surface
))
895 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
);
897 target
= _cairo_paginated_surface_get_target (surface
);
899 return target
->status
;
901 if (! _cairo_surface_is_ps (target
))
902 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
);
904 *ps_surface
= (cairo_ps_surface_t
*) target
;
906 return CAIRO_STATUS_SUCCESS
;
910 * cairo_ps_surface_restrict_to_level:
911 * @surface: a PostScript #cairo_surface_t
912 * @level: PostScript level
914 * Restricts the generated PostSript file to @level. See
915 * cairo_ps_get_levels() for a list of available level values that
918 * This function should only be called before any drawing operations
919 * have been performed on the given surface. The simplest way to do
920 * this is to call this function immediately after creating the
926 cairo_ps_surface_restrict_to_level (cairo_surface_t
*surface
,
927 cairo_ps_level_t level
)
929 cairo_ps_surface_t
*ps_surface
= NULL
;
930 cairo_status_t status
;
932 status
= _extract_ps_surface (surface
, &ps_surface
);
934 status
= _cairo_surface_set_error (surface
, status
);
938 if (level
< CAIRO_PS_LEVEL_LAST
)
939 ps_surface
->ps_level
= level
;
943 * cairo_ps_get_levels:
944 * @levels: supported level list
945 * @num_levels: list length
947 * Used to retrieve the list of supported levels. See
948 * cairo_ps_surface_restrict_to_level().
953 cairo_ps_get_levels (cairo_ps_level_t
const **levels
,
957 *levels
= _cairo_ps_levels
;
959 if (num_levels
!= NULL
)
960 *num_levels
= CAIRO_PS_LEVEL_LAST
;
964 * cairo_ps_level_to_string:
967 * Get the string representation of the given @level id. This function
968 * will return %NULL if @level id isn't valid. See cairo_ps_get_levels()
969 * for a way to get the list of valid level ids.
971 * Return value: the string associated to given level.
976 cairo_ps_level_to_string (cairo_ps_level_t level
)
978 if (level
>= CAIRO_PS_LEVEL_LAST
)
981 return _cairo_ps_level_strings
[level
];
985 * cairo_ps_surface_set_eps:
986 * @surface: a PostScript #cairo_surface_t
987 * @eps: %TRUE to output EPS format PostScript
989 * If @eps is %TRUE, the PostScript surface will output Encapsulated
992 * This function should only be called before any drawing operations
993 * have been performed on the current page. The simplest way to do
994 * this is to call this function immediately after creating the
995 * surface. An Encapsulated PostScript file should never contain more
1001 cairo_ps_surface_set_eps (cairo_surface_t
*surface
,
1004 cairo_ps_surface_t
*ps_surface
= NULL
;
1005 cairo_status_t status
;
1007 status
= _extract_ps_surface (surface
, &ps_surface
);
1009 status
= _cairo_surface_set_error (surface
, status
);
1013 ps_surface
->eps
= eps
;
1017 * cairo_ps_surface_get_eps:
1018 * @surface: a PostScript #cairo_surface_t
1020 * Check whether the PostScript surface will output Encapsulated PostScript.
1022 * Return value: %TRUE if the surface will output Encapsulated PostScript.
1026 cairo_public cairo_bool_t
1027 cairo_ps_surface_get_eps (cairo_surface_t
*surface
)
1029 cairo_ps_surface_t
*ps_surface
= NULL
;
1030 cairo_status_t status
;
1032 status
= _extract_ps_surface (surface
, &ps_surface
);
1034 status
= _cairo_surface_set_error (surface
, status
);
1038 return ps_surface
->eps
;
1042 * cairo_ps_surface_set_size:
1043 * @surface: a PostScript #cairo_surface_t
1044 * @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
1045 * @height_in_points: new surface height, in points (1 point == 1/72.0 inch)
1047 * Changes the size of a PostScript surface for the current (and
1048 * subsequent) pages.
1050 * This function should only be called before any drawing operations
1051 * have been performed on the current page. The simplest way to do
1052 * this is to call this function immediately after creating the
1053 * surface or immediately after completing a page with either
1054 * cairo_show_page() or cairo_copy_page().
1059 cairo_ps_surface_set_size (cairo_surface_t
*surface
,
1060 double width_in_points
,
1061 double height_in_points
)
1063 cairo_ps_surface_t
*ps_surface
= NULL
;
1064 cairo_status_t status
;
1066 status
= _extract_ps_surface (surface
, &ps_surface
);
1068 status
= _cairo_surface_set_error (surface
, status
);
1072 ps_surface
->width
= width_in_points
;
1073 ps_surface
->height
= height_in_points
;
1074 cairo_matrix_init (&ps_surface
->cairo_to_ps
, 1, 0, 0, -1, 0, height_in_points
);
1075 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface
->pdf_operators
,
1076 &ps_surface
->cairo_to_ps
);
1077 status
= _cairo_paginated_surface_set_size (ps_surface
->paginated_surface
,
1081 status
= _cairo_surface_set_error (surface
, status
);
1085 * cairo_ps_surface_dsc_comment:
1086 * @surface: a PostScript #cairo_surface_t
1087 * @comment: a comment string to be emitted into the PostScript output
1089 * Emit a comment into the PostScript output for the given surface.
1091 * The comment is expected to conform to the PostScript Language
1092 * Document Structuring Conventions (DSC). Please see that manual for
1093 * details on the available comments and their meanings. In
1094 * particular, the %%IncludeFeature comment allows a
1095 * device-independent means of controlling printer device features. So
1096 * the PostScript Printer Description Files Specification will also be
1097 * a useful reference.
1099 * The comment string must begin with a percent character (%) and the
1100 * total length of the string (including any initial percent
1101 * characters) must not exceed 255 characters. Violating either of
1102 * these conditions will place @surface into an error state. But
1103 * beyond these two conditions, this function will not enforce
1104 * conformance of the comment with any particular specification.
1106 * The comment string should not have a trailing newline.
1108 * The DSC specifies different sections in which particular comments
1109 * can appear. This function provides for comments to be emitted
1110 * within three sections: the header, the Setup section, and the
1111 * PageSetup section. Comments appearing in the first two sections
1112 * apply to the entire document while comments in the BeginPageSetup
1113 * section apply only to a single page.
1115 * For comments to appear in the header section, this function should
1116 * be called after the surface is created, but before a call to
1117 * cairo_ps_surface_begin_setup().
1119 * For comments to appear in the Setup section, this function should
1120 * be called after a call to cairo_ps_surface_begin_setup() but before
1121 * a call to cairo_ps_surface_begin_page_setup().
1123 * For comments to appear in the PageSetup section, this function
1124 * should be called after a call to cairo_ps_surface_begin_page_setup().
1126 * Note that it is only necessary to call cairo_ps_surface_begin_page_setup()
1127 * for the first page of any surface. After a call to
1128 * cairo_show_page() or cairo_copy_page() comments are unambiguously
1129 * directed to the PageSetup section of the current page. But it
1130 * doesn't hurt to call this function at the beginning of every page
1131 * as that consistency may make the calling code simpler.
1133 * As a final note, cairo automatically generates several comments on
1134 * its own. As such, applications must not manually generate any of
1135 * the following comments:
1137 * Header section: %!PS-Adobe-3.0, %%Creator, %%CreationDate, %%Pages,
1138 * %%BoundingBox, %%DocumentData, %%LanguageLevel, %%EndComments.
1140 * Setup section: %%BeginSetup, %%EndSetup
1142 * PageSetup section: %%BeginPageSetup, %%PageBoundingBox,
1145 * Other sections: %%BeginProlog, %%EndProlog, %%Page, %%Trailer, %%EOF
1147 * Here is an example sequence showing how this function might be used:
1149 * <informalexample><programlisting>
1150 * #cairo_surface_t *surface = cairo_ps_surface_create (filename, width, height);
1152 * cairo_ps_surface_dsc_comment (surface, "%%Title: My excellent document");
1153 * cairo_ps_surface_dsc_comment (surface, "%%Copyright: Copyright (C) 2006 Cairo Lover")
1155 * cairo_ps_surface_dsc_begin_setup (surface);
1156 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor White");
1158 * cairo_ps_surface_dsc_begin_page_setup (surface);
1159 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A3");
1160 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *InputSlot LargeCapacity");
1161 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaType Glossy");
1162 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor Blue");
1163 * ... draw to first page here ..
1164 * cairo_show_page (cr);
1166 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A5");
1168 * </programlisting></informalexample>
1173 cairo_ps_surface_dsc_comment (cairo_surface_t
*surface
,
1174 const char *comment
)
1176 cairo_ps_surface_t
*ps_surface
= NULL
;
1177 cairo_status_t status
;
1180 status
= _extract_ps_surface (surface
, &ps_surface
);
1182 status
= _cairo_surface_set_error (surface
, status
);
1186 /* A couple of sanity checks on the comment value. */
1187 if (comment
== NULL
) {
1188 status
= _cairo_surface_set_error (surface
, CAIRO_STATUS_NULL_POINTER
);
1192 if (comment
[0] != '%' || strlen (comment
) > 255) {
1193 status
= _cairo_surface_set_error (surface
, CAIRO_STATUS_INVALID_DSC_COMMENT
);
1197 /* Then, copy the comment and store it in the appropriate array. */
1198 comment_copy
= strdup (comment
);
1199 if (comment_copy
== NULL
) {
1200 status
= _cairo_surface_set_error (surface
, CAIRO_STATUS_NO_MEMORY
);
1204 status
= _cairo_array_append (ps_surface
->dsc_comment_target
, &comment_copy
);
1206 free (comment_copy
);
1207 status
= _cairo_surface_set_error (surface
, status
);
1213 * cairo_ps_surface_dsc_begin_setup:
1214 * @surface: a PostScript #cairo_surface_t
1216 * This function indicates that subsequent calls to
1217 * cairo_ps_surface_dsc_comment() should direct comments to the Setup
1218 * section of the PostScript output.
1220 * This function should be called at most once per surface, and must
1221 * be called before any call to cairo_ps_surface_dsc_begin_page_setup()
1222 * and before any drawing is performed to the surface.
1224 * See cairo_ps_surface_dsc_comment() for more details.
1229 cairo_ps_surface_dsc_begin_setup (cairo_surface_t
*surface
)
1231 cairo_ps_surface_t
*ps_surface
= NULL
;
1232 cairo_status_t status
;
1234 status
= _extract_ps_surface (surface
, &ps_surface
);
1236 status
= _cairo_surface_set_error (surface
, status
);
1240 if (ps_surface
->dsc_comment_target
== &ps_surface
->dsc_header_comments
)
1242 ps_surface
->dsc_comment_target
= &ps_surface
->dsc_setup_comments
;
1247 * cairo_ps_surface_dsc_begin_page_setup:
1248 * @surface: a PostScript #cairo_surface_t
1250 * This function indicates that subsequent calls to
1251 * cairo_ps_surface_dsc_comment() should direct comments to the
1252 * PageSetup section of the PostScript output.
1254 * This function call is only needed for the first page of a
1255 * surface. It should be called after any call to
1256 * cairo_ps_surface_dsc_begin_setup() and before any drawing is
1257 * performed to the surface.
1259 * See cairo_ps_surface_dsc_comment() for more details.
1264 cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t
*surface
)
1266 cairo_ps_surface_t
*ps_surface
= NULL
;
1267 cairo_status_t status
;
1269 status
= _extract_ps_surface (surface
, &ps_surface
);
1271 status
= _cairo_surface_set_error (surface
, status
);
1275 if (ps_surface
->dsc_comment_target
== &ps_surface
->dsc_header_comments
||
1276 ps_surface
->dsc_comment_target
== &ps_surface
->dsc_setup_comments
)
1278 ps_surface
->dsc_comment_target
= &ps_surface
->dsc_page_setup_comments
;
1282 static cairo_surface_t
*
1283 _cairo_ps_surface_create_similar (void *abstract_surface
,
1284 cairo_content_t content
,
1288 return _cairo_meta_surface_create (content
, width
, height
);
1291 static cairo_status_t
1292 _cairo_ps_surface_finish (void *abstract_surface
)
1294 cairo_status_t status
, status2
;
1295 cairo_ps_surface_t
*surface
= abstract_surface
;
1296 int i
, num_comments
;
1299 _cairo_ps_surface_emit_header (surface
);
1301 status
= _cairo_ps_surface_emit_font_subsets (surface
);
1305 status
= _cairo_ps_surface_emit_body (surface
);
1309 _cairo_ps_surface_emit_footer (surface
);
1312 status2
= _cairo_output_stream_destroy (surface
->stream
);
1313 if (status
== CAIRO_STATUS_SUCCESS
)
1316 fclose (surface
->tmpfile
);
1318 status2
= _cairo_output_stream_destroy (surface
->final_stream
);
1319 if (status
== CAIRO_STATUS_SUCCESS
)
1322 num_comments
= _cairo_array_num_elements (&surface
->dsc_header_comments
);
1323 comments
= _cairo_array_index (&surface
->dsc_header_comments
, 0);
1324 for (i
= 0; i
< num_comments
; i
++)
1326 _cairo_array_fini (&surface
->dsc_header_comments
);
1328 num_comments
= _cairo_array_num_elements (&surface
->dsc_setup_comments
);
1329 comments
= _cairo_array_index (&surface
->dsc_setup_comments
, 0);
1330 for (i
= 0; i
< num_comments
; i
++)
1332 _cairo_array_fini (&surface
->dsc_setup_comments
);
1334 num_comments
= _cairo_array_num_elements (&surface
->dsc_page_setup_comments
);
1335 comments
= _cairo_array_index (&surface
->dsc_page_setup_comments
, 0);
1336 for (i
= 0; i
< num_comments
; i
++)
1338 _cairo_array_fini (&surface
->dsc_page_setup_comments
);
1343 static cairo_int_status_t
1344 _cairo_ps_surface_start_page (void *abstract_surface
)
1346 cairo_ps_surface_t
*surface
= abstract_surface
;
1348 /* Increment before print so page numbers start at 1. */
1349 surface
->num_pages
++;
1351 return CAIRO_STATUS_SUCCESS
;
1354 static cairo_int_status_t
1355 _cairo_ps_surface_end_page (cairo_ps_surface_t
*surface
)
1357 cairo_int_status_t status
;
1359 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
1363 _cairo_output_stream_printf (surface
->stream
,
1366 return CAIRO_STATUS_SUCCESS
;
1369 static cairo_int_status_t
1370 _cairo_ps_surface_show_page (void *abstract_surface
)
1372 cairo_ps_surface_t
*surface
= abstract_surface
;
1373 cairo_int_status_t status
;
1375 status
= _cairo_ps_surface_end_page (surface
);
1379 _cairo_output_stream_printf (surface
->stream
, "showpage\n");
1381 return CAIRO_STATUS_SUCCESS
;
1385 color_is_gray (double red
, double green
, double blue
)
1387 const double epsilon
= 0.00001;
1389 return (fabs (red
- green
) < epsilon
&&
1390 fabs (red
- blue
) < epsilon
);
1393 static cairo_int_status_t
1394 _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t
*surface
,
1395 cairo_surface_pattern_t
*pattern
)
1397 cairo_image_surface_t
*image
;
1399 cairo_int_status_t status
;
1400 cairo_image_transparency_t transparency
;
1402 status
= _cairo_surface_acquire_source_image (pattern
->surface
,
1408 if (image
->base
.status
)
1409 return image
->base
.status
;
1411 transparency
= _cairo_image_analyze_transparency (image
);
1412 switch (transparency
) {
1413 case CAIRO_IMAGE_IS_OPAQUE
:
1414 status
= CAIRO_STATUS_SUCCESS
;
1417 case CAIRO_IMAGE_HAS_BILEVEL_ALPHA
:
1418 if (surface
->ps_level
== CAIRO_PS_LEVEL_2
) {
1419 status
= CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
;
1421 surface
->ps_level_used
= CAIRO_PS_LEVEL_3
;
1422 status
= CAIRO_STATUS_SUCCESS
;
1426 case CAIRO_IMAGE_HAS_ALPHA
:
1427 status
= CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
;
1430 case CAIRO_IMAGE_UNKNOWN
:
1434 _cairo_surface_release_source_image (pattern
->surface
, image
, image_extra
);
1440 surface_pattern_supported (cairo_surface_pattern_t
*pattern
)
1442 cairo_extend_t extend
;
1444 if (_cairo_surface_is_meta (pattern
->surface
))
1447 if (pattern
->surface
->backend
->acquire_source_image
== NULL
)
1450 /* Does an ALPHA-only source surface even make sense? Maybe, but I
1451 * don't think it's worth the extra code to support it. */
1453 /* XXX: Need to write this function here...
1454 content = cairo_surface_get_content (pattern->surface);
1455 if (content == CAIRO_CONTENT_ALPHA)
1459 /* Cast away the const, trusting get_extend not to muck with it.
1460 * And I really wish I had a way to cast away just the const, and
1461 * not potentially coerce this pointer to an incorrect type at the
1464 extend
= cairo_pattern_get_extend ((cairo_pattern_t
*)&pattern
->base
);
1466 case CAIRO_EXTEND_NONE
:
1467 case CAIRO_EXTEND_REPEAT
:
1468 case CAIRO_EXTEND_REFLECT
:
1469 /* There's no point returning FALSE for EXTEND_PAD, as the image
1470 * surface does not currently implement it either */
1471 case CAIRO_EXTEND_PAD
:
1480 _gradient_pattern_supported (cairo_ps_surface_t
*surface
,
1481 cairo_pattern_t
*pattern
)
1483 cairo_gradient_pattern_t
*gradient
= (cairo_gradient_pattern_t
*) pattern
;
1485 cairo_extend_t extend
;
1488 if (surface
->ps_level
== CAIRO_PS_LEVEL_2
)
1491 if (gradient
->n_stops
== 0)
1494 /* Alpha gradients are only supported (by flattening the alpha)
1495 * if there is no variation in the alpha across the gradient. */
1496 alpha
= gradient
->stops
[0].color
.alpha_short
;
1497 for (i
= 0; i
< gradient
->n_stops
; i
++) {
1498 if (gradient
->stops
[i
].color
.alpha_short
!= alpha
)
1502 extend
= cairo_pattern_get_extend (pattern
);
1504 /* Radial gradients are currently only supported when one circle
1505 * is inside the other. */
1506 if (pattern
->type
== CAIRO_PATTERN_TYPE_RADIAL
) {
1507 double x1
, y1
, x2
, y2
, r1
, r2
, d
;
1508 cairo_radial_pattern_t
*radial
= (cairo_radial_pattern_t
*) pattern
;
1510 if (extend
== CAIRO_EXTEND_REPEAT
||
1511 extend
== CAIRO_EXTEND_REFLECT
) {
1515 x1
= _cairo_fixed_to_double (radial
->c1
.x
);
1516 y1
= _cairo_fixed_to_double (radial
->c1
.y
);
1517 r1
= _cairo_fixed_to_double (radial
->r1
);
1518 x2
= _cairo_fixed_to_double (radial
->c2
.x
);
1519 y2
= _cairo_fixed_to_double (radial
->c2
.y
);
1520 r2
= _cairo_fixed_to_double (radial
->r2
);
1522 d
= sqrt((x2
- x1
)*(x2
- x1
) + (y2
- y1
)*(y2
- y1
));
1523 if (d
> fabs(r2
- r1
)) {
1528 surface
->ps_level_used
= CAIRO_PS_LEVEL_3
;
1534 pattern_supported (cairo_ps_surface_t
*surface
, cairo_pattern_t
*pattern
)
1536 if (pattern
->type
== CAIRO_PATTERN_TYPE_SOLID
)
1539 if (pattern
->type
== CAIRO_PATTERN_TYPE_LINEAR
||
1540 pattern
->type
== CAIRO_PATTERN_TYPE_RADIAL
)
1541 return _gradient_pattern_supported (surface
, pattern
);
1543 if (pattern
->type
== CAIRO_PATTERN_TYPE_SURFACE
)
1544 return surface_pattern_supported ((cairo_surface_pattern_t
*) pattern
);
1549 static cairo_int_status_t
1550 _cairo_ps_surface_analyze_operation (cairo_ps_surface_t
*surface
,
1551 cairo_operator_t op
,
1552 cairo_pattern_t
*pattern
)
1554 if (surface
->force_fallbacks
&& surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
)
1555 return CAIRO_INT_STATUS_UNSUPPORTED
;
1557 if (! pattern_supported (surface
, pattern
))
1558 return CAIRO_INT_STATUS_UNSUPPORTED
;
1560 if (!(op
== CAIRO_OPERATOR_SOURCE
||
1561 op
== CAIRO_OPERATOR_OVER
))
1562 return CAIRO_INT_STATUS_UNSUPPORTED
;
1564 if (pattern
->type
== CAIRO_PATTERN_TYPE_SURFACE
) {
1565 cairo_surface_pattern_t
*surface_pattern
= (cairo_surface_pattern_t
*) pattern
;
1567 if ( _cairo_surface_is_meta (surface_pattern
->surface
))
1568 return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN
;
1571 if (op
== CAIRO_OPERATOR_SOURCE
)
1572 return CAIRO_STATUS_SUCCESS
;
1574 /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
1575 * the pattern contains transparency, we return
1576 * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
1577 * surface. If the analysis surface determines that there is
1578 * anything drawn under this operation, a fallback image will be
1579 * used. Otherwise the operation will be replayed during the
1580 * render stage and we blend the transparency into the white
1581 * background to convert the pattern to opaque.
1584 if (pattern
->type
== CAIRO_PATTERN_TYPE_SURFACE
) {
1585 cairo_surface_pattern_t
*surface_pattern
= (cairo_surface_pattern_t
*) pattern
;
1587 return _cairo_ps_surface_analyze_surface_pattern_transparency (surface
,
1591 if (_cairo_pattern_is_opaque (pattern
))
1592 return CAIRO_STATUS_SUCCESS
;
1594 return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
;
1598 _cairo_ps_surface_operation_supported (cairo_ps_surface_t
*surface
,
1599 cairo_operator_t op
,
1600 cairo_pattern_t
*pattern
)
1602 if (_cairo_ps_surface_analyze_operation (surface
, op
, pattern
) != CAIRO_INT_STATUS_UNSUPPORTED
)
1608 /* The "standard" implementation limit for PostScript string sizes is
1609 * 65535 characters (see PostScript Language Reference, Appendix
1610 * B). We go one short of that because we sometimes need two
1611 * characters in a string to represent a single ASCII85 byte, (for the
1612 * escape sequences "\\", "\(", and "\)") and we must not split these
1613 * across two strings. So we'd be in trouble if we went right to the
1614 * limit and one of these escape sequences just happened to land at
1617 #define STRING_ARRAY_MAX_STRING_SIZE (65535-1)
1618 #define STRING_ARRAY_MAX_COLUMN 72
1620 typedef struct _string_array_stream
{
1621 cairo_output_stream_t base
;
1622 cairo_output_stream_t
*output
;
1625 cairo_bool_t use_strings
;
1626 } string_array_stream_t
;
1628 static cairo_status_t
1629 _string_array_stream_write (cairo_output_stream_t
*base
,
1630 const unsigned char *data
,
1631 unsigned int length
)
1633 string_array_stream_t
*stream
= (string_array_stream_t
*) base
;
1635 const unsigned char backslash
= '\\';
1638 return CAIRO_STATUS_SUCCESS
;
1641 if (stream
->string_size
== 0 && stream
->use_strings
) {
1642 _cairo_output_stream_printf (stream
->output
, "(");
1647 if (stream
->use_strings
) {
1652 _cairo_output_stream_write (stream
->output
, &backslash
, 1);
1654 stream
->string_size
++;
1658 /* Have to be careful to never split the final ~> sequence. */
1660 _cairo_output_stream_write (stream
->output
, &c
, 1);
1662 stream
->string_size
++;
1669 _cairo_output_stream_write (stream
->output
, &c
, 1);
1671 stream
->string_size
++;
1673 if (stream
->use_strings
&&
1674 stream
->string_size
>= STRING_ARRAY_MAX_STRING_SIZE
)
1676 _cairo_output_stream_printf (stream
->output
, ")\n");
1677 stream
->string_size
= 0;
1680 if (stream
->column
>= STRING_ARRAY_MAX_COLUMN
) {
1681 _cairo_output_stream_printf (stream
->output
, "\n ");
1682 stream
->string_size
+= 2;
1687 return _cairo_output_stream_get_status (stream
->output
);
1690 static cairo_status_t
1691 _string_array_stream_close (cairo_output_stream_t
*base
)
1693 cairo_status_t status
;
1694 string_array_stream_t
*stream
= (string_array_stream_t
*) base
;
1696 if (stream
->use_strings
)
1697 _cairo_output_stream_printf (stream
->output
, ")\n");
1699 status
= _cairo_output_stream_get_status (stream
->output
);
1704 /* A string_array_stream wraps an existing output stream. It takes the
1705 * data provided to it and output one or more consecutive string
1706 * objects, each within the standard PostScript implementation limit
1707 * of 65k characters.
1709 * The strings are each separated by a space character for easy
1710 * inclusion within an array object, (but the array delimiters are not
1711 * added by the string_array_stream).
1713 * The string array stream is also careful to wrap the output within
1714 * STRING_ARRAY_MAX_COLUMN columns (+/- 1). The stream also adds
1715 * necessary escaping for special characters within a string,
1716 * (specifically '\', '(', and ')').
1718 static cairo_output_stream_t
*
1719 _string_array_stream_create (cairo_output_stream_t
*output
)
1721 string_array_stream_t
*stream
;
1723 stream
= malloc (sizeof (string_array_stream_t
));
1724 if (stream
== NULL
) {
1725 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
1726 return (cairo_output_stream_t
*) &_cairo_output_stream_nil
;
1729 _cairo_output_stream_init (&stream
->base
,
1730 _string_array_stream_write
,
1731 _string_array_stream_close
);
1732 stream
->output
= output
;
1734 stream
->string_size
= 0;
1735 stream
->use_strings
= TRUE
;
1737 return &stream
->base
;
1740 /* A base85_array_stream wraps an existing output stream. It wraps the
1741 * output within STRING_ARRAY_MAX_COLUMN columns (+/- 1). The output
1742 * is not enclosed in strings like string_array_stream.
1744 static cairo_output_stream_t
*
1745 _base85_array_stream_create (cairo_output_stream_t
*output
)
1747 string_array_stream_t
*stream
;
1749 stream
= malloc (sizeof (string_array_stream_t
));
1750 if (stream
== NULL
) {
1751 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
1752 return (cairo_output_stream_t
*) &_cairo_output_stream_nil
;
1755 _cairo_output_stream_init (&stream
->base
,
1756 _string_array_stream_write
,
1757 _string_array_stream_close
);
1758 stream
->output
= output
;
1760 stream
->string_size
= 0;
1761 stream
->use_strings
= FALSE
;
1763 return &stream
->base
;
1767 /* PS Output - this section handles output of the parts of the meta
1768 * surface we can render natively in PS. */
1770 static cairo_status_t
1771 _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t
*surface
,
1772 cairo_image_surface_t
*image
,
1773 cairo_image_surface_t
**opaque_image
)
1775 const cairo_color_t
*background_color
;
1776 cairo_surface_t
*opaque
;
1777 cairo_surface_pattern_t pattern
;
1778 cairo_status_t status
;
1780 if (surface
->content
== CAIRO_CONTENT_COLOR_ALPHA
)
1781 background_color
= CAIRO_COLOR_WHITE
;
1783 background_color
= CAIRO_COLOR_BLACK
;
1785 opaque
= cairo_image_surface_create (CAIRO_FORMAT_RGB24
,
1789 return opaque
->status
;
1791 _cairo_pattern_init_for_surface (&pattern
, &image
->base
);
1793 status
= _cairo_surface_fill_rectangle (opaque
,
1794 CAIRO_OPERATOR_SOURCE
,
1797 image
->width
, image
->height
);
1801 status
= _cairo_surface_composite (CAIRO_OPERATOR_OVER
,
1813 _cairo_pattern_fini (&pattern
.base
);
1814 *opaque_image
= (cairo_image_surface_t
*) opaque
;
1816 return CAIRO_STATUS_SUCCESS
;
1819 _cairo_pattern_fini (&pattern
.base
);
1820 cairo_surface_destroy (opaque
);
1825 static cairo_status_t
1826 _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t
*surface
,
1827 unsigned char *data
,
1828 unsigned long length
,
1829 cairo_bool_t use_strings
)
1831 cairo_output_stream_t
*base85_stream
, *string_array_stream
;
1832 cairo_status_t status
, status2
;
1835 string_array_stream
= _string_array_stream_create (surface
->stream
);
1837 string_array_stream
= _base85_array_stream_create (surface
->stream
);
1839 status
= _cairo_output_stream_get_status (string_array_stream
);
1841 return _cairo_output_stream_destroy (string_array_stream
);
1843 base85_stream
= _cairo_base85_stream_create (string_array_stream
);
1844 status
= _cairo_output_stream_get_status (base85_stream
);
1846 status2
= _cairo_output_stream_destroy (string_array_stream
);
1847 return _cairo_output_stream_destroy (base85_stream
);
1850 _cairo_output_stream_write (base85_stream
, data
, length
);
1852 status
= _cairo_output_stream_destroy (base85_stream
);
1853 status2
= _cairo_output_stream_destroy (string_array_stream
);
1854 if (status
== CAIRO_STATUS_SUCCESS
)
1860 static cairo_status_t
1861 _cairo_ps_surface_emit_image (cairo_ps_surface_t
*surface
,
1862 cairo_image_surface_t
*image
,
1863 cairo_operator_t op
)
1865 cairo_status_t status
;
1866 unsigned char *data
, *data_compressed
;
1867 unsigned long data_size
, data_compressed_size
;
1868 cairo_image_surface_t
*opaque_image
= NULL
;
1870 cairo_image_transparency_t transparency
;
1871 cairo_bool_t use_mask
;
1875 if (image
->base
.status
)
1876 return image
->base
.status
;
1878 transparency
= _cairo_image_analyze_transparency (image
);
1880 /* PostScript can not represent the alpha channel, so we blend the
1881 current image over a white (or black for CONTENT_COLOR
1882 surfaces) RGB surface to eliminate it. */
1884 if (op
== CAIRO_OPERATOR_SOURCE
||
1885 transparency
== CAIRO_IMAGE_HAS_ALPHA
||
1886 (transparency
== CAIRO_IMAGE_HAS_BILEVEL_ALPHA
&&
1887 surface
->ps_level
== CAIRO_PS_LEVEL_2
))
1889 status
= _cairo_ps_surface_flatten_image_transparency (surface
,
1896 } else if (transparency
== CAIRO_IMAGE_IS_OPAQUE
) {
1897 opaque_image
= image
;
1904 /* Type 2 (mask and image interleaved) has the mask and image
1905 * samples interleaved by row. The mask row is first, one bit
1906 * per pixel with (bit 7 first). The row is padded to byte
1907 * boundaries. The image data is 3 bytes per pixel RGB
1909 data_size
= image
->height
* ((image
->width
+ 7)/8 + 3*image
->width
);
1911 data_size
= image
->height
* image
->width
* 3;
1913 data
= malloc (data_size
);
1915 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1921 for (y
= 0; y
< image
->height
; y
++) {
1923 pixel
= (uint32_t *) (image
->data
+ y
* image
->stride
);
1925 for (x
= 0; x
< image
->width
; x
++, pixel
++) {
1928 if (((*pixel
& 0xff000000) >> 24) > 0x80)
1929 data
[i
] |= (1 << bit
);
1940 pixel
= (uint32_t *) (image
->data
+ y
* image
->stride
);
1941 for (x
= 0; x
< image
->width
; x
++, pixel
++) {
1942 data
[i
++] = (*pixel
& 0x00ff0000) >> 16;
1943 data
[i
++] = (*pixel
& 0x0000ff00) >> 8;
1944 data
[i
++] = (*pixel
& 0x000000ff) >> 0;
1949 for (y
= 0; y
< opaque_image
->height
; y
++) {
1950 pixel
= (uint32_t *) (opaque_image
->data
+ y
* opaque_image
->stride
);
1951 for (x
= 0; x
< opaque_image
->width
; x
++, pixel
++) {
1952 data
[i
++] = (*pixel
& 0x00ff0000) >> 16;
1953 data
[i
++] = (*pixel
& 0x0000ff00) >> 8;
1954 data
[i
++] = (*pixel
& 0x000000ff) >> 0;
1959 /* XXX: Should fix cairo-lzw to provide a stream-based interface
1961 data_compressed_size
= data_size
;
1962 data_compressed
= _cairo_lzw_compress (data
, &data_compressed_size
);
1963 if (data_compressed
== NULL
) {
1964 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1968 if (surface
->use_string_datasource
) {
1969 /* Emit the image data as a base85-encoded string which will
1970 * be used as the data source for the image operator later. */
1971 _cairo_output_stream_printf (surface
->stream
,
1972 "/CairoImageData [\n");
1974 status
= _cairo_ps_surface_emit_base85_string (surface
,
1976 data_compressed_size
,
1981 _cairo_output_stream_printf (surface
->stream
,
1983 _cairo_output_stream_printf (surface
->stream
,
1984 "/CairoImageDataIndex 0 def\n");
1988 _cairo_output_stream_printf (surface
->stream
,
1989 "/DeviceRGB setcolorspace\n"
1990 "5 dict dup begin\n"
1991 " /ImageType 3 def\n"
1992 " /InterleaveType 2 def\n"
1993 " /DataDict 8 dict def\n"
1995 " /ImageType 1 def\n"
1998 " /BitsPerComponent 8 def\n"
1999 " /Decode [ 0 1 0 1 0 1 ] def\n",
2003 if (surface
->use_string_datasource
) {
2004 _cairo_output_stream_printf (surface
->stream
,
2006 " CairoImageData CairoImageDataIndex get\n"
2007 " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2008 " CairoImageDataIndex CairoImageData length 1 sub gt\n"
2009 " { /CairoImageDataIndex 0 def } if\n"
2010 " } /ASCII85Decode filter /LZWDecode filter def\n");
2012 _cairo_output_stream_printf (surface
->stream
,
2013 " /DataSource currentfile /ASCII85Decode filter /LZWDecode filter def\n");
2016 _cairo_output_stream_printf (surface
->stream
,
2017 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2019 " /MaskDict 8 dict def\n"
2021 " /ImageType 1 def\n"
2024 " /BitsPerComponent 1 def\n"
2025 " /Decode [ 1 0 ] def\n"
2026 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2035 _cairo_output_stream_printf (surface
->stream
,
2036 "/DeviceRGB setcolorspace\n"
2037 "8 dict dup begin\n"
2038 " /ImageType 1 def\n"
2041 " /BitsPerComponent 8 def\n"
2042 " /Decode [ 0 1 0 1 0 1 ] def\n",
2043 opaque_image
->width
,
2044 opaque_image
->height
);
2045 if (surface
->use_string_datasource
) {
2046 _cairo_output_stream_printf (surface
->stream
,
2048 " CairoImageData CairoImageDataIndex get\n"
2049 " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2050 " CairoImageDataIndex CairoImageData length 1 sub gt\n"
2051 " { /CairoImageDataIndex 0 def } if\n"
2052 " } /ASCII85Decode filter /LZWDecode filter def\n");
2054 _cairo_output_stream_printf (surface
->stream
,
2055 " /DataSource currentfile /ASCII85Decode filter /LZWDecode filter def\n");
2058 _cairo_output_stream_printf (surface
->stream
,
2059 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2062 opaque_image
->height
);
2065 if (!surface
->use_string_datasource
) {
2066 /* Emit the image data as a base85-encoded string which will
2067 * be used as the data source for the image operator. */
2068 status
= _cairo_ps_surface_emit_base85_string (surface
,
2070 data_compressed_size
,
2073 status
= CAIRO_STATUS_SUCCESS
;
2077 free (data_compressed
);
2083 if (!use_mask
&& opaque_image
!= image
)
2084 cairo_surface_destroy (&opaque_image
->base
);
2089 static cairo_status_t
2090 _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t
*surface
,
2091 cairo_surface_t
*meta_surface
)
2093 double old_width
, old_height
;
2094 cairo_matrix_t old_cairo_to_ps
;
2095 cairo_content_t old_content
;
2096 cairo_clip_t
*old_clip
;
2097 cairo_rectangle_int_t meta_extents
;
2098 cairo_status_t status
;
2100 status
= _cairo_surface_get_extents (meta_surface
, &meta_extents
);
2104 old_content
= surface
->content
;
2105 old_width
= surface
->width
;
2106 old_height
= surface
->height
;
2107 old_cairo_to_ps
= surface
->cairo_to_ps
;
2108 old_clip
= _cairo_surface_get_clip (&surface
->base
);
2109 surface
->width
= meta_extents
.width
;
2110 surface
->height
= meta_extents
.height
;
2111 surface
->current_pattern_is_solid_color
= FALSE
;
2112 _cairo_pdf_operators_reset (&surface
->pdf_operators
);
2113 cairo_matrix_init (&surface
->cairo_to_ps
, 1, 0, 0, -1, 0, surface
->height
);
2114 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface
->pdf_operators
,
2115 &surface
->cairo_to_ps
);
2116 _cairo_output_stream_printf (surface
->stream
,
2118 " 0 0 %f %f rectclip\n",
2122 if (cairo_surface_get_content (meta_surface
) == CAIRO_CONTENT_COLOR
) {
2123 surface
->content
= CAIRO_CONTENT_COLOR
;
2124 _cairo_output_stream_printf (surface
->stream
,
2125 " 0 g 0 0 %f %f rectfill\n",
2130 status
= _cairo_meta_surface_replay_region (meta_surface
, &surface
->base
,
2131 CAIRO_META_REGION_NATIVE
);
2132 assert (status
!= CAIRO_INT_STATUS_UNSUPPORTED
);
2136 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
2140 _cairo_output_stream_printf (surface
->stream
,
2142 surface
->content
= old_content
;
2143 surface
->width
= old_width
;
2144 surface
->height
= old_height
;
2145 surface
->current_pattern_is_solid_color
= FALSE
;
2146 _cairo_pdf_operators_reset (&surface
->pdf_operators
);
2147 surface
->cairo_to_ps
= old_cairo_to_ps
;
2148 status
= _cairo_surface_set_clip (&surface
->base
, old_clip
);
2152 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface
->pdf_operators
,
2153 &surface
->cairo_to_ps
);
2155 return CAIRO_STATUS_SUCCESS
;
2159 _cairo_ps_surface_flatten_transparency (cairo_ps_surface_t
*surface
,
2160 const cairo_color_t
*color
,
2166 *green
= color
->green
;
2167 *blue
= color
->blue
;
2169 if (! CAIRO_COLOR_IS_OPAQUE (color
)) {
2170 *red
*= color
->alpha
;
2171 *green
*= color
->alpha
;
2172 *blue
*= color
->alpha
;
2173 if (surface
->content
== CAIRO_CONTENT_COLOR_ALPHA
) {
2174 double one_minus_alpha
= 1. - color
->alpha
;
2175 *red
+= one_minus_alpha
;
2176 *green
+= one_minus_alpha
;
2177 *blue
+= one_minus_alpha
;
2183 _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t
*surface
,
2184 cairo_solid_pattern_t
*pattern
)
2186 double red
, green
, blue
;
2188 _cairo_ps_surface_flatten_transparency (surface
, &pattern
->color
, &red
, &green
, &blue
);
2190 if (color_is_gray (red
, green
, blue
))
2191 _cairo_output_stream_printf (surface
->stream
,
2195 _cairo_output_stream_printf (surface
->stream
,
2200 static cairo_status_t
2201 _cairo_ps_surface_acquire_surface (cairo_ps_surface_t
*surface
,
2202 cairo_surface_pattern_t
*pattern
,
2205 cairo_operator_t op
)
2207 cairo_status_t status
;
2209 if (_cairo_surface_is_meta (pattern
->surface
)) {
2210 cairo_surface_t
*meta_surface
= pattern
->surface
;
2211 cairo_rectangle_int_t pattern_extents
;
2213 status
= _cairo_surface_get_extents (meta_surface
, &pattern_extents
);
2217 *width
= pattern_extents
.width
;
2218 *height
= pattern_extents
.height
;
2220 status
= _cairo_surface_acquire_source_image (pattern
->surface
,
2222 &surface
->image_extra
);
2226 *width
= surface
->image
->width
;
2227 *height
= surface
->image
->height
;
2230 return CAIRO_STATUS_SUCCESS
;
2233 static cairo_status_t
2234 _cairo_ps_surface_emit_surface (cairo_ps_surface_t
*surface
,
2235 cairo_surface_pattern_t
*pattern
,
2236 cairo_operator_t op
)
2238 cairo_status_t status
;
2240 if (_cairo_surface_is_meta (pattern
->surface
)) {
2241 cairo_surface_t
*meta_surface
= pattern
->surface
;
2243 status
= _cairo_ps_surface_emit_meta_surface (surface
,
2246 status
= _cairo_ps_surface_emit_image (surface
, surface
->image
, op
);
2253 _cairo_ps_surface_release_surface (cairo_ps_surface_t
*surface
,
2254 cairo_surface_pattern_t
*pattern
)
2256 if (!_cairo_surface_is_meta (pattern
->surface
))
2257 _cairo_surface_release_source_image (pattern
->surface
, surface
->image
,
2258 surface
->image_extra
);
2261 static cairo_status_t
2262 _cairo_ps_surface_paint_surface (cairo_ps_surface_t
*surface
,
2263 cairo_surface_pattern_t
*pattern
,
2264 cairo_operator_t op
)
2266 cairo_status_t status
;
2268 cairo_matrix_t cairo_p2d
, ps_p2d
;
2270 status
= _cairo_ps_surface_acquire_surface (surface
,
2278 cairo_p2d
= pattern
->base
.matrix
;
2280 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_FALLBACK
) {
2281 double scale
= cairo_p2d
.xx
;
2283 _cairo_output_stream_printf (surface
->stream
,
2284 "%% Fallback Image: x=%f, y=%f, w=%d, h=%d res=%fdpi size=%ld\n",
2285 -cairo_p2d
.x0
/scale
,
2286 -cairo_p2d
.y0
/scale
,
2288 (int)(height
/scale
),
2290 (long)width
*height
*3);
2292 if (op
== CAIRO_OPERATOR_SOURCE
) {
2293 _cairo_output_stream_printf (surface
->stream
,
2294 "%d g 0 0 %f %f rectfill\n",
2295 surface
->content
== CAIRO_CONTENT_COLOR
? 0 : 1,
2301 status
= cairo_matrix_invert (&cairo_p2d
);
2302 /* cairo_pattern_set_matrix ensures the matrix is invertible */
2303 assert (status
== CAIRO_STATUS_SUCCESS
);
2305 ps_p2d
= surface
->cairo_to_ps
;
2306 cairo_matrix_multiply (&ps_p2d
, &cairo_p2d
, &ps_p2d
);
2307 cairo_matrix_translate (&ps_p2d
, 0.0, height
);
2308 cairo_matrix_scale (&ps_p2d
, 1.0, -1.0);
2310 if (! _cairo_matrix_is_identity (&ps_p2d
)) {
2311 _cairo_output_stream_printf (surface
->stream
,
2312 "[ %f %f %f %f %f %f ] concat\n",
2313 ps_p2d
.xx
, ps_p2d
.yx
,
2314 ps_p2d
.xy
, ps_p2d
.yy
,
2315 ps_p2d
.x0
, ps_p2d
.y0
);
2318 status
= _cairo_ps_surface_emit_surface (surface
, pattern
, op
);
2319 _cairo_ps_surface_release_surface (surface
, pattern
);
2324 static cairo_status_t
2325 _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t
*surface
,
2326 cairo_surface_pattern_t
*pattern
,
2327 cairo_operator_t op
)
2329 cairo_status_t status
;
2330 int pattern_width
= 0; /* squelch bogus compiler warning */
2331 int pattern_height
= 0; /* squelch bogus compiler warning */
2332 double xstep
, ystep
;
2333 cairo_matrix_t cairo_p2d
, ps_p2d
;
2334 cairo_rectangle_int_t surface_extents
;
2335 cairo_bool_t old_use_string_datasource
;
2337 cairo_p2d
= pattern
->base
.matrix
;
2338 status
= cairo_matrix_invert (&cairo_p2d
);
2339 /* cairo_pattern_set_matrix ensures the matrix is invertible */
2340 assert (status
== CAIRO_STATUS_SUCCESS
);
2342 ps_p2d
= surface
->cairo_to_ps
;
2343 cairo_matrix_multiply (&ps_p2d
, &cairo_p2d
, &ps_p2d
);
2344 cairo_matrix_translate (&ps_p2d
, 0.0, pattern_height
);
2345 cairo_matrix_scale (&ps_p2d
, 1.0, -1.0);
2347 status
= _cairo_ps_surface_acquire_surface (surface
,
2355 switch (pattern
->base
.extend
) {
2356 /* We implement EXTEND_PAD like EXTEND_NONE for now */
2357 case CAIRO_EXTEND_PAD
:
2358 case CAIRO_EXTEND_NONE
:
2360 /* In PS/PDF, (as far as I can tell), all patterns are
2361 * repeating. So we support cairo's EXTEND_NONE semantics
2362 * by setting the repeat step size to a size large enough
2363 * to guarantee that no more than a single occurrence will
2366 * First, map the surface extents into pattern space (since
2367 * xstep and ystep are in pattern space). Then use an upper
2368 * bound on the length of the diagonal of the pattern image
2369 * and the surface as repeat size. This guarantees to never
2372 double x1
= 0.0, y1
= 0.0;
2373 double x2
= surface
->width
, y2
= surface
->height
;
2374 _cairo_matrix_transform_bounding_box (&pattern
->base
.matrix
,
2378 /* Rather than computing precise bounds of the union, just
2379 * add the surface extents unconditionally. We only
2380 * required an answer that's large enough, we don't really
2381 * care if it's not as tight as possible.*/
2382 xstep
= ystep
= ceil ((x2
- x1
) + (y2
- y1
) +
2383 pattern_width
+ pattern_height
);
2386 case CAIRO_EXTEND_REPEAT
:
2387 xstep
= pattern_width
;
2388 ystep
= pattern_height
;
2390 case CAIRO_EXTEND_REFLECT
:
2391 xstep
= pattern_width
*2;
2392 ystep
= pattern_height
*2;
2394 /* All the rest (if any) should have been analyzed away, so these
2395 * cases should be unreachable. */
2402 _cairo_output_stream_printf (surface
->stream
,
2403 "/CairoPattern {\n");
2405 old_use_string_datasource
= surface
->use_string_datasource
;
2406 surface
->use_string_datasource
= TRUE
;
2407 if (op
== CAIRO_OPERATOR_SOURCE
) {
2408 _cairo_output_stream_printf (surface
->stream
,
2409 "%d g 0 0 %f %f rectfill\n",
2410 surface
->content
== CAIRO_CONTENT_COLOR
? 0 : 1,
2413 status
= _cairo_ps_surface_emit_surface (surface
, pattern
, op
);
2417 surface
->use_string_datasource
= old_use_string_datasource
;
2418 _cairo_output_stream_printf (surface
->stream
,
2421 _cairo_output_stream_printf (surface
->stream
,
2422 "<< /PatternType 1\n"
2424 " /TilingType 1\n");
2425 _cairo_output_stream_printf (surface
->stream
,
2426 " /XStep %f /YStep %f\n",
2429 if (pattern
->base
.extend
== CAIRO_EXTEND_REFLECT
) {
2430 _cairo_output_stream_printf (surface
->stream
,
2431 " /BBox [0 0 %d %d]\n"
2434 " [-1 0 0 1 %d 0] concat CairoPattern\n"
2435 " [ 1 0 0 -1 0 %d] concat CairoPattern\n"
2436 " [-1 0 0 1 %d 0] concat CairoPattern\n"
2439 pattern_width
*2, pattern_height
*2,
2444 if (op
== CAIRO_OPERATOR_SOURCE
) {
2445 _cairo_output_stream_printf (surface
->stream
,
2446 " /BBox [0 0 %f %f]\n",
2449 _cairo_output_stream_printf (surface
->stream
,
2450 " /BBox [0 0 %d %d]\n",
2451 pattern_width
, pattern_height
);
2453 _cairo_output_stream_printf (surface
->stream
,
2454 " /PaintProc { CairoPattern }\n");
2457 _cairo_output_stream_printf (surface
->stream
,
2460 status
= _cairo_surface_get_extents (&surface
->base
, &surface_extents
);
2464 cairo_p2d
= pattern
->base
.matrix
;
2465 status
= cairo_matrix_invert (&cairo_p2d
);
2466 /* cairo_pattern_set_matrix ensures the matrix is invertible */
2467 assert (status
== CAIRO_STATUS_SUCCESS
);
2469 cairo_matrix_init_identity (&ps_p2d
);
2470 cairo_matrix_translate (&ps_p2d
, 0.0, surface_extents
.height
);
2471 cairo_matrix_scale (&ps_p2d
, 1.0, -1.0);
2472 cairo_matrix_multiply (&ps_p2d
, &cairo_p2d
, &ps_p2d
);
2473 cairo_matrix_translate (&ps_p2d
, 0.0, pattern_height
);
2474 cairo_matrix_scale (&ps_p2d
, 1.0, -1.0);
2476 _cairo_output_stream_printf (surface
->stream
,
2477 "[ %f %f %f %f %f %f ]\n",
2478 ps_p2d
.xx
, ps_p2d
.yx
,
2479 ps_p2d
.xy
, ps_p2d
.yy
,
2480 ps_p2d
.x0
, ps_p2d
.y0
);
2481 _cairo_output_stream_printf (surface
->stream
,
2482 "makepattern setpattern\n");
2484 return CAIRO_STATUS_SUCCESS
;
2487 typedef struct _cairo_ps_color_stop
{
2490 } cairo_ps_color_stop_t
;
2493 _cairo_ps_surface_emit_linear_colorgradient (cairo_ps_surface_t
*surface
,
2494 cairo_ps_color_stop_t
*stop1
,
2495 cairo_ps_color_stop_t
*stop2
)
2497 _cairo_output_stream_printf (surface
->stream
,
2498 " << /FunctionType 2\n"
2499 " /Domain [ 0 1 ]\n"
2500 " /C0 [ %f %f %f ]\n"
2501 " /C1 [ %f %f %f ]\n"
2513 _cairo_ps_surface_emit_stitched_colorgradient (cairo_ps_surface_t
*surface
,
2514 unsigned int n_stops
,
2515 cairo_ps_color_stop_t stops
[])
2519 _cairo_output_stream_printf (surface
->stream
,
2520 "<< /FunctionType 3\n"
2521 " /Domain [ 0 1 ]\n"
2523 for (i
= 0; i
< n_stops
- 1; i
++)
2524 _cairo_ps_surface_emit_linear_colorgradient (surface
, &stops
[i
], &stops
[i
+1]);
2526 _cairo_output_stream_printf (surface
->stream
, " ]\n");
2528 _cairo_output_stream_printf (surface
->stream
, " /Bounds [ ");
2529 for (i
= 1; i
< n_stops
-1; i
++)
2530 _cairo_output_stream_printf (surface
->stream
, "%f ", stops
[i
].offset
);
2531 _cairo_output_stream_printf (surface
->stream
, "]\n");
2533 _cairo_output_stream_printf (surface
->stream
, " /Encode [ 1 1 %d { pop 0 1 } for ]\n",
2536 _cairo_output_stream_printf (surface
->stream
, ">>\n");
2540 calc_gradient_color (cairo_ps_color_stop_t
*new_stop
,
2541 cairo_ps_color_stop_t
*stop1
,
2542 cairo_ps_color_stop_t
*stop2
)
2545 double offset
= stop1
->offset
/ (stop1
->offset
+ 1.0 - stop2
->offset
);
2547 for (i
= 0; i
< 4; i
++)
2548 new_stop
->color
[i
] = stop1
->color
[i
] + offset
*(stop2
->color
[i
] - stop1
->color
[i
]);
2551 #define COLOR_STOP_EPSILON 1e-6
2553 static cairo_status_t
2554 _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t
*surface
,
2555 cairo_gradient_pattern_t
*pattern
)
2557 cairo_ps_color_stop_t
*allstops
, *stops
;
2558 unsigned int i
, n_stops
;
2560 allstops
= _cairo_malloc_ab ((pattern
->n_stops
+ 2), sizeof (cairo_ps_color_stop_t
));
2561 if (allstops
== NULL
)
2562 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
2564 stops
= &allstops
[1];
2565 n_stops
= pattern
->n_stops
;
2567 for (i
= 0; i
< n_stops
; i
++) {
2568 cairo_gradient_stop_t
*stop
= &pattern
->stops
[i
];
2570 stops
[i
].color
[0] = stop
->color
.red
;
2571 stops
[i
].color
[1] = stop
->color
.green
;
2572 stops
[i
].color
[2] = stop
->color
.blue
;
2573 stops
[i
].color
[3] = stop
->color
.alpha
;
2574 stops
[i
].offset
= pattern
->stops
[i
].offset
;
2577 if (pattern
->base
.extend
== CAIRO_EXTEND_REPEAT
||
2578 pattern
->base
.extend
== CAIRO_EXTEND_REFLECT
) {
2579 if (stops
[0].offset
> COLOR_STOP_EPSILON
) {
2580 if (pattern
->base
.extend
== CAIRO_EXTEND_REFLECT
)
2581 memcpy (allstops
, stops
, sizeof (cairo_ps_color_stop_t
));
2583 calc_gradient_color (&allstops
[0], &stops
[0], &stops
[n_stops
-1]);
2587 stops
[0].offset
= 0.0;
2589 if (stops
[n_stops
-1].offset
< 1.0 - COLOR_STOP_EPSILON
) {
2590 if (pattern
->base
.extend
== CAIRO_EXTEND_REFLECT
) {
2591 memcpy (&stops
[n_stops
],
2592 &stops
[n_stops
- 1],
2593 sizeof (cairo_ps_color_stop_t
));
2595 calc_gradient_color (&stops
[n_stops
], &stops
[0], &stops
[n_stops
-1]);
2599 stops
[n_stops
-1].offset
= 1.0;
2602 for (i
= 0; i
< n_stops
; i
++) {
2603 double red
, green
, blue
;
2604 cairo_color_t color
;
2606 _cairo_color_init_rgba (&color
,
2611 _cairo_ps_surface_flatten_transparency (surface
, &color
,
2612 &red
, &green
, &blue
);
2613 stops
[i
].color
[0] = red
;
2614 stops
[i
].color
[1] = green
;
2615 stops
[i
].color
[2] = blue
;
2618 _cairo_output_stream_printf (surface
->stream
,
2619 "/CairoFunction\n");
2621 /* no need for stitched function */
2622 _cairo_ps_surface_emit_linear_colorgradient (surface
, &stops
[0], &stops
[1]);
2624 /* multiple stops: stitch. XXX possible optimization: regulary spaced
2625 * stops do not require stitching. XXX */
2626 _cairo_ps_surface_emit_stitched_colorgradient (surface
, n_stops
,stops
);
2628 _cairo_output_stream_printf (surface
->stream
,
2633 return CAIRO_STATUS_SUCCESS
;
2636 static cairo_status_t
2637 _cairo_ps_surface_emit_repeating_function (cairo_ps_surface_t
*surface
,
2638 cairo_gradient_pattern_t
*pattern
,
2642 _cairo_output_stream_printf (surface
->stream
,
2644 "<< /FunctionType 3\n"
2645 " /Domain [ %d %d ]\n"
2646 " /Functions [ %d {CairoFunction} repeat ]\n"
2647 " /Bounds [ %d 1 %d {} for ]\n",
2654 if (pattern
->base
.extend
== CAIRO_EXTEND_REFLECT
) {
2655 _cairo_output_stream_printf (surface
->stream
, " /Encode [ %d 1 %d { 2 mod 0 eq {0 1} {1 0} ifelse } for ]\n",
2659 _cairo_output_stream_printf (surface
->stream
, " /Encode [ %d 1 %d { pop 0 1 } for ]\n",
2664 _cairo_output_stream_printf (surface
->stream
, ">> def\n");
2666 return CAIRO_STATUS_SUCCESS
;
2669 static cairo_status_t
2670 _cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t
*surface
,
2671 cairo_linear_pattern_t
*pattern
)
2673 double x1
, y1
, x2
, y2
;
2674 double _x1
, _y1
, _x2
, _y2
;
2675 cairo_matrix_t pat_to_ps
;
2676 cairo_extend_t extend
;
2677 cairo_status_t status
;
2678 cairo_gradient_pattern_t
*gradient
= &pattern
->base
;
2679 double first_stop
, last_stop
;
2680 int repeat_begin
= 0, repeat_end
= 1;
2682 if (pattern
->base
.n_stops
== 0)
2683 return CAIRO_INT_STATUS_NOTHING_TO_DO
;
2685 if (pattern
->base
.n_stops
== 1) {
2686 cairo_solid_pattern_t solid
;
2688 _cairo_pattern_init_solid (&solid
,
2689 &pattern
->base
.stops
[0].color
,
2690 CAIRO_CONTENT_COLOR_ALPHA
);
2691 _cairo_ps_surface_emit_solid_pattern (surface
,
2693 _cairo_pattern_fini (&solid
.base
);
2695 return CAIRO_STATUS_SUCCESS
;
2698 extend
= cairo_pattern_get_extend (&pattern
->base
.base
);
2700 pat_to_ps
= pattern
->base
.base
.matrix
;
2701 status
= cairo_matrix_invert (&pat_to_ps
);
2702 /* cairo_pattern_set_matrix ensures the matrix is invertible */
2703 assert (status
== CAIRO_STATUS_SUCCESS
);
2705 cairo_matrix_multiply (&pat_to_ps
, &pat_to_ps
, &surface
->cairo_to_ps
);
2706 first_stop
= gradient
->stops
[0].offset
;
2707 last_stop
= gradient
->stops
[gradient
->n_stops
- 1].offset
;
2709 if (pattern
->base
.base
.extend
== CAIRO_EXTEND_REPEAT
||
2710 pattern
->base
.base
.extend
== CAIRO_EXTEND_REFLECT
) {
2712 int x_rep
= 0, y_rep
= 0;
2714 x1
= _cairo_fixed_to_double (pattern
->p1
.x
);
2715 y1
= _cairo_fixed_to_double (pattern
->p1
.y
);
2716 cairo_matrix_transform_point (&pat_to_ps
, &x1
, &y1
);
2718 x2
= _cairo_fixed_to_double (pattern
->p2
.x
);
2719 y2
= _cairo_fixed_to_double (pattern
->p2
.y
);
2720 cairo_matrix_transform_point (&pat_to_ps
, &x2
, &y2
);
2722 dx
= fabs (x2
- x1
);
2723 dy
= fabs (y2
- y1
);
2725 x_rep
= (int) ceil (surface
->width
/dx
);
2727 y_rep
= (int) ceil (surface
->height
/dy
);
2729 repeat_end
= MAX (x_rep
, y_rep
);
2730 repeat_begin
= -repeat_end
;
2731 first_stop
= repeat_begin
;
2732 last_stop
= repeat_end
;
2735 /* PS requires the first and last stop to be the same as the line
2736 * coordinates. For repeating patterns this moves the line
2737 * coordinates out to the begin/end of the repeating function. For
2738 * non repeating patterns this may move the line coordinates in if
2739 * there are not stops at offset 0 and 1. */
2740 x1
= _cairo_fixed_to_double (pattern
->p1
.x
);
2741 y1
= _cairo_fixed_to_double (pattern
->p1
.y
);
2742 x2
= _cairo_fixed_to_double (pattern
->p2
.x
);
2743 y2
= _cairo_fixed_to_double (pattern
->p2
.y
);
2745 _x1
= x1
+ (x2
- x1
)*first_stop
;
2746 _y1
= y1
+ (y2
- y1
)*first_stop
;
2747 _x2
= x1
+ (x2
- x1
)*last_stop
;
2748 _y2
= y1
+ (y2
- y1
)*last_stop
;
2755 /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a
2756 * Type 2 function is used by itself without a stitching
2757 * function. Type 2 functions always have the domain [0 1] */
2758 if ((pattern
->base
.base
.extend
== CAIRO_EXTEND_NONE
||
2759 pattern
->base
.base
.extend
== CAIRO_EXTEND_PAD
) &&
2760 gradient
->n_stops
== 2) {
2765 status
= _cairo_ps_surface_emit_pattern_stops (surface
,
2770 if (pattern
->base
.base
.extend
== CAIRO_EXTEND_REPEAT
||
2771 pattern
->base
.base
.extend
== CAIRO_EXTEND_REFLECT
) {
2772 status
= _cairo_ps_surface_emit_repeating_function (surface
,
2780 _cairo_output_stream_printf (surface
->stream
,
2781 "<< /PatternType 2\n"
2783 " << /ShadingType 2\n"
2784 " /ColorSpace /DeviceRGB\n"
2785 " /Coords [ %f %f %f %f ]\n"
2786 " /Domain [ %f %f ]\n"
2787 " /Function CairoFunction\n",
2789 first_stop
, last_stop
);
2791 if (extend
== CAIRO_EXTEND_PAD
) {
2792 _cairo_output_stream_printf (surface
->stream
,
2793 " /Extend [ true true ]\n");
2795 _cairo_output_stream_printf (surface
->stream
,
2796 " /Extend [ false false ]\n");
2799 _cairo_output_stream_printf (surface
->stream
,
2802 _cairo_output_stream_printf (surface
->stream
,
2803 "[ %f %f %f %f %f %f ]\n",
2804 pat_to_ps
.xx
, pat_to_ps
.yx
,
2805 pat_to_ps
.xy
, pat_to_ps
.yy
,
2806 pat_to_ps
.x0
, pat_to_ps
.y0
);
2807 _cairo_output_stream_printf (surface
->stream
,
2808 "makepattern setpattern\n");
2813 static cairo_status_t
2814 _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t
*surface
,
2815 cairo_radial_pattern_t
*pattern
)
2817 double x1
, y1
, x2
, y2
, r1
, r2
;
2818 cairo_matrix_t pat_to_ps
;
2819 cairo_extend_t extend
;
2820 cairo_status_t status
;
2822 if (pattern
->base
.n_stops
== 0)
2823 return CAIRO_INT_STATUS_NOTHING_TO_DO
;
2825 if (pattern
->base
.n_stops
== 1) {
2826 cairo_solid_pattern_t solid
;
2828 _cairo_pattern_init_solid (&solid
,
2829 &pattern
->base
.stops
[0].color
,
2830 CAIRO_CONTENT_COLOR_ALPHA
);
2831 _cairo_ps_surface_emit_solid_pattern (surface
,
2833 _cairo_pattern_fini (&solid
.base
);
2835 return CAIRO_STATUS_SUCCESS
;
2838 extend
= cairo_pattern_get_extend (&pattern
->base
.base
);
2840 pat_to_ps
= pattern
->base
.base
.matrix
;
2841 status
= cairo_matrix_invert (&pat_to_ps
);
2842 /* cairo_pattern_set_matrix ensures the matrix is invertible */
2843 assert (status
== CAIRO_STATUS_SUCCESS
);
2845 cairo_matrix_multiply (&pat_to_ps
, &pat_to_ps
, &surface
->cairo_to_ps
);
2846 x1
= _cairo_fixed_to_double (pattern
->c1
.x
);
2847 y1
= _cairo_fixed_to_double (pattern
->c1
.y
);
2848 r1
= _cairo_fixed_to_double (pattern
->r1
);
2849 x2
= _cairo_fixed_to_double (pattern
->c2
.x
);
2850 y2
= _cairo_fixed_to_double (pattern
->c2
.y
);
2851 r2
= _cairo_fixed_to_double (pattern
->r2
);
2853 status
= _cairo_ps_surface_emit_pattern_stops (surface
, &pattern
->base
);
2857 _cairo_output_stream_printf (surface
->stream
,
2858 "<< /PatternType 2\n"
2860 " << /ShadingType 3\n"
2861 " /ColorSpace /DeviceRGB\n"
2862 " /Coords [ %f %f %f %f %f %f ]\n"
2863 " /Function CairoFunction\n",
2864 x1
, y1
, r1
, x2
, y2
, r2
);
2866 if (extend
== CAIRO_EXTEND_PAD
) {
2867 _cairo_output_stream_printf (surface
->stream
,
2868 " /Extend [ true true ]\n");
2870 _cairo_output_stream_printf (surface
->stream
,
2871 " /Extend [ false false ]\n");
2874 _cairo_output_stream_printf (surface
->stream
,
2878 _cairo_output_stream_printf (surface
->stream
,
2879 "[ %f %f %f %f %f %f ]\n",
2880 pat_to_ps
.xx
, pat_to_ps
.yx
,
2881 pat_to_ps
.xy
, pat_to_ps
.yy
,
2882 pat_to_ps
.x0
, pat_to_ps
.y0
);
2883 _cairo_output_stream_printf (surface
->stream
,
2884 "makepattern setpattern\n");
2889 static cairo_status_t
2890 _cairo_ps_surface_emit_pattern (cairo_ps_surface_t
*surface
,
2891 cairo_pattern_t
*pattern
,
2892 cairo_operator_t op
)
2894 cairo_status_t status
;
2896 if (pattern
->type
== CAIRO_PATTERN_TYPE_SOLID
) {
2897 cairo_solid_pattern_t
*solid
= (cairo_solid_pattern_t
*) pattern
;
2899 if (surface
->current_pattern_is_solid_color
== FALSE
||
2900 ! _cairo_color_equal (&surface
->current_color
, &solid
->color
))
2902 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
2906 _cairo_ps_surface_emit_solid_pattern (surface
, (cairo_solid_pattern_t
*) pattern
);
2908 surface
->current_pattern_is_solid_color
= TRUE
;
2909 surface
->current_color
= solid
->color
;
2912 return CAIRO_STATUS_SUCCESS
;
2915 surface
->current_pattern_is_solid_color
= FALSE
;
2916 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
2920 switch (pattern
->type
) {
2921 case CAIRO_PATTERN_TYPE_SOLID
:
2923 _cairo_ps_surface_emit_solid_pattern (surface
, (cairo_solid_pattern_t
*) pattern
);
2926 case CAIRO_PATTERN_TYPE_SURFACE
:
2927 status
= _cairo_ps_surface_emit_surface_pattern (surface
,
2928 (cairo_surface_pattern_t
*) pattern
,
2934 case CAIRO_PATTERN_TYPE_LINEAR
:
2935 status
= _cairo_ps_surface_emit_linear_pattern (surface
,
2936 (cairo_linear_pattern_t
*) pattern
);
2941 case CAIRO_PATTERN_TYPE_RADIAL
:
2942 status
= _cairo_ps_surface_emit_radial_pattern (surface
,
2943 (cairo_radial_pattern_t
*) pattern
);
2949 return CAIRO_STATUS_SUCCESS
;
2952 static cairo_int_status_t
2953 _cairo_ps_surface_intersect_clip_path (void *abstract_surface
,
2954 cairo_path_fixed_t
*path
,
2955 cairo_fill_rule_t fill_rule
,
2957 cairo_antialias_t antialias
)
2959 cairo_ps_surface_t
*surface
= abstract_surface
;
2960 cairo_output_stream_t
*stream
= surface
->stream
;
2961 cairo_status_t status
;
2963 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
)
2964 return CAIRO_STATUS_SUCCESS
;
2967 _cairo_output_stream_printf (stream
,
2968 "%% _cairo_ps_surface_intersect_clip_path\n");
2972 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
2976 _cairo_output_stream_printf (stream
, "Q q\n");
2977 surface
->current_pattern_is_solid_color
= FALSE
;
2978 _cairo_pdf_operators_reset (&surface
->pdf_operators
);
2980 return CAIRO_STATUS_SUCCESS
;
2983 return _cairo_pdf_operators_clip (&surface
->pdf_operators
,
2988 static cairo_int_status_t
2989 _cairo_ps_surface_get_extents (void *abstract_surface
,
2990 cairo_rectangle_int_t
*rectangle
)
2992 cairo_ps_surface_t
*surface
= abstract_surface
;
2997 /* XXX: The conversion to integers here is pretty bogus, (not to
2998 * mention the aribitray limitation of width to a short(!). We
2999 * may need to come up with a better interface for get_extents.
3001 rectangle
->width
= (int) ceil (surface
->width
);
3002 rectangle
->height
= (int) ceil (surface
->height
);
3004 return CAIRO_STATUS_SUCCESS
;
3008 _cairo_ps_surface_get_font_options (void *abstract_surface
,
3009 cairo_font_options_t
*options
)
3011 _cairo_font_options_init_default (options
);
3013 cairo_font_options_set_hint_style (options
, CAIRO_HINT_STYLE_NONE
);
3014 cairo_font_options_set_hint_metrics (options
, CAIRO_HINT_METRICS_OFF
);
3015 cairo_font_options_set_antialias (options
, CAIRO_ANTIALIAS_GRAY
);
3018 static cairo_int_status_t
3019 _cairo_ps_surface_paint (void *abstract_surface
,
3020 cairo_operator_t op
,
3021 cairo_pattern_t
*source
)
3023 cairo_ps_surface_t
*surface
= abstract_surface
;
3024 cairo_output_stream_t
*stream
= surface
->stream
;
3025 cairo_rectangle_int_t extents
;
3026 cairo_status_t status
;
3028 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
)
3029 return _cairo_ps_surface_analyze_operation (surface
, op
, source
);
3031 assert (_cairo_ps_surface_operation_supported (surface
, op
, source
));
3034 _cairo_output_stream_printf (stream
,
3035 "%% _cairo_ps_surface_paint\n");
3038 status
= _cairo_surface_get_extents (&surface
->base
, &extents
);
3042 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
3046 if (source
->type
== CAIRO_PATTERN_TYPE_SURFACE
&&
3047 (source
->extend
== CAIRO_EXTEND_NONE
||
3048 source
->extend
== CAIRO_EXTEND_PAD
))
3050 _cairo_output_stream_printf (stream
, "q 0 0 %d %d rectclip\n",
3054 status
= _cairo_ps_surface_paint_surface (surface
,
3055 (cairo_surface_pattern_t
*) source
,
3060 _cairo_output_stream_printf (stream
, "Q\n");
3062 status
= _cairo_ps_surface_emit_pattern (surface
, source
, op
);
3063 if (status
== CAIRO_INT_STATUS_NOTHING_TO_DO
)
3064 return CAIRO_STATUS_SUCCESS
;
3069 _cairo_output_stream_printf (stream
, "0 0 %d %d rectfill\n",
3074 return CAIRO_STATUS_SUCCESS
;
3077 static cairo_int_status_t
3078 _cairo_ps_surface_stroke (void *abstract_surface
,
3079 cairo_operator_t op
,
3080 cairo_pattern_t
*source
,
3081 cairo_path_fixed_t
*path
,
3082 cairo_stroke_style_t
*style
,
3083 cairo_matrix_t
*ctm
,
3084 cairo_matrix_t
*ctm_inverse
,
3086 cairo_antialias_t antialias
)
3088 cairo_ps_surface_t
*surface
= abstract_surface
;
3089 cairo_int_status_t status
;
3091 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
)
3092 return _cairo_ps_surface_analyze_operation (surface
, op
, source
);
3094 assert (_cairo_ps_surface_operation_supported (surface
, op
, source
));
3097 _cairo_output_stream_printf (surface
->stream
,
3098 "%% _cairo_ps_surface_stroke\n");
3101 status
= _cairo_ps_surface_emit_pattern (surface
, source
, op
);
3102 if (status
== CAIRO_INT_STATUS_NOTHING_TO_DO
)
3103 return CAIRO_STATUS_SUCCESS
;
3105 return _cairo_pdf_operators_stroke (&surface
->pdf_operators
,
3112 static cairo_int_status_t
3113 _cairo_ps_surface_fill (void *abstract_surface
,
3114 cairo_operator_t op
,
3115 cairo_pattern_t
*source
,
3116 cairo_path_fixed_t
*path
,
3117 cairo_fill_rule_t fill_rule
,
3119 cairo_antialias_t antialias
)
3121 cairo_ps_surface_t
*surface
= abstract_surface
;
3122 cairo_int_status_t status
;
3124 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
)
3125 return _cairo_ps_surface_analyze_operation (surface
, op
, source
);
3127 assert (_cairo_ps_surface_operation_supported (surface
, op
, source
));
3130 _cairo_output_stream_printf (surface
->stream
,
3131 "%% _cairo_ps_surface_fill\n");
3134 if (source
->type
== CAIRO_PATTERN_TYPE_SURFACE
&&
3135 (source
->extend
== CAIRO_EXTEND_NONE
||
3136 source
->extend
== CAIRO_EXTEND_PAD
))
3138 status
= _cairo_pdf_operators_flush (&surface
->pdf_operators
);
3142 _cairo_output_stream_printf (surface
->stream
, "q\n");
3144 status
= _cairo_pdf_operators_clip (&surface
->pdf_operators
,
3150 status
= _cairo_ps_surface_paint_surface (surface
,
3151 (cairo_surface_pattern_t
*) source
,
3156 _cairo_output_stream_printf (surface
->stream
, "Q\n");
3157 _cairo_pdf_operators_reset (&surface
->pdf_operators
);
3159 status
= _cairo_ps_surface_emit_pattern (surface
, source
, op
);
3160 if (status
== CAIRO_INT_STATUS_NOTHING_TO_DO
)
3161 return CAIRO_STATUS_SUCCESS
;
3166 status
= _cairo_pdf_operators_fill (&surface
->pdf_operators
,
3174 static cairo_int_status_t
3175 _cairo_ps_surface_show_glyphs (void *abstract_surface
,
3176 cairo_operator_t op
,
3177 cairo_pattern_t
*source
,
3178 cairo_glyph_t
*glyphs
,
3180 cairo_scaled_font_t
*scaled_font
,
3181 int *remaining_glyphs
)
3183 cairo_ps_surface_t
*surface
= abstract_surface
;
3184 cairo_status_t status
;
3186 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
)
3187 return _cairo_ps_surface_analyze_operation (surface
, op
, source
);
3189 assert (_cairo_ps_surface_operation_supported (surface
, op
, source
));
3192 _cairo_output_stream_printf (surface
->stream
,
3193 "%% _cairo_ps_surface_show_glyphs\n");
3196 if (num_glyphs
<= 0)
3197 return CAIRO_STATUS_SUCCESS
;
3199 status
= _cairo_ps_surface_emit_pattern (surface
, source
, op
);
3200 if (status
== CAIRO_INT_STATUS_NOTHING_TO_DO
)
3201 return CAIRO_STATUS_SUCCESS
;
3206 return _cairo_pdf_operators_show_text_glyphs (&surface
->pdf_operators
,
3215 _cairo_ps_surface_set_paginated_mode (void *abstract_surface
,
3216 cairo_paginated_mode_t paginated_mode
)
3218 cairo_ps_surface_t
*surface
= abstract_surface
;
3220 surface
->paginated_mode
= paginated_mode
;
3223 static cairo_int_status_t
3224 _cairo_ps_surface_set_bounding_box (void *abstract_surface
,
3227 cairo_ps_surface_t
*surface
= abstract_surface
;
3228 int i
, num_comments
;
3233 x1
= (int) floor (_cairo_fixed_to_double (bbox
->p1
.x
));
3234 y1
= (int) floor (surface
->height
- _cairo_fixed_to_double (bbox
->p2
.y
));
3235 x2
= (int) ceil (_cairo_fixed_to_double (bbox
->p2
.x
));
3236 y2
= (int) ceil (surface
->height
- _cairo_fixed_to_double (bbox
->p1
.y
));
3240 x2
= (int) ceil (surface
->width
);
3241 y2
= (int) ceil (surface
->height
);
3244 _cairo_output_stream_printf (surface
->stream
,
3245 "%%%%Page: %d %d\n",
3247 surface
->num_pages
);
3249 _cairo_output_stream_printf (surface
->stream
,
3250 "%%%%BeginPageSetup\n");
3252 num_comments
= _cairo_array_num_elements (&surface
->dsc_page_setup_comments
);
3253 comments
= _cairo_array_index (&surface
->dsc_page_setup_comments
, 0);
3254 for (i
= 0; i
< num_comments
; i
++) {
3255 _cairo_output_stream_printf (surface
->stream
,
3256 "%s\n", comments
[i
]);
3260 _cairo_array_truncate (&surface
->dsc_page_setup_comments
, 0);
3262 _cairo_output_stream_printf (surface
->stream
,
3263 "%%%%PageBoundingBox: %d %d %d %d\n",
3266 _cairo_output_stream_printf (surface
->stream
,
3267 "%%%%EndPageSetup\n"
3270 if (surface
->num_pages
== 1) {
3271 surface
->bbox_x1
= x1
;
3272 surface
->bbox_y1
= y1
;
3273 surface
->bbox_x2
= x2
;
3274 surface
->bbox_y2
= y2
;
3276 if (x1
< surface
->bbox_x1
)
3277 surface
->bbox_x1
= x1
;
3278 if (y1
< surface
->bbox_y1
)
3279 surface
->bbox_y1
= y1
;
3280 if (x2
> surface
->bbox_x2
)
3281 surface
->bbox_x2
= x2
;
3282 if (y2
> surface
->bbox_y2
)
3283 surface
->bbox_y2
= y2
;
3285 surface
->current_pattern_is_solid_color
= FALSE
;
3286 _cairo_pdf_operators_reset (&surface
->pdf_operators
);
3288 return _cairo_output_stream_get_status (surface
->stream
);
3292 _cairo_ps_surface_supports_fine_grained_fallbacks (void *abstract_surface
)
3297 static const cairo_surface_backend_t cairo_ps_surface_backend
= {
3298 CAIRO_SURFACE_TYPE_PS
,
3299 _cairo_ps_surface_create_similar
,
3300 _cairo_ps_surface_finish
,
3301 NULL
, /* acquire_source_image */
3302 NULL
, /* release_source_image */
3303 NULL
, /* acquire_dest_image */
3304 NULL
, /* release_dest_image */
3305 NULL
, /* clone_similar */
3306 NULL
, /* composite */
3307 NULL
, /* fill_rectangles */
3308 NULL
, /* composite_trapezoids */
3309 NULL
, /* cairo_ps_surface_copy_page */
3310 _cairo_ps_surface_show_page
,
3311 NULL
, /* set_clip_region */
3312 _cairo_ps_surface_intersect_clip_path
,
3313 _cairo_ps_surface_get_extents
,
3314 NULL
, /* old_show_glyphs */
3315 _cairo_ps_surface_get_font_options
,
3317 NULL
, /* mark_dirty_rectangle */
3318 NULL
, /* scaled_font_fini */
3319 NULL
, /* scaled_glyph_fini */
3321 /* Here are the drawing functions */
3323 _cairo_ps_surface_paint
, /* paint */
3325 _cairo_ps_surface_stroke
,
3326 _cairo_ps_surface_fill
,
3327 _cairo_ps_surface_show_glyphs
,
3328 NULL
, /* snapshot */
3331 static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend
= {
3332 _cairo_ps_surface_start_page
,
3333 _cairo_ps_surface_set_paginated_mode
,
3334 _cairo_ps_surface_set_bounding_box
,
3335 NULL
, /* _cairo_ps_surface_has_fallback_images, */
3336 _cairo_ps_surface_supports_fine_grained_fallbacks
,