LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-pdf-operators.c (source / functions) Found Hit Coverage
Test: app.info Lines: 606 0 0.0 %
Date: 2012-06-02 Functions: 43 0 0.0 %

       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 corect 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.7