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