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
3  *
4  * Copyright © 2003 University of Southern California
5  * Copyright © 2005 Red Hat, Inc
6  * Copyright © 2007,2008 Adrian Johnson
7  *
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.
15  *
16  * You should have received a copy of the LGPL along with this library
17  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19  * You should have received a copy of the MPL along with this library
20  * in the file COPYING-MPL-1.1
21  *
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/
26  *
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.
30  *
31  * The Original Code is the cairo graphics library.
32  *
33  * The Initial Developer of the Original Code is University of Southern
34  * California.
35  *
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>
41  */
42 
43 
44 /*
45  * Design of the PS output:
46  *
47  * The PS output is harmonised with the PDF operations using PS procedures
48  * to emulate the PDF operators.
49  *
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.
54  */
55 
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-composite-rectangles-private.h"
62 #include "cairo-error-private.h"
63 #include "cairo-scaled-font-subsets-private.h"
64 #include "cairo-paginated-private.h"
65 #include "cairo-recording-surface-private.h"
66 #include "cairo-surface-clipper-private.h"
67 #include "cairo-surface-subsurface-private.h"
68 #include "cairo-output-stream-private.h"
69 #include "cairo-type3-glyph-surface-private.h"
70 #include "cairo-image-info-private.h"
71 
72 #include <stdio.h>
73 #include <ctype.h>
74 #include <time.h>
75 #include <zlib.h>
76 #include <errno.h>
77 
78 #define DEBUG_PS 0
79 
80 #if DEBUG_PS
81 #define DEBUG_FALLBACK(s) \
82     fprintf (stderr, "%s::%d -- %s\n", __FUNCTION__, __LINE__, (s))
83 #else
84 #define DEBUG_FALLBACK(s)
85 #endif
86 
87 #ifndef HAVE_CTIME_R
88 #define ctime_r(T, BUF) ctime (T)
89 #endif
90 
91 /**
92  * SECTION:cairo-ps
93  * @Title: PostScript Surfaces
94  * @Short_Description: Rendering PostScript documents
95  * @See_Also: #cairo_surface_t
96  *
97  * The PostScript surface is used to render cairo graphics to Adobe
98  * PostScript files and is a multi-page vector surface backend.
99  */
100 
101 /**
102  * CAIRO_HAS_PS_SURFACE:
103  *
104  * Defined if the PostScript surface backend is available.
105  * This macro can be used to conditionally compile backend-specific code.
106  */
107 
108 static const cairo_surface_backend_t cairo_ps_surface_backend;
109 static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend;
110 
111 static void
112 _cairo_ps_surface_release_surface (cairo_ps_surface_t      *surface,
113 				   cairo_surface_pattern_t *pattern);
114 
115 static const cairo_ps_level_t _cairo_ps_levels[] =
116 {
117     CAIRO_PS_LEVEL_2,
118     CAIRO_PS_LEVEL_3
119 };
120 
121 #define CAIRO_PS_LEVEL_LAST ARRAY_LENGTH (_cairo_ps_levels)
122 
123 static const char * _cairo_ps_level_strings[CAIRO_PS_LEVEL_LAST] =
124 {
125     "PS Level 2",
126     "PS Level 3"
127 };
128 
129 typedef struct _cairo_page_standard_media {
130     const char *name;
131     int width;
132     int height;
133 } cairo_page_standard_media_t;
134 
135 static const cairo_page_standard_media_t _cairo_page_standard_media[] =
136 {
137     { "A0",       2384, 3371 },
138     { "A1",       1685, 2384 },
139     { "A2",       1190, 1684 },
140     { "A3",        842, 1190 },
141     { "A4",        595,  842 },
142     { "A5",        420,  595 },
143     { "B4",        729, 1032 },
144     { "B5",        516,  729 },
145     { "Letter",    612,  792 },
146     { "Tabloid",   792, 1224 },
147     { "Ledger",   1224,  792 },
148     { "Legal",     612, 1008 },
149     { "Statement", 396,  612 },
150     { "Executive", 540,  720 },
151     { "Folio",     612,  936 },
152     { "Quarto",    610,  780 },
153     { "10x14",     720, 1008 },
154 };
155 
156 typedef struct _cairo_page_media {
157     char *name;
158     int width;
159     int height;
160     cairo_list_t link;
161 } cairo_page_media_t;
162 
163 static void
_cairo_ps_surface_emit_header(cairo_ps_surface_t * surface)164 _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
165 {
166     char ctime_buf[26];
167     time_t now;
168     char **comments;
169     int i, num_comments;
170     int level;
171     const char *eps_header = "";
172 
173     if (surface->has_creation_date)
174 	now = surface->creation_date;
175     else
176 	now = time (NULL);
177 
178     if (surface->ps_level_used == CAIRO_PS_LEVEL_2)
179 	level = 2;
180     else
181 	level = 3;
182 
183     if (surface->eps)
184 	eps_header = " EPSF-3.0";
185 
186     _cairo_output_stream_printf (surface->final_stream,
187 				 "%%!PS-Adobe-3.0%s\n"
188 				 "%%%%Creator: cairo %s (http://cairographics.org)\n"
189 				 "%%%%CreationDate: %s"
190 				 "%%%%Pages: %d\n"
191 				 "%%%%BoundingBox: %d %d %d %d\n",
192 				 eps_header,
193 				 cairo_version_string (),
194 				 ctime_r (&now, ctime_buf),
195 				 surface->num_pages,
196 				 surface->bbox_x1,
197 				 surface->bbox_y1,
198 				 surface->bbox_x2,
199 				 surface->bbox_y2);
200 
201     _cairo_output_stream_printf (surface->final_stream,
202 				 "%%%%DocumentData: Clean7Bit\n"
203 				 "%%%%LanguageLevel: %d\n",
204 				 level);
205 
206     if (!cairo_list_is_empty (&surface->document_media)) {
207 	cairo_page_media_t *page;
208 	cairo_bool_t first = TRUE;
209 
210 	cairo_list_foreach_entry (page, cairo_page_media_t, &surface->document_media, link) {
211 	    if (first) {
212 		_cairo_output_stream_printf (surface->final_stream,
213 					     "%%%%DocumentMedia: ");
214 		first = FALSE;
215 	    } else {
216 		_cairo_output_stream_printf (surface->final_stream,
217 					     "%%%%+ ");
218 	    }
219 	    _cairo_output_stream_printf (surface->final_stream,
220 					 "%s %d %d 0 () ()\n",
221 					 page->name,
222 					 page->width,
223 					 page->height);
224 	}
225     }
226 
227     num_comments = _cairo_array_num_elements (&surface->dsc_header_comments);
228     comments = _cairo_array_index (&surface->dsc_header_comments, 0);
229     for (i = 0; i < num_comments; i++) {
230 	_cairo_output_stream_printf (surface->final_stream,
231 				     "%s\n", comments[i]);
232 	free (comments[i]);
233 	comments[i] = NULL;
234     }
235 
236     _cairo_output_stream_printf (surface->final_stream,
237 				 "%%%%EndComments\n");
238 
239     _cairo_output_stream_printf (surface->final_stream,
240 				 "%%%%BeginProlog\n");
241 
242     if (surface->eps) {
243 	_cairo_output_stream_printf (surface->final_stream,
244 				     "/cairo_eps_state save def\n"
245 				     "/dict_count countdictstack def\n"
246 				     "/op_count count 1 sub def\n"
247 				     "userdict begin\n");
248     } else {
249 	_cairo_output_stream_printf (surface->final_stream,
250 				     "/languagelevel where\n"
251 				     "{ pop languagelevel } { 1 } ifelse\n"
252 				     "%d lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto\n"
253 				     "  (This print job requires a PostScript Language Level %d printer.) show\n"
254 				     "  showpage quit } if\n",
255 				     level,
256 				     level);
257     }
258 
259     _cairo_output_stream_printf (surface->final_stream,
260 				 "/q { gsave } bind def\n"
261 				 "/Q { grestore } bind def\n"
262 				 "/cm { 6 array astore concat } bind def\n"
263 				 "/w { setlinewidth } bind def\n"
264 				 "/J { setlinecap } bind def\n"
265 				 "/j { setlinejoin } bind def\n"
266 				 "/M { setmiterlimit } bind def\n"
267 				 "/d { setdash } bind def\n"
268 				 "/m { moveto } bind def\n"
269 				 "/l { lineto } bind def\n"
270 				 "/c { curveto } bind def\n"
271 				 "/h { closepath } bind def\n"
272 				 "/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto\n"
273 				 "      0 exch rlineto 0 rlineto closepath } bind def\n"
274 				 "/S { stroke } bind def\n"
275 				 "/f { fill } bind def\n"
276 				 "/f* { eofill } bind def\n"
277 				 "/n { newpath } bind def\n"
278 				 "/W { clip } bind def\n"
279 				 "/W* { eoclip } bind def\n"
280 				 "/BT { } bind def\n"
281 				 "/ET { } bind def\n"
282 				 "/pdfmark where { pop globaldict /?pdfmark /exec load put }\n"
283 				 "    { globaldict begin /?pdfmark /pop load def /pdfmark\n"
284 				 "    /cleartomark load def end } ifelse\n"
285 				 "/BDC { mark 3 1 roll /BDC pdfmark } bind def\n"
286 				 "/EMC { mark /EMC pdfmark } bind def\n"
287 				 "/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def\n"
288 				 "/Tj { show currentpoint cairo_store_point } bind def\n"
289 				 "/TJ {\n"
290 				 "  {\n"
291 				 "    dup\n"
292 				 "    type /stringtype eq\n"
293 				 "    { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse\n"
294 				 "  } forall\n"
295 				 "  currentpoint cairo_store_point\n"
296 				 "} bind def\n"
297 				 "/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore\n"
298 				 "    cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def\n"
299 				 "/Tf { pop /cairo_font exch def /cairo_font_matrix where\n"
300 				 "      { pop cairo_selectfont } if } bind def\n"
301 				 "/Td { matrix translate cairo_font_matrix matrix concatmatrix dup\n"
302 				 "      /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point\n"
303 				 "      /cairo_font where { pop cairo_selectfont } if } bind def\n"
304 				 "/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def\n"
305 				 "      cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def\n"
306 				 "/g { setgray } bind def\n"
307 				 "/rg { setrgbcolor } bind def\n"
308 				 "/d1 { setcachedevice } bind def\n");
309 
310     _cairo_output_stream_printf (surface->final_stream,
311 				 "%%%%EndProlog\n");
312 
313     num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
314     if (num_comments) {
315 	_cairo_output_stream_printf (surface->final_stream,
316 				     "%%%%BeginSetup\n");
317 
318 	comments = _cairo_array_index (&surface->dsc_setup_comments, 0);
319 	for (i = 0; i < num_comments; i++) {
320 	    _cairo_output_stream_printf (surface->final_stream,
321 					 "%s\n", comments[i]);
322 	    free (comments[i]);
323 	    comments[i] = NULL;
324 	}
325 
326 	_cairo_output_stream_printf (surface->final_stream,
327 				     "%%%%EndSetup\n");
328     }
329 }
330 
331 #if CAIRO_HAS_FT_FONT
332 static cairo_status_t
_cairo_ps_surface_emit_type1_font_subset(cairo_ps_surface_t * surface,cairo_scaled_font_subset_t * font_subset)333 _cairo_ps_surface_emit_type1_font_subset (cairo_ps_surface_t		*surface,
334 					  cairo_scaled_font_subset_t	*font_subset)
335 
336 
337 {
338     cairo_type1_subset_t subset;
339     cairo_status_t status;
340     int length;
341     char name[64];
342 
343     snprintf (name, sizeof name, "f-%d-%d",
344 	      font_subset->font_id, font_subset->subset_id);
345     status = _cairo_type1_subset_init (&subset, name, font_subset, TRUE);
346     if (unlikely (status))
347 	return status;
348 
349     /* FIXME: Figure out document structure convention for fonts */
350 
351 #if DEBUG_PS
352     _cairo_output_stream_printf (surface->final_stream,
353 				 "%% _cairo_ps_surface_emit_type1_font_subset\n");
354 #endif
355 
356     length = subset.header_length + subset.data_length + subset.trailer_length;
357     _cairo_output_stream_write (surface->final_stream, subset.data, length);
358 
359     _cairo_type1_subset_fini (&subset);
360 
361     return CAIRO_STATUS_SUCCESS;
362 }
363 #endif
364 
365 static cairo_status_t
_cairo_ps_surface_emit_type1_font_fallback(cairo_ps_surface_t * surface,cairo_scaled_font_subset_t * font_subset)366 _cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t		*surface,
367                                             cairo_scaled_font_subset_t	*font_subset)
368 {
369     cairo_type1_subset_t subset;
370     cairo_status_t status;
371     int length;
372     char name[64];
373 
374     snprintf (name, sizeof name, "f-%d-%d",
375 	      font_subset->font_id, font_subset->subset_id);
376     status = _cairo_type1_fallback_init_hex (&subset, name, font_subset);
377     if (unlikely (status))
378 	return status;
379 
380     /* FIXME: Figure out document structure convention for fonts */
381 
382 #if DEBUG_PS
383     _cairo_output_stream_printf (surface->final_stream,
384 				 "%% _cairo_ps_surface_emit_type1_font_fallback\n");
385 #endif
386 
387     length = subset.header_length + subset.data_length + subset.trailer_length;
388     _cairo_output_stream_write (surface->final_stream, subset.data, length);
389 
390     _cairo_type1_fallback_fini (&subset);
391 
392     return CAIRO_STATUS_SUCCESS;
393 }
394 
395 static cairo_status_t
_cairo_ps_surface_emit_truetype_font_subset(cairo_ps_surface_t * surface,cairo_scaled_font_subset_t * font_subset)396 _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t		*surface,
397 					     cairo_scaled_font_subset_t	*font_subset)
398 
399 
400 {
401     cairo_truetype_subset_t subset;
402     cairo_status_t status;
403     unsigned int i, begin, end;
404 
405     status = _cairo_truetype_subset_init (&subset, font_subset);
406     if (unlikely (status))
407 	return status;
408 
409     /* FIXME: Figure out document structure convention for fonts */
410 
411 #if DEBUG_PS
412     _cairo_output_stream_printf (surface->final_stream,
413 				 "%% _cairo_ps_surface_emit_truetype_font_subset\n");
414 #endif
415 
416     _cairo_output_stream_printf (surface->final_stream,
417 				 "11 dict begin\n"
418 				 "/FontType 42 def\n"
419 				 "/FontName /%s def\n"
420 				 "/PaintType 0 def\n"
421 				 "/FontMatrix [ 1 0 0 1 0 0 ] def\n"
422 				 "/FontBBox [ 0 0 0 0 ] def\n"
423 				 "/Encoding 256 array def\n"
424 				 "0 1 255 { Encoding exch /.notdef put } for\n",
425 				 subset.ps_name);
426 
427     /* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */
428 
429     for (i = 1; i < font_subset->num_glyphs; i++) {
430 	if (font_subset->glyph_names != NULL) {
431 	    _cairo_output_stream_printf (surface->final_stream,
432 					 "Encoding %d /%s put\n",
433 					 i, font_subset->glyph_names[i]);
434 	} else {
435 	    _cairo_output_stream_printf (surface->final_stream,
436 					 "Encoding %d /g%d put\n", i, i);
437 	}
438     }
439 
440     _cairo_output_stream_printf (surface->final_stream,
441 				 "/CharStrings %d dict dup begin\n"
442 				 "/.notdef 0 def\n",
443 				 font_subset->num_glyphs);
444 
445     for (i = 1; i < font_subset->num_glyphs; i++) {
446 	if (font_subset->glyph_names != NULL) {
447 	    _cairo_output_stream_printf (surface->final_stream,
448 					 "/%s %d def\n",
449 					 font_subset->glyph_names[i], i);
450 	} else {
451 	    _cairo_output_stream_printf (surface->final_stream,
452 					 "/g%d %d def\n", i, i);
453 	}
454     }
455 
456     _cairo_output_stream_printf (surface->final_stream,
457 				 "end readonly def\n");
458 
459     _cairo_output_stream_printf (surface->final_stream,
460 				 "/sfnts [\n");
461     begin = 0;
462     end = 0;
463     for (i = 0; i < subset.num_string_offsets; i++) {
464         end = subset.string_offsets[i];
465         _cairo_output_stream_printf (surface->final_stream,"<");
466         _cairo_output_stream_write_hex_string (surface->final_stream,
467                                                subset.data + begin, end - begin);
468         _cairo_output_stream_printf (surface->final_stream,"00>\n");
469         begin = end;
470     }
471     if (subset.data_length > end) {
472         _cairo_output_stream_printf (surface->final_stream,"<");
473         _cairo_output_stream_write_hex_string (surface->final_stream,
474                                                subset.data + end, subset.data_length - end);
475         _cairo_output_stream_printf (surface->final_stream,"00>\n");
476     }
477 
478     _cairo_output_stream_printf (surface->final_stream,
479 				 "] def\n"
480 				 "/f-%d-%d currentdict end definefont pop\n",
481 				 font_subset->font_id,
482 				 font_subset->subset_id);
483 
484     _cairo_truetype_subset_fini (&subset);
485 
486     return CAIRO_STATUS_SUCCESS;
487 }
488 
489 static cairo_status_t
_cairo_ps_emit_imagemask(cairo_image_surface_t * image,cairo_output_stream_t * stream)490 _cairo_ps_emit_imagemask (cairo_image_surface_t *image,
491 			  cairo_output_stream_t *stream)
492 {
493     uint8_t *row, *byte;
494     int rows, cols;
495 
496     /* The only image type supported by Type 3 fonts are 1-bit image
497      * masks */
498     assert (image->format == CAIRO_FORMAT_A1);
499 
500     _cairo_output_stream_printf (stream,
501 				 "<<\n"
502 				 "   /ImageType 1\n"
503 				 "   /Width %d\n"
504 				 "   /Height %d\n"
505 				 "   /ImageMatrix [%d 0 0 %d 0 %d]\n"
506 				 "   /Decode [1 0]\n"
507 				 "   /BitsPerComponent 1\n",
508 				 image->width,
509 				 image->height,
510 				 image->width,
511 				 -image->height,
512 				 image->height);
513 
514     _cairo_output_stream_printf (stream,
515 				 "   /DataSource {<\n   ");
516     for (row = image->data, rows = image->height; rows; row += image->stride, rows--) {
517 	for (byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) {
518 	    uint8_t output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
519 	    _cairo_output_stream_printf (stream, "%02x ", output_byte);
520 	}
521 	_cairo_output_stream_printf (stream, "\n   ");
522     }
523     _cairo_output_stream_printf (stream, ">}\n>>\n");
524 
525     _cairo_output_stream_printf (stream,
526 				 "imagemask\n");
527 
528     return _cairo_output_stream_get_status (stream);
529 }
530 
531 static cairo_status_t
_cairo_ps_surface_analyze_user_font_subset(cairo_scaled_font_subset_t * font_subset,void * closure)532 _cairo_ps_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset,
533 					    void		       *closure)
534 {
535     cairo_ps_surface_t *surface = closure;
536     cairo_status_t status = CAIRO_STATUS_SUCCESS;
537     unsigned int i;
538     cairo_surface_t *type3_surface;
539 
540     type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
541 						       NULL,
542 						       _cairo_ps_emit_imagemask,
543 						       surface->font_subsets);
544 
545     for (i = 0; i < font_subset->num_glyphs; i++) {
546 	status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
547 							   font_subset->glyphs[i]);
548 	if (unlikely (status))
549 	    break;
550 
551     }
552     cairo_surface_finish (type3_surface);
553     cairo_surface_destroy (type3_surface);
554 
555     return status;
556 }
557 
558 static cairo_status_t
_cairo_ps_surface_emit_type3_font_subset(cairo_ps_surface_t * surface,cairo_scaled_font_subset_t * font_subset)559 _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t		*surface,
560 					  cairo_scaled_font_subset_t	*font_subset)
561 
562 
563 {
564     cairo_status_t status;
565     unsigned int i;
566     cairo_box_t font_bbox = {{0,0},{0,0}};
567     cairo_box_t bbox = {{0,0},{0,0}};
568     cairo_surface_t *type3_surface;
569     double width;
570 
571     if (font_subset->num_glyphs == 0)
572 	return CAIRO_STATUS_SUCCESS;
573 
574 #if DEBUG_PS
575     _cairo_output_stream_printf (surface->final_stream,
576 				 "%% _cairo_ps_surface_emit_type3_font_subset\n");
577 #endif
578 
579     _cairo_output_stream_printf (surface->final_stream,
580 				 "8 dict begin\n"
581 				 "/FontType 3 def\n"
582 				 "/FontMatrix [1 0 0 1 0 0] def\n"
583 				 "/Encoding 256 array def\n"
584 				 "0 1 255 { Encoding exch /.notdef put } for\n");
585 
586     type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
587 						       NULL,
588 						       _cairo_ps_emit_imagemask,
589 						       surface->font_subsets);
590     status = type3_surface->status;
591     if (unlikely (status))
592 	return status;
593 
594     for (i = 0; i < font_subset->num_glyphs; i++) {
595 	if (font_subset->glyph_names != NULL) {
596 	    _cairo_output_stream_printf (surface->final_stream,
597 					 "Encoding %d /%s put\n",
598 					 i, font_subset->glyph_names[i]);
599 	} else {
600 	    _cairo_output_stream_printf (surface->final_stream,
601 					 "Encoding %d /g%d put\n", i, i);
602 	}
603     }
604 
605     _cairo_output_stream_printf (surface->final_stream,
606 				 "/Glyphs [\n");
607 
608     for (i = 0; i < font_subset->num_glyphs; i++) {
609 	_cairo_output_stream_printf (surface->final_stream,
610 				     "    { %% %d\n", i);
611 	status = _cairo_type3_glyph_surface_emit_glyph (type3_surface,
612 							surface->final_stream,
613 							font_subset->glyphs[i],
614 							&bbox,
615 							&width);
616 	if (unlikely (status))
617 	    break;
618 
619 	_cairo_output_stream_printf (surface->final_stream,
620 				     "    }\n");
621         if (i == 0) {
622             font_bbox.p1.x = bbox.p1.x;
623             font_bbox.p1.y = bbox.p1.y;
624             font_bbox.p2.x = bbox.p2.x;
625             font_bbox.p2.y = bbox.p2.y;
626         } else {
627             if (bbox.p1.x < font_bbox.p1.x)
628                 font_bbox.p1.x = bbox.p1.x;
629             if (bbox.p1.y < font_bbox.p1.y)
630                 font_bbox.p1.y = bbox.p1.y;
631             if (bbox.p2.x > font_bbox.p2.x)
632                 font_bbox.p2.x = bbox.p2.x;
633             if (bbox.p2.y > font_bbox.p2.y)
634                 font_bbox.p2.y = bbox.p2.y;
635         }
636     }
637     cairo_surface_finish (type3_surface);
638     cairo_surface_destroy (type3_surface);
639     if (unlikely (status))
640 	return status;
641 
642     _cairo_output_stream_printf (surface->final_stream,
643 				 "] def\n"
644 				 "/FontBBox [%f %f %f %f] def\n"
645 				 "/BuildChar {\n"
646 				 "  exch /Glyphs get\n"
647 				 "  exch get\n"
648 				 "  10 dict begin exec end\n"
649 				 "} bind def\n"
650 				 "currentdict\n"
651 				 "end\n"
652 				 "/f-%d-%d exch definefont pop\n",
653 				 _cairo_fixed_to_double (font_bbox.p1.x),
654 				 - _cairo_fixed_to_double (font_bbox.p2.y),
655 				 _cairo_fixed_to_double (font_bbox.p2.x),
656 				 - _cairo_fixed_to_double (font_bbox.p1.y),
657 				 font_subset->font_id,
658 				 font_subset->subset_id);
659 
660     return CAIRO_STATUS_SUCCESS;
661 }
662 
663 static cairo_status_t
_cairo_ps_surface_emit_unscaled_font_subset(cairo_scaled_font_subset_t * font_subset,void * closure)664 _cairo_ps_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t	*font_subset,
665 				            void			*closure)
666 {
667     cairo_ps_surface_t *surface = closure;
668     cairo_status_t status;
669 
670 
671     status = _cairo_scaled_font_subset_create_glyph_names (font_subset);
672     if (_cairo_status_is_error (status))
673 	return status;
674 
675 #if CAIRO_HAS_FT_FONT
676     status = _cairo_ps_surface_emit_type1_font_subset (surface, font_subset);
677     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
678 	return status;
679 #endif
680 
681     status = _cairo_ps_surface_emit_truetype_font_subset (surface, font_subset);
682     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
683 	return status;
684 
685     status = _cairo_ps_surface_emit_type1_font_fallback (surface, font_subset);
686     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
687 	return status;
688 
689     ASSERT_NOT_REACHED;
690     return CAIRO_STATUS_SUCCESS;
691 }
692 
693 static cairo_status_t
_cairo_ps_surface_emit_scaled_font_subset(cairo_scaled_font_subset_t * font_subset,void * closure)694 _cairo_ps_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset,
695                                            void			      *closure)
696 {
697     cairo_ps_surface_t *surface = closure;
698     cairo_status_t status;
699 
700     status = _cairo_scaled_font_subset_create_glyph_names (font_subset);
701     if (_cairo_status_is_error (status))
702 	return status;
703 
704     status = _cairo_ps_surface_emit_type3_font_subset (surface, font_subset);
705     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
706 	return status;
707 
708     ASSERT_NOT_REACHED;
709     return CAIRO_STATUS_SUCCESS;
710 }
711 
712 static cairo_status_t
_cairo_ps_surface_emit_font_subsets(cairo_ps_surface_t * surface)713 _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface)
714 {
715     cairo_status_t status;
716 
717 #if DEBUG_PS
718     _cairo_output_stream_printf (surface->final_stream,
719 				 "%% _cairo_ps_surface_emit_font_subsets\n");
720 #endif
721 
722     status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
723 						      _cairo_ps_surface_analyze_user_font_subset,
724 						      surface);
725     if (unlikely (status))
726 	return status;
727 
728     status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
729                                                           _cairo_ps_surface_emit_unscaled_font_subset,
730                                                           surface);
731     if (unlikely (status))
732 	return status;
733 
734     status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
735                                                         _cairo_ps_surface_emit_scaled_font_subset,
736                                                         surface);
737     if (unlikely (status))
738 	return status;
739 
740     return _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
741 						    _cairo_ps_surface_emit_scaled_font_subset,
742 						    surface);
743 }
744 
745 static cairo_status_t
_cairo_ps_surface_emit_body(cairo_ps_surface_t * surface)746 _cairo_ps_surface_emit_body (cairo_ps_surface_t *surface)
747 {
748     char    buf[4096];
749     int	    n;
750 
751     if (ferror (surface->tmpfile) != 0)
752 	return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
753 
754     rewind (surface->tmpfile);
755     while ((n = fread (buf, 1, sizeof (buf), surface->tmpfile)) > 0)
756 	_cairo_output_stream_write (surface->final_stream, buf, n);
757 
758     if (ferror (surface->tmpfile) != 0)
759 	return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
760 
761     return CAIRO_STATUS_SUCCESS;
762 }
763 
764 static void
_cairo_ps_surface_emit_footer(cairo_ps_surface_t * surface)765 _cairo_ps_surface_emit_footer (cairo_ps_surface_t *surface)
766 {
767     _cairo_output_stream_printf (surface->final_stream,
768 				 "%%%%Trailer\n");
769 
770     if (surface->eps) {
771 	_cairo_output_stream_printf (surface->final_stream,
772 				     "count op_count sub {pop} repeat\n"
773 				     "countdictstack dict_count sub {end} repeat\n"
774 				     "cairo_eps_state restore\n");
775     }
776 
777     _cairo_output_stream_printf (surface->final_stream,
778 				 "%%%%EOF\n");
779 }
780 
781 static cairo_bool_t
_path_covers_bbox(cairo_ps_surface_t * surface,cairo_path_fixed_t * path)782 _path_covers_bbox (cairo_ps_surface_t *surface,
783 		   cairo_path_fixed_t *path)
784 {
785     cairo_box_t box;
786 
787     if (_cairo_path_fixed_is_box (path, &box)) {
788 	cairo_rectangle_int_t rect;
789 
790 	_cairo_box_round_to_rectangle (&box, &rect);
791 
792 	/* skip trivial whole-page clips */
793 	if (_cairo_rectangle_intersect (&rect, &surface->page_bbox)) {
794 	    if (rect.x == surface->page_bbox.x &&
795 		rect.width == surface->page_bbox.width &&
796 		rect.y == surface->page_bbox.y &&
797 		rect.height == surface->page_bbox.height)
798 	    {
799 		return TRUE;
800 	    }
801 	}
802     }
803 
804     return FALSE;
805 }
806 
807 static cairo_status_t
_cairo_ps_surface_clipper_intersect_clip_path(cairo_surface_clipper_t * clipper,cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias)808 _cairo_ps_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
809 					       cairo_path_fixed_t *path,
810 					       cairo_fill_rule_t   fill_rule,
811 					       double		    tolerance,
812 					       cairo_antialias_t   antialias)
813 {
814     cairo_ps_surface_t *surface = cairo_container_of (clipper,
815 						      cairo_ps_surface_t,
816 						      clipper);
817     cairo_output_stream_t *stream = surface->stream;
818     cairo_status_t status;
819 
820     assert (surface->paginated_mode != CAIRO_PAGINATED_MODE_ANALYZE);
821 
822 #if DEBUG_PS
823     _cairo_output_stream_printf (stream,
824 				 "%% _cairo_ps_surface_intersect_clip_path\n");
825 #endif
826 
827     if (path == NULL) {
828 	status = _cairo_pdf_operators_flush (&surface->pdf_operators);
829 	if (unlikely (status))
830 	    return status;
831 
832 	_cairo_output_stream_printf (stream, "Q q\n");
833 
834 	surface->current_pattern_is_solid_color = FALSE;
835 	_cairo_pdf_operators_reset (&surface->pdf_operators);
836 
837 	return CAIRO_STATUS_SUCCESS;
838     }
839 
840     if (_path_covers_bbox (surface, path))
841 	return CAIRO_STATUS_SUCCESS;
842 
843     return _cairo_pdf_operators_clip (&surface->pdf_operators,
844 				      path,
845 				      fill_rule);
846 }
847 
848 /* PLRM specifies a tolerance of 5 points when matching page sizes */
849 static cairo_bool_t
_ps_page_dimension_equal(int a,int b)850 _ps_page_dimension_equal (int a, int b)
851 {
852     return (abs (a - b) < 5);
853 }
854 
855 static const char *
_cairo_ps_surface_get_page_media(cairo_ps_surface_t * surface)856 _cairo_ps_surface_get_page_media (cairo_ps_surface_t     *surface)
857 {
858     int width, height, i;
859     char buf[50];
860     cairo_page_media_t *page;
861     const char *page_name;
862 
863     width = _cairo_lround (surface->width);
864     height = _cairo_lround (surface->height);
865 
866     /* search previously used page sizes */
867     cairo_list_foreach_entry (page, cairo_page_media_t, &surface->document_media, link) {
868 	if (_ps_page_dimension_equal (width, page->width) &&
869 	    _ps_page_dimension_equal (height, page->height))
870 	    return page->name;
871     }
872 
873     /* search list of standard page sizes */
874     page_name = NULL;
875     for (i = 0; i < ARRAY_LENGTH (_cairo_page_standard_media); i++) {
876 	if (_ps_page_dimension_equal (width, _cairo_page_standard_media[i].width) &&
877 	    _ps_page_dimension_equal (height, _cairo_page_standard_media[i].height))
878 	{
879 	    page_name = _cairo_page_standard_media[i].name;
880 	    width = _cairo_page_standard_media[i].width;
881 	    height = _cairo_page_standard_media[i].height;
882 	    break;
883 	}
884     }
885 
886     page = malloc (sizeof (cairo_page_media_t));
887     if (unlikely (page == NULL)) {
888 	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
889 	return NULL;
890     }
891 
892     if (page_name) {
893 	page->name = strdup (page_name);
894     } else {
895 	snprintf (buf, sizeof (buf), "%dx%dmm",
896 		  (int) _cairo_lround (surface->width * 25.4/72),
897 		  (int) _cairo_lround (surface->height * 25.4/72));
898 	page->name = strdup (buf);
899     }
900 
901     if (unlikely (page->name == NULL)) {
902 	free (page);
903 	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
904 	return NULL;
905     }
906 
907     page->width = width;
908     page->height = height;
909     cairo_list_add_tail (&page->link, &surface->document_media);
910 
911     return page->name;
912 }
913 
914 static cairo_surface_t *
_cairo_ps_surface_create_for_stream_internal(cairo_output_stream_t * stream,double width,double height)915 _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
916 					      double		     width,
917 					      double		     height)
918 {
919     cairo_status_t status, status_ignored;
920     cairo_ps_surface_t *surface;
921 
922     surface = malloc (sizeof (cairo_ps_surface_t));
923     if (unlikely (surface == NULL)) {
924 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
925 	goto CLEANUP;
926     }
927 
928     _cairo_surface_init (&surface->base,
929 			 &cairo_ps_surface_backend,
930 			 NULL, /* device */
931 			 CAIRO_CONTENT_COLOR_ALPHA);
932 
933     surface->final_stream = stream;
934 
935     surface->tmpfile = tmpfile ();
936     if (surface->tmpfile == NULL) {
937 	switch (errno) {
938 	case ENOMEM:
939 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
940 	    break;
941 	default:
942 	    status = _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
943 	    break;
944 	}
945 	goto CLEANUP_SURFACE;
946     }
947 
948     surface->stream = _cairo_output_stream_create_for_file (surface->tmpfile);
949     status = _cairo_output_stream_get_status (surface->stream);
950     if (unlikely (status))
951 	goto CLEANUP_OUTPUT_STREAM;
952 
953     surface->font_subsets = _cairo_scaled_font_subsets_create_simple ();
954     if (unlikely (surface->font_subsets == NULL)) {
955 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
956 	goto CLEANUP_OUTPUT_STREAM;
957     }
958 
959     surface->has_creation_date = FALSE;
960     surface->eps = FALSE;
961     surface->ps_level = CAIRO_PS_LEVEL_3;
962     surface->ps_level_used = CAIRO_PS_LEVEL_2;
963     surface->width  = width;
964     surface->height = height;
965     cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, height);
966     surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
967     surface->force_fallbacks = FALSE;
968     surface->content = CAIRO_CONTENT_COLOR_ALPHA;
969     surface->use_string_datasource = FALSE;
970     surface->current_pattern_is_solid_color = FALSE;
971 
972     surface->page_bbox.x = 0;
973     surface->page_bbox.y = 0;
974     surface->page_bbox.width  = width;
975     surface->page_bbox.height = height;
976 
977     _cairo_surface_clipper_init (&surface->clipper,
978 				 _cairo_ps_surface_clipper_intersect_clip_path);
979 
980     _cairo_pdf_operators_init (&surface->pdf_operators,
981 			       surface->stream,
982 			       &surface->cairo_to_ps,
983 			       surface->font_subsets);
984     surface->num_pages = 0;
985 
986     cairo_list_init (&surface->document_media);
987     _cairo_array_init (&surface->dsc_header_comments, sizeof (char *));
988     _cairo_array_init (&surface->dsc_setup_comments, sizeof (char *));
989     _cairo_array_init (&surface->dsc_page_setup_comments, sizeof (char *));
990 
991     surface->dsc_comment_target = &surface->dsc_header_comments;
992 
993     surface->paginated_surface = _cairo_paginated_surface_create (
994 	                                   &surface->base,
995 					   CAIRO_CONTENT_COLOR_ALPHA,
996 					   &cairo_ps_surface_paginated_backend);
997     status = surface->paginated_surface->status;
998     if (status == CAIRO_STATUS_SUCCESS) {
999 	/* paginated keeps the only reference to surface now, drop ours */
1000 	cairo_surface_destroy (&surface->base);
1001 	return surface->paginated_surface;
1002     }
1003 
1004     _cairo_scaled_font_subsets_destroy (surface->font_subsets);
1005  CLEANUP_OUTPUT_STREAM:
1006     status_ignored = _cairo_output_stream_destroy (surface->stream);
1007     fclose (surface->tmpfile);
1008  CLEANUP_SURFACE:
1009     free (surface);
1010  CLEANUP:
1011     /* destroy stream on behalf of caller */
1012     status_ignored = _cairo_output_stream_destroy (stream);
1013 
1014     return _cairo_surface_create_in_error (status);
1015 }
1016 
1017 /**
1018  * cairo_ps_surface_create:
1019  * @filename: a filename for the PS output (must be writable), %NULL may be
1020  *            used to specify no output. This will generate a PS surface that
1021  *            may be queried and used as a source, without generating a
1022  *            temporary file.
1023  * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
1024  * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
1025  *
1026  * Creates a PostScript surface of the specified size in points to be
1027  * written to @filename. See cairo_ps_surface_create_for_stream() for
1028  * a more flexible mechanism for handling the PostScript output than
1029  * simply writing it to a named file.
1030  *
1031  * Note that the size of individual pages of the PostScript output can
1032  * vary. See cairo_ps_surface_set_size().
1033  *
1034  * Return value: a pointer to the newly created surface. The caller
1035  * owns the surface and should call cairo_surface_destroy() when done
1036  * with it.
1037  *
1038  * This function always returns a valid pointer, but it will return a
1039  * pointer to a "nil" surface if an error such as out of memory
1040  * occurs. You can use cairo_surface_status() to check for this.
1041  *
1042  * Since: 1.2
1043  **/
1044 cairo_surface_t *
cairo_ps_surface_create(const char * filename,double width_in_points,double height_in_points)1045 cairo_ps_surface_create (const char		*filename,
1046 			 double			 width_in_points,
1047 			 double			 height_in_points)
1048 {
1049     cairo_output_stream_t *stream;
1050 
1051     stream = _cairo_output_stream_create_for_filename (filename);
1052     if (_cairo_output_stream_get_status (stream))
1053 	return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream));
1054 
1055     return _cairo_ps_surface_create_for_stream_internal (stream,
1056 							 width_in_points,
1057 							 height_in_points);
1058 }
1059 
1060 /**
1061  * cairo_ps_surface_create_for_stream:
1062  * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL
1063  *              to indicate a no-op @write_func. With a no-op @write_func,
1064  *              the surface may be queried or used as a source without
1065  *              generating any temporary files.
1066  * @closure: the closure argument for @write_func
1067  * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
1068  * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
1069  *
1070  * Creates a PostScript surface of the specified size in points to be
1071  * written incrementally to the stream represented by @write_func and
1072  * @closure. See cairo_ps_surface_create() for a more convenient way
1073  * to simply direct the PostScript output to a named file.
1074  *
1075  * Note that the size of individual pages of the PostScript
1076  * output can vary. See cairo_ps_surface_set_size().
1077  *
1078  * Return value: a pointer to the newly created surface. The caller
1079  * owns the surface and should call cairo_surface_destroy() when done
1080  * with it.
1081  *
1082  * This function always returns a valid pointer, but it will return a
1083  * pointer to a "nil" surface if an error such as out of memory
1084  * occurs. You can use cairo_surface_status() to check for this.
1085  *
1086  * Since: 1.2
1087  */
1088 cairo_surface_t *
cairo_ps_surface_create_for_stream(cairo_write_func_t write_func,void * closure,double width_in_points,double height_in_points)1089 cairo_ps_surface_create_for_stream (cairo_write_func_t	write_func,
1090 				    void	       *closure,
1091 				    double		width_in_points,
1092 				    double		height_in_points)
1093 {
1094     cairo_output_stream_t *stream;
1095 
1096     stream = _cairo_output_stream_create (write_func, NULL, closure);
1097     if (_cairo_output_stream_get_status (stream))
1098 	return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream));
1099 
1100     return _cairo_ps_surface_create_for_stream_internal (stream,
1101 							 width_in_points,
1102 							 height_in_points);
1103 }
1104 
1105 static cairo_bool_t
_cairo_surface_is_ps(cairo_surface_t * surface)1106 _cairo_surface_is_ps (cairo_surface_t *surface)
1107 {
1108     return surface->backend == &cairo_ps_surface_backend;
1109 }
1110 
1111 /* If the abstract_surface is a paginated surface, and that paginated
1112  * surface's target is a ps_surface, then set ps_surface to that
1113  * target. Otherwise return FALSE.
1114  */
1115 static cairo_bool_t
_extract_ps_surface(cairo_surface_t * surface,cairo_bool_t set_error_on_failure,cairo_ps_surface_t ** ps_surface)1116 _extract_ps_surface (cairo_surface_t	 *surface,
1117                      cairo_bool_t         set_error_on_failure,
1118 		     cairo_ps_surface_t **ps_surface)
1119 {
1120     cairo_surface_t *target;
1121     cairo_status_t status_ignored;
1122 
1123     if (surface->status)
1124 	return FALSE;
1125     if (surface->finished) {
1126         if (set_error_on_failure)
1127             status_ignored = _cairo_surface_set_error (surface,
1128                                                        _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
1129 	return FALSE;
1130     }
1131 
1132     if (! _cairo_surface_is_paginated (surface)) {
1133         if (set_error_on_failure)
1134             status_ignored = _cairo_surface_set_error (surface,
1135                                                        _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
1136 	return FALSE;
1137     }
1138 
1139     target = _cairo_paginated_surface_get_target (surface);
1140     if (target->status) {
1141         if (set_error_on_failure)
1142             status_ignored = _cairo_surface_set_error (surface, target->status);
1143 	return FALSE;
1144     }
1145     if (target->finished) {
1146         if (set_error_on_failure)
1147             status_ignored = _cairo_surface_set_error (surface,
1148                                                        _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
1149 	return FALSE;
1150     }
1151 
1152     if (! _cairo_surface_is_ps (target)) {
1153         if (set_error_on_failure)
1154             status_ignored = _cairo_surface_set_error (surface,
1155                                                        _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
1156 	return FALSE;
1157     }
1158 
1159     *ps_surface = (cairo_ps_surface_t *) target;
1160     return TRUE;
1161 }
1162 
1163 /**
1164  * cairo_ps_surface_restrict_to_level:
1165  * @surface: a PostScript #cairo_surface_t
1166  * @level: PostScript level
1167  *
1168  * Restricts the generated PostSript file to @level. See
1169  * cairo_ps_get_levels() for a list of available level values that
1170  * can be used here.
1171  *
1172  * This function should only be called before any drawing operations
1173  * have been performed on the given surface. The simplest way to do
1174  * this is to call this function immediately after creating the
1175  * surface.
1176  *
1177  * Since: 1.6
1178  **/
1179 void
cairo_ps_surface_restrict_to_level(cairo_surface_t * surface,cairo_ps_level_t level)1180 cairo_ps_surface_restrict_to_level (cairo_surface_t  *surface,
1181                                     cairo_ps_level_t  level)
1182 {
1183     cairo_ps_surface_t *ps_surface = NULL;
1184 
1185     if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1186 	return;
1187 
1188     if (level < CAIRO_PS_LEVEL_LAST)
1189 	ps_surface->ps_level = level;
1190 }
1191 
1192 /**
1193  * cairo_ps_get_levels:
1194  * @levels: supported level list
1195  * @num_levels: list length
1196  *
1197  * Used to retrieve the list of supported levels. See
1198  * cairo_ps_surface_restrict_to_level().
1199  *
1200  * Since: 1.6
1201  **/
1202 void
cairo_ps_get_levels(cairo_ps_level_t const ** levels,int * num_levels)1203 cairo_ps_get_levels (cairo_ps_level_t const	**levels,
1204                      int                     	 *num_levels)
1205 {
1206     if (levels != NULL)
1207 	*levels = _cairo_ps_levels;
1208 
1209     if (num_levels != NULL)
1210 	*num_levels = CAIRO_PS_LEVEL_LAST;
1211 }
1212 
1213 /**
1214  * cairo_ps_level_to_string:
1215  * @level: a level id
1216  *
1217  * Get the string representation of the given @level id. This function
1218  * will return %NULL if @level id isn't valid. See cairo_ps_get_levels()
1219  * for a way to get the list of valid level ids.
1220  *
1221  * Return value: the string associated to given level.
1222  *
1223  * Since: 1.6
1224  **/
1225 const char *
cairo_ps_level_to_string(cairo_ps_level_t level)1226 cairo_ps_level_to_string (cairo_ps_level_t level)
1227 {
1228     if (level >= CAIRO_PS_LEVEL_LAST)
1229 	return NULL;
1230 
1231     return _cairo_ps_level_strings[level];
1232 }
1233 
1234 /**
1235  * cairo_ps_surface_set_eps:
1236  * @surface: a PostScript #cairo_surface_t
1237  * @eps: %TRUE to output EPS format PostScript
1238  *
1239  * If @eps is %TRUE, the PostScript surface will output Encapsulated
1240  * PostScript.
1241  *
1242  * This function should only be called before any drawing operations
1243  * have been performed on the current page. The simplest way to do
1244  * this is to call this function immediately after creating the
1245  * surface. An Encapsulated PostScript file should never contain more
1246  * than one page.
1247  *
1248  * Since: 1.6
1249  **/
1250 void
cairo_ps_surface_set_eps(cairo_surface_t * surface,cairo_bool_t eps)1251 cairo_ps_surface_set_eps (cairo_surface_t	*surface,
1252 			  cairo_bool_t           eps)
1253 {
1254     cairo_ps_surface_t *ps_surface = NULL;
1255 
1256     if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1257 	return;
1258 
1259     ps_surface->eps = eps;
1260 }
1261 
1262 /**
1263  * cairo_ps_surface_get_eps:
1264  * @surface: a PostScript #cairo_surface_t
1265  *
1266  * Check whether the PostScript surface will output Encapsulated PostScript.
1267  *
1268  * Return value: %TRUE if the surface will output Encapsulated PostScript.
1269  *
1270  * Since: 1.6
1271  **/
1272 cairo_public cairo_bool_t
cairo_ps_surface_get_eps(cairo_surface_t * surface)1273 cairo_ps_surface_get_eps (cairo_surface_t	*surface)
1274 {
1275     cairo_ps_surface_t *ps_surface = NULL;
1276 
1277     if (! _extract_ps_surface (surface, FALSE, &ps_surface))
1278 	return FALSE;
1279 
1280     return ps_surface->eps;
1281 }
1282 
1283 /**
1284  * cairo_ps_surface_set_size:
1285  * @surface: a PostScript #cairo_surface_t
1286  * @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
1287  * @height_in_points: new surface height, in points (1 point == 1/72.0 inch)
1288  *
1289  * Changes the size of a PostScript surface for the current (and
1290  * subsequent) pages.
1291  *
1292  * This function should only be called before any drawing operations
1293  * have been performed on the current page. The simplest way to do
1294  * this is to call this function immediately after creating the
1295  * surface or immediately after completing a page with either
1296  * cairo_show_page() or cairo_copy_page().
1297  *
1298  * Since: 1.2
1299  **/
1300 void
cairo_ps_surface_set_size(cairo_surface_t * surface,double width_in_points,double height_in_points)1301 cairo_ps_surface_set_size (cairo_surface_t	*surface,
1302 			   double		 width_in_points,
1303 			   double		 height_in_points)
1304 {
1305     cairo_ps_surface_t *ps_surface = NULL;
1306 
1307     if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1308 	return;
1309 
1310     ps_surface->width = width_in_points;
1311     ps_surface->height = height_in_points;
1312     cairo_matrix_init (&ps_surface->cairo_to_ps, 1, 0, 0, -1, 0, height_in_points);
1313     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface->pdf_operators,
1314 						  &ps_surface->cairo_to_ps);
1315 }
1316 
1317 /**
1318  * cairo_ps_surface_dsc_comment:
1319  * @surface: a PostScript #cairo_surface_t
1320  * @comment: a comment string to be emitted into the PostScript output
1321  *
1322  * Emit a comment into the PostScript output for the given surface.
1323  *
1324  * The comment is expected to conform to the PostScript Language
1325  * Document Structuring Conventions (DSC). Please see that manual for
1326  * details on the available comments and their meanings. In
1327  * particular, the %%IncludeFeature comment allows a
1328  * device-independent means of controlling printer device features. So
1329  * the PostScript Printer Description Files Specification will also be
1330  * a useful reference.
1331  *
1332  * The comment string must begin with a percent character (%) and the
1333  * total length of the string (including any initial percent
1334  * characters) must not exceed 255 characters. Violating either of
1335  * these conditions will place @surface into an error state. But
1336  * beyond these two conditions, this function will not enforce
1337  * conformance of the comment with any particular specification.
1338  *
1339  * The comment string should not have a trailing newline.
1340  *
1341  * The DSC specifies different sections in which particular comments
1342  * can appear. This function provides for comments to be emitted
1343  * within three sections: the header, the Setup section, and the
1344  * PageSetup section.  Comments appearing in the first two sections
1345  * apply to the entire document while comments in the BeginPageSetup
1346  * section apply only to a single page.
1347  *
1348  * For comments to appear in the header section, this function should
1349  * be called after the surface is created, but before a call to
1350  * cairo_ps_surface_begin_setup().
1351  *
1352  * For comments to appear in the Setup section, this function should
1353  * be called after a call to cairo_ps_surface_begin_setup() but before
1354  * a call to cairo_ps_surface_begin_page_setup().
1355  *
1356  * For comments to appear in the PageSetup section, this function
1357  * should be called after a call to cairo_ps_surface_begin_page_setup().
1358  *
1359  * Note that it is only necessary to call cairo_ps_surface_begin_page_setup()
1360  * for the first page of any surface. After a call to
1361  * cairo_show_page() or cairo_copy_page() comments are unambiguously
1362  * directed to the PageSetup section of the current page. But it
1363  * doesn't hurt to call this function at the beginning of every page
1364  * as that consistency may make the calling code simpler.
1365  *
1366  * As a final note, cairo automatically generates several comments on
1367  * its own. As such, applications must not manually generate any of
1368  * the following comments:
1369  *
1370  * Header section: %!PS-Adobe-3.0, %%Creator, %%CreationDate, %%Pages,
1371  * %%BoundingBox, %%DocumentData, %%LanguageLevel, %%EndComments.
1372  *
1373  * Setup section: %%BeginSetup, %%EndSetup
1374  *
1375  * PageSetup section: %%BeginPageSetup, %%PageBoundingBox,
1376  * %%EndPageSetup.
1377  *
1378  * Other sections: %%BeginProlog, %%EndProlog, %%Page, %%Trailer, %%EOF
1379  *
1380  * Here is an example sequence showing how this function might be used:
1381  *
1382  * <informalexample><programlisting>
1383  * #cairo_surface_t *surface = cairo_ps_surface_create (filename, width, height);
1384  * ...
1385  * cairo_ps_surface_dsc_comment (surface, "%%Title: My excellent document");
1386  * cairo_ps_surface_dsc_comment (surface, "%%Copyright: Copyright (C) 2006 Cairo Lover")
1387  * ...
1388  * cairo_ps_surface_dsc_begin_setup (surface);
1389  * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor White");
1390  * ...
1391  * cairo_ps_surface_dsc_begin_page_setup (surface);
1392  * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A3");
1393  * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *InputSlot LargeCapacity");
1394  * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaType Glossy");
1395  * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor Blue");
1396  * ... draw to first page here ..
1397  * cairo_show_page (cr);
1398  * ...
1399  * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A5");
1400  * ...
1401  * </programlisting></informalexample>
1402  *
1403  * Since: 1.2
1404  **/
1405 void
cairo_ps_surface_dsc_comment(cairo_surface_t * surface,const char * comment)1406 cairo_ps_surface_dsc_comment (cairo_surface_t	*surface,
1407 			      const char	*comment)
1408 {
1409     cairo_ps_surface_t *ps_surface = NULL;
1410     cairo_status_t status;
1411     char *comment_copy;
1412 
1413     if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1414 	return;
1415 
1416     /* A couple of sanity checks on the comment value. */
1417     if (comment == NULL) {
1418 	status = _cairo_surface_set_error (surface, CAIRO_STATUS_NULL_POINTER);
1419 	return;
1420     }
1421 
1422     if (comment[0] != '%' || strlen (comment) > 255) {
1423 	status = _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_DSC_COMMENT);
1424 	return;
1425     }
1426 
1427     /* Then, copy the comment and store it in the appropriate array. */
1428     comment_copy = strdup (comment);
1429     if (unlikely (comment_copy == NULL)) {
1430 	status = _cairo_surface_set_error (surface, CAIRO_STATUS_NO_MEMORY);
1431 	return;
1432     }
1433 
1434     status = _cairo_array_append (ps_surface->dsc_comment_target, &comment_copy);
1435     if (unlikely (status)) {
1436 	free (comment_copy);
1437 	status = _cairo_surface_set_error (surface, status);
1438 	return;
1439     }
1440 }
1441 
1442 /**
1443  * cairo_ps_surface_dsc_begin_setup:
1444  * @surface: a PostScript #cairo_surface_t
1445  *
1446  * This function indicates that subsequent calls to
1447  * cairo_ps_surface_dsc_comment() should direct comments to the Setup
1448  * section of the PostScript output.
1449  *
1450  * This function should be called at most once per surface, and must
1451  * be called before any call to cairo_ps_surface_dsc_begin_page_setup()
1452  * and before any drawing is performed to the surface.
1453  *
1454  * See cairo_ps_surface_dsc_comment() for more details.
1455  *
1456  * Since: 1.2
1457  **/
1458 void
cairo_ps_surface_dsc_begin_setup(cairo_surface_t * surface)1459 cairo_ps_surface_dsc_begin_setup (cairo_surface_t *surface)
1460 {
1461     cairo_ps_surface_t *ps_surface = NULL;
1462 
1463     if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1464 	return;
1465 
1466     if (ps_surface->dsc_comment_target == &ps_surface->dsc_header_comments)
1467 	ps_surface->dsc_comment_target = &ps_surface->dsc_setup_comments;
1468 }
1469 
1470 /**
1471  * cairo_ps_surface_dsc_begin_page_setup:
1472  * @surface: a PostScript #cairo_surface_t
1473  *
1474  * This function indicates that subsequent calls to
1475  * cairo_ps_surface_dsc_comment() should direct comments to the
1476  * PageSetup section of the PostScript output.
1477  *
1478  * This function call is only needed for the first page of a
1479  * surface. It should be called after any call to
1480  * cairo_ps_surface_dsc_begin_setup() and before any drawing is
1481  * performed to the surface.
1482  *
1483  * See cairo_ps_surface_dsc_comment() for more details.
1484  *
1485  * Since: 1.2
1486  **/
1487 void
cairo_ps_surface_dsc_begin_page_setup(cairo_surface_t * surface)1488 cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface)
1489 {
1490     cairo_ps_surface_t *ps_surface = NULL;
1491 
1492     if (! _extract_ps_surface (surface, TRUE, &ps_surface))
1493 	return;
1494 
1495     if (ps_surface->dsc_comment_target == &ps_surface->dsc_header_comments ||
1496 	ps_surface->dsc_comment_target == &ps_surface->dsc_setup_comments)
1497     {
1498 	ps_surface->dsc_comment_target = &ps_surface->dsc_page_setup_comments;
1499     }
1500 }
1501 
1502 static cairo_status_t
_cairo_ps_surface_finish(void * abstract_surface)1503 _cairo_ps_surface_finish (void *abstract_surface)
1504 {
1505     cairo_status_t status, status2;
1506     cairo_ps_surface_t *surface = abstract_surface;
1507     int i, num_comments;
1508     char **comments;
1509 
1510     status = surface->base.status;
1511     if (unlikely (status))
1512 	goto CLEANUP;
1513 
1514     _cairo_ps_surface_emit_header (surface);
1515 
1516     status = _cairo_ps_surface_emit_font_subsets (surface);
1517     if (unlikely (status))
1518 	goto CLEANUP;
1519 
1520     status = _cairo_ps_surface_emit_body (surface);
1521     if (unlikely (status))
1522 	goto CLEANUP;
1523 
1524     _cairo_ps_surface_emit_footer (surface);
1525 
1526 CLEANUP:
1527     _cairo_scaled_font_subsets_destroy (surface->font_subsets);
1528 
1529     status2 = _cairo_output_stream_destroy (surface->stream);
1530     if (status == CAIRO_STATUS_SUCCESS)
1531 	status = status2;
1532 
1533     fclose (surface->tmpfile);
1534 
1535     status2 = _cairo_output_stream_destroy (surface->final_stream);
1536     if (status == CAIRO_STATUS_SUCCESS)
1537 	status = status2;
1538 
1539     while (! cairo_list_is_empty (&surface->document_media)) {
1540         cairo_page_media_t *page;
1541 
1542         page = cairo_list_first_entry (&surface->document_media,
1543                                        cairo_page_media_t,
1544                                        link);
1545         cairo_list_del (&page->link);
1546 	free (page->name);
1547 	free (page);
1548     }
1549 
1550     num_comments = _cairo_array_num_elements (&surface->dsc_header_comments);
1551     comments = _cairo_array_index (&surface->dsc_header_comments, 0);
1552     for (i = 0; i < num_comments; i++)
1553 	free (comments[i]);
1554     _cairo_array_fini (&surface->dsc_header_comments);
1555 
1556     num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
1557     comments = _cairo_array_index (&surface->dsc_setup_comments, 0);
1558     for (i = 0; i < num_comments; i++)
1559 	free (comments[i]);
1560     _cairo_array_fini (&surface->dsc_setup_comments);
1561 
1562     num_comments = _cairo_array_num_elements (&surface->dsc_page_setup_comments);
1563     comments = _cairo_array_index (&surface->dsc_page_setup_comments, 0);
1564     for (i = 0; i < num_comments; i++)
1565 	free (comments[i]);
1566     _cairo_array_fini (&surface->dsc_page_setup_comments);
1567 
1568     _cairo_surface_clipper_reset (&surface->clipper);
1569 
1570     return status;
1571 }
1572 
1573 static cairo_int_status_t
_cairo_ps_surface_start_page(void * abstract_surface)1574 _cairo_ps_surface_start_page (void *abstract_surface)
1575 {
1576     cairo_ps_surface_t *surface = abstract_surface;
1577 
1578     /* Increment before print so page numbers start at 1. */
1579     surface->num_pages++;
1580 
1581     return CAIRO_STATUS_SUCCESS;
1582 }
1583 
1584 static cairo_int_status_t
_cairo_ps_surface_end_page(cairo_ps_surface_t * surface)1585 _cairo_ps_surface_end_page (cairo_ps_surface_t *surface)
1586 {
1587     cairo_int_status_t status;
1588 
1589     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
1590     if (unlikely (status))
1591 	return status;
1592 
1593     if (surface->clipper.clip.path != NULL) {
1594 	_cairo_output_stream_printf (surface->stream, "Q Q\n");
1595 	_cairo_surface_clipper_reset (&surface->clipper);
1596     } else
1597 	_cairo_output_stream_printf (surface->stream, "Q\n");
1598 
1599     return CAIRO_STATUS_SUCCESS;
1600 }
1601 
1602 static cairo_int_status_t
_cairo_ps_surface_show_page(void * abstract_surface)1603 _cairo_ps_surface_show_page (void *abstract_surface)
1604 {
1605     cairo_ps_surface_t *surface = abstract_surface;
1606     cairo_int_status_t status;
1607 
1608     status = _cairo_ps_surface_end_page (surface);
1609     if (unlikely (status))
1610 	return status;
1611 
1612     _cairo_output_stream_printf (surface->stream, "showpage\n");
1613 
1614     return CAIRO_STATUS_SUCCESS;
1615 }
1616 
1617 static cairo_bool_t
color_is_gray(double red,double green,double blue)1618 color_is_gray (double red, double green, double blue)
1619 {
1620     const double epsilon = 0.00001;
1621 
1622     return (fabs (red - green) < epsilon &&
1623 	    fabs (red - blue) < epsilon);
1624 }
1625 
1626 static cairo_int_status_t
_cairo_ps_surface_analyze_surface_pattern_transparency(cairo_ps_surface_t * surface,cairo_surface_pattern_t * pattern)1627 _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t      *surface,
1628 						       cairo_surface_pattern_t *pattern)
1629 {
1630     cairo_image_surface_t  *image;
1631     void		   *image_extra;
1632     cairo_int_status_t      status;
1633     cairo_image_transparency_t transparency;
1634 
1635     status = _cairo_surface_acquire_source_image (pattern->surface,
1636 						  &image,
1637 						  &image_extra);
1638     if (unlikely (status))
1639 	return status;
1640 
1641     if (image->base.status)
1642 	return image->base.status;
1643 
1644     transparency = _cairo_image_analyze_transparency (image);
1645     switch (transparency) {
1646     case CAIRO_IMAGE_IS_OPAQUE:
1647 	status = CAIRO_STATUS_SUCCESS;
1648 	break;
1649 
1650     case CAIRO_IMAGE_HAS_BILEVEL_ALPHA:
1651 	if (surface->ps_level == CAIRO_PS_LEVEL_2) {
1652 	    status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1653 	} else {
1654 	    surface->ps_level_used = CAIRO_PS_LEVEL_3;
1655 	    status = CAIRO_STATUS_SUCCESS;
1656 	}
1657 	break;
1658 
1659     case CAIRO_IMAGE_HAS_ALPHA:
1660 	status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1661 	break;
1662 
1663     case CAIRO_IMAGE_UNKNOWN:
1664 	ASSERT_NOT_REACHED;
1665     }
1666 
1667     _cairo_surface_release_source_image (pattern->surface, image, image_extra);
1668 
1669     return status;
1670 }
1671 
1672 static cairo_bool_t
surface_pattern_supported(const cairo_surface_pattern_t * pattern)1673 surface_pattern_supported (const cairo_surface_pattern_t *pattern)
1674 {
1675     if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
1676 	return TRUE;
1677 
1678     if (pattern->surface->backend->acquire_source_image == NULL)
1679 	return FALSE;
1680 
1681     /* Does an ALPHA-only source surface even make sense? Maybe, but I
1682      * don't think it's worth the extra code to support it. */
1683 
1684 /* XXX: Need to write this function here...
1685     content = pattern->surface->content;
1686     if (content == CAIRO_CONTENT_ALPHA)
1687 	return FALSE;
1688 */
1689 
1690     return TRUE;
1691 }
1692 
1693 static cairo_bool_t
_gradient_pattern_supported(cairo_ps_surface_t * surface,const cairo_pattern_t * pattern)1694 _gradient_pattern_supported (cairo_ps_surface_t    *surface,
1695 			     const cairo_pattern_t *pattern)
1696 {
1697     const cairo_gradient_pattern_t *gradient = (const cairo_gradient_pattern_t *) pattern;
1698     uint16_t alpha;
1699     cairo_extend_t extend;
1700     unsigned int i;
1701 
1702     if (surface->ps_level == CAIRO_PS_LEVEL_2)
1703 	return FALSE;
1704 
1705     if (gradient->n_stops == 0)
1706 	return TRUE;
1707 
1708     /* Alpha gradients are only supported (by flattening the alpha)
1709      * if there is no variation in the alpha across the gradient. */
1710     alpha = gradient->stops[0].color.alpha_short;
1711     for (i = 0; i < gradient->n_stops; i++) {
1712 	if (gradient->stops[i].color.alpha_short != alpha)
1713 	    return FALSE;
1714     }
1715 
1716     extend = cairo_pattern_get_extend ((cairo_pattern_t *) pattern);
1717 
1718     /* Radial gradients are currently only supported when one circle
1719      * is inside the other. */
1720     if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
1721         double x1, y1, x2, y2, r1, r2, d;
1722         cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
1723 
1724 	if (extend == CAIRO_EXTEND_REPEAT ||
1725 	    extend == CAIRO_EXTEND_REFLECT) {
1726 	    return FALSE;
1727 	}
1728 
1729         x1 = _cairo_fixed_to_double (radial->c1.x);
1730         y1 = _cairo_fixed_to_double (radial->c1.y);
1731         r1 = _cairo_fixed_to_double (radial->r1);
1732         x2 = _cairo_fixed_to_double (radial->c2.x);
1733         y2 = _cairo_fixed_to_double (radial->c2.y);
1734         r2 = _cairo_fixed_to_double (radial->r2);
1735 
1736         d = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
1737         if (d > fabs(r2 - r1)) {
1738             return FALSE;
1739         }
1740     }
1741 
1742     surface->ps_level_used = CAIRO_PS_LEVEL_3;
1743 
1744     return TRUE;
1745 }
1746 
1747 static cairo_bool_t
pattern_supported(cairo_ps_surface_t * surface,const cairo_pattern_t * pattern)1748 pattern_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *pattern)
1749 {
1750     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
1751 	return TRUE;
1752 
1753     if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
1754 	pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
1755 	return _gradient_pattern_supported (surface, pattern);
1756 
1757     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
1758 	return surface_pattern_supported ((cairo_surface_pattern_t *) pattern);
1759 
1760     return FALSE;
1761 }
1762 
1763 static cairo_int_status_t
_cairo_ps_surface_analyze_operation(cairo_ps_surface_t * surface,cairo_operator_t op,const cairo_pattern_t * pattern,const cairo_rectangle_int_t * extents)1764 _cairo_ps_surface_analyze_operation (cairo_ps_surface_t    *surface,
1765 				     cairo_operator_t       op,
1766 				     const cairo_pattern_t       *pattern,
1767 				     const cairo_rectangle_int_t *extents)
1768 {
1769     if (surface->force_fallbacks &&
1770 	surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
1771     {
1772 	return CAIRO_INT_STATUS_UNSUPPORTED;
1773     }
1774 
1775     if (! pattern_supported (surface, pattern))
1776     {
1777 	return CAIRO_INT_STATUS_UNSUPPORTED;
1778     }
1779 
1780     if (! (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
1781 	return CAIRO_INT_STATUS_UNSUPPORTED;
1782 
1783     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
1784 	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
1785 
1786 	if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
1787 	    if (pattern->extend == CAIRO_EXTEND_PAD)
1788 		return CAIRO_INT_STATUS_UNSUPPORTED;
1789 	    else
1790 		return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
1791 	}
1792     }
1793 
1794     if (op == CAIRO_OPERATOR_SOURCE)
1795 	return CAIRO_STATUS_SUCCESS;
1796 
1797     /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
1798      * the pattern contains transparency, we return
1799      * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
1800      * surface. If the analysis surface determines that there is
1801      * anything drawn under this operation, a fallback image will be
1802      * used. Otherwise the operation will be replayed during the
1803      * render stage and we blend the transparency into the white
1804      * background to convert the pattern to opaque.
1805      */
1806     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
1807 	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
1808 
1809 	return _cairo_ps_surface_analyze_surface_pattern_transparency (surface,
1810 								       surface_pattern);
1811     }
1812 
1813     if (_cairo_pattern_is_opaque (pattern, extents))
1814 	return CAIRO_STATUS_SUCCESS;
1815 
1816     return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1817 }
1818 
1819 static cairo_bool_t
_cairo_ps_surface_operation_supported(cairo_ps_surface_t * surface,cairo_operator_t op,const cairo_pattern_t * pattern,const cairo_rectangle_int_t * extents)1820 _cairo_ps_surface_operation_supported (cairo_ps_surface_t    *surface,
1821 				       cairo_operator_t       op,
1822 				       const cairo_pattern_t       *pattern,
1823 				       const cairo_rectangle_int_t *extents)
1824 {
1825     return _cairo_ps_surface_analyze_operation (surface, op, pattern, extents) != CAIRO_INT_STATUS_UNSUPPORTED;
1826 }
1827 
1828 /* The "standard" implementation limit for PostScript string sizes is
1829  * 65535 characters (see PostScript Language Reference, Appendix
1830  * B). We go one short of that because we sometimes need two
1831  * characters in a string to represent a single ASCII85 byte, (for the
1832  * escape sequences "\\", "\(", and "\)") and we must not split these
1833  * across two strings. So we'd be in trouble if we went right to the
1834  * limit and one of these escape sequences just happened to land at
1835  * the end.
1836  */
1837 #define STRING_ARRAY_MAX_STRING_SIZE (65535-1)
1838 #define STRING_ARRAY_MAX_COLUMN	     72
1839 
1840 typedef struct _string_array_stream {
1841     cairo_output_stream_t base;
1842     cairo_output_stream_t *output;
1843     int column;
1844     int string_size;
1845     cairo_bool_t use_strings;
1846 } string_array_stream_t;
1847 
1848 static cairo_status_t
_string_array_stream_write(cairo_output_stream_t * base,const unsigned char * data,unsigned int length)1849 _string_array_stream_write (cairo_output_stream_t *base,
1850 			    const unsigned char   *data,
1851 			    unsigned int	   length)
1852 {
1853     string_array_stream_t *stream = (string_array_stream_t *) base;
1854     unsigned char c;
1855     const unsigned char backslash = '\\';
1856 
1857     if (length == 0)
1858 	return CAIRO_STATUS_SUCCESS;
1859 
1860     while (length--) {
1861 	if (stream->string_size == 0 && stream->use_strings) {
1862 	    _cairo_output_stream_printf (stream->output, "(");
1863 	    stream->column++;
1864 	}
1865 
1866 	c = *data++;
1867 	if (stream->use_strings) {
1868 	    switch (c) {
1869 	    case '\\':
1870 	    case '(':
1871 	    case ')':
1872 		_cairo_output_stream_write (stream->output, &backslash, 1);
1873 		stream->column++;
1874 		stream->string_size++;
1875 		break;
1876 	    }
1877 	}
1878 	/* Have to be careful to never split the final ~> sequence. */
1879         if (c == '~') {
1880 	    _cairo_output_stream_write (stream->output, &c, 1);
1881 	    stream->column++;
1882 	    stream->string_size++;
1883 
1884 	    if (length-- == 0)
1885 		break;
1886 
1887 	    c = *data++;
1888 	}
1889 	_cairo_output_stream_write (stream->output, &c, 1);
1890 	stream->column++;
1891 	stream->string_size++;
1892 
1893 	if (stream->use_strings &&
1894 	    stream->string_size >= STRING_ARRAY_MAX_STRING_SIZE)
1895 	{
1896 	    _cairo_output_stream_printf (stream->output, ")\n");
1897 	    stream->string_size = 0;
1898 	    stream->column = 0;
1899 	}
1900 	if (stream->column >= STRING_ARRAY_MAX_COLUMN) {
1901 	    _cairo_output_stream_printf (stream->output, "\n ");
1902 	    stream->string_size += 2;
1903 	    stream->column = 1;
1904 	}
1905     }
1906 
1907     return _cairo_output_stream_get_status (stream->output);
1908 }
1909 
1910 static cairo_status_t
_string_array_stream_close(cairo_output_stream_t * base)1911 _string_array_stream_close (cairo_output_stream_t *base)
1912 {
1913     cairo_status_t status;
1914     string_array_stream_t *stream = (string_array_stream_t *) base;
1915 
1916     if (stream->use_strings)
1917 	_cairo_output_stream_printf (stream->output, ")\n");
1918 
1919     status = _cairo_output_stream_get_status (stream->output);
1920 
1921     return status;
1922 }
1923 
1924 /* A string_array_stream wraps an existing output stream. It takes the
1925  * data provided to it and output one or more consecutive string
1926  * objects, each within the standard PostScript implementation limit
1927  * of 65k characters.
1928  *
1929  * The strings are each separated by a space character for easy
1930  * inclusion within an array object, (but the array delimiters are not
1931  * added by the string_array_stream).
1932  *
1933  * The string array stream is also careful to wrap the output within
1934  * STRING_ARRAY_MAX_COLUMN columns (+/- 1). The stream also adds
1935  * necessary escaping for special characters within a string,
1936  * (specifically '\', '(', and ')').
1937  */
1938 static cairo_output_stream_t *
_string_array_stream_create(cairo_output_stream_t * output)1939 _string_array_stream_create (cairo_output_stream_t *output)
1940 {
1941     string_array_stream_t *stream;
1942 
1943     stream = malloc (sizeof (string_array_stream_t));
1944     if (unlikely (stream == NULL)) {
1945 	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
1946 	return (cairo_output_stream_t *) &_cairo_output_stream_nil;
1947     }
1948 
1949     _cairo_output_stream_init (&stream->base,
1950 			       _string_array_stream_write,
1951 			       NULL,
1952 			       _string_array_stream_close);
1953     stream->output = output;
1954     stream->column = 0;
1955     stream->string_size = 0;
1956     stream->use_strings = TRUE;
1957 
1958     return &stream->base;
1959 }
1960 
1961 /* A base85_array_stream wraps an existing output stream. It wraps the
1962  * output within STRING_ARRAY_MAX_COLUMN columns (+/- 1). The output
1963  * is not enclosed in strings like string_array_stream.
1964  */
1965 static cairo_output_stream_t *
_base85_array_stream_create(cairo_output_stream_t * output)1966 _base85_array_stream_create (cairo_output_stream_t *output)
1967 {
1968     string_array_stream_t *stream;
1969 
1970     stream = malloc (sizeof (string_array_stream_t));
1971     if (unlikely (stream == NULL)) {
1972 	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
1973 	return (cairo_output_stream_t *) &_cairo_output_stream_nil;
1974     }
1975 
1976     _cairo_output_stream_init (&stream->base,
1977 			       _string_array_stream_write,
1978 			       NULL,
1979 			       _string_array_stream_close);
1980     stream->output = output;
1981     stream->column = 0;
1982     stream->string_size = 0;
1983     stream->use_strings = FALSE;
1984 
1985     return &stream->base;
1986 }
1987 
1988 
1989 /* PS Output - this section handles output of the parts of the recording
1990  * surface we can render natively in PS. */
1991 
1992 static cairo_status_t
_cairo_ps_surface_flatten_image_transparency(cairo_ps_surface_t * surface,cairo_image_surface_t * image,cairo_image_surface_t ** opaque_image)1993 _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t    *surface,
1994 					      cairo_image_surface_t *image,
1995 					      cairo_image_surface_t **opaque_image)
1996 {
1997     cairo_surface_t *opaque;
1998     cairo_surface_pattern_t pattern;
1999     cairo_status_t status;
2000 
2001     opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
2002 					 image->width,
2003 					 image->height);
2004     if (unlikely (opaque->status))
2005 	return opaque->status;
2006 
2007     if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
2008 	status = _cairo_surface_paint (opaque,
2009 				       CAIRO_OPERATOR_SOURCE,
2010 				       &_cairo_pattern_white.base,
2011 				       NULL);
2012 	if (unlikely (status)) {
2013 	    cairo_surface_destroy (opaque);
2014 	    return status;
2015 	}
2016     }
2017 
2018     _cairo_pattern_init_for_surface (&pattern, &image->base);
2019     pattern.base.filter = CAIRO_FILTER_NEAREST;
2020     status = _cairo_surface_paint (opaque, CAIRO_OPERATOR_OVER, &pattern.base, NULL);
2021     _cairo_pattern_fini (&pattern.base);
2022     if (unlikely (status)) {
2023 	cairo_surface_destroy (opaque);
2024 	return status;
2025     }
2026 
2027     *opaque_image = (cairo_image_surface_t *) opaque;
2028     return CAIRO_STATUS_SUCCESS;
2029 }
2030 
2031 static cairo_status_t
_cairo_ps_surface_emit_base85_string(cairo_ps_surface_t * surface,const unsigned char * data,unsigned long length,cairo_bool_t use_strings)2032 _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t    *surface,
2033 				      const unsigned char   *data,
2034 				      unsigned long	     length,
2035 				      cairo_bool_t           use_strings)
2036 {
2037     cairo_output_stream_t *base85_stream, *string_array_stream;
2038     cairo_status_t status, status2;
2039 
2040     if (use_strings)
2041 	string_array_stream = _string_array_stream_create (surface->stream);
2042     else
2043 	string_array_stream = _base85_array_stream_create (surface->stream);
2044 
2045     status = _cairo_output_stream_get_status (string_array_stream);
2046     if (unlikely (status))
2047 	return _cairo_output_stream_destroy (string_array_stream);
2048 
2049     base85_stream = _cairo_base85_stream_create (string_array_stream);
2050     status = _cairo_output_stream_get_status (base85_stream);
2051     if (unlikely (status)) {
2052 	status2 = _cairo_output_stream_destroy (string_array_stream);
2053 	return _cairo_output_stream_destroy (base85_stream);
2054     }
2055 
2056     _cairo_output_stream_write (base85_stream, data, length);
2057 
2058     status = _cairo_output_stream_destroy (base85_stream);
2059 
2060     /* Mark end of base85 data */
2061     _cairo_output_stream_printf (string_array_stream, "~>");
2062     status2 = _cairo_output_stream_destroy (string_array_stream);
2063     if (status == CAIRO_STATUS_SUCCESS)
2064 	status = status2;
2065 
2066 
2067     return status;
2068 }
2069 
2070 static cairo_status_t
_cairo_ps_surface_emit_image(cairo_ps_surface_t * surface,cairo_image_surface_t * image,cairo_operator_t op,cairo_filter_t filter)2071 _cairo_ps_surface_emit_image (cairo_ps_surface_t    *surface,
2072 			      cairo_image_surface_t *image,
2073 			      cairo_operator_t	     op,
2074 			      cairo_filter_t         filter)
2075 {
2076     cairo_status_t status;
2077     unsigned char *data, *data_compressed;
2078     unsigned long data_size, data_compressed_size;
2079     cairo_image_surface_t *opaque_image = NULL;
2080     int x, y, i;
2081     cairo_image_transparency_t transparency;
2082     cairo_bool_t use_mask;
2083     uint32_t *pixel;
2084     int bit;
2085     const char *interpolate;
2086 
2087     if (image->base.status)
2088 	return image->base.status;
2089 
2090     switch (filter) {
2091     default:
2092     case CAIRO_FILTER_GOOD:
2093     case CAIRO_FILTER_BEST:
2094     case CAIRO_FILTER_BILINEAR:
2095 	interpolate = "true";
2096 	break;
2097     case CAIRO_FILTER_FAST:
2098     case CAIRO_FILTER_NEAREST:
2099     case CAIRO_FILTER_GAUSSIAN:
2100 	interpolate = "false";
2101 	break;
2102     }
2103 
2104     transparency = _cairo_image_analyze_transparency (image);
2105 
2106     /* PostScript can not represent the alpha channel, so we blend the
2107        current image over a white (or black for CONTENT_COLOR
2108        surfaces) RGB surface to eliminate it. */
2109 
2110     if (op == CAIRO_OPERATOR_SOURCE ||
2111 	transparency == CAIRO_IMAGE_HAS_ALPHA ||
2112 	(transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA &&
2113 	 surface->ps_level == CAIRO_PS_LEVEL_2))
2114     {
2115 	status = _cairo_ps_surface_flatten_image_transparency (surface,
2116 							       image,
2117 							       &opaque_image);
2118 	if (unlikely (status))
2119 	    return status;
2120 
2121 	use_mask = FALSE;
2122     } else if (transparency == CAIRO_IMAGE_IS_OPAQUE) {
2123 	opaque_image = image;
2124 	use_mask = FALSE;
2125     } else {
2126 	use_mask = TRUE;
2127     }
2128 
2129     if (use_mask) {
2130 	/* Type 2 (mask and image interleaved) has the mask and image
2131 	 * samples interleaved by row.  The mask row is first, one bit
2132 	 * per pixel with (bit 7 first). The row is padded to byte
2133 	 * boundaries. The image data is 3 bytes per pixel RGB
2134 	 * format. */
2135 	data_size = image->height * ((image->width + 7)/8 + 3*image->width);
2136     } else {
2137 	data_size = image->height * image->width * 3;
2138     }
2139     data = malloc (data_size);
2140     if (unlikely (data == NULL)) {
2141 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2142 	goto bail1;
2143     }
2144 
2145     if (use_mask) {
2146 	i = 0;
2147 	for (y = 0; y < image->height; y++) {
2148 	    /* mask row */
2149 	    pixel = (uint32_t *) (image->data + y * image->stride);
2150 	    bit = 7;
2151 	    for (x = 0; x < image->width; x++, pixel++) {
2152 		if (bit == 7)
2153 		    data[i] = 0;
2154 		if (((*pixel & 0xff000000) >> 24) > 0x80)
2155 		    data[i] |= (1 << bit);
2156 		bit--;
2157 		if (bit < 0) {
2158 		    bit = 7;
2159 		    i++;
2160 		}
2161 	    }
2162 	    if (bit != 7)
2163 		i++;
2164 
2165 	    /* image row*/
2166 	    pixel = (uint32_t *) (image->data + y * image->stride);
2167 	    for (x = 0; x < image->width; x++, pixel++) {
2168 		data[i++] = (*pixel & 0x00ff0000) >> 16;
2169 		data[i++] = (*pixel & 0x0000ff00) >>  8;
2170 		data[i++] = (*pixel & 0x000000ff) >>  0;
2171 	    }
2172 	}
2173     } else {
2174 	i = 0;
2175 	for (y = 0; y < opaque_image->height; y++) {
2176 	    pixel = (uint32_t *) (opaque_image->data + y * opaque_image->stride);
2177 	    for (x = 0; x < opaque_image->width; x++, pixel++) {
2178 		data[i++] = (*pixel & 0x00ff0000) >> 16;
2179 		data[i++] = (*pixel & 0x0000ff00) >>  8;
2180 		data[i++] = (*pixel & 0x000000ff) >>  0;
2181 	    }
2182 	}
2183     }
2184 
2185     /* XXX: Should fix cairo-lzw to provide a stream-based interface
2186      * instead. */
2187     data_compressed_size = data_size;
2188     data_compressed = _cairo_lzw_compress (data, &data_compressed_size);
2189     if (unlikely (data_compressed == NULL)) {
2190 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2191 	goto bail2;
2192     }
2193 
2194     if (surface->use_string_datasource) {
2195 	/* Emit the image data as a base85-encoded string which will
2196 	 * be used as the data source for the image operator later. */
2197 	_cairo_output_stream_printf (surface->stream,
2198 				     "/CairoImageData [\n");
2199 
2200 	status = _cairo_ps_surface_emit_base85_string (surface,
2201 						       data_compressed,
2202 						       data_compressed_size,
2203 						       TRUE);
2204 	if (unlikely (status))
2205 	    goto bail3;
2206 
2207 	_cairo_output_stream_printf (surface->stream,
2208 				     "] def\n");
2209 	_cairo_output_stream_printf (surface->stream,
2210 				     "/CairoImageDataIndex 0 def\n");
2211     }
2212 
2213     if (use_mask) {
2214 	_cairo_output_stream_printf (surface->stream,
2215 				     "/DeviceRGB setcolorspace\n"
2216 				     "5 dict dup begin\n"
2217 				     "  /ImageType 3 def\n"
2218 				     "  /InterleaveType 2 def\n"
2219 				     "  /DataDict 8 dict def\n"
2220 				     "    DataDict begin\n"
2221 				     "    /ImageType 1 def\n"
2222 				     "    /Width %d def\n"
2223 				     "    /Height %d def\n"
2224 				     "    /Interpolate %s def\n"
2225 				     "    /BitsPerComponent 8 def\n"
2226 				     "    /Decode [ 0 1 0 1 0 1 ] def\n",
2227 				     image->width,
2228 				     image->height,
2229 				     interpolate);
2230 
2231 	if (surface->use_string_datasource) {
2232 	    _cairo_output_stream_printf (surface->stream,
2233 					 "    /DataSource {\n"
2234 					 "      CairoImageData CairoImageDataIndex get\n"
2235 					 "	/CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2236 					 "	CairoImageDataIndex CairoImageData length 1 sub gt\n"
2237 					 "       { /CairoImageDataIndex 0 def } if\n"
2238 					 "    } /ASCII85Decode filter /LZWDecode filter def\n");
2239 	} else {
2240 	    _cairo_output_stream_printf (surface->stream,
2241 					 "    /DataSource currentfile /ASCII85Decode filter /LZWDecode filter def\n");
2242 	}
2243 
2244 	_cairo_output_stream_printf (surface->stream,
2245 				     "    /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2246 				     "  end\n"
2247 				     "  /MaskDict 8 dict def\n"
2248 				     "     MaskDict begin\n"
2249 				     "    /ImageType 1 def\n"
2250 				     "    /Width %d def\n"
2251 				     "    /Height %d def\n"
2252 				     "    /Interpolate %s def\n"
2253 				     "    /BitsPerComponent 1 def\n"
2254 				     "    /Decode [ 1 0 ] def\n"
2255 				     "    /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2256 				     "  end\n"
2257 				     "end\n"
2258 				     "image\n",
2259 				     image->height,
2260 				     image->width,
2261 				     image->height,
2262 				     interpolate,
2263 				     image->height);
2264     } else {
2265 	_cairo_output_stream_printf (surface->stream,
2266 				     "/DeviceRGB setcolorspace\n"
2267 				     "8 dict dup begin\n"
2268 				     "  /ImageType 1 def\n"
2269 				     "  /Width %d def\n"
2270 				     "  /Height %d def\n"
2271 				     "  /BitsPerComponent 8 def\n"
2272 				     "  /Decode [ 0 1 0 1 0 1 ] def\n",
2273 				     opaque_image->width,
2274 				     opaque_image->height);
2275 	if (surface->use_string_datasource) {
2276 	    _cairo_output_stream_printf (surface->stream,
2277 					 "  /DataSource {\n"
2278 					 "    CairoImageData CairoImageDataIndex get\n"
2279 					 "    /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2280 					 "    CairoImageDataIndex CairoImageData length 1 sub gt\n"
2281 					 "     { /CairoImageDataIndex 0 def } if\n"
2282 					 "  } /ASCII85Decode filter /LZWDecode filter def\n");
2283 	} else {
2284 	    _cairo_output_stream_printf (surface->stream,
2285 					 "  /DataSource currentfile /ASCII85Decode filter /LZWDecode filter def\n");
2286 	}
2287 
2288 	_cairo_output_stream_printf (surface->stream,
2289 				     "  /Interpolate %s def\n"
2290 				     "  /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2291 				     "end\n"
2292 				     "image\n",
2293 				     interpolate,
2294 				     opaque_image->height);
2295     }
2296 
2297     if (!surface->use_string_datasource) {
2298 	/* Emit the image data as a base85-encoded string which will
2299 	 * be used as the data source for the image operator. */
2300 	status = _cairo_ps_surface_emit_base85_string (surface,
2301 						       data_compressed,
2302 						       data_compressed_size,
2303 						       FALSE);
2304 	_cairo_output_stream_printf (surface->stream, "\n");
2305     } else {
2306 	status = CAIRO_STATUS_SUCCESS;
2307     }
2308 
2309 bail3:
2310     free (data_compressed);
2311 
2312 bail2:
2313     free (data);
2314 
2315 bail1:
2316     if (!use_mask && opaque_image != image)
2317 	cairo_surface_destroy (&opaque_image->base);
2318 
2319     return status;
2320 }
2321 
2322 static cairo_status_t
_cairo_ps_surface_emit_jpeg_image(cairo_ps_surface_t * surface,cairo_surface_t * source,int width,int height)2323 _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t    *surface,
2324 				   cairo_surface_t	 *source,
2325 				   int                    width,
2326 				   int                    height)
2327 {
2328     cairo_status_t status;
2329     const unsigned char *mime_data;
2330     unsigned long mime_data_length;
2331     cairo_image_info_t info;
2332 
2333     cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
2334 				 &mime_data, &mime_data_length);
2335     if (unlikely (source->status))
2336 	return source->status;
2337     if (mime_data == NULL)
2338 	return CAIRO_INT_STATUS_UNSUPPORTED;
2339 
2340     status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length);
2341     if (unlikely (status))
2342 	return status;
2343 
2344     if (info.num_components != 1 && info.num_components != 3)
2345 	return CAIRO_INT_STATUS_UNSUPPORTED;
2346 
2347     if (surface->use_string_datasource) {
2348 	/* Emit the image data as a base85-encoded string which will
2349 	 * be used as the data source for the image operator later. */
2350 	_cairo_output_stream_printf (surface->stream,
2351 				     "/CairoImageData [\n");
2352 
2353 	status = _cairo_ps_surface_emit_base85_string (surface,
2354 						       mime_data,
2355 						       mime_data_length,
2356 						       TRUE);
2357 	if (unlikely (status))
2358 	    return status;
2359 
2360 	_cairo_output_stream_printf (surface->stream,
2361 				     "] def\n");
2362 	_cairo_output_stream_printf (surface->stream,
2363 				     "/CairoImageDataIndex 0 def\n");
2364     }
2365 
2366     _cairo_output_stream_printf (surface->stream,
2367 				 "/%s setcolorspace\n"
2368 				 "8 dict dup begin\n"
2369 				 "  /ImageType 1 def\n"
2370 				 "  /Width %d def\n"
2371 				 "  /Height %d def\n"
2372 				 "  /BitsPerComponent %d def\n"
2373 				 "  /Decode [ 0 1 0 1 0 1 ] def\n",
2374 				 info.num_components == 1 ? "DeviceGray" : "DeviceRGB",
2375 				 info.width,
2376 				 info.height,
2377 				 info.bits_per_component);
2378 
2379     if (surface->use_string_datasource) {
2380 	_cairo_output_stream_printf (surface->stream,
2381 				     "  /DataSource {\n"
2382 				     "    CairoImageData CairoImageDataIndex get\n"
2383 				     "    /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
2384 				     "    CairoImageDataIndex CairoImageData length 1 sub gt\n"
2385 				     "     { /CairoImageDataIndex 0 def } if\n"
2386 				     "  } /ASCII85Decode filter /DCTDecode filter def\n");
2387     } else {
2388 	_cairo_output_stream_printf (surface->stream,
2389 				     "  /DataSource currentfile /ASCII85Decode filter /DCTDecode filter def\n");
2390     }
2391 
2392     _cairo_output_stream_printf (surface->stream,
2393 				 "  /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
2394 				 "end\n"
2395 				 "image\n",
2396 				 info.height);
2397 
2398     if (!surface->use_string_datasource) {
2399 	/* Emit the image data as a base85-encoded string which will
2400 	 * be used as the data source for the image operator. */
2401 	status = _cairo_ps_surface_emit_base85_string (surface,
2402 						       mime_data,
2403 						       mime_data_length,
2404 						       FALSE);
2405     }
2406 
2407     return status;
2408 }
2409 
2410 static cairo_status_t
_cairo_ps_surface_emit_recording_surface(cairo_ps_surface_t * surface,cairo_surface_t * recording_surface)2411 _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
2412 					  cairo_surface_t    *recording_surface)
2413 {
2414     double old_width, old_height;
2415     cairo_matrix_t old_cairo_to_ps;
2416     cairo_content_t old_content;
2417     cairo_rectangle_int_t old_page_bbox;
2418     cairo_box_t bbox;
2419     cairo_status_t status;
2420 
2421     old_content = surface->content;
2422     old_width = surface->width;
2423     old_height = surface->height;
2424     old_page_bbox = surface->page_bbox;
2425     old_cairo_to_ps = surface->cairo_to_ps;
2426 
2427     status =
2428 	_cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
2429 					   &bbox,
2430 					   NULL);
2431     if (unlikely (status))
2432 	return status;
2433 
2434 #if DEBUG_PS
2435     _cairo_output_stream_printf (surface->stream,
2436 				 "%% _cairo_ps_surface_emit_recording_surface (%f, %f), (%f, %f)\n",
2437 				 _cairo_fixed_to_double (bbox.p1.x),
2438 				 _cairo_fixed_to_double (bbox.p1.y),
2439 				 _cairo_fixed_to_double (bbox.p2.x),
2440 				 _cairo_fixed_to_double (bbox.p2.y));
2441 #endif
2442 
2443     surface->width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
2444     surface->height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
2445     _cairo_box_round_to_rectangle (&bbox, &surface->page_bbox);
2446 
2447     surface->current_pattern_is_solid_color = FALSE;
2448     _cairo_pdf_operators_reset (&surface->pdf_operators);
2449     cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
2450     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
2451 						  &surface->cairo_to_ps);
2452     _cairo_output_stream_printf (surface->stream, "  q\n");
2453 
2454     if (recording_surface->content == CAIRO_CONTENT_COLOR) {
2455 	surface->content = CAIRO_CONTENT_COLOR;
2456 	_cairo_output_stream_printf (surface->stream,
2457 				     "  0 g %d %d %d %d rectfill\n",
2458 				     surface->page_bbox.x,
2459 				     surface->page_bbox.y,
2460 				     surface->page_bbox.width,
2461 				     surface->page_bbox.height);
2462     }
2463 
2464     status = _cairo_recording_surface_replay_region (recording_surface,
2465 						     NULL,
2466 						     &surface->base,
2467 						     CAIRO_RECORDING_REGION_NATIVE);
2468     assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
2469     if (unlikely (status))
2470 	return status;
2471 
2472     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
2473     if (unlikely (status))
2474 	return status;
2475 
2476     _cairo_output_stream_printf (surface->stream, "  Q\n");
2477     surface->content = old_content;
2478     surface->width = old_width;
2479     surface->height = old_height;
2480     surface->page_bbox = old_page_bbox;
2481     surface->current_pattern_is_solid_color = FALSE;
2482     _cairo_pdf_operators_reset (&surface->pdf_operators);
2483     surface->cairo_to_ps = old_cairo_to_ps;
2484 
2485     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
2486 						  &surface->cairo_to_ps);
2487 
2488     return CAIRO_STATUS_SUCCESS;
2489 }
2490 
2491 static cairo_status_t
_cairo_ps_surface_emit_recording_subsurface(cairo_ps_surface_t * surface,cairo_surface_t * recording_surface,const cairo_rectangle_int_t * extents)2492 _cairo_ps_surface_emit_recording_subsurface (cairo_ps_surface_t *surface,
2493 					     cairo_surface_t    *recording_surface,
2494 					     const cairo_rectangle_int_t *extents)
2495 {
2496     double old_width, old_height;
2497     cairo_matrix_t old_cairo_to_ps;
2498     cairo_content_t old_content;
2499     cairo_rectangle_int_t old_page_bbox;
2500     cairo_status_t status;
2501 
2502     old_content = surface->content;
2503     old_width = surface->width;
2504     old_height = surface->height;
2505     old_page_bbox = surface->page_bbox;
2506     old_cairo_to_ps = surface->cairo_to_ps;
2507 
2508 #if DEBUG_PS
2509     _cairo_output_stream_printf (surface->stream,
2510 				 "%% _cairo_ps_surface_emit_recording_subsurface (%d, %d), (%d, %d)\n",
2511 				 extents->x, extents->y,
2512 				 extents->width, extents->height);
2513 #endif
2514 
2515     surface->page_bbox.x = surface->page_bbox.y = 0;
2516     surface->page_bbox.width = surface->width  = extents->width;
2517     surface->page_bbox.height = surface->height = extents->height;
2518 
2519     surface->current_pattern_is_solid_color = FALSE;
2520     _cairo_pdf_operators_reset (&surface->pdf_operators);
2521     cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
2522     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
2523 						  &surface->cairo_to_ps);
2524     _cairo_output_stream_printf (surface->stream, "  q\n");
2525 
2526     if (recording_surface->content == CAIRO_CONTENT_COLOR) {
2527 	surface->content = CAIRO_CONTENT_COLOR;
2528 	_cairo_output_stream_printf (surface->stream,
2529 				     "  0 g %d %d %d %d rectfill\n",
2530 				     surface->page_bbox.x,
2531 				     surface->page_bbox.y,
2532 				     surface->page_bbox.width,
2533 				     surface->page_bbox.height);
2534     }
2535 
2536     status = _cairo_recording_surface_replay_region (recording_surface,
2537 						     extents,
2538 						     &surface->base,
2539 						     CAIRO_RECORDING_REGION_NATIVE);
2540     assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
2541     if (unlikely (status))
2542 	return status;
2543 
2544     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
2545     if (unlikely (status))
2546 	return status;
2547 
2548     _cairo_output_stream_printf (surface->stream, "  Q\n");
2549     surface->content = old_content;
2550     surface->width = old_width;
2551     surface->height = old_height;
2552     surface->page_bbox = old_page_bbox;
2553     surface->current_pattern_is_solid_color = FALSE;
2554     _cairo_pdf_operators_reset (&surface->pdf_operators);
2555     surface->cairo_to_ps = old_cairo_to_ps;
2556 
2557     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
2558 						  &surface->cairo_to_ps);
2559 
2560     return CAIRO_STATUS_SUCCESS;
2561 }
2562 
2563 static void
_cairo_ps_surface_flatten_transparency(cairo_ps_surface_t * surface,const cairo_color_t * color,double * red,double * green,double * blue)2564 _cairo_ps_surface_flatten_transparency (cairo_ps_surface_t	*surface,
2565 					const cairo_color_t	*color,
2566 					double			*red,
2567 					double			*green,
2568 					double			*blue)
2569 {
2570     *red   = color->red;
2571     *green = color->green;
2572     *blue  = color->blue;
2573 
2574     if (! CAIRO_COLOR_IS_OPAQUE (color)) {
2575 	*red   *= color->alpha;
2576 	*green *= color->alpha;
2577 	*blue  *= color->alpha;
2578 	if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
2579 	    double one_minus_alpha = 1. - color->alpha;
2580 	    *red   += one_minus_alpha;
2581 	    *green += one_minus_alpha;
2582 	    *blue  += one_minus_alpha;
2583 	}
2584     }
2585 }
2586 
2587 static void
_cairo_ps_surface_emit_solid_pattern(cairo_ps_surface_t * surface,cairo_solid_pattern_t * pattern)2588 _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t    *surface,
2589 				      cairo_solid_pattern_t *pattern)
2590 {
2591     double red, green, blue;
2592 
2593     _cairo_ps_surface_flatten_transparency (surface, &pattern->color, &red, &green, &blue);
2594 
2595     if (color_is_gray (red, green, blue))
2596 	_cairo_output_stream_printf (surface->stream,
2597 				     "%f g\n",
2598 				     red);
2599     else
2600 	_cairo_output_stream_printf (surface->stream,
2601 				     "%f %f %f rg\n",
2602 				     red, green, blue);
2603 }
2604 
2605 static cairo_status_t
_cairo_ps_surface_acquire_surface(cairo_ps_surface_t * surface,cairo_surface_pattern_t * pattern,cairo_rectangle_int_t * extents,int * width,int * height,int * origin_x,int * origin_y)2606 _cairo_ps_surface_acquire_surface (cairo_ps_surface_t      *surface,
2607 				   cairo_surface_pattern_t *pattern,
2608 				   cairo_rectangle_int_t   *extents,
2609 				   int                     *width,
2610 				   int                     *height,
2611 				   int			   *origin_x,
2612 				   int			   *origin_y)
2613 {
2614     cairo_status_t          status;
2615     cairo_surface_t	   *pad_image;
2616     int x = 0;
2617     int y = 0;
2618 
2619     surface->acquired_image = NULL;
2620     surface->image = NULL;
2621 
2622     if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
2623 	if (pattern->surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
2624 	    cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) pattern->surface;
2625 
2626 	    *width  = sub->extents.width;
2627 	    *height = sub->extents.height;
2628 	} else {
2629 	    cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) pattern->surface;
2630 	    cairo_box_t bbox;
2631 	    cairo_rectangle_int_t extents;
2632 
2633 	    status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
2634 	    if (unlikely (status))
2635 		return status;
2636 
2637 	    _cairo_box_round_to_rectangle (&bbox, &extents);
2638 	    *width  = extents.width;
2639 	    *height = extents.height;
2640 	}
2641 	return CAIRO_STATUS_SUCCESS;
2642     } else {
2643 	status = _cairo_surface_acquire_source_image (pattern->surface,
2644 						      &surface->acquired_image,
2645 						      &surface->image_extra);
2646 	if (unlikely (status))
2647 	    return status;
2648 
2649 	pad_image = &surface->acquired_image->base;
2650 	if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD) {
2651 	    cairo_box_t box;
2652 	    cairo_rectangle_int_t rect;
2653 	    cairo_surface_pattern_t pad_pattern;
2654 
2655 	    /* get the operation extents in pattern space */
2656 	    _cairo_box_from_rectangle (&box, extents);
2657 	    _cairo_matrix_transform_bounding_box_fixed (&pattern->base.matrix, &box, NULL);
2658 	    _cairo_box_round_to_rectangle (&box, &rect);
2659 	    x = -rect.x;
2660 	    y = -rect.y;
2661 
2662 	    pad_image =
2663 		_cairo_image_surface_create_with_pixman_format (NULL,
2664 								surface->acquired_image->pixman_format,
2665 								rect.width, rect.height,
2666 								0);
2667 	    if (pad_image->status) {
2668 		status = pad_image->status;
2669 		goto BAIL;
2670 	    }
2671 
2672 	    _cairo_pattern_init_for_surface (&pad_pattern, &surface->acquired_image->base);
2673 	    cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y);
2674 	    pad_pattern.base.extend = CAIRO_EXTEND_PAD;
2675 	    status = _cairo_surface_paint (pad_image,
2676 					   CAIRO_OPERATOR_SOURCE,
2677 					   &pad_pattern.base,
2678 					   NULL);
2679 	    _cairo_pattern_fini (&pad_pattern.base);
2680 	    if (unlikely (status)) {
2681 		if (pad_image != &surface->acquired_image->base)
2682 		    cairo_surface_destroy (pad_image);
2683 
2684 		goto BAIL;
2685 	    }
2686 	}
2687 
2688 	surface->image = (cairo_image_surface_t *) pad_image;
2689 	*width = surface->image->width;
2690 	*height = surface->image->height;
2691 	*origin_x = x;
2692 	*origin_y = y;
2693 	return CAIRO_STATUS_SUCCESS;
2694     }
2695 
2696 BAIL:
2697     _cairo_ps_surface_release_surface (surface, pattern);
2698     return status;
2699 }
2700 
2701 static cairo_status_t
_cairo_ps_surface_emit_surface(cairo_ps_surface_t * surface,cairo_surface_pattern_t * pattern,cairo_operator_t op,int width,int height)2702 _cairo_ps_surface_emit_surface (cairo_ps_surface_t      *surface,
2703 				cairo_surface_pattern_t *pattern,
2704 				cairo_operator_t	 op,
2705 				int                      width,
2706 				int                      height)
2707 {
2708     cairo_status_t status;
2709 
2710     if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
2711 	cairo_surface_t *source = pattern->surface;
2712 
2713 	if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
2714 	    cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
2715 	    status = _cairo_ps_surface_emit_recording_subsurface (surface, sub->target, &sub->extents);
2716 	} else {
2717 	    status = _cairo_ps_surface_emit_recording_surface (surface, source);
2718 	}
2719     } else {
2720 	if (pattern->base.extend != CAIRO_EXTEND_PAD) {
2721 	    status = _cairo_ps_surface_emit_jpeg_image (surface, pattern->surface,
2722 							width, height);
2723 	    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2724 		return status;
2725 	}
2726 
2727 	status = _cairo_ps_surface_emit_image (surface, surface->image,
2728 					       op, pattern->base.filter);
2729     }
2730 
2731     return status;
2732 }
2733 
2734 static void
_cairo_ps_surface_release_surface(cairo_ps_surface_t * surface,cairo_surface_pattern_t * pattern)2735 _cairo_ps_surface_release_surface (cairo_ps_surface_t      *surface,
2736 				   cairo_surface_pattern_t *pattern)
2737 {
2738     if (surface->image != surface->acquired_image)
2739 	cairo_surface_destroy (&surface->image->base);
2740 
2741     if (pattern->surface->type != CAIRO_SURFACE_TYPE_RECORDING) {
2742 	_cairo_surface_release_source_image (pattern->surface,
2743 					     surface->acquired_image,
2744 					     surface->image_extra);
2745     }
2746 
2747     surface->acquired_image = NULL;
2748     surface->image = NULL;
2749 }
2750 
2751 static void
_path_fixed_init_rectangle(cairo_path_fixed_t * path,cairo_rectangle_int_t * rect)2752 _path_fixed_init_rectangle (cairo_path_fixed_t *path,
2753 			    cairo_rectangle_int_t *rect)
2754 {
2755     cairo_status_t status;
2756 
2757     _cairo_path_fixed_init (path);
2758 
2759     status = _cairo_path_fixed_move_to (path,
2760 					_cairo_fixed_from_int (rect->x),
2761 					_cairo_fixed_from_int (rect->y));
2762     assert (status == CAIRO_STATUS_SUCCESS);
2763     status = _cairo_path_fixed_rel_line_to (path,
2764 					    _cairo_fixed_from_int (rect->width),
2765 					    _cairo_fixed_from_int (0));
2766     assert (status == CAIRO_STATUS_SUCCESS);
2767     status = _cairo_path_fixed_rel_line_to (path,
2768 					    _cairo_fixed_from_int (0),
2769 					    _cairo_fixed_from_int (rect->height));
2770     assert (status == CAIRO_STATUS_SUCCESS);
2771     status = _cairo_path_fixed_rel_line_to (path,
2772 					    _cairo_fixed_from_int (-rect->width),
2773 					    _cairo_fixed_from_int (0));
2774     assert (status == CAIRO_STATUS_SUCCESS);
2775 
2776     status = _cairo_path_fixed_close_path (path);
2777     assert (status == CAIRO_STATUS_SUCCESS);
2778 }
2779 
2780 static cairo_status_t
_cairo_ps_surface_paint_surface(cairo_ps_surface_t * surface,cairo_surface_pattern_t * pattern,cairo_rectangle_int_t * extents,cairo_operator_t op)2781 _cairo_ps_surface_paint_surface (cairo_ps_surface_t      *surface,
2782 				 cairo_surface_pattern_t *pattern,
2783 				 cairo_rectangle_int_t   *extents,
2784 				 cairo_operator_t	  op)
2785 {
2786     cairo_status_t status;
2787     int width, height;
2788     cairo_matrix_t cairo_p2d, ps_p2d;
2789     cairo_path_fixed_t path;
2790     int origin_x = 0;
2791     int origin_y = 0;
2792 
2793     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
2794     if (unlikely (status))
2795 	return status;
2796 
2797     status = _cairo_ps_surface_acquire_surface (surface,
2798 						pattern,
2799 						extents,
2800 						&width, &height,
2801 						&origin_x, &origin_y);
2802     if (unlikely (status))
2803 	return status;
2804 
2805     _path_fixed_init_rectangle (&path, extents);
2806     status = _cairo_pdf_operators_clip (&surface->pdf_operators,
2807 					&path,
2808 					CAIRO_FILL_RULE_WINDING);
2809     _cairo_path_fixed_fini (&path);
2810     if (unlikely (status))
2811 	return status;
2812 
2813     cairo_p2d = pattern->base.matrix;
2814 
2815     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
2816 	double scale = cairo_p2d.xx;
2817 
2818 	_cairo_output_stream_printf (surface->stream,
2819 				     "%% Fallback Image: x=%f, y=%f, w=%d, h=%d res=%fdpi size=%ld\n",
2820 				     -cairo_p2d.x0/scale,
2821 				     -cairo_p2d.y0/scale,
2822 				     (int)(width/scale),
2823 				     (int)(height/scale),
2824 				     scale*72,
2825 				     (long)width*height*3);
2826     } else {
2827 	if (op == CAIRO_OPERATOR_SOURCE) {
2828 	    _cairo_output_stream_printf (surface->stream,
2829 					 "%d g 0 0 %f %f rectfill\n",
2830 					 surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
2831 					 surface->width,
2832 					 surface->height);
2833 	}
2834     }
2835 
2836     status = cairo_matrix_invert (&cairo_p2d);
2837     /* cairo_pattern_set_matrix ensures the matrix is invertible */
2838     assert (status == CAIRO_STATUS_SUCCESS);
2839 
2840     ps_p2d = surface->cairo_to_ps;
2841     cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
2842     cairo_matrix_translate (&ps_p2d, -origin_x, -origin_y);
2843     cairo_matrix_translate (&ps_p2d, 0.0, height);
2844     cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
2845 
2846     if (! _cairo_matrix_is_identity (&ps_p2d)) {
2847 	_cairo_output_stream_printf (surface->stream,
2848 				     "[ %f %f %f %f %f %f ] concat\n",
2849 				     ps_p2d.xx, ps_p2d.yx,
2850 				     ps_p2d.xy, ps_p2d.yy,
2851 				     ps_p2d.x0, ps_p2d.y0);
2852     }
2853 
2854     status = _cairo_ps_surface_emit_surface (surface, pattern, op, width, height);
2855     _cairo_ps_surface_release_surface (surface, pattern);
2856 
2857     return status;
2858 }
2859 
2860 static cairo_status_t
_cairo_ps_surface_emit_surface_pattern(cairo_ps_surface_t * surface,cairo_surface_pattern_t * pattern,cairo_rectangle_int_t * extents,cairo_operator_t op)2861 _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t      *surface,
2862 					cairo_surface_pattern_t *pattern,
2863 					cairo_rectangle_int_t   *extents,
2864 					cairo_operator_t	 op)
2865 {
2866     cairo_status_t status;
2867     int pattern_width = 0; /* squelch bogus compiler warning */
2868     int pattern_height = 0; /* squelch bogus compiler warning */
2869     double xstep, ystep;
2870     cairo_matrix_t cairo_p2d, ps_p2d;
2871     cairo_bool_t old_use_string_datasource;
2872     int origin_x = 0;
2873     int origin_y = 0;
2874 
2875     cairo_p2d = pattern->base.matrix;
2876     status = cairo_matrix_invert (&cairo_p2d);
2877     /* cairo_pattern_set_matrix ensures the matrix is invertible */
2878     assert (status == CAIRO_STATUS_SUCCESS);
2879 
2880     status = _cairo_ps_surface_acquire_surface (surface,
2881 						pattern,
2882 						extents,
2883 						&pattern_width, &pattern_height,
2884 						&origin_x, &origin_y);
2885     if (unlikely (status))
2886 	return status;
2887 
2888     switch (pattern->base.extend) {
2889     case CAIRO_EXTEND_PAD:
2890     case CAIRO_EXTEND_NONE:
2891     {
2892 	/* In PS/PDF, (as far as I can tell), all patterns are
2893 	 * repeating. So we support cairo's EXTEND_NONE semantics
2894 	 * by setting the repeat step size to a size large enough
2895 	 * to guarantee that no more than a single occurrence will
2896 	 * be visible.
2897 	 *
2898 	 * First, map the surface extents into pattern space (since
2899 	 * xstep and ystep are in pattern space).  Then use an upper
2900 	 * bound on the length of the diagonal of the pattern image
2901 	 * and the surface as repeat size.  This guarantees to never
2902 	 * repeat visibly.
2903 	 */
2904 	double x1 = 0.0, y1 = 0.0;
2905 	double x2 = surface->width, y2 = surface->height;
2906 	_cairo_matrix_transform_bounding_box (&pattern->base.matrix,
2907 					      &x1, &y1, &x2, &y2,
2908 					      NULL);
2909 
2910 	/* Rather than computing precise bounds of the union, just
2911 	 * add the surface extents unconditionally. We only
2912 	 * required an answer that's large enough, we don't really
2913 	 * care if it's not as tight as possible.*/
2914 	xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
2915 			      pattern_width + pattern_height);
2916 	break;
2917     }
2918     case CAIRO_EXTEND_REPEAT:
2919 	xstep = pattern_width;
2920 	ystep = pattern_height;
2921 	break;
2922     case CAIRO_EXTEND_REFLECT:
2923 	xstep = pattern_width*2;
2924 	ystep = pattern_height*2;
2925 	break;
2926 	/* All the rest (if any) should have been analyzed away, so these
2927 	 * cases should be unreachable. */
2928     default:
2929 	ASSERT_NOT_REACHED;
2930 	xstep = 0;
2931 	ystep = 0;
2932     }
2933 
2934     _cairo_output_stream_printf (surface->stream,
2935 				 "/CairoPattern {\n");
2936 
2937     old_use_string_datasource = surface->use_string_datasource;
2938     surface->use_string_datasource = TRUE;
2939     if (op == CAIRO_OPERATOR_SOURCE) {
2940 	_cairo_output_stream_printf (surface->stream,
2941 				     "%d g 0 0 %f %f rectfill\n",
2942 				     surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
2943 				     xstep, ystep);
2944     }
2945     status = _cairo_ps_surface_emit_surface (surface, pattern, op,
2946 					     pattern_width, pattern_height);
2947     if (unlikely (status))
2948 	return status;
2949 
2950     surface->use_string_datasource = old_use_string_datasource;
2951     _cairo_output_stream_printf (surface->stream,
2952 				 "} bind def\n");
2953 
2954     _cairo_output_stream_printf (surface->stream,
2955 				 "<< /PatternType 1\n"
2956 				 "   /PaintType 1\n"
2957 				 "   /TilingType 1\n");
2958     _cairo_output_stream_printf (surface->stream,
2959 				 "   /XStep %f /YStep %f\n",
2960 				 xstep, ystep);
2961 
2962     if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
2963 	_cairo_output_stream_printf (surface->stream,
2964 				     "   /BBox [0 0 %d %d]\n"
2965 				     "   /PaintProc {\n"
2966 				     "      CairoPattern\n"
2967 				     "      [-1 0 0  1 %d 0] concat CairoPattern\n"
2968 				     "      [ 1 0 0 -1 0 %d] concat CairoPattern\n"
2969 				     "      [-1 0 0  1 %d 0] concat CairoPattern\n"
2970 				     "      CairoPattern\n"
2971 				     "   } bind\n",
2972 				     pattern_width*2, pattern_height*2,
2973 				     pattern_width*2,
2974 				     pattern_height*2,
2975 				     pattern_width*2);
2976     } else {
2977 	if (op == CAIRO_OPERATOR_SOURCE) {
2978 	    _cairo_output_stream_printf (surface->stream,
2979 					 "   /BBox [0 0 %f %f]\n",
2980 					 xstep, ystep);
2981 	} else {
2982 	    _cairo_output_stream_printf (surface->stream,
2983 					 "   /BBox [0 0 %d %d]\n",
2984 					 pattern_width, pattern_height);
2985 	}
2986 	_cairo_output_stream_printf (surface->stream,
2987 				     "   /PaintProc { CairoPattern }\n");
2988     }
2989 
2990     _cairo_output_stream_printf (surface->stream,
2991 				 ">>\n");
2992 
2993     cairo_p2d = pattern->base.matrix;
2994     status = cairo_matrix_invert (&cairo_p2d);
2995     /* cairo_pattern_set_matrix ensures the matrix is invertible */
2996     assert (status == CAIRO_STATUS_SUCCESS);
2997 
2998     cairo_matrix_init_identity (&ps_p2d);
2999     cairo_matrix_translate (&ps_p2d, 0.0, surface->height);
3000     cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
3001     cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
3002     cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
3003     cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
3004 
3005     _cairo_output_stream_printf (surface->stream,
3006 				 "[ %f %f %f %f %f %f ]\n",
3007 				 ps_p2d.xx, ps_p2d.yx,
3008 				 ps_p2d.xy, ps_p2d.yy,
3009 				 ps_p2d.x0, ps_p2d.y0);
3010     _cairo_output_stream_printf (surface->stream,
3011 				 "makepattern setpattern\n");
3012 
3013     return CAIRO_STATUS_SUCCESS;
3014 }
3015 
3016 typedef struct _cairo_ps_color_stop {
3017     double offset;
3018     double color[4];
3019 } cairo_ps_color_stop_t;
3020 
3021 static void
_cairo_ps_surface_emit_linear_colorgradient(cairo_ps_surface_t * surface,cairo_ps_color_stop_t * stop1,cairo_ps_color_stop_t * stop2)3022 _cairo_ps_surface_emit_linear_colorgradient (cairo_ps_surface_t     *surface,
3023 					     cairo_ps_color_stop_t  *stop1,
3024 					     cairo_ps_color_stop_t  *stop2)
3025 {
3026     _cairo_output_stream_printf (surface->stream,
3027 				 "   << /FunctionType 2\n"
3028 				 "      /Domain [ 0 1 ]\n"
3029 				 "      /C0 [ %f %f %f ]\n"
3030 				 "      /C1 [ %f %f %f ]\n"
3031 				 "      /N 1\n"
3032 				 "   >>\n",
3033 				 stop1->color[0],
3034 				 stop1->color[1],
3035 				 stop1->color[2],
3036 				 stop2->color[0],
3037 				 stop2->color[1],
3038 				 stop2->color[2]);
3039 }
3040 
3041 static void
_cairo_ps_surface_emit_stitched_colorgradient(cairo_ps_surface_t * surface,unsigned int n_stops,cairo_ps_color_stop_t stops[])3042 _cairo_ps_surface_emit_stitched_colorgradient (cairo_ps_surface_t    *surface,
3043 					       unsigned int 	      n_stops,
3044 					       cairo_ps_color_stop_t  stops[])
3045 {
3046     unsigned int i;
3047 
3048     _cairo_output_stream_printf (surface->stream,
3049 				 "<< /FunctionType 3\n"
3050 				 "   /Domain [ 0 1 ]\n"
3051 				 "   /Functions [\n");
3052     for (i = 0; i < n_stops - 1; i++)
3053 	_cairo_ps_surface_emit_linear_colorgradient (surface, &stops[i], &stops[i+1]);
3054 
3055     _cairo_output_stream_printf (surface->stream, "   ]\n");
3056 
3057     _cairo_output_stream_printf (surface->stream, "   /Bounds [ ");
3058     for (i = 1; i < n_stops-1; i++)
3059 	_cairo_output_stream_printf (surface->stream, "%f ", stops[i].offset);
3060     _cairo_output_stream_printf (surface->stream, "]\n");
3061 
3062     _cairo_output_stream_printf (surface->stream, "   /Encode [ 1 1 %d { pop 0 1 } for ]\n",
3063 				 n_stops - 1);
3064 
3065     _cairo_output_stream_printf (surface->stream, ">>\n");
3066 }
3067 
3068 static void
calc_gradient_color(cairo_ps_color_stop_t * new_stop,cairo_ps_color_stop_t * stop1,cairo_ps_color_stop_t * stop2)3069 calc_gradient_color (cairo_ps_color_stop_t *new_stop,
3070 		     cairo_ps_color_stop_t *stop1,
3071 		     cairo_ps_color_stop_t *stop2)
3072 {
3073     int i;
3074     double offset = stop1->offset / (stop1->offset + 1.0 - stop2->offset);
3075 
3076     for (i = 0; i < 4; i++)
3077 	new_stop->color[i] = stop1->color[i] + offset*(stop2->color[i] - stop1->color[i]);
3078 }
3079 
3080 #define COLOR_STOP_EPSILON 1e-6
3081 
3082 static cairo_status_t
_cairo_ps_surface_emit_pattern_stops(cairo_ps_surface_t * surface,cairo_gradient_pattern_t * pattern)3083 _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t       *surface,
3084 				      cairo_gradient_pattern_t *pattern)
3085 {
3086     cairo_ps_color_stop_t *allstops, *stops;
3087     unsigned int i, n_stops;
3088 
3089     allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_ps_color_stop_t));
3090     if (unlikely (allstops == NULL))
3091 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3092 
3093     stops = &allstops[1];
3094     n_stops = pattern->n_stops;
3095 
3096     for (i = 0; i < n_stops; i++) {
3097 	cairo_gradient_stop_t *stop = &pattern->stops[i];
3098 
3099 	stops[i].color[0] = stop->color.red;
3100 	stops[i].color[1] = stop->color.green;
3101 	stops[i].color[2] = stop->color.blue;
3102 	stops[i].color[3] = stop->color.alpha;
3103 	stops[i].offset = pattern->stops[i].offset;
3104     }
3105 
3106     if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
3107 	pattern->base.extend == CAIRO_EXTEND_REFLECT) {
3108 	if (stops[0].offset > COLOR_STOP_EPSILON) {
3109 	    if (pattern->base.extend == CAIRO_EXTEND_REFLECT)
3110 		memcpy (allstops, stops, sizeof (cairo_ps_color_stop_t));
3111 	    else
3112 		calc_gradient_color (&allstops[0], &stops[0], &stops[n_stops-1]);
3113 	    stops = allstops;
3114 	    n_stops++;
3115 	}
3116 	stops[0].offset = 0.0;
3117 
3118 	if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
3119 	    if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
3120 		memcpy (&stops[n_stops],
3121 			&stops[n_stops - 1],
3122 			sizeof (cairo_ps_color_stop_t));
3123 	    } else {
3124 		calc_gradient_color (&stops[n_stops], &stops[0], &stops[n_stops-1]);
3125 	    }
3126 	    n_stops++;
3127 	}
3128 	stops[n_stops-1].offset = 1.0;
3129     }
3130 
3131     for (i = 0; i < n_stops; i++) {
3132 	double red, green, blue;
3133 	cairo_color_t color;
3134 
3135 	_cairo_color_init_rgba (&color,
3136 				stops[i].color[0],
3137 				stops[i].color[1],
3138 				stops[i].color[2],
3139 				stops[i].color[3]);
3140 	_cairo_ps_surface_flatten_transparency (surface, &color,
3141 						&red, &green, &blue);
3142 	stops[i].color[0] = red;
3143 	stops[i].color[1] = green;
3144 	stops[i].color[2] = blue;
3145     }
3146 
3147     _cairo_output_stream_printf (surface->stream,
3148 				 "/CairoFunction\n");
3149     if (n_stops == 1) {
3150 	/* work around single stop gradients */
3151 	_cairo_ps_surface_emit_linear_colorgradient (surface, &stops[0], &stops[0]);
3152     } else if (n_stops == 2) {
3153 	/* no need for stitched function */
3154 	_cairo_ps_surface_emit_linear_colorgradient (surface, &stops[0], &stops[1]);
3155     } else {
3156 	/* multiple stops: stitch. XXX possible optimization: regulary spaced
3157 	 * stops do not require stitching. XXX */
3158 	_cairo_ps_surface_emit_stitched_colorgradient (surface, n_stops,stops);
3159     }
3160     _cairo_output_stream_printf (surface->stream,
3161 				 "def\n");
3162 
3163     free (allstops);
3164 
3165     return CAIRO_STATUS_SUCCESS;
3166 }
3167 
3168 static cairo_status_t
_cairo_ps_surface_emit_repeating_function(cairo_ps_surface_t * surface,cairo_gradient_pattern_t * pattern,int begin,int end)3169 _cairo_ps_surface_emit_repeating_function (cairo_ps_surface_t       *surface,
3170 					   cairo_gradient_pattern_t *pattern,
3171 					   int                       begin,
3172 					   int                       end)
3173 {
3174     _cairo_output_stream_printf (surface->stream,
3175 				 "/CairoFunction\n"
3176 				 "<< /FunctionType 3\n"
3177 				 "   /Domain [ %d %d ]\n"
3178 				 "   /Functions [ %d {CairoFunction} repeat ]\n"
3179 				 "   /Bounds [ %d 1 %d {} for ]\n",
3180 				 begin,
3181                                  end,
3182 				 end - begin,
3183 				 begin + 1,
3184 				 end - 1);
3185 
3186     if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
3187 	_cairo_output_stream_printf (surface->stream, "   /Encode [ %d 1 %d { 2 mod 0 eq {0 1} {1 0} ifelse } for ]\n",
3188 				     begin,
3189 				     end - 1);
3190     } else {
3191 	_cairo_output_stream_printf (surface->stream, "   /Encode [ %d 1 %d { pop 0 1 } for ]\n",
3192 				     begin,
3193 				     end - 1);
3194     }
3195 
3196     _cairo_output_stream_printf (surface->stream, ">> def\n");
3197 
3198     return CAIRO_STATUS_SUCCESS;
3199 }
3200 
3201 static cairo_status_t
_cairo_ps_surface_emit_linear_pattern(cairo_ps_surface_t * surface,cairo_linear_pattern_t * pattern)3202 _cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t     *surface,
3203 				       cairo_linear_pattern_t *pattern)
3204 {
3205     double x1, y1, x2, y2;
3206     double _x1, _y1, _x2, _y2;
3207     cairo_matrix_t pat_to_ps;
3208     cairo_extend_t extend;
3209     cairo_status_t status;
3210     cairo_gradient_pattern_t *gradient = &pattern->base;
3211     double first_stop, last_stop;
3212     int repeat_begin = 0, repeat_end = 1;
3213 
3214     extend = cairo_pattern_get_extend (&pattern->base.base);
3215 
3216     pat_to_ps = pattern->base.base.matrix;
3217     status = cairo_matrix_invert (&pat_to_ps);
3218     /* cairo_pattern_set_matrix ensures the matrix is invertible */
3219     assert (status == CAIRO_STATUS_SUCCESS);
3220 
3221     cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
3222     first_stop = gradient->stops[0].offset;
3223     last_stop = gradient->stops[gradient->n_stops - 1].offset;
3224 
3225     if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
3226 	pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
3227 	double dx, dy;
3228 	int x_rep = 0, y_rep = 0;
3229 
3230 	x1 = _cairo_fixed_to_double (pattern->p1.x);
3231 	y1 = _cairo_fixed_to_double (pattern->p1.y);
3232 	cairo_matrix_transform_point (&pat_to_ps, &x1, &y1);
3233 
3234 	x2 = _cairo_fixed_to_double (pattern->p2.x);
3235 	y2 = _cairo_fixed_to_double (pattern->p2.y);
3236 	cairo_matrix_transform_point (&pat_to_ps, &x2, &y2);
3237 
3238 	dx = fabs (x2 - x1);
3239 	dy = fabs (y2 - y1);
3240 	if (dx > 1e-6)
3241 	    x_rep = ceil (surface->width/dx);
3242 	if (dy > 1e-6)
3243 	    y_rep = ceil (surface->height/dy);
3244 
3245 	repeat_end = MAX (x_rep, y_rep);
3246 	repeat_begin = -repeat_end;
3247 	first_stop = repeat_begin;
3248 	last_stop = repeat_end;
3249     }
3250 
3251     /* PS requires the first and last stop to be the same as the line
3252      * coordinates. For repeating patterns this moves the line
3253      * coordinates out to the begin/end of the repeating function. For
3254      * non repeating patterns this may move the line coordinates in if
3255      * there are not stops at offset 0 and 1. */
3256     x1 = _cairo_fixed_to_double (pattern->p1.x);
3257     y1 = _cairo_fixed_to_double (pattern->p1.y);
3258     x2 = _cairo_fixed_to_double (pattern->p2.x);
3259     y2 = _cairo_fixed_to_double (pattern->p2.y);
3260 
3261     _x1 = x1 + (x2 - x1)*first_stop;
3262     _y1 = y1 + (y2 - y1)*first_stop;
3263     _x2 = x1 + (x2 - x1)*last_stop;
3264     _y2 = y1 + (y2 - y1)*last_stop;
3265 
3266     x1 = _x1;
3267     x2 = _x2;
3268     y1 = _y1;
3269     y2 = _y2;
3270 
3271     /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a
3272      * Type 2 function is used by itself without a stitching
3273      * function. Type 2 functions always have the domain [0 1] */
3274     if ((pattern->base.base.extend == CAIRO_EXTEND_NONE ||
3275 	 pattern->base.base.extend == CAIRO_EXTEND_PAD) &&
3276 	gradient->n_stops == 2) {
3277 	first_stop = 0.0;
3278 	last_stop = 1.0;
3279     }
3280 
3281     status = _cairo_ps_surface_emit_pattern_stops (surface,
3282 						   &pattern->base);
3283     if (unlikely (status))
3284 	return status;
3285 
3286     if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
3287 	pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
3288 	status = _cairo_ps_surface_emit_repeating_function (surface,
3289 							    &pattern->base,
3290 							    repeat_begin,
3291 							    repeat_end);
3292 	if (unlikely (status))
3293 	    return status;
3294     }
3295 
3296     _cairo_output_stream_printf (surface->stream,
3297 				 "<< /PatternType 2\n"
3298 				 "   /Shading\n"
3299 				 "   << /ShadingType 2\n"
3300 				 "      /ColorSpace /DeviceRGB\n"
3301 				 "      /Coords [ %f %f %f %f ]\n"
3302                                  "      /Domain [ %f %f ]\n"
3303 				 "      /Function CairoFunction\n",
3304 				 x1, y1, x2, y2,
3305 				 first_stop, last_stop);
3306 
3307     if (extend == CAIRO_EXTEND_PAD) {
3308 	_cairo_output_stream_printf (surface->stream,
3309                                      "      /Extend [ true true ]\n");
3310     } else {
3311 	_cairo_output_stream_printf (surface->stream,
3312                                      "      /Extend [ false false ]\n");
3313     }
3314 
3315     _cairo_output_stream_printf (surface->stream,
3316 				 "   >>\n"
3317 				 ">>\n");
3318     _cairo_output_stream_printf (surface->stream,
3319 				 "[ %f %f %f %f %f %f ]\n",
3320                                  pat_to_ps.xx, pat_to_ps.yx,
3321                                  pat_to_ps.xy, pat_to_ps.yy,
3322                                  pat_to_ps.x0, pat_to_ps.y0);
3323     _cairo_output_stream_printf (surface->stream,
3324 				 "makepattern setpattern\n");
3325 
3326     return status;
3327 }
3328 
3329 static cairo_status_t
_cairo_ps_surface_emit_radial_pattern(cairo_ps_surface_t * surface,cairo_radial_pattern_t * pattern)3330 _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t     *surface,
3331 				       cairo_radial_pattern_t *pattern)
3332 {
3333     double x1, y1, x2, y2, r1, r2;
3334     cairo_matrix_t pat_to_ps;
3335     cairo_extend_t extend;
3336     cairo_status_t status;
3337 
3338     extend = cairo_pattern_get_extend (&pattern->base.base);
3339 
3340     pat_to_ps = pattern->base.base.matrix;
3341     status = cairo_matrix_invert (&pat_to_ps);
3342     /* cairo_pattern_set_matrix ensures the matrix is invertible */
3343     assert (status == CAIRO_STATUS_SUCCESS);
3344 
3345     cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
3346     x1 = _cairo_fixed_to_double (pattern->c1.x);
3347     y1 = _cairo_fixed_to_double (pattern->c1.y);
3348     r1 = _cairo_fixed_to_double (pattern->r1);
3349     x2 = _cairo_fixed_to_double (pattern->c2.x);
3350     y2 = _cairo_fixed_to_double (pattern->c2.y);
3351     r2 = _cairo_fixed_to_double (pattern->r2);
3352 
3353    status = _cairo_ps_surface_emit_pattern_stops (surface, &pattern->base);
3354    if (unlikely (status))
3355       return status;
3356 
3357    _cairo_output_stream_printf (surface->stream,
3358 				 "<< /PatternType 2\n"
3359 				 "   /Shading\n"
3360 				 "   << /ShadingType 3\n"
3361 				 "      /ColorSpace /DeviceRGB\n"
3362 				 "      /Coords [ %f %f %f %f %f %f ]\n"
3363 				 "      /Function CairoFunction\n",
3364 				 x1, y1, r1, x2, y2, r2);
3365 
3366     if (extend == CAIRO_EXTEND_PAD) {
3367 	_cairo_output_stream_printf (surface->stream,
3368                                      "      /Extend [ true true ]\n");
3369     } else {
3370 	_cairo_output_stream_printf (surface->stream,
3371                                      "      /Extend [ false false ]\n");
3372     }
3373 
3374     _cairo_output_stream_printf (surface->stream,
3375 				 "   >>\n"
3376 				 ">>\n");
3377 
3378     _cairo_output_stream_printf (surface->stream,
3379 				 "[ %f %f %f %f %f %f ]\n",
3380 				 pat_to_ps.xx, pat_to_ps.yx,
3381                                  pat_to_ps.xy, pat_to_ps.yy,
3382                                  pat_to_ps.x0, pat_to_ps.y0);
3383     _cairo_output_stream_printf (surface->stream,
3384 				 "makepattern setpattern\n");
3385 
3386     return status;
3387 }
3388 
3389 static cairo_status_t
_cairo_ps_surface_emit_pattern(cairo_ps_surface_t * surface,const cairo_pattern_t * pattern,cairo_rectangle_int_t * extents,cairo_operator_t op)3390 _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
3391 				const cairo_pattern_t *pattern,
3392 				cairo_rectangle_int_t *extents,
3393 				cairo_operator_t       op)
3394 {
3395     cairo_status_t status;
3396 
3397     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3398     if (unlikely (status))
3399 	return status;
3400 
3401     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
3402 	cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
3403 
3404 	if (surface->current_pattern_is_solid_color == FALSE ||
3405 	    ! _cairo_color_equal (&surface->current_color, &solid->color))
3406 	{
3407 	    status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3408 	    if (unlikely (status))
3409 		return status;
3410 
3411 	    _cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
3412 
3413 	    surface->current_pattern_is_solid_color = TRUE;
3414 	    surface->current_color = solid->color;
3415 	}
3416 
3417 	return CAIRO_STATUS_SUCCESS;
3418     }
3419 
3420     surface->current_pattern_is_solid_color = FALSE;
3421     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3422     if (unlikely (status))
3423 	    return status;
3424 
3425     switch (pattern->type) {
3426     case CAIRO_PATTERN_TYPE_SOLID:
3427 
3428 	_cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
3429 	break;
3430 
3431     case CAIRO_PATTERN_TYPE_SURFACE:
3432 	status = _cairo_ps_surface_emit_surface_pattern (surface,
3433 							 (cairo_surface_pattern_t *) pattern,
3434 							 extents,
3435 							 op);
3436 	if (unlikely (status))
3437 	    return status;
3438 	break;
3439 
3440     case CAIRO_PATTERN_TYPE_LINEAR:
3441 	status = _cairo_ps_surface_emit_linear_pattern (surface,
3442 					  (cairo_linear_pattern_t *) pattern);
3443 	if (unlikely (status))
3444 	    return status;
3445 	break;
3446 
3447     case CAIRO_PATTERN_TYPE_RADIAL:
3448 	status = _cairo_ps_surface_emit_radial_pattern (surface,
3449 					  (cairo_radial_pattern_t *) pattern);
3450 	if (unlikely (status))
3451 	    return status;
3452 	break;
3453     }
3454 
3455     return CAIRO_STATUS_SUCCESS;
3456 }
3457 
3458 static cairo_bool_t
_cairo_ps_surface_get_extents(void * abstract_surface,cairo_rectangle_int_t * rectangle)3459 _cairo_ps_surface_get_extents (void		       *abstract_surface,
3460 			       cairo_rectangle_int_t   *rectangle)
3461 {
3462     cairo_ps_surface_t *surface = abstract_surface;
3463 
3464     rectangle->x = 0;
3465     rectangle->y = 0;
3466 
3467     /* XXX: The conversion to integers here is pretty bogus, (not to
3468      * mention the aribitray limitation of width to a short(!). We
3469      * may need to come up with a better interface for get_extents.
3470      */
3471     rectangle->width  = ceil (surface->width);
3472     rectangle->height = ceil (surface->height);
3473 
3474     return TRUE;
3475 }
3476 
3477 static void
_cairo_ps_surface_get_font_options(void * abstract_surface,cairo_font_options_t * options)3478 _cairo_ps_surface_get_font_options (void                  *abstract_surface,
3479 				    cairo_font_options_t  *options)
3480 {
3481     _cairo_font_options_init_default (options);
3482 
3483     cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
3484     cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
3485     cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
3486 }
3487 
3488 static cairo_int_status_t
_cairo_ps_surface_paint(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_clip_t * clip)3489 _cairo_ps_surface_paint (void			*abstract_surface,
3490 			 cairo_operator_t	 op,
3491 			 const cairo_pattern_t	*source,
3492 			 cairo_clip_t		*clip)
3493 {
3494     cairo_ps_surface_t *surface = abstract_surface;
3495     cairo_output_stream_t *stream = surface->stream;
3496     cairo_composite_rectangles_t extents;
3497     cairo_status_t status;
3498 
3499     cairo_rectangle_int_t rect;
3500     rect.x = rect.y = 0;
3501     rect.width = surface->width;
3502     rect.height = surface->height;
3503 
3504     status = _cairo_composite_rectangles_init_for_paint (&extents,
3505 							 &rect,
3506 							 op, source, clip);
3507     if (unlikely (status))
3508 	return status;
3509 
3510     if (! _cairo_rectangle_intersect (&extents.bounded, &surface->page_bbox))
3511 	return CAIRO_STATUS_SUCCESS;
3512 
3513     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
3514 	return _cairo_ps_surface_analyze_operation (surface, op, source, &extents.bounded);
3515 
3516     assert (_cairo_ps_surface_operation_supported (surface, op, source, &extents.bounded));
3517 
3518 #if DEBUG_PS
3519     _cairo_output_stream_printf (stream,
3520 				 "%% _cairo_ps_surface_paint\n");
3521 #endif
3522 
3523     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
3524     if (unlikely (status))
3525 	return status;
3526 
3527     if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
3528 	(source->extend == CAIRO_EXTEND_NONE ||
3529 	 source->extend == CAIRO_EXTEND_PAD))
3530     {
3531 	status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3532 	if (unlikely (status))
3533 	    return status;
3534 
3535 	_cairo_output_stream_printf (stream, "q\n");
3536 	status = _cairo_ps_surface_paint_surface (surface,
3537 						 (cairo_surface_pattern_t *) source,
3538 						  &extents.bounded, op);
3539 	if (unlikely (status))
3540 	    return status;
3541 
3542 	_cairo_output_stream_printf (stream, "Q\n");
3543     } else {
3544 	status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
3545 	if (unlikely (status))
3546 	    return status;
3547 
3548 	_cairo_output_stream_printf (stream, "%d %d %d %d rectfill\n",
3549 				     extents.bounded.x, extents.bounded.y,
3550 				     extents.bounded.width, extents.bounded.height);
3551     }
3552 
3553     return CAIRO_STATUS_SUCCESS;
3554 }
3555 
3556 static cairo_int_status_t
_cairo_ps_surface_stroke(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,const cairo_stroke_style_t * style,const cairo_matrix_t * ctm,const cairo_matrix_t * ctm_inverse,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)3557 _cairo_ps_surface_stroke (void			*abstract_surface,
3558 			  cairo_operator_t	 op,
3559 			  const cairo_pattern_t	*source,
3560 			  cairo_path_fixed_t	*path,
3561 			  const cairo_stroke_style_t	*style,
3562 			  const cairo_matrix_t	*ctm,
3563 			  const cairo_matrix_t	*ctm_inverse,
3564 			  double		 tolerance,
3565 			  cairo_antialias_t	 antialias,
3566 			  cairo_clip_t		*clip)
3567 {
3568     cairo_ps_surface_t *surface = abstract_surface;
3569     cairo_composite_rectangles_t extents;
3570     cairo_int_status_t status;
3571 
3572     cairo_rectangle_int_t rect;
3573     rect.x = rect.y = 0;
3574     rect.width = surface->width;
3575     rect.height = surface->height;
3576 
3577     status = _cairo_composite_rectangles_init_for_stroke (&extents,
3578 							  &rect,
3579 							  op, source,
3580 							  path, style, ctm,
3581 							  clip);
3582     if (unlikely (status))
3583 	return status;
3584 
3585     if (! _cairo_rectangle_intersect (&extents.bounded, &surface->page_bbox))
3586 	return CAIRO_STATUS_SUCCESS;
3587 
3588     /* use the more accurate extents */
3589     if (extents.is_bounded) {
3590 	status = _cairo_path_fixed_stroke_extents (path, style,
3591 						   ctm, ctm_inverse,
3592 						   tolerance,
3593 						   &extents.mask);
3594 	if (unlikely (status))
3595 	    return status;
3596 
3597 	if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
3598 	    return CAIRO_STATUS_SUCCESS;
3599     }
3600 
3601 
3602     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
3603 	return _cairo_ps_surface_analyze_operation (surface, op, source, &extents.bounded);
3604 
3605     assert (_cairo_ps_surface_operation_supported (surface, op, source, &extents.bounded));
3606 
3607 #if DEBUG_PS
3608     _cairo_output_stream_printf (surface->stream,
3609 				 "%% _cairo_ps_surface_stroke\n");
3610 #endif
3611 
3612     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
3613     if (unlikely (status))
3614 	return status;
3615 
3616     status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
3617     if (unlikely (status))
3618 	return status;
3619 
3620     return _cairo_pdf_operators_stroke (&surface->pdf_operators,
3621 					path,
3622 					style,
3623 					ctm,
3624 					ctm_inverse);
3625 }
3626 
3627 static cairo_int_status_t
_cairo_ps_surface_fill(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)3628 _cairo_ps_surface_fill (void		*abstract_surface,
3629 			cairo_operator_t	 op,
3630 			const cairo_pattern_t	*source,
3631 			cairo_path_fixed_t	*path,
3632 			cairo_fill_rule_t	 fill_rule,
3633 			double			 tolerance,
3634 			cairo_antialias_t	 antialias,
3635 			cairo_clip_t		*clip)
3636 {
3637     cairo_ps_surface_t *surface = abstract_surface;
3638     cairo_composite_rectangles_t extents;
3639     cairo_int_status_t status;
3640 
3641     cairo_rectangle_int_t rect;
3642     rect.x = rect.y = 0;
3643     rect.width = surface->width;
3644     rect.height = surface->height;
3645 
3646     status = _cairo_composite_rectangles_init_for_fill (&extents,
3647 							&rect,
3648 							op, source, path,
3649 							clip);
3650     if (unlikely (status))
3651 	return status;
3652 
3653     if (! _cairo_rectangle_intersect (&extents.bounded, &surface->page_bbox))
3654 	return CAIRO_STATUS_SUCCESS;
3655 
3656     /* use the more accurate extents */
3657     if (extents.is_bounded) {
3658 	_cairo_path_fixed_fill_extents (path,
3659 					fill_rule,
3660 					tolerance,
3661 					&extents.mask);
3662 
3663 	if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
3664 	    return CAIRO_STATUS_SUCCESS;
3665     }
3666 
3667     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
3668 	return _cairo_ps_surface_analyze_operation (surface, op, source, &extents.bounded);
3669 
3670     assert (_cairo_ps_surface_operation_supported (surface, op, source, &extents.bounded));
3671 
3672 #if DEBUG_PS
3673     _cairo_output_stream_printf (surface->stream,
3674 				 "%% _cairo_ps_surface_fill\n");
3675 #endif
3676 
3677     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3678     if (unlikely (status))
3679 	return status;
3680 
3681     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
3682     if (unlikely (status))
3683 	return status;
3684 
3685     if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
3686 	(source->extend == CAIRO_EXTEND_NONE ||
3687 	 source->extend == CAIRO_EXTEND_PAD))
3688     {
3689 	_cairo_output_stream_printf (surface->stream, "q\n");
3690 
3691 	status =  _cairo_pdf_operators_clip (&surface->pdf_operators,
3692 					     path,
3693 					     fill_rule);
3694 	if (unlikely (status))
3695 	    return status;
3696 
3697 	status = _cairo_ps_surface_paint_surface (surface,
3698 						 (cairo_surface_pattern_t *) source,
3699 						  &extents.bounded, op);
3700 	if (unlikely (status))
3701 	    return status;
3702 
3703 	_cairo_output_stream_printf (surface->stream, "Q\n");
3704 	_cairo_pdf_operators_reset (&surface->pdf_operators);
3705     } else {
3706 	status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
3707 	if (unlikely (status))
3708 	    return status;
3709 
3710 	status = _cairo_pdf_operators_fill (&surface->pdf_operators,
3711 					    path,
3712 					    fill_rule);
3713     }
3714 
3715     return status;
3716 }
3717 
3718 static cairo_int_status_t
_cairo_ps_surface_show_glyphs(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_glyph_t * glyphs,int num_glyphs,cairo_scaled_font_t * scaled_font,cairo_clip_t * clip,int * remaining_glyphs)3719 _cairo_ps_surface_show_glyphs (void		     *abstract_surface,
3720 			       cairo_operator_t	      op,
3721 			       const cairo_pattern_t *source,
3722 			       cairo_glyph_t         *glyphs,
3723 			       int		      num_glyphs,
3724 			       cairo_scaled_font_t   *scaled_font,
3725 			       cairo_clip_t	     *clip,
3726 			       int		     *remaining_glyphs)
3727 {
3728     cairo_ps_surface_t *surface = abstract_surface;
3729     cairo_composite_rectangles_t extents;
3730     cairo_bool_t overlap;
3731     cairo_status_t status;
3732 
3733     cairo_rectangle_int_t rect;
3734     rect.x = rect.y = 0;
3735     rect.width = surface->width;
3736     rect.height = surface->height;
3737 
3738     status = _cairo_composite_rectangles_init_for_glyphs (&extents,
3739 							  &rect,
3740 							  op, source,
3741 							  scaled_font,
3742 							  glyphs, num_glyphs,
3743 							  clip,
3744 							  &overlap);
3745     if (unlikely (status))
3746 	return status;
3747 
3748     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
3749 	return _cairo_ps_surface_analyze_operation (surface, op, source, &extents.bounded);
3750 
3751     assert (_cairo_ps_surface_operation_supported (surface, op, source, &extents.bounded));
3752 
3753 #if DEBUG_PS
3754     _cairo_output_stream_printf (surface->stream,
3755 				 "%% _cairo_ps_surface_show_glyphs\n");
3756 #endif
3757 
3758     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
3759     if (unlikely (status))
3760 	return status;
3761 
3762     status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
3763     if (unlikely (status))
3764 	return status;
3765 
3766     return _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
3767 						  NULL, 0,
3768 						  glyphs, num_glyphs,
3769 						  NULL, 0,
3770 						  FALSE,
3771 						  scaled_font);
3772 }
3773 
3774 static void
_cairo_ps_surface_set_paginated_mode(void * abstract_surface,cairo_paginated_mode_t paginated_mode)3775 _cairo_ps_surface_set_paginated_mode (void			*abstract_surface,
3776 				      cairo_paginated_mode_t	 paginated_mode)
3777 {
3778     cairo_ps_surface_t *surface = abstract_surface;
3779     cairo_status_t status;
3780 
3781     surface->paginated_mode = paginated_mode;
3782 
3783     if (surface->clipper.clip.path != NULL) {
3784 	status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3785 
3786 	_cairo_output_stream_printf (surface->stream, "Q q\n");
3787 	_cairo_surface_clipper_reset (&surface->clipper);
3788     }
3789 }
3790 
3791 static cairo_int_status_t
_cairo_ps_surface_set_bounding_box(void * abstract_surface,cairo_box_t * bbox)3792 _cairo_ps_surface_set_bounding_box (void		*abstract_surface,
3793 				    cairo_box_t		*bbox)
3794 {
3795     cairo_ps_surface_t *surface = abstract_surface;
3796     int i, num_comments;
3797     char **comments;
3798     int x1, y1, x2, y2;
3799     cairo_bool_t has_page_media;
3800     const char *page_media;
3801 
3802     if (surface->eps) {
3803 	x1 = floor (_cairo_fixed_to_double (bbox->p1.x));
3804 	y1 = floor (surface->height - _cairo_fixed_to_double (bbox->p2.y));
3805 	x2 = ceil (_cairo_fixed_to_double (bbox->p2.x));
3806 	y2 = ceil (surface->height - _cairo_fixed_to_double (bbox->p1.y));
3807     } else {
3808 	x1 = 0;
3809 	y1 = 0;
3810 	x2 = ceil (surface->width);
3811 	y2 = ceil (surface->height);
3812     }
3813 
3814     surface->page_bbox.x = x1;
3815     surface->page_bbox.y = y1;
3816     surface->page_bbox.width  = x2 - x1;
3817     surface->page_bbox.height = y2 - y1;
3818 
3819     _cairo_output_stream_printf (surface->stream,
3820 				 "%%%%Page: %d %d\n",
3821 				 surface->num_pages,
3822 				 surface->num_pages);
3823 
3824     _cairo_output_stream_printf (surface->stream,
3825 				 "%%%%BeginPageSetup\n");
3826 
3827     has_page_media = FALSE;
3828     num_comments = _cairo_array_num_elements (&surface->dsc_page_setup_comments);
3829     comments = _cairo_array_index (&surface->dsc_page_setup_comments, 0);
3830     for (i = 0; i < num_comments; i++) {
3831 	_cairo_output_stream_printf (surface->stream,
3832 				     "%s\n", comments[i]);
3833 	if (strncmp (comments[i], "%%PageMedia:", 11) == 0)
3834 	    has_page_media = TRUE;
3835 	free (comments[i]);
3836 	comments[i] = NULL;
3837     }
3838     _cairo_array_truncate (&surface->dsc_page_setup_comments, 0);
3839 
3840     if (!has_page_media && !surface->eps) {
3841 	page_media = _cairo_ps_surface_get_page_media (surface);
3842 	if (unlikely (page_media == NULL))
3843 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3844 
3845 	_cairo_output_stream_printf (surface->stream,
3846 				     "%%%%PageMedia: %s\n",
3847 				     page_media);
3848     }
3849 
3850     _cairo_output_stream_printf (surface->stream,
3851 				 "%%%%PageBoundingBox: %d %d %d %d\n",
3852 				 x1, y1, x2, y2);
3853 
3854     _cairo_output_stream_printf (surface->stream,
3855                                  "%%%%EndPageSetup\n"
3856 				 "q %d %d %d %d rectclip q\n",
3857 				 surface->page_bbox.x,
3858 				 surface->page_bbox.y,
3859 				 surface->page_bbox.width,
3860 				 surface->page_bbox.height);
3861 
3862     if (surface->num_pages == 1) {
3863 	surface->bbox_x1 = x1;
3864 	surface->bbox_y1 = y1;
3865 	surface->bbox_x2 = x2;
3866 	surface->bbox_y2 = y2;
3867     } else {
3868 	if (x1 < surface->bbox_x1)
3869 	    surface->bbox_x1 = x1;
3870 	if (y1 < surface->bbox_y1)
3871 	    surface->bbox_y1 = y1;
3872 	if (x2 > surface->bbox_x2)
3873 	    surface->bbox_x2 = x2;
3874 	if (y2 > surface->bbox_y2)
3875 	    surface->bbox_y2 = y2;
3876     }
3877     surface->current_pattern_is_solid_color = FALSE;
3878     _cairo_pdf_operators_reset (&surface->pdf_operators);
3879 
3880     return _cairo_output_stream_get_status (surface->stream);
3881 }
3882 
3883 static cairo_bool_t
_cairo_ps_surface_supports_fine_grained_fallbacks(void * abstract_surface)3884 _cairo_ps_surface_supports_fine_grained_fallbacks (void	    *abstract_surface)
3885 {
3886     return TRUE;
3887 }
3888 
3889 static const cairo_surface_backend_t cairo_ps_surface_backend = {
3890     CAIRO_SURFACE_TYPE_PS,
3891     NULL, /* create similar: handled by wrapper */
3892     _cairo_ps_surface_finish,
3893     NULL, /* acquire_source_image */
3894     NULL, /* release_source_image */
3895     NULL, /* acquire_dest_image */
3896     NULL, /* release_dest_image */
3897     NULL, /* clone_similar */
3898     NULL, /* composite */
3899     NULL, /* fill_rectangles */
3900     NULL, /* composite_trapezoids */
3901     NULL, /* create_span_renderer */
3902     NULL, /* check_span_renderer */
3903     NULL, /* cairo_ps_surface_copy_page */
3904     _cairo_ps_surface_show_page,
3905     _cairo_ps_surface_get_extents,
3906     NULL, /* old_show_glyphs */
3907     _cairo_ps_surface_get_font_options,
3908     NULL, /* flush */
3909     NULL, /* mark_dirty_rectangle */
3910     NULL, /* scaled_font_fini */
3911     NULL, /* scaled_glyph_fini */
3912 
3913     /* Here are the drawing functions */
3914 
3915     _cairo_ps_surface_paint, /* paint */
3916     NULL, /* mask */
3917     _cairo_ps_surface_stroke,
3918     _cairo_ps_surface_fill,
3919     _cairo_ps_surface_show_glyphs,
3920     NULL, /* snapshot */
3921 };
3922 
3923 static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend = {
3924     _cairo_ps_surface_start_page,
3925     _cairo_ps_surface_set_paginated_mode,
3926     _cairo_ps_surface_set_bounding_box,
3927     NULL, /* _cairo_ps_surface_has_fallback_images, */
3928     _cairo_ps_surface_supports_fine_grained_fallbacks,
3929 };
3930