beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-pdf-surface.c
blob4bc2947964ed993d32c09c8a0c80b449bb59b5be
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
4 * Copyright © 2004 Red Hat, Inc
5 * Copyright © 2006 Red Hat, Inc
6 * Copyright © 2007, 2008 Adrian Johnson
8 * This library is free software; you can redistribute it and/or
9 * modify it either under the terms of the GNU Lesser General Public
10 * License version 2.1 as published by the Free Software Foundation
11 * (the "LGPL") or, at your option, under the terms of the Mozilla
12 * Public License Version 1.1 (the "MPL"). If you do not alter this
13 * notice, a recipient may use your version of this file under either
14 * the MPL or the LGPL.
16 * You should have received a copy of the LGPL along with this library
17 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18 * Foundation, Inc., 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
22 * The contents of this file are subject to the Mozilla Public License
23 * Version 1.1 (the "License"); you may not use this file except in
24 * compliance with the License. You may obtain a copy of the License at
25 * http://www.mozilla.org/MPL/
27 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29 * the specific language governing rights and limitations.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is University of Southern
34 * California.
36 * Contributor(s):
37 * Kristian Høgsberg <krh@redhat.com>
38 * Carl Worth <cworth@cworth.org>
39 * Adrian Johnson <ajohnson@redneon.com>
42 #define _BSD_SOURCE /* for snprintf() */
43 #include "cairoint.h"
45 #include "cairo-pdf.h"
46 #include "cairo-pdf-surface-private.h"
47 #include "cairo-pdf-operators-private.h"
48 #include "cairo-pdf-shading-private.h"
50 #include "cairo-array-private.h"
51 #include "cairo-analysis-surface-private.h"
52 #include "cairo-composite-rectangles-private.h"
53 #include "cairo-default-context-private.h"
54 #include "cairo-error-private.h"
55 #include "cairo-image-surface-inline.h"
56 #include "cairo-image-info-private.h"
57 #include "cairo-recording-surface-private.h"
58 #include "cairo-output-stream-private.h"
59 #include "cairo-paginated-private.h"
60 #include "cairo-scaled-font-subsets-private.h"
61 #include "cairo-surface-clipper-private.h"
62 #include "cairo-surface-snapshot-inline.h"
63 #include "cairo-surface-subsurface-private.h"
64 #include "cairo-type3-glyph-surface-private.h"
66 #include <time.h>
67 #include <zlib.h>
69 /* Issues:
71 * - We embed an image in the stream each time it's composited. We
72 * could add generation counters to surfaces and remember the stream
73 * ID for a particular generation for a particular surface.
75 * - Backend specific meta data.
79 * Page Structure of the Generated PDF:
81 * Each page requiring fallbacks images contains a knockout group at
82 * the top level. The first operation of the knockout group paints a
83 * group containing all the supported drawing operations. Fallback
84 * images (if any) are painted in the knockout group. This ensures
85 * that fallback images do not composite with any content under the
86 * fallback images.
88 * Streams:
90 * This PDF surface has three types of streams:
91 * - PDF Stream
92 * - Content Stream
93 * - Group Stream
95 * Calling _cairo_output_stream_printf (surface->output, ...) will
96 * write to the currently open stream.
98 * PDF Stream:
99 * A PDF Stream may be opened and closed with the following functions:
100 * _cairo_pdf_surface_open stream ()
101 * _cairo_pdf_surface_close_stream ()
103 * PDF Streams are written directly to the PDF file. They are used for
104 * fonts, images and patterns.
106 * Content Stream:
107 * The Content Stream is opened and closed with the following functions:
108 * _cairo_pdf_surface_open_content_stream ()
109 * _cairo_pdf_surface_close_content_stream ()
111 * The Content Stream contains the text and graphics operators.
113 * Group Stream:
114 * A Group Stream may be opened and closed with the following functions:
115 * _cairo_pdf_surface_open_group ()
116 * _cairo_pdf_surface_close_group ()
118 * A Group Stream is a Form XObject. It is used for short sequences
119 * of operators. As the content is very short the group is stored in
120 * memory until it is closed. This allows some optimization such as
121 * including the Resource dictionary and stream length inside the
122 * XObject instead of using an indirect object.
126 * SECTION:cairo-pdf
127 * @Title: PDF Surfaces
128 * @Short_Description: Rendering PDF documents
129 * @See_Also: #cairo_surface_t
131 * The PDF surface is used to render cairo graphics to Adobe
132 * PDF files and is a multi-page vector surface backend.
134 * The following mime types are supported: %CAIRO_MIME_TYPE_JPEG,
135 * %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_UNIQUE_ID,
136 * %CAIRO_MIME_TYPE_JBIG2, %CAIRO_MIME_TYPE_JBIG2_GLOBAL,
137 * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID.
139 * JBIG2 data in PDF must be in the embedded format as described in
140 * ISO/IEC 11544. Image specific JBIG2 data must be in
141 * %CAIRO_MIME_TYPE_JBIG2. Any global segments in the JBIG2 data
142 * (segments with page association field set to 0) must be in
143 * %CAIRO_MIME_TYPE_JBIG2_GLOBAL. The global data may be shared by
144 * multiple images. All images sharing the same global data must set
145 * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID to a unique identifer. At least
146 * one of the images must provide the global data using
147 * %CAIRO_MIME_TYPE_JBIG2_GLOBAL. The global data will only be
148 * embedded once but shared by all JBIG2 images with the same
149 * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID.
152 static cairo_bool_t
153 _cairo_pdf_surface_get_extents (void *abstract_surface,
154 cairo_rectangle_int_t *rectangle);
157 * CAIRO_HAS_PDF_SURFACE:
159 * Defined if the PDF surface backend is available.
160 * This macro can be used to conditionally compile backend-specific code.
162 * Since: 1.2
165 static const cairo_pdf_version_t _cairo_pdf_versions[] =
167 CAIRO_PDF_VERSION_1_4,
168 CAIRO_PDF_VERSION_1_5
171 #define CAIRO_PDF_VERSION_LAST ARRAY_LENGTH (_cairo_pdf_versions)
173 static const char * _cairo_pdf_version_strings[CAIRO_PDF_VERSION_LAST] =
175 "PDF 1.4",
176 "PDF 1.5"
179 static const char *_cairo_pdf_supported_mime_types[] =
181 CAIRO_MIME_TYPE_JPEG,
182 CAIRO_MIME_TYPE_JP2,
183 CAIRO_MIME_TYPE_UNIQUE_ID,
184 CAIRO_MIME_TYPE_JBIG2,
185 CAIRO_MIME_TYPE_JBIG2_GLOBAL,
186 CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID,
187 NULL
190 typedef struct _cairo_pdf_object {
191 long offset;
192 } cairo_pdf_object_t;
194 typedef struct _cairo_pdf_font {
195 unsigned int font_id;
196 unsigned int subset_id;
197 cairo_pdf_resource_t subset_resource;
198 } cairo_pdf_font_t;
200 typedef struct _cairo_pdf_rgb_linear_function {
201 cairo_pdf_resource_t resource;
202 double color1[3];
203 double color2[3];
204 } cairo_pdf_rgb_linear_function_t;
206 typedef struct _cairo_pdf_alpha_linear_function {
207 cairo_pdf_resource_t resource;
208 double alpha1;
209 double alpha2;
210 } cairo_pdf_alpha_linear_function_t;
212 static cairo_pdf_resource_t
213 _cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface);
215 static void
216 _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
218 static void
219 _cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group);
221 static cairo_int_status_t
222 _cairo_pdf_surface_add_font (unsigned int font_id,
223 unsigned int subset_id,
224 void *closure);
226 static void
227 _cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res);
229 static cairo_int_status_t
230 _cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface,
231 cairo_pdf_resource_t *resource,
232 cairo_bool_t compressed,
233 const char *fmt,
234 ...) CAIRO_PRINTF_FORMAT(4, 5);
235 static cairo_int_status_t
236 _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface);
238 static cairo_int_status_t
239 _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
241 static void
242 _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface);
244 static cairo_pdf_resource_t
245 _cairo_pdf_surface_write_info (cairo_pdf_surface_t *surface);
247 static cairo_pdf_resource_t
248 _cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface);
250 static long
251 _cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface);
253 static cairo_int_status_t
254 _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
256 static cairo_int_status_t
257 _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface);
259 static cairo_bool_t
260 _cairo_pdf_source_surface_equal (const void *key_a, const void *key_b);
262 static const cairo_surface_backend_t cairo_pdf_surface_backend;
263 static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend;
265 static cairo_pdf_resource_t
266 _cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface)
268 cairo_pdf_resource_t resource;
269 cairo_int_status_t status;
270 cairo_pdf_object_t object;
272 object.offset = _cairo_output_stream_get_position (surface->output);
274 status = _cairo_array_append (&surface->objects, &object);
275 if (unlikely (status)) {
276 resource.id = 0;
277 return resource;
280 resource = surface->next_available_resource;
281 surface->next_available_resource.id++;
283 return resource;
286 static void
287 _cairo_pdf_surface_update_object (cairo_pdf_surface_t *surface,
288 cairo_pdf_resource_t resource)
290 cairo_pdf_object_t *object;
292 object = _cairo_array_index (&surface->objects, resource.id - 1);
293 object->offset = _cairo_output_stream_get_position (surface->output);
296 static void
297 _cairo_pdf_surface_set_size_internal (cairo_pdf_surface_t *surface,
298 double width,
299 double height)
301 surface->width = width;
302 surface->height = height;
303 cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, height);
304 _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
305 &surface->cairo_to_pdf);
308 static cairo_bool_t
309 _path_covers_bbox (cairo_pdf_surface_t *surface,
310 cairo_path_fixed_t *path)
312 cairo_box_t box;
314 return _cairo_path_fixed_is_box (path, &box) &&
315 box.p1.x <= 0 &&
316 box.p1.y <= 0 &&
317 box.p2.x >= _cairo_fixed_from_double (surface->width) &&
318 box.p2.y >= _cairo_fixed_from_double (surface->height);
321 static cairo_status_t
322 _cairo_pdf_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
323 cairo_path_fixed_t *path,
324 cairo_fill_rule_t fill_rule,
325 double tolerance,
326 cairo_antialias_t antialias)
328 cairo_pdf_surface_t *surface = cairo_container_of (clipper,
329 cairo_pdf_surface_t,
330 clipper);
331 cairo_int_status_t status;
333 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
334 if (unlikely (status))
335 return status;
337 if (path == NULL) {
338 _cairo_output_stream_printf (surface->output, "Q q\n");
340 surface->current_pattern_is_solid_color = FALSE;
341 _cairo_pdf_operators_reset (&surface->pdf_operators);
343 return CAIRO_STATUS_SUCCESS;
346 if (_path_covers_bbox (surface, path))
347 return CAIRO_STATUS_SUCCESS;
349 return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule);
352 static cairo_surface_t *
353 _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
354 double width,
355 double height)
357 cairo_pdf_surface_t *surface;
358 cairo_status_t status, status_ignored;
360 surface = malloc (sizeof (cairo_pdf_surface_t));
361 if (unlikely (surface == NULL)) {
362 /* destroy stream on behalf of caller */
363 status = _cairo_output_stream_destroy (output);
364 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
367 _cairo_surface_init (&surface->base,
368 &cairo_pdf_surface_backend,
369 NULL, /* device */
370 CAIRO_CONTENT_COLOR_ALPHA);
372 surface->output = output;
373 surface->width = width;
374 surface->height = height;
375 cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, height);
377 _cairo_array_init (&surface->objects, sizeof (cairo_pdf_object_t));
378 _cairo_array_init (&surface->pages, sizeof (cairo_pdf_resource_t));
379 _cairo_array_init (&surface->rgb_linear_functions, sizeof (cairo_pdf_rgb_linear_function_t));
380 _cairo_array_init (&surface->alpha_linear_functions, sizeof (cairo_pdf_alpha_linear_function_t));
381 _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
382 _cairo_array_init (&surface->smask_groups, sizeof (cairo_pdf_smask_group_t *));
383 _cairo_array_init (&surface->knockout_group, sizeof (cairo_pdf_resource_t));
385 _cairo_array_init (&surface->page_patterns, sizeof (cairo_pdf_pattern_t));
386 _cairo_array_init (&surface->page_surfaces, sizeof (cairo_pdf_source_surface_t));
387 _cairo_array_init (&surface->jbig2_global, sizeof (cairo_pdf_jbig2_global_t));
388 surface->all_surfaces = _cairo_hash_table_create (_cairo_pdf_source_surface_equal);
389 if (unlikely (surface->all_surfaces == NULL)) {
390 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
391 goto BAIL0;
394 _cairo_pdf_group_resources_init (&surface->resources);
396 surface->font_subsets = _cairo_scaled_font_subsets_create_composite ();
397 if (! surface->font_subsets) {
398 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
399 goto BAIL1;
402 _cairo_scaled_font_subsets_enable_latin_subset (surface->font_subsets, TRUE);
404 surface->next_available_resource.id = 1;
405 surface->pages_resource = _cairo_pdf_surface_new_object (surface);
406 if (surface->pages_resource.id == 0) {
407 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
408 goto BAIL2;
411 surface->pdf_version = CAIRO_PDF_VERSION_1_5;
412 surface->compress_content = TRUE;
413 surface->pdf_stream.active = FALSE;
414 surface->pdf_stream.old_output = NULL;
415 surface->group_stream.active = FALSE;
416 surface->group_stream.stream = NULL;
417 surface->group_stream.mem_stream = NULL;
419 surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
421 surface->force_fallbacks = FALSE;
422 surface->select_pattern_gstate_saved = FALSE;
423 surface->current_pattern_is_solid_color = FALSE;
424 surface->current_operator = CAIRO_OPERATOR_OVER;
425 surface->header_emitted = FALSE;
427 _cairo_surface_clipper_init (&surface->clipper,
428 _cairo_pdf_surface_clipper_intersect_clip_path);
430 _cairo_pdf_operators_init (&surface->pdf_operators,
431 surface->output,
432 &surface->cairo_to_pdf,
433 surface->font_subsets,
434 FALSE);
435 _cairo_pdf_operators_set_font_subsets_callback (&surface->pdf_operators,
436 _cairo_pdf_surface_add_font,
437 surface);
438 _cairo_pdf_operators_enable_actual_text(&surface->pdf_operators, TRUE);
440 surface->paginated_surface = _cairo_paginated_surface_create (
441 &surface->base,
442 CAIRO_CONTENT_COLOR_ALPHA,
443 &cairo_pdf_surface_paginated_backend);
445 status = surface->paginated_surface->status;
446 if (status == CAIRO_STATUS_SUCCESS) {
447 /* paginated keeps the only reference to surface now, drop ours */
448 cairo_surface_destroy (&surface->base);
449 return surface->paginated_surface;
452 BAIL2:
453 _cairo_scaled_font_subsets_destroy (surface->font_subsets);
454 BAIL1:
455 _cairo_hash_table_destroy (surface->all_surfaces);
456 BAIL0:
457 _cairo_array_fini (&surface->objects);
458 free (surface);
460 /* destroy stream on behalf of caller */
461 status_ignored = _cairo_output_stream_destroy (output);
463 return _cairo_surface_create_in_error (status);
467 * cairo_pdf_surface_create_for_stream:
468 * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL
469 * to indicate a no-op @write_func. With a no-op @write_func,
470 * the surface may be queried or used as a source without
471 * generating any temporary files.
472 * @closure: the closure argument for @write_func
473 * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
474 * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
476 * Creates a PDF surface of the specified size in points to be written
477 * incrementally to the stream represented by @write_func and @closure.
479 * Return value: a pointer to the newly created surface. The caller
480 * owns the surface and should call cairo_surface_destroy() when done
481 * with it.
483 * This function always returns a valid pointer, but it will return a
484 * pointer to a "nil" surface if an error such as out of memory
485 * occurs. You can use cairo_surface_status() to check for this.
487 * Since: 1.2
489 cairo_surface_t *
490 cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func,
491 void *closure,
492 double width_in_points,
493 double height_in_points)
495 cairo_output_stream_t *output;
497 output = _cairo_output_stream_create (write_func, NULL, closure);
498 if (_cairo_output_stream_get_status (output))
499 return _cairo_surface_create_in_error (_cairo_output_stream_destroy (output));
501 return _cairo_pdf_surface_create_for_stream_internal (output,
502 width_in_points,
503 height_in_points);
507 * cairo_pdf_surface_create:
508 * @filename: a filename for the PDF output (must be writable), %NULL may be
509 * used to specify no output. This will generate a PDF surface that
510 * may be queried and used as a source, without generating a
511 * temporary file.
512 * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
513 * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
515 * Creates a PDF surface of the specified size in points to be written
516 * to @filename.
518 * Return value: a pointer to the newly created surface. The caller
519 * owns the surface and should call cairo_surface_destroy() when done
520 * with it.
522 * This function always returns a valid pointer, but it will return a
523 * pointer to a "nil" surface if an error such as out of memory
524 * occurs. You can use cairo_surface_status() to check for this.
526 * Since: 1.2
528 cairo_surface_t *
529 cairo_pdf_surface_create (const char *filename,
530 double width_in_points,
531 double height_in_points)
533 cairo_output_stream_t *output;
535 output = _cairo_output_stream_create_for_filename (filename);
536 if (_cairo_output_stream_get_status (output))
537 return _cairo_surface_create_in_error (_cairo_output_stream_destroy (output));
539 return _cairo_pdf_surface_create_for_stream_internal (output,
540 width_in_points,
541 height_in_points);
544 static cairo_bool_t
545 _cairo_surface_is_pdf (cairo_surface_t *surface)
547 return surface->backend == &cairo_pdf_surface_backend;
550 /* If the abstract_surface is a paginated surface, and that paginated
551 * surface's target is a pdf_surface, then set pdf_surface to that
552 * target. Otherwise return FALSE.
554 static cairo_bool_t
555 _extract_pdf_surface (cairo_surface_t *surface,
556 cairo_pdf_surface_t **pdf_surface)
558 cairo_surface_t *target;
559 cairo_status_t status_ignored;
561 if (surface->status)
562 return FALSE;
563 if (surface->finished) {
564 status_ignored = _cairo_surface_set_error (surface,
565 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
566 return FALSE;
569 if (! _cairo_surface_is_paginated (surface)) {
570 status_ignored = _cairo_surface_set_error (surface,
571 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
572 return FALSE;
575 target = _cairo_paginated_surface_get_target (surface);
576 if (target->status) {
577 status_ignored = _cairo_surface_set_error (surface,
578 target->status);
579 return FALSE;
581 if (target->finished) {
582 status_ignored = _cairo_surface_set_error (surface,
583 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
584 return FALSE;
587 if (! _cairo_surface_is_pdf (target)) {
588 status_ignored = _cairo_surface_set_error (surface,
589 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
590 return FALSE;
593 *pdf_surface = (cairo_pdf_surface_t *) target;
594 return TRUE;
598 * cairo_pdf_surface_restrict_to_version:
599 * @surface: a PDF #cairo_surface_t
600 * @version: PDF version
602 * Restricts the generated PDF file to @version. See cairo_pdf_get_versions()
603 * for a list of available version values that can be used here.
605 * This function should only be called before any drawing operations
606 * have been performed on the given surface. The simplest way to do
607 * this is to call this function immediately after creating the
608 * surface.
610 * Since: 1.10
612 void
613 cairo_pdf_surface_restrict_to_version (cairo_surface_t *abstract_surface,
614 cairo_pdf_version_t version)
616 cairo_pdf_surface_t *surface = NULL; /* hide compiler warning */
618 if (! _extract_pdf_surface (abstract_surface, &surface))
619 return;
621 if (version < CAIRO_PDF_VERSION_LAST)
622 surface->pdf_version = version;
624 _cairo_pdf_operators_enable_actual_text(&surface->pdf_operators,
625 version >= CAIRO_PDF_VERSION_1_5);
629 * cairo_pdf_get_versions:
630 * @versions: supported version list
631 * @num_versions: list length
633 * Used to retrieve the list of supported versions. See
634 * cairo_pdf_surface_restrict_to_version().
636 * Since: 1.10
638 void
639 cairo_pdf_get_versions (cairo_pdf_version_t const **versions,
640 int *num_versions)
642 if (versions != NULL)
643 *versions = _cairo_pdf_versions;
645 if (num_versions != NULL)
646 *num_versions = CAIRO_PDF_VERSION_LAST;
650 * cairo_pdf_version_to_string:
651 * @version: a version id
653 * Get the string representation of the given @version id. This function
654 * will return %NULL if @version isn't valid. See cairo_pdf_get_versions()
655 * for a way to get the list of valid version ids.
657 * Return value: the string associated to given version.
659 * Since: 1.10
661 const char *
662 cairo_pdf_version_to_string (cairo_pdf_version_t version)
664 if (version >= CAIRO_PDF_VERSION_LAST)
665 return NULL;
667 return _cairo_pdf_version_strings[version];
671 * cairo_pdf_surface_set_size:
672 * @surface: a PDF #cairo_surface_t
673 * @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
674 * @height_in_points: new surface height, in points (1 point == 1/72.0 inch)
676 * Changes the size of a PDF surface for the current (and
677 * subsequent) pages.
679 * This function should only be called before any drawing operations
680 * have been performed on the current page. The simplest way to do
681 * this is to call this function immediately after creating the
682 * surface or immediately after completing a page with either
683 * cairo_show_page() or cairo_copy_page().
685 * Since: 1.2
687 void
688 cairo_pdf_surface_set_size (cairo_surface_t *surface,
689 double width_in_points,
690 double height_in_points)
692 cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */
693 cairo_status_t status;
695 if (! _extract_pdf_surface (surface, &pdf_surface))
696 return;
698 _cairo_pdf_surface_set_size_internal (pdf_surface,
699 width_in_points,
700 height_in_points);
701 status = _cairo_paginated_surface_set_size (pdf_surface->paginated_surface,
702 width_in_points,
703 height_in_points);
704 if (status)
705 status = _cairo_surface_set_error (surface, status);
708 static void
709 _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
711 int i, size;
712 cairo_pdf_pattern_t *pattern;
713 cairo_pdf_source_surface_t *src_surface;
714 cairo_pdf_smask_group_t *group;
716 size = _cairo_array_num_elements (&surface->page_patterns);
717 for (i = 0; i < size; i++) {
718 pattern = (cairo_pdf_pattern_t *) _cairo_array_index (&surface->page_patterns, i);
719 cairo_pattern_destroy (pattern->pattern);
721 _cairo_array_truncate (&surface->page_patterns, 0);
723 size = _cairo_array_num_elements (&surface->page_surfaces);
724 for (i = 0; i < size; i++) {
725 src_surface = (cairo_pdf_source_surface_t *) _cairo_array_index (&surface->page_surfaces, i);
726 cairo_surface_destroy (src_surface->surface);
728 _cairo_array_truncate (&surface->page_surfaces, 0);
730 size = _cairo_array_num_elements (&surface->smask_groups);
731 for (i = 0; i < size; i++) {
732 _cairo_array_copy_element (&surface->smask_groups, i, &group);
733 _cairo_pdf_smask_group_destroy (group);
735 _cairo_array_truncate (&surface->smask_groups, 0);
736 _cairo_array_truncate (&surface->knockout_group, 0);
739 static void
740 _cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res)
742 int i;
744 for (i = 0; i < CAIRO_NUM_OPERATORS; i++)
745 res->operators[i] = FALSE;
747 _cairo_array_init (&res->alphas, sizeof (double));
748 _cairo_array_init (&res->smasks, sizeof (cairo_pdf_resource_t));
749 _cairo_array_init (&res->patterns, sizeof (cairo_pdf_resource_t));
750 _cairo_array_init (&res->shadings, sizeof (cairo_pdf_resource_t));
751 _cairo_array_init (&res->xobjects, sizeof (cairo_pdf_resource_t));
752 _cairo_array_init (&res->fonts, sizeof (cairo_pdf_font_t));
755 static void
756 _cairo_pdf_group_resources_fini (cairo_pdf_group_resources_t *res)
758 _cairo_array_fini (&res->alphas);
759 _cairo_array_fini (&res->smasks);
760 _cairo_array_fini (&res->patterns);
761 _cairo_array_fini (&res->shadings);
762 _cairo_array_fini (&res->xobjects);
763 _cairo_array_fini (&res->fonts);
766 static void
767 _cairo_pdf_group_resources_clear (cairo_pdf_group_resources_t *res)
769 int i;
771 for (i = 0; i < CAIRO_NUM_OPERATORS; i++)
772 res->operators[i] = FALSE;
774 _cairo_array_truncate (&res->alphas, 0);
775 _cairo_array_truncate (&res->smasks, 0);
776 _cairo_array_truncate (&res->patterns, 0);
777 _cairo_array_truncate (&res->shadings, 0);
778 _cairo_array_truncate (&res->xobjects, 0);
779 _cairo_array_truncate (&res->fonts, 0);
782 static void
783 _cairo_pdf_surface_add_operator (cairo_pdf_surface_t *surface,
784 cairo_operator_t op)
786 cairo_pdf_group_resources_t *res = &surface->resources;
788 res->operators[op] = TRUE;
791 static cairo_int_status_t
792 _cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface,
793 double alpha,
794 int *index)
796 int num_alphas, i;
797 double other;
798 cairo_int_status_t status;
799 cairo_pdf_group_resources_t *res = &surface->resources;
801 num_alphas = _cairo_array_num_elements (&res->alphas);
802 for (i = 0; i < num_alphas; i++) {
803 _cairo_array_copy_element (&res->alphas, i, &other);
804 if (alpha == other) {
805 *index = i;
806 return CAIRO_STATUS_SUCCESS;
810 status = _cairo_array_append (&res->alphas, &alpha);
811 if (unlikely (status))
812 return status;
814 *index = _cairo_array_num_elements (&res->alphas) - 1;
816 return CAIRO_STATUS_SUCCESS;
819 static cairo_int_status_t
820 _cairo_pdf_surface_add_smask (cairo_pdf_surface_t *surface,
821 cairo_pdf_resource_t smask)
823 return _cairo_array_append (&(surface->resources.smasks), &smask);
826 static cairo_int_status_t
827 _cairo_pdf_surface_add_pattern (cairo_pdf_surface_t *surface,
828 cairo_pdf_resource_t pattern)
830 return _cairo_array_append (&(surface->resources.patterns), &pattern);
833 static cairo_int_status_t
834 _cairo_pdf_surface_add_shading (cairo_pdf_surface_t *surface,
835 cairo_pdf_resource_t shading)
837 return _cairo_array_append (&(surface->resources.shadings), &shading);
841 static cairo_int_status_t
842 _cairo_pdf_surface_add_xobject (cairo_pdf_surface_t *surface,
843 cairo_pdf_resource_t xobject)
845 return _cairo_array_append (&(surface->resources.xobjects), &xobject);
848 static cairo_int_status_t
849 _cairo_pdf_surface_add_font (unsigned int font_id,
850 unsigned int subset_id,
851 void *closure)
853 cairo_pdf_surface_t *surface = closure;
854 cairo_pdf_font_t font;
855 int num_fonts, i;
856 cairo_int_status_t status;
857 cairo_pdf_group_resources_t *res = &surface->resources;
859 num_fonts = _cairo_array_num_elements (&res->fonts);
860 for (i = 0; i < num_fonts; i++) {
861 _cairo_array_copy_element (&res->fonts, i, &font);
862 if (font.font_id == font_id &&
863 font.subset_id == subset_id)
864 return CAIRO_STATUS_SUCCESS;
867 num_fonts = _cairo_array_num_elements (&surface->fonts);
868 for (i = 0; i < num_fonts; i++) {
869 _cairo_array_copy_element (&surface->fonts, i, &font);
870 if (font.font_id == font_id &&
871 font.subset_id == subset_id)
872 return _cairo_array_append (&res->fonts, &font);
875 font.font_id = font_id;
876 font.subset_id = subset_id;
877 font.subset_resource = _cairo_pdf_surface_new_object (surface);
878 if (font.subset_resource.id == 0)
879 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
881 status = _cairo_array_append (&surface->fonts, &font);
882 if (unlikely (status))
883 return status;
885 return _cairo_array_append (&res->fonts, &font);
888 static cairo_pdf_resource_t
889 _cairo_pdf_surface_get_font_resource (cairo_pdf_surface_t *surface,
890 unsigned int font_id,
891 unsigned int subset_id)
893 cairo_pdf_font_t font;
894 int num_fonts, i;
896 num_fonts = _cairo_array_num_elements (&surface->fonts);
897 for (i = 0; i < num_fonts; i++) {
898 _cairo_array_copy_element (&surface->fonts, i, &font);
899 if (font.font_id == font_id && font.subset_id == subset_id)
900 return font.subset_resource;
903 font.subset_resource.id = 0;
904 return font.subset_resource;
907 static const char *
908 _cairo_operator_to_pdf_blend_mode (cairo_operator_t op)
910 switch (op) {
911 /* The extend blend mode operators */
912 case CAIRO_OPERATOR_MULTIPLY: return "Multiply";
913 case CAIRO_OPERATOR_SCREEN: return "Screen";
914 case CAIRO_OPERATOR_OVERLAY: return "Overlay";
915 case CAIRO_OPERATOR_DARKEN: return "Darken";
916 case CAIRO_OPERATOR_LIGHTEN: return "Lighten";
917 case CAIRO_OPERATOR_COLOR_DODGE: return "ColorDodge";
918 case CAIRO_OPERATOR_COLOR_BURN: return "ColorBurn";
919 case CAIRO_OPERATOR_HARD_LIGHT: return "HardLight";
920 case CAIRO_OPERATOR_SOFT_LIGHT: return "SoftLight";
921 case CAIRO_OPERATOR_DIFFERENCE: return "Difference";
922 case CAIRO_OPERATOR_EXCLUSION: return "Exclusion";
923 case CAIRO_OPERATOR_HSL_HUE: return "Hue";
924 case CAIRO_OPERATOR_HSL_SATURATION: return "Saturation";
925 case CAIRO_OPERATOR_HSL_COLOR: return "Color";
926 case CAIRO_OPERATOR_HSL_LUMINOSITY: return "Luminosity";
928 default:
929 /* The original Porter-Duff set */
930 case CAIRO_OPERATOR_CLEAR:
931 case CAIRO_OPERATOR_SOURCE:
932 case CAIRO_OPERATOR_OVER:
933 case CAIRO_OPERATOR_IN:
934 case CAIRO_OPERATOR_OUT:
935 case CAIRO_OPERATOR_ATOP:
936 case CAIRO_OPERATOR_DEST:
937 case CAIRO_OPERATOR_DEST_OVER:
938 case CAIRO_OPERATOR_DEST_IN:
939 case CAIRO_OPERATOR_DEST_OUT:
940 case CAIRO_OPERATOR_DEST_ATOP:
941 case CAIRO_OPERATOR_XOR:
942 case CAIRO_OPERATOR_ADD:
943 case CAIRO_OPERATOR_SATURATE:
944 return "Normal";
948 static void
949 _cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t *surface,
950 cairo_pdf_group_resources_t *res)
952 int num_alphas, num_smasks, num_resources, i;
953 double alpha;
954 cairo_pdf_resource_t *smask, *pattern, *shading, *xobject;
955 cairo_pdf_font_t *font;
957 _cairo_output_stream_printf (surface->output, "<<\n");
959 num_alphas = _cairo_array_num_elements (&res->alphas);
960 num_smasks = _cairo_array_num_elements (&res->smasks);
961 if (num_alphas > 0 || num_smasks > 0) {
962 _cairo_output_stream_printf (surface->output,
963 " /ExtGState <<\n");
965 for (i = 0; i < CAIRO_NUM_OPERATORS; i++) {
966 if (res->operators[i]) {
967 _cairo_output_stream_printf (surface->output,
968 " /b%d << /BM /%s >>\n",
969 i, _cairo_operator_to_pdf_blend_mode(i));
973 for (i = 0; i < num_alphas; i++) {
974 _cairo_array_copy_element (&res->alphas, i, &alpha);
975 _cairo_output_stream_printf (surface->output,
976 " /a%d << /CA %f /ca %f >>\n",
977 i, alpha, alpha);
980 for (i = 0; i < num_smasks; i++) {
981 smask = _cairo_array_index (&res->smasks, i);
982 _cairo_output_stream_printf (surface->output,
983 " /s%d %d 0 R\n",
984 smask->id, smask->id);
987 _cairo_output_stream_printf (surface->output,
988 " >>\n");
991 num_resources = _cairo_array_num_elements (&res->patterns);
992 if (num_resources > 0) {
993 _cairo_output_stream_printf (surface->output,
994 " /Pattern <<");
995 for (i = 0; i < num_resources; i++) {
996 pattern = _cairo_array_index (&res->patterns, i);
997 _cairo_output_stream_printf (surface->output,
998 " /p%d %d 0 R",
999 pattern->id, pattern->id);
1002 _cairo_output_stream_printf (surface->output,
1003 " >>\n");
1006 num_resources = _cairo_array_num_elements (&res->shadings);
1007 if (num_resources > 0) {
1008 _cairo_output_stream_printf (surface->output,
1009 " /Shading <<");
1010 for (i = 0; i < num_resources; i++) {
1011 shading = _cairo_array_index (&res->shadings, i);
1012 _cairo_output_stream_printf (surface->output,
1013 " /sh%d %d 0 R",
1014 shading->id, shading->id);
1017 _cairo_output_stream_printf (surface->output,
1018 " >>\n");
1021 num_resources = _cairo_array_num_elements (&res->xobjects);
1022 if (num_resources > 0) {
1023 _cairo_output_stream_printf (surface->output,
1024 " /XObject <<");
1026 for (i = 0; i < num_resources; i++) {
1027 xobject = _cairo_array_index (&res->xobjects, i);
1028 _cairo_output_stream_printf (surface->output,
1029 " /x%d %d 0 R",
1030 xobject->id, xobject->id);
1033 _cairo_output_stream_printf (surface->output,
1034 " >>\n");
1037 num_resources = _cairo_array_num_elements (&res->fonts);
1038 if (num_resources > 0) {
1039 _cairo_output_stream_printf (surface->output," /Font <<\n");
1040 for (i = 0; i < num_resources; i++) {
1041 font = _cairo_array_index (&res->fonts, i);
1042 _cairo_output_stream_printf (surface->output,
1043 " /f-%d-%d %d 0 R\n",
1044 font->font_id,
1045 font->subset_id,
1046 font->subset_resource.id);
1048 _cairo_output_stream_printf (surface->output, " >>\n");
1051 _cairo_output_stream_printf (surface->output,
1052 ">>\n");
1055 static cairo_pdf_smask_group_t *
1056 _cairo_pdf_surface_create_smask_group (cairo_pdf_surface_t *surface,
1057 const cairo_rectangle_int_t *extents)
1059 cairo_pdf_smask_group_t *group;
1061 group = calloc (1, sizeof (cairo_pdf_smask_group_t));
1062 if (unlikely (group == NULL)) {
1063 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
1064 return NULL;
1067 group->group_res = _cairo_pdf_surface_new_object (surface);
1068 if (group->group_res.id == 0) {
1069 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
1070 free (group);
1071 return NULL;
1073 group->width = surface->width;
1074 group->height = surface->height;
1075 if (extents != NULL) {
1076 group->extents = *extents;
1077 } else {
1078 group->extents.x = 0;
1079 group->extents.y = 0;
1080 group->extents.width = surface->width;
1081 group->extents.height = surface->height;
1083 group->extents = *extents;
1085 return group;
1088 static void
1089 _cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group)
1091 if (group->operation == PDF_FILL || group->operation == PDF_STROKE)
1092 _cairo_path_fixed_fini (&group->path);
1093 if (group->source)
1094 cairo_pattern_destroy (group->source);
1095 if (group->mask)
1096 cairo_pattern_destroy (group->mask);
1097 free (group->utf8);
1098 free (group->glyphs);
1099 free (group->clusters);
1100 if (group->scaled_font)
1101 cairo_scaled_font_destroy (group->scaled_font);
1102 free (group);
1105 static cairo_int_status_t
1106 _cairo_pdf_surface_add_smask_group (cairo_pdf_surface_t *surface,
1107 cairo_pdf_smask_group_t *group)
1109 return _cairo_array_append (&surface->smask_groups, &group);
1112 static cairo_bool_t
1113 _cairo_pdf_source_surface_equal (const void *key_a, const void *key_b)
1115 const cairo_pdf_source_surface_entry_t *a = key_a;
1116 const cairo_pdf_source_surface_entry_t *b = key_b;
1118 if (a->interpolate != b->interpolate)
1119 return FALSE;
1121 if (a->unique_id && b->unique_id && a->unique_id_length == b->unique_id_length)
1122 return (memcmp (a->unique_id, b->unique_id, a->unique_id_length) == 0);
1124 return (a->id == b->id);
1127 static void
1128 _cairo_pdf_source_surface_init_key (cairo_pdf_source_surface_entry_t *key)
1130 if (key->unique_id && key->unique_id_length > 0) {
1131 key->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE,
1132 key->unique_id, key->unique_id_length);
1133 } else {
1134 key->base.hash = key->id;
1138 static cairo_int_status_t
1139 _cairo_pdf_surface_acquire_source_image_from_pattern (cairo_pdf_surface_t *surface,
1140 const cairo_pattern_t *pattern,
1141 cairo_image_surface_t **image,
1142 void **image_extra)
1144 switch (pattern->type) {
1145 case CAIRO_PATTERN_TYPE_SURFACE: {
1146 cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) pattern;
1147 return _cairo_surface_acquire_source_image (surf_pat->surface, image, image_extra);
1148 } break;
1150 case CAIRO_PATTERN_TYPE_RASTER_SOURCE: {
1151 cairo_surface_t *surf;
1152 surf = _cairo_raster_source_pattern_acquire (pattern, &surface->base, NULL);
1153 if (!surf)
1154 return CAIRO_INT_STATUS_UNSUPPORTED;
1155 assert (_cairo_surface_is_image (surf));
1156 *image = (cairo_image_surface_t *) surf;
1157 } break;
1159 case CAIRO_PATTERN_TYPE_SOLID:
1160 case CAIRO_PATTERN_TYPE_LINEAR:
1161 case CAIRO_PATTERN_TYPE_RADIAL:
1162 case CAIRO_PATTERN_TYPE_MESH:
1163 default:
1164 ASSERT_NOT_REACHED;
1165 break;
1168 return CAIRO_STATUS_SUCCESS;
1171 static void
1172 _cairo_pdf_surface_release_source_image_from_pattern (cairo_pdf_surface_t *surface,
1173 const cairo_pattern_t *pattern,
1174 cairo_image_surface_t *image,
1175 void *image_extra)
1177 switch (pattern->type) {
1178 case CAIRO_PATTERN_TYPE_SURFACE: {
1179 cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) pattern;
1180 _cairo_surface_release_source_image (surf_pat->surface, image, image_extra);
1181 } break;
1183 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
1184 _cairo_raster_source_pattern_release (pattern, &image->base);
1185 break;
1187 case CAIRO_PATTERN_TYPE_SOLID:
1188 case CAIRO_PATTERN_TYPE_LINEAR:
1189 case CAIRO_PATTERN_TYPE_RADIAL:
1190 case CAIRO_PATTERN_TYPE_MESH:
1191 default:
1193 ASSERT_NOT_REACHED;
1194 break;
1198 static cairo_int_status_t
1199 _get_jbig2_image_info (cairo_surface_t *source,
1200 cairo_image_info_t *info,
1201 const unsigned char **mime_data,
1202 unsigned long *mime_data_length)
1204 cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JBIG2,
1205 mime_data, mime_data_length);
1206 if (*mime_data == NULL)
1207 return CAIRO_INT_STATUS_UNSUPPORTED;
1209 return _cairo_image_info_get_jbig2_info (info, *mime_data, *mime_data_length);
1212 static cairo_int_status_t
1213 _get_jpx_image_info (cairo_surface_t *source,
1214 cairo_image_info_t *info,
1215 const unsigned char **mime_data,
1216 unsigned long *mime_data_length)
1218 cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JP2,
1219 mime_data, mime_data_length);
1220 if (*mime_data == NULL)
1221 return CAIRO_INT_STATUS_UNSUPPORTED;
1223 return _cairo_image_info_get_jpx_info (info, *mime_data, *mime_data_length);
1226 static cairo_int_status_t
1227 _get_jpeg_image_info (cairo_surface_t *source,
1228 cairo_image_info_t *info,
1229 const unsigned char **mime_data,
1230 unsigned long *mime_data_length)
1232 cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
1233 mime_data, mime_data_length);
1234 if (*mime_data == NULL)
1235 return CAIRO_INT_STATUS_UNSUPPORTED;
1237 return _cairo_image_info_get_jpeg_info (info, *mime_data, *mime_data_length);
1240 static cairo_int_status_t
1241 _get_source_surface_size (cairo_surface_t *source,
1242 int *width,
1243 int *height,
1244 cairo_rectangle_int_t *extents)
1246 cairo_int_status_t status;
1247 cairo_image_info_t info;
1248 const unsigned char *mime_data;
1249 unsigned long mime_data_length;
1251 if (source->type == CAIRO_SURFACE_TYPE_RECORDING) {
1252 if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1253 cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
1255 *extents = sub->extents;
1256 *width = extents->width;
1257 *height = extents->height;
1258 } else {
1259 cairo_surface_t *free_me = NULL;
1260 cairo_rectangle_int_t surf_extents;
1261 cairo_box_t box;
1262 cairo_bool_t bounded;
1264 if (_cairo_surface_is_snapshot (source))
1265 free_me = source = _cairo_surface_snapshot_get_target (source);
1267 status = _cairo_recording_surface_get_ink_bbox ((cairo_recording_surface_t *)source,
1268 &box, NULL);
1269 if (unlikely (status)) {
1270 cairo_surface_destroy (free_me);
1271 return status;
1274 bounded = _cairo_surface_get_extents (source, &surf_extents);
1275 cairo_surface_destroy (free_me);
1277 *width = surf_extents.width;
1278 *height = surf_extents.height;
1280 _cairo_box_round_to_rectangle (&box, extents);
1283 return CAIRO_STATUS_SUCCESS;
1286 extents->x = 0;
1287 extents->y = 0;
1289 status = _get_jbig2_image_info (source, &info, &mime_data, &mime_data_length);
1290 if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
1291 *width = info.width;
1292 *height = info.height;
1293 extents->width = info.width;
1294 extents->height = info.height;
1295 return status;
1298 status = _get_jpx_image_info (source, &info, &mime_data, &mime_data_length);
1299 if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
1300 *width = info.width;
1301 *height = info.height;
1302 extents->width = info.width;
1303 extents->height = info.height;
1304 return status;
1307 status = _get_jpeg_image_info (source, &info, &mime_data, &mime_data_length);
1308 if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
1309 *width = info.width;
1310 *height = info.height;
1311 extents->width = info.width;
1312 extents->height = info.height;
1313 return status;
1316 if (! _cairo_surface_get_extents (source, extents))
1317 return CAIRO_INT_STATUS_UNSUPPORTED;
1319 *width = extents->width;
1320 *height = extents->height;
1322 return CAIRO_STATUS_SUCCESS;
1326 * _cairo_pdf_surface_add_source_surface:
1327 * @surface: the pdf surface
1328 * @source_surface: A #cairo_surface_t to use as the source surface
1329 * @source_pattern: A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source
1330 * @op: the operator used to composite this source
1331 * @filter: filter type of the source pattern
1332 * @stencil_mask: if true, the surface will be written to the PDF as an /ImageMask
1333 * @smask: if true, only the alpha channel will be written (images only)
1334 * @extents: extents of the operation that is using this source
1335 * @smask_res: if not NULL, the image written will specify this resource as the smask for the image (images only)
1336 * @surface_res: return PDF resource number of the surface
1337 * @width: returns width of surface
1338 * @height: returns height of surface
1339 * @x_offset: x offset of surface
1340 * @t_offset: y offset of surface
1341 * @source_extents: returns extents of source (either ink extents or extents needed to cover @extents)
1343 * Add surface or raster_source pattern to list of surfaces to be
1344 * written to the PDF file when the current page is finished. Returns
1345 * a PDF resource to reference the image. A hash table of all images
1346 * in the PDF files (keyed by CAIRO_MIME_TYPE_UNIQUE_ID or surface
1347 * unique_id) to ensure surfaces with the same id are only written
1348 * once to the PDF file.
1350 * Only one of @source_pattern or @source_surface is to be
1351 * specified. Set the other to NULL.
1353 static cairo_int_status_t
1354 _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
1355 cairo_surface_t *source_surface,
1356 const cairo_pattern_t *source_pattern,
1357 cairo_operator_t op,
1358 cairo_filter_t filter,
1359 cairo_bool_t stencil_mask,
1360 cairo_bool_t smask,
1361 const cairo_rectangle_int_t *extents,
1362 cairo_pdf_resource_t *smask_res,
1363 cairo_pdf_resource_t *surface_res,
1364 int *width,
1365 int *height,
1366 double *x_offset,
1367 double *y_offset,
1368 cairo_rectangle_int_t *source_extents)
1370 cairo_pdf_source_surface_t src_surface;
1371 cairo_pdf_source_surface_entry_t surface_key;
1372 cairo_pdf_source_surface_entry_t *surface_entry;
1373 cairo_int_status_t status;
1374 cairo_bool_t interpolate;
1375 unsigned char *unique_id = NULL;
1376 unsigned long unique_id_length = 0;
1377 cairo_image_surface_t *image;
1378 void *image_extra;
1380 switch (filter) {
1381 default:
1382 case CAIRO_FILTER_GOOD:
1383 case CAIRO_FILTER_BEST:
1384 case CAIRO_FILTER_BILINEAR:
1385 interpolate = TRUE;
1386 break;
1387 case CAIRO_FILTER_FAST:
1388 case CAIRO_FILTER_NEAREST:
1389 case CAIRO_FILTER_GAUSSIAN:
1390 interpolate = FALSE;
1391 break;
1394 *x_offset = 0;
1395 *y_offset = 0;
1396 if (source_pattern) {
1397 if (source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
1398 status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, source_pattern,
1399 &image, &image_extra);
1400 if (unlikely (status))
1401 return status;
1402 source_surface = &image->base;
1403 cairo_surface_get_device_offset (source_surface, x_offset, y_offset);
1404 } else {
1405 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source_pattern;
1406 source_surface = surface_pattern->surface;
1410 surface_key.id = source_surface->unique_id;
1411 surface_key.interpolate = interpolate;
1412 cairo_surface_get_mime_data (source_surface, CAIRO_MIME_TYPE_UNIQUE_ID,
1413 (const unsigned char **) &surface_key.unique_id,
1414 &surface_key.unique_id_length);
1415 _cairo_pdf_source_surface_init_key (&surface_key);
1416 surface_entry = _cairo_hash_table_lookup (surface->all_surfaces, &surface_key.base);
1417 if (surface_entry) {
1418 *surface_res = surface_entry->surface_res;
1419 *width = surface_entry->width;
1420 *height = surface_entry->height;
1421 *source_extents = surface_entry->extents;
1422 status = CAIRO_STATUS_SUCCESS;
1423 } else {
1424 status = _get_source_surface_size (source_surface,
1425 width,
1426 height,
1427 source_extents);
1428 if (unlikely(status))
1429 goto release_source;
1431 if (surface_key.unique_id && surface_key.unique_id_length > 0) {
1432 unique_id = _cairo_malloc (surface_key.unique_id_length);
1433 if (unique_id == NULL) {
1434 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1435 goto release_source;
1438 unique_id_length = surface_key.unique_id_length;
1439 memcpy (unique_id, surface_key.unique_id, unique_id_length);
1440 } else {
1441 unique_id = NULL;
1442 unique_id_length = 0;
1446 release_source:
1447 if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)
1448 _cairo_pdf_surface_release_source_image_from_pattern (surface, source_pattern, image, image_extra);
1450 if (status || surface_entry)
1451 return status;
1453 surface_entry = malloc (sizeof (cairo_pdf_source_surface_entry_t));
1454 if (surface_entry == NULL) {
1455 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1456 goto fail1;
1459 surface_entry->id = surface_key.id;
1460 surface_entry->operator = op;
1461 surface_entry->interpolate = interpolate;
1462 surface_entry->stencil_mask = stencil_mask;
1463 surface_entry->smask = smask;
1464 surface_entry->unique_id_length = unique_id_length;
1465 surface_entry->unique_id = unique_id;
1466 surface_entry->width = *width;
1467 surface_entry->height = *height;
1468 surface_entry->extents = *source_extents;
1469 if (smask_res)
1470 surface_entry->smask_res = *smask_res;
1471 else
1472 surface_entry->smask_res.id = 0;
1473 _cairo_pdf_source_surface_init_key (surface_entry);
1475 src_surface.hash_entry = surface_entry;
1476 if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
1477 src_surface.type = CAIRO_PATTERN_TYPE_RASTER_SOURCE;
1478 src_surface.surface = NULL;
1479 status = _cairo_pattern_create_copy (&src_surface.raster_pattern, source_pattern);
1480 if (unlikely (status))
1481 goto fail2;
1483 } else {
1484 src_surface.type = CAIRO_PATTERN_TYPE_SURFACE;
1485 src_surface.surface = cairo_surface_reference (source_surface);
1486 src_surface.raster_pattern = NULL;
1489 surface_entry->surface_res = _cairo_pdf_surface_new_object (surface);
1490 if (surface_entry->surface_res.id == 0) {
1491 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1492 goto fail3;
1495 status = _cairo_array_append (&surface->page_surfaces, &src_surface);
1496 if (unlikely (status))
1497 goto fail3;
1499 status = _cairo_hash_table_insert (surface->all_surfaces,
1500 &surface_entry->base);
1501 if (unlikely(status))
1502 goto fail3;
1504 *surface_res = surface_entry->surface_res;
1506 return status;
1508 fail3:
1509 if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)
1510 cairo_pattern_destroy (src_surface.raster_pattern);
1511 else
1512 cairo_surface_destroy (src_surface.surface);
1514 fail2:
1515 free (surface_entry);
1517 fail1:
1518 free (unique_id);
1520 return status;
1523 static cairo_int_status_t
1524 _cairo_pdf_surface_add_pdf_pattern_or_shading (cairo_pdf_surface_t *surface,
1525 const cairo_pattern_t *pattern,
1526 cairo_operator_t op,
1527 const cairo_rectangle_int_t *extents,
1528 cairo_bool_t is_shading,
1529 cairo_pdf_resource_t *pattern_res,
1530 cairo_pdf_resource_t *gstate_res)
1532 cairo_pdf_pattern_t pdf_pattern;
1533 cairo_int_status_t status;
1535 pdf_pattern.is_shading = is_shading;
1536 pdf_pattern.operator = op;
1538 /* Solid colors are emitted into the content stream */
1539 if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
1540 pattern_res->id = 0;
1541 gstate_res->id = 0;
1542 return CAIRO_INT_STATUS_SUCCESS;
1545 status = _cairo_pattern_create_copy (&pdf_pattern.pattern, pattern);
1546 if (unlikely (status))
1547 return status;
1549 pdf_pattern.pattern_res = _cairo_pdf_surface_new_object (surface);
1550 if (pdf_pattern.pattern_res.id == 0) {
1551 cairo_pattern_destroy (pdf_pattern.pattern);
1552 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1555 pdf_pattern.gstate_res.id = 0;
1557 /* gradient patterns require an smask object to implement transparency */
1558 if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
1559 pattern->type == CAIRO_PATTERN_TYPE_RADIAL ||
1560 pattern->type == CAIRO_PATTERN_TYPE_MESH)
1562 double min_alpha;
1564 _cairo_pattern_alpha_range (pattern, &min_alpha, NULL);
1565 if (! CAIRO_ALPHA_IS_OPAQUE (min_alpha)) {
1566 pdf_pattern.gstate_res = _cairo_pdf_surface_new_object (surface);
1567 if (pdf_pattern.gstate_res.id == 0) {
1568 cairo_pattern_destroy (pdf_pattern.pattern);
1569 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1574 pdf_pattern.width = surface->width;
1575 pdf_pattern.height = surface->height;
1576 if (extents != NULL) {
1577 pdf_pattern.extents = *extents;
1578 } else {
1579 pdf_pattern.extents.x = 0;
1580 pdf_pattern.extents.y = 0;
1581 pdf_pattern.extents.width = surface->width;
1582 pdf_pattern.extents.height = surface->height;
1585 *pattern_res = pdf_pattern.pattern_res;
1586 *gstate_res = pdf_pattern.gstate_res;
1588 status = _cairo_array_append (&surface->page_patterns, &pdf_pattern);
1589 if (unlikely (status)) {
1590 cairo_pattern_destroy (pdf_pattern.pattern);
1591 return status;
1594 return CAIRO_INT_STATUS_SUCCESS;
1597 /* Get BBox in PDF coordinates from extents in cairo coordinates */
1598 static void
1599 _get_bbox_from_extents (double surface_height,
1600 const cairo_rectangle_int_t *extents,
1601 cairo_box_double_t *bbox)
1603 bbox->p1.x = extents->x;
1604 bbox->p1.y = surface_height - (extents->y + extents->height);
1605 bbox->p2.x = extents->x + extents->width;
1606 bbox->p2.y = surface_height - extents->y;
1609 static cairo_int_status_t
1610 _cairo_pdf_surface_add_pdf_shading (cairo_pdf_surface_t *surface,
1611 const cairo_pattern_t *pattern,
1612 cairo_operator_t op,
1613 const cairo_rectangle_int_t *extents,
1614 cairo_pdf_resource_t *shading_res,
1615 cairo_pdf_resource_t *gstate_res)
1617 return _cairo_pdf_surface_add_pdf_pattern_or_shading (surface,
1618 pattern,
1620 extents,
1621 TRUE,
1622 shading_res,
1623 gstate_res);
1626 static cairo_int_status_t
1627 _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
1628 const cairo_pattern_t *pattern,
1629 cairo_operator_t op,
1630 const cairo_rectangle_int_t *extents,
1631 cairo_pdf_resource_t *pattern_res,
1632 cairo_pdf_resource_t *gstate_res)
1634 return _cairo_pdf_surface_add_pdf_pattern_or_shading (surface,
1635 pattern,
1637 extents,
1638 FALSE,
1639 pattern_res,
1640 gstate_res);
1643 static cairo_int_status_t
1644 _cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface,
1645 cairo_pdf_resource_t *resource,
1646 cairo_bool_t compressed,
1647 const char *fmt,
1648 ...)
1650 va_list ap;
1651 cairo_pdf_resource_t self, length;
1652 cairo_output_stream_t *output = NULL;
1654 if (resource) {
1655 self = *resource;
1656 _cairo_pdf_surface_update_object (surface, self);
1657 } else {
1658 self = _cairo_pdf_surface_new_object (surface);
1659 if (self.id == 0)
1660 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1663 length = _cairo_pdf_surface_new_object (surface);
1664 if (length.id == 0)
1665 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1667 if (compressed) {
1668 output = _cairo_deflate_stream_create (surface->output);
1669 if (_cairo_output_stream_get_status (output))
1670 return _cairo_output_stream_destroy (output);
1673 surface->pdf_stream.active = TRUE;
1674 surface->pdf_stream.self = self;
1675 surface->pdf_stream.length = length;
1676 surface->pdf_stream.compressed = compressed;
1677 surface->current_pattern_is_solid_color = FALSE;
1678 surface->current_operator = CAIRO_OPERATOR_OVER;
1679 _cairo_pdf_operators_reset (&surface->pdf_operators);
1681 _cairo_output_stream_printf (surface->output,
1682 "%d 0 obj\n"
1683 "<< /Length %d 0 R\n",
1684 surface->pdf_stream.self.id,
1685 surface->pdf_stream.length.id);
1686 if (compressed)
1687 _cairo_output_stream_printf (surface->output,
1688 " /Filter /FlateDecode\n");
1690 if (fmt != NULL) {
1691 va_start (ap, fmt);
1692 _cairo_output_stream_vprintf (surface->output, fmt, ap);
1693 va_end (ap);
1696 _cairo_output_stream_printf (surface->output,
1697 ">>\n"
1698 "stream\n");
1700 surface->pdf_stream.start_offset = _cairo_output_stream_get_position (surface->output);
1702 if (compressed) {
1703 assert (surface->pdf_stream.old_output == NULL);
1704 surface->pdf_stream.old_output = surface->output;
1705 surface->output = output;
1706 _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
1709 return _cairo_output_stream_get_status (surface->output);
1712 static cairo_int_status_t
1713 _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
1715 cairo_int_status_t status;
1716 long length;
1718 if (! surface->pdf_stream.active)
1719 return CAIRO_INT_STATUS_SUCCESS;
1721 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
1723 if (surface->pdf_stream.compressed) {
1724 cairo_int_status_t status2;
1726 status2 = _cairo_output_stream_destroy (surface->output);
1727 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
1728 status = status2;
1730 surface->output = surface->pdf_stream.old_output;
1731 _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
1732 surface->pdf_stream.old_output = NULL;
1735 length = _cairo_output_stream_get_position (surface->output) -
1736 surface->pdf_stream.start_offset;
1737 _cairo_output_stream_printf (surface->output,
1738 "\n"
1739 "endstream\n"
1740 "endobj\n");
1742 _cairo_pdf_surface_update_object (surface,
1743 surface->pdf_stream.length);
1744 _cairo_output_stream_printf (surface->output,
1745 "%d 0 obj\n"
1746 " %ld\n"
1747 "endobj\n",
1748 surface->pdf_stream.length.id,
1749 length);
1751 surface->pdf_stream.active = FALSE;
1753 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
1754 status = _cairo_output_stream_get_status (surface->output);
1756 return status;
1759 static void
1760 _cairo_pdf_surface_write_memory_stream (cairo_pdf_surface_t *surface,
1761 cairo_output_stream_t *mem_stream,
1762 cairo_pdf_resource_t resource,
1763 cairo_pdf_group_resources_t *resources,
1764 cairo_bool_t is_knockout_group,
1765 const cairo_box_double_t *bbox)
1767 _cairo_pdf_surface_update_object (surface, resource);
1769 _cairo_output_stream_printf (surface->output,
1770 "%d 0 obj\n"
1771 "<< /Type /XObject\n"
1772 " /Length %d\n",
1773 resource.id,
1774 _cairo_memory_stream_length (mem_stream));
1776 if (surface->compress_content) {
1777 _cairo_output_stream_printf (surface->output,
1778 " /Filter /FlateDecode\n");
1781 _cairo_output_stream_printf (surface->output,
1782 " /Subtype /Form\n"
1783 " /BBox [ %f %f %f %f ]\n"
1784 " /Group <<\n"
1785 " /Type /Group\n"
1786 " /S /Transparency\n"
1787 " /I true\n"
1788 " /CS /DeviceRGB\n",
1789 bbox->p1.x, bbox->p1.y, bbox->p2.x, bbox->p2.y);
1791 if (is_knockout_group)
1792 _cairo_output_stream_printf (surface->output,
1793 " /K true\n");
1795 _cairo_output_stream_printf (surface->output,
1796 " >>\n"
1797 " /Resources\n");
1798 _cairo_pdf_surface_emit_group_resources (surface, resources);
1799 _cairo_output_stream_printf (surface->output,
1800 ">>\n"
1801 "stream\n");
1802 _cairo_memory_stream_copy (mem_stream, surface->output);
1803 _cairo_output_stream_printf (surface->output,
1804 "endstream\n"
1805 "endobj\n");
1808 static cairo_int_status_t
1809 _cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface,
1810 const cairo_box_double_t *bbox,
1811 cairo_pdf_resource_t *resource)
1813 cairo_int_status_t status;
1815 assert (surface->pdf_stream.active == FALSE);
1816 assert (surface->group_stream.active == FALSE);
1818 surface->group_stream.active = TRUE;
1819 surface->current_pattern_is_solid_color = FALSE;
1820 surface->current_operator = CAIRO_OPERATOR_OVER;
1821 _cairo_pdf_operators_reset (&surface->pdf_operators);
1823 surface->group_stream.mem_stream = _cairo_memory_stream_create ();
1825 if (surface->compress_content) {
1826 surface->group_stream.stream =
1827 _cairo_deflate_stream_create (surface->group_stream.mem_stream);
1828 } else {
1829 surface->group_stream.stream = surface->group_stream.mem_stream;
1831 status = _cairo_output_stream_get_status (surface->group_stream.stream);
1833 surface->group_stream.old_output = surface->output;
1834 surface->output = surface->group_stream.stream;
1835 _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
1836 _cairo_pdf_group_resources_clear (&surface->resources);
1838 if (resource) {
1839 surface->group_stream.resource = *resource;
1840 } else {
1841 surface->group_stream.resource = _cairo_pdf_surface_new_object (surface);
1842 if (surface->group_stream.resource.id == 0)
1843 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1845 surface->group_stream.is_knockout = FALSE;
1846 surface->group_stream.bbox = *bbox;
1848 return status;
1851 static cairo_int_status_t
1852 _cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t *surface,
1853 const cairo_box_double_t *bbox)
1855 cairo_int_status_t status;
1857 status = _cairo_pdf_surface_open_group (surface, bbox, NULL);
1858 if (unlikely (status))
1859 return status;
1861 surface->group_stream.is_knockout = TRUE;
1863 return CAIRO_INT_STATUS_SUCCESS;
1866 static cairo_int_status_t
1867 _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
1868 cairo_pdf_resource_t *group)
1870 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS, status2;
1872 assert (surface->pdf_stream.active == FALSE);
1873 assert (surface->group_stream.active == TRUE);
1875 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
1876 if (unlikely (status))
1877 return status;
1879 if (surface->compress_content) {
1880 status = _cairo_output_stream_destroy (surface->group_stream.stream);
1881 surface->group_stream.stream = NULL;
1883 _cairo_output_stream_printf (surface->group_stream.mem_stream,
1884 "\n");
1886 surface->output = surface->group_stream.old_output;
1887 _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
1888 surface->group_stream.active = FALSE;
1889 _cairo_pdf_surface_write_memory_stream (surface,
1890 surface->group_stream.mem_stream,
1891 surface->group_stream.resource,
1892 &surface->resources,
1893 surface->group_stream.is_knockout,
1894 &surface->group_stream.bbox);
1895 if (group)
1896 *group = surface->group_stream.resource;
1898 status2 = _cairo_output_stream_destroy (surface->group_stream.mem_stream);
1899 if (status == CAIRO_INT_STATUS_SUCCESS)
1900 status = status2;
1902 surface->group_stream.mem_stream = NULL;
1903 surface->group_stream.stream = NULL;
1905 return status;
1908 static cairo_int_status_t
1909 _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface,
1910 const cairo_box_double_t *bbox,
1911 cairo_pdf_resource_t *resource,
1912 cairo_bool_t is_form,
1913 cairo_bool_t is_group)
1915 cairo_int_status_t status;
1917 assert (surface->pdf_stream.active == FALSE);
1918 assert (surface->group_stream.active == FALSE);
1920 surface->content_resources = _cairo_pdf_surface_new_object (surface);
1921 if (surface->content_resources.id == 0)
1922 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1924 if (is_form) {
1925 assert (bbox != NULL);
1927 if (is_group) {
1928 status =
1929 _cairo_pdf_surface_open_stream (surface,
1930 resource,
1931 surface->compress_content,
1932 " /Type /XObject\n"
1933 " /Subtype /Form\n"
1934 " /BBox [ %f %f %f %f ]\n"
1935 " /Group <<\n"
1936 " /Type /Group\n"
1937 " /S /Transparency\n"
1938 " /I true\n"
1939 " /CS /DeviceRGB\n"
1940 " >>\n"
1941 " /Resources %d 0 R\n",
1942 bbox->p1.x,
1943 bbox->p1.y,
1944 bbox->p2.x,
1945 bbox->p2.y,
1946 surface->content_resources.id);
1947 } else {
1948 status =
1949 _cairo_pdf_surface_open_stream (surface,
1950 resource,
1951 surface->compress_content,
1952 " /Type /XObject\n"
1953 " /Subtype /Form\n"
1954 " /BBox [ %f %f %f %f ]\n"
1955 " /Resources %d 0 R\n",
1956 bbox->p1.x,
1957 bbox->p1.y,
1958 bbox->p2.x,
1959 bbox->p2.y,
1960 surface->content_resources.id);
1962 } else {
1963 status =
1964 _cairo_pdf_surface_open_stream (surface,
1965 resource,
1966 surface->compress_content,
1967 NULL);
1969 if (unlikely (status))
1970 return status;
1972 surface->content = surface->pdf_stream.self;
1974 _cairo_output_stream_printf (surface->output, "q\n");
1976 return _cairo_output_stream_get_status (surface->output);
1979 static cairo_int_status_t
1980 _cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface)
1982 cairo_int_status_t status;
1984 assert (surface->pdf_stream.active == TRUE);
1985 assert (surface->group_stream.active == FALSE);
1987 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
1988 if (unlikely (status))
1989 return status;
1991 _cairo_output_stream_printf (surface->output, "Q\n");
1992 status = _cairo_pdf_surface_close_stream (surface);
1993 if (unlikely (status))
1994 return status;
1996 _cairo_pdf_surface_update_object (surface, surface->content_resources);
1997 _cairo_output_stream_printf (surface->output,
1998 "%d 0 obj\n",
1999 surface->content_resources.id);
2000 _cairo_pdf_surface_emit_group_resources (surface, &surface->resources);
2001 _cairo_output_stream_printf (surface->output,
2002 "endobj\n");
2004 return _cairo_output_stream_get_status (surface->output);
2007 static void
2008 _cairo_pdf_source_surface_entry_pluck (void *entry, void *closure)
2010 cairo_pdf_source_surface_entry_t *surface_entry = entry;
2011 cairo_hash_table_t *patterns = closure;
2013 _cairo_hash_table_remove (patterns, &surface_entry->base);
2014 free (surface_entry->unique_id);
2016 free (surface_entry);
2019 static cairo_status_t
2020 _cairo_pdf_surface_finish (void *abstract_surface)
2022 cairo_pdf_surface_t *surface = abstract_surface;
2023 long offset;
2024 cairo_pdf_resource_t info, catalog;
2025 cairo_status_t status, status2;
2026 int size, i;
2027 cairo_pdf_jbig2_global_t *global;
2029 status = surface->base.status;
2030 if (status == CAIRO_STATUS_SUCCESS)
2031 status = _cairo_pdf_surface_emit_font_subsets (surface);
2033 _cairo_pdf_surface_write_pages (surface);
2035 info = _cairo_pdf_surface_write_info (surface);
2036 if (info.id == 0 && status == CAIRO_STATUS_SUCCESS)
2037 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2039 catalog = _cairo_pdf_surface_write_catalog (surface);
2040 if (catalog.id == 0 && status == CAIRO_STATUS_SUCCESS)
2041 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2043 offset = _cairo_pdf_surface_write_xref (surface);
2045 _cairo_output_stream_printf (surface->output,
2046 "trailer\n"
2047 "<< /Size %d\n"
2048 " /Root %d 0 R\n"
2049 " /Info %d 0 R\n"
2050 ">>\n",
2051 surface->next_available_resource.id,
2052 catalog.id,
2053 info.id);
2055 _cairo_output_stream_printf (surface->output,
2056 "startxref\n"
2057 "%ld\n"
2058 "%%%%EOF\n",
2059 offset);
2061 /* pdf_operators has already been flushed when the last stream was
2062 * closed so we should never be writing anything here - however,
2063 * the stream may itself be in an error state. */
2064 status2 = _cairo_pdf_operators_fini (&surface->pdf_operators);
2065 if (status == CAIRO_STATUS_SUCCESS)
2066 status = status2;
2068 /* close any active streams still open due to fatal errors */
2069 status2 = _cairo_pdf_surface_close_stream (surface);
2070 if (status == CAIRO_STATUS_SUCCESS)
2071 status = status2;
2073 if (surface->group_stream.stream != NULL) {
2074 status2 = _cairo_output_stream_destroy (surface->group_stream.stream);
2075 if (status == CAIRO_STATUS_SUCCESS)
2076 status = status2;
2078 if (surface->group_stream.mem_stream != NULL) {
2079 status2 = _cairo_output_stream_destroy (surface->group_stream.mem_stream);
2080 if (status == CAIRO_STATUS_SUCCESS)
2081 status = status2;
2083 if (surface->pdf_stream.active)
2084 surface->output = surface->pdf_stream.old_output;
2085 if (surface->group_stream.active)
2086 surface->output = surface->group_stream.old_output;
2088 /* and finish the pdf surface */
2089 status2 = _cairo_output_stream_destroy (surface->output);
2090 if (status == CAIRO_STATUS_SUCCESS)
2091 status = status2;
2093 _cairo_pdf_surface_clear (surface);
2094 _cairo_pdf_group_resources_fini (&surface->resources);
2096 _cairo_array_fini (&surface->objects);
2097 _cairo_array_fini (&surface->pages);
2098 _cairo_array_fini (&surface->rgb_linear_functions);
2099 _cairo_array_fini (&surface->alpha_linear_functions);
2100 _cairo_array_fini (&surface->page_patterns);
2101 _cairo_array_fini (&surface->page_surfaces);
2102 _cairo_hash_table_foreach (surface->all_surfaces,
2103 _cairo_pdf_source_surface_entry_pluck,
2104 surface->all_surfaces);
2105 _cairo_hash_table_destroy (surface->all_surfaces);
2106 _cairo_array_fini (&surface->smask_groups);
2107 _cairo_array_fini (&surface->fonts);
2108 _cairo_array_fini (&surface->knockout_group);
2110 if (surface->font_subsets) {
2111 _cairo_scaled_font_subsets_destroy (surface->font_subsets);
2112 surface->font_subsets = NULL;
2115 size = _cairo_array_num_elements (&surface->jbig2_global);
2116 for (i = 0; i < size; i++) {
2117 global = (cairo_pdf_jbig2_global_t *) _cairo_array_index (&surface->jbig2_global, i);
2118 free(global->id);
2119 if (!global->emitted)
2120 return _cairo_error (CAIRO_STATUS_JBIG2_GLOBAL_MISSING);
2122 _cairo_array_fini (&surface->jbig2_global);
2124 _cairo_array_truncate (&surface->page_surfaces, 0);
2126 _cairo_surface_clipper_reset (&surface->clipper);
2128 return status;
2131 static cairo_int_status_t
2132 _cairo_pdf_surface_start_page (void *abstract_surface)
2134 cairo_pdf_surface_t *surface = abstract_surface;
2136 /* Document header */
2137 if (! surface->header_emitted) {
2138 const char *version;
2140 switch (surface->pdf_version) {
2141 case CAIRO_PDF_VERSION_1_4:
2142 version = "1.4";
2143 break;
2144 default:
2145 case CAIRO_PDF_VERSION_1_5:
2146 version = "1.5";
2147 break;
2150 _cairo_output_stream_printf (surface->output,
2151 "%%PDF-%s\n", version);
2152 _cairo_output_stream_printf (surface->output,
2153 "%%%c%c%c%c\n", 181, 237, 174, 251);
2154 surface->header_emitted = TRUE;
2157 _cairo_pdf_group_resources_clear (&surface->resources);
2159 return CAIRO_STATUS_SUCCESS;
2162 static cairo_int_status_t
2163 _cairo_pdf_surface_has_fallback_images (void *abstract_surface,
2164 cairo_bool_t has_fallbacks)
2166 cairo_int_status_t status;
2167 cairo_pdf_surface_t *surface = abstract_surface;
2168 cairo_box_double_t bbox;
2170 surface->has_fallback_images = has_fallbacks;
2171 bbox.p1.x = 0;
2172 bbox.p1.y = 0;
2173 bbox.p2.x = surface->width;
2174 bbox.p2.y = surface->height;
2175 status = _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, has_fallbacks, has_fallbacks);
2176 if (unlikely (status))
2177 return status;
2179 return CAIRO_STATUS_SUCCESS;
2182 static cairo_bool_t
2183 _cairo_pdf_surface_supports_fine_grained_fallbacks (void *abstract_surface)
2185 return TRUE;
2188 static cairo_int_status_t
2189 _cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surface,
2190 const cairo_pattern_t *source,
2191 const cairo_rectangle_int_t *extents,
2192 cairo_pdf_resource_t *surface_res,
2193 int *width,
2194 int *height,
2195 double *x_offset,
2196 double *y_offset)
2198 cairo_image_surface_t *image;
2199 cairo_surface_t *pad_image;
2200 void *image_extra;
2201 cairo_int_status_t status;
2202 int w, h;
2203 cairo_rectangle_int_t extents2;
2204 cairo_box_t box;
2205 cairo_rectangle_int_t rect;
2206 cairo_surface_pattern_t pad_pattern;
2208 status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, source,
2209 &image, &image_extra);
2210 if (unlikely (status))
2211 return status;
2213 pad_image = &image->base;
2215 /* get the operation extents in pattern space */
2216 _cairo_box_from_rectangle (&box, extents);
2217 _cairo_matrix_transform_bounding_box_fixed (&source->matrix, &box, NULL);
2218 _cairo_box_round_to_rectangle (&box, &rect);
2220 /* Check if image needs padding to fill extents */
2221 w = image->width;
2222 h = image->height;
2223 if (_cairo_fixed_integer_ceil(box.p1.x) < 0 ||
2224 _cairo_fixed_integer_ceil(box.p1.y) < 0 ||
2225 _cairo_fixed_integer_floor(box.p2.x) > w ||
2226 _cairo_fixed_integer_floor(box.p2.y) > h)
2228 pad_image = _cairo_image_surface_create_with_content (image->base.content,
2229 rect.width,
2230 rect.height);
2231 if (pad_image->status) {
2232 status = pad_image->status;
2233 goto BAIL;
2236 _cairo_pattern_init_for_surface (&pad_pattern, &image->base);
2237 cairo_matrix_init_translate (&pad_pattern.base.matrix, rect.x, rect.y);
2238 pad_pattern.base.extend = CAIRO_EXTEND_PAD;
2239 status = _cairo_surface_paint (pad_image,
2240 CAIRO_OPERATOR_SOURCE, &pad_pattern.base,
2241 NULL);
2242 _cairo_pattern_fini (&pad_pattern.base);
2243 if (unlikely (status))
2244 goto BAIL;
2247 status = _cairo_pdf_surface_add_source_surface (surface,
2248 pad_image,
2249 NULL,
2250 FALSE,
2251 source->filter,
2252 FALSE,
2253 FALSE,
2254 extents,
2255 NULL,
2256 surface_res,
2257 width,
2258 height,
2259 x_offset,
2260 y_offset,
2261 &extents2);
2262 if (unlikely (status))
2263 goto BAIL;
2265 if (pad_image != &image->base) {
2266 /* If using a padded image, replace _add_source_surface
2267 * x/y_offset with padded image offset. Note:
2268 * _add_source_surface only sets a non zero x/y_offset for
2269 * RASTER_SOURCE patterns. _add_source_surface will always set
2270 * x/y_offset to 0 for surfaces so we can ignore the returned
2271 * offset and replace it with the offset required for the
2272 * padded image */
2273 *x_offset = rect.x;
2274 *y_offset = rect.y;
2277 BAIL:
2278 if (pad_image != &image->base)
2279 cairo_surface_destroy (pad_image);
2281 _cairo_pdf_surface_release_source_image_from_pattern (surface, source, image, image_extra);
2283 return status;
2286 /* Emit alpha channel from the image into stream_res.
2288 static cairo_int_status_t
2289 _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface,
2290 cairo_image_surface_t *image,
2291 cairo_bool_t stencil_mask,
2292 cairo_bool_t interpolate,
2293 cairo_pdf_resource_t *stream_res)
2295 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
2296 char *alpha;
2297 unsigned long alpha_size;
2298 uint32_t *pixel32;
2299 uint8_t *pixel8;
2300 int i, x, y, bit, a;
2301 cairo_image_transparency_t transparency;
2303 /* This is the only image format we support, which simplifies things. */
2304 assert (image->format == CAIRO_FORMAT_ARGB32 ||
2305 image->format == CAIRO_FORMAT_RGB24 ||
2306 image->format == CAIRO_FORMAT_A8 ||
2307 image->format == CAIRO_FORMAT_A1 );
2309 transparency = _cairo_image_analyze_transparency (image);
2310 if (stencil_mask) {
2311 assert (transparency == CAIRO_IMAGE_IS_OPAQUE ||
2312 transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA);
2313 } else {
2314 assert (transparency != CAIRO_IMAGE_IS_OPAQUE);
2317 if (transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA || transparency == CAIRO_IMAGE_IS_OPAQUE) {
2318 alpha_size = (image->width + 7) / 8 * image->height;
2319 alpha = _cairo_malloc_ab ((image->width+7) / 8, image->height);
2320 } else {
2321 alpha_size = image->height * image->width;
2322 alpha = _cairo_malloc_ab (image->height, image->width);
2325 if (unlikely (alpha == NULL)) {
2326 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2327 goto CLEANUP;
2330 i = 0;
2331 for (y = 0; y < image->height; y++) {
2332 if (transparency == CAIRO_IMAGE_IS_OPAQUE) {
2333 for (x = 0; x < (image->width + 7) / 8; x++)
2334 alpha[i++] = 0xff;
2335 } else if (image->format == CAIRO_FORMAT_A1) {
2336 pixel8 = (uint8_t *) (image->data + y * image->stride);
2338 for (x = 0; x < (image->width + 7) / 8; x++, pixel8++) {
2339 a = *pixel8;
2340 a = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (a);
2341 alpha[i++] = a;
2343 } else {
2344 pixel8 = (uint8_t *) (image->data + y * image->stride);
2345 pixel32 = (uint32_t *) (image->data + y * image->stride);
2346 bit = 7;
2347 for (x = 0; x < image->width; x++) {
2348 if (image->format == CAIRO_FORMAT_ARGB32) {
2349 a = (*pixel32 & 0xff000000) >> 24;
2350 pixel32++;
2351 } else {
2352 a = *pixel8;
2353 pixel8++;
2356 if (transparency == CAIRO_IMAGE_HAS_ALPHA) {
2357 alpha[i++] = a;
2358 } else { /* transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA or CAIRO_IMAGE_IS_OPAQUE */
2359 if (bit == 7)
2360 alpha[i] = 0;
2361 if (a != 0)
2362 alpha[i] |= (1 << bit);
2363 bit--;
2364 if (bit < 0) {
2365 bit = 7;
2366 i++;
2370 if (bit != 7)
2371 i++;
2375 if (stencil_mask) {
2376 status = _cairo_pdf_surface_open_stream (surface,
2377 stream_res,
2378 TRUE,
2379 " /Type /XObject\n"
2380 " /Subtype /Image\n"
2381 " /ImageMask true\n"
2382 " /Width %d\n"
2383 " /Height %d\n"
2384 " /Interpolate %s\n"
2385 " /BitsPerComponent 1\n"
2386 " /Decode [1 0]\n",
2387 image->width, image->height,
2388 interpolate ? "true" : "false");
2389 } else {
2390 status = _cairo_pdf_surface_open_stream (surface,
2391 stream_res,
2392 TRUE,
2393 " /Type /XObject\n"
2394 " /Subtype /Image\n"
2395 " /Width %d\n"
2396 " /Height %d\n"
2397 " /ColorSpace /DeviceGray\n"
2398 " /Interpolate %s\n"
2399 " /BitsPerComponent %d\n",
2400 image->width, image->height,
2401 interpolate ? "true" : "false",
2402 transparency == CAIRO_IMAGE_HAS_ALPHA ? 8 : 1);
2404 if (unlikely (status))
2405 goto CLEANUP_ALPHA;
2407 _cairo_output_stream_write (surface->output, alpha, alpha_size);
2408 status = _cairo_pdf_surface_close_stream (surface);
2410 CLEANUP_ALPHA:
2411 free (alpha);
2412 CLEANUP:
2413 return status;
2417 * _cairo_pdf_surface_emit_image:
2418 * @surface: the pdf surface
2419 * @image_surf: The image to write
2420 * @surface_entry: Contains image resource, smask resource, interpolate and stencil mask parameters.
2422 * Emit an image stream using the @image_res resource and write out
2423 * the image data from @image_surf. If @smask_res is not null, @smask_res will
2424 * be specified as the smask for the image. Otherwise emit the an smask if
2425 * the image is requires one.
2427 static cairo_int_status_t
2428 _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
2429 cairo_image_surface_t *image_surf,
2430 cairo_pdf_source_surface_entry_t *surface_entry)
2432 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
2433 char *data;
2434 unsigned long data_size;
2435 uint32_t *pixel;
2436 int i, x, y, bit;
2437 cairo_pdf_resource_t smask = {0}; /* squelch bogus compiler warning */
2438 cairo_bool_t need_smask;
2439 cairo_image_color_t color;
2440 cairo_image_surface_t *image;
2441 cairo_image_transparency_t transparency;
2442 char smask_buf[30];
2444 image = image_surf;
2445 if (image->format != CAIRO_FORMAT_RGB24 &&
2446 image->format != CAIRO_FORMAT_ARGB32 &&
2447 image->format != CAIRO_FORMAT_A8 &&
2448 image->format != CAIRO_FORMAT_A1)
2450 cairo_surface_t *surf;
2451 cairo_surface_pattern_t pattern;
2453 surf = _cairo_image_surface_create_with_content (image_surf->base.content,
2454 image_surf->width,
2455 image_surf->height);
2456 image = (cairo_image_surface_t *) surf;
2457 if (surf->status) {
2458 status = surf->status;
2459 goto CLEANUP;
2462 _cairo_pattern_init_for_surface (&pattern, &image_surf->base);
2463 status = _cairo_surface_paint (surf,
2464 CAIRO_OPERATOR_SOURCE, &pattern.base,
2465 NULL);
2466 _cairo_pattern_fini (&pattern.base);
2467 if (unlikely (status))
2468 goto CLEANUP;
2471 if (surface_entry->smask || surface_entry->stencil_mask) {
2472 return _cairo_pdf_surface_emit_smask (surface, image,
2473 surface_entry->stencil_mask,
2474 surface_entry->interpolate,
2475 &surface_entry->surface_res);
2478 color = _cairo_image_analyze_color (image);
2479 switch (color) {
2480 default:
2481 case CAIRO_IMAGE_UNKNOWN_COLOR:
2482 ASSERT_NOT_REACHED;
2483 case CAIRO_IMAGE_IS_COLOR:
2484 data_size = image->height * image->width * 3;
2485 data = _cairo_malloc_abc (image->width, image->height, 3);
2486 break;
2488 case CAIRO_IMAGE_IS_GRAYSCALE:
2489 data_size = image->height * image->width;
2490 data = _cairo_malloc_ab (image->width, image->height);
2491 break;
2492 case CAIRO_IMAGE_IS_MONOCHROME:
2493 data_size = (image->width + 7) / 8 * image->height;
2494 data = _cairo_malloc_ab ((image->width+7) / 8, image->height);
2495 break;
2497 if (unlikely (data == NULL)) {
2498 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2499 goto CLEANUP;
2502 i = 0;
2503 for (y = 0; y < image->height; y++) {
2504 pixel = (uint32_t *) (image->data + y * image->stride);
2506 bit = 7;
2507 for (x = 0; x < image->width; x++, pixel++) {
2508 int r, g, b;
2510 /* XXX: We're un-premultiplying alpha here. My reading of the PDF
2511 * specification suggests that we should be able to avoid having
2512 * to do this by filling in the SMask's Matte dictionary
2513 * appropriately, but my attempts to do that so far have
2514 * failed. */
2515 if (image->format == CAIRO_FORMAT_ARGB32) {
2516 uint8_t a;
2517 a = (*pixel & 0xff000000) >> 24;
2518 if (a == 0) {
2519 r = g = b = 0;
2520 } else {
2521 r = (((*pixel & 0xff0000) >> 16) * 255 + a / 2) / a;
2522 g = (((*pixel & 0x00ff00) >> 8) * 255 + a / 2) / a;
2523 b = (((*pixel & 0x0000ff) >> 0) * 255 + a / 2) / a;
2525 } else if (image->format == CAIRO_FORMAT_RGB24) {
2526 r = (*pixel & 0x00ff0000) >> 16;
2527 g = (*pixel & 0x0000ff00) >> 8;
2528 b = (*pixel & 0x000000ff) >> 0;
2529 } else {
2530 r = g = b = 0;
2533 switch (color) {
2534 case CAIRO_IMAGE_IS_COLOR:
2535 case CAIRO_IMAGE_UNKNOWN_COLOR:
2536 data[i++] = r;
2537 data[i++] = g;
2538 data[i++] = b;
2539 break;
2541 case CAIRO_IMAGE_IS_GRAYSCALE:
2542 data[i++] = r;
2543 break;
2545 case CAIRO_IMAGE_IS_MONOCHROME:
2546 if (bit == 7)
2547 data[i] = 0;
2548 if (r != 0)
2549 data[i] |= (1 << bit);
2550 bit--;
2551 if (bit < 0) {
2552 bit = 7;
2553 i++;
2555 break;
2558 if (bit != 7)
2559 i++;
2562 if (surface_entry->smask_res.id != 0) {
2563 need_smask = TRUE;
2564 smask = surface_entry->smask_res;
2565 } else {
2566 need_smask = FALSE;
2567 if (image->format == CAIRO_FORMAT_ARGB32 ||
2568 image->format == CAIRO_FORMAT_A8 ||
2569 image->format == CAIRO_FORMAT_A1)
2571 transparency = _cairo_image_analyze_transparency (image);
2572 if (transparency != CAIRO_IMAGE_IS_OPAQUE) {
2573 need_smask = TRUE;
2574 smask = _cairo_pdf_surface_new_object (surface);
2575 if (smask.id == 0) {
2576 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2577 goto CLEANUP_RGB;
2580 status = _cairo_pdf_surface_emit_smask (surface, image, FALSE, surface_entry->interpolate, &smask);
2581 if (unlikely (status))
2582 goto CLEANUP_RGB;
2587 if (need_smask)
2588 snprintf(smask_buf, sizeof(smask_buf), " /SMask %d 0 R\n", smask.id);
2589 else
2590 smask_buf[0] = 0;
2592 status = _cairo_pdf_surface_open_stream (surface,
2593 &surface_entry->surface_res,
2594 TRUE,
2595 " /Type /XObject\n"
2596 " /Subtype /Image\n"
2597 " /Width %d\n"
2598 " /Height %d\n"
2599 " /ColorSpace %s\n"
2600 " /Interpolate %s\n"
2601 " /BitsPerComponent %d\n"
2602 "%s",
2603 image->width,
2604 image->height,
2605 color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray",
2606 surface_entry->interpolate ? "true" : "false",
2607 color == CAIRO_IMAGE_IS_MONOCHROME? 1 : 8,
2608 smask_buf);
2609 if (unlikely (status))
2610 goto CLEANUP_RGB;
2612 #undef IMAGE_DICTIONARY
2614 _cairo_output_stream_write (surface->output, data, data_size);
2615 status = _cairo_pdf_surface_close_stream (surface);
2617 CLEANUP_RGB:
2618 free (data);
2619 CLEANUP:
2620 if (image != image_surf)
2621 cairo_surface_destroy (&image->base);
2623 return status;
2626 static cairo_int_status_t
2627 _cairo_pdf_surface_lookup_jbig2_global (cairo_pdf_surface_t *surface,
2628 const unsigned char *global_id,
2629 unsigned long global_id_length,
2630 cairo_pdf_jbig2_global_t **entry)
2632 cairo_pdf_jbig2_global_t global;
2633 int size, i;
2634 cairo_int_status_t status;
2636 size = _cairo_array_num_elements (&surface->jbig2_global);
2637 for (i = 0; i < size; i++) {
2638 *entry = (cairo_pdf_jbig2_global_t *) _cairo_array_index (&surface->jbig2_global, i);
2639 if ((*entry)->id && global_id && (*entry)->id_length == global_id_length
2640 && memcmp((*entry)->id, global_id, global_id_length) == 0) {
2641 return CAIRO_STATUS_SUCCESS;
2645 global.id = malloc(global_id_length);
2646 if (unlikely (global.id == NULL)) {
2647 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2650 memcpy (global.id, global_id, global_id_length);
2651 global.id_length = global_id_length;
2652 global.res = _cairo_pdf_surface_new_object (surface);
2653 if (global.res.id == 0) {
2654 free(global.id);
2655 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2658 global.emitted = FALSE;
2659 status = _cairo_array_append (&surface->jbig2_global, &global);
2660 if (unlikely(status))
2661 return status;
2663 size = _cairo_array_num_elements (&surface->jbig2_global);
2664 *entry = (cairo_pdf_jbig2_global_t *) _cairo_array_index (&surface->jbig2_global, size - 1);
2665 return CAIRO_STATUS_SUCCESS;
2668 static cairo_int_status_t
2669 _cairo_pdf_surface_emit_jbig2_image (cairo_pdf_surface_t *surface,
2670 cairo_surface_t *source,
2671 cairo_pdf_source_surface_entry_t *surface_entry)
2673 cairo_int_status_t status;
2674 const unsigned char *mime_data;
2675 unsigned long mime_data_length;
2676 cairo_image_info_t info;
2677 const unsigned char *global_id;
2678 unsigned long global_id_length;
2679 const unsigned char *global_data;
2680 unsigned long global_data_length;
2681 cairo_pdf_jbig2_global_t *global_entry = NULL; /* hide compiler warning */
2682 char smask_buf[30];
2683 char decode_parms_buf[100];
2685 cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JBIG2,
2686 &mime_data, &mime_data_length);
2687 if (mime_data == NULL)
2688 return CAIRO_INT_STATUS_UNSUPPORTED;
2690 status = _cairo_image_info_get_jbig2_info (&info, mime_data, mime_data_length);
2691 if (status)
2692 return status;
2694 cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID,
2695 &global_id, &global_id_length);
2696 if (global_id && global_id_length > 0) {
2697 status = _cairo_pdf_surface_lookup_jbig2_global (surface, global_id, global_id_length, &global_entry);
2698 if (unlikely(status))
2699 return status;
2701 if (!global_entry->emitted) {
2702 cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JBIG2_GLOBAL,
2703 &global_data, &global_data_length);
2704 if (global_data) {
2705 status = _cairo_pdf_surface_open_stream (surface, &global_entry->res, FALSE, NULL);
2706 if (unlikely(status))
2707 return status;
2709 _cairo_output_stream_write (surface->output, global_data, global_data_length);
2710 status = _cairo_pdf_surface_close_stream (surface);
2711 if (unlikely(status))
2712 return status;
2714 global_entry->emitted = TRUE;
2718 snprintf(decode_parms_buf, sizeof(decode_parms_buf),
2719 " /DecodeParms << /JBIG2Globals %d 0 R >>\n", global_entry->res.id);
2720 } else {
2721 decode_parms_buf[0] = 0;
2724 if (surface_entry->smask_res.id)
2725 snprintf(smask_buf, sizeof(smask_buf), " /SMask %d 0 R\n", surface_entry->smask_res.id);
2726 else
2727 smask_buf[0] = 0;
2729 if (surface_entry->stencil_mask) {
2730 status = _cairo_pdf_surface_open_stream (surface,
2731 &surface_entry->surface_res,
2732 FALSE,
2733 " /Type /XObject\n"
2734 " /Subtype /Image\n"
2735 " /ImageMask true\n"
2736 " /Width %d\n"
2737 " /Height %d\n"
2738 " /Interpolate %s\n"
2739 " /BitsPerComponent 1\n"
2740 " /Decode [1 0]\n"
2741 " /Filter /JPXDecode\n"
2742 "%s",
2743 info.width,
2744 info.height,
2745 surface_entry->interpolate ? "true" : "false",
2746 decode_parms_buf);
2747 } else {
2748 status = _cairo_pdf_surface_open_stream (surface,
2749 &surface_entry->surface_res,
2750 FALSE,
2751 " /Type /XObject\n"
2752 " /Subtype /Image\n"
2753 " /Width %d\n"
2754 " /Height %d\n"
2755 " /ColorSpace /DeviceGray\n"
2756 " /BitsPerComponent 1\n"
2757 " /Interpolate %s\n"
2758 "%s"
2759 " /Filter /JBIG2Decode\n"
2760 "%s",
2761 info.width,
2762 info.height,
2763 surface_entry->interpolate ? "true" : "false",
2764 smask_buf,
2765 decode_parms_buf);
2767 if (unlikely(status))
2768 return status;
2770 _cairo_output_stream_write (surface->output, mime_data, mime_data_length);
2771 status = _cairo_pdf_surface_close_stream (surface);
2773 return status;
2776 static cairo_int_status_t
2777 _cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface,
2778 cairo_surface_t *source,
2779 cairo_pdf_source_surface_entry_t *surface_entry)
2781 cairo_int_status_t status;
2782 const unsigned char *mime_data;
2783 unsigned long mime_data_length;
2784 cairo_image_info_t info;
2785 char smask_buf[30];
2787 if (surface->pdf_version < CAIRO_PDF_VERSION_1_5)
2788 return CAIRO_INT_STATUS_UNSUPPORTED;
2790 cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JP2,
2791 &mime_data, &mime_data_length);
2792 if (mime_data == NULL)
2793 return CAIRO_INT_STATUS_UNSUPPORTED;
2795 status = _cairo_image_info_get_jpx_info (&info, mime_data, mime_data_length);
2796 if (status)
2797 return status;
2799 if ((surface_entry->smask || surface_entry->stencil_mask) && info.num_components != 1)
2800 return CAIRO_INT_STATUS_UNSUPPORTED;
2802 if ((surface_entry->stencil_mask) && info.bits_per_component != 1)
2803 return CAIRO_INT_STATUS_UNSUPPORTED;
2805 if (surface_entry->smask_res.id)
2806 snprintf(smask_buf, sizeof(smask_buf), " /SMask %d 0 R\n", surface_entry->smask_res.id);
2807 else
2808 smask_buf[0] = 0;
2810 if (surface_entry->stencil_mask) {
2811 status = _cairo_pdf_surface_open_stream (surface,
2812 &surface_entry->surface_res,
2813 FALSE,
2814 " /Type /XObject\n"
2815 " /Subtype /Image\n"
2816 " /ImageMask true\n"
2817 " /Width %d\n"
2818 " /Height %d\n"
2819 " /Interpolate %s\n"
2820 " /BitsPerComponent 1\n"
2821 " /Decode [1 0]\n"
2822 " /Filter /JPXDecode\n",
2823 info.width,
2824 info.height,
2825 surface_entry->interpolate ? "true" : "false");
2826 } else {
2827 status = _cairo_pdf_surface_open_stream (surface,
2828 &surface_entry->surface_res,
2829 FALSE,
2830 " /Type /XObject\n"
2831 " /Subtype /Image\n"
2832 " /Width %d\n"
2833 " /Height %d\n"
2834 " /Interpolate %s\n"
2835 "%s"
2836 " /Filter /JPXDecode\n",
2837 info.width,
2838 info.height,
2839 surface_entry->interpolate ? "true" : "false",
2840 smask_buf);
2842 if (status)
2843 return status;
2845 _cairo_output_stream_write (surface->output, mime_data, mime_data_length);
2846 status = _cairo_pdf_surface_close_stream (surface);
2848 return status;
2851 static cairo_int_status_t
2852 _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface,
2853 cairo_surface_t *source,
2854 cairo_pdf_source_surface_entry_t *surface_entry)
2856 cairo_int_status_t status;
2857 const unsigned char *mime_data;
2858 unsigned long mime_data_length;
2859 cairo_image_info_t info;
2860 const char *colorspace;
2861 char smask_buf[30];
2863 cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
2864 &mime_data, &mime_data_length);
2865 if (unlikely (source->status))
2866 return source->status;
2867 if (mime_data == NULL)
2868 return CAIRO_INT_STATUS_UNSUPPORTED;
2870 status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length);
2871 if (unlikely (status))
2872 return status;
2874 if ((surface_entry->smask || surface_entry->stencil_mask) && info.num_components != 1)
2875 return CAIRO_INT_STATUS_UNSUPPORTED;
2877 if ((surface_entry->stencil_mask) && info.bits_per_component != 1)
2878 return CAIRO_INT_STATUS_UNSUPPORTED;
2880 switch (info.num_components) {
2881 case 1:
2882 colorspace = "/DeviceGray";
2883 break;
2884 case 3:
2885 colorspace = "/DeviceRGB";
2886 break;
2887 case 4:
2888 colorspace = "/DeviceCMYK";
2889 break;
2890 default:
2891 return CAIRO_INT_STATUS_UNSUPPORTED;
2894 if (surface_entry->smask_res.id)
2895 snprintf(smask_buf, sizeof(smask_buf), " /SMask %d 0 R\n", surface_entry->smask_res.id);
2896 else
2897 smask_buf[0] = 0;
2899 if (surface_entry->stencil_mask) {
2900 status = _cairo_pdf_surface_open_stream (surface,
2901 &surface_entry->surface_res,
2902 FALSE,
2903 " /Type /XObject\n"
2904 " /Subtype /Image\n"
2905 " /ImageMask true\n"
2906 " /Width %d\n"
2907 " /Height %d\n"
2908 " /Interpolate %s\n"
2909 " /BitsPerComponent 1\n"
2910 " /Decode [1 0]\n"
2911 " /Filter /DCTDecode\n",
2912 info.width,
2913 info.height,
2914 surface_entry->interpolate ? "true" : "false");
2915 } else {
2916 status = _cairo_pdf_surface_open_stream (surface,
2917 &surface_entry->surface_res,
2918 FALSE,
2919 " /Type /XObject\n"
2920 " /Subtype /Image\n"
2921 " /Width %d\n"
2922 " /Height %d\n"
2923 " /ColorSpace %s\n"
2924 " /Interpolate %s\n"
2925 " /BitsPerComponent %d\n"
2926 "%s"
2927 " /Filter /DCTDecode\n",
2928 info.width,
2929 info.height,
2930 colorspace,
2931 surface_entry->interpolate ? "true" : "false",
2932 info.bits_per_component,
2933 smask_buf);
2935 if (unlikely (status))
2936 return status;
2938 _cairo_output_stream_write (surface->output, mime_data, mime_data_length);
2939 status = _cairo_pdf_surface_close_stream (surface);
2941 return status;
2944 static cairo_int_status_t
2945 _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface,
2946 cairo_pdf_source_surface_t *source)
2948 cairo_image_surface_t *image;
2949 void *image_extra;
2950 cairo_int_status_t status;
2952 if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
2953 status = _cairo_pdf_surface_emit_jbig2_image (surface, source->surface, source->hash_entry);
2954 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2955 return status;
2957 status = _cairo_pdf_surface_emit_jpx_image (surface, source->surface, source->hash_entry);
2958 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2959 return status;
2961 status = _cairo_pdf_surface_emit_jpeg_image (surface, source->surface, source->hash_entry);
2962 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2963 return status;
2966 if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
2967 status = _cairo_surface_acquire_source_image (source->surface, &image, &image_extra);
2968 } else {
2969 status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, source->raster_pattern,
2970 &image, &image_extra);
2972 if (unlikely (status))
2973 return status;
2975 status = _cairo_pdf_surface_emit_image (surface,
2976 image,
2977 source->hash_entry);
2979 if (source->type == CAIRO_PATTERN_TYPE_SURFACE)
2980 _cairo_surface_release_source_image (source->surface, image, image_extra);
2981 else
2982 _cairo_pdf_surface_release_source_image_from_pattern (surface, source->raster_pattern,
2983 image, image_extra);
2985 return status;
2988 static cairo_int_status_t
2989 _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
2990 cairo_pdf_source_surface_t *pdf_source)
2992 double old_width, old_height;
2993 cairo_paginated_mode_t old_paginated_mode;
2994 cairo_surface_clipper_t old_clipper;
2995 cairo_box_double_t bbox;
2996 cairo_int_status_t status;
2997 int alpha = 0;
2998 cairo_surface_t *free_me = NULL;
2999 cairo_surface_t *source;
3000 const cairo_rectangle_int_t *extents;
3001 int width;
3002 int height;
3003 cairo_bool_t is_subsurface;
3004 cairo_bool_t transparency_group;
3005 cairo_recording_surface_t *recording;
3007 assert (pdf_source->type == CAIRO_PATTERN_TYPE_SURFACE);
3008 extents = &pdf_source->hash_entry->extents;
3009 width = pdf_source->hash_entry->width;
3010 height = pdf_source->hash_entry->height;
3011 is_subsurface = FALSE;
3012 source = pdf_source->surface;
3013 if (_cairo_surface_is_snapshot (source)) {
3014 free_me = source = _cairo_surface_snapshot_get_target (source);
3015 } else if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
3016 cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
3018 source = sub->target;
3019 extents = &sub->extents;
3020 width = extents->width;
3021 height = extents->height;
3022 is_subsurface = TRUE;
3025 assert (source->type == CAIRO_SURFACE_TYPE_RECORDING);
3026 recording = (cairo_recording_surface_t *) source;
3028 old_width = surface->width;
3029 old_height = surface->height;
3030 old_paginated_mode = surface->paginated_mode;
3031 old_clipper = surface->clipper;
3032 _cairo_surface_clipper_init (&surface->clipper,
3033 _cairo_pdf_surface_clipper_intersect_clip_path);
3035 _cairo_pdf_surface_set_size_internal (surface, width, height);
3037 /* Patterns are emitted after fallback images. The paginated mode
3038 * needs to be set to _RENDER while the recording surface is replayed
3039 * back to this surface.
3041 surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER;
3042 _cairo_pdf_group_resources_clear (&surface->resources);
3043 _get_bbox_from_extents (height, extents, &bbox);
3045 /* We can optimize away the transparency group allowing the viewer
3046 * to replay the group in place when all operators are OVER and the
3047 * recording contains only opaque and/or clear alpha.
3049 transparency_group = !(pdf_source->hash_entry->operator == CAIRO_OPERATOR_OVER &&
3050 _cairo_recording_surface_has_only_bilevel_alpha (recording) &&
3051 _cairo_recording_surface_has_only_op_over (recording));
3052 status = _cairo_pdf_surface_open_content_stream (surface, &bbox, &pdf_source->hash_entry->surface_res,
3053 TRUE, transparency_group);
3054 if (unlikely (status))
3055 goto err;
3057 if (source->content == CAIRO_CONTENT_COLOR) {
3058 status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
3059 if (unlikely (status))
3060 goto err;
3062 _cairo_output_stream_printf (surface->output,
3063 "q /a%d gs 0 0 0 rg 0 0 %f %f re f Q\n",
3064 alpha,
3065 surface->width,
3066 surface->height);
3069 status = _cairo_recording_surface_replay_region (source,
3070 is_subsurface ? extents : NULL,
3071 &surface->base,
3072 CAIRO_RECORDING_REGION_NATIVE);
3073 assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
3074 if (unlikely (status))
3075 goto err;
3077 status = _cairo_pdf_surface_close_content_stream (surface);
3079 _cairo_surface_clipper_reset (&surface->clipper);
3080 surface->clipper = old_clipper;
3081 _cairo_pdf_surface_set_size_internal (surface,
3082 old_width,
3083 old_height);
3084 surface->paginated_mode = old_paginated_mode;
3086 err:
3087 cairo_surface_destroy (free_me);
3088 return status;
3091 static cairo_int_status_t
3092 _cairo_pdf_surface_emit_surface (cairo_pdf_surface_t *surface,
3093 cairo_pdf_source_surface_t *src_surface)
3095 if (src_surface->type == CAIRO_PATTERN_TYPE_SURFACE &&
3096 src_surface->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
3097 return _cairo_pdf_surface_emit_recording_surface (surface, src_surface);
3099 return _cairo_pdf_surface_emit_image_surface (surface, src_surface);
3102 static cairo_int_status_t
3103 _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
3104 cairo_pdf_pattern_t *pdf_pattern)
3106 cairo_pattern_t *pattern = pdf_pattern->pattern;
3107 cairo_int_status_t status;
3108 cairo_pdf_resource_t pattern_resource = {0};
3109 cairo_matrix_t cairo_p2d, pdf_p2d;
3110 cairo_extend_t extend = cairo_pattern_get_extend (pattern);
3111 double xstep, ystep;
3112 cairo_rectangle_int_t pattern_extents;
3113 int pattern_width = 0; /* squelch bogus compiler warning */
3114 int pattern_height = 0; /* squelch bogus compiler warning */
3115 double x_offset;
3116 double y_offset;
3117 char draw_surface[200];
3118 cairo_box_double_t bbox;
3120 if (pattern->extend == CAIRO_EXTEND_PAD) {
3121 status = _cairo_pdf_surface_add_padded_image_surface (surface,
3122 pattern,
3123 &pdf_pattern->extents,
3124 &pattern_resource,
3125 &pattern_width,
3126 &pattern_height,
3127 &x_offset,
3128 &y_offset);
3129 pattern_extents.x = 0;
3130 pattern_extents.y = 0;
3131 pattern_extents.width = pattern_width;
3132 pattern_extents.height = pattern_height;
3133 } else {
3134 status = _cairo_pdf_surface_add_source_surface (surface,
3135 NULL,
3136 pattern,
3137 pdf_pattern->operator,
3138 pattern->filter,
3139 FALSE,
3140 FALSE,
3141 &pdf_pattern->extents,
3142 NULL,
3143 &pattern_resource,
3144 &pattern_width,
3145 &pattern_height,
3146 &x_offset,
3147 &y_offset,
3148 &pattern_extents);
3150 if (unlikely (status))
3151 return status;
3153 switch (extend) {
3154 case CAIRO_EXTEND_PAD:
3155 case CAIRO_EXTEND_NONE:
3157 /* In PS/PDF, (as far as I can tell), all patterns are
3158 * repeating. So we support cairo's EXTEND_NONE semantics
3159 * by setting the repeat step size to a size large enough
3160 * to guarantee that no more than a single occurrence will
3161 * be visible.
3163 * First, map the surface extents into pattern space (since
3164 * xstep and ystep are in pattern space). Then use an upper
3165 * bound on the length of the diagonal of the pattern image
3166 * and the surface as repeat size. This guarantees to never
3167 * repeat visibly.
3169 double x1 = 0.0, y1 = 0.0;
3170 double x2 = surface->width, y2 = surface->height;
3171 _cairo_matrix_transform_bounding_box (&pattern->matrix,
3172 &x1, &y1, &x2, &y2,
3173 NULL);
3175 /* Rather than computing precise bounds of the union, just
3176 * add the surface extents unconditionally. We only
3177 * required an answer that's large enough, we don't really
3178 * care if it's not as tight as possible.*/
3179 xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
3180 pattern_width + pattern_height);
3182 break;
3183 case CAIRO_EXTEND_REPEAT:
3184 xstep = pattern_width;
3185 ystep = pattern_height;
3186 break;
3187 case CAIRO_EXTEND_REFLECT:
3188 pattern_extents.x = 0;
3189 pattern_extents.y = 0;
3190 pattern_extents.width = pattern_width*2;
3191 pattern_extents.height = pattern_height*2;
3192 xstep = pattern_width*2;
3193 ystep = pattern_height*2;
3194 break;
3195 /* All the rest (if any) should have been analyzed away, so this
3196 * case should be unreachable. */
3197 default:
3198 ASSERT_NOT_REACHED;
3199 xstep = 0;
3200 ystep = 0;
3203 /* At this point, (that is, within the surface backend interface),
3204 * the pattern's matrix maps from cairo's device space to cairo's
3205 * pattern space, (both with their origin at the upper-left, and
3206 * cairo's pattern space of size width,height).
3208 * Then, we must emit a PDF pattern object that maps from its own
3209 * pattern space, (which has a size that we establish in the BBox
3210 * dictionary entry), to the PDF page's *initial* space, (which
3211 * does not benefit from the Y-axis flipping matrix that we emit
3212 * on each page). So the PDF patterns matrix maps from a
3213 * (width,height) pattern space to a device space with the origin
3214 * in the lower-left corner.
3216 * So to handle all of that, we start with an identity matrix for
3217 * the PDF pattern to device matrix. We translate it up by the
3218 * image height then flip it in the Y direction, (moving us from
3219 * the PDF origin to cairo's origin). We then multiply in the
3220 * inverse of the cairo pattern matrix, (since it maps from device
3221 * to pattern, while we're setting up pattern to device). Finally,
3222 * we translate back down by the image height and flip again to
3223 * end up at the lower-left origin that PDF expects.
3225 * Additionally, within the stream that paints the pattern itself,
3226 * we are using a PDF image object that has a size of (1,1) so we
3227 * have to scale it up by the image width and height to fill our
3228 * pattern cell.
3230 cairo_p2d = pattern->matrix;
3231 status = cairo_matrix_invert (&cairo_p2d);
3232 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3233 assert (status == CAIRO_INT_STATUS_SUCCESS);
3235 cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &surface->cairo_to_pdf);
3236 cairo_matrix_translate (&pdf_p2d, -x_offset, -y_offset);
3237 cairo_matrix_translate (&pdf_p2d, 0.0, pattern_height);
3238 cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
3240 _get_bbox_from_extents (pattern_height, &pattern_extents, &bbox);
3241 _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
3242 status = _cairo_pdf_surface_open_stream (surface,
3243 &pdf_pattern->pattern_res,
3244 FALSE,
3245 " /PatternType 1\n"
3246 " /BBox [ %f %f %f %f ]\n"
3247 " /XStep %f\n"
3248 " /YStep %f\n"
3249 " /TilingType 1\n"
3250 " /PaintType 1\n"
3251 " /Matrix [ %f %f %f %f %f %f ]\n"
3252 " /Resources << /XObject << /x%d %d 0 R >> >>\n",
3253 bbox.p1.x, bbox.p1.y, bbox.p2.x, bbox.p2.y,
3254 xstep, ystep,
3255 pdf_p2d.xx, pdf_p2d.yx,
3256 pdf_p2d.xy, pdf_p2d.yy,
3257 pdf_p2d.x0, pdf_p2d.y0,
3258 pattern_resource.id,
3259 pattern_resource.id);
3260 if (unlikely (status))
3261 return status;
3263 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE &&
3264 ((cairo_surface_pattern_t *) pattern)->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
3265 snprintf(draw_surface,
3266 sizeof (draw_surface),
3267 "/x%d Do\n",
3268 pattern_resource.id);
3269 } else {
3270 snprintf(draw_surface,
3271 sizeof (draw_surface),
3272 "q %d 0 0 %d 0 0 cm /x%d Do Q",
3273 pattern_width,
3274 pattern_height,
3275 pattern_resource.id);
3278 if (extend == CAIRO_EXTEND_REFLECT) {
3279 _cairo_output_stream_printf (surface->output,
3280 "q 0 0 %d %d re W n %s Q\n"
3281 "q -1 0 0 1 %d 0 cm 0 0 %d %d re W n %s Q\n"
3282 "q 1 0 0 -1 0 %d cm 0 0 %d %d re W n %s Q\n"
3283 "q -1 0 0 -1 %d %d cm 0 0 %d %d re W n %s Q\n",
3284 pattern_width, pattern_height,
3285 draw_surface,
3286 pattern_width*2, pattern_width, pattern_height,
3287 draw_surface,
3288 pattern_height*2, pattern_width, pattern_height,
3289 draw_surface,
3290 pattern_width*2, pattern_height*2, pattern_width, pattern_height,
3291 draw_surface);
3292 } else {
3293 _cairo_output_stream_printf (surface->output,
3294 " %s \n",
3295 draw_surface);
3298 status = _cairo_pdf_surface_close_stream (surface);
3299 if (unlikely (status))
3300 return status;
3302 return _cairo_output_stream_get_status (surface->output);
3305 typedef struct _cairo_pdf_color_stop {
3306 double offset;
3307 double color[4];
3308 cairo_pdf_resource_t resource;
3309 } cairo_pdf_color_stop_t;
3311 static cairo_int_status_t
3312 cairo_pdf_surface_emit_rgb_linear_function (cairo_pdf_surface_t *surface,
3313 cairo_pdf_color_stop_t *stop1,
3314 cairo_pdf_color_stop_t *stop2,
3315 cairo_pdf_resource_t *function)
3317 int num_elems, i;
3318 cairo_pdf_rgb_linear_function_t elem;
3319 cairo_pdf_resource_t res;
3320 cairo_int_status_t status;
3322 num_elems = _cairo_array_num_elements (&surface->rgb_linear_functions);
3323 for (i = 0; i < num_elems; i++) {
3324 _cairo_array_copy_element (&surface->rgb_linear_functions, i, &elem);
3325 if (memcmp (&elem.color1[0], &stop1->color[0], sizeof (double)*3) != 0)
3326 continue;
3327 if (memcmp (&elem.color2[0], &stop2->color[0], sizeof (double)*3) != 0)
3328 continue;
3329 *function = elem.resource;
3330 return CAIRO_STATUS_SUCCESS;
3333 res = _cairo_pdf_surface_new_object (surface);
3334 if (res.id == 0)
3335 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3337 _cairo_output_stream_printf (surface->output,
3338 "%d 0 obj\n"
3339 "<< /FunctionType 2\n"
3340 " /Domain [ 0 1 ]\n"
3341 " /C0 [ %f %f %f ]\n"
3342 " /C1 [ %f %f %f ]\n"
3343 " /N 1\n"
3344 ">>\n"
3345 "endobj\n",
3346 res.id,
3347 stop1->color[0],
3348 stop1->color[1],
3349 stop1->color[2],
3350 stop2->color[0],
3351 stop2->color[1],
3352 stop2->color[2]);
3354 elem.resource = res;
3355 memcpy (&elem.color1[0], &stop1->color[0], sizeof (double)*3);
3356 memcpy (&elem.color2[0], &stop2->color[0], sizeof (double)*3);
3358 status = _cairo_array_append (&surface->rgb_linear_functions, &elem);
3359 *function = res;
3361 return status;
3364 static cairo_int_status_t
3365 cairo_pdf_surface_emit_alpha_linear_function (cairo_pdf_surface_t *surface,
3366 cairo_pdf_color_stop_t *stop1,
3367 cairo_pdf_color_stop_t *stop2,
3368 cairo_pdf_resource_t *function)
3370 int num_elems, i;
3371 cairo_pdf_alpha_linear_function_t elem;
3372 cairo_pdf_resource_t res;
3373 cairo_int_status_t status;
3375 num_elems = _cairo_array_num_elements (&surface->alpha_linear_functions);
3376 for (i = 0; i < num_elems; i++) {
3377 _cairo_array_copy_element (&surface->alpha_linear_functions, i, &elem);
3378 if (elem.alpha1 != stop1->color[3])
3379 continue;
3380 if (elem.alpha2 != stop2->color[3])
3381 continue;
3382 *function = elem.resource;
3383 return CAIRO_STATUS_SUCCESS;
3386 res = _cairo_pdf_surface_new_object (surface);
3387 if (res.id == 0)
3388 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3390 _cairo_output_stream_printf (surface->output,
3391 "%d 0 obj\n"
3392 "<< /FunctionType 2\n"
3393 " /Domain [ 0 1 ]\n"
3394 " /C0 [ %f ]\n"
3395 " /C1 [ %f ]\n"
3396 " /N 1\n"
3397 ">>\n"
3398 "endobj\n",
3399 res.id,
3400 stop1->color[3],
3401 stop2->color[3]);
3403 elem.resource = res;
3404 elem.alpha1 = stop1->color[3];
3405 elem.alpha2 = stop2->color[3];
3407 status = _cairo_array_append (&surface->alpha_linear_functions, &elem);
3408 *function = res;
3410 return status;
3413 static cairo_int_status_t
3414 _cairo_pdf_surface_emit_stitched_colorgradient (cairo_pdf_surface_t *surface,
3415 unsigned int n_stops,
3416 cairo_pdf_color_stop_t *stops,
3417 cairo_bool_t is_alpha,
3418 cairo_pdf_resource_t *function)
3420 cairo_pdf_resource_t res;
3421 unsigned int i;
3422 cairo_int_status_t status;
3424 /* emit linear gradients between pairs of subsequent stops... */
3425 for (i = 0; i < n_stops-1; i++) {
3426 if (is_alpha) {
3427 status = cairo_pdf_surface_emit_alpha_linear_function (surface,
3428 &stops[i],
3429 &stops[i+1],
3430 &stops[i].resource);
3431 if (unlikely (status))
3432 return status;
3433 } else {
3434 status = cairo_pdf_surface_emit_rgb_linear_function (surface,
3435 &stops[i],
3436 &stops[i+1],
3437 &stops[i].resource);
3438 if (unlikely (status))
3439 return status;
3443 /* ... and stitch them together */
3444 res = _cairo_pdf_surface_new_object (surface);
3445 if (res.id == 0)
3446 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3448 _cairo_output_stream_printf (surface->output,
3449 "%d 0 obj\n"
3450 "<< /FunctionType 3\n"
3451 " /Domain [ %f %f ]\n",
3452 res.id,
3453 stops[0].offset,
3454 stops[n_stops - 1].offset);
3456 _cairo_output_stream_printf (surface->output,
3457 " /Functions [ ");
3458 for (i = 0; i < n_stops-1; i++)
3459 _cairo_output_stream_printf (surface->output,
3460 "%d 0 R ", stops[i].resource.id);
3461 _cairo_output_stream_printf (surface->output,
3462 "]\n");
3464 _cairo_output_stream_printf (surface->output,
3465 " /Bounds [ ");
3466 for (i = 1; i < n_stops-1; i++)
3467 _cairo_output_stream_printf (surface->output,
3468 "%f ", stops[i].offset);
3469 _cairo_output_stream_printf (surface->output,
3470 "]\n");
3472 _cairo_output_stream_printf (surface->output,
3473 " /Encode [ ");
3474 for (i = 1; i < n_stops; i++)
3475 _cairo_output_stream_printf (surface->output,
3476 "0 1 ");
3477 _cairo_output_stream_printf (surface->output,
3478 "]\n");
3480 _cairo_output_stream_printf (surface->output,
3481 ">>\n"
3482 "endobj\n");
3484 *function = res;
3486 return _cairo_output_stream_get_status (surface->output);
3490 static void
3491 calc_gradient_color (cairo_pdf_color_stop_t *new_stop,
3492 cairo_pdf_color_stop_t *stop1,
3493 cairo_pdf_color_stop_t *stop2)
3495 int i;
3496 double offset = stop1->offset / (stop1->offset + 1.0 - stop2->offset);
3498 for (i = 0; i < 4; i++)
3499 new_stop->color[i] = stop1->color[i] + offset*(stop2->color[i] - stop1->color[i]);
3502 #define COLOR_STOP_EPSILON 1e-6
3504 static cairo_int_status_t
3505 _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface,
3506 cairo_gradient_pattern_t *pattern,
3507 cairo_pdf_resource_t *color_function,
3508 cairo_pdf_resource_t *alpha_function)
3510 cairo_pdf_color_stop_t *allstops, *stops;
3511 unsigned int n_stops;
3512 unsigned int i;
3513 cairo_bool_t emit_alpha = FALSE;
3514 cairo_int_status_t status;
3516 color_function->id = 0;
3517 alpha_function->id = 0;
3519 allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_pdf_color_stop_t));
3520 if (unlikely (allstops == NULL))
3521 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3523 stops = &allstops[1];
3524 n_stops = pattern->n_stops;
3526 for (i = 0; i < n_stops; i++) {
3527 stops[i].color[0] = pattern->stops[i].color.red;
3528 stops[i].color[1] = pattern->stops[i].color.green;
3529 stops[i].color[2] = pattern->stops[i].color.blue;
3530 stops[i].color[3] = pattern->stops[i].color.alpha;
3531 if (!CAIRO_ALPHA_IS_OPAQUE (stops[i].color[3]))
3532 emit_alpha = TRUE;
3533 stops[i].offset = pattern->stops[i].offset;
3536 if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
3537 pattern->base.extend == CAIRO_EXTEND_REFLECT) {
3538 if (stops[0].offset > COLOR_STOP_EPSILON) {
3539 if (pattern->base.extend == CAIRO_EXTEND_REFLECT)
3540 memcpy (allstops, stops, sizeof (cairo_pdf_color_stop_t));
3541 else
3542 calc_gradient_color (&allstops[0], &stops[0], &stops[n_stops-1]);
3543 stops = allstops;
3544 n_stops++;
3546 stops[0].offset = 0.0;
3548 if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
3549 if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
3550 memcpy (&stops[n_stops],
3551 &stops[n_stops - 1],
3552 sizeof (cairo_pdf_color_stop_t));
3553 } else {
3554 calc_gradient_color (&stops[n_stops], &stops[0], &stops[n_stops-1]);
3556 n_stops++;
3558 stops[n_stops-1].offset = 1.0;
3561 if (stops[0].offset == stops[n_stops - 1].offset) {
3563 * The first and the last stops have the same offset, but we
3564 * don't want a function with an empty domain, because that
3565 * would provoke underdefined behaviour from rasterisers.
3566 * This can only happen with EXTEND_PAD, because EXTEND_NONE
3567 * is optimised into a clear pattern in cairo-gstate, and
3568 * REFLECT/REPEAT are always transformed to have the first
3569 * stop at t=0 and the last stop at t=1. Thus we want a step
3570 * function going from the first color to the last one.
3572 * This can be accomplished by stitching three functions:
3573 * - a constant first color function,
3574 * - a step from the first color to the last color (with empty domain)
3575 * - a constant last color function
3577 cairo_pdf_color_stop_t pad_stops[4];
3579 assert (pattern->base.extend == CAIRO_EXTEND_PAD);
3581 pad_stops[0] = pad_stops[1] = stops[0];
3582 pad_stops[2] = pad_stops[3] = stops[n_stops - 1];
3584 pad_stops[0].offset = 0;
3585 pad_stops[3].offset = 1;
3587 status = _cairo_pdf_surface_emit_stitched_colorgradient (surface,
3589 pad_stops,
3590 FALSE,
3591 color_function);
3592 if (unlikely (status))
3593 goto BAIL;
3595 if (emit_alpha) {
3596 status = _cairo_pdf_surface_emit_stitched_colorgradient (surface,
3598 pad_stops,
3599 TRUE,
3600 alpha_function);
3601 if (unlikely (status))
3602 goto BAIL;
3604 } else if (n_stops == 2) {
3605 /* no need for stitched function */
3606 status = cairo_pdf_surface_emit_rgb_linear_function (surface,
3607 &stops[0],
3608 &stops[n_stops - 1],
3609 color_function);
3610 if (unlikely (status))
3611 goto BAIL;
3613 if (emit_alpha) {
3614 status = cairo_pdf_surface_emit_alpha_linear_function (surface,
3615 &stops[0],
3616 &stops[n_stops - 1],
3617 alpha_function);
3618 if (unlikely (status))
3619 goto BAIL;
3621 } else {
3622 /* multiple stops: stitch. XXX possible optimization: regularly spaced
3623 * stops do not require stitching. XXX */
3624 status = _cairo_pdf_surface_emit_stitched_colorgradient (surface,
3625 n_stops,
3626 stops,
3627 FALSE,
3628 color_function);
3629 if (unlikely (status))
3630 goto BAIL;
3632 if (emit_alpha) {
3633 status = _cairo_pdf_surface_emit_stitched_colorgradient (surface,
3634 n_stops,
3635 stops,
3636 TRUE,
3637 alpha_function);
3638 if (unlikely (status))
3639 goto BAIL;
3643 BAIL:
3644 free (allstops);
3645 return status;
3648 static cairo_int_status_t
3649 _cairo_pdf_surface_emit_repeating_function (cairo_pdf_surface_t *surface,
3650 cairo_gradient_pattern_t *pattern,
3651 cairo_pdf_resource_t *function,
3652 int begin,
3653 int end)
3655 cairo_pdf_resource_t res;
3656 int i;
3658 res = _cairo_pdf_surface_new_object (surface);
3659 if (res.id == 0)
3660 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3662 _cairo_output_stream_printf (surface->output,
3663 "%d 0 obj\n"
3664 "<< /FunctionType 3\n"
3665 " /Domain [ %d %d ]\n",
3666 res.id,
3667 begin,
3668 end);
3670 _cairo_output_stream_printf (surface->output,
3671 " /Functions [ ");
3672 for (i = begin; i < end; i++)
3673 _cairo_output_stream_printf (surface->output,
3674 "%d 0 R ", function->id);
3675 _cairo_output_stream_printf (surface->output,
3676 "]\n");
3678 _cairo_output_stream_printf (surface->output,
3679 " /Bounds [ ");
3680 for (i = begin + 1; i < end; i++)
3681 _cairo_output_stream_printf (surface->output,
3682 "%d ", i);
3683 _cairo_output_stream_printf (surface->output,
3684 "]\n");
3686 _cairo_output_stream_printf (surface->output,
3687 " /Encode [ ");
3688 for (i = begin; i < end; i++) {
3689 if ((i % 2) && pattern->base.extend == CAIRO_EXTEND_REFLECT) {
3690 _cairo_output_stream_printf (surface->output,
3691 "1 0 ");
3692 } else {
3693 _cairo_output_stream_printf (surface->output,
3694 "0 1 ");
3697 _cairo_output_stream_printf (surface->output,
3698 "]\n");
3700 _cairo_output_stream_printf (surface->output,
3701 ">>\n"
3702 "endobj\n");
3704 *function = res;
3706 return _cairo_output_stream_get_status (surface->output);
3709 static cairo_int_status_t
3710 cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t *surface,
3711 cairo_pdf_pattern_t *pdf_pattern,
3712 cairo_pdf_resource_t gstate_resource,
3713 cairo_pdf_resource_t gradient_mask)
3715 cairo_pdf_resource_t smask_resource;
3716 cairo_int_status_t status;
3717 char buf[100];
3718 double x1, y1, x2, y2;
3720 if (pdf_pattern->is_shading) {
3721 snprintf(buf, sizeof(buf),
3722 " /Shading\n"
3723 " << /sh%d %d 0 R >>\n",
3724 gradient_mask.id,
3725 gradient_mask.id);
3726 } else {
3727 snprintf(buf, sizeof(buf),
3728 " /Pattern\n"
3729 " << /p%d %d 0 R >>\n",
3730 gradient_mask.id,
3731 gradient_mask.id);
3734 if (pdf_pattern->is_shading) {
3735 cairo_box_t box;
3737 /* When emitting a shading operator we are in cairo pattern
3738 * coordinates. _cairo_pdf_surface_paint_gradient has set the
3739 * ctm to the pattern matrix (including the convertion from
3740 * pdf to cairo coordinates) */
3741 _cairo_box_from_rectangle (&box, &pdf_pattern->extents);
3742 _cairo_box_to_doubles (&box, &x1, &y1, &x2, &y2);
3743 _cairo_matrix_transform_bounding_box (&pdf_pattern->pattern->matrix, &x1, &y1, &x2, &y2, NULL);
3744 } else {
3745 cairo_box_double_t box;
3747 /* When emitting a shading pattern we are in pdf page
3748 * coordinates. The color and alpha shading patterns painted
3749 * in the XObject below contain the cairo pattern to pdf page
3750 * matrix in the /Matrix entry of the pattern. */
3751 _get_bbox_from_extents (pdf_pattern->height, &pdf_pattern->extents, &box);
3752 x1 = box.p1.x;
3753 y1 = box.p1.y;
3754 x2 = box.p2.x;
3755 y2 = box.p2.y;
3757 status = _cairo_pdf_surface_open_stream (surface,
3758 NULL,
3759 surface->compress_content,
3760 " /Type /XObject\n"
3761 " /Subtype /Form\n"
3762 " /FormType 1\n"
3763 " /BBox [ %f %f %f %f ]\n"
3764 " /Resources\n"
3765 " << /ExtGState\n"
3766 " << /a0 << /ca 1 /CA 1 >>"
3767 " >>\n"
3768 "%s"
3769 " >>\n"
3770 " /Group\n"
3771 " << /Type /Group\n"
3772 " /S /Transparency\n"
3773 " /I true\n"
3774 " /CS /DeviceGray\n"
3775 " >>\n",
3776 x1,y1,x2,y2,
3777 buf);
3778 if (unlikely (status))
3779 return status;
3781 if (pdf_pattern->is_shading) {
3782 _cairo_output_stream_printf (surface->output,
3783 "/a0 gs /sh%d sh\n",
3784 gradient_mask.id);
3785 } else {
3786 _cairo_output_stream_printf (surface->output,
3787 "q\n"
3788 "/a0 gs\n"
3789 "/Pattern cs /p%d scn\n"
3790 "0 0 %f %f re\n"
3791 "f\n"
3792 "Q\n",
3793 gradient_mask.id,
3794 surface->width,
3795 surface->height);
3798 status = _cairo_pdf_surface_close_stream (surface);
3799 if (unlikely (status))
3800 return status;
3802 smask_resource = _cairo_pdf_surface_new_object (surface);
3803 if (smask_resource.id == 0)
3804 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3806 _cairo_output_stream_printf (surface->output,
3807 "%d 0 obj\n"
3808 "<< /Type /Mask\n"
3809 " /S /Luminosity\n"
3810 " /G %d 0 R\n"
3811 ">>\n"
3812 "endobj\n",
3813 smask_resource.id,
3814 surface->pdf_stream.self.id);
3816 /* Create GState which uses the transparency group as an SMask. */
3817 _cairo_pdf_surface_update_object (surface, gstate_resource);
3819 _cairo_output_stream_printf (surface->output,
3820 "%d 0 obj\n"
3821 "<< /Type /ExtGState\n"
3822 " /SMask %d 0 R\n"
3823 " /ca 1\n"
3824 " /CA 1\n"
3825 " /AIS false\n"
3826 ">>\n"
3827 "endobj\n",
3828 gstate_resource.id,
3829 smask_resource.id);
3831 return _cairo_output_stream_get_status (surface->output);
3834 static void
3835 _cairo_pdf_surface_output_gradient (cairo_pdf_surface_t *surface,
3836 const cairo_pdf_pattern_t *pdf_pattern,
3837 cairo_pdf_resource_t pattern_resource,
3838 const cairo_matrix_t *pat_to_pdf,
3839 const cairo_circle_double_t*start,
3840 const cairo_circle_double_t*end,
3841 const double *domain,
3842 const char *colorspace,
3843 cairo_pdf_resource_t color_function)
3845 _cairo_output_stream_printf (surface->output,
3846 "%d 0 obj\n",
3847 pattern_resource.id);
3849 if (!pdf_pattern->is_shading) {
3850 _cairo_output_stream_printf (surface->output,
3851 "<< /Type /Pattern\n"
3852 " /PatternType 2\n"
3853 " /Matrix [ ");
3854 _cairo_output_stream_print_matrix (surface->output, pat_to_pdf);
3855 _cairo_output_stream_printf (surface->output,
3856 " ]\n"
3857 " /Shading\n");
3860 if (pdf_pattern->pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
3861 _cairo_output_stream_printf (surface->output,
3862 " << /ShadingType 2\n"
3863 " /ColorSpace %s\n"
3864 " /Coords [ %f %f %f %f ]\n",
3865 colorspace,
3866 start->center.x, start->center.y,
3867 end->center.x, end->center.y);
3868 } else {
3869 _cairo_output_stream_printf (surface->output,
3870 " << /ShadingType 3\n"
3871 " /ColorSpace %s\n"
3872 " /Coords [ %f %f %f %f %f %f ]\n",
3873 colorspace,
3874 start->center.x, start->center.y,
3875 MAX (start->radius, 0),
3876 end->center.x, end->center.y,
3877 MAX (end->radius, 0));
3880 _cairo_output_stream_printf (surface->output,
3881 " /Domain [ %f %f ]\n",
3882 domain[0], domain[1]);
3884 if (pdf_pattern->pattern->extend != CAIRO_EXTEND_NONE) {
3885 _cairo_output_stream_printf (surface->output,
3886 " /Extend [ true true ]\n");
3887 } else {
3888 _cairo_output_stream_printf (surface->output,
3889 " /Extend [ false false ]\n");
3892 _cairo_output_stream_printf (surface->output,
3893 " /Function %d 0 R\n"
3894 " >>\n",
3895 color_function.id);
3897 if (!pdf_pattern->is_shading) {
3898 _cairo_output_stream_printf (surface->output,
3899 ">>\n");
3902 _cairo_output_stream_printf (surface->output,
3903 "endobj\n");
3906 static cairo_int_status_t
3907 _cairo_pdf_surface_emit_gradient (cairo_pdf_surface_t *surface,
3908 cairo_pdf_pattern_t *pdf_pattern)
3910 cairo_gradient_pattern_t *pattern = (cairo_gradient_pattern_t *) pdf_pattern->pattern;
3911 cairo_pdf_resource_t color_function, alpha_function;
3912 cairo_matrix_t pat_to_pdf;
3913 cairo_circle_double_t start, end;
3914 double domain[2];
3915 cairo_int_status_t status;
3917 assert (pattern->n_stops != 0);
3919 status = _cairo_pdf_surface_emit_pattern_stops (surface,
3920 pattern,
3921 &color_function,
3922 &alpha_function);
3923 if (unlikely (status))
3924 return status;
3926 pat_to_pdf = pattern->base.matrix;
3927 status = cairo_matrix_invert (&pat_to_pdf);
3928 /* cairo_pattern_set_matrix ensures the matrix is invertible */
3929 assert (status == CAIRO_INT_STATUS_SUCCESS);
3930 cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
3932 if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
3933 pattern->base.extend == CAIRO_EXTEND_REFLECT)
3935 double bounds_x1, bounds_x2, bounds_y1, bounds_y2;
3936 double x_scale, y_scale, tolerance;
3938 /* TODO: use tighter extents */
3939 bounds_x1 = 0;
3940 bounds_y1 = 0;
3941 bounds_x2 = surface->width;
3942 bounds_y2 = surface->height;
3943 _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
3944 &bounds_x1, &bounds_y1,
3945 &bounds_x2, &bounds_y2,
3946 NULL);
3948 x_scale = surface->base.x_resolution / surface->base.x_fallback_resolution;
3949 y_scale = surface->base.y_resolution / surface->base.y_fallback_resolution;
3951 tolerance = fabs (_cairo_matrix_compute_determinant (&pattern->base.matrix));
3952 tolerance /= _cairo_matrix_transformed_circle_major_axis (&pattern->base.matrix, 1);
3953 tolerance *= MIN (x_scale, y_scale);
3955 _cairo_gradient_pattern_box_to_parameter (pattern,
3956 bounds_x1, bounds_y1,
3957 bounds_x2, bounds_y2,
3958 tolerance, domain);
3959 } else if (pattern->stops[0].offset == pattern->stops[pattern->n_stops - 1].offset) {
3961 * If the first and the last stop offset are the same, then
3962 * the color function is a step function.
3963 * _cairo_ps_surface_emit_pattern_stops emits it as a stitched
3964 * function no matter how many stops the pattern has. The
3965 * domain of the stitched function will be [0 1] in this case.
3967 * This is done to avoid emitting degenerate gradients for
3968 * EXTEND_PAD patterns having a step color function.
3970 domain[0] = 0.0;
3971 domain[1] = 1.0;
3973 assert (pattern->base.extend == CAIRO_EXTEND_PAD);
3974 } else {
3975 domain[0] = pattern->stops[0].offset;
3976 domain[1] = pattern->stops[pattern->n_stops - 1].offset;
3979 /* PDF requires the first and last stop to be the same as the
3980 * extreme coordinates. For repeating patterns this moves the
3981 * extreme coordinates out to the begin/end of the repeating
3982 * function. For non repeating patterns this may move the extreme
3983 * coordinates in if there are not stops at offset 0 and 1. */
3984 _cairo_gradient_pattern_interpolate (pattern, domain[0], &start);
3985 _cairo_gradient_pattern_interpolate (pattern, domain[1], &end);
3987 if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
3988 pattern->base.extend == CAIRO_EXTEND_REFLECT)
3990 int repeat_begin, repeat_end;
3992 repeat_begin = floor (domain[0]);
3993 repeat_end = ceil (domain[1]);
3995 status = _cairo_pdf_surface_emit_repeating_function (surface,
3996 pattern,
3997 &color_function,
3998 repeat_begin,
3999 repeat_end);
4000 if (unlikely (status))
4001 return status;
4003 if (alpha_function.id != 0) {
4004 status = _cairo_pdf_surface_emit_repeating_function (surface,
4005 pattern,
4006 &alpha_function,
4007 repeat_begin,
4008 repeat_end);
4009 if (unlikely (status))
4010 return status;
4012 } else if (pattern->n_stops <= 2) {
4013 /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a
4014 * Type 2 function is used by itself without a stitching
4015 * function. Type 2 functions always have the domain [0 1] */
4016 domain[0] = 0.0;
4017 domain[1] = 1.0;
4020 _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
4021 _cairo_pdf_surface_output_gradient (surface, pdf_pattern,
4022 pdf_pattern->pattern_res,
4023 &pat_to_pdf, &start, &end, domain,
4024 "/DeviceRGB", color_function);
4026 if (alpha_function.id != 0) {
4027 cairo_pdf_resource_t mask_resource;
4029 assert (pdf_pattern->gstate_res.id != 0);
4031 /* Create pattern for SMask. */
4032 mask_resource = _cairo_pdf_surface_new_object (surface);
4033 if (mask_resource.id == 0)
4034 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4036 _cairo_pdf_surface_output_gradient (surface, pdf_pattern,
4037 mask_resource,
4038 &pat_to_pdf, &start, &end, domain,
4039 "/DeviceGray", alpha_function);
4041 status = cairo_pdf_surface_emit_transparency_group (surface,
4042 pdf_pattern,
4043 pdf_pattern->gstate_res,
4044 mask_resource);
4045 if (unlikely (status))
4046 return status;
4049 return _cairo_output_stream_get_status (surface->output);
4052 static cairo_int_status_t
4053 _cairo_pdf_surface_emit_mesh_pattern (cairo_pdf_surface_t *surface,
4054 cairo_pdf_pattern_t *pdf_pattern)
4056 cairo_matrix_t pat_to_pdf;
4057 cairo_int_status_t status;
4058 cairo_pattern_t *pattern = pdf_pattern->pattern;
4059 cairo_pdf_shading_t shading;
4060 int i;
4061 cairo_pdf_resource_t res;
4063 pat_to_pdf = pattern->matrix;
4064 status = cairo_matrix_invert (&pat_to_pdf);
4065 /* cairo_pattern_set_matrix ensures the matrix is invertible */
4066 assert (status == CAIRO_INT_STATUS_SUCCESS);
4068 cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
4070 status = _cairo_pdf_shading_init_color (&shading, (cairo_mesh_pattern_t *) pattern);
4071 if (unlikely (status))
4072 return status;
4074 res = _cairo_pdf_surface_new_object (surface);
4075 if (unlikely (res.id == 0))
4076 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4078 _cairo_output_stream_printf (surface->output,
4079 "%d 0 obj\n"
4080 "<< /ShadingType %d\n"
4081 " /ColorSpace /DeviceRGB\n"
4082 " /BitsPerCoordinate %d\n"
4083 " /BitsPerComponent %d\n"
4084 " /BitsPerFlag %d\n"
4085 " /Decode [",
4086 res.id,
4087 shading.shading_type,
4088 shading.bits_per_coordinate,
4089 shading.bits_per_component,
4090 shading.bits_per_flag);
4092 for (i = 0; i < shading.decode_array_length; i++)
4093 _cairo_output_stream_printf (surface->output, "%f ", shading.decode_array[i]);
4095 _cairo_output_stream_printf (surface->output,
4096 "]\n"
4097 " /Length %ld\n"
4098 ">>\n"
4099 "stream\n",
4100 shading.data_length);
4102 _cairo_output_stream_write (surface->output, shading.data, shading.data_length);
4104 _cairo_output_stream_printf (surface->output,
4105 "\nendstream\n"
4106 "endobj\n");
4108 _cairo_pdf_shading_fini (&shading);
4110 _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
4111 _cairo_output_stream_printf (surface->output,
4112 "%d 0 obj\n"
4113 "<< /Type /Pattern\n"
4114 " /PatternType 2\n"
4115 " /Matrix [ ",
4116 pdf_pattern->pattern_res.id);
4117 _cairo_output_stream_print_matrix (surface->output, &pat_to_pdf);
4118 _cairo_output_stream_printf (surface->output,
4119 " ]\n"
4120 " /Shading %d 0 R\n"
4121 ">>\n"
4122 "endobj\n",
4123 res.id);
4125 if (pdf_pattern->gstate_res.id != 0) {
4126 cairo_pdf_resource_t mask_resource;
4128 /* Create pattern for SMask. */
4129 res = _cairo_pdf_surface_new_object (surface);
4130 if (unlikely (res.id == 0))
4131 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4133 status = _cairo_pdf_shading_init_alpha (&shading, (cairo_mesh_pattern_t *) pattern);
4134 if (unlikely (status))
4135 return status;
4137 _cairo_output_stream_printf (surface->output,
4138 "%d 0 obj\n"
4139 "<< /ShadingType %d\n"
4140 " /ColorSpace /DeviceGray\n"
4141 " /BitsPerCoordinate %d\n"
4142 " /BitsPerComponent %d\n"
4143 " /BitsPerFlag %d\n"
4144 " /Decode [",
4145 res.id,
4146 shading.shading_type,
4147 shading.bits_per_coordinate,
4148 shading.bits_per_component,
4149 shading.bits_per_flag);
4151 for (i = 0; i < shading.decode_array_length; i++)
4152 _cairo_output_stream_printf (surface->output, "%f ", shading.decode_array[i]);
4154 _cairo_output_stream_printf (surface->output,
4155 "]\n"
4156 " /Length %ld\n"
4157 ">>\n"
4158 "stream\n",
4159 shading.data_length);
4161 _cairo_output_stream_write (surface->output, shading.data, shading.data_length);
4163 _cairo_output_stream_printf (surface->output,
4164 "\nendstream\n"
4165 "endobj\n");
4166 _cairo_pdf_shading_fini (&shading);
4168 mask_resource = _cairo_pdf_surface_new_object (surface);
4169 if (unlikely (mask_resource.id == 0))
4170 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4172 _cairo_output_stream_printf (surface->output,
4173 "%d 0 obj\n"
4174 "<< /Type /Pattern\n"
4175 " /PatternType 2\n"
4176 " /Matrix [ ",
4177 mask_resource.id);
4178 _cairo_output_stream_print_matrix (surface->output, &pat_to_pdf);
4179 _cairo_output_stream_printf (surface->output,
4180 " ]\n"
4181 " /Shading %d 0 R\n"
4182 ">>\n"
4183 "endobj\n",
4184 res.id);
4186 status = cairo_pdf_surface_emit_transparency_group (surface,
4187 pdf_pattern,
4188 pdf_pattern->gstate_res,
4189 mask_resource);
4190 if (unlikely (status))
4191 return status;
4194 return _cairo_output_stream_get_status (surface->output);
4197 static cairo_int_status_t
4198 _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern_t *pdf_pattern)
4200 double old_width, old_height;
4201 cairo_int_status_t status;
4203 old_width = surface->width;
4204 old_height = surface->height;
4205 _cairo_pdf_surface_set_size_internal (surface,
4206 pdf_pattern->width,
4207 pdf_pattern->height);
4209 switch (pdf_pattern->pattern->type) {
4210 case CAIRO_PATTERN_TYPE_SOLID:
4211 ASSERT_NOT_REACHED;
4212 status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
4213 break;
4215 case CAIRO_PATTERN_TYPE_SURFACE:
4216 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
4217 status = _cairo_pdf_surface_emit_surface_pattern (surface, pdf_pattern);
4218 break;
4220 case CAIRO_PATTERN_TYPE_LINEAR:
4221 case CAIRO_PATTERN_TYPE_RADIAL:
4222 status = _cairo_pdf_surface_emit_gradient (surface, pdf_pattern);
4223 break;
4225 case CAIRO_PATTERN_TYPE_MESH:
4226 status = _cairo_pdf_surface_emit_mesh_pattern (surface, pdf_pattern);
4227 break;
4229 default:
4230 ASSERT_NOT_REACHED;
4231 status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
4232 break;
4235 _cairo_pdf_surface_set_size_internal (surface,
4236 old_width,
4237 old_height);
4239 return status;
4242 static cairo_int_status_t
4243 _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
4244 cairo_operator_t op,
4245 const cairo_pattern_t *source,
4246 const cairo_rectangle_int_t *extents,
4247 cairo_pdf_resource_t *smask_res,
4248 cairo_bool_t stencil_mask)
4250 cairo_pdf_resource_t surface_res;
4251 int width, height;
4252 cairo_matrix_t cairo_p2d, pdf_p2d;
4253 cairo_int_status_t status;
4254 int alpha;
4255 cairo_rectangle_int_t extents2;
4256 double x_offset;
4257 double y_offset;
4259 if (source->extend == CAIRO_EXTEND_PAD &&
4260 !(source->type == CAIRO_PATTERN_TYPE_SURFACE &&
4261 ((cairo_surface_pattern_t *)source)->surface->type == CAIRO_SURFACE_TYPE_RECORDING))
4263 status = _cairo_pdf_surface_add_padded_image_surface (surface,
4264 source,
4265 extents,
4266 &surface_res,
4267 &width,
4268 &height,
4269 &x_offset,
4270 &y_offset);
4271 } else {
4272 status = _cairo_pdf_surface_add_source_surface (surface,
4273 NULL,
4274 source,
4276 source->filter,
4277 stencil_mask,
4278 FALSE,
4279 extents,
4280 smask_res,
4281 &surface_res,
4282 &width,
4283 &height,
4284 &x_offset,
4285 &y_offset,
4286 &extents2);
4288 if (unlikely (status))
4289 return status;
4291 cairo_p2d = source->matrix;
4292 status = cairo_matrix_invert (&cairo_p2d);
4293 /* cairo_pattern_set_matrix ensures the matrix is invertible */
4294 assert (status == CAIRO_INT_STATUS_SUCCESS);
4296 pdf_p2d = surface->cairo_to_pdf;
4297 cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d);
4298 cairo_matrix_translate (&pdf_p2d, x_offset, y_offset);
4299 cairo_matrix_translate (&pdf_p2d, 0.0, height);
4300 cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
4301 if (!(source->type == CAIRO_PATTERN_TYPE_SURFACE &&
4302 ((cairo_surface_pattern_t *)source)->surface->type == CAIRO_SURFACE_TYPE_RECORDING))
4304 cairo_matrix_scale (&pdf_p2d, width, height);
4307 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4308 if (unlikely (status))
4309 return status;
4311 if (! _cairo_matrix_is_identity (&pdf_p2d)) {
4312 _cairo_output_stream_print_matrix (surface->output, &pdf_p2d);
4313 _cairo_output_stream_printf (surface->output, " cm\n");
4316 status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
4317 if (unlikely (status))
4318 return status;
4320 if (stencil_mask) {
4321 _cairo_output_stream_printf (surface->output,
4322 "/x%d Do\n",
4323 surface_res.id);
4324 } else {
4325 _cairo_output_stream_printf (surface->output,
4326 "/a%d gs /x%d Do\n",
4327 alpha,
4328 surface_res.id);
4331 return _cairo_pdf_surface_add_xobject (surface, surface_res);
4334 static cairo_int_status_t
4335 _cairo_pdf_surface_paint_gradient (cairo_pdf_surface_t *surface,
4336 cairo_operator_t op,
4337 const cairo_pattern_t *source,
4338 const cairo_rectangle_int_t *extents)
4340 cairo_pdf_resource_t shading_res, gstate_res;
4341 cairo_matrix_t pat_to_pdf;
4342 cairo_int_status_t status;
4343 int alpha;
4345 status = _cairo_pdf_surface_add_pdf_shading (surface, source,
4346 op, extents,
4347 &shading_res, &gstate_res);
4348 if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
4349 return CAIRO_INT_STATUS_SUCCESS;
4350 if (unlikely (status))
4351 return status;
4353 pat_to_pdf = source->matrix;
4354 status = cairo_matrix_invert (&pat_to_pdf);
4355 /* cairo_pattern_set_matrix ensures the matrix is invertible */
4356 assert (status == CAIRO_INT_STATUS_SUCCESS);
4357 cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
4359 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4360 if (unlikely (status))
4361 return status;
4363 if (! _cairo_matrix_is_identity (&pat_to_pdf)) {
4364 _cairo_output_stream_print_matrix (surface->output, &pat_to_pdf);
4365 _cairo_output_stream_printf (surface->output, " cm\n");
4368 status = _cairo_pdf_surface_add_shading (surface, shading_res);
4369 if (unlikely (status))
4370 return status;
4372 if (gstate_res.id != 0) {
4373 status = _cairo_pdf_surface_add_smask (surface, gstate_res);
4374 if (unlikely (status))
4375 return status;
4377 _cairo_output_stream_printf (surface->output,
4378 "/s%d gs /sh%d sh\n",
4379 gstate_res.id,
4380 shading_res.id);
4381 } else {
4382 status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
4383 if (unlikely (status))
4384 return status;
4386 _cairo_output_stream_printf (surface->output,
4387 "/a%d gs /sh%d sh\n",
4388 alpha,
4389 shading_res.id);
4392 return status;
4395 static cairo_int_status_t
4396 _cairo_pdf_surface_paint_pattern (cairo_pdf_surface_t *surface,
4397 cairo_operator_t op,
4398 const cairo_pattern_t *source,
4399 const cairo_rectangle_int_t *extents,
4400 cairo_bool_t mask)
4402 switch (source->type) {
4403 case CAIRO_PATTERN_TYPE_SURFACE:
4404 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
4405 return _cairo_pdf_surface_paint_surface_pattern (surface,
4407 source,
4408 extents,
4409 NULL,
4410 mask);
4411 case CAIRO_PATTERN_TYPE_LINEAR:
4412 case CAIRO_PATTERN_TYPE_RADIAL:
4413 case CAIRO_PATTERN_TYPE_MESH:
4414 return _cairo_pdf_surface_paint_gradient (surface,
4416 source,
4417 extents);
4419 case CAIRO_PATTERN_TYPE_SOLID:
4420 default:
4421 ASSERT_NOT_REACHED;
4422 return CAIRO_STATUS_SUCCESS;
4426 static cairo_bool_t
4427 _can_paint_pattern (const cairo_pattern_t *pattern)
4429 switch (pattern->type) {
4430 case CAIRO_PATTERN_TYPE_SOLID:
4431 return FALSE;
4433 case CAIRO_PATTERN_TYPE_SURFACE:
4434 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
4435 return (pattern->extend == CAIRO_EXTEND_NONE ||
4436 pattern->extend == CAIRO_EXTEND_PAD);
4438 case CAIRO_PATTERN_TYPE_LINEAR:
4439 case CAIRO_PATTERN_TYPE_RADIAL:
4440 return TRUE;
4442 case CAIRO_PATTERN_TYPE_MESH:
4443 return FALSE;
4445 default:
4446 ASSERT_NOT_REACHED;
4447 return FALSE;
4451 static cairo_int_status_t
4452 _cairo_pdf_surface_select_operator (cairo_pdf_surface_t *surface,
4453 cairo_operator_t op)
4455 cairo_int_status_t status;
4457 if (op == surface->current_operator)
4458 return CAIRO_STATUS_SUCCESS;
4460 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4461 if (unlikely (status))
4462 return status;
4464 _cairo_output_stream_printf (surface->output,
4465 "/b%d gs\n", op);
4466 surface->current_operator = op;
4467 _cairo_pdf_surface_add_operator (surface, op);
4469 return CAIRO_STATUS_SUCCESS;
4472 static cairo_int_status_t
4473 _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
4474 const cairo_pattern_t *pattern,
4475 cairo_pdf_resource_t pattern_res,
4476 cairo_bool_t is_stroke)
4478 cairo_int_status_t status;
4479 int alpha;
4480 const cairo_color_t *solid_color = NULL;
4482 if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
4483 const cairo_solid_pattern_t *solid = (const cairo_solid_pattern_t *) pattern;
4485 solid_color = &solid->color;
4488 if (solid_color != NULL) {
4489 if (surface->current_pattern_is_solid_color == FALSE ||
4490 surface->current_color_red != solid_color->red ||
4491 surface->current_color_green != solid_color->green ||
4492 surface->current_color_blue != solid_color->blue ||
4493 surface->current_color_is_stroke != is_stroke)
4495 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4496 if (unlikely (status))
4497 return status;
4499 _cairo_output_stream_printf (surface->output,
4500 "%f %f %f ",
4501 solid_color->red,
4502 solid_color->green,
4503 solid_color->blue);
4505 if (is_stroke)
4506 _cairo_output_stream_printf (surface->output, "RG ");
4507 else
4508 _cairo_output_stream_printf (surface->output, "rg ");
4510 surface->current_color_red = solid_color->red;
4511 surface->current_color_green = solid_color->green;
4512 surface->current_color_blue = solid_color->blue;
4513 surface->current_color_is_stroke = is_stroke;
4516 if (surface->current_pattern_is_solid_color == FALSE ||
4517 surface->current_color_alpha != solid_color->alpha)
4519 status = _cairo_pdf_surface_add_alpha (surface, solid_color->alpha, &alpha);
4520 if (unlikely (status))
4521 return status;
4523 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4524 if (unlikely (status))
4525 return status;
4527 _cairo_output_stream_printf (surface->output,
4528 "/a%d gs\n",
4529 alpha);
4530 surface->current_color_alpha = solid_color->alpha;
4533 surface->current_pattern_is_solid_color = TRUE;
4534 } else {
4535 status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
4536 if (unlikely (status))
4537 return status;
4539 status = _cairo_pdf_surface_add_pattern (surface, pattern_res);
4540 if (unlikely (status))
4541 return status;
4543 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4544 if (unlikely (status))
4545 return status;
4547 /* fill-stroke calls select_pattern twice. Don't save if the
4548 * gstate is already saved. */
4549 if (!surface->select_pattern_gstate_saved)
4550 _cairo_output_stream_printf (surface->output, "q ");
4552 if (is_stroke) {
4553 _cairo_output_stream_printf (surface->output,
4554 "/Pattern CS /p%d SCN ",
4555 pattern_res.id);
4556 } else {
4557 _cairo_output_stream_printf (surface->output,
4558 "/Pattern cs /p%d scn ",
4559 pattern_res.id);
4561 _cairo_output_stream_printf (surface->output,
4562 "/a%d gs\n",
4563 alpha);
4564 surface->select_pattern_gstate_saved = TRUE;
4565 surface->current_pattern_is_solid_color = FALSE;
4568 return _cairo_output_stream_get_status (surface->output);
4571 static cairo_int_status_t
4572 _cairo_pdf_surface_unselect_pattern (cairo_pdf_surface_t *surface)
4574 cairo_int_status_t status;
4576 if (surface->select_pattern_gstate_saved) {
4577 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
4578 if (unlikely (status))
4579 return status;
4581 _cairo_output_stream_printf (surface->output, "Q\n");
4582 _cairo_pdf_operators_reset (&surface->pdf_operators);
4583 surface->current_pattern_is_solid_color = FALSE;
4585 surface->select_pattern_gstate_saved = FALSE;
4587 return CAIRO_STATUS_SUCCESS;
4590 static cairo_int_status_t
4591 _cairo_pdf_surface_show_page (void *abstract_surface)
4593 cairo_pdf_surface_t *surface = abstract_surface;
4594 cairo_int_status_t status;
4596 status = _cairo_pdf_surface_close_content_stream (surface);
4597 if (unlikely (status))
4598 return status;
4600 _cairo_surface_clipper_reset (&surface->clipper);
4602 status = _cairo_pdf_surface_write_page (surface);
4603 if (unlikely (status))
4604 return status;
4606 _cairo_pdf_surface_clear (surface);
4608 return CAIRO_STATUS_SUCCESS;
4611 static cairo_bool_t
4612 _cairo_pdf_surface_get_extents (void *abstract_surface,
4613 cairo_rectangle_int_t *rectangle)
4615 cairo_pdf_surface_t *surface = abstract_surface;
4617 rectangle->x = 0;
4618 rectangle->y = 0;
4620 /* XXX: The conversion to integers here is pretty bogus, (not to
4621 * mention the arbitrary limitation of width to a short(!). We
4622 * may need to come up with a better interface for get_size.
4624 rectangle->width = ceil (surface->width);
4625 rectangle->height = ceil (surface->height);
4627 return TRUE;
4630 static void
4631 _cairo_pdf_surface_get_font_options (void *abstract_surface,
4632 cairo_font_options_t *options)
4634 _cairo_font_options_init_default (options);
4636 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
4637 cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
4638 cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
4639 _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_OFF);
4642 static cairo_pdf_resource_t
4643 _cairo_pdf_surface_write_info (cairo_pdf_surface_t *surface)
4645 cairo_pdf_resource_t info;
4647 info = _cairo_pdf_surface_new_object (surface);
4648 if (info.id == 0)
4649 return info;
4651 _cairo_output_stream_printf (surface->output,
4652 "%d 0 obj\n"
4653 "<< /Creator (cairo %s (http://cairographics.org))\n"
4654 " /Producer (cairo %s (http://cairographics.org))\n"
4655 ">>\n"
4656 "endobj\n",
4657 info.id,
4658 cairo_version_string (),
4659 cairo_version_string ());
4661 return info;
4664 static void
4665 _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface)
4667 cairo_pdf_resource_t page;
4668 int num_pages, i;
4670 _cairo_pdf_surface_update_object (surface, surface->pages_resource);
4671 _cairo_output_stream_printf (surface->output,
4672 "%d 0 obj\n"
4673 "<< /Type /Pages\n"
4674 " /Kids [ ",
4675 surface->pages_resource.id);
4677 num_pages = _cairo_array_num_elements (&surface->pages);
4678 for (i = 0; i < num_pages; i++) {
4679 _cairo_array_copy_element (&surface->pages, i, &page);
4680 _cairo_output_stream_printf (surface->output, "%d 0 R ", page.id);
4683 _cairo_output_stream_printf (surface->output, "]\n");
4684 _cairo_output_stream_printf (surface->output, " /Count %d\n", num_pages);
4687 /* TODO: Figure out which other defaults to be inherited by /Page
4688 * objects. */
4689 _cairo_output_stream_printf (surface->output,
4690 ">>\n"
4691 "endobj\n");
4694 static cairo_int_status_t
4695 _utf8_to_pdf_string (const char *utf8, char **str_out)
4697 int i;
4698 int len;
4699 cairo_bool_t ascii;
4700 char *str;
4701 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
4703 ascii = TRUE;
4704 len = strlen (utf8);
4705 for (i = 0; i < len; i++) {
4706 unsigned c = utf8[i];
4707 if (c < 32 || c > 126 || c == '(' || c == ')' || c == '\\') {
4708 ascii = FALSE;
4709 break;
4713 if (ascii) {
4714 str = malloc (len + 3);
4715 if (str == NULL)
4716 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4718 str[0] = '(';
4719 for (i = 0; i < len; i++)
4720 str[i+1] = utf8[i];
4721 str[i+1] = ')';
4722 str[i+2] = 0;
4723 } else {
4724 uint16_t *utf16 = NULL;
4725 int utf16_len = 0;
4727 status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
4728 if (unlikely (status))
4729 return status;
4731 str = malloc (utf16_len*4 + 7);
4732 if (str == NULL) {
4733 free (utf16);
4734 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4737 strcpy (str, "<FEFF");
4738 for (i = 0; i < utf16_len; i++)
4739 snprintf (str + 4*i + 5, 5, "%04X", utf16[i]);
4741 strcat (str, ">");
4742 free (utf16);
4744 *str_out = str;
4746 return status;
4749 static cairo_int_status_t
4750 _cairo_pdf_surface_emit_unicode_for_glyph (cairo_pdf_surface_t *surface,
4751 const char *utf8)
4753 uint16_t *utf16 = NULL;
4754 int utf16_len = 0;
4755 cairo_int_status_t status;
4756 int i;
4758 if (utf8 && *utf8) {
4759 status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
4760 if (unlikely (status))
4761 return status;
4764 _cairo_output_stream_printf (surface->output, "<");
4765 if (utf16 == NULL || utf16_len == 0) {
4766 /* According to the "ToUnicode Mapping File Tutorial"
4767 * http://www.adobe.com/devnet/acrobat/pdfs/5411.ToUnicode.pdf
4769 * Glyphs that do not map to a Unicode code point must be
4770 * mapped to 0xfffd "REPLACEMENT CHARACTER".
4772 _cairo_output_stream_printf (surface->output,
4773 "fffd");
4774 } else {
4775 for (i = 0; i < utf16_len; i++)
4776 _cairo_output_stream_printf (surface->output,
4777 "%04x", (int) (utf16[i]));
4779 _cairo_output_stream_printf (surface->output, ">");
4781 free (utf16);
4783 return CAIRO_STATUS_SUCCESS;
4786 /* Bob Jenkins hash
4788 * Public domain code from:
4789 * http://burtleburtle.net/bob/hash/doobs.html
4792 #define HASH_MIX(a,b,c) \
4794 a -= b; a -= c; a ^= (c>>13); \
4795 b -= c; b -= a; b ^= (a<<8); \
4796 c -= a; c -= b; c ^= (b>>13); \
4797 a -= b; a -= c; a ^= (c>>12); \
4798 b -= c; b -= a; b ^= (a<<16); \
4799 c -= a; c -= b; c ^= (b>>5); \
4800 a -= b; a -= c; a ^= (c>>3); \
4801 b -= c; b -= a; b ^= (a<<10); \
4802 c -= a; c -= b; c ^= (b>>15); \
4805 static uint32_t
4806 _hash_data (const unsigned char *data, int length, uint32_t initval)
4808 uint32_t a, b, c, len;
4810 len = length;
4811 a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
4812 c = initval; /* the previous hash value */
4814 while (len >= 12) {
4815 a += (data[0] + ((uint32_t)data[1]<<8) + ((uint32_t)data[2]<<16) + ((uint32_t)data[3]<<24));
4816 b += (data[4] + ((uint32_t)data[5]<<8) + ((uint32_t)data[6]<<16) + ((uint32_t)data[7]<<24));
4817 c += (data[8] + ((uint32_t)data[9]<<8) + ((uint32_t)data[10]<<16)+ ((uint32_t)data[11]<<24));
4818 HASH_MIX (a,b,c);
4819 data += 12;
4820 len -= 12;
4823 c += length;
4824 switch(len) {
4825 case 11: c+= ((uint32_t) data[10] << 24);
4826 case 10: c+= ((uint32_t) data[9] << 16);
4827 case 9 : c+= ((uint32_t) data[8] << 8);
4828 case 8 : b+= ((uint32_t) data[7] << 24);
4829 case 7 : b+= ((uint32_t) data[6] << 16);
4830 case 6 : b+= ((uint32_t) data[5] << 8);
4831 case 5 : b+= data[4];
4832 case 4 : a+= ((uint32_t) data[3] << 24);
4833 case 3 : a+= ((uint32_t) data[2] << 16);
4834 case 2 : a+= ((uint32_t) data[1] << 8);
4835 case 1 : a+= data[0];
4837 HASH_MIX (a,b,c);
4839 return c;
4842 static void
4843 _create_font_subset_tag (cairo_scaled_font_subset_t *font_subset,
4844 const char *font_name,
4845 char *tag)
4847 uint32_t hash;
4848 int i;
4849 long numerator;
4850 ldiv_t d;
4852 hash = _hash_data ((unsigned char *) font_name, strlen(font_name), 0);
4853 hash = _hash_data ((unsigned char *) (font_subset->glyphs),
4854 font_subset->num_glyphs * sizeof(unsigned long), hash);
4856 numerator = abs (hash);
4857 for (i = 0; i < 6; i++) {
4858 d = ldiv (numerator, 26);
4859 numerator = d.quot;
4860 tag[i] = 'A' + d.rem;
4862 tag[i] = 0;
4865 static cairo_int_status_t
4866 _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
4867 cairo_scaled_font_subset_t *font_subset,
4868 cairo_pdf_resource_t *stream)
4870 unsigned int i, num_bfchar;
4871 cairo_int_status_t status;
4873 stream->id = 0;
4875 status = _cairo_pdf_surface_open_stream (surface,
4876 NULL,
4877 surface->compress_content,
4878 NULL);
4879 if (unlikely (status))
4880 return status;
4882 _cairo_output_stream_printf (surface->output,
4883 "/CIDInit /ProcSet findresource begin\n"
4884 "12 dict begin\n"
4885 "begincmap\n"
4886 "/CIDSystemInfo\n"
4887 "<< /Registry (Adobe)\n"
4888 " /Ordering (UCS)\n"
4889 " /Supplement 0\n"
4890 ">> def\n"
4891 "/CMapName /Adobe-Identity-UCS def\n"
4892 "/CMapType 2 def\n"
4893 "1 begincodespacerange\n");
4895 if (font_subset->is_composite && !font_subset->is_latin) {
4896 _cairo_output_stream_printf (surface->output,
4897 "<0000> <ffff>\n");
4898 } else {
4899 _cairo_output_stream_printf (surface->output,
4900 "<00> <ff>\n");
4903 _cairo_output_stream_printf (surface->output,
4904 "endcodespacerange\n");
4906 if (font_subset->is_scaled) {
4907 /* Type 3 fonts include glyph 0 in the subset */
4908 num_bfchar = font_subset->num_glyphs;
4910 /* The CMap specification has a limit of 100 characters per beginbfchar operator */
4911 _cairo_output_stream_printf (surface->output,
4912 "%d beginbfchar\n",
4913 num_bfchar > 100 ? 100 : num_bfchar);
4915 for (i = 0; i < num_bfchar; i++) {
4916 if (i != 0 && i % 100 == 0) {
4917 _cairo_output_stream_printf (surface->output,
4918 "endbfchar\n"
4919 "%d beginbfchar\n",
4920 num_bfchar - i > 100 ? 100 : num_bfchar - i);
4922 _cairo_output_stream_printf (surface->output, "<%02x> ", i);
4923 status = _cairo_pdf_surface_emit_unicode_for_glyph (surface,
4924 font_subset->utf8[i]);
4925 if (unlikely (status))
4926 return status;
4928 _cairo_output_stream_printf (surface->output,
4929 "\n");
4931 } else {
4932 /* Other fonts reserve glyph 0 for .notdef. Omit glyph 0 from the /ToUnicode map */
4933 num_bfchar = font_subset->num_glyphs - 1;
4935 /* The CMap specification has a limit of 100 characters per beginbfchar operator */
4936 _cairo_output_stream_printf (surface->output,
4937 "%d beginbfchar\n",
4938 num_bfchar > 100 ? 100 : num_bfchar);
4940 for (i = 0; i < num_bfchar; i++) {
4941 if (i != 0 && i % 100 == 0) {
4942 _cairo_output_stream_printf (surface->output,
4943 "endbfchar\n"
4944 "%d beginbfchar\n",
4945 num_bfchar - i > 100 ? 100 : num_bfchar - i);
4947 if (font_subset->is_latin)
4948 _cairo_output_stream_printf (surface->output, "<%02x> ", font_subset->to_latin_char[i + 1]);
4949 else if (font_subset->is_composite)
4950 _cairo_output_stream_printf (surface->output, "<%04x> ", i + 1);
4951 else
4952 _cairo_output_stream_printf (surface->output, "<%02x> ", i + 1);
4954 status = _cairo_pdf_surface_emit_unicode_for_glyph (surface,
4955 font_subset->utf8[i + 1]);
4956 if (unlikely (status))
4957 return status;
4959 _cairo_output_stream_printf (surface->output,
4960 "\n");
4964 _cairo_output_stream_printf (surface->output,
4965 "endbfchar\n");
4967 _cairo_output_stream_printf (surface->output,
4968 "endcmap\n"
4969 "CMapName currentdict /CMap defineresource pop\n"
4970 "end\n"
4971 "end\n");
4973 *stream = surface->pdf_stream.self;
4974 return _cairo_pdf_surface_close_stream (surface);
4977 #define PDF_UNITS_PER_EM 1000
4979 static cairo_int_status_t
4980 _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface,
4981 cairo_scaled_font_subset_t *font_subset,
4982 cairo_cff_subset_t *subset)
4984 cairo_pdf_resource_t stream, descriptor, cidfont_dict;
4985 cairo_pdf_resource_t subset_resource, to_unicode_stream;
4986 cairo_pdf_font_t font;
4987 unsigned int i, last_glyph;
4988 cairo_int_status_t status;
4989 char tag[10];
4991 _create_font_subset_tag (font_subset, subset->ps_name, tag);
4993 subset_resource = _cairo_pdf_surface_get_font_resource (surface,
4994 font_subset->font_id,
4995 font_subset->subset_id);
4996 if (subset_resource.id == 0)
4997 return CAIRO_STATUS_SUCCESS;
4999 status = _cairo_pdf_surface_open_stream (surface,
5000 NULL,
5001 TRUE,
5002 font_subset->is_latin ?
5003 " /Subtype /Type1C\n" :
5004 " /Subtype /CIDFontType0C\n");
5005 if (unlikely (status))
5006 return status;
5008 stream = surface->pdf_stream.self;
5009 _cairo_output_stream_write (surface->output,
5010 subset->data, subset->data_length);
5011 status = _cairo_pdf_surface_close_stream (surface);
5012 if (unlikely (status))
5013 return status;
5015 status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
5016 font_subset,
5017 &to_unicode_stream);
5018 if (_cairo_int_status_is_error (status))
5019 return status;
5021 descriptor = _cairo_pdf_surface_new_object (surface);
5022 if (descriptor.id == 0)
5023 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5025 _cairo_output_stream_printf (surface->output,
5026 "%d 0 obj\n"
5027 "<< /Type /FontDescriptor\n"
5028 " /FontName /%s+%s\n",
5029 descriptor.id,
5030 tag,
5031 subset->ps_name);
5033 if (subset->family_name_utf8) {
5034 char *pdf_str;
5036 status = _utf8_to_pdf_string (subset->family_name_utf8, &pdf_str);
5037 if (unlikely (status))
5038 return status;
5040 _cairo_output_stream_printf (surface->output,
5041 " /FontFamily %s\n",
5042 pdf_str);
5043 free (pdf_str);
5046 _cairo_output_stream_printf (surface->output,
5047 " /Flags 4\n"
5048 " /FontBBox [ %ld %ld %ld %ld ]\n"
5049 " /ItalicAngle 0\n"
5050 " /Ascent %ld\n"
5051 " /Descent %ld\n"
5052 " /CapHeight %ld\n"
5053 " /StemV 80\n"
5054 " /StemH 80\n"
5055 " /FontFile3 %u 0 R\n"
5056 ">>\n"
5057 "endobj\n",
5058 (long)(subset->x_min*PDF_UNITS_PER_EM),
5059 (long)(subset->y_min*PDF_UNITS_PER_EM),
5060 (long)(subset->x_max*PDF_UNITS_PER_EM),
5061 (long)(subset->y_max*PDF_UNITS_PER_EM),
5062 (long)(subset->ascent*PDF_UNITS_PER_EM),
5063 (long)(subset->descent*PDF_UNITS_PER_EM),
5064 (long)(subset->y_max*PDF_UNITS_PER_EM),
5065 stream.id);
5067 if (font_subset->is_latin) {
5068 /* find last glyph used */
5069 for (i = 255; i >= 32; i--)
5070 if (font_subset->latin_to_subset_glyph_index[i] > 0)
5071 break;
5073 last_glyph = i;
5074 _cairo_pdf_surface_update_object (surface, subset_resource);
5075 _cairo_output_stream_printf (surface->output,
5076 "%d 0 obj\n"
5077 "<< /Type /Font\n"
5078 " /Subtype /Type1\n"
5079 " /BaseFont /%s+%s\n"
5080 " /FirstChar 32\n"
5081 " /LastChar %d\n"
5082 " /FontDescriptor %d 0 R\n"
5083 " /Encoding /WinAnsiEncoding\n"
5084 " /Widths [",
5085 subset_resource.id,
5086 tag,
5087 subset->ps_name,
5088 last_glyph,
5089 descriptor.id);
5091 for (i = 32; i < last_glyph + 1; i++) {
5092 int glyph = font_subset->latin_to_subset_glyph_index[i];
5093 if (glyph > 0) {
5094 _cairo_output_stream_printf (surface->output,
5095 " %ld",
5096 (long)(subset->widths[glyph]*PDF_UNITS_PER_EM));
5097 } else {
5098 _cairo_output_stream_printf (surface->output, " 0");
5102 _cairo_output_stream_printf (surface->output,
5103 " ]\n");
5105 if (to_unicode_stream.id != 0)
5106 _cairo_output_stream_printf (surface->output,
5107 " /ToUnicode %d 0 R\n",
5108 to_unicode_stream.id);
5110 _cairo_output_stream_printf (surface->output,
5111 ">>\n"
5112 "endobj\n");
5113 } else {
5114 cidfont_dict = _cairo_pdf_surface_new_object (surface);
5115 if (cidfont_dict.id == 0)
5116 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5118 _cairo_output_stream_printf (surface->output,
5119 "%d 0 obj\n"
5120 "<< /Type /Font\n"
5121 " /Subtype /CIDFontType0\n"
5122 " /BaseFont /%s+%s\n"
5123 " /CIDSystemInfo\n"
5124 " << /Registry (Adobe)\n"
5125 " /Ordering (Identity)\n"
5126 " /Supplement 0\n"
5127 " >>\n"
5128 " /FontDescriptor %d 0 R\n"
5129 " /W [0 [",
5130 cidfont_dict.id,
5131 tag,
5132 subset->ps_name,
5133 descriptor.id);
5135 for (i = 0; i < font_subset->num_glyphs; i++)
5136 _cairo_output_stream_printf (surface->output,
5137 " %ld",
5138 (long)(subset->widths[i]*PDF_UNITS_PER_EM));
5140 _cairo_output_stream_printf (surface->output,
5141 " ]]\n"
5142 ">>\n"
5143 "endobj\n");
5145 _cairo_pdf_surface_update_object (surface, subset_resource);
5146 _cairo_output_stream_printf (surface->output,
5147 "%d 0 obj\n"
5148 "<< /Type /Font\n"
5149 " /Subtype /Type0\n"
5150 " /BaseFont /%s+%s\n"
5151 " /Encoding /Identity-H\n"
5152 " /DescendantFonts [ %d 0 R]\n",
5153 subset_resource.id,
5154 tag,
5155 subset->ps_name,
5156 cidfont_dict.id);
5158 if (to_unicode_stream.id != 0)
5159 _cairo_output_stream_printf (surface->output,
5160 " /ToUnicode %d 0 R\n",
5161 to_unicode_stream.id);
5163 _cairo_output_stream_printf (surface->output,
5164 ">>\n"
5165 "endobj\n");
5168 font.font_id = font_subset->font_id;
5169 font.subset_id = font_subset->subset_id;
5170 font.subset_resource = subset_resource;
5171 status = _cairo_array_append (&surface->fonts, &font);
5173 return status;
5176 static cairo_int_status_t
5177 _cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface,
5178 cairo_scaled_font_subset_t *font_subset)
5180 cairo_int_status_t status;
5181 cairo_cff_subset_t subset;
5182 char name[64];
5184 snprintf (name, sizeof name, "CairoFont-%d-%d",
5185 font_subset->font_id, font_subset->subset_id);
5186 status = _cairo_cff_subset_init (&subset, name, font_subset);
5187 if (unlikely (status))
5188 return status;
5190 status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset);
5192 _cairo_cff_subset_fini (&subset);
5194 return status;
5197 static cairo_int_status_t
5198 _cairo_pdf_surface_emit_cff_fallback_font (cairo_pdf_surface_t *surface,
5199 cairo_scaled_font_subset_t *font_subset)
5201 cairo_int_status_t status;
5202 cairo_cff_subset_t subset;
5203 char name[64];
5205 /* CFF fallback subsetting does not work with 8-bit glyphs unless
5206 * they are a latin subset */
5207 if (!font_subset->is_composite && !font_subset->is_latin)
5208 return CAIRO_INT_STATUS_UNSUPPORTED;
5210 snprintf (name, sizeof name, "CairoFont-%d-%d",
5211 font_subset->font_id, font_subset->subset_id);
5212 status = _cairo_cff_fallback_init (&subset, name, font_subset);
5213 if (unlikely (status))
5214 return status;
5216 status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset);
5218 _cairo_cff_fallback_fini (&subset);
5220 return status;
5223 static cairo_int_status_t
5224 _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface,
5225 cairo_scaled_font_subset_t *font_subset,
5226 cairo_type1_subset_t *subset)
5228 cairo_pdf_resource_t stream, descriptor, subset_resource, to_unicode_stream;
5229 cairo_pdf_font_t font;
5230 cairo_int_status_t status;
5231 unsigned long length;
5232 unsigned int i, last_glyph;
5233 char tag[10];
5235 _create_font_subset_tag (font_subset, subset->base_font, tag);
5237 subset_resource = _cairo_pdf_surface_get_font_resource (surface,
5238 font_subset->font_id,
5239 font_subset->subset_id);
5240 if (subset_resource.id == 0)
5241 return CAIRO_STATUS_SUCCESS;
5243 length = subset->header_length + subset->data_length + subset->trailer_length;
5244 status = _cairo_pdf_surface_open_stream (surface,
5245 NULL,
5246 TRUE,
5247 " /Length1 %lu\n"
5248 " /Length2 %lu\n"
5249 " /Length3 %lu\n",
5250 subset->header_length,
5251 subset->data_length,
5252 subset->trailer_length);
5253 if (unlikely (status))
5254 return status;
5256 stream = surface->pdf_stream.self;
5257 _cairo_output_stream_write (surface->output, subset->data, length);
5258 status = _cairo_pdf_surface_close_stream (surface);
5259 if (unlikely (status))
5260 return status;
5262 status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
5263 font_subset,
5264 &to_unicode_stream);
5265 if (_cairo_int_status_is_error (status))
5266 return status;
5268 last_glyph = font_subset->num_glyphs - 1;
5269 if (font_subset->is_latin) {
5270 /* find last glyph used */
5271 for (i = 255; i >= 32; i--)
5272 if (font_subset->latin_to_subset_glyph_index[i] > 0)
5273 break;
5275 last_glyph = i;
5278 descriptor = _cairo_pdf_surface_new_object (surface);
5279 if (descriptor.id == 0)
5280 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5282 _cairo_output_stream_printf (surface->output,
5283 "%d 0 obj\n"
5284 "<< /Type /FontDescriptor\n"
5285 " /FontName /%s+%s\n"
5286 " /Flags 4\n"
5287 " /FontBBox [ %ld %ld %ld %ld ]\n"
5288 " /ItalicAngle 0\n"
5289 " /Ascent %ld\n"
5290 " /Descent %ld\n"
5291 " /CapHeight %ld\n"
5292 " /StemV 80\n"
5293 " /StemH 80\n"
5294 " /FontFile %u 0 R\n"
5295 ">>\n"
5296 "endobj\n",
5297 descriptor.id,
5298 tag,
5299 subset->base_font,
5300 (long)(subset->x_min*PDF_UNITS_PER_EM),
5301 (long)(subset->y_min*PDF_UNITS_PER_EM),
5302 (long)(subset->x_max*PDF_UNITS_PER_EM),
5303 (long)(subset->y_max*PDF_UNITS_PER_EM),
5304 (long)(subset->ascent*PDF_UNITS_PER_EM),
5305 (long)(subset->descent*PDF_UNITS_PER_EM),
5306 (long)(subset->y_max*PDF_UNITS_PER_EM),
5307 stream.id);
5309 _cairo_pdf_surface_update_object (surface, subset_resource);
5310 _cairo_output_stream_printf (surface->output,
5311 "%d 0 obj\n"
5312 "<< /Type /Font\n"
5313 " /Subtype /Type1\n"
5314 " /BaseFont /%s+%s\n"
5315 " /FirstChar %d\n"
5316 " /LastChar %d\n"
5317 " /FontDescriptor %d 0 R\n",
5318 subset_resource.id,
5319 tag,
5320 subset->base_font,
5321 font_subset->is_latin ? 32 : 0,
5322 last_glyph,
5323 descriptor.id);
5325 if (font_subset->is_latin)
5326 _cairo_output_stream_printf (surface->output, " /Encoding /WinAnsiEncoding\n");
5328 _cairo_output_stream_printf (surface->output, " /Widths [");
5329 if (font_subset->is_latin) {
5330 for (i = 32; i < last_glyph + 1; i++) {
5331 int glyph = font_subset->latin_to_subset_glyph_index[i];
5332 if (glyph > 0) {
5333 _cairo_output_stream_printf (surface->output,
5334 " %ld",
5335 (long)(subset->widths[glyph]*PDF_UNITS_PER_EM));
5336 } else {
5337 _cairo_output_stream_printf (surface->output, " 0");
5340 } else {
5341 for (i = 0; i < font_subset->num_glyphs; i++)
5342 _cairo_output_stream_printf (surface->output,
5343 " %ld",
5344 (long)(subset->widths[i]*PDF_UNITS_PER_EM));
5347 _cairo_output_stream_printf (surface->output,
5348 " ]\n");
5350 if (to_unicode_stream.id != 0)
5351 _cairo_output_stream_printf (surface->output,
5352 " /ToUnicode %d 0 R\n",
5353 to_unicode_stream.id);
5355 _cairo_output_stream_printf (surface->output,
5356 ">>\n"
5357 "endobj\n");
5359 font.font_id = font_subset->font_id;
5360 font.subset_id = font_subset->subset_id;
5361 font.subset_resource = subset_resource;
5362 return _cairo_array_append (&surface->fonts, &font);
5365 static cairo_int_status_t
5366 _cairo_pdf_surface_emit_type1_font_subset (cairo_pdf_surface_t *surface,
5367 cairo_scaled_font_subset_t *font_subset)
5369 cairo_int_status_t status;
5370 cairo_type1_subset_t subset;
5371 char name[64];
5373 /* 16-bit glyphs not compatible with Type 1 fonts */
5374 if (font_subset->is_composite && !font_subset->is_latin)
5375 return CAIRO_INT_STATUS_UNSUPPORTED;
5377 snprintf (name, sizeof name, "CairoFont-%d-%d",
5378 font_subset->font_id, font_subset->subset_id);
5379 status = _cairo_type1_subset_init (&subset, name, font_subset, FALSE);
5380 if (unlikely (status))
5381 return status;
5383 status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset);
5385 _cairo_type1_subset_fini (&subset);
5386 return status;
5389 static cairo_int_status_t
5390 _cairo_pdf_surface_emit_type1_fallback_font (cairo_pdf_surface_t *surface,
5391 cairo_scaled_font_subset_t *font_subset)
5393 cairo_int_status_t status;
5394 cairo_type1_subset_t subset;
5395 char name[64];
5397 /* 16-bit glyphs not compatible with Type 1 fonts */
5398 if (font_subset->is_composite && !font_subset->is_latin)
5399 return CAIRO_INT_STATUS_UNSUPPORTED;
5401 snprintf (name, sizeof name, "CairoFont-%d-%d",
5402 font_subset->font_id, font_subset->subset_id);
5403 status = _cairo_type1_fallback_init_binary (&subset, name, font_subset);
5404 if (unlikely (status))
5405 return status;
5407 status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset);
5409 _cairo_type1_fallback_fini (&subset);
5410 return status;
5413 static cairo_int_status_t
5414 _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
5415 cairo_scaled_font_subset_t *font_subset)
5417 cairo_pdf_resource_t stream, descriptor, cidfont_dict;
5418 cairo_pdf_resource_t subset_resource, to_unicode_stream;
5419 cairo_int_status_t status;
5420 cairo_pdf_font_t font;
5421 cairo_truetype_subset_t subset;
5422 unsigned int i, last_glyph;
5423 char tag[10];
5425 subset_resource = _cairo_pdf_surface_get_font_resource (surface,
5426 font_subset->font_id,
5427 font_subset->subset_id);
5428 if (subset_resource.id == 0)
5429 return CAIRO_STATUS_SUCCESS;
5431 status = _cairo_truetype_subset_init_pdf (&subset, font_subset);
5432 if (unlikely (status))
5433 return status;
5435 _create_font_subset_tag (font_subset, subset.ps_name, tag);
5437 status = _cairo_pdf_surface_open_stream (surface,
5438 NULL,
5439 TRUE,
5440 " /Length1 %lu\n",
5441 subset.data_length);
5442 if (unlikely (status)) {
5443 _cairo_truetype_subset_fini (&subset);
5444 return status;
5447 stream = surface->pdf_stream.self;
5448 _cairo_output_stream_write (surface->output,
5449 subset.data, subset.data_length);
5450 status = _cairo_pdf_surface_close_stream (surface);
5451 if (unlikely (status)) {
5452 _cairo_truetype_subset_fini (&subset);
5453 return status;
5456 status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
5457 font_subset,
5458 &to_unicode_stream);
5459 if (_cairo_int_status_is_error (status)) {
5460 _cairo_truetype_subset_fini (&subset);
5461 return status;
5464 descriptor = _cairo_pdf_surface_new_object (surface);
5465 if (descriptor.id == 0) {
5466 _cairo_truetype_subset_fini (&subset);
5467 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5470 _cairo_output_stream_printf (surface->output,
5471 "%d 0 obj\n"
5472 "<< /Type /FontDescriptor\n"
5473 " /FontName /%s+%s\n",
5474 descriptor.id,
5475 tag,
5476 subset.ps_name);
5478 if (subset.family_name_utf8) {
5479 char *pdf_str;
5481 status = _utf8_to_pdf_string (subset.family_name_utf8, &pdf_str);
5482 if (unlikely (status))
5483 return status;
5485 _cairo_output_stream_printf (surface->output,
5486 " /FontFamily %s\n",
5487 pdf_str);
5488 free (pdf_str);
5491 _cairo_output_stream_printf (surface->output,
5492 " /Flags %d\n"
5493 " /FontBBox [ %ld %ld %ld %ld ]\n"
5494 " /ItalicAngle 0\n"
5495 " /Ascent %ld\n"
5496 " /Descent %ld\n"
5497 " /CapHeight %ld\n"
5498 " /StemV 80\n"
5499 " /StemH 80\n"
5500 " /FontFile2 %u 0 R\n"
5501 ">>\n"
5502 "endobj\n",
5503 font_subset->is_latin ? 32 : 4,
5504 (long)(subset.x_min*PDF_UNITS_PER_EM),
5505 (long)(subset.y_min*PDF_UNITS_PER_EM),
5506 (long)(subset.x_max*PDF_UNITS_PER_EM),
5507 (long)(subset.y_max*PDF_UNITS_PER_EM),
5508 (long)(subset.ascent*PDF_UNITS_PER_EM),
5509 (long)(subset.descent*PDF_UNITS_PER_EM),
5510 (long)(subset.y_max*PDF_UNITS_PER_EM),
5511 stream.id);
5513 if (font_subset->is_latin) {
5514 /* find last glyph used */
5515 for (i = 255; i >= 32; i--)
5516 if (font_subset->latin_to_subset_glyph_index[i] > 0)
5517 break;
5519 last_glyph = i;
5520 _cairo_pdf_surface_update_object (surface, subset_resource);
5521 _cairo_output_stream_printf (surface->output,
5522 "%d 0 obj\n"
5523 "<< /Type /Font\n"
5524 " /Subtype /TrueType\n"
5525 " /BaseFont /%s+%s\n"
5526 " /FirstChar 32\n"
5527 " /LastChar %d\n"
5528 " /FontDescriptor %d 0 R\n"
5529 " /Encoding /WinAnsiEncoding\n"
5530 " /Widths [",
5531 subset_resource.id,
5532 tag,
5533 subset.ps_name,
5534 last_glyph,
5535 descriptor.id);
5537 for (i = 32; i < last_glyph + 1; i++) {
5538 int glyph = font_subset->latin_to_subset_glyph_index[i];
5539 if (glyph > 0) {
5540 _cairo_output_stream_printf (surface->output,
5541 " %ld",
5542 (long)(subset.widths[glyph]*PDF_UNITS_PER_EM));
5543 } else {
5544 _cairo_output_stream_printf (surface->output, " 0");
5548 _cairo_output_stream_printf (surface->output,
5549 " ]\n");
5551 if (to_unicode_stream.id != 0)
5552 _cairo_output_stream_printf (surface->output,
5553 " /ToUnicode %d 0 R\n",
5554 to_unicode_stream.id);
5556 _cairo_output_stream_printf (surface->output,
5557 ">>\n"
5558 "endobj\n");
5559 } else {
5560 cidfont_dict = _cairo_pdf_surface_new_object (surface);
5561 if (cidfont_dict.id == 0) {
5562 _cairo_truetype_subset_fini (&subset);
5563 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5566 _cairo_output_stream_printf (surface->output,
5567 "%d 0 obj\n"
5568 "<< /Type /Font\n"
5569 " /Subtype /CIDFontType2\n"
5570 " /BaseFont /%s+%s\n"
5571 " /CIDSystemInfo\n"
5572 " << /Registry (Adobe)\n"
5573 " /Ordering (Identity)\n"
5574 " /Supplement 0\n"
5575 " >>\n"
5576 " /FontDescriptor %d 0 R\n"
5577 " /W [0 [",
5578 cidfont_dict.id,
5579 tag,
5580 subset.ps_name,
5581 descriptor.id);
5583 for (i = 0; i < font_subset->num_glyphs; i++)
5584 _cairo_output_stream_printf (surface->output,
5585 " %ld",
5586 (long)(subset.widths[i]*PDF_UNITS_PER_EM));
5588 _cairo_output_stream_printf (surface->output,
5589 " ]]\n"
5590 ">>\n"
5591 "endobj\n");
5593 _cairo_pdf_surface_update_object (surface, subset_resource);
5594 _cairo_output_stream_printf (surface->output,
5595 "%d 0 obj\n"
5596 "<< /Type /Font\n"
5597 " /Subtype /Type0\n"
5598 " /BaseFont /%s+%s\n"
5599 " /Encoding /Identity-H\n"
5600 " /DescendantFonts [ %d 0 R]\n",
5601 subset_resource.id,
5602 tag,
5603 subset.ps_name,
5604 cidfont_dict.id);
5606 if (to_unicode_stream.id != 0)
5607 _cairo_output_stream_printf (surface->output,
5608 " /ToUnicode %d 0 R\n",
5609 to_unicode_stream.id);
5611 _cairo_output_stream_printf (surface->output,
5612 ">>\n"
5613 "endobj\n");
5616 font.font_id = font_subset->font_id;
5617 font.subset_id = font_subset->subset_id;
5618 font.subset_resource = subset_resource;
5619 status = _cairo_array_append (&surface->fonts, &font);
5621 _cairo_truetype_subset_fini (&subset);
5623 return status;
5626 static cairo_int_status_t
5627 _cairo_pdf_emit_imagemask (cairo_image_surface_t *image,
5628 cairo_output_stream_t *stream)
5630 uint8_t *byte, output_byte;
5631 int row, col, num_cols;
5633 /* The only image type supported by Type 3 fonts are 1-bit image
5634 * masks */
5635 assert (image->format == CAIRO_FORMAT_A1);
5637 _cairo_output_stream_printf (stream,
5638 "BI\n"
5639 "/IM true\n"
5640 "/W %d\n"
5641 "/H %d\n"
5642 "/BPC 1\n"
5643 "/D [1 0]\n",
5644 image->width,
5645 image->height);
5647 _cairo_output_stream_printf (stream,
5648 "ID ");
5650 num_cols = (image->width + 7) / 8;
5651 for (row = 0; row < image->height; row++) {
5652 byte = image->data + row * image->stride;
5653 for (col = 0; col < num_cols; col++) {
5654 output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
5655 _cairo_output_stream_write (stream, &output_byte, 1);
5656 byte++;
5660 _cairo_output_stream_printf (stream,
5661 "\nEI\n");
5663 return _cairo_output_stream_get_status (stream);
5666 static cairo_int_status_t
5667 _cairo_pdf_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset,
5668 void *closure)
5670 cairo_pdf_surface_t *surface = closure;
5671 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
5672 cairo_int_status_t status2;
5673 unsigned int i;
5674 cairo_surface_t *type3_surface;
5675 cairo_output_stream_t *null_stream;
5677 null_stream = _cairo_null_stream_create ();
5678 type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
5679 null_stream,
5680 _cairo_pdf_emit_imagemask,
5681 surface->font_subsets,
5682 FALSE);
5683 if (unlikely (type3_surface->status)) {
5684 status2 = _cairo_output_stream_destroy (null_stream);
5685 return type3_surface->status;
5688 _cairo_type3_glyph_surface_set_font_subsets_callback (type3_surface,
5689 _cairo_pdf_surface_add_font,
5690 surface);
5692 for (i = 0; i < font_subset->num_glyphs; i++) {
5693 status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
5694 font_subset->glyphs[i]);
5695 if (unlikely (status))
5696 break;
5699 cairo_surface_destroy (type3_surface);
5700 status2 = _cairo_output_stream_destroy (null_stream);
5701 if (status == CAIRO_INT_STATUS_SUCCESS)
5702 status = status2;
5704 return status;
5707 static cairo_int_status_t
5708 _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
5709 cairo_scaled_font_subset_t *font_subset)
5711 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
5712 cairo_pdf_resource_t *glyphs, encoding, char_procs, subset_resource, to_unicode_stream;
5713 cairo_pdf_font_t font;
5714 double *widths;
5715 unsigned int i;
5716 cairo_box_t font_bbox = {{0,0},{0,0}};
5717 cairo_box_t bbox = {{0,0},{0,0}};
5718 cairo_surface_t *type3_surface;
5720 if (font_subset->num_glyphs == 0)
5721 return CAIRO_STATUS_SUCCESS;
5723 subset_resource = _cairo_pdf_surface_get_font_resource (surface,
5724 font_subset->font_id,
5725 font_subset->subset_id);
5726 if (subset_resource.id == 0)
5727 return CAIRO_STATUS_SUCCESS;
5729 glyphs = _cairo_malloc_ab (font_subset->num_glyphs, sizeof (cairo_pdf_resource_t));
5730 if (unlikely (glyphs == NULL))
5731 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5733 widths = _cairo_malloc_ab (font_subset->num_glyphs, sizeof (double));
5734 if (unlikely (widths == NULL)) {
5735 free (glyphs);
5736 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5739 _cairo_pdf_group_resources_clear (&surface->resources);
5740 type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
5741 NULL,
5742 _cairo_pdf_emit_imagemask,
5743 surface->font_subsets,
5744 FALSE);
5745 if (unlikely (type3_surface->status)) {
5746 free (glyphs);
5747 free (widths);
5748 return type3_surface->status;
5751 _cairo_type3_glyph_surface_set_font_subsets_callback (type3_surface,
5752 _cairo_pdf_surface_add_font,
5753 surface);
5755 for (i = 0; i < font_subset->num_glyphs; i++) {
5756 status = _cairo_pdf_surface_open_stream (surface,
5757 NULL,
5758 surface->compress_content,
5759 NULL);
5760 if (unlikely (status))
5761 break;
5763 glyphs[i] = surface->pdf_stream.self;
5764 status = _cairo_type3_glyph_surface_emit_glyph (type3_surface,
5765 surface->output,
5766 font_subset->glyphs[i],
5767 &bbox,
5768 &widths[i]);
5769 if (unlikely (status))
5770 break;
5772 status = _cairo_pdf_surface_close_stream (surface);
5773 if (unlikely (status))
5774 break;
5776 if (i == 0) {
5777 font_bbox.p1.x = bbox.p1.x;
5778 font_bbox.p1.y = bbox.p1.y;
5779 font_bbox.p2.x = bbox.p2.x;
5780 font_bbox.p2.y = bbox.p2.y;
5781 } else {
5782 if (bbox.p1.x < font_bbox.p1.x)
5783 font_bbox.p1.x = bbox.p1.x;
5784 if (bbox.p1.y < font_bbox.p1.y)
5785 font_bbox.p1.y = bbox.p1.y;
5786 if (bbox.p2.x > font_bbox.p2.x)
5787 font_bbox.p2.x = bbox.p2.x;
5788 if (bbox.p2.y > font_bbox.p2.y)
5789 font_bbox.p2.y = bbox.p2.y;
5792 cairo_surface_destroy (type3_surface);
5793 if (unlikely (status)) {
5794 free (glyphs);
5795 free (widths);
5796 return status;
5799 encoding = _cairo_pdf_surface_new_object (surface);
5800 if (encoding.id == 0) {
5801 free (glyphs);
5802 free (widths);
5803 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5806 _cairo_output_stream_printf (surface->output,
5807 "%d 0 obj\n"
5808 "<< /Type /Encoding\n"
5809 " /Differences [0", encoding.id);
5810 for (i = 0; i < font_subset->num_glyphs; i++)
5811 _cairo_output_stream_printf (surface->output,
5812 " /%d", i);
5813 _cairo_output_stream_printf (surface->output,
5814 "]\n"
5815 ">>\n"
5816 "endobj\n");
5818 char_procs = _cairo_pdf_surface_new_object (surface);
5819 if (char_procs.id == 0) {
5820 free (glyphs);
5821 free (widths);
5822 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
5825 _cairo_output_stream_printf (surface->output,
5826 "%d 0 obj\n"
5827 "<<\n", char_procs.id);
5828 for (i = 0; i < font_subset->num_glyphs; i++)
5829 _cairo_output_stream_printf (surface->output,
5830 " /%d %d 0 R\n",
5831 i, glyphs[i].id);
5832 _cairo_output_stream_printf (surface->output,
5833 ">>\n"
5834 "endobj\n");
5836 free (glyphs);
5838 status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
5839 font_subset,
5840 &to_unicode_stream);
5841 if (_cairo_int_status_is_error (status)) {
5842 free (widths);
5843 return status;
5846 _cairo_pdf_surface_update_object (surface, subset_resource);
5847 _cairo_output_stream_printf (surface->output,
5848 "%d 0 obj\n"
5849 "<< /Type /Font\n"
5850 " /Subtype /Type3\n"
5851 " /FontBBox [%f %f %f %f]\n"
5852 " /FontMatrix [ 1 0 0 1 0 0 ]\n"
5853 " /Encoding %d 0 R\n"
5854 " /CharProcs %d 0 R\n"
5855 " /FirstChar 0\n"
5856 " /LastChar %d\n",
5857 subset_resource.id,
5858 _cairo_fixed_to_double (font_bbox.p1.x),
5859 - _cairo_fixed_to_double (font_bbox.p2.y),
5860 _cairo_fixed_to_double (font_bbox.p2.x),
5861 - _cairo_fixed_to_double (font_bbox.p1.y),
5862 encoding.id,
5863 char_procs.id,
5864 font_subset->num_glyphs - 1);
5866 _cairo_output_stream_printf (surface->output,
5867 " /Widths [");
5868 for (i = 0; i < font_subset->num_glyphs; i++)
5869 _cairo_output_stream_printf (surface->output, " %f", widths[i]);
5870 _cairo_output_stream_printf (surface->output,
5871 "]\n");
5872 free (widths);
5874 _cairo_output_stream_printf (surface->output,
5875 " /Resources\n");
5876 _cairo_pdf_surface_emit_group_resources (surface, &surface->resources);
5878 if (to_unicode_stream.id != 0)
5879 _cairo_output_stream_printf (surface->output,
5880 " /ToUnicode %d 0 R\n",
5881 to_unicode_stream.id);
5883 _cairo_output_stream_printf (surface->output,
5884 ">>\n"
5885 "endobj\n");
5887 font.font_id = font_subset->font_id;
5888 font.subset_id = font_subset->subset_id;
5889 font.subset_resource = subset_resource;
5890 return _cairo_array_append (&surface->fonts, &font);
5893 static cairo_int_status_t
5894 _cairo_pdf_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset,
5895 void *closure)
5897 cairo_pdf_surface_t *surface = closure;
5898 cairo_int_status_t status;
5900 status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset);
5901 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
5902 return status;
5904 status = _cairo_pdf_surface_emit_truetype_font_subset (surface, font_subset);
5905 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
5906 return status;
5908 status = _cairo_pdf_surface_emit_type1_font_subset (surface, font_subset);
5909 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
5910 return status;
5912 status = _cairo_pdf_surface_emit_cff_fallback_font (surface, font_subset);
5913 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
5914 return status;
5916 status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset);
5917 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
5918 return status;
5920 ASSERT_NOT_REACHED;
5921 return CAIRO_INT_STATUS_SUCCESS;
5924 static cairo_int_status_t
5925 _cairo_pdf_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset,
5926 void *closure)
5928 cairo_pdf_surface_t *surface = closure;
5929 cairo_int_status_t status;
5931 status = _cairo_pdf_surface_emit_type3_font_subset (surface, font_subset);
5932 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
5933 return status;
5935 ASSERT_NOT_REACHED;
5936 return CAIRO_INT_STATUS_SUCCESS;
5939 static cairo_int_status_t
5940 _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface)
5942 cairo_int_status_t status;
5944 status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
5945 _cairo_pdf_surface_analyze_user_font_subset,
5946 surface);
5947 if (unlikely (status))
5948 goto BAIL;
5950 status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
5951 _cairo_pdf_surface_emit_unscaled_font_subset,
5952 surface);
5953 if (unlikely (status))
5954 goto BAIL;
5956 status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
5957 _cairo_pdf_surface_emit_scaled_font_subset,
5958 surface);
5959 if (unlikely (status))
5960 goto BAIL;
5962 status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
5963 _cairo_pdf_surface_emit_scaled_font_subset,
5964 surface);
5966 BAIL:
5967 _cairo_scaled_font_subsets_destroy (surface->font_subsets);
5968 surface->font_subsets = NULL;
5970 return status;
5973 static cairo_pdf_resource_t
5974 _cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface)
5976 cairo_pdf_resource_t catalog;
5978 catalog = _cairo_pdf_surface_new_object (surface);
5979 if (catalog.id == 0)
5980 return catalog;
5982 _cairo_output_stream_printf (surface->output,
5983 "%d 0 obj\n"
5984 "<< /Type /Catalog\n"
5985 " /Pages %d 0 R\n"
5986 ">>\n"
5987 "endobj\n",
5988 catalog.id,
5989 surface->pages_resource.id);
5991 return catalog;
5994 static long
5995 _cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface)
5997 cairo_pdf_object_t *object;
5998 int num_objects, i;
5999 long offset;
6000 char buffer[11];
6002 num_objects = _cairo_array_num_elements (&surface->objects);
6004 offset = _cairo_output_stream_get_position (surface->output);
6005 _cairo_output_stream_printf (surface->output,
6006 "xref\n"
6007 "%d %d\n",
6008 0, num_objects + 1);
6010 _cairo_output_stream_printf (surface->output,
6011 "0000000000 65535 f \n");
6012 for (i = 0; i < num_objects; i++) {
6013 object = _cairo_array_index (&surface->objects, i);
6014 snprintf (buffer, sizeof buffer, "%010ld", object->offset);
6015 _cairo_output_stream_printf (surface->output,
6016 "%s 00000 n \n", buffer);
6019 return offset;
6022 static cairo_int_status_t
6023 _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
6024 cairo_pdf_smask_group_t *group)
6026 cairo_pdf_resource_t mask_group;
6027 cairo_pdf_resource_t smask;
6028 cairo_pdf_smask_group_t *smask_group;
6029 cairo_pdf_resource_t pattern_res, gstate_res;
6030 cairo_int_status_t status;
6031 cairo_box_double_t bbox;
6033 /* Create mask group */
6034 _get_bbox_from_extents (group->height, &group->extents, &bbox);
6035 status = _cairo_pdf_surface_open_group (surface, &bbox, NULL);
6036 if (unlikely (status))
6037 return status;
6039 if (_can_paint_pattern (group->mask)) {
6040 _cairo_output_stream_printf (surface->output, "q\n");
6041 status = _cairo_pdf_surface_paint_pattern (surface,
6042 CAIRO_OPERATOR_OVER,
6043 group->mask,
6044 &group->extents,
6045 FALSE);
6046 if (unlikely (status))
6047 return status;
6049 _cairo_output_stream_printf (surface->output, "Q\n");
6050 } else {
6051 pattern_res.id = 0;
6052 gstate_res.id = 0;
6053 status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask,
6054 CAIRO_OPERATOR_OVER,
6055 NULL,
6056 &pattern_res, &gstate_res);
6057 if (unlikely (status))
6058 return status;
6060 if (gstate_res.id != 0) {
6061 smask_group = _cairo_pdf_surface_create_smask_group (surface, &group->extents);
6062 if (unlikely (smask_group == NULL))
6063 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
6065 smask_group->width = group->width;
6066 smask_group->height = group->height;
6067 smask_group->operation = PDF_PAINT;
6068 smask_group->source = cairo_pattern_reference (group->mask);
6069 smask_group->source_res = pattern_res;
6070 status = _cairo_pdf_surface_add_smask_group (surface, smask_group);
6071 if (unlikely (status)) {
6072 _cairo_pdf_smask_group_destroy (smask_group);
6073 return status;
6076 status = _cairo_pdf_surface_add_smask (surface, gstate_res);
6077 if (unlikely (status))
6078 return status;
6080 status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res);
6081 if (unlikely (status))
6082 return status;
6084 _cairo_output_stream_printf (surface->output,
6085 "q /s%d gs /x%d Do Q\n",
6086 gstate_res.id,
6087 smask_group->group_res.id);
6088 } else {
6089 status = _cairo_pdf_surface_select_pattern (surface, group->mask, pattern_res, FALSE);
6090 if (unlikely (status))
6091 return status;
6093 _cairo_output_stream_printf (surface->output,
6094 "%f %f %f %f re f\n",
6095 bbox.p1.x,
6096 bbox.p1.y,
6097 bbox.p2.x - bbox.p1.x,
6098 bbox.p2.y - bbox.p1.y);
6100 status = _cairo_pdf_surface_unselect_pattern (surface);
6101 if (unlikely (status))
6102 return status;
6106 status = _cairo_pdf_surface_close_group (surface, &mask_group);
6107 if (unlikely (status))
6108 return status;
6110 /* Create source group */
6111 status = _cairo_pdf_surface_open_group (surface, &bbox, &group->source_res);
6112 if (unlikely (status))
6113 return status;
6115 if (_can_paint_pattern (group->source)) {
6116 _cairo_output_stream_printf (surface->output, "q\n");
6117 status = _cairo_pdf_surface_paint_pattern (surface,
6118 CAIRO_OPERATOR_OVER,
6119 group->source,
6120 &group->extents,
6121 FALSE);
6122 if (unlikely (status))
6123 return status;
6125 _cairo_output_stream_printf (surface->output, "Q\n");
6126 } else {
6127 pattern_res.id = 0;
6128 gstate_res.id = 0;
6129 status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source,
6130 CAIRO_OPERATOR_OVER,
6131 NULL,
6132 &pattern_res, &gstate_res);
6133 if (unlikely (status))
6134 return status;
6136 if (gstate_res.id != 0) {
6137 smask_group = _cairo_pdf_surface_create_smask_group (surface, &group->extents);
6138 if (unlikely (smask_group == NULL))
6139 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
6141 smask_group->operation = PDF_PAINT;
6142 smask_group->source = cairo_pattern_reference (group->source);
6143 smask_group->source_res = pattern_res;
6144 status = _cairo_pdf_surface_add_smask_group (surface, smask_group);
6145 if (unlikely (status)) {
6146 _cairo_pdf_smask_group_destroy (smask_group);
6147 return status;
6150 status = _cairo_pdf_surface_add_smask (surface, gstate_res);
6151 if (unlikely (status))
6152 return status;
6154 status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res);
6155 if (unlikely (status))
6156 return status;
6158 _cairo_output_stream_printf (surface->output,
6159 "q /s%d gs /x%d Do Q\n",
6160 gstate_res.id,
6161 smask_group->group_res.id);
6162 } else {
6163 status = _cairo_pdf_surface_select_pattern (surface, group->source, pattern_res, FALSE);
6164 if (unlikely (status))
6165 return status;
6167 _cairo_output_stream_printf (surface->output,
6168 "%f %f %f %f re f\n",
6169 bbox.p1.x,
6170 bbox.p1.y,
6171 bbox.p2.x - bbox.p1.x,
6172 bbox.p2.y - bbox.p1.y);
6174 status = _cairo_pdf_surface_unselect_pattern (surface);
6175 if (unlikely (status))
6176 return status;
6180 status = _cairo_pdf_surface_close_group (surface, NULL);
6181 if (unlikely (status))
6182 return status;
6184 /* Create an smask based on the alpha component of mask_group */
6185 smask = _cairo_pdf_surface_new_object (surface);
6186 if (smask.id == 0)
6187 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
6189 _cairo_output_stream_printf (surface->output,
6190 "%d 0 obj\n"
6191 "<< /Type /Mask\n"
6192 " /S /Alpha\n"
6193 " /G %d 0 R\n"
6194 ">>\n"
6195 "endobj\n",
6196 smask.id,
6197 mask_group.id);
6199 /* Create a GState that uses the smask */
6200 _cairo_pdf_surface_update_object (surface, group->group_res);
6201 _cairo_output_stream_printf (surface->output,
6202 "%d 0 obj\n"
6203 "<< /Type /ExtGState\n"
6204 " /SMask %d 0 R\n"
6205 " /ca 1\n"
6206 " /CA 1\n"
6207 " /AIS false\n"
6208 ">>\n"
6209 "endobj\n",
6210 group->group_res.id,
6211 smask.id);
6213 return _cairo_output_stream_get_status (surface->output);
6216 static cairo_int_status_t
6217 _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface,
6218 cairo_pdf_smask_group_t *group)
6220 double old_width, old_height;
6221 cairo_int_status_t status;
6222 cairo_box_double_t bbox;
6224 old_width = surface->width;
6225 old_height = surface->height;
6226 _cairo_pdf_surface_set_size_internal (surface,
6227 group->width,
6228 group->height);
6229 /* _mask is a special case that requires two groups - source
6230 * and mask as well as a smask and gstate dictionary */
6231 if (group->operation == PDF_MASK) {
6232 status = _cairo_pdf_surface_write_mask_group (surface, group);
6233 goto RESTORE_SIZE;
6236 _get_bbox_from_extents (group->height, &group->extents, &bbox);
6237 status = _cairo_pdf_surface_open_group (surface, &bbox, &group->group_res);
6238 if (unlikely (status))
6239 return status;
6241 status = _cairo_pdf_surface_select_pattern (surface,
6242 group->source,
6243 group->source_res,
6244 group->operation == PDF_STROKE);
6245 if (unlikely (status))
6246 return status;
6248 switch (group->operation) {
6249 case PDF_PAINT:
6250 _cairo_output_stream_printf (surface->output,
6251 "0 0 %f %f re f\n",
6252 surface->width, surface->height);
6253 break;
6254 case PDF_MASK:
6255 ASSERT_NOT_REACHED;
6256 break;
6257 case PDF_FILL:
6258 status = _cairo_pdf_operators_fill (&surface->pdf_operators,
6259 &group->path,
6260 group->fill_rule);
6261 break;
6262 case PDF_STROKE:
6263 status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
6264 &group->path,
6265 &group->style,
6266 &group->ctm,
6267 &group->ctm_inverse);
6268 break;
6269 case PDF_SHOW_GLYPHS:
6270 status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
6271 group->utf8, group->utf8_len,
6272 group->glyphs, group->num_glyphs,
6273 group->clusters, group->num_clusters,
6274 group->cluster_flags,
6275 group->scaled_font);
6276 break;
6278 if (unlikely (status))
6279 return status;
6281 status = _cairo_pdf_surface_unselect_pattern (surface);
6282 if (unlikely (status))
6283 return status;
6285 status = _cairo_pdf_surface_close_group (surface, NULL);
6287 RESTORE_SIZE:
6288 _cairo_pdf_surface_set_size_internal (surface,
6289 old_width,
6290 old_height);
6292 return status;
6295 static cairo_int_status_t
6296 _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface)
6298 cairo_pdf_pattern_t pattern;
6299 cairo_pdf_smask_group_t *group;
6300 cairo_pdf_source_surface_t src_surface;
6301 unsigned int pattern_index, group_index, surface_index;
6302 cairo_int_status_t status;
6304 /* Writing out PDF_MASK groups will cause additional smask groups
6305 * to be appended to surface->smask_groups. Additional patterns
6306 * may also be appended to surface->patterns.
6308 * Writing recording surface patterns will cause additional patterns
6309 * and groups to be appended.
6311 pattern_index = 0;
6312 group_index = 0;
6313 surface_index = 0;
6314 while ((pattern_index < _cairo_array_num_elements (&surface->page_patterns)) ||
6315 (group_index < _cairo_array_num_elements (&surface->smask_groups)) ||
6316 (surface_index < _cairo_array_num_elements (&surface->page_surfaces)))
6318 for (; group_index < _cairo_array_num_elements (&surface->smask_groups); group_index++) {
6319 _cairo_array_copy_element (&surface->smask_groups, group_index, &group);
6320 status = _cairo_pdf_surface_write_smask_group (surface, group);
6321 if (unlikely (status))
6322 return status;
6325 for (; pattern_index < _cairo_array_num_elements (&surface->page_patterns); pattern_index++) {
6326 _cairo_array_copy_element (&surface->page_patterns, pattern_index, &pattern);
6327 status = _cairo_pdf_surface_emit_pattern (surface, &pattern);
6328 if (unlikely (status))
6329 return status;
6332 for (; surface_index < _cairo_array_num_elements (&surface->page_surfaces); surface_index++) {
6333 _cairo_array_copy_element (&surface->page_surfaces, surface_index, &src_surface);
6334 status = _cairo_pdf_surface_emit_surface (surface, &src_surface);
6335 if (unlikely (status))
6336 return status;
6340 return CAIRO_STATUS_SUCCESS;
6343 static cairo_int_status_t
6344 _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
6346 cairo_pdf_resource_t page, knockout, res;
6347 cairo_int_status_t status;
6348 unsigned int i, len;
6350 _cairo_pdf_group_resources_clear (&surface->resources);
6351 if (surface->has_fallback_images) {
6352 cairo_rectangle_int_t extents;
6353 cairo_box_double_t bbox;
6355 extents.x = 0;
6356 extents.y = 0;
6357 extents.width = ceil (surface->width);
6358 extents.height = ceil (surface->height);
6359 _get_bbox_from_extents (surface->height, &extents, &bbox);
6360 status = _cairo_pdf_surface_open_knockout_group (surface, &bbox);
6361 if (unlikely (status))
6362 return status;
6364 len = _cairo_array_num_elements (&surface->knockout_group);
6365 for (i = 0; i < len; i++) {
6366 _cairo_array_copy_element (&surface->knockout_group, i, &res);
6367 _cairo_output_stream_printf (surface->output,
6368 "/x%d Do\n",
6369 res.id);
6370 status = _cairo_pdf_surface_add_xobject (surface, res);
6371 if (unlikely (status))
6372 return status;
6374 _cairo_output_stream_printf (surface->output,
6375 "/x%d Do\n",
6376 surface->content.id);
6377 status = _cairo_pdf_surface_add_xobject (surface, surface->content);
6378 if (unlikely (status))
6379 return status;
6381 status = _cairo_pdf_surface_close_group (surface, &knockout);
6382 if (unlikely (status))
6383 return status;
6385 _cairo_pdf_group_resources_clear (&surface->resources);
6386 status = _cairo_pdf_surface_open_content_stream (surface, NULL, NULL, FALSE, FALSE);
6387 if (unlikely (status))
6388 return status;
6390 _cairo_output_stream_printf (surface->output,
6391 "/x%d Do\n",
6392 knockout.id);
6393 status = _cairo_pdf_surface_add_xobject (surface, knockout);
6394 if (unlikely (status))
6395 return status;
6397 status = _cairo_pdf_surface_close_content_stream (surface);
6398 if (unlikely (status))
6399 return status;
6402 page = _cairo_pdf_surface_new_object (surface);
6403 if (page.id == 0)
6404 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
6406 _cairo_output_stream_printf (surface->output,
6407 "%d 0 obj\n"
6408 "<< /Type /Page\n"
6409 " /Parent %d 0 R\n"
6410 " /MediaBox [ 0 0 %f %f ]\n"
6411 " /Contents %d 0 R\n"
6412 " /Group <<\n"
6413 " /Type /Group\n"
6414 " /S /Transparency\n"
6415 " /I true\n"
6416 " /CS /DeviceRGB\n"
6417 " >>\n"
6418 " /Resources %d 0 R\n"
6419 ">>\n"
6420 "endobj\n",
6421 page.id,
6422 surface->pages_resource.id,
6423 surface->width,
6424 surface->height,
6425 surface->content.id,
6426 surface->content_resources.id);
6428 status = _cairo_array_append (&surface->pages, &page);
6429 if (unlikely (status))
6430 return status;
6432 status = _cairo_pdf_surface_write_patterns_and_smask_groups (surface);
6433 if (unlikely (status))
6434 return status;
6436 return CAIRO_STATUS_SUCCESS;
6439 static cairo_int_status_t
6440 _cairo_pdf_surface_analyze_surface_pattern_transparency (cairo_pdf_surface_t *surface,
6441 cairo_surface_pattern_t *pattern)
6443 cairo_image_surface_t *image;
6444 void *image_extra;
6445 cairo_int_status_t status;
6446 cairo_image_transparency_t transparency;
6448 status = _cairo_surface_acquire_source_image (pattern->surface,
6449 &image,
6450 &image_extra);
6451 if (unlikely (status))
6452 return status;
6454 if (image->base.status)
6455 return image->base.status;
6457 transparency = _cairo_image_analyze_transparency (image);
6458 if (transparency == CAIRO_IMAGE_IS_OPAQUE)
6459 status = CAIRO_STATUS_SUCCESS;
6460 else
6461 status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
6463 _cairo_surface_release_source_image (pattern->surface, image, image_extra);
6465 return status;
6468 static cairo_bool_t
6469 _surface_pattern_supported (cairo_surface_pattern_t *pattern)
6471 cairo_extend_t extend;
6473 if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
6474 return TRUE;
6476 if (pattern->surface->backend->acquire_source_image == NULL)
6477 return FALSE;
6479 /* Does an ALPHA-only source surface even make sense? Maybe, but I
6480 * don't think it's worth the extra code to support it. */
6482 /* XXX: Need to write this function here...
6483 if (pattern->surface->content == CAIRO_CONTENT_ALPHA)
6484 return FALSE;
6487 extend = cairo_pattern_get_extend (&pattern->base);
6488 switch (extend) {
6489 case CAIRO_EXTEND_NONE:
6490 case CAIRO_EXTEND_REPEAT:
6491 case CAIRO_EXTEND_REFLECT:
6492 /* There's no point returning FALSE for EXTEND_PAD, as the image
6493 * surface does not currently implement it either */
6494 case CAIRO_EXTEND_PAD:
6495 return TRUE;
6498 ASSERT_NOT_REACHED;
6499 return FALSE;
6502 static cairo_bool_t
6503 _pattern_supported (const cairo_pattern_t *pattern)
6505 switch (pattern->type) {
6506 case CAIRO_PATTERN_TYPE_SOLID:
6507 case CAIRO_PATTERN_TYPE_LINEAR:
6508 case CAIRO_PATTERN_TYPE_RADIAL:
6509 case CAIRO_PATTERN_TYPE_MESH:
6510 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
6511 return TRUE;
6513 case CAIRO_PATTERN_TYPE_SURFACE:
6514 return _surface_pattern_supported ((cairo_surface_pattern_t *) pattern);
6516 default:
6517 ASSERT_NOT_REACHED;
6518 return FALSE;
6522 static cairo_bool_t
6523 _pdf_operator_supported (cairo_operator_t op)
6525 switch (op) {
6526 case CAIRO_OPERATOR_OVER:
6527 case CAIRO_OPERATOR_MULTIPLY:
6528 case CAIRO_OPERATOR_SCREEN:
6529 case CAIRO_OPERATOR_OVERLAY:
6530 case CAIRO_OPERATOR_DARKEN:
6531 case CAIRO_OPERATOR_LIGHTEN:
6532 case CAIRO_OPERATOR_COLOR_DODGE:
6533 case CAIRO_OPERATOR_COLOR_BURN:
6534 case CAIRO_OPERATOR_HARD_LIGHT:
6535 case CAIRO_OPERATOR_SOFT_LIGHT:
6536 case CAIRO_OPERATOR_DIFFERENCE:
6537 case CAIRO_OPERATOR_EXCLUSION:
6538 case CAIRO_OPERATOR_HSL_HUE:
6539 case CAIRO_OPERATOR_HSL_SATURATION:
6540 case CAIRO_OPERATOR_HSL_COLOR:
6541 case CAIRO_OPERATOR_HSL_LUMINOSITY:
6542 return TRUE;
6544 default:
6545 case CAIRO_OPERATOR_CLEAR:
6546 case CAIRO_OPERATOR_SOURCE:
6547 case CAIRO_OPERATOR_IN:
6548 case CAIRO_OPERATOR_OUT:
6549 case CAIRO_OPERATOR_ATOP:
6550 case CAIRO_OPERATOR_DEST:
6551 case CAIRO_OPERATOR_DEST_OVER:
6552 case CAIRO_OPERATOR_DEST_IN:
6553 case CAIRO_OPERATOR_DEST_OUT:
6554 case CAIRO_OPERATOR_DEST_ATOP:
6555 case CAIRO_OPERATOR_XOR:
6556 case CAIRO_OPERATOR_ADD:
6557 case CAIRO_OPERATOR_SATURATE:
6558 return FALSE;
6562 static cairo_int_status_t
6563 _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
6564 cairo_operator_t op,
6565 const cairo_pattern_t *pattern,
6566 const cairo_rectangle_int_t *extents)
6568 if (surface->force_fallbacks &&
6569 surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
6571 return CAIRO_INT_STATUS_UNSUPPORTED;
6574 if (! _pattern_supported (pattern))
6575 return CAIRO_INT_STATUS_UNSUPPORTED;
6577 if (_pdf_operator_supported (op)) {
6578 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
6579 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
6581 if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
6582 if (pattern->extend == CAIRO_EXTEND_PAD) {
6583 cairo_box_t box;
6584 cairo_rectangle_int_t rect;
6585 cairo_rectangle_int_t rec_extents;
6587 /* get the operation extents in pattern space */
6588 _cairo_box_from_rectangle (&box, extents);
6589 _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &box, NULL);
6590 _cairo_box_round_to_rectangle (&box, &rect);
6592 /* Check if surface needs padding to fill extents */
6593 if (_cairo_surface_get_extents (surface_pattern->surface, &rec_extents)) {
6594 if (_cairo_fixed_integer_ceil(box.p1.x) < rec_extents.x ||
6595 _cairo_fixed_integer_ceil(box.p1.y) < rec_extents.y ||
6596 _cairo_fixed_integer_floor(box.p2.y) > rec_extents.x + rec_extents.width ||
6597 _cairo_fixed_integer_floor(box.p2.y) > rec_extents.y + rec_extents.height)
6599 return CAIRO_INT_STATUS_UNSUPPORTED;
6603 return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
6607 return CAIRO_STATUS_SUCCESS;
6611 /* The SOURCE operator is supported if the pattern is opaque or if
6612 * there is nothing painted underneath. */
6613 if (op == CAIRO_OPERATOR_SOURCE) {
6614 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
6615 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
6617 if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
6618 if (_cairo_pattern_is_opaque (pattern, extents)) {
6619 return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
6620 } else {
6621 /* FIXME: The analysis surface does not yet have
6622 * the capability to analyze a non opaque recording
6623 * surface and mark it supported if there is
6624 * nothing underneath. For now recording surfaces of
6625 * type CONTENT_COLOR_ALPHA painted with
6626 * OPERATOR_SOURCE will result in a fallback
6627 * image. */
6629 return CAIRO_INT_STATUS_UNSUPPORTED;
6631 } else {
6632 return _cairo_pdf_surface_analyze_surface_pattern_transparency (surface,
6633 surface_pattern);
6637 if (_cairo_pattern_is_opaque (pattern, extents))
6638 return CAIRO_STATUS_SUCCESS;
6639 else
6640 return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
6643 return CAIRO_INT_STATUS_UNSUPPORTED;
6646 static cairo_bool_t
6647 _cairo_pdf_surface_operation_supported (cairo_pdf_surface_t *surface,
6648 cairo_operator_t op,
6649 const cairo_pattern_t *pattern,
6650 const cairo_rectangle_int_t *extents)
6652 return _cairo_pdf_surface_analyze_operation (surface, op, pattern, extents) != CAIRO_INT_STATUS_UNSUPPORTED;
6655 static cairo_int_status_t
6656 _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
6658 cairo_box_double_t bbox;
6659 cairo_int_status_t status;
6661 status = _cairo_pdf_surface_close_content_stream (surface);
6662 if (unlikely (status))
6663 return status;
6665 status = _cairo_array_append (&surface->knockout_group, &surface->content);
6666 if (unlikely (status))
6667 return status;
6669 _cairo_pdf_group_resources_clear (&surface->resources);
6670 bbox.p1.x = 0;
6671 bbox.p1.y = 0;
6672 bbox.p2.x = surface->width;
6673 bbox.p2.y = surface->height;
6674 return _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, TRUE, TRUE);
6677 /* If source is an opaque image and mask is an image and both images
6678 * have the same bounding box we can emit them as a image/smask pair.
6680 static cairo_int_status_t
6681 _cairo_pdf_surface_emit_combined_smask (cairo_pdf_surface_t *surface,
6682 cairo_operator_t op,
6683 const cairo_pattern_t *source,
6684 const cairo_pattern_t *mask,
6685 const cairo_rectangle_int_t *extents)
6687 cairo_int_status_t status;
6688 cairo_image_surface_t *image;
6689 void *image_extra;
6690 cairo_image_transparency_t transparency;
6691 cairo_pdf_resource_t smask_res;
6692 int src_width, src_height;
6693 int mask_width, mask_height;
6694 double src_x_offset, src_y_offset;
6695 double mask_x_offset, mask_y_offset;
6696 double src_x1, src_y1, src_x2, src_y2;
6697 double mask_x1, mask_y1, mask_x2, mask_y2;
6698 cairo_matrix_t p2u;
6699 double src_radius, mask_radius, e;
6700 cairo_rectangle_int_t extents2;
6701 cairo_bool_t need_smask;
6703 /* Check that source and mask are images */
6705 if (!((source->type == CAIRO_PATTERN_TYPE_SURFACE || source->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) &&
6706 (mask->type == CAIRO_PATTERN_TYPE_SURFACE || mask->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)))
6707 return CAIRO_INT_STATUS_UNSUPPORTED;
6709 if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
6710 ((cairo_surface_pattern_t *) source)->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
6712 return CAIRO_INT_STATUS_UNSUPPORTED;
6715 if (mask->type == CAIRO_PATTERN_TYPE_SURFACE &&
6716 ((cairo_surface_pattern_t *) mask)->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
6718 return CAIRO_INT_STATUS_UNSUPPORTED;
6721 if (source->extend != CAIRO_EXTEND_NONE || mask->extend != CAIRO_EXTEND_NONE)
6722 return CAIRO_INT_STATUS_UNSUPPORTED;
6724 /* Check that source is opaque and get image sizes */
6726 status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, source,
6727 &image, &image_extra);
6728 if (unlikely (status))
6729 return status;
6731 if (image->base.status)
6732 return image->base.status;
6734 src_width = image->width;
6735 src_height = image->height;
6736 if (source->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
6737 cairo_surface_get_device_offset (&image->base, &src_x_offset, &src_y_offset);
6738 } else {
6739 src_x_offset = 0;
6740 src_y_offset = 0;
6743 transparency = _cairo_image_analyze_transparency (image);
6744 _cairo_pdf_surface_release_source_image_from_pattern (surface, source, image, image_extra);
6746 if (transparency != CAIRO_IMAGE_IS_OPAQUE)
6747 return CAIRO_INT_STATUS_UNSUPPORTED;
6749 status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, mask,
6750 &image, &image_extra);
6751 if (unlikely (status))
6752 return status;
6754 if (image->base.status)
6755 return image->base.status;
6757 mask_width = image->width;
6758 mask_height = image->height;
6759 if (mask->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
6760 cairo_surface_get_device_offset (&image->base, &mask_x_offset, &mask_y_offset);
6761 } else {
6762 mask_x_offset = 0;
6763 mask_y_offset = 0;
6766 transparency = _cairo_image_analyze_transparency (image);
6767 need_smask = transparency != CAIRO_IMAGE_IS_OPAQUE;
6769 _cairo_pdf_surface_release_source_image_from_pattern (surface, mask, image, image_extra);
6771 /* Check that both images have the same extents with a tolerance
6772 * of half the smallest source pixel. */
6774 p2u = source->matrix;
6775 status = cairo_matrix_invert (&p2u);
6776 /* cairo_pattern_set_matrix ensures the matrix is invertible */
6777 assert (status == CAIRO_INT_STATUS_SUCCESS);
6778 src_x1 = 0;
6779 src_y1 = 0;
6780 src_x2 = src_width;
6781 src_y2 = src_height;
6782 cairo_matrix_transform_point (&p2u, &src_x1, &src_y1);
6783 cairo_matrix_transform_point (&p2u, &src_x2, &src_y2);
6784 src_radius = _cairo_matrix_transformed_circle_major_axis (&p2u, 0.5);
6786 p2u = mask->matrix;
6787 status = cairo_matrix_invert (&p2u);
6788 /* cairo_pattern_set_matrix ensures the matrix is invertible */
6789 assert (status == CAIRO_INT_STATUS_SUCCESS);
6790 mask_x1 = 0;
6791 mask_y1 = 0;
6792 mask_x2 = mask_width;
6793 mask_y2 = mask_height;
6794 cairo_matrix_transform_point (&p2u, &mask_x1, &mask_y1);
6795 cairo_matrix_transform_point (&p2u, &mask_x2, &mask_y2);
6796 mask_radius = _cairo_matrix_transformed_circle_major_axis (&p2u, 0.5);
6798 if (src_radius < mask_radius)
6799 e = src_radius;
6800 else
6801 e = mask_radius;
6803 if (fabs(src_x1 - mask_x1) > e ||
6804 fabs(src_x2 - mask_x2) > e ||
6805 fabs(src_y1 - mask_y1) > e ||
6806 fabs(src_y2 - mask_y2) > e)
6807 return CAIRO_INT_STATUS_UNSUPPORTED;
6809 /* Check both images have same device offset */
6810 if (fabs(src_x_offset - mask_x_offset) > e ||
6811 fabs(src_y_offset - mask_y_offset) > e)
6812 return CAIRO_INT_STATUS_UNSUPPORTED;
6814 if (need_smask) {
6815 status = _cairo_pdf_surface_add_source_surface (surface,
6816 NULL,
6817 mask,
6819 source->filter,
6820 FALSE,
6821 TRUE,
6822 extents,
6823 NULL,
6824 &smask_res,
6825 &mask_width,
6826 &mask_height,
6827 &mask_x_offset,
6828 &mask_y_offset,
6829 &extents2);
6830 if (unlikely (status))
6831 return status;
6834 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
6835 if (unlikely (status))
6836 return status;
6838 _cairo_output_stream_printf (surface->output, "q\n");
6839 status = _cairo_pdf_surface_paint_surface_pattern (surface, op, source, extents,
6840 need_smask ? &smask_res : NULL,
6841 FALSE);
6842 if (unlikely (status))
6843 return status;
6845 _cairo_output_stream_printf (surface->output, "Q\n");
6847 status = _cairo_output_stream_get_status (surface->output);
6850 return status;
6853 /* A PDF stencil mask is an A1 mask used with the current color */
6854 static cairo_int_status_t
6855 _cairo_pdf_surface_emit_stencil_mask (cairo_pdf_surface_t *surface,
6856 cairo_operator_t op,
6857 const cairo_pattern_t *source,
6858 const cairo_pattern_t *mask,
6859 const cairo_rectangle_int_t *extents)
6861 cairo_int_status_t status;
6862 cairo_image_surface_t *image;
6863 void *image_extra;
6864 cairo_image_transparency_t transparency;
6865 cairo_pdf_resource_t pattern_res = {0};
6867 if (! (source->type == CAIRO_PATTERN_TYPE_SOLID &&
6868 (mask->type == CAIRO_PATTERN_TYPE_SURFACE || mask->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)))
6869 return CAIRO_INT_STATUS_UNSUPPORTED;
6871 if (mask->type == CAIRO_PATTERN_TYPE_SURFACE &&
6872 ((cairo_surface_pattern_t *) mask)->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
6874 return CAIRO_INT_STATUS_UNSUPPORTED;
6877 status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, mask,
6878 &image, &image_extra);
6879 if (unlikely (status))
6880 return status;
6882 if (image->base.status)
6883 return image->base.status;
6885 transparency = _cairo_image_analyze_transparency (image);
6886 if (transparency != CAIRO_IMAGE_IS_OPAQUE &&
6887 transparency != CAIRO_IMAGE_HAS_BILEVEL_ALPHA)
6889 status = CAIRO_INT_STATUS_UNSUPPORTED;
6890 goto cleanup;
6893 status = _cairo_pdf_surface_select_pattern (surface, source,
6894 pattern_res, FALSE);
6895 if (unlikely (status))
6896 return status;
6898 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
6899 if (unlikely (status))
6900 return status;
6902 _cairo_output_stream_printf (surface->output, "q\n");
6903 status = _cairo_pdf_surface_paint_surface_pattern (surface, op, mask, extents, NULL, TRUE);
6904 if (unlikely (status))
6905 return status;
6907 _cairo_output_stream_printf (surface->output, "Q\n");
6909 status = _cairo_output_stream_get_status (surface->output);
6911 cleanup:
6912 _cairo_pdf_surface_release_source_image_from_pattern (surface, mask, image, image_extra);
6914 return status;
6917 static cairo_int_status_t
6918 _cairo_pdf_surface_set_clip (cairo_pdf_surface_t *surface,
6919 cairo_composite_rectangles_t *composite)
6921 cairo_clip_t *clip = composite->clip;
6923 if (_cairo_composite_rectangles_can_reduce_clip (composite, clip))
6924 clip = NULL;
6926 if (clip == NULL) {
6927 if (_cairo_composite_rectangles_can_reduce_clip (composite,
6928 surface->clipper.clip))
6929 return CAIRO_STATUS_SUCCESS;
6932 return _cairo_surface_clipper_set_clip (&surface->clipper, clip);
6935 static cairo_int_status_t
6936 _cairo_pdf_surface_paint (void *abstract_surface,
6937 cairo_operator_t op,
6938 const cairo_pattern_t *source,
6939 const cairo_clip_t *clip)
6941 cairo_pdf_surface_t *surface = abstract_surface;
6942 cairo_pdf_smask_group_t *group;
6943 cairo_pdf_resource_t pattern_res, gstate_res;
6944 cairo_composite_rectangles_t extents;
6945 cairo_int_status_t status;
6947 status = _cairo_composite_rectangles_init_for_paint (&extents,
6948 &surface->base,
6949 op, source, clip);
6950 if (unlikely (status))
6951 return status;
6953 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
6954 status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
6955 goto cleanup;
6956 } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
6957 status = _cairo_pdf_surface_start_fallback (surface);
6958 if (unlikely (status))
6959 goto cleanup;
6962 assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
6964 status = _cairo_pdf_surface_set_clip (surface, &extents);
6965 if (unlikely (status))
6966 goto cleanup;
6968 status = _cairo_pdf_surface_select_operator (surface, op);
6969 if (unlikely (status))
6970 goto cleanup;
6972 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
6973 if (unlikely (status))
6974 goto cleanup;
6976 if (_can_paint_pattern (source)) {
6977 _cairo_output_stream_printf (surface->output, "q\n");
6978 status = _cairo_pdf_surface_paint_pattern (surface,
6980 source,
6981 &extents.bounded,
6982 FALSE);
6983 if (unlikely (status))
6984 goto cleanup;
6986 _cairo_output_stream_printf (surface->output, "Q\n");
6987 _cairo_composite_rectangles_fini (&extents);
6988 return _cairo_output_stream_get_status (surface->output);
6991 pattern_res.id = 0;
6992 gstate_res.id = 0;
6993 status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op,
6994 &extents.bounded,
6995 &pattern_res, &gstate_res);
6996 if (unlikely (status))
6997 goto cleanup;
6999 if (gstate_res.id != 0) {
7000 group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded);
7001 if (unlikely (group == NULL)) {
7002 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
7003 goto cleanup;
7006 group->operation = PDF_PAINT;
7007 status = _cairo_pattern_create_copy (&group->source, source);
7008 if (unlikely (status)) {
7009 _cairo_pdf_smask_group_destroy (group);
7010 goto cleanup;
7012 group->source_res = pattern_res;
7013 status = _cairo_pdf_surface_add_smask_group (surface, group);
7014 if (unlikely (status)) {
7015 _cairo_pdf_smask_group_destroy (group);
7016 goto cleanup;
7019 status = _cairo_pdf_surface_add_smask (surface, gstate_res);
7020 if (unlikely (status))
7021 goto cleanup;
7023 status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
7024 if (unlikely (status))
7025 goto cleanup;
7027 _cairo_output_stream_printf (surface->output,
7028 "q /s%d gs /x%d Do Q\n",
7029 gstate_res.id,
7030 group->group_res.id);
7031 } else {
7032 status = _cairo_pdf_surface_select_pattern (surface, source,
7033 pattern_res, FALSE);
7034 if (unlikely (status))
7035 goto cleanup;
7037 _cairo_output_stream_printf (surface->output,
7038 "0 0 %f %f re f\n",
7039 surface->width, surface->height);
7041 status = _cairo_pdf_surface_unselect_pattern (surface);
7042 if (unlikely (status))
7043 goto cleanup;
7046 _cairo_composite_rectangles_fini (&extents);
7047 return _cairo_output_stream_get_status (surface->output);
7049 cleanup:
7050 _cairo_composite_rectangles_fini (&extents);
7051 return status;
7054 static cairo_int_status_t
7055 _cairo_pdf_surface_mask (void *abstract_surface,
7056 cairo_operator_t op,
7057 const cairo_pattern_t *source,
7058 const cairo_pattern_t *mask,
7059 const cairo_clip_t *clip)
7061 cairo_pdf_surface_t *surface = abstract_surface;
7062 cairo_pdf_smask_group_t *group;
7063 cairo_composite_rectangles_t extents;
7064 cairo_int_status_t status;
7065 cairo_rectangle_int_t r;
7066 cairo_box_t box;
7068 status = _cairo_composite_rectangles_init_for_mask (&extents,
7069 &surface->base,
7070 op, source, mask, clip);
7071 if (unlikely (status))
7072 return status;
7074 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
7075 cairo_int_status_t source_status, mask_status;
7077 status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
7078 if (_cairo_int_status_is_error (status))
7079 goto cleanup;
7080 source_status = status;
7082 if (mask->has_component_alpha) {
7083 status = CAIRO_INT_STATUS_UNSUPPORTED;
7084 } else {
7085 status = _cairo_pdf_surface_analyze_operation (surface, op, mask, &extents.bounded);
7086 if (_cairo_int_status_is_error (status))
7087 goto cleanup;
7089 mask_status = status;
7091 _cairo_composite_rectangles_fini (&extents);
7092 return _cairo_analysis_surface_merge_status (source_status,
7093 mask_status);
7094 } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
7095 status = _cairo_pdf_surface_start_fallback (surface);
7096 if (unlikely (status))
7097 goto cleanup;
7100 assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
7101 assert (_cairo_pdf_surface_operation_supported (surface, op, mask, &extents.bounded));
7103 /* get the accurate extents */
7104 status = _cairo_pattern_get_ink_extents (source, &r);
7105 if (unlikely (status))
7106 goto cleanup;
7108 /* XXX slight impedance mismatch */
7109 _cairo_box_from_rectangle (&box, &r);
7110 status = _cairo_composite_rectangles_intersect_source_extents (&extents,
7111 &box);
7112 if (unlikely (status))
7113 goto cleanup;
7115 status = _cairo_pattern_get_ink_extents (mask, &r);
7116 if (unlikely (status))
7117 goto cleanup;
7119 _cairo_box_from_rectangle (&box, &r);
7120 status = _cairo_composite_rectangles_intersect_mask_extents (&extents,
7121 &box);
7122 if (unlikely (status))
7123 goto cleanup;
7125 status = _cairo_pdf_surface_set_clip (surface, &extents);
7126 if (unlikely (status))
7127 goto cleanup;
7129 status = _cairo_pdf_surface_select_operator (surface, op);
7130 if (unlikely (status))
7131 goto cleanup;
7133 /* Check if we can combine source and mask into a smask image */
7134 status = _cairo_pdf_surface_emit_combined_smask (surface, op, source, mask, &extents.bounded);
7135 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
7136 goto cleanup;
7138 /* Check if we can use a stencil mask */
7139 status = _cairo_pdf_surface_emit_stencil_mask (surface, op, source, mask, &extents.bounded);
7140 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
7141 goto cleanup;
7143 group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded);
7144 if (unlikely (group == NULL)) {
7145 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
7146 goto cleanup;
7149 group->operation = PDF_MASK;
7150 status = _cairo_pattern_create_copy (&group->source, source);
7151 if (unlikely (status)) {
7152 _cairo_pdf_smask_group_destroy (group);
7153 goto cleanup;
7155 status = _cairo_pattern_create_copy (&group->mask, mask);
7156 if (unlikely (status)) {
7157 _cairo_pdf_smask_group_destroy (group);
7158 goto cleanup;
7160 group->source_res = _cairo_pdf_surface_new_object (surface);
7161 if (group->source_res.id == 0) {
7162 _cairo_pdf_smask_group_destroy (group);
7163 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
7164 goto cleanup;
7167 status = _cairo_pdf_surface_add_smask_group (surface, group);
7168 if (unlikely (status)) {
7169 _cairo_pdf_smask_group_destroy (group);
7170 goto cleanup;
7173 status = _cairo_pdf_surface_add_smask (surface, group->group_res);
7174 if (unlikely (status))
7175 goto cleanup;
7177 status = _cairo_pdf_surface_add_xobject (surface, group->source_res);
7178 if (unlikely (status))
7179 goto cleanup;
7181 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
7182 if (unlikely (status))
7183 goto cleanup;
7185 _cairo_output_stream_printf (surface->output,
7186 "q /s%d gs /x%d Do Q\n",
7187 group->group_res.id,
7188 group->source_res.id);
7190 _cairo_composite_rectangles_fini (&extents);
7191 return _cairo_output_stream_get_status (surface->output);
7193 cleanup:
7194 _cairo_composite_rectangles_fini (&extents);
7195 return status;
7198 static cairo_int_status_t
7199 _cairo_pdf_surface_stroke (void *abstract_surface,
7200 cairo_operator_t op,
7201 const cairo_pattern_t *source,
7202 const cairo_path_fixed_t *path,
7203 const cairo_stroke_style_t *style,
7204 const cairo_matrix_t *ctm,
7205 const cairo_matrix_t *ctm_inverse,
7206 double tolerance,
7207 cairo_antialias_t antialias,
7208 const cairo_clip_t *clip)
7210 cairo_pdf_surface_t *surface = abstract_surface;
7211 cairo_pdf_smask_group_t *group;
7212 cairo_pdf_resource_t pattern_res, gstate_res;
7213 cairo_composite_rectangles_t extents;
7214 cairo_int_status_t status;
7216 status = _cairo_composite_rectangles_init_for_stroke (&extents,
7217 &surface->base,
7218 op, source,
7219 path, style, ctm,
7220 clip);
7221 if (unlikely (status))
7222 return status;
7224 /* use the more accurate extents */
7225 if (extents.is_bounded) {
7226 cairo_rectangle_int_t mask;
7227 cairo_box_t box;
7229 status = _cairo_path_fixed_stroke_extents (path, style,
7230 ctm, ctm_inverse,
7231 tolerance,
7232 &mask);
7233 if (unlikely (status))
7234 goto cleanup;
7236 _cairo_box_from_rectangle (&box, &mask);
7237 status = _cairo_composite_rectangles_intersect_mask_extents (&extents,
7238 &box);
7239 if (unlikely (status))
7240 goto cleanup;
7243 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
7244 status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
7245 goto cleanup;
7248 assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
7250 status = _cairo_pdf_surface_set_clip (surface, &extents);
7251 if (unlikely (status))
7252 goto cleanup;
7254 pattern_res.id = 0;
7255 gstate_res.id = 0;
7256 status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op,
7257 &extents.bounded,
7258 &pattern_res, &gstate_res);
7259 if (unlikely (status))
7260 goto cleanup;
7262 status = _cairo_pdf_surface_select_operator (surface, op);
7263 if (unlikely (status))
7264 goto cleanup;
7266 if (gstate_res.id != 0) {
7267 group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded);
7268 if (unlikely (group == NULL)) {
7269 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
7270 goto cleanup;
7273 group->operation = PDF_STROKE;
7274 status = _cairo_pattern_create_copy (&group->source, source);
7275 if (unlikely (status)) {
7276 _cairo_pdf_smask_group_destroy (group);
7277 goto cleanup;
7279 group->source_res = pattern_res;
7280 status = _cairo_path_fixed_init_copy (&group->path, path);
7281 if (unlikely (status)) {
7282 _cairo_pdf_smask_group_destroy (group);
7283 goto cleanup;
7286 group->style = *style;
7287 group->ctm = *ctm;
7288 group->ctm_inverse = *ctm_inverse;
7289 status = _cairo_pdf_surface_add_smask_group (surface, group);
7290 if (unlikely (status)) {
7291 _cairo_pdf_smask_group_destroy (group);
7292 goto cleanup;
7295 status = _cairo_pdf_surface_add_smask (surface, gstate_res);
7296 if (unlikely (status))
7297 goto cleanup;
7299 status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
7300 if (unlikely (status))
7301 goto cleanup;
7303 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
7304 if (unlikely (status))
7305 goto cleanup;
7307 _cairo_output_stream_printf (surface->output,
7308 "q /s%d gs /x%d Do Q\n",
7309 gstate_res.id,
7310 group->group_res.id);
7311 } else {
7312 status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, TRUE);
7313 if (unlikely (status))
7314 goto cleanup;
7316 status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
7317 path,
7318 style,
7319 ctm,
7320 ctm_inverse);
7321 if (unlikely (status))
7322 goto cleanup;
7324 status = _cairo_pdf_surface_unselect_pattern (surface);
7325 if (unlikely (status))
7326 goto cleanup;
7329 _cairo_composite_rectangles_fini (&extents);
7330 return _cairo_output_stream_get_status (surface->output);
7332 cleanup:
7333 _cairo_composite_rectangles_fini (&extents);
7334 return status;
7337 static cairo_int_status_t
7338 _cairo_pdf_surface_fill (void *abstract_surface,
7339 cairo_operator_t op,
7340 const cairo_pattern_t *source,
7341 const cairo_path_fixed_t*path,
7342 cairo_fill_rule_t fill_rule,
7343 double tolerance,
7344 cairo_antialias_t antialias,
7345 const cairo_clip_t *clip)
7347 cairo_pdf_surface_t *surface = abstract_surface;
7348 cairo_int_status_t status;
7349 cairo_pdf_smask_group_t *group;
7350 cairo_pdf_resource_t pattern_res, gstate_res;
7351 cairo_composite_rectangles_t extents;
7353 status = _cairo_composite_rectangles_init_for_fill (&extents,
7354 &surface->base,
7355 op, source, path,
7356 clip);
7357 if (unlikely (status))
7358 return status;
7360 /* use the more accurate extents */
7361 if (extents.is_bounded) {
7362 cairo_rectangle_int_t mask;
7363 cairo_box_t box;
7365 _cairo_path_fixed_fill_extents (path,
7366 fill_rule,
7367 tolerance,
7368 &mask);
7370 _cairo_box_from_rectangle (&box, &mask);
7371 status = _cairo_composite_rectangles_intersect_mask_extents (&extents,
7372 &box);
7373 if (unlikely (status))
7374 goto cleanup;
7377 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
7378 status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
7379 goto cleanup;
7380 } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
7381 status = _cairo_pdf_surface_start_fallback (surface);
7382 if (unlikely (status))
7383 goto cleanup;
7386 assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
7388 status = _cairo_pdf_surface_set_clip (surface, &extents);
7389 if (unlikely (status))
7390 goto cleanup;
7392 status = _cairo_pdf_surface_select_operator (surface, op);
7393 if (unlikely (status))
7394 goto cleanup;
7396 if (_can_paint_pattern (source)) {
7397 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
7398 if (unlikely (status))
7399 goto cleanup;
7401 _cairo_output_stream_printf (surface->output, "q\n");
7402 status = _cairo_pdf_operators_clip (&surface->pdf_operators,
7403 path,
7404 fill_rule);
7405 if (unlikely (status))
7406 goto cleanup;
7408 status = _cairo_pdf_surface_paint_pattern (surface,
7410 source,
7411 &extents.bounded,
7412 FALSE);
7413 if (unlikely (status))
7414 goto cleanup;
7416 _cairo_output_stream_printf (surface->output, "Q\n");
7417 status = _cairo_output_stream_get_status (surface->output);
7418 goto cleanup;
7421 pattern_res.id = 0;
7422 gstate_res.id = 0;
7423 status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op,
7424 &extents.bounded,
7425 &pattern_res, &gstate_res);
7426 if (unlikely (status))
7427 goto cleanup;
7429 if (gstate_res.id != 0) {
7430 group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded);
7431 if (unlikely (group == NULL)) {
7432 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
7433 goto cleanup;
7436 group->operation = PDF_FILL;
7437 status = _cairo_pattern_create_copy (&group->source, source);
7438 if (unlikely (status)) {
7439 _cairo_pdf_smask_group_destroy (group);
7440 goto cleanup;
7442 group->source_res = pattern_res;
7443 status = _cairo_path_fixed_init_copy (&group->path, path);
7444 if (unlikely (status)) {
7445 _cairo_pdf_smask_group_destroy (group);
7446 goto cleanup;
7449 group->fill_rule = fill_rule;
7450 status = _cairo_pdf_surface_add_smask_group (surface, group);
7451 if (unlikely (status)) {
7452 _cairo_pdf_smask_group_destroy (group);
7453 goto cleanup;
7456 status = _cairo_pdf_surface_add_smask (surface, gstate_res);
7457 if (unlikely (status))
7458 goto cleanup;
7460 status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
7461 if (unlikely (status))
7462 goto cleanup;
7464 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
7465 if (unlikely (status))
7466 goto cleanup;
7468 _cairo_output_stream_printf (surface->output,
7469 "q /s%d gs /x%d Do Q\n",
7470 gstate_res.id,
7471 group->group_res.id);
7472 } else {
7473 status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
7474 if (unlikely (status))
7475 goto cleanup;
7477 status = _cairo_pdf_operators_fill (&surface->pdf_operators,
7478 path,
7479 fill_rule);
7480 if (unlikely (status))
7481 goto cleanup;
7483 status = _cairo_pdf_surface_unselect_pattern (surface);
7484 if (unlikely (status))
7485 goto cleanup;
7488 _cairo_composite_rectangles_fini (&extents);
7489 return _cairo_output_stream_get_status (surface->output);
7491 cleanup:
7492 _cairo_composite_rectangles_fini (&extents);
7493 return status;
7496 static cairo_int_status_t
7497 _cairo_pdf_surface_fill_stroke (void *abstract_surface,
7498 cairo_operator_t fill_op,
7499 const cairo_pattern_t *fill_source,
7500 cairo_fill_rule_t fill_rule,
7501 double fill_tolerance,
7502 cairo_antialias_t fill_antialias,
7503 const cairo_path_fixed_t*path,
7504 cairo_operator_t stroke_op,
7505 const cairo_pattern_t *stroke_source,
7506 const cairo_stroke_style_t *stroke_style,
7507 const cairo_matrix_t *stroke_ctm,
7508 const cairo_matrix_t *stroke_ctm_inverse,
7509 double stroke_tolerance,
7510 cairo_antialias_t stroke_antialias,
7511 const cairo_clip_t *clip)
7513 cairo_pdf_surface_t *surface = abstract_surface;
7514 cairo_int_status_t status;
7515 cairo_pdf_resource_t fill_pattern_res, stroke_pattern_res, gstate_res;
7516 cairo_composite_rectangles_t extents;
7518 /* During analysis we return unsupported and let the _fill and
7519 * _stroke functions that are on the fallback path do the analysis
7520 * for us. During render we may still encounter unsupported
7521 * combinations of fill/stroke patterns. However we can return
7522 * unsupported anytime to let the _fill and _stroke functions take
7523 * over.
7525 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
7526 return CAIRO_INT_STATUS_UNSUPPORTED;
7528 /* PDF rendering of fill-stroke is not the same as cairo when
7529 * either the fill or stroke is not opaque.
7531 if ( !_cairo_pattern_is_opaque (fill_source, NULL) ||
7532 !_cairo_pattern_is_opaque (stroke_source, NULL))
7534 return CAIRO_INT_STATUS_UNSUPPORTED;
7537 if (fill_op != stroke_op)
7538 return CAIRO_INT_STATUS_UNSUPPORTED;
7540 /* Compute the operation extents using the stroke which will naturally
7541 * be larger than the fill extents.
7543 status = _cairo_composite_rectangles_init_for_stroke (&extents,
7544 &surface->base,
7545 stroke_op, stroke_source,
7546 path, stroke_style, stroke_ctm,
7547 clip);
7548 if (unlikely (status))
7549 return status;
7551 /* use the more accurate extents */
7552 if (extents.is_bounded) {
7553 cairo_rectangle_int_t mask;
7554 cairo_box_t box;
7556 status = _cairo_path_fixed_stroke_extents (path, stroke_style,
7557 stroke_ctm, stroke_ctm_inverse,
7558 stroke_tolerance,
7559 &mask);
7560 if (unlikely (status))
7561 goto cleanup;
7563 _cairo_box_from_rectangle (&box, &mask);
7564 status = _cairo_composite_rectangles_intersect_mask_extents (&extents,
7565 &box);
7566 if (unlikely (status))
7567 goto cleanup;
7570 status = _cairo_pdf_surface_set_clip (surface, &extents);
7571 if (unlikely (status))
7572 goto cleanup;
7574 status = _cairo_pdf_surface_select_operator (surface, fill_op);
7575 if (unlikely (status))
7576 goto cleanup;
7578 /* use the more accurate extents */
7579 if (extents.is_bounded) {
7580 cairo_rectangle_int_t mask;
7581 cairo_box_t box;
7583 _cairo_path_fixed_fill_extents (path,
7584 fill_rule,
7585 fill_tolerance,
7586 &mask);
7588 _cairo_box_from_rectangle (&box, &mask);
7589 status = _cairo_composite_rectangles_intersect_mask_extents (&extents,
7590 &box);
7591 if (unlikely (status))
7592 goto cleanup;
7595 fill_pattern_res.id = 0;
7596 gstate_res.id = 0;
7597 status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source,
7598 fill_op,
7599 &extents.bounded,
7600 &fill_pattern_res,
7601 &gstate_res);
7602 if (unlikely (status))
7603 goto cleanup;
7605 assert (gstate_res.id == 0);
7607 stroke_pattern_res.id = 0;
7608 gstate_res.id = 0;
7609 status = _cairo_pdf_surface_add_pdf_pattern (surface,
7610 stroke_source,
7611 stroke_op,
7612 &extents.bounded,
7613 &stroke_pattern_res,
7614 &gstate_res);
7615 if (unlikely (status))
7616 goto cleanup;
7618 assert (gstate_res.id == 0);
7620 /* As PDF has separate graphics state for fill and stroke we can
7621 * select both at the same time */
7622 status = _cairo_pdf_surface_select_pattern (surface, fill_source,
7623 fill_pattern_res, FALSE);
7624 if (unlikely (status))
7625 goto cleanup;
7627 status = _cairo_pdf_surface_select_pattern (surface, stroke_source,
7628 stroke_pattern_res, TRUE);
7629 if (unlikely (status))
7630 goto cleanup;
7632 status = _cairo_pdf_operators_fill_stroke (&surface->pdf_operators,
7633 path,
7634 fill_rule,
7635 stroke_style,
7636 stroke_ctm,
7637 stroke_ctm_inverse);
7638 if (unlikely (status))
7639 goto cleanup;
7641 status = _cairo_pdf_surface_unselect_pattern (surface);
7642 if (unlikely (status))
7643 goto cleanup;
7645 _cairo_composite_rectangles_fini (&extents);
7646 return _cairo_output_stream_get_status (surface->output);
7648 cleanup:
7649 _cairo_composite_rectangles_fini (&extents);
7650 return status;
7653 static cairo_bool_t
7654 _cairo_pdf_surface_has_show_text_glyphs (void *abstract_surface)
7656 return TRUE;
7659 static cairo_int_status_t
7660 _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
7661 cairo_operator_t op,
7662 const cairo_pattern_t *source,
7663 const char *utf8,
7664 int utf8_len,
7665 cairo_glyph_t *glyphs,
7666 int num_glyphs,
7667 const cairo_text_cluster_t *clusters,
7668 int num_clusters,
7669 cairo_text_cluster_flags_t cluster_flags,
7670 cairo_scaled_font_t *scaled_font,
7671 const cairo_clip_t *clip)
7673 cairo_pdf_surface_t *surface = abstract_surface;
7674 cairo_pdf_smask_group_t *group;
7675 cairo_pdf_resource_t pattern_res, gstate_res;
7676 cairo_composite_rectangles_t extents;
7677 cairo_bool_t overlap;
7678 cairo_int_status_t status;
7680 status = _cairo_composite_rectangles_init_for_glyphs (&extents,
7681 &surface->base,
7682 op, source,
7683 scaled_font,
7684 glyphs, num_glyphs,
7685 clip,
7686 &overlap);
7687 if (unlikely (status))
7688 return status;
7690 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
7691 status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
7692 goto cleanup;
7695 assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
7697 status = _cairo_pdf_surface_set_clip (surface, &extents);
7698 if (unlikely (status))
7699 goto cleanup;
7701 pattern_res.id = 0;
7702 gstate_res.id = 0;
7703 status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op,
7704 &extents.bounded,
7705 &pattern_res, &gstate_res);
7706 if (unlikely (status))
7707 goto cleanup;
7709 status = _cairo_pdf_surface_select_operator (surface, op);
7710 if (unlikely (status))
7711 goto cleanup;
7713 if (gstate_res.id != 0) {
7714 group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded);
7715 if (unlikely (group == NULL)) {
7716 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
7717 goto cleanup;
7720 group->operation = PDF_SHOW_GLYPHS;
7721 status = _cairo_pattern_create_copy (&group->source, source);
7722 if (unlikely (status)) {
7723 _cairo_pdf_smask_group_destroy (group);
7724 goto cleanup;
7726 group->source_res = pattern_res;
7728 if (utf8_len) {
7729 group->utf8 = malloc (utf8_len);
7730 if (unlikely (group->utf8 == NULL)) {
7731 _cairo_pdf_smask_group_destroy (group);
7732 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
7733 goto cleanup;
7735 memcpy (group->utf8, utf8, utf8_len);
7737 group->utf8_len = utf8_len;
7739 if (num_glyphs) {
7740 group->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
7741 if (unlikely (group->glyphs == NULL)) {
7742 _cairo_pdf_smask_group_destroy (group);
7743 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
7744 goto cleanup;
7746 memcpy (group->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
7748 group->num_glyphs = num_glyphs;
7750 if (num_clusters) {
7751 group->clusters = _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t));
7752 if (unlikely (group->clusters == NULL)) {
7753 _cairo_pdf_smask_group_destroy (group);
7754 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
7755 goto cleanup;
7757 memcpy (group->clusters, clusters, sizeof (cairo_text_cluster_t) * num_clusters);
7759 group->num_clusters = num_clusters;
7761 group->scaled_font = cairo_scaled_font_reference (scaled_font);
7762 status = _cairo_pdf_surface_add_smask_group (surface, group);
7763 if (unlikely (status)) {
7764 _cairo_pdf_smask_group_destroy (group);
7765 goto cleanup;
7768 status = _cairo_pdf_surface_add_smask (surface, gstate_res);
7769 if (unlikely (status))
7770 goto cleanup;
7772 status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
7773 if (unlikely (status))
7774 goto cleanup;
7776 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
7777 if (unlikely (status))
7778 goto cleanup;
7780 _cairo_output_stream_printf (surface->output,
7781 "q /s%d gs /x%d Do Q\n",
7782 gstate_res.id,
7783 group->group_res.id);
7784 } else {
7785 status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
7786 if (unlikely (status))
7787 goto cleanup;
7789 /* Each call to show_glyphs() with a transclucent pattern must
7790 * be in a separate text object otherwise overlapping text
7791 * from separate calls to show_glyphs will not composite with
7792 * each other. */
7793 if (! _cairo_pattern_is_opaque (source, &extents.bounded)) {
7794 status = _cairo_pdf_operators_flush (&surface->pdf_operators);
7795 if (unlikely (status))
7796 goto cleanup;
7799 status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
7800 utf8, utf8_len,
7801 glyphs, num_glyphs,
7802 clusters, num_clusters,
7803 cluster_flags,
7804 scaled_font);
7805 if (unlikely (status))
7806 goto cleanup;
7808 status = _cairo_pdf_surface_unselect_pattern (surface);
7809 if (unlikely (status))
7810 goto cleanup;
7813 _cairo_composite_rectangles_fini (&extents);
7814 return _cairo_output_stream_get_status (surface->output);
7816 cleanup:
7817 _cairo_composite_rectangles_fini (&extents);
7818 return status;
7821 static const char **
7822 _cairo_pdf_surface_get_supported_mime_types (void *abstract_surface)
7824 return _cairo_pdf_supported_mime_types;
7827 static void
7828 _cairo_pdf_surface_set_paginated_mode (void *abstract_surface,
7829 cairo_paginated_mode_t paginated_mode)
7831 cairo_pdf_surface_t *surface = abstract_surface;
7833 surface->paginated_mode = paginated_mode;
7836 static const cairo_surface_backend_t cairo_pdf_surface_backend = {
7837 CAIRO_SURFACE_TYPE_PDF,
7838 _cairo_pdf_surface_finish,
7840 _cairo_default_context_create,
7842 NULL, /* create similar: handled by wrapper */
7843 NULL, /* create similar image */
7844 NULL, /* map to image */
7845 NULL, /* unmap image */
7847 _cairo_surface_default_source,
7848 NULL, /* acquire_source_image */
7849 NULL, /* release_source_image */
7850 NULL, /* snapshot */
7852 NULL, /* _cairo_pdf_surface_copy_page */
7853 _cairo_pdf_surface_show_page,
7855 _cairo_pdf_surface_get_extents,
7856 _cairo_pdf_surface_get_font_options,
7858 NULL, /* flush */
7859 NULL, /* mark_dirty_rectangle */
7861 /* Here are the drawing functions */
7862 _cairo_pdf_surface_paint,
7863 _cairo_pdf_surface_mask,
7864 _cairo_pdf_surface_stroke,
7865 _cairo_pdf_surface_fill,
7866 _cairo_pdf_surface_fill_stroke,
7867 NULL, /* show_glyphs */
7868 _cairo_pdf_surface_has_show_text_glyphs,
7869 _cairo_pdf_surface_show_text_glyphs,
7870 _cairo_pdf_surface_get_supported_mime_types,
7873 static const cairo_paginated_surface_backend_t
7874 cairo_pdf_surface_paginated_backend = {
7875 _cairo_pdf_surface_start_page,
7876 _cairo_pdf_surface_set_paginated_mode,
7877 NULL, /* set_bounding_box */
7878 _cairo_pdf_surface_has_fallback_images,
7879 _cairo_pdf_surface_supports_fine_grained_fallbacks,