ShaderEffect subclasses from Effect, not DependencyObject
[moon.git] / cairo / src / cairo-pdf-operators.c
blob819318a19b6cfcc7acb55dd0e54b88eef3fbb32a
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
4 * Copyright © 2004 Red Hat, Inc
5 * Copyright © 2006 Red Hat, Inc
6 * Copyright © 2007, 2008 Adrian Johnson
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * You should have received a copy of the MPL along with this library
20 * in the file COPYING-MPL-1.1
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/
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.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is University of Southern
34 * California.
36 * Contributor(s):
37 * Kristian Høgsberg <krh@redhat.com>
38 * Carl Worth <cworth@cworth.org>
39 * Adrian Johnson <ajohnson@redneon.com>
42 #include "cairoint.h"
44 #if CAIRO_HAS_PDF_OPERATORS
46 #include "cairo-pdf-operators-private.h"
47 #include "cairo-path-fixed-private.h"
48 #include "cairo-output-stream-private.h"
49 #include "cairo-scaled-font-subsets-private.h"
51 #include <ctype.h>
53 static cairo_status_t
54 _cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators);
57 void
58 _cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators,
59 cairo_output_stream_t *stream,
60 cairo_matrix_t *cairo_to_pdf,
61 cairo_scaled_font_subsets_t *font_subsets)
63 pdf_operators->stream = stream;
64 pdf_operators->cairo_to_pdf = *cairo_to_pdf;
65 pdf_operators->font_subsets = font_subsets;
66 pdf_operators->use_font_subset = NULL;
67 pdf_operators->use_font_subset_closure = NULL;
68 pdf_operators->in_text_object = FALSE;
69 pdf_operators->num_glyphs = 0;
70 pdf_operators->has_line_style = FALSE;
73 cairo_status_t
74 _cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators)
76 return _cairo_pdf_operators_flush (pdf_operators);
79 void
80 _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)
84 pdf_operators->use_font_subset = use_font_subset;
85 pdf_operators->use_font_subset_closure = closure;
88 /* Change the output stream to a different stream.
89 * _cairo_pdf_operators_flush() should always be called before calling
90 * this function.
92 void
93 _cairo_pdf_operators_set_stream (cairo_pdf_operators_t *pdf_operators,
94 cairo_output_stream_t *stream)
96 pdf_operators->stream = stream;
97 pdf_operators->has_line_style = FALSE;
100 void
101 _cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators,
102 cairo_matrix_t *cairo_to_pdf)
104 pdf_operators->cairo_to_pdf = *cairo_to_pdf;
105 pdf_operators->has_line_style = FALSE;
108 /* Finish writing out any pending commands to the stream. This
109 * function must be called by the surface before emitting anything
110 * into the PDF stream.
112 * pdf_operators may leave the emitted PDF for some operations
113 * unfinished in case subsequent operations can be merged. This
114 * function will finish off any incomplete operation so the stream
115 * will be in a state where the surface may emit it's own PDF
116 * operations (eg changing patterns).
119 cairo_status_t
120 _cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators)
122 cairo_status_t status = CAIRO_STATUS_SUCCESS;
124 if (pdf_operators->in_text_object)
125 status = _cairo_pdf_operators_end_text (pdf_operators);
127 return status;
130 /* Reset the known graphics state of the PDF consumer. ie no
131 * assumptions will be made about the state. The next time a
132 * particular graphics state is required (eg line width) the state
133 * operator is always emitted and then remembered for subsequent
134 * operatations.
136 * This should be called when starting a new stream or after emitting
137 * the 'Q' operator (where pdf-operators functions were called inside
138 * the q/Q pair).
140 void
141 _cairo_pdf_operators_reset (cairo_pdf_operators_t *pdf_operators)
143 pdf_operators->has_line_style = FALSE;
146 /* A word wrap stream can be used as a filter to do word wrapping on
147 * top of an existing output stream. The word wrapping is quite
148 * simple, using isspace to determine characters that separate
149 * words. Any word that will cause the column count exceed the given
150 * max_column will have a '\n' character emitted before it.
152 * The stream is careful to maintain integrity for words that cross
153 * the boundary from one call to write to the next.
155 * Note: This stream does not guarantee that the output will never
156 * exceed max_column. In particular, if a single word is larger than
157 * max_column it will not be broken up.
159 typedef struct _word_wrap_stream {
160 cairo_output_stream_t base;
161 cairo_output_stream_t *output;
162 int max_column;
163 int column;
164 cairo_bool_t last_write_was_space;
165 cairo_bool_t in_hexstring;
166 cairo_bool_t empty_hexstring;
167 } word_wrap_stream_t;
169 static int
170 _count_word_up_to (const unsigned char *s, int length)
172 int word = 0;
174 while (length--) {
175 if (! (isspace (*s) || *s == '<')) {
176 s++;
177 word++;
178 } else {
179 return word;
183 return word;
187 /* Count up to either the end of the ASCII hexstring or the number
188 * of columns remaining.
190 static int
191 _count_hexstring_up_to (const unsigned char *s, int length, int columns)
193 int word = 0;
195 while (length--) {
196 if (*s++ != '>')
197 word++;
198 else
199 return word;
201 columns--;
202 if (columns < 0 && word > 1)
203 return word;
206 return word;
209 static cairo_status_t
210 _word_wrap_stream_write (cairo_output_stream_t *base,
211 const unsigned char *data,
212 unsigned int length)
214 word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
215 cairo_bool_t newline;
216 int word;
218 while (length) {
219 if (*data == '<') {
220 stream->in_hexstring = TRUE;
221 stream->empty_hexstring = TRUE;
222 stream->last_write_was_space = FALSE;
223 data++;
224 length--;
225 _cairo_output_stream_printf (stream->output, "<");
226 stream->column++;
227 } else if (*data == '>') {
228 stream->in_hexstring = FALSE;
229 stream->last_write_was_space = FALSE;
230 data++;
231 length--;
232 _cairo_output_stream_printf (stream->output, ">");
233 stream->column++;
234 } else if (isspace (*data)) {
235 newline = (*data == '\n' || *data == '\r');
236 if (! newline && stream->column >= stream->max_column) {
237 _cairo_output_stream_printf (stream->output, "\n");
238 stream->column = 0;
240 _cairo_output_stream_write (stream->output, data, 1);
241 data++;
242 length--;
243 if (newline) {
244 stream->column = 0;
246 else
247 stream->column++;
248 stream->last_write_was_space = TRUE;
249 } else {
250 if (stream->in_hexstring) {
251 word = _count_hexstring_up_to (data, length,
252 MAX (stream->max_column - stream->column, 0));
253 } else {
254 word = _count_word_up_to (data, length);
256 /* Don't wrap if this word is a continuation of a non hex
257 * string word from a previous call to write. */
258 if (stream->column + word >= stream->max_column) {
259 if (stream->last_write_was_space ||
260 (stream->in_hexstring && !stream->empty_hexstring))
262 _cairo_output_stream_printf (stream->output, "\n");
263 stream->column = 0;
266 _cairo_output_stream_write (stream->output, data, word);
267 data += word;
268 length -= word;
269 stream->column += word;
270 stream->last_write_was_space = FALSE;
271 if (stream->in_hexstring)
272 stream->empty_hexstring = FALSE;
276 return _cairo_output_stream_get_status (stream->output);
279 static cairo_status_t
280 _word_wrap_stream_close (cairo_output_stream_t *base)
282 word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
284 return _cairo_output_stream_get_status (stream->output);
287 static cairo_output_stream_t *
288 _word_wrap_stream_create (cairo_output_stream_t *output, int max_column)
290 word_wrap_stream_t *stream;
292 if (output->status)
293 return _cairo_output_stream_create_in_error (output->status);
295 stream = malloc (sizeof (word_wrap_stream_t));
296 if (stream == NULL) {
297 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
298 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
301 _cairo_output_stream_init (&stream->base,
302 _word_wrap_stream_write,
303 _word_wrap_stream_close);
304 stream->output = output;
305 stream->max_column = max_column;
306 stream->column = 0;
307 stream->last_write_was_space = FALSE;
308 stream->in_hexstring = FALSE;
309 stream->empty_hexstring = TRUE;
311 return &stream->base;
314 typedef struct _pdf_path_info {
315 cairo_output_stream_t *output;
316 cairo_matrix_t *path_transform;
317 cairo_line_cap_t line_cap;
318 cairo_point_t last_move_to_point;
319 cairo_bool_t has_sub_path;
320 } pdf_path_info_t;
322 static cairo_status_t
323 _cairo_pdf_path_move_to (void *closure, cairo_point_t *point)
325 pdf_path_info_t *info = closure;
326 double x = _cairo_fixed_to_double (point->x);
327 double y = _cairo_fixed_to_double (point->y);
329 info->last_move_to_point = *point;
330 info->has_sub_path = FALSE;
331 cairo_matrix_transform_point (info->path_transform, &x, &y);
332 _cairo_output_stream_printf (info->output,
333 "%g %g m ", x, y);
335 return _cairo_output_stream_get_status (info->output);
338 static cairo_status_t
339 _cairo_pdf_path_line_to (void *closure, cairo_point_t *point)
341 pdf_path_info_t *info = closure;
342 double x = _cairo_fixed_to_double (point->x);
343 double y = _cairo_fixed_to_double (point->y);
345 if (info->line_cap != CAIRO_LINE_CAP_ROUND &&
346 ! info->has_sub_path &&
347 point->x == info->last_move_to_point.x &&
348 point->y == info->last_move_to_point.y)
350 return CAIRO_STATUS_SUCCESS;
353 info->has_sub_path = TRUE;
354 cairo_matrix_transform_point (info->path_transform, &x, &y);
355 _cairo_output_stream_printf (info->output,
356 "%g %g l ", x, y);
358 return _cairo_output_stream_get_status (info->output);
361 static cairo_status_t
362 _cairo_pdf_path_curve_to (void *closure,
363 cairo_point_t *b,
364 cairo_point_t *c,
365 cairo_point_t *d)
367 pdf_path_info_t *info = closure;
368 double bx = _cairo_fixed_to_double (b->x);
369 double by = _cairo_fixed_to_double (b->y);
370 double cx = _cairo_fixed_to_double (c->x);
371 double cy = _cairo_fixed_to_double (c->y);
372 double dx = _cairo_fixed_to_double (d->x);
373 double dy = _cairo_fixed_to_double (d->y);
375 info->has_sub_path = TRUE;
376 cairo_matrix_transform_point (info->path_transform, &bx, &by);
377 cairo_matrix_transform_point (info->path_transform, &cx, &cy);
378 cairo_matrix_transform_point (info->path_transform, &dx, &dy);
379 _cairo_output_stream_printf (info->output,
380 "%g %g %g %g %g %g c ",
381 bx, by, cx, cy, dx, dy);
382 return _cairo_output_stream_get_status (info->output);
385 static cairo_status_t
386 _cairo_pdf_path_close_path (void *closure)
388 pdf_path_info_t *info = closure;
390 if (info->line_cap != CAIRO_LINE_CAP_ROUND &&
391 ! info->has_sub_path)
393 return CAIRO_STATUS_SUCCESS;
396 _cairo_output_stream_printf (info->output,
397 "h\n");
399 return _cairo_output_stream_get_status (info->output);
402 static cairo_status_t
403 _cairo_pdf_path_rectangle (pdf_path_info_t *info, cairo_box_t *box)
405 double x1 = _cairo_fixed_to_double (box->p1.x);
406 double y1 = _cairo_fixed_to_double (box->p1.y);
407 double x2 = _cairo_fixed_to_double (box->p2.x);
408 double y2 = _cairo_fixed_to_double (box->p2.y);
410 cairo_matrix_transform_point (info->path_transform, &x1, &y1);
411 cairo_matrix_transform_point (info->path_transform, &x2, &y2);
412 _cairo_output_stream_printf (info->output,
413 "%g %g %g %g re ",
414 x1, y1, x2 - x1, y2 - y1);
416 return _cairo_output_stream_get_status (info->output);
419 /* The line cap value is needed to workaround the fact that PostScript
420 * and PDF semantics for stroking degenerate sub-paths do not match
421 * cairo semantics. (PostScript draws something for any line cap
422 * value, while cairo draws something only for round caps).
424 * When using this function to emit a path to be filled, rather than
425 * stroked, simply pass %CAIRO_LINE_CAP_ROUND which will guarantee that
426 * the stroke workaround will not modify the path being emitted.
428 static cairo_status_t
429 _cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators,
430 cairo_path_fixed_t *path,
431 cairo_matrix_t *path_transform,
432 cairo_line_cap_t line_cap)
434 cairo_output_stream_t *word_wrap;
435 cairo_status_t status, status2;
436 pdf_path_info_t info;
437 cairo_box_t box;
439 word_wrap = _word_wrap_stream_create (pdf_operators->stream, 72);
440 status = _cairo_output_stream_get_status (word_wrap);
441 if (status)
442 return _cairo_output_stream_destroy (word_wrap);
444 info.output = word_wrap;
445 info.path_transform = path_transform;
446 info.line_cap = line_cap;
447 if (_cairo_path_fixed_is_rectangle (path, &box)) {
448 status = _cairo_pdf_path_rectangle (&info, &box);
449 } else {
450 status = _cairo_path_fixed_interpret (path,
451 CAIRO_DIRECTION_FORWARD,
452 _cairo_pdf_path_move_to,
453 _cairo_pdf_path_line_to,
454 _cairo_pdf_path_curve_to,
455 _cairo_pdf_path_close_path,
456 &info);
459 status2 = _cairo_output_stream_destroy (word_wrap);
460 if (status == CAIRO_STATUS_SUCCESS)
461 status = status2;
463 return status;
466 cairo_int_status_t
467 _cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators,
468 cairo_path_fixed_t *path,
469 cairo_fill_rule_t fill_rule)
471 const char *pdf_operator;
472 cairo_status_t status;
474 if (! path->has_current_point) {
475 /* construct an empty path */
476 _cairo_output_stream_printf (pdf_operators->stream, "0 0 m ");
477 } else {
478 status = _cairo_pdf_operators_emit_path (pdf_operators,
479 path,
480 &pdf_operators->cairo_to_pdf,
481 CAIRO_LINE_CAP_ROUND);
482 if (status)
483 return status;
486 switch (fill_rule) {
487 case CAIRO_FILL_RULE_WINDING:
488 pdf_operator = "W";
489 break;
490 case CAIRO_FILL_RULE_EVEN_ODD:
491 pdf_operator = "W*";
492 break;
493 default:
494 ASSERT_NOT_REACHED;
497 _cairo_output_stream_printf (pdf_operators->stream,
498 "%s n\n",
499 pdf_operator);
501 return _cairo_output_stream_get_status (pdf_operators->stream);
504 static int
505 _cairo_pdf_line_cap (cairo_line_cap_t cap)
507 switch (cap) {
508 case CAIRO_LINE_CAP_BUTT:
509 return 0;
510 case CAIRO_LINE_CAP_ROUND:
511 return 1;
512 case CAIRO_LINE_CAP_SQUARE:
513 return 2;
514 default:
515 ASSERT_NOT_REACHED;
516 return 0;
520 static int
521 _cairo_pdf_line_join (cairo_line_join_t join)
523 switch (join) {
524 case CAIRO_LINE_JOIN_MITER:
525 return 0;
526 case CAIRO_LINE_JOIN_ROUND:
527 return 1;
528 case CAIRO_LINE_JOIN_BEVEL:
529 return 2;
530 default:
531 ASSERT_NOT_REACHED;
532 return 0;
536 cairo_int_status_t
537 _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
538 cairo_stroke_style_t *style,
539 double scale)
541 double *dash = style->dash;
542 int num_dashes = style->num_dashes;
543 double dash_offset = style->dash_offset;
544 double line_width = style->line_width * scale;
546 /* PostScript has "special needs" when it comes to zero-length
547 * dash segments with butt caps. It apparently (at least
548 * according to ghostscript) draws hairlines for this
549 * case. That's not what the cairo semantics want, so we first
550 * touch up the array to eliminate any 0.0 values that will
551 * result in "on" segments.
553 if (num_dashes && style->line_cap == CAIRO_LINE_CAP_BUTT) {
554 int i;
556 /* If there's an odd number of dash values they will each get
557 * interpreted as both on and off. So we first explicitly
558 * expand the array to remove the duplicate usage so that we
559 * can modify some of the values.
561 if (num_dashes % 2) {
562 dash = _cairo_malloc_abc (num_dashes, 2, sizeof (double));
563 if (dash == NULL)
564 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
566 memcpy (dash, style->dash, num_dashes * sizeof (double));
567 memcpy (dash + num_dashes, style->dash, num_dashes * sizeof (double));
569 num_dashes *= 2;
572 for (i = 0; i < num_dashes; i += 2) {
573 if (dash[i] == 0.0) {
574 /* Do not modify the dashes in-place, as we may need to also
575 * replay this stroke to an image fallback.
577 if (dash == style->dash) {
578 dash = _cairo_malloc_ab (num_dashes, sizeof (double));
579 if (dash == NULL)
580 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
581 memcpy (dash, style->dash, num_dashes * sizeof (double));
584 /* If we're at the front of the list, we first rotate
585 * two elements from the end of the list to the front
586 * of the list before folding away the 0.0. Or, if
587 * there are only two dash elements, then there is
588 * nothing at all to draw.
590 if (i == 0) {
591 double last_two[2];
593 if (num_dashes == 2) {
594 free (dash);
595 return CAIRO_INT_STATUS_NOTHING_TO_DO;
598 /* The cases of num_dashes == 0, 1, or 3 elements
599 * cannot exist, so the rotation of 2 elements
600 * will always be safe */
601 memcpy (last_two, dash + num_dashes - 2, sizeof (last_two));
602 memmove (dash + 2, dash, (num_dashes - 2) * sizeof (double));
603 memcpy (dash, last_two, sizeof (last_two));
604 dash_offset += dash[0] + dash[1];
605 i = 2;
607 dash[i-1] += dash[i+1];
608 num_dashes -= 2;
609 memmove (dash + i, dash + i + 2, (num_dashes - i) * sizeof (double));
610 /* If we might have just rotated, it's possible that
611 * we rotated a 0.0 value to the front of the list.
612 * Set i to -2 so it will get incremented to 0. */
613 if (i == 2)
614 i = -2;
619 if (!pdf_operators->has_line_style || pdf_operators->line_width != line_width) {
620 _cairo_output_stream_printf (pdf_operators->stream,
621 "%f w\n",
622 line_width);
623 pdf_operators->line_width = line_width;
626 if (!pdf_operators->has_line_style || pdf_operators->line_cap != style->line_cap) {
627 _cairo_output_stream_printf (pdf_operators->stream,
628 "%d J\n",
629 _cairo_pdf_line_cap (style->line_cap));
630 pdf_operators->line_cap = style->line_cap;
633 if (!pdf_operators->has_line_style || pdf_operators->line_join != style->line_join) {
634 _cairo_output_stream_printf (pdf_operators->stream,
635 "%d j\n",
636 _cairo_pdf_line_join (style->line_join));
637 pdf_operators->line_join = style->line_join;
640 if (num_dashes) {
641 int d;
643 _cairo_output_stream_printf (pdf_operators->stream, "[");
644 for (d = 0; d < num_dashes; d++)
645 _cairo_output_stream_printf (pdf_operators->stream, " %f", dash[d] * scale);
646 _cairo_output_stream_printf (pdf_operators->stream, "] %f d\n",
647 dash_offset * scale);
648 pdf_operators->has_dashes = TRUE;
649 } else if (!pdf_operators->has_line_style || pdf_operators->has_dashes) {
650 _cairo_output_stream_printf (pdf_operators->stream, "[] 0.0 d\n");
651 pdf_operators->has_dashes = FALSE;
653 if (dash != style->dash)
654 free (dash);
656 if (!pdf_operators->has_line_style || pdf_operators->miter_limit != style->miter_limit) {
657 _cairo_output_stream_printf (pdf_operators->stream,
658 "%f M ",
659 style->miter_limit < 1.0 ? 1.0 : style->miter_limit);
660 pdf_operators->miter_limit = style->miter_limit;
662 pdf_operators->has_line_style = TRUE;
664 return _cairo_output_stream_get_status (pdf_operators->stream);
667 /* Scale the matrix so the largest absolute value of the non
668 * translation components is 1.0. Return the scale required to restore
669 * the matrix to the original values.
671 * eg the matrix [ 100 0 0 50 20 10 ]
673 * is rescaled to [ 1 0 0 0.5 0.2 0.1 ]
674 * and the scale returned is 100
676 static void
677 _cairo_matrix_factor_out_scale (cairo_matrix_t *m, double *scale)
679 double s;
681 s = fabs (m->xx);
682 if (fabs (m->xy) > s)
683 s = fabs (m->xy);
684 if (fabs (m->yx) > s)
685 s = fabs (m->yx);
686 if (fabs (m->yy) > s)
687 s = fabs (m->yy);
688 *scale = s;
689 s = 1.0/s;
690 cairo_matrix_scale (m, s, s);
693 static cairo_int_status_t
694 _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
695 cairo_path_fixed_t *path,
696 cairo_stroke_style_t *style,
697 cairo_matrix_t *ctm,
698 cairo_matrix_t *ctm_inverse,
699 const char *pdf_operator)
701 cairo_status_t status;
702 cairo_matrix_t m, path_transform;
703 cairo_bool_t has_ctm = TRUE;
704 double scale = 1.0;
706 if (pdf_operators->in_text_object) {
707 status = _cairo_pdf_operators_end_text (pdf_operators);
708 if (status)
709 return status;
712 /* Optimize away the stroke ctm when it does not affect the
713 * stroke. There are other ctm cases that could be optimized
714 * however this is the most common.
716 if (fabs(ctm->xx) == 1.0 && fabs(ctm->yy) == 1.0 &&
717 fabs(ctm->xy) == 0.0 && fabs(ctm->yx) == 0.0)
719 has_ctm = FALSE;
722 /* The PDF CTM is transformed to the user space CTM when stroking
723 * so the corect pen shape will be used. This also requires that
724 * the path be transformed to user space when emitted. The
725 * conversion of path coordinates to user space may cause rounding
726 * errors. For example the device space point (1.234, 3.142) when
727 * transformed to a user space CTM of [100 0 0 100 0 0] will be
728 * emitted as (0.012, 0.031).
730 * To avoid the rounding problem we scale the user space CTM
731 * matrix so that all the non translation components of the matrix
732 * are <= 1. The line width and and dashes are scaled by the
733 * inverse of the scale applied to the CTM. This maintains the
734 * shape of the stroke pen while keeping the user space CTM within
735 * the range that maximizes the precision of the emitted path.
737 if (has_ctm) {
738 m = *ctm;
739 /* Zero out the translation since it does not affect the pen
740 * shape however it may cause unnecessary digits to be emitted.
742 m.x0 = 0.0;
743 m.y0 = 0.0;
744 _cairo_matrix_factor_out_scale (&m, &scale);
745 path_transform = m;
746 status = cairo_matrix_invert (&path_transform);
747 if (status)
748 return status;
750 cairo_matrix_multiply (&m, &m, &pdf_operators->cairo_to_pdf);
753 status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style, scale);
754 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
755 return CAIRO_STATUS_SUCCESS;
756 if (status)
757 return status;
759 if (has_ctm) {
760 _cairo_output_stream_printf (pdf_operators->stream,
761 "q %f %f %f %f %f %f cm\n",
762 m.xx, m.yx, m.xy, m.yy,
763 m.x0, m.y0);
764 } else {
765 path_transform = pdf_operators->cairo_to_pdf;
768 status = _cairo_pdf_operators_emit_path (pdf_operators,
769 path,
770 &path_transform,
771 style->line_cap);
772 if (status)
773 return status;
775 _cairo_output_stream_printf (pdf_operators->stream, "%s", pdf_operator);
776 if (has_ctm)
777 _cairo_output_stream_printf (pdf_operators->stream, " Q");
779 _cairo_output_stream_printf (pdf_operators->stream, "\n");
781 return _cairo_output_stream_get_status (pdf_operators->stream);
784 cairo_int_status_t
785 _cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
786 cairo_path_fixed_t *path,
787 cairo_stroke_style_t *style,
788 cairo_matrix_t *ctm,
789 cairo_matrix_t *ctm_inverse)
791 return _cairo_pdf_operators_emit_stroke (pdf_operators,
792 path,
793 style,
794 ctm,
795 ctm_inverse,
796 "S");
799 cairo_int_status_t
800 _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
801 cairo_path_fixed_t *path,
802 cairo_fill_rule_t fill_rule)
804 const char *pdf_operator;
805 cairo_status_t status;
807 if (pdf_operators->in_text_object) {
808 status = _cairo_pdf_operators_end_text (pdf_operators);
809 if (status)
810 return status;
813 status = _cairo_pdf_operators_emit_path (pdf_operators,
814 path,
815 &pdf_operators->cairo_to_pdf,
816 CAIRO_LINE_CAP_ROUND);
817 if (status)
818 return status;
820 switch (fill_rule) {
821 case CAIRO_FILL_RULE_WINDING:
822 pdf_operator = "f";
823 break;
824 case CAIRO_FILL_RULE_EVEN_ODD:
825 pdf_operator = "f*";
826 break;
827 default:
828 ASSERT_NOT_REACHED;
831 _cairo_output_stream_printf (pdf_operators->stream,
832 "%s\n",
833 pdf_operator);
835 return _cairo_output_stream_get_status (pdf_operators->stream);
838 cairo_int_status_t
839 _cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
840 cairo_path_fixed_t *path,
841 cairo_fill_rule_t fill_rule,
842 cairo_stroke_style_t *style,
843 cairo_matrix_t *ctm,
844 cairo_matrix_t *ctm_inverse)
846 const char *operator;
848 switch (fill_rule) {
849 case CAIRO_FILL_RULE_WINDING:
850 operator = "B";
851 break;
852 case CAIRO_FILL_RULE_EVEN_ODD:
853 operator = "B*";
854 break;
855 default:
856 ASSERT_NOT_REACHED;
859 return _cairo_pdf_operators_emit_stroke (pdf_operators,
860 path,
861 style,
862 ctm,
863 ctm_inverse,
864 operator);
867 #define GLYPH_POSITION_TOLERANCE 0.001
869 /* Emit the string of glyphs using the 'Tj' operator. This requires
870 * that the glyphs are positioned at their natural glyph advances. */
871 static cairo_status_t
872 _cairo_pdf_operators_emit_glyph_string (cairo_pdf_operators_t *pdf_operators,
873 cairo_output_stream_t *stream)
875 int i;
877 _cairo_output_stream_printf (stream, "<");
878 for (i = 0; i < pdf_operators->num_glyphs; i++) {
879 _cairo_output_stream_printf (stream,
880 "%0*x",
881 pdf_operators->hex_width,
882 pdf_operators->glyphs[i].glyph_index);
883 pdf_operators->cur_x += pdf_operators->glyphs[i].x_advance;
885 _cairo_output_stream_printf (stream, ">Tj\n");
887 return _cairo_output_stream_get_status (stream);
890 /* Emit the string of glyphs using the 'TJ' operator.
892 * The TJ operator takes an array of strings of glyphs. Each string of
893 * glyphs is displayed using the glyph advances of each glyph to
894 * position the glyphs. A relative adjustment to the glyph advance may
895 * be specified by including the adjustment between two strings. The
896 * adjustment is in units of text space * -1000.
898 static cairo_status_t
899 _cairo_pdf_operators_emit_glyph_string_with_positioning (
900 cairo_pdf_operators_t *pdf_operators,
901 cairo_output_stream_t *stream)
903 int i;
905 _cairo_output_stream_printf (stream, "[<");
906 for (i = 0; i < pdf_operators->num_glyphs; i++) {
907 if (pdf_operators->glyphs[i].x_position != pdf_operators->cur_x)
909 double delta = pdf_operators->glyphs[i].x_position - pdf_operators->cur_x;
910 int rounded_delta;
912 delta = -1000.0*delta;
913 /* As the delta is in 1/1000 of a unit of text space,
914 * rounding to an integer should still provide sufficient
915 * precision. We round the delta before adding to Tm_x so
916 * that we keep track of the accumulated rounding error in
917 * the PDF interpreter and compensate for it when
918 * calculating subsequent deltas.
920 rounded_delta = _cairo_lround (delta);
921 if (rounded_delta != 0) {
922 _cairo_output_stream_printf (stream,
923 ">%d<",
924 rounded_delta);
927 /* Convert the rounded delta back to text
928 * space before adding to the current text
929 * position. */
930 delta = rounded_delta/-1000.0;
931 pdf_operators->cur_x += delta;
934 _cairo_output_stream_printf (stream,
935 "%0*x",
936 pdf_operators->hex_width,
937 pdf_operators->glyphs[i].glyph_index);
938 pdf_operators->cur_x += pdf_operators->glyphs[i].x_advance;
940 _cairo_output_stream_printf (stream, ">]TJ\n");
942 return _cairo_output_stream_get_status (stream);
945 static cairo_status_t
946 _cairo_pdf_operators_flush_glyphs (cairo_pdf_operators_t *pdf_operators)
948 cairo_output_stream_t *word_wrap_stream;
949 cairo_status_t status, status2;
950 int i;
951 double x;
953 if (pdf_operators->num_glyphs == 0)
954 return CAIRO_STATUS_SUCCESS;
956 word_wrap_stream = _word_wrap_stream_create (pdf_operators->stream, 72);
957 status = _cairo_output_stream_get_status (word_wrap_stream);
958 if (status)
959 return _cairo_output_stream_destroy (word_wrap_stream);
961 /* Check if glyph advance used to position every glyph */
962 x = pdf_operators->cur_x;
963 for (i = 0; i < pdf_operators->num_glyphs; i++) {
964 if (fabs(pdf_operators->glyphs[i].x_position - x) > GLYPH_POSITION_TOLERANCE)
965 break;
966 x += pdf_operators->glyphs[i].x_advance;
968 if (i == pdf_operators->num_glyphs) {
969 status = _cairo_pdf_operators_emit_glyph_string (pdf_operators,
970 word_wrap_stream);
971 } else {
972 status = _cairo_pdf_operators_emit_glyph_string_with_positioning (
973 pdf_operators, word_wrap_stream);
976 pdf_operators->num_glyphs = 0;
977 status2 = _cairo_output_stream_destroy (word_wrap_stream);
978 if (status == CAIRO_STATUS_SUCCESS)
979 status = status2;
981 return status;
984 static cairo_status_t
985 _cairo_pdf_operators_add_glyph (cairo_pdf_operators_t *pdf_operators,
986 cairo_scaled_font_subsets_glyph_t *glyph,
987 double x_position)
989 double x, y;
991 x = glyph->x_advance;
992 y = glyph->y_advance;
993 if (glyph->is_scaled)
994 cairo_matrix_transform_distance (&pdf_operators->font_matrix_inverse, &x, &y);
996 pdf_operators->glyphs[pdf_operators->num_glyphs].x_position = x_position;
997 pdf_operators->glyphs[pdf_operators->num_glyphs].glyph_index = glyph->subset_glyph_index;
998 pdf_operators->glyphs[pdf_operators->num_glyphs].x_advance = x;
999 pdf_operators->num_glyphs++;
1000 if (pdf_operators->num_glyphs == PDF_GLYPH_BUFFER_SIZE)
1001 return _cairo_pdf_operators_flush_glyphs (pdf_operators);
1003 return CAIRO_STATUS_SUCCESS;
1006 /* Use 'Tm' operator to set the PDF text matrix. */
1007 static cairo_status_t
1008 _cairo_pdf_operators_set_text_matrix (cairo_pdf_operators_t *pdf_operators,
1009 cairo_matrix_t *matrix)
1011 cairo_matrix_t inverse;
1012 cairo_status_t status;
1014 /* We require the matrix to be invertable. */
1015 inverse = *matrix;
1016 status = cairo_matrix_invert (&inverse);
1017 if (status)
1018 return status;
1020 pdf_operators->text_matrix = *matrix;
1021 pdf_operators->cur_x = 0;
1022 pdf_operators->cur_y = 0;
1023 _cairo_output_stream_printf (pdf_operators->stream,
1024 "%f %f %f %f %f %f Tm\n",
1025 pdf_operators->text_matrix.xx,
1026 pdf_operators->text_matrix.yx,
1027 pdf_operators->text_matrix.xy,
1028 pdf_operators->text_matrix.yy,
1029 pdf_operators->text_matrix.x0,
1030 pdf_operators->text_matrix.y0);
1032 pdf_operators->cairo_to_pdftext = *matrix;
1033 status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext);
1034 assert (status == CAIRO_STATUS_SUCCESS);
1035 cairo_matrix_multiply (&pdf_operators->cairo_to_pdftext,
1036 &pdf_operators->cairo_to_pdf,
1037 &pdf_operators->cairo_to_pdftext);
1039 return _cairo_output_stream_get_status (pdf_operators->stream);
1042 #define TEXT_MATRIX_TOLERANCE 1e-6
1044 /* Set the translation components of the PDF text matrix to x, y. The
1045 * 'Td' operator is used to transform the text matrix.
1047 static cairo_status_t
1048 _cairo_pdf_operators_set_text_position (cairo_pdf_operators_t *pdf_operators,
1049 double x,
1050 double y)
1052 cairo_matrix_t translate, inverse;
1053 cairo_status_t status;
1055 /* The Td operator transforms the text_matrix with:
1057 * text_matrix' = T x text_matrix
1059 * where T is a translation matrix with the translation components
1060 * set to the Td operands tx and ty.
1062 inverse = pdf_operators->text_matrix;
1063 status = cairo_matrix_invert (&inverse);
1064 assert (status == CAIRO_STATUS_SUCCESS);
1065 pdf_operators->text_matrix.x0 = x;
1066 pdf_operators->text_matrix.y0 = y;
1067 cairo_matrix_multiply (&translate, &pdf_operators->text_matrix, &inverse);
1068 if (fabs(translate.x0) < TEXT_MATRIX_TOLERANCE)
1069 translate.x0 = 0.0;
1070 if (fabs(translate.y0) < TEXT_MATRIX_TOLERANCE)
1071 translate.y0 = 0.0;
1072 _cairo_output_stream_printf (pdf_operators->stream,
1073 "%f %f Td\n",
1074 translate.x0,
1075 translate.y0);
1076 pdf_operators->cur_x = 0;
1077 pdf_operators->cur_y = 0;
1079 pdf_operators->cairo_to_pdftext = pdf_operators->text_matrix;
1080 status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext);
1081 assert (status == CAIRO_STATUS_SUCCESS);
1082 cairo_matrix_multiply (&pdf_operators->cairo_to_pdftext,
1083 &pdf_operators->cairo_to_pdf,
1084 &pdf_operators->cairo_to_pdftext);
1086 return _cairo_output_stream_get_status (pdf_operators->stream);
1089 /* Select the font using the 'Tf' operator. The font size is set to 1
1090 * as we use the 'Tm' operator to set the font scale.
1092 static cairo_status_t
1093 _cairo_pdf_operators_set_font_subset (cairo_pdf_operators_t *pdf_operators,
1094 cairo_scaled_font_subsets_glyph_t *subset_glyph)
1096 cairo_status_t status;
1098 _cairo_output_stream_printf (pdf_operators->stream,
1099 "/f-%d-%d 1 Tf\n",
1100 subset_glyph->font_id,
1101 subset_glyph->subset_id);
1102 if (pdf_operators->use_font_subset) {
1103 status = pdf_operators->use_font_subset (subset_glyph->font_id,
1104 subset_glyph->subset_id,
1105 pdf_operators->use_font_subset_closure);
1106 if (status)
1107 return status;
1109 pdf_operators->font_id = subset_glyph->font_id;
1110 pdf_operators->subset_id = subset_glyph->subset_id;
1112 if (subset_glyph->is_composite)
1113 pdf_operators->hex_width = 4;
1114 else
1115 pdf_operators->hex_width = 2;
1117 return CAIRO_STATUS_SUCCESS;
1120 static cairo_status_t
1121 _cairo_pdf_operators_begin_text (cairo_pdf_operators_t *pdf_operators)
1123 _cairo_output_stream_printf (pdf_operators->stream, "BT\n");
1125 pdf_operators->in_text_object = TRUE;
1126 pdf_operators->num_glyphs = 0;
1128 return _cairo_output_stream_get_status (pdf_operators->stream);
1131 static cairo_status_t
1132 _cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators)
1134 cairo_status_t status;
1136 status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
1137 if (status)
1138 return status;
1140 _cairo_output_stream_printf (pdf_operators->stream, "ET\n");
1142 pdf_operators->in_text_object = FALSE;
1144 return _cairo_output_stream_get_status (pdf_operators->stream);
1147 /* Compare the scale components of two matrices. The translation
1148 * components are ignored. */
1149 static cairo_bool_t
1150 _cairo_matrix_scale_equal (cairo_matrix_t *a, cairo_matrix_t *b)
1152 return (a->xx == b->xx &&
1153 a->xy == b->xy &&
1154 a->yx == b->yx &&
1155 a->yy == b->yy);
1158 static cairo_status_t
1159 _cairo_pdf_operators_begin_actualtext (cairo_pdf_operators_t *pdf_operators,
1160 const char *utf8,
1161 int utf8_len)
1163 uint16_t *utf16;
1164 int utf16_len;
1165 cairo_status_t status;
1166 int i;
1168 _cairo_output_stream_printf (pdf_operators->stream, "/Span << /ActualText <feff");
1169 if (utf8_len) {
1170 status = _cairo_utf8_to_utf16 (utf8, utf8_len, &utf16, &utf16_len);
1171 if (status)
1172 return status;
1174 for (i = 0; i < utf16_len; i++) {
1175 _cairo_output_stream_printf (pdf_operators->stream,
1176 "%04x", (int) (utf16[i]));
1178 free (utf16);
1180 _cairo_output_stream_printf (pdf_operators->stream, "> >> BDC\n");
1182 return _cairo_output_stream_get_status (pdf_operators->stream);
1185 static cairo_status_t
1186 _cairo_pdf_operators_end_actualtext (cairo_pdf_operators_t *pdf_operators)
1188 _cairo_output_stream_printf (pdf_operators->stream, "EMC\n");
1190 return _cairo_output_stream_get_status (pdf_operators->stream);
1193 static cairo_status_t
1194 _cairo_pdf_operators_emit_glyph (cairo_pdf_operators_t *pdf_operators,
1195 cairo_glyph_t *glyph,
1196 cairo_scaled_font_subsets_glyph_t *subset_glyph)
1198 double x, y;
1199 cairo_status_t status;
1201 if (pdf_operators->is_new_text_object ||
1202 pdf_operators->font_id != subset_glyph->font_id ||
1203 pdf_operators->subset_id != subset_glyph->subset_id)
1205 status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
1206 if (status)
1207 return status;
1209 status = _cairo_pdf_operators_set_font_subset (pdf_operators, subset_glyph);
1210 if (status)
1211 return status;
1213 pdf_operators->is_new_text_object = FALSE;
1216 x = glyph->x;
1217 y = glyph->y;
1218 cairo_matrix_transform_point (&pdf_operators->cairo_to_pdftext, &x, &y);
1220 /* The TJ operator for displaying text strings can only set
1221 * the horizontal position of the glyphs. If the y position
1222 * (in text space) changes, use the Td operator to change the
1223 * current position to the next glyph. We also use the Td
1224 * operator to move the current position if the horizontal
1225 * position changes by more than 10 (in text space
1226 * units). This is becauses the horizontal glyph positioning
1227 * in the TJ operator is intended for kerning and there may be
1228 * PDF consumers that do not handle very large position
1229 * adjustments in TJ.
1231 if (fabs(x - pdf_operators->cur_x) > 10 ||
1232 fabs(y - pdf_operators->cur_y) > GLYPH_POSITION_TOLERANCE)
1234 status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
1235 if (status)
1236 return status;
1238 x = glyph->x;
1239 y = glyph->y;
1240 cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y);
1241 status = _cairo_pdf_operators_set_text_position (pdf_operators, x, y);
1242 if (status)
1243 return status;
1245 x = 0.0;
1246 y = 0.0;
1249 status = _cairo_pdf_operators_add_glyph (pdf_operators,
1250 subset_glyph,
1252 return status;
1255 /* A utf8_len of -1 indicates no unicode text. A utf8_len = 0 is an
1256 * empty string.
1258 static cairo_int_status_t
1259 _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators,
1260 const char *utf8,
1261 int utf8_len,
1262 cairo_glyph_t *glyphs,
1263 int num_glyphs,
1264 cairo_text_cluster_flags_t cluster_flags,
1265 cairo_scaled_font_t *scaled_font)
1267 cairo_scaled_font_subsets_glyph_t subset_glyph;
1268 cairo_glyph_t *cur_glyph;
1269 cairo_status_t status;
1270 int i;
1272 /* If the cluster maps 1 glyph to 1 or more unicode characters, we
1273 * first try _map_glyph() with the unicode string to see if it can
1274 * use toUnicode to map our glyph to the unicode. This will fail
1275 * if the glyph is already mapped to a different unicode string.
1277 * We also go through this path if no unicode mapping was
1278 * supplied (utf8_len < 0).
1280 * Mapping a glyph to a zero length unicode string requires the
1281 * use of ActualText.
1283 if (num_glyphs == 1 && utf8_len != 0) {
1284 status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
1285 scaled_font,
1286 glyphs->index,
1287 utf8,
1288 utf8_len,
1289 &subset_glyph);
1290 if (status)
1291 return status;
1293 if (subset_glyph.utf8_is_mapped || utf8_len < 0) {
1294 status = _cairo_pdf_operators_emit_glyph (pdf_operators,
1295 glyphs,
1296 &subset_glyph);
1297 if (status)
1298 return status;
1300 return CAIRO_STATUS_SUCCESS;
1304 /* Fallback to using ActualText to map zero or more glyphs to a
1305 * unicode string. */
1306 status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
1307 if (status)
1308 return status;
1310 status = _cairo_pdf_operators_begin_actualtext (pdf_operators, utf8, utf8_len);
1311 if (status)
1312 return status;
1314 cur_glyph = glyphs;
1315 /* XXX
1316 * If no glyphs, we should put *something* here for the text to be selectable. */
1317 for (i = 0; i < num_glyphs; i++) {
1318 status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
1319 scaled_font,
1320 cur_glyph->index,
1321 NULL, -1,
1322 &subset_glyph);
1323 if (status)
1324 return status;
1326 status = _cairo_pdf_operators_emit_glyph (pdf_operators,
1327 cur_glyph,
1328 &subset_glyph);
1329 if (status)
1330 return status;
1332 if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD))
1333 cur_glyph--;
1334 else
1335 cur_glyph++;
1337 status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
1338 if (status)
1339 return status;
1341 status = _cairo_pdf_operators_end_actualtext (pdf_operators);
1343 return status;
1346 cairo_int_status_t
1347 _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
1348 const char *utf8,
1349 int utf8_len,
1350 cairo_glyph_t *glyphs,
1351 int num_glyphs,
1352 const cairo_text_cluster_t *clusters,
1353 int num_clusters,
1354 cairo_text_cluster_flags_t cluster_flags,
1355 cairo_scaled_font_t *scaled_font)
1357 cairo_status_t status;
1358 int i;
1359 cairo_matrix_t text_matrix, invert_y_axis;
1360 double x, y;
1361 const char *cur_text;
1362 cairo_glyph_t *cur_glyph;
1364 pdf_operators->font_matrix_inverse = scaled_font->font_matrix;
1365 status = cairo_matrix_invert (&pdf_operators->font_matrix_inverse);
1366 if (status == CAIRO_STATUS_INVALID_MATRIX)
1367 return CAIRO_STATUS_SUCCESS;
1368 if (status)
1369 return status;
1371 pdf_operators->is_new_text_object = FALSE;
1372 if (pdf_operators->in_text_object == FALSE) {
1373 status = _cairo_pdf_operators_begin_text (pdf_operators);
1374 if (status)
1375 return status;
1377 /* Force Tm and Tf to be emitted when starting a new text
1378 * object.*/
1379 pdf_operators->is_new_text_object = TRUE;
1382 cairo_matrix_init_scale (&invert_y_axis, 1, -1);
1383 text_matrix = scaled_font->scale;
1385 /* Invert y axis in font space */
1386 cairo_matrix_multiply (&text_matrix, &text_matrix, &invert_y_axis);
1388 /* Invert y axis in device space */
1389 cairo_matrix_multiply (&text_matrix, &invert_y_axis, &text_matrix);
1391 if (pdf_operators->is_new_text_object ||
1392 ! _cairo_matrix_scale_equal (&pdf_operators->text_matrix, &text_matrix))
1394 status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
1395 if (status)
1396 return status;
1398 x = glyphs[0].x;
1399 y = glyphs[0].y;
1400 cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y);
1401 text_matrix.x0 = x;
1402 text_matrix.y0 = y;
1403 status = _cairo_pdf_operators_set_text_matrix (pdf_operators, &text_matrix);
1404 if (status == CAIRO_STATUS_INVALID_MATRIX)
1405 return CAIRO_STATUS_SUCCESS;
1406 if (status)
1407 return status;
1410 if (num_clusters > 0) {
1411 cur_text = utf8;
1412 if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD))
1413 cur_glyph = glyphs + num_glyphs;
1414 else
1415 cur_glyph = glyphs;
1416 for (i = 0; i < num_clusters; i++) {
1417 if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD))
1418 cur_glyph -= clusters[i].num_glyphs;
1419 status = _cairo_pdf_operators_emit_cluster (pdf_operators,
1420 cur_text,
1421 clusters[i].num_bytes,
1422 cur_glyph,
1423 clusters[i].num_glyphs,
1424 cluster_flags,
1425 scaled_font);
1426 if (status)
1427 return status;
1429 cur_text += clusters[i].num_bytes;
1430 if (!(cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD))
1431 cur_glyph += clusters[i].num_glyphs;
1433 } else {
1434 for (i = 0; i < num_glyphs; i++) {
1435 status = _cairo_pdf_operators_emit_cluster (pdf_operators,
1436 NULL,
1437 -1, /* no unicode string available */
1438 &glyphs[i],
1440 FALSE,
1441 scaled_font);
1442 if (status)
1443 return status;
1447 return _cairo_output_stream_get_status (pdf_operators->stream);
1450 #endif /* CAIRO_HAS_PDF_OPERATORS */