* MoonlightTypeConverter.cs: Convert CacheMode's from strings.
[moon.git] / cairo / src / cairo-ps-surface.c
blobbfe424dde625eb98b696498c1f9a7cdb7c3aef03
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
34 * California.
36 * Contributor(s):
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() */
57 #include "cairoint.h"
58 #include "cairo-ps.h"
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"
67 #include <stdio.h>
68 #include <ctype.h>
69 #include <time.h>
70 #include <zlib.h>
71 #include <errno.h>
73 #define DEBUG_PS 0
75 #ifndef HAVE_CTIME_R
76 #define ctime_r(T, BUF) ctime (T)
77 #endif
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[] =
84 CAIRO_PS_LEVEL_2,
85 CAIRO_PS_LEVEL_3
88 #define CAIRO_PS_LEVEL_LAST ARRAY_LENGTH (_cairo_ps_levels)
90 static const char * _cairo_ps_level_strings[CAIRO_PS_LEVEL_LAST] =
92 "PS Level 2",
93 "PS Level 3"
96 static void
97 _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
99 char ctime_buf[26];
100 time_t now;
101 char **comments;
102 int i, num_comments;
103 int level;
104 const char *eps_header = "";
106 if (surface->has_creation_date)
107 now = surface->creation_date;
108 else
109 now = time (NULL);
111 if (surface->ps_level_used == CAIRO_PS_LEVEL_2)
112 level = 2;
113 else
114 level = 3;
116 if (surface->eps)
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"
123 "%%%%Pages: %d\n"
124 "%%%%BoundingBox: %d %d %d %d\n",
125 eps_header,
126 cairo_version_string (),
127 ctime_r (&now, ctime_buf),
128 surface->num_pages,
129 surface->bbox_x1,
130 surface->bbox_y1,
131 surface->bbox_x2,
132 surface->bbox_y2);
134 _cairo_output_stream_printf (surface->final_stream,
135 "%%%%DocumentData: Clean7Bit\n"
136 "%%%%LanguageLevel: %d\n",
137 level);
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]);
144 free (comments[i]);
145 comments[i] = NULL;
148 _cairo_output_stream_printf (surface->final_stream,
149 "%%%%EndComments\n");
151 _cairo_output_stream_printf (surface->final_stream,
152 "%%%%BeginProlog\n");
154 if (surface->eps) {
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"
159 "userdict begin\n");
160 } else {
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",
167 level,
168 level);
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"
194 "/BT { } bind def\n"
195 "/ET { } 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"
203 "/TJ {\n"
204 " {\n"
205 " dup\n"
206 " type /stringtype eq\n"
207 " { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse\n"
208 " } forall\n"
209 " currentpoint cairo_store_point\n"
210 "} bind def\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,
225 "%%%%EndProlog\n");
227 num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
228 if (num_comments) {
229 _cairo_output_stream_printf (surface->final_stream,
230 "%%%%BeginSetup\n");
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]);
236 free (comments[i]);
237 comments[i] = NULL;
240 _cairo_output_stream_printf (surface->final_stream,
241 "%%%%EndSetup\n");
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;
254 int length;
255 char name[64];
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);
260 if (status)
261 return status;
263 /* FIXME: Figure out document structure convention for fonts */
265 #if DEBUG_PS
266 _cairo_output_stream_printf (surface->final_stream,
267 "%% _cairo_ps_surface_emit_type1_font_subset\n");
268 #endif
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;
277 #endif
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;
285 int length;
286 char name[64];
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);
291 if (status)
292 return status;
294 /* FIXME: Figure out document structure convention for fonts */
296 #if DEBUG_PS
297 _cairo_output_stream_printf (surface->final_stream,
298 "%% _cairo_ps_surface_emit_type1_font_fallback\n");
299 #endif
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);
320 if (status)
321 return status;
323 /* FIXME: Figure out document structure convention for fonts */
325 #if DEBUG_PS
326 _cairo_output_stream_printf (surface->final_stream,
327 "%% _cairo_ps_surface_emit_truetype_font_subset\n");
328 #endif
330 _cairo_output_stream_printf (surface->final_stream,
331 "11 dict begin\n"
332 "/FontType 42 def\n"
333 "/FontName /f-%d-%d def\n"
334 "/PaintType 0 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]);
349 } else {
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"
357 "/.notdef 0 def\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,
363 "/%s %d def\n",
364 font_subset->glyph_names[i], i);
365 } else {
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,
375 "/sfnts [\n");
376 begin = 0;
377 end = 0;
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");
384 begin = end;
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,
394 "] def\n"
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)
406 uint8_t *row, *byte;
407 int rows, cols;
409 /* The only image type supported by Type 3 fonts are 1-bit image
410 * masks */
411 assert (image->format == CAIRO_FORMAT_A1);
413 _cairo_output_stream_printf (stream,
414 "<<\n"
415 " /ImageType 1\n"
416 " /Width %d\n"
417 " /Height %d\n"
418 " /ImageMatrix [%d 0 0 %d 0 %d]\n"
419 " /Decode [1 0]\n"
420 " /BitsPerComponent 1\n",
421 image->width,
422 image->height,
423 image->width,
424 -image->height,
425 image->height);
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,
439 "imagemask\n");
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,
446 void *closure)
448 cairo_ps_surface_t *surface = closure;
449 cairo_status_t status = CAIRO_STATUS_SUCCESS;
450 unsigned int i;
451 cairo_surface_t *type3_surface;
453 type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
454 NULL,
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]);
461 if (status)
462 break;
465 cairo_surface_destroy (type3_surface);
467 return status;
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;
477 unsigned int i;
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;
481 double width;
483 if (font_subset->num_glyphs == 0)
484 return CAIRO_STATUS_SUCCESS;
486 #if DEBUG_PS
487 _cairo_output_stream_printf (surface->final_stream,
488 "%% _cairo_ps_surface_emit_type3_font_subset\n");
489 #endif
491 _cairo_output_stream_printf (surface->final_stream,
492 "8 dict begin\n"
493 "/FontType 3 def\n"
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,
499 NULL,
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]);
508 } else {
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,
515 "/Glyphs [\n");
517 for (i = 0; i < font_subset->num_glyphs; i++) {
518 _cairo_output_stream_printf (surface->final_stream,
519 " { %% %d\n", i);
520 status = _cairo_type3_glyph_surface_emit_glyph (type3_surface,
521 surface->final_stream,
522 font_subset->glyphs[i],
523 &bbox,
524 &width);
525 if (status)
526 break;
528 _cairo_output_stream_printf (surface->final_stream,
529 " }\n");
530 if (i == 0) {
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;
535 } else {
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);
547 if (status)
548 return status;
550 _cairo_output_stream_printf (surface->final_stream,
551 "] def\n"
552 "/FontBBox [%f %f %f %f] def\n"
553 "/BuildChar {\n"
554 " exch /Glyphs get\n"
555 " exch get\n"
556 " 10 dict begin exec end\n"
557 "} bind def\n"
558 "currentdict\n"
559 "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,
573 void *closure)
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)
581 return status;
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)
586 return status;
587 #endif
589 status = _cairo_ps_surface_emit_truetype_font_subset (surface, font_subset);
590 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
591 return status;
593 status = _cairo_ps_surface_emit_type1_font_fallback (surface, font_subset);
594 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
595 return status;
597 ASSERT_NOT_REACHED;
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,
603 void *closure)
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)
610 return status;
612 status = _cairo_ps_surface_emit_type3_font_subset (surface, font_subset);
613 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
614 return status;
616 ASSERT_NOT_REACHED;
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;
625 #if DEBUG_PS
626 _cairo_output_stream_printf (surface->final_stream,
627 "%% _cairo_ps_surface_emit_font_subsets\n");
628 #endif
630 status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
631 _cairo_ps_surface_analyze_user_font_subset,
632 surface);
633 if (status)
634 goto BAIL;
636 status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
637 _cairo_ps_surface_emit_unscaled_font_subset,
638 surface);
639 if (status)
640 goto BAIL;
642 status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
643 _cairo_ps_surface_emit_scaled_font_subset,
644 surface);
645 if (status)
646 goto BAIL;
648 status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
649 _cairo_ps_surface_emit_scaled_font_subset,
650 surface);
651 BAIL:
652 _cairo_scaled_font_subsets_destroy (surface->font_subsets);
653 surface->font_subsets = NULL;
655 return status;
658 static cairo_status_t
659 _cairo_ps_surface_emit_body (cairo_ps_surface_t *surface)
661 char buf[4096];
662 int n;
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;
677 static void
678 _cairo_ps_surface_emit_footer (cairo_ps_surface_t *surface)
680 _cairo_output_stream_printf (surface->final_stream,
681 "%%%%Trailer\n");
683 if (surface->eps) {
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,
691 "%%%%EOF\n");
694 static cairo_surface_t *
695 _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
696 double width,
697 double height)
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);
705 goto CLEANUP;
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) {
715 switch (errno) {
716 case ENOMEM:
717 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
718 break;
719 default:
720 status = _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
721 break;
723 goto CLEANUP_SURFACE;
726 surface->stream = _cairo_output_stream_create_for_file (surface->tmpfile);
727 status = _cairo_output_stream_get_status (surface->stream);
728 if (status)
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,
751 surface->stream,
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 (
763 &surface->base,
764 CAIRO_CONTENT_COLOR_ALPHA,
765 width, height,
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);
778 CLEANUP_SURFACE:
779 free (surface);
780 CLEANUP:
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
792 * temporary file.
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
806 * with it.
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.
812 * Since: 1.2
814 cairo_surface_t *
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,
826 width_in_points,
827 height_in_points);
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
850 * with it.
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.
856 * Since: 1.2
858 cairo_surface_t *
859 cairo_ps_surface_create_for_stream (cairo_write_func_t write_func,
860 void *closure,
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,
871 width_in_points,
872 height_in_points);
875 static cairo_bool_t
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;
891 if (surface->status)
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);
898 if (target->status)
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
916 * can be used here.
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
921 * surface.
923 * Since: 1.6
925 void
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);
933 if (status) {
934 status = _cairo_surface_set_error (surface, status);
935 return;
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().
950 * Since: 1.6
952 void
953 cairo_ps_get_levels (cairo_ps_level_t const **levels,
954 int *num_levels)
956 if (levels != NULL)
957 *levels = _cairo_ps_levels;
959 if (num_levels != NULL)
960 *num_levels = CAIRO_PS_LEVEL_LAST;
964 * cairo_ps_level_to_string:
965 * @level: a level id
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.
973 * Since: 1.6
975 const char *
976 cairo_ps_level_to_string (cairo_ps_level_t level)
978 if (level >= CAIRO_PS_LEVEL_LAST)
979 return NULL;
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
990 * PostScript.
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
996 * than one page.
998 * Since: 1.6
1000 void
1001 cairo_ps_surface_set_eps (cairo_surface_t *surface,
1002 cairo_bool_t eps)
1004 cairo_ps_surface_t *ps_surface = NULL;
1005 cairo_status_t status;
1007 status = _extract_ps_surface (surface, &ps_surface);
1008 if (status) {
1009 status = _cairo_surface_set_error (surface, status);
1010 return;
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.
1024 * Since: 1.6
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);
1033 if (status) {
1034 status = _cairo_surface_set_error (surface, status);
1035 return FALSE;
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().
1056 * Since: 1.2
1058 void
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);
1067 if (status) {
1068 status = _cairo_surface_set_error (surface, status);
1069 return;
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,
1078 width_in_points,
1079 height_in_points);
1080 if (status)
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,
1143 * %%EndPageSetup.
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);
1151 * ...
1152 * cairo_ps_surface_dsc_comment (surface, "%%Title: My excellent document");
1153 * cairo_ps_surface_dsc_comment (surface, "%%Copyright: Copyright (C) 2006 Cairo Lover")
1154 * ...
1155 * cairo_ps_surface_dsc_begin_setup (surface);
1156 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor White");
1157 * ...
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);
1165 * ...
1166 * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A5");
1167 * ...
1168 * </programlisting></informalexample>
1170 * Since: 1.2
1172 void
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;
1178 char *comment_copy;
1180 status = _extract_ps_surface (surface, &ps_surface);
1181 if (status) {
1182 status = _cairo_surface_set_error (surface, status);
1183 return;
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);
1189 return;
1192 if (comment[0] != '%' || strlen (comment) > 255) {
1193 status = _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_DSC_COMMENT);
1194 return;
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);
1201 return;
1204 status = _cairo_array_append (ps_surface->dsc_comment_target, &comment_copy);
1205 if (status) {
1206 free (comment_copy);
1207 status = _cairo_surface_set_error (surface, status);
1208 return;
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.
1226 * Since: 1.2
1228 void
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);
1235 if (status) {
1236 status = _cairo_surface_set_error (surface, status);
1237 return;
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.
1261 * Since: 1.2
1263 void
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);
1270 if (status) {
1271 status = _cairo_surface_set_error (surface, status);
1272 return;
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,
1285 int width,
1286 int height)
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;
1297 char **comments;
1299 _cairo_ps_surface_emit_header (surface);
1301 status = _cairo_ps_surface_emit_font_subsets (surface);
1302 if (status)
1303 goto CLEANUP;
1305 status = _cairo_ps_surface_emit_body (surface);
1306 if (status)
1307 goto CLEANUP;
1309 _cairo_ps_surface_emit_footer (surface);
1311 CLEANUP:
1312 status2 = _cairo_output_stream_destroy (surface->stream);
1313 if (status == CAIRO_STATUS_SUCCESS)
1314 status = status2;
1316 fclose (surface->tmpfile);
1318 status2 = _cairo_output_stream_destroy (surface->final_stream);
1319 if (status == CAIRO_STATUS_SUCCESS)
1320 status = status2;
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++)
1325 free (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++)
1331 free (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++)
1337 free (comments[i]);
1338 _cairo_array_fini (&surface->dsc_page_setup_comments);
1340 return status;
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);
1360 if (status)
1361 return status;
1363 _cairo_output_stream_printf (surface->stream,
1364 "Q\n");
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);
1376 if (status)
1377 return status;
1379 _cairo_output_stream_printf (surface->stream, "showpage\n");
1381 return CAIRO_STATUS_SUCCESS;
1384 static cairo_bool_t
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;
1398 void *image_extra;
1399 cairo_int_status_t status;
1400 cairo_image_transparency_t transparency;
1402 status = _cairo_surface_acquire_source_image (pattern->surface,
1403 &image,
1404 &image_extra);
1405 if (status)
1406 return status;
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;
1415 break;
1417 case CAIRO_IMAGE_HAS_BILEVEL_ALPHA:
1418 if (surface->ps_level == CAIRO_PS_LEVEL_2) {
1419 status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1420 } else {
1421 surface->ps_level_used = CAIRO_PS_LEVEL_3;
1422 status = CAIRO_STATUS_SUCCESS;
1424 break;
1426 case CAIRO_IMAGE_HAS_ALPHA:
1427 status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1428 break;
1430 case CAIRO_IMAGE_UNKNOWN:
1431 ASSERT_NOT_REACHED;
1434 _cairo_surface_release_source_image (pattern->surface, image, image_extra);
1436 return status;
1439 static cairo_bool_t
1440 surface_pattern_supported (cairo_surface_pattern_t *pattern)
1442 cairo_extend_t extend;
1444 if (_cairo_surface_is_meta (pattern->surface))
1445 return TRUE;
1447 if (pattern->surface->backend->acquire_source_image == NULL)
1448 return FALSE;
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)
1456 return FALSE;
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
1462 * same time. :-(
1464 extend = cairo_pattern_get_extend ((cairo_pattern_t*)&pattern->base);
1465 switch (extend) {
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:
1472 return TRUE;
1475 ASSERT_NOT_REACHED;
1476 return FALSE;
1479 static cairo_bool_t
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;
1484 uint16_t alpha;
1485 cairo_extend_t extend;
1486 unsigned int i;
1488 if (surface->ps_level == CAIRO_PS_LEVEL_2)
1489 return FALSE;
1491 if (gradient->n_stops == 0)
1492 return TRUE;
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)
1499 return FALSE;
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) {
1512 return FALSE;
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)) {
1524 return FALSE;
1528 surface->ps_level_used = CAIRO_PS_LEVEL_3;
1530 return TRUE;
1533 static cairo_bool_t
1534 pattern_supported (cairo_ps_surface_t *surface, cairo_pattern_t *pattern)
1536 if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
1537 return TRUE;
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);
1546 return FALSE;
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,
1588 surface_pattern);
1591 if (_cairo_pattern_is_opaque (pattern))
1592 return CAIRO_STATUS_SUCCESS;
1593 else
1594 return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1597 static cairo_bool_t
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)
1603 return TRUE;
1604 else
1605 return FALSE;
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
1615 * the end.
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;
1623 int column;
1624 int string_size;
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;
1634 unsigned char c;
1635 const unsigned char backslash = '\\';
1637 if (length == 0)
1638 return CAIRO_STATUS_SUCCESS;
1640 while (length--) {
1641 if (stream->string_size == 0 && stream->use_strings) {
1642 _cairo_output_stream_printf (stream->output, "(");
1643 stream->column++;
1646 c = *data++;
1647 if (stream->use_strings) {
1648 switch (c) {
1649 case '\\':
1650 case '(':
1651 case ')':
1652 _cairo_output_stream_write (stream->output, &backslash, 1);
1653 stream->column++;
1654 stream->string_size++;
1655 break;
1658 /* Have to be careful to never split the final ~> sequence. */
1659 if (c == '~') {
1660 _cairo_output_stream_write (stream->output, &c, 1);
1661 stream->column++;
1662 stream->string_size++;
1664 if (length-- == 0)
1665 break;
1667 c = *data++;
1669 _cairo_output_stream_write (stream->output, &c, 1);
1670 stream->column++;
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;
1678 stream->column = 0;
1680 if (stream->column >= STRING_ARRAY_MAX_COLUMN) {
1681 _cairo_output_stream_printf (stream->output, "\n ");
1682 stream->string_size += 2;
1683 stream->column = 1;
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);
1701 return status;
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;
1733 stream->column = 0;
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;
1759 stream->column = 0;
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;
1782 else
1783 background_color = CAIRO_COLOR_BLACK;
1785 opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
1786 image->width,
1787 image->height);
1788 if (opaque->status)
1789 return opaque->status;
1791 _cairo_pattern_init_for_surface (&pattern, &image->base);
1793 status = _cairo_surface_fill_rectangle (opaque,
1794 CAIRO_OPERATOR_SOURCE,
1795 background_color,
1796 0, 0,
1797 image->width, image->height);
1798 if (status)
1799 goto fail;
1801 status = _cairo_surface_composite (CAIRO_OPERATOR_OVER,
1802 &pattern.base,
1803 NULL,
1804 opaque,
1805 0, 0,
1806 0, 0,
1807 0, 0,
1808 image->width,
1809 image->height);
1810 if (status)
1811 goto fail;
1813 _cairo_pattern_fini (&pattern.base);
1814 *opaque_image = (cairo_image_surface_t *) opaque;
1816 return CAIRO_STATUS_SUCCESS;
1818 fail:
1819 _cairo_pattern_fini (&pattern.base);
1820 cairo_surface_destroy (opaque);
1822 return status;
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;
1834 if (use_strings)
1835 string_array_stream = _string_array_stream_create (surface->stream);
1836 else
1837 string_array_stream = _base85_array_stream_create (surface->stream);
1839 status = _cairo_output_stream_get_status (string_array_stream);
1840 if (status)
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);
1845 if (status) {
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)
1855 status = status2;
1857 return status;
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;
1869 int x, y, i;
1870 cairo_image_transparency_t transparency;
1871 cairo_bool_t use_mask;
1872 uint32_t *pixel;
1873 int bit;
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,
1890 image,
1891 &opaque_image);
1892 if (status)
1893 return status;
1895 use_mask = FALSE;
1896 } else if (transparency == CAIRO_IMAGE_IS_OPAQUE) {
1897 opaque_image = image;
1898 use_mask = FALSE;
1899 } else {
1900 use_mask = TRUE;
1903 if (use_mask) {
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
1908 * format. */
1909 data_size = image->height * ((image->width + 7)/8 + 3*image->width);
1910 } else {
1911 data_size = image->height * image->width * 3;
1913 data = malloc (data_size);
1914 if (data == NULL) {
1915 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1916 goto bail1;
1919 if (use_mask) {
1920 i = 0;
1921 for (y = 0; y < image->height; y++) {
1922 /* mask row */
1923 pixel = (uint32_t *) (image->data + y * image->stride);
1924 bit = 7;
1925 for (x = 0; x < image->width; x++, pixel++) {
1926 if (bit == 7)
1927 data[i] = 0;
1928 if (((*pixel & 0xff000000) >> 24) > 0x80)
1929 data[i] |= (1 << bit);
1930 bit--;
1931 if (bit < 0) {
1932 bit = 7;
1933 i++;
1936 if (bit != 7)
1937 i++;
1939 /* image row*/
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;
1947 } else {
1948 i = 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
1960 * instead. */
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);
1965 goto bail2;
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,
1975 data_compressed,
1976 data_compressed_size,
1977 TRUE);
1978 if (status)
1979 goto bail3;
1981 _cairo_output_stream_printf (surface->stream,
1982 "] def\n");
1983 _cairo_output_stream_printf (surface->stream,
1984 "/CairoImageDataIndex 0 def\n");
1987 if (use_mask) {
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"
1994 " DataDict begin\n"
1995 " /ImageType 1 def\n"
1996 " /Width %d def\n"
1997 " /Height %d def\n"
1998 " /BitsPerComponent 8 def\n"
1999 " /Decode [ 0 1 0 1 0 1 ] def\n",
2000 image->width,
2001 image->height);
2003 if (surface->use_string_datasource) {
2004 _cairo_output_stream_printf (surface->stream,
2005 " /DataSource {\n"
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");
2011 } else {
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"
2018 " end\n"
2019 " /MaskDict 8 dict def\n"
2020 " MaskDict begin\n"
2021 " /ImageType 1 def\n"
2022 " /Width %d def\n"
2023 " /Height %d def\n"
2024 " /BitsPerComponent 1 def\n"
2025 " /Decode [ 1 0 ] def\n"
2026 " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2027 " end\n"
2028 "end\n"
2029 "image\n",
2030 image->height,
2031 image->width,
2032 image->height,
2033 image->height);
2034 } else {
2035 _cairo_output_stream_printf (surface->stream,
2036 "/DeviceRGB setcolorspace\n"
2037 "8 dict dup begin\n"
2038 " /ImageType 1 def\n"
2039 " /Width %d def\n"
2040 " /Height %d 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,
2047 " /DataSource {\n"
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");
2053 } else {
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"
2060 "end\n"
2061 "image\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,
2069 data_compressed,
2070 data_compressed_size,
2071 FALSE);
2072 } else {
2073 status = CAIRO_STATUS_SUCCESS;
2076 bail3:
2077 free (data_compressed);
2079 bail2:
2080 free (data);
2082 bail1:
2083 if (!use_mask && opaque_image != image)
2084 cairo_surface_destroy (&opaque_image->base);
2086 return status;
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);
2101 if (status)
2102 return status;
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,
2117 " q\n"
2118 " 0 0 %f %f rectclip\n",
2119 surface->width,
2120 surface->height);
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",
2126 surface->width,
2127 surface->height);
2130 status = _cairo_meta_surface_replay_region (meta_surface, &surface->base,
2131 CAIRO_META_REGION_NATIVE);
2132 assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
2133 if (status)
2134 return status;
2136 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
2137 if (status)
2138 return status;
2140 _cairo_output_stream_printf (surface->stream,
2141 " Q\n");
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);
2149 if (status)
2150 return status;
2152 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
2153 &surface->cairo_to_ps);
2155 return CAIRO_STATUS_SUCCESS;
2158 static void
2159 _cairo_ps_surface_flatten_transparency (cairo_ps_surface_t *surface,
2160 const cairo_color_t *color,
2161 double *red,
2162 double *green,
2163 double *blue)
2165 *red = color->red;
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;
2182 static void
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,
2192 "%f g\n",
2193 red);
2194 else
2195 _cairo_output_stream_printf (surface->stream,
2196 "%f %f %f rg\n",
2197 red, green, blue);
2200 static cairo_status_t
2201 _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
2202 cairo_surface_pattern_t *pattern,
2203 int *width,
2204 int *height,
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);
2214 if (status)
2215 return status;
2217 *width = pattern_extents.width;
2218 *height = pattern_extents.height;
2219 } else {
2220 status = _cairo_surface_acquire_source_image (pattern->surface,
2221 &surface->image,
2222 &surface->image_extra);
2223 if (status)
2224 return status;
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,
2244 meta_surface);
2245 } else {
2246 status = _cairo_ps_surface_emit_image (surface, surface->image, op);
2249 return status;
2252 static void
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;
2267 int width, height;
2268 cairo_matrix_t cairo_p2d, ps_p2d;
2270 status = _cairo_ps_surface_acquire_surface (surface,
2271 pattern,
2272 &width,
2273 &height,
2274 op);
2275 if (status)
2276 return status;
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,
2287 (int)(width/scale),
2288 (int)(height/scale),
2289 scale*72,
2290 (long)width*height*3);
2291 } else {
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,
2296 surface->width,
2297 surface->height);
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);
2321 return status;
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,
2348 pattern,
2349 &pattern_width,
2350 &pattern_height,
2351 op);
2352 if (status)
2353 return status;
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
2364 * be visible.
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
2370 * repeat visibly.
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,
2375 &x1, &y1, &x2, &y2,
2376 NULL);
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);
2384 break;
2386 case CAIRO_EXTEND_REPEAT:
2387 xstep = pattern_width;
2388 ystep = pattern_height;
2389 break;
2390 case CAIRO_EXTEND_REFLECT:
2391 xstep = pattern_width*2;
2392 ystep = pattern_height*2;
2393 break;
2394 /* All the rest (if any) should have been analyzed away, so these
2395 * cases should be unreachable. */
2396 default:
2397 ASSERT_NOT_REACHED;
2398 xstep = 0;
2399 ystep = 0;
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,
2411 xstep, ystep);
2413 status = _cairo_ps_surface_emit_surface (surface, pattern, op);
2414 if (status)
2415 return status;
2417 surface->use_string_datasource = old_use_string_datasource;
2418 _cairo_output_stream_printf (surface->stream,
2419 "} bind def\n");
2421 _cairo_output_stream_printf (surface->stream,
2422 "<< /PatternType 1\n"
2423 " /PaintType 1\n"
2424 " /TilingType 1\n");
2425 _cairo_output_stream_printf (surface->stream,
2426 " /XStep %f /YStep %f\n",
2427 xstep, ystep);
2429 if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
2430 _cairo_output_stream_printf (surface->stream,
2431 " /BBox [0 0 %d %d]\n"
2432 " /PaintProc {\n"
2433 " CairoPattern\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"
2437 " CairoPattern\n"
2438 " } bind\n",
2439 pattern_width*2, pattern_height*2,
2440 pattern_width*2,
2441 pattern_height*2,
2442 pattern_width*2);
2443 } else {
2444 if (op == CAIRO_OPERATOR_SOURCE) {
2445 _cairo_output_stream_printf (surface->stream,
2446 " /BBox [0 0 %f %f]\n",
2447 xstep, ystep);
2448 } else {
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,
2458 ">>\n");
2460 status = _cairo_surface_get_extents (&surface->base, &surface_extents);
2461 if (status)
2462 return status;
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 {
2488 double offset;
2489 double color[4];
2490 } cairo_ps_color_stop_t;
2492 static void
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"
2502 " /N 1\n"
2503 " >>\n",
2504 stop1->color[0],
2505 stop1->color[1],
2506 stop1->color[2],
2507 stop2->color[0],
2508 stop2->color[1],
2509 stop2->color[2]);
2512 static void
2513 _cairo_ps_surface_emit_stitched_colorgradient (cairo_ps_surface_t *surface,
2514 unsigned int n_stops,
2515 cairo_ps_color_stop_t stops[])
2517 unsigned int i;
2519 _cairo_output_stream_printf (surface->stream,
2520 "<< /FunctionType 3\n"
2521 " /Domain [ 0 1 ]\n"
2522 " /Functions [\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",
2534 n_stops - 1);
2536 _cairo_output_stream_printf (surface->stream, ">>\n");
2539 static void
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)
2544 int i;
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));
2582 else
2583 calc_gradient_color (&allstops[0], &stops[0], &stops[n_stops-1]);
2584 stops = allstops;
2585 n_stops++;
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));
2594 } else {
2595 calc_gradient_color (&stops[n_stops], &stops[0], &stops[n_stops-1]);
2597 n_stops++;
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,
2607 stops[i].color[0],
2608 stops[i].color[1],
2609 stops[i].color[2],
2610 stops[i].color[3]);
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");
2620 if (n_stops == 2) {
2621 /* no need for stitched function */
2622 _cairo_ps_surface_emit_linear_colorgradient (surface, &stops[0], &stops[1]);
2623 } else {
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,
2629 "def\n");
2631 free (allstops);
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,
2639 int begin,
2640 int end)
2642 _cairo_output_stream_printf (surface->stream,
2643 "/CairoFunction\n"
2644 "<< /FunctionType 3\n"
2645 " /Domain [ %d %d ]\n"
2646 " /Functions [ %d {CairoFunction} repeat ]\n"
2647 " /Bounds [ %d 1 %d {} for ]\n",
2648 begin,
2649 end,
2650 end - begin,
2651 begin + 1,
2652 end - 1);
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",
2656 begin,
2657 end - 1);
2658 } else {
2659 _cairo_output_stream_printf (surface->stream, " /Encode [ %d 1 %d { pop 0 1 } for ]\n",
2660 begin,
2661 end - 1);
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,
2692 &solid);
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) {
2711 double dx, dy;
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);
2724 if (dx > 1e-6)
2725 x_rep = (int) ceil (surface->width/dx);
2726 if (dy > 1e-6)
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;
2750 x1 = _x1;
2751 x2 = _x2;
2752 y1 = _y1;
2753 y2 = _y2;
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) {
2761 first_stop = 0.0;
2762 last_stop = 1.0;
2765 status = _cairo_ps_surface_emit_pattern_stops (surface,
2766 &pattern->base);
2767 if (status)
2768 return status;
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,
2773 &pattern->base,
2774 repeat_begin,
2775 repeat_end);
2776 if (status)
2777 return status;
2780 _cairo_output_stream_printf (surface->stream,
2781 "<< /PatternType 2\n"
2782 " /Shading\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",
2788 x1, y1, x2, y2,
2789 first_stop, last_stop);
2791 if (extend == CAIRO_EXTEND_PAD) {
2792 _cairo_output_stream_printf (surface->stream,
2793 " /Extend [ true true ]\n");
2794 } else {
2795 _cairo_output_stream_printf (surface->stream,
2796 " /Extend [ false false ]\n");
2799 _cairo_output_stream_printf (surface->stream,
2800 " >>\n"
2801 ">>\n");
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");
2810 return status;
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,
2832 &solid);
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);
2854 if (status)
2855 return status;
2857 _cairo_output_stream_printf (surface->stream,
2858 "<< /PatternType 2\n"
2859 " /Shading\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");
2869 } else {
2870 _cairo_output_stream_printf (surface->stream,
2871 " /Extend [ false false ]\n");
2874 _cairo_output_stream_printf (surface->stream,
2875 " >>\n"
2876 ">>\n");
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");
2886 return status;
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);
2903 if (status)
2904 return status;
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);
2917 if (status)
2918 return status;
2920 switch (pattern->type) {
2921 case CAIRO_PATTERN_TYPE_SOLID:
2923 _cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
2924 break;
2926 case CAIRO_PATTERN_TYPE_SURFACE:
2927 status = _cairo_ps_surface_emit_surface_pattern (surface,
2928 (cairo_surface_pattern_t *) pattern,
2929 op);
2930 if (status)
2931 return status;
2932 break;
2934 case CAIRO_PATTERN_TYPE_LINEAR:
2935 status = _cairo_ps_surface_emit_linear_pattern (surface,
2936 (cairo_linear_pattern_t *) pattern);
2937 if (status)
2938 return status;
2939 break;
2941 case CAIRO_PATTERN_TYPE_RADIAL:
2942 status = _cairo_ps_surface_emit_radial_pattern (surface,
2943 (cairo_radial_pattern_t *) pattern);
2944 if (status)
2945 return status;
2946 break;
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,
2956 double tolerance,
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;
2966 #if DEBUG_PS
2967 _cairo_output_stream_printf (stream,
2968 "%% _cairo_ps_surface_intersect_clip_path\n");
2969 #endif
2971 if (path == NULL) {
2972 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
2973 if (status)
2974 return status;
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,
2984 path,
2985 fill_rule);
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;
2994 rectangle->x = 0;
2995 rectangle->y = 0;
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;
3007 static void
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));
3033 #if DEBUG_PS
3034 _cairo_output_stream_printf (stream,
3035 "%% _cairo_ps_surface_paint\n");
3036 #endif
3038 status = _cairo_surface_get_extents (&surface->base, &extents);
3039 if (status)
3040 return status;
3042 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3043 if (status)
3044 return status;
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",
3051 extents.width,
3052 extents.height);
3054 status = _cairo_ps_surface_paint_surface (surface,
3055 (cairo_surface_pattern_t *) source,
3056 op);
3057 if (status)
3058 return status;
3060 _cairo_output_stream_printf (stream, "Q\n");
3061 } else {
3062 status = _cairo_ps_surface_emit_pattern (surface, source, op);
3063 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
3064 return CAIRO_STATUS_SUCCESS;
3066 if (status)
3067 return status;
3069 _cairo_output_stream_printf (stream, "0 0 %d %d rectfill\n",
3070 extents.width,
3071 extents.height);
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,
3085 double tolerance,
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));
3096 #if DEBUG_PS
3097 _cairo_output_stream_printf (surface->stream,
3098 "%% _cairo_ps_surface_stroke\n");
3099 #endif
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,
3106 path,
3107 style,
3108 ctm,
3109 ctm_inverse);
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,
3118 double tolerance,
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));
3129 #if DEBUG_PS
3130 _cairo_output_stream_printf (surface->stream,
3131 "%% _cairo_ps_surface_fill\n");
3132 #endif
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);
3139 if (status)
3140 return status;
3142 _cairo_output_stream_printf (surface->stream, "q\n");
3144 status = _cairo_pdf_operators_clip (&surface->pdf_operators,
3145 path,
3146 fill_rule);
3147 if (status)
3148 return status;
3150 status = _cairo_ps_surface_paint_surface (surface,
3151 (cairo_surface_pattern_t *) source,
3152 op);
3153 if (status)
3154 return status;
3156 _cairo_output_stream_printf (surface->stream, "Q\n");
3157 _cairo_pdf_operators_reset (&surface->pdf_operators);
3158 } else {
3159 status = _cairo_ps_surface_emit_pattern (surface, source, op);
3160 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
3161 return CAIRO_STATUS_SUCCESS;
3163 if (status)
3164 return status;
3166 status = _cairo_pdf_operators_fill (&surface->pdf_operators,
3167 path,
3168 fill_rule);
3171 return status;
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,
3179 int num_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));
3191 #if DEBUG_PS
3192 _cairo_output_stream_printf (surface->stream,
3193 "%% _cairo_ps_surface_show_glyphs\n");
3194 #endif
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;
3203 if (status)
3204 return status;
3206 return _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
3207 NULL, 0,
3208 glyphs, num_glyphs,
3209 NULL, 0,
3210 FALSE,
3211 scaled_font);
3214 static void
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,
3225 cairo_box_t *bbox)
3227 cairo_ps_surface_t *surface = abstract_surface;
3228 int i, num_comments;
3229 char **comments;
3230 int x1, y1, x2, y2;
3232 if (surface->eps) {
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));
3237 } else {
3238 x1 = 0;
3239 y1 = 0;
3240 x2 = (int) ceil (surface->width);
3241 y2 = (int) ceil (surface->height);
3244 _cairo_output_stream_printf (surface->stream,
3245 "%%%%Page: %d %d\n",
3246 surface->num_pages,
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]);
3257 free (comments[i]);
3258 comments[i] = NULL;
3260 _cairo_array_truncate (&surface->dsc_page_setup_comments, 0);
3262 _cairo_output_stream_printf (surface->stream,
3263 "%%%%PageBoundingBox: %d %d %d %d\n",
3264 x1, y1, x2, y2);
3266 _cairo_output_stream_printf (surface->stream,
3267 "%%%%EndPageSetup\n"
3268 "q\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;
3275 } else {
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);
3291 static cairo_bool_t
3292 _cairo_ps_surface_supports_fine_grained_fallbacks (void *abstract_surface)
3294 return TRUE;
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,
3316 NULL, /* flush */
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 */
3324 NULL, /* mask */
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,