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
_cairo_pdf_operators_init(cairo_pdf_operators_t * pdf_operators,cairo_output_stream_t * stream,cairo_matrix_t * cairo_to_pdf,cairo_scaled_font_subsets_t * font_subsets,cairo_bool_t ps)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 {
63 pdf_operators->stream = stream;
64 pdf_operators->cairo_to_pdf = *cairo_to_pdf;
65 pdf_operators->font_subsets = font_subsets;
66 pdf_operators->ps_output = ps;
67 pdf_operators->use_font_subset = NULL;
68 pdf_operators->use_font_subset_closure = NULL;
69 pdf_operators->in_text_object = FALSE;
70 pdf_operators->num_glyphs = 0;
71 pdf_operators->has_line_style = FALSE;
72 pdf_operators->use_actual_text = FALSE;
73 }
74
75 cairo_status_t
_cairo_pdf_operators_fini(cairo_pdf_operators_t * pdf_operators)76 _cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators)
77 {
78 return _cairo_pdf_operators_flush (pdf_operators);
79 }
80
81 void
_cairo_pdf_operators_set_font_subsets_callback(cairo_pdf_operators_t * pdf_operators,cairo_pdf_operators_use_font_subset_t use_font_subset,void * closure)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 {
86 pdf_operators->use_font_subset = use_font_subset;
87 pdf_operators->use_font_subset_closure = closure;
88 }
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
_cairo_pdf_operators_set_stream(cairo_pdf_operators_t * pdf_operators,cairo_output_stream_t * stream)95 _cairo_pdf_operators_set_stream (cairo_pdf_operators_t *pdf_operators,
96 cairo_output_stream_t *stream)
97 {
98 pdf_operators->stream = stream;
99 pdf_operators->has_line_style = FALSE;
100 }
101
102 void
_cairo_pdf_operators_set_cairo_to_pdf_matrix(cairo_pdf_operators_t * pdf_operators,cairo_matrix_t * cairo_to_pdf)103 _cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators,
104 cairo_matrix_t *cairo_to_pdf)
105 {
106 pdf_operators->cairo_to_pdf = *cairo_to_pdf;
107 pdf_operators->has_line_style = FALSE;
108 }
109
110 cairo_private void
_cairo_pdf_operators_enable_actual_text(cairo_pdf_operators_t * pdf_operators,cairo_bool_t enable)111 _cairo_pdf_operators_enable_actual_text (cairo_pdf_operators_t *pdf_operators,
112 cairo_bool_t enable)
113 {
114 pdf_operators->use_actual_text = enable;
115 }
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
_cairo_pdf_operators_flush(cairo_pdf_operators_t * pdf_operators)129 _cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators)
130 {
131 cairo_status_t status = CAIRO_STATUS_SUCCESS;
132
133 if (pdf_operators->in_text_object)
134 status = _cairo_pdf_operators_end_text (pdf_operators);
135
136 return status;
137 }
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
_cairo_pdf_operators_reset(cairo_pdf_operators_t * pdf_operators)150 _cairo_pdf_operators_reset (cairo_pdf_operators_t *pdf_operators)
151 {
152 pdf_operators->has_line_style = FALSE;
153 }
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
_word_wrap_stream_count_word_up_to(word_wrap_stream_t * stream,const unsigned char * data,int length)192 _word_wrap_stream_count_word_up_to (word_wrap_stream_t *stream,
193 const unsigned char *data, int length)
194 {
195 const unsigned char *s = data;
196 int count = 0;
197
198 while (length--) {
199 if (_cairo_isspace (*s) || *s == '<' || *s == '(') {
200 stream->state = WRAP_STATE_DELIMITER;
201 break;
202 }
203
204 count++;
205 stream->column++;
206 s++;
207 }
208
209 if (count)
210 _cairo_output_stream_write (stream->output, data, count);
211
212 return count;
213 }
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
_word_wrap_stream_count_hexstring_up_to(word_wrap_stream_t * stream,const unsigned char * data,int length)220 _word_wrap_stream_count_hexstring_up_to (word_wrap_stream_t *stream,
221 const unsigned char *data, int length)
222 {
223 const unsigned char *s = data;
224 int count = 0;
225 cairo_bool_t newline = FALSE;
226
227 while (length--) {
228 count++;
229 stream->column++;
230 if (*s == '>') {
231 stream->state = WRAP_STATE_DELIMITER;
232 break;
233 }
234
235 if (stream->column > stream->max_column) {
236 newline = TRUE;
237 break;
238 }
239 s++;
240 }
241
242 if (count)
243 _cairo_output_stream_write (stream->output, data, count);
244
245 if (newline) {
246 _cairo_output_stream_printf (stream->output, "\n");
247 stream->column = 0;
248 }
249
250 return count;
251 }
252
253 /* Count up to either the end of the string or the number of columns
254 * remaining.
255 */
256 static int
_word_wrap_stream_count_string_up_to(word_wrap_stream_t * stream,const unsigned char * data,int length)257 _word_wrap_stream_count_string_up_to (word_wrap_stream_t *stream,
258 const unsigned char *data, int length)
259 {
260 const unsigned char *s = data;
261 int count = 0;
262 cairo_bool_t newline = FALSE;
263
264 while (length--) {
265 count++;
266 stream->column++;
267 if (!stream->in_escape) {
268 if (*s == ')') {
269 stream->state = WRAP_STATE_DELIMITER;
270 break;
271 }
272 if (*s == '\\') {
273 stream->in_escape = TRUE;
274 stream->escape_digits = 0;
275 } else if (stream->ps_output && stream->column > stream->max_column) {
276 newline = TRUE;
277 break;
278 }
279 } else {
280 if (!_cairo_isdigit(*s) || ++stream->escape_digits == 3)
281 stream->in_escape = FALSE;
282 }
283 s++;
284 }
285
286 if (count)
287 _cairo_output_stream_write (stream->output, data, count);
288
289 if (newline) {
290 _cairo_output_stream_printf (stream->output, "\\\n");
291 stream->column = 0;
292 }
293
294 return count;
295 }
296
297 static cairo_status_t
_word_wrap_stream_write(cairo_output_stream_t * base,const unsigned char * data,unsigned int length)298 _word_wrap_stream_write (cairo_output_stream_t *base,
299 const unsigned char *data,
300 unsigned int length)
301 {
302 word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
303 int count;
304
305 while (length) {
306 switch (stream->state) {
307 case WRAP_STATE_WORD:
308 count = _word_wrap_stream_count_word_up_to (stream, data, length);
309 break;
310 case WRAP_STATE_HEXSTRING:
311 count = _word_wrap_stream_count_hexstring_up_to (stream, data, length);
312 break;
313 case WRAP_STATE_STRING:
314 count = _word_wrap_stream_count_string_up_to (stream, data, length);
315 break;
316 case WRAP_STATE_DELIMITER:
317 count = 1;
318 stream->column++;
319 if (*data == '\n' || stream->column >= stream->max_column) {
320 _cairo_output_stream_printf (stream->output, "\n");
321 stream->column = 0;
322 }
323 if (*data == '<') {
324 stream->state = WRAP_STATE_HEXSTRING;
325 } else if (*data == '(') {
326 stream->state = WRAP_STATE_STRING;
327 } else if (!_cairo_isspace (*data)) {
328 stream->state = WRAP_STATE_WORD;
329 }
330 if (*data != '\n')
331 _cairo_output_stream_write (stream->output, data, 1);
332 break;
333
334 default:
335 ASSERT_NOT_REACHED;
336 count = length;
337 break;
338 }
339 data += count;
340 length -= count;
341 }
342
343 return _cairo_output_stream_get_status (stream->output);
344 }
345
346 static cairo_status_t
_word_wrap_stream_close(cairo_output_stream_t * base)347 _word_wrap_stream_close (cairo_output_stream_t *base)
348 {
349 word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
350
351 return _cairo_output_stream_get_status (stream->output);
352 }
353
354 static cairo_output_stream_t *
_word_wrap_stream_create(cairo_output_stream_t * output,cairo_bool_t ps,int max_column)355 _word_wrap_stream_create (cairo_output_stream_t *output, cairo_bool_t ps, int max_column)
356 {
357 word_wrap_stream_t *stream;
358
359 if (output->status)
360 return _cairo_output_stream_create_in_error (output->status);
361
362 stream = _cairo_malloc (sizeof (word_wrap_stream_t));
363 if (unlikely (stream == NULL)) {
364 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
365 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
366 }
367
368 _cairo_output_stream_init (&stream->base,
369 _word_wrap_stream_write,
370 NULL,
371 _word_wrap_stream_close);
372 stream->output = output;
373 stream->max_column = max_column;
374 stream->ps_output = ps;
375 stream->column = 0;
376 stream->state = WRAP_STATE_DELIMITER;
377 stream->in_escape = FALSE;
378 stream->escape_digits = 0;
379
380 return &stream->base;
381 }
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
_cairo_pdf_path_move_to(void * closure,const cairo_point_t * point)392 _cairo_pdf_path_move_to (void *closure,
393 const cairo_point_t *point)
394 {
395 pdf_path_info_t *info = closure;
396 double x = _cairo_fixed_to_double (point->x);
397 double y = _cairo_fixed_to_double (point->y);
398
399 info->last_move_to_point = *point;
400 info->has_sub_path = FALSE;
401 cairo_matrix_transform_point (info->path_transform, &x, &y);
402 _cairo_output_stream_printf (info->output,
403 "%g %g m ", x, y);
404
405 return _cairo_output_stream_get_status (info->output);
406 }
407
408 static cairo_status_t
_cairo_pdf_path_line_to(void * closure,const cairo_point_t * point)409 _cairo_pdf_path_line_to (void *closure,
410 const cairo_point_t *point)
411 {
412 pdf_path_info_t *info = closure;
413 double x = _cairo_fixed_to_double (point->x);
414 double y = _cairo_fixed_to_double (point->y);
415
416 if (info->line_cap != CAIRO_LINE_CAP_ROUND &&
417 ! info->has_sub_path &&
418 point->x == info->last_move_to_point.x &&
419 point->y == info->last_move_to_point.y)
420 {
421 return CAIRO_STATUS_SUCCESS;
422 }
423
424 info->has_sub_path = TRUE;
425 cairo_matrix_transform_point (info->path_transform, &x, &y);
426 _cairo_output_stream_printf (info->output,
427 "%g %g l ", x, y);
428
429 return _cairo_output_stream_get_status (info->output);
430 }
431
432 static cairo_status_t
_cairo_pdf_path_curve_to(void * closure,const cairo_point_t * b,const cairo_point_t * c,const cairo_point_t * d)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 {
438 pdf_path_info_t *info = closure;
439 double bx = _cairo_fixed_to_double (b->x);
440 double by = _cairo_fixed_to_double (b->y);
441 double cx = _cairo_fixed_to_double (c->x);
442 double cy = _cairo_fixed_to_double (c->y);
443 double dx = _cairo_fixed_to_double (d->x);
444 double dy = _cairo_fixed_to_double (d->y);
445
446 info->has_sub_path = TRUE;
447 cairo_matrix_transform_point (info->path_transform, &bx, &by);
448 cairo_matrix_transform_point (info->path_transform, &cx, &cy);
449 cairo_matrix_transform_point (info->path_transform, &dx, &dy);
450 _cairo_output_stream_printf (info->output,
451 "%g %g %g %g %g %g c ",
452 bx, by, cx, cy, dx, dy);
453 return _cairo_output_stream_get_status (info->output);
454 }
455
456 static cairo_status_t
_cairo_pdf_path_close_path(void * closure)457 _cairo_pdf_path_close_path (void *closure)
458 {
459 pdf_path_info_t *info = closure;
460
461 if (info->line_cap != CAIRO_LINE_CAP_ROUND &&
462 ! info->has_sub_path)
463 {
464 return CAIRO_STATUS_SUCCESS;
465 }
466
467 _cairo_output_stream_printf (info->output,
468 "h\n");
469
470 return _cairo_output_stream_get_status (info->output);
471 }
472
473 static cairo_status_t
_cairo_pdf_path_rectangle(pdf_path_info_t * info,cairo_box_t * box)474 _cairo_pdf_path_rectangle (pdf_path_info_t *info, cairo_box_t *box)
475 {
476 double x1 = _cairo_fixed_to_double (box->p1.x);
477 double y1 = _cairo_fixed_to_double (box->p1.y);
478 double x2 = _cairo_fixed_to_double (box->p2.x);
479 double y2 = _cairo_fixed_to_double (box->p2.y);
480
481 cairo_matrix_transform_point (info->path_transform, &x1, &y1);
482 cairo_matrix_transform_point (info->path_transform, &x2, &y2);
483 _cairo_output_stream_printf (info->output,
484 "%g %g %g %g re ",
485 x1, y1, x2 - x1, y2 - y1);
486
487 return _cairo_output_stream_get_status (info->output);
488 }
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
_cairo_pdf_operators_emit_path(cairo_pdf_operators_t * pdf_operators,const cairo_path_fixed_t * path,cairo_matrix_t * path_transform,cairo_line_cap_t line_cap)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 {
505 cairo_output_stream_t *word_wrap;
506 cairo_status_t status, status2;
507 pdf_path_info_t info;
508 cairo_box_t box;
509
510 word_wrap = _word_wrap_stream_create (pdf_operators->stream, pdf_operators->ps_output, 72);
511 status = _cairo_output_stream_get_status (word_wrap);
512 if (unlikely (status))
513 return _cairo_output_stream_destroy (word_wrap);
514
515 info.output = word_wrap;
516 info.path_transform = path_transform;
517 info.line_cap = line_cap;
518 if (_cairo_path_fixed_is_rectangle (path, &box) &&
519 ((path_transform->xx == 0 && path_transform->yy == 0) ||
520 (path_transform->xy == 0 && path_transform->yx == 0))) {
521 status = _cairo_pdf_path_rectangle (&info, &box);
522 } else {
523 status = _cairo_path_fixed_interpret (path,
524 _cairo_pdf_path_move_to,
525 _cairo_pdf_path_line_to,
526 _cairo_pdf_path_curve_to,
527 _cairo_pdf_path_close_path,
528 &info);
529 }
530
531 status2 = _cairo_output_stream_destroy (word_wrap);
532 if (status == CAIRO_STATUS_SUCCESS)
533 status = status2;
534
535 return status;
536 }
537
538 cairo_int_status_t
_cairo_pdf_operators_clip(cairo_pdf_operators_t * pdf_operators,const cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule)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 {
543 const char *pdf_operator;
544 cairo_status_t status;
545
546 if (pdf_operators->in_text_object) {
547 status = _cairo_pdf_operators_end_text (pdf_operators);
548 if (unlikely (status))
549 return status;
550 }
551
552 if (! path->has_current_point) {
553 /* construct an empty path */
554 _cairo_output_stream_printf (pdf_operators->stream, "0 0 m ");
555 } else {
556 status = _cairo_pdf_operators_emit_path (pdf_operators,
557 path,
558 &pdf_operators->cairo_to_pdf,
559 CAIRO_LINE_CAP_ROUND);
560 if (unlikely (status))
561 return status;
562 }
563
564 switch (fill_rule) {
565 default:
566 ASSERT_NOT_REACHED;
567 case CAIRO_FILL_RULE_WINDING:
568 pdf_operator = "W";
569 break;
570 case CAIRO_FILL_RULE_EVEN_ODD:
571 pdf_operator = "W*";
572 break;
573 }
574
575 _cairo_output_stream_printf (pdf_operators->stream,
576 "%s n\n",
577 pdf_operator);
578
579 return _cairo_output_stream_get_status (pdf_operators->stream);
580 }
581
582 static int
_cairo_pdf_line_cap(cairo_line_cap_t cap)583 _cairo_pdf_line_cap (cairo_line_cap_t cap)
584 {
585 switch (cap) {
586 case CAIRO_LINE_CAP_BUTT:
587 return 0;
588 case CAIRO_LINE_CAP_ROUND:
589 return 1;
590 case CAIRO_LINE_CAP_SQUARE:
591 return 2;
592 default:
593 ASSERT_NOT_REACHED;
594 return 0;
595 }
596 }
597
598 static int
_cairo_pdf_line_join(cairo_line_join_t join)599 _cairo_pdf_line_join (cairo_line_join_t join)
600 {
601 switch (join) {
602 case CAIRO_LINE_JOIN_MITER:
603 return 0;
604 case CAIRO_LINE_JOIN_ROUND:
605 return 1;
606 case CAIRO_LINE_JOIN_BEVEL:
607 return 2;
608 default:
609 ASSERT_NOT_REACHED;
610 return 0;
611 }
612 }
613
614 cairo_int_status_t
_cairo_pdf_operators_emit_stroke_style(cairo_pdf_operators_t * pdf_operators,const cairo_stroke_style_t * style,double scale)615 _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
616 const cairo_stroke_style_t *style,
617 double scale)
618 {
619 double *dash = style->dash;
620 int num_dashes = style->num_dashes;
621 double dash_offset = style->dash_offset;
622 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 if (num_dashes && style->line_cap == CAIRO_LINE_CAP_BUTT) {
632 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 if (num_dashes % 2) {
640 dash = _cairo_malloc_abc (num_dashes, 2, sizeof (double));
641 if (unlikely (dash == NULL))
642 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
643
644 memcpy (dash, style->dash, num_dashes * sizeof (double));
645 memcpy (dash + num_dashes, style->dash, num_dashes * sizeof (double));
646
647 num_dashes *= 2;
648 }
649
650 for (i = 0; i < num_dashes; i += 2) {
651 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 if (dash == style->dash) {
656 dash = _cairo_malloc_ab (num_dashes, sizeof (double));
657 if (unlikely (dash == NULL))
658 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
659 memcpy (dash, style->dash, num_dashes * sizeof (double));
660 }
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 if (i == 0) {
669 double last_two[2];
670
671 if (num_dashes == 2) {
672 free (dash);
673 return CAIRO_INT_STATUS_NOTHING_TO_DO;
674 }
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 memcpy (last_two, dash + num_dashes - 2, sizeof (last_two));
680 memmove (dash + 2, dash, (num_dashes - 2) * sizeof (double));
681 memcpy (dash, last_two, sizeof (last_two));
682 dash_offset += dash[0] + dash[1];
683 i = 2;
684 }
685 dash[i-1] += dash[i+1];
686 num_dashes -= 2;
687 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 if (i == 2)
692 i = -2;
693 }
694 }
695 }
696
697 if (!pdf_operators->has_line_style || pdf_operators->line_width != line_width) {
698 _cairo_output_stream_printf (pdf_operators->stream,
699 "%f w\n",
700 line_width);
701 pdf_operators->line_width = line_width;
702 }
703
704 if (!pdf_operators->has_line_style || pdf_operators->line_cap != style->line_cap) {
705 _cairo_output_stream_printf (pdf_operators->stream,
706 "%d J\n",
707 _cairo_pdf_line_cap (style->line_cap));
708 pdf_operators->line_cap = style->line_cap;
709 }
710
711 if (!pdf_operators->has_line_style || pdf_operators->line_join != style->line_join) {
712 _cairo_output_stream_printf (pdf_operators->stream,
713 "%d j\n",
714 _cairo_pdf_line_join (style->line_join));
715 pdf_operators->line_join = style->line_join;
716 }
717
718 if (num_dashes) {
719 int d;
720
721 _cairo_output_stream_printf (pdf_operators->stream, "[");
722 for (d = 0; d < num_dashes; d++)
723 _cairo_output_stream_printf (pdf_operators->stream, " %f", dash[d] * scale);
724 _cairo_output_stream_printf (pdf_operators->stream, "] %f d\n",
725 dash_offset * scale);
726 pdf_operators->has_dashes = TRUE;
727 } else if (!pdf_operators->has_line_style || pdf_operators->has_dashes) {
728 _cairo_output_stream_printf (pdf_operators->stream, "[] 0.0 d\n");
729 pdf_operators->has_dashes = FALSE;
730 }
731 if (dash != style->dash)
732 free (dash);
733
734 if (!pdf_operators->has_line_style || pdf_operators->miter_limit != style->miter_limit) {
735 _cairo_output_stream_printf (pdf_operators->stream,
736 "%f M ",
737 style->miter_limit < 1.0 ? 1.0 : style->miter_limit);
738 pdf_operators->miter_limit = style->miter_limit;
739 }
740 pdf_operators->has_line_style = TRUE;
741
742 return _cairo_output_stream_get_status (pdf_operators->stream);
743 }
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
_cairo_matrix_factor_out_scale(cairo_matrix_t * m,double * scale)755 _cairo_matrix_factor_out_scale (cairo_matrix_t *m, double *scale)
756 {
757 double s;
758
759 s = fabs (m->xx);
760 if (fabs (m->xy) > s)
761 s = fabs (m->xy);
762 if (fabs (m->yx) > s)
763 s = fabs (m->yx);
764 if (fabs (m->yy) > s)
765 s = fabs (m->yy);
766 *scale = s;
767 s = 1.0/s;
768 cairo_matrix_scale (m, s, s);
769 }
770
771 static cairo_int_status_t
_cairo_pdf_operators_emit_stroke(cairo_pdf_operators_t * pdf_operators,const cairo_path_fixed_t * path,const cairo_stroke_style_t * style,const cairo_matrix_t * ctm,const cairo_matrix_t * ctm_inverse,const char * pdf_operator)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 {
779 cairo_int_status_t status;
780 cairo_matrix_t m, path_transform;
781 cairo_bool_t has_ctm = TRUE;
782 double scale = 1.0;
783
784 if (pdf_operators->in_text_object) {
785 status = _cairo_pdf_operators_end_text (pdf_operators);
786 if (unlikely (status))
787 return status;
788 }
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 if (fabs(ctm->xx) == 1.0 && fabs(ctm->yy) == 1.0 &&
795 fabs(ctm->xy) == 0.0 && fabs(ctm->yx) == 0.0)
796 {
797 has_ctm = FALSE;
798 }
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 if (has_ctm) {
816 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 m.x0 = 0.0;
821 m.y0 = 0.0;
822 _cairo_matrix_factor_out_scale (&m, &scale);
823 path_transform = m;
824 status = cairo_matrix_invert (&path_transform);
825 if (unlikely (status))
826 return status;
827
828 cairo_matrix_multiply (&m, &m, &pdf_operators->cairo_to_pdf);
829 }
830
831 status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style, scale);
832 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
833 return CAIRO_STATUS_SUCCESS;
834 if (unlikely (status))
835 return status;
836
837 if (has_ctm) {
838 _cairo_output_stream_printf (pdf_operators->stream, "q ");
839 _cairo_output_stream_print_matrix (pdf_operators->stream, &m);
840 _cairo_output_stream_printf (pdf_operators->stream, " cm\n");
841 } else {
842 path_transform = pdf_operators->cairo_to_pdf;
843 }
844
845 status = _cairo_pdf_operators_emit_path (pdf_operators,
846 path,
847 &path_transform,
848 style->line_cap);
849 if (unlikely (status))
850 return status;
851
852 _cairo_output_stream_printf (pdf_operators->stream, "%s", pdf_operator);
853 if (has_ctm)
854 _cairo_output_stream_printf (pdf_operators->stream, " Q");
855
856 _cairo_output_stream_printf (pdf_operators->stream, "\n");
857
858 return _cairo_output_stream_get_status (pdf_operators->stream);
859 }
860
861 cairo_int_status_t
_cairo_pdf_operators_stroke(cairo_pdf_operators_t * pdf_operators,const cairo_path_fixed_t * path,const cairo_stroke_style_t * style,const cairo_matrix_t * ctm,const cairo_matrix_t * ctm_inverse)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 {
868 return _cairo_pdf_operators_emit_stroke (pdf_operators,
869 path,
870 style,
871 ctm,
872 ctm_inverse,
873 "S");
874 }
875
876 cairo_int_status_t
_cairo_pdf_operators_fill(cairo_pdf_operators_t * pdf_operators,const cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule)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 {
881 const char *pdf_operator;
882 cairo_status_t status;
883
884 if (pdf_operators->in_text_object) {
885 status = _cairo_pdf_operators_end_text (pdf_operators);
886 if (unlikely (status))
887 return status;
888 }
889
890 status = _cairo_pdf_operators_emit_path (pdf_operators,
891 path,
892 &pdf_operators->cairo_to_pdf,
893 CAIRO_LINE_CAP_ROUND);
894 if (unlikely (status))
895 return status;
896
897 switch (fill_rule) {
898 default:
899 ASSERT_NOT_REACHED;
900 case CAIRO_FILL_RULE_WINDING:
901 pdf_operator = "f";
902 break;
903 case CAIRO_FILL_RULE_EVEN_ODD:
904 pdf_operator = "f*";
905 break;
906 }
907
908 _cairo_output_stream_printf (pdf_operators->stream,
909 "%s\n",
910 pdf_operator);
911
912 return _cairo_output_stream_get_status (pdf_operators->stream);
913 }
914
915 cairo_int_status_t
_cairo_pdf_operators_fill_stroke(cairo_pdf_operators_t * pdf_operators,const cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,const cairo_stroke_style_t * style,const cairo_matrix_t * ctm,const cairo_matrix_t * ctm_inverse)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 {
923 const char *operator;
924
925 switch (fill_rule) {
926 default:
927 ASSERT_NOT_REACHED;
928 case CAIRO_FILL_RULE_WINDING:
929 operator = "B";
930 break;
931 case CAIRO_FILL_RULE_EVEN_ODD:
932 operator = "B*";
933 break;
934 }
935
936 return _cairo_pdf_operators_emit_stroke (pdf_operators,
937 path,
938 style,
939 ctm,
940 ctm_inverse,
941 operator);
942 }
943
944 static void
_cairo_pdf_operators_emit_glyph_index(cairo_pdf_operators_t * pdf_operators,cairo_output_stream_t * stream,unsigned int glyph)945 _cairo_pdf_operators_emit_glyph_index (cairo_pdf_operators_t *pdf_operators,
946 cairo_output_stream_t *stream,
947 unsigned int glyph)
948 {
949 if (pdf_operators->is_latin) {
950 if (glyph == '(' || glyph == ')' || glyph == '\\')
951 _cairo_output_stream_printf (stream, "\\%c", glyph);
952 else if (glyph >= 0x20 && glyph <= 0x7e)
953 _cairo_output_stream_printf (stream, "%c", glyph);
954 else
955 _cairo_output_stream_printf (stream, "\\%03o", glyph);
956 } else {
957 _cairo_output_stream_printf (stream,
958 "%0*x",
959 pdf_operators->hex_width,
960 glyph);
961 }
962 }
963
964 #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
_cairo_pdf_operators_emit_glyph_string(cairo_pdf_operators_t * pdf_operators,cairo_output_stream_t * stream)969 _cairo_pdf_operators_emit_glyph_string (cairo_pdf_operators_t *pdf_operators,
970 cairo_output_stream_t *stream)
971 {
972 int i;
973
974 _cairo_output_stream_printf (stream, "%s", pdf_operators->is_latin ? "(" : "<");
975 for (i = 0; i < pdf_operators->num_glyphs; i++) {
976 _cairo_pdf_operators_emit_glyph_index (pdf_operators,
977 stream,
978 pdf_operators->glyphs[i].glyph_index);
979 pdf_operators->cur_x += pdf_operators->glyphs[i].x_advance;
980 }
981 _cairo_output_stream_printf (stream, "%sTj\n", pdf_operators->is_latin ? ")" : ">");
982
983 return _cairo_output_stream_get_status (stream);
984 }
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
_cairo_pdf_operators_emit_glyph_string_with_positioning(cairo_pdf_operators_t * pdf_operators,cairo_output_stream_t * stream)995 _cairo_pdf_operators_emit_glyph_string_with_positioning (
996 cairo_pdf_operators_t *pdf_operators,
997 cairo_output_stream_t *stream)
998 {
999 int i;
1000
1001 _cairo_output_stream_printf (stream, "[%s", pdf_operators->is_latin ? "(" : "<");
1002 for (i = 0; i < pdf_operators->num_glyphs; i++) {
1003 if (pdf_operators->glyphs[i].x_position != pdf_operators->cur_x)
1004 {
1005 double delta = pdf_operators->glyphs[i].x_position - pdf_operators->cur_x;
1006 int rounded_delta;
1007
1008 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 rounded_delta = _cairo_lround (delta);
1017 if (abs(rounded_delta) < 3)
1018 rounded_delta = 0;
1019 if (rounded_delta != 0) {
1020 if (pdf_operators->is_latin) {
1021 _cairo_output_stream_printf (stream,
1022 ")%d(",
1023 rounded_delta);
1024 } else {
1025 _cairo_output_stream_printf (stream,
1026 ">%d<",
1027 rounded_delta);
1028 }
1029 }
1030
1031 /* Convert the rounded delta back to text
1032 * space before adding to the current text
1033 * position. */
1034 delta = rounded_delta/-1000.0;
1035 pdf_operators->cur_x += delta;
1036 }
1037
1038 _cairo_pdf_operators_emit_glyph_index (pdf_operators,
1039 stream,
1040 pdf_operators->glyphs[i].glyph_index);
1041 pdf_operators->cur_x += pdf_operators->glyphs[i].x_advance;
1042 }
1043 _cairo_output_stream_printf (stream, "%s]TJ\n", pdf_operators->is_latin ? ")" : ">");
1044
1045 return _cairo_output_stream_get_status (stream);
1046 }
1047
1048 static cairo_status_t
_cairo_pdf_operators_flush_glyphs(cairo_pdf_operators_t * pdf_operators)1049 _cairo_pdf_operators_flush_glyphs (cairo_pdf_operators_t *pdf_operators)
1050 {
1051 cairo_output_stream_t *word_wrap_stream;
1052 cairo_status_t status, status2;
1053 int i;
1054 double x;
1055
1056 if (pdf_operators->num_glyphs == 0)
1057 return CAIRO_STATUS_SUCCESS;
1058
1059 word_wrap_stream = _word_wrap_stream_create (pdf_operators->stream, pdf_operators->ps_output, 72);
1060 status = _cairo_output_stream_get_status (word_wrap_stream);
1061 if (unlikely (status))
1062 return _cairo_output_stream_destroy (word_wrap_stream);
1063
1064 /* Check if glyph advance used to position every glyph */
1065 x = pdf_operators->cur_x;
1066 for (i = 0; i < pdf_operators->num_glyphs; i++) {
1067 if (fabs(pdf_operators->glyphs[i].x_position - x) > GLYPH_POSITION_TOLERANCE)
1068 break;
1069 x += pdf_operators->glyphs[i].x_advance;
1070 }
1071 if (i == pdf_operators->num_glyphs) {
1072 status = _cairo_pdf_operators_emit_glyph_string (pdf_operators,
1073 word_wrap_stream);
1074 } else {
1075 status = _cairo_pdf_operators_emit_glyph_string_with_positioning (
1076 pdf_operators, word_wrap_stream);
1077 }
1078
1079 pdf_operators->num_glyphs = 0;
1080 pdf_operators->glyph_buf_x_pos = pdf_operators->cur_x;
1081 status2 = _cairo_output_stream_destroy (word_wrap_stream);
1082 if (status == CAIRO_STATUS_SUCCESS)
1083 status = status2;
1084
1085 return status;
1086 }
1087
1088 static cairo_status_t
_cairo_pdf_operators_add_glyph(cairo_pdf_operators_t * pdf_operators,cairo_scaled_font_subsets_glyph_t * glyph,double x_position)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 {
1093 double x, y;
1094
1095 x = glyph->x_advance;
1096 y = glyph->y_advance;
1097 if (glyph->is_scaled)
1098 cairo_matrix_transform_distance (&pdf_operators->font_matrix_inverse, &x, &y);
1099
1100 pdf_operators->glyphs[pdf_operators->num_glyphs].x_position = x_position;
1101 pdf_operators->glyphs[pdf_operators->num_glyphs].glyph_index = glyph->subset_glyph_index;
1102 pdf_operators->glyphs[pdf_operators->num_glyphs].x_advance = x;
1103 pdf_operators->glyph_buf_x_pos += x;
1104 pdf_operators->num_glyphs++;
1105 if (pdf_operators->num_glyphs == PDF_GLYPH_BUFFER_SIZE)
1106 return _cairo_pdf_operators_flush_glyphs (pdf_operators);
1107
1108 return CAIRO_STATUS_SUCCESS;
1109 }
1110
1111 /* Use 'Tm' operator to set the PDF text matrix. */
1112 static cairo_status_t
_cairo_pdf_operators_set_text_matrix(cairo_pdf_operators_t * pdf_operators,cairo_matrix_t * matrix)1113 _cairo_pdf_operators_set_text_matrix (cairo_pdf_operators_t *pdf_operators,
1114 cairo_matrix_t *matrix)
1115 {
1116 cairo_matrix_t inverse;
1117 cairo_status_t status;
1118
1119 /* We require the matrix to be invertable. */
1120 inverse = *matrix;
1121 status = cairo_matrix_invert (&inverse);
1122 if (unlikely (status))
1123 return status;
1124
1125 pdf_operators->text_matrix = *matrix;
1126 pdf_operators->cur_x = 0;
1127 pdf_operators->cur_y = 0;
1128 pdf_operators->glyph_buf_x_pos = 0;
1129 _cairo_output_stream_print_matrix (pdf_operators->stream, &pdf_operators->text_matrix);
1130 _cairo_output_stream_printf (pdf_operators->stream, " Tm\n");
1131
1132 pdf_operators->cairo_to_pdftext = *matrix;
1133 status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext);
1134 assert (status == CAIRO_STATUS_SUCCESS);
1135 cairo_matrix_multiply (&pdf_operators->cairo_to_pdftext,
1136 &pdf_operators->cairo_to_pdf,
1137 &pdf_operators->cairo_to_pdftext);
1138
1139 return _cairo_output_stream_get_status (pdf_operators->stream);
1140 }
1141
1142 #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
_cairo_pdf_operators_set_text_position(cairo_pdf_operators_t * pdf_operators,double x,double y)1148 _cairo_pdf_operators_set_text_position (cairo_pdf_operators_t *pdf_operators,
1149 double x,
1150 double y)
1151 {
1152 cairo_matrix_t translate, inverse;
1153 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 inverse = pdf_operators->text_matrix;
1163 status = cairo_matrix_invert (&inverse);
1164 assert (status == CAIRO_STATUS_SUCCESS);
1165 pdf_operators->text_matrix.x0 = x;
1166 pdf_operators->text_matrix.y0 = y;
1167 cairo_matrix_multiply (&translate, &pdf_operators->text_matrix, &inverse);
1168 if (fabs(translate.x0) < TEXT_MATRIX_TOLERANCE)
1169 translate.x0 = 0.0;
1170 if (fabs(translate.y0) < TEXT_MATRIX_TOLERANCE)
1171 translate.y0 = 0.0;
1172 _cairo_output_stream_printf (pdf_operators->stream,
1173 "%f %f Td\n",
1174 translate.x0,
1175 translate.y0);
1176 pdf_operators->cur_x = 0;
1177 pdf_operators->cur_y = 0;
1178 pdf_operators->glyph_buf_x_pos = 0;
1179
1180 pdf_operators->cairo_to_pdftext = pdf_operators->text_matrix;
1181 status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext);
1182 assert (status == CAIRO_STATUS_SUCCESS);
1183 cairo_matrix_multiply (&pdf_operators->cairo_to_pdftext,
1184 &pdf_operators->cairo_to_pdf,
1185 &pdf_operators->cairo_to_pdftext);
1186
1187 return _cairo_output_stream_get_status (pdf_operators->stream);
1188 }
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
_cairo_pdf_operators_set_font_subset(cairo_pdf_operators_t * pdf_operators,cairo_scaled_font_subsets_glyph_t * subset_glyph)1194 _cairo_pdf_operators_set_font_subset (cairo_pdf_operators_t *pdf_operators,
1195 cairo_scaled_font_subsets_glyph_t *subset_glyph)
1196 {
1197 cairo_status_t status;
1198
1199 _cairo_output_stream_printf (pdf_operators->stream,
1200 "/f-%d-%d 1 Tf\n",
1201 subset_glyph->font_id,
1202 subset_glyph->subset_id);
1203 if (pdf_operators->use_font_subset) {
1204 status = pdf_operators->use_font_subset (subset_glyph->font_id,
1205 subset_glyph->subset_id,
1206 pdf_operators->use_font_subset_closure);
1207 if (unlikely (status))
1208 return status;
1209 }
1210 pdf_operators->font_id = subset_glyph->font_id;
1211 pdf_operators->subset_id = subset_glyph->subset_id;
1212 pdf_operators->is_latin = subset_glyph->is_latin;
1213
1214 if (subset_glyph->is_composite)
1215 pdf_operators->hex_width = 4;
1216 else
1217 pdf_operators->hex_width = 2;
1218
1219 return CAIRO_STATUS_SUCCESS;
1220 }
1221
1222 static cairo_status_t
_cairo_pdf_operators_begin_text(cairo_pdf_operators_t * pdf_operators)1223 _cairo_pdf_operators_begin_text (cairo_pdf_operators_t *pdf_operators)
1224 {
1225 _cairo_output_stream_printf (pdf_operators->stream, "BT\n");
1226
1227 pdf_operators->in_text_object = TRUE;
1228 pdf_operators->num_glyphs = 0;
1229 pdf_operators->glyph_buf_x_pos = 0;
1230
1231 return _cairo_output_stream_get_status (pdf_operators->stream);
1232 }
1233
1234 static cairo_status_t
_cairo_pdf_operators_end_text(cairo_pdf_operators_t * pdf_operators)1235 _cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators)
1236 {
1237 cairo_status_t status;
1238
1239 status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
1240 if (unlikely (status))
1241 return status;
1242
1243 _cairo_output_stream_printf (pdf_operators->stream, "ET\n");
1244
1245 pdf_operators->in_text_object = FALSE;
1246
1247 return _cairo_output_stream_get_status (pdf_operators->stream);
1248 }
1249
1250 /* Compare the scale components of two matrices. The translation
1251 * components are ignored. */
1252 static cairo_bool_t
_cairo_matrix_scale_equal(cairo_matrix_t * a,cairo_matrix_t * b)1253 _cairo_matrix_scale_equal (cairo_matrix_t *a, cairo_matrix_t *b)
1254 {
1255 return (a->xx == b->xx &&
1256 a->xy == b->xy &&
1257 a->yx == b->yx &&
1258 a->yy == b->yy);
1259 }
1260
1261 static cairo_status_t
_cairo_pdf_operators_begin_actualtext(cairo_pdf_operators_t * pdf_operators,const char * utf8,int utf8_len)1262 _cairo_pdf_operators_begin_actualtext (cairo_pdf_operators_t *pdf_operators,
1263 const char *utf8,
1264 int utf8_len)
1265 {
1266 uint16_t *utf16;
1267 int utf16_len;
1268 cairo_status_t status;
1269 int i;
1270
1271 _cairo_output_stream_printf (pdf_operators->stream, "/Span << /ActualText <feff");
1272 if (utf8_len) {
1273 status = _cairo_utf8_to_utf16 (utf8, utf8_len, &utf16, &utf16_len);
1274 if (unlikely (status))
1275 return status;
1276
1277 for (i = 0; i < utf16_len; i++) {
1278 _cairo_output_stream_printf (pdf_operators->stream,
1279 "%04x", (int) (utf16[i]));
1280 }
1281 free (utf16);
1282 }
1283 _cairo_output_stream_printf (pdf_operators->stream, "> >> BDC\n");
1284
1285 return _cairo_output_stream_get_status (pdf_operators->stream);
1286 }
1287
1288 static cairo_status_t
_cairo_pdf_operators_end_actualtext(cairo_pdf_operators_t * pdf_operators)1289 _cairo_pdf_operators_end_actualtext (cairo_pdf_operators_t *pdf_operators)
1290 {
1291 _cairo_output_stream_printf (pdf_operators->stream, "EMC\n");
1292
1293 return _cairo_output_stream_get_status (pdf_operators->stream);
1294 }
1295
1296 static cairo_status_t
_cairo_pdf_operators_emit_glyph(cairo_pdf_operators_t * pdf_operators,cairo_glyph_t * glyph,cairo_scaled_font_subsets_glyph_t * subset_glyph)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 {
1301 double x, y;
1302 cairo_status_t status;
1303
1304 if (pdf_operators->is_new_text_object ||
1305 pdf_operators->font_id != subset_glyph->font_id ||
1306 pdf_operators->subset_id != subset_glyph->subset_id)
1307 {
1308 status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
1309 if (unlikely (status))
1310 return status;
1311
1312 status = _cairo_pdf_operators_set_font_subset (pdf_operators, subset_glyph);
1313 if (unlikely (status))
1314 return status;
1315
1316 pdf_operators->is_new_text_object = FALSE;
1317 }
1318
1319 x = glyph->x;
1320 y = glyph->y;
1321 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 if (fabs(x - pdf_operators->glyph_buf_x_pos) > 10 ||
1335 fabs(y - pdf_operators->cur_y) > GLYPH_POSITION_TOLERANCE)
1336 {
1337 status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
1338 if (unlikely (status))
1339 return status;
1340
1341 x = glyph->x;
1342 y = glyph->y;
1343 cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y);
1344 status = _cairo_pdf_operators_set_text_position (pdf_operators, x, y);
1345 if (unlikely (status))
1346 return status;
1347
1348 x = 0.0;
1349 y = 0.0;
1350 }
1351
1352 status = _cairo_pdf_operators_add_glyph (pdf_operators,
1353 subset_glyph,
1354 x);
1355 return status;
1356 }
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
_cairo_pdf_operators_emit_cluster(cairo_pdf_operators_t * pdf_operators,const char * utf8,int utf8_len,cairo_glyph_t * glyphs,int num_glyphs,cairo_text_cluster_flags_t cluster_flags,cairo_scaled_font_t * scaled_font)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 {
1370 cairo_scaled_font_subsets_glyph_t subset_glyph;
1371 cairo_glyph_t *cur_glyph;
1372 cairo_status_t status = CAIRO_STATUS_SUCCESS;
1373 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 if (num_glyphs == 1 && utf8_len != 0) {
1387 status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
1388 scaled_font,
1389 glyphs->index,
1390 utf8,
1391 utf8_len,
1392 &subset_glyph);
1393 if (unlikely (status))
1394 return status;
1395
1396 if (subset_glyph.utf8_is_mapped || utf8_len < 0) {
1397 status = _cairo_pdf_operators_emit_glyph (pdf_operators,
1398 glyphs,
1399 &subset_glyph);
1400 if (unlikely (status))
1401 return status;
1402
1403 return CAIRO_STATUS_SUCCESS;
1404 }
1405 }
1406
1407 if (pdf_operators->use_actual_text) {
1408 /* Fallback to using ActualText to map zero or more glyphs to a
1409 * unicode string. */
1410 status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
1411 if (unlikely (status))
1412 return status;
1413
1414 status = _cairo_pdf_operators_begin_actualtext (pdf_operators, utf8, utf8_len);
1415 if (unlikely (status))
1416 return status;
1417 }
1418
1419 if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
1420 cur_glyph = glyphs + num_glyphs - 1;
1421 else
1422 cur_glyph = glyphs;
1423
1424 /* XXX
1425 * If no glyphs, we should put *something* here for the text to be selectable. */
1426 for (i = 0; i < num_glyphs; i++) {
1427 status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
1428 scaled_font,
1429 cur_glyph->index,
1430 NULL, -1,
1431 &subset_glyph);
1432 if (unlikely (status))
1433 return status;
1434
1435 status = _cairo_pdf_operators_emit_glyph (pdf_operators,
1436 cur_glyph,
1437 &subset_glyph);
1438 if (unlikely (status))
1439 return status;
1440
1441 if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD))
1442 cur_glyph--;
1443 else
1444 cur_glyph++;
1445 }
1446
1447 if (pdf_operators->use_actual_text) {
1448 status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
1449 if (unlikely (status))
1450 return status;
1451
1452 status = _cairo_pdf_operators_end_actualtext (pdf_operators);
1453 }
1454
1455 return status;
1456 }
1457
1458 cairo_int_status_t
_cairo_pdf_operators_show_text_glyphs(cairo_pdf_operators_t * pdf_operators,const char * utf8,int utf8_len,cairo_glyph_t * glyphs,int num_glyphs,const cairo_text_cluster_t * clusters,int num_clusters,cairo_text_cluster_flags_t cluster_flags,cairo_scaled_font_t * scaled_font)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 {
1469 cairo_status_t status;
1470 int i;
1471 cairo_matrix_t text_matrix, invert_y_axis;
1472 double x, y;
1473 const char *cur_text;
1474 cairo_glyph_t *cur_glyph;
1475
1476 pdf_operators->font_matrix_inverse = scaled_font->font_matrix;
1477 status = cairo_matrix_invert (&pdf_operators->font_matrix_inverse);
1478 if (status == CAIRO_STATUS_INVALID_MATRIX)
1479 return CAIRO_STATUS_SUCCESS;
1480 assert (status == CAIRO_STATUS_SUCCESS);
1481
1482 pdf_operators->is_new_text_object = FALSE;
1483 if (pdf_operators->in_text_object == FALSE) {
1484 status = _cairo_pdf_operators_begin_text (pdf_operators);
1485 if (unlikely (status))
1486 return status;
1487
1488 /* Force Tm and Tf to be emitted when starting a new text
1489 * object.*/
1490 pdf_operators->is_new_text_object = TRUE;
1491 }
1492
1493 cairo_matrix_init_scale (&invert_y_axis, 1, -1);
1494 text_matrix = scaled_font->scale;
1495
1496 /* Invert y axis in device space */
1497 cairo_matrix_multiply (&text_matrix, &invert_y_axis, &text_matrix);
1498
1499 if (pdf_operators->is_new_text_object ||
1500 ! _cairo_matrix_scale_equal (&pdf_operators->text_matrix, &text_matrix))
1501 {
1502 status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
1503 if (unlikely (status))
1504 return status;
1505
1506 x = glyphs[0].x;
1507 y = glyphs[0].y;
1508 cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y);
1509 text_matrix.x0 = x;
1510 text_matrix.y0 = y;
1511 status = _cairo_pdf_operators_set_text_matrix (pdf_operators, &text_matrix);
1512 if (status == CAIRO_STATUS_INVALID_MATRIX)
1513 return CAIRO_STATUS_SUCCESS;
1514 if (unlikely (status))
1515 return status;
1516 }
1517
1518 if (num_clusters > 0) {
1519 cur_text = utf8;
1520 if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD))
1521 cur_glyph = glyphs + num_glyphs;
1522 else
1523 cur_glyph = glyphs;
1524 for (i = 0; i < num_clusters; i++) {
1525 if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD))
1526 cur_glyph -= clusters[i].num_glyphs;
1527 status = _cairo_pdf_operators_emit_cluster (pdf_operators,
1528 cur_text,
1529 clusters[i].num_bytes,
1530 cur_glyph,
1531 clusters[i].num_glyphs,
1532 cluster_flags,
1533 scaled_font);
1534 if (unlikely (status))
1535 return status;
1536
1537 cur_text += clusters[i].num_bytes;
1538 if (!(cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD))
1539 cur_glyph += clusters[i].num_glyphs;
1540 }
1541 } else {
1542 for (i = 0; i < num_glyphs; i++) {
1543 status = _cairo_pdf_operators_emit_cluster (pdf_operators,
1544 NULL,
1545 -1, /* no unicode string available */
1546 &glyphs[i],
1547 1,
1548 FALSE,
1549 scaled_font);
1550 if (unlikely (status))
1551 return status;
1552 }
1553 }
1554
1555 return _cairo_output_stream_get_status (pdf_operators->stream);
1556 }
1557
1558 cairo_int_status_t
_cairo_pdf_operators_tag_begin(cairo_pdf_operators_t * pdf_operators,const char * tag_name,int mcid)1559 _cairo_pdf_operators_tag_begin (cairo_pdf_operators_t *pdf_operators,
1560 const char *tag_name,
1561 int mcid)
1562 {
1563 cairo_status_t status;
1564
1565 if (pdf_operators->in_text_object) {
1566 status = _cairo_pdf_operators_end_text (pdf_operators);
1567 if (unlikely (status))
1568 return status;
1569 }
1570
1571 _cairo_output_stream_printf (pdf_operators->stream,
1572 "/%s << /MCID %d >> BDC\n",
1573 tag_name,
1574 mcid);
1575
1576 return _cairo_output_stream_get_status (pdf_operators->stream);
1577 }
1578
1579 cairo_int_status_t
_cairo_pdf_operators_tag_end(cairo_pdf_operators_t * pdf_operators)1580 _cairo_pdf_operators_tag_end (cairo_pdf_operators_t *pdf_operators)
1581 {
1582 cairo_status_t status;
1583
1584 if (pdf_operators->in_text_object) {
1585 status = _cairo_pdf_operators_end_text (pdf_operators);
1586 if (unlikely (status))
1587 return status;
1588 }
1589
1590 _cairo_output_stream_printf (pdf_operators->stream, "EMC\n");
1591
1592 return _cairo_output_stream_get_status (pdf_operators->stream);
1593 }
1594
1595 #endif /* CAIRO_HAS_PDF_OPERATORS */
1596