~ubuntu-branches/ubuntu/karmic/moon/karmic

« back to all changes in this revision

Viewing changes to cairo/src/cairo-ps-surface.c

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2009-02-14 12:01:08 UTC
  • Revision ID: james.westby@ubuntu.com-20090214120108-06539vb25vhbd8bn
Tags: upstream-1.0
ImportĀ upstreamĀ versionĀ 1.0

Show diffs side-by-side

added added

removed removed

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