Line data Source code
1 : /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 : /* cairo - a vector graphics library with display and print output
3 : *
4 : * Copyright © 2004 Red Hat, Inc
5 : * Copyright © 2006 Red Hat, Inc
6 : * Copyright © 2007, 2008 Adrian Johnson
7 : *
8 : * This library is free software; you can redistribute it and/or
9 : * modify it either under the terms of the GNU Lesser General Public
10 : * License version 2.1 as published by the Free Software Foundation
11 : * (the "LGPL") or, at your option, under the terms of the Mozilla
12 : * Public License Version 1.1 (the "MPL"). If you do not alter this
13 : * notice, a recipient may use your version of this file under either
14 : * the MPL or the LGPL.
15 : *
16 : * You should have received a copy of the LGPL along with this library
17 : * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19 : * You should have received a copy of the MPL along with this library
20 : * in the file COPYING-MPL-1.1
21 : *
22 : * The contents of this file are subject to the Mozilla Public License
23 : * Version 1.1 (the "License"); you may not use this file except in
24 : * compliance with the License. You may obtain a copy of the License at
25 : * http://www.mozilla.org/MPL/
26 : *
27 : * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28 : * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29 : * the specific language governing rights and limitations.
30 : *
31 : * The Original Code is the cairo graphics library.
32 : *
33 : * The Initial Developer of the Original Code is University of Southern
34 : * California.
35 : *
36 : * Contributor(s):
37 : * Kristian Høgsberg <krh@redhat.com>
38 : * Carl Worth <cworth@cworth.org>
39 : * Adrian Johnson <ajohnson@redneon.com>
40 : */
41 :
42 : #define _BSD_SOURCE /* for snprintf() */
43 : #include "cairoint.h"
44 : #include "cairo-pdf.h"
45 : #include "cairo-pdf-surface-private.h"
46 : #include "cairo-pdf-operators-private.h"
47 : #include "cairo-analysis-surface-private.h"
48 : #include "cairo-composite-rectangles-private.h"
49 : #include "cairo-error-private.h"
50 : #include "cairo-image-info-private.h"
51 : #include "cairo-recording-surface-private.h"
52 : #include "cairo-output-stream-private.h"
53 : #include "cairo-paginated-private.h"
54 : #include "cairo-scaled-font-subsets-private.h"
55 : #include "cairo-surface-clipper-private.h"
56 : #include "cairo-surface-subsurface-private.h"
57 : #include "cairo-type3-glyph-surface-private.h"
58 :
59 : #include <time.h>
60 : #include <zlib.h>
61 :
62 : /* Issues:
63 : *
64 : * - We embed an image in the stream each time it's composited. We
65 : * could add generation counters to surfaces and remember the stream
66 : * ID for a particular generation for a particular surface.
67 : *
68 : * - Backend specific meta data.
69 : */
70 :
71 : /*
72 : * Page Structure of the Generated PDF:
73 : *
74 : * Each page requiring fallbacks images contains a knockout group at
75 : * the top level. The first operation of the knockout group paints a
76 : * group containing all the supported drawing operations. Fallback
77 : * images (if any) are painted in the knockout group. This ensures
78 : * that fallback images do not composite with any content under the
79 : * fallback images.
80 : *
81 : * Streams:
82 : *
83 : * This PDF surface has three types of streams:
84 : * - PDF Stream
85 : * - Content Stream
86 : * - Group Stream
87 : *
88 : * Calling _cairo_output_stream_printf (surface->output, ...) will
89 : * write to the currently open stream.
90 : *
91 : * PDF Stream:
92 : * A PDF Stream may be opened and closed with the following functions:
93 : * _cairo_pdf_surface_open stream ()
94 : * _cairo_pdf_surface_close_stream ()
95 : *
96 : * PDF Streams are written directly to the PDF file. They are used for
97 : * fonts, images and patterns.
98 : *
99 : * Content Stream:
100 : * The Content Stream is opened and closed with the following functions:
101 : * _cairo_pdf_surface_open_content_stream ()
102 : * _cairo_pdf_surface_close_content_stream ()
103 : *
104 : * The Content Stream contains the text and graphics operators.
105 : *
106 : * Group Stream:
107 : * A Group Stream may be opened and closed with the following functions:
108 : * _cairo_pdf_surface_open_group ()
109 : * _cairo_pdf_surface_close_group ()
110 : *
111 : * A Group Stream is a Form XObject. It is used for short sequences
112 : * of operators. As the content is very short the group is stored in
113 : * memory until it is closed. This allows some optimization such as
114 : * including the Resource dictionary and stream length inside the
115 : * XObject instead of using an indirect object.
116 : */
117 :
118 : /**
119 : * SECTION:cairo-pdf
120 : * @Title: PDF Surfaces
121 : * @Short_Description: Rendering PDF documents
122 : * @See_Also: #cairo_surface_t
123 : *
124 : * The PDF surface is used to render cairo graphics to Adobe
125 : * PDF files and is a multi-page vector surface backend.
126 : */
127 :
128 : /**
129 : * CAIRO_HAS_PDF_SURFACE:
130 : *
131 : * Defined if the PDF surface backend is available.
132 : * This macro can be used to conditionally compile backend-specific code.
133 : */
134 :
135 : static const cairo_pdf_version_t _cairo_pdf_versions[] =
136 : {
137 : CAIRO_PDF_VERSION_1_4,
138 : CAIRO_PDF_VERSION_1_5
139 : };
140 :
141 : #define CAIRO_PDF_VERSION_LAST ARRAY_LENGTH (_cairo_pdf_versions)
142 :
143 : static const char * _cairo_pdf_version_strings[CAIRO_PDF_VERSION_LAST] =
144 : {
145 : "PDF 1.4",
146 : "PDF 1.5"
147 : };
148 :
149 : typedef struct _cairo_pdf_object {
150 : long offset;
151 : } cairo_pdf_object_t;
152 :
153 : typedef struct _cairo_pdf_font {
154 : unsigned int font_id;
155 : unsigned int subset_id;
156 : cairo_pdf_resource_t subset_resource;
157 : } cairo_pdf_font_t;
158 :
159 : typedef struct _cairo_pdf_rgb_linear_function {
160 : cairo_pdf_resource_t resource;
161 : double color1[3];
162 : double color2[3];
163 : } cairo_pdf_rgb_linear_function_t;
164 :
165 : typedef struct _cairo_pdf_alpha_linear_function {
166 : cairo_pdf_resource_t resource;
167 : double alpha1;
168 : double alpha2;
169 : } cairo_pdf_alpha_linear_function_t;
170 :
171 : static cairo_pdf_resource_t
172 : _cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface);
173 :
174 : static void
175 : _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
176 :
177 : static void
178 : _cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group);
179 :
180 : static cairo_status_t
181 : _cairo_pdf_surface_add_font (unsigned int font_id,
182 : unsigned int subset_id,
183 : void *closure);
184 :
185 : static void
186 : _cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res);
187 :
188 : static cairo_status_t
189 : _cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface,
190 : cairo_pdf_resource_t *resource,
191 : cairo_bool_t compressed,
192 : const char *fmt,
193 : ...) CAIRO_PRINTF_FORMAT(4, 5);
194 : static cairo_status_t
195 : _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface);
196 :
197 : static cairo_status_t
198 : _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
199 :
200 : static void
201 : _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface);
202 :
203 : static cairo_pdf_resource_t
204 : _cairo_pdf_surface_write_info (cairo_pdf_surface_t *surface);
205 :
206 : static cairo_pdf_resource_t
207 : _cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface);
208 :
209 : static long
210 : _cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface);
211 :
212 : static cairo_status_t
213 : _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
214 :
215 : static cairo_status_t
216 : _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface);
217 :
218 : static cairo_bool_t
219 : _cairo_pdf_source_surface_equal (const void *key_a, const void *key_b);
220 :
221 : static const cairo_surface_backend_t cairo_pdf_surface_backend;
222 : static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend;
223 :
224 : static cairo_pdf_resource_t
225 0 : _cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface)
226 : {
227 : cairo_pdf_resource_t resource;
228 : cairo_status_t status;
229 : cairo_pdf_object_t object;
230 :
231 0 : object.offset = _cairo_output_stream_get_position (surface->output);
232 :
233 0 : status = _cairo_array_append (&surface->objects, &object);
234 0 : if (unlikely (status)) {
235 0 : resource.id = 0;
236 0 : return resource;
237 : }
238 :
239 0 : resource = surface->next_available_resource;
240 0 : surface->next_available_resource.id++;
241 :
242 0 : return resource;
243 : }
244 :
245 : static void
246 0 : _cairo_pdf_surface_update_object (cairo_pdf_surface_t *surface,
247 : cairo_pdf_resource_t resource)
248 : {
249 : cairo_pdf_object_t *object;
250 :
251 0 : object = _cairo_array_index (&surface->objects, resource.id - 1);
252 0 : object->offset = _cairo_output_stream_get_position (surface->output);
253 0 : }
254 :
255 : static void
256 0 : _cairo_pdf_surface_set_size_internal (cairo_pdf_surface_t *surface,
257 : double width,
258 : double height)
259 : {
260 0 : surface->width = width;
261 0 : surface->height = height;
262 0 : cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, height);
263 0 : _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
264 : &surface->cairo_to_pdf);
265 0 : }
266 :
267 : static cairo_bool_t
268 0 : _path_covers_bbox (cairo_pdf_surface_t *surface,
269 : cairo_path_fixed_t *path)
270 : {
271 : cairo_box_t box;
272 :
273 0 : return _cairo_path_fixed_is_box (path, &box) &&
274 0 : box.p1.x <= 0 &&
275 0 : box.p1.y <= 0 &&
276 0 : box.p2.x >= _cairo_fixed_from_double (surface->width) &&
277 0 : box.p2.y >= _cairo_fixed_from_double (surface->height);
278 : }
279 :
280 : static cairo_status_t
281 0 : _cairo_pdf_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
282 : cairo_path_fixed_t *path,
283 : cairo_fill_rule_t fill_rule,
284 : double tolerance,
285 : cairo_antialias_t antialias)
286 : {
287 0 : cairo_pdf_surface_t *surface = cairo_container_of (clipper,
288 : cairo_pdf_surface_t,
289 : clipper);
290 : cairo_int_status_t status;
291 :
292 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
293 0 : if (unlikely (status))
294 0 : return status;
295 :
296 0 : if (path == NULL) {
297 0 : _cairo_output_stream_printf (surface->output, "Q q\n");
298 :
299 0 : surface->current_pattern_is_solid_color = FALSE;
300 0 : _cairo_pdf_operators_reset (&surface->pdf_operators);
301 :
302 0 : return CAIRO_STATUS_SUCCESS;
303 : }
304 :
305 0 : if (_path_covers_bbox (surface, path))
306 0 : return CAIRO_STATUS_SUCCESS;
307 :
308 0 : return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule);
309 : }
310 :
311 : static cairo_surface_t *
312 0 : _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
313 : double width,
314 : double height)
315 : {
316 : cairo_pdf_surface_t *surface;
317 : cairo_status_t status, status_ignored;
318 :
319 0 : surface = malloc (sizeof (cairo_pdf_surface_t));
320 0 : if (unlikely (surface == NULL)) {
321 : /* destroy stream on behalf of caller */
322 0 : status = _cairo_output_stream_destroy (output);
323 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
324 : }
325 :
326 0 : _cairo_surface_init (&surface->base,
327 : &cairo_pdf_surface_backend,
328 : NULL, /* device */
329 : CAIRO_CONTENT_COLOR_ALPHA);
330 :
331 0 : surface->output = output;
332 0 : surface->width = width;
333 0 : surface->height = height;
334 0 : cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, height);
335 :
336 0 : _cairo_array_init (&surface->objects, sizeof (cairo_pdf_object_t));
337 0 : _cairo_array_init (&surface->pages, sizeof (cairo_pdf_resource_t));
338 0 : _cairo_array_init (&surface->rgb_linear_functions, sizeof (cairo_pdf_rgb_linear_function_t));
339 0 : _cairo_array_init (&surface->alpha_linear_functions, sizeof (cairo_pdf_alpha_linear_function_t));
340 0 : _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
341 0 : _cairo_array_init (&surface->smask_groups, sizeof (cairo_pdf_smask_group_t *));
342 0 : _cairo_array_init (&surface->knockout_group, sizeof (cairo_pdf_resource_t));
343 :
344 0 : _cairo_array_init (&surface->page_patterns, sizeof (cairo_pdf_pattern_t));
345 0 : _cairo_array_init (&surface->page_surfaces, sizeof (cairo_pdf_source_surface_t));
346 0 : surface->all_surfaces = _cairo_hash_table_create (_cairo_pdf_source_surface_equal);
347 0 : if (unlikely (surface->all_surfaces == NULL)) {
348 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
349 0 : goto BAIL0;
350 : }
351 :
352 0 : _cairo_pdf_group_resources_init (&surface->resources);
353 :
354 0 : surface->font_subsets = _cairo_scaled_font_subsets_create_composite ();
355 0 : if (! surface->font_subsets) {
356 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
357 0 : goto BAIL1;
358 : }
359 :
360 0 : surface->next_available_resource.id = 1;
361 0 : surface->pages_resource = _cairo_pdf_surface_new_object (surface);
362 0 : if (surface->pages_resource.id == 0) {
363 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
364 0 : goto BAIL2;
365 : }
366 :
367 0 : surface->pdf_version = CAIRO_PDF_VERSION_1_5;
368 0 : surface->compress_content = TRUE;
369 0 : surface->pdf_stream.active = FALSE;
370 0 : surface->pdf_stream.old_output = NULL;
371 0 : surface->group_stream.active = FALSE;
372 0 : surface->group_stream.stream = NULL;
373 0 : surface->group_stream.mem_stream = NULL;
374 :
375 0 : surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
376 :
377 0 : surface->force_fallbacks = FALSE;
378 0 : surface->select_pattern_gstate_saved = FALSE;
379 0 : surface->current_pattern_is_solid_color = FALSE;
380 0 : surface->current_operator = CAIRO_OPERATOR_OVER;
381 0 : surface->header_emitted = FALSE;
382 :
383 0 : _cairo_surface_clipper_init (&surface->clipper,
384 : _cairo_pdf_surface_clipper_intersect_clip_path);
385 :
386 0 : _cairo_pdf_operators_init (&surface->pdf_operators,
387 : surface->output,
388 : &surface->cairo_to_pdf,
389 : surface->font_subsets);
390 0 : _cairo_pdf_operators_set_font_subsets_callback (&surface->pdf_operators,
391 : _cairo_pdf_surface_add_font,
392 : surface);
393 0 : _cairo_pdf_operators_enable_actual_text(&surface->pdf_operators, TRUE);
394 :
395 0 : surface->paginated_surface = _cairo_paginated_surface_create (
396 : &surface->base,
397 : CAIRO_CONTENT_COLOR_ALPHA,
398 : &cairo_pdf_surface_paginated_backend);
399 :
400 0 : status = surface->paginated_surface->status;
401 0 : if (status == CAIRO_STATUS_SUCCESS) {
402 : /* paginated keeps the only reference to surface now, drop ours */
403 0 : cairo_surface_destroy (&surface->base);
404 0 : return surface->paginated_surface;
405 : }
406 :
407 : BAIL2:
408 0 : _cairo_scaled_font_subsets_destroy (surface->font_subsets);
409 : BAIL1:
410 0 : _cairo_hash_table_destroy (surface->all_surfaces);
411 : BAIL0:
412 0 : _cairo_array_fini (&surface->objects);
413 0 : free (surface);
414 :
415 : /* destroy stream on behalf of caller */
416 0 : status_ignored = _cairo_output_stream_destroy (output);
417 :
418 0 : return _cairo_surface_create_in_error (status);
419 : }
420 :
421 : /**
422 : * cairo_pdf_surface_create_for_stream:
423 : * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL
424 : * to indicate a no-op @write_func. With a no-op @write_func,
425 : * the surface may be queried or used as a source without
426 : * generating any temporary files.
427 : * @closure: the closure argument for @write_func
428 : * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
429 : * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
430 : *
431 : * Creates a PDF surface of the specified size in points to be written
432 : * incrementally to the stream represented by @write_func and @closure.
433 : *
434 : * Return value: a pointer to the newly created surface. The caller
435 : * owns the surface and should call cairo_surface_destroy() when done
436 : * with it.
437 : *
438 : * This function always returns a valid pointer, but it will return a
439 : * pointer to a "nil" surface if an error such as out of memory
440 : * occurs. You can use cairo_surface_status() to check for this.
441 : *
442 : * Since: 1.2
443 : */
444 : cairo_surface_t *
445 0 : cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func,
446 : void *closure,
447 : double width_in_points,
448 : double height_in_points)
449 : {
450 : cairo_output_stream_t *output;
451 :
452 0 : output = _cairo_output_stream_create (write_func, NULL, closure);
453 0 : if (_cairo_output_stream_get_status (output))
454 0 : return _cairo_surface_create_in_error (_cairo_output_stream_destroy (output));
455 :
456 0 : return _cairo_pdf_surface_create_for_stream_internal (output,
457 : width_in_points,
458 : height_in_points);
459 : }
460 :
461 : /**
462 : * cairo_pdf_surface_create:
463 : * @filename: a filename for the PDF output (must be writable), %NULL may be
464 : * used to specify no output. This will generate a PDF surface that
465 : * may be queried and used as a source, without generating a
466 : * temporary file.
467 : * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
468 : * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
469 : *
470 : * Creates a PDF surface of the specified size in points to be written
471 : * to @filename.
472 : *
473 : * Return value: a pointer to the newly created surface. The caller
474 : * owns the surface and should call cairo_surface_destroy() when done
475 : * with it.
476 : *
477 : * This function always returns a valid pointer, but it will return a
478 : * pointer to a "nil" surface if an error such as out of memory
479 : * occurs. You can use cairo_surface_status() to check for this.
480 : *
481 : * Since: 1.2
482 : **/
483 : cairo_surface_t *
484 0 : cairo_pdf_surface_create (const char *filename,
485 : double width_in_points,
486 : double height_in_points)
487 : {
488 : cairo_output_stream_t *output;
489 :
490 0 : output = _cairo_output_stream_create_for_filename (filename);
491 0 : if (_cairo_output_stream_get_status (output))
492 0 : return _cairo_surface_create_in_error (_cairo_output_stream_destroy (output));
493 :
494 0 : return _cairo_pdf_surface_create_for_stream_internal (output,
495 : width_in_points,
496 : height_in_points);
497 : }
498 :
499 : static cairo_bool_t
500 0 : _cairo_surface_is_pdf (cairo_surface_t *surface)
501 : {
502 0 : return surface->backend == &cairo_pdf_surface_backend;
503 : }
504 :
505 : /* If the abstract_surface is a paginated surface, and that paginated
506 : * surface's target is a pdf_surface, then set pdf_surface to that
507 : * target. Otherwise return FALSE.
508 : */
509 : static cairo_bool_t
510 0 : _extract_pdf_surface (cairo_surface_t *surface,
511 : cairo_pdf_surface_t **pdf_surface)
512 : {
513 : cairo_surface_t *target;
514 : cairo_status_t status_ignored;
515 :
516 0 : if (surface->status)
517 0 : return FALSE;
518 0 : if (surface->finished) {
519 0 : status_ignored = _cairo_surface_set_error (surface,
520 : _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
521 0 : return FALSE;
522 : }
523 :
524 0 : if (! _cairo_surface_is_paginated (surface)) {
525 0 : status_ignored = _cairo_surface_set_error (surface,
526 : _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
527 0 : return FALSE;
528 : }
529 :
530 0 : target = _cairo_paginated_surface_get_target (surface);
531 0 : if (target->status) {
532 0 : status_ignored = _cairo_surface_set_error (surface,
533 : target->status);
534 0 : return FALSE;
535 : }
536 0 : if (target->finished) {
537 0 : status_ignored = _cairo_surface_set_error (surface,
538 : _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
539 0 : return FALSE;
540 : }
541 :
542 0 : if (! _cairo_surface_is_pdf (target)) {
543 0 : status_ignored = _cairo_surface_set_error (surface,
544 : _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
545 0 : return FALSE;
546 : }
547 :
548 0 : *pdf_surface = (cairo_pdf_surface_t *) target;
549 0 : return TRUE;
550 : }
551 :
552 : /**
553 : * cairo_pdf_surface_restrict_to_version:
554 : * @surface: a PDF #cairo_surface_t
555 : * @version: PDF version
556 : *
557 : * Restricts the generated PDF file to @version. See cairo_pdf_get_versions()
558 : * for a list of available version values that can be used here.
559 : *
560 : * This function should only be called before any drawing operations
561 : * have been performed on the given surface. The simplest way to do
562 : * this is to call this function immediately after creating the
563 : * surface.
564 : *
565 : * Since: 1.10
566 : **/
567 : void
568 0 : cairo_pdf_surface_restrict_to_version (cairo_surface_t *abstract_surface,
569 : cairo_pdf_version_t version)
570 : {
571 0 : cairo_pdf_surface_t *surface = NULL; /* hide compiler warning */
572 :
573 0 : if (! _extract_pdf_surface (abstract_surface, &surface))
574 0 : return;
575 :
576 0 : if (version < CAIRO_PDF_VERSION_LAST)
577 0 : surface->pdf_version = version;
578 :
579 0 : _cairo_pdf_operators_enable_actual_text(&surface->pdf_operators,
580 : version >= CAIRO_PDF_VERSION_1_5);
581 : }
582 :
583 : /**
584 : * cairo_pdf_get_versions:
585 : * @versions: supported version list
586 : * @num_versions: list length
587 : *
588 : * Used to retrieve the list of supported versions. See
589 : * cairo_pdf_surface_restrict_to_version().
590 : *
591 : * Since: 1.10
592 : **/
593 : void
594 0 : cairo_pdf_get_versions (cairo_pdf_version_t const **versions,
595 : int *num_versions)
596 : {
597 0 : if (versions != NULL)
598 0 : *versions = _cairo_pdf_versions;
599 :
600 0 : if (num_versions != NULL)
601 0 : *num_versions = CAIRO_PDF_VERSION_LAST;
602 0 : }
603 :
604 : /**
605 : * cairo_pdf_version_to_string:
606 : * @version: a version id
607 : *
608 : * Get the string representation of the given @version id. This function
609 : * will return %NULL if @version isn't valid. See cairo_pdf_get_versions()
610 : * for a way to get the list of valid version ids.
611 : *
612 : * Return value: the string associated to given version.
613 : *
614 : * Since: 1.10
615 : **/
616 : const char *
617 0 : cairo_pdf_version_to_string (cairo_pdf_version_t version)
618 : {
619 0 : if (version >= CAIRO_PDF_VERSION_LAST)
620 0 : return NULL;
621 :
622 0 : return _cairo_pdf_version_strings[version];
623 : }
624 :
625 : /**
626 : * cairo_pdf_surface_set_size:
627 : * @surface: a PDF #cairo_surface_t
628 : * @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
629 : * @height_in_points: new surface height, in points (1 point == 1/72.0 inch)
630 : *
631 : * Changes the size of a PDF surface for the current (and
632 : * subsequent) pages.
633 : *
634 : * This function should only be called before any drawing operations
635 : * have been performed on the current page. The simplest way to do
636 : * this is to call this function immediately after creating the
637 : * surface or immediately after completing a page with either
638 : * cairo_show_page() or cairo_copy_page().
639 : *
640 : * Since: 1.2
641 : **/
642 : void
643 0 : cairo_pdf_surface_set_size (cairo_surface_t *surface,
644 : double width_in_points,
645 : double height_in_points)
646 : {
647 0 : cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */
648 :
649 0 : if (! _extract_pdf_surface (surface, &pdf_surface))
650 0 : return;
651 :
652 0 : _cairo_pdf_surface_set_size_internal (pdf_surface,
653 : width_in_points,
654 : height_in_points);
655 : }
656 :
657 : static void
658 0 : _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
659 : {
660 : int i, size;
661 : cairo_pdf_pattern_t *pattern;
662 : cairo_pdf_source_surface_t *src_surface;
663 : cairo_pdf_smask_group_t *group;
664 :
665 0 : size = _cairo_array_num_elements (&surface->page_patterns);
666 0 : for (i = 0; i < size; i++) {
667 0 : pattern = (cairo_pdf_pattern_t *) _cairo_array_index (&surface->page_patterns, i);
668 0 : cairo_pattern_destroy (pattern->pattern);
669 : }
670 0 : _cairo_array_truncate (&surface->page_patterns, 0);
671 :
672 0 : size = _cairo_array_num_elements (&surface->page_surfaces);
673 0 : for (i = 0; i < size; i++) {
674 0 : src_surface = (cairo_pdf_source_surface_t *) _cairo_array_index (&surface->page_surfaces, i);
675 0 : cairo_surface_destroy (src_surface->surface);
676 : }
677 0 : _cairo_array_truncate (&surface->page_surfaces, 0);
678 :
679 0 : size = _cairo_array_num_elements (&surface->smask_groups);
680 0 : for (i = 0; i < size; i++) {
681 0 : _cairo_array_copy_element (&surface->smask_groups, i, &group);
682 0 : _cairo_pdf_smask_group_destroy (group);
683 : }
684 0 : _cairo_array_truncate (&surface->smask_groups, 0);
685 0 : _cairo_array_truncate (&surface->knockout_group, 0);
686 0 : }
687 :
688 : static void
689 0 : _cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res)
690 : {
691 : int i;
692 :
693 0 : for (i = 0; i < CAIRO_NUM_OPERATORS; i++)
694 0 : res->operators[i] = FALSE;
695 :
696 0 : _cairo_array_init (&res->alphas, sizeof (double));
697 0 : _cairo_array_init (&res->smasks, sizeof (cairo_pdf_resource_t));
698 0 : _cairo_array_init (&res->patterns, sizeof (cairo_pdf_resource_t));
699 0 : _cairo_array_init (&res->xobjects, sizeof (cairo_pdf_resource_t));
700 0 : _cairo_array_init (&res->fonts, sizeof (cairo_pdf_font_t));
701 0 : }
702 :
703 : static void
704 0 : _cairo_pdf_group_resources_fini (cairo_pdf_group_resources_t *res)
705 : {
706 0 : _cairo_array_fini (&res->alphas);
707 0 : _cairo_array_fini (&res->smasks);
708 0 : _cairo_array_fini (&res->patterns);
709 0 : _cairo_array_fini (&res->xobjects);
710 0 : _cairo_array_fini (&res->fonts);
711 0 : }
712 :
713 : static void
714 0 : _cairo_pdf_group_resources_clear (cairo_pdf_group_resources_t *res)
715 : {
716 : int i;
717 :
718 0 : for (i = 0; i < CAIRO_NUM_OPERATORS; i++)
719 0 : res->operators[i] = FALSE;
720 :
721 0 : _cairo_array_truncate (&res->alphas, 0);
722 0 : _cairo_array_truncate (&res->smasks, 0);
723 0 : _cairo_array_truncate (&res->patterns, 0);
724 0 : _cairo_array_truncate (&res->xobjects, 0);
725 0 : _cairo_array_truncate (&res->fonts, 0);
726 0 : }
727 :
728 : static void
729 0 : _cairo_pdf_surface_add_operator (cairo_pdf_surface_t *surface,
730 : cairo_operator_t op)
731 : {
732 0 : cairo_pdf_group_resources_t *res = &surface->resources;
733 :
734 0 : res->operators[op] = TRUE;
735 0 : }
736 :
737 : static cairo_status_t
738 0 : _cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface,
739 : double alpha,
740 : int *index)
741 : {
742 : int num_alphas, i;
743 : double other;
744 : cairo_status_t status;
745 0 : cairo_pdf_group_resources_t *res = &surface->resources;
746 :
747 0 : num_alphas = _cairo_array_num_elements (&res->alphas);
748 0 : for (i = 0; i < num_alphas; i++) {
749 0 : _cairo_array_copy_element (&res->alphas, i, &other);
750 0 : if (alpha == other) {
751 0 : *index = i;
752 0 : return CAIRO_STATUS_SUCCESS;
753 : }
754 : }
755 :
756 0 : status = _cairo_array_append (&res->alphas, &alpha);
757 0 : if (unlikely (status))
758 0 : return status;
759 :
760 0 : *index = _cairo_array_num_elements (&res->alphas) - 1;
761 :
762 0 : return CAIRO_STATUS_SUCCESS;
763 : }
764 :
765 : static cairo_status_t
766 0 : _cairo_pdf_surface_add_smask (cairo_pdf_surface_t *surface,
767 : cairo_pdf_resource_t smask)
768 : {
769 0 : return _cairo_array_append (&(surface->resources.smasks), &smask);
770 : }
771 :
772 : static cairo_status_t
773 0 : _cairo_pdf_surface_add_pattern (cairo_pdf_surface_t *surface,
774 : cairo_pdf_resource_t pattern)
775 : {
776 0 : return _cairo_array_append (&(surface->resources.patterns), &pattern);
777 : }
778 :
779 : static cairo_status_t
780 0 : _cairo_pdf_surface_add_xobject (cairo_pdf_surface_t *surface,
781 : cairo_pdf_resource_t xobject)
782 : {
783 0 : return _cairo_array_append (&(surface->resources.xobjects), &xobject);
784 : }
785 :
786 : static cairo_status_t
787 0 : _cairo_pdf_surface_add_font (unsigned int font_id,
788 : unsigned int subset_id,
789 : void *closure)
790 : {
791 0 : cairo_pdf_surface_t *surface = closure;
792 : cairo_pdf_font_t font;
793 : int num_fonts, i;
794 : cairo_status_t status;
795 0 : cairo_pdf_group_resources_t *res = &surface->resources;
796 :
797 0 : num_fonts = _cairo_array_num_elements (&res->fonts);
798 0 : for (i = 0; i < num_fonts; i++) {
799 0 : _cairo_array_copy_element (&res->fonts, i, &font);
800 0 : if (font.font_id == font_id &&
801 0 : font.subset_id == subset_id)
802 0 : return CAIRO_STATUS_SUCCESS;
803 : }
804 :
805 0 : num_fonts = _cairo_array_num_elements (&surface->fonts);
806 0 : for (i = 0; i < num_fonts; i++) {
807 0 : _cairo_array_copy_element (&surface->fonts, i, &font);
808 0 : if (font.font_id == font_id &&
809 0 : font.subset_id == subset_id)
810 0 : return _cairo_array_append (&res->fonts, &font);
811 : }
812 :
813 0 : font.font_id = font_id;
814 0 : font.subset_id = subset_id;
815 0 : font.subset_resource = _cairo_pdf_surface_new_object (surface);
816 0 : if (font.subset_resource.id == 0)
817 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
818 :
819 0 : status = _cairo_array_append (&surface->fonts, &font);
820 0 : if (unlikely (status))
821 0 : return status;
822 :
823 0 : return _cairo_array_append (&res->fonts, &font);
824 : }
825 :
826 : static cairo_pdf_resource_t
827 0 : _cairo_pdf_surface_get_font_resource (cairo_pdf_surface_t *surface,
828 : unsigned int font_id,
829 : unsigned int subset_id)
830 : {
831 : cairo_pdf_font_t font;
832 : int num_fonts, i;
833 :
834 0 : num_fonts = _cairo_array_num_elements (&surface->fonts);
835 0 : for (i = 0; i < num_fonts; i++) {
836 0 : _cairo_array_copy_element (&surface->fonts, i, &font);
837 0 : if (font.font_id == font_id && font.subset_id == subset_id)
838 0 : return font.subset_resource;
839 : }
840 :
841 0 : font.subset_resource.id = 0;
842 0 : return font.subset_resource;
843 : }
844 :
845 : static const char *
846 0 : _cairo_operator_to_pdf_blend_mode (cairo_operator_t op)
847 : {
848 0 : switch (op) {
849 : /* The extend blend mode operators */
850 0 : case CAIRO_OPERATOR_MULTIPLY: return "Multiply";
851 0 : case CAIRO_OPERATOR_SCREEN: return "Screen";
852 0 : case CAIRO_OPERATOR_OVERLAY: return "Overlay";
853 0 : case CAIRO_OPERATOR_DARKEN: return "Darken";
854 0 : case CAIRO_OPERATOR_LIGHTEN: return "Lighten";
855 0 : case CAIRO_OPERATOR_COLOR_DODGE: return "ColorDodge";
856 0 : case CAIRO_OPERATOR_COLOR_BURN: return "ColorBurn";
857 0 : case CAIRO_OPERATOR_HARD_LIGHT: return "HardLight";
858 0 : case CAIRO_OPERATOR_SOFT_LIGHT: return "SoftLight";
859 0 : case CAIRO_OPERATOR_DIFFERENCE: return "Difference";
860 0 : case CAIRO_OPERATOR_EXCLUSION: return "Exclusion";
861 0 : case CAIRO_OPERATOR_HSL_HUE: return "Hue";
862 0 : case CAIRO_OPERATOR_HSL_SATURATION: return "Saturation";
863 0 : case CAIRO_OPERATOR_HSL_COLOR: return "Color";
864 0 : case CAIRO_OPERATOR_HSL_LUMINOSITY: return "Luminosity";
865 :
866 : default:
867 : /* The original Porter-Duff set */
868 : case CAIRO_OPERATOR_CLEAR:
869 : case CAIRO_OPERATOR_SOURCE:
870 : case CAIRO_OPERATOR_OVER:
871 : case CAIRO_OPERATOR_IN:
872 : case CAIRO_OPERATOR_OUT:
873 : case CAIRO_OPERATOR_ATOP:
874 : case CAIRO_OPERATOR_DEST:
875 : case CAIRO_OPERATOR_DEST_OVER:
876 : case CAIRO_OPERATOR_DEST_IN:
877 : case CAIRO_OPERATOR_DEST_OUT:
878 : case CAIRO_OPERATOR_DEST_ATOP:
879 : case CAIRO_OPERATOR_XOR:
880 : case CAIRO_OPERATOR_ADD:
881 : case CAIRO_OPERATOR_SATURATE:
882 0 : return "Normal";
883 : }
884 : }
885 :
886 : static void
887 0 : _cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t *surface,
888 : cairo_pdf_group_resources_t *res)
889 : {
890 : int num_alphas, num_smasks, num_resources, i;
891 : double alpha;
892 : cairo_pdf_resource_t *smask, *pattern, *xobject;
893 : cairo_pdf_font_t *font;
894 :
895 0 : _cairo_output_stream_printf (surface->output, "<<\n");
896 :
897 0 : num_alphas = _cairo_array_num_elements (&res->alphas);
898 0 : num_smasks = _cairo_array_num_elements (&res->smasks);
899 0 : if (num_alphas > 0 || num_smasks > 0) {
900 0 : _cairo_output_stream_printf (surface->output,
901 : " /ExtGState <<\n");
902 :
903 0 : for (i = 0; i < CAIRO_NUM_OPERATORS; i++) {
904 0 : if (res->operators[i]) {
905 0 : _cairo_output_stream_printf (surface->output,
906 : " /b%d << /BM /%s >>\n",
907 : i, _cairo_operator_to_pdf_blend_mode(i));
908 : }
909 : }
910 :
911 0 : for (i = 0; i < num_alphas; i++) {
912 0 : _cairo_array_copy_element (&res->alphas, i, &alpha);
913 0 : _cairo_output_stream_printf (surface->output,
914 : " /a%d << /CA %f /ca %f >>\n",
915 : i, alpha, alpha);
916 : }
917 :
918 0 : for (i = 0; i < num_smasks; i++) {
919 0 : smask = _cairo_array_index (&res->smasks, i);
920 0 : _cairo_output_stream_printf (surface->output,
921 : " /s%d %d 0 R\n",
922 : smask->id, smask->id);
923 : }
924 :
925 0 : _cairo_output_stream_printf (surface->output,
926 : " >>\n");
927 : }
928 :
929 0 : num_resources = _cairo_array_num_elements (&res->patterns);
930 0 : if (num_resources > 0) {
931 0 : _cairo_output_stream_printf (surface->output,
932 : " /Pattern <<");
933 0 : for (i = 0; i < num_resources; i++) {
934 0 : pattern = _cairo_array_index (&res->patterns, i);
935 0 : _cairo_output_stream_printf (surface->output,
936 : " /p%d %d 0 R",
937 : pattern->id, pattern->id);
938 : }
939 :
940 0 : _cairo_output_stream_printf (surface->output,
941 : " >>\n");
942 : }
943 :
944 0 : num_resources = _cairo_array_num_elements (&res->xobjects);
945 0 : if (num_resources > 0) {
946 0 : _cairo_output_stream_printf (surface->output,
947 : " /XObject <<");
948 :
949 0 : for (i = 0; i < num_resources; i++) {
950 0 : xobject = _cairo_array_index (&res->xobjects, i);
951 0 : _cairo_output_stream_printf (surface->output,
952 : " /x%d %d 0 R",
953 : xobject->id, xobject->id);
954 : }
955 :
956 0 : _cairo_output_stream_printf (surface->output,
957 : " >>\n");
958 : }
959 :
960 0 : num_resources = _cairo_array_num_elements (&res->fonts);
961 0 : if (num_resources > 0) {
962 0 : _cairo_output_stream_printf (surface->output," /Font <<\n");
963 0 : for (i = 0; i < num_resources; i++) {
964 0 : font = _cairo_array_index (&res->fonts, i);
965 0 : _cairo_output_stream_printf (surface->output,
966 : " /f-%d-%d %d 0 R\n",
967 : font->font_id,
968 : font->subset_id,
969 : font->subset_resource.id);
970 : }
971 0 : _cairo_output_stream_printf (surface->output, " >>\n");
972 : }
973 :
974 0 : _cairo_output_stream_printf (surface->output,
975 : ">>\n");
976 0 : }
977 :
978 : static cairo_pdf_smask_group_t *
979 0 : _cairo_pdf_surface_create_smask_group (cairo_pdf_surface_t *surface)
980 : {
981 : cairo_pdf_smask_group_t *group;
982 :
983 0 : group = calloc (1, sizeof (cairo_pdf_smask_group_t));
984 0 : if (unlikely (group == NULL)) {
985 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
986 0 : return NULL;
987 : }
988 :
989 0 : group->group_res = _cairo_pdf_surface_new_object (surface);
990 0 : if (group->group_res.id == 0) {
991 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
992 0 : free (group);
993 0 : return NULL;
994 : }
995 0 : group->width = surface->width;
996 0 : group->height = surface->height;
997 :
998 0 : return group;
999 : }
1000 :
1001 : static void
1002 0 : _cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group)
1003 : {
1004 0 : if (group->operation == PDF_FILL || group->operation == PDF_STROKE)
1005 0 : _cairo_path_fixed_fini (&group->path);
1006 0 : if (group->source)
1007 0 : cairo_pattern_destroy (group->source);
1008 0 : if (group->mask)
1009 0 : cairo_pattern_destroy (group->mask);
1010 0 : if (group->utf8)
1011 0 : free (group->utf8);
1012 0 : if (group->glyphs)
1013 0 : free (group->glyphs);
1014 0 : if (group->clusters)
1015 0 : free (group->clusters);
1016 0 : if (group->scaled_font)
1017 0 : cairo_scaled_font_destroy (group->scaled_font);
1018 0 : free (group);
1019 0 : }
1020 :
1021 : static cairo_status_t
1022 0 : _cairo_pdf_surface_add_smask_group (cairo_pdf_surface_t *surface,
1023 : cairo_pdf_smask_group_t *group)
1024 : {
1025 0 : return _cairo_array_append (&surface->smask_groups, &group);
1026 : }
1027 :
1028 : static cairo_bool_t
1029 0 : _cairo_pdf_source_surface_equal (const void *key_a, const void *key_b)
1030 : {
1031 0 : const cairo_pdf_source_surface_entry_t *a = key_a;
1032 0 : const cairo_pdf_source_surface_entry_t *b = key_b;
1033 :
1034 0 : return (a->id == b->id) && (a->interpolate == b->interpolate);
1035 : }
1036 :
1037 : static void
1038 0 : _cairo_pdf_source_surface_init_key (cairo_pdf_source_surface_entry_t *key)
1039 : {
1040 0 : key->base.hash = key->id;
1041 0 : }
1042 :
1043 : static cairo_int_status_t
1044 0 : _get_jpx_image_info (cairo_surface_t *source,
1045 : cairo_image_info_t *info,
1046 : const unsigned char **mime_data,
1047 : unsigned long *mime_data_length)
1048 : {
1049 0 : cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JP2,
1050 : mime_data, mime_data_length);
1051 0 : if (*mime_data == NULL)
1052 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1053 :
1054 0 : return _cairo_image_info_get_jpx_info (info, *mime_data, *mime_data_length);
1055 : }
1056 :
1057 : static cairo_int_status_t
1058 0 : _get_jpeg_image_info (cairo_surface_t *source,
1059 : cairo_image_info_t *info,
1060 : const unsigned char **mime_data,
1061 : unsigned long *mime_data_length)
1062 : {
1063 0 : cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
1064 : mime_data, mime_data_length);
1065 0 : if (*mime_data == NULL)
1066 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1067 :
1068 0 : return _cairo_image_info_get_jpeg_info (info, *mime_data, *mime_data_length);
1069 : }
1070 :
1071 : static cairo_status_t
1072 0 : _get_source_surface_size (cairo_surface_t *source,
1073 : int *width,
1074 : int *height)
1075 : {
1076 : cairo_status_t status;
1077 : cairo_rectangle_int_t extents;
1078 : cairo_image_info_t info;
1079 : const unsigned char *mime_data;
1080 : unsigned long mime_data_length;
1081 :
1082 0 : if (source->type == CAIRO_SURFACE_TYPE_RECORDING) {
1083 0 : if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1084 0 : cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
1085 :
1086 0 : *width = sub->extents.width;
1087 0 : *height = sub->extents.height;
1088 :
1089 : } else {
1090 0 : cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) source;
1091 : cairo_box_t bbox;
1092 :
1093 0 : status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
1094 0 : if (unlikely (status))
1095 0 : return status;
1096 :
1097 0 : _cairo_box_round_to_rectangle (&bbox, &extents);
1098 :
1099 0 : *width = extents.width;
1100 0 : *height = extents.height;
1101 : }
1102 0 : return CAIRO_STATUS_SUCCESS;
1103 : }
1104 :
1105 0 : status = _get_jpx_image_info (source, &info, &mime_data, &mime_data_length);
1106 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
1107 0 : *width = info.width;
1108 0 : *height = info.height;
1109 0 : return status;
1110 : }
1111 :
1112 0 : status = _get_jpeg_image_info (source, &info, &mime_data, &mime_data_length);
1113 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
1114 0 : *width = info.width;
1115 0 : *height = info.height;
1116 0 : return status;
1117 : }
1118 :
1119 0 : if (! _cairo_surface_get_extents (source, &extents))
1120 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1121 :
1122 0 : *width = extents.width;
1123 0 : *height = extents.height;
1124 :
1125 0 : return CAIRO_STATUS_SUCCESS;
1126 : }
1127 :
1128 : static cairo_status_t
1129 0 : _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
1130 : cairo_surface_t *source,
1131 : cairo_filter_t filter,
1132 : cairo_pdf_resource_t *surface_res,
1133 : int *width,
1134 : int *height)
1135 : {
1136 : cairo_pdf_source_surface_t src_surface;
1137 : cairo_pdf_source_surface_entry_t surface_key;
1138 : cairo_pdf_source_surface_entry_t *surface_entry;
1139 : cairo_status_t status;
1140 : cairo_bool_t interpolate;
1141 :
1142 0 : switch (filter) {
1143 : default:
1144 : case CAIRO_FILTER_GOOD:
1145 : case CAIRO_FILTER_BEST:
1146 : case CAIRO_FILTER_BILINEAR:
1147 0 : interpolate = TRUE;
1148 0 : break;
1149 : case CAIRO_FILTER_FAST:
1150 : case CAIRO_FILTER_NEAREST:
1151 : case CAIRO_FILTER_GAUSSIAN:
1152 0 : interpolate = FALSE;
1153 0 : break;
1154 : }
1155 :
1156 0 : surface_key.id = source->unique_id;
1157 0 : surface_key.interpolate = interpolate;
1158 0 : _cairo_pdf_source_surface_init_key (&surface_key);
1159 0 : surface_entry = _cairo_hash_table_lookup (surface->all_surfaces, &surface_key.base);
1160 0 : if (surface_entry) {
1161 0 : *surface_res = surface_entry->surface_res;
1162 0 : *width = surface_entry->width;
1163 0 : *height = surface_entry->height;
1164 :
1165 0 : return CAIRO_STATUS_SUCCESS;
1166 : }
1167 :
1168 0 : surface_entry = malloc (sizeof (cairo_pdf_source_surface_entry_t));
1169 0 : if (surface_entry == NULL)
1170 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1171 :
1172 0 : surface_entry->id = surface_key.id;
1173 0 : surface_entry->interpolate = interpolate;
1174 0 : _cairo_pdf_source_surface_init_key (surface_entry);
1175 :
1176 0 : src_surface.hash_entry = surface_entry;
1177 0 : src_surface.surface = cairo_surface_reference (source);
1178 0 : surface_entry->surface_res = _cairo_pdf_surface_new_object (surface);
1179 0 : if (surface_entry->surface_res.id == 0) {
1180 0 : cairo_surface_destroy (source);
1181 0 : free (surface_entry);
1182 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1183 : }
1184 :
1185 0 : status = _get_source_surface_size (source, &surface_entry->width,
1186 : &surface_entry->height);
1187 :
1188 0 : status = _cairo_array_append (&surface->page_surfaces, &src_surface);
1189 0 : if (unlikely (status)) {
1190 0 : cairo_surface_destroy (source);
1191 0 : free (surface_entry);
1192 0 : return status;
1193 : }
1194 :
1195 0 : status = _cairo_hash_table_insert (surface->all_surfaces,
1196 : &surface_entry->base);
1197 :
1198 0 : *surface_res = surface_entry->surface_res;
1199 0 : *width = surface_entry->width;
1200 0 : *height = surface_entry->height;
1201 :
1202 0 : return status;
1203 : }
1204 :
1205 : static cairo_status_t
1206 0 : _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
1207 : const cairo_pattern_t *pattern,
1208 : const cairo_rectangle_int_t *extents,
1209 : cairo_pdf_resource_t *pattern_res,
1210 : cairo_pdf_resource_t *gstate_res)
1211 : {
1212 : cairo_pdf_pattern_t pdf_pattern;
1213 : cairo_status_t status;
1214 :
1215 : /* Solid colors are emitted into the content stream */
1216 0 : if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
1217 0 : pattern_res->id = 0;
1218 0 : gstate_res->id = 0;
1219 0 : return CAIRO_STATUS_SUCCESS;
1220 : }
1221 :
1222 0 : status = _cairo_pattern_create_copy (&pdf_pattern.pattern, pattern);
1223 0 : if (unlikely (status))
1224 0 : return status;
1225 :
1226 0 : pdf_pattern.pattern_res = _cairo_pdf_surface_new_object (surface);
1227 0 : if (pdf_pattern.pattern_res.id == 0) {
1228 0 : cairo_pattern_destroy (pdf_pattern.pattern);
1229 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1230 : }
1231 :
1232 0 : pdf_pattern.gstate_res.id = 0;
1233 :
1234 : /* gradient patterns require an smask object to implement transparency */
1235 0 : if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
1236 0 : pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
1237 : {
1238 0 : if (_cairo_pattern_is_opaque (pattern, extents) == FALSE) {
1239 0 : pdf_pattern.gstate_res = _cairo_pdf_surface_new_object (surface);
1240 0 : if (pdf_pattern.gstate_res.id == 0) {
1241 0 : cairo_pattern_destroy (pdf_pattern.pattern);
1242 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1243 : }
1244 : }
1245 : }
1246 :
1247 0 : pdf_pattern.width = surface->width;
1248 0 : pdf_pattern.height = surface->height;
1249 0 : if (extents != NULL) {
1250 0 : pdf_pattern.extents = *extents;
1251 : } else {
1252 0 : pdf_pattern.extents.x = 0;
1253 0 : pdf_pattern.extents.y = 0;
1254 0 : pdf_pattern.extents.width = surface->width;
1255 0 : pdf_pattern.extents.height = surface->height;
1256 : }
1257 :
1258 0 : *pattern_res = pdf_pattern.pattern_res;
1259 0 : *gstate_res = pdf_pattern.gstate_res;
1260 :
1261 0 : status = _cairo_array_append (&surface->page_patterns, &pdf_pattern);
1262 0 : if (unlikely (status)) {
1263 0 : cairo_pattern_destroy (pdf_pattern.pattern);
1264 0 : return status;
1265 : }
1266 :
1267 0 : return CAIRO_STATUS_SUCCESS;
1268 : }
1269 :
1270 : static cairo_status_t
1271 0 : _cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface,
1272 : cairo_pdf_resource_t *resource,
1273 : cairo_bool_t compressed,
1274 : const char *fmt,
1275 : ...)
1276 : {
1277 : va_list ap;
1278 : cairo_pdf_resource_t self, length;
1279 0 : cairo_output_stream_t *output = NULL;
1280 :
1281 0 : if (resource) {
1282 0 : self = *resource;
1283 0 : _cairo_pdf_surface_update_object (surface, self);
1284 : } else {
1285 0 : self = _cairo_pdf_surface_new_object (surface);
1286 0 : if (self.id == 0)
1287 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1288 : }
1289 :
1290 0 : length = _cairo_pdf_surface_new_object (surface);
1291 0 : if (length.id == 0)
1292 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1293 :
1294 0 : if (compressed) {
1295 0 : output = _cairo_deflate_stream_create (surface->output);
1296 0 : if (_cairo_output_stream_get_status (output))
1297 0 : return _cairo_output_stream_destroy (output);
1298 : }
1299 :
1300 0 : surface->pdf_stream.active = TRUE;
1301 0 : surface->pdf_stream.self = self;
1302 0 : surface->pdf_stream.length = length;
1303 0 : surface->pdf_stream.compressed = compressed;
1304 0 : surface->current_pattern_is_solid_color = FALSE;
1305 0 : surface->current_operator = CAIRO_OPERATOR_OVER;
1306 0 : _cairo_pdf_operators_reset (&surface->pdf_operators);
1307 :
1308 0 : _cairo_output_stream_printf (surface->output,
1309 : "%d 0 obj\n"
1310 : "<< /Length %d 0 R\n",
1311 : surface->pdf_stream.self.id,
1312 : surface->pdf_stream.length.id);
1313 0 : if (compressed)
1314 0 : _cairo_output_stream_printf (surface->output,
1315 : " /Filter /FlateDecode\n");
1316 :
1317 0 : if (fmt != NULL) {
1318 0 : va_start (ap, fmt);
1319 0 : _cairo_output_stream_vprintf (surface->output, fmt, ap);
1320 0 : va_end (ap);
1321 : }
1322 :
1323 0 : _cairo_output_stream_printf (surface->output,
1324 : ">>\n"
1325 : "stream\n");
1326 :
1327 0 : surface->pdf_stream.start_offset = _cairo_output_stream_get_position (surface->output);
1328 :
1329 0 : if (compressed) {
1330 0 : assert (surface->pdf_stream.old_output == NULL);
1331 0 : surface->pdf_stream.old_output = surface->output;
1332 0 : surface->output = output;
1333 0 : _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
1334 : }
1335 :
1336 0 : return _cairo_output_stream_get_status (surface->output);
1337 : }
1338 :
1339 : static cairo_status_t
1340 0 : _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
1341 : {
1342 : cairo_status_t status;
1343 : long length;
1344 :
1345 0 : if (! surface->pdf_stream.active)
1346 0 : return CAIRO_STATUS_SUCCESS;
1347 :
1348 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
1349 :
1350 0 : if (surface->pdf_stream.compressed) {
1351 : cairo_status_t status2;
1352 :
1353 0 : status2 = _cairo_output_stream_destroy (surface->output);
1354 0 : if (likely (status == CAIRO_STATUS_SUCCESS))
1355 0 : status = status2;
1356 :
1357 0 : surface->output = surface->pdf_stream.old_output;
1358 0 : _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
1359 0 : surface->pdf_stream.old_output = NULL;
1360 : }
1361 :
1362 0 : length = _cairo_output_stream_get_position (surface->output) -
1363 0 : surface->pdf_stream.start_offset;
1364 0 : _cairo_output_stream_printf (surface->output,
1365 : "\n"
1366 : "endstream\n"
1367 : "endobj\n");
1368 :
1369 0 : _cairo_pdf_surface_update_object (surface,
1370 : surface->pdf_stream.length);
1371 0 : _cairo_output_stream_printf (surface->output,
1372 : "%d 0 obj\n"
1373 : " %ld\n"
1374 : "endobj\n",
1375 : surface->pdf_stream.length.id,
1376 : length);
1377 :
1378 0 : surface->pdf_stream.active = FALSE;
1379 :
1380 0 : if (likely (status == CAIRO_STATUS_SUCCESS))
1381 0 : status = _cairo_output_stream_get_status (surface->output);
1382 :
1383 0 : return status;
1384 : }
1385 :
1386 : static void
1387 0 : _cairo_pdf_surface_write_memory_stream (cairo_pdf_surface_t *surface,
1388 : cairo_output_stream_t *mem_stream,
1389 : cairo_pdf_resource_t resource,
1390 : cairo_pdf_group_resources_t *resources,
1391 : cairo_bool_t is_knockout_group)
1392 : {
1393 0 : _cairo_pdf_surface_update_object (surface, resource);
1394 :
1395 0 : _cairo_output_stream_printf (surface->output,
1396 : "%d 0 obj\n"
1397 : "<< /Type /XObject\n"
1398 : " /Length %d\n",
1399 : resource.id,
1400 : _cairo_memory_stream_length (mem_stream));
1401 :
1402 0 : if (surface->compress_content) {
1403 0 : _cairo_output_stream_printf (surface->output,
1404 : " /Filter /FlateDecode\n");
1405 : }
1406 :
1407 0 : _cairo_output_stream_printf (surface->output,
1408 : " /Subtype /Form\n"
1409 : " /BBox [ 0 0 %f %f ]\n"
1410 : " /Group <<\n"
1411 : " /Type /Group\n"
1412 : " /S /Transparency\n"
1413 : " /CS /DeviceRGB\n",
1414 : surface->width,
1415 : surface->height);
1416 :
1417 0 : if (is_knockout_group)
1418 0 : _cairo_output_stream_printf (surface->output,
1419 : " /K true\n");
1420 :
1421 0 : _cairo_output_stream_printf (surface->output,
1422 : " >>\n"
1423 : " /Resources\n");
1424 0 : _cairo_pdf_surface_emit_group_resources (surface, resources);
1425 0 : _cairo_output_stream_printf (surface->output,
1426 : ">>\n"
1427 : "stream\n");
1428 0 : _cairo_memory_stream_copy (mem_stream, surface->output);
1429 0 : _cairo_output_stream_printf (surface->output,
1430 : "endstream\n"
1431 : "endobj\n");
1432 0 : }
1433 :
1434 : static cairo_status_t
1435 0 : _cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface,
1436 : cairo_pdf_resource_t *resource)
1437 : {
1438 : cairo_status_t status;
1439 :
1440 0 : assert (surface->pdf_stream.active == FALSE);
1441 0 : assert (surface->group_stream.active == FALSE);
1442 :
1443 0 : surface->group_stream.active = TRUE;
1444 0 : surface->current_pattern_is_solid_color = FALSE;
1445 0 : surface->current_operator = CAIRO_OPERATOR_OVER;
1446 0 : _cairo_pdf_operators_reset (&surface->pdf_operators);
1447 :
1448 0 : surface->group_stream.mem_stream = _cairo_memory_stream_create ();
1449 :
1450 0 : if (surface->compress_content) {
1451 0 : surface->group_stream.stream =
1452 0 : _cairo_deflate_stream_create (surface->group_stream.mem_stream);
1453 : } else {
1454 0 : surface->group_stream.stream = surface->group_stream.mem_stream;
1455 : }
1456 0 : status = _cairo_output_stream_get_status (surface->group_stream.stream);
1457 :
1458 0 : surface->group_stream.old_output = surface->output;
1459 0 : surface->output = surface->group_stream.stream;
1460 0 : _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
1461 0 : _cairo_pdf_group_resources_clear (&surface->resources);
1462 :
1463 0 : if (resource) {
1464 0 : surface->group_stream.resource = *resource;
1465 : } else {
1466 0 : surface->group_stream.resource = _cairo_pdf_surface_new_object (surface);
1467 0 : if (surface->group_stream.resource.id == 0)
1468 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1469 : }
1470 0 : surface->group_stream.is_knockout = FALSE;
1471 :
1472 0 : return status;
1473 : }
1474 :
1475 : static cairo_status_t
1476 0 : _cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t *surface)
1477 : {
1478 : cairo_status_t status;
1479 :
1480 0 : status = _cairo_pdf_surface_open_group (surface, NULL);
1481 0 : if (unlikely (status))
1482 0 : return status;
1483 :
1484 0 : surface->group_stream.is_knockout = TRUE;
1485 :
1486 0 : return CAIRO_STATUS_SUCCESS;
1487 : }
1488 :
1489 : static cairo_status_t
1490 0 : _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
1491 : cairo_pdf_resource_t *group)
1492 : {
1493 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS, status2;
1494 :
1495 0 : assert (surface->pdf_stream.active == FALSE);
1496 0 : assert (surface->group_stream.active == TRUE);
1497 :
1498 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
1499 0 : if (unlikely (status))
1500 0 : return status;
1501 :
1502 0 : if (surface->compress_content) {
1503 0 : status = _cairo_output_stream_destroy (surface->group_stream.stream);
1504 0 : surface->group_stream.stream = NULL;
1505 :
1506 0 : _cairo_output_stream_printf (surface->group_stream.mem_stream,
1507 : "\n");
1508 : }
1509 0 : surface->output = surface->group_stream.old_output;
1510 0 : _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
1511 0 : surface->group_stream.active = FALSE;
1512 0 : _cairo_pdf_surface_write_memory_stream (surface,
1513 : surface->group_stream.mem_stream,
1514 : surface->group_stream.resource,
1515 : &surface->resources,
1516 : surface->group_stream.is_knockout);
1517 0 : if (group)
1518 0 : *group = surface->group_stream.resource;
1519 :
1520 0 : status2 = _cairo_output_stream_destroy (surface->group_stream.mem_stream);
1521 0 : if (status == CAIRO_STATUS_SUCCESS)
1522 0 : status = status2;
1523 :
1524 0 : surface->group_stream.mem_stream = NULL;
1525 0 : surface->group_stream.stream = NULL;
1526 :
1527 0 : return status;
1528 : }
1529 :
1530 : static cairo_status_t
1531 0 : _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface,
1532 : cairo_pdf_resource_t *resource,
1533 : cairo_bool_t is_form)
1534 : {
1535 : cairo_status_t status;
1536 :
1537 0 : assert (surface->pdf_stream.active == FALSE);
1538 0 : assert (surface->group_stream.active == FALSE);
1539 :
1540 0 : surface->content_resources = _cairo_pdf_surface_new_object (surface);
1541 0 : if (surface->content_resources.id == 0)
1542 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1543 :
1544 0 : if (is_form) {
1545 0 : status =
1546 0 : _cairo_pdf_surface_open_stream (surface,
1547 : resource,
1548 : surface->compress_content,
1549 : " /Type /XObject\n"
1550 : " /Subtype /Form\n"
1551 : " /BBox [ 0 0 %f %f ]\n"
1552 : " /Group <<\n"
1553 : " /Type /Group\n"
1554 : " /S /Transparency\n"
1555 : " /CS /DeviceRGB\n"
1556 : " >>\n"
1557 : " /Resources %d 0 R\n",
1558 : surface->width,
1559 : surface->height,
1560 : surface->content_resources.id);
1561 : } else {
1562 0 : status =
1563 0 : _cairo_pdf_surface_open_stream (surface,
1564 : resource,
1565 : surface->compress_content,
1566 : NULL);
1567 : }
1568 0 : if (unlikely (status))
1569 0 : return status;
1570 :
1571 0 : surface->content = surface->pdf_stream.self;
1572 :
1573 0 : _cairo_output_stream_printf (surface->output, "q\n");
1574 :
1575 0 : return _cairo_output_stream_get_status (surface->output);
1576 : }
1577 :
1578 : static cairo_status_t
1579 0 : _cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface)
1580 : {
1581 : cairo_status_t status;
1582 :
1583 0 : assert (surface->pdf_stream.active == TRUE);
1584 0 : assert (surface->group_stream.active == FALSE);
1585 :
1586 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
1587 0 : if (unlikely (status))
1588 0 : return status;
1589 :
1590 0 : _cairo_output_stream_printf (surface->output, "Q\n");
1591 0 : status = _cairo_pdf_surface_close_stream (surface);
1592 0 : if (unlikely (status))
1593 0 : return status;
1594 :
1595 0 : _cairo_pdf_surface_update_object (surface, surface->content_resources);
1596 0 : _cairo_output_stream_printf (surface->output,
1597 : "%d 0 obj\n",
1598 : surface->content_resources.id);
1599 0 : _cairo_pdf_surface_emit_group_resources (surface, &surface->resources);
1600 0 : _cairo_output_stream_printf (surface->output,
1601 : "endobj\n");
1602 :
1603 0 : return _cairo_output_stream_get_status (surface->output);
1604 : }
1605 :
1606 : static void
1607 0 : _cairo_pdf_source_surface_entry_pluck (void *entry, void *closure)
1608 : {
1609 0 : cairo_pdf_source_surface_entry_t *surface_entry = entry;
1610 0 : cairo_hash_table_t *patterns = closure;
1611 :
1612 0 : _cairo_hash_table_remove (patterns, &surface_entry->base);
1613 0 : free (surface_entry);
1614 0 : }
1615 :
1616 : static cairo_status_t
1617 0 : _cairo_pdf_surface_finish (void *abstract_surface)
1618 : {
1619 0 : cairo_pdf_surface_t *surface = abstract_surface;
1620 : long offset;
1621 : cairo_pdf_resource_t info, catalog;
1622 : cairo_status_t status, status2;
1623 :
1624 0 : status = surface->base.status;
1625 0 : if (status == CAIRO_STATUS_SUCCESS)
1626 0 : status = _cairo_pdf_surface_emit_font_subsets (surface);
1627 :
1628 0 : _cairo_pdf_surface_write_pages (surface);
1629 :
1630 0 : info = _cairo_pdf_surface_write_info (surface);
1631 0 : if (info.id == 0 && status == CAIRO_STATUS_SUCCESS)
1632 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1633 :
1634 0 : catalog = _cairo_pdf_surface_write_catalog (surface);
1635 0 : if (catalog.id == 0 && status == CAIRO_STATUS_SUCCESS)
1636 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1637 :
1638 0 : offset = _cairo_pdf_surface_write_xref (surface);
1639 :
1640 0 : _cairo_output_stream_printf (surface->output,
1641 : "trailer\n"
1642 : "<< /Size %d\n"
1643 : " /Root %d 0 R\n"
1644 : " /Info %d 0 R\n"
1645 : ">>\n",
1646 : surface->next_available_resource.id,
1647 : catalog.id,
1648 : info.id);
1649 :
1650 0 : _cairo_output_stream_printf (surface->output,
1651 : "startxref\n"
1652 : "%ld\n"
1653 : "%%%%EOF\n",
1654 : offset);
1655 :
1656 : /* pdf_operators has already been flushed when the last stream was
1657 : * closed so we should never be writing anything here - however,
1658 : * the stream may itself be in an error state. */
1659 0 : status2 = _cairo_pdf_operators_fini (&surface->pdf_operators);
1660 0 : if (status == CAIRO_STATUS_SUCCESS)
1661 0 : status = status2;
1662 :
1663 : /* close any active streams still open due to fatal errors */
1664 0 : status2 = _cairo_pdf_surface_close_stream (surface);
1665 0 : if (status == CAIRO_STATUS_SUCCESS)
1666 0 : status = status2;
1667 :
1668 0 : if (surface->group_stream.stream != NULL) {
1669 0 : status2 = _cairo_output_stream_destroy (surface->group_stream.stream);
1670 0 : if (status == CAIRO_STATUS_SUCCESS)
1671 0 : status = status2;
1672 : }
1673 0 : if (surface->group_stream.mem_stream != NULL) {
1674 0 : status2 = _cairo_output_stream_destroy (surface->group_stream.mem_stream);
1675 0 : if (status == CAIRO_STATUS_SUCCESS)
1676 0 : status = status2;
1677 : }
1678 0 : if (surface->pdf_stream.active)
1679 0 : surface->output = surface->pdf_stream.old_output;
1680 0 : if (surface->group_stream.active)
1681 0 : surface->output = surface->group_stream.old_output;
1682 :
1683 : /* and finish the pdf surface */
1684 0 : status2 = _cairo_output_stream_destroy (surface->output);
1685 0 : if (status == CAIRO_STATUS_SUCCESS)
1686 0 : status = status2;
1687 :
1688 0 : _cairo_pdf_surface_clear (surface);
1689 0 : _cairo_pdf_group_resources_fini (&surface->resources);
1690 :
1691 0 : _cairo_array_fini (&surface->objects);
1692 0 : _cairo_array_fini (&surface->pages);
1693 0 : _cairo_array_fini (&surface->rgb_linear_functions);
1694 0 : _cairo_array_fini (&surface->alpha_linear_functions);
1695 0 : _cairo_array_fini (&surface->page_patterns);
1696 0 : _cairo_array_fini (&surface->page_surfaces);
1697 0 : _cairo_hash_table_foreach (surface->all_surfaces,
1698 : _cairo_pdf_source_surface_entry_pluck,
1699 0 : surface->all_surfaces);
1700 0 : _cairo_hash_table_destroy (surface->all_surfaces);
1701 0 : _cairo_array_fini (&surface->smask_groups);
1702 0 : _cairo_array_fini (&surface->fonts);
1703 0 : _cairo_array_fini (&surface->knockout_group);
1704 :
1705 0 : if (surface->font_subsets) {
1706 0 : _cairo_scaled_font_subsets_destroy (surface->font_subsets);
1707 0 : surface->font_subsets = NULL;
1708 : }
1709 :
1710 0 : _cairo_surface_clipper_reset (&surface->clipper);
1711 :
1712 0 : return status;
1713 : }
1714 :
1715 : static cairo_int_status_t
1716 0 : _cairo_pdf_surface_start_page (void *abstract_surface)
1717 : {
1718 0 : cairo_pdf_surface_t *surface = abstract_surface;
1719 :
1720 : /* Document header */
1721 0 : if (! surface->header_emitted) {
1722 : const char *version;
1723 :
1724 0 : switch (surface->pdf_version) {
1725 : case CAIRO_PDF_VERSION_1_4:
1726 0 : version = "1.4";
1727 0 : break;
1728 : default:
1729 : case CAIRO_PDF_VERSION_1_5:
1730 0 : version = "1.5";
1731 0 : break;
1732 : }
1733 :
1734 0 : _cairo_output_stream_printf (surface->output,
1735 : "%%PDF-%s\n", version);
1736 0 : _cairo_output_stream_printf (surface->output,
1737 : "%%%c%c%c%c\n", 181, 237, 174, 251);
1738 0 : surface->header_emitted = TRUE;
1739 : }
1740 :
1741 0 : _cairo_pdf_group_resources_clear (&surface->resources);
1742 :
1743 0 : return CAIRO_STATUS_SUCCESS;
1744 : }
1745 :
1746 : static cairo_int_status_t
1747 0 : _cairo_pdf_surface_has_fallback_images (void *abstract_surface,
1748 : cairo_bool_t has_fallbacks)
1749 : {
1750 : cairo_status_t status;
1751 0 : cairo_pdf_surface_t *surface = abstract_surface;
1752 :
1753 0 : surface->has_fallback_images = has_fallbacks;
1754 0 : status = _cairo_pdf_surface_open_content_stream (surface, NULL, has_fallbacks);
1755 0 : if (unlikely (status))
1756 0 : return status;
1757 :
1758 0 : return CAIRO_STATUS_SUCCESS;
1759 : }
1760 :
1761 : static cairo_bool_t
1762 0 : _cairo_pdf_surface_supports_fine_grained_fallbacks (void *abstract_surface)
1763 : {
1764 0 : return TRUE;
1765 : }
1766 :
1767 : /* Emit alpha channel from the image into the given data, providing
1768 : * an id that can be used to reference the resulting SMask object.
1769 : *
1770 : * In the case that the alpha channel happens to be all opaque, then
1771 : * no SMask object will be emitted and *id_ret will be set to 0.
1772 : */
1773 : static cairo_status_t
1774 0 : _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface,
1775 : cairo_image_surface_t *image,
1776 : cairo_pdf_resource_t *stream_ret)
1777 : {
1778 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
1779 : char *alpha;
1780 : unsigned long alpha_size;
1781 : uint32_t *pixel32;
1782 : uint8_t *pixel8;
1783 : int i, x, y;
1784 : cairo_bool_t opaque;
1785 : uint8_t a;
1786 :
1787 : /* This is the only image format we support, which simplifies things. */
1788 0 : assert (image->format == CAIRO_FORMAT_ARGB32 ||
1789 : image->format == CAIRO_FORMAT_A8 ||
1790 : image->format == CAIRO_FORMAT_A1 );
1791 :
1792 0 : stream_ret->id = 0;
1793 :
1794 0 : if (image->format == CAIRO_FORMAT_A1) {
1795 0 : alpha_size = (image->width + 7) / 8 * image->height;
1796 0 : alpha = _cairo_malloc_ab ((image->width+7) / 8, image->height);
1797 : } else {
1798 0 : alpha_size = image->height * image->width;
1799 0 : alpha = _cairo_malloc_ab (image->height, image->width);
1800 : }
1801 :
1802 0 : if (unlikely (alpha == NULL)) {
1803 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1804 0 : goto CLEANUP;
1805 : }
1806 :
1807 0 : opaque = TRUE;
1808 0 : i = 0;
1809 0 : for (y = 0; y < image->height; y++) {
1810 0 : if (image->format == CAIRO_FORMAT_ARGB32) {
1811 0 : pixel32 = (uint32_t *) (image->data + y * image->stride);
1812 :
1813 0 : for (x = 0; x < image->width; x++, pixel32++) {
1814 0 : a = (*pixel32 & 0xff000000) >> 24;
1815 0 : alpha[i++] = a;
1816 0 : if (a != 0xff)
1817 0 : opaque = FALSE;
1818 : }
1819 0 : } else if (image->format == CAIRO_FORMAT_A8){
1820 0 : pixel8 = (uint8_t *) (image->data + y * image->stride);
1821 :
1822 0 : for (x = 0; x < image->width; x++, pixel8++) {
1823 0 : a = *pixel8;
1824 0 : alpha[i++] = a;
1825 0 : if (a != 0xff)
1826 0 : opaque = FALSE;
1827 : }
1828 : } else { /* image->format == CAIRO_FORMAT_A1 */
1829 0 : pixel8 = (uint8_t *) (image->data + y * image->stride);
1830 :
1831 0 : for (x = 0; x < (image->width + 7) / 8; x++, pixel8++) {
1832 0 : a = *pixel8;
1833 0 : a = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (a);
1834 0 : alpha[i++] = a;
1835 0 : if (a != 0xff)
1836 0 : opaque = FALSE;
1837 : }
1838 : }
1839 : }
1840 :
1841 : /* Bail out without emitting smask if it's all opaque. */
1842 0 : if (opaque)
1843 0 : goto CLEANUP_ALPHA;
1844 :
1845 0 : status = _cairo_pdf_surface_open_stream (surface,
1846 : NULL,
1847 : TRUE,
1848 : " /Type /XObject\n"
1849 : " /Subtype /Image\n"
1850 : " /Width %d\n"
1851 : " /Height %d\n"
1852 : " /ColorSpace /DeviceGray\n"
1853 : " /BitsPerComponent %d\n",
1854 : image->width, image->height,
1855 0 : image->format == CAIRO_FORMAT_A1 ? 1 : 8);
1856 0 : if (unlikely (status))
1857 0 : goto CLEANUP_ALPHA;
1858 :
1859 0 : *stream_ret = surface->pdf_stream.self;
1860 0 : _cairo_output_stream_write (surface->output, alpha, alpha_size);
1861 0 : status = _cairo_pdf_surface_close_stream (surface);
1862 :
1863 : CLEANUP_ALPHA:
1864 0 : free (alpha);
1865 : CLEANUP:
1866 0 : return status;
1867 : }
1868 :
1869 : /* Emit image data into the given surface, providing a resource that
1870 : * can be used to reference the data in image_ret. */
1871 : static cairo_status_t
1872 0 : _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
1873 : cairo_image_surface_t *image,
1874 : cairo_pdf_resource_t *image_res,
1875 : cairo_filter_t filter)
1876 : {
1877 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
1878 : char *rgb;
1879 : unsigned long rgb_size;
1880 : uint32_t *pixel;
1881 : int i, x, y;
1882 0 : cairo_pdf_resource_t smask = {0}; /* squelch bogus compiler warning */
1883 : cairo_bool_t need_smask;
1884 0 : const char *interpolate = "true";
1885 :
1886 : /* These are the only image formats we currently support, (which
1887 : * makes things a lot simpler here). This is enforced through
1888 : * _cairo_pdf_surface_analyze_operation which only accept source surfaces of
1889 : * CONTENT_COLOR or CONTENT_COLOR_ALPHA.
1890 : */
1891 0 : assert (image->format == CAIRO_FORMAT_RGB24 ||
1892 : image->format == CAIRO_FORMAT_ARGB32 ||
1893 : image->format == CAIRO_FORMAT_A8 ||
1894 : image->format == CAIRO_FORMAT_A1);
1895 :
1896 0 : rgb_size = image->height * image->width * 3;
1897 0 : rgb = _cairo_malloc_abc (image->width, image->height, 3);
1898 0 : if (unlikely (rgb == NULL)) {
1899 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1900 0 : goto CLEANUP;
1901 : }
1902 :
1903 0 : i = 0;
1904 0 : for (y = 0; y < image->height; y++) {
1905 0 : pixel = (uint32_t *) (image->data + y * image->stride);
1906 :
1907 0 : for (x = 0; x < image->width; x++, pixel++) {
1908 : /* XXX: We're un-premultiplying alpha here. My reading of the PDF
1909 : * specification suggests that we should be able to avoid having
1910 : * to do this by filling in the SMask's Matte dictionary
1911 : * appropriately, but my attempts to do that so far have
1912 : * failed. */
1913 0 : if (image->format == CAIRO_FORMAT_ARGB32) {
1914 : uint8_t a;
1915 0 : a = (*pixel & 0xff000000) >> 24;
1916 0 : if (a == 0) {
1917 0 : rgb[i++] = 0;
1918 0 : rgb[i++] = 0;
1919 0 : rgb[i++] = 0;
1920 : } else {
1921 0 : rgb[i++] = (((*pixel & 0xff0000) >> 16) * 255 + a / 2) / a;
1922 0 : rgb[i++] = (((*pixel & 0x00ff00) >> 8) * 255 + a / 2) / a;
1923 0 : rgb[i++] = (((*pixel & 0x0000ff) >> 0) * 255 + a / 2) / a;
1924 : }
1925 0 : } else if (image->format == CAIRO_FORMAT_RGB24) {
1926 0 : rgb[i++] = (*pixel & 0x00ff0000) >> 16;
1927 0 : rgb[i++] = (*pixel & 0x0000ff00) >> 8;
1928 0 : rgb[i++] = (*pixel & 0x000000ff) >> 0;
1929 : } else {
1930 0 : rgb[i++] = 0;
1931 0 : rgb[i++] = 0;
1932 0 : rgb[i++] = 0;
1933 : }
1934 : }
1935 : }
1936 :
1937 0 : need_smask = FALSE;
1938 0 : if (image->format == CAIRO_FORMAT_ARGB32 ||
1939 0 : image->format == CAIRO_FORMAT_A8 ||
1940 0 : image->format == CAIRO_FORMAT_A1) {
1941 0 : status = _cairo_pdf_surface_emit_smask (surface, image, &smask);
1942 0 : if (unlikely (status))
1943 0 : goto CLEANUP_RGB;
1944 :
1945 0 : if (smask.id)
1946 0 : need_smask = TRUE;
1947 : }
1948 :
1949 0 : switch (filter) {
1950 : case CAIRO_FILTER_GOOD:
1951 : case CAIRO_FILTER_BEST:
1952 : case CAIRO_FILTER_BILINEAR:
1953 0 : interpolate = "true";
1954 0 : break;
1955 : case CAIRO_FILTER_FAST:
1956 : case CAIRO_FILTER_NEAREST:
1957 : case CAIRO_FILTER_GAUSSIAN:
1958 0 : interpolate = "false";
1959 0 : break;
1960 : }
1961 :
1962 : #define IMAGE_DICTIONARY " /Type /XObject\n" \
1963 : " /Subtype /Image\n" \
1964 : " /Width %d\n" \
1965 : " /Height %d\n" \
1966 : " /ColorSpace /DeviceRGB\n" \
1967 : " /Interpolate %s\n" \
1968 : " /BitsPerComponent 8\n"
1969 :
1970 0 : if (need_smask)
1971 0 : status = _cairo_pdf_surface_open_stream (surface,
1972 : image_res,
1973 : TRUE,
1974 : IMAGE_DICTIONARY
1975 : " /SMask %d 0 R\n",
1976 : image->width, image->height,
1977 : interpolate,
1978 : smask.id);
1979 : else
1980 0 : status = _cairo_pdf_surface_open_stream (surface,
1981 : image_res,
1982 : TRUE,
1983 : IMAGE_DICTIONARY,
1984 : image->width, image->height,
1985 : interpolate);
1986 0 : if (unlikely (status))
1987 0 : goto CLEANUP_RGB;
1988 :
1989 : #undef IMAGE_DICTIONARY
1990 :
1991 0 : _cairo_output_stream_write (surface->output, rgb, rgb_size);
1992 0 : status = _cairo_pdf_surface_close_stream (surface);
1993 :
1994 : CLEANUP_RGB:
1995 0 : free (rgb);
1996 : CLEANUP:
1997 0 : return status;
1998 : }
1999 :
2000 : static cairo_int_status_t
2001 0 : _cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface,
2002 : cairo_surface_t *source,
2003 : cairo_pdf_resource_t res)
2004 : {
2005 : cairo_status_t status;
2006 : const unsigned char *mime_data;
2007 : unsigned long mime_data_length;
2008 : cairo_image_info_t info;
2009 :
2010 0 : if (surface->pdf_version < CAIRO_PDF_VERSION_1_5)
2011 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2012 :
2013 0 : cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JP2,
2014 : &mime_data, &mime_data_length);
2015 0 : if (mime_data == NULL)
2016 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2017 :
2018 0 : status = _cairo_image_info_get_jpx_info (&info, mime_data, mime_data_length);
2019 0 : if (status)
2020 0 : return status;
2021 :
2022 0 : status = _cairo_pdf_surface_open_stream (surface,
2023 : &res,
2024 : FALSE,
2025 : " /Type /XObject\n"
2026 : " /Subtype /Image\n"
2027 : " /Width %d\n"
2028 : " /Height %d\n"
2029 : " /Filter /JPXDecode\n",
2030 : info.width,
2031 : info.height);
2032 0 : if (status)
2033 0 : return status;
2034 :
2035 0 : _cairo_output_stream_write (surface->output, mime_data, mime_data_length);
2036 0 : status = _cairo_pdf_surface_close_stream (surface);
2037 :
2038 0 : return status;
2039 : }
2040 :
2041 : static cairo_int_status_t
2042 0 : _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface,
2043 : cairo_surface_t *source,
2044 : cairo_pdf_resource_t res)
2045 : {
2046 : cairo_status_t status;
2047 : const unsigned char *mime_data;
2048 : unsigned long mime_data_length;
2049 : cairo_image_info_t info;
2050 :
2051 0 : cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
2052 : &mime_data, &mime_data_length);
2053 0 : if (unlikely (source->status))
2054 0 : return source->status;
2055 0 : if (mime_data == NULL)
2056 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2057 :
2058 0 : status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length);
2059 0 : if (unlikely (status))
2060 0 : return status;
2061 :
2062 0 : if (info.num_components != 1 && info.num_components != 3)
2063 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2064 :
2065 0 : status = _cairo_pdf_surface_open_stream (surface,
2066 : &res,
2067 : FALSE,
2068 : " /Type /XObject\n"
2069 : " /Subtype /Image\n"
2070 : " /Width %d\n"
2071 : " /Height %d\n"
2072 : " /ColorSpace %s\n"
2073 : " /BitsPerComponent %d\n"
2074 : " /Filter /DCTDecode\n",
2075 : info.width,
2076 : info.height,
2077 0 : info.num_components == 1 ? "/DeviceGray" : "/DeviceRGB",
2078 : info.bits_per_component);
2079 0 : if (unlikely (status))
2080 0 : return status;
2081 :
2082 0 : _cairo_output_stream_write (surface->output, mime_data, mime_data_length);
2083 0 : status = _cairo_pdf_surface_close_stream (surface);
2084 :
2085 0 : return status;
2086 : }
2087 :
2088 : static cairo_status_t
2089 0 : _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface,
2090 : cairo_surface_t *source,
2091 : cairo_pdf_resource_t resource,
2092 : cairo_bool_t interpolate)
2093 : {
2094 : cairo_image_surface_t *image;
2095 : void *image_extra;
2096 : cairo_status_t status;
2097 :
2098 0 : status = _cairo_pdf_surface_emit_jpx_image (surface, source, resource);
2099 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2100 0 : return status;
2101 :
2102 0 : status = _cairo_pdf_surface_emit_jpeg_image (surface, source, resource);
2103 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2104 0 : return status;
2105 :
2106 0 : status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
2107 0 : if (unlikely (status))
2108 0 : return status;
2109 :
2110 0 : status = _cairo_pdf_surface_emit_image (surface, image,
2111 : &resource, interpolate);
2112 0 : if (unlikely (status))
2113 0 : goto BAIL;
2114 :
2115 : BAIL:
2116 0 : _cairo_surface_release_source_image (source, image, image_extra);
2117 :
2118 0 : return status;
2119 : }
2120 :
2121 : static cairo_status_t
2122 0 : _cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t *surface,
2123 : cairo_pdf_pattern_t *pdf_pattern,
2124 : cairo_pdf_resource_t *resource,
2125 : int *width,
2126 : int *height,
2127 : int *origin_x,
2128 : int *origin_y)
2129 : {
2130 : cairo_image_surface_t *image;
2131 : cairo_surface_t *pad_image;
2132 : void *image_extra;
2133 : cairo_status_t status;
2134 0 : cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern;
2135 0 : int x = 0;
2136 0 : int y = 0;
2137 : cairo_bool_t interpolate;
2138 :
2139 0 : status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
2140 0 : if (unlikely (status))
2141 0 : return status;
2142 :
2143 0 : pad_image = &image->base;
2144 0 : if (pattern->base.extend == CAIRO_EXTEND_PAD) {
2145 : cairo_box_t box;
2146 : cairo_rectangle_int_t rect;
2147 : cairo_surface_pattern_t pad_pattern;
2148 :
2149 : /* get the operation extents in pattern space */
2150 0 : _cairo_box_from_rectangle (&box, &pdf_pattern->extents);
2151 0 : _cairo_matrix_transform_bounding_box_fixed (&pattern->base.matrix, &box, NULL);
2152 0 : _cairo_box_round_to_rectangle (&box, &rect);
2153 0 : x = -rect.x;
2154 0 : y = -rect.y;
2155 :
2156 0 : pad_image = _cairo_image_surface_create_with_content (pattern->surface->content,
2157 : rect.width,
2158 : rect.height);
2159 0 : if (pad_image->status) {
2160 0 : status = pad_image->status;
2161 0 : goto BAIL;
2162 : }
2163 :
2164 0 : _cairo_pattern_init_for_surface (&pad_pattern, &image->base);
2165 0 : cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y);
2166 0 : pad_pattern.base.extend = CAIRO_EXTEND_PAD;
2167 0 : status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
2168 : &pad_pattern.base,
2169 : NULL,
2170 : pad_image,
2171 : 0, 0,
2172 : 0, 0,
2173 : 0, 0,
2174 0 : rect.width,
2175 0 : rect.height,
2176 : NULL);
2177 0 : _cairo_pattern_fini (&pad_pattern.base);
2178 0 : if (unlikely (status))
2179 0 : goto BAIL;
2180 : }
2181 :
2182 0 : switch (pdf_pattern->pattern->filter) {
2183 : case CAIRO_FILTER_GOOD:
2184 : case CAIRO_FILTER_BEST:
2185 : case CAIRO_FILTER_BILINEAR:
2186 0 : interpolate = TRUE;
2187 0 : break;
2188 : case CAIRO_FILTER_FAST:
2189 : case CAIRO_FILTER_NEAREST:
2190 : case CAIRO_FILTER_GAUSSIAN:
2191 0 : interpolate = FALSE;
2192 0 : break;
2193 : }
2194 :
2195 0 : *resource = _cairo_pdf_surface_new_object (surface);
2196 0 : if (resource->id == 0) {
2197 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2198 0 : goto BAIL;
2199 : }
2200 :
2201 0 : status = _cairo_pdf_surface_emit_image (surface, (cairo_image_surface_t *)pad_image,
2202 : resource, interpolate);
2203 0 : if (unlikely (status))
2204 0 : goto BAIL;
2205 :
2206 0 : *width = ((cairo_image_surface_t *)pad_image)->width;
2207 0 : *height = ((cairo_image_surface_t *)pad_image)->height;
2208 0 : *origin_x = x;
2209 0 : *origin_y = y;
2210 :
2211 : BAIL:
2212 0 : if (pad_image != &image->base)
2213 0 : cairo_surface_destroy (pad_image);
2214 :
2215 0 : _cairo_surface_release_source_image (pattern->surface, image, image_extra);
2216 :
2217 0 : return status;
2218 : }
2219 :
2220 :
2221 : static cairo_status_t
2222 0 : _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
2223 : cairo_surface_t *recording_surface,
2224 : cairo_pdf_resource_t resource)
2225 : {
2226 : double old_width, old_height;
2227 : cairo_paginated_mode_t old_paginated_mode;
2228 : cairo_rectangle_int_t recording_extents;
2229 : cairo_bool_t is_bounded;
2230 : cairo_status_t status;
2231 0 : int alpha = 0;
2232 :
2233 0 : is_bounded = _cairo_surface_get_extents (recording_surface, &recording_extents);
2234 0 : assert (is_bounded);
2235 :
2236 0 : old_width = surface->width;
2237 0 : old_height = surface->height;
2238 0 : old_paginated_mode = surface->paginated_mode;
2239 :
2240 0 : _cairo_pdf_surface_set_size_internal (surface,
2241 0 : recording_extents.width,
2242 0 : recording_extents.height);
2243 : /* Patterns are emitted after fallback images. The paginated mode
2244 : * needs to be set to _RENDER while the recording surface is replayed
2245 : * back to this surface.
2246 : */
2247 0 : surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER;
2248 0 : _cairo_pdf_group_resources_clear (&surface->resources);
2249 0 : status = _cairo_pdf_surface_open_content_stream (surface, &resource, TRUE);
2250 0 : if (unlikely (status))
2251 0 : return status;
2252 :
2253 0 : if (cairo_surface_get_content (recording_surface) == CAIRO_CONTENT_COLOR) {
2254 0 : status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
2255 0 : if (unlikely (status))
2256 0 : return status;
2257 :
2258 0 : _cairo_output_stream_printf (surface->output,
2259 : "q /a%d gs 0 0 0 rg 0 0 %f %f re f Q\n",
2260 : alpha,
2261 : surface->width,
2262 : surface->height);
2263 : }
2264 :
2265 0 : status = _cairo_recording_surface_replay_region (recording_surface,
2266 : NULL,
2267 : &surface->base,
2268 : CAIRO_RECORDING_REGION_NATIVE);
2269 0 : assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
2270 0 : if (unlikely (status))
2271 0 : return status;
2272 :
2273 0 : status = _cairo_pdf_surface_close_content_stream (surface);
2274 :
2275 0 : _cairo_pdf_surface_set_size_internal (surface,
2276 : old_width,
2277 : old_height);
2278 0 : surface->paginated_mode = old_paginated_mode;
2279 :
2280 0 : return status;
2281 : }
2282 :
2283 : static cairo_status_t
2284 0 : _cairo_pdf_surface_emit_recording_subsurface (cairo_pdf_surface_t *surface,
2285 : cairo_surface_t *recording_surface,
2286 : const cairo_rectangle_int_t *extents,
2287 : cairo_pdf_resource_t resource)
2288 : {
2289 : double old_width, old_height;
2290 : cairo_paginated_mode_t old_paginated_mode;
2291 : cairo_status_t status;
2292 0 : int alpha = 0;
2293 :
2294 0 : old_width = surface->width;
2295 0 : old_height = surface->height;
2296 0 : old_paginated_mode = surface->paginated_mode;
2297 :
2298 0 : _cairo_pdf_surface_set_size_internal (surface,
2299 0 : extents->width,
2300 0 : extents->height);
2301 : /* Patterns are emitted after fallback images. The paginated mode
2302 : * needs to be set to _RENDER while the recording surface is replayed
2303 : * back to this surface.
2304 : */
2305 0 : surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER;
2306 0 : _cairo_pdf_group_resources_clear (&surface->resources);
2307 0 : status = _cairo_pdf_surface_open_content_stream (surface, &resource, TRUE);
2308 0 : if (unlikely (status))
2309 0 : return status;
2310 :
2311 0 : if (cairo_surface_get_content (recording_surface) == CAIRO_CONTENT_COLOR) {
2312 0 : status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
2313 0 : if (unlikely (status))
2314 0 : return status;
2315 :
2316 0 : _cairo_output_stream_printf (surface->output,
2317 : "q /a%d gs 0 0 0 rg 0 0 %f %f re f Q\n",
2318 : alpha,
2319 : surface->width,
2320 : surface->height);
2321 : }
2322 :
2323 0 : status = _cairo_recording_surface_replay_region (recording_surface,
2324 : extents,
2325 : &surface->base,
2326 : CAIRO_RECORDING_REGION_NATIVE);
2327 0 : assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
2328 0 : if (unlikely (status))
2329 0 : return status;
2330 :
2331 0 : status = _cairo_pdf_surface_close_content_stream (surface);
2332 :
2333 0 : _cairo_pdf_surface_set_size_internal (surface,
2334 : old_width,
2335 : old_height);
2336 0 : surface->paginated_mode = old_paginated_mode;
2337 :
2338 0 : return status;
2339 : }
2340 :
2341 : static cairo_status_t
2342 0 : _cairo_pdf_surface_emit_surface (cairo_pdf_surface_t *surface,
2343 : cairo_pdf_source_surface_t *src_surface)
2344 : {
2345 0 : if (src_surface->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
2346 0 : if (src_surface->surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
2347 0 : cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) src_surface->surface;
2348 0 : return _cairo_pdf_surface_emit_recording_subsurface (surface,
2349 : sub->target,
2350 0 : &sub->extents,
2351 0 : src_surface->hash_entry->surface_res);
2352 : } else {
2353 0 : return _cairo_pdf_surface_emit_recording_surface (surface,
2354 : src_surface->surface,
2355 0 : src_surface->hash_entry->surface_res);
2356 : }
2357 : } else {
2358 0 : return _cairo_pdf_surface_emit_image_surface (surface,
2359 : src_surface->surface,
2360 0 : src_surface->hash_entry->surface_res,
2361 0 : src_surface->hash_entry->interpolate);
2362 : }
2363 : }
2364 :
2365 : static cairo_status_t
2366 0 : _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
2367 : cairo_pdf_pattern_t *pdf_pattern)
2368 : {
2369 0 : cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern;
2370 : cairo_status_t status;
2371 0 : cairo_pdf_resource_t pattern_resource = {0};
2372 : cairo_matrix_t cairo_p2d, pdf_p2d;
2373 0 : cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base);
2374 : double xstep, ystep;
2375 0 : int pattern_width = 0; /* squelch bogus compiler warning */
2376 0 : int pattern_height = 0; /* squelch bogus compiler warning */
2377 0 : int origin_x = 0; /* squelch bogus compiler warning */
2378 0 : int origin_y = 0; /* squelch bogus compiler warning */
2379 : int bbox_x, bbox_y;
2380 : char draw_surface[200];
2381 :
2382 0 : if (pattern->base.extend == CAIRO_EXTEND_PAD &&
2383 0 : pattern->surface->type != CAIRO_SURFACE_TYPE_RECORDING)
2384 : {
2385 0 : status = _cairo_pdf_surface_emit_padded_image_surface (surface,
2386 : pdf_pattern,
2387 : &pattern_resource,
2388 : &pattern_width,
2389 : &pattern_height,
2390 : &origin_x,
2391 : &origin_y);
2392 : }
2393 : else
2394 : {
2395 0 : status = _cairo_pdf_surface_add_source_surface (surface,
2396 : pattern->surface,
2397 0 : pdf_pattern->pattern->filter,
2398 : &pattern_resource,
2399 : &pattern_width,
2400 : &pattern_height);
2401 : }
2402 0 : if (unlikely (status))
2403 0 : return status;
2404 :
2405 0 : bbox_x = pattern_width;
2406 0 : bbox_y = pattern_height;
2407 0 : switch (extend) {
2408 : case CAIRO_EXTEND_PAD:
2409 : case CAIRO_EXTEND_NONE:
2410 : {
2411 : /* In PS/PDF, (as far as I can tell), all patterns are
2412 : * repeating. So we support cairo's EXTEND_NONE semantics
2413 : * by setting the repeat step size to a size large enough
2414 : * to guarantee that no more than a single occurrence will
2415 : * be visible.
2416 : *
2417 : * First, map the surface extents into pattern space (since
2418 : * xstep and ystep are in pattern space). Then use an upper
2419 : * bound on the length of the diagonal of the pattern image
2420 : * and the surface as repeat size. This guarantees to never
2421 : * repeat visibly.
2422 : */
2423 0 : double x1 = 0.0, y1 = 0.0;
2424 0 : double x2 = surface->width, y2 = surface->height;
2425 0 : _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
2426 : &x1, &y1, &x2, &y2,
2427 : NULL);
2428 :
2429 : /* Rather than computing precise bounds of the union, just
2430 : * add the surface extents unconditionally. We only
2431 : * required an answer that's large enough, we don't really
2432 : * care if it's not as tight as possible.*/
2433 0 : xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
2434 : pattern_width + pattern_height);
2435 : }
2436 0 : break;
2437 : case CAIRO_EXTEND_REPEAT:
2438 0 : xstep = pattern_width;
2439 0 : ystep = pattern_height;
2440 0 : break;
2441 : case CAIRO_EXTEND_REFLECT:
2442 0 : bbox_x = pattern_width*2;
2443 0 : bbox_y = pattern_height*2;
2444 0 : xstep = bbox_x;
2445 0 : ystep = bbox_y;
2446 0 : break;
2447 : /* All the rest (if any) should have been analyzed away, so this
2448 : * case should be unreachable. */
2449 : default:
2450 0 : ASSERT_NOT_REACHED;
2451 0 : xstep = 0;
2452 0 : ystep = 0;
2453 : }
2454 :
2455 : /* At this point, (that is, within the surface backend interface),
2456 : * the pattern's matrix maps from cairo's device space to cairo's
2457 : * pattern space, (both with their origin at the upper-left, and
2458 : * cairo's pattern space of size width,height).
2459 : *
2460 : * Then, we must emit a PDF pattern object that maps from its own
2461 : * pattern space, (which has a size that we establish in the BBox
2462 : * dictionary entry), to the PDF page's *initial* space, (which
2463 : * does not benefit from the Y-axis flipping matrix that we emit
2464 : * on each page). So the PDF patterns matrix maps from a
2465 : * (width,height) pattern space to a device space with the origin
2466 : * in the lower-left corner.
2467 : *
2468 : * So to handle all of that, we start with an identity matrix for
2469 : * the PDF pattern to device matrix. We translate it up by the
2470 : * image height then flip it in the Y direction, (moving us from
2471 : * the PDF origin to cairo's origin). We then multiply in the
2472 : * inverse of the cairo pattern matrix, (since it maps from device
2473 : * to pattern, while we're setting up pattern to device). Finally,
2474 : * we translate back down by the image height and flip again to
2475 : * end up at the lower-left origin that PDF expects.
2476 : *
2477 : * Additionally, within the stream that paints the pattern itself,
2478 : * we are using a PDF image object that has a size of (1,1) so we
2479 : * have to scale it up by the image width and height to fill our
2480 : * pattern cell.
2481 : */
2482 0 : cairo_p2d = pattern->base.matrix;
2483 0 : status = cairo_matrix_invert (&cairo_p2d);
2484 : /* cairo_pattern_set_matrix ensures the matrix is invertible */
2485 0 : assert (status == CAIRO_STATUS_SUCCESS);
2486 :
2487 0 : cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &surface->cairo_to_pdf);
2488 0 : cairo_matrix_translate (&pdf_p2d, -origin_x, -origin_y);
2489 0 : cairo_matrix_translate (&pdf_p2d, 0.0, pattern_height);
2490 0 : cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
2491 :
2492 0 : _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
2493 0 : status = _cairo_pdf_surface_open_stream (surface,
2494 : &pdf_pattern->pattern_res,
2495 : FALSE,
2496 : " /PatternType 1\n"
2497 : " /BBox [0 0 %d %d]\n"
2498 : " /XStep %f\n"
2499 : " /YStep %f\n"
2500 : " /TilingType 1\n"
2501 : " /PaintType 1\n"
2502 : " /Matrix [ %f %f %f %f %f %f ]\n"
2503 : " /Resources << /XObject << /x%d %d 0 R >> >>\n",
2504 : bbox_x, bbox_y,
2505 : xstep, ystep,
2506 : pdf_p2d.xx, pdf_p2d.yx,
2507 : pdf_p2d.xy, pdf_p2d.yy,
2508 : pdf_p2d.x0, pdf_p2d.y0,
2509 : pattern_resource.id,
2510 : pattern_resource.id);
2511 0 : if (unlikely (status))
2512 0 : return status;
2513 :
2514 0 : if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
2515 0 : snprintf(draw_surface,
2516 : sizeof (draw_surface),
2517 : "/x%d Do\n",
2518 : pattern_resource.id);
2519 : } else {
2520 0 : snprintf(draw_surface,
2521 : sizeof (draw_surface),
2522 : "q %d 0 0 %d 0 0 cm /x%d Do Q",
2523 : pattern_width,
2524 : pattern_height,
2525 : pattern_resource.id);
2526 : }
2527 :
2528 0 : if (extend == CAIRO_EXTEND_REFLECT) {
2529 0 : _cairo_output_stream_printf (surface->output,
2530 : "q 0 0 %d %d re W n %s Q\n"
2531 : "q -1 0 0 1 %d 0 cm 0 0 %d %d re W n %s Q\n"
2532 : "q 1 0 0 -1 0 %d cm 0 0 %d %d re W n %s Q\n"
2533 : "q -1 0 0 -1 %d %d cm 0 0 %d %d re W n %s Q\n",
2534 : pattern_width, pattern_height,
2535 : draw_surface,
2536 : pattern_width*2, pattern_width, pattern_height,
2537 : draw_surface,
2538 : pattern_height*2, pattern_width, pattern_height,
2539 : draw_surface,
2540 : pattern_width*2, pattern_height*2, pattern_width, pattern_height,
2541 : draw_surface);
2542 : } else {
2543 0 : _cairo_output_stream_printf (surface->output,
2544 : " %s \n",
2545 : draw_surface);
2546 : }
2547 :
2548 0 : status = _cairo_pdf_surface_close_stream (surface);
2549 0 : if (unlikely (status))
2550 0 : return status;
2551 :
2552 0 : return _cairo_output_stream_get_status (surface->output);
2553 : }
2554 :
2555 : typedef struct _cairo_pdf_color_stop {
2556 : double offset;
2557 : double color[4];
2558 : cairo_pdf_resource_t resource;
2559 : } cairo_pdf_color_stop_t;
2560 :
2561 : static cairo_status_t
2562 0 : cairo_pdf_surface_emit_rgb_linear_function (cairo_pdf_surface_t *surface,
2563 : cairo_pdf_color_stop_t *stop1,
2564 : cairo_pdf_color_stop_t *stop2,
2565 : cairo_pdf_resource_t *function)
2566 : {
2567 : int num_elems, i;
2568 : cairo_pdf_rgb_linear_function_t elem;
2569 : cairo_pdf_resource_t res;
2570 : cairo_status_t status;
2571 :
2572 0 : num_elems = _cairo_array_num_elements (&surface->rgb_linear_functions);
2573 0 : for (i = 0; i < num_elems; i++) {
2574 0 : _cairo_array_copy_element (&surface->rgb_linear_functions, i, &elem);
2575 0 : if (memcmp (&elem.color1[0], &stop1->color[0], sizeof (double)*3) != 0)
2576 0 : continue;
2577 0 : if (memcmp (&elem.color2[0], &stop2->color[0], sizeof (double)*3) != 0)
2578 0 : continue;
2579 0 : *function = elem.resource;
2580 0 : return CAIRO_STATUS_SUCCESS;
2581 : }
2582 :
2583 0 : res = _cairo_pdf_surface_new_object (surface);
2584 0 : if (res.id == 0)
2585 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2586 :
2587 0 : _cairo_output_stream_printf (surface->output,
2588 : "%d 0 obj\n"
2589 : "<< /FunctionType 2\n"
2590 : " /Domain [ 0 1 ]\n"
2591 : " /C0 [ %f %f %f ]\n"
2592 : " /C1 [ %f %f %f ]\n"
2593 : " /N 1\n"
2594 : ">>\n"
2595 : "endobj\n",
2596 : res.id,
2597 : stop1->color[0],
2598 : stop1->color[1],
2599 : stop1->color[2],
2600 : stop2->color[0],
2601 : stop2->color[1],
2602 : stop2->color[2]);
2603 :
2604 0 : elem.resource = res;
2605 0 : memcpy (&elem.color1[0], &stop1->color[0], sizeof (double)*3);
2606 0 : memcpy (&elem.color2[0], &stop2->color[0], sizeof (double)*3);
2607 :
2608 0 : status = _cairo_array_append (&surface->rgb_linear_functions, &elem);
2609 0 : *function = res;
2610 :
2611 0 : return status;
2612 : }
2613 :
2614 : static cairo_status_t
2615 0 : cairo_pdf_surface_emit_alpha_linear_function (cairo_pdf_surface_t *surface,
2616 : cairo_pdf_color_stop_t *stop1,
2617 : cairo_pdf_color_stop_t *stop2,
2618 : cairo_pdf_resource_t *function)
2619 : {
2620 : int num_elems, i;
2621 : cairo_pdf_alpha_linear_function_t elem;
2622 : cairo_pdf_resource_t res;
2623 : cairo_status_t status;
2624 :
2625 0 : num_elems = _cairo_array_num_elements (&surface->alpha_linear_functions);
2626 0 : for (i = 0; i < num_elems; i++) {
2627 0 : _cairo_array_copy_element (&surface->alpha_linear_functions, i, &elem);
2628 0 : if (elem.alpha1 != stop1->color[3])
2629 0 : continue;
2630 0 : if (elem.alpha2 != stop2->color[3])
2631 0 : continue;
2632 0 : *function = elem.resource;
2633 0 : return CAIRO_STATUS_SUCCESS;
2634 : }
2635 :
2636 0 : res = _cairo_pdf_surface_new_object (surface);
2637 0 : if (res.id == 0)
2638 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2639 :
2640 0 : _cairo_output_stream_printf (surface->output,
2641 : "%d 0 obj\n"
2642 : "<< /FunctionType 2\n"
2643 : " /Domain [ 0 1 ]\n"
2644 : " /C0 [ %f ]\n"
2645 : " /C1 [ %f ]\n"
2646 : " /N 1\n"
2647 : ">>\n"
2648 : "endobj\n",
2649 : res.id,
2650 : stop1->color[3],
2651 : stop2->color[3]);
2652 :
2653 0 : elem.resource = res;
2654 0 : elem.alpha1 = stop1->color[3];
2655 0 : elem.alpha2 = stop2->color[3];
2656 :
2657 0 : status = _cairo_array_append (&surface->alpha_linear_functions, &elem);
2658 0 : *function = res;
2659 :
2660 0 : return status;
2661 : }
2662 :
2663 : static cairo_status_t
2664 0 : _cairo_pdf_surface_emit_stitched_colorgradient (cairo_pdf_surface_t *surface,
2665 : unsigned int n_stops,
2666 : cairo_pdf_color_stop_t *stops,
2667 : cairo_bool_t is_alpha,
2668 : cairo_pdf_resource_t *function)
2669 : {
2670 : cairo_pdf_resource_t res;
2671 : unsigned int i;
2672 : cairo_status_t status;
2673 :
2674 : /* emit linear gradients between pairs of subsequent stops... */
2675 0 : for (i = 0; i < n_stops-1; i++) {
2676 0 : if (is_alpha) {
2677 0 : status = cairo_pdf_surface_emit_alpha_linear_function (surface,
2678 0 : &stops[i],
2679 0 : &stops[i+1],
2680 0 : &stops[i].resource);
2681 0 : if (unlikely (status))
2682 0 : return status;
2683 : } else {
2684 0 : status = cairo_pdf_surface_emit_rgb_linear_function (surface,
2685 0 : &stops[i],
2686 0 : &stops[i+1],
2687 0 : &stops[i].resource);
2688 0 : if (unlikely (status))
2689 0 : return status;
2690 : }
2691 : }
2692 :
2693 : /* ... and stitch them together */
2694 0 : res = _cairo_pdf_surface_new_object (surface);
2695 0 : if (res.id == 0)
2696 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2697 :
2698 0 : _cairo_output_stream_printf (surface->output,
2699 : "%d 0 obj\n"
2700 : "<< /FunctionType 3\n"
2701 : " /Domain [ %f %f ]\n",
2702 : res.id,
2703 : stops[0].offset,
2704 0 : stops[n_stops - 1].offset);
2705 :
2706 0 : _cairo_output_stream_printf (surface->output,
2707 : " /Functions [ ");
2708 0 : for (i = 0; i < n_stops-1; i++)
2709 0 : _cairo_output_stream_printf (surface->output,
2710 0 : "%d 0 R ", stops[i].resource.id);
2711 0 : _cairo_output_stream_printf (surface->output,
2712 : "]\n");
2713 :
2714 0 : _cairo_output_stream_printf (surface->output,
2715 : " /Bounds [ ");
2716 0 : for (i = 1; i < n_stops-1; i++)
2717 0 : _cairo_output_stream_printf (surface->output,
2718 0 : "%f ", stops[i].offset);
2719 0 : _cairo_output_stream_printf (surface->output,
2720 : "]\n");
2721 :
2722 0 : _cairo_output_stream_printf (surface->output,
2723 : " /Encode [ ");
2724 0 : for (i = 1; i < n_stops; i++)
2725 0 : _cairo_output_stream_printf (surface->output,
2726 : "0 1 ");
2727 0 : _cairo_output_stream_printf (surface->output,
2728 : "]\n");
2729 :
2730 0 : _cairo_output_stream_printf (surface->output,
2731 : ">>\n"
2732 : "endobj\n");
2733 :
2734 0 : *function = res;
2735 :
2736 0 : return _cairo_output_stream_get_status (surface->output);
2737 : }
2738 :
2739 :
2740 : static void
2741 0 : calc_gradient_color (cairo_pdf_color_stop_t *new_stop,
2742 : cairo_pdf_color_stop_t *stop1,
2743 : cairo_pdf_color_stop_t *stop2)
2744 : {
2745 : int i;
2746 0 : double offset = stop1->offset / (stop1->offset + 1.0 - stop2->offset);
2747 :
2748 0 : for (i = 0; i < 4; i++)
2749 0 : new_stop->color[i] = stop1->color[i] + offset*(stop2->color[i] - stop1->color[i]);
2750 0 : }
2751 :
2752 : #define COLOR_STOP_EPSILON 1e-6
2753 :
2754 : static cairo_status_t
2755 0 : _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface,
2756 : cairo_gradient_pattern_t *pattern,
2757 : cairo_pdf_resource_t *color_function,
2758 : cairo_pdf_resource_t *alpha_function)
2759 : {
2760 : cairo_pdf_color_stop_t *allstops, *stops;
2761 : unsigned int n_stops;
2762 : unsigned int i;
2763 0 : cairo_bool_t emit_alpha = FALSE;
2764 : cairo_status_t status;
2765 :
2766 0 : color_function->id = 0;
2767 0 : alpha_function->id = 0;
2768 :
2769 0 : allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_pdf_color_stop_t));
2770 0 : if (unlikely (allstops == NULL))
2771 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2772 :
2773 0 : stops = &allstops[1];
2774 0 : n_stops = pattern->n_stops;
2775 :
2776 0 : for (i = 0; i < n_stops; i++) {
2777 0 : stops[i].color[0] = pattern->stops[i].color.red;
2778 0 : stops[i].color[1] = pattern->stops[i].color.green;
2779 0 : stops[i].color[2] = pattern->stops[i].color.blue;
2780 0 : stops[i].color[3] = pattern->stops[i].color.alpha;
2781 0 : if (!CAIRO_ALPHA_IS_OPAQUE (stops[i].color[3]))
2782 0 : emit_alpha = TRUE;
2783 0 : stops[i].offset = pattern->stops[i].offset;
2784 : }
2785 :
2786 0 : if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
2787 0 : pattern->base.extend == CAIRO_EXTEND_REFLECT) {
2788 0 : if (stops[0].offset > COLOR_STOP_EPSILON) {
2789 0 : if (pattern->base.extend == CAIRO_EXTEND_REFLECT)
2790 0 : memcpy (allstops, stops, sizeof (cairo_pdf_color_stop_t));
2791 : else
2792 0 : calc_gradient_color (&allstops[0], &stops[0], &stops[n_stops-1]);
2793 0 : stops = allstops;
2794 0 : n_stops++;
2795 : }
2796 0 : stops[0].offset = 0.0;
2797 :
2798 0 : if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
2799 0 : if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
2800 0 : memcpy (&stops[n_stops],
2801 0 : &stops[n_stops - 1],
2802 : sizeof (cairo_pdf_color_stop_t));
2803 : } else {
2804 0 : calc_gradient_color (&stops[n_stops], &stops[0], &stops[n_stops-1]);
2805 : }
2806 0 : n_stops++;
2807 : }
2808 0 : stops[n_stops-1].offset = 1.0;
2809 : }
2810 :
2811 0 : if (n_stops <= 2) {
2812 : /* no need for stitched function */
2813 0 : status = cairo_pdf_surface_emit_rgb_linear_function (surface,
2814 : &stops[0],
2815 0 : &stops[n_stops - 1],
2816 : color_function);
2817 0 : if (unlikely (status))
2818 0 : goto BAIL;
2819 :
2820 0 : if (emit_alpha) {
2821 0 : status = cairo_pdf_surface_emit_alpha_linear_function (surface,
2822 : &stops[0],
2823 0 : &stops[n_stops - 1],
2824 : alpha_function);
2825 0 : if (unlikely (status))
2826 0 : goto BAIL;
2827 : }
2828 : } else {
2829 : /* multiple stops: stitch. XXX possible optimization: regularly spaced
2830 : * stops do not require stitching. XXX */
2831 0 : status = _cairo_pdf_surface_emit_stitched_colorgradient (surface,
2832 : n_stops,
2833 : stops,
2834 : FALSE,
2835 : color_function);
2836 0 : if (unlikely (status))
2837 0 : goto BAIL;
2838 :
2839 0 : if (emit_alpha) {
2840 0 : status = _cairo_pdf_surface_emit_stitched_colorgradient (surface,
2841 : n_stops,
2842 : stops,
2843 : TRUE,
2844 : alpha_function);
2845 0 : if (unlikely (status))
2846 0 : goto BAIL;
2847 : }
2848 : }
2849 :
2850 : BAIL:
2851 0 : free (allstops);
2852 0 : return status;
2853 : }
2854 :
2855 : static cairo_status_t
2856 0 : _cairo_pdf_surface_emit_repeating_function (cairo_pdf_surface_t *surface,
2857 : cairo_gradient_pattern_t *pattern,
2858 : cairo_pdf_resource_t *function,
2859 : int begin,
2860 : int end)
2861 : {
2862 : cairo_pdf_resource_t res;
2863 : int i;
2864 :
2865 0 : res = _cairo_pdf_surface_new_object (surface);
2866 0 : if (res.id == 0)
2867 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2868 :
2869 0 : _cairo_output_stream_printf (surface->output,
2870 : "%d 0 obj\n"
2871 : "<< /FunctionType 3\n"
2872 : " /Domain [ %d %d ]\n",
2873 : res.id,
2874 : begin,
2875 : end);
2876 :
2877 0 : _cairo_output_stream_printf (surface->output,
2878 : " /Functions [ ");
2879 0 : for (i = begin; i < end; i++)
2880 0 : _cairo_output_stream_printf (surface->output,
2881 : "%d 0 R ", function->id);
2882 0 : _cairo_output_stream_printf (surface->output,
2883 : "]\n");
2884 :
2885 0 : _cairo_output_stream_printf (surface->output,
2886 : " /Bounds [ ");
2887 0 : for (i = begin + 1; i < end; i++)
2888 0 : _cairo_output_stream_printf (surface->output,
2889 : "%d ", i);
2890 0 : _cairo_output_stream_printf (surface->output,
2891 : "]\n");
2892 :
2893 0 : _cairo_output_stream_printf (surface->output,
2894 : " /Encode [ ");
2895 0 : for (i = begin; i < end; i++) {
2896 0 : if ((i % 2) && pattern->base.extend == CAIRO_EXTEND_REFLECT) {
2897 0 : _cairo_output_stream_printf (surface->output,
2898 : "1 0 ");
2899 : } else {
2900 0 : _cairo_output_stream_printf (surface->output,
2901 : "0 1 ");
2902 : }
2903 : }
2904 0 : _cairo_output_stream_printf (surface->output,
2905 : "]\n");
2906 :
2907 0 : _cairo_output_stream_printf (surface->output,
2908 : ">>\n"
2909 : "endobj\n");
2910 :
2911 0 : *function = res;
2912 :
2913 0 : return _cairo_output_stream_get_status (surface->output);
2914 : }
2915 :
2916 : static cairo_status_t
2917 0 : cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t *surface,
2918 : cairo_pdf_resource_t gstate_resource,
2919 : cairo_pdf_resource_t gradient_mask)
2920 : {
2921 : cairo_pdf_resource_t smask_resource;
2922 : cairo_status_t status;
2923 :
2924 0 : status = _cairo_pdf_surface_open_stream (surface,
2925 : NULL,
2926 : surface->compress_content,
2927 : " /Type /XObject\n"
2928 : " /Subtype /Form\n"
2929 : " /FormType 1\n"
2930 : " /BBox [ 0 0 %f %f ]\n"
2931 : " /Resources\n"
2932 : " << /ExtGState\n"
2933 : " << /a0 << /ca 1 /CA 1 >>"
2934 : " >>\n"
2935 : " /Pattern\n"
2936 : " << /p%d %d 0 R >>\n"
2937 : " >>\n"
2938 : " /Group\n"
2939 : " << /Type /Group\n"
2940 : " /S /Transparency\n"
2941 : " /CS /DeviceGray\n"
2942 : " >>\n",
2943 : surface->width,
2944 : surface->height,
2945 : gradient_mask.id,
2946 : gradient_mask.id);
2947 0 : if (unlikely (status))
2948 0 : return status;
2949 :
2950 0 : _cairo_output_stream_printf (surface->output,
2951 : "q\n"
2952 : "/a0 gs\n"
2953 : "/Pattern cs /p%d scn\n"
2954 : "0 0 %f %f re\n"
2955 : "f\n"
2956 : "Q\n",
2957 : gradient_mask.id,
2958 : surface->width,
2959 : surface->height);
2960 :
2961 0 : status = _cairo_pdf_surface_close_stream (surface);
2962 0 : if (unlikely (status))
2963 0 : return status;
2964 :
2965 0 : smask_resource = _cairo_pdf_surface_new_object (surface);
2966 0 : if (smask_resource.id == 0)
2967 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2968 :
2969 0 : _cairo_output_stream_printf (surface->output,
2970 : "%d 0 obj\n"
2971 : "<< /Type /Mask\n"
2972 : " /S /Luminosity\n"
2973 : " /G %d 0 R\n"
2974 : ">>\n"
2975 : "endobj\n",
2976 : smask_resource.id,
2977 : surface->pdf_stream.self.id);
2978 :
2979 : /* Create GState which uses the transparency group as an SMask. */
2980 0 : _cairo_pdf_surface_update_object (surface, gstate_resource);
2981 :
2982 0 : _cairo_output_stream_printf (surface->output,
2983 : "%d 0 obj\n"
2984 : "<< /Type /ExtGState\n"
2985 : " /SMask %d 0 R\n"
2986 : " /ca 1\n"
2987 : " /CA 1\n"
2988 : " /AIS false\n"
2989 : ">>\n"
2990 : "endobj\n",
2991 : gstate_resource.id,
2992 : smask_resource.id);
2993 :
2994 0 : return _cairo_output_stream_get_status (surface->output);
2995 : }
2996 :
2997 : static cairo_status_t
2998 0 : _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
2999 : cairo_pdf_pattern_t *pdf_pattern)
3000 : {
3001 0 : cairo_linear_pattern_t *pattern = (cairo_linear_pattern_t *) pdf_pattern->pattern;
3002 : cairo_pdf_resource_t color_function, alpha_function;
3003 : double x1, y1, x2, y2;
3004 : double _x1, _y1, _x2, _y2;
3005 : cairo_matrix_t pat_to_pdf;
3006 : cairo_extend_t extend;
3007 : cairo_status_t status;
3008 0 : cairo_gradient_pattern_t *gradient = &pattern->base;
3009 : double first_stop, last_stop;
3010 0 : int repeat_begin = 0, repeat_end = 1;
3011 :
3012 0 : assert (pattern->base.n_stops != 0);
3013 :
3014 0 : extend = cairo_pattern_get_extend (pdf_pattern->pattern);
3015 :
3016 0 : pat_to_pdf = pattern->base.base.matrix;
3017 0 : status = cairo_matrix_invert (&pat_to_pdf);
3018 : /* cairo_pattern_set_matrix ensures the matrix is invertible */
3019 0 : assert (status == CAIRO_STATUS_SUCCESS);
3020 :
3021 0 : cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
3022 0 : first_stop = gradient->stops[0].offset;
3023 0 : last_stop = gradient->stops[gradient->n_stops - 1].offset;
3024 :
3025 0 : if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
3026 0 : pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
3027 : double dx, dy;
3028 0 : int x_rep = 0, y_rep = 0;
3029 :
3030 0 : x1 = _cairo_fixed_to_double (pattern->p1.x);
3031 0 : y1 = _cairo_fixed_to_double (pattern->p1.y);
3032 0 : cairo_matrix_transform_point (&pat_to_pdf, &x1, &y1);
3033 :
3034 0 : x2 = _cairo_fixed_to_double (pattern->p2.x);
3035 0 : y2 = _cairo_fixed_to_double (pattern->p2.y);
3036 0 : cairo_matrix_transform_point (&pat_to_pdf, &x2, &y2);
3037 :
3038 0 : dx = fabs (x2 - x1);
3039 0 : dy = fabs (y2 - y1);
3040 0 : if (dx > 1e-6)
3041 0 : x_rep = ceil (surface->width/dx);
3042 0 : if (dy > 1e-6)
3043 0 : y_rep = ceil (surface->height/dy);
3044 :
3045 0 : repeat_end = MAX (x_rep, y_rep);
3046 0 : repeat_begin = -repeat_end;
3047 0 : first_stop = repeat_begin;
3048 0 : last_stop = repeat_end;
3049 : }
3050 :
3051 : /* PDF requires the first and last stop to be the same as the line
3052 : * coordinates. For repeating patterns this moves the line
3053 : * coordinates out to the begin/end of the repeating function. For
3054 : * non repeating patterns this may move the line coordinates in if
3055 : * there are not stops at offset 0 and 1. */
3056 0 : x1 = _cairo_fixed_to_double (pattern->p1.x);
3057 0 : y1 = _cairo_fixed_to_double (pattern->p1.y);
3058 0 : x2 = _cairo_fixed_to_double (pattern->p2.x);
3059 0 : y2 = _cairo_fixed_to_double (pattern->p2.y);
3060 :
3061 0 : _x1 = x1 + (x2 - x1)*first_stop;
3062 0 : _y1 = y1 + (y2 - y1)*first_stop;
3063 0 : _x2 = x1 + (x2 - x1)*last_stop;
3064 0 : _y2 = y1 + (y2 - y1)*last_stop;
3065 :
3066 0 : x1 = _x1;
3067 0 : x2 = _x2;
3068 0 : y1 = _y1;
3069 0 : y2 = _y2;
3070 :
3071 : /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a
3072 : * Type 2 function is used by itself without a stitching
3073 : * function. Type 2 functions always have the domain [0 1] */
3074 0 : if ((pattern->base.base.extend == CAIRO_EXTEND_NONE ||
3075 0 : pattern->base.base.extend == CAIRO_EXTEND_PAD) &&
3076 0 : gradient->n_stops == 2) {
3077 0 : first_stop = 0.0;
3078 0 : last_stop = 1.0;
3079 : }
3080 :
3081 0 : status = _cairo_pdf_surface_emit_pattern_stops (surface,
3082 : &pattern->base,
3083 : &color_function,
3084 : &alpha_function);
3085 0 : if (unlikely (status))
3086 0 : return status;
3087 :
3088 0 : if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
3089 0 : pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
3090 0 : status = _cairo_pdf_surface_emit_repeating_function (surface,
3091 : &pattern->base,
3092 : &color_function,
3093 : repeat_begin,
3094 : repeat_end);
3095 0 : if (unlikely (status))
3096 0 : return status;
3097 :
3098 0 : if (alpha_function.id != 0) {
3099 0 : status = _cairo_pdf_surface_emit_repeating_function (surface,
3100 : &pattern->base,
3101 : &alpha_function,
3102 : repeat_begin,
3103 : repeat_end);
3104 0 : if (unlikely (status))
3105 0 : return status;
3106 : }
3107 : }
3108 :
3109 0 : _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
3110 0 : _cairo_output_stream_printf (surface->output,
3111 : "%d 0 obj\n"
3112 : "<< /Type /Pattern\n"
3113 : " /PatternType 2\n"
3114 : " /Matrix [ %f %f %f %f %f %f ]\n"
3115 : " /Shading\n"
3116 : " << /ShadingType 2\n"
3117 : " /ColorSpace /DeviceRGB\n"
3118 : " /Coords [ %f %f %f %f ]\n"
3119 : " /Domain [ %f %f ]\n"
3120 : " /Function %d 0 R\n",
3121 : pdf_pattern->pattern_res.id,
3122 : pat_to_pdf.xx, pat_to_pdf.yx,
3123 : pat_to_pdf.xy, pat_to_pdf.yy,
3124 : pat_to_pdf.x0, pat_to_pdf.y0,
3125 : x1, y1, x2, y2,
3126 : first_stop, last_stop,
3127 : color_function.id);
3128 :
3129 0 : if (extend == CAIRO_EXTEND_PAD) {
3130 0 : _cairo_output_stream_printf (surface->output,
3131 : " /Extend [ true true ]\n");
3132 : } else {
3133 0 : _cairo_output_stream_printf (surface->output,
3134 : " /Extend [ false false ]\n");
3135 : }
3136 :
3137 0 : _cairo_output_stream_printf (surface->output,
3138 : " >>\n"
3139 : ">>\n"
3140 : "endobj\n");
3141 :
3142 0 : if (alpha_function.id != 0) {
3143 : cairo_pdf_resource_t mask_resource;
3144 :
3145 0 : assert (pdf_pattern->gstate_res.id != 0);
3146 :
3147 : /* Create pattern for SMask. */
3148 0 : mask_resource = _cairo_pdf_surface_new_object (surface);
3149 0 : if (mask_resource.id == 0)
3150 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3151 :
3152 0 : _cairo_output_stream_printf (surface->output,
3153 : "%d 0 obj\n"
3154 : "<< /Type /Pattern\n"
3155 : " /PatternType 2\n"
3156 : " /Matrix [ %f %f %f %f %f %f ]\n"
3157 : " /Shading\n"
3158 : " << /ShadingType 2\n"
3159 : " /ColorSpace /DeviceGray\n"
3160 : " /Coords [ %f %f %f %f ]\n"
3161 : " /Domain [ %f %f ]\n"
3162 : " /Function %d 0 R\n",
3163 : mask_resource.id,
3164 : pat_to_pdf.xx, pat_to_pdf.yx,
3165 : pat_to_pdf.xy, pat_to_pdf.yy,
3166 : pat_to_pdf.x0, pat_to_pdf.y0,
3167 : x1, y1, x2, y2,
3168 : first_stop, last_stop,
3169 : alpha_function.id);
3170 :
3171 0 : if (extend == CAIRO_EXTEND_PAD) {
3172 0 : _cairo_output_stream_printf (surface->output,
3173 : " /Extend [ true true ]\n");
3174 : } else {
3175 0 : _cairo_output_stream_printf (surface->output,
3176 : " /Extend [ false false ]\n");
3177 : }
3178 :
3179 0 : _cairo_output_stream_printf (surface->output,
3180 : " >>\n"
3181 : ">>\n"
3182 : "endobj\n");
3183 0 : status = _cairo_pdf_surface_add_pattern (surface, mask_resource);
3184 0 : if (unlikely (status))
3185 0 : return status;
3186 :
3187 0 : status = cairo_pdf_surface_emit_transparency_group (surface,
3188 : pdf_pattern->gstate_res,
3189 : mask_resource);
3190 0 : if (unlikely (status))
3191 0 : return status;
3192 : }
3193 :
3194 0 : return _cairo_output_stream_get_status (surface->output);
3195 : }
3196 :
3197 : static cairo_status_t
3198 0 : _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface,
3199 : cairo_pdf_pattern_t *pdf_pattern)
3200 : {
3201 : cairo_pdf_resource_t color_function, alpha_function;
3202 : double x1, y1, x2, y2, r1, r2;
3203 : cairo_matrix_t pat_to_pdf;
3204 : cairo_extend_t extend;
3205 : cairo_status_t status;
3206 0 : cairo_radial_pattern_t *pattern = (cairo_radial_pattern_t *) pdf_pattern->pattern;
3207 :
3208 0 : assert (pattern->base.n_stops != 0);
3209 :
3210 0 : extend = cairo_pattern_get_extend (pdf_pattern->pattern);
3211 :
3212 0 : status = _cairo_pdf_surface_emit_pattern_stops (surface,
3213 : &pattern->base,
3214 : &color_function,
3215 : &alpha_function);
3216 0 : if (unlikely (status))
3217 0 : return status;
3218 :
3219 0 : pat_to_pdf = pattern->base.base.matrix;
3220 0 : status = cairo_matrix_invert (&pat_to_pdf);
3221 : /* cairo_pattern_set_matrix ensures the matrix is invertible */
3222 0 : assert (status == CAIRO_STATUS_SUCCESS);
3223 :
3224 0 : cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
3225 0 : x1 = _cairo_fixed_to_double (pattern->c1.x);
3226 0 : y1 = _cairo_fixed_to_double (pattern->c1.y);
3227 0 : r1 = _cairo_fixed_to_double (pattern->r1);
3228 0 : x2 = _cairo_fixed_to_double (pattern->c2.x);
3229 0 : y2 = _cairo_fixed_to_double (pattern->c2.y);
3230 0 : r2 = _cairo_fixed_to_double (pattern->r2);
3231 :
3232 0 : _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
3233 :
3234 0 : _cairo_output_stream_printf (surface->output,
3235 : "%d 0 obj\n"
3236 : "<< /Type /Pattern\n"
3237 : " /PatternType 2\n"
3238 : " /Matrix [ %f %f %f %f %f %f ]\n"
3239 : " /Shading\n"
3240 : " << /ShadingType 3\n"
3241 : " /ColorSpace /DeviceRGB\n"
3242 : " /Coords [ %f %f %f %f %f %f ]\n"
3243 : " /Function %d 0 R\n",
3244 : pdf_pattern->pattern_res.id,
3245 : pat_to_pdf.xx, pat_to_pdf.yx,
3246 : pat_to_pdf.xy, pat_to_pdf.yy,
3247 : pat_to_pdf.x0, pat_to_pdf.y0,
3248 : x1, y1, r1, x2, y2, r2,
3249 : color_function.id);
3250 :
3251 0 : if (extend == CAIRO_EXTEND_PAD) {
3252 0 : _cairo_output_stream_printf (surface->output,
3253 : " /Extend [ true true ]\n");
3254 : } else {
3255 0 : _cairo_output_stream_printf (surface->output,
3256 : " /Extend [ false false ]\n");
3257 : }
3258 :
3259 0 : _cairo_output_stream_printf (surface->output,
3260 : " >>\n"
3261 : ">>\n"
3262 : "endobj\n");
3263 :
3264 0 : if (alpha_function.id != 0) {
3265 : cairo_pdf_resource_t mask_resource;
3266 :
3267 0 : assert (pdf_pattern->gstate_res.id != 0);
3268 :
3269 : /* Create pattern for SMask. */
3270 0 : mask_resource = _cairo_pdf_surface_new_object (surface);
3271 0 : if (mask_resource.id == 0)
3272 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3273 :
3274 0 : _cairo_output_stream_printf (surface->output,
3275 : "%d 0 obj\n"
3276 : "<< /Type /Pattern\n"
3277 : " /PatternType 2\n"
3278 : " /Matrix [ %f %f %f %f %f %f ]\n"
3279 : " /Shading\n"
3280 : " << /ShadingType 3\n"
3281 : " /ColorSpace /DeviceGray\n"
3282 : " /Coords [ %f %f %f %f %f %f ]\n"
3283 : " /Function %d 0 R\n",
3284 : mask_resource.id,
3285 : pat_to_pdf.xx, pat_to_pdf.yx,
3286 : pat_to_pdf.xy, pat_to_pdf.yy,
3287 : pat_to_pdf.x0, pat_to_pdf.y0,
3288 : x1, y1, r1, x2, y2, r2,
3289 : alpha_function.id);
3290 :
3291 0 : if (extend == CAIRO_EXTEND_PAD) {
3292 0 : _cairo_output_stream_printf (surface->output,
3293 : " /Extend [ true true ]\n");
3294 : } else {
3295 0 : _cairo_output_stream_printf (surface->output,
3296 : " /Extend [ false false ]\n");
3297 : }
3298 :
3299 0 : _cairo_output_stream_printf (surface->output,
3300 : " >>\n"
3301 : ">>\n"
3302 : "endobj\n");
3303 :
3304 0 : status = cairo_pdf_surface_emit_transparency_group (surface,
3305 : pdf_pattern->gstate_res,
3306 : mask_resource);
3307 0 : if (unlikely (status))
3308 0 : return status;
3309 : }
3310 :
3311 0 : return _cairo_output_stream_get_status (surface->output);
3312 : }
3313 :
3314 : static cairo_status_t
3315 0 : _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern_t *pdf_pattern)
3316 : {
3317 : double old_width, old_height;
3318 : cairo_status_t status;
3319 :
3320 0 : old_width = surface->width;
3321 0 : old_height = surface->height;
3322 0 : _cairo_pdf_surface_set_size_internal (surface,
3323 : pdf_pattern->width,
3324 : pdf_pattern->height);
3325 :
3326 0 : switch (pdf_pattern->pattern->type) {
3327 : case CAIRO_PATTERN_TYPE_SOLID:
3328 0 : ASSERT_NOT_REACHED;
3329 0 : status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
3330 0 : break;
3331 :
3332 : case CAIRO_PATTERN_TYPE_SURFACE:
3333 0 : status = _cairo_pdf_surface_emit_surface_pattern (surface, pdf_pattern);
3334 0 : break;
3335 :
3336 : case CAIRO_PATTERN_TYPE_LINEAR:
3337 0 : status = _cairo_pdf_surface_emit_linear_pattern (surface, pdf_pattern);
3338 0 : break;
3339 :
3340 : case CAIRO_PATTERN_TYPE_RADIAL:
3341 0 : status = _cairo_pdf_surface_emit_radial_pattern (surface, pdf_pattern);
3342 0 : break;
3343 :
3344 : default:
3345 0 : ASSERT_NOT_REACHED;
3346 0 : status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
3347 0 : break;
3348 : }
3349 :
3350 0 : _cairo_pdf_surface_set_size_internal (surface,
3351 : old_width,
3352 : old_height);
3353 :
3354 0 : return status;
3355 : }
3356 :
3357 : static cairo_status_t
3358 0 : _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
3359 : cairo_surface_pattern_t *source)
3360 : {
3361 : cairo_pdf_resource_t surface_res;
3362 : int width, height;
3363 : cairo_matrix_t cairo_p2d, pdf_p2d;
3364 : cairo_status_t status;
3365 : int alpha;
3366 :
3367 0 : status = _cairo_pdf_surface_add_source_surface (surface,
3368 : source->surface,
3369 : source->base.filter,
3370 : &surface_res,
3371 : &width,
3372 : &height);
3373 0 : if (unlikely (status))
3374 0 : return status;
3375 :
3376 0 : cairo_p2d = source->base.matrix;
3377 0 : status = cairo_matrix_invert (&cairo_p2d);
3378 : /* cairo_pattern_set_matrix ensures the matrix is invertible */
3379 0 : assert (status == CAIRO_STATUS_SUCCESS);
3380 :
3381 0 : pdf_p2d = surface->cairo_to_pdf;
3382 0 : cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d);
3383 0 : cairo_matrix_translate (&pdf_p2d, 0.0, height);
3384 0 : cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
3385 0 : if (source->surface->type != CAIRO_SURFACE_TYPE_RECORDING)
3386 0 : cairo_matrix_scale (&pdf_p2d, width, height);
3387 :
3388 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3389 0 : if (unlikely (status))
3390 0 : return status;
3391 :
3392 0 : if (! _cairo_matrix_is_identity (&pdf_p2d)) {
3393 0 : _cairo_output_stream_printf (surface->output,
3394 : "%f %f %f %f %f %f cm\n",
3395 : pdf_p2d.xx, pdf_p2d.yx,
3396 : pdf_p2d.xy, pdf_p2d.yy,
3397 : pdf_p2d.x0, pdf_p2d.y0);
3398 : }
3399 :
3400 0 : status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
3401 0 : if (unlikely (status))
3402 0 : return status;
3403 :
3404 0 : _cairo_output_stream_printf (surface->output,
3405 : "/a%d gs /x%d Do\n",
3406 : alpha,
3407 : surface_res.id);
3408 :
3409 0 : return _cairo_pdf_surface_add_xobject (surface, surface_res);
3410 : }
3411 :
3412 : static cairo_status_t
3413 0 : _cairo_pdf_surface_select_operator (cairo_pdf_surface_t *surface,
3414 : cairo_operator_t op)
3415 : {
3416 : cairo_status_t status;
3417 :
3418 0 : if (op == surface->current_operator)
3419 0 : return CAIRO_STATUS_SUCCESS;
3420 :
3421 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3422 0 : if (unlikely (status))
3423 0 : return status;
3424 :
3425 0 : _cairo_output_stream_printf (surface->output,
3426 : "/b%d gs\n", op);
3427 0 : surface->current_operator = op;
3428 0 : _cairo_pdf_surface_add_operator (surface, op);
3429 :
3430 0 : return CAIRO_STATUS_SUCCESS;
3431 : }
3432 :
3433 : static cairo_status_t
3434 0 : _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
3435 : const cairo_pattern_t *pattern,
3436 : cairo_pdf_resource_t pattern_res,
3437 : cairo_bool_t is_stroke)
3438 : {
3439 : cairo_status_t status;
3440 : int alpha;
3441 0 : const cairo_color_t *solid_color = NULL;
3442 :
3443 0 : if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
3444 0 : const cairo_solid_pattern_t *solid = (const cairo_solid_pattern_t *) pattern;
3445 :
3446 0 : solid_color = &solid->color;
3447 : }
3448 :
3449 0 : if (solid_color != NULL) {
3450 0 : if (surface->current_pattern_is_solid_color == FALSE ||
3451 0 : surface->current_color_red != solid_color->red ||
3452 0 : surface->current_color_green != solid_color->green ||
3453 0 : surface->current_color_blue != solid_color->blue ||
3454 0 : surface->current_color_is_stroke != is_stroke)
3455 : {
3456 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3457 0 : if (unlikely (status))
3458 0 : return status;
3459 :
3460 0 : _cairo_output_stream_printf (surface->output,
3461 : "%f %f %f ",
3462 : solid_color->red,
3463 : solid_color->green,
3464 : solid_color->blue);
3465 :
3466 0 : if (is_stroke)
3467 0 : _cairo_output_stream_printf (surface->output, "RG ");
3468 : else
3469 0 : _cairo_output_stream_printf (surface->output, "rg ");
3470 :
3471 0 : surface->current_color_red = solid_color->red;
3472 0 : surface->current_color_green = solid_color->green;
3473 0 : surface->current_color_blue = solid_color->blue;
3474 0 : surface->current_color_is_stroke = is_stroke;
3475 : }
3476 :
3477 0 : if (surface->current_pattern_is_solid_color == FALSE ||
3478 0 : surface->current_color_alpha != solid_color->alpha)
3479 : {
3480 0 : status = _cairo_pdf_surface_add_alpha (surface, solid_color->alpha, &alpha);
3481 0 : if (unlikely (status))
3482 0 : return status;
3483 :
3484 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3485 0 : if (unlikely (status))
3486 0 : return status;
3487 :
3488 0 : _cairo_output_stream_printf (surface->output,
3489 : "/a%d gs\n",
3490 : alpha);
3491 0 : surface->current_color_alpha = solid_color->alpha;
3492 : }
3493 :
3494 0 : surface->current_pattern_is_solid_color = TRUE;
3495 : } else {
3496 0 : status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
3497 0 : if (unlikely (status))
3498 0 : return status;
3499 :
3500 0 : status = _cairo_pdf_surface_add_pattern (surface, pattern_res);
3501 0 : if (unlikely (status))
3502 0 : return status;
3503 :
3504 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3505 0 : if (unlikely (status))
3506 0 : return status;
3507 :
3508 : /* fill-stroke calls select_pattern twice. Don't save if the
3509 : * gstate is already saved. */
3510 0 : if (!surface->select_pattern_gstate_saved)
3511 0 : _cairo_output_stream_printf (surface->output, "q ");
3512 :
3513 0 : if (is_stroke) {
3514 0 : _cairo_output_stream_printf (surface->output,
3515 : "/Pattern CS /p%d SCN ",
3516 : pattern_res.id);
3517 : } else {
3518 0 : _cairo_output_stream_printf (surface->output,
3519 : "/Pattern cs /p%d scn ",
3520 : pattern_res.id);
3521 : }
3522 0 : _cairo_output_stream_printf (surface->output,
3523 : "/a%d gs\n",
3524 : alpha);
3525 0 : surface->select_pattern_gstate_saved = TRUE;
3526 0 : surface->current_pattern_is_solid_color = FALSE;
3527 : }
3528 :
3529 0 : return _cairo_output_stream_get_status (surface->output);
3530 : }
3531 :
3532 : static cairo_int_status_t
3533 0 : _cairo_pdf_surface_unselect_pattern (cairo_pdf_surface_t *surface)
3534 : {
3535 : cairo_int_status_t status;
3536 :
3537 0 : if (surface->select_pattern_gstate_saved) {
3538 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
3539 0 : if (unlikely (status))
3540 0 : return status;
3541 :
3542 0 : _cairo_output_stream_printf (surface->output, "Q\n");
3543 0 : _cairo_pdf_operators_reset (&surface->pdf_operators);
3544 : }
3545 0 : surface->select_pattern_gstate_saved = FALSE;
3546 :
3547 0 : return CAIRO_STATUS_SUCCESS;
3548 : }
3549 :
3550 : static cairo_int_status_t
3551 0 : _cairo_pdf_surface_show_page (void *abstract_surface)
3552 : {
3553 0 : cairo_pdf_surface_t *surface = abstract_surface;
3554 : cairo_int_status_t status;
3555 :
3556 0 : status = _cairo_pdf_surface_close_content_stream (surface);
3557 0 : if (unlikely (status))
3558 0 : return status;
3559 :
3560 0 : status = _cairo_pdf_surface_write_page (surface);
3561 0 : if (unlikely (status))
3562 0 : return status;
3563 :
3564 0 : _cairo_pdf_surface_clear (surface);
3565 :
3566 0 : return CAIRO_STATUS_SUCCESS;
3567 : }
3568 :
3569 : static cairo_bool_t
3570 0 : _cairo_pdf_surface_get_extents (void *abstract_surface,
3571 : cairo_rectangle_int_t *rectangle)
3572 : {
3573 0 : cairo_pdf_surface_t *surface = abstract_surface;
3574 :
3575 0 : rectangle->x = 0;
3576 0 : rectangle->y = 0;
3577 :
3578 : /* XXX: The conversion to integers here is pretty bogus, (not to
3579 : * mention the arbitrary limitation of width to a short(!). We
3580 : * may need to come up with a better interface for get_size.
3581 : */
3582 0 : rectangle->width = ceil (surface->width);
3583 0 : rectangle->height = ceil (surface->height);
3584 :
3585 0 : return TRUE;
3586 : }
3587 :
3588 : static void
3589 0 : _cairo_pdf_surface_get_font_options (void *abstract_surface,
3590 : cairo_font_options_t *options)
3591 : {
3592 0 : _cairo_font_options_init_default (options);
3593 :
3594 0 : cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
3595 0 : cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
3596 0 : cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
3597 0 : }
3598 :
3599 : static cairo_pdf_resource_t
3600 0 : _cairo_pdf_surface_write_info (cairo_pdf_surface_t *surface)
3601 : {
3602 : cairo_pdf_resource_t info;
3603 :
3604 0 : info = _cairo_pdf_surface_new_object (surface);
3605 0 : if (info.id == 0)
3606 0 : return info;
3607 :
3608 0 : _cairo_output_stream_printf (surface->output,
3609 : "%d 0 obj\n"
3610 : "<< /Creator (cairo %s (http://cairographics.org))\n"
3611 : " /Producer (cairo %s (http://cairographics.org))\n"
3612 : ">>\n"
3613 : "endobj\n",
3614 : info.id,
3615 : cairo_version_string (),
3616 : cairo_version_string ());
3617 :
3618 0 : return info;
3619 : }
3620 :
3621 : static void
3622 0 : _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface)
3623 : {
3624 : cairo_pdf_resource_t page;
3625 : int num_pages, i;
3626 :
3627 0 : _cairo_pdf_surface_update_object (surface, surface->pages_resource);
3628 0 : _cairo_output_stream_printf (surface->output,
3629 : "%d 0 obj\n"
3630 : "<< /Type /Pages\n"
3631 : " /Kids [ ",
3632 : surface->pages_resource.id);
3633 :
3634 0 : num_pages = _cairo_array_num_elements (&surface->pages);
3635 0 : for (i = 0; i < num_pages; i++) {
3636 0 : _cairo_array_copy_element (&surface->pages, i, &page);
3637 0 : _cairo_output_stream_printf (surface->output, "%d 0 R ", page.id);
3638 : }
3639 :
3640 0 : _cairo_output_stream_printf (surface->output, "]\n");
3641 0 : _cairo_output_stream_printf (surface->output, " /Count %d\n", num_pages);
3642 :
3643 :
3644 : /* TODO: Figure out which other defaults to be inherited by /Page
3645 : * objects. */
3646 0 : _cairo_output_stream_printf (surface->output,
3647 : ">>\n"
3648 : "endobj\n");
3649 0 : }
3650 :
3651 : static cairo_status_t
3652 0 : _cairo_pdf_surface_emit_unicode_for_glyph (cairo_pdf_surface_t *surface,
3653 : const char *utf8)
3654 : {
3655 0 : uint16_t *utf16 = NULL;
3656 0 : int utf16_len = 0;
3657 : cairo_status_t status;
3658 : int i;
3659 :
3660 0 : if (utf8 && *utf8) {
3661 0 : status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
3662 0 : if (unlikely (status))
3663 0 : return status;
3664 : }
3665 :
3666 0 : _cairo_output_stream_printf (surface->output, "<");
3667 0 : if (utf16 == NULL || utf16_len == 0) {
3668 : /* According to the "ToUnicode Mapping File Tutorial"
3669 : * http://www.adobe.com/devnet/acrobat/pdfs/5411.ToUnicode.pdf
3670 : *
3671 : * Glyphs that do not map to a Unicode code point must be
3672 : * mapped to 0xfffd "REPLACEMENT CHARACTER".
3673 : */
3674 0 : _cairo_output_stream_printf (surface->output,
3675 : "fffd");
3676 : } else {
3677 0 : for (i = 0; i < utf16_len; i++)
3678 0 : _cairo_output_stream_printf (surface->output,
3679 0 : "%04x", (int) (utf16[i]));
3680 : }
3681 0 : _cairo_output_stream_printf (surface->output, ">");
3682 :
3683 0 : if (utf16)
3684 0 : free (utf16);
3685 :
3686 0 : return CAIRO_STATUS_SUCCESS;
3687 : }
3688 :
3689 : /* Bob Jenkins hash
3690 : *
3691 : * Public domain code from:
3692 : * http://burtleburtle.net/bob/hash/doobs.html
3693 : */
3694 :
3695 : #define HASH_MIX(a,b,c) \
3696 : { \
3697 : a -= b; a -= c; a ^= (c>>13); \
3698 : b -= c; b -= a; b ^= (a<<8); \
3699 : c -= a; c -= b; c ^= (b>>13); \
3700 : a -= b; a -= c; a ^= (c>>12); \
3701 : b -= c; b -= a; b ^= (a<<16); \
3702 : c -= a; c -= b; c ^= (b>>5); \
3703 : a -= b; a -= c; a ^= (c>>3); \
3704 : b -= c; b -= a; b ^= (a<<10); \
3705 : c -= a; c -= b; c ^= (b>>15); \
3706 : }
3707 :
3708 : static uint32_t
3709 0 : _hash_data (const unsigned char *data, int length, uint32_t initval)
3710 : {
3711 : uint32_t a, b, c, len;
3712 :
3713 0 : len = length;
3714 0 : a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
3715 0 : c = initval; /* the previous hash value */
3716 :
3717 0 : while (len >= 12) {
3718 0 : a += (data[0] + ((uint32_t)data[1]<<8) + ((uint32_t)data[2]<<16) + ((uint32_t)data[3]<<24));
3719 0 : b += (data[4] + ((uint32_t)data[5]<<8) + ((uint32_t)data[6]<<16) + ((uint32_t)data[7]<<24));
3720 0 : c += (data[8] + ((uint32_t)data[9]<<8) + ((uint32_t)data[10]<<16)+ ((uint32_t)data[11]<<24));
3721 0 : HASH_MIX (a,b,c);
3722 0 : data += 12;
3723 0 : len -= 12;
3724 : }
3725 :
3726 0 : c += length;
3727 0 : switch(len) {
3728 0 : case 11: c+= ((uint32_t) data[10] << 24);
3729 0 : case 10: c+= ((uint32_t) data[9] << 16);
3730 0 : case 9 : c+= ((uint32_t) data[8] << 8);
3731 0 : case 8 : b+= ((uint32_t) data[7] << 24);
3732 0 : case 7 : b+= ((uint32_t) data[6] << 16);
3733 0 : case 6 : b+= ((uint32_t) data[5] << 8);
3734 0 : case 5 : b+= data[4];
3735 0 : case 4 : a+= ((uint32_t) data[3] << 24);
3736 0 : case 3 : a+= ((uint32_t) data[2] << 16);
3737 0 : case 2 : a+= ((uint32_t) data[1] << 8);
3738 0 : case 1 : a+= data[0];
3739 : }
3740 0 : HASH_MIX (a,b,c);
3741 :
3742 0 : return c;
3743 : }
3744 :
3745 : static void
3746 0 : _create_font_subset_tag (cairo_scaled_font_subset_t *font_subset,
3747 : const char *font_name,
3748 : char *tag)
3749 : {
3750 : uint32_t hash;
3751 : int i;
3752 : long numerator;
3753 : ldiv_t d;
3754 :
3755 0 : hash = _hash_data ((unsigned char *) font_name, strlen(font_name), 0);
3756 0 : hash = _hash_data ((unsigned char *) (font_subset->glyphs),
3757 0 : font_subset->num_glyphs * sizeof(unsigned long), hash);
3758 :
3759 0 : numerator = abs (hash);
3760 0 : for (i = 0; i < 6; i++) {
3761 0 : d = ldiv (numerator, 26);
3762 0 : numerator = d.quot;
3763 0 : tag[i] = 'A' + d.rem;
3764 : }
3765 0 : tag[i] = 0;
3766 0 : }
3767 :
3768 : static cairo_int_status_t
3769 0 : _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
3770 : cairo_scaled_font_subset_t *font_subset,
3771 : cairo_bool_t is_composite,
3772 : cairo_pdf_resource_t *stream)
3773 : {
3774 : unsigned int i, num_bfchar;
3775 : cairo_int_status_t status;
3776 :
3777 0 : stream->id = 0;
3778 :
3779 0 : status = _cairo_pdf_surface_open_stream (surface,
3780 : NULL,
3781 : surface->compress_content,
3782 : NULL);
3783 0 : if (unlikely (status))
3784 0 : return status;
3785 :
3786 0 : _cairo_output_stream_printf (surface->output,
3787 : "/CIDInit /ProcSet findresource begin\n"
3788 : "12 dict begin\n"
3789 : "begincmap\n"
3790 : "/CIDSystemInfo\n"
3791 : "<< /Registry (Adobe)\n"
3792 : " /Ordering (UCS)\n"
3793 : " /Supplement 0\n"
3794 : ">> def\n"
3795 : "/CMapName /Adobe-Identity-UCS def\n"
3796 : "/CMapType 2 def\n"
3797 : "1 begincodespacerange\n");
3798 :
3799 0 : if (is_composite) {
3800 0 : _cairo_output_stream_printf (surface->output,
3801 : "<0000> <ffff>\n");
3802 : } else {
3803 0 : _cairo_output_stream_printf (surface->output,
3804 : "<00> <ff>\n");
3805 : }
3806 :
3807 0 : _cairo_output_stream_printf (surface->output,
3808 : "endcodespacerange\n");
3809 :
3810 0 : if (font_subset->is_scaled) {
3811 : /* Type 3 fonts include glyph 0 in the subset */
3812 0 : num_bfchar = font_subset->num_glyphs;
3813 :
3814 : /* The CMap specification has a limit of 100 characters per beginbfchar operator */
3815 0 : _cairo_output_stream_printf (surface->output,
3816 : "%d beginbfchar\n",
3817 : num_bfchar > 100 ? 100 : num_bfchar);
3818 :
3819 0 : for (i = 0; i < num_bfchar; i++) {
3820 0 : if (i != 0 && i % 100 == 0) {
3821 0 : _cairo_output_stream_printf (surface->output,
3822 : "endbfchar\n"
3823 : "%d beginbfchar\n",
3824 0 : num_bfchar - i > 100 ? 100 : num_bfchar - i);
3825 : }
3826 0 : _cairo_output_stream_printf (surface->output, "<%02x> ", i);
3827 0 : status = _cairo_pdf_surface_emit_unicode_for_glyph (surface,
3828 0 : font_subset->utf8[i]);
3829 0 : if (unlikely (status))
3830 0 : return status;
3831 :
3832 0 : _cairo_output_stream_printf (surface->output,
3833 : "\n");
3834 : }
3835 : } else {
3836 : /* Other fonts reserve glyph 0 for .notdef. Omit glyph 0 from the /ToUnicode map */
3837 0 : num_bfchar = font_subset->num_glyphs - 1;
3838 :
3839 : /* The CMap specification has a limit of 100 characters per beginbfchar operator */
3840 0 : _cairo_output_stream_printf (surface->output,
3841 : "%d beginbfchar\n",
3842 : num_bfchar > 100 ? 100 : num_bfchar);
3843 :
3844 0 : for (i = 0; i < num_bfchar; i++) {
3845 0 : if (i != 0 && i % 100 == 0) {
3846 0 : _cairo_output_stream_printf (surface->output,
3847 : "endbfchar\n"
3848 : "%d beginbfchar\n",
3849 0 : num_bfchar - i > 100 ? 100 : num_bfchar - i);
3850 : }
3851 0 : if (is_composite)
3852 0 : _cairo_output_stream_printf (surface->output, "<%04x> ", i + 1);
3853 : else
3854 0 : _cairo_output_stream_printf (surface->output, "<%02x> ", i + 1);
3855 :
3856 0 : status = _cairo_pdf_surface_emit_unicode_for_glyph (surface,
3857 0 : font_subset->utf8[i + 1]);
3858 0 : if (unlikely (status))
3859 0 : return status;
3860 :
3861 0 : _cairo_output_stream_printf (surface->output,
3862 : "\n");
3863 : }
3864 : }
3865 :
3866 0 : _cairo_output_stream_printf (surface->output,
3867 : "endbfchar\n");
3868 :
3869 0 : _cairo_output_stream_printf (surface->output,
3870 : "endcmap\n"
3871 : "CMapName currentdict /CMap defineresource pop\n"
3872 : "end\n"
3873 : "end\n");
3874 :
3875 0 : *stream = surface->pdf_stream.self;
3876 0 : return _cairo_pdf_surface_close_stream (surface);
3877 : }
3878 :
3879 : #define PDF_UNITS_PER_EM 1000
3880 :
3881 : static cairo_status_t
3882 0 : _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface,
3883 : cairo_scaled_font_subset_t *font_subset,
3884 : cairo_cff_subset_t *subset)
3885 : {
3886 : cairo_pdf_resource_t stream, descriptor, cidfont_dict;
3887 : cairo_pdf_resource_t subset_resource, to_unicode_stream;
3888 : cairo_pdf_font_t font;
3889 : unsigned int i;
3890 : cairo_status_t status;
3891 : char tag[10];
3892 :
3893 0 : _create_font_subset_tag (font_subset, subset->ps_name, tag);
3894 :
3895 0 : subset_resource = _cairo_pdf_surface_get_font_resource (surface,
3896 : font_subset->font_id,
3897 : font_subset->subset_id);
3898 0 : if (subset_resource.id == 0)
3899 0 : return CAIRO_STATUS_SUCCESS;
3900 :
3901 0 : status = _cairo_pdf_surface_open_stream (surface,
3902 : NULL,
3903 : TRUE,
3904 : " /Subtype /CIDFontType0C\n");
3905 0 : if (unlikely (status))
3906 0 : return status;
3907 :
3908 0 : stream = surface->pdf_stream.self;
3909 0 : _cairo_output_stream_write (surface->output,
3910 0 : subset->data, subset->data_length);
3911 0 : status = _cairo_pdf_surface_close_stream (surface);
3912 0 : if (unlikely (status))
3913 0 : return status;
3914 :
3915 0 : status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
3916 : font_subset, TRUE,
3917 : &to_unicode_stream);
3918 0 : if (_cairo_status_is_error (status))
3919 0 : return status;
3920 :
3921 0 : descriptor = _cairo_pdf_surface_new_object (surface);
3922 0 : if (descriptor.id == 0)
3923 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3924 :
3925 0 : _cairo_output_stream_printf (surface->output,
3926 : "%d 0 obj\n"
3927 : "<< /Type /FontDescriptor\n"
3928 : " /FontName /%s+%s\n",
3929 : descriptor.id,
3930 : tag,
3931 : subset->ps_name);
3932 :
3933 0 : if (subset->font_name) {
3934 0 : _cairo_output_stream_printf (surface->output,
3935 : " /FontFamily (%s)\n",
3936 : subset->font_name);
3937 : }
3938 :
3939 0 : _cairo_output_stream_printf (surface->output,
3940 : " /Flags 4\n"
3941 : " /FontBBox [ %ld %ld %ld %ld ]\n"
3942 : " /ItalicAngle 0\n"
3943 : " /Ascent %ld\n"
3944 : " /Descent %ld\n"
3945 : " /CapHeight %ld\n"
3946 : " /StemV 80\n"
3947 : " /StemH 80\n"
3948 : " /FontFile3 %u 0 R\n"
3949 : ">>\n"
3950 : "endobj\n",
3951 0 : (long)(subset->x_min*PDF_UNITS_PER_EM),
3952 0 : (long)(subset->y_min*PDF_UNITS_PER_EM),
3953 0 : (long)(subset->x_max*PDF_UNITS_PER_EM),
3954 0 : (long)(subset->y_max*PDF_UNITS_PER_EM),
3955 0 : (long)(subset->ascent*PDF_UNITS_PER_EM),
3956 0 : (long)(subset->descent*PDF_UNITS_PER_EM),
3957 0 : (long)(subset->y_max*PDF_UNITS_PER_EM),
3958 : stream.id);
3959 :
3960 0 : cidfont_dict = _cairo_pdf_surface_new_object (surface);
3961 0 : if (cidfont_dict.id == 0)
3962 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3963 :
3964 0 : _cairo_output_stream_printf (surface->output,
3965 : "%d 0 obj\n"
3966 : "<< /Type /Font\n"
3967 : " /Subtype /CIDFontType0\n"
3968 : " /BaseFont /%s+%s\n"
3969 : " /CIDSystemInfo\n"
3970 : " << /Registry (Adobe)\n"
3971 : " /Ordering (Identity)\n"
3972 : " /Supplement 0\n"
3973 : " >>\n"
3974 : " /FontDescriptor %d 0 R\n"
3975 : " /W [0 [",
3976 : cidfont_dict.id,
3977 : tag,
3978 : subset->ps_name,
3979 : descriptor.id);
3980 :
3981 0 : for (i = 0; i < font_subset->num_glyphs; i++)
3982 0 : _cairo_output_stream_printf (surface->output,
3983 : " %ld",
3984 0 : (long)(subset->widths[i]*PDF_UNITS_PER_EM));
3985 :
3986 0 : _cairo_output_stream_printf (surface->output,
3987 : " ]]\n"
3988 : ">>\n"
3989 : "endobj\n");
3990 :
3991 0 : _cairo_pdf_surface_update_object (surface, subset_resource);
3992 0 : _cairo_output_stream_printf (surface->output,
3993 : "%d 0 obj\n"
3994 : "<< /Type /Font\n"
3995 : " /Subtype /Type0\n"
3996 : " /BaseFont /%s+%s\n"
3997 : " /Encoding /Identity-H\n"
3998 : " /DescendantFonts [ %d 0 R]\n",
3999 : subset_resource.id,
4000 : tag,
4001 : subset->ps_name,
4002 : cidfont_dict.id);
4003 :
4004 0 : if (to_unicode_stream.id != 0)
4005 0 : _cairo_output_stream_printf (surface->output,
4006 : " /ToUnicode %d 0 R\n",
4007 : to_unicode_stream.id);
4008 :
4009 0 : _cairo_output_stream_printf (surface->output,
4010 : ">>\n"
4011 : "endobj\n");
4012 :
4013 0 : font.font_id = font_subset->font_id;
4014 0 : font.subset_id = font_subset->subset_id;
4015 0 : font.subset_resource = subset_resource;
4016 0 : status = _cairo_array_append (&surface->fonts, &font);
4017 :
4018 0 : return status;
4019 : }
4020 :
4021 : static cairo_status_t
4022 0 : _cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface,
4023 : cairo_scaled_font_subset_t *font_subset)
4024 : {
4025 : cairo_status_t status;
4026 : cairo_cff_subset_t subset;
4027 : char name[64];
4028 :
4029 0 : snprintf (name, sizeof name, "CairoFont-%d-%d",
4030 : font_subset->font_id, font_subset->subset_id);
4031 0 : status = _cairo_cff_subset_init (&subset, name, font_subset);
4032 0 : if (unlikely (status))
4033 0 : return status;
4034 :
4035 0 : status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset);
4036 :
4037 0 : _cairo_cff_subset_fini (&subset);
4038 :
4039 0 : return status;
4040 : }
4041 :
4042 : static cairo_status_t
4043 0 : _cairo_pdf_surface_emit_cff_fallback_font (cairo_pdf_surface_t *surface,
4044 : cairo_scaled_font_subset_t *font_subset)
4045 : {
4046 : cairo_status_t status;
4047 : cairo_cff_subset_t subset;
4048 : char name[64];
4049 :
4050 0 : snprintf (name, sizeof name, "CairoFont-%d-%d",
4051 : font_subset->font_id, font_subset->subset_id);
4052 0 : status = _cairo_cff_fallback_init (&subset, name, font_subset);
4053 0 : if (unlikely (status))
4054 0 : return status;
4055 :
4056 0 : status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset);
4057 :
4058 0 : _cairo_cff_fallback_fini (&subset);
4059 :
4060 0 : return status;
4061 : }
4062 :
4063 : static cairo_status_t
4064 0 : _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface,
4065 : cairo_scaled_font_subset_t *font_subset,
4066 : cairo_type1_subset_t *subset)
4067 : {
4068 : cairo_pdf_resource_t stream, descriptor, subset_resource, to_unicode_stream;
4069 : cairo_pdf_font_t font;
4070 : cairo_status_t status;
4071 : unsigned long length;
4072 : unsigned int i;
4073 : char tag[10];
4074 :
4075 0 : _create_font_subset_tag (font_subset, subset->base_font, tag);
4076 :
4077 0 : subset_resource = _cairo_pdf_surface_get_font_resource (surface,
4078 : font_subset->font_id,
4079 : font_subset->subset_id);
4080 0 : if (subset_resource.id == 0)
4081 0 : return CAIRO_STATUS_SUCCESS;
4082 :
4083 0 : length = subset->header_length + subset->data_length + subset->trailer_length;
4084 0 : status = _cairo_pdf_surface_open_stream (surface,
4085 : NULL,
4086 : TRUE,
4087 : " /Length1 %lu\n"
4088 : " /Length2 %lu\n"
4089 : " /Length3 %lu\n",
4090 : subset->header_length,
4091 : subset->data_length,
4092 : subset->trailer_length);
4093 0 : if (unlikely (status))
4094 0 : return status;
4095 :
4096 0 : stream = surface->pdf_stream.self;
4097 0 : _cairo_output_stream_write (surface->output, subset->data, length);
4098 0 : status = _cairo_pdf_surface_close_stream (surface);
4099 0 : if (unlikely (status))
4100 0 : return status;
4101 :
4102 0 : status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
4103 : font_subset, FALSE,
4104 : &to_unicode_stream);
4105 0 : if (_cairo_status_is_error (status))
4106 0 : return status;
4107 :
4108 0 : descriptor = _cairo_pdf_surface_new_object (surface);
4109 0 : if (descriptor.id == 0)
4110 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4111 :
4112 0 : _cairo_output_stream_printf (surface->output,
4113 : "%d 0 obj\n"
4114 : "<< /Type /FontDescriptor\n"
4115 : " /FontName /%s+%s\n"
4116 : " /Flags 4\n"
4117 : " /FontBBox [ %ld %ld %ld %ld ]\n"
4118 : " /ItalicAngle 0\n"
4119 : " /Ascent %ld\n"
4120 : " /Descent %ld\n"
4121 : " /CapHeight %ld\n"
4122 : " /StemV 80\n"
4123 : " /StemH 80\n"
4124 : " /FontFile %u 0 R\n"
4125 : ">>\n"
4126 : "endobj\n",
4127 : descriptor.id,
4128 : tag,
4129 : subset->base_font,
4130 0 : (long)(subset->x_min*PDF_UNITS_PER_EM),
4131 0 : (long)(subset->y_min*PDF_UNITS_PER_EM),
4132 0 : (long)(subset->x_max*PDF_UNITS_PER_EM),
4133 0 : (long)(subset->y_max*PDF_UNITS_PER_EM),
4134 0 : (long)(subset->ascent*PDF_UNITS_PER_EM),
4135 0 : (long)(subset->descent*PDF_UNITS_PER_EM),
4136 0 : (long)(subset->y_max*PDF_UNITS_PER_EM),
4137 : stream.id);
4138 :
4139 0 : _cairo_pdf_surface_update_object (surface, subset_resource);
4140 0 : _cairo_output_stream_printf (surface->output,
4141 : "%d 0 obj\n"
4142 : "<< /Type /Font\n"
4143 : " /Subtype /Type1\n"
4144 : " /BaseFont /%s+%s\n"
4145 : " /FirstChar 0\n"
4146 : " /LastChar %d\n"
4147 : " /FontDescriptor %d 0 R\n"
4148 : " /Widths [",
4149 : subset_resource.id,
4150 : tag,
4151 : subset->base_font,
4152 0 : font_subset->num_glyphs - 1,
4153 : descriptor.id);
4154 :
4155 0 : for (i = 0; i < font_subset->num_glyphs; i++)
4156 0 : _cairo_output_stream_printf (surface->output,
4157 : " %ld",
4158 0 : (long)(subset->widths[i]*PDF_UNITS_PER_EM));
4159 :
4160 0 : _cairo_output_stream_printf (surface->output,
4161 : " ]\n");
4162 :
4163 0 : if (to_unicode_stream.id != 0)
4164 0 : _cairo_output_stream_printf (surface->output,
4165 : " /ToUnicode %d 0 R\n",
4166 : to_unicode_stream.id);
4167 :
4168 0 : _cairo_output_stream_printf (surface->output,
4169 : ">>\n"
4170 : "endobj\n");
4171 :
4172 0 : font.font_id = font_subset->font_id;
4173 0 : font.subset_id = font_subset->subset_id;
4174 0 : font.subset_resource = subset_resource;
4175 0 : return _cairo_array_append (&surface->fonts, &font);
4176 : }
4177 :
4178 : #if CAIRO_HAS_FT_FONT
4179 : static cairo_status_t
4180 0 : _cairo_pdf_surface_emit_type1_font_subset (cairo_pdf_surface_t *surface,
4181 : cairo_scaled_font_subset_t *font_subset)
4182 : {
4183 : cairo_status_t status;
4184 : cairo_type1_subset_t subset;
4185 : char name[64];
4186 :
4187 0 : snprintf (name, sizeof name, "CairoFont-%d-%d",
4188 : font_subset->font_id, font_subset->subset_id);
4189 0 : status = _cairo_type1_subset_init (&subset, name, font_subset, FALSE);
4190 0 : if (unlikely (status))
4191 0 : return status;
4192 :
4193 0 : status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset);
4194 :
4195 0 : _cairo_type1_subset_fini (&subset);
4196 0 : return status;
4197 : }
4198 : #endif
4199 :
4200 : static cairo_status_t
4201 0 : _cairo_pdf_surface_emit_type1_fallback_font (cairo_pdf_surface_t *surface,
4202 : cairo_scaled_font_subset_t *font_subset)
4203 : {
4204 : cairo_status_t status;
4205 : cairo_type1_subset_t subset;
4206 : char name[64];
4207 :
4208 0 : snprintf (name, sizeof name, "CairoFont-%d-%d",
4209 : font_subset->font_id, font_subset->subset_id);
4210 0 : status = _cairo_type1_fallback_init_binary (&subset, name, font_subset);
4211 0 : if (unlikely (status))
4212 0 : return status;
4213 :
4214 0 : status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset);
4215 :
4216 0 : _cairo_type1_fallback_fini (&subset);
4217 0 : return status;
4218 : }
4219 :
4220 : static cairo_status_t
4221 0 : _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
4222 : cairo_scaled_font_subset_t *font_subset)
4223 : {
4224 : cairo_pdf_resource_t stream, descriptor, cidfont_dict;
4225 : cairo_pdf_resource_t subset_resource, to_unicode_stream;
4226 : cairo_status_t status;
4227 : cairo_pdf_font_t font;
4228 : cairo_truetype_subset_t subset;
4229 : unsigned int i;
4230 : char tag[10];
4231 :
4232 0 : subset_resource = _cairo_pdf_surface_get_font_resource (surface,
4233 : font_subset->font_id,
4234 : font_subset->subset_id);
4235 0 : if (subset_resource.id == 0)
4236 0 : return CAIRO_STATUS_SUCCESS;
4237 :
4238 0 : status = _cairo_truetype_subset_init (&subset, font_subset);
4239 0 : if (unlikely (status))
4240 0 : return status;
4241 :
4242 0 : _create_font_subset_tag (font_subset, subset.ps_name, tag);
4243 :
4244 0 : status = _cairo_pdf_surface_open_stream (surface,
4245 : NULL,
4246 : TRUE,
4247 : " /Length1 %lu\n",
4248 : subset.data_length);
4249 0 : if (unlikely (status)) {
4250 0 : _cairo_truetype_subset_fini (&subset);
4251 0 : return status;
4252 : }
4253 :
4254 0 : stream = surface->pdf_stream.self;
4255 0 : _cairo_output_stream_write (surface->output,
4256 0 : subset.data, subset.data_length);
4257 0 : status = _cairo_pdf_surface_close_stream (surface);
4258 0 : if (unlikely (status)) {
4259 0 : _cairo_truetype_subset_fini (&subset);
4260 0 : return status;
4261 : }
4262 :
4263 0 : status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
4264 : font_subset, TRUE,
4265 : &to_unicode_stream);
4266 0 : if (_cairo_status_is_error (status)) {
4267 0 : _cairo_truetype_subset_fini (&subset);
4268 0 : return status;
4269 : }
4270 :
4271 0 : descriptor = _cairo_pdf_surface_new_object (surface);
4272 0 : if (descriptor.id == 0) {
4273 0 : _cairo_truetype_subset_fini (&subset);
4274 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4275 : }
4276 :
4277 0 : _cairo_output_stream_printf (surface->output,
4278 : "%d 0 obj\n"
4279 : "<< /Type /FontDescriptor\n"
4280 : " /FontName /%s+%s\n",
4281 : descriptor.id,
4282 : tag,
4283 : subset.ps_name);
4284 :
4285 0 : if (subset.font_name) {
4286 0 : _cairo_output_stream_printf (surface->output,
4287 : " /FontFamily (%s)\n",
4288 : subset.font_name);
4289 : }
4290 :
4291 0 : _cairo_output_stream_printf (surface->output,
4292 : " /Flags 4\n"
4293 : " /FontBBox [ %ld %ld %ld %ld ]\n"
4294 : " /ItalicAngle 0\n"
4295 : " /Ascent %ld\n"
4296 : " /Descent %ld\n"
4297 : " /CapHeight %ld\n"
4298 : " /StemV 80\n"
4299 : " /StemH 80\n"
4300 : " /FontFile2 %u 0 R\n"
4301 : ">>\n"
4302 : "endobj\n",
4303 0 : (long)(subset.x_min*PDF_UNITS_PER_EM),
4304 0 : (long)(subset.y_min*PDF_UNITS_PER_EM),
4305 0 : (long)(subset.x_max*PDF_UNITS_PER_EM),
4306 0 : (long)(subset.y_max*PDF_UNITS_PER_EM),
4307 0 : (long)(subset.ascent*PDF_UNITS_PER_EM),
4308 0 : (long)(subset.descent*PDF_UNITS_PER_EM),
4309 0 : (long)(subset.y_max*PDF_UNITS_PER_EM),
4310 : stream.id);
4311 :
4312 0 : cidfont_dict = _cairo_pdf_surface_new_object (surface);
4313 0 : if (cidfont_dict.id == 0) {
4314 0 : _cairo_truetype_subset_fini (&subset);
4315 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4316 : }
4317 :
4318 0 : _cairo_output_stream_printf (surface->output,
4319 : "%d 0 obj\n"
4320 : "<< /Type /Font\n"
4321 : " /Subtype /CIDFontType2\n"
4322 : " /BaseFont /%s+%s\n"
4323 : " /CIDSystemInfo\n"
4324 : " << /Registry (Adobe)\n"
4325 : " /Ordering (Identity)\n"
4326 : " /Supplement 0\n"
4327 : " >>\n"
4328 : " /FontDescriptor %d 0 R\n"
4329 : " /W [0 [",
4330 : cidfont_dict.id,
4331 : tag,
4332 : subset.ps_name,
4333 : descriptor.id);
4334 :
4335 0 : for (i = 0; i < font_subset->num_glyphs; i++)
4336 0 : _cairo_output_stream_printf (surface->output,
4337 : " %ld",
4338 0 : (long)(subset.widths[i]*PDF_UNITS_PER_EM));
4339 :
4340 0 : _cairo_output_stream_printf (surface->output,
4341 : " ]]\n"
4342 : ">>\n"
4343 : "endobj\n");
4344 :
4345 0 : _cairo_pdf_surface_update_object (surface, subset_resource);
4346 0 : _cairo_output_stream_printf (surface->output,
4347 : "%d 0 obj\n"
4348 : "<< /Type /Font\n"
4349 : " /Subtype /Type0\n"
4350 : " /BaseFont /%s+%s\n"
4351 : " /Encoding /Identity-H\n"
4352 : " /DescendantFonts [ %d 0 R]\n",
4353 : subset_resource.id,
4354 : tag,
4355 : subset.ps_name,
4356 : cidfont_dict.id);
4357 :
4358 0 : if (to_unicode_stream.id != 0)
4359 0 : _cairo_output_stream_printf (surface->output,
4360 : " /ToUnicode %d 0 R\n",
4361 : to_unicode_stream.id);
4362 :
4363 0 : _cairo_output_stream_printf (surface->output,
4364 : ">>\n"
4365 : "endobj\n");
4366 :
4367 0 : font.font_id = font_subset->font_id;
4368 0 : font.subset_id = font_subset->subset_id;
4369 0 : font.subset_resource = subset_resource;
4370 0 : status = _cairo_array_append (&surface->fonts, &font);
4371 :
4372 0 : _cairo_truetype_subset_fini (&subset);
4373 :
4374 0 : return status;
4375 : }
4376 :
4377 : static cairo_status_t
4378 0 : _cairo_pdf_emit_imagemask (cairo_image_surface_t *image,
4379 : cairo_output_stream_t *stream)
4380 : {
4381 : uint8_t *byte, output_byte;
4382 : int row, col, num_cols;
4383 :
4384 : /* The only image type supported by Type 3 fonts are 1-bit image
4385 : * masks */
4386 0 : assert (image->format == CAIRO_FORMAT_A1);
4387 :
4388 0 : _cairo_output_stream_printf (stream,
4389 : "BI\n"
4390 : "/IM true\n"
4391 : "/W %d\n"
4392 : "/H %d\n"
4393 : "/BPC 1\n"
4394 : "/D [1 0]\n",
4395 : image->width,
4396 : image->height);
4397 :
4398 0 : _cairo_output_stream_printf (stream,
4399 : "ID ");
4400 :
4401 0 : num_cols = (image->width + 7) / 8;
4402 0 : for (row = 0; row < image->height; row++) {
4403 0 : byte = image->data + row * image->stride;
4404 0 : for (col = 0; col < num_cols; col++) {
4405 0 : output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
4406 0 : _cairo_output_stream_write (stream, &output_byte, 1);
4407 0 : byte++;
4408 : }
4409 : }
4410 :
4411 0 : _cairo_output_stream_printf (stream,
4412 : "\nEI\n");
4413 :
4414 0 : return _cairo_output_stream_get_status (stream);
4415 : }
4416 :
4417 : static cairo_status_t
4418 0 : _cairo_pdf_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset,
4419 : void *closure)
4420 : {
4421 0 : cairo_pdf_surface_t *surface = closure;
4422 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
4423 : cairo_status_t status2;
4424 : unsigned int i;
4425 : cairo_surface_t *type3_surface;
4426 : cairo_output_stream_t *null_stream;
4427 :
4428 0 : null_stream = _cairo_null_stream_create ();
4429 0 : type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
4430 : null_stream,
4431 : _cairo_pdf_emit_imagemask,
4432 : surface->font_subsets);
4433 0 : if (unlikely (type3_surface->status)) {
4434 0 : status2 = _cairo_output_stream_destroy (null_stream);
4435 0 : return type3_surface->status;
4436 : }
4437 :
4438 0 : _cairo_type3_glyph_surface_set_font_subsets_callback (type3_surface,
4439 : _cairo_pdf_surface_add_font,
4440 : surface);
4441 :
4442 0 : for (i = 0; i < font_subset->num_glyphs; i++) {
4443 0 : status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
4444 0 : font_subset->glyphs[i]);
4445 0 : if (unlikely (status))
4446 0 : break;
4447 : }
4448 :
4449 0 : cairo_surface_destroy (type3_surface);
4450 0 : status2 = _cairo_output_stream_destroy (null_stream);
4451 0 : if (status == CAIRO_STATUS_SUCCESS)
4452 0 : status = status2;
4453 :
4454 0 : return status;
4455 : }
4456 :
4457 : static cairo_status_t
4458 0 : _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
4459 : cairo_scaled_font_subset_t *font_subset)
4460 : {
4461 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
4462 : cairo_pdf_resource_t *glyphs, encoding, char_procs, subset_resource, to_unicode_stream;
4463 : cairo_pdf_font_t font;
4464 : double *widths;
4465 : unsigned int i;
4466 0 : cairo_box_t font_bbox = {{0,0},{0,0}};
4467 0 : cairo_box_t bbox = {{0,0},{0,0}};
4468 : cairo_surface_t *type3_surface;
4469 :
4470 0 : if (font_subset->num_glyphs == 0)
4471 0 : return CAIRO_STATUS_SUCCESS;
4472 :
4473 0 : subset_resource = _cairo_pdf_surface_get_font_resource (surface,
4474 : font_subset->font_id,
4475 : font_subset->subset_id);
4476 0 : if (subset_resource.id == 0)
4477 0 : return CAIRO_STATUS_SUCCESS;
4478 :
4479 0 : glyphs = _cairo_malloc_ab (font_subset->num_glyphs, sizeof (cairo_pdf_resource_t));
4480 0 : if (unlikely (glyphs == NULL))
4481 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4482 :
4483 0 : widths = _cairo_malloc_ab (font_subset->num_glyphs, sizeof (double));
4484 0 : if (unlikely (widths == NULL)) {
4485 0 : free (glyphs);
4486 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4487 : }
4488 :
4489 0 : _cairo_pdf_group_resources_clear (&surface->resources);
4490 0 : type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
4491 : NULL,
4492 : _cairo_pdf_emit_imagemask,
4493 : surface->font_subsets);
4494 0 : if (unlikely (type3_surface->status)) {
4495 0 : free (glyphs);
4496 0 : free (widths);
4497 0 : return type3_surface->status;
4498 : }
4499 :
4500 0 : _cairo_type3_glyph_surface_set_font_subsets_callback (type3_surface,
4501 : _cairo_pdf_surface_add_font,
4502 : surface);
4503 :
4504 0 : for (i = 0; i < font_subset->num_glyphs; i++) {
4505 0 : status = _cairo_pdf_surface_open_stream (surface,
4506 : NULL,
4507 : surface->compress_content,
4508 : NULL);
4509 0 : if (unlikely (status))
4510 0 : break;
4511 :
4512 0 : glyphs[i] = surface->pdf_stream.self;
4513 0 : status = _cairo_type3_glyph_surface_emit_glyph (type3_surface,
4514 : surface->output,
4515 0 : font_subset->glyphs[i],
4516 : &bbox,
4517 0 : &widths[i]);
4518 0 : if (unlikely (status))
4519 0 : break;
4520 :
4521 0 : status = _cairo_pdf_surface_close_stream (surface);
4522 0 : if (unlikely (status))
4523 0 : break;
4524 :
4525 0 : if (i == 0) {
4526 0 : font_bbox.p1.x = bbox.p1.x;
4527 0 : font_bbox.p1.y = bbox.p1.y;
4528 0 : font_bbox.p2.x = bbox.p2.x;
4529 0 : font_bbox.p2.y = bbox.p2.y;
4530 : } else {
4531 0 : if (bbox.p1.x < font_bbox.p1.x)
4532 0 : font_bbox.p1.x = bbox.p1.x;
4533 0 : if (bbox.p1.y < font_bbox.p1.y)
4534 0 : font_bbox.p1.y = bbox.p1.y;
4535 0 : if (bbox.p2.x > font_bbox.p2.x)
4536 0 : font_bbox.p2.x = bbox.p2.x;
4537 0 : if (bbox.p2.y > font_bbox.p2.y)
4538 0 : font_bbox.p2.y = bbox.p2.y;
4539 : }
4540 : }
4541 0 : cairo_surface_destroy (type3_surface);
4542 0 : if (unlikely (status)) {
4543 0 : free (glyphs);
4544 0 : free (widths);
4545 0 : return status;
4546 : }
4547 :
4548 0 : encoding = _cairo_pdf_surface_new_object (surface);
4549 0 : if (encoding.id == 0) {
4550 0 : free (glyphs);
4551 0 : free (widths);
4552 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4553 : }
4554 :
4555 0 : _cairo_output_stream_printf (surface->output,
4556 : "%d 0 obj\n"
4557 : "<< /Type /Encoding\n"
4558 : " /Differences [0", encoding.id);
4559 0 : for (i = 0; i < font_subset->num_glyphs; i++)
4560 0 : _cairo_output_stream_printf (surface->output,
4561 : " /%d", i);
4562 0 : _cairo_output_stream_printf (surface->output,
4563 : "]\n"
4564 : ">>\n"
4565 : "endobj\n");
4566 :
4567 0 : char_procs = _cairo_pdf_surface_new_object (surface);
4568 0 : if (char_procs.id == 0) {
4569 0 : free (glyphs);
4570 0 : free (widths);
4571 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4572 : }
4573 :
4574 0 : _cairo_output_stream_printf (surface->output,
4575 : "%d 0 obj\n"
4576 : "<<\n", char_procs.id);
4577 0 : for (i = 0; i < font_subset->num_glyphs; i++)
4578 0 : _cairo_output_stream_printf (surface->output,
4579 : " /%d %d 0 R\n",
4580 0 : i, glyphs[i].id);
4581 0 : _cairo_output_stream_printf (surface->output,
4582 : ">>\n"
4583 : "endobj\n");
4584 :
4585 0 : free (glyphs);
4586 :
4587 0 : status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
4588 : font_subset, FALSE,
4589 : &to_unicode_stream);
4590 0 : if (_cairo_status_is_error (status)) {
4591 0 : free (widths);
4592 0 : return status;
4593 : }
4594 :
4595 0 : _cairo_pdf_surface_update_object (surface, subset_resource);
4596 0 : _cairo_output_stream_printf (surface->output,
4597 : "%d 0 obj\n"
4598 : "<< /Type /Font\n"
4599 : " /Subtype /Type3\n"
4600 : " /FontBBox [%f %f %f %f]\n"
4601 : " /FontMatrix [ 1 0 0 1 0 0 ]\n"
4602 : " /Encoding %d 0 R\n"
4603 : " /CharProcs %d 0 R\n"
4604 : " /FirstChar 0\n"
4605 : " /LastChar %d\n",
4606 : subset_resource.id,
4607 : _cairo_fixed_to_double (font_bbox.p1.x),
4608 0 : - _cairo_fixed_to_double (font_bbox.p2.y),
4609 : _cairo_fixed_to_double (font_bbox.p2.x),
4610 0 : - _cairo_fixed_to_double (font_bbox.p1.y),
4611 : encoding.id,
4612 : char_procs.id,
4613 0 : font_subset->num_glyphs - 1);
4614 :
4615 0 : _cairo_output_stream_printf (surface->output,
4616 : " /Widths [");
4617 0 : for (i = 0; i < font_subset->num_glyphs; i++)
4618 0 : _cairo_output_stream_printf (surface->output, " %f", widths[i]);
4619 0 : _cairo_output_stream_printf (surface->output,
4620 : "]\n");
4621 0 : free (widths);
4622 :
4623 0 : _cairo_output_stream_printf (surface->output,
4624 : " /Resources\n");
4625 0 : _cairo_pdf_surface_emit_group_resources (surface, &surface->resources);
4626 :
4627 0 : if (to_unicode_stream.id != 0)
4628 0 : _cairo_output_stream_printf (surface->output,
4629 : " /ToUnicode %d 0 R\n",
4630 : to_unicode_stream.id);
4631 :
4632 0 : _cairo_output_stream_printf (surface->output,
4633 : ">>\n"
4634 : "endobj\n");
4635 :
4636 0 : font.font_id = font_subset->font_id;
4637 0 : font.subset_id = font_subset->subset_id;
4638 0 : font.subset_resource = subset_resource;
4639 0 : return _cairo_array_append (&surface->fonts, &font);
4640 : }
4641 :
4642 : static cairo_status_t
4643 0 : _cairo_pdf_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset,
4644 : void *closure)
4645 : {
4646 0 : cairo_pdf_surface_t *surface = closure;
4647 : cairo_status_t status;
4648 :
4649 0 : if (font_subset->is_composite) {
4650 0 : status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset);
4651 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
4652 0 : return status;
4653 :
4654 0 : status = _cairo_pdf_surface_emit_truetype_font_subset (surface, font_subset);
4655 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
4656 0 : return status;
4657 :
4658 0 : status = _cairo_pdf_surface_emit_cff_fallback_font (surface, font_subset);
4659 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
4660 0 : return status;
4661 : } else {
4662 : #if CAIRO_HAS_FT_FONT
4663 0 : status = _cairo_pdf_surface_emit_type1_font_subset (surface, font_subset);
4664 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
4665 0 : return status;
4666 : #endif
4667 :
4668 0 : status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset);
4669 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
4670 0 : return status;
4671 :
4672 : }
4673 :
4674 0 : ASSERT_NOT_REACHED;
4675 0 : return CAIRO_STATUS_SUCCESS;
4676 : }
4677 :
4678 : static cairo_status_t
4679 0 : _cairo_pdf_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset,
4680 : void *closure)
4681 : {
4682 0 : cairo_pdf_surface_t *surface = closure;
4683 : cairo_status_t status;
4684 :
4685 0 : status = _cairo_pdf_surface_emit_type3_font_subset (surface, font_subset);
4686 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
4687 0 : return status;
4688 :
4689 0 : ASSERT_NOT_REACHED;
4690 0 : return CAIRO_STATUS_SUCCESS;
4691 : }
4692 :
4693 : static cairo_status_t
4694 0 : _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface)
4695 : {
4696 : cairo_status_t status;
4697 :
4698 0 : status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
4699 : _cairo_pdf_surface_analyze_user_font_subset,
4700 : surface);
4701 0 : if (unlikely (status))
4702 0 : goto BAIL;
4703 :
4704 0 : status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
4705 : _cairo_pdf_surface_emit_unscaled_font_subset,
4706 : surface);
4707 0 : if (unlikely (status))
4708 0 : goto BAIL;
4709 :
4710 0 : status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
4711 : _cairo_pdf_surface_emit_scaled_font_subset,
4712 : surface);
4713 0 : if (unlikely (status))
4714 0 : goto BAIL;
4715 :
4716 0 : status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
4717 : _cairo_pdf_surface_emit_scaled_font_subset,
4718 : surface);
4719 :
4720 : BAIL:
4721 0 : _cairo_scaled_font_subsets_destroy (surface->font_subsets);
4722 0 : surface->font_subsets = NULL;
4723 :
4724 0 : return status;
4725 : }
4726 :
4727 : static cairo_pdf_resource_t
4728 0 : _cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface)
4729 : {
4730 : cairo_pdf_resource_t catalog;
4731 :
4732 0 : catalog = _cairo_pdf_surface_new_object (surface);
4733 0 : if (catalog.id == 0)
4734 0 : return catalog;
4735 :
4736 0 : _cairo_output_stream_printf (surface->output,
4737 : "%d 0 obj\n"
4738 : "<< /Type /Catalog\n"
4739 : " /Pages %d 0 R\n"
4740 : ">>\n"
4741 : "endobj\n",
4742 : catalog.id,
4743 : surface->pages_resource.id);
4744 :
4745 0 : return catalog;
4746 : }
4747 :
4748 : static long
4749 0 : _cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface)
4750 : {
4751 : cairo_pdf_object_t *object;
4752 : int num_objects, i;
4753 : long offset;
4754 : char buffer[11];
4755 :
4756 0 : num_objects = _cairo_array_num_elements (&surface->objects);
4757 :
4758 0 : offset = _cairo_output_stream_get_position (surface->output);
4759 0 : _cairo_output_stream_printf (surface->output,
4760 : "xref\n"
4761 : "%d %d\n",
4762 : 0, num_objects + 1);
4763 :
4764 0 : _cairo_output_stream_printf (surface->output,
4765 : "0000000000 65535 f \n");
4766 0 : for (i = 0; i < num_objects; i++) {
4767 0 : object = _cairo_array_index (&surface->objects, i);
4768 0 : snprintf (buffer, sizeof buffer, "%010ld", object->offset);
4769 0 : _cairo_output_stream_printf (surface->output,
4770 : "%s 00000 n \n", buffer);
4771 : }
4772 :
4773 0 : return offset;
4774 : }
4775 :
4776 : static cairo_status_t
4777 0 : _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
4778 : cairo_pdf_smask_group_t *group)
4779 : {
4780 : cairo_pdf_resource_t mask_group;
4781 : cairo_pdf_resource_t smask;
4782 : cairo_pdf_smask_group_t *smask_group;
4783 : cairo_pdf_resource_t pattern_res, gstate_res;
4784 : cairo_status_t status;
4785 :
4786 : /* Create mask group */
4787 0 : status = _cairo_pdf_surface_open_group (surface, NULL);
4788 0 : if (unlikely (status))
4789 0 : return status;
4790 :
4791 0 : pattern_res.id = 0;
4792 0 : gstate_res.id = 0;
4793 0 : status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask, NULL,
4794 : &pattern_res, &gstate_res);
4795 0 : if (unlikely (status))
4796 0 : return status;
4797 :
4798 0 : if (gstate_res.id != 0) {
4799 0 : smask_group = _cairo_pdf_surface_create_smask_group (surface);
4800 0 : if (unlikely (smask_group == NULL))
4801 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4802 :
4803 0 : smask_group->operation = PDF_PAINT;
4804 0 : smask_group->source = cairo_pattern_reference (group->mask);
4805 0 : smask_group->source_res = pattern_res;
4806 0 : status = _cairo_pdf_surface_add_smask_group (surface, smask_group);
4807 0 : if (unlikely (status)) {
4808 0 : _cairo_pdf_smask_group_destroy (smask_group);
4809 0 : return status;
4810 : }
4811 :
4812 0 : status = _cairo_pdf_surface_add_smask (surface, gstate_res);
4813 0 : if (unlikely (status))
4814 0 : return status;
4815 :
4816 0 : status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res);
4817 0 : if (unlikely (status))
4818 0 : return status;
4819 :
4820 0 : _cairo_output_stream_printf (surface->output,
4821 : "q /s%d gs /x%d Do Q\n",
4822 : gstate_res.id,
4823 : smask_group->group_res.id);
4824 : } else {
4825 0 : status = _cairo_pdf_surface_select_pattern (surface, group->mask, pattern_res, FALSE);
4826 0 : if (unlikely (status))
4827 0 : return status;
4828 :
4829 0 : _cairo_output_stream_printf (surface->output,
4830 : "0 0 %f %f re f\n",
4831 : surface->width, surface->height);
4832 :
4833 0 : status = _cairo_pdf_surface_unselect_pattern (surface);
4834 0 : if (unlikely (status))
4835 0 : return status;
4836 : }
4837 :
4838 0 : status = _cairo_pdf_surface_close_group (surface, &mask_group);
4839 0 : if (unlikely (status))
4840 0 : return status;
4841 :
4842 : /* Create source group */
4843 0 : status = _cairo_pdf_surface_open_group (surface, &group->source_res);
4844 0 : if (unlikely (status))
4845 0 : return status;
4846 :
4847 0 : pattern_res.id = 0;
4848 0 : gstate_res.id = 0;
4849 0 : status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source, NULL,
4850 : &pattern_res, &gstate_res);
4851 0 : if (unlikely (status))
4852 0 : return status;
4853 :
4854 0 : if (gstate_res.id != 0) {
4855 0 : smask_group = _cairo_pdf_surface_create_smask_group (surface);
4856 0 : if (unlikely (smask_group == NULL))
4857 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4858 :
4859 0 : smask_group->operation = PDF_PAINT;
4860 0 : smask_group->source = cairo_pattern_reference (group->source);
4861 0 : smask_group->source_res = pattern_res;
4862 0 : status = _cairo_pdf_surface_add_smask_group (surface, smask_group);
4863 0 : if (unlikely (status)) {
4864 0 : _cairo_pdf_smask_group_destroy (smask_group);
4865 0 : return status;
4866 : }
4867 :
4868 0 : status = _cairo_pdf_surface_add_smask (surface, gstate_res);
4869 0 : if (unlikely (status))
4870 0 : return status;
4871 :
4872 0 : status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res);
4873 0 : if (unlikely (status))
4874 0 : return status;
4875 :
4876 0 : _cairo_output_stream_printf (surface->output,
4877 : "q /s%d gs /x%d Do Q\n",
4878 : gstate_res.id,
4879 : smask_group->group_res.id);
4880 : } else {
4881 0 : status = _cairo_pdf_surface_select_pattern (surface, group->source, pattern_res, FALSE);
4882 0 : if (unlikely (status))
4883 0 : return status;
4884 :
4885 0 : _cairo_output_stream_printf (surface->output,
4886 : "0 0 %f %f re f\n",
4887 : surface->width, surface->height);
4888 :
4889 0 : status = _cairo_pdf_surface_unselect_pattern (surface);
4890 0 : if (unlikely (status))
4891 0 : return status;
4892 : }
4893 :
4894 0 : status = _cairo_pdf_surface_close_group (surface, NULL);
4895 0 : if (unlikely (status))
4896 0 : return status;
4897 :
4898 : /* Create an smask based on the alpha component of mask_group */
4899 0 : smask = _cairo_pdf_surface_new_object (surface);
4900 0 : if (smask.id == 0)
4901 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4902 :
4903 0 : _cairo_output_stream_printf (surface->output,
4904 : "%d 0 obj\n"
4905 : "<< /Type /Mask\n"
4906 : " /S /Alpha\n"
4907 : " /G %d 0 R\n"
4908 : ">>\n"
4909 : "endobj\n",
4910 : smask.id,
4911 : mask_group.id);
4912 :
4913 : /* Create a GState that uses the smask */
4914 0 : _cairo_pdf_surface_update_object (surface, group->group_res);
4915 0 : _cairo_output_stream_printf (surface->output,
4916 : "%d 0 obj\n"
4917 : "<< /Type /ExtGState\n"
4918 : " /SMask %d 0 R\n"
4919 : " /ca 1\n"
4920 : " /CA 1\n"
4921 : " /AIS false\n"
4922 : ">>\n"
4923 : "endobj\n",
4924 : group->group_res.id,
4925 : smask.id);
4926 :
4927 0 : return _cairo_output_stream_get_status (surface->output);
4928 : }
4929 :
4930 : static cairo_status_t
4931 0 : _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface,
4932 : cairo_pdf_smask_group_t *group)
4933 : {
4934 : double old_width, old_height;
4935 : cairo_status_t status;
4936 :
4937 0 : old_width = surface->width;
4938 0 : old_height = surface->height;
4939 0 : _cairo_pdf_surface_set_size_internal (surface,
4940 : group->width,
4941 : group->height);
4942 : /* _mask is a special case that requires two groups - source
4943 : * and mask as well as a smask and gstate dictionary */
4944 0 : if (group->operation == PDF_MASK) {
4945 0 : status = _cairo_pdf_surface_write_mask_group (surface, group);
4946 0 : goto RESTORE_SIZE;
4947 : }
4948 :
4949 0 : status = _cairo_pdf_surface_open_group (surface, &group->group_res);
4950 0 : if (unlikely (status))
4951 0 : return status;
4952 :
4953 0 : status = _cairo_pdf_surface_select_pattern (surface,
4954 0 : group->source,
4955 : group->source_res,
4956 0 : group->operation == PDF_STROKE);
4957 0 : if (unlikely (status))
4958 0 : return status;
4959 :
4960 0 : switch (group->operation) {
4961 : case PDF_PAINT:
4962 0 : _cairo_output_stream_printf (surface->output,
4963 : "0 0 %f %f re f\n",
4964 : surface->width, surface->height);
4965 0 : break;
4966 : case PDF_MASK:
4967 0 : ASSERT_NOT_REACHED;
4968 0 : break;
4969 : case PDF_FILL:
4970 0 : status = _cairo_pdf_operators_fill (&surface->pdf_operators,
4971 : &group->path,
4972 : group->fill_rule);
4973 0 : break;
4974 : case PDF_STROKE:
4975 0 : status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
4976 : &group->path,
4977 0 : &group->style,
4978 0 : &group->ctm,
4979 0 : &group->ctm_inverse);
4980 0 : break;
4981 : case PDF_SHOW_GLYPHS:
4982 0 : status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
4983 0 : group->utf8, group->utf8_len,
4984 : group->glyphs, group->num_glyphs,
4985 0 : group->clusters, group->num_clusters,
4986 0 : group->cluster_flags,
4987 : group->scaled_font);
4988 0 : break;
4989 : }
4990 0 : if (unlikely (status))
4991 0 : return status;
4992 :
4993 0 : status = _cairo_pdf_surface_unselect_pattern (surface);
4994 0 : if (unlikely (status))
4995 0 : return status;
4996 :
4997 0 : status = _cairo_pdf_surface_close_group (surface, NULL);
4998 :
4999 : RESTORE_SIZE:
5000 0 : _cairo_pdf_surface_set_size_internal (surface,
5001 : old_width,
5002 : old_height);
5003 :
5004 0 : return status;
5005 : }
5006 :
5007 : static cairo_status_t
5008 0 : _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface)
5009 : {
5010 : cairo_pdf_pattern_t pattern;
5011 : cairo_pdf_smask_group_t *group;
5012 : cairo_pdf_source_surface_t src_surface;
5013 : int pattern_index, group_index, surface_index;
5014 : cairo_status_t status;
5015 :
5016 : /* Writing out PDF_MASK groups will cause additional smask groups
5017 : * to be appended to surface->smask_groups. Additional patterns
5018 : * may also be appended to surface->patterns.
5019 : *
5020 : * Writing recording surface patterns will cause additional patterns
5021 : * and groups to be appended.
5022 : */
5023 0 : pattern_index = 0;
5024 0 : group_index = 0;
5025 0 : surface_index = 0;
5026 0 : while ((pattern_index < _cairo_array_num_elements (&surface->page_patterns)) ||
5027 0 : (group_index < _cairo_array_num_elements (&surface->smask_groups)) ||
5028 0 : (surface_index < _cairo_array_num_elements (&surface->page_surfaces)))
5029 : {
5030 0 : for (; group_index < _cairo_array_num_elements (&surface->smask_groups); group_index++) {
5031 0 : _cairo_array_copy_element (&surface->smask_groups, group_index, &group);
5032 0 : status = _cairo_pdf_surface_write_smask_group (surface, group);
5033 0 : if (unlikely (status))
5034 0 : return status;
5035 : }
5036 :
5037 0 : for (; pattern_index < _cairo_array_num_elements (&surface->page_patterns); pattern_index++) {
5038 0 : _cairo_array_copy_element (&surface->page_patterns, pattern_index, &pattern);
5039 0 : status = _cairo_pdf_surface_emit_pattern (surface, &pattern);
5040 0 : if (unlikely (status))
5041 0 : return status;
5042 : }
5043 :
5044 0 : for (; surface_index < _cairo_array_num_elements (&surface->page_surfaces); surface_index++) {
5045 0 : _cairo_array_copy_element (&surface->page_surfaces, surface_index, &src_surface);
5046 0 : status = _cairo_pdf_surface_emit_surface (surface, &src_surface);
5047 0 : if (unlikely (status))
5048 0 : return status;
5049 : }
5050 : }
5051 :
5052 0 : return CAIRO_STATUS_SUCCESS;
5053 : }
5054 :
5055 : static cairo_status_t
5056 0 : _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
5057 : {
5058 : cairo_pdf_resource_t page, knockout, res;
5059 : cairo_status_t status;
5060 : int i, len;
5061 :
5062 0 : _cairo_pdf_group_resources_clear (&surface->resources);
5063 0 : if (surface->has_fallback_images) {
5064 0 : status = _cairo_pdf_surface_open_knockout_group (surface);
5065 0 : if (unlikely (status))
5066 0 : return status;
5067 :
5068 0 : len = _cairo_array_num_elements (&surface->knockout_group);
5069 0 : for (i = 0; i < len; i++) {
5070 0 : _cairo_array_copy_element (&surface->knockout_group, i, &res);
5071 0 : _cairo_output_stream_printf (surface->output,
5072 : "/x%d Do\n",
5073 : res.id);
5074 0 : status = _cairo_pdf_surface_add_xobject (surface, res);
5075 0 : if (unlikely (status))
5076 0 : return status;
5077 : }
5078 0 : _cairo_output_stream_printf (surface->output,
5079 : "/x%d Do\n",
5080 : surface->content.id);
5081 0 : status = _cairo_pdf_surface_add_xobject (surface, surface->content);
5082 0 : if (unlikely (status))
5083 0 : return status;
5084 :
5085 0 : status = _cairo_pdf_surface_close_group (surface, &knockout);
5086 0 : if (unlikely (status))
5087 0 : return status;
5088 :
5089 0 : _cairo_pdf_group_resources_clear (&surface->resources);
5090 0 : status = _cairo_pdf_surface_open_content_stream (surface, NULL, FALSE);
5091 0 : if (unlikely (status))
5092 0 : return status;
5093 :
5094 0 : _cairo_output_stream_printf (surface->output,
5095 : "/x%d Do\n",
5096 : knockout.id);
5097 0 : status = _cairo_pdf_surface_add_xobject (surface, knockout);
5098 0 : if (unlikely (status))
5099 0 : return status;
5100 :
5101 0 : status = _cairo_pdf_surface_close_content_stream (surface);
5102 0 : if (unlikely (status))
5103 0 : return status;
5104 : }
5105 :
5106 0 : page = _cairo_pdf_surface_new_object (surface);
5107 0 : if (page.id == 0)
5108 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5109 :
5110 0 : _cairo_output_stream_printf (surface->output,
5111 : "%d 0 obj\n"
5112 : "<< /Type /Page\n"
5113 : " /Parent %d 0 R\n"
5114 : " /MediaBox [ 0 0 %f %f ]\n"
5115 : " /Contents %d 0 R\n"
5116 : " /Group <<\n"
5117 : " /Type /Group\n"
5118 : " /S /Transparency\n"
5119 : " /CS /DeviceRGB\n"
5120 : " >>\n"
5121 : " /Resources %d 0 R\n"
5122 : ">>\n"
5123 : "endobj\n",
5124 : page.id,
5125 : surface->pages_resource.id,
5126 : surface->width,
5127 : surface->height,
5128 : surface->content.id,
5129 : surface->content_resources.id);
5130 :
5131 0 : status = _cairo_array_append (&surface->pages, &page);
5132 0 : if (unlikely (status))
5133 0 : return status;
5134 :
5135 0 : status = _cairo_pdf_surface_write_patterns_and_smask_groups (surface);
5136 0 : if (unlikely (status))
5137 0 : return status;
5138 :
5139 0 : return CAIRO_STATUS_SUCCESS;
5140 : }
5141 :
5142 : static cairo_int_status_t
5143 0 : _cairo_pdf_surface_analyze_surface_pattern_transparency (cairo_pdf_surface_t *surface,
5144 : cairo_surface_pattern_t *pattern)
5145 : {
5146 : cairo_image_surface_t *image;
5147 : void *image_extra;
5148 : cairo_int_status_t status;
5149 : cairo_image_transparency_t transparency;
5150 :
5151 0 : status = _cairo_surface_acquire_source_image (pattern->surface,
5152 : &image,
5153 : &image_extra);
5154 0 : if (unlikely (status))
5155 0 : return status;
5156 :
5157 0 : if (image->base.status)
5158 0 : return image->base.status;
5159 :
5160 0 : transparency = _cairo_image_analyze_transparency (image);
5161 0 : if (transparency == CAIRO_IMAGE_IS_OPAQUE)
5162 0 : status = CAIRO_STATUS_SUCCESS;
5163 : else
5164 0 : status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
5165 :
5166 0 : _cairo_surface_release_source_image (pattern->surface, image, image_extra);
5167 :
5168 0 : return status;
5169 : }
5170 :
5171 : static cairo_bool_t
5172 0 : _surface_pattern_supported (cairo_surface_pattern_t *pattern)
5173 : {
5174 : cairo_extend_t extend;
5175 :
5176 0 : if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
5177 0 : return TRUE;
5178 :
5179 0 : if (pattern->surface->backend->acquire_source_image == NULL)
5180 0 : return FALSE;
5181 :
5182 : /* Does an ALPHA-only source surface even make sense? Maybe, but I
5183 : * don't think it's worth the extra code to support it. */
5184 :
5185 : /* XXX: Need to write this function here...
5186 : content = cairo_surface_get_content (pattern->surface);
5187 : if (content == CAIRO_CONTENT_ALPHA)
5188 : return FALSE;
5189 : */
5190 :
5191 0 : extend = cairo_pattern_get_extend (&pattern->base);
5192 0 : switch (extend) {
5193 : case CAIRO_EXTEND_NONE:
5194 : case CAIRO_EXTEND_REPEAT:
5195 : case CAIRO_EXTEND_REFLECT:
5196 : /* There's no point returning FALSE for EXTEND_PAD, as the image
5197 : * surface does not currently implement it either */
5198 : case CAIRO_EXTEND_PAD:
5199 0 : return TRUE;
5200 : }
5201 :
5202 0 : ASSERT_NOT_REACHED;
5203 0 : return FALSE;
5204 : }
5205 :
5206 : static cairo_bool_t
5207 0 : _gradient_pattern_supported (const cairo_pattern_t *pattern)
5208 : {
5209 : cairo_extend_t extend;
5210 :
5211 0 : extend = cairo_pattern_get_extend ((cairo_pattern_t *) pattern);
5212 :
5213 :
5214 : /* Radial gradients are currently only supported with EXTEND_NONE
5215 : * and EXTEND_PAD and when one circle is inside the other. */
5216 0 : if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
5217 : double x1, y1, x2, y2, r1, r2, d;
5218 0 : cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
5219 :
5220 0 : if (extend == CAIRO_EXTEND_REPEAT ||
5221 : extend == CAIRO_EXTEND_REFLECT) {
5222 0 : return FALSE;
5223 : }
5224 :
5225 0 : x1 = _cairo_fixed_to_double (radial->c1.x);
5226 0 : y1 = _cairo_fixed_to_double (radial->c1.y);
5227 0 : r1 = _cairo_fixed_to_double (radial->r1);
5228 0 : x2 = _cairo_fixed_to_double (radial->c2.x);
5229 0 : y2 = _cairo_fixed_to_double (radial->c2.y);
5230 0 : r2 = _cairo_fixed_to_double (radial->r2);
5231 :
5232 0 : d = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
5233 0 : if (d > fabs(r2 - r1)) {
5234 0 : return FALSE;
5235 : }
5236 : }
5237 :
5238 0 : return TRUE;
5239 : }
5240 :
5241 : static cairo_bool_t
5242 0 : _pattern_supported (const cairo_pattern_t *pattern)
5243 : {
5244 0 : if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
5245 0 : return TRUE;
5246 :
5247 0 : if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
5248 0 : pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
5249 0 : return _gradient_pattern_supported (pattern);
5250 :
5251 0 : if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
5252 0 : return _surface_pattern_supported ((cairo_surface_pattern_t *) pattern);
5253 :
5254 0 : return FALSE;
5255 : }
5256 :
5257 : static cairo_bool_t
5258 0 : _pdf_operator_supported (cairo_operator_t op)
5259 : {
5260 0 : switch (op) {
5261 : case CAIRO_OPERATOR_OVER:
5262 : case CAIRO_OPERATOR_MULTIPLY:
5263 : case CAIRO_OPERATOR_SCREEN:
5264 : case CAIRO_OPERATOR_OVERLAY:
5265 : case CAIRO_OPERATOR_DARKEN:
5266 : case CAIRO_OPERATOR_LIGHTEN:
5267 : case CAIRO_OPERATOR_COLOR_DODGE:
5268 : case CAIRO_OPERATOR_COLOR_BURN:
5269 : case CAIRO_OPERATOR_HARD_LIGHT:
5270 : case CAIRO_OPERATOR_SOFT_LIGHT:
5271 : case CAIRO_OPERATOR_DIFFERENCE:
5272 : case CAIRO_OPERATOR_EXCLUSION:
5273 : case CAIRO_OPERATOR_HSL_HUE:
5274 : case CAIRO_OPERATOR_HSL_SATURATION:
5275 : case CAIRO_OPERATOR_HSL_COLOR:
5276 : case CAIRO_OPERATOR_HSL_LUMINOSITY:
5277 0 : return TRUE;
5278 :
5279 : default:
5280 : case CAIRO_OPERATOR_CLEAR:
5281 : case CAIRO_OPERATOR_SOURCE:
5282 : case CAIRO_OPERATOR_IN:
5283 : case CAIRO_OPERATOR_OUT:
5284 : case CAIRO_OPERATOR_ATOP:
5285 : case CAIRO_OPERATOR_DEST:
5286 : case CAIRO_OPERATOR_DEST_OVER:
5287 : case CAIRO_OPERATOR_DEST_IN:
5288 : case CAIRO_OPERATOR_DEST_OUT:
5289 : case CAIRO_OPERATOR_DEST_ATOP:
5290 : case CAIRO_OPERATOR_XOR:
5291 : case CAIRO_OPERATOR_ADD:
5292 : case CAIRO_OPERATOR_SATURATE:
5293 0 : return FALSE;
5294 : }
5295 : }
5296 :
5297 : static cairo_int_status_t
5298 0 : _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
5299 : cairo_operator_t op,
5300 : const cairo_pattern_t *pattern,
5301 : const cairo_rectangle_int_t *extents)
5302 : {
5303 0 : if (surface->force_fallbacks &&
5304 0 : surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
5305 : {
5306 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
5307 : }
5308 :
5309 0 : if (! _pattern_supported (pattern))
5310 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
5311 :
5312 0 : if (_pdf_operator_supported (op)) {
5313 0 : if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
5314 0 : cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
5315 :
5316 0 : if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
5317 0 : if (pattern->extend == CAIRO_EXTEND_PAD)
5318 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
5319 : else
5320 0 : return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
5321 : }
5322 : }
5323 :
5324 0 : return CAIRO_STATUS_SUCCESS;
5325 : }
5326 :
5327 :
5328 : /* The SOURCE operator is supported if the pattern is opaque or if
5329 : * there is nothing painted underneath. */
5330 0 : if (op == CAIRO_OPERATOR_SOURCE) {
5331 0 : if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
5332 0 : cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
5333 :
5334 0 : if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
5335 0 : if (_cairo_pattern_is_opaque (pattern, extents)) {
5336 0 : return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
5337 : } else {
5338 : /* FIXME: The analysis surface does not yet have
5339 : * the capability to analyze a non opaque recording
5340 : * surface and mark it supported if there is
5341 : * nothing underneath. For now recording surfaces of
5342 : * type CONTENT_COLOR_ALPHA painted with
5343 : * OPERATOR_SOURCE will result in a fallback
5344 : * image. */
5345 :
5346 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
5347 : }
5348 : } else {
5349 0 : return _cairo_pdf_surface_analyze_surface_pattern_transparency (surface,
5350 : surface_pattern);
5351 : }
5352 : }
5353 :
5354 0 : if (_cairo_pattern_is_opaque (pattern, extents))
5355 0 : return CAIRO_STATUS_SUCCESS;
5356 : else
5357 0 : return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
5358 : }
5359 :
5360 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
5361 : }
5362 :
5363 : static cairo_bool_t
5364 0 : _cairo_pdf_surface_operation_supported (cairo_pdf_surface_t *surface,
5365 : cairo_operator_t op,
5366 : const cairo_pattern_t *pattern,
5367 : const cairo_rectangle_int_t *extents)
5368 : {
5369 0 : return _cairo_pdf_surface_analyze_operation (surface, op, pattern, extents) != CAIRO_INT_STATUS_UNSUPPORTED;
5370 : }
5371 :
5372 : static cairo_int_status_t
5373 0 : _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
5374 : {
5375 : cairo_status_t status;
5376 :
5377 0 : status = _cairo_pdf_surface_close_content_stream (surface);
5378 0 : if (unlikely (status))
5379 0 : return status;
5380 :
5381 0 : status = _cairo_array_append (&surface->knockout_group, &surface->content);
5382 0 : if (unlikely (status))
5383 0 : return status;
5384 :
5385 0 : _cairo_pdf_group_resources_clear (&surface->resources);
5386 0 : return _cairo_pdf_surface_open_content_stream (surface, NULL, TRUE);
5387 : }
5388 :
5389 : static cairo_int_status_t
5390 0 : _cairo_pdf_surface_paint (void *abstract_surface,
5391 : cairo_operator_t op,
5392 : const cairo_pattern_t *source,
5393 : cairo_clip_t *clip)
5394 : {
5395 0 : cairo_pdf_surface_t *surface = abstract_surface;
5396 : cairo_status_t status;
5397 : cairo_pdf_smask_group_t *group;
5398 : cairo_pdf_resource_t pattern_res, gstate_res;
5399 : cairo_composite_rectangles_t extents;
5400 :
5401 : cairo_rectangle_int_t rect;
5402 0 : rect.x = rect.y = 0;
5403 0 : rect.width = surface->width;
5404 0 : rect.height = surface->height;
5405 :
5406 0 : status = _cairo_composite_rectangles_init_for_paint (&extents,
5407 : &rect,
5408 : op, source, clip);
5409 0 : if (unlikely (status)) {
5410 0 : if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
5411 0 : return CAIRO_STATUS_SUCCESS;
5412 :
5413 0 : return status;
5414 : }
5415 :
5416 0 : if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
5417 0 : return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
5418 0 : } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
5419 0 : status = _cairo_pdf_surface_start_fallback (surface);
5420 0 : if (unlikely (status))
5421 0 : return status;
5422 : }
5423 :
5424 0 : assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
5425 :
5426 0 : status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
5427 0 : if (unlikely (status))
5428 0 : return status;
5429 :
5430 0 : status = _cairo_pdf_surface_select_operator (surface, op);
5431 0 : if (unlikely (status))
5432 0 : return status;
5433 :
5434 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
5435 0 : if (unlikely (status))
5436 0 : return status;
5437 :
5438 0 : if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
5439 0 : source->extend == CAIRO_EXTEND_NONE)
5440 : {
5441 0 : _cairo_output_stream_printf (surface->output, "q\n");
5442 0 : status = _cairo_pdf_surface_paint_surface_pattern (surface,
5443 : (cairo_surface_pattern_t *) source);
5444 0 : if (unlikely (status))
5445 0 : return status;
5446 :
5447 0 : _cairo_output_stream_printf (surface->output, "Q\n");
5448 0 : return _cairo_output_stream_get_status (surface->output);
5449 : }
5450 :
5451 0 : pattern_res.id = 0;
5452 0 : gstate_res.id = 0;
5453 0 : status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
5454 : &extents.bounded,
5455 : &pattern_res, &gstate_res);
5456 0 : if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
5457 0 : return CAIRO_STATUS_SUCCESS;
5458 0 : if (unlikely (status))
5459 0 : return status;
5460 :
5461 0 : if (gstate_res.id != 0) {
5462 0 : group = _cairo_pdf_surface_create_smask_group (surface);
5463 0 : if (unlikely (group == NULL))
5464 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5465 :
5466 0 : group->operation = PDF_PAINT;
5467 0 : status = _cairo_pattern_create_copy (&group->source, source);
5468 0 : if (unlikely (status)) {
5469 0 : _cairo_pdf_smask_group_destroy (group);
5470 0 : return status;
5471 : }
5472 0 : group->source_res = pattern_res;
5473 0 : status = _cairo_pdf_surface_add_smask_group (surface, group);
5474 0 : if (unlikely (status)) {
5475 0 : _cairo_pdf_smask_group_destroy (group);
5476 0 : return status;
5477 : }
5478 :
5479 0 : status = _cairo_pdf_surface_add_smask (surface, gstate_res);
5480 0 : if (unlikely (status))
5481 0 : return status;
5482 :
5483 0 : status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
5484 0 : if (unlikely (status))
5485 0 : return status;
5486 :
5487 0 : _cairo_output_stream_printf (surface->output,
5488 : "q /s%d gs /x%d Do Q\n",
5489 : gstate_res.id,
5490 : group->group_res.id);
5491 : } else {
5492 0 : status = _cairo_pdf_surface_select_pattern (surface, source,
5493 : pattern_res, FALSE);
5494 0 : if (unlikely (status))
5495 0 : return status;
5496 :
5497 0 : _cairo_output_stream_printf (surface->output,
5498 : "0 0 %f %f re f\n",
5499 : surface->width, surface->height);
5500 :
5501 0 : status = _cairo_pdf_surface_unselect_pattern (surface);
5502 0 : if (unlikely (status))
5503 0 : return status;
5504 : }
5505 :
5506 0 : return _cairo_output_stream_get_status (surface->output);
5507 : }
5508 :
5509 : static cairo_int_status_t
5510 0 : _cairo_pdf_surface_mask (void *abstract_surface,
5511 : cairo_operator_t op,
5512 : const cairo_pattern_t *source,
5513 : const cairo_pattern_t *mask,
5514 : cairo_clip_t *clip)
5515 : {
5516 0 : cairo_pdf_surface_t *surface = abstract_surface;
5517 : cairo_pdf_smask_group_t *group;
5518 : cairo_status_t status;
5519 : cairo_composite_rectangles_t extents;
5520 :
5521 : cairo_rectangle_int_t rect;
5522 0 : rect.x = rect.y = 0;
5523 0 : rect.width = surface->width;
5524 0 : rect.height = surface->height;
5525 :
5526 0 : status = _cairo_composite_rectangles_init_for_mask (&extents,
5527 : &rect,
5528 : op, source, mask, clip);
5529 0 : if (unlikely (status)) {
5530 0 : if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
5531 0 : return CAIRO_STATUS_SUCCESS;
5532 :
5533 0 : return status;
5534 : }
5535 :
5536 0 : if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
5537 : cairo_status_t source_status, mask_status;
5538 :
5539 0 : source_status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
5540 0 : if (_cairo_status_is_error (source_status))
5541 0 : return source_status;
5542 :
5543 0 : if (mask->has_component_alpha) {
5544 0 : mask_status = CAIRO_INT_STATUS_UNSUPPORTED;
5545 : } else {
5546 0 : mask_status = _cairo_pdf_surface_analyze_operation (surface, op, mask, &extents.bounded);
5547 0 : if (_cairo_status_is_error (mask_status))
5548 0 : return mask_status;
5549 : }
5550 :
5551 0 : return _cairo_analysis_surface_merge_status (source_status,
5552 : mask_status);
5553 0 : } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
5554 0 : status = _cairo_pdf_surface_start_fallback (surface);
5555 0 : if (unlikely (status))
5556 0 : return status;
5557 : }
5558 :
5559 0 : assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
5560 0 : assert (_cairo_pdf_surface_operation_supported (surface, op, mask, &extents.bounded));
5561 :
5562 0 : status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
5563 0 : if (unlikely (status))
5564 0 : return status;
5565 :
5566 0 : group = _cairo_pdf_surface_create_smask_group (surface);
5567 0 : if (unlikely (group == NULL))
5568 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5569 :
5570 0 : group->operation = PDF_MASK;
5571 0 : status = _cairo_pattern_create_copy (&group->source, source);
5572 0 : if (unlikely (status)) {
5573 0 : _cairo_pdf_smask_group_destroy (group);
5574 0 : return status;
5575 : }
5576 0 : status = _cairo_pattern_create_copy (&group->mask, mask);
5577 0 : if (unlikely (status)) {
5578 0 : _cairo_pdf_smask_group_destroy (group);
5579 0 : return status;
5580 : }
5581 0 : group->source_res = _cairo_pdf_surface_new_object (surface);
5582 0 : if (group->source_res.id == 0) {
5583 0 : _cairo_pdf_smask_group_destroy (group);
5584 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5585 : }
5586 :
5587 0 : status = _cairo_pdf_surface_add_smask_group (surface, group);
5588 0 : if (unlikely (status)) {
5589 0 : _cairo_pdf_smask_group_destroy (group);
5590 0 : return status;
5591 : }
5592 :
5593 0 : status = _cairo_pdf_surface_add_smask (surface, group->group_res);
5594 0 : if (unlikely (status))
5595 0 : return status;
5596 :
5597 0 : status = _cairo_pdf_surface_add_xobject (surface, group->source_res);
5598 0 : if (unlikely (status))
5599 0 : return status;
5600 :
5601 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
5602 0 : if (unlikely (status))
5603 0 : return status;
5604 :
5605 0 : status = _cairo_pdf_surface_select_operator (surface, op);
5606 0 : if (unlikely (status))
5607 0 : return status;
5608 :
5609 0 : _cairo_output_stream_printf (surface->output,
5610 : "q /s%d gs /x%d Do Q\n",
5611 : group->group_res.id,
5612 : group->source_res.id);
5613 :
5614 0 : return _cairo_output_stream_get_status (surface->output);
5615 : }
5616 :
5617 : static cairo_int_status_t
5618 0 : _cairo_pdf_surface_stroke (void *abstract_surface,
5619 : cairo_operator_t op,
5620 : const cairo_pattern_t *source,
5621 : cairo_path_fixed_t *path,
5622 : const cairo_stroke_style_t *style,
5623 : const cairo_matrix_t *ctm,
5624 : const cairo_matrix_t *ctm_inverse,
5625 : double tolerance,
5626 : cairo_antialias_t antialias,
5627 : cairo_clip_t *clip)
5628 : {
5629 0 : cairo_pdf_surface_t *surface = abstract_surface;
5630 : cairo_pdf_smask_group_t *group;
5631 : cairo_pdf_resource_t pattern_res, gstate_res;
5632 : cairo_composite_rectangles_t extents;
5633 : cairo_status_t status;
5634 :
5635 : cairo_rectangle_int_t rect;
5636 0 : rect.x = rect.y = 0;
5637 0 : rect.width = surface->width;
5638 0 : rect.height = surface->height;
5639 :
5640 0 : status = _cairo_composite_rectangles_init_for_stroke (&extents,
5641 : &rect,
5642 : op, source,
5643 : path, style, ctm,
5644 : clip);
5645 0 : if (unlikely (status)) {
5646 0 : if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
5647 0 : return CAIRO_STATUS_SUCCESS;
5648 :
5649 0 : return status;
5650 : }
5651 :
5652 : /* use the more accurate extents */
5653 0 : if (extents.is_bounded) {
5654 0 : status = _cairo_path_fixed_stroke_extents (path, style,
5655 : ctm, ctm_inverse,
5656 : tolerance,
5657 : &extents.mask);
5658 0 : if (unlikely (status))
5659 0 : return status;
5660 :
5661 0 : if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
5662 0 : return CAIRO_STATUS_SUCCESS;
5663 : }
5664 :
5665 0 : if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
5666 0 : return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
5667 :
5668 0 : assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
5669 :
5670 0 : status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
5671 0 : if (unlikely (status))
5672 0 : return status;
5673 :
5674 0 : pattern_res.id = 0;
5675 0 : gstate_res.id = 0;
5676 0 : status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
5677 : &extents.bounded,
5678 : &pattern_res, &gstate_res);
5679 0 : if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
5680 0 : return CAIRO_STATUS_SUCCESS;
5681 0 : if (unlikely (status))
5682 0 : return status;
5683 :
5684 0 : status = _cairo_pdf_surface_select_operator (surface, op);
5685 0 : if (unlikely (status))
5686 0 : return status;
5687 :
5688 0 : if (gstate_res.id != 0) {
5689 0 : group = _cairo_pdf_surface_create_smask_group (surface);
5690 0 : if (unlikely (group == NULL))
5691 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5692 :
5693 0 : group->operation = PDF_STROKE;
5694 0 : status = _cairo_pattern_create_copy (&group->source, source);
5695 0 : if (unlikely (status)) {
5696 0 : _cairo_pdf_smask_group_destroy (group);
5697 0 : return status;
5698 : }
5699 0 : group->source_res = pattern_res;
5700 0 : status = _cairo_path_fixed_init_copy (&group->path, path);
5701 0 : if (unlikely (status)) {
5702 0 : _cairo_pdf_smask_group_destroy (group);
5703 0 : return status;
5704 : }
5705 :
5706 0 : group->style = *style;
5707 0 : group->ctm = *ctm;
5708 0 : group->ctm_inverse = *ctm_inverse;
5709 0 : status = _cairo_pdf_surface_add_smask_group (surface, group);
5710 0 : if (unlikely (status)) {
5711 0 : _cairo_pdf_smask_group_destroy (group);
5712 0 : return status;
5713 : }
5714 :
5715 0 : status = _cairo_pdf_surface_add_smask (surface, gstate_res);
5716 0 : if (unlikely (status))
5717 0 : return status;
5718 :
5719 0 : status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
5720 0 : if (unlikely (status))
5721 0 : return status;
5722 :
5723 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
5724 0 : if (unlikely (status))
5725 0 : return status;
5726 :
5727 0 : _cairo_output_stream_printf (surface->output,
5728 : "q /s%d gs /x%d Do Q\n",
5729 : gstate_res.id,
5730 : group->group_res.id);
5731 : } else {
5732 0 : status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, TRUE);
5733 0 : if (unlikely (status))
5734 0 : return status;
5735 :
5736 0 : status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
5737 : path,
5738 : style,
5739 : ctm,
5740 : ctm_inverse);
5741 0 : if (unlikely (status))
5742 0 : return status;
5743 :
5744 0 : status = _cairo_pdf_surface_unselect_pattern (surface);
5745 0 : if (unlikely (status))
5746 0 : return status;
5747 : }
5748 :
5749 0 : return _cairo_output_stream_get_status (surface->output);
5750 : }
5751 :
5752 : static cairo_int_status_t
5753 0 : _cairo_pdf_surface_fill (void *abstract_surface,
5754 : cairo_operator_t op,
5755 : const cairo_pattern_t *source,
5756 : cairo_path_fixed_t *path,
5757 : cairo_fill_rule_t fill_rule,
5758 : double tolerance,
5759 : cairo_antialias_t antialias,
5760 : cairo_clip_t *clip)
5761 : {
5762 0 : cairo_pdf_surface_t *surface = abstract_surface;
5763 : cairo_status_t status;
5764 : cairo_pdf_smask_group_t *group;
5765 : cairo_pdf_resource_t pattern_res, gstate_res;
5766 : cairo_composite_rectangles_t extents;
5767 :
5768 : cairo_rectangle_int_t rect;
5769 0 : rect.x = rect.y = 0;
5770 0 : rect.width = surface->width;
5771 0 : rect.height = surface->height;
5772 :
5773 0 : status = _cairo_composite_rectangles_init_for_fill (&extents,
5774 : &rect,
5775 : op, source, path,
5776 : clip);
5777 0 : if (unlikely (status)) {
5778 0 : if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
5779 0 : return CAIRO_STATUS_SUCCESS;
5780 :
5781 0 : return status;
5782 : }
5783 :
5784 : /* use the more accurate extents */
5785 0 : if (extents.is_bounded) {
5786 0 : _cairo_path_fixed_fill_extents (path,
5787 : fill_rule,
5788 : tolerance,
5789 : &extents.mask);
5790 :
5791 0 : if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
5792 0 : return CAIRO_STATUS_SUCCESS;
5793 : }
5794 :
5795 0 : if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
5796 0 : return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
5797 0 : } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
5798 0 : status = _cairo_pdf_surface_start_fallback (surface);
5799 0 : if (unlikely (status))
5800 0 : return status;
5801 : }
5802 :
5803 0 : assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
5804 :
5805 0 : status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
5806 0 : if (unlikely (status))
5807 0 : return status;
5808 :
5809 0 : status = _cairo_pdf_surface_select_operator (surface, op);
5810 0 : if (unlikely (status))
5811 0 : return status;
5812 :
5813 0 : if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
5814 0 : source->extend == CAIRO_EXTEND_NONE)
5815 : {
5816 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
5817 0 : if (unlikely (status))
5818 0 : return status;
5819 :
5820 0 : _cairo_output_stream_printf (surface->output, "q\n");
5821 0 : status = _cairo_pdf_operators_clip (&surface->pdf_operators,
5822 : path,
5823 : fill_rule);
5824 0 : if (unlikely (status))
5825 0 : return status;
5826 :
5827 0 : status = _cairo_pdf_surface_paint_surface_pattern (surface,
5828 : (cairo_surface_pattern_t *) source);
5829 0 : if (unlikely (status))
5830 0 : return status;
5831 :
5832 0 : _cairo_output_stream_printf (surface->output, "Q\n");
5833 0 : return _cairo_output_stream_get_status (surface->output);
5834 : }
5835 :
5836 0 : pattern_res.id = 0;
5837 0 : gstate_res.id = 0;
5838 0 : status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
5839 : &extents.bounded,
5840 : &pattern_res, &gstate_res);
5841 0 : if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
5842 0 : return CAIRO_STATUS_SUCCESS;
5843 0 : if (unlikely (status))
5844 0 : return status;
5845 :
5846 0 : if (gstate_res.id != 0) {
5847 0 : group = _cairo_pdf_surface_create_smask_group (surface);
5848 0 : if (unlikely (group == NULL))
5849 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5850 :
5851 0 : group->operation = PDF_FILL;
5852 0 : status = _cairo_pattern_create_copy (&group->source, source);
5853 0 : if (unlikely (status)) {
5854 0 : _cairo_pdf_smask_group_destroy (group);
5855 0 : return status;
5856 : }
5857 0 : group->source_res = pattern_res;
5858 0 : status = _cairo_path_fixed_init_copy (&group->path, path);
5859 0 : if (unlikely (status)) {
5860 0 : _cairo_pdf_smask_group_destroy (group);
5861 0 : return status;
5862 : }
5863 :
5864 0 : group->fill_rule = fill_rule;
5865 0 : status = _cairo_pdf_surface_add_smask_group (surface, group);
5866 0 : if (unlikely (status)) {
5867 0 : _cairo_pdf_smask_group_destroy (group);
5868 0 : return status;
5869 : }
5870 :
5871 0 : status = _cairo_pdf_surface_add_smask (surface, gstate_res);
5872 0 : if (unlikely (status))
5873 0 : return status;
5874 :
5875 0 : status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
5876 0 : if (unlikely (status))
5877 0 : return status;
5878 :
5879 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
5880 0 : if (unlikely (status))
5881 0 : return status;
5882 :
5883 0 : _cairo_output_stream_printf (surface->output,
5884 : "q /s%d gs /x%d Do Q\n",
5885 : gstate_res.id,
5886 : group->group_res.id);
5887 : } else {
5888 0 : status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
5889 0 : if (unlikely (status))
5890 0 : return status;
5891 :
5892 0 : status = _cairo_pdf_operators_fill (&surface->pdf_operators,
5893 : path,
5894 : fill_rule);
5895 0 : if (unlikely (status))
5896 0 : return status;
5897 :
5898 0 : status = _cairo_pdf_surface_unselect_pattern (surface);
5899 0 : if (unlikely (status))
5900 0 : return status;
5901 : }
5902 :
5903 0 : return _cairo_output_stream_get_status (surface->output);
5904 : }
5905 :
5906 : static cairo_int_status_t
5907 0 : _cairo_pdf_surface_fill_stroke (void *abstract_surface,
5908 : cairo_operator_t fill_op,
5909 : const cairo_pattern_t *fill_source,
5910 : cairo_fill_rule_t fill_rule,
5911 : double fill_tolerance,
5912 : cairo_antialias_t fill_antialias,
5913 : cairo_path_fixed_t *path,
5914 : cairo_operator_t stroke_op,
5915 : const cairo_pattern_t *stroke_source,
5916 : const cairo_stroke_style_t *stroke_style,
5917 : const cairo_matrix_t *stroke_ctm,
5918 : const cairo_matrix_t *stroke_ctm_inverse,
5919 : double stroke_tolerance,
5920 : cairo_antialias_t stroke_antialias,
5921 : cairo_clip_t *clip)
5922 : {
5923 0 : cairo_pdf_surface_t *surface = abstract_surface;
5924 : cairo_status_t status;
5925 : cairo_pdf_resource_t fill_pattern_res, stroke_pattern_res, gstate_res;
5926 : cairo_rectangle_int_t extents;
5927 :
5928 : /* During analysis we return unsupported and let the _fill and
5929 : * _stroke functions that are on the fallback path do the analysis
5930 : * for us. During render we may still encounter unsupported
5931 : * combinations of fill/stroke patterns. However we can return
5932 : * unsupported anytime to let the _fill and _stroke functions take
5933 : * over.
5934 : */
5935 0 : if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
5936 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
5937 :
5938 : /* PDF rendering of fill-stroke is not the same as cairo when
5939 : * either the fill or stroke is not opaque.
5940 : */
5941 0 : if ( !_cairo_pattern_is_opaque (fill_source, NULL) ||
5942 0 : !_cairo_pattern_is_opaque (stroke_source, NULL))
5943 : {
5944 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
5945 : }
5946 :
5947 0 : if (fill_op != stroke_op)
5948 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
5949 :
5950 0 : status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
5951 0 : if (unlikely (status))
5952 0 : return status;
5953 :
5954 0 : status = _cairo_pdf_surface_select_operator (surface, fill_op);
5955 0 : if (unlikely (status))
5956 0 : return status;
5957 :
5958 0 : status = _cairo_surface_fill_extents (&surface->base,
5959 : fill_op, fill_source, path, fill_rule,
5960 : fill_tolerance, fill_antialias,
5961 : clip, &extents);
5962 0 : if (unlikely (status))
5963 0 : return status;
5964 :
5965 :
5966 0 : fill_pattern_res.id = 0;
5967 0 : gstate_res.id = 0;
5968 0 : status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source,
5969 : &extents,
5970 : &fill_pattern_res,
5971 : &gstate_res);
5972 0 : if (unlikely (status))
5973 0 : return status;
5974 :
5975 0 : assert (gstate_res.id == 0);
5976 :
5977 0 : status = _cairo_surface_stroke_extents (&surface->base,
5978 : stroke_op, stroke_source, path,
5979 : stroke_style, stroke_ctm, stroke_ctm_inverse,
5980 : stroke_tolerance, stroke_antialias,
5981 : clip, &extents);
5982 0 : if (unlikely (status))
5983 0 : return status;
5984 :
5985 0 : stroke_pattern_res.id = 0;
5986 0 : gstate_res.id = 0;
5987 0 : status = _cairo_pdf_surface_add_pdf_pattern (surface,
5988 : stroke_source,
5989 : &extents,
5990 : &stroke_pattern_res,
5991 : &gstate_res);
5992 0 : if (unlikely (status))
5993 0 : return status;
5994 :
5995 0 : assert (gstate_res.id == 0);
5996 :
5997 : /* As PDF has separate graphics state for fill and stroke we can
5998 : * select both at the same time */
5999 0 : status = _cairo_pdf_surface_select_pattern (surface, fill_source,
6000 : fill_pattern_res, FALSE);
6001 0 : if (unlikely (status))
6002 0 : return status;
6003 :
6004 0 : status = _cairo_pdf_surface_select_pattern (surface, stroke_source,
6005 : stroke_pattern_res, TRUE);
6006 0 : if (unlikely (status))
6007 0 : return status;
6008 :
6009 0 : status = _cairo_pdf_operators_fill_stroke (&surface->pdf_operators,
6010 : path,
6011 : fill_rule,
6012 : stroke_style,
6013 : stroke_ctm,
6014 : stroke_ctm_inverse);
6015 0 : if (unlikely (status))
6016 0 : return status;
6017 :
6018 0 : status = _cairo_pdf_surface_unselect_pattern (surface);
6019 0 : if (unlikely (status))
6020 0 : return status;
6021 :
6022 0 : return _cairo_output_stream_get_status (surface->output);
6023 : }
6024 :
6025 : static cairo_bool_t
6026 0 : _cairo_pdf_surface_has_show_text_glyphs (void *abstract_surface)
6027 : {
6028 0 : return TRUE;
6029 : }
6030 :
6031 : static cairo_int_status_t
6032 0 : _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
6033 : cairo_operator_t op,
6034 : const cairo_pattern_t *source,
6035 : const char *utf8,
6036 : int utf8_len,
6037 : cairo_glyph_t *glyphs,
6038 : int num_glyphs,
6039 : const cairo_text_cluster_t *clusters,
6040 : int num_clusters,
6041 : cairo_text_cluster_flags_t cluster_flags,
6042 : cairo_scaled_font_t *scaled_font,
6043 : cairo_clip_t *clip)
6044 : {
6045 0 : cairo_pdf_surface_t *surface = abstract_surface;
6046 : cairo_pdf_smask_group_t *group;
6047 : cairo_pdf_resource_t pattern_res, gstate_res;
6048 : cairo_composite_rectangles_t extents;
6049 : cairo_bool_t overlap;
6050 : cairo_status_t status;
6051 :
6052 : cairo_rectangle_int_t rect;
6053 0 : rect.x = rect.y = 0;
6054 0 : rect.width = surface->width;
6055 0 : rect.height = surface->height;
6056 :
6057 0 : status = _cairo_composite_rectangles_init_for_glyphs (&extents,
6058 : &rect,
6059 : op, source,
6060 : scaled_font,
6061 : glyphs, num_glyphs,
6062 : clip,
6063 : &overlap);
6064 0 : if (unlikely (status)) {
6065 0 : if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
6066 0 : return CAIRO_STATUS_SUCCESS;
6067 :
6068 0 : return status;
6069 : }
6070 :
6071 0 : if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
6072 0 : return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
6073 :
6074 0 : assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
6075 :
6076 0 : status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
6077 0 : if (unlikely (status))
6078 0 : return status;
6079 :
6080 0 : pattern_res.id = 0;
6081 0 : gstate_res.id = 0;
6082 0 : status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
6083 : &extents.bounded,
6084 : &pattern_res, &gstate_res);
6085 0 : if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
6086 0 : return CAIRO_STATUS_SUCCESS;
6087 0 : if (unlikely (status))
6088 0 : return status;
6089 :
6090 0 : status = _cairo_pdf_surface_select_operator (surface, op);
6091 0 : if (unlikely (status))
6092 0 : return status;
6093 :
6094 0 : if (gstate_res.id != 0) {
6095 0 : group = _cairo_pdf_surface_create_smask_group (surface);
6096 0 : if (unlikely (group == NULL))
6097 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
6098 :
6099 0 : group->operation = PDF_SHOW_GLYPHS;
6100 0 : status = _cairo_pattern_create_copy (&group->source, source);
6101 0 : if (unlikely (status)) {
6102 0 : _cairo_pdf_smask_group_destroy (group);
6103 0 : return status;
6104 : }
6105 0 : group->source_res = pattern_res;
6106 :
6107 0 : if (utf8_len) {
6108 0 : group->utf8 = malloc (utf8_len);
6109 0 : if (unlikely (group->utf8 == NULL)) {
6110 0 : _cairo_pdf_smask_group_destroy (group);
6111 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
6112 : }
6113 0 : memcpy (group->utf8, utf8, utf8_len);
6114 : }
6115 0 : group->utf8_len = utf8_len;
6116 :
6117 0 : if (num_glyphs) {
6118 0 : group->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
6119 0 : if (unlikely (group->glyphs == NULL)) {
6120 0 : _cairo_pdf_smask_group_destroy (group);
6121 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
6122 : }
6123 0 : memcpy (group->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
6124 : }
6125 0 : group->num_glyphs = num_glyphs;
6126 :
6127 0 : if (num_clusters) {
6128 0 : group->clusters = _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t));
6129 0 : if (unlikely (group->clusters == NULL)) {
6130 0 : _cairo_pdf_smask_group_destroy (group);
6131 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
6132 : }
6133 0 : memcpy (group->clusters, clusters, sizeof (cairo_text_cluster_t) * num_clusters);
6134 : }
6135 0 : group->num_clusters = num_clusters;
6136 :
6137 0 : group->scaled_font = cairo_scaled_font_reference (scaled_font);
6138 0 : status = _cairo_pdf_surface_add_smask_group (surface, group);
6139 0 : if (unlikely (status)) {
6140 0 : _cairo_pdf_smask_group_destroy (group);
6141 0 : return status;
6142 : }
6143 :
6144 0 : status = _cairo_pdf_surface_add_smask (surface, gstate_res);
6145 0 : if (unlikely (status))
6146 0 : return status;
6147 :
6148 0 : status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
6149 0 : if (unlikely (status))
6150 0 : return status;
6151 :
6152 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
6153 0 : if (unlikely (status))
6154 0 : return status;
6155 :
6156 0 : _cairo_output_stream_printf (surface->output,
6157 : "q /s%d gs /x%d Do Q\n",
6158 : gstate_res.id,
6159 : group->group_res.id);
6160 : } else {
6161 0 : status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
6162 0 : if (unlikely (status))
6163 0 : return status;
6164 :
6165 : /* Each call to show_glyphs() with a transclucent pattern must
6166 : * be in a separate text object otherwise overlapping text
6167 : * from separate calls to show_glyphs will not composite with
6168 : * each other. */
6169 0 : if (! _cairo_pattern_is_opaque (source, &extents.bounded)) {
6170 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
6171 0 : if (unlikely (status))
6172 0 : return status;
6173 : }
6174 :
6175 0 : status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
6176 : utf8, utf8_len,
6177 : glyphs, num_glyphs,
6178 : clusters, num_clusters,
6179 : cluster_flags,
6180 : scaled_font);
6181 0 : if (unlikely (status))
6182 0 : return status;
6183 :
6184 0 : status = _cairo_pdf_surface_unselect_pattern (surface);
6185 0 : if (unlikely (status))
6186 0 : return status;
6187 : }
6188 :
6189 0 : return _cairo_output_stream_get_status (surface->output);
6190 : }
6191 :
6192 :
6193 : static void
6194 0 : _cairo_pdf_surface_set_paginated_mode (void *abstract_surface,
6195 : cairo_paginated_mode_t paginated_mode)
6196 : {
6197 0 : cairo_pdf_surface_t *surface = abstract_surface;
6198 :
6199 0 : surface->paginated_mode = paginated_mode;
6200 0 : }
6201 :
6202 : static const cairo_surface_backend_t cairo_pdf_surface_backend = {
6203 : CAIRO_SURFACE_TYPE_PDF,
6204 : NULL, /* create similar: handled by wrapper */
6205 : _cairo_pdf_surface_finish,
6206 : NULL, /* acquire_source_image */
6207 : NULL, /* release_source_image */
6208 : NULL, /* acquire_dest_image */
6209 : NULL, /* release_dest_image */
6210 : NULL, /* clone_similar */
6211 : NULL, /* composite */
6212 : NULL, /* fill_rectangles */
6213 : NULL, /* composite_trapezoids */
6214 : NULL, /* create_span_renderer */
6215 : NULL, /* check_span_renderer */
6216 : NULL, /* _cairo_pdf_surface_copy_page */
6217 : _cairo_pdf_surface_show_page,
6218 : _cairo_pdf_surface_get_extents,
6219 : NULL, /* old_show_glyphs */
6220 : _cairo_pdf_surface_get_font_options,
6221 : NULL, /* flush */
6222 : NULL, /* mark_dirty_rectangle */
6223 : NULL, /* scaled_font_fini */
6224 : NULL, /* scaled_glyph_fini */
6225 :
6226 : /* Here are the drawing functions */
6227 :
6228 : _cairo_pdf_surface_paint,
6229 : _cairo_pdf_surface_mask,
6230 : _cairo_pdf_surface_stroke,
6231 : _cairo_pdf_surface_fill,
6232 : NULL, /* show_glyphs */
6233 : NULL, /* snapshot */
6234 :
6235 : NULL, /* is_compatible */
6236 : _cairo_pdf_surface_fill_stroke,
6237 : NULL, /* create_solid_pattern_surface */
6238 : NULL, /* can_repaint_solid_pattern_surface */
6239 : _cairo_pdf_surface_has_show_text_glyphs,
6240 : _cairo_pdf_surface_show_text_glyphs,
6241 : };
6242 :
6243 : static const cairo_paginated_surface_backend_t
6244 : cairo_pdf_surface_paginated_backend = {
6245 : _cairo_pdf_surface_start_page,
6246 : _cairo_pdf_surface_set_paginated_mode,
6247 : NULL, /* set_bounding_box */
6248 : _cairo_pdf_surface_has_fallback_images,
6249 : _cairo_pdf_surface_supports_fine_grained_fallbacks,
6250 : };
|