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