Coverage Report

Created: 2025-12-31 07:23

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