LCOV - app.info - gfx/cairo/cairo/src/cairo-pdf-operators.c

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