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