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