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

          Line data    Source code
       1             : /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
       2             : /* cairo - a vector graphics library with display and print output
       3             :  *
       4             :  * Copyright © 2004 Red Hat, Inc
       5             :  * Copyright © 2006 Red Hat, Inc
       6             :  * Copyright © 2007, 2008 Adrian Johnson
       7             :  *
       8             :  * This library is free software; you can redistribute it and/or
       9             :  * modify it either under the terms of the GNU Lesser General Public
      10             :  * License version 2.1 as published by the Free Software Foundation
      11             :  * (the "LGPL") or, at your option, under the terms of the Mozilla
      12             :  * Public License Version 1.1 (the "MPL"). If you do not alter this
      13             :  * notice, a recipient may use your version of this file under either
      14             :  * the MPL or the LGPL.
      15             :  *
      16             :  * You should have received a copy of the LGPL along with this library
      17             :  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
      19             :  * You should have received a copy of the MPL along with this library
      20             :  * in the file COPYING-MPL-1.1
      21             :  *
      22             :  * The contents of this file are subject to the Mozilla Public License
      23             :  * Version 1.1 (the "License"); you may not use this file except in
      24             :  * compliance with the License. You may obtain a copy of the License at
      25             :  * http://www.mozilla.org/MPL/
      26             :  *
      27             :  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
      28             :  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
      29             :  * the specific language governing rights and limitations.
      30             :  *
      31             :  * The Original Code is the cairo graphics library.
      32             :  *
      33             :  * The Initial Developer of the Original Code is University of Southern
      34             :  * California.
      35             :  *
      36             :  * Contributor(s):
      37             :  *      Kristian Høgsberg <krh@redhat.com>
      38             :  *      Carl Worth <cworth@cworth.org>
      39             :  *      Adrian Johnson <ajohnson@redneon.com>
      40             :  */
      41             : 
      42             : #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           0 :                                                                    &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           0 :                                                                  &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           0 :                                                              &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           0 :                                                                    &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.13