LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-pdf-operators.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 606 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 43 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13