LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-pdf-surface.c (source / functions) Found Hit Coverage
Test: app.info Lines: 2620 0 0.0 %
Date: 2012-06-02 Functions: 118 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                 : #define _BSD_SOURCE /* for snprintf() */
      43                 : #include "cairoint.h"
      44                 : #include "cairo-pdf.h"
      45                 : #include "cairo-pdf-surface-private.h"
      46                 : #include "cairo-pdf-operators-private.h"
      47                 : #include "cairo-analysis-surface-private.h"
      48                 : #include "cairo-composite-rectangles-private.h"
      49                 : #include "cairo-error-private.h"
      50                 : #include "cairo-image-info-private.h"
      51                 : #include "cairo-recording-surface-private.h"
      52                 : #include "cairo-output-stream-private.h"
      53                 : #include "cairo-paginated-private.h"
      54                 : #include "cairo-scaled-font-subsets-private.h"
      55                 : #include "cairo-surface-clipper-private.h"
      56                 : #include "cairo-surface-subsurface-private.h"
      57                 : #include "cairo-type3-glyph-surface-private.h"
      58                 : 
      59                 : #include <time.h>
      60                 : #include <zlib.h>
      61                 : 
      62                 : /* Issues:
      63                 :  *
      64                 :  * - We embed an image in the stream each time it's composited.  We
      65                 :  *   could add generation counters to surfaces and remember the stream
      66                 :  *   ID for a particular generation for a particular surface.
      67                 :  *
      68                 :  * - Backend specific meta data.
      69                 :  */
      70                 : 
      71                 : /*
      72                 :  * Page Structure of the Generated PDF:
      73                 :  *
      74                 :  * Each page requiring fallbacks images contains a knockout group at
      75                 :  * the top level. The first operation of the knockout group paints a
      76                 :  * group containing all the supported drawing operations. Fallback
      77                 :  * images (if any) are painted in the knockout group. This ensures
      78                 :  * that fallback images do not composite with any content under the
      79                 :  * fallback images.
      80                 :  *
      81                 :  * Streams:
      82                 :  *
      83                 :  * This PDF surface has three types of streams:
      84                 :  *  - PDF Stream
      85                 :  *  - Content Stream
      86                 :  *  - Group Stream
      87                 :  *
      88                 :  * Calling _cairo_output_stream_printf (surface->output, ...) will
      89                 :  * write to the currently open stream.
      90                 :  *
      91                 :  * PDF Stream:
      92                 :  *   A PDF Stream may be opened and closed with the following functions:
      93                 :  *     _cairo_pdf_surface_open stream ()
      94                 :  *     _cairo_pdf_surface_close_stream ()
      95                 :  *
      96                 :  *   PDF Streams are written directly to the PDF file. They are used for
      97                 :  *   fonts, images and patterns.
      98                 :  *
      99                 :  * Content Stream:
     100                 :  *   The Content Stream is opened and closed with the following functions:
     101                 :  *     _cairo_pdf_surface_open_content_stream ()
     102                 :  *     _cairo_pdf_surface_close_content_stream ()
     103                 :  *
     104                 :  *   The Content Stream contains the text and graphics operators.
     105                 :  *
     106                 :  * Group Stream:
     107                 :  *   A Group Stream may be opened and closed with the following functions:
     108                 :  *     _cairo_pdf_surface_open_group ()
     109                 :  *     _cairo_pdf_surface_close_group ()
     110                 :  *
     111                 :  *   A Group Stream is a Form XObject. It is used for short sequences
     112                 :  *   of operators. As the content is very short the group is stored in
     113                 :  *   memory until it is closed. This allows some optimization such as
     114                 :  *   including the Resource dictionary and stream length inside the
     115                 :  *   XObject instead of using an indirect object.
     116                 :  */
     117                 : 
     118                 : /**
     119                 :  * SECTION:cairo-pdf
     120                 :  * @Title: PDF Surfaces
     121                 :  * @Short_Description: Rendering PDF documents
     122                 :  * @See_Also: #cairo_surface_t
     123                 :  *
     124                 :  * The PDF surface is used to render cairo graphics to Adobe
     125                 :  * PDF files and is a multi-page vector surface backend.
     126                 :  */
     127                 : 
     128                 : /**
     129                 :  * CAIRO_HAS_PDF_SURFACE:
     130                 :  *
     131                 :  * Defined if the PDF surface backend is available.
     132                 :  * This macro can be used to conditionally compile backend-specific code.
     133                 :  */
     134                 : 
     135                 : static const cairo_pdf_version_t _cairo_pdf_versions[] =
     136                 : {
     137                 :     CAIRO_PDF_VERSION_1_4,
     138                 :     CAIRO_PDF_VERSION_1_5
     139                 : };
     140                 : 
     141                 : #define CAIRO_PDF_VERSION_LAST ARRAY_LENGTH (_cairo_pdf_versions)
     142                 : 
     143                 : static const char * _cairo_pdf_version_strings[CAIRO_PDF_VERSION_LAST] =
     144                 : {
     145                 :     "PDF 1.4",
     146                 :     "PDF 1.5"
     147                 : };
     148                 : 
     149                 : typedef struct _cairo_pdf_object {
     150                 :     long offset;
     151                 : } cairo_pdf_object_t;
     152                 : 
     153                 : typedef struct _cairo_pdf_font {
     154                 :     unsigned int font_id;
     155                 :     unsigned int subset_id;
     156                 :     cairo_pdf_resource_t subset_resource;
     157                 : } cairo_pdf_font_t;
     158                 : 
     159                 : typedef struct _cairo_pdf_rgb_linear_function {
     160                 :     cairo_pdf_resource_t resource;
     161                 :     double               color1[3];
     162                 :     double               color2[3];
     163                 : } cairo_pdf_rgb_linear_function_t;
     164                 : 
     165                 : typedef struct _cairo_pdf_alpha_linear_function {
     166                 :     cairo_pdf_resource_t resource;
     167                 :     double               alpha1;
     168                 :     double               alpha2;
     169                 : } cairo_pdf_alpha_linear_function_t;
     170                 : 
     171                 : static cairo_pdf_resource_t
     172                 : _cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface);
     173                 : 
     174                 : static void
     175                 : _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
     176                 : 
     177                 : static void
     178                 : _cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group);
     179                 : 
     180                 : static cairo_status_t
     181                 : _cairo_pdf_surface_add_font (unsigned int        font_id,
     182                 :                              unsigned int        subset_id,
     183                 :                              void               *closure);
     184                 : 
     185                 : static void
     186                 : _cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res);
     187                 : 
     188                 : static cairo_status_t
     189                 : _cairo_pdf_surface_open_stream (cairo_pdf_surface_t     *surface,
     190                 :                                 cairo_pdf_resource_t    *resource,
     191                 :                                 cairo_bool_t             compressed,
     192                 :                                 const char              *fmt,
     193                 :                                 ...) CAIRO_PRINTF_FORMAT(4, 5);
     194                 : static cairo_status_t
     195                 : _cairo_pdf_surface_close_stream (cairo_pdf_surface_t    *surface);
     196                 : 
     197                 : static cairo_status_t
     198                 : _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
     199                 : 
     200                 : static void
     201                 : _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface);
     202                 : 
     203                 : static cairo_pdf_resource_t
     204                 : _cairo_pdf_surface_write_info (cairo_pdf_surface_t *surface);
     205                 : 
     206                 : static cairo_pdf_resource_t
     207                 : _cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface);
     208                 : 
     209                 : static long
     210                 : _cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface);
     211                 : 
     212                 : static cairo_status_t
     213                 : _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
     214                 : 
     215                 : static cairo_status_t
     216                 : _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface);
     217                 : 
     218                 : static cairo_bool_t
     219                 : _cairo_pdf_source_surface_equal (const void *key_a, const void *key_b);
     220                 : 
     221                 : static const cairo_surface_backend_t cairo_pdf_surface_backend;
     222                 : static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend;
     223                 : 
     224                 : static cairo_pdf_resource_t
     225               0 : _cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface)
     226                 : {
     227                 :     cairo_pdf_resource_t resource;
     228                 :     cairo_status_t status;
     229                 :     cairo_pdf_object_t object;
     230                 : 
     231               0 :     object.offset = _cairo_output_stream_get_position (surface->output);
     232                 : 
     233               0 :     status = _cairo_array_append (&surface->objects, &object);
     234               0 :     if (unlikely (status)) {
     235               0 :         resource.id = 0;
     236               0 :         return resource;
     237                 :     }
     238                 : 
     239               0 :     resource = surface->next_available_resource;
     240               0 :     surface->next_available_resource.id++;
     241                 : 
     242               0 :     return resource;
     243                 : }
     244                 : 
     245                 : static void
     246               0 : _cairo_pdf_surface_update_object (cairo_pdf_surface_t   *surface,
     247                 :                                   cairo_pdf_resource_t   resource)
     248                 : {
     249                 :     cairo_pdf_object_t *object;
     250                 : 
     251               0 :     object = _cairo_array_index (&surface->objects, resource.id - 1);
     252               0 :     object->offset = _cairo_output_stream_get_position (surface->output);
     253               0 : }
     254                 : 
     255                 : static void
     256               0 : _cairo_pdf_surface_set_size_internal (cairo_pdf_surface_t *surface,
     257                 :                                       double              width,
     258                 :                                       double              height)
     259                 : {
     260               0 :     surface->width = width;
     261               0 :     surface->height = height;
     262               0 :     cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, height);
     263               0 :     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
     264                 :                                                   &surface->cairo_to_pdf);
     265               0 : }
     266                 : 
     267                 : static cairo_bool_t
     268               0 : _path_covers_bbox (cairo_pdf_surface_t *surface,
     269                 :                    cairo_path_fixed_t *path)
     270                 : {
     271                 :     cairo_box_t box;
     272                 : 
     273               0 :     return _cairo_path_fixed_is_box (path, &box) &&
     274               0 :            box.p1.x <= 0 &&
     275               0 :            box.p1.y <= 0 &&
     276               0 :            box.p2.x >= _cairo_fixed_from_double (surface->width) &&
     277               0 :            box.p2.y >= _cairo_fixed_from_double (surface->height);
     278                 : }
     279                 : 
     280                 : static cairo_status_t
     281               0 : _cairo_pdf_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
     282                 :                                                 cairo_path_fixed_t      *path,
     283                 :                                                 cairo_fill_rule_t       fill_rule,
     284                 :                                                 double                  tolerance,
     285                 :                                                 cairo_antialias_t       antialias)
     286                 : {
     287               0 :     cairo_pdf_surface_t *surface = cairo_container_of (clipper,
     288                 :                                                        cairo_pdf_surface_t,
     289                 :                                                        clipper);
     290                 :     cairo_int_status_t status;
     291                 : 
     292               0 :     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
     293               0 :     if (unlikely (status))
     294               0 :         return status;
     295                 : 
     296               0 :     if (path == NULL) {
     297               0 :         _cairo_output_stream_printf (surface->output, "Q q\n");
     298                 : 
     299               0 :         surface->current_pattern_is_solid_color = FALSE;
     300               0 :         _cairo_pdf_operators_reset (&surface->pdf_operators);
     301                 : 
     302               0 :         return CAIRO_STATUS_SUCCESS;
     303                 :     }
     304                 : 
     305               0 :     if (_path_covers_bbox (surface, path))
     306               0 :         return CAIRO_STATUS_SUCCESS;
     307                 : 
     308               0 :     return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule);
     309                 : }
     310                 : 
     311                 : static cairo_surface_t *
     312               0 : _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t    *output,
     313                 :                                                double                    width,
     314                 :                                                double                    height)
     315                 : {
     316                 :     cairo_pdf_surface_t *surface;
     317                 :     cairo_status_t status, status_ignored;
     318                 : 
     319               0 :     surface = malloc (sizeof (cairo_pdf_surface_t));
     320               0 :     if (unlikely (surface == NULL)) {
     321                 :         /* destroy stream on behalf of caller */
     322               0 :         status = _cairo_output_stream_destroy (output);
     323               0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     324                 :     }
     325                 : 
     326               0 :     _cairo_surface_init (&surface->base,
     327                 :                          &cairo_pdf_surface_backend,
     328                 :                          NULL, /* device */
     329                 :                          CAIRO_CONTENT_COLOR_ALPHA);
     330                 : 
     331               0 :     surface->output = output;
     332               0 :     surface->width = width;
     333               0 :     surface->height = height;
     334               0 :     cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, height);
     335                 : 
     336               0 :     _cairo_array_init (&surface->objects, sizeof (cairo_pdf_object_t));
     337               0 :     _cairo_array_init (&surface->pages, sizeof (cairo_pdf_resource_t));
     338               0 :     _cairo_array_init (&surface->rgb_linear_functions, sizeof (cairo_pdf_rgb_linear_function_t));
     339               0 :     _cairo_array_init (&surface->alpha_linear_functions, sizeof (cairo_pdf_alpha_linear_function_t));
     340               0 :     _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
     341               0 :     _cairo_array_init (&surface->smask_groups, sizeof (cairo_pdf_smask_group_t *));
     342               0 :     _cairo_array_init (&surface->knockout_group, sizeof (cairo_pdf_resource_t));
     343                 : 
     344               0 :     _cairo_array_init (&surface->page_patterns, sizeof (cairo_pdf_pattern_t));
     345               0 :     _cairo_array_init (&surface->page_surfaces, sizeof (cairo_pdf_source_surface_t));
     346               0 :     surface->all_surfaces = _cairo_hash_table_create (_cairo_pdf_source_surface_equal);
     347               0 :     if (unlikely (surface->all_surfaces == NULL)) {
     348               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     349               0 :         goto BAIL0;
     350                 :     }
     351                 : 
     352               0 :     _cairo_pdf_group_resources_init (&surface->resources);
     353                 : 
     354               0 :     surface->font_subsets = _cairo_scaled_font_subsets_create_composite ();
     355               0 :     if (! surface->font_subsets) {
     356               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     357               0 :         goto BAIL1;
     358                 :     }
     359                 : 
     360               0 :     surface->next_available_resource.id = 1;
     361               0 :     surface->pages_resource = _cairo_pdf_surface_new_object (surface);
     362               0 :     if (surface->pages_resource.id == 0) {
     363               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     364               0 :         goto BAIL2;
     365                 :     }
     366                 : 
     367               0 :     surface->pdf_version = CAIRO_PDF_VERSION_1_5;
     368               0 :     surface->compress_content = TRUE;
     369               0 :     surface->pdf_stream.active = FALSE;
     370               0 :     surface->pdf_stream.old_output = NULL;
     371               0 :     surface->group_stream.active = FALSE;
     372               0 :     surface->group_stream.stream = NULL;
     373               0 :     surface->group_stream.mem_stream = NULL;
     374                 : 
     375               0 :     surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
     376                 : 
     377               0 :     surface->force_fallbacks = FALSE;
     378               0 :     surface->select_pattern_gstate_saved = FALSE;
     379               0 :     surface->current_pattern_is_solid_color = FALSE;
     380               0 :     surface->current_operator = CAIRO_OPERATOR_OVER;
     381               0 :     surface->header_emitted = FALSE;
     382                 : 
     383               0 :     _cairo_surface_clipper_init (&surface->clipper,
     384                 :                                  _cairo_pdf_surface_clipper_intersect_clip_path);
     385                 : 
     386               0 :     _cairo_pdf_operators_init (&surface->pdf_operators,
     387                 :                                surface->output,
     388                 :                                &surface->cairo_to_pdf,
     389                 :                                surface->font_subsets);
     390               0 :     _cairo_pdf_operators_set_font_subsets_callback (&surface->pdf_operators,
     391                 :                                                     _cairo_pdf_surface_add_font,
     392                 :                                                     surface);
     393               0 :     _cairo_pdf_operators_enable_actual_text(&surface->pdf_operators, TRUE);
     394                 : 
     395               0 :     surface->paginated_surface =  _cairo_paginated_surface_create (
     396                 :                                           &surface->base,
     397                 :                                           CAIRO_CONTENT_COLOR_ALPHA,
     398                 :                                           &cairo_pdf_surface_paginated_backend);
     399                 : 
     400               0 :     status = surface->paginated_surface->status;
     401               0 :     if (status == CAIRO_STATUS_SUCCESS) {
     402                 :         /* paginated keeps the only reference to surface now, drop ours */
     403               0 :         cairo_surface_destroy (&surface->base);
     404               0 :         return surface->paginated_surface;
     405                 :     }
     406                 : 
     407                 : BAIL2:
     408               0 :     _cairo_scaled_font_subsets_destroy (surface->font_subsets);
     409                 : BAIL1:
     410               0 :     _cairo_hash_table_destroy (surface->all_surfaces);
     411                 : BAIL0:
     412               0 :     _cairo_array_fini (&surface->objects);
     413               0 :     free (surface);
     414                 : 
     415                 :     /* destroy stream on behalf of caller */
     416               0 :     status_ignored = _cairo_output_stream_destroy (output);
     417                 : 
     418               0 :     return _cairo_surface_create_in_error (status);
     419                 : }
     420                 : 
     421                 : /**
     422                 :  * cairo_pdf_surface_create_for_stream:
     423                 :  * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL
     424                 :  *              to indicate a no-op @write_func. With a no-op @write_func,
     425                 :  *              the surface may be queried or used as a source without
     426                 :  *              generating any temporary files.
     427                 :  * @closure: the closure argument for @write_func
     428                 :  * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
     429                 :  * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
     430                 :  *
     431                 :  * Creates a PDF surface of the specified size in points to be written
     432                 :  * incrementally to the stream represented by @write_func and @closure.
     433                 :  *
     434                 :  * Return value: a pointer to the newly created surface. The caller
     435                 :  * owns the surface and should call cairo_surface_destroy() when done
     436                 :  * with it.
     437                 :  *
     438                 :  * This function always returns a valid pointer, but it will return a
     439                 :  * pointer to a "nil" surface if an error such as out of memory
     440                 :  * occurs. You can use cairo_surface_status() to check for this.
     441                 :  *
     442                 :  * Since: 1.2
     443                 :  */
     444                 : cairo_surface_t *
     445               0 : cairo_pdf_surface_create_for_stream (cairo_write_func_t          write_func,
     446                 :                                      void                       *closure,
     447                 :                                      double                      width_in_points,
     448                 :                                      double                      height_in_points)
     449                 : {
     450                 :     cairo_output_stream_t *output;
     451                 : 
     452               0 :     output = _cairo_output_stream_create (write_func, NULL, closure);
     453               0 :     if (_cairo_output_stream_get_status (output))
     454               0 :         return _cairo_surface_create_in_error (_cairo_output_stream_destroy (output));
     455                 : 
     456               0 :     return _cairo_pdf_surface_create_for_stream_internal (output,
     457                 :                                                           width_in_points,
     458                 :                                                           height_in_points);
     459                 : }
     460                 : 
     461                 : /**
     462                 :  * cairo_pdf_surface_create:
     463                 :  * @filename: a filename for the PDF output (must be writable), %NULL may be
     464                 :  *            used to specify no output. This will generate a PDF surface that
     465                 :  *            may be queried and used as a source, without generating a
     466                 :  *            temporary file.
     467                 :  * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
     468                 :  * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
     469                 :  *
     470                 :  * Creates a PDF surface of the specified size in points to be written
     471                 :  * to @filename.
     472                 :  *
     473                 :  * Return value: a pointer to the newly created surface. The caller
     474                 :  * owns the surface and should call cairo_surface_destroy() when done
     475                 :  * with it.
     476                 :  *
     477                 :  * This function always returns a valid pointer, but it will return a
     478                 :  * pointer to a "nil" surface if an error such as out of memory
     479                 :  * occurs. You can use cairo_surface_status() to check for this.
     480                 :  *
     481                 :  * Since: 1.2
     482                 :  **/
     483                 : cairo_surface_t *
     484               0 : cairo_pdf_surface_create (const char            *filename,
     485                 :                           double                 width_in_points,
     486                 :                           double                 height_in_points)
     487                 : {
     488                 :     cairo_output_stream_t *output;
     489                 : 
     490               0 :     output = _cairo_output_stream_create_for_filename (filename);
     491               0 :     if (_cairo_output_stream_get_status (output))
     492               0 :         return _cairo_surface_create_in_error (_cairo_output_stream_destroy (output));
     493                 : 
     494               0 :     return _cairo_pdf_surface_create_for_stream_internal (output,
     495                 :                                                           width_in_points,
     496                 :                                                           height_in_points);
     497                 : }
     498                 : 
     499                 : static cairo_bool_t
     500               0 : _cairo_surface_is_pdf (cairo_surface_t *surface)
     501                 : {
     502               0 :     return surface->backend == &cairo_pdf_surface_backend;
     503                 : }
     504                 : 
     505                 : /* If the abstract_surface is a paginated surface, and that paginated
     506                 :  * surface's target is a pdf_surface, then set pdf_surface to that
     507                 :  * target. Otherwise return FALSE.
     508                 :  */
     509                 : static cairo_bool_t
     510               0 : _extract_pdf_surface (cairo_surface_t            *surface,
     511                 :                       cairo_pdf_surface_t       **pdf_surface)
     512                 : {
     513                 :     cairo_surface_t *target;
     514                 :     cairo_status_t status_ignored;
     515                 : 
     516               0 :     if (surface->status)
     517               0 :         return FALSE;
     518               0 :     if (surface->finished) {
     519               0 :         status_ignored = _cairo_surface_set_error (surface,
     520                 :                                                    _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
     521               0 :         return FALSE;
     522                 :     }
     523                 : 
     524               0 :     if (! _cairo_surface_is_paginated (surface)) {
     525               0 :         status_ignored = _cairo_surface_set_error (surface,
     526                 :                                                    _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
     527               0 :         return FALSE;
     528                 :     }
     529                 : 
     530               0 :     target = _cairo_paginated_surface_get_target (surface);
     531               0 :     if (target->status) {
     532               0 :         status_ignored = _cairo_surface_set_error (surface,
     533                 :                                                    target->status);
     534               0 :         return FALSE;
     535                 :     }
     536               0 :     if (target->finished) {
     537               0 :         status_ignored = _cairo_surface_set_error (surface,
     538                 :                                                    _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
     539               0 :         return FALSE;
     540                 :     }
     541                 : 
     542               0 :     if (! _cairo_surface_is_pdf (target)) {
     543               0 :         status_ignored = _cairo_surface_set_error (surface,
     544                 :                                                    _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
     545               0 :         return FALSE;
     546                 :     }
     547                 : 
     548               0 :     *pdf_surface = (cairo_pdf_surface_t *) target;
     549               0 :     return TRUE;
     550                 : }
     551                 : 
     552                 : /**
     553                 :  * cairo_pdf_surface_restrict_to_version:
     554                 :  * @surface: a PDF #cairo_surface_t
     555                 :  * @version: PDF version
     556                 :  *
     557                 :  * Restricts the generated PDF file to @version. See cairo_pdf_get_versions()
     558                 :  * for a list of available version values that can be used here.
     559                 :  *
     560                 :  * This function should only be called before any drawing operations
     561                 :  * have been performed on the given surface. The simplest way to do
     562                 :  * this is to call this function immediately after creating the
     563                 :  * surface.
     564                 :  *
     565                 :  * Since: 1.10
     566                 :  **/
     567                 : void
     568               0 : cairo_pdf_surface_restrict_to_version (cairo_surface_t          *abstract_surface,
     569                 :                                        cairo_pdf_version_t       version)
     570                 : {
     571               0 :     cairo_pdf_surface_t *surface = NULL; /* hide compiler warning */
     572                 : 
     573               0 :     if (! _extract_pdf_surface (abstract_surface, &surface))
     574               0 :         return;
     575                 : 
     576               0 :     if (version < CAIRO_PDF_VERSION_LAST)
     577               0 :         surface->pdf_version = version;
     578                 : 
     579               0 :     _cairo_pdf_operators_enable_actual_text(&surface->pdf_operators,
     580                 :                                             version >= CAIRO_PDF_VERSION_1_5);
     581                 : }
     582                 : 
     583                 : /**
     584                 :  * cairo_pdf_get_versions:
     585                 :  * @versions: supported version list
     586                 :  * @num_versions: list length
     587                 :  *
     588                 :  * Used to retrieve the list of supported versions. See
     589                 :  * cairo_pdf_surface_restrict_to_version().
     590                 :  *
     591                 :  * Since: 1.10
     592                 :  **/
     593                 : void
     594               0 : cairo_pdf_get_versions (cairo_pdf_version_t const       **versions,
     595                 :                         int                              *num_versions)
     596                 : {
     597               0 :     if (versions != NULL)
     598               0 :         *versions = _cairo_pdf_versions;
     599                 : 
     600               0 :     if (num_versions != NULL)
     601               0 :         *num_versions = CAIRO_PDF_VERSION_LAST;
     602               0 : }
     603                 : 
     604                 : /**
     605                 :  * cairo_pdf_version_to_string:
     606                 :  * @version: a version id
     607                 :  *
     608                 :  * Get the string representation of the given @version id. This function
     609                 :  * will return %NULL if @version isn't valid. See cairo_pdf_get_versions()
     610                 :  * for a way to get the list of valid version ids.
     611                 :  *
     612                 :  * Return value: the string associated to given version.
     613                 :  *
     614                 :  * Since: 1.10
     615                 :  **/
     616                 : const char *
     617               0 : cairo_pdf_version_to_string (cairo_pdf_version_t version)
     618                 : {
     619               0 :     if (version >= CAIRO_PDF_VERSION_LAST)
     620               0 :         return NULL;
     621                 : 
     622               0 :     return _cairo_pdf_version_strings[version];
     623                 : }
     624                 : 
     625                 : /**
     626                 :  * cairo_pdf_surface_set_size:
     627                 :  * @surface: a PDF #cairo_surface_t
     628                 :  * @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
     629                 :  * @height_in_points: new surface height, in points (1 point == 1/72.0 inch)
     630                 :  *
     631                 :  * Changes the size of a PDF surface for the current (and
     632                 :  * subsequent) pages.
     633                 :  *
     634                 :  * This function should only be called before any drawing operations
     635                 :  * have been performed on the current page. The simplest way to do
     636                 :  * this is to call this function immediately after creating the
     637                 :  * surface or immediately after completing a page with either
     638                 :  * cairo_show_page() or cairo_copy_page().
     639                 :  *
     640                 :  * Since: 1.2
     641                 :  **/
     642                 : void
     643               0 : cairo_pdf_surface_set_size (cairo_surface_t     *surface,
     644                 :                             double               width_in_points,
     645                 :                             double               height_in_points)
     646                 : {
     647               0 :     cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */
     648                 : 
     649               0 :     if (! _extract_pdf_surface (surface, &pdf_surface))
     650               0 :         return;
     651                 : 
     652               0 :     _cairo_pdf_surface_set_size_internal (pdf_surface,
     653                 :                                           width_in_points,
     654                 :                                           height_in_points);
     655                 : }
     656                 : 
     657                 : static void
     658               0 : _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
     659                 : {
     660                 :     int i, size;
     661                 :     cairo_pdf_pattern_t *pattern;
     662                 :     cairo_pdf_source_surface_t *src_surface;
     663                 :     cairo_pdf_smask_group_t *group;
     664                 : 
     665               0 :     size = _cairo_array_num_elements (&surface->page_patterns);
     666               0 :     for (i = 0; i < size; i++) {
     667               0 :         pattern = (cairo_pdf_pattern_t *) _cairo_array_index (&surface->page_patterns, i);
     668               0 :         cairo_pattern_destroy (pattern->pattern);
     669                 :     }
     670               0 :     _cairo_array_truncate (&surface->page_patterns, 0);
     671                 : 
     672               0 :     size = _cairo_array_num_elements (&surface->page_surfaces);
     673               0 :     for (i = 0; i < size; i++) {
     674               0 :         src_surface = (cairo_pdf_source_surface_t *) _cairo_array_index (&surface->page_surfaces, i);
     675               0 :         cairo_surface_destroy (src_surface->surface);
     676                 :     }
     677               0 :     _cairo_array_truncate (&surface->page_surfaces, 0);
     678                 : 
     679               0 :     size = _cairo_array_num_elements (&surface->smask_groups);
     680               0 :     for (i = 0; i < size; i++) {
     681               0 :         _cairo_array_copy_element (&surface->smask_groups, i, &group);
     682               0 :         _cairo_pdf_smask_group_destroy (group);
     683                 :     }
     684               0 :     _cairo_array_truncate (&surface->smask_groups, 0);
     685               0 :     _cairo_array_truncate (&surface->knockout_group, 0);
     686               0 : }
     687                 : 
     688                 : static void
     689               0 : _cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res)
     690                 : {
     691                 :     int i;
     692                 : 
     693               0 :     for (i = 0; i < CAIRO_NUM_OPERATORS; i++)
     694               0 :         res->operators[i] = FALSE;
     695                 : 
     696               0 :     _cairo_array_init (&res->alphas, sizeof (double));
     697               0 :     _cairo_array_init (&res->smasks, sizeof (cairo_pdf_resource_t));
     698               0 :     _cairo_array_init (&res->patterns, sizeof (cairo_pdf_resource_t));
     699               0 :     _cairo_array_init (&res->xobjects, sizeof (cairo_pdf_resource_t));
     700               0 :     _cairo_array_init (&res->fonts, sizeof (cairo_pdf_font_t));
     701               0 : }
     702                 : 
     703                 : static void
     704               0 : _cairo_pdf_group_resources_fini (cairo_pdf_group_resources_t *res)
     705                 : {
     706               0 :     _cairo_array_fini (&res->alphas);
     707               0 :     _cairo_array_fini (&res->smasks);
     708               0 :     _cairo_array_fini (&res->patterns);
     709               0 :     _cairo_array_fini (&res->xobjects);
     710               0 :     _cairo_array_fini (&res->fonts);
     711               0 : }
     712                 : 
     713                 : static void
     714               0 : _cairo_pdf_group_resources_clear (cairo_pdf_group_resources_t *res)
     715                 : {
     716                 :     int i;
     717                 : 
     718               0 :     for (i = 0; i < CAIRO_NUM_OPERATORS; i++)
     719               0 :         res->operators[i] = FALSE;
     720                 : 
     721               0 :     _cairo_array_truncate (&res->alphas, 0);
     722               0 :     _cairo_array_truncate (&res->smasks, 0);
     723               0 :     _cairo_array_truncate (&res->patterns, 0);
     724               0 :     _cairo_array_truncate (&res->xobjects, 0);
     725               0 :     _cairo_array_truncate (&res->fonts, 0);
     726               0 : }
     727                 : 
     728                 : static void
     729               0 : _cairo_pdf_surface_add_operator (cairo_pdf_surface_t *surface,
     730                 :                                  cairo_operator_t     op)
     731                 : {
     732               0 :     cairo_pdf_group_resources_t *res = &surface->resources;
     733                 : 
     734               0 :     res->operators[op] = TRUE;
     735               0 : }
     736                 : 
     737                 : static cairo_status_t
     738               0 : _cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface,
     739                 :                               double               alpha,
     740                 :                               int                 *index)
     741                 : {
     742                 :     int num_alphas, i;
     743                 :     double other;
     744                 :     cairo_status_t status;
     745               0 :     cairo_pdf_group_resources_t *res = &surface->resources;
     746                 : 
     747               0 :     num_alphas = _cairo_array_num_elements (&res->alphas);
     748               0 :     for (i = 0; i < num_alphas; i++) {
     749               0 :         _cairo_array_copy_element (&res->alphas, i, &other);
     750               0 :         if (alpha == other) {
     751               0 :             *index = i;
     752               0 :             return CAIRO_STATUS_SUCCESS;
     753                 :         }
     754                 :     }
     755                 : 
     756               0 :     status = _cairo_array_append (&res->alphas, &alpha);
     757               0 :     if (unlikely (status))
     758               0 :         return status;
     759                 : 
     760               0 :     *index = _cairo_array_num_elements (&res->alphas) - 1;
     761                 : 
     762               0 :     return CAIRO_STATUS_SUCCESS;
     763                 : }
     764                 : 
     765                 : static cairo_status_t
     766               0 : _cairo_pdf_surface_add_smask (cairo_pdf_surface_t  *surface,
     767                 :                               cairo_pdf_resource_t  smask)
     768                 : {
     769               0 :     return _cairo_array_append (&(surface->resources.smasks), &smask);
     770                 : }
     771                 : 
     772                 : static cairo_status_t
     773               0 : _cairo_pdf_surface_add_pattern (cairo_pdf_surface_t  *surface,
     774                 :                                 cairo_pdf_resource_t  pattern)
     775                 : {
     776               0 :     return _cairo_array_append (&(surface->resources.patterns), &pattern);
     777                 : }
     778                 : 
     779                 : static cairo_status_t
     780               0 : _cairo_pdf_surface_add_xobject (cairo_pdf_surface_t  *surface,
     781                 :                                 cairo_pdf_resource_t  xobject)
     782                 : {
     783               0 :     return _cairo_array_append (&(surface->resources.xobjects), &xobject);
     784                 : }
     785                 : 
     786                 : static cairo_status_t
     787               0 : _cairo_pdf_surface_add_font (unsigned int        font_id,
     788                 :                              unsigned int        subset_id,
     789                 :                              void               *closure)
     790                 : {
     791               0 :     cairo_pdf_surface_t *surface = closure;
     792                 :     cairo_pdf_font_t font;
     793                 :     int num_fonts, i;
     794                 :     cairo_status_t status;
     795               0 :     cairo_pdf_group_resources_t *res = &surface->resources;
     796                 : 
     797               0 :     num_fonts = _cairo_array_num_elements (&res->fonts);
     798               0 :     for (i = 0; i < num_fonts; i++) {
     799               0 :         _cairo_array_copy_element (&res->fonts, i, &font);
     800               0 :         if (font.font_id == font_id &&
     801               0 :             font.subset_id == subset_id)
     802               0 :             return CAIRO_STATUS_SUCCESS;
     803                 :     }
     804                 : 
     805               0 :     num_fonts = _cairo_array_num_elements (&surface->fonts);
     806               0 :     for (i = 0; i < num_fonts; i++) {
     807               0 :         _cairo_array_copy_element (&surface->fonts, i, &font);
     808               0 :         if (font.font_id == font_id &&
     809               0 :             font.subset_id == subset_id)
     810               0 :             return _cairo_array_append (&res->fonts, &font);
     811                 :     }
     812                 : 
     813               0 :     font.font_id = font_id;
     814               0 :     font.subset_id = subset_id;
     815               0 :     font.subset_resource = _cairo_pdf_surface_new_object (surface);
     816               0 :     if (font.subset_resource.id == 0)
     817               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     818                 : 
     819               0 :     status = _cairo_array_append (&surface->fonts, &font);
     820               0 :     if (unlikely (status))
     821               0 :         return status;
     822                 : 
     823               0 :     return _cairo_array_append (&res->fonts, &font);
     824                 : }
     825                 : 
     826                 : static cairo_pdf_resource_t
     827               0 : _cairo_pdf_surface_get_font_resource (cairo_pdf_surface_t *surface,
     828                 :                                       unsigned int         font_id,
     829                 :                                       unsigned int         subset_id)
     830                 : {
     831                 :     cairo_pdf_font_t font;
     832                 :     int num_fonts, i;
     833                 : 
     834               0 :     num_fonts = _cairo_array_num_elements (&surface->fonts);
     835               0 :     for (i = 0; i < num_fonts; i++) {
     836               0 :         _cairo_array_copy_element (&surface->fonts, i, &font);
     837               0 :         if (font.font_id == font_id && font.subset_id == subset_id)
     838               0 :             return font.subset_resource;
     839                 :     }
     840                 : 
     841               0 :     font.subset_resource.id = 0;
     842               0 :     return font.subset_resource;
     843                 : }
     844                 : 
     845                 : static const char *
     846               0 : _cairo_operator_to_pdf_blend_mode (cairo_operator_t op)
     847                 : {
     848               0 :     switch (op) {
     849                 :     /* The extend blend mode operators */
     850               0 :     case CAIRO_OPERATOR_MULTIPLY:       return "Multiply";
     851               0 :     case CAIRO_OPERATOR_SCREEN:         return "Screen";
     852               0 :     case CAIRO_OPERATOR_OVERLAY:        return "Overlay";
     853               0 :     case CAIRO_OPERATOR_DARKEN:         return "Darken";
     854               0 :     case CAIRO_OPERATOR_LIGHTEN:        return "Lighten";
     855               0 :     case CAIRO_OPERATOR_COLOR_DODGE:    return "ColorDodge";
     856               0 :     case CAIRO_OPERATOR_COLOR_BURN:     return "ColorBurn";
     857               0 :     case CAIRO_OPERATOR_HARD_LIGHT:     return "HardLight";
     858               0 :     case CAIRO_OPERATOR_SOFT_LIGHT:     return "SoftLight";
     859               0 :     case CAIRO_OPERATOR_DIFFERENCE:     return "Difference";
     860               0 :     case CAIRO_OPERATOR_EXCLUSION:      return "Exclusion";
     861               0 :     case CAIRO_OPERATOR_HSL_HUE:        return "Hue";
     862               0 :     case CAIRO_OPERATOR_HSL_SATURATION: return "Saturation";
     863               0 :     case CAIRO_OPERATOR_HSL_COLOR:      return "Color";
     864               0 :     case CAIRO_OPERATOR_HSL_LUMINOSITY: return "Luminosity";
     865                 : 
     866                 :     default:
     867                 :     /* The original Porter-Duff set */
     868                 :     case CAIRO_OPERATOR_CLEAR:
     869                 :     case CAIRO_OPERATOR_SOURCE:
     870                 :     case CAIRO_OPERATOR_OVER:
     871                 :     case CAIRO_OPERATOR_IN:
     872                 :     case CAIRO_OPERATOR_OUT:
     873                 :     case CAIRO_OPERATOR_ATOP:
     874                 :     case CAIRO_OPERATOR_DEST:
     875                 :     case CAIRO_OPERATOR_DEST_OVER:
     876                 :     case CAIRO_OPERATOR_DEST_IN:
     877                 :     case CAIRO_OPERATOR_DEST_OUT:
     878                 :     case CAIRO_OPERATOR_DEST_ATOP:
     879                 :     case CAIRO_OPERATOR_XOR:
     880                 :     case CAIRO_OPERATOR_ADD:
     881                 :     case CAIRO_OPERATOR_SATURATE:
     882               0 :         return "Normal";
     883                 :     }
     884                 : }
     885                 : 
     886                 : static void
     887               0 : _cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t         *surface,
     888                 :                                          cairo_pdf_group_resources_t *res)
     889                 : {
     890                 :     int num_alphas, num_smasks, num_resources, i;
     891                 :     double alpha;
     892                 :     cairo_pdf_resource_t *smask, *pattern, *xobject;
     893                 :     cairo_pdf_font_t *font;
     894                 : 
     895               0 :     _cairo_output_stream_printf (surface->output, "<<\n");
     896                 : 
     897               0 :     num_alphas = _cairo_array_num_elements (&res->alphas);
     898               0 :     num_smasks = _cairo_array_num_elements (&res->smasks);
     899               0 :     if (num_alphas > 0 || num_smasks > 0) {
     900               0 :         _cairo_output_stream_printf (surface->output,
     901                 :                                      "   /ExtGState <<\n");
     902                 : 
     903               0 :         for (i = 0; i < CAIRO_NUM_OPERATORS; i++) {
     904               0 :             if (res->operators[i]) {
     905               0 :                 _cairo_output_stream_printf (surface->output,
     906                 :                                              "      /b%d << /BM /%s >>\n",
     907                 :                                              i, _cairo_operator_to_pdf_blend_mode(i));
     908                 :             }
     909                 :         }
     910                 : 
     911               0 :         for (i = 0; i < num_alphas; i++) {
     912               0 :             _cairo_array_copy_element (&res->alphas, i, &alpha);
     913               0 :             _cairo_output_stream_printf (surface->output,
     914                 :                                          "      /a%d << /CA %f /ca %f >>\n",
     915                 :                                          i, alpha, alpha);
     916                 :         }
     917                 : 
     918               0 :         for (i = 0; i < num_smasks; i++) {
     919               0 :             smask = _cairo_array_index (&res->smasks, i);
     920               0 :             _cairo_output_stream_printf (surface->output,
     921                 :                                          "      /s%d %d 0 R\n",
     922                 :                                          smask->id, smask->id);
     923                 :         }
     924                 : 
     925               0 :         _cairo_output_stream_printf (surface->output,
     926                 :                                      "   >>\n");
     927                 :     }
     928                 : 
     929               0 :     num_resources = _cairo_array_num_elements (&res->patterns);
     930               0 :     if (num_resources > 0) {
     931               0 :         _cairo_output_stream_printf (surface->output,
     932                 :                                      "   /Pattern <<");
     933               0 :         for (i = 0; i < num_resources; i++) {
     934               0 :             pattern = _cairo_array_index (&res->patterns, i);
     935               0 :             _cairo_output_stream_printf (surface->output,
     936                 :                                          " /p%d %d 0 R",
     937                 :                                          pattern->id, pattern->id);
     938                 :         }
     939                 : 
     940               0 :         _cairo_output_stream_printf (surface->output,
     941                 :                                      " >>\n");
     942                 :     }
     943                 : 
     944               0 :     num_resources = _cairo_array_num_elements (&res->xobjects);
     945               0 :     if (num_resources > 0) {
     946               0 :         _cairo_output_stream_printf (surface->output,
     947                 :                                      "   /XObject <<");
     948                 : 
     949               0 :         for (i = 0; i < num_resources; i++) {
     950               0 :             xobject = _cairo_array_index (&res->xobjects, i);
     951               0 :             _cairo_output_stream_printf (surface->output,
     952                 :                                          " /x%d %d 0 R",
     953                 :                                          xobject->id, xobject->id);
     954                 :         }
     955                 : 
     956               0 :         _cairo_output_stream_printf (surface->output,
     957                 :                                      " >>\n");
     958                 :     }
     959                 : 
     960               0 :     num_resources = _cairo_array_num_elements (&res->fonts);
     961               0 :     if (num_resources > 0) {
     962               0 :         _cairo_output_stream_printf (surface->output,"   /Font <<\n");
     963               0 :         for (i = 0; i < num_resources; i++) {
     964               0 :             font = _cairo_array_index (&res->fonts, i);
     965               0 :             _cairo_output_stream_printf (surface->output,
     966                 :                                          "      /f-%d-%d %d 0 R\n",
     967                 :                                          font->font_id,
     968                 :                                          font->subset_id,
     969                 :                                          font->subset_resource.id);
     970                 :         }
     971               0 :         _cairo_output_stream_printf (surface->output, "   >>\n");
     972                 :     }
     973                 : 
     974               0 :     _cairo_output_stream_printf (surface->output,
     975                 :                                  ">>\n");
     976               0 : }
     977                 : 
     978                 : static cairo_pdf_smask_group_t *
     979               0 : _cairo_pdf_surface_create_smask_group (cairo_pdf_surface_t      *surface)
     980                 : {
     981                 :     cairo_pdf_smask_group_t     *group;
     982                 : 
     983               0 :     group = calloc (1, sizeof (cairo_pdf_smask_group_t));
     984               0 :     if (unlikely (group == NULL)) {
     985               0 :         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     986               0 :         return NULL;
     987                 :     }
     988                 : 
     989               0 :     group->group_res = _cairo_pdf_surface_new_object (surface);
     990               0 :     if (group->group_res.id == 0) {
     991               0 :         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     992               0 :         free (group);
     993               0 :         return NULL;
     994                 :     }
     995               0 :     group->width = surface->width;
     996               0 :     group->height = surface->height;
     997                 : 
     998               0 :     return group;
     999                 : }
    1000                 : 
    1001                 : static void
    1002               0 : _cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group)
    1003                 : {
    1004               0 :     if (group->operation == PDF_FILL ||      group->operation == PDF_STROKE)
    1005               0 :         _cairo_path_fixed_fini (&group->path);
    1006               0 :     if (group->source)
    1007               0 :         cairo_pattern_destroy (group->source);
    1008               0 :     if (group->mask)
    1009               0 :         cairo_pattern_destroy (group->mask);
    1010               0 :     if (group->utf8)
    1011               0 :         free (group->utf8);
    1012               0 :     if (group->glyphs)
    1013               0 :         free (group->glyphs);
    1014               0 :     if (group->clusters)
    1015               0 :         free (group->clusters);
    1016               0 :     if (group->scaled_font)
    1017               0 :         cairo_scaled_font_destroy (group->scaled_font);
    1018               0 :     free (group);
    1019               0 : }
    1020                 : 
    1021                 : static cairo_status_t
    1022               0 : _cairo_pdf_surface_add_smask_group (cairo_pdf_surface_t     *surface,
    1023                 :                                     cairo_pdf_smask_group_t *group)
    1024                 : {
    1025               0 :     return _cairo_array_append (&surface->smask_groups, &group);
    1026                 : }
    1027                 : 
    1028                 : static cairo_bool_t
    1029               0 : _cairo_pdf_source_surface_equal (const void *key_a, const void *key_b)
    1030                 : {
    1031               0 :     const cairo_pdf_source_surface_entry_t *a = key_a;
    1032               0 :     const cairo_pdf_source_surface_entry_t *b = key_b;
    1033                 : 
    1034               0 :     return (a->id == b->id) && (a->interpolate == b->interpolate);
    1035                 : }
    1036                 : 
    1037                 : static void
    1038               0 : _cairo_pdf_source_surface_init_key (cairo_pdf_source_surface_entry_t *key)
    1039                 : {
    1040               0 :     key->base.hash = key->id;
    1041               0 : }
    1042                 : 
    1043                 : static cairo_int_status_t
    1044               0 : _get_jpx_image_info (cairo_surface_t             *source,
    1045                 :                      cairo_image_info_t         *info,
    1046                 :                      const unsigned char        **mime_data,
    1047                 :                      unsigned long               *mime_data_length)
    1048                 : {
    1049               0 :     cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JP2,
    1050                 :                                  mime_data, mime_data_length);
    1051               0 :     if (*mime_data == NULL)
    1052               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    1053                 : 
    1054               0 :     return _cairo_image_info_get_jpx_info (info, *mime_data, *mime_data_length);
    1055                 : }
    1056                 : 
    1057                 : static cairo_int_status_t
    1058               0 : _get_jpeg_image_info (cairo_surface_t            *source,
    1059                 :                       cairo_image_info_t         *info,
    1060                 :                       const unsigned char       **mime_data,
    1061                 :                       unsigned long              *mime_data_length)
    1062                 : {
    1063               0 :     cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
    1064                 :                                  mime_data, mime_data_length);
    1065               0 :     if (*mime_data == NULL)
    1066               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    1067                 : 
    1068               0 :     return _cairo_image_info_get_jpeg_info (info, *mime_data, *mime_data_length);
    1069                 : }
    1070                 : 
    1071                 : static cairo_status_t
    1072               0 : _get_source_surface_size (cairo_surface_t         *source,
    1073                 :                           int                     *width,
    1074                 :                           int                     *height)
    1075                 : {
    1076                 :     cairo_status_t status;
    1077                 :     cairo_rectangle_int_t extents;
    1078                 :     cairo_image_info_t info;
    1079                 :     const unsigned char *mime_data;
    1080                 :     unsigned long mime_data_length;
    1081                 : 
    1082               0 :     if (source->type == CAIRO_SURFACE_TYPE_RECORDING) {
    1083               0 :         if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
    1084               0 :              cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
    1085                 : 
    1086               0 :             *width  = sub->extents.width;
    1087               0 :             *height = sub->extents.height;
    1088                 : 
    1089                 :         } else {
    1090               0 :             cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) source;
    1091                 :             cairo_box_t bbox;
    1092                 : 
    1093               0 :             status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
    1094               0 :             if (unlikely (status))
    1095               0 :                 return status;
    1096                 : 
    1097               0 :             _cairo_box_round_to_rectangle (&bbox, &extents);
    1098                 : 
    1099               0 :             *width = extents.width;
    1100               0 :             *height = extents.height;
    1101                 :         }
    1102               0 :         return CAIRO_STATUS_SUCCESS;
    1103                 :     }
    1104                 : 
    1105               0 :     status = _get_jpx_image_info (source, &info, &mime_data, &mime_data_length);
    1106               0 :     if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
    1107               0 :         *width = info.width;
    1108               0 :         *height = info.height;
    1109               0 :         return status;
    1110                 :     }
    1111                 : 
    1112               0 :     status = _get_jpeg_image_info (source, &info, &mime_data, &mime_data_length);
    1113               0 :     if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
    1114               0 :         *width = info.width;
    1115               0 :         *height = info.height;
    1116               0 :         return status;
    1117                 :     }
    1118                 : 
    1119               0 :     if (! _cairo_surface_get_extents (source, &extents))
    1120               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    1121                 : 
    1122               0 :     *width = extents.width;
    1123               0 :     *height = extents.height;
    1124                 : 
    1125               0 :     return CAIRO_STATUS_SUCCESS;
    1126                 : }
    1127                 : 
    1128                 : static cairo_status_t
    1129               0 : _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t      *surface,
    1130                 :                                        cairo_surface_t          *source,
    1131                 :                                        cairo_filter_t            filter,
    1132                 :                                        cairo_pdf_resource_t     *surface_res,
    1133                 :                                        int                      *width,
    1134                 :                                        int                      *height)
    1135                 : {
    1136                 :     cairo_pdf_source_surface_t src_surface;
    1137                 :     cairo_pdf_source_surface_entry_t surface_key;
    1138                 :     cairo_pdf_source_surface_entry_t *surface_entry;
    1139                 :     cairo_status_t status;
    1140                 :     cairo_bool_t interpolate;
    1141                 : 
    1142               0 :     switch (filter) {
    1143                 :     default:
    1144                 :     case CAIRO_FILTER_GOOD:
    1145                 :     case CAIRO_FILTER_BEST:
    1146                 :     case CAIRO_FILTER_BILINEAR:
    1147               0 :         interpolate = TRUE;
    1148               0 :         break;
    1149                 :     case CAIRO_FILTER_FAST:
    1150                 :     case CAIRO_FILTER_NEAREST:
    1151                 :     case CAIRO_FILTER_GAUSSIAN:
    1152               0 :         interpolate = FALSE;
    1153               0 :         break;
    1154                 :     }
    1155                 : 
    1156               0 :     surface_key.id  = source->unique_id;
    1157               0 :     surface_key.interpolate = interpolate;
    1158               0 :     _cairo_pdf_source_surface_init_key (&surface_key);
    1159               0 :     surface_entry = _cairo_hash_table_lookup (surface->all_surfaces, &surface_key.base);
    1160               0 :     if (surface_entry) {
    1161               0 :         *surface_res = surface_entry->surface_res;
    1162               0 :         *width = surface_entry->width;
    1163               0 :         *height = surface_entry->height;
    1164                 : 
    1165               0 :         return CAIRO_STATUS_SUCCESS;
    1166                 :     }
    1167                 : 
    1168               0 :     surface_entry = malloc (sizeof (cairo_pdf_source_surface_entry_t));
    1169               0 :     if (surface_entry == NULL)
    1170               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1171                 : 
    1172               0 :     surface_entry->id = surface_key.id;
    1173               0 :     surface_entry->interpolate = interpolate;
    1174               0 :     _cairo_pdf_source_surface_init_key (surface_entry);
    1175                 : 
    1176               0 :     src_surface.hash_entry = surface_entry;
    1177               0 :     src_surface.surface = cairo_surface_reference (source);
    1178               0 :     surface_entry->surface_res = _cairo_pdf_surface_new_object (surface);
    1179               0 :     if (surface_entry->surface_res.id == 0) {
    1180               0 :         cairo_surface_destroy (source);
    1181               0 :         free (surface_entry);
    1182               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1183                 :     }
    1184                 : 
    1185               0 :     status = _get_source_surface_size (source, &surface_entry->width,
    1186                 :                                        &surface_entry->height);
    1187                 : 
    1188               0 :     status = _cairo_array_append (&surface->page_surfaces, &src_surface);
    1189               0 :     if (unlikely (status)) {
    1190               0 :         cairo_surface_destroy (source);
    1191               0 :         free (surface_entry);
    1192               0 :         return status;
    1193                 :     }
    1194                 : 
    1195               0 :     status = _cairo_hash_table_insert (surface->all_surfaces,
    1196                 :                                        &surface_entry->base);
    1197                 : 
    1198               0 :     *surface_res = surface_entry->surface_res;
    1199               0 :     *width = surface_entry->width;
    1200               0 :     *height = surface_entry->height;
    1201                 : 
    1202               0 :     return status;
    1203                 : }
    1204                 : 
    1205                 : static cairo_status_t
    1206               0 : _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t         *surface,
    1207                 :                                     const cairo_pattern_t       *pattern,
    1208                 :                                     const cairo_rectangle_int_t *extents,
    1209                 :                                     cairo_pdf_resource_t        *pattern_res,
    1210                 :                                     cairo_pdf_resource_t        *gstate_res)
    1211                 : {
    1212                 :     cairo_pdf_pattern_t pdf_pattern;
    1213                 :     cairo_status_t status;
    1214                 : 
    1215                 :     /* Solid colors are emitted into the content stream */
    1216               0 :     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
    1217               0 :         pattern_res->id = 0;
    1218               0 :         gstate_res->id = 0;
    1219               0 :         return CAIRO_STATUS_SUCCESS;
    1220                 :     }
    1221                 : 
    1222               0 :     status = _cairo_pattern_create_copy (&pdf_pattern.pattern, pattern);
    1223               0 :     if (unlikely (status))
    1224               0 :         return status;
    1225                 : 
    1226               0 :     pdf_pattern.pattern_res = _cairo_pdf_surface_new_object (surface);
    1227               0 :     if (pdf_pattern.pattern_res.id == 0) {
    1228               0 :         cairo_pattern_destroy (pdf_pattern.pattern);
    1229               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1230                 :     }
    1231                 : 
    1232               0 :     pdf_pattern.gstate_res.id = 0;
    1233                 : 
    1234                 :     /* gradient patterns require an smask object to implement transparency */
    1235               0 :     if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
    1236               0 :         pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
    1237                 :     {
    1238               0 :         if (_cairo_pattern_is_opaque (pattern, extents) == FALSE) {
    1239               0 :             pdf_pattern.gstate_res = _cairo_pdf_surface_new_object (surface);
    1240               0 :             if (pdf_pattern.gstate_res.id == 0) {
    1241               0 :                 cairo_pattern_destroy (pdf_pattern.pattern);
    1242               0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1243                 :             }
    1244                 :         }
    1245                 :     }
    1246                 : 
    1247               0 :     pdf_pattern.width  = surface->width;
    1248               0 :     pdf_pattern.height = surface->height;
    1249               0 :     if (extents != NULL) {
    1250               0 :         pdf_pattern.extents = *extents;
    1251                 :     } else {
    1252               0 :         pdf_pattern.extents.x = 0;
    1253               0 :         pdf_pattern.extents.y = 0;
    1254               0 :         pdf_pattern.extents.width  = surface->width;
    1255               0 :         pdf_pattern.extents.height = surface->height;
    1256                 :     }
    1257                 : 
    1258               0 :     *pattern_res = pdf_pattern.pattern_res;
    1259               0 :     *gstate_res = pdf_pattern.gstate_res;
    1260                 : 
    1261               0 :     status = _cairo_array_append (&surface->page_patterns, &pdf_pattern);
    1262               0 :     if (unlikely (status)) {
    1263               0 :         cairo_pattern_destroy (pdf_pattern.pattern);
    1264               0 :         return status;
    1265                 :     }
    1266                 : 
    1267               0 :     return CAIRO_STATUS_SUCCESS;
    1268                 : }
    1269                 : 
    1270                 : static cairo_status_t
    1271               0 : _cairo_pdf_surface_open_stream (cairo_pdf_surface_t     *surface,
    1272                 :                                 cairo_pdf_resource_t    *resource,
    1273                 :                                 cairo_bool_t             compressed,
    1274                 :                                 const char              *fmt,
    1275                 :                                 ...)
    1276                 : {
    1277                 :     va_list ap;
    1278                 :     cairo_pdf_resource_t self, length;
    1279               0 :     cairo_output_stream_t *output = NULL;
    1280                 : 
    1281               0 :     if (resource) {
    1282               0 :         self = *resource;
    1283               0 :         _cairo_pdf_surface_update_object (surface, self);
    1284                 :     } else {
    1285               0 :         self = _cairo_pdf_surface_new_object (surface);
    1286               0 :         if (self.id == 0)
    1287               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1288                 :     }
    1289                 : 
    1290               0 :     length = _cairo_pdf_surface_new_object (surface);
    1291               0 :     if (length.id == 0)
    1292               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1293                 : 
    1294               0 :     if (compressed) {
    1295               0 :         output = _cairo_deflate_stream_create (surface->output);
    1296               0 :         if (_cairo_output_stream_get_status (output))
    1297               0 :             return _cairo_output_stream_destroy (output);
    1298                 :     }
    1299                 : 
    1300               0 :     surface->pdf_stream.active = TRUE;
    1301               0 :     surface->pdf_stream.self = self;
    1302               0 :     surface->pdf_stream.length = length;
    1303               0 :     surface->pdf_stream.compressed = compressed;
    1304               0 :     surface->current_pattern_is_solid_color = FALSE;
    1305               0 :     surface->current_operator = CAIRO_OPERATOR_OVER;
    1306               0 :     _cairo_pdf_operators_reset (&surface->pdf_operators);
    1307                 : 
    1308               0 :     _cairo_output_stream_printf (surface->output,
    1309                 :                                  "%d 0 obj\n"
    1310                 :                                  "<< /Length %d 0 R\n",
    1311                 :                                  surface->pdf_stream.self.id,
    1312                 :                                  surface->pdf_stream.length.id);
    1313               0 :     if (compressed)
    1314               0 :         _cairo_output_stream_printf (surface->output,
    1315                 :                                      "   /Filter /FlateDecode\n");
    1316                 : 
    1317               0 :     if (fmt != NULL) {
    1318               0 :         va_start (ap, fmt);
    1319               0 :         _cairo_output_stream_vprintf (surface->output, fmt, ap);
    1320               0 :         va_end (ap);
    1321                 :     }
    1322                 : 
    1323               0 :     _cairo_output_stream_printf (surface->output,
    1324                 :                                  ">>\n"
    1325                 :                                  "stream\n");
    1326                 : 
    1327               0 :     surface->pdf_stream.start_offset = _cairo_output_stream_get_position (surface->output);
    1328                 : 
    1329               0 :     if (compressed) {
    1330               0 :         assert (surface->pdf_stream.old_output == NULL);
    1331               0 :         surface->pdf_stream.old_output = surface->output;
    1332               0 :         surface->output = output;
    1333               0 :         _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
    1334                 :     }
    1335                 : 
    1336               0 :     return _cairo_output_stream_get_status (surface->output);
    1337                 : }
    1338                 : 
    1339                 : static cairo_status_t
    1340               0 : _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
    1341                 : {
    1342                 :     cairo_status_t status;
    1343                 :     long length;
    1344                 : 
    1345               0 :     if (! surface->pdf_stream.active)
    1346               0 :         return CAIRO_STATUS_SUCCESS;
    1347                 : 
    1348               0 :     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    1349                 : 
    1350               0 :     if (surface->pdf_stream.compressed) {
    1351                 :         cairo_status_t status2;
    1352                 : 
    1353               0 :         status2 = _cairo_output_stream_destroy (surface->output);
    1354               0 :         if (likely (status == CAIRO_STATUS_SUCCESS))
    1355               0 :             status = status2;
    1356                 : 
    1357               0 :         surface->output = surface->pdf_stream.old_output;
    1358               0 :         _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
    1359               0 :         surface->pdf_stream.old_output = NULL;
    1360                 :     }
    1361                 : 
    1362               0 :     length = _cairo_output_stream_get_position (surface->output) -
    1363               0 :         surface->pdf_stream.start_offset;
    1364               0 :     _cairo_output_stream_printf (surface->output,
    1365                 :                                  "\n"
    1366                 :                                  "endstream\n"
    1367                 :                                  "endobj\n");
    1368                 : 
    1369               0 :     _cairo_pdf_surface_update_object (surface,
    1370                 :                                       surface->pdf_stream.length);
    1371               0 :     _cairo_output_stream_printf (surface->output,
    1372                 :                                  "%d 0 obj\n"
    1373                 :                                  "   %ld\n"
    1374                 :                                  "endobj\n",
    1375                 :                                  surface->pdf_stream.length.id,
    1376                 :                                  length);
    1377                 : 
    1378               0 :     surface->pdf_stream.active = FALSE;
    1379                 : 
    1380               0 :     if (likely (status == CAIRO_STATUS_SUCCESS))
    1381               0 :         status = _cairo_output_stream_get_status (surface->output);
    1382                 : 
    1383               0 :     return status;
    1384                 : }
    1385                 : 
    1386                 : static void
    1387               0 : _cairo_pdf_surface_write_memory_stream (cairo_pdf_surface_t         *surface,
    1388                 :                                         cairo_output_stream_t       *mem_stream,
    1389                 :                                         cairo_pdf_resource_t         resource,
    1390                 :                                         cairo_pdf_group_resources_t *resources,
    1391                 :                                         cairo_bool_t                 is_knockout_group)
    1392                 : {
    1393               0 :     _cairo_pdf_surface_update_object (surface, resource);
    1394                 : 
    1395               0 :     _cairo_output_stream_printf (surface->output,
    1396                 :                                  "%d 0 obj\n"
    1397                 :                                  "<< /Type /XObject\n"
    1398                 :                                  "   /Length %d\n",
    1399                 :                                  resource.id,
    1400                 :                                  _cairo_memory_stream_length (mem_stream));
    1401                 : 
    1402               0 :     if (surface->compress_content) {
    1403               0 :         _cairo_output_stream_printf (surface->output,
    1404                 :                                      "   /Filter /FlateDecode\n");
    1405                 :     }
    1406                 : 
    1407               0 :     _cairo_output_stream_printf (surface->output,
    1408                 :                                  "   /Subtype /Form\n"
    1409                 :                                  "   /BBox [ 0 0 %f %f ]\n"
    1410                 :                                  "   /Group <<\n"
    1411                 :                                  "      /Type /Group\n"
    1412                 :                                  "      /S /Transparency\n"
    1413                 :                                  "      /CS /DeviceRGB\n",
    1414                 :                                  surface->width,
    1415                 :                                  surface->height);
    1416                 : 
    1417               0 :     if (is_knockout_group)
    1418               0 :         _cairo_output_stream_printf (surface->output,
    1419                 :                                      "      /K true\n");
    1420                 : 
    1421               0 :     _cairo_output_stream_printf (surface->output,
    1422                 :                                  "   >>\n"
    1423                 :                                  "   /Resources\n");
    1424               0 :     _cairo_pdf_surface_emit_group_resources (surface, resources);
    1425               0 :     _cairo_output_stream_printf (surface->output,
    1426                 :                                  ">>\n"
    1427                 :                                  "stream\n");
    1428               0 :     _cairo_memory_stream_copy (mem_stream, surface->output);
    1429               0 :     _cairo_output_stream_printf (surface->output,
    1430                 :                                  "endstream\n"
    1431                 :                                  "endobj\n");
    1432               0 : }
    1433                 : 
    1434                 : static cairo_status_t
    1435               0 : _cairo_pdf_surface_open_group (cairo_pdf_surface_t  *surface,
    1436                 :                                cairo_pdf_resource_t *resource)
    1437                 : {
    1438                 :     cairo_status_t status;
    1439                 : 
    1440               0 :     assert (surface->pdf_stream.active == FALSE);
    1441               0 :     assert (surface->group_stream.active == FALSE);
    1442                 : 
    1443               0 :     surface->group_stream.active = TRUE;
    1444               0 :     surface->current_pattern_is_solid_color = FALSE;
    1445               0 :     surface->current_operator = CAIRO_OPERATOR_OVER;
    1446               0 :     _cairo_pdf_operators_reset (&surface->pdf_operators);
    1447                 : 
    1448               0 :     surface->group_stream.mem_stream = _cairo_memory_stream_create ();
    1449                 : 
    1450               0 :     if (surface->compress_content) {
    1451               0 :         surface->group_stream.stream =
    1452               0 :             _cairo_deflate_stream_create (surface->group_stream.mem_stream);
    1453                 :     } else {
    1454               0 :         surface->group_stream.stream = surface->group_stream.mem_stream;
    1455                 :     }
    1456               0 :     status = _cairo_output_stream_get_status (surface->group_stream.stream);
    1457                 : 
    1458               0 :     surface->group_stream.old_output = surface->output;
    1459               0 :     surface->output = surface->group_stream.stream;
    1460               0 :     _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
    1461               0 :     _cairo_pdf_group_resources_clear (&surface->resources);
    1462                 : 
    1463               0 :     if (resource) {
    1464               0 :         surface->group_stream.resource = *resource;
    1465                 :     } else {
    1466               0 :         surface->group_stream.resource = _cairo_pdf_surface_new_object (surface);
    1467               0 :         if (surface->group_stream.resource.id == 0)
    1468               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1469                 :     }
    1470               0 :     surface->group_stream.is_knockout = FALSE;
    1471                 : 
    1472               0 :     return status;
    1473                 : }
    1474                 : 
    1475                 : static cairo_status_t
    1476               0 : _cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t  *surface)
    1477                 : {
    1478                 :     cairo_status_t status;
    1479                 : 
    1480               0 :     status = _cairo_pdf_surface_open_group (surface, NULL);
    1481               0 :     if (unlikely (status))
    1482               0 :         return status;
    1483                 : 
    1484               0 :     surface->group_stream.is_knockout = TRUE;
    1485                 : 
    1486               0 :     return CAIRO_STATUS_SUCCESS;
    1487                 : }
    1488                 : 
    1489                 : static cairo_status_t
    1490               0 : _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
    1491                 :                                 cairo_pdf_resource_t *group)
    1492                 : {
    1493               0 :     cairo_status_t status = CAIRO_STATUS_SUCCESS, status2;
    1494                 : 
    1495               0 :     assert (surface->pdf_stream.active == FALSE);
    1496               0 :     assert (surface->group_stream.active == TRUE);
    1497                 : 
    1498               0 :     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    1499               0 :     if (unlikely (status))
    1500               0 :         return status;
    1501                 : 
    1502               0 :     if (surface->compress_content) {
    1503               0 :         status = _cairo_output_stream_destroy (surface->group_stream.stream);
    1504               0 :         surface->group_stream.stream = NULL;
    1505                 : 
    1506               0 :         _cairo_output_stream_printf (surface->group_stream.mem_stream,
    1507                 :                                      "\n");
    1508                 :     }
    1509               0 :     surface->output = surface->group_stream.old_output;
    1510               0 :     _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
    1511               0 :     surface->group_stream.active = FALSE;
    1512               0 :     _cairo_pdf_surface_write_memory_stream (surface,
    1513                 :                                             surface->group_stream.mem_stream,
    1514                 :                                             surface->group_stream.resource,
    1515                 :                                             &surface->resources,
    1516                 :                                             surface->group_stream.is_knockout);
    1517               0 :     if (group)
    1518               0 :         *group = surface->group_stream.resource;
    1519                 : 
    1520               0 :     status2 = _cairo_output_stream_destroy (surface->group_stream.mem_stream);
    1521               0 :     if (status == CAIRO_STATUS_SUCCESS)
    1522               0 :         status = status2;
    1523                 : 
    1524               0 :     surface->group_stream.mem_stream = NULL;
    1525               0 :     surface->group_stream.stream = NULL;
    1526                 : 
    1527               0 :     return status;
    1528                 : }
    1529                 : 
    1530                 : static cairo_status_t
    1531               0 : _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t  *surface,
    1532                 :                                         cairo_pdf_resource_t *resource,
    1533                 :                                         cairo_bool_t          is_form)
    1534                 : {
    1535                 :     cairo_status_t status;
    1536                 : 
    1537               0 :     assert (surface->pdf_stream.active == FALSE);
    1538               0 :     assert (surface->group_stream.active == FALSE);
    1539                 : 
    1540               0 :     surface->content_resources = _cairo_pdf_surface_new_object (surface);
    1541               0 :     if (surface->content_resources.id == 0)
    1542               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1543                 : 
    1544               0 :     if (is_form) {
    1545               0 :         status =
    1546               0 :             _cairo_pdf_surface_open_stream (surface,
    1547                 :                                             resource,
    1548                 :                                             surface->compress_content,
    1549                 :                                             "   /Type /XObject\n"
    1550                 :                                             "   /Subtype /Form\n"
    1551                 :                                             "   /BBox [ 0 0 %f %f ]\n"
    1552                 :                                             "   /Group <<\n"
    1553                 :                                             "      /Type /Group\n"
    1554                 :                                             "      /S /Transparency\n"
    1555                 :                                             "      /CS /DeviceRGB\n"
    1556                 :                                             "   >>\n"
    1557                 :                                             "   /Resources %d 0 R\n",
    1558                 :                                             surface->width,
    1559                 :                                             surface->height,
    1560                 :                                             surface->content_resources.id);
    1561                 :     } else {
    1562               0 :         status =
    1563               0 :             _cairo_pdf_surface_open_stream (surface,
    1564                 :                                             resource,
    1565                 :                                             surface->compress_content,
    1566                 :                                             NULL);
    1567                 :     }
    1568               0 :     if (unlikely (status))
    1569               0 :         return status;
    1570                 : 
    1571               0 :     surface->content = surface->pdf_stream.self;
    1572                 : 
    1573               0 :     _cairo_output_stream_printf (surface->output, "q\n");
    1574                 : 
    1575               0 :     return _cairo_output_stream_get_status (surface->output);
    1576                 : }
    1577                 : 
    1578                 : static cairo_status_t
    1579               0 : _cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface)
    1580                 : {
    1581                 :     cairo_status_t status;
    1582                 : 
    1583               0 :     assert (surface->pdf_stream.active == TRUE);
    1584               0 :     assert (surface->group_stream.active == FALSE);
    1585                 : 
    1586               0 :     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    1587               0 :     if (unlikely (status))
    1588               0 :         return status;
    1589                 : 
    1590               0 :     _cairo_output_stream_printf (surface->output, "Q\n");
    1591               0 :     status = _cairo_pdf_surface_close_stream (surface);
    1592               0 :     if (unlikely (status))
    1593               0 :         return status;
    1594                 : 
    1595               0 :     _cairo_pdf_surface_update_object (surface, surface->content_resources);
    1596               0 :     _cairo_output_stream_printf (surface->output,
    1597                 :                                  "%d 0 obj\n",
    1598                 :                                  surface->content_resources.id);
    1599               0 :     _cairo_pdf_surface_emit_group_resources (surface, &surface->resources);
    1600               0 :     _cairo_output_stream_printf (surface->output,
    1601                 :                                  "endobj\n");
    1602                 : 
    1603               0 :     return _cairo_output_stream_get_status (surface->output);
    1604                 : }
    1605                 : 
    1606                 : static void
    1607               0 : _cairo_pdf_source_surface_entry_pluck (void *entry, void *closure)
    1608                 : {
    1609               0 :     cairo_pdf_source_surface_entry_t *surface_entry = entry;
    1610               0 :     cairo_hash_table_t *patterns = closure;
    1611                 : 
    1612               0 :     _cairo_hash_table_remove (patterns, &surface_entry->base);
    1613               0 :     free (surface_entry);
    1614               0 : }
    1615                 : 
    1616                 : static cairo_status_t
    1617               0 : _cairo_pdf_surface_finish (void *abstract_surface)
    1618                 : {
    1619               0 :     cairo_pdf_surface_t *surface = abstract_surface;
    1620                 :     long offset;
    1621                 :     cairo_pdf_resource_t info, catalog;
    1622                 :     cairo_status_t status, status2;
    1623                 : 
    1624               0 :     status = surface->base.status;
    1625               0 :     if (status == CAIRO_STATUS_SUCCESS)
    1626               0 :         status = _cairo_pdf_surface_emit_font_subsets (surface);
    1627                 : 
    1628               0 :     _cairo_pdf_surface_write_pages (surface);
    1629                 : 
    1630               0 :     info = _cairo_pdf_surface_write_info (surface);
    1631               0 :     if (info.id == 0 && status == CAIRO_STATUS_SUCCESS)
    1632               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1633                 : 
    1634               0 :     catalog = _cairo_pdf_surface_write_catalog (surface);
    1635               0 :     if (catalog.id == 0 && status == CAIRO_STATUS_SUCCESS)
    1636               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1637                 : 
    1638               0 :     offset = _cairo_pdf_surface_write_xref (surface);
    1639                 : 
    1640               0 :     _cairo_output_stream_printf (surface->output,
    1641                 :                                  "trailer\n"
    1642                 :                                  "<< /Size %d\n"
    1643                 :                                  "   /Root %d 0 R\n"
    1644                 :                                  "   /Info %d 0 R\n"
    1645                 :                                  ">>\n",
    1646                 :                                  surface->next_available_resource.id,
    1647                 :                                  catalog.id,
    1648                 :                                  info.id);
    1649                 : 
    1650               0 :     _cairo_output_stream_printf (surface->output,
    1651                 :                                  "startxref\n"
    1652                 :                                  "%ld\n"
    1653                 :                                  "%%%%EOF\n",
    1654                 :                                  offset);
    1655                 : 
    1656                 :     /* pdf_operators has already been flushed when the last stream was
    1657                 :      * closed so we should never be writing anything here - however,
    1658                 :      * the stream may itself be in an error state. */
    1659               0 :     status2 = _cairo_pdf_operators_fini (&surface->pdf_operators);
    1660               0 :     if (status == CAIRO_STATUS_SUCCESS)
    1661               0 :         status = status2;
    1662                 : 
    1663                 :     /* close any active streams still open due to fatal errors */
    1664               0 :     status2 = _cairo_pdf_surface_close_stream (surface);
    1665               0 :     if (status == CAIRO_STATUS_SUCCESS)
    1666               0 :         status = status2;
    1667                 : 
    1668               0 :     if (surface->group_stream.stream != NULL) {
    1669               0 :         status2 = _cairo_output_stream_destroy (surface->group_stream.stream);
    1670               0 :         if (status == CAIRO_STATUS_SUCCESS)
    1671               0 :             status = status2;
    1672                 :     }
    1673               0 :     if (surface->group_stream.mem_stream != NULL) {
    1674               0 :         status2 = _cairo_output_stream_destroy (surface->group_stream.mem_stream);
    1675               0 :         if (status == CAIRO_STATUS_SUCCESS)
    1676               0 :             status = status2;
    1677                 :     }
    1678               0 :     if (surface->pdf_stream.active)
    1679               0 :         surface->output = surface->pdf_stream.old_output;
    1680               0 :     if (surface->group_stream.active)
    1681               0 :         surface->output = surface->group_stream.old_output;
    1682                 : 
    1683                 :     /* and finish the pdf surface */
    1684               0 :     status2 = _cairo_output_stream_destroy (surface->output);
    1685               0 :     if (status == CAIRO_STATUS_SUCCESS)
    1686               0 :         status = status2;
    1687                 : 
    1688               0 :     _cairo_pdf_surface_clear (surface);
    1689               0 :     _cairo_pdf_group_resources_fini (&surface->resources);
    1690                 : 
    1691               0 :     _cairo_array_fini (&surface->objects);
    1692               0 :     _cairo_array_fini (&surface->pages);
    1693               0 :     _cairo_array_fini (&surface->rgb_linear_functions);
    1694               0 :     _cairo_array_fini (&surface->alpha_linear_functions);
    1695               0 :     _cairo_array_fini (&surface->page_patterns);
    1696               0 :     _cairo_array_fini (&surface->page_surfaces);
    1697               0 :     _cairo_hash_table_foreach (surface->all_surfaces,
    1698                 :                                _cairo_pdf_source_surface_entry_pluck,
    1699               0 :                                surface->all_surfaces);
    1700               0 :     _cairo_hash_table_destroy (surface->all_surfaces);
    1701               0 :     _cairo_array_fini (&surface->smask_groups);
    1702               0 :     _cairo_array_fini (&surface->fonts);
    1703               0 :     _cairo_array_fini (&surface->knockout_group);
    1704                 : 
    1705               0 :     if (surface->font_subsets) {
    1706               0 :         _cairo_scaled_font_subsets_destroy (surface->font_subsets);
    1707               0 :         surface->font_subsets = NULL;
    1708                 :     }
    1709                 : 
    1710               0 :     _cairo_surface_clipper_reset (&surface->clipper);
    1711                 : 
    1712               0 :     return status;
    1713                 : }
    1714                 : 
    1715                 : static cairo_int_status_t
    1716               0 : _cairo_pdf_surface_start_page (void *abstract_surface)
    1717                 : {
    1718               0 :     cairo_pdf_surface_t *surface = abstract_surface;
    1719                 : 
    1720                 :     /* Document header */
    1721               0 :     if (! surface->header_emitted) {
    1722                 :         const char *version;
    1723                 : 
    1724               0 :         switch (surface->pdf_version) {
    1725                 :         case CAIRO_PDF_VERSION_1_4:
    1726               0 :             version = "1.4";
    1727               0 :             break;
    1728                 :         default:
    1729                 :         case CAIRO_PDF_VERSION_1_5:
    1730               0 :             version = "1.5";
    1731               0 :             break;
    1732                 :         }
    1733                 : 
    1734               0 :         _cairo_output_stream_printf (surface->output,
    1735                 :                                      "%%PDF-%s\n", version);
    1736               0 :         _cairo_output_stream_printf (surface->output,
    1737                 :                                      "%%%c%c%c%c\n", 181, 237, 174, 251);
    1738               0 :         surface->header_emitted = TRUE;
    1739                 :     }
    1740                 : 
    1741               0 :     _cairo_pdf_group_resources_clear (&surface->resources);
    1742                 : 
    1743               0 :     return CAIRO_STATUS_SUCCESS;
    1744                 : }
    1745                 : 
    1746                 : static cairo_int_status_t
    1747               0 : _cairo_pdf_surface_has_fallback_images (void            *abstract_surface,
    1748                 :                                         cairo_bool_t     has_fallbacks)
    1749                 : {
    1750                 :     cairo_status_t status;
    1751               0 :     cairo_pdf_surface_t *surface = abstract_surface;
    1752                 : 
    1753               0 :     surface->has_fallback_images = has_fallbacks;
    1754               0 :     status = _cairo_pdf_surface_open_content_stream (surface, NULL, has_fallbacks);
    1755               0 :     if (unlikely (status))
    1756               0 :         return status;
    1757                 : 
    1758               0 :     return CAIRO_STATUS_SUCCESS;
    1759                 : }
    1760                 : 
    1761                 : static cairo_bool_t
    1762               0 : _cairo_pdf_surface_supports_fine_grained_fallbacks (void *abstract_surface)
    1763                 : {
    1764               0 :     return TRUE;
    1765                 : }
    1766                 : 
    1767                 : /* Emit alpha channel from the image into the given data, providing
    1768                 :  * an id that can be used to reference the resulting SMask object.
    1769                 :  *
    1770                 :  * In the case that the alpha channel happens to be all opaque, then
    1771                 :  * no SMask object will be emitted and *id_ret will be set to 0.
    1772                 :  */
    1773                 : static cairo_status_t
    1774               0 : _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t      *surface,
    1775                 :                                cairo_image_surface_t    *image,
    1776                 :                                cairo_pdf_resource_t     *stream_ret)
    1777                 : {
    1778               0 :     cairo_status_t status = CAIRO_STATUS_SUCCESS;
    1779                 :     char *alpha;
    1780                 :     unsigned long alpha_size;
    1781                 :     uint32_t *pixel32;
    1782                 :     uint8_t *pixel8;
    1783                 :     int i, x, y;
    1784                 :     cairo_bool_t opaque;
    1785                 :     uint8_t a;
    1786                 : 
    1787                 :     /* This is the only image format we support, which simplifies things. */
    1788               0 :     assert (image->format == CAIRO_FORMAT_ARGB32 ||
    1789                 :             image->format == CAIRO_FORMAT_A8 ||
    1790                 :             image->format == CAIRO_FORMAT_A1 );
    1791                 : 
    1792               0 :     stream_ret->id = 0;
    1793                 : 
    1794               0 :     if (image->format == CAIRO_FORMAT_A1) {
    1795               0 :         alpha_size = (image->width + 7) / 8 * image->height;
    1796               0 :         alpha = _cairo_malloc_ab ((image->width+7) / 8, image->height);
    1797                 :     } else {
    1798               0 :         alpha_size = image->height * image->width;
    1799               0 :         alpha = _cairo_malloc_ab (image->height, image->width);
    1800                 :     }
    1801                 : 
    1802               0 :     if (unlikely (alpha == NULL)) {
    1803               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1804               0 :         goto CLEANUP;
    1805                 :     }
    1806                 : 
    1807               0 :     opaque = TRUE;
    1808               0 :     i = 0;
    1809               0 :     for (y = 0; y < image->height; y++) {
    1810               0 :         if (image->format == CAIRO_FORMAT_ARGB32) {
    1811               0 :             pixel32 = (uint32_t *) (image->data + y * image->stride);
    1812                 : 
    1813               0 :             for (x = 0; x < image->width; x++, pixel32++) {
    1814               0 :                 a = (*pixel32 & 0xff000000) >> 24;
    1815               0 :                 alpha[i++] = a;
    1816               0 :                 if (a != 0xff)
    1817               0 :                     opaque = FALSE;
    1818                 :             }
    1819               0 :         } else if (image->format == CAIRO_FORMAT_A8){
    1820               0 :             pixel8 = (uint8_t *) (image->data + y * image->stride);
    1821                 : 
    1822               0 :             for (x = 0; x < image->width; x++, pixel8++) {
    1823               0 :                 a = *pixel8;
    1824               0 :                 alpha[i++] = a;
    1825               0 :                 if (a != 0xff)
    1826               0 :                     opaque = FALSE;
    1827                 :             }
    1828                 :         } else { /* image->format == CAIRO_FORMAT_A1 */
    1829               0 :             pixel8 = (uint8_t *) (image->data + y * image->stride);
    1830                 : 
    1831               0 :             for (x = 0; x < (image->width + 7) / 8; x++, pixel8++) {
    1832               0 :                 a = *pixel8;
    1833               0 :                 a = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (a);
    1834               0 :                 alpha[i++] = a;
    1835               0 :                 if (a != 0xff)
    1836               0 :                     opaque = FALSE;
    1837                 :             }
    1838                 :         }
    1839                 :     }
    1840                 : 
    1841                 :     /* Bail out without emitting smask if it's all opaque. */
    1842               0 :     if (opaque)
    1843               0 :         goto CLEANUP_ALPHA;
    1844                 : 
    1845               0 :     status = _cairo_pdf_surface_open_stream (surface,
    1846                 :                                              NULL,
    1847                 :                                              TRUE,
    1848                 :                                              "   /Type /XObject\n"
    1849                 :                                              "   /Subtype /Image\n"
    1850                 :                                              "   /Width %d\n"
    1851                 :                                              "   /Height %d\n"
    1852                 :                                              "   /ColorSpace /DeviceGray\n"
    1853                 :                                              "   /BitsPerComponent %d\n",
    1854                 :                                              image->width, image->height,
    1855               0 :                                              image->format == CAIRO_FORMAT_A1 ? 1 : 8);
    1856               0 :     if (unlikely (status))
    1857               0 :         goto CLEANUP_ALPHA;
    1858                 : 
    1859               0 :     *stream_ret = surface->pdf_stream.self;
    1860               0 :     _cairo_output_stream_write (surface->output, alpha, alpha_size);
    1861               0 :     status = _cairo_pdf_surface_close_stream (surface);
    1862                 : 
    1863                 :  CLEANUP_ALPHA:
    1864               0 :     free (alpha);
    1865                 :  CLEANUP:
    1866               0 :     return status;
    1867                 : }
    1868                 : 
    1869                 : /* Emit image data into the given surface, providing a resource that
    1870                 :  * can be used to reference the data in image_ret. */
    1871                 : static cairo_status_t
    1872               0 : _cairo_pdf_surface_emit_image (cairo_pdf_surface_t     *surface,
    1873                 :                                cairo_image_surface_t   *image,
    1874                 :                                cairo_pdf_resource_t    *image_res,
    1875                 :                                cairo_filter_t           filter)
    1876                 : {
    1877               0 :     cairo_status_t status = CAIRO_STATUS_SUCCESS;
    1878                 :     char *rgb;
    1879                 :     unsigned long rgb_size;
    1880                 :     uint32_t *pixel;
    1881                 :     int i, x, y;
    1882               0 :     cairo_pdf_resource_t smask = {0}; /* squelch bogus compiler warning */
    1883                 :     cairo_bool_t need_smask;
    1884               0 :     const char *interpolate = "true";
    1885                 : 
    1886                 :     /* These are the only image formats we currently support, (which
    1887                 :      * makes things a lot simpler here). This is enforced through
    1888                 :      * _cairo_pdf_surface_analyze_operation which only accept source surfaces of
    1889                 :      * CONTENT_COLOR or CONTENT_COLOR_ALPHA.
    1890                 :      */
    1891               0 :     assert (image->format == CAIRO_FORMAT_RGB24 ||
    1892                 :             image->format == CAIRO_FORMAT_ARGB32 ||
    1893                 :             image->format == CAIRO_FORMAT_A8 ||
    1894                 :             image->format == CAIRO_FORMAT_A1);
    1895                 : 
    1896               0 :     rgb_size = image->height * image->width * 3;
    1897               0 :     rgb = _cairo_malloc_abc (image->width, image->height, 3);
    1898               0 :     if (unlikely (rgb == NULL)) {
    1899               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1900               0 :         goto CLEANUP;
    1901                 :     }
    1902                 : 
    1903               0 :     i = 0;
    1904               0 :     for (y = 0; y < image->height; y++) {
    1905               0 :         pixel = (uint32_t *) (image->data + y * image->stride);
    1906                 : 
    1907               0 :         for (x = 0; x < image->width; x++, pixel++) {
    1908                 :             /* XXX: We're un-premultiplying alpha here. My reading of the PDF
    1909                 :              * specification suggests that we should be able to avoid having
    1910                 :              * to do this by filling in the SMask's Matte dictionary
    1911                 :              * appropriately, but my attempts to do that so far have
    1912                 :              * failed. */
    1913               0 :             if (image->format == CAIRO_FORMAT_ARGB32) {
    1914                 :                 uint8_t a;
    1915               0 :                 a = (*pixel & 0xff000000) >> 24;
    1916               0 :                 if (a == 0) {
    1917               0 :                     rgb[i++] = 0;
    1918               0 :                     rgb[i++] = 0;
    1919               0 :                     rgb[i++] = 0;
    1920                 :                 } else {
    1921               0 :                     rgb[i++] = (((*pixel & 0xff0000) >> 16) * 255 + a / 2) / a;
    1922               0 :                     rgb[i++] = (((*pixel & 0x00ff00) >>  8) * 255 + a / 2) / a;
    1923               0 :                     rgb[i++] = (((*pixel & 0x0000ff) >>  0) * 255 + a / 2) / a;
    1924                 :                 }
    1925               0 :             } else if (image->format == CAIRO_FORMAT_RGB24) {
    1926               0 :                 rgb[i++] = (*pixel & 0x00ff0000) >> 16;
    1927               0 :                 rgb[i++] = (*pixel & 0x0000ff00) >>  8;
    1928               0 :                 rgb[i++] = (*pixel & 0x000000ff) >>  0;
    1929                 :             } else {
    1930               0 :                 rgb[i++] = 0;
    1931               0 :                 rgb[i++] = 0;
    1932               0 :                 rgb[i++] = 0;
    1933                 :             }
    1934                 :         }
    1935                 :     }
    1936                 : 
    1937               0 :     need_smask = FALSE;
    1938               0 :     if (image->format == CAIRO_FORMAT_ARGB32 ||
    1939               0 :         image->format == CAIRO_FORMAT_A8 ||
    1940               0 :         image->format == CAIRO_FORMAT_A1) {
    1941               0 :         status = _cairo_pdf_surface_emit_smask (surface, image, &smask);
    1942               0 :         if (unlikely (status))
    1943               0 :             goto CLEANUP_RGB;
    1944                 : 
    1945               0 :         if (smask.id)
    1946               0 :             need_smask = TRUE;
    1947                 :     }
    1948                 : 
    1949               0 :     switch (filter) {
    1950                 :     case CAIRO_FILTER_GOOD:
    1951                 :     case CAIRO_FILTER_BEST:
    1952                 :     case CAIRO_FILTER_BILINEAR:
    1953               0 :         interpolate = "true";
    1954               0 :         break;
    1955                 :     case CAIRO_FILTER_FAST:
    1956                 :     case CAIRO_FILTER_NEAREST:
    1957                 :     case CAIRO_FILTER_GAUSSIAN:
    1958               0 :         interpolate = "false";
    1959               0 :         break;
    1960                 :     }
    1961                 : 
    1962                 : #define IMAGE_DICTIONARY        "   /Type /XObject\n"         \
    1963                 :                                 "   /Subtype /Image\n"        \
    1964                 :                                 "   /Width %d\n"              \
    1965                 :                                 "   /Height %d\n"             \
    1966                 :                                 "   /ColorSpace /DeviceRGB\n" \
    1967                 :                                 "   /Interpolate %s\n" \
    1968                 :                                 "   /BitsPerComponent 8\n"
    1969                 : 
    1970               0 :     if (need_smask)
    1971               0 :         status = _cairo_pdf_surface_open_stream (surface,
    1972                 :                                                  image_res,
    1973                 :                                                  TRUE,
    1974                 :                                                  IMAGE_DICTIONARY
    1975                 :                                                  "   /SMask %d 0 R\n",
    1976                 :                                                  image->width, image->height,
    1977                 :                                                  interpolate,
    1978                 :                                                  smask.id);
    1979                 :     else
    1980               0 :         status = _cairo_pdf_surface_open_stream (surface,
    1981                 :                                                  image_res,
    1982                 :                                                  TRUE,
    1983                 :                                                  IMAGE_DICTIONARY,
    1984                 :                                                  image->width, image->height,
    1985                 :                                                  interpolate);
    1986               0 :     if (unlikely (status))
    1987               0 :         goto CLEANUP_RGB;
    1988                 : 
    1989                 : #undef IMAGE_DICTIONARY
    1990                 : 
    1991               0 :     _cairo_output_stream_write (surface->output, rgb, rgb_size);
    1992               0 :     status = _cairo_pdf_surface_close_stream (surface);
    1993                 : 
    1994                 : CLEANUP_RGB:
    1995               0 :     free (rgb);
    1996                 : CLEANUP:
    1997               0 :     return status;
    1998                 : }
    1999                 : 
    2000                 : static cairo_int_status_t
    2001               0 : _cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t   *surface,
    2002                 :                                    cairo_surface_t       *source,
    2003                 :                                    cairo_pdf_resource_t   res)
    2004                 : {
    2005                 :     cairo_status_t status;
    2006                 :     const unsigned char *mime_data;
    2007                 :     unsigned long mime_data_length;
    2008                 :     cairo_image_info_t info;
    2009                 : 
    2010               0 :     if (surface->pdf_version < CAIRO_PDF_VERSION_1_5)
    2011               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    2012                 : 
    2013               0 :     cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JP2,
    2014                 :                                  &mime_data, &mime_data_length);
    2015               0 :     if (mime_data == NULL)
    2016               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    2017                 : 
    2018               0 :     status = _cairo_image_info_get_jpx_info (&info, mime_data, mime_data_length);
    2019               0 :     if (status)
    2020               0 :         return status;
    2021                 : 
    2022               0 :     status = _cairo_pdf_surface_open_stream (surface,
    2023                 :                                              &res,
    2024                 :                                              FALSE,
    2025                 :                                              "   /Type /XObject\n"
    2026                 :                                              "   /Subtype /Image\n"
    2027                 :                                              "   /Width %d\n"
    2028                 :                                              "   /Height %d\n"
    2029                 :                                              "   /Filter /JPXDecode\n",
    2030                 :                                              info.width,
    2031                 :                                              info.height);
    2032               0 :     if (status)
    2033               0 :         return status;
    2034                 : 
    2035               0 :     _cairo_output_stream_write (surface->output, mime_data, mime_data_length);
    2036               0 :     status = _cairo_pdf_surface_close_stream (surface);
    2037                 : 
    2038               0 :     return status;
    2039                 : }
    2040                 : 
    2041                 : static cairo_int_status_t
    2042               0 : _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t   *surface,
    2043                 :                                     cairo_surface_t       *source,
    2044                 :                                     cairo_pdf_resource_t   res)
    2045                 : {
    2046                 :     cairo_status_t status;
    2047                 :     const unsigned char *mime_data;
    2048                 :     unsigned long mime_data_length;
    2049                 :     cairo_image_info_t info;
    2050                 : 
    2051               0 :     cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
    2052                 :                                  &mime_data, &mime_data_length);
    2053               0 :     if (unlikely (source->status))
    2054               0 :         return source->status;
    2055               0 :     if (mime_data == NULL)
    2056               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    2057                 : 
    2058               0 :     status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length);
    2059               0 :     if (unlikely (status))
    2060               0 :         return status;
    2061                 : 
    2062               0 :     if (info.num_components != 1 && info.num_components != 3)
    2063               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    2064                 : 
    2065               0 :     status = _cairo_pdf_surface_open_stream (surface,
    2066                 :                                              &res,
    2067                 :                                              FALSE,
    2068                 :                                              "   /Type /XObject\n"
    2069                 :                                              "   /Subtype /Image\n"
    2070                 :                                              "   /Width %d\n"
    2071                 :                                              "   /Height %d\n"
    2072                 :                                              "   /ColorSpace %s\n"
    2073                 :                                              "   /BitsPerComponent %d\n"
    2074                 :                                              "   /Filter /DCTDecode\n",
    2075                 :                                              info.width,
    2076                 :                                              info.height,
    2077               0 :                                              info.num_components == 1 ? "/DeviceGray" : "/DeviceRGB",
    2078                 :                                              info.bits_per_component);
    2079               0 :     if (unlikely (status))
    2080               0 :         return status;
    2081                 : 
    2082               0 :     _cairo_output_stream_write (surface->output, mime_data, mime_data_length);
    2083               0 :     status = _cairo_pdf_surface_close_stream (surface);
    2084                 : 
    2085               0 :     return status;
    2086                 : }
    2087                 : 
    2088                 : static cairo_status_t
    2089               0 : _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t     *surface,
    2090                 :                                        cairo_surface_t         *source,
    2091                 :                                        cairo_pdf_resource_t     resource,
    2092                 :                                        cairo_bool_t             interpolate)
    2093                 : {
    2094                 :     cairo_image_surface_t *image;
    2095                 :     void *image_extra;
    2096                 :     cairo_status_t status;
    2097                 : 
    2098               0 :     status = _cairo_pdf_surface_emit_jpx_image (surface, source, resource);
    2099               0 :     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    2100               0 :         return status;
    2101                 : 
    2102               0 :     status = _cairo_pdf_surface_emit_jpeg_image (surface, source, resource);
    2103               0 :     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    2104               0 :         return status;
    2105                 : 
    2106               0 :     status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
    2107               0 :     if (unlikely (status))
    2108               0 :         return status;
    2109                 : 
    2110               0 :     status = _cairo_pdf_surface_emit_image (surface, image,
    2111                 :                                             &resource, interpolate);
    2112               0 :     if (unlikely (status))
    2113               0 :         goto BAIL;
    2114                 : 
    2115                 : BAIL:
    2116               0 :     _cairo_surface_release_source_image (source, image, image_extra);
    2117                 : 
    2118               0 :     return status;
    2119                 : }
    2120                 : 
    2121                 : static cairo_status_t
    2122               0 : _cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t     *surface,
    2123                 :                                               cairo_pdf_pattern_t     *pdf_pattern,
    2124                 :                                               cairo_pdf_resource_t    *resource,
    2125                 :                                               int                     *width,
    2126                 :                                               int                     *height,
    2127                 :                                               int                     *origin_x,
    2128                 :                                               int                     *origin_y)
    2129                 : {
    2130                 :     cairo_image_surface_t *image;
    2131                 :     cairo_surface_t *pad_image;
    2132                 :     void *image_extra;
    2133                 :     cairo_status_t status;
    2134               0 :     cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern;
    2135               0 :     int x = 0;
    2136               0 :     int y = 0;
    2137                 :     cairo_bool_t interpolate;
    2138                 : 
    2139               0 :     status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
    2140               0 :     if (unlikely (status))
    2141               0 :         return status;
    2142                 : 
    2143               0 :     pad_image = &image->base;
    2144               0 :     if (pattern->base.extend == CAIRO_EXTEND_PAD) {
    2145                 :         cairo_box_t box;
    2146                 :         cairo_rectangle_int_t rect;
    2147                 :         cairo_surface_pattern_t pad_pattern;
    2148                 : 
    2149                 :         /* get the operation extents in pattern space */
    2150               0 :         _cairo_box_from_rectangle (&box, &pdf_pattern->extents);
    2151               0 :         _cairo_matrix_transform_bounding_box_fixed (&pattern->base.matrix, &box, NULL);
    2152               0 :         _cairo_box_round_to_rectangle (&box, &rect);
    2153               0 :         x = -rect.x;
    2154               0 :         y = -rect.y;
    2155                 : 
    2156               0 :         pad_image = _cairo_image_surface_create_with_content (pattern->surface->content,
    2157                 :                                                               rect.width,
    2158                 :                                                               rect.height);
    2159               0 :         if (pad_image->status) {
    2160               0 :             status = pad_image->status;
    2161               0 :             goto BAIL;
    2162                 :         }
    2163                 : 
    2164               0 :         _cairo_pattern_init_for_surface (&pad_pattern, &image->base);
    2165               0 :         cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y);
    2166               0 :         pad_pattern.base.extend = CAIRO_EXTEND_PAD;
    2167               0 :         status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
    2168                 :                                            &pad_pattern.base,
    2169                 :                                            NULL,
    2170                 :                                            pad_image,
    2171                 :                                            0, 0,
    2172                 :                                            0, 0,
    2173                 :                                            0, 0,
    2174               0 :                                            rect.width,
    2175               0 :                                            rect.height,
    2176                 :                                            NULL);
    2177               0 :         _cairo_pattern_fini (&pad_pattern.base);
    2178               0 :         if (unlikely (status))
    2179               0 :             goto BAIL;
    2180                 :     }
    2181                 : 
    2182               0 :     switch (pdf_pattern->pattern->filter) {
    2183                 :     case CAIRO_FILTER_GOOD:
    2184                 :     case CAIRO_FILTER_BEST:
    2185                 :     case CAIRO_FILTER_BILINEAR:
    2186               0 :         interpolate = TRUE;
    2187               0 :         break;
    2188                 :     case CAIRO_FILTER_FAST:
    2189                 :     case CAIRO_FILTER_NEAREST:
    2190                 :     case CAIRO_FILTER_GAUSSIAN:
    2191               0 :         interpolate = FALSE;
    2192               0 :         break;
    2193                 :     }
    2194                 : 
    2195               0 :     *resource = _cairo_pdf_surface_new_object (surface);
    2196               0 :     if (resource->id == 0) {
    2197               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2198               0 :         goto BAIL;
    2199                 :     }
    2200                 : 
    2201               0 :     status = _cairo_pdf_surface_emit_image (surface, (cairo_image_surface_t *)pad_image,
    2202                 :                                             resource, interpolate);
    2203               0 :     if (unlikely (status))
    2204               0 :         goto BAIL;
    2205                 : 
    2206               0 :     *width = ((cairo_image_surface_t *)pad_image)->width;
    2207               0 :     *height = ((cairo_image_surface_t *)pad_image)->height;
    2208               0 :     *origin_x = x;
    2209               0 :     *origin_y = y;
    2210                 : 
    2211                 : BAIL:
    2212               0 :     if (pad_image != &image->base)
    2213               0 :         cairo_surface_destroy (pad_image);
    2214                 : 
    2215               0 :     _cairo_surface_release_source_image (pattern->surface, image, image_extra);
    2216                 : 
    2217               0 :     return status;
    2218                 : }
    2219                 : 
    2220                 : 
    2221                 : static cairo_status_t
    2222               0 : _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t  *surface,
    2223                 :                                            cairo_surface_t      *recording_surface,
    2224                 :                                            cairo_pdf_resource_t  resource)
    2225                 : {
    2226                 :     double old_width, old_height;
    2227                 :     cairo_paginated_mode_t old_paginated_mode;
    2228                 :     cairo_rectangle_int_t recording_extents;
    2229                 :     cairo_bool_t is_bounded;
    2230                 :     cairo_status_t status;
    2231               0 :     int alpha = 0;
    2232                 : 
    2233               0 :     is_bounded = _cairo_surface_get_extents (recording_surface, &recording_extents);
    2234               0 :     assert (is_bounded);
    2235                 : 
    2236               0 :     old_width = surface->width;
    2237               0 :     old_height = surface->height;
    2238               0 :     old_paginated_mode = surface->paginated_mode;
    2239                 : 
    2240               0 :     _cairo_pdf_surface_set_size_internal (surface,
    2241               0 :                                           recording_extents.width,
    2242               0 :                                           recording_extents.height);
    2243                 :     /* Patterns are emitted after fallback images. The paginated mode
    2244                 :      * needs to be set to _RENDER while the recording surface is replayed
    2245                 :      * back to this surface.
    2246                 :      */
    2247               0 :     surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER;
    2248               0 :     _cairo_pdf_group_resources_clear (&surface->resources);
    2249               0 :     status = _cairo_pdf_surface_open_content_stream (surface, &resource, TRUE);
    2250               0 :     if (unlikely (status))
    2251               0 :         return status;
    2252                 : 
    2253               0 :     if (cairo_surface_get_content (recording_surface) == CAIRO_CONTENT_COLOR) {
    2254               0 :         status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
    2255               0 :         if (unlikely (status))
    2256               0 :             return status;
    2257                 : 
    2258               0 :         _cairo_output_stream_printf (surface->output,
    2259                 :                                      "q /a%d gs 0 0 0 rg 0 0 %f %f re f Q\n",
    2260                 :                                      alpha,
    2261                 :                                      surface->width,
    2262                 :                                      surface->height);
    2263                 :     }
    2264                 : 
    2265               0 :     status = _cairo_recording_surface_replay_region (recording_surface,
    2266                 :                                                      NULL,
    2267                 :                                                      &surface->base,
    2268                 :                                                      CAIRO_RECORDING_REGION_NATIVE);
    2269               0 :     assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
    2270               0 :     if (unlikely (status))
    2271               0 :         return status;
    2272                 : 
    2273               0 :     status = _cairo_pdf_surface_close_content_stream (surface);
    2274                 : 
    2275               0 :     _cairo_pdf_surface_set_size_internal (surface,
    2276                 :                                           old_width,
    2277                 :                                           old_height);
    2278               0 :     surface->paginated_mode = old_paginated_mode;
    2279                 : 
    2280               0 :     return status;
    2281                 : }
    2282                 : 
    2283                 : static cairo_status_t
    2284               0 : _cairo_pdf_surface_emit_recording_subsurface (cairo_pdf_surface_t  *surface,
    2285                 :                                               cairo_surface_t      *recording_surface,
    2286                 :                                               const cairo_rectangle_int_t *extents,
    2287                 :                                               cairo_pdf_resource_t  resource)
    2288                 : {
    2289                 :     double old_width, old_height;
    2290                 :     cairo_paginated_mode_t old_paginated_mode;
    2291                 :     cairo_status_t status;
    2292               0 :     int alpha = 0;
    2293                 : 
    2294               0 :     old_width = surface->width;
    2295               0 :     old_height = surface->height;
    2296               0 :     old_paginated_mode = surface->paginated_mode;
    2297                 : 
    2298               0 :     _cairo_pdf_surface_set_size_internal (surface,
    2299               0 :                                           extents->width,
    2300               0 :                                           extents->height);
    2301                 :     /* Patterns are emitted after fallback images. The paginated mode
    2302                 :      * needs to be set to _RENDER while the recording surface is replayed
    2303                 :      * back to this surface.
    2304                 :      */
    2305               0 :     surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER;
    2306               0 :     _cairo_pdf_group_resources_clear (&surface->resources);
    2307               0 :     status = _cairo_pdf_surface_open_content_stream (surface, &resource, TRUE);
    2308               0 :     if (unlikely (status))
    2309               0 :         return status;
    2310                 : 
    2311               0 :     if (cairo_surface_get_content (recording_surface) == CAIRO_CONTENT_COLOR) {
    2312               0 :         status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
    2313               0 :         if (unlikely (status))
    2314               0 :             return status;
    2315                 : 
    2316               0 :         _cairo_output_stream_printf (surface->output,
    2317                 :                                      "q /a%d gs 0 0 0 rg 0 0 %f %f re f Q\n",
    2318                 :                                      alpha,
    2319                 :                                      surface->width,
    2320                 :                                      surface->height);
    2321                 :     }
    2322                 : 
    2323               0 :     status = _cairo_recording_surface_replay_region (recording_surface,
    2324                 :                                                      extents,
    2325                 :                                                      &surface->base,
    2326                 :                                                      CAIRO_RECORDING_REGION_NATIVE);
    2327               0 :     assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
    2328               0 :     if (unlikely (status))
    2329               0 :         return status;
    2330                 : 
    2331               0 :     status = _cairo_pdf_surface_close_content_stream (surface);
    2332                 : 
    2333               0 :     _cairo_pdf_surface_set_size_internal (surface,
    2334                 :                                           old_width,
    2335                 :                                           old_height);
    2336               0 :     surface->paginated_mode = old_paginated_mode;
    2337                 : 
    2338               0 :     return status;
    2339                 : }
    2340                 : 
    2341                 : static cairo_status_t
    2342               0 : _cairo_pdf_surface_emit_surface (cairo_pdf_surface_t        *surface,
    2343                 :                                  cairo_pdf_source_surface_t *src_surface)
    2344                 : {
    2345               0 :     if (src_surface->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
    2346               0 :         if (src_surface->surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
    2347               0 :             cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) src_surface->surface;
    2348               0 :             return _cairo_pdf_surface_emit_recording_subsurface (surface,
    2349                 :                                                                  sub->target,
    2350               0 :                                                                  &sub->extents,
    2351               0 :                                                                  src_surface->hash_entry->surface_res);
    2352                 :         } else {
    2353               0 :             return _cairo_pdf_surface_emit_recording_surface (surface,
    2354                 :                                                               src_surface->surface,
    2355               0 :                                                               src_surface->hash_entry->surface_res);
    2356                 :         }
    2357                 :     } else {
    2358               0 :         return _cairo_pdf_surface_emit_image_surface (surface,
    2359                 :                                                       src_surface->surface,
    2360               0 :                                                       src_surface->hash_entry->surface_res,
    2361               0 :                                                       src_surface->hash_entry->interpolate);
    2362                 :     }
    2363                 : }
    2364                 : 
    2365                 : static cairo_status_t
    2366               0 : _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t    *surface,
    2367                 :                                          cairo_pdf_pattern_t    *pdf_pattern)
    2368                 : {
    2369               0 :     cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern;
    2370                 :     cairo_status_t status;
    2371               0 :     cairo_pdf_resource_t pattern_resource = {0};
    2372                 :     cairo_matrix_t cairo_p2d, pdf_p2d;
    2373               0 :     cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base);
    2374                 :     double xstep, ystep;
    2375               0 :     int pattern_width = 0; /* squelch bogus compiler warning */
    2376               0 :     int pattern_height = 0; /* squelch bogus compiler warning */
    2377               0 :     int origin_x = 0; /* squelch bogus compiler warning */
    2378               0 :     int origin_y = 0; /* squelch bogus compiler warning */
    2379                 :     int bbox_x, bbox_y;
    2380                 :     char draw_surface[200];
    2381                 : 
    2382               0 :     if (pattern->base.extend == CAIRO_EXTEND_PAD &&
    2383               0 :         pattern->surface->type != CAIRO_SURFACE_TYPE_RECORDING)
    2384                 :     {
    2385               0 :         status = _cairo_pdf_surface_emit_padded_image_surface (surface,
    2386                 :                                                                pdf_pattern,
    2387                 :                                                                &pattern_resource,
    2388                 :                                                                &pattern_width,
    2389                 :                                                                &pattern_height,
    2390                 :                                                                &origin_x,
    2391                 :                                                                &origin_y);
    2392                 :     }
    2393                 :     else
    2394                 :     {
    2395               0 :         status = _cairo_pdf_surface_add_source_surface (surface,
    2396                 :                                                         pattern->surface,
    2397               0 :                                                         pdf_pattern->pattern->filter,
    2398                 :                                                         &pattern_resource,
    2399                 :                                                         &pattern_width,
    2400                 :                                                         &pattern_height);
    2401                 :     }
    2402               0 :     if (unlikely (status))
    2403               0 :         return status;
    2404                 : 
    2405               0 :     bbox_x = pattern_width;
    2406               0 :     bbox_y = pattern_height;
    2407               0 :     switch (extend) {
    2408                 :     case CAIRO_EXTEND_PAD:
    2409                 :     case CAIRO_EXTEND_NONE:
    2410                 :     {
    2411                 :         /* In PS/PDF, (as far as I can tell), all patterns are
    2412                 :          * repeating. So we support cairo's EXTEND_NONE semantics
    2413                 :          * by setting the repeat step size to a size large enough
    2414                 :          * to guarantee that no more than a single occurrence will
    2415                 :          * be visible.
    2416                 :          *
    2417                 :          * First, map the surface extents into pattern space (since
    2418                 :          * xstep and ystep are in pattern space).  Then use an upper
    2419                 :          * bound on the length of the diagonal of the pattern image
    2420                 :          * and the surface as repeat size.  This guarantees to never
    2421                 :          * repeat visibly.
    2422                 :          */
    2423               0 :         double x1 = 0.0, y1 = 0.0;
    2424               0 :         double x2 = surface->width, y2 = surface->height;
    2425               0 :         _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
    2426                 :                                               &x1, &y1, &x2, &y2,
    2427                 :                                               NULL);
    2428                 : 
    2429                 :         /* Rather than computing precise bounds of the union, just
    2430                 :          * add the surface extents unconditionally. We only
    2431                 :          * required an answer that's large enough, we don't really
    2432                 :          * care if it's not as tight as possible.*/
    2433               0 :         xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
    2434                 :                               pattern_width + pattern_height);
    2435                 :     }
    2436               0 :     break;
    2437                 :     case CAIRO_EXTEND_REPEAT:
    2438               0 :         xstep = pattern_width;
    2439               0 :         ystep = pattern_height;
    2440               0 :         break;
    2441                 :     case CAIRO_EXTEND_REFLECT:
    2442               0 :         bbox_x = pattern_width*2;
    2443               0 :         bbox_y = pattern_height*2;
    2444               0 :         xstep = bbox_x;
    2445               0 :         ystep = bbox_y;
    2446               0 :         break;
    2447                 :         /* All the rest (if any) should have been analyzed away, so this
    2448                 :          * case should be unreachable. */
    2449                 :     default:
    2450               0 :         ASSERT_NOT_REACHED;
    2451               0 :         xstep = 0;
    2452               0 :         ystep = 0;
    2453                 :     }
    2454                 : 
    2455                 :     /* At this point, (that is, within the surface backend interface),
    2456                 :      * the pattern's matrix maps from cairo's device space to cairo's
    2457                 :      * pattern space, (both with their origin at the upper-left, and
    2458                 :      * cairo's pattern space of size width,height).
    2459                 :      *
    2460                 :      * Then, we must emit a PDF pattern object that maps from its own
    2461                 :      * pattern space, (which has a size that we establish in the BBox
    2462                 :      * dictionary entry), to the PDF page's *initial* space, (which
    2463                 :      * does not benefit from the Y-axis flipping matrix that we emit
    2464                 :      * on each page). So the PDF patterns matrix maps from a
    2465                 :      * (width,height) pattern space to a device space with the origin
    2466                 :      * in the lower-left corner.
    2467                 :      *
    2468                 :      * So to handle all of that, we start with an identity matrix for
    2469                 :      * the PDF pattern to device matrix. We translate it up by the
    2470                 :      * image height then flip it in the Y direction, (moving us from
    2471                 :      * the PDF origin to cairo's origin). We then multiply in the
    2472                 :      * inverse of the cairo pattern matrix, (since it maps from device
    2473                 :      * to pattern, while we're setting up pattern to device). Finally,
    2474                 :      * we translate back down by the image height and flip again to
    2475                 :      * end up at the lower-left origin that PDF expects.
    2476                 :      *
    2477                 :      * Additionally, within the stream that paints the pattern itself,
    2478                 :      * we are using a PDF image object that has a size of (1,1) so we
    2479                 :      * have to scale it up by the image width and height to fill our
    2480                 :      * pattern cell.
    2481                 :      */
    2482               0 :     cairo_p2d = pattern->base.matrix;
    2483               0 :     status = cairo_matrix_invert (&cairo_p2d);
    2484                 :     /* cairo_pattern_set_matrix ensures the matrix is invertible */
    2485               0 :     assert (status == CAIRO_STATUS_SUCCESS);
    2486                 : 
    2487               0 :     cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &surface->cairo_to_pdf);
    2488               0 :     cairo_matrix_translate (&pdf_p2d, -origin_x, -origin_y);
    2489               0 :     cairo_matrix_translate (&pdf_p2d, 0.0, pattern_height);
    2490               0 :     cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
    2491                 : 
    2492               0 :     _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
    2493               0 :     status = _cairo_pdf_surface_open_stream (surface,
    2494                 :                                              &pdf_pattern->pattern_res,
    2495                 :                                              FALSE,
    2496                 :                                              "   /PatternType 1\n"
    2497                 :                                              "   /BBox [0 0 %d %d]\n"
    2498                 :                                              "   /XStep %f\n"
    2499                 :                                              "   /YStep %f\n"
    2500                 :                                              "   /TilingType 1\n"
    2501                 :                                              "   /PaintType 1\n"
    2502                 :                                              "   /Matrix [ %f %f %f %f %f %f ]\n"
    2503                 :                                              "   /Resources << /XObject << /x%d %d 0 R >> >>\n",
    2504                 :                                              bbox_x, bbox_y,
    2505                 :                                              xstep, ystep,
    2506                 :                                              pdf_p2d.xx, pdf_p2d.yx,
    2507                 :                                              pdf_p2d.xy, pdf_p2d.yy,
    2508                 :                                              pdf_p2d.x0, pdf_p2d.y0,
    2509                 :                                              pattern_resource.id,
    2510                 :                                              pattern_resource.id);
    2511               0 :     if (unlikely (status))
    2512               0 :         return status;
    2513                 : 
    2514               0 :     if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
    2515               0 :         snprintf(draw_surface,
    2516                 :                  sizeof (draw_surface),
    2517                 :                  "/x%d Do\n",
    2518                 :                  pattern_resource.id);
    2519                 :     } else {
    2520               0 :         snprintf(draw_surface,
    2521                 :                  sizeof (draw_surface),
    2522                 :                  "q %d 0 0 %d 0 0 cm /x%d Do Q",
    2523                 :                  pattern_width,
    2524                 :                  pattern_height,
    2525                 :                  pattern_resource.id);
    2526                 :     }
    2527                 : 
    2528               0 :     if (extend == CAIRO_EXTEND_REFLECT) {
    2529               0 :         _cairo_output_stream_printf (surface->output,
    2530                 :                                      "q 0 0 %d %d re W n %s Q\n"
    2531                 :                                      "q -1 0 0 1 %d 0 cm 0 0 %d %d re W n %s Q\n"
    2532                 :                                      "q 1 0 0 -1 0 %d cm 0 0 %d %d re W n %s Q\n"
    2533                 :                                      "q -1 0 0 -1 %d %d cm 0 0 %d %d re W n %s Q\n",
    2534                 :                                      pattern_width, pattern_height,
    2535                 :                                      draw_surface,
    2536                 :                                      pattern_width*2, pattern_width, pattern_height,
    2537                 :                                      draw_surface,
    2538                 :                                      pattern_height*2, pattern_width, pattern_height,
    2539                 :                                      draw_surface,
    2540                 :                                      pattern_width*2, pattern_height*2, pattern_width, pattern_height,
    2541                 :                                      draw_surface);
    2542                 :     } else {
    2543               0 :         _cairo_output_stream_printf (surface->output,
    2544                 :                                      " %s \n",
    2545                 :                                      draw_surface);
    2546                 :     }
    2547                 : 
    2548               0 :     status = _cairo_pdf_surface_close_stream (surface);
    2549               0 :     if (unlikely (status))
    2550               0 :         return status;
    2551                 : 
    2552               0 :     return _cairo_output_stream_get_status (surface->output);
    2553                 : }
    2554                 : 
    2555                 : typedef struct _cairo_pdf_color_stop {
    2556                 :     double offset;
    2557                 :     double color[4];
    2558                 :     cairo_pdf_resource_t resource;
    2559                 : } cairo_pdf_color_stop_t;
    2560                 : 
    2561                 : static cairo_status_t
    2562               0 : cairo_pdf_surface_emit_rgb_linear_function (cairo_pdf_surface_t    *surface,
    2563                 :                                             cairo_pdf_color_stop_t *stop1,
    2564                 :                                             cairo_pdf_color_stop_t *stop2,
    2565                 :                                             cairo_pdf_resource_t   *function)
    2566                 : {
    2567                 :     int num_elems, i;
    2568                 :     cairo_pdf_rgb_linear_function_t elem;
    2569                 :     cairo_pdf_resource_t res;
    2570                 :     cairo_status_t status;
    2571                 : 
    2572               0 :     num_elems = _cairo_array_num_elements (&surface->rgb_linear_functions);
    2573               0 :     for (i = 0; i < num_elems; i++) {
    2574               0 :         _cairo_array_copy_element (&surface->rgb_linear_functions, i, &elem);
    2575               0 :         if (memcmp (&elem.color1[0], &stop1->color[0], sizeof (double)*3) != 0)
    2576               0 :             continue;
    2577               0 :         if (memcmp (&elem.color2[0], &stop2->color[0], sizeof (double)*3) != 0)
    2578               0 :             continue;
    2579               0 :         *function =  elem.resource;
    2580               0 :         return CAIRO_STATUS_SUCCESS;
    2581                 :     }
    2582                 : 
    2583               0 :     res = _cairo_pdf_surface_new_object (surface);
    2584               0 :     if (res.id == 0)
    2585               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2586                 : 
    2587               0 :     _cairo_output_stream_printf (surface->output,
    2588                 :                                  "%d 0 obj\n"
    2589                 :                                  "<< /FunctionType 2\n"
    2590                 :                                  "   /Domain [ 0 1 ]\n"
    2591                 :                                  "   /C0 [ %f %f %f ]\n"
    2592                 :                                  "   /C1 [ %f %f %f ]\n"
    2593                 :                                  "   /N 1\n"
    2594                 :                                  ">>\n"
    2595                 :                                  "endobj\n",
    2596                 :                                  res.id,
    2597                 :                                  stop1->color[0],
    2598                 :                                  stop1->color[1],
    2599                 :                                  stop1->color[2],
    2600                 :                                  stop2->color[0],
    2601                 :                                  stop2->color[1],
    2602                 :                                  stop2->color[2]);
    2603                 : 
    2604               0 :     elem.resource = res;
    2605               0 :     memcpy (&elem.color1[0], &stop1->color[0], sizeof (double)*3);
    2606               0 :     memcpy (&elem.color2[0], &stop2->color[0], sizeof (double)*3);
    2607                 : 
    2608               0 :     status = _cairo_array_append (&surface->rgb_linear_functions, &elem);
    2609               0 :     *function = res;
    2610                 : 
    2611               0 :     return status;
    2612                 : }
    2613                 : 
    2614                 : static cairo_status_t
    2615               0 : cairo_pdf_surface_emit_alpha_linear_function (cairo_pdf_surface_t    *surface,
    2616                 :                                               cairo_pdf_color_stop_t *stop1,
    2617                 :                                               cairo_pdf_color_stop_t *stop2,
    2618                 :                                               cairo_pdf_resource_t   *function)
    2619                 : {
    2620                 :     int num_elems, i;
    2621                 :     cairo_pdf_alpha_linear_function_t elem;
    2622                 :     cairo_pdf_resource_t res;
    2623                 :     cairo_status_t status;
    2624                 : 
    2625               0 :     num_elems = _cairo_array_num_elements (&surface->alpha_linear_functions);
    2626               0 :     for (i = 0; i < num_elems; i++) {
    2627               0 :         _cairo_array_copy_element (&surface->alpha_linear_functions, i, &elem);
    2628               0 :         if (elem.alpha1 != stop1->color[3])
    2629               0 :             continue;
    2630               0 :         if (elem.alpha2 != stop2->color[3])
    2631               0 :             continue;
    2632               0 :         *function =  elem.resource;
    2633               0 :         return CAIRO_STATUS_SUCCESS;
    2634                 :     }
    2635                 : 
    2636               0 :     res = _cairo_pdf_surface_new_object (surface);
    2637               0 :     if (res.id == 0)
    2638               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2639                 : 
    2640               0 :     _cairo_output_stream_printf (surface->output,
    2641                 :                                  "%d 0 obj\n"
    2642                 :                                  "<< /FunctionType 2\n"
    2643                 :                                  "   /Domain [ 0 1 ]\n"
    2644                 :                                  "   /C0 [ %f ]\n"
    2645                 :                                  "   /C1 [ %f ]\n"
    2646                 :                                  "   /N 1\n"
    2647                 :                                  ">>\n"
    2648                 :                                  "endobj\n",
    2649                 :                                  res.id,
    2650                 :                                  stop1->color[3],
    2651                 :                                  stop2->color[3]);
    2652                 : 
    2653               0 :     elem.resource = res;
    2654               0 :     elem.alpha1 = stop1->color[3];
    2655               0 :     elem.alpha2 = stop2->color[3];
    2656                 : 
    2657               0 :     status = _cairo_array_append (&surface->alpha_linear_functions, &elem);
    2658               0 :     *function = res;
    2659                 : 
    2660               0 :     return status;
    2661                 : }
    2662                 : 
    2663                 : static cairo_status_t
    2664               0 : _cairo_pdf_surface_emit_stitched_colorgradient (cairo_pdf_surface_t    *surface,
    2665                 :                                                 unsigned int            n_stops,
    2666                 :                                                 cairo_pdf_color_stop_t *stops,
    2667                 :                                                 cairo_bool_t            is_alpha,
    2668                 :                                                 cairo_pdf_resource_t   *function)
    2669                 : {
    2670                 :     cairo_pdf_resource_t res;
    2671                 :     unsigned int i;
    2672                 :     cairo_status_t status;
    2673                 : 
    2674                 :     /* emit linear gradients between pairs of subsequent stops... */
    2675               0 :     for (i = 0; i < n_stops-1; i++) {
    2676               0 :         if (is_alpha) {
    2677               0 :             status = cairo_pdf_surface_emit_alpha_linear_function (surface,
    2678               0 :                                                                    &stops[i],
    2679                 :                                                                    &stops[i+1],
    2680               0 :                                                                    &stops[i].resource);
    2681               0 :             if (unlikely (status))
    2682               0 :                 return status;
    2683                 :         } else {
    2684               0 :             status = cairo_pdf_surface_emit_rgb_linear_function (surface,
    2685               0 :                                                                  &stops[i],
    2686                 :                                                                  &stops[i+1],
    2687               0 :                                                                  &stops[i].resource);
    2688               0 :             if (unlikely (status))
    2689               0 :                 return status;
    2690                 :         }
    2691                 :     }
    2692                 : 
    2693                 :     /* ... and stitch them together */
    2694               0 :     res = _cairo_pdf_surface_new_object (surface);
    2695               0 :     if (res.id == 0)
    2696               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2697                 : 
    2698               0 :     _cairo_output_stream_printf (surface->output,
    2699                 :                                  "%d 0 obj\n"
    2700                 :                                  "<< /FunctionType 3\n"
    2701                 :                                  "   /Domain [ %f %f ]\n",
    2702                 :                                  res.id,
    2703                 :                                  stops[0].offset,
    2704               0 :                                  stops[n_stops - 1].offset);
    2705                 : 
    2706               0 :     _cairo_output_stream_printf (surface->output,
    2707                 :                                  "   /Functions [ ");
    2708               0 :     for (i = 0; i < n_stops-1; i++)
    2709               0 :         _cairo_output_stream_printf (surface->output,
    2710               0 :                                      "%d 0 R ", stops[i].resource.id);
    2711               0 :     _cairo_output_stream_printf (surface->output,
    2712                 :                                  "]\n");
    2713                 : 
    2714               0 :     _cairo_output_stream_printf (surface->output,
    2715                 :                                  "   /Bounds [ ");
    2716               0 :     for (i = 1; i < n_stops-1; i++)
    2717               0 :         _cairo_output_stream_printf (surface->output,
    2718               0 :                                      "%f ", stops[i].offset);
    2719               0 :     _cairo_output_stream_printf (surface->output,
    2720                 :                                  "]\n");
    2721                 : 
    2722               0 :     _cairo_output_stream_printf (surface->output,
    2723                 :                                  "   /Encode [ ");
    2724               0 :     for (i = 1; i < n_stops; i++)
    2725               0 :         _cairo_output_stream_printf (surface->output,
    2726                 :                                      "0 1 ");
    2727               0 :     _cairo_output_stream_printf (surface->output,
    2728                 :                                  "]\n");
    2729                 : 
    2730               0 :     _cairo_output_stream_printf (surface->output,
    2731                 :                                  ">>\n"
    2732                 :                                  "endobj\n");
    2733                 : 
    2734               0 :     *function = res;
    2735                 : 
    2736               0 :     return _cairo_output_stream_get_status (surface->output);
    2737                 : }
    2738                 : 
    2739                 : 
    2740                 : static void
    2741               0 : calc_gradient_color (cairo_pdf_color_stop_t *new_stop,
    2742                 :                      cairo_pdf_color_stop_t *stop1,
    2743                 :                      cairo_pdf_color_stop_t *stop2)
    2744                 : {
    2745                 :     int i;
    2746               0 :     double offset = stop1->offset / (stop1->offset + 1.0 - stop2->offset);
    2747                 : 
    2748               0 :     for (i = 0; i < 4; i++)
    2749               0 :         new_stop->color[i] = stop1->color[i] + offset*(stop2->color[i] - stop1->color[i]);
    2750               0 : }
    2751                 : 
    2752                 : #define COLOR_STOP_EPSILON 1e-6
    2753                 : 
    2754                 : static cairo_status_t
    2755               0 : _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t      *surface,
    2756                 :                                        cairo_gradient_pattern_t *pattern,
    2757                 :                                        cairo_pdf_resource_t     *color_function,
    2758                 :                                        cairo_pdf_resource_t     *alpha_function)
    2759                 : {
    2760                 :     cairo_pdf_color_stop_t *allstops, *stops;
    2761                 :     unsigned int n_stops;
    2762                 :     unsigned int i;
    2763               0 :     cairo_bool_t emit_alpha = FALSE;
    2764                 :     cairo_status_t status;
    2765                 : 
    2766               0 :     color_function->id = 0;
    2767               0 :     alpha_function->id = 0;
    2768                 : 
    2769               0 :     allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_pdf_color_stop_t));
    2770               0 :     if (unlikely (allstops == NULL))
    2771               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2772                 : 
    2773               0 :     stops = &allstops[1];
    2774               0 :     n_stops = pattern->n_stops;
    2775                 : 
    2776               0 :     for (i = 0; i < n_stops; i++) {
    2777               0 :         stops[i].color[0] = pattern->stops[i].color.red;
    2778               0 :         stops[i].color[1] = pattern->stops[i].color.green;
    2779               0 :         stops[i].color[2] = pattern->stops[i].color.blue;
    2780               0 :         stops[i].color[3] = pattern->stops[i].color.alpha;
    2781               0 :         if (!CAIRO_ALPHA_IS_OPAQUE (stops[i].color[3]))
    2782               0 :             emit_alpha = TRUE;
    2783               0 :         stops[i].offset = pattern->stops[i].offset;
    2784                 :     }
    2785                 : 
    2786               0 :     if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
    2787               0 :         pattern->base.extend == CAIRO_EXTEND_REFLECT) {
    2788               0 :         if (stops[0].offset > COLOR_STOP_EPSILON) {
    2789               0 :             if (pattern->base.extend == CAIRO_EXTEND_REFLECT)
    2790               0 :                 memcpy (allstops, stops, sizeof (cairo_pdf_color_stop_t));
    2791                 :             else
    2792               0 :                 calc_gradient_color (&allstops[0], &stops[0], &stops[n_stops-1]);
    2793               0 :             stops = allstops;
    2794               0 :             n_stops++;
    2795                 :         }
    2796               0 :         stops[0].offset = 0.0;
    2797                 : 
    2798               0 :         if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
    2799               0 :             if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
    2800               0 :                 memcpy (&stops[n_stops],
    2801               0 :                         &stops[n_stops - 1],
    2802                 :                         sizeof (cairo_pdf_color_stop_t));
    2803                 :             } else {
    2804               0 :                 calc_gradient_color (&stops[n_stops], &stops[0], &stops[n_stops-1]);
    2805                 :             }
    2806               0 :             n_stops++;
    2807                 :         }
    2808               0 :         stops[n_stops-1].offset = 1.0;
    2809                 :     }
    2810                 : 
    2811               0 :     if (n_stops <= 2) {
    2812                 :         /* no need for stitched function */
    2813               0 :         status = cairo_pdf_surface_emit_rgb_linear_function (surface,
    2814                 :                                                              &stops[0],
    2815                 :                                                              &stops[n_stops - 1],
    2816                 :                                                              color_function);
    2817               0 :         if (unlikely (status))
    2818               0 :             goto BAIL;
    2819                 : 
    2820               0 :         if (emit_alpha) {
    2821               0 :             status = cairo_pdf_surface_emit_alpha_linear_function (surface,
    2822                 :                                                                    &stops[0],
    2823                 :                                                                    &stops[n_stops - 1],
    2824                 :                                                                    alpha_function);
    2825               0 :             if (unlikely (status))
    2826               0 :                 goto BAIL;
    2827                 :         }
    2828                 :     } else {
    2829                 :         /* multiple stops: stitch. XXX possible optimization: regularly spaced
    2830                 :          * stops do not require stitching. XXX */
    2831               0 :         status = _cairo_pdf_surface_emit_stitched_colorgradient (surface,
    2832                 :                                                                  n_stops,
    2833                 :                                                                  stops,
    2834                 :                                                                  FALSE,
    2835                 :                                                                  color_function);
    2836               0 :         if (unlikely (status))
    2837               0 :             goto BAIL;
    2838                 : 
    2839               0 :         if (emit_alpha) {
    2840               0 :             status = _cairo_pdf_surface_emit_stitched_colorgradient (surface,
    2841                 :                                                                      n_stops,
    2842                 :                                                                      stops,
    2843                 :                                                                      TRUE,
    2844                 :                                                                      alpha_function);
    2845               0 :             if (unlikely (status))
    2846               0 :                 goto BAIL;
    2847                 :         }
    2848                 :     }
    2849                 : 
    2850                 : BAIL:
    2851               0 :     free (allstops);
    2852               0 :     return status;
    2853                 : }
    2854                 : 
    2855                 : static cairo_status_t
    2856               0 : _cairo_pdf_surface_emit_repeating_function (cairo_pdf_surface_t      *surface,
    2857                 :                                             cairo_gradient_pattern_t *pattern,
    2858                 :                                             cairo_pdf_resource_t     *function,
    2859                 :                                             int                       begin,
    2860                 :                                             int                       end)
    2861                 : {
    2862                 :     cairo_pdf_resource_t res;
    2863                 :     int i;
    2864                 : 
    2865               0 :     res = _cairo_pdf_surface_new_object (surface);
    2866               0 :     if (res.id == 0)
    2867               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2868                 : 
    2869               0 :     _cairo_output_stream_printf (surface->output,
    2870                 :                                  "%d 0 obj\n"
    2871                 :                                  "<< /FunctionType 3\n"
    2872                 :                                  "   /Domain [ %d %d ]\n",
    2873                 :                                  res.id,
    2874                 :                                  begin,
    2875                 :                                  end);
    2876                 : 
    2877               0 :     _cairo_output_stream_printf (surface->output,
    2878                 :                                  "   /Functions [ ");
    2879               0 :     for (i = begin; i < end; i++)
    2880               0 :         _cairo_output_stream_printf (surface->output,
    2881                 :                                      "%d 0 R ", function->id);
    2882               0 :     _cairo_output_stream_printf (surface->output,
    2883                 :                                  "]\n");
    2884                 : 
    2885               0 :     _cairo_output_stream_printf (surface->output,
    2886                 :                                  "   /Bounds [ ");
    2887               0 :     for (i = begin + 1; i < end; i++)
    2888               0 :         _cairo_output_stream_printf (surface->output,
    2889                 :                                      "%d ", i);
    2890               0 :     _cairo_output_stream_printf (surface->output,
    2891                 :                                  "]\n");
    2892                 : 
    2893               0 :     _cairo_output_stream_printf (surface->output,
    2894                 :                                  "   /Encode [ ");
    2895               0 :     for (i = begin; i < end; i++) {
    2896               0 :         if ((i % 2) && pattern->base.extend == CAIRO_EXTEND_REFLECT) {
    2897               0 :             _cairo_output_stream_printf (surface->output,
    2898                 :                                          "1 0 ");
    2899                 :         } else {
    2900               0 :             _cairo_output_stream_printf (surface->output,
    2901                 :                                          "0 1 ");
    2902                 :         }
    2903                 :     }
    2904               0 :     _cairo_output_stream_printf (surface->output,
    2905                 :                                  "]\n");
    2906                 : 
    2907               0 :     _cairo_output_stream_printf (surface->output,
    2908                 :                                  ">>\n"
    2909                 :                                  "endobj\n");
    2910                 : 
    2911               0 :     *function = res;
    2912                 : 
    2913               0 :     return _cairo_output_stream_get_status (surface->output);
    2914                 : }
    2915                 : 
    2916                 : static cairo_status_t
    2917               0 : cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t  *surface,
    2918                 :                                            cairo_pdf_resource_t  gstate_resource,
    2919                 :                                            cairo_pdf_resource_t  gradient_mask)
    2920                 : {
    2921                 :     cairo_pdf_resource_t smask_resource;
    2922                 :     cairo_status_t status;
    2923                 : 
    2924               0 :     status = _cairo_pdf_surface_open_stream (surface,
    2925                 :                                              NULL,
    2926                 :                                              surface->compress_content,
    2927                 :                                              "   /Type /XObject\n"
    2928                 :                                              "   /Subtype /Form\n"
    2929                 :                                              "   /FormType 1\n"
    2930                 :                                              "   /BBox [ 0 0 %f %f ]\n"
    2931                 :                                              "   /Resources\n"
    2932                 :                                              "      << /ExtGState\n"
    2933                 :                                              "            << /a0 << /ca 1 /CA 1 >>"
    2934                 :                                              "      >>\n"
    2935                 :                                              "         /Pattern\n"
    2936                 :                                              "            << /p%d %d 0 R >>\n"
    2937                 :                                              "      >>\n"
    2938                 :                                              "   /Group\n"
    2939                 :                                              "      << /Type /Group\n"
    2940                 :                                              "         /S /Transparency\n"
    2941                 :                                              "         /CS /DeviceGray\n"
    2942                 :                                              "      >>\n",
    2943                 :                                              surface->width,
    2944                 :                                              surface->height,
    2945                 :                                              gradient_mask.id,
    2946                 :                                              gradient_mask.id);
    2947               0 :     if (unlikely (status))
    2948               0 :         return status;
    2949                 : 
    2950               0 :     _cairo_output_stream_printf (surface->output,
    2951                 :                                  "q\n"
    2952                 :                                  "/a0 gs\n"
    2953                 :                                  "/Pattern cs /p%d scn\n"
    2954                 :                                  "0 0 %f %f re\n"
    2955                 :                                  "f\n"
    2956                 :                                  "Q\n",
    2957                 :                                  gradient_mask.id,
    2958                 :                                  surface->width,
    2959                 :                                  surface->height);
    2960                 : 
    2961               0 :      status = _cairo_pdf_surface_close_stream (surface);
    2962               0 :      if (unlikely (status))
    2963               0 :         return status;
    2964                 : 
    2965               0 :     smask_resource = _cairo_pdf_surface_new_object (surface);
    2966               0 :     if (smask_resource.id == 0)
    2967               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2968                 : 
    2969               0 :     _cairo_output_stream_printf (surface->output,
    2970                 :                                  "%d 0 obj\n"
    2971                 :                                  "<< /Type /Mask\n"
    2972                 :                                  "   /S /Luminosity\n"
    2973                 :                                  "   /G %d 0 R\n"
    2974                 :                                  ">>\n"
    2975                 :                                  "endobj\n",
    2976                 :                                  smask_resource.id,
    2977                 :                                  surface->pdf_stream.self.id);
    2978                 : 
    2979                 :     /* Create GState which uses the transparency group as an SMask. */
    2980               0 :     _cairo_pdf_surface_update_object (surface, gstate_resource);
    2981                 : 
    2982               0 :     _cairo_output_stream_printf (surface->output,
    2983                 :                                  "%d 0 obj\n"
    2984                 :                                  "<< /Type /ExtGState\n"
    2985                 :                                  "   /SMask %d 0 R\n"
    2986                 :                                  "   /ca 1\n"
    2987                 :                                  "   /CA 1\n"
    2988                 :                                  "   /AIS false\n"
    2989                 :                                  ">>\n"
    2990                 :                                  "endobj\n",
    2991                 :                                  gstate_resource.id,
    2992                 :                                  smask_resource.id);
    2993                 : 
    2994               0 :     return _cairo_output_stream_get_status (surface->output);
    2995                 : }
    2996                 : 
    2997                 : static cairo_status_t
    2998               0 : _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t    *surface,
    2999                 :                                         cairo_pdf_pattern_t    *pdf_pattern)
    3000                 : {
    3001               0 :     cairo_linear_pattern_t *pattern = (cairo_linear_pattern_t *) pdf_pattern->pattern;
    3002                 :     cairo_pdf_resource_t color_function, alpha_function;
    3003                 :     double x1, y1, x2, y2;
    3004                 :     double _x1, _y1, _x2, _y2;
    3005                 :     cairo_matrix_t pat_to_pdf;
    3006                 :     cairo_extend_t extend;
    3007                 :     cairo_status_t status;
    3008               0 :     cairo_gradient_pattern_t *gradient = &pattern->base;
    3009                 :     double first_stop, last_stop;
    3010               0 :     int repeat_begin = 0, repeat_end = 1;
    3011                 : 
    3012               0 :     assert (pattern->base.n_stops != 0);
    3013                 : 
    3014               0 :     extend = cairo_pattern_get_extend (pdf_pattern->pattern);
    3015                 : 
    3016               0 :     pat_to_pdf = pattern->base.base.matrix;
    3017               0 :     status = cairo_matrix_invert (&pat_to_pdf);
    3018                 :     /* cairo_pattern_set_matrix ensures the matrix is invertible */
    3019               0 :     assert (status == CAIRO_STATUS_SUCCESS);
    3020                 : 
    3021               0 :     cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
    3022               0 :     first_stop = gradient->stops[0].offset;
    3023               0 :     last_stop = gradient->stops[gradient->n_stops - 1].offset;
    3024                 : 
    3025               0 :     if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
    3026               0 :         pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
    3027                 :         double dx, dy;
    3028               0 :         int x_rep = 0, y_rep = 0;
    3029                 : 
    3030               0 :         x1 = _cairo_fixed_to_double (pattern->p1.x);
    3031               0 :         y1 = _cairo_fixed_to_double (pattern->p1.y);
    3032               0 :         cairo_matrix_transform_point (&pat_to_pdf, &x1, &y1);
    3033                 : 
    3034               0 :         x2 = _cairo_fixed_to_double (pattern->p2.x);
    3035               0 :         y2 = _cairo_fixed_to_double (pattern->p2.y);
    3036               0 :         cairo_matrix_transform_point (&pat_to_pdf, &x2, &y2);
    3037                 : 
    3038               0 :         dx = fabs (x2 - x1);
    3039               0 :         dy = fabs (y2 - y1);
    3040               0 :         if (dx > 1e-6)
    3041               0 :             x_rep = ceil (surface->width/dx);
    3042               0 :         if (dy > 1e-6)
    3043               0 :             y_rep = ceil (surface->height/dy);
    3044                 : 
    3045               0 :         repeat_end = MAX (x_rep, y_rep);
    3046               0 :         repeat_begin = -repeat_end;
    3047               0 :         first_stop = repeat_begin;
    3048               0 :         last_stop = repeat_end;
    3049                 :     }
    3050                 : 
    3051                 :     /* PDF requires the first and last stop to be the same as the line
    3052                 :      * coordinates. For repeating patterns this moves the line
    3053                 :      * coordinates out to the begin/end of the repeating function. For
    3054                 :      * non repeating patterns this may move the line coordinates in if
    3055                 :      * there are not stops at offset 0 and 1. */
    3056               0 :     x1 = _cairo_fixed_to_double (pattern->p1.x);
    3057               0 :     y1 = _cairo_fixed_to_double (pattern->p1.y);
    3058               0 :     x2 = _cairo_fixed_to_double (pattern->p2.x);
    3059               0 :     y2 = _cairo_fixed_to_double (pattern->p2.y);
    3060                 : 
    3061               0 :     _x1 = x1 + (x2 - x1)*first_stop;
    3062               0 :     _y1 = y1 + (y2 - y1)*first_stop;
    3063               0 :     _x2 = x1 + (x2 - x1)*last_stop;
    3064               0 :     _y2 = y1 + (y2 - y1)*last_stop;
    3065                 : 
    3066               0 :     x1 = _x1;
    3067               0 :     x2 = _x2;
    3068               0 :     y1 = _y1;
    3069               0 :     y2 = _y2;
    3070                 : 
    3071                 :     /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a
    3072                 :      * Type 2 function is used by itself without a stitching
    3073                 :      * function. Type 2 functions always have the domain [0 1] */
    3074               0 :     if ((pattern->base.base.extend == CAIRO_EXTEND_NONE ||
    3075               0 :          pattern->base.base.extend == CAIRO_EXTEND_PAD) &&
    3076               0 :         gradient->n_stops == 2) {
    3077               0 :         first_stop = 0.0;
    3078               0 :         last_stop = 1.0;
    3079                 :     }
    3080                 : 
    3081               0 :     status = _cairo_pdf_surface_emit_pattern_stops (surface,
    3082                 :                                                     &pattern->base,
    3083                 :                                                     &color_function,
    3084                 :                                                     &alpha_function);
    3085               0 :     if (unlikely (status))
    3086               0 :         return status;
    3087                 : 
    3088               0 :     if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
    3089               0 :         pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
    3090               0 :         status = _cairo_pdf_surface_emit_repeating_function (surface,
    3091                 :                                                              &pattern->base,
    3092                 :                                                              &color_function,
    3093                 :                                                              repeat_begin,
    3094                 :                                                              repeat_end);
    3095               0 :         if (unlikely (status))
    3096               0 :             return status;
    3097                 : 
    3098               0 :         if (alpha_function.id != 0) {
    3099               0 :             status = _cairo_pdf_surface_emit_repeating_function (surface,
    3100                 :                                                                  &pattern->base,
    3101                 :                                                                  &alpha_function,
    3102                 :                                                                  repeat_begin,
    3103                 :                                                                  repeat_end);
    3104               0 :             if (unlikely (status))
    3105               0 :                 return status;
    3106                 :         }
    3107                 :     }
    3108                 : 
    3109               0 :     _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
    3110               0 :     _cairo_output_stream_printf (surface->output,
    3111                 :                                  "%d 0 obj\n"
    3112                 :                                  "<< /Type /Pattern\n"
    3113                 :                                  "   /PatternType 2\n"
    3114                 :                                  "   /Matrix [ %f %f %f %f %f %f ]\n"
    3115                 :                                  "   /Shading\n"
    3116                 :                                  "      << /ShadingType 2\n"
    3117                 :                                  "         /ColorSpace /DeviceRGB\n"
    3118                 :                                  "         /Coords [ %f %f %f %f ]\n"
    3119                 :                                  "         /Domain [ %f %f ]\n"
    3120                 :                                  "         /Function %d 0 R\n",
    3121                 :                                  pdf_pattern->pattern_res.id,
    3122                 :                                  pat_to_pdf.xx, pat_to_pdf.yx,
    3123                 :                                  pat_to_pdf.xy, pat_to_pdf.yy,
    3124                 :                                  pat_to_pdf.x0, pat_to_pdf.y0,
    3125                 :                                  x1, y1, x2, y2,
    3126                 :                                  first_stop, last_stop,
    3127                 :                                  color_function.id);
    3128                 : 
    3129               0 :     if (extend == CAIRO_EXTEND_PAD) {
    3130               0 :         _cairo_output_stream_printf (surface->output,
    3131                 :                                      "         /Extend [ true true ]\n");
    3132                 :     } else {
    3133               0 :         _cairo_output_stream_printf (surface->output,
    3134                 :                                      "         /Extend [ false false ]\n");
    3135                 :     }
    3136                 : 
    3137               0 :     _cairo_output_stream_printf (surface->output,
    3138                 :                                  "      >>\n"
    3139                 :                                  ">>\n"
    3140                 :                                  "endobj\n");
    3141                 : 
    3142               0 :     if (alpha_function.id != 0) {
    3143                 :         cairo_pdf_resource_t mask_resource;
    3144                 : 
    3145               0 :         assert (pdf_pattern->gstate_res.id != 0);
    3146                 : 
    3147                 :         /* Create pattern for SMask. */
    3148               0 :         mask_resource = _cairo_pdf_surface_new_object (surface);
    3149               0 :         if (mask_resource.id == 0)
    3150               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3151                 : 
    3152               0 :         _cairo_output_stream_printf (surface->output,
    3153                 :                                      "%d 0 obj\n"
    3154                 :                                      "<< /Type /Pattern\n"
    3155                 :                                      "   /PatternType 2\n"
    3156                 :                                      "   /Matrix [ %f %f %f %f %f %f ]\n"
    3157                 :                                      "   /Shading\n"
    3158                 :                                      "      << /ShadingType 2\n"
    3159                 :                                      "         /ColorSpace /DeviceGray\n"
    3160                 :                                      "         /Coords [ %f %f %f %f ]\n"
    3161                 :                                      "         /Domain [ %f %f ]\n"
    3162                 :                                      "         /Function %d 0 R\n",
    3163                 :                                      mask_resource.id,
    3164                 :                                      pat_to_pdf.xx, pat_to_pdf.yx,
    3165                 :                                      pat_to_pdf.xy, pat_to_pdf.yy,
    3166                 :                                      pat_to_pdf.x0, pat_to_pdf.y0,
    3167                 :                                      x1, y1, x2, y2,
    3168                 :                                      first_stop, last_stop,
    3169                 :                                      alpha_function.id);
    3170                 : 
    3171               0 :         if (extend == CAIRO_EXTEND_PAD) {
    3172               0 :             _cairo_output_stream_printf (surface->output,
    3173                 :                                          "         /Extend [ true true ]\n");
    3174                 :         } else {
    3175               0 :             _cairo_output_stream_printf (surface->output,
    3176                 :                                          "         /Extend [ false false ]\n");
    3177                 :         }
    3178                 : 
    3179               0 :         _cairo_output_stream_printf (surface->output,
    3180                 :                                      "      >>\n"
    3181                 :                                      ">>\n"
    3182                 :                                      "endobj\n");
    3183               0 :         status = _cairo_pdf_surface_add_pattern (surface, mask_resource);
    3184               0 :         if (unlikely (status))
    3185               0 :             return status;
    3186                 : 
    3187               0 :         status = cairo_pdf_surface_emit_transparency_group (surface,
    3188                 :                                                             pdf_pattern->gstate_res,
    3189                 :                                                             mask_resource);
    3190               0 :         if (unlikely (status))
    3191               0 :             return status;
    3192                 :     }
    3193                 : 
    3194               0 :     return _cairo_output_stream_get_status (surface->output);
    3195                 : }
    3196                 : 
    3197                 : static cairo_status_t
    3198               0 : _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t    *surface,
    3199                 :                                         cairo_pdf_pattern_t    *pdf_pattern)
    3200                 : {
    3201                 :     cairo_pdf_resource_t color_function, alpha_function;
    3202                 :     double x1, y1, x2, y2, r1, r2;
    3203                 :     cairo_matrix_t pat_to_pdf;
    3204                 :     cairo_extend_t extend;
    3205                 :     cairo_status_t status;
    3206               0 :     cairo_radial_pattern_t *pattern = (cairo_radial_pattern_t *) pdf_pattern->pattern;
    3207                 : 
    3208               0 :     assert (pattern->base.n_stops != 0);
    3209                 : 
    3210               0 :     extend = cairo_pattern_get_extend (pdf_pattern->pattern);
    3211                 : 
    3212               0 :     status = _cairo_pdf_surface_emit_pattern_stops (surface,
    3213                 :                                                     &pattern->base,
    3214                 :                                                     &color_function,
    3215                 :                                                     &alpha_function);
    3216               0 :     if (unlikely (status))
    3217               0 :         return status;
    3218                 : 
    3219               0 :     pat_to_pdf = pattern->base.base.matrix;
    3220               0 :     status = cairo_matrix_invert (&pat_to_pdf);
    3221                 :     /* cairo_pattern_set_matrix ensures the matrix is invertible */
    3222               0 :     assert (status == CAIRO_STATUS_SUCCESS);
    3223                 : 
    3224               0 :     cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
    3225               0 :     x1 = _cairo_fixed_to_double (pattern->c1.x);
    3226               0 :     y1 = _cairo_fixed_to_double (pattern->c1.y);
    3227               0 :     r1 = _cairo_fixed_to_double (pattern->r1);
    3228               0 :     x2 = _cairo_fixed_to_double (pattern->c2.x);
    3229               0 :     y2 = _cairo_fixed_to_double (pattern->c2.y);
    3230               0 :     r2 = _cairo_fixed_to_double (pattern->r2);
    3231                 : 
    3232               0 :     _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
    3233                 : 
    3234               0 :     _cairo_output_stream_printf (surface->output,
    3235                 :                                  "%d 0 obj\n"
    3236                 :                                  "<< /Type /Pattern\n"
    3237                 :                                  "   /PatternType 2\n"
    3238                 :                                  "   /Matrix [ %f %f %f %f %f %f ]\n"
    3239                 :                                  "   /Shading\n"
    3240                 :                                  "      << /ShadingType 3\n"
    3241                 :                                  "         /ColorSpace /DeviceRGB\n"
    3242                 :                                  "         /Coords [ %f %f %f %f %f %f ]\n"
    3243                 :                                  "         /Function %d 0 R\n",
    3244                 :                                  pdf_pattern->pattern_res.id,
    3245                 :                                  pat_to_pdf.xx, pat_to_pdf.yx,
    3246                 :                                  pat_to_pdf.xy, pat_to_pdf.yy,
    3247                 :                                  pat_to_pdf.x0, pat_to_pdf.y0,
    3248                 :                                  x1, y1, r1, x2, y2, r2,
    3249                 :                                  color_function.id);
    3250                 : 
    3251               0 :     if (extend == CAIRO_EXTEND_PAD) {
    3252               0 :         _cairo_output_stream_printf (surface->output,
    3253                 :                                      "         /Extend [ true true ]\n");
    3254                 :     } else {
    3255               0 :         _cairo_output_stream_printf (surface->output,
    3256                 :                                      "         /Extend [ false false ]\n");
    3257                 :     }
    3258                 : 
    3259               0 :     _cairo_output_stream_printf (surface->output,
    3260                 :                                  "      >>\n"
    3261                 :                                  ">>\n"
    3262                 :                                  "endobj\n");
    3263                 : 
    3264               0 :     if (alpha_function.id != 0) {
    3265                 :         cairo_pdf_resource_t mask_resource;
    3266                 : 
    3267               0 :         assert (pdf_pattern->gstate_res.id != 0);
    3268                 : 
    3269                 :         /* Create pattern for SMask. */
    3270               0 :         mask_resource = _cairo_pdf_surface_new_object (surface);
    3271               0 :         if (mask_resource.id == 0)
    3272               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3273                 : 
    3274               0 :         _cairo_output_stream_printf (surface->output,
    3275                 :                                      "%d 0 obj\n"
    3276                 :                                      "<< /Type /Pattern\n"
    3277                 :                                      "   /PatternType 2\n"
    3278                 :                                      "   /Matrix [ %f %f %f %f %f %f ]\n"
    3279                 :                                      "   /Shading\n"
    3280                 :                                      "      << /ShadingType 3\n"
    3281                 :                                      "         /ColorSpace /DeviceGray\n"
    3282                 :                                      "         /Coords [ %f %f %f %f %f %f ]\n"
    3283                 :                                      "         /Function %d 0 R\n",
    3284                 :                                      mask_resource.id,
    3285                 :                                      pat_to_pdf.xx, pat_to_pdf.yx,
    3286                 :                                      pat_to_pdf.xy, pat_to_pdf.yy,
    3287                 :                                      pat_to_pdf.x0, pat_to_pdf.y0,
    3288                 :                                      x1, y1, r1, x2, y2, r2,
    3289                 :                                      alpha_function.id);
    3290                 : 
    3291               0 :         if (extend == CAIRO_EXTEND_PAD) {
    3292               0 :             _cairo_output_stream_printf (surface->output,
    3293                 :                                          "         /Extend [ true true ]\n");
    3294                 :         } else {
    3295               0 :             _cairo_output_stream_printf (surface->output,
    3296                 :                                          "         /Extend [ false false ]\n");
    3297                 :         }
    3298                 : 
    3299               0 :         _cairo_output_stream_printf (surface->output,
    3300                 :                                      "      >>\n"
    3301                 :                                      ">>\n"
    3302                 :                                      "endobj\n");
    3303                 : 
    3304               0 :         status = cairo_pdf_surface_emit_transparency_group (surface,
    3305                 :                                                             pdf_pattern->gstate_res,
    3306                 :                                                             mask_resource);
    3307               0 :         if (unlikely (status))
    3308               0 :             return status;
    3309                 :     }
    3310                 : 
    3311               0 :     return _cairo_output_stream_get_status (surface->output);
    3312                 : }
    3313                 : 
    3314                 : static cairo_status_t
    3315               0 : _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern_t *pdf_pattern)
    3316                 : {
    3317                 :     double old_width, old_height;
    3318                 :     cairo_status_t status;
    3319                 : 
    3320               0 :     old_width = surface->width;
    3321               0 :     old_height = surface->height;
    3322               0 :     _cairo_pdf_surface_set_size_internal (surface,
    3323                 :                                           pdf_pattern->width,
    3324                 :                                           pdf_pattern->height);
    3325                 : 
    3326               0 :     switch (pdf_pattern->pattern->type) {
    3327                 :     case CAIRO_PATTERN_TYPE_SOLID:
    3328               0 :         ASSERT_NOT_REACHED;
    3329               0 :         status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
    3330               0 :         break;
    3331                 : 
    3332                 :     case CAIRO_PATTERN_TYPE_SURFACE:
    3333               0 :         status = _cairo_pdf_surface_emit_surface_pattern (surface, pdf_pattern);
    3334               0 :         break;
    3335                 : 
    3336                 :     case CAIRO_PATTERN_TYPE_LINEAR:
    3337               0 :         status = _cairo_pdf_surface_emit_linear_pattern (surface, pdf_pattern);
    3338               0 :         break;
    3339                 : 
    3340                 :     case CAIRO_PATTERN_TYPE_RADIAL:
    3341               0 :         status = _cairo_pdf_surface_emit_radial_pattern (surface, pdf_pattern);
    3342               0 :         break;
    3343                 : 
    3344                 :     default:
    3345               0 :         ASSERT_NOT_REACHED;
    3346               0 :         status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
    3347               0 :         break;
    3348                 :     }
    3349                 : 
    3350               0 :     _cairo_pdf_surface_set_size_internal (surface,
    3351                 :                                           old_width,
    3352                 :                                           old_height);
    3353                 : 
    3354               0 :     return status;
    3355                 : }
    3356                 : 
    3357                 : static cairo_status_t
    3358               0 : _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t     *surface,
    3359                 :                                           cairo_surface_pattern_t *source)
    3360                 : {
    3361                 :     cairo_pdf_resource_t surface_res;
    3362                 :     int width, height;
    3363                 :     cairo_matrix_t cairo_p2d, pdf_p2d;
    3364                 :     cairo_status_t status;
    3365                 :     int alpha;
    3366                 : 
    3367               0 :     status = _cairo_pdf_surface_add_source_surface (surface,
    3368                 :                                                     source->surface,
    3369                 :                                                     source->base.filter,
    3370                 :                                                     &surface_res,
    3371                 :                                                     &width,
    3372                 :                                                     &height);
    3373               0 :     if (unlikely (status))
    3374               0 :         return status;
    3375                 : 
    3376               0 :     cairo_p2d = source->base.matrix;
    3377               0 :     status = cairo_matrix_invert (&cairo_p2d);
    3378                 :     /* cairo_pattern_set_matrix ensures the matrix is invertible */
    3379               0 :     assert (status == CAIRO_STATUS_SUCCESS);
    3380                 : 
    3381               0 :     pdf_p2d = surface->cairo_to_pdf;
    3382               0 :     cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d);
    3383               0 :     cairo_matrix_translate (&pdf_p2d, 0.0, height);
    3384               0 :     cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
    3385               0 :     if (source->surface->type != CAIRO_SURFACE_TYPE_RECORDING)
    3386               0 :         cairo_matrix_scale (&pdf_p2d, width, height);
    3387                 : 
    3388               0 :     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    3389               0 :     if (unlikely (status))
    3390               0 :         return status;
    3391                 : 
    3392               0 :     if (! _cairo_matrix_is_identity (&pdf_p2d)) {
    3393               0 :         _cairo_output_stream_printf (surface->output,
    3394                 :                                      "%f %f %f %f %f %f cm\n",
    3395                 :                                      pdf_p2d.xx, pdf_p2d.yx,
    3396                 :                                      pdf_p2d.xy, pdf_p2d.yy,
    3397                 :                                      pdf_p2d.x0, pdf_p2d.y0);
    3398                 :     }
    3399                 : 
    3400               0 :     status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
    3401               0 :     if (unlikely (status))
    3402               0 :         return status;
    3403                 : 
    3404               0 :     _cairo_output_stream_printf (surface->output,
    3405                 :                                  "/a%d gs /x%d Do\n",
    3406                 :                                  alpha,
    3407                 :                                  surface_res.id);
    3408                 : 
    3409               0 :     return _cairo_pdf_surface_add_xobject (surface, surface_res);
    3410                 : }
    3411                 : 
    3412                 : static cairo_status_t
    3413               0 : _cairo_pdf_surface_select_operator (cairo_pdf_surface_t *surface,
    3414                 :                                     cairo_operator_t     op)
    3415                 : {
    3416                 :     cairo_status_t status;
    3417                 : 
    3418               0 :     if (op == surface->current_operator)
    3419               0 :         return CAIRO_STATUS_SUCCESS;
    3420                 : 
    3421               0 :     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    3422               0 :     if (unlikely (status))
    3423               0 :         return status;
    3424                 : 
    3425               0 :     _cairo_output_stream_printf (surface->output,
    3426                 :                                  "/b%d gs\n", op);
    3427               0 :     surface->current_operator = op;
    3428               0 :     _cairo_pdf_surface_add_operator (surface, op);
    3429                 : 
    3430               0 :     return CAIRO_STATUS_SUCCESS;
    3431                 : }
    3432                 : 
    3433                 : static cairo_status_t
    3434               0 : _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
    3435                 :                                    const cairo_pattern_t     *pattern,
    3436                 :                                    cairo_pdf_resource_t pattern_res,
    3437                 :                                    cairo_bool_t         is_stroke)
    3438                 : {
    3439                 :     cairo_status_t status;
    3440                 :     int alpha;
    3441               0 :     const cairo_color_t *solid_color = NULL;
    3442                 : 
    3443               0 :     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
    3444               0 :         const cairo_solid_pattern_t *solid = (const cairo_solid_pattern_t *) pattern;
    3445                 : 
    3446               0 :         solid_color = &solid->color;
    3447                 :     }
    3448                 : 
    3449               0 :     if (solid_color != NULL) {
    3450               0 :         if (surface->current_pattern_is_solid_color == FALSE ||
    3451               0 :             surface->current_color_red != solid_color->red ||
    3452               0 :             surface->current_color_green != solid_color->green ||
    3453               0 :             surface->current_color_blue != solid_color->blue ||
    3454               0 :             surface->current_color_is_stroke != is_stroke)
    3455                 :         {
    3456               0 :             status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    3457               0 :             if (unlikely (status))
    3458               0 :                 return status;
    3459                 : 
    3460               0 :             _cairo_output_stream_printf (surface->output,
    3461                 :                                          "%f %f %f ",
    3462                 :                                          solid_color->red,
    3463                 :                                          solid_color->green,
    3464                 :                                          solid_color->blue);
    3465                 : 
    3466               0 :             if (is_stroke)
    3467               0 :                 _cairo_output_stream_printf (surface->output, "RG ");
    3468                 :             else
    3469               0 :                 _cairo_output_stream_printf (surface->output, "rg ");
    3470                 : 
    3471               0 :             surface->current_color_red = solid_color->red;
    3472               0 :             surface->current_color_green = solid_color->green;
    3473               0 :             surface->current_color_blue = solid_color->blue;
    3474               0 :             surface->current_color_is_stroke = is_stroke;
    3475                 :         }
    3476                 : 
    3477               0 :         if (surface->current_pattern_is_solid_color == FALSE ||
    3478               0 :             surface->current_color_alpha != solid_color->alpha)
    3479                 :         {
    3480               0 :             status = _cairo_pdf_surface_add_alpha (surface, solid_color->alpha, &alpha);
    3481               0 :             if (unlikely (status))
    3482               0 :                 return status;
    3483                 : 
    3484               0 :             status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    3485               0 :             if (unlikely (status))
    3486               0 :                 return status;
    3487                 : 
    3488               0 :             _cairo_output_stream_printf (surface->output,
    3489                 :                                          "/a%d gs\n",
    3490                 :                                          alpha);
    3491               0 :             surface->current_color_alpha = solid_color->alpha;
    3492                 :         }
    3493                 : 
    3494               0 :         surface->current_pattern_is_solid_color = TRUE;
    3495                 :     } else {
    3496               0 :         status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
    3497               0 :         if (unlikely (status))
    3498               0 :             return status;
    3499                 : 
    3500               0 :         status = _cairo_pdf_surface_add_pattern (surface, pattern_res);
    3501               0 :         if (unlikely (status))
    3502               0 :             return status;
    3503                 : 
    3504               0 :         status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    3505               0 :         if (unlikely (status))
    3506               0 :             return status;
    3507                 : 
    3508                 :         /* fill-stroke calls select_pattern twice. Don't save if the
    3509                 :          * gstate is already saved. */
    3510               0 :         if (!surface->select_pattern_gstate_saved)
    3511               0 :             _cairo_output_stream_printf (surface->output, "q ");
    3512                 : 
    3513               0 :         if (is_stroke) {
    3514               0 :             _cairo_output_stream_printf (surface->output,
    3515                 :                                          "/Pattern CS /p%d SCN ",
    3516                 :                                          pattern_res.id);
    3517                 :         } else {
    3518               0 :             _cairo_output_stream_printf (surface->output,
    3519                 :                                          "/Pattern cs /p%d scn ",
    3520                 :                                          pattern_res.id);
    3521                 :         }
    3522               0 :         _cairo_output_stream_printf (surface->output,
    3523                 :                                      "/a%d gs\n",
    3524                 :                                      alpha);
    3525               0 :         surface->select_pattern_gstate_saved = TRUE;
    3526               0 :         surface->current_pattern_is_solid_color = FALSE;
    3527                 :     }
    3528                 : 
    3529               0 :     return _cairo_output_stream_get_status (surface->output);
    3530                 : }
    3531                 : 
    3532                 : static cairo_int_status_t
    3533               0 : _cairo_pdf_surface_unselect_pattern (cairo_pdf_surface_t *surface)
    3534                 : {
    3535                 :     cairo_int_status_t status;
    3536                 : 
    3537               0 :     if (surface->select_pattern_gstate_saved) {
    3538               0 :         status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    3539               0 :         if (unlikely (status))
    3540               0 :             return status;
    3541                 : 
    3542               0 :         _cairo_output_stream_printf (surface->output, "Q\n");
    3543               0 :         _cairo_pdf_operators_reset (&surface->pdf_operators);
    3544                 :     }
    3545               0 :     surface->select_pattern_gstate_saved = FALSE;
    3546                 : 
    3547               0 :     return CAIRO_STATUS_SUCCESS;
    3548                 : }
    3549                 : 
    3550                 : static cairo_int_status_t
    3551               0 : _cairo_pdf_surface_show_page (void *abstract_surface)
    3552                 : {
    3553               0 :     cairo_pdf_surface_t *surface = abstract_surface;
    3554                 :     cairo_int_status_t status;
    3555                 : 
    3556               0 :     status = _cairo_pdf_surface_close_content_stream (surface);
    3557               0 :     if (unlikely (status))
    3558               0 :         return status;
    3559                 : 
    3560               0 :     status = _cairo_pdf_surface_write_page (surface);
    3561               0 :     if (unlikely (status))
    3562               0 :         return status;
    3563                 : 
    3564               0 :     _cairo_pdf_surface_clear (surface);
    3565                 : 
    3566               0 :     return CAIRO_STATUS_SUCCESS;
    3567                 : }
    3568                 : 
    3569                 : static cairo_bool_t
    3570               0 : _cairo_pdf_surface_get_extents (void                    *abstract_surface,
    3571                 :                                 cairo_rectangle_int_t   *rectangle)
    3572                 : {
    3573               0 :     cairo_pdf_surface_t *surface = abstract_surface;
    3574                 : 
    3575               0 :     rectangle->x = 0;
    3576               0 :     rectangle->y = 0;
    3577                 : 
    3578                 :     /* XXX: The conversion to integers here is pretty bogus, (not to
    3579                 :      * mention the arbitrary limitation of width to a short(!). We
    3580                 :      * may need to come up with a better interface for get_size.
    3581                 :      */
    3582               0 :     rectangle->width  = ceil (surface->width);
    3583               0 :     rectangle->height = ceil (surface->height);
    3584                 : 
    3585               0 :     return TRUE;
    3586                 : }
    3587                 : 
    3588                 : static void
    3589               0 : _cairo_pdf_surface_get_font_options (void                  *abstract_surface,
    3590                 :                                      cairo_font_options_t  *options)
    3591                 : {
    3592               0 :     _cairo_font_options_init_default (options);
    3593                 : 
    3594               0 :     cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
    3595               0 :     cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
    3596               0 :     cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
    3597               0 : }
    3598                 : 
    3599                 : static cairo_pdf_resource_t
    3600               0 : _cairo_pdf_surface_write_info (cairo_pdf_surface_t *surface)
    3601                 : {
    3602                 :     cairo_pdf_resource_t info;
    3603                 : 
    3604               0 :     info = _cairo_pdf_surface_new_object (surface);
    3605               0 :     if (info.id == 0)
    3606               0 :         return info;
    3607                 : 
    3608               0 :     _cairo_output_stream_printf (surface->output,
    3609                 :                                  "%d 0 obj\n"
    3610                 :                                  "<< /Creator (cairo %s (http://cairographics.org))\n"
    3611                 :                                  "   /Producer (cairo %s (http://cairographics.org))\n"
    3612                 :                                  ">>\n"
    3613                 :                                  "endobj\n",
    3614                 :                                  info.id,
    3615                 :                                  cairo_version_string (),
    3616                 :                                  cairo_version_string ());
    3617                 : 
    3618               0 :     return info;
    3619                 : }
    3620                 : 
    3621                 : static void
    3622               0 : _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface)
    3623                 : {
    3624                 :     cairo_pdf_resource_t page;
    3625                 :     int num_pages, i;
    3626                 : 
    3627               0 :     _cairo_pdf_surface_update_object (surface, surface->pages_resource);
    3628               0 :     _cairo_output_stream_printf (surface->output,
    3629                 :                                  "%d 0 obj\n"
    3630                 :                                  "<< /Type /Pages\n"
    3631                 :                                  "   /Kids [ ",
    3632                 :                                  surface->pages_resource.id);
    3633                 : 
    3634               0 :     num_pages = _cairo_array_num_elements (&surface->pages);
    3635               0 :     for (i = 0; i < num_pages; i++) {
    3636               0 :         _cairo_array_copy_element (&surface->pages, i, &page);
    3637               0 :         _cairo_output_stream_printf (surface->output, "%d 0 R ", page.id);
    3638                 :     }
    3639                 : 
    3640               0 :     _cairo_output_stream_printf (surface->output, "]\n");
    3641               0 :     _cairo_output_stream_printf (surface->output, "   /Count %d\n", num_pages);
    3642                 : 
    3643                 : 
    3644                 :     /* TODO: Figure out which other defaults to be inherited by /Page
    3645                 :      * objects. */
    3646               0 :     _cairo_output_stream_printf (surface->output,
    3647                 :                                  ">>\n"
    3648                 :                                  "endobj\n");
    3649               0 : }
    3650                 : 
    3651                 : static cairo_status_t
    3652               0 : _cairo_pdf_surface_emit_unicode_for_glyph (cairo_pdf_surface_t  *surface,
    3653                 :                                            const char           *utf8)
    3654                 : {
    3655               0 :     uint16_t *utf16 = NULL;
    3656               0 :     int utf16_len = 0;
    3657                 :     cairo_status_t status;
    3658                 :     int i;
    3659                 : 
    3660               0 :     if (utf8 && *utf8) {
    3661               0 :         status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
    3662               0 :         if (unlikely (status))
    3663               0 :             return status;
    3664                 :     }
    3665                 : 
    3666               0 :     _cairo_output_stream_printf (surface->output, "<");
    3667               0 :     if (utf16 == NULL || utf16_len == 0) {
    3668                 :         /* According to the "ToUnicode Mapping File Tutorial"
    3669                 :          * http://www.adobe.com/devnet/acrobat/pdfs/5411.ToUnicode.pdf
    3670                 :          *
    3671                 :          * Glyphs that do not map to a Unicode code point must be
    3672                 :          * mapped to 0xfffd "REPLACEMENT CHARACTER".
    3673                 :          */
    3674               0 :         _cairo_output_stream_printf (surface->output,
    3675                 :                                      "fffd");
    3676                 :     } else {
    3677               0 :         for (i = 0; i < utf16_len; i++)
    3678               0 :             _cairo_output_stream_printf (surface->output,
    3679               0 :                                          "%04x", (int) (utf16[i]));
    3680                 :     }
    3681               0 :     _cairo_output_stream_printf (surface->output, ">");
    3682                 : 
    3683               0 :     if (utf16)
    3684               0 :         free (utf16);
    3685                 : 
    3686               0 :     return CAIRO_STATUS_SUCCESS;
    3687                 : }
    3688                 : 
    3689                 : /* Bob Jenkins hash
    3690                 :  *
    3691                 :  * Public domain code from:
    3692                 :  *   http://burtleburtle.net/bob/hash/doobs.html
    3693                 :  */
    3694                 : 
    3695                 : #define HASH_MIX(a,b,c)                 \
    3696                 : {                                       \
    3697                 :     a -= b; a -= c; a ^= (c>>13); \
    3698                 :     b -= c; b -= a; b ^= (a<<8);  \
    3699                 :     c -= a; c -= b; c ^= (b>>13); \
    3700                 :     a -= b; a -= c; a ^= (c>>12); \
    3701                 :     b -= c; b -= a; b ^= (a<<16); \
    3702                 :     c -= a; c -= b; c ^= (b>>5);  \
    3703                 :     a -= b; a -= c; a ^= (c>>3);  \
    3704                 :     b -= c; b -= a; b ^= (a<<10); \
    3705                 :     c -= a; c -= b; c ^= (b>>15); \
    3706                 : }
    3707                 : 
    3708                 : static uint32_t
    3709               0 : _hash_data (const unsigned char *data, int length, uint32_t initval)
    3710                 : {
    3711                 :     uint32_t a, b, c, len;
    3712                 : 
    3713               0 :     len = length;
    3714               0 :     a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
    3715               0 :     c = initval;         /* the previous hash value */
    3716                 : 
    3717               0 :     while (len >= 12) {
    3718               0 :         a += (data[0] + ((uint32_t)data[1]<<8) + ((uint32_t)data[2]<<16) + ((uint32_t)data[3]<<24));
    3719               0 :         b += (data[4] + ((uint32_t)data[5]<<8) + ((uint32_t)data[6]<<16) + ((uint32_t)data[7]<<24));
    3720               0 :         c += (data[8] + ((uint32_t)data[9]<<8) + ((uint32_t)data[10]<<16)+ ((uint32_t)data[11]<<24));
    3721               0 :         HASH_MIX (a,b,c);
    3722               0 :         data += 12;
    3723               0 :         len -= 12;
    3724                 :     }
    3725                 : 
    3726               0 :     c += length;
    3727               0 :     switch(len) {
    3728               0 :     case 11: c+= ((uint32_t) data[10] << 24);
    3729               0 :     case 10: c+= ((uint32_t) data[9] << 16);
    3730               0 :     case 9 : c+= ((uint32_t) data[8] << 8);
    3731               0 :     case 8 : b+= ((uint32_t) data[7] << 24);
    3732               0 :     case 7 : b+= ((uint32_t) data[6] << 16);
    3733               0 :     case 6 : b+= ((uint32_t) data[5] << 8);
    3734               0 :     case 5 : b+= data[4];
    3735               0 :     case 4 : a+= ((uint32_t) data[3] << 24);
    3736               0 :     case 3 : a+= ((uint32_t) data[2] << 16);
    3737               0 :     case 2 : a+= ((uint32_t) data[1] << 8);
    3738               0 :     case 1 : a+= data[0];
    3739                 :     }
    3740               0 :     HASH_MIX (a,b,c);
    3741                 : 
    3742               0 :     return c;
    3743                 : }
    3744                 : 
    3745                 : static void
    3746               0 : _create_font_subset_tag (cairo_scaled_font_subset_t     *font_subset,
    3747                 :                          const char                     *font_name,
    3748                 :                          char                           *tag)
    3749                 : {
    3750                 :     uint32_t hash;
    3751                 :     int i;
    3752                 :     long numerator;
    3753                 :     ldiv_t d;
    3754                 : 
    3755               0 :     hash = _hash_data ((unsigned char *) font_name, strlen(font_name), 0);
    3756               0 :     hash = _hash_data ((unsigned char *) (font_subset->glyphs),
    3757               0 :                        font_subset->num_glyphs * sizeof(unsigned long), hash);
    3758                 : 
    3759               0 :     numerator = abs (hash);
    3760               0 :     for (i = 0; i < 6; i++) {
    3761               0 :         d = ldiv (numerator, 26);
    3762               0 :         numerator = d.quot;
    3763               0 :         tag[i] = 'A' + d.rem;
    3764                 :     }
    3765               0 :     tag[i] = 0;
    3766               0 : }
    3767                 : 
    3768                 : static cairo_int_status_t
    3769               0 : _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t          *surface,
    3770                 :                                            cairo_scaled_font_subset_t   *font_subset,
    3771                 :                                            cairo_bool_t                  is_composite,
    3772                 :                                            cairo_pdf_resource_t         *stream)
    3773                 : {
    3774                 :     unsigned int i, num_bfchar;
    3775                 :     cairo_int_status_t status;
    3776                 : 
    3777               0 :     stream->id = 0;
    3778                 : 
    3779               0 :     status = _cairo_pdf_surface_open_stream (surface,
    3780                 :                                               NULL,
    3781                 :                                               surface->compress_content,
    3782                 :                                               NULL);
    3783               0 :     if (unlikely (status))
    3784               0 :         return status;
    3785                 : 
    3786               0 :     _cairo_output_stream_printf (surface->output,
    3787                 :                                  "/CIDInit /ProcSet findresource begin\n"
    3788                 :                                  "12 dict begin\n"
    3789                 :                                  "begincmap\n"
    3790                 :                                  "/CIDSystemInfo\n"
    3791                 :                                  "<< /Registry (Adobe)\n"
    3792                 :                                  "   /Ordering (UCS)\n"
    3793                 :                                  "   /Supplement 0\n"
    3794                 :                                  ">> def\n"
    3795                 :                                  "/CMapName /Adobe-Identity-UCS def\n"
    3796                 :                                  "/CMapType 2 def\n"
    3797                 :                                  "1 begincodespacerange\n");
    3798                 : 
    3799               0 :     if (is_composite) {
    3800               0 :         _cairo_output_stream_printf (surface->output,
    3801                 :                                      "<0000> <ffff>\n");
    3802                 :     } else {
    3803               0 :         _cairo_output_stream_printf (surface->output,
    3804                 :                                      "<00> <ff>\n");
    3805                 :     }
    3806                 : 
    3807               0 :     _cairo_output_stream_printf (surface->output,
    3808                 :                                   "endcodespacerange\n");
    3809                 : 
    3810               0 :     if (font_subset->is_scaled) {
    3811                 :         /* Type 3 fonts include glyph 0 in the subset */
    3812               0 :         num_bfchar = font_subset->num_glyphs;
    3813                 : 
    3814                 :         /* The CMap specification has a limit of 100 characters per beginbfchar operator */
    3815               0 :         _cairo_output_stream_printf (surface->output,
    3816                 :                                      "%d beginbfchar\n",
    3817                 :                                      num_bfchar > 100 ? 100 : num_bfchar);
    3818                 : 
    3819               0 :         for (i = 0; i < num_bfchar; i++) {
    3820               0 :             if (i != 0 && i % 100 == 0) {
    3821               0 :                 _cairo_output_stream_printf (surface->output,
    3822                 :                                              "endbfchar\n"
    3823                 :                                              "%d beginbfchar\n",
    3824               0 :                                              num_bfchar - i > 100 ? 100 : num_bfchar - i);
    3825                 :             }
    3826               0 :             _cairo_output_stream_printf (surface->output, "<%02x> ", i);
    3827               0 :             status = _cairo_pdf_surface_emit_unicode_for_glyph (surface,
    3828               0 :                                                                 font_subset->utf8[i]);
    3829               0 :             if (unlikely (status))
    3830               0 :                 return status;
    3831                 : 
    3832               0 :             _cairo_output_stream_printf (surface->output,
    3833                 :                                          "\n");
    3834                 :         }
    3835                 :     } else {
    3836                 :         /* Other fonts reserve glyph 0 for .notdef. Omit glyph 0 from the /ToUnicode map */
    3837               0 :         num_bfchar = font_subset->num_glyphs - 1;
    3838                 : 
    3839                 :         /* The CMap specification has a limit of 100 characters per beginbfchar operator */
    3840               0 :         _cairo_output_stream_printf (surface->output,
    3841                 :                                      "%d beginbfchar\n",
    3842                 :                                      num_bfchar > 100 ? 100 : num_bfchar);
    3843                 : 
    3844               0 :         for (i = 0; i < num_bfchar; i++) {
    3845               0 :             if (i != 0 && i % 100 == 0) {
    3846               0 :                 _cairo_output_stream_printf (surface->output,
    3847                 :                                              "endbfchar\n"
    3848                 :                                              "%d beginbfchar\n",
    3849               0 :                                              num_bfchar - i > 100 ? 100 : num_bfchar - i);
    3850                 :             }
    3851               0 :             if (is_composite)
    3852               0 :                 _cairo_output_stream_printf (surface->output, "<%04x> ", i + 1);
    3853                 :             else
    3854               0 :                 _cairo_output_stream_printf (surface->output, "<%02x> ", i + 1);
    3855                 : 
    3856               0 :             status = _cairo_pdf_surface_emit_unicode_for_glyph (surface,
    3857               0 :                                                                 font_subset->utf8[i + 1]);
    3858               0 :             if (unlikely (status))
    3859               0 :                 return status;
    3860                 : 
    3861               0 :             _cairo_output_stream_printf (surface->output,
    3862                 :                                          "\n");
    3863                 :         }
    3864                 :     }
    3865                 : 
    3866               0 :     _cairo_output_stream_printf (surface->output,
    3867                 :                                  "endbfchar\n");
    3868                 : 
    3869               0 :     _cairo_output_stream_printf (surface->output,
    3870                 :                                  "endcmap\n"
    3871                 :                                  "CMapName currentdict /CMap defineresource pop\n"
    3872                 :                                  "end\n"
    3873                 :                                  "end\n");
    3874                 : 
    3875               0 :     *stream = surface->pdf_stream.self;
    3876               0 :     return _cairo_pdf_surface_close_stream (surface);
    3877                 : }
    3878                 : 
    3879                 : #define PDF_UNITS_PER_EM 1000
    3880                 : 
    3881                 : static cairo_status_t
    3882               0 : _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t           *surface,
    3883                 :                                   cairo_scaled_font_subset_t    *font_subset,
    3884                 :                                   cairo_cff_subset_t            *subset)
    3885                 : {
    3886                 :     cairo_pdf_resource_t stream, descriptor, cidfont_dict;
    3887                 :     cairo_pdf_resource_t subset_resource, to_unicode_stream;
    3888                 :     cairo_pdf_font_t font;
    3889                 :     unsigned int i;
    3890                 :     cairo_status_t status;
    3891                 :     char tag[10];
    3892                 : 
    3893               0 :     _create_font_subset_tag (font_subset, subset->ps_name, tag);
    3894                 : 
    3895               0 :     subset_resource = _cairo_pdf_surface_get_font_resource (surface,
    3896                 :                                                             font_subset->font_id,
    3897                 :                                                             font_subset->subset_id);
    3898               0 :     if (subset_resource.id == 0)
    3899               0 :         return CAIRO_STATUS_SUCCESS;
    3900                 : 
    3901               0 :     status = _cairo_pdf_surface_open_stream (surface,
    3902                 :                                              NULL,
    3903                 :                                              TRUE,
    3904                 :                                              "   /Subtype /CIDFontType0C\n");
    3905               0 :     if (unlikely (status))
    3906               0 :         return status;
    3907                 : 
    3908               0 :     stream = surface->pdf_stream.self;
    3909               0 :     _cairo_output_stream_write (surface->output,
    3910               0 :                                 subset->data, subset->data_length);
    3911               0 :     status = _cairo_pdf_surface_close_stream (surface);
    3912               0 :     if (unlikely (status))
    3913               0 :         return status;
    3914                 : 
    3915               0 :     status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
    3916                 :                                                         font_subset, TRUE,
    3917                 :                                                         &to_unicode_stream);
    3918               0 :     if (_cairo_status_is_error (status))
    3919               0 :         return status;
    3920                 : 
    3921               0 :     descriptor = _cairo_pdf_surface_new_object (surface);
    3922               0 :     if (descriptor.id == 0)
    3923               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3924                 : 
    3925               0 :     _cairo_output_stream_printf (surface->output,
    3926                 :                                  "%d 0 obj\n"
    3927                 :                                  "<< /Type /FontDescriptor\n"
    3928                 :                                  "   /FontName /%s+%s\n",
    3929                 :                                  descriptor.id,
    3930                 :                                  tag,
    3931                 :                                  subset->ps_name);
    3932                 : 
    3933               0 :     if (subset->font_name) {
    3934               0 :         _cairo_output_stream_printf (surface->output,
    3935                 :                                      "   /FontFamily (%s)\n",
    3936                 :                                      subset->font_name);
    3937                 :     }
    3938                 : 
    3939               0 :     _cairo_output_stream_printf (surface->output,
    3940                 :                                  "   /Flags 4\n"
    3941                 :                                  "   /FontBBox [ %ld %ld %ld %ld ]\n"
    3942                 :                                  "   /ItalicAngle 0\n"
    3943                 :                                  "   /Ascent %ld\n"
    3944                 :                                  "   /Descent %ld\n"
    3945                 :                                  "   /CapHeight %ld\n"
    3946                 :                                  "   /StemV 80\n"
    3947                 :                                  "   /StemH 80\n"
    3948                 :                                  "   /FontFile3 %u 0 R\n"
    3949                 :                                  ">>\n"
    3950                 :                                  "endobj\n",
    3951               0 :                                  (long)(subset->x_min*PDF_UNITS_PER_EM),
    3952               0 :                                  (long)(subset->y_min*PDF_UNITS_PER_EM),
    3953               0 :                                  (long)(subset->x_max*PDF_UNITS_PER_EM),
    3954               0 :                                  (long)(subset->y_max*PDF_UNITS_PER_EM),
    3955               0 :                                  (long)(subset->ascent*PDF_UNITS_PER_EM),
    3956               0 :                                  (long)(subset->descent*PDF_UNITS_PER_EM),
    3957               0 :                                  (long)(subset->y_max*PDF_UNITS_PER_EM),
    3958                 :                                  stream.id);
    3959                 : 
    3960               0 :     cidfont_dict = _cairo_pdf_surface_new_object (surface);
    3961               0 :     if (cidfont_dict.id == 0)
    3962               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3963                 : 
    3964               0 :     _cairo_output_stream_printf (surface->output,
    3965                 :                                  "%d 0 obj\n"
    3966                 :                                  "<< /Type /Font\n"
    3967                 :                                  "   /Subtype /CIDFontType0\n"
    3968                 :                                  "   /BaseFont /%s+%s\n"
    3969                 :                                  "   /CIDSystemInfo\n"
    3970                 :                                  "   << /Registry (Adobe)\n"
    3971                 :                                  "      /Ordering (Identity)\n"
    3972                 :                                  "      /Supplement 0\n"
    3973                 :                                  "   >>\n"
    3974                 :                                  "   /FontDescriptor %d 0 R\n"
    3975                 :                                  "   /W [0 [",
    3976                 :                                  cidfont_dict.id,
    3977                 :                                  tag,
    3978                 :                                  subset->ps_name,
    3979                 :                                  descriptor.id);
    3980                 : 
    3981               0 :     for (i = 0; i < font_subset->num_glyphs; i++)
    3982               0 :         _cairo_output_stream_printf (surface->output,
    3983                 :                                      " %ld",
    3984               0 :                                      (long)(subset->widths[i]*PDF_UNITS_PER_EM));
    3985                 : 
    3986               0 :     _cairo_output_stream_printf (surface->output,
    3987                 :                                  " ]]\n"
    3988                 :                                  ">>\n"
    3989                 :                                  "endobj\n");
    3990                 : 
    3991               0 :     _cairo_pdf_surface_update_object (surface, subset_resource);
    3992               0 :     _cairo_output_stream_printf (surface->output,
    3993                 :                                  "%d 0 obj\n"
    3994                 :                                  "<< /Type /Font\n"
    3995                 :                                  "   /Subtype /Type0\n"
    3996                 :                                  "   /BaseFont /%s+%s\n"
    3997                 :                                  "   /Encoding /Identity-H\n"
    3998                 :                                  "   /DescendantFonts [ %d 0 R]\n",
    3999                 :                                  subset_resource.id,
    4000                 :                                  tag,
    4001                 :                                  subset->ps_name,
    4002                 :                                  cidfont_dict.id);
    4003                 : 
    4004               0 :     if (to_unicode_stream.id != 0)
    4005               0 :         _cairo_output_stream_printf (surface->output,
    4006                 :                                      "   /ToUnicode %d 0 R\n",
    4007                 :                                      to_unicode_stream.id);
    4008                 : 
    4009               0 :     _cairo_output_stream_printf (surface->output,
    4010                 :                                  ">>\n"
    4011                 :                                  "endobj\n");
    4012                 : 
    4013               0 :     font.font_id = font_subset->font_id;
    4014               0 :     font.subset_id = font_subset->subset_id;
    4015               0 :     font.subset_resource = subset_resource;
    4016               0 :     status = _cairo_array_append (&surface->fonts, &font);
    4017                 : 
    4018               0 :     return status;
    4019                 : }
    4020                 : 
    4021                 : static cairo_status_t
    4022               0 : _cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t         *surface,
    4023                 :                                          cairo_scaled_font_subset_t  *font_subset)
    4024                 : {
    4025                 :     cairo_status_t status;
    4026                 :     cairo_cff_subset_t subset;
    4027                 :     char name[64];
    4028                 : 
    4029               0 :     snprintf (name, sizeof name, "CairoFont-%d-%d",
    4030                 :               font_subset->font_id, font_subset->subset_id);
    4031               0 :     status = _cairo_cff_subset_init (&subset, name, font_subset);
    4032               0 :     if (unlikely (status))
    4033               0 :         return status;
    4034                 : 
    4035               0 :     status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset);
    4036                 : 
    4037               0 :     _cairo_cff_subset_fini (&subset);
    4038                 : 
    4039               0 :     return status;
    4040                 : }
    4041                 : 
    4042                 : static cairo_status_t
    4043               0 : _cairo_pdf_surface_emit_cff_fallback_font (cairo_pdf_surface_t         *surface,
    4044                 :                                            cairo_scaled_font_subset_t  *font_subset)
    4045                 : {
    4046                 :     cairo_status_t status;
    4047                 :     cairo_cff_subset_t subset;
    4048                 :     char name[64];
    4049                 : 
    4050               0 :     snprintf (name, sizeof name, "CairoFont-%d-%d",
    4051                 :               font_subset->font_id, font_subset->subset_id);
    4052               0 :     status = _cairo_cff_fallback_init (&subset, name, font_subset);
    4053               0 :     if (unlikely (status))
    4054               0 :         return status;
    4055                 : 
    4056               0 :     status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset);
    4057                 : 
    4058               0 :     _cairo_cff_fallback_fini (&subset);
    4059                 : 
    4060               0 :     return status;
    4061                 : }
    4062                 : 
    4063                 : static cairo_status_t
    4064               0 : _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t         *surface,
    4065                 :                                     cairo_scaled_font_subset_t  *font_subset,
    4066                 :                                     cairo_type1_subset_t        *subset)
    4067                 : {
    4068                 :     cairo_pdf_resource_t stream, descriptor, subset_resource, to_unicode_stream;
    4069                 :     cairo_pdf_font_t font;
    4070                 :     cairo_status_t status;
    4071                 :     unsigned long length;
    4072                 :     unsigned int i;
    4073                 :     char tag[10];
    4074                 : 
    4075               0 :     _create_font_subset_tag (font_subset, subset->base_font, tag);
    4076                 : 
    4077               0 :     subset_resource = _cairo_pdf_surface_get_font_resource (surface,
    4078                 :                                                             font_subset->font_id,
    4079                 :                                                             font_subset->subset_id);
    4080               0 :     if (subset_resource.id == 0)
    4081               0 :         return CAIRO_STATUS_SUCCESS;
    4082                 : 
    4083               0 :     length = subset->header_length + subset->data_length + subset->trailer_length;
    4084               0 :     status = _cairo_pdf_surface_open_stream (surface,
    4085                 :                                              NULL,
    4086                 :                                              TRUE,
    4087                 :                                              "   /Length1 %lu\n"
    4088                 :                                              "   /Length2 %lu\n"
    4089                 :                                              "   /Length3 %lu\n",
    4090                 :                                              subset->header_length,
    4091                 :                                              subset->data_length,
    4092                 :                                              subset->trailer_length);
    4093               0 :     if (unlikely (status))
    4094               0 :         return status;
    4095                 : 
    4096               0 :     stream = surface->pdf_stream.self;
    4097               0 :     _cairo_output_stream_write (surface->output, subset->data, length);
    4098               0 :     status = _cairo_pdf_surface_close_stream (surface);
    4099               0 :     if (unlikely (status))
    4100               0 :         return status;
    4101                 : 
    4102               0 :     status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
    4103                 :                                                         font_subset, FALSE,
    4104                 :                                                         &to_unicode_stream);
    4105               0 :     if (_cairo_status_is_error (status))
    4106               0 :         return status;
    4107                 : 
    4108               0 :     descriptor = _cairo_pdf_surface_new_object (surface);
    4109               0 :     if (descriptor.id == 0)
    4110               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4111                 : 
    4112               0 :     _cairo_output_stream_printf (surface->output,
    4113                 :                                  "%d 0 obj\n"
    4114                 :                                  "<< /Type /FontDescriptor\n"
    4115                 :                                  "   /FontName /%s+%s\n"
    4116                 :                                  "   /Flags 4\n"
    4117                 :                                  "   /FontBBox [ %ld %ld %ld %ld ]\n"
    4118                 :                                  "   /ItalicAngle 0\n"
    4119                 :                                  "   /Ascent %ld\n"
    4120                 :                                  "   /Descent %ld\n"
    4121                 :                                  "   /CapHeight %ld\n"
    4122                 :                                  "   /StemV 80\n"
    4123                 :                                  "   /StemH 80\n"
    4124                 :                                  "   /FontFile %u 0 R\n"
    4125                 :                                  ">>\n"
    4126                 :                                  "endobj\n",
    4127                 :                                  descriptor.id,
    4128                 :                                  tag,
    4129                 :                                  subset->base_font,
    4130               0 :                                  (long)(subset->x_min*PDF_UNITS_PER_EM),
    4131               0 :                                  (long)(subset->y_min*PDF_UNITS_PER_EM),
    4132               0 :                                  (long)(subset->x_max*PDF_UNITS_PER_EM),
    4133               0 :                                  (long)(subset->y_max*PDF_UNITS_PER_EM),
    4134               0 :                                  (long)(subset->ascent*PDF_UNITS_PER_EM),
    4135               0 :                                  (long)(subset->descent*PDF_UNITS_PER_EM),
    4136               0 :                                  (long)(subset->y_max*PDF_UNITS_PER_EM),
    4137                 :                                  stream.id);
    4138                 : 
    4139               0 :     _cairo_pdf_surface_update_object (surface, subset_resource);
    4140               0 :     _cairo_output_stream_printf (surface->output,
    4141                 :                                  "%d 0 obj\n"
    4142                 :                                  "<< /Type /Font\n"
    4143                 :                                  "   /Subtype /Type1\n"
    4144                 :                                  "   /BaseFont /%s+%s\n"
    4145                 :                                  "   /FirstChar 0\n"
    4146                 :                                  "   /LastChar %d\n"
    4147                 :                                  "   /FontDescriptor %d 0 R\n"
    4148                 :                                  "   /Widths [",
    4149                 :                                  subset_resource.id,
    4150                 :                                  tag,
    4151                 :                                  subset->base_font,
    4152               0 :                                  font_subset->num_glyphs - 1,
    4153                 :                                  descriptor.id);
    4154                 : 
    4155               0 :     for (i = 0; i < font_subset->num_glyphs; i++)
    4156               0 :         _cairo_output_stream_printf (surface->output,
    4157                 :                                      " %ld",
    4158               0 :                                      (long)(subset->widths[i]*PDF_UNITS_PER_EM));
    4159                 : 
    4160               0 :     _cairo_output_stream_printf (surface->output,
    4161                 :                                  " ]\n");
    4162                 : 
    4163               0 :     if (to_unicode_stream.id != 0)
    4164               0 :         _cairo_output_stream_printf (surface->output,
    4165                 :                                      "    /ToUnicode %d 0 R\n",
    4166                 :                                      to_unicode_stream.id);
    4167                 : 
    4168               0 :     _cairo_output_stream_printf (surface->output,
    4169                 :                                  ">>\n"
    4170                 :                                  "endobj\n");
    4171                 : 
    4172               0 :     font.font_id = font_subset->font_id;
    4173               0 :     font.subset_id = font_subset->subset_id;
    4174               0 :     font.subset_resource = subset_resource;
    4175               0 :     return _cairo_array_append (&surface->fonts, &font);
    4176                 : }
    4177                 : 
    4178                 : #if CAIRO_HAS_FT_FONT
    4179                 : static cairo_status_t
    4180               0 : _cairo_pdf_surface_emit_type1_font_subset (cairo_pdf_surface_t          *surface,
    4181                 :                                            cairo_scaled_font_subset_t   *font_subset)
    4182                 : {
    4183                 :     cairo_status_t status;
    4184                 :     cairo_type1_subset_t subset;
    4185                 :     char name[64];
    4186                 : 
    4187               0 :     snprintf (name, sizeof name, "CairoFont-%d-%d",
    4188                 :               font_subset->font_id, font_subset->subset_id);
    4189               0 :     status = _cairo_type1_subset_init (&subset, name, font_subset, FALSE);
    4190               0 :     if (unlikely (status))
    4191               0 :         return status;
    4192                 : 
    4193               0 :     status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset);
    4194                 : 
    4195               0 :     _cairo_type1_subset_fini (&subset);
    4196               0 :     return status;
    4197                 : }
    4198                 : #endif
    4199                 : 
    4200                 : static cairo_status_t
    4201               0 : _cairo_pdf_surface_emit_type1_fallback_font (cairo_pdf_surface_t        *surface,
    4202                 :                                              cairo_scaled_font_subset_t *font_subset)
    4203                 : {
    4204                 :     cairo_status_t status;
    4205                 :     cairo_type1_subset_t subset;
    4206                 :     char name[64];
    4207                 : 
    4208               0 :     snprintf (name, sizeof name, "CairoFont-%d-%d",
    4209                 :               font_subset->font_id, font_subset->subset_id);
    4210               0 :     status = _cairo_type1_fallback_init_binary (&subset, name, font_subset);
    4211               0 :     if (unlikely (status))
    4212               0 :         return status;
    4213                 : 
    4214               0 :     status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset);
    4215                 : 
    4216               0 :     _cairo_type1_fallback_fini (&subset);
    4217               0 :     return status;
    4218                 : }
    4219                 : 
    4220                 : static cairo_status_t
    4221               0 : _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t               *surface,
    4222                 :                                               cairo_scaled_font_subset_t        *font_subset)
    4223                 : {
    4224                 :     cairo_pdf_resource_t stream, descriptor, cidfont_dict;
    4225                 :     cairo_pdf_resource_t subset_resource, to_unicode_stream;
    4226                 :     cairo_status_t status;
    4227                 :     cairo_pdf_font_t font;
    4228                 :     cairo_truetype_subset_t subset;
    4229                 :     unsigned int i;
    4230                 :     char tag[10];
    4231                 : 
    4232               0 :     subset_resource = _cairo_pdf_surface_get_font_resource (surface,
    4233                 :                                                             font_subset->font_id,
    4234                 :                                                             font_subset->subset_id);
    4235               0 :     if (subset_resource.id == 0)
    4236               0 :         return CAIRO_STATUS_SUCCESS;
    4237                 : 
    4238               0 :     status = _cairo_truetype_subset_init (&subset, font_subset);
    4239               0 :     if (unlikely (status))
    4240               0 :         return status;
    4241                 : 
    4242               0 :     _create_font_subset_tag (font_subset, subset.ps_name, tag);
    4243                 : 
    4244               0 :     status = _cairo_pdf_surface_open_stream (surface,
    4245                 :                                              NULL,
    4246                 :                                              TRUE,
    4247                 :                                              "   /Length1 %lu\n",
    4248                 :                                              subset.data_length);
    4249               0 :     if (unlikely (status)) {
    4250               0 :         _cairo_truetype_subset_fini (&subset);
    4251               0 :         return status;
    4252                 :     }
    4253                 : 
    4254               0 :     stream = surface->pdf_stream.self;
    4255               0 :     _cairo_output_stream_write (surface->output,
    4256               0 :                                 subset.data, subset.data_length);
    4257               0 :     status = _cairo_pdf_surface_close_stream (surface);
    4258               0 :     if (unlikely (status)) {
    4259               0 :         _cairo_truetype_subset_fini (&subset);
    4260               0 :         return status;
    4261                 :     }
    4262                 : 
    4263               0 :     status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
    4264                 :                                                         font_subset, TRUE,
    4265                 :                                                         &to_unicode_stream);
    4266               0 :     if (_cairo_status_is_error (status)) {
    4267               0 :         _cairo_truetype_subset_fini (&subset);
    4268               0 :         return status;
    4269                 :     }
    4270                 : 
    4271               0 :     descriptor = _cairo_pdf_surface_new_object (surface);
    4272               0 :     if (descriptor.id == 0) {
    4273               0 :         _cairo_truetype_subset_fini (&subset);
    4274               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4275                 :     }
    4276                 : 
    4277               0 :     _cairo_output_stream_printf (surface->output,
    4278                 :                                  "%d 0 obj\n"
    4279                 :                                  "<< /Type /FontDescriptor\n"
    4280                 :                                  "   /FontName /%s+%s\n",
    4281                 :                                  descriptor.id,
    4282                 :                                  tag,
    4283                 :                                  subset.ps_name);
    4284                 : 
    4285               0 :     if (subset.font_name) {
    4286               0 :         _cairo_output_stream_printf (surface->output,
    4287                 :                                      "   /FontFamily (%s)\n",
    4288                 :                                      subset.font_name);
    4289                 :     }
    4290                 : 
    4291               0 :     _cairo_output_stream_printf (surface->output,
    4292                 :                                  "   /Flags 4\n"
    4293                 :                                  "   /FontBBox [ %ld %ld %ld %ld ]\n"
    4294                 :                                  "   /ItalicAngle 0\n"
    4295                 :                                  "   /Ascent %ld\n"
    4296                 :                                  "   /Descent %ld\n"
    4297                 :                                  "   /CapHeight %ld\n"
    4298                 :                                  "   /StemV 80\n"
    4299                 :                                  "   /StemH 80\n"
    4300                 :                                  "   /FontFile2 %u 0 R\n"
    4301                 :                                  ">>\n"
    4302                 :                                  "endobj\n",
    4303               0 :                                  (long)(subset.x_min*PDF_UNITS_PER_EM),
    4304               0 :                                  (long)(subset.y_min*PDF_UNITS_PER_EM),
    4305               0 :                                  (long)(subset.x_max*PDF_UNITS_PER_EM),
    4306               0 :                                  (long)(subset.y_max*PDF_UNITS_PER_EM),
    4307               0 :                                  (long)(subset.ascent*PDF_UNITS_PER_EM),
    4308               0 :                                  (long)(subset.descent*PDF_UNITS_PER_EM),
    4309               0 :                                  (long)(subset.y_max*PDF_UNITS_PER_EM),
    4310                 :                                  stream.id);
    4311                 : 
    4312               0 :     cidfont_dict = _cairo_pdf_surface_new_object (surface);
    4313               0 :     if (cidfont_dict.id == 0) {
    4314               0 :         _cairo_truetype_subset_fini (&subset);
    4315               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4316                 :     }
    4317                 : 
    4318               0 :     _cairo_output_stream_printf (surface->output,
    4319                 :                                  "%d 0 obj\n"
    4320                 :                                  "<< /Type /Font\n"
    4321                 :                                  "   /Subtype /CIDFontType2\n"
    4322                 :                                  "   /BaseFont /%s+%s\n"
    4323                 :                                  "   /CIDSystemInfo\n"
    4324                 :                                  "   << /Registry (Adobe)\n"
    4325                 :                                  "      /Ordering (Identity)\n"
    4326                 :                                  "      /Supplement 0\n"
    4327                 :                                  "   >>\n"
    4328                 :                                  "   /FontDescriptor %d 0 R\n"
    4329                 :                                  "   /W [0 [",
    4330                 :                                  cidfont_dict.id,
    4331                 :                                  tag,
    4332                 :                                  subset.ps_name,
    4333                 :                                  descriptor.id);
    4334                 : 
    4335               0 :     for (i = 0; i < font_subset->num_glyphs; i++)
    4336               0 :         _cairo_output_stream_printf (surface->output,
    4337                 :                                      " %ld",
    4338               0 :                                      (long)(subset.widths[i]*PDF_UNITS_PER_EM));
    4339                 : 
    4340               0 :     _cairo_output_stream_printf (surface->output,
    4341                 :                                  " ]]\n"
    4342                 :                                  ">>\n"
    4343                 :                                  "endobj\n");
    4344                 : 
    4345               0 :     _cairo_pdf_surface_update_object (surface, subset_resource);
    4346               0 :     _cairo_output_stream_printf (surface->output,
    4347                 :                                  "%d 0 obj\n"
    4348                 :                                  "<< /Type /Font\n"
    4349                 :                                  "   /Subtype /Type0\n"
    4350                 :                                  "   /BaseFont /%s+%s\n"
    4351                 :                                  "   /Encoding /Identity-H\n"
    4352                 :                                  "   /DescendantFonts [ %d 0 R]\n",
    4353                 :                                  subset_resource.id,
    4354                 :                                  tag,
    4355                 :                                  subset.ps_name,
    4356                 :                                  cidfont_dict.id);
    4357                 : 
    4358               0 :     if (to_unicode_stream.id != 0)
    4359               0 :         _cairo_output_stream_printf (surface->output,
    4360                 :                                      "   /ToUnicode %d 0 R\n",
    4361                 :                                      to_unicode_stream.id);
    4362                 : 
    4363               0 :     _cairo_output_stream_printf (surface->output,
    4364                 :                                  ">>\n"
    4365                 :                                  "endobj\n");
    4366                 : 
    4367               0 :     font.font_id = font_subset->font_id;
    4368               0 :     font.subset_id = font_subset->subset_id;
    4369               0 :     font.subset_resource = subset_resource;
    4370               0 :     status = _cairo_array_append (&surface->fonts, &font);
    4371                 : 
    4372               0 :     _cairo_truetype_subset_fini (&subset);
    4373                 : 
    4374               0 :     return status;
    4375                 : }
    4376                 : 
    4377                 : static cairo_status_t
    4378               0 : _cairo_pdf_emit_imagemask (cairo_image_surface_t *image,
    4379                 :                              cairo_output_stream_t *stream)
    4380                 : {
    4381                 :     uint8_t *byte, output_byte;
    4382                 :     int row, col, num_cols;
    4383                 : 
    4384                 :     /* The only image type supported by Type 3 fonts are 1-bit image
    4385                 :      * masks */
    4386               0 :     assert (image->format == CAIRO_FORMAT_A1);
    4387                 : 
    4388               0 :     _cairo_output_stream_printf (stream,
    4389                 :                                  "BI\n"
    4390                 :                                  "/IM true\n"
    4391                 :                                  "/W %d\n"
    4392                 :                                  "/H %d\n"
    4393                 :                                  "/BPC 1\n"
    4394                 :                                  "/D [1 0]\n",
    4395                 :                                  image->width,
    4396                 :                                  image->height);
    4397                 : 
    4398               0 :     _cairo_output_stream_printf (stream,
    4399                 :                                  "ID ");
    4400                 : 
    4401               0 :     num_cols = (image->width + 7) / 8;
    4402               0 :     for (row = 0; row < image->height; row++) {
    4403               0 :         byte = image->data + row * image->stride;
    4404               0 :         for (col = 0; col < num_cols; col++) {
    4405               0 :             output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
    4406               0 :             _cairo_output_stream_write (stream, &output_byte, 1);
    4407               0 :             byte++;
    4408                 :         }
    4409                 :     }
    4410                 : 
    4411               0 :     _cairo_output_stream_printf (stream,
    4412                 :                                  "\nEI\n");
    4413                 : 
    4414               0 :     return _cairo_output_stream_get_status (stream);
    4415                 : }
    4416                 : 
    4417                 : static cairo_status_t
    4418               0 : _cairo_pdf_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset,
    4419                 :                                              void                       *closure)
    4420                 : {
    4421               0 :     cairo_pdf_surface_t *surface = closure;
    4422               0 :     cairo_status_t status = CAIRO_STATUS_SUCCESS;
    4423                 :     cairo_status_t status2;
    4424                 :     unsigned int i;
    4425                 :     cairo_surface_t *type3_surface;
    4426                 :     cairo_output_stream_t *null_stream;
    4427                 : 
    4428               0 :     null_stream = _cairo_null_stream_create ();
    4429               0 :     type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
    4430                 :                                                        null_stream,
    4431                 :                                                        _cairo_pdf_emit_imagemask,
    4432                 :                                                        surface->font_subsets);
    4433               0 :     if (unlikely (type3_surface->status)) {
    4434               0 :         status2 = _cairo_output_stream_destroy (null_stream);
    4435               0 :         return type3_surface->status;
    4436                 :     }
    4437                 : 
    4438               0 :     _cairo_type3_glyph_surface_set_font_subsets_callback (type3_surface,
    4439                 :                                                           _cairo_pdf_surface_add_font,
    4440                 :                                                           surface);
    4441                 : 
    4442               0 :     for (i = 0; i < font_subset->num_glyphs; i++) {
    4443               0 :         status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
    4444               0 :                                                            font_subset->glyphs[i]);
    4445               0 :         if (unlikely (status))
    4446               0 :             break;
    4447                 :     }
    4448                 : 
    4449               0 :     cairo_surface_destroy (type3_surface);
    4450               0 :     status2 = _cairo_output_stream_destroy (null_stream);
    4451               0 :     if (status == CAIRO_STATUS_SUCCESS)
    4452               0 :         status = status2;
    4453                 : 
    4454               0 :     return status;
    4455                 : }
    4456                 : 
    4457                 : static cairo_status_t
    4458               0 : _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t          *surface,
    4459                 :                                            cairo_scaled_font_subset_t   *font_subset)
    4460                 : {
    4461               0 :     cairo_status_t status = CAIRO_STATUS_SUCCESS;
    4462                 :     cairo_pdf_resource_t *glyphs, encoding, char_procs, subset_resource, to_unicode_stream;
    4463                 :     cairo_pdf_font_t font;
    4464                 :     double *widths;
    4465                 :     unsigned int i;
    4466               0 :     cairo_box_t font_bbox = {{0,0},{0,0}};
    4467               0 :     cairo_box_t bbox = {{0,0},{0,0}};
    4468                 :     cairo_surface_t *type3_surface;
    4469                 : 
    4470               0 :     if (font_subset->num_glyphs == 0)
    4471               0 :         return CAIRO_STATUS_SUCCESS;
    4472                 : 
    4473               0 :     subset_resource = _cairo_pdf_surface_get_font_resource (surface,
    4474                 :                                                             font_subset->font_id,
    4475                 :                                                             font_subset->subset_id);
    4476               0 :     if (subset_resource.id == 0)
    4477               0 :         return CAIRO_STATUS_SUCCESS;
    4478                 : 
    4479               0 :     glyphs = _cairo_malloc_ab (font_subset->num_glyphs, sizeof (cairo_pdf_resource_t));
    4480               0 :     if (unlikely (glyphs == NULL))
    4481               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4482                 : 
    4483               0 :     widths = _cairo_malloc_ab (font_subset->num_glyphs, sizeof (double));
    4484               0 :     if (unlikely (widths == NULL)) {
    4485               0 :         free (glyphs);
    4486               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4487                 :     }
    4488                 : 
    4489               0 :     _cairo_pdf_group_resources_clear (&surface->resources);
    4490               0 :     type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
    4491                 :                                                        NULL,
    4492                 :                                                        _cairo_pdf_emit_imagemask,
    4493                 :                                                        surface->font_subsets);
    4494               0 :     if (unlikely (type3_surface->status)) {
    4495               0 :         free (glyphs);
    4496               0 :         free (widths);
    4497               0 :         return type3_surface->status;
    4498                 :     }
    4499                 : 
    4500               0 :     _cairo_type3_glyph_surface_set_font_subsets_callback (type3_surface,
    4501                 :                                                           _cairo_pdf_surface_add_font,
    4502                 :                                                           surface);
    4503                 : 
    4504               0 :     for (i = 0; i < font_subset->num_glyphs; i++) {
    4505               0 :         status = _cairo_pdf_surface_open_stream (surface,
    4506                 :                                                  NULL,
    4507                 :                                                  surface->compress_content,
    4508                 :                                                  NULL);
    4509               0 :         if (unlikely (status))
    4510               0 :             break;
    4511                 : 
    4512               0 :         glyphs[i] = surface->pdf_stream.self;
    4513               0 :         status = _cairo_type3_glyph_surface_emit_glyph (type3_surface,
    4514                 :                                                         surface->output,
    4515               0 :                                                         font_subset->glyphs[i],
    4516                 :                                                         &bbox,
    4517               0 :                                                         &widths[i]);
    4518               0 :         if (unlikely (status))
    4519               0 :             break;
    4520                 : 
    4521               0 :         status = _cairo_pdf_surface_close_stream (surface);
    4522               0 :         if (unlikely (status))
    4523               0 :             break;
    4524                 : 
    4525               0 :         if (i == 0) {
    4526               0 :             font_bbox.p1.x = bbox.p1.x;
    4527               0 :             font_bbox.p1.y = bbox.p1.y;
    4528               0 :             font_bbox.p2.x = bbox.p2.x;
    4529               0 :             font_bbox.p2.y = bbox.p2.y;
    4530                 :         } else {
    4531               0 :             if (bbox.p1.x < font_bbox.p1.x)
    4532               0 :                 font_bbox.p1.x = bbox.p1.x;
    4533               0 :             if (bbox.p1.y < font_bbox.p1.y)
    4534               0 :                 font_bbox.p1.y = bbox.p1.y;
    4535               0 :             if (bbox.p2.x > font_bbox.p2.x)
    4536               0 :                 font_bbox.p2.x = bbox.p2.x;
    4537               0 :             if (bbox.p2.y > font_bbox.p2.y)
    4538               0 :                 font_bbox.p2.y = bbox.p2.y;
    4539                 :         }
    4540                 :     }
    4541               0 :     cairo_surface_destroy (type3_surface);
    4542               0 :     if (unlikely (status)) {
    4543               0 :         free (glyphs);
    4544               0 :         free (widths);
    4545               0 :         return status;
    4546                 :     }
    4547                 : 
    4548               0 :     encoding = _cairo_pdf_surface_new_object (surface);
    4549               0 :     if (encoding.id == 0) {
    4550               0 :         free (glyphs);
    4551               0 :         free (widths);
    4552               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4553                 :     }
    4554                 : 
    4555               0 :     _cairo_output_stream_printf (surface->output,
    4556                 :                                  "%d 0 obj\n"
    4557                 :                                  "<< /Type /Encoding\n"
    4558                 :                                  "   /Differences [0", encoding.id);
    4559               0 :     for (i = 0; i < font_subset->num_glyphs; i++)
    4560               0 :         _cairo_output_stream_printf (surface->output,
    4561                 :                                      " /%d", i);
    4562               0 :     _cairo_output_stream_printf (surface->output,
    4563                 :                                  "]\n"
    4564                 :                                  ">>\n"
    4565                 :                                  "endobj\n");
    4566                 : 
    4567               0 :     char_procs = _cairo_pdf_surface_new_object (surface);
    4568               0 :     if (char_procs.id == 0) {
    4569               0 :         free (glyphs);
    4570               0 :         free (widths);
    4571               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4572                 :     }
    4573                 : 
    4574               0 :     _cairo_output_stream_printf (surface->output,
    4575                 :                                  "%d 0 obj\n"
    4576                 :                                  "<<\n", char_procs.id);
    4577               0 :     for (i = 0; i < font_subset->num_glyphs; i++)
    4578               0 :         _cairo_output_stream_printf (surface->output,
    4579                 :                                      " /%d %d 0 R\n",
    4580               0 :                                      i, glyphs[i].id);
    4581               0 :     _cairo_output_stream_printf (surface->output,
    4582                 :                                  ">>\n"
    4583                 :                                  "endobj\n");
    4584                 : 
    4585               0 :     free (glyphs);
    4586                 : 
    4587               0 :     status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
    4588                 :                                                         font_subset, FALSE,
    4589                 :                                                         &to_unicode_stream);
    4590               0 :     if (_cairo_status_is_error (status)) {
    4591               0 :         free (widths);
    4592               0 :         return status;
    4593                 :     }
    4594                 : 
    4595               0 :     _cairo_pdf_surface_update_object (surface, subset_resource);
    4596               0 :     _cairo_output_stream_printf (surface->output,
    4597                 :                                  "%d 0 obj\n"
    4598                 :                                  "<< /Type /Font\n"
    4599                 :                                  "   /Subtype /Type3\n"
    4600                 :                                  "   /FontBBox [%f %f %f %f]\n"
    4601                 :                                  "   /FontMatrix [ 1 0 0 1 0 0 ]\n"
    4602                 :                                  "   /Encoding %d 0 R\n"
    4603                 :                                  "   /CharProcs %d 0 R\n"
    4604                 :                                  "   /FirstChar 0\n"
    4605                 :                                  "   /LastChar %d\n",
    4606                 :                                  subset_resource.id,
    4607                 :                                  _cairo_fixed_to_double (font_bbox.p1.x),
    4608               0 :                                  - _cairo_fixed_to_double (font_bbox.p2.y),
    4609                 :                                  _cairo_fixed_to_double (font_bbox.p2.x),
    4610               0 :                                  - _cairo_fixed_to_double (font_bbox.p1.y),
    4611                 :                                  encoding.id,
    4612                 :                                  char_procs.id,
    4613               0 :                                  font_subset->num_glyphs - 1);
    4614                 : 
    4615               0 :     _cairo_output_stream_printf (surface->output,
    4616                 :                                  "   /Widths [");
    4617               0 :     for (i = 0; i < font_subset->num_glyphs; i++)
    4618               0 :         _cairo_output_stream_printf (surface->output, " %f", widths[i]);
    4619               0 :     _cairo_output_stream_printf (surface->output,
    4620                 :                                  "]\n");
    4621               0 :     free (widths);
    4622                 : 
    4623               0 :     _cairo_output_stream_printf (surface->output,
    4624                 :                                  "   /Resources\n");
    4625               0 :     _cairo_pdf_surface_emit_group_resources (surface, &surface->resources);
    4626                 : 
    4627               0 :     if (to_unicode_stream.id != 0)
    4628               0 :         _cairo_output_stream_printf (surface->output,
    4629                 :                                      "    /ToUnicode %d 0 R\n",
    4630                 :                                      to_unicode_stream.id);
    4631                 : 
    4632               0 :     _cairo_output_stream_printf (surface->output,
    4633                 :                                  ">>\n"
    4634                 :                                  "endobj\n");
    4635                 : 
    4636               0 :     font.font_id = font_subset->font_id;
    4637               0 :     font.subset_id = font_subset->subset_id;
    4638               0 :     font.subset_resource = subset_resource;
    4639               0 :     return _cairo_array_append (&surface->fonts, &font);
    4640                 : }
    4641                 : 
    4642                 : static cairo_status_t
    4643               0 : _cairo_pdf_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset,
    4644                 :                                               void                       *closure)
    4645                 : {
    4646               0 :     cairo_pdf_surface_t *surface = closure;
    4647                 :     cairo_status_t status;
    4648                 : 
    4649               0 :     if (font_subset->is_composite) {
    4650               0 :         status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset);
    4651               0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    4652               0 :             return status;
    4653                 : 
    4654               0 :         status = _cairo_pdf_surface_emit_truetype_font_subset (surface, font_subset);
    4655               0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    4656               0 :             return status;
    4657                 : 
    4658               0 :         status = _cairo_pdf_surface_emit_cff_fallback_font (surface, font_subset);
    4659               0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    4660               0 :             return status;
    4661                 :     } else {
    4662                 : #if CAIRO_HAS_FT_FONT
    4663               0 :         status = _cairo_pdf_surface_emit_type1_font_subset (surface, font_subset);
    4664               0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    4665               0 :             return status;
    4666                 : #endif
    4667                 : 
    4668               0 :         status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset);
    4669               0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    4670               0 :             return status;
    4671                 : 
    4672                 :     }
    4673                 : 
    4674               0 :     ASSERT_NOT_REACHED;
    4675               0 :     return CAIRO_STATUS_SUCCESS;
    4676                 : }
    4677                 : 
    4678                 : static cairo_status_t
    4679               0 : _cairo_pdf_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset,
    4680                 :                                             void                       *closure)
    4681                 : {
    4682               0 :     cairo_pdf_surface_t *surface = closure;
    4683                 :     cairo_status_t status;
    4684                 : 
    4685               0 :     status = _cairo_pdf_surface_emit_type3_font_subset (surface, font_subset);
    4686               0 :     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    4687               0 :         return status;
    4688                 : 
    4689               0 :     ASSERT_NOT_REACHED;
    4690               0 :     return CAIRO_STATUS_SUCCESS;
    4691                 : }
    4692                 : 
    4693                 : static cairo_status_t
    4694               0 : _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface)
    4695                 : {
    4696                 :     cairo_status_t status;
    4697                 : 
    4698               0 :     status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
    4699                 :                                                       _cairo_pdf_surface_analyze_user_font_subset,
    4700                 :                                                       surface);
    4701               0 :     if (unlikely (status))
    4702               0 :         goto BAIL;
    4703                 : 
    4704               0 :     status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
    4705                 :                                                           _cairo_pdf_surface_emit_unscaled_font_subset,
    4706                 :                                                           surface);
    4707               0 :     if (unlikely (status))
    4708               0 :         goto BAIL;
    4709                 : 
    4710               0 :     status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
    4711                 :                                                         _cairo_pdf_surface_emit_scaled_font_subset,
    4712                 :                                                         surface);
    4713               0 :     if (unlikely (status))
    4714               0 :         goto BAIL;
    4715                 : 
    4716               0 :     status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
    4717                 :                                                       _cairo_pdf_surface_emit_scaled_font_subset,
    4718                 :                                                       surface);
    4719                 : 
    4720                 : BAIL:
    4721               0 :     _cairo_scaled_font_subsets_destroy (surface->font_subsets);
    4722               0 :     surface->font_subsets = NULL;
    4723                 : 
    4724               0 :     return status;
    4725                 : }
    4726                 : 
    4727                 : static cairo_pdf_resource_t
    4728               0 : _cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface)
    4729                 : {
    4730                 :     cairo_pdf_resource_t catalog;
    4731                 : 
    4732               0 :     catalog = _cairo_pdf_surface_new_object (surface);
    4733               0 :     if (catalog.id == 0)
    4734               0 :         return catalog;
    4735                 : 
    4736               0 :     _cairo_output_stream_printf (surface->output,
    4737                 :                                  "%d 0 obj\n"
    4738                 :                                  "<< /Type /Catalog\n"
    4739                 :                                  "   /Pages %d 0 R\n"
    4740                 :                                  ">>\n"
    4741                 :                                  "endobj\n",
    4742                 :                                  catalog.id,
    4743                 :                                  surface->pages_resource.id);
    4744                 : 
    4745               0 :     return catalog;
    4746                 : }
    4747                 : 
    4748                 : static long
    4749               0 : _cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface)
    4750                 : {
    4751                 :     cairo_pdf_object_t *object;
    4752                 :     int num_objects, i;
    4753                 :     long offset;
    4754                 :     char buffer[11];
    4755                 : 
    4756               0 :     num_objects = _cairo_array_num_elements (&surface->objects);
    4757                 : 
    4758               0 :     offset = _cairo_output_stream_get_position (surface->output);
    4759               0 :     _cairo_output_stream_printf (surface->output,
    4760                 :                                  "xref\n"
    4761                 :                                  "%d %d\n",
    4762                 :                                  0, num_objects + 1);
    4763                 : 
    4764               0 :     _cairo_output_stream_printf (surface->output,
    4765                 :                                  "0000000000 65535 f \n");
    4766               0 :     for (i = 0; i < num_objects; i++) {
    4767               0 :         object = _cairo_array_index (&surface->objects, i);
    4768               0 :         snprintf (buffer, sizeof buffer, "%010ld", object->offset);
    4769               0 :         _cairo_output_stream_printf (surface->output,
    4770                 :                                      "%s 00000 n \n", buffer);
    4771                 :     }
    4772                 : 
    4773               0 :     return offset;
    4774                 : }
    4775                 : 
    4776                 : static cairo_status_t
    4777               0 : _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t        *surface,
    4778                 :                                      cairo_pdf_smask_group_t    *group)
    4779                 : {
    4780                 :     cairo_pdf_resource_t mask_group;
    4781                 :     cairo_pdf_resource_t smask;
    4782                 :     cairo_pdf_smask_group_t *smask_group;
    4783                 :     cairo_pdf_resource_t pattern_res, gstate_res;
    4784                 :     cairo_status_t status;
    4785                 : 
    4786                 :     /* Create mask group */
    4787               0 :     status = _cairo_pdf_surface_open_group (surface, NULL);
    4788               0 :     if (unlikely (status))
    4789               0 :         return status;
    4790                 : 
    4791               0 :     pattern_res.id = 0;
    4792               0 :     gstate_res.id = 0;
    4793               0 :     status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask, NULL,
    4794                 :                                                  &pattern_res, &gstate_res);
    4795               0 :     if (unlikely (status))
    4796               0 :         return status;
    4797                 : 
    4798               0 :     if (gstate_res.id != 0) {
    4799               0 :         smask_group = _cairo_pdf_surface_create_smask_group (surface);
    4800               0 :         if (unlikely (smask_group == NULL))
    4801               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4802                 : 
    4803               0 :         smask_group->operation = PDF_PAINT;
    4804               0 :         smask_group->source = cairo_pattern_reference (group->mask);
    4805               0 :         smask_group->source_res = pattern_res;
    4806               0 :         status = _cairo_pdf_surface_add_smask_group (surface, smask_group);
    4807               0 :         if (unlikely (status)) {
    4808               0 :             _cairo_pdf_smask_group_destroy (smask_group);
    4809               0 :             return status;
    4810                 :         }
    4811                 : 
    4812               0 :         status = _cairo_pdf_surface_add_smask (surface, gstate_res);
    4813               0 :         if (unlikely (status))
    4814               0 :             return status;
    4815                 : 
    4816               0 :         status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res);
    4817               0 :         if (unlikely (status))
    4818               0 :             return status;
    4819                 : 
    4820               0 :         _cairo_output_stream_printf (surface->output,
    4821                 :                                      "q /s%d gs /x%d Do Q\n",
    4822                 :                                      gstate_res.id,
    4823                 :                                      smask_group->group_res.id);
    4824                 :     } else {
    4825               0 :         status = _cairo_pdf_surface_select_pattern (surface, group->mask, pattern_res, FALSE);
    4826               0 :         if (unlikely (status))
    4827               0 :             return status;
    4828                 : 
    4829               0 :         _cairo_output_stream_printf (surface->output,
    4830                 :                                      "0 0 %f %f re f\n",
    4831                 :                                      surface->width, surface->height);
    4832                 : 
    4833               0 :         status = _cairo_pdf_surface_unselect_pattern (surface);
    4834               0 :         if (unlikely (status))
    4835               0 :             return status;
    4836                 :     }
    4837                 : 
    4838               0 :     status = _cairo_pdf_surface_close_group (surface, &mask_group);
    4839               0 :     if (unlikely (status))
    4840               0 :         return status;
    4841                 : 
    4842                 :     /* Create source group */
    4843               0 :     status = _cairo_pdf_surface_open_group (surface, &group->source_res);
    4844               0 :     if (unlikely (status))
    4845               0 :         return status;
    4846                 : 
    4847               0 :     pattern_res.id = 0;
    4848               0 :     gstate_res.id = 0;
    4849               0 :     status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source, NULL,
    4850                 :                                                  &pattern_res, &gstate_res);
    4851               0 :     if (unlikely (status))
    4852               0 :         return status;
    4853                 : 
    4854               0 :     if (gstate_res.id != 0) {
    4855               0 :         smask_group = _cairo_pdf_surface_create_smask_group (surface);
    4856               0 :         if (unlikely (smask_group == NULL))
    4857               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4858                 : 
    4859               0 :         smask_group->operation = PDF_PAINT;
    4860               0 :         smask_group->source = cairo_pattern_reference (group->source);
    4861               0 :         smask_group->source_res = pattern_res;
    4862               0 :         status = _cairo_pdf_surface_add_smask_group (surface, smask_group);
    4863               0 :         if (unlikely (status)) {
    4864               0 :             _cairo_pdf_smask_group_destroy (smask_group);
    4865               0 :             return status;
    4866                 :         }
    4867                 : 
    4868               0 :         status = _cairo_pdf_surface_add_smask (surface, gstate_res);
    4869               0 :         if (unlikely (status))
    4870               0 :             return status;
    4871                 : 
    4872               0 :         status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res);
    4873               0 :         if (unlikely (status))
    4874               0 :             return status;
    4875                 : 
    4876               0 :         _cairo_output_stream_printf (surface->output,
    4877                 :                                      "q /s%d gs /x%d Do Q\n",
    4878                 :                                      gstate_res.id,
    4879                 :                                      smask_group->group_res.id);
    4880                 :     } else {
    4881               0 :         status = _cairo_pdf_surface_select_pattern (surface, group->source, pattern_res, FALSE);
    4882               0 :         if (unlikely (status))
    4883               0 :             return status;
    4884                 : 
    4885               0 :         _cairo_output_stream_printf (surface->output,
    4886                 :                                      "0 0 %f %f re f\n",
    4887                 :                                      surface->width, surface->height);
    4888                 : 
    4889               0 :         status = _cairo_pdf_surface_unselect_pattern (surface);
    4890               0 :         if (unlikely (status))
    4891               0 :             return status;
    4892                 :     }
    4893                 : 
    4894               0 :     status = _cairo_pdf_surface_close_group (surface, NULL);
    4895               0 :     if (unlikely (status))
    4896               0 :         return status;
    4897                 : 
    4898                 :     /* Create an smask based on the alpha component of mask_group */
    4899               0 :     smask = _cairo_pdf_surface_new_object (surface);
    4900               0 :     if (smask.id == 0)
    4901               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4902                 : 
    4903               0 :     _cairo_output_stream_printf (surface->output,
    4904                 :                                  "%d 0 obj\n"
    4905                 :                                  "<< /Type /Mask\n"
    4906                 :                                  "   /S /Alpha\n"
    4907                 :                                  "   /G %d 0 R\n"
    4908                 :                                  ">>\n"
    4909                 :                                  "endobj\n",
    4910                 :                                  smask.id,
    4911                 :                                  mask_group.id);
    4912                 : 
    4913                 :     /* Create a GState that uses the smask */
    4914               0 :     _cairo_pdf_surface_update_object (surface, group->group_res);
    4915               0 :     _cairo_output_stream_printf (surface->output,
    4916                 :                                  "%d 0 obj\n"
    4917                 :                                  "<< /Type /ExtGState\n"
    4918                 :                                  "   /SMask %d 0 R\n"
    4919                 :                                  "   /ca 1\n"
    4920                 :                                  "   /CA 1\n"
    4921                 :                                  "   /AIS false\n"
    4922                 :                                  ">>\n"
    4923                 :                                  "endobj\n",
    4924                 :                                  group->group_res.id,
    4925                 :                                  smask.id);
    4926                 : 
    4927               0 :     return _cairo_output_stream_get_status (surface->output);
    4928                 : }
    4929                 : 
    4930                 : static cairo_status_t
    4931               0 : _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t     *surface,
    4932                 :                                       cairo_pdf_smask_group_t *group)
    4933                 : {
    4934                 :     double old_width, old_height;
    4935                 :     cairo_status_t status;
    4936                 : 
    4937               0 :     old_width = surface->width;
    4938               0 :     old_height = surface->height;
    4939               0 :     _cairo_pdf_surface_set_size_internal (surface,
    4940                 :                                           group->width,
    4941                 :                                           group->height);
    4942                 :     /* _mask is a special case that requires two groups - source
    4943                 :      * and mask as well as a smask and gstate dictionary */
    4944               0 :     if (group->operation == PDF_MASK) {
    4945               0 :         status = _cairo_pdf_surface_write_mask_group (surface, group);
    4946               0 :         goto RESTORE_SIZE;
    4947                 :     }
    4948                 : 
    4949               0 :     status = _cairo_pdf_surface_open_group (surface, &group->group_res);
    4950               0 :     if (unlikely (status))
    4951               0 :         return status;
    4952                 : 
    4953               0 :     status = _cairo_pdf_surface_select_pattern (surface,
    4954               0 :                                                 group->source,
    4955                 :                                                 group->source_res,
    4956               0 :                                                 group->operation == PDF_STROKE);
    4957               0 :     if (unlikely (status))
    4958               0 :         return status;
    4959                 : 
    4960               0 :     switch (group->operation) {
    4961                 :     case PDF_PAINT:
    4962               0 :         _cairo_output_stream_printf (surface->output,
    4963                 :                                      "0 0 %f %f re f\n",
    4964                 :                                      surface->width, surface->height);
    4965               0 :         break;
    4966                 :     case PDF_MASK:
    4967               0 :         ASSERT_NOT_REACHED;
    4968               0 :         break;
    4969                 :     case PDF_FILL:
    4970               0 :         status = _cairo_pdf_operators_fill (&surface->pdf_operators,
    4971                 :                                             &group->path,
    4972                 :                                             group->fill_rule);
    4973               0 :         break;
    4974                 :     case PDF_STROKE:
    4975               0 :         status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
    4976                 :                                               &group->path,
    4977               0 :                                               &group->style,
    4978               0 :                                               &group->ctm,
    4979               0 :                                               &group->ctm_inverse);
    4980               0 :         break;
    4981                 :     case PDF_SHOW_GLYPHS:
    4982               0 :         status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
    4983               0 :                                                         group->utf8, group->utf8_len,
    4984                 :                                                         group->glyphs, group->num_glyphs,
    4985               0 :                                                         group->clusters, group->num_clusters,
    4986               0 :                                                         group->cluster_flags,
    4987                 :                                                         group->scaled_font);
    4988               0 :         break;
    4989                 :     }
    4990               0 :     if (unlikely (status))
    4991               0 :         return status;
    4992                 : 
    4993               0 :     status = _cairo_pdf_surface_unselect_pattern (surface);
    4994               0 :     if (unlikely (status))
    4995               0 :         return status;
    4996                 : 
    4997               0 :     status = _cairo_pdf_surface_close_group (surface, NULL);
    4998                 : 
    4999                 : RESTORE_SIZE:
    5000               0 :     _cairo_pdf_surface_set_size_internal (surface,
    5001                 :                                           old_width,
    5002                 :                                           old_height);
    5003                 : 
    5004               0 :     return status;
    5005                 : }
    5006                 : 
    5007                 : static cairo_status_t
    5008               0 : _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface)
    5009                 : {
    5010                 :     cairo_pdf_pattern_t pattern;
    5011                 :     cairo_pdf_smask_group_t *group;
    5012                 :     cairo_pdf_source_surface_t src_surface;
    5013                 :     int pattern_index, group_index, surface_index;
    5014                 :     cairo_status_t status;
    5015                 : 
    5016                 :     /* Writing out PDF_MASK groups will cause additional smask groups
    5017                 :      * to be appended to surface->smask_groups. Additional patterns
    5018                 :      * may also be appended to surface->patterns.
    5019                 :      *
    5020                 :      * Writing recording surface patterns will cause additional patterns
    5021                 :      * and groups to be appended.
    5022                 :      */
    5023               0 :     pattern_index = 0;
    5024               0 :     group_index = 0;
    5025               0 :     surface_index = 0;
    5026               0 :     while ((pattern_index < _cairo_array_num_elements (&surface->page_patterns)) ||
    5027               0 :            (group_index < _cairo_array_num_elements (&surface->smask_groups)) ||
    5028               0 :            (surface_index < _cairo_array_num_elements (&surface->page_surfaces)))
    5029                 :     {
    5030               0 :         for (; group_index < _cairo_array_num_elements (&surface->smask_groups); group_index++) {
    5031               0 :             _cairo_array_copy_element (&surface->smask_groups, group_index, &group);
    5032               0 :             status = _cairo_pdf_surface_write_smask_group (surface, group);
    5033               0 :             if (unlikely (status))
    5034               0 :                 return status;
    5035                 :         }
    5036                 : 
    5037               0 :         for (; pattern_index < _cairo_array_num_elements (&surface->page_patterns); pattern_index++) {
    5038               0 :             _cairo_array_copy_element (&surface->page_patterns, pattern_index, &pattern);
    5039               0 :             status = _cairo_pdf_surface_emit_pattern (surface, &pattern);
    5040               0 :             if (unlikely (status))
    5041               0 :                 return status;
    5042                 :         }
    5043                 : 
    5044               0 :         for (; surface_index < _cairo_array_num_elements (&surface->page_surfaces); surface_index++) {
    5045               0 :             _cairo_array_copy_element (&surface->page_surfaces, surface_index, &src_surface);
    5046               0 :             status = _cairo_pdf_surface_emit_surface (surface, &src_surface);
    5047               0 :             if (unlikely (status))
    5048               0 :                 return status;
    5049                 :         }
    5050                 :     }
    5051                 : 
    5052               0 :     return CAIRO_STATUS_SUCCESS;
    5053                 : }
    5054                 : 
    5055                 : static cairo_status_t
    5056               0 : _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
    5057                 : {
    5058                 :     cairo_pdf_resource_t page, knockout, res;
    5059                 :     cairo_status_t status;
    5060                 :     int i, len;
    5061                 : 
    5062               0 :     _cairo_pdf_group_resources_clear (&surface->resources);
    5063               0 :     if (surface->has_fallback_images) {
    5064               0 :         status = _cairo_pdf_surface_open_knockout_group (surface);
    5065               0 :         if (unlikely (status))
    5066               0 :             return status;
    5067                 : 
    5068               0 :         len = _cairo_array_num_elements (&surface->knockout_group);
    5069               0 :         for (i = 0; i < len; i++) {
    5070               0 :             _cairo_array_copy_element (&surface->knockout_group, i, &res);
    5071               0 :             _cairo_output_stream_printf (surface->output,
    5072                 :                                          "/x%d Do\n",
    5073                 :                                          res.id);
    5074               0 :             status = _cairo_pdf_surface_add_xobject (surface, res);
    5075               0 :             if (unlikely (status))
    5076               0 :                 return status;
    5077                 :         }
    5078               0 :         _cairo_output_stream_printf (surface->output,
    5079                 :                                      "/x%d Do\n",
    5080                 :                                      surface->content.id);
    5081               0 :         status = _cairo_pdf_surface_add_xobject (surface, surface->content);
    5082               0 :         if (unlikely (status))
    5083               0 :             return status;
    5084                 : 
    5085               0 :         status = _cairo_pdf_surface_close_group (surface, &knockout);
    5086               0 :         if (unlikely (status))
    5087               0 :             return status;
    5088                 : 
    5089               0 :         _cairo_pdf_group_resources_clear (&surface->resources);
    5090               0 :         status = _cairo_pdf_surface_open_content_stream (surface, NULL, FALSE);
    5091               0 :         if (unlikely (status))
    5092               0 :             return status;
    5093                 : 
    5094               0 :         _cairo_output_stream_printf (surface->output,
    5095                 :                                      "/x%d Do\n",
    5096                 :                                      knockout.id);
    5097               0 :         status = _cairo_pdf_surface_add_xobject (surface, knockout);
    5098               0 :         if (unlikely (status))
    5099               0 :             return status;
    5100                 : 
    5101               0 :         status = _cairo_pdf_surface_close_content_stream (surface);
    5102               0 :         if (unlikely (status))
    5103               0 :             return status;
    5104                 :     }
    5105                 : 
    5106               0 :     page = _cairo_pdf_surface_new_object (surface);
    5107               0 :     if (page.id == 0)
    5108               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    5109                 : 
    5110               0 :     _cairo_output_stream_printf (surface->output,
    5111                 :                                  "%d 0 obj\n"
    5112                 :                                  "<< /Type /Page\n"
    5113                 :                                  "   /Parent %d 0 R\n"
    5114                 :                                  "   /MediaBox [ 0 0 %f %f ]\n"
    5115                 :                                  "   /Contents %d 0 R\n"
    5116                 :                                  "   /Group <<\n"
    5117                 :                                  "      /Type /Group\n"
    5118                 :                                  "      /S /Transparency\n"
    5119                 :                                  "      /CS /DeviceRGB\n"
    5120                 :                                  "   >>\n"
    5121                 :                                  "   /Resources %d 0 R\n"
    5122                 :                                  ">>\n"
    5123                 :                                  "endobj\n",
    5124                 :                                  page.id,
    5125                 :                                  surface->pages_resource.id,
    5126                 :                                  surface->width,
    5127                 :                                  surface->height,
    5128                 :                                  surface->content.id,
    5129                 :                                  surface->content_resources.id);
    5130                 : 
    5131               0 :     status = _cairo_array_append (&surface->pages, &page);
    5132               0 :     if (unlikely (status))
    5133               0 :         return status;
    5134                 : 
    5135               0 :     status = _cairo_pdf_surface_write_patterns_and_smask_groups (surface);
    5136               0 :     if (unlikely (status))
    5137               0 :         return status;
    5138                 : 
    5139               0 :     return CAIRO_STATUS_SUCCESS;
    5140                 : }
    5141                 : 
    5142                 : static cairo_int_status_t
    5143               0 : _cairo_pdf_surface_analyze_surface_pattern_transparency (cairo_pdf_surface_t      *surface,
    5144                 :                                                          cairo_surface_pattern_t *pattern)
    5145                 : {
    5146                 :     cairo_image_surface_t  *image;
    5147                 :     void                   *image_extra;
    5148                 :     cairo_int_status_t      status;
    5149                 :     cairo_image_transparency_t transparency;
    5150                 : 
    5151               0 :     status = _cairo_surface_acquire_source_image (pattern->surface,
    5152                 :                                                   &image,
    5153                 :                                                   &image_extra);
    5154               0 :     if (unlikely (status))
    5155               0 :         return status;
    5156                 : 
    5157               0 :     if (image->base.status)
    5158               0 :         return image->base.status;
    5159                 : 
    5160               0 :     transparency = _cairo_image_analyze_transparency (image);
    5161               0 :     if (transparency == CAIRO_IMAGE_IS_OPAQUE)
    5162               0 :         status = CAIRO_STATUS_SUCCESS;
    5163                 :     else
    5164               0 :         status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
    5165                 : 
    5166               0 :     _cairo_surface_release_source_image (pattern->surface, image, image_extra);
    5167                 : 
    5168               0 :     return status;
    5169                 : }
    5170                 : 
    5171                 : static cairo_bool_t
    5172               0 : _surface_pattern_supported (cairo_surface_pattern_t *pattern)
    5173                 : {
    5174                 :     cairo_extend_t extend;
    5175                 : 
    5176               0 :     if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
    5177               0 :         return TRUE;
    5178                 : 
    5179               0 :     if (pattern->surface->backend->acquire_source_image == NULL)
    5180               0 :         return FALSE;
    5181                 : 
    5182                 :     /* Does an ALPHA-only source surface even make sense? Maybe, but I
    5183                 :      * don't think it's worth the extra code to support it. */
    5184                 : 
    5185                 : /* XXX: Need to write this function here...
    5186                 :     content = cairo_surface_get_content (pattern->surface);
    5187                 :     if (content == CAIRO_CONTENT_ALPHA)
    5188                 :         return FALSE;
    5189                 : */
    5190                 : 
    5191               0 :     extend = cairo_pattern_get_extend (&pattern->base);
    5192               0 :     switch (extend) {
    5193                 :     case CAIRO_EXTEND_NONE:
    5194                 :     case CAIRO_EXTEND_REPEAT:
    5195                 :     case CAIRO_EXTEND_REFLECT:
    5196                 :     /* There's no point returning FALSE for EXTEND_PAD, as the image
    5197                 :      * surface does not currently implement it either */
    5198                 :     case CAIRO_EXTEND_PAD:
    5199               0 :         return TRUE;
    5200                 :     }
    5201                 : 
    5202               0 :     ASSERT_NOT_REACHED;
    5203               0 :     return FALSE;
    5204                 : }
    5205                 : 
    5206                 : static cairo_bool_t
    5207               0 : _gradient_pattern_supported (const cairo_pattern_t *pattern)
    5208                 : {
    5209                 :     cairo_extend_t extend;
    5210                 : 
    5211               0 :     extend = cairo_pattern_get_extend ((cairo_pattern_t *) pattern);
    5212                 : 
    5213                 : 
    5214                 :     /* Radial gradients are currently only supported with EXTEND_NONE
    5215                 :      * and EXTEND_PAD and when one circle is inside the other. */
    5216               0 :     if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
    5217                 :         double x1, y1, x2, y2, r1, r2, d;
    5218               0 :         cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
    5219                 : 
    5220               0 :         if (extend == CAIRO_EXTEND_REPEAT ||
    5221                 :             extend == CAIRO_EXTEND_REFLECT) {
    5222               0 :             return FALSE;
    5223                 :         }
    5224                 : 
    5225               0 :         x1 = _cairo_fixed_to_double (radial->c1.x);
    5226               0 :         y1 = _cairo_fixed_to_double (radial->c1.y);
    5227               0 :         r1 = _cairo_fixed_to_double (radial->r1);
    5228               0 :         x2 = _cairo_fixed_to_double (radial->c2.x);
    5229               0 :         y2 = _cairo_fixed_to_double (radial->c2.y);
    5230               0 :         r2 = _cairo_fixed_to_double (radial->r2);
    5231                 : 
    5232               0 :         d = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
    5233               0 :         if (d > fabs(r2 - r1)) {
    5234               0 :             return FALSE;
    5235                 :         }
    5236                 :     }
    5237                 : 
    5238               0 :     return TRUE;
    5239                 : }
    5240                 : 
    5241                 : static cairo_bool_t
    5242               0 : _pattern_supported (const cairo_pattern_t *pattern)
    5243                 : {
    5244               0 :     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
    5245               0 :         return TRUE;
    5246                 : 
    5247               0 :     if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
    5248               0 :         pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
    5249               0 :         return _gradient_pattern_supported (pattern);
    5250                 : 
    5251               0 :     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
    5252               0 :         return _surface_pattern_supported ((cairo_surface_pattern_t *) pattern);
    5253                 : 
    5254               0 :     return FALSE;
    5255                 : }
    5256                 : 
    5257                 : static cairo_bool_t
    5258               0 : _pdf_operator_supported (cairo_operator_t op)
    5259                 : {
    5260               0 :     switch (op) {
    5261                 :     case CAIRO_OPERATOR_OVER:
    5262                 :     case CAIRO_OPERATOR_MULTIPLY:
    5263                 :     case CAIRO_OPERATOR_SCREEN:
    5264                 :     case CAIRO_OPERATOR_OVERLAY:
    5265                 :     case CAIRO_OPERATOR_DARKEN:
    5266                 :     case CAIRO_OPERATOR_LIGHTEN:
    5267                 :     case CAIRO_OPERATOR_COLOR_DODGE:
    5268                 :     case CAIRO_OPERATOR_COLOR_BURN:
    5269                 :     case CAIRO_OPERATOR_HARD_LIGHT:
    5270                 :     case CAIRO_OPERATOR_SOFT_LIGHT:
    5271                 :     case CAIRO_OPERATOR_DIFFERENCE:
    5272                 :     case CAIRO_OPERATOR_EXCLUSION:
    5273                 :     case CAIRO_OPERATOR_HSL_HUE:
    5274                 :     case CAIRO_OPERATOR_HSL_SATURATION:
    5275                 :     case CAIRO_OPERATOR_HSL_COLOR:
    5276                 :     case CAIRO_OPERATOR_HSL_LUMINOSITY:
    5277               0 :         return TRUE;
    5278                 : 
    5279                 :     default:
    5280                 :     case CAIRO_OPERATOR_CLEAR:
    5281                 :     case CAIRO_OPERATOR_SOURCE:
    5282                 :     case CAIRO_OPERATOR_IN:
    5283                 :     case CAIRO_OPERATOR_OUT:
    5284                 :     case CAIRO_OPERATOR_ATOP:
    5285                 :     case CAIRO_OPERATOR_DEST:
    5286                 :     case CAIRO_OPERATOR_DEST_OVER:
    5287                 :     case CAIRO_OPERATOR_DEST_IN:
    5288                 :     case CAIRO_OPERATOR_DEST_OUT:
    5289                 :     case CAIRO_OPERATOR_DEST_ATOP:
    5290                 :     case CAIRO_OPERATOR_XOR:
    5291                 :     case CAIRO_OPERATOR_ADD:
    5292                 :     case CAIRO_OPERATOR_SATURATE:
    5293               0 :         return FALSE;
    5294                 :     }
    5295                 : }
    5296                 : 
    5297                 : static cairo_int_status_t
    5298               0 : _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t  *surface,
    5299                 :                                       cairo_operator_t      op,
    5300                 :                                       const cairo_pattern_t      *pattern,
    5301                 :                                       const cairo_rectangle_int_t        *extents)
    5302                 : {
    5303               0 :     if (surface->force_fallbacks &&
    5304               0 :         surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
    5305                 :     {
    5306               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    5307                 :     }
    5308                 : 
    5309               0 :     if (! _pattern_supported (pattern))
    5310               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    5311                 : 
    5312               0 :     if (_pdf_operator_supported (op)) {
    5313               0 :         if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
    5314               0 :             cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
    5315                 : 
    5316               0 :             if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
    5317               0 :                 if (pattern->extend == CAIRO_EXTEND_PAD)
    5318               0 :                     return CAIRO_INT_STATUS_UNSUPPORTED;
    5319                 :                 else
    5320               0 :                     return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
    5321                 :             }
    5322                 :         }
    5323                 : 
    5324               0 :         return CAIRO_STATUS_SUCCESS;
    5325                 :     }
    5326                 : 
    5327                 : 
    5328                 :     /* The SOURCE operator is supported if the pattern is opaque or if
    5329                 :      * there is nothing painted underneath. */
    5330               0 :     if (op == CAIRO_OPERATOR_SOURCE) {
    5331               0 :         if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
    5332               0 :             cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
    5333                 : 
    5334               0 :             if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
    5335               0 :                 if (_cairo_pattern_is_opaque (pattern, extents)) {
    5336               0 :                     return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
    5337                 :                 } else {
    5338                 :                     /* FIXME: The analysis surface does not yet have
    5339                 :                      * the capability to analyze a non opaque recording
    5340                 :                      * surface and mark it supported if there is
    5341                 :                      * nothing underneath. For now recording surfaces of
    5342                 :                      * type CONTENT_COLOR_ALPHA painted with
    5343                 :                      * OPERATOR_SOURCE will result in a fallback
    5344                 :                      * image. */
    5345                 : 
    5346               0 :                     return CAIRO_INT_STATUS_UNSUPPORTED;
    5347                 :                 }
    5348                 :             } else {
    5349               0 :                 return _cairo_pdf_surface_analyze_surface_pattern_transparency (surface,
    5350                 :                                                                                 surface_pattern);
    5351                 :             }
    5352                 :         }
    5353                 : 
    5354               0 :         if (_cairo_pattern_is_opaque (pattern, extents))
    5355               0 :             return CAIRO_STATUS_SUCCESS;
    5356                 :         else
    5357               0 :             return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
    5358                 :     }
    5359                 : 
    5360               0 :     return CAIRO_INT_STATUS_UNSUPPORTED;
    5361                 : }
    5362                 : 
    5363                 : static cairo_bool_t
    5364               0 : _cairo_pdf_surface_operation_supported (cairo_pdf_surface_t  *surface,
    5365                 :                                         cairo_operator_t      op,
    5366                 :                                         const cairo_pattern_t      *pattern,
    5367                 :                                         const cairo_rectangle_int_t *extents)
    5368                 : {
    5369               0 :     return _cairo_pdf_surface_analyze_operation (surface, op, pattern, extents) != CAIRO_INT_STATUS_UNSUPPORTED;
    5370                 : }
    5371                 : 
    5372                 : static cairo_int_status_t
    5373               0 : _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
    5374                 : {
    5375                 :     cairo_status_t status;
    5376                 : 
    5377               0 :     status = _cairo_pdf_surface_close_content_stream (surface);
    5378               0 :     if (unlikely (status))
    5379               0 :         return status;
    5380                 : 
    5381               0 :     status = _cairo_array_append (&surface->knockout_group, &surface->content);
    5382               0 :     if (unlikely (status))
    5383               0 :         return status;
    5384                 : 
    5385               0 :     _cairo_pdf_group_resources_clear (&surface->resources);
    5386               0 :     return _cairo_pdf_surface_open_content_stream (surface, NULL, TRUE);
    5387                 : }
    5388                 : 
    5389                 : static cairo_int_status_t
    5390               0 : _cairo_pdf_surface_paint (void                  *abstract_surface,
    5391                 :                           cairo_operator_t       op,
    5392                 :                           const cairo_pattern_t *source,
    5393                 :                           cairo_clip_t          *clip)
    5394                 : {
    5395               0 :     cairo_pdf_surface_t *surface = abstract_surface;
    5396                 :     cairo_status_t status;
    5397                 :     cairo_pdf_smask_group_t *group;
    5398                 :     cairo_pdf_resource_t pattern_res, gstate_res;
    5399                 :     cairo_composite_rectangles_t extents;
    5400                 : 
    5401                 :     cairo_rectangle_int_t rect;
    5402               0 :     rect.x = rect.y = 0;
    5403               0 :     rect.width = surface->width;
    5404               0 :     rect.height = surface->height;
    5405                 : 
    5406               0 :     status = _cairo_composite_rectangles_init_for_paint (&extents,
    5407                 :                                                          &rect,
    5408                 :                                                          op, source, clip);
    5409               0 :     if (unlikely (status)) {
    5410               0 :         if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
    5411               0 :             return CAIRO_STATUS_SUCCESS;
    5412                 : 
    5413               0 :         return status;
    5414                 :     }
    5415                 : 
    5416               0 :     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
    5417               0 :         return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
    5418               0 :     } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
    5419               0 :         status = _cairo_pdf_surface_start_fallback (surface);
    5420               0 :         if (unlikely (status))
    5421               0 :             return status;
    5422                 :     }
    5423                 : 
    5424               0 :     assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
    5425                 : 
    5426               0 :     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
    5427               0 :     if (unlikely (status))
    5428               0 :         return status;
    5429                 : 
    5430               0 :     status = _cairo_pdf_surface_select_operator (surface, op);
    5431               0 :     if (unlikely (status))
    5432               0 :         return status;
    5433                 : 
    5434               0 :     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    5435               0 :     if (unlikely (status))
    5436               0 :         return status;
    5437                 : 
    5438               0 :     if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
    5439               0 :         source->extend == CAIRO_EXTEND_NONE)
    5440                 :     {
    5441               0 :         _cairo_output_stream_printf (surface->output, "q\n");
    5442               0 :         status = _cairo_pdf_surface_paint_surface_pattern (surface,
    5443                 :                                                            (cairo_surface_pattern_t *) source);
    5444               0 :         if (unlikely (status))
    5445               0 :             return status;
    5446                 : 
    5447               0 :         _cairo_output_stream_printf (surface->output, "Q\n");
    5448               0 :         return _cairo_output_stream_get_status (surface->output);
    5449                 :     }
    5450                 : 
    5451               0 :     pattern_res.id = 0;
    5452               0 :     gstate_res.id = 0;
    5453               0 :     status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
    5454                 :                                                  &extents.bounded,
    5455                 :                                                  &pattern_res, &gstate_res);
    5456               0 :     if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
    5457               0 :         return CAIRO_STATUS_SUCCESS;
    5458               0 :     if (unlikely (status))
    5459               0 :         return status;
    5460                 : 
    5461               0 :     if (gstate_res.id != 0) {
    5462               0 :         group = _cairo_pdf_surface_create_smask_group (surface);
    5463               0 :         if (unlikely (group == NULL))
    5464               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    5465                 : 
    5466               0 :         group->operation = PDF_PAINT;
    5467               0 :         status = _cairo_pattern_create_copy (&group->source, source);
    5468               0 :         if (unlikely (status)) {
    5469               0 :             _cairo_pdf_smask_group_destroy (group);
    5470               0 :             return status;
    5471                 :         }
    5472               0 :         group->source_res = pattern_res;
    5473               0 :         status = _cairo_pdf_surface_add_smask_group (surface, group);
    5474               0 :         if (unlikely (status)) {
    5475               0 :             _cairo_pdf_smask_group_destroy (group);
    5476               0 :             return status;
    5477                 :         }
    5478                 : 
    5479               0 :         status = _cairo_pdf_surface_add_smask (surface, gstate_res);
    5480               0 :         if (unlikely (status))
    5481               0 :             return status;
    5482                 : 
    5483               0 :         status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
    5484               0 :         if (unlikely (status))
    5485               0 :             return status;
    5486                 : 
    5487               0 :         _cairo_output_stream_printf (surface->output,
    5488                 :                                      "q /s%d gs /x%d Do Q\n",
    5489                 :                                      gstate_res.id,
    5490                 :                                      group->group_res.id);
    5491                 :     } else {
    5492               0 :         status = _cairo_pdf_surface_select_pattern (surface, source,
    5493                 :                                                     pattern_res, FALSE);
    5494               0 :         if (unlikely (status))
    5495               0 :             return status;
    5496                 : 
    5497               0 :         _cairo_output_stream_printf (surface->output,
    5498                 :                                      "0 0 %f %f re f\n",
    5499                 :                                      surface->width, surface->height);
    5500                 : 
    5501               0 :         status = _cairo_pdf_surface_unselect_pattern (surface);
    5502               0 :         if (unlikely (status))
    5503               0 :             return status;
    5504                 :     }
    5505                 : 
    5506               0 :     return _cairo_output_stream_get_status (surface->output);
    5507                 : }
    5508                 : 
    5509                 : static cairo_int_status_t
    5510               0 : _cairo_pdf_surface_mask (void                   *abstract_surface,
    5511                 :                          cairo_operator_t        op,
    5512                 :                          const cairo_pattern_t  *source,
    5513                 :                          const cairo_pattern_t  *mask,
    5514                 :                          cairo_clip_t           *clip)
    5515                 : {
    5516               0 :     cairo_pdf_surface_t *surface = abstract_surface;
    5517                 :     cairo_pdf_smask_group_t *group;
    5518                 :     cairo_status_t status;
    5519                 :     cairo_composite_rectangles_t extents;
    5520                 : 
    5521                 :     cairo_rectangle_int_t rect;
    5522               0 :     rect.x = rect.y = 0;
    5523               0 :     rect.width = surface->width;
    5524               0 :     rect.height = surface->height;
    5525                 : 
    5526               0 :     status = _cairo_composite_rectangles_init_for_mask (&extents,
    5527                 :                                                         &rect,
    5528                 :                                                         op, source, mask, clip);
    5529               0 :     if (unlikely (status)) {
    5530               0 :         if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
    5531               0 :             return CAIRO_STATUS_SUCCESS;
    5532                 : 
    5533               0 :         return status;
    5534                 :     }
    5535                 : 
    5536               0 :     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
    5537                 :         cairo_status_t source_status, mask_status;
    5538                 : 
    5539               0 :         source_status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
    5540               0 :         if (_cairo_status_is_error (source_status))
    5541               0 :             return source_status;
    5542                 : 
    5543               0 :         if (mask->has_component_alpha) {
    5544               0 :             mask_status = CAIRO_INT_STATUS_UNSUPPORTED;
    5545                 :         } else {
    5546               0 :             mask_status = _cairo_pdf_surface_analyze_operation (surface, op, mask, &extents.bounded);
    5547               0 :             if (_cairo_status_is_error (mask_status))
    5548               0 :                 return mask_status;
    5549                 :         }
    5550                 : 
    5551               0 :         return _cairo_analysis_surface_merge_status (source_status,
    5552                 :                                                      mask_status);
    5553               0 :     } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
    5554               0 :         status = _cairo_pdf_surface_start_fallback (surface);
    5555               0 :         if (unlikely (status))
    5556               0 :             return status;
    5557                 :     }
    5558                 : 
    5559               0 :     assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
    5560               0 :     assert (_cairo_pdf_surface_operation_supported (surface, op, mask, &extents.bounded));
    5561                 : 
    5562               0 :     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
    5563               0 :     if (unlikely (status))
    5564               0 :         return status;
    5565                 : 
    5566               0 :     group = _cairo_pdf_surface_create_smask_group (surface);
    5567               0 :     if (unlikely (group == NULL))
    5568               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    5569                 : 
    5570               0 :     group->operation = PDF_MASK;
    5571               0 :     status = _cairo_pattern_create_copy (&group->source, source);
    5572               0 :     if (unlikely (status)) {
    5573               0 :         _cairo_pdf_smask_group_destroy (group);
    5574               0 :         return status;
    5575                 :     }
    5576               0 :     status = _cairo_pattern_create_copy (&group->mask, mask);
    5577               0 :     if (unlikely (status)) {
    5578               0 :         _cairo_pdf_smask_group_destroy (group);
    5579               0 :         return status;
    5580                 :     }
    5581               0 :     group->source_res = _cairo_pdf_surface_new_object (surface);
    5582               0 :     if (group->source_res.id == 0) {
    5583               0 :         _cairo_pdf_smask_group_destroy (group);
    5584               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    5585                 :     }
    5586                 : 
    5587               0 :     status = _cairo_pdf_surface_add_smask_group (surface, group);
    5588               0 :     if (unlikely (status)) {
    5589               0 :         _cairo_pdf_smask_group_destroy (group);
    5590               0 :         return status;
    5591                 :     }
    5592                 : 
    5593               0 :     status = _cairo_pdf_surface_add_smask (surface, group->group_res);
    5594               0 :     if (unlikely (status))
    5595               0 :         return status;
    5596                 : 
    5597               0 :     status = _cairo_pdf_surface_add_xobject (surface, group->source_res);
    5598               0 :     if (unlikely (status))
    5599               0 :         return status;
    5600                 : 
    5601               0 :     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    5602               0 :     if (unlikely (status))
    5603               0 :         return status;
    5604                 : 
    5605               0 :     status = _cairo_pdf_surface_select_operator (surface, op);
    5606               0 :     if (unlikely (status))
    5607               0 :         return status;
    5608                 : 
    5609               0 :     _cairo_output_stream_printf (surface->output,
    5610                 :                                  "q /s%d gs /x%d Do Q\n",
    5611                 :                                  group->group_res.id,
    5612                 :                                  group->source_res.id);
    5613                 : 
    5614               0 :     return _cairo_output_stream_get_status (surface->output);
    5615                 : }
    5616                 : 
    5617                 : static cairo_int_status_t
    5618               0 : _cairo_pdf_surface_stroke (void                 *abstract_surface,
    5619                 :                            cairo_operator_t      op,
    5620                 :                            const cairo_pattern_t *source,
    5621                 :                            cairo_path_fixed_t   *path,
    5622                 :                            const cairo_stroke_style_t   *style,
    5623                 :                            const cairo_matrix_t *ctm,
    5624                 :                            const cairo_matrix_t *ctm_inverse,
    5625                 :                            double                tolerance,
    5626                 :                            cairo_antialias_t     antialias,
    5627                 :                            cairo_clip_t         *clip)
    5628                 : {
    5629               0 :     cairo_pdf_surface_t *surface = abstract_surface;
    5630                 :     cairo_pdf_smask_group_t *group;
    5631                 :     cairo_pdf_resource_t pattern_res, gstate_res;
    5632                 :     cairo_composite_rectangles_t extents;
    5633                 :     cairo_status_t status;
    5634                 : 
    5635                 :     cairo_rectangle_int_t rect;
    5636               0 :     rect.x = rect.y = 0;
    5637               0 :     rect.width = surface->width;
    5638               0 :     rect.height = surface->height;
    5639                 : 
    5640               0 :     status = _cairo_composite_rectangles_init_for_stroke (&extents,
    5641                 :                                                           &rect,
    5642                 :                                                           op, source,
    5643                 :                                                           path, style, ctm,
    5644                 :                                                           clip);
    5645               0 :     if (unlikely (status)) {
    5646               0 :         if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
    5647               0 :             return CAIRO_STATUS_SUCCESS;
    5648                 : 
    5649               0 :         return status;
    5650                 :     }
    5651                 : 
    5652                 :     /* use the more accurate extents */
    5653               0 :     if (extents.is_bounded) {
    5654               0 :         status = _cairo_path_fixed_stroke_extents (path, style,
    5655                 :                                                    ctm, ctm_inverse,
    5656                 :                                                    tolerance,
    5657                 :                                                    &extents.mask);
    5658               0 :         if (unlikely (status))
    5659               0 :             return status;
    5660                 : 
    5661               0 :         if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
    5662               0 :             return CAIRO_STATUS_SUCCESS;
    5663                 :     }
    5664                 : 
    5665               0 :     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
    5666               0 :         return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
    5667                 : 
    5668               0 :     assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
    5669                 : 
    5670               0 :     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
    5671               0 :     if (unlikely (status))
    5672               0 :         return status;
    5673                 : 
    5674               0 :     pattern_res.id = 0;
    5675               0 :     gstate_res.id = 0;
    5676               0 :     status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
    5677                 :                                                  &extents.bounded,
    5678                 :                                                  &pattern_res, &gstate_res);
    5679               0 :     if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
    5680               0 :         return CAIRO_STATUS_SUCCESS;
    5681               0 :     if (unlikely (status))
    5682               0 :         return status;
    5683                 : 
    5684               0 :     status = _cairo_pdf_surface_select_operator (surface, op);
    5685               0 :     if (unlikely (status))
    5686               0 :         return status;
    5687                 : 
    5688               0 :     if (gstate_res.id != 0) {
    5689               0 :         group = _cairo_pdf_surface_create_smask_group (surface);
    5690               0 :         if (unlikely (group == NULL))
    5691               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    5692                 : 
    5693               0 :         group->operation = PDF_STROKE;
    5694               0 :         status = _cairo_pattern_create_copy (&group->source, source);
    5695               0 :         if (unlikely (status)) {
    5696               0 :             _cairo_pdf_smask_group_destroy (group);
    5697               0 :             return status;
    5698                 :         }
    5699               0 :         group->source_res = pattern_res;
    5700               0 :         status = _cairo_path_fixed_init_copy (&group->path, path);
    5701               0 :         if (unlikely (status)) {
    5702               0 :             _cairo_pdf_smask_group_destroy (group);
    5703               0 :             return status;
    5704                 :         }
    5705                 : 
    5706               0 :         group->style = *style;
    5707               0 :         group->ctm = *ctm;
    5708               0 :         group->ctm_inverse = *ctm_inverse;
    5709               0 :         status = _cairo_pdf_surface_add_smask_group (surface, group);
    5710               0 :         if (unlikely (status)) {
    5711               0 :             _cairo_pdf_smask_group_destroy (group);
    5712               0 :             return status;
    5713                 :         }
    5714                 : 
    5715               0 :         status = _cairo_pdf_surface_add_smask (surface, gstate_res);
    5716               0 :         if (unlikely (status))
    5717               0 :             return status;
    5718                 : 
    5719               0 :         status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
    5720               0 :         if (unlikely (status))
    5721               0 :             return status;
    5722                 : 
    5723               0 :         status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    5724               0 :         if (unlikely (status))
    5725               0 :             return status;
    5726                 : 
    5727               0 :         _cairo_output_stream_printf (surface->output,
    5728                 :                                      "q /s%d gs /x%d Do Q\n",
    5729                 :                                      gstate_res.id,
    5730                 :                                      group->group_res.id);
    5731                 :     } else {
    5732               0 :         status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, TRUE);
    5733               0 :         if (unlikely (status))
    5734               0 :             return status;
    5735                 : 
    5736               0 :         status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
    5737                 :                                               path,
    5738                 :                                               style,
    5739                 :                                               ctm,
    5740                 :                                               ctm_inverse);
    5741               0 :         if (unlikely (status))
    5742               0 :             return status;
    5743                 : 
    5744               0 :         status = _cairo_pdf_surface_unselect_pattern (surface);
    5745               0 :         if (unlikely (status))
    5746               0 :             return status;
    5747                 :     }
    5748                 : 
    5749               0 :     return _cairo_output_stream_get_status (surface->output);
    5750                 : }
    5751                 : 
    5752                 : static cairo_int_status_t
    5753               0 : _cairo_pdf_surface_fill (void                   *abstract_surface,
    5754                 :                          cairo_operator_t        op,
    5755                 :                          const cairo_pattern_t  *source,
    5756                 :                          cairo_path_fixed_t     *path,
    5757                 :                          cairo_fill_rule_t       fill_rule,
    5758                 :                          double                  tolerance,
    5759                 :                          cairo_antialias_t       antialias,
    5760                 :                          cairo_clip_t           *clip)
    5761                 : {
    5762               0 :     cairo_pdf_surface_t *surface = abstract_surface;
    5763                 :     cairo_status_t status;
    5764                 :     cairo_pdf_smask_group_t *group;
    5765                 :     cairo_pdf_resource_t pattern_res, gstate_res;
    5766                 :     cairo_composite_rectangles_t extents;
    5767                 : 
    5768                 :     cairo_rectangle_int_t rect;
    5769               0 :     rect.x = rect.y = 0;
    5770               0 :     rect.width = surface->width;
    5771               0 :     rect.height = surface->height;
    5772                 : 
    5773               0 :     status = _cairo_composite_rectangles_init_for_fill (&extents,
    5774                 :                                                         &rect,
    5775                 :                                                         op, source, path,
    5776                 :                                                         clip);
    5777               0 :     if (unlikely (status)) {
    5778               0 :         if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
    5779               0 :             return CAIRO_STATUS_SUCCESS;
    5780                 : 
    5781               0 :         return status;
    5782                 :     }
    5783                 : 
    5784                 :     /* use the more accurate extents */
    5785               0 :     if (extents.is_bounded) {
    5786               0 :         _cairo_path_fixed_fill_extents (path,
    5787                 :                                         fill_rule,
    5788                 :                                         tolerance,
    5789                 :                                         &extents.mask);
    5790                 : 
    5791               0 :         if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
    5792               0 :             return CAIRO_STATUS_SUCCESS;
    5793                 :     }
    5794                 : 
    5795               0 :     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
    5796               0 :         return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
    5797               0 :     } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
    5798               0 :         status = _cairo_pdf_surface_start_fallback (surface);
    5799               0 :         if (unlikely (status))
    5800               0 :             return status;
    5801                 :     }
    5802                 : 
    5803               0 :     assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
    5804                 : 
    5805               0 :     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
    5806               0 :     if (unlikely (status))
    5807               0 :         return status;
    5808                 : 
    5809               0 :     status = _cairo_pdf_surface_select_operator (surface, op);
    5810               0 :     if (unlikely (status))
    5811               0 :         return status;
    5812                 : 
    5813               0 :     if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
    5814               0 :         source->extend == CAIRO_EXTEND_NONE)
    5815                 :     {
    5816               0 :         status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    5817               0 :         if (unlikely (status))
    5818               0 :             return status;
    5819                 : 
    5820               0 :         _cairo_output_stream_printf (surface->output, "q\n");
    5821               0 :         status =  _cairo_pdf_operators_clip (&surface->pdf_operators,
    5822                 :                                              path,
    5823                 :                                              fill_rule);
    5824               0 :         if (unlikely (status))
    5825               0 :             return status;
    5826                 : 
    5827               0 :         status = _cairo_pdf_surface_paint_surface_pattern (surface,
    5828                 :                                                            (cairo_surface_pattern_t *) source);
    5829               0 :         if (unlikely (status))
    5830               0 :             return status;
    5831                 : 
    5832               0 :         _cairo_output_stream_printf (surface->output, "Q\n");
    5833               0 :         return _cairo_output_stream_get_status (surface->output);
    5834                 :     }
    5835                 : 
    5836               0 :     pattern_res.id = 0;
    5837               0 :     gstate_res.id = 0;
    5838               0 :     status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
    5839                 :                                                  &extents.bounded,
    5840                 :                                                  &pattern_res, &gstate_res);
    5841               0 :     if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
    5842               0 :         return CAIRO_STATUS_SUCCESS;
    5843               0 :     if (unlikely (status))
    5844               0 :         return status;
    5845                 : 
    5846               0 :     if (gstate_res.id != 0) {
    5847               0 :         group = _cairo_pdf_surface_create_smask_group (surface);
    5848               0 :         if (unlikely (group == NULL))
    5849               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    5850                 : 
    5851               0 :         group->operation = PDF_FILL;
    5852               0 :         status = _cairo_pattern_create_copy (&group->source, source);
    5853               0 :         if (unlikely (status)) {
    5854               0 :             _cairo_pdf_smask_group_destroy (group);
    5855               0 :             return status;
    5856                 :         }
    5857               0 :         group->source_res = pattern_res;
    5858               0 :         status = _cairo_path_fixed_init_copy (&group->path, path);
    5859               0 :         if (unlikely (status)) {
    5860               0 :             _cairo_pdf_smask_group_destroy (group);
    5861               0 :             return status;
    5862                 :         }
    5863                 : 
    5864               0 :         group->fill_rule = fill_rule;
    5865               0 :         status = _cairo_pdf_surface_add_smask_group (surface, group);
    5866               0 :         if (unlikely (status)) {
    5867               0 :             _cairo_pdf_smask_group_destroy (group);
    5868               0 :             return status;
    5869                 :         }
    5870                 : 
    5871               0 :         status = _cairo_pdf_surface_add_smask (surface, gstate_res);
    5872               0 :         if (unlikely (status))
    5873               0 :             return status;
    5874                 : 
    5875               0 :         status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
    5876               0 :         if (unlikely (status))
    5877               0 :             return status;
    5878                 : 
    5879               0 :         status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    5880               0 :         if (unlikely (status))
    5881               0 :             return status;
    5882                 : 
    5883               0 :         _cairo_output_stream_printf (surface->output,
    5884                 :                                      "q /s%d gs /x%d Do Q\n",
    5885                 :                                      gstate_res.id,
    5886                 :                                      group->group_res.id);
    5887                 :     } else {
    5888               0 :         status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
    5889               0 :         if (unlikely (status))
    5890               0 :             return status;
    5891                 : 
    5892               0 :         status = _cairo_pdf_operators_fill (&surface->pdf_operators,
    5893                 :                                             path,
    5894                 :                                             fill_rule);
    5895               0 :         if (unlikely (status))
    5896               0 :             return status;
    5897                 : 
    5898               0 :         status = _cairo_pdf_surface_unselect_pattern (surface);
    5899               0 :         if (unlikely (status))
    5900               0 :             return status;
    5901                 :     }
    5902                 : 
    5903               0 :     return _cairo_output_stream_get_status (surface->output);
    5904                 : }
    5905                 : 
    5906                 : static cairo_int_status_t
    5907               0 : _cairo_pdf_surface_fill_stroke (void                    *abstract_surface,
    5908                 :                                 cairo_operator_t         fill_op,
    5909                 :                                 const cairo_pattern_t   *fill_source,
    5910                 :                                 cairo_fill_rule_t        fill_rule,
    5911                 :                                 double                   fill_tolerance,
    5912                 :                                 cairo_antialias_t        fill_antialias,
    5913                 :                                 cairo_path_fixed_t      *path,
    5914                 :                                 cairo_operator_t         stroke_op,
    5915                 :                                 const cairo_pattern_t   *stroke_source,
    5916                 :                                 const cairo_stroke_style_t *stroke_style,
    5917                 :                                 const cairo_matrix_t    *stroke_ctm,
    5918                 :                                 const cairo_matrix_t    *stroke_ctm_inverse,
    5919                 :                                 double                   stroke_tolerance,
    5920                 :                                 cairo_antialias_t        stroke_antialias,
    5921                 :                                 cairo_clip_t            *clip)
    5922                 : {
    5923               0 :     cairo_pdf_surface_t *surface = abstract_surface;
    5924                 :     cairo_status_t status;
    5925                 :     cairo_pdf_resource_t fill_pattern_res, stroke_pattern_res, gstate_res;
    5926                 :     cairo_rectangle_int_t extents;
    5927                 : 
    5928                 :     /* During analysis we return unsupported and let the _fill and
    5929                 :      * _stroke functions that are on the fallback path do the analysis
    5930                 :      * for us. During render we may still encounter unsupported
    5931                 :      * combinations of fill/stroke patterns. However we can return
    5932                 :      * unsupported anytime to let the _fill and _stroke functions take
    5933                 :      * over.
    5934                 :      */
    5935               0 :     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
    5936               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    5937                 : 
    5938                 :     /* PDF rendering of fill-stroke is not the same as cairo when
    5939                 :      * either the fill or stroke is not opaque.
    5940                 :      */
    5941               0 :     if ( !_cairo_pattern_is_opaque (fill_source, NULL) ||
    5942               0 :          !_cairo_pattern_is_opaque (stroke_source, NULL))
    5943                 :     {
    5944               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    5945                 :     }
    5946                 : 
    5947               0 :     if (fill_op != stroke_op)
    5948               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    5949                 : 
    5950               0 :     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
    5951               0 :     if (unlikely (status))
    5952               0 :         return status;
    5953                 : 
    5954               0 :     status = _cairo_pdf_surface_select_operator (surface, fill_op);
    5955               0 :     if (unlikely (status))
    5956               0 :         return status;
    5957                 : 
    5958               0 :     status = _cairo_surface_fill_extents (&surface->base,
    5959                 :                                           fill_op, fill_source, path, fill_rule,
    5960                 :                                           fill_tolerance, fill_antialias,
    5961                 :                                           clip, &extents);
    5962               0 :     if (unlikely (status))
    5963               0 :         return status;
    5964                 : 
    5965                 : 
    5966               0 :     fill_pattern_res.id = 0;
    5967               0 :     gstate_res.id = 0;
    5968               0 :     status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source,
    5969                 :                                                  &extents,
    5970                 :                                                  &fill_pattern_res,
    5971                 :                                                  &gstate_res);
    5972               0 :     if (unlikely (status))
    5973               0 :         return status;
    5974                 : 
    5975               0 :     assert (gstate_res.id == 0);
    5976                 : 
    5977               0 :     status = _cairo_surface_stroke_extents (&surface->base,
    5978                 :                                             stroke_op, stroke_source, path,
    5979                 :                                             stroke_style, stroke_ctm, stroke_ctm_inverse,
    5980                 :                                             stroke_tolerance, stroke_antialias,
    5981                 :                                             clip, &extents);
    5982               0 :     if (unlikely (status))
    5983               0 :         return status;
    5984                 : 
    5985               0 :     stroke_pattern_res.id = 0;
    5986               0 :     gstate_res.id = 0;
    5987               0 :     status = _cairo_pdf_surface_add_pdf_pattern (surface,
    5988                 :                                                  stroke_source,
    5989                 :                                                  &extents,
    5990                 :                                                  &stroke_pattern_res,
    5991                 :                                                  &gstate_res);
    5992               0 :     if (unlikely (status))
    5993               0 :         return status;
    5994                 : 
    5995               0 :     assert (gstate_res.id == 0);
    5996                 : 
    5997                 :     /* As PDF has separate graphics state for fill and stroke we can
    5998                 :      * select both at the same time */
    5999               0 :     status = _cairo_pdf_surface_select_pattern (surface, fill_source,
    6000                 :                                                 fill_pattern_res, FALSE);
    6001               0 :     if (unlikely (status))
    6002               0 :         return status;
    6003                 : 
    6004               0 :     status = _cairo_pdf_surface_select_pattern (surface, stroke_source,
    6005                 :                                                 stroke_pattern_res, TRUE);
    6006               0 :     if (unlikely (status))
    6007               0 :         return status;
    6008                 : 
    6009               0 :     status = _cairo_pdf_operators_fill_stroke (&surface->pdf_operators,
    6010                 :                                                path,
    6011                 :                                                fill_rule,
    6012                 :                                                stroke_style,
    6013                 :                                                stroke_ctm,
    6014                 :                                                stroke_ctm_inverse);
    6015               0 :     if (unlikely (status))
    6016               0 :         return status;
    6017                 : 
    6018               0 :     status = _cairo_pdf_surface_unselect_pattern (surface);
    6019               0 :     if (unlikely (status))
    6020               0 :         return status;
    6021                 : 
    6022               0 :     return _cairo_output_stream_get_status (surface->output);
    6023                 : }
    6024                 : 
    6025                 : static cairo_bool_t
    6026               0 : _cairo_pdf_surface_has_show_text_glyphs (void                   *abstract_surface)
    6027                 : {
    6028               0 :     return TRUE;
    6029                 : }
    6030                 : 
    6031                 : static cairo_int_status_t
    6032               0 : _cairo_pdf_surface_show_text_glyphs (void                       *abstract_surface,
    6033                 :                                      cairo_operator_t            op,
    6034                 :                                      const cairo_pattern_t      *source,
    6035                 :                                      const char                 *utf8,
    6036                 :                                      int                         utf8_len,
    6037                 :                                      cairo_glyph_t              *glyphs,
    6038                 :                                      int                         num_glyphs,
    6039                 :                                      const cairo_text_cluster_t *clusters,
    6040                 :                                      int                         num_clusters,
    6041                 :                                      cairo_text_cluster_flags_t  cluster_flags,
    6042                 :                                      cairo_scaled_font_t        *scaled_font,
    6043                 :                                      cairo_clip_t               *clip)
    6044                 : {
    6045               0 :     cairo_pdf_surface_t *surface = abstract_surface;
    6046                 :     cairo_pdf_smask_group_t *group;
    6047                 :     cairo_pdf_resource_t pattern_res, gstate_res;
    6048                 :     cairo_composite_rectangles_t extents;
    6049                 :     cairo_bool_t overlap;
    6050                 :     cairo_status_t status;
    6051                 : 
    6052                 :     cairo_rectangle_int_t rect;
    6053               0 :     rect.x = rect.y = 0;
    6054               0 :     rect.width = surface->width;
    6055               0 :     rect.height = surface->height;
    6056                 : 
    6057               0 :     status = _cairo_composite_rectangles_init_for_glyphs (&extents,
    6058                 :                                                           &rect,
    6059                 :                                                           op, source,
    6060                 :                                                           scaled_font,
    6061                 :                                                           glyphs, num_glyphs,
    6062                 :                                                           clip,
    6063                 :                                                           &overlap);
    6064               0 :     if (unlikely (status)) {
    6065               0 :         if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
    6066               0 :             return CAIRO_STATUS_SUCCESS;
    6067                 : 
    6068               0 :         return status;
    6069                 :     }
    6070                 : 
    6071               0 :     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
    6072               0 :         return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
    6073                 : 
    6074               0 :     assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
    6075                 : 
    6076               0 :     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
    6077               0 :     if (unlikely (status))
    6078               0 :         return status;
    6079                 : 
    6080               0 :     pattern_res.id = 0;
    6081               0 :     gstate_res.id = 0;
    6082               0 :     status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
    6083                 :                                                  &extents.bounded,
    6084                 :                                                  &pattern_res, &gstate_res);
    6085               0 :     if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
    6086               0 :         return CAIRO_STATUS_SUCCESS;
    6087               0 :     if (unlikely (status))
    6088               0 :         return status;
    6089                 : 
    6090               0 :     status = _cairo_pdf_surface_select_operator (surface, op);
    6091               0 :     if (unlikely (status))
    6092               0 :         return status;
    6093                 : 
    6094               0 :     if (gstate_res.id != 0) {
    6095               0 :         group = _cairo_pdf_surface_create_smask_group (surface);
    6096               0 :         if (unlikely (group == NULL))
    6097               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    6098                 : 
    6099               0 :         group->operation = PDF_SHOW_GLYPHS;
    6100               0 :         status = _cairo_pattern_create_copy (&group->source, source);
    6101               0 :         if (unlikely (status)) {
    6102               0 :             _cairo_pdf_smask_group_destroy (group);
    6103               0 :             return status;
    6104                 :         }
    6105               0 :         group->source_res = pattern_res;
    6106                 : 
    6107               0 :         if (utf8_len) {
    6108               0 :             group->utf8 = malloc (utf8_len);
    6109               0 :             if (unlikely (group->utf8 == NULL)) {
    6110               0 :                 _cairo_pdf_smask_group_destroy (group);
    6111               0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    6112                 :             }
    6113               0 :             memcpy (group->utf8, utf8, utf8_len);
    6114                 :         }
    6115               0 :         group->utf8_len = utf8_len;
    6116                 : 
    6117               0 :         if (num_glyphs) {
    6118               0 :             group->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
    6119               0 :             if (unlikely (group->glyphs == NULL)) {
    6120               0 :                 _cairo_pdf_smask_group_destroy (group);
    6121               0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    6122                 :             }
    6123               0 :             memcpy (group->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
    6124                 :         }
    6125               0 :         group->num_glyphs = num_glyphs;
    6126                 : 
    6127               0 :         if (num_clusters) {
    6128               0 :             group->clusters = _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t));
    6129               0 :             if (unlikely (group->clusters == NULL)) {
    6130               0 :                 _cairo_pdf_smask_group_destroy (group);
    6131               0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    6132                 :             }
    6133               0 :             memcpy (group->clusters, clusters, sizeof (cairo_text_cluster_t) * num_clusters);
    6134                 :         }
    6135               0 :         group->num_clusters = num_clusters;
    6136                 : 
    6137               0 :         group->scaled_font = cairo_scaled_font_reference (scaled_font);
    6138               0 :         status = _cairo_pdf_surface_add_smask_group (surface, group);
    6139               0 :         if (unlikely (status)) {
    6140               0 :             _cairo_pdf_smask_group_destroy (group);
    6141               0 :             return status;
    6142                 :         }
    6143                 : 
    6144               0 :         status = _cairo_pdf_surface_add_smask (surface, gstate_res);
    6145               0 :         if (unlikely (status))
    6146               0 :             return status;
    6147                 : 
    6148               0 :         status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
    6149               0 :         if (unlikely (status))
    6150               0 :             return status;
    6151                 : 
    6152               0 :         status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    6153               0 :         if (unlikely (status))
    6154               0 :             return status;
    6155                 : 
    6156               0 :         _cairo_output_stream_printf (surface->output,
    6157                 :                                      "q /s%d gs /x%d Do Q\n",
    6158                 :                                      gstate_res.id,
    6159                 :                                      group->group_res.id);
    6160                 :     } else {
    6161               0 :         status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
    6162               0 :         if (unlikely (status))
    6163               0 :             return status;
    6164                 : 
    6165                 :         /* Each call to show_glyphs() with a transclucent pattern must
    6166                 :          * be in a separate text object otherwise overlapping text
    6167                 :          * from separate calls to show_glyphs will not composite with
    6168                 :          * each other. */
    6169               0 :         if (! _cairo_pattern_is_opaque (source, &extents.bounded)) {
    6170               0 :             status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    6171               0 :             if (unlikely (status))
    6172               0 :                 return status;
    6173                 :         }
    6174                 : 
    6175               0 :         status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
    6176                 :                                                         utf8, utf8_len,
    6177                 :                                                         glyphs, num_glyphs,
    6178                 :                                                         clusters, num_clusters,
    6179                 :                                                         cluster_flags,
    6180                 :                                                         scaled_font);
    6181               0 :         if (unlikely (status))
    6182               0 :             return status;
    6183                 : 
    6184               0 :         status = _cairo_pdf_surface_unselect_pattern (surface);
    6185               0 :         if (unlikely (status))
    6186               0 :             return status;
    6187                 :     }
    6188                 : 
    6189               0 :     return _cairo_output_stream_get_status (surface->output);
    6190                 : }
    6191                 : 
    6192                 : 
    6193                 : static void
    6194               0 : _cairo_pdf_surface_set_paginated_mode (void                     *abstract_surface,
    6195                 :                                        cairo_paginated_mode_t    paginated_mode)
    6196                 : {
    6197               0 :     cairo_pdf_surface_t *surface = abstract_surface;
    6198                 : 
    6199               0 :     surface->paginated_mode = paginated_mode;
    6200               0 : }
    6201                 : 
    6202                 : static const cairo_surface_backend_t cairo_pdf_surface_backend = {
    6203                 :     CAIRO_SURFACE_TYPE_PDF,
    6204                 :     NULL, /* create similar: handled by wrapper */
    6205                 :     _cairo_pdf_surface_finish,
    6206                 :     NULL, /* acquire_source_image */
    6207                 :     NULL, /* release_source_image */
    6208                 :     NULL, /* acquire_dest_image */
    6209                 :     NULL, /* release_dest_image */
    6210                 :     NULL, /* clone_similar */
    6211                 :     NULL, /* composite */
    6212                 :     NULL, /* fill_rectangles */
    6213                 :     NULL, /* composite_trapezoids */
    6214                 :     NULL, /* create_span_renderer */
    6215                 :     NULL, /* check_span_renderer */
    6216                 :     NULL,  /* _cairo_pdf_surface_copy_page */
    6217                 :     _cairo_pdf_surface_show_page,
    6218                 :     _cairo_pdf_surface_get_extents,
    6219                 :     NULL, /* old_show_glyphs */
    6220                 :     _cairo_pdf_surface_get_font_options,
    6221                 :     NULL, /* flush */
    6222                 :     NULL, /* mark_dirty_rectangle */
    6223                 :     NULL, /* scaled_font_fini */
    6224                 :     NULL, /* scaled_glyph_fini */
    6225                 : 
    6226                 :     /* Here are the drawing functions */
    6227                 : 
    6228                 :     _cairo_pdf_surface_paint,
    6229                 :     _cairo_pdf_surface_mask,
    6230                 :     _cairo_pdf_surface_stroke,
    6231                 :     _cairo_pdf_surface_fill,
    6232                 :     NULL, /* show_glyphs */
    6233                 :     NULL, /* snapshot */
    6234                 : 
    6235                 :     NULL, /* is_compatible */
    6236                 :     _cairo_pdf_surface_fill_stroke,
    6237                 :     NULL, /* create_solid_pattern_surface */
    6238                 :     NULL, /* can_repaint_solid_pattern_surface */
    6239                 :     _cairo_pdf_surface_has_show_text_glyphs,
    6240                 :     _cairo_pdf_surface_show_text_glyphs,
    6241                 : };
    6242                 : 
    6243                 : static const cairo_paginated_surface_backend_t
    6244                 : cairo_pdf_surface_paginated_backend = {
    6245                 :     _cairo_pdf_surface_start_page,
    6246                 :     _cairo_pdf_surface_set_paginated_mode,
    6247                 :     NULL, /* set_bounding_box */
    6248                 :     _cairo_pdf_surface_has_fallback_images,
    6249                 :     _cairo_pdf_surface_supports_fine_grained_fallbacks,
    6250                 : };

Generated by: LCOV version 1.7