/src/cairo/src/cairo-pdf-operators.c
Line | Count | Source |
1 | | /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ |
2 | | /* cairo - a vector graphics library with display and print output |
3 | | * |
4 | | * Copyright © 2004 Red Hat, Inc |
5 | | * Copyright © 2006 Red Hat, Inc |
6 | | * Copyright © 2007, 2008 Adrian Johnson |
7 | | * |
8 | | * This library is free software; you can redistribute it and/or |
9 | | * modify it either under the terms of the GNU Lesser General Public |
10 | | * License version 2.1 as published by the Free Software Foundation |
11 | | * (the "LGPL") or, at your option, under the terms of the Mozilla |
12 | | * Public License Version 1.1 (the "MPL"). If you do not alter this |
13 | | * notice, a recipient may use your version of this file under either |
14 | | * the MPL or the LGPL. |
15 | | * |
16 | | * You should have received a copy of the LGPL along with this library |
17 | | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
19 | | * You should have received a copy of the MPL along with this library |
20 | | * in the file COPYING-MPL-1.1 |
21 | | * |
22 | | * The contents of this file are subject to the Mozilla Public License |
23 | | * Version 1.1 (the "License"); you may not use this file except in |
24 | | * compliance with the License. You may obtain a copy of the License at |
25 | | * http://www.mozilla.org/MPL/ |
26 | | * |
27 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
28 | | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
29 | | * the specific language governing rights and limitations. |
30 | | * |
31 | | * The Original Code is the cairo graphics library. |
32 | | * |
33 | | * The Initial Developer of the Original Code is University of Southern |
34 | | * California. |
35 | | * |
36 | | * Contributor(s): |
37 | | * Kristian Høgsberg <krh@redhat.com> |
38 | | * Carl Worth <cworth@cworth.org> |
39 | | * Adrian Johnson <ajohnson@redneon.com> |
40 | | */ |
41 | | |
42 | | #include "cairoint.h" |
43 | | |
44 | | #if CAIRO_HAS_PDF_OPERATORS |
45 | | |
46 | | #include "cairo-error-private.h" |
47 | | #include "cairo-pdf-operators-private.h" |
48 | | #include "cairo-path-fixed-private.h" |
49 | | #include "cairo-output-stream-private.h" |
50 | | #include "cairo-scaled-font-subsets-private.h" |
51 | | |
52 | | static cairo_status_t |
53 | | _cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators); |
54 | | |
55 | | |
56 | | void |
57 | | _cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators, |
58 | | cairo_output_stream_t *stream, |
59 | | cairo_matrix_t *cairo_to_pdf, |
60 | | cairo_scaled_font_subsets_t *font_subsets, |
61 | | cairo_bool_t ps) |
62 | 762 | { |
63 | 762 | pdf_operators->stream = stream; |
64 | 762 | pdf_operators->cairo_to_pdf = *cairo_to_pdf; |
65 | 762 | pdf_operators->font_subsets = font_subsets; |
66 | 762 | pdf_operators->ps_output = ps; |
67 | 762 | pdf_operators->use_font_subset = NULL; |
68 | 762 | pdf_operators->use_font_subset_closure = NULL; |
69 | 762 | pdf_operators->in_text_object = FALSE; |
70 | 762 | pdf_operators->num_glyphs = 0; |
71 | 762 | pdf_operators->has_line_style = FALSE; |
72 | 762 | pdf_operators->use_actual_text = FALSE; |
73 | 762 | } |
74 | | |
75 | | cairo_status_t |
76 | | _cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators) |
77 | 762 | { |
78 | 762 | return _cairo_pdf_operators_flush (pdf_operators); |
79 | 762 | } |
80 | | |
81 | | void |
82 | | _cairo_pdf_operators_set_font_subsets_callback (cairo_pdf_operators_t *pdf_operators, |
83 | | cairo_pdf_operators_use_font_subset_t use_font_subset, |
84 | | void *closure) |
85 | 762 | { |
86 | 762 | pdf_operators->use_font_subset = use_font_subset; |
87 | 762 | pdf_operators->use_font_subset_closure = closure; |
88 | 762 | } |
89 | | |
90 | | /* Change the output stream to a different stream. |
91 | | * _cairo_pdf_operators_flush() should always be called before calling |
92 | | * this function. |
93 | | */ |
94 | | void |
95 | | _cairo_pdf_operators_set_stream (cairo_pdf_operators_t *pdf_operators, |
96 | | cairo_output_stream_t *stream) |
97 | 30.3k | { |
98 | 30.3k | pdf_operators->stream = stream; |
99 | 30.3k | pdf_operators->has_line_style = FALSE; |
100 | 30.3k | } |
101 | | |
102 | | void |
103 | | _cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators, |
104 | | cairo_matrix_t *cairo_to_pdf) |
105 | 0 | { |
106 | 0 | pdf_operators->cairo_to_pdf = *cairo_to_pdf; |
107 | 0 | pdf_operators->has_line_style = FALSE; |
108 | 0 | } |
109 | | |
110 | | cairo_private void |
111 | | _cairo_pdf_operators_enable_actual_text (cairo_pdf_operators_t *pdf_operators, |
112 | | cairo_bool_t enable) |
113 | 701 | { |
114 | 701 | pdf_operators->use_actual_text = enable; |
115 | 701 | } |
116 | | |
117 | | /* Finish writing out any pending commands to the stream. This |
118 | | * function must be called by the surface before emitting anything |
119 | | * into the PDF stream. |
120 | | * |
121 | | * pdf_operators may leave the emitted PDF for some operations |
122 | | * unfinished in case subsequent operations can be merged. This |
123 | | * function will finish off any incomplete operation so the stream |
124 | | * will be in a state where the surface may emit its own PDF |
125 | | * operations (eg changing patterns). |
126 | | * |
127 | | */ |
128 | | cairo_status_t |
129 | | _cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators) |
130 | 83.9k | { |
131 | 83.9k | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
132 | | |
133 | 83.9k | if (pdf_operators->in_text_object) |
134 | 6.26k | status = _cairo_pdf_operators_end_text (pdf_operators); |
135 | | |
136 | 83.9k | return status; |
137 | 83.9k | } |
138 | | |
139 | | /* Reset the known graphics state of the PDF consumer. ie no |
140 | | * assumptions will be made about the state. The next time a |
141 | | * particular graphics state is required (eg line width) the state |
142 | | * operator is always emitted and then remembered for subsequent |
143 | | * operations. |
144 | | * |
145 | | * This should be called when starting a new stream or after emitting |
146 | | * the 'Q' operator (where pdf-operators functions were called inside |
147 | | * the q/Q pair). |
148 | | */ |
149 | | void |
150 | | _cairo_pdf_operators_reset (cairo_pdf_operators_t *pdf_operators) |
151 | 50.0k | { |
152 | 50.0k | pdf_operators->has_line_style = FALSE; |
153 | 50.0k | } |
154 | | |
155 | | /* A word wrap stream can be used as a filter to do word wrapping on |
156 | | * top of an existing output stream. The word wrapping is quite |
157 | | * simple, using isspace to determine characters that separate |
158 | | * words. Any word that will cause the column count exceed the given |
159 | | * max_column will have a '\n' character emitted before it. |
160 | | * |
161 | | * The stream is careful to maintain integrity for words that cross |
162 | | * the boundary from one call to write to the next. |
163 | | * |
164 | | * Note: This stream does not guarantee that the output will never |
165 | | * exceed max_column. In particular, if a single word is larger than |
166 | | * max_column it will not be broken up. |
167 | | */ |
168 | | |
169 | | typedef enum _cairo_word_wrap_state { |
170 | | WRAP_STATE_DELIMITER, |
171 | | WRAP_STATE_WORD, |
172 | | WRAP_STATE_STRING, |
173 | | WRAP_STATE_HEXSTRING |
174 | | } cairo_word_wrap_state_t; |
175 | | |
176 | | |
177 | | typedef struct _word_wrap_stream { |
178 | | cairo_output_stream_t base; |
179 | | cairo_output_stream_t *output; |
180 | | int max_column; |
181 | | cairo_bool_t ps_output; |
182 | | int column; |
183 | | cairo_word_wrap_state_t state; |
184 | | cairo_bool_t in_escape; |
185 | | int escape_digits; |
186 | | } word_wrap_stream_t; |
187 | | |
188 | | |
189 | | |
190 | | /* Emit word bytes up to the next delimiter character */ |
191 | | static int |
192 | | _word_wrap_stream_count_word_up_to (word_wrap_stream_t *stream, |
193 | | const unsigned char *data, int length) |
194 | 4.12M | { |
195 | 4.12M | const unsigned char *s = data; |
196 | 4.12M | int count = 0; |
197 | | |
198 | 15.6M | while (length--) { |
199 | 15.6M | if (_cairo_isspace (*s) || *s == '<' || *s == '(') { |
200 | 4.12M | stream->state = WRAP_STATE_DELIMITER; |
201 | 4.12M | break; |
202 | 4.12M | } |
203 | | |
204 | 11.5M | count++; |
205 | 11.5M | stream->column++; |
206 | 11.5M | s++; |
207 | 11.5M | } |
208 | | |
209 | 4.12M | if (count) |
210 | 3.63M | _cairo_output_stream_write (stream->output, data, count); |
211 | | |
212 | 4.12M | return count; |
213 | 4.12M | } |
214 | | |
215 | | |
216 | | /* Emit hexstring bytes up to either the end of the ASCII hexstring or the number |
217 | | * of columns remaining. |
218 | | */ |
219 | | static int |
220 | | _word_wrap_stream_count_hexstring_up_to (word_wrap_stream_t *stream, |
221 | | const unsigned char *data, int length) |
222 | 1.45M | { |
223 | 1.45M | const unsigned char *s = data; |
224 | 1.45M | int count = 0; |
225 | 1.45M | cairo_bool_t newline = FALSE; |
226 | | |
227 | 4.51M | while (length--) { |
228 | 3.73M | count++; |
229 | 3.73M | stream->column++; |
230 | 3.73M | if (*s == '>') { |
231 | 640k | stream->state = WRAP_STATE_DELIMITER; |
232 | 640k | break; |
233 | 640k | } |
234 | | |
235 | 3.09M | if (stream->column > stream->max_column) { |
236 | 29.1k | newline = TRUE; |
237 | 29.1k | break; |
238 | 29.1k | } |
239 | 3.06M | s++; |
240 | 3.06M | } |
241 | | |
242 | 1.45M | if (count) |
243 | 1.45M | _cairo_output_stream_write (stream->output, data, count); |
244 | | |
245 | 1.45M | if (newline) { |
246 | 29.1k | _cairo_output_stream_printf (stream->output, "\n"); |
247 | 29.1k | stream->column = 0; |
248 | 29.1k | } |
249 | | |
250 | 1.45M | return count; |
251 | 1.45M | } |
252 | | |
253 | | /* Count up to either the end of the string or the number of columns |
254 | | * remaining. |
255 | | */ |
256 | | static int |
257 | | _word_wrap_stream_count_string_up_to (word_wrap_stream_t *stream, |
258 | | const unsigned char *data, int length) |
259 | 4.95M | { |
260 | 4.95M | const unsigned char *s = data; |
261 | 4.95M | int count = 0; |
262 | 4.95M | cairo_bool_t newline = FALSE; |
263 | | |
264 | 7.93M | while (length--) { |
265 | 4.96M | count++; |
266 | 4.96M | stream->column++; |
267 | 4.96M | if (!stream->in_escape) { |
268 | 4.94M | if (*s == ')') { |
269 | 1.99M | stream->state = WRAP_STATE_DELIMITER; |
270 | 1.99M | break; |
271 | 1.99M | } |
272 | 2.94M | if (*s == '\\') { |
273 | 18.2k | stream->in_escape = TRUE; |
274 | 18.2k | stream->escape_digits = 0; |
275 | 2.92M | } else if (stream->ps_output && stream->column > stream->max_column) { |
276 | 0 | newline = TRUE; |
277 | 0 | break; |
278 | 0 | } |
279 | 2.94M | } else { |
280 | 29.4k | if (!_cairo_isdigit(*s) || ++stream->escape_digits == 3) |
281 | 18.2k | stream->in_escape = FALSE; |
282 | 29.4k | } |
283 | 2.97M | s++; |
284 | 2.97M | } |
285 | | |
286 | 4.95M | if (count) |
287 | 4.95M | _cairo_output_stream_write (stream->output, data, count); |
288 | | |
289 | 4.95M | if (newline) { |
290 | 0 | _cairo_output_stream_printf (stream->output, "\\\n"); |
291 | 0 | stream->column = 0; |
292 | 0 | } |
293 | | |
294 | 4.95M | return count; |
295 | 4.95M | } |
296 | | |
297 | | static cairo_status_t |
298 | | _word_wrap_stream_write (cairo_output_stream_t *base, |
299 | | const unsigned char *data, |
300 | | unsigned int length) |
301 | 10.4M | { |
302 | 10.4M | word_wrap_stream_t *stream = (word_wrap_stream_t *) base; |
303 | 10.4M | int count; |
304 | | |
305 | 29.2M | while (length) { |
306 | 18.8M | switch (stream->state) { |
307 | 4.12M | case WRAP_STATE_WORD: |
308 | 4.12M | count = _word_wrap_stream_count_word_up_to (stream, data, length); |
309 | 4.12M | break; |
310 | 1.45M | case WRAP_STATE_HEXSTRING: |
311 | 1.45M | count = _word_wrap_stream_count_hexstring_up_to (stream, data, length); |
312 | 1.45M | break; |
313 | 4.95M | case WRAP_STATE_STRING: |
314 | 4.95M | count = _word_wrap_stream_count_string_up_to (stream, data, length); |
315 | 4.95M | break; |
316 | 8.27M | case WRAP_STATE_DELIMITER: |
317 | 8.27M | count = 1; |
318 | 8.27M | stream->column++; |
319 | 8.27M | if (*data == '\n' || stream->column >= stream->max_column) { |
320 | 469k | _cairo_output_stream_printf (stream->output, "\n"); |
321 | 469k | stream->column = 0; |
322 | 469k | } |
323 | 8.27M | if (*data == '<') { |
324 | 640k | stream->state = WRAP_STATE_HEXSTRING; |
325 | 7.63M | } else if (*data == '(') { |
326 | 1.99M | stream->state = WRAP_STATE_STRING; |
327 | 5.64M | } else if (!_cairo_isspace (*data)) { |
328 | 4.12M | stream->state = WRAP_STATE_WORD; |
329 | 4.12M | } |
330 | 8.27M | if (*data != '\n') |
331 | 8.07M | _cairo_output_stream_write (stream->output, data, 1); |
332 | 8.27M | break; |
333 | | |
334 | 0 | default: |
335 | 0 | ASSERT_NOT_REACHED; |
336 | 0 | count = length; |
337 | 0 | break; |
338 | 18.8M | } |
339 | 18.8M | data += count; |
340 | 18.8M | length -= count; |
341 | 18.8M | } |
342 | | |
343 | 10.4M | return _cairo_output_stream_get_status (stream->output); |
344 | 10.4M | } |
345 | | |
346 | | static cairo_status_t |
347 | | _word_wrap_stream_close (cairo_output_stream_t *base) |
348 | 216k | { |
349 | 216k | word_wrap_stream_t *stream = (word_wrap_stream_t *) base; |
350 | | |
351 | 216k | return _cairo_output_stream_get_status (stream->output); |
352 | 216k | } |
353 | | |
354 | | static cairo_output_stream_t * |
355 | | _word_wrap_stream_create (cairo_output_stream_t *output, cairo_bool_t ps, int max_column) |
356 | 216k | { |
357 | 216k | word_wrap_stream_t *stream; |
358 | | |
359 | 216k | if (output->status) |
360 | 0 | return _cairo_output_stream_create_in_error (output->status); |
361 | | |
362 | 216k | stream = _cairo_calloc (sizeof (word_wrap_stream_t)); |
363 | 216k | if (unlikely (stream == NULL)) { |
364 | 0 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
365 | 0 | return (cairo_output_stream_t *) &_cairo_output_stream_nil; |
366 | 0 | } |
367 | | |
368 | 216k | _cairo_output_stream_init (&stream->base, |
369 | 216k | _word_wrap_stream_write, |
370 | 216k | NULL, |
371 | 216k | _word_wrap_stream_close); |
372 | 216k | stream->output = output; |
373 | 216k | stream->max_column = max_column; |
374 | 216k | stream->ps_output = ps; |
375 | 216k | stream->column = 0; |
376 | 216k | stream->state = WRAP_STATE_DELIMITER; |
377 | 216k | stream->in_escape = FALSE; |
378 | 216k | stream->escape_digits = 0; |
379 | | |
380 | 216k | return &stream->base; |
381 | 216k | } |
382 | | |
383 | | typedef struct _pdf_path_info { |
384 | | cairo_output_stream_t *output; |
385 | | cairo_matrix_t *path_transform; |
386 | | cairo_line_cap_t line_cap; |
387 | | cairo_point_t last_move_to_point; |
388 | | cairo_bool_t has_sub_path; |
389 | | } pdf_path_info_t; |
390 | | |
391 | | static cairo_status_t |
392 | | _cairo_pdf_path_move_to (void *closure, |
393 | | const cairo_point_t *point) |
394 | 41.3k | { |
395 | 41.3k | pdf_path_info_t *info = closure; |
396 | 41.3k | double x = _cairo_fixed_to_double (point->x); |
397 | 41.3k | double y = _cairo_fixed_to_double (point->y); |
398 | | |
399 | 41.3k | info->last_move_to_point = *point; |
400 | 41.3k | info->has_sub_path = FALSE; |
401 | 41.3k | cairo_matrix_transform_point (info->path_transform, &x, &y); |
402 | 41.3k | _cairo_output_stream_printf (info->output, |
403 | 41.3k | "%g %g m ", x, y); |
404 | | |
405 | 41.3k | return _cairo_output_stream_get_status (info->output); |
406 | 41.3k | } |
407 | | |
408 | | static cairo_status_t |
409 | | _cairo_pdf_path_line_to (void *closure, |
410 | | const cairo_point_t *point) |
411 | 78.1k | { |
412 | 78.1k | pdf_path_info_t *info = closure; |
413 | 78.1k | double x = _cairo_fixed_to_double (point->x); |
414 | 78.1k | double y = _cairo_fixed_to_double (point->y); |
415 | | |
416 | 78.1k | if (info->line_cap != CAIRO_LINE_CAP_ROUND && |
417 | 30.9k | ! info->has_sub_path && |
418 | 16.5k | point->x == info->last_move_to_point.x && |
419 | 3.45k | point->y == info->last_move_to_point.y) |
420 | 0 | { |
421 | 0 | return CAIRO_STATUS_SUCCESS; |
422 | 0 | } |
423 | | |
424 | 78.1k | info->has_sub_path = TRUE; |
425 | 78.1k | cairo_matrix_transform_point (info->path_transform, &x, &y); |
426 | 78.1k | _cairo_output_stream_printf (info->output, |
427 | 78.1k | "%g %g l ", x, y); |
428 | | |
429 | 78.1k | return _cairo_output_stream_get_status (info->output); |
430 | 78.1k | } |
431 | | |
432 | | static cairo_status_t |
433 | | _cairo_pdf_path_curve_to (void *closure, |
434 | | const cairo_point_t *b, |
435 | | const cairo_point_t *c, |
436 | | const cairo_point_t *d) |
437 | 125k | { |
438 | 125k | pdf_path_info_t *info = closure; |
439 | 125k | double bx = _cairo_fixed_to_double (b->x); |
440 | 125k | double by = _cairo_fixed_to_double (b->y); |
441 | 125k | double cx = _cairo_fixed_to_double (c->x); |
442 | 125k | double cy = _cairo_fixed_to_double (c->y); |
443 | 125k | double dx = _cairo_fixed_to_double (d->x); |
444 | 125k | double dy = _cairo_fixed_to_double (d->y); |
445 | | |
446 | 125k | info->has_sub_path = TRUE; |
447 | 125k | cairo_matrix_transform_point (info->path_transform, &bx, &by); |
448 | 125k | cairo_matrix_transform_point (info->path_transform, &cx, &cy); |
449 | 125k | cairo_matrix_transform_point (info->path_transform, &dx, &dy); |
450 | 125k | _cairo_output_stream_printf (info->output, |
451 | 125k | "%g %g %g %g %g %g c ", |
452 | 125k | bx, by, cx, cy, dx, dy); |
453 | 125k | return _cairo_output_stream_get_status (info->output); |
454 | 125k | } |
455 | | |
456 | | static cairo_status_t |
457 | | _cairo_pdf_path_close_path (void *closure) |
458 | 21.0k | { |
459 | 21.0k | pdf_path_info_t *info = closure; |
460 | | |
461 | 21.0k | if (info->line_cap != CAIRO_LINE_CAP_ROUND && |
462 | 7.47k | ! info->has_sub_path) |
463 | 1 | { |
464 | 1 | return CAIRO_STATUS_SUCCESS; |
465 | 1 | } |
466 | | |
467 | 21.0k | _cairo_output_stream_printf (info->output, |
468 | 21.0k | "h\n"); |
469 | | |
470 | 21.0k | return _cairo_output_stream_get_status (info->output); |
471 | 21.0k | } |
472 | | |
473 | | static cairo_status_t |
474 | | _cairo_pdf_path_rectangle (pdf_path_info_t *info, cairo_box_t *box) |
475 | 15.1k | { |
476 | 15.1k | double x1 = _cairo_fixed_to_double (box->p1.x); |
477 | 15.1k | double y1 = _cairo_fixed_to_double (box->p1.y); |
478 | 15.1k | double x2 = _cairo_fixed_to_double (box->p2.x); |
479 | 15.1k | double y2 = _cairo_fixed_to_double (box->p2.y); |
480 | | |
481 | 15.1k | cairo_matrix_transform_point (info->path_transform, &x1, &y1); |
482 | 15.1k | cairo_matrix_transform_point (info->path_transform, &x2, &y2); |
483 | 15.1k | _cairo_output_stream_printf (info->output, |
484 | 15.1k | "%g %g %g %g re ", |
485 | 15.1k | x1, y1, x2 - x1, y2 - y1); |
486 | | |
487 | 15.1k | return _cairo_output_stream_get_status (info->output); |
488 | 15.1k | } |
489 | | |
490 | | /* The line cap value is needed to workaround the fact that PostScript |
491 | | * and PDF semantics for stroking degenerate sub-paths do not match |
492 | | * cairo semantics. (PostScript draws something for any line cap |
493 | | * value, while cairo draws something only for round caps). |
494 | | * |
495 | | * When using this function to emit a path to be filled, rather than |
496 | | * stroked, simply pass %CAIRO_LINE_CAP_ROUND which will guarantee that |
497 | | * the stroke workaround will not modify the path being emitted. |
498 | | */ |
499 | | static cairo_status_t |
500 | | _cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators, |
501 | | const cairo_path_fixed_t*path, |
502 | | cairo_matrix_t *path_transform, |
503 | | cairo_line_cap_t line_cap) |
504 | 30.8k | { |
505 | 30.8k | cairo_output_stream_t *word_wrap; |
506 | 30.8k | cairo_status_t status, status2; |
507 | 30.8k | pdf_path_info_t info; |
508 | 30.8k | cairo_box_t box; |
509 | | |
510 | 30.8k | word_wrap = _word_wrap_stream_create (pdf_operators->stream, pdf_operators->ps_output, 72); |
511 | 30.8k | status = _cairo_output_stream_get_status (word_wrap); |
512 | 30.8k | if (unlikely (status)) |
513 | 0 | return _cairo_output_stream_destroy (word_wrap); |
514 | | |
515 | 30.8k | info.output = word_wrap; |
516 | 30.8k | info.path_transform = path_transform; |
517 | 30.8k | info.line_cap = line_cap; |
518 | 30.8k | if (_cairo_path_fixed_is_rectangle (path, &box) && |
519 | 15.1k | ((path_transform->xx == 0 && path_transform->yy == 0) || |
520 | 15.1k | (path_transform->xy == 0 && path_transform->yx == 0))) { |
521 | 15.1k | status = _cairo_pdf_path_rectangle (&info, &box); |
522 | 15.6k | } else { |
523 | 15.6k | status = _cairo_path_fixed_interpret (path, |
524 | 15.6k | _cairo_pdf_path_move_to, |
525 | 15.6k | _cairo_pdf_path_line_to, |
526 | 15.6k | _cairo_pdf_path_curve_to, |
527 | 15.6k | _cairo_pdf_path_close_path, |
528 | 15.6k | &info); |
529 | 15.6k | } |
530 | | |
531 | 30.8k | status2 = _cairo_output_stream_destroy (word_wrap); |
532 | 30.8k | if (status == CAIRO_STATUS_SUCCESS) |
533 | 30.8k | status = status2; |
534 | | |
535 | 30.8k | return status; |
536 | 30.8k | } |
537 | | |
538 | | cairo_int_status_t |
539 | | _cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators, |
540 | | const cairo_path_fixed_t *path, |
541 | | cairo_fill_rule_t fill_rule) |
542 | 7.25k | { |
543 | 7.25k | const char *pdf_operator; |
544 | 7.25k | cairo_status_t status; |
545 | | |
546 | 7.25k | if (pdf_operators->in_text_object) { |
547 | 0 | status = _cairo_pdf_operators_end_text (pdf_operators); |
548 | 0 | if (unlikely (status)) |
549 | 0 | return status; |
550 | 0 | } |
551 | | |
552 | 7.25k | if (! path->has_current_point) { |
553 | | /* construct an empty path */ |
554 | 0 | _cairo_output_stream_printf (pdf_operators->stream, "0 0 m "); |
555 | 7.25k | } else { |
556 | 7.25k | status = _cairo_pdf_operators_emit_path (pdf_operators, |
557 | 7.25k | path, |
558 | 7.25k | &pdf_operators->cairo_to_pdf, |
559 | 7.25k | CAIRO_LINE_CAP_ROUND); |
560 | 7.25k | if (unlikely (status)) |
561 | 0 | return status; |
562 | 7.25k | } |
563 | | |
564 | 7.25k | switch (fill_rule) { |
565 | 0 | default: |
566 | 0 | ASSERT_NOT_REACHED; |
567 | 7.25k | case CAIRO_FILL_RULE_WINDING: |
568 | 7.25k | pdf_operator = "W"; |
569 | 7.25k | break; |
570 | 0 | case CAIRO_FILL_RULE_EVEN_ODD: |
571 | 0 | pdf_operator = "W*"; |
572 | 0 | break; |
573 | 7.25k | } |
574 | | |
575 | 7.25k | _cairo_output_stream_printf (pdf_operators->stream, |
576 | 7.25k | "%s n\n", |
577 | 7.25k | pdf_operator); |
578 | | |
579 | 7.25k | return _cairo_output_stream_get_status (pdf_operators->stream); |
580 | 7.25k | } |
581 | | |
582 | | static int |
583 | | _cairo_pdf_line_cap (cairo_line_cap_t cap) |
584 | 8.00k | { |
585 | 8.00k | switch (cap) { |
586 | 5.80k | case CAIRO_LINE_CAP_BUTT: |
587 | 5.80k | return 0; |
588 | 2.19k | case CAIRO_LINE_CAP_ROUND: |
589 | 2.19k | return 1; |
590 | 1 | case CAIRO_LINE_CAP_SQUARE: |
591 | 1 | return 2; |
592 | 0 | default: |
593 | 0 | ASSERT_NOT_REACHED; |
594 | 0 | return 0; |
595 | 8.00k | } |
596 | 8.00k | } |
597 | | |
598 | | static int |
599 | | _cairo_pdf_line_join (cairo_line_join_t join) |
600 | 10.3k | { |
601 | 10.3k | switch (join) { |
602 | 4.81k | case CAIRO_LINE_JOIN_MITER: |
603 | 4.81k | return 0; |
604 | 5.57k | case CAIRO_LINE_JOIN_ROUND: |
605 | 5.57k | return 1; |
606 | 1 | case CAIRO_LINE_JOIN_BEVEL: |
607 | 1 | return 2; |
608 | 0 | default: |
609 | 0 | ASSERT_NOT_REACHED; |
610 | 0 | return 0; |
611 | 10.3k | } |
612 | 10.3k | } |
613 | | |
614 | | cairo_int_status_t |
615 | | _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, |
616 | | const cairo_stroke_style_t *style, |
617 | | double scale) |
618 | 16.0k | { |
619 | 16.0k | double *dash = style->dash; |
620 | 16.0k | int num_dashes = style->num_dashes; |
621 | 16.0k | double dash_offset = style->dash_offset; |
622 | 16.0k | double line_width = style->line_width * scale; |
623 | | |
624 | | /* PostScript has "special needs" when it comes to zero-length |
625 | | * dash segments with butt caps. It apparently (at least |
626 | | * according to ghostscript) draws hairlines for this |
627 | | * case. That's not what the cairo semantics want, so we first |
628 | | * touch up the array to eliminate any 0.0 values that will |
629 | | * result in "on" segments. |
630 | | */ |
631 | 16.0k | if (num_dashes && style->line_cap == CAIRO_LINE_CAP_BUTT) { |
632 | 20 | int i; |
633 | | |
634 | | /* If there's an odd number of dash values they will each get |
635 | | * interpreted as both on and off. So we first explicitly |
636 | | * expand the array to remove the duplicate usage so that we |
637 | | * can modify some of the values. |
638 | | */ |
639 | 20 | if (num_dashes % 2) { |
640 | 0 | dash = _cairo_malloc_abc (num_dashes, 2, sizeof (double)); |
641 | 0 | if (unlikely (dash == NULL)) |
642 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
643 | | |
644 | 0 | memcpy (dash, style->dash, num_dashes * sizeof (double)); |
645 | 0 | memcpy (dash + num_dashes, style->dash, num_dashes * sizeof (double)); |
646 | |
|
647 | 0 | num_dashes *= 2; |
648 | 0 | } |
649 | | |
650 | 40 | for (i = 0; i < num_dashes; i += 2) { |
651 | 20 | if (dash[i] == 0.0) { |
652 | | /* Do not modify the dashes in-place, as we may need to also |
653 | | * replay this stroke to an image fallback. |
654 | | */ |
655 | 0 | if (dash == style->dash) { |
656 | 0 | dash = _cairo_malloc_ab (num_dashes, sizeof (double)); |
657 | 0 | if (unlikely (dash == NULL)) |
658 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
659 | 0 | memcpy (dash, style->dash, num_dashes * sizeof (double)); |
660 | 0 | } |
661 | | |
662 | | /* If we're at the front of the list, we first rotate |
663 | | * two elements from the end of the list to the front |
664 | | * of the list before folding away the 0.0. Or, if |
665 | | * there are only two dash elements, then there is |
666 | | * nothing at all to draw. |
667 | | */ |
668 | 0 | if (i == 0) { |
669 | 0 | double last_two[2]; |
670 | |
|
671 | 0 | if (num_dashes == 2) { |
672 | 0 | free (dash); |
673 | 0 | return CAIRO_INT_STATUS_NOTHING_TO_DO; |
674 | 0 | } |
675 | | |
676 | | /* The cases of num_dashes == 0, 1, or 3 elements |
677 | | * cannot exist, so the rotation of 2 elements |
678 | | * will always be safe */ |
679 | 0 | memcpy (last_two, dash + num_dashes - 2, sizeof (last_two)); |
680 | 0 | memmove (dash + 2, dash, (num_dashes - 2) * sizeof (double)); |
681 | 0 | memcpy (dash, last_two, sizeof (last_two)); |
682 | 0 | dash_offset += dash[0] + dash[1]; |
683 | 0 | i = 2; |
684 | 0 | } |
685 | 0 | dash[i-1] += dash[i+1]; |
686 | 0 | num_dashes -= 2; |
687 | 0 | memmove (dash + i, dash + i + 2, (num_dashes - i) * sizeof (double)); |
688 | | /* If we might have just rotated, it's possible that |
689 | | * we rotated a 0.0 value to the front of the list. |
690 | | * Set i to -2 so it will get incremented to 0. */ |
691 | 0 | if (i == 2) |
692 | 0 | i = -2; |
693 | 0 | } |
694 | 20 | } |
695 | 20 | } |
696 | | |
697 | 16.0k | if (!pdf_operators->has_line_style || pdf_operators->line_width != line_width) { |
698 | 7.69k | _cairo_output_stream_printf (pdf_operators->stream, |
699 | 7.69k | "%f w\n", |
700 | 7.69k | line_width); |
701 | 7.69k | pdf_operators->line_width = line_width; |
702 | 7.69k | } |
703 | | |
704 | 16.0k | if (!pdf_operators->has_line_style || pdf_operators->line_cap != style->line_cap) { |
705 | 8.00k | _cairo_output_stream_printf (pdf_operators->stream, |
706 | 8.00k | "%d J\n", |
707 | 8.00k | _cairo_pdf_line_cap (style->line_cap)); |
708 | 8.00k | pdf_operators->line_cap = style->line_cap; |
709 | 8.00k | } |
710 | | |
711 | 16.0k | if (!pdf_operators->has_line_style || pdf_operators->line_join != style->line_join) { |
712 | 10.3k | _cairo_output_stream_printf (pdf_operators->stream, |
713 | 10.3k | "%d j\n", |
714 | 10.3k | _cairo_pdf_line_join (style->line_join)); |
715 | 10.3k | pdf_operators->line_join = style->line_join; |
716 | 10.3k | } |
717 | | |
718 | 16.0k | if (num_dashes) { |
719 | 639 | int d; |
720 | | |
721 | 639 | _cairo_output_stream_printf (pdf_operators->stream, "["); |
722 | 1.91k | for (d = 0; d < num_dashes; d++) |
723 | 1.27k | _cairo_output_stream_printf (pdf_operators->stream, " %f", dash[d] * scale); |
724 | 639 | _cairo_output_stream_printf (pdf_operators->stream, "] %f d\n", |
725 | 639 | dash_offset * scale); |
726 | 639 | pdf_operators->has_dashes = TRUE; |
727 | 15.3k | } else if (!pdf_operators->has_line_style || pdf_operators->has_dashes) { |
728 | 4.69k | _cairo_output_stream_printf (pdf_operators->stream, "[] 0.0 d\n"); |
729 | 4.69k | pdf_operators->has_dashes = FALSE; |
730 | 4.69k | } |
731 | 16.0k | if (dash != style->dash) |
732 | 0 | free (dash); |
733 | | |
734 | 16.0k | if (!pdf_operators->has_line_style || pdf_operators->miter_limit != style->miter_limit) { |
735 | 4.21k | _cairo_output_stream_printf (pdf_operators->stream, |
736 | 4.21k | "%f M ", |
737 | 4.21k | style->miter_limit < 1.0 ? 1.0 : style->miter_limit); |
738 | 4.21k | pdf_operators->miter_limit = style->miter_limit; |
739 | 4.21k | } |
740 | 16.0k | pdf_operators->has_line_style = TRUE; |
741 | | |
742 | 16.0k | return _cairo_output_stream_get_status (pdf_operators->stream); |
743 | 16.0k | } |
744 | | |
745 | | /* Scale the matrix so the largest absolute value of the non |
746 | | * translation components is 1.0. Return the scale required to restore |
747 | | * the matrix to the original values. |
748 | | * |
749 | | * eg the matrix [ 100 0 0 50 20 10 ] |
750 | | * |
751 | | * is rescaled to [ 1 0 0 0.5 0.2 0.1 ] |
752 | | * and the scale returned is 100 |
753 | | */ |
754 | | static void |
755 | | _cairo_matrix_factor_out_scale (cairo_matrix_t *m, double *scale) |
756 | 12.1k | { |
757 | 12.1k | double s; |
758 | | |
759 | 12.1k | s = fabs (m->xx); |
760 | 12.1k | if (fabs (m->xy) > s) |
761 | 0 | s = fabs (m->xy); |
762 | 12.1k | if (fabs (m->yx) > s) |
763 | 0 | s = fabs (m->yx); |
764 | 12.1k | if (fabs (m->yy) > s) |
765 | 13 | s = fabs (m->yy); |
766 | 12.1k | *scale = s; |
767 | 12.1k | s = 1.0/s; |
768 | 12.1k | cairo_matrix_scale (m, s, s); |
769 | 12.1k | } |
770 | | |
771 | | static cairo_int_status_t |
772 | | _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators, |
773 | | const cairo_path_fixed_t *path, |
774 | | const cairo_stroke_style_t *style, |
775 | | const cairo_matrix_t *ctm, |
776 | | const cairo_matrix_t *ctm_inverse, |
777 | | const char *pdf_operator) |
778 | 16.0k | { |
779 | 16.0k | cairo_int_status_t status; |
780 | 16.0k | cairo_matrix_t m, path_transform; |
781 | 16.0k | cairo_bool_t has_ctm = TRUE; |
782 | 16.0k | double scale = 1.0; |
783 | | |
784 | 16.0k | if (pdf_operators->in_text_object) { |
785 | 0 | status = _cairo_pdf_operators_end_text (pdf_operators); |
786 | 0 | if (unlikely (status)) |
787 | 0 | return status; |
788 | 0 | } |
789 | | |
790 | | /* Optimize away the stroke ctm when it does not affect the |
791 | | * stroke. There are other ctm cases that could be optimized |
792 | | * however this is the most common. |
793 | | */ |
794 | 16.0k | if (fabs(ctm->xx) == 1.0 && fabs(ctm->yy) == 1.0 && |
795 | 3.88k | fabs(ctm->xy) == 0.0 && fabs(ctm->yx) == 0.0) |
796 | 3.88k | { |
797 | 3.88k | has_ctm = FALSE; |
798 | 3.88k | } |
799 | | |
800 | | /* The PDF CTM is transformed to the user space CTM when stroking |
801 | | * so the correct pen shape will be used. This also requires that |
802 | | * the path be transformed to user space when emitted. The |
803 | | * conversion of path coordinates to user space may cause rounding |
804 | | * errors. For example the device space point (1.234, 3.142) when |
805 | | * transformed to a user space CTM of [100 0 0 100 0 0] will be |
806 | | * emitted as (0.012, 0.031). |
807 | | * |
808 | | * To avoid the rounding problem we scale the user space CTM |
809 | | * matrix so that all the non translation components of the matrix |
810 | | * are <= 1. The line width and and dashes are scaled by the |
811 | | * inverse of the scale applied to the CTM. This maintains the |
812 | | * shape of the stroke pen while keeping the user space CTM within |
813 | | * the range that maximizes the precision of the emitted path. |
814 | | */ |
815 | 16.0k | if (has_ctm) { |
816 | 12.1k | m = *ctm; |
817 | | /* Zero out the translation since it does not affect the pen |
818 | | * shape however it may cause unnecessary digits to be emitted. |
819 | | */ |
820 | 12.1k | m.x0 = 0.0; |
821 | 12.1k | m.y0 = 0.0; |
822 | 12.1k | _cairo_matrix_factor_out_scale (&m, &scale); |
823 | 12.1k | path_transform = m; |
824 | 12.1k | status = cairo_matrix_invert (&path_transform); |
825 | 12.1k | if (unlikely (status)) |
826 | 0 | return status; |
827 | | |
828 | 12.1k | cairo_matrix_multiply (&m, &m, &pdf_operators->cairo_to_pdf); |
829 | 12.1k | } |
830 | | |
831 | 16.0k | status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style, scale); |
832 | 16.0k | if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) |
833 | 0 | return CAIRO_STATUS_SUCCESS; |
834 | 16.0k | if (unlikely (status)) |
835 | 0 | return status; |
836 | | |
837 | 16.0k | if (has_ctm) { |
838 | 12.1k | _cairo_output_stream_printf (pdf_operators->stream, "q "); |
839 | 12.1k | _cairo_output_stream_print_matrix (pdf_operators->stream, &m); |
840 | 12.1k | _cairo_output_stream_printf (pdf_operators->stream, " cm\n"); |
841 | 12.1k | } else { |
842 | 3.88k | path_transform = pdf_operators->cairo_to_pdf; |
843 | 3.88k | } |
844 | | |
845 | 16.0k | status = _cairo_pdf_operators_emit_path (pdf_operators, |
846 | 16.0k | path, |
847 | 16.0k | &path_transform, |
848 | 16.0k | style->line_cap); |
849 | 16.0k | if (unlikely (status)) |
850 | 0 | return status; |
851 | | |
852 | 16.0k | _cairo_output_stream_printf (pdf_operators->stream, "%s", pdf_operator); |
853 | 16.0k | if (has_ctm) |
854 | 12.1k | _cairo_output_stream_printf (pdf_operators->stream, " Q"); |
855 | | |
856 | 16.0k | _cairo_output_stream_printf (pdf_operators->stream, "\n"); |
857 | | |
858 | 16.0k | return _cairo_output_stream_get_status (pdf_operators->stream); |
859 | 16.0k | } |
860 | | |
861 | | cairo_int_status_t |
862 | | _cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators, |
863 | | const cairo_path_fixed_t *path, |
864 | | const cairo_stroke_style_t *style, |
865 | | const cairo_matrix_t *ctm, |
866 | | const cairo_matrix_t *ctm_inverse) |
867 | 12.1k | { |
868 | 12.1k | return _cairo_pdf_operators_emit_stroke (pdf_operators, |
869 | 12.1k | path, |
870 | 12.1k | style, |
871 | 12.1k | ctm, |
872 | 12.1k | ctm_inverse, |
873 | 12.1k | "S"); |
874 | 12.1k | } |
875 | | |
876 | | cairo_int_status_t |
877 | | _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators, |
878 | | const cairo_path_fixed_t *path, |
879 | | cairo_fill_rule_t fill_rule) |
880 | 7.55k | { |
881 | 7.55k | const char *pdf_operator; |
882 | 7.55k | cairo_status_t status; |
883 | | |
884 | 7.55k | if (pdf_operators->in_text_object) { |
885 | 301 | status = _cairo_pdf_operators_end_text (pdf_operators); |
886 | 301 | if (unlikely (status)) |
887 | 0 | return status; |
888 | 301 | } |
889 | | |
890 | 7.55k | status = _cairo_pdf_operators_emit_path (pdf_operators, |
891 | 7.55k | path, |
892 | 7.55k | &pdf_operators->cairo_to_pdf, |
893 | 7.55k | CAIRO_LINE_CAP_ROUND); |
894 | 7.55k | if (unlikely (status)) |
895 | 0 | return status; |
896 | | |
897 | 7.55k | switch (fill_rule) { |
898 | 0 | default: |
899 | 0 | ASSERT_NOT_REACHED; |
900 | 5.02k | case CAIRO_FILL_RULE_WINDING: |
901 | 5.02k | pdf_operator = "f"; |
902 | 5.02k | break; |
903 | 2.53k | case CAIRO_FILL_RULE_EVEN_ODD: |
904 | 2.53k | pdf_operator = "f*"; |
905 | 2.53k | break; |
906 | 7.55k | } |
907 | | |
908 | 7.55k | _cairo_output_stream_printf (pdf_operators->stream, |
909 | 7.55k | "%s\n", |
910 | 7.55k | pdf_operator); |
911 | | |
912 | 7.55k | return _cairo_output_stream_get_status (pdf_operators->stream); |
913 | 7.55k | } |
914 | | |
915 | | cairo_int_status_t |
916 | | _cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators, |
917 | | const cairo_path_fixed_t *path, |
918 | | cairo_fill_rule_t fill_rule, |
919 | | const cairo_stroke_style_t *style, |
920 | | const cairo_matrix_t *ctm, |
921 | | const cairo_matrix_t *ctm_inverse) |
922 | 3.84k | { |
923 | 3.84k | const char *operator; |
924 | | |
925 | 3.84k | switch (fill_rule) { |
926 | 0 | default: |
927 | 0 | ASSERT_NOT_REACHED; |
928 | 3.81k | case CAIRO_FILL_RULE_WINDING: |
929 | 3.81k | operator = "B"; |
930 | 3.81k | break; |
931 | 30 | case CAIRO_FILL_RULE_EVEN_ODD: |
932 | 30 | operator = "B*"; |
933 | 30 | break; |
934 | 3.84k | } |
935 | | |
936 | 3.84k | return _cairo_pdf_operators_emit_stroke (pdf_operators, |
937 | 3.84k | path, |
938 | 3.84k | style, |
939 | 3.84k | ctm, |
940 | 3.84k | ctm_inverse, |
941 | 3.84k | operator); |
942 | 3.84k | } |
943 | | |
944 | | static void |
945 | | _cairo_pdf_operators_emit_glyph_index (cairo_pdf_operators_t *pdf_operators, |
946 | | cairo_output_stream_t *stream, |
947 | | unsigned int glyph) |
948 | 3.73M | { |
949 | 3.73M | if (pdf_operators->is_latin) { |
950 | 2.94M | if (glyph == '(' || glyph == ')' || glyph == '\\') |
951 | 12.6k | _cairo_output_stream_printf (stream, "\\%c", glyph); |
952 | 2.93M | else if (glyph >= 0x20 && glyph <= 0x7e) |
953 | 2.92M | _cairo_output_stream_printf (stream, "%c", glyph); |
954 | 5.61k | else |
955 | 5.61k | _cairo_output_stream_printf (stream, "\\%03o", glyph); |
956 | 2.94M | } else { |
957 | 791k | _cairo_output_stream_printf (stream, |
958 | 791k | "%0*x", |
959 | 791k | pdf_operators->hex_width, |
960 | 791k | glyph); |
961 | 791k | } |
962 | 3.73M | } |
963 | | |
964 | 4.07M | #define GLYPH_POSITION_TOLERANCE 0.001 |
965 | | |
966 | | /* Emit the string of glyphs using the 'Tj' operator. This requires |
967 | | * that the glyphs are positioned at their natural glyph advances. */ |
968 | | static cairo_status_t |
969 | | _cairo_pdf_operators_emit_glyph_string (cairo_pdf_operators_t *pdf_operators, |
970 | | cairo_output_stream_t *stream) |
971 | 22.8k | { |
972 | 22.8k | int i; |
973 | | |
974 | 22.8k | _cairo_output_stream_printf (stream, "%s", pdf_operators->is_latin ? "(" : "<"); |
975 | 75.0k | for (i = 0; i < pdf_operators->num_glyphs; i++) { |
976 | 52.2k | _cairo_pdf_operators_emit_glyph_index (pdf_operators, |
977 | 52.2k | stream, |
978 | 52.2k | pdf_operators->glyphs[i].glyph_index); |
979 | 52.2k | pdf_operators->cur_x += pdf_operators->glyphs[i].x_advance; |
980 | 52.2k | } |
981 | 22.8k | _cairo_output_stream_printf (stream, "%sTj\n", pdf_operators->is_latin ? ")" : ">"); |
982 | | |
983 | 22.8k | return _cairo_output_stream_get_status (stream); |
984 | 22.8k | } |
985 | | |
986 | | /* Emit the string of glyphs using the 'TJ' operator. |
987 | | * |
988 | | * The TJ operator takes an array of strings of glyphs. Each string of |
989 | | * glyphs is displayed using the glyph advances of each glyph to |
990 | | * position the glyphs. A relative adjustment to the glyph advance may |
991 | | * be specified by including the adjustment between two strings. The |
992 | | * adjustment is in units of text space * -1000. |
993 | | */ |
994 | | static cairo_status_t |
995 | | _cairo_pdf_operators_emit_glyph_string_with_positioning ( |
996 | | cairo_pdf_operators_t *pdf_operators, |
997 | | cairo_output_stream_t *stream) |
998 | 162k | { |
999 | 162k | int i; |
1000 | | |
1001 | 162k | _cairo_output_stream_printf (stream, "[%s", pdf_operators->is_latin ? "(" : "<"); |
1002 | 3.84M | for (i = 0; i < pdf_operators->num_glyphs; i++) { |
1003 | 3.68M | if (pdf_operators->glyphs[i].x_position != pdf_operators->cur_x) |
1004 | 3.52M | { |
1005 | 3.52M | double delta = pdf_operators->glyphs[i].x_position - pdf_operators->cur_x; |
1006 | 3.52M | int rounded_delta; |
1007 | | |
1008 | 3.52M | delta = -1000.0*delta; |
1009 | | /* As the delta is in 1/1000 of a unit of text space, |
1010 | | * rounding to an integer should still provide sufficient |
1011 | | * precision. We round the delta before adding to Tm_x so |
1012 | | * that we keep track of the accumulated rounding error in |
1013 | | * the PDF interpreter and compensate for it when |
1014 | | * calculating subsequent deltas. |
1015 | | */ |
1016 | 3.52M | rounded_delta = _cairo_lround (delta); |
1017 | 3.52M | if (abs(rounded_delta) < 3) |
1018 | 1.07M | rounded_delta = 0; |
1019 | 3.52M | if (rounded_delta != 0) { |
1020 | 2.44M | if (pdf_operators->is_latin) { |
1021 | 1.88M | _cairo_output_stream_printf (stream, |
1022 | 1.88M | ")%d(", |
1023 | 1.88M | rounded_delta); |
1024 | 1.88M | } else { |
1025 | 558k | _cairo_output_stream_printf (stream, |
1026 | 558k | ">%d<", |
1027 | 558k | rounded_delta); |
1028 | 558k | } |
1029 | 2.44M | } |
1030 | | |
1031 | | /* Convert the rounded delta back to text |
1032 | | * space before adding to the current text |
1033 | | * position. */ |
1034 | 3.52M | delta = rounded_delta/-1000.0; |
1035 | 3.52M | pdf_operators->cur_x += delta; |
1036 | 3.52M | } |
1037 | | |
1038 | 3.68M | _cairo_pdf_operators_emit_glyph_index (pdf_operators, |
1039 | 3.68M | stream, |
1040 | 3.68M | pdf_operators->glyphs[i].glyph_index); |
1041 | 3.68M | pdf_operators->cur_x += pdf_operators->glyphs[i].x_advance; |
1042 | 3.68M | } |
1043 | 162k | _cairo_output_stream_printf (stream, "%s]TJ\n", pdf_operators->is_latin ? ")" : ">"); |
1044 | | |
1045 | 162k | return _cairo_output_stream_get_status (stream); |
1046 | 162k | } |
1047 | | |
1048 | | static cairo_status_t |
1049 | | _cairo_pdf_operators_flush_glyphs (cairo_pdf_operators_t *pdf_operators) |
1050 | 254k | { |
1051 | 254k | cairo_output_stream_t *word_wrap_stream; |
1052 | 254k | cairo_status_t status, status2; |
1053 | 254k | int i; |
1054 | 254k | double x; |
1055 | | |
1056 | 254k | if (pdf_operators->num_glyphs == 0) |
1057 | 69.5k | return CAIRO_STATUS_SUCCESS; |
1058 | | |
1059 | 185k | word_wrap_stream = _word_wrap_stream_create (pdf_operators->stream, pdf_operators->ps_output, 72); |
1060 | 185k | status = _cairo_output_stream_get_status (word_wrap_stream); |
1061 | 185k | if (unlikely (status)) |
1062 | 0 | return _cairo_output_stream_destroy (word_wrap_stream); |
1063 | | |
1064 | | /* Check if glyph advance used to position every glyph */ |
1065 | 185k | x = pdf_operators->cur_x; |
1066 | 431k | for (i = 0; i < pdf_operators->num_glyphs; i++) { |
1067 | 408k | if (fabs(pdf_operators->glyphs[i].x_position - x) > GLYPH_POSITION_TOLERANCE) |
1068 | 162k | break; |
1069 | 246k | x += pdf_operators->glyphs[i].x_advance; |
1070 | 246k | } |
1071 | 185k | if (i == pdf_operators->num_glyphs) { |
1072 | 22.8k | status = _cairo_pdf_operators_emit_glyph_string (pdf_operators, |
1073 | 22.8k | word_wrap_stream); |
1074 | 162k | } else { |
1075 | 162k | status = _cairo_pdf_operators_emit_glyph_string_with_positioning ( |
1076 | 162k | pdf_operators, word_wrap_stream); |
1077 | 162k | } |
1078 | | |
1079 | 185k | pdf_operators->num_glyphs = 0; |
1080 | 185k | pdf_operators->glyph_buf_x_pos = pdf_operators->cur_x; |
1081 | 185k | status2 = _cairo_output_stream_destroy (word_wrap_stream); |
1082 | 185k | if (status == CAIRO_STATUS_SUCCESS) |
1083 | 185k | status = status2; |
1084 | | |
1085 | 185k | return status; |
1086 | 185k | } |
1087 | | |
1088 | | static cairo_status_t |
1089 | | _cairo_pdf_operators_add_glyph (cairo_pdf_operators_t *pdf_operators, |
1090 | | cairo_scaled_font_subsets_glyph_t *glyph, |
1091 | | double x_position) |
1092 | 3.73M | { |
1093 | 3.73M | double x, y; |
1094 | | |
1095 | 3.73M | x = glyph->x_advance; |
1096 | 3.73M | y = glyph->y_advance; |
1097 | 3.73M | if (glyph->is_scaled) |
1098 | 34.1k | cairo_matrix_transform_distance (&pdf_operators->font_matrix_inverse, &x, &y); |
1099 | | |
1100 | 3.73M | pdf_operators->glyphs[pdf_operators->num_glyphs].x_position = x_position; |
1101 | 3.73M | pdf_operators->glyphs[pdf_operators->num_glyphs].glyph_index = glyph->subset_glyph_index; |
1102 | 3.73M | pdf_operators->glyphs[pdf_operators->num_glyphs].x_advance = x; |
1103 | 3.73M | pdf_operators->glyph_buf_x_pos += x; |
1104 | 3.73M | pdf_operators->num_glyphs++; |
1105 | 3.73M | if (pdf_operators->num_glyphs == PDF_GLYPH_BUFFER_SIZE) |
1106 | 0 | return _cairo_pdf_operators_flush_glyphs (pdf_operators); |
1107 | | |
1108 | 3.73M | return CAIRO_STATUS_SUCCESS; |
1109 | 3.73M | } |
1110 | | |
1111 | | /* Use 'Tm' operator to set the PDF text matrix. */ |
1112 | | static cairo_status_t |
1113 | | _cairo_pdf_operators_set_text_matrix (cairo_pdf_operators_t *pdf_operators, |
1114 | | cairo_matrix_t *matrix) |
1115 | 18.4k | { |
1116 | 18.4k | cairo_matrix_t inverse; |
1117 | 18.4k | cairo_status_t status; |
1118 | | |
1119 | | /* We require the matrix to be invertable. */ |
1120 | 18.4k | inverse = *matrix; |
1121 | 18.4k | status = cairo_matrix_invert (&inverse); |
1122 | 18.4k | if (unlikely (status)) |
1123 | 0 | return status; |
1124 | | |
1125 | 18.4k | pdf_operators->text_matrix = *matrix; |
1126 | 18.4k | pdf_operators->cur_x = 0; |
1127 | 18.4k | pdf_operators->cur_y = 0; |
1128 | 18.4k | pdf_operators->glyph_buf_x_pos = 0; |
1129 | 18.4k | _cairo_output_stream_print_matrix (pdf_operators->stream, &pdf_operators->text_matrix); |
1130 | 18.4k | _cairo_output_stream_printf (pdf_operators->stream, " Tm\n"); |
1131 | | |
1132 | 18.4k | pdf_operators->cairo_to_pdftext = *matrix; |
1133 | 18.4k | status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext); |
1134 | 18.4k | assert (status == CAIRO_STATUS_SUCCESS); |
1135 | 18.4k | cairo_matrix_multiply (&pdf_operators->cairo_to_pdftext, |
1136 | 18.4k | &pdf_operators->cairo_to_pdf, |
1137 | 18.4k | &pdf_operators->cairo_to_pdftext); |
1138 | | |
1139 | 18.4k | return _cairo_output_stream_get_status (pdf_operators->stream); |
1140 | 18.4k | } |
1141 | | |
1142 | 164k | #define TEXT_MATRIX_TOLERANCE 1e-6 |
1143 | | |
1144 | | /* Set the translation components of the PDF text matrix to x, y. The |
1145 | | * 'Td' operator is used to transform the text matrix. |
1146 | | */ |
1147 | | static cairo_status_t |
1148 | | _cairo_pdf_operators_set_text_position (cairo_pdf_operators_t *pdf_operators, |
1149 | | double x, |
1150 | | double y) |
1151 | 82.4k | { |
1152 | 82.4k | cairo_matrix_t translate, inverse; |
1153 | 82.4k | cairo_status_t status; |
1154 | | |
1155 | | /* The Td operator transforms the text_matrix with: |
1156 | | * |
1157 | | * text_matrix' = T x text_matrix |
1158 | | * |
1159 | | * where T is a translation matrix with the translation components |
1160 | | * set to the Td operands tx and ty. |
1161 | | */ |
1162 | 82.4k | inverse = pdf_operators->text_matrix; |
1163 | 82.4k | status = cairo_matrix_invert (&inverse); |
1164 | 82.4k | assert (status == CAIRO_STATUS_SUCCESS); |
1165 | 82.4k | pdf_operators->text_matrix.x0 = x; |
1166 | 82.4k | pdf_operators->text_matrix.y0 = y; |
1167 | 82.4k | cairo_matrix_multiply (&translate, &pdf_operators->text_matrix, &inverse); |
1168 | 82.4k | if (fabs(translate.x0) < TEXT_MATRIX_TOLERANCE) |
1169 | 46.0k | translate.x0 = 0.0; |
1170 | 82.4k | if (fabs(translate.y0) < TEXT_MATRIX_TOLERANCE) |
1171 | 10.1k | translate.y0 = 0.0; |
1172 | 82.4k | _cairo_output_stream_printf (pdf_operators->stream, |
1173 | 82.4k | "%f %f Td\n", |
1174 | 82.4k | translate.x0, |
1175 | 82.4k | translate.y0); |
1176 | 82.4k | pdf_operators->cur_x = 0; |
1177 | 82.4k | pdf_operators->cur_y = 0; |
1178 | 82.4k | pdf_operators->glyph_buf_x_pos = 0; |
1179 | | |
1180 | 82.4k | pdf_operators->cairo_to_pdftext = pdf_operators->text_matrix; |
1181 | 82.4k | status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext); |
1182 | 82.4k | assert (status == CAIRO_STATUS_SUCCESS); |
1183 | 82.4k | cairo_matrix_multiply (&pdf_operators->cairo_to_pdftext, |
1184 | 82.4k | &pdf_operators->cairo_to_pdf, |
1185 | 82.4k | &pdf_operators->cairo_to_pdftext); |
1186 | | |
1187 | 82.4k | return _cairo_output_stream_get_status (pdf_operators->stream); |
1188 | 82.4k | } |
1189 | | |
1190 | | /* Select the font using the 'Tf' operator. The font size is set to 1 |
1191 | | * as we use the 'Tm' operator to set the font scale. |
1192 | | */ |
1193 | | static cairo_status_t |
1194 | | _cairo_pdf_operators_set_font_subset (cairo_pdf_operators_t *pdf_operators, |
1195 | | cairo_scaled_font_subsets_glyph_t *subset_glyph) |
1196 | 91.6k | { |
1197 | 91.6k | cairo_status_t status; |
1198 | | |
1199 | 91.6k | _cairo_output_stream_printf (pdf_operators->stream, |
1200 | 91.6k | "/f-%d-%d 1 Tf\n", |
1201 | 91.6k | subset_glyph->font_id, |
1202 | 91.6k | subset_glyph->subset_id); |
1203 | 91.6k | if (pdf_operators->use_font_subset) { |
1204 | 91.6k | status = pdf_operators->use_font_subset (subset_glyph->font_id, |
1205 | 91.6k | subset_glyph->subset_id, |
1206 | 91.6k | pdf_operators->use_font_subset_closure); |
1207 | 91.6k | if (unlikely (status)) |
1208 | 0 | return status; |
1209 | 91.6k | } |
1210 | 91.6k | pdf_operators->font_id = subset_glyph->font_id; |
1211 | 91.6k | pdf_operators->subset_id = subset_glyph->subset_id; |
1212 | 91.6k | pdf_operators->is_latin = subset_glyph->is_latin; |
1213 | | |
1214 | 91.6k | if (subset_glyph->is_composite) |
1215 | 55.6k | pdf_operators->hex_width = 4; |
1216 | 35.9k | else |
1217 | 35.9k | pdf_operators->hex_width = 2; |
1218 | | |
1219 | 91.6k | return CAIRO_STATUS_SUCCESS; |
1220 | 91.6k | } |
1221 | | |
1222 | | static cairo_status_t |
1223 | | _cairo_pdf_operators_begin_text (cairo_pdf_operators_t *pdf_operators) |
1224 | 6.56k | { |
1225 | 6.56k | _cairo_output_stream_printf (pdf_operators->stream, "BT\n"); |
1226 | | |
1227 | 6.56k | pdf_operators->in_text_object = TRUE; |
1228 | 6.56k | pdf_operators->num_glyphs = 0; |
1229 | 6.56k | pdf_operators->glyph_buf_x_pos = 0; |
1230 | | |
1231 | 6.56k | return _cairo_output_stream_get_status (pdf_operators->stream); |
1232 | 6.56k | } |
1233 | | |
1234 | | static cairo_status_t |
1235 | | _cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators) |
1236 | 6.56k | { |
1237 | 6.56k | cairo_status_t status; |
1238 | | |
1239 | 6.56k | status = _cairo_pdf_operators_flush_glyphs (pdf_operators); |
1240 | 6.56k | if (unlikely (status)) |
1241 | 0 | return status; |
1242 | | |
1243 | 6.56k | _cairo_output_stream_printf (pdf_operators->stream, "ET\n"); |
1244 | | |
1245 | 6.56k | pdf_operators->in_text_object = FALSE; |
1246 | | |
1247 | 6.56k | return _cairo_output_stream_get_status (pdf_operators->stream); |
1248 | 6.56k | } |
1249 | | |
1250 | | /* Compare the scale components of two matrices. The translation |
1251 | | * components are ignored. */ |
1252 | | static cairo_bool_t |
1253 | | _cairo_matrix_scale_equal (cairo_matrix_t *a, cairo_matrix_t *b) |
1254 | 1.02M | { |
1255 | 1.02M | return (a->xx == b->xx && |
1256 | 1.01M | a->xy == b->xy && |
1257 | 1.01M | a->yx == b->yx && |
1258 | 1.01M | a->yy == b->yy); |
1259 | 1.02M | } |
1260 | | |
1261 | | static cairo_status_t |
1262 | | _cairo_pdf_operators_begin_actualtext (cairo_pdf_operators_t *pdf_operators, |
1263 | | const char *utf8, |
1264 | | int utf8_len) |
1265 | 27.7k | { |
1266 | 27.7k | uint16_t *utf16; |
1267 | 27.7k | int utf16_len; |
1268 | 27.7k | cairo_status_t status; |
1269 | 27.7k | int i; |
1270 | | |
1271 | 27.7k | _cairo_output_stream_printf (pdf_operators->stream, "/Span << /ActualText <feff"); |
1272 | 27.7k | if (utf8_len) { |
1273 | 1.17k | status = _cairo_utf8_to_utf16 (utf8, utf8_len, &utf16, &utf16_len); |
1274 | 1.17k | if (unlikely (status)) |
1275 | 0 | return status; |
1276 | | |
1277 | 2.34k | for (i = 0; i < utf16_len; i++) { |
1278 | 1.17k | _cairo_output_stream_printf (pdf_operators->stream, |
1279 | 1.17k | "%04x", (int) (utf16[i])); |
1280 | 1.17k | } |
1281 | 1.17k | free (utf16); |
1282 | 1.17k | } |
1283 | 27.7k | _cairo_output_stream_printf (pdf_operators->stream, "> >> BDC\n"); |
1284 | | |
1285 | 27.7k | return _cairo_output_stream_get_status (pdf_operators->stream); |
1286 | 27.7k | } |
1287 | | |
1288 | | static cairo_status_t |
1289 | | _cairo_pdf_operators_end_actualtext (cairo_pdf_operators_t *pdf_operators) |
1290 | 27.7k | { |
1291 | 27.7k | _cairo_output_stream_printf (pdf_operators->stream, "EMC\n"); |
1292 | | |
1293 | 27.7k | return _cairo_output_stream_get_status (pdf_operators->stream); |
1294 | 27.7k | } |
1295 | | |
1296 | | static cairo_status_t |
1297 | | _cairo_pdf_operators_emit_glyph (cairo_pdf_operators_t *pdf_operators, |
1298 | | cairo_glyph_t *glyph, |
1299 | | cairo_scaled_font_subsets_glyph_t *subset_glyph) |
1300 | 3.73M | { |
1301 | 3.73M | double x, y; |
1302 | 3.73M | cairo_status_t status; |
1303 | | |
1304 | 3.73M | if (pdf_operators->is_new_text_object || |
1305 | 3.73M | pdf_operators->font_id != subset_glyph->font_id || |
1306 | 3.67M | pdf_operators->subset_id != subset_glyph->subset_id) |
1307 | 91.6k | { |
1308 | 91.6k | status = _cairo_pdf_operators_flush_glyphs (pdf_operators); |
1309 | 91.6k | if (unlikely (status)) |
1310 | 0 | return status; |
1311 | | |
1312 | 91.6k | status = _cairo_pdf_operators_set_font_subset (pdf_operators, subset_glyph); |
1313 | 91.6k | if (unlikely (status)) |
1314 | 0 | return status; |
1315 | | |
1316 | 91.6k | pdf_operators->is_new_text_object = FALSE; |
1317 | 91.6k | } |
1318 | | |
1319 | 3.73M | x = glyph->x; |
1320 | 3.73M | y = glyph->y; |
1321 | 3.73M | cairo_matrix_transform_point (&pdf_operators->cairo_to_pdftext, &x, &y); |
1322 | | |
1323 | | /* The TJ operator for displaying text strings can only set |
1324 | | * the horizontal position of the glyphs. If the y position |
1325 | | * (in text space) changes, use the Td operator to change the |
1326 | | * current position to the next glyph. We also use the Td |
1327 | | * operator to move the current position if the horizontal |
1328 | | * position changes by more than 10 (in text space |
1329 | | * units). This is because the horizontal glyph positioning |
1330 | | * in the TJ operator is intended for kerning and there may be |
1331 | | * PDF consumers that do not handle very large position |
1332 | | * adjustments in TJ. |
1333 | | */ |
1334 | 3.73M | if (fabs(x - pdf_operators->glyph_buf_x_pos) > 10 || |
1335 | 3.66M | fabs(y - pdf_operators->cur_y) > GLYPH_POSITION_TOLERANCE) |
1336 | 82.4k | { |
1337 | 82.4k | status = _cairo_pdf_operators_flush_glyphs (pdf_operators); |
1338 | 82.4k | if (unlikely (status)) |
1339 | 0 | return status; |
1340 | | |
1341 | 82.4k | x = glyph->x; |
1342 | 82.4k | y = glyph->y; |
1343 | 82.4k | cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y); |
1344 | 82.4k | status = _cairo_pdf_operators_set_text_position (pdf_operators, x, y); |
1345 | 82.4k | if (unlikely (status)) |
1346 | 0 | return status; |
1347 | | |
1348 | 82.4k | x = 0.0; |
1349 | 82.4k | y = 0.0; |
1350 | 82.4k | } |
1351 | | |
1352 | 3.73M | status = _cairo_pdf_operators_add_glyph (pdf_operators, |
1353 | 3.73M | subset_glyph, |
1354 | 3.73M | x); |
1355 | 3.73M | return status; |
1356 | 3.73M | } |
1357 | | |
1358 | | /* A utf8_len of -1 indicates no unicode text. A utf8_len = 0 is an |
1359 | | * empty string. |
1360 | | */ |
1361 | | static cairo_int_status_t |
1362 | | _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators, |
1363 | | const char *utf8, |
1364 | | int utf8_len, |
1365 | | cairo_glyph_t *glyphs, |
1366 | | int num_glyphs, |
1367 | | cairo_text_cluster_flags_t cluster_flags, |
1368 | | cairo_scaled_font_t *scaled_font) |
1369 | 3.73M | { |
1370 | 3.73M | cairo_scaled_font_subsets_glyph_t subset_glyph; |
1371 | 3.73M | cairo_glyph_t *cur_glyph; |
1372 | 3.73M | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
1373 | 3.73M | int i; |
1374 | | |
1375 | | /* If the cluster maps 1 glyph to 1 or more unicode characters, we |
1376 | | * first try _map_glyph() with the unicode string to see if it can |
1377 | | * use toUnicode to map our glyph to the unicode. This will fail |
1378 | | * if the glyph is already mapped to a different unicode string. |
1379 | | * |
1380 | | * We also go through this path if no unicode mapping was |
1381 | | * supplied (utf8_len < 0). |
1382 | | * |
1383 | | * Mapping a glyph to a zero length unicode string requires the |
1384 | | * use of ActualText. |
1385 | | */ |
1386 | 3.73M | if (num_glyphs == 1 && utf8_len != 0) { |
1387 | 3.71M | status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets, |
1388 | 3.71M | scaled_font, |
1389 | 3.71M | glyphs->index, |
1390 | 3.71M | utf8, |
1391 | 3.71M | utf8_len, |
1392 | 3.71M | &subset_glyph); |
1393 | 3.71M | if (unlikely (status)) |
1394 | 0 | return status; |
1395 | | |
1396 | 3.71M | if (subset_glyph.utf8_is_mapped || utf8_len < 0) { |
1397 | 3.71M | status = _cairo_pdf_operators_emit_glyph (pdf_operators, |
1398 | 3.71M | glyphs, |
1399 | 3.71M | &subset_glyph); |
1400 | 3.71M | if (unlikely (status)) |
1401 | 0 | return status; |
1402 | | |
1403 | 3.71M | return CAIRO_STATUS_SUCCESS; |
1404 | 3.71M | } |
1405 | 3.71M | } |
1406 | | |
1407 | 27.7k | if (pdf_operators->use_actual_text) { |
1408 | | /* Fallback to using ActualText to map zero or more glyphs to a |
1409 | | * unicode string. */ |
1410 | 27.7k | status = _cairo_pdf_operators_flush_glyphs (pdf_operators); |
1411 | 27.7k | if (unlikely (status)) |
1412 | 0 | return status; |
1413 | | |
1414 | 27.7k | status = _cairo_pdf_operators_begin_actualtext (pdf_operators, utf8, utf8_len); |
1415 | 27.7k | if (unlikely (status)) |
1416 | 0 | return status; |
1417 | 27.7k | } |
1418 | | |
1419 | 27.7k | if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) |
1420 | 0 | cur_glyph = glyphs + num_glyphs - 1; |
1421 | 27.7k | else |
1422 | 27.7k | cur_glyph = glyphs; |
1423 | | |
1424 | | /* XXX |
1425 | | * If no glyphs, we should put *something* here for the text to be selectable. */ |
1426 | 54.8k | for (i = 0; i < num_glyphs; i++) { |
1427 | 27.0k | status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets, |
1428 | 27.0k | scaled_font, |
1429 | 27.0k | cur_glyph->index, |
1430 | 27.0k | NULL, -1, |
1431 | 27.0k | &subset_glyph); |
1432 | 27.0k | if (unlikely (status)) |
1433 | 0 | return status; |
1434 | | |
1435 | 27.0k | status = _cairo_pdf_operators_emit_glyph (pdf_operators, |
1436 | 27.0k | cur_glyph, |
1437 | 27.0k | &subset_glyph); |
1438 | 27.0k | if (unlikely (status)) |
1439 | 0 | return status; |
1440 | | |
1441 | 27.0k | if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)) |
1442 | 0 | cur_glyph--; |
1443 | 27.0k | else |
1444 | 27.0k | cur_glyph++; |
1445 | 27.0k | } |
1446 | | |
1447 | 27.7k | if (pdf_operators->use_actual_text) { |
1448 | 27.7k | status = _cairo_pdf_operators_flush_glyphs (pdf_operators); |
1449 | 27.7k | if (unlikely (status)) |
1450 | 0 | return status; |
1451 | | |
1452 | 27.7k | status = _cairo_pdf_operators_end_actualtext (pdf_operators); |
1453 | 27.7k | } |
1454 | | |
1455 | 27.7k | return status; |
1456 | 27.7k | } |
1457 | | |
1458 | | cairo_int_status_t |
1459 | | _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators, |
1460 | | const char *utf8, |
1461 | | int utf8_len, |
1462 | | cairo_glyph_t *glyphs, |
1463 | | int num_glyphs, |
1464 | | const cairo_text_cluster_t *clusters, |
1465 | | int num_clusters, |
1466 | | cairo_text_cluster_flags_t cluster_flags, |
1467 | | cairo_scaled_font_t *scaled_font) |
1468 | 1.03M | { |
1469 | 1.03M | cairo_status_t status; |
1470 | 1.03M | int i; |
1471 | 1.03M | cairo_matrix_t text_matrix, invert_y_axis; |
1472 | 1.03M | double x, y; |
1473 | 1.03M | const char *cur_text; |
1474 | 1.03M | cairo_glyph_t *cur_glyph; |
1475 | | |
1476 | 1.03M | pdf_operators->font_matrix_inverse = scaled_font->font_matrix; |
1477 | 1.03M | status = cairo_matrix_invert (&pdf_operators->font_matrix_inverse); |
1478 | 1.03M | if (status == CAIRO_STATUS_INVALID_MATRIX) |
1479 | 0 | return CAIRO_STATUS_SUCCESS; |
1480 | 1.03M | assert (status == CAIRO_STATUS_SUCCESS); |
1481 | | |
1482 | 1.03M | pdf_operators->is_new_text_object = FALSE; |
1483 | 1.03M | if (pdf_operators->in_text_object == FALSE) { |
1484 | 6.56k | status = _cairo_pdf_operators_begin_text (pdf_operators); |
1485 | 6.56k | if (unlikely (status)) |
1486 | 0 | return status; |
1487 | | |
1488 | | /* Force Tm and Tf to be emitted when starting a new text |
1489 | | * object.*/ |
1490 | 6.56k | pdf_operators->is_new_text_object = TRUE; |
1491 | 6.56k | } |
1492 | | |
1493 | 1.03M | cairo_matrix_init_scale (&invert_y_axis, 1, -1); |
1494 | 1.03M | text_matrix = scaled_font->scale; |
1495 | | |
1496 | | /* Invert y axis in device space */ |
1497 | 1.03M | cairo_matrix_multiply (&text_matrix, &invert_y_axis, &text_matrix); |
1498 | | |
1499 | 1.03M | if (pdf_operators->is_new_text_object || |
1500 | 1.02M | ! _cairo_matrix_scale_equal (&pdf_operators->text_matrix, &text_matrix)) |
1501 | 18.4k | { |
1502 | 18.4k | status = _cairo_pdf_operators_flush_glyphs (pdf_operators); |
1503 | 18.4k | if (unlikely (status)) |
1504 | 0 | return status; |
1505 | | |
1506 | 18.4k | x = glyphs[0].x; |
1507 | 18.4k | y = glyphs[0].y; |
1508 | 18.4k | cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y); |
1509 | 18.4k | text_matrix.x0 = x; |
1510 | 18.4k | text_matrix.y0 = y; |
1511 | 18.4k | status = _cairo_pdf_operators_set_text_matrix (pdf_operators, &text_matrix); |
1512 | 18.4k | if (status == CAIRO_STATUS_INVALID_MATRIX) |
1513 | 0 | return CAIRO_STATUS_SUCCESS; |
1514 | 18.4k | if (unlikely (status)) |
1515 | 0 | return status; |
1516 | 18.4k | } |
1517 | | |
1518 | 1.03M | if (num_clusters > 0) { |
1519 | 108k | cur_text = utf8; |
1520 | 108k | if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)) |
1521 | 0 | cur_glyph = glyphs + num_glyphs; |
1522 | 108k | else |
1523 | 108k | cur_glyph = glyphs; |
1524 | 330k | for (i = 0; i < num_clusters; i++) { |
1525 | 221k | if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)) |
1526 | 0 | cur_glyph -= clusters[i].num_glyphs; |
1527 | 221k | status = _cairo_pdf_operators_emit_cluster (pdf_operators, |
1528 | 221k | cur_text, |
1529 | 221k | clusters[i].num_bytes, |
1530 | 221k | cur_glyph, |
1531 | 221k | clusters[i].num_glyphs, |
1532 | 221k | cluster_flags, |
1533 | 221k | scaled_font); |
1534 | 221k | if (unlikely (status)) |
1535 | 0 | return status; |
1536 | | |
1537 | 221k | cur_text += clusters[i].num_bytes; |
1538 | 221k | if (!(cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)) |
1539 | 221k | cur_glyph += clusters[i].num_glyphs; |
1540 | 221k | } |
1541 | 924k | } else { |
1542 | 4.44M | for (i = 0; i < num_glyphs; i++) { |
1543 | 3.51M | status = _cairo_pdf_operators_emit_cluster (pdf_operators, |
1544 | 3.51M | NULL, |
1545 | 3.51M | -1, /* no unicode string available */ |
1546 | 3.51M | &glyphs[i], |
1547 | 3.51M | 1, |
1548 | 3.51M | FALSE, |
1549 | 3.51M | scaled_font); |
1550 | 3.51M | if (unlikely (status)) |
1551 | 0 | return status; |
1552 | 3.51M | } |
1553 | 924k | } |
1554 | | |
1555 | 1.03M | return _cairo_output_stream_get_status (pdf_operators->stream); |
1556 | 1.03M | } |
1557 | | |
1558 | | cairo_int_status_t |
1559 | | _cairo_pdf_operators_tag_begin (cairo_pdf_operators_t *pdf_operators, |
1560 | | const char *tag_name, |
1561 | | int mcid) |
1562 | 0 | { |
1563 | 0 | cairo_status_t status; |
1564 | |
|
1565 | 0 | if (pdf_operators->in_text_object) { |
1566 | 0 | status = _cairo_pdf_operators_end_text (pdf_operators); |
1567 | 0 | if (unlikely (status)) |
1568 | 0 | return status; |
1569 | 0 | } |
1570 | | |
1571 | 0 | if (mcid >= 0) { |
1572 | 0 | _cairo_output_stream_printf (pdf_operators->stream, |
1573 | 0 | "/%s << /MCID %d >> BDC\n", |
1574 | 0 | tag_name, |
1575 | 0 | mcid); |
1576 | 0 | } else { |
1577 | 0 | _cairo_output_stream_printf (pdf_operators->stream, |
1578 | 0 | "/%s BMC\n", |
1579 | 0 | tag_name); |
1580 | 0 | } |
1581 | |
|
1582 | 0 | return _cairo_output_stream_get_status (pdf_operators->stream); |
1583 | 0 | } |
1584 | | |
1585 | | cairo_int_status_t |
1586 | | _cairo_pdf_operators_tag_end (cairo_pdf_operators_t *pdf_operators) |
1587 | 0 | { |
1588 | 0 | cairo_status_t status; |
1589 | |
|
1590 | 0 | if (pdf_operators->in_text_object) { |
1591 | 0 | status = _cairo_pdf_operators_end_text (pdf_operators); |
1592 | 0 | if (unlikely (status)) |
1593 | 0 | return status; |
1594 | 0 | } |
1595 | | |
1596 | 0 | _cairo_output_stream_printf (pdf_operators->stream, "EMC\n"); |
1597 | |
|
1598 | 0 | return _cairo_output_stream_get_status (pdf_operators->stream); |
1599 | 0 | } |
1600 | | |
1601 | | #endif /* CAIRO_HAS_PDF_OPERATORS */ |