Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
  2. /* cairo - a vector graphics library with display and print output
  3.  *
  4.  * Copyright © 2003 University of Southern California
  5.  * Copyright © 2005 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.  *      Carl D. Worth <cworth@cworth.org>
  38.  *      Kristian Høgsberg <krh@redhat.com>
  39.  *      Keith Packard <keithp@keithp.com>
  40.  *      Adrian Johnson <ajohnson@redneon.com>
  41.  */
  42.  
  43.  
  44. /*
  45.  * Design of the PS output:
  46.  *
  47.  * The PS output is harmonised with the PDF operations using PS procedures
  48.  * to emulate the PDF operators.
  49.  *
  50.  * This has a number of advantages:
  51.  *   1. A large chunk of code is shared between the PDF and PS backends.
  52.  *      See cairo-pdf-operators.
  53.  *   2. Using gs to do PS -> PDF and PDF -> PS will always work well.
  54.  */
  55.  
  56. #define _BSD_SOURCE /* for ctime_r(), snprintf(), strdup() */
  57. #include "cairoint.h"
  58.  
  59. #include "cairo-ps.h"
  60. #include "cairo-ps-surface-private.h"
  61.  
  62. #include "cairo-pdf-operators-private.h"
  63. #include "cairo-pdf-shading-private.h"
  64.  
  65. #include "cairo-array-private.h"
  66. #include "cairo-composite-rectangles-private.h"
  67. #include "cairo-default-context-private.h"
  68. #include "cairo-error-private.h"
  69. #include "cairo-image-surface-inline.h"
  70. #include "cairo-list-inline.h"
  71. #include "cairo-scaled-font-subsets-private.h"
  72. #include "cairo-paginated-private.h"
  73. #include "cairo-recording-surface-private.h"
  74. #include "cairo-surface-clipper-private.h"
  75. #include "cairo-surface-snapshot-inline.h"
  76. #include "cairo-surface-subsurface-private.h"
  77. #include "cairo-output-stream-private.h"
  78. #include "cairo-type3-glyph-surface-private.h"
  79. #include "cairo-image-info-private.h"
  80.  
  81. #include <stdio.h>
  82. #include <ctype.h>
  83. #include <time.h>
  84. #include <zlib.h>
  85. #include <errno.h>
  86.  
  87. #define DEBUG_PS 0
  88.  
  89. #if DEBUG_PS
  90. #define DEBUG_FALLBACK(s) \
  91.     fprintf (stderr, "%s::%d -- %s\n", __FUNCTION__, __LINE__, (s))
  92. #else
  93. #define DEBUG_FALLBACK(s)
  94. #endif
  95.  
  96. #ifndef HAVE_CTIME_R
  97. #define ctime_r(T, BUF) ctime (T)
  98. #endif
  99.  
  100. /**
  101.  * SECTION:cairo-ps
  102.  * @Title: PostScript Surfaces
  103.  * @Short_Description: Rendering PostScript documents
  104.  * @See_Also: #cairo_surface_t
  105.  *
  106.  * The PostScript surface is used to render cairo graphics to Adobe
  107.  * PostScript files and is a multi-page vector surface backend.
  108.  **/
  109.  
  110. /**
  111.  * CAIRO_HAS_PS_SURFACE:
  112.  *
  113.  * Defined if the PostScript surface backend is available.
  114.  * This macro can be used to conditionally compile backend-specific code.
  115.  *
  116.  * Since: 1.2
  117.  **/
  118.  
  119. typedef enum {
  120.     CAIRO_PS_COMPRESS_NONE,
  121.     CAIRO_PS_COMPRESS_LZW,
  122.     CAIRO_PS_COMPRESS_DEFLATE
  123.  } cairo_ps_compress_t;
  124.  
  125. static const cairo_surface_backend_t cairo_ps_surface_backend;
  126. static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend;
  127.  
  128. static cairo_bool_t
  129. _cairo_ps_surface_get_extents (void                    *abstract_surface,
  130.                                cairo_rectangle_int_t   *rectangle);
  131.  
  132. static const cairo_ps_level_t _cairo_ps_levels[] =
  133. {
  134.     CAIRO_PS_LEVEL_2,
  135.     CAIRO_PS_LEVEL_3
  136. };
  137.  
  138. #define CAIRO_PS_LEVEL_LAST ARRAY_LENGTH (_cairo_ps_levels)
  139.  
  140. static const char * _cairo_ps_level_strings[CAIRO_PS_LEVEL_LAST] =
  141. {
  142.     "PS Level 2",
  143.     "PS Level 3"
  144. };
  145.  
  146. static const char *_cairo_ps_supported_mime_types[] =
  147. {
  148.     CAIRO_MIME_TYPE_JPEG,
  149.     NULL
  150. };
  151.  
  152. typedef struct _cairo_page_standard_media {
  153.     const char *name;
  154.     int width;
  155.     int height;
  156. } cairo_page_standard_media_t;
  157.  
  158. static const cairo_page_standard_media_t _cairo_page_standard_media[] =
  159. {
  160.     { "A0",       2384, 3371 },
  161.     { "A1",       1685, 2384 },
  162.     { "A2",       1190, 1684 },
  163.     { "A3",        842, 1190 },
  164.     { "A4",        595,  842 },
  165.     { "A5",        420,  595 },
  166.     { "B4",        729, 1032 },
  167.     { "B5",        516,  729 },
  168.     { "Letter",    612,  792 },
  169.     { "Tabloid",   792, 1224 },
  170.     { "Ledger",   1224,  792 },
  171.     { "Legal",     612, 1008 },
  172.     { "Statement", 396,  612 },
  173.     { "Executive", 540,  720 },
  174.     { "Folio",     612,  936 },
  175.     { "Quarto",    610,  780 },
  176.     { "10x14",     720, 1008 },
  177. };
  178.  
  179. typedef struct _cairo_page_media {
  180.     char *name;
  181.     int width;
  182.     int height;
  183.     cairo_list_t link;
  184. } cairo_page_media_t;
  185.  
  186. static void
  187. _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
  188. {
  189.     char ctime_buf[26];
  190.     time_t now;
  191.     char **comments;
  192.     int i, num_comments;
  193.     int level;
  194.     const char *eps_header = "";
  195.     cairo_bool_t has_bbox;
  196.  
  197.     if (surface->has_creation_date)
  198.         now = surface->creation_date;
  199.     else
  200.         now = time (NULL);
  201.  
  202.     if (surface->ps_level_used == CAIRO_PS_LEVEL_2)
  203.         level = 2;
  204.     else
  205.         level = 3;
  206.  
  207.     if (surface->eps)
  208.         eps_header = " EPSF-3.0";
  209.  
  210.     _cairo_output_stream_printf (surface->final_stream,
  211.                                  "%%!PS-Adobe-3.0%s\n"
  212.                                  "%%%%Creator: cairo %s (http://cairographics.org)\n"
  213.                                  "%%%%CreationDate: %s"
  214.                                  "%%%%Pages: %d\n",
  215.                                  eps_header,
  216.                                  cairo_version_string (),
  217.                                  ctime_r (&now, ctime_buf),
  218.                                  surface->num_pages);
  219.  
  220.     _cairo_output_stream_printf (surface->final_stream,
  221.                                  "%%%%DocumentData: Clean7Bit\n"
  222.                                  "%%%%LanguageLevel: %d\n",
  223.                                  level);
  224.  
  225.     if (!cairo_list_is_empty (&surface->document_media)) {
  226.         cairo_page_media_t *page;
  227.         cairo_bool_t first = TRUE;
  228.  
  229.         cairo_list_foreach_entry (page, cairo_page_media_t, &surface->document_media, link) {
  230.             if (first) {
  231.                 _cairo_output_stream_printf (surface->final_stream,
  232.                                              "%%%%DocumentMedia: ");
  233.                 first = FALSE;
  234.             } else {
  235.                 _cairo_output_stream_printf (surface->final_stream,
  236.                                              "%%%%+ ");
  237.             }
  238.             _cairo_output_stream_printf (surface->final_stream,
  239.                                          "%s %d %d 0 () ()\n",
  240.                                          page->name,
  241.                                          page->width,
  242.                                          page->height);
  243.         }
  244.     }
  245.  
  246.     has_bbox = FALSE;
  247.     num_comments = _cairo_array_num_elements (&surface->dsc_header_comments);
  248.     comments = _cairo_array_index (&surface->dsc_header_comments, 0);
  249.     for (i = 0; i < num_comments; i++) {
  250.         _cairo_output_stream_printf (surface->final_stream,
  251.                                      "%s\n", comments[i]);
  252.         if (strncmp (comments[i], "%%BoundingBox:", 14) == 0)
  253.             has_bbox = TRUE;
  254.  
  255.         free (comments[i]);
  256.         comments[i] = NULL;
  257.     }
  258.  
  259.     if (!has_bbox) {
  260.         _cairo_output_stream_printf (surface->final_stream,
  261.                                      "%%%%BoundingBox: %d %d %d %d\n",
  262.                                      surface->bbox_x1,
  263.                                      surface->bbox_y1,
  264.                                      surface->bbox_x2,
  265.                                      surface->bbox_y2);
  266.     }
  267.  
  268.     _cairo_output_stream_printf (surface->final_stream,
  269.                                  "%%%%EndComments\n");
  270.  
  271.     _cairo_output_stream_printf (surface->final_stream,
  272.                                  "%%%%BeginProlog\n");
  273.  
  274.     if (surface->eps) {
  275.         _cairo_output_stream_printf (surface->final_stream,
  276.                                      "save\n"
  277.                                      "50 dict begin\n");
  278.     } else {
  279.         _cairo_output_stream_printf (surface->final_stream,
  280.                                      "/languagelevel where\n"
  281.                                      "{ pop languagelevel } { 1 } ifelse\n"
  282.                                      "%d lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto\n"
  283.                                      "  (This print job requires a PostScript Language Level %d printer.) show\n"
  284.                                      "  showpage quit } if\n",
  285.                                      level,
  286.                                      level);
  287.     }
  288.  
  289.     _cairo_output_stream_printf (surface->final_stream,
  290.                                  "/q { gsave } bind def\n"
  291.                                  "/Q { grestore } bind def\n"
  292.                                  "/cm { 6 array astore concat } bind def\n"
  293.                                  "/w { setlinewidth } bind def\n"
  294.                                  "/J { setlinecap } bind def\n"
  295.                                  "/j { setlinejoin } bind def\n"
  296.                                  "/M { setmiterlimit } bind def\n"
  297.                                  "/d { setdash } bind def\n"
  298.                                  "/m { moveto } bind def\n"
  299.                                  "/l { lineto } bind def\n"
  300.                                  "/c { curveto } bind def\n"
  301.                                  "/h { closepath } bind def\n"
  302.                                  "/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto\n"
  303.                                  "      0 exch rlineto 0 rlineto closepath } bind def\n"
  304.                                  "/S { stroke } bind def\n"
  305.                                  "/f { fill } bind def\n"
  306.                                  "/f* { eofill } bind def\n"
  307.                                  "/n { newpath } bind def\n"
  308.                                  "/W { clip } bind def\n"
  309.                                  "/W* { eoclip } bind def\n"
  310.                                  "/BT { } bind def\n"
  311.                                  "/ET { } bind def\n"
  312.                                  "/pdfmark where { pop globaldict /?pdfmark /exec load put }\n"
  313.                                  "    { globaldict begin /?pdfmark /pop load def /pdfmark\n"
  314.                                  "    /cleartomark load def end } ifelse\n"
  315.                                  "/BDC { mark 3 1 roll /BDC pdfmark } bind def\n"
  316.                                  "/EMC { mark /EMC pdfmark } bind def\n"
  317.                                  "/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def\n"
  318.                                  "/Tj { show currentpoint cairo_store_point } bind def\n"
  319.                                  "/TJ {\n"
  320.                                  "  {\n"
  321.                                  "    dup\n"
  322.                                  "    type /stringtype eq\n"
  323.                                  "    { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse\n"
  324.                                  "  } forall\n"
  325.                                  "  currentpoint cairo_store_point\n"
  326.                                  "} bind def\n"
  327.                                  "/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore\n"
  328.                                  "    cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def\n"
  329.                                  "/Tf { pop /cairo_font exch def /cairo_font_matrix where\n"
  330.                                  "      { pop cairo_selectfont } if } bind def\n"
  331.                                  "/Td { matrix translate cairo_font_matrix matrix concatmatrix dup\n"
  332.                                  "      /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point\n"
  333.                                  "      /cairo_font where { pop cairo_selectfont } if } bind def\n"
  334.                                  "/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def\n"
  335.                                  "      cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def\n"
  336.                                  "/g { setgray } bind def\n"
  337.                                  "/rg { setrgbcolor } bind def\n"
  338.                                  "/d1 { setcachedevice } bind def\n");
  339.  
  340.     _cairo_output_stream_printf (surface->final_stream,
  341.                                  "%%%%EndProlog\n");
  342.  
  343.     num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
  344.     if (num_comments) {
  345.         _cairo_output_stream_printf (surface->final_stream,
  346.                                      "%%%%BeginSetup\n");
  347.  
  348.         comments = _cairo_array_index (&surface->dsc_setup_comments, 0);
  349.         for (i = 0; i < num_comments; i++) {
  350.             _cairo_output_stream_printf (surface->final_stream,
  351.                                          "%s\n", comments[i]);
  352.             free (comments[i]);
  353.             comments[i] = NULL;
  354.         }
  355.  
  356.         _cairo_output_stream_printf (surface->final_stream,
  357.                                      "%%%%EndSetup\n");
  358.     }
  359. }
  360.  
  361. static cairo_status_t
  362. _cairo_ps_surface_emit_type1_font_subset (cairo_ps_surface_t            *surface,
  363.                                           cairo_scaled_font_subset_t    *font_subset)
  364.  
  365.  
  366. {
  367.     cairo_type1_subset_t subset;
  368.     cairo_status_t status;
  369.     int length;
  370.     char name[64];
  371.  
  372.     snprintf (name, sizeof name, "f-%d-%d",
  373.               font_subset->font_id, font_subset->subset_id);
  374.     status = _cairo_type1_subset_init (&subset, name, font_subset, TRUE);
  375.     if (unlikely (status))
  376.         return status;
  377.  
  378.     /* FIXME: Figure out document structure convention for fonts */
  379.  
  380. #if DEBUG_PS
  381.     _cairo_output_stream_printf (surface->final_stream,
  382.                                  "%% _cairo_ps_surface_emit_type1_font_subset\n");
  383. #endif
  384.  
  385.     length = subset.header_length + subset.data_length + subset.trailer_length;
  386.     _cairo_output_stream_write (surface->final_stream, subset.data, length);
  387.  
  388.     _cairo_type1_subset_fini (&subset);
  389.  
  390.     return CAIRO_STATUS_SUCCESS;
  391. }
  392.  
  393.  
  394. static cairo_status_t
  395. _cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t          *surface,
  396.                                             cairo_scaled_font_subset_t  *font_subset)
  397. {
  398.     cairo_type1_subset_t subset;
  399.     cairo_status_t status;
  400.     int length;
  401.     char name[64];
  402.  
  403.     snprintf (name, sizeof name, "f-%d-%d",
  404.               font_subset->font_id, font_subset->subset_id);
  405.     status = _cairo_type1_fallback_init_hex (&subset, name, font_subset);
  406.     if (unlikely (status))
  407.         return status;
  408.  
  409.     /* FIXME: Figure out document structure convention for fonts */
  410.  
  411. #if DEBUG_PS
  412.     _cairo_output_stream_printf (surface->final_stream,
  413.                                  "%% _cairo_ps_surface_emit_type1_font_fallback\n");
  414. #endif
  415.  
  416.     length = subset.header_length + subset.data_length + subset.trailer_length;
  417.     _cairo_output_stream_write (surface->final_stream, subset.data, length);
  418.  
  419.     _cairo_type1_fallback_fini (&subset);
  420.  
  421.     return CAIRO_STATUS_SUCCESS;
  422. }
  423.  
  424. static cairo_status_t
  425. _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t         *surface,
  426.                                              cairo_scaled_font_subset_t *font_subset)
  427.  
  428.  
  429. {
  430.     cairo_truetype_subset_t subset;
  431.     cairo_status_t status;
  432.     unsigned int i, begin, end;
  433.  
  434.     status = _cairo_truetype_subset_init_ps (&subset, font_subset);
  435.     if (unlikely (status))
  436.         return status;
  437.  
  438.     /* FIXME: Figure out document structure convention for fonts */
  439.  
  440. #if DEBUG_PS
  441.     _cairo_output_stream_printf (surface->final_stream,
  442.                                  "%% _cairo_ps_surface_emit_truetype_font_subset\n");
  443. #endif
  444.  
  445.     _cairo_output_stream_printf (surface->final_stream,
  446.                                  "11 dict begin\n"
  447.                                  "/FontType 42 def\n"
  448.                                  "/FontName /%s def\n"
  449.                                  "/PaintType 0 def\n"
  450.                                  "/FontMatrix [ 1 0 0 1 0 0 ] def\n"
  451.                                  "/FontBBox [ 0 0 0 0 ] def\n"
  452.                                  "/Encoding 256 array def\n"
  453.                                  "0 1 255 { Encoding exch /.notdef put } for\n",
  454.                                  subset.ps_name);
  455.  
  456.     /* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */
  457.  
  458.     if (font_subset->is_latin) {
  459.         for (i = 1; i < 256; i++) {
  460.             if (font_subset->latin_to_subset_glyph_index[i] > 0) {
  461.                 if (font_subset->glyph_names != NULL) {
  462.                     _cairo_output_stream_printf (surface->final_stream,
  463.                                                  "Encoding %d /%s put\n",
  464.                                                  i, font_subset->glyph_names[font_subset->latin_to_subset_glyph_index[i]]);
  465.                 } else {
  466.                     _cairo_output_stream_printf (surface->final_stream,
  467.                                                  "Encoding %d /g%ld put\n", i, font_subset->latin_to_subset_glyph_index[i]);
  468.                 }
  469.             }
  470.         }
  471.     } else {
  472.         for (i = 1; i < font_subset->num_glyphs; i++) {
  473.             if (font_subset->glyph_names != NULL) {
  474.                 _cairo_output_stream_printf (surface->final_stream,
  475.                                              "Encoding %d /%s put\n",
  476.                                              i, font_subset->glyph_names[i]);
  477.             } else {
  478.                 _cairo_output_stream_printf (surface->final_stream,
  479.                                              "Encoding %d /g%d put\n", i, i);
  480.             }
  481.         }
  482.     }
  483.  
  484.     _cairo_output_stream_printf (surface->final_stream,
  485.                                  "/CharStrings %d dict dup begin\n"
  486.                                  "/.notdef 0 def\n",
  487.                                  font_subset->num_glyphs);
  488.  
  489.     for (i = 1; i < font_subset->num_glyphs; i++) {
  490.         if (font_subset->glyph_names != NULL) {
  491.             _cairo_output_stream_printf (surface->final_stream,
  492.                                          "/%s %d def\n",
  493.                                          font_subset->glyph_names[i], i);
  494.         } else {
  495.             _cairo_output_stream_printf (surface->final_stream,
  496.                                          "/g%d %d def\n", i, i);
  497.         }
  498.     }
  499.  
  500.     _cairo_output_stream_printf (surface->final_stream,
  501.                                  "end readonly def\n");
  502.  
  503.     _cairo_output_stream_printf (surface->final_stream,
  504.                                  "/sfnts [\n");
  505.     begin = 0;
  506.     end = 0;
  507.     for (i = 0; i < subset.num_string_offsets; i++) {
  508.         end = subset.string_offsets[i];
  509.         _cairo_output_stream_printf (surface->final_stream,"<");
  510.         _cairo_output_stream_write_hex_string (surface->final_stream,
  511.                                                subset.data + begin, end - begin);
  512.         _cairo_output_stream_printf (surface->final_stream,"00>\n");
  513.         begin = end;
  514.     }
  515.     if (subset.data_length > end) {
  516.         _cairo_output_stream_printf (surface->final_stream,"<");
  517.         _cairo_output_stream_write_hex_string (surface->final_stream,
  518.                                                subset.data + end, subset.data_length - end);
  519.         _cairo_output_stream_printf (surface->final_stream,"00>\n");
  520.     }
  521.  
  522.     _cairo_output_stream_printf (surface->final_stream,
  523.                                  "] def\n"
  524.                                  "/f-%d-%d currentdict end definefont pop\n",
  525.                                  font_subset->font_id,
  526.                                  font_subset->subset_id);
  527.  
  528.     _cairo_truetype_subset_fini (&subset);
  529.  
  530.     return CAIRO_STATUS_SUCCESS;
  531. }
  532.  
  533. static cairo_int_status_t
  534. _cairo_ps_emit_imagemask (cairo_image_surface_t *image,
  535.                           cairo_output_stream_t *stream)
  536. {
  537.     uint8_t *row, *byte;
  538.     int rows, cols;
  539.  
  540.     /* The only image type supported by Type 3 fonts are 1-bit image
  541.      * masks */
  542.     assert (image->format == CAIRO_FORMAT_A1);
  543.  
  544.     _cairo_output_stream_printf (stream,
  545.                                  "<<\n"
  546.                                  "   /ImageType 1\n"
  547.                                  "   /Width %d\n"
  548.                                  "   /Height %d\n"
  549.                                  "   /ImageMatrix [%d 0 0 %d 0 %d]\n"
  550.                                  "   /Decode [1 0]\n"
  551.                                  "   /BitsPerComponent 1\n",
  552.                                  image->width,
  553.                                  image->height,
  554.                                  image->width,
  555.                                  -image->height,
  556.                                  image->height);
  557.  
  558.     _cairo_output_stream_printf (stream,
  559.                                  "   /DataSource {<\n   ");
  560.     for (row = image->data, rows = image->height; rows; row += image->stride, rows--) {
  561.         for (byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) {
  562.             uint8_t output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
  563.             _cairo_output_stream_printf (stream, "%02x ", output_byte);
  564.         }
  565.         _cairo_output_stream_printf (stream, "\n   ");
  566.     }
  567.     _cairo_output_stream_printf (stream, ">}\n>>\n");
  568.  
  569.     _cairo_output_stream_printf (stream,
  570.                                  "imagemask\n");
  571.  
  572.     return _cairo_output_stream_get_status (stream);
  573. }
  574.  
  575. static cairo_int_status_t
  576. _cairo_ps_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset,
  577.                                             void                       *closure)
  578. {
  579.     cairo_ps_surface_t *surface = closure;
  580.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  581.     unsigned int i;
  582.     cairo_surface_t *type3_surface;
  583.  
  584.     type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
  585.                                                        NULL,
  586.                                                        _cairo_ps_emit_imagemask,
  587.                                                        surface->font_subsets);
  588.  
  589.     for (i = 0; i < font_subset->num_glyphs; i++) {
  590.         status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
  591.                                                            font_subset->glyphs[i]);
  592.         if (unlikely (status))
  593.             break;
  594.  
  595.     }
  596.     cairo_surface_finish (type3_surface);
  597.     cairo_surface_destroy (type3_surface);
  598.  
  599.     return status;
  600. }
  601.  
  602. static cairo_status_t
  603. _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t            *surface,
  604.                                           cairo_scaled_font_subset_t    *font_subset)
  605.  
  606.  
  607. {
  608.     cairo_status_t status;
  609.     unsigned int i;
  610.     cairo_box_t font_bbox = {{0,0},{0,0}};
  611.     cairo_box_t bbox = {{0,0},{0,0}};
  612.     cairo_surface_t *type3_surface;
  613.     double width;
  614.  
  615.     if (font_subset->num_glyphs == 0)
  616.         return CAIRO_STATUS_SUCCESS;
  617.  
  618. #if DEBUG_PS
  619.     _cairo_output_stream_printf (surface->final_stream,
  620.                                  "%% _cairo_ps_surface_emit_type3_font_subset\n");
  621. #endif
  622.  
  623.     _cairo_output_stream_printf (surface->final_stream,
  624.                                  "8 dict begin\n"
  625.                                  "/FontType 3 def\n"
  626.                                  "/FontMatrix [1 0 0 1 0 0] def\n"
  627.                                  "/Encoding 256 array def\n"
  628.                                  "0 1 255 { Encoding exch /.notdef put } for\n");
  629.  
  630.     type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
  631.                                                        NULL,
  632.                                                        _cairo_ps_emit_imagemask,
  633.                                                        surface->font_subsets);
  634.     status = type3_surface->status;
  635.     if (unlikely (status))
  636.         return status;
  637.  
  638.     for (i = 0; i < font_subset->num_glyphs; i++) {
  639.         if (font_subset->glyph_names != NULL) {
  640.             _cairo_output_stream_printf (surface->final_stream,
  641.                                          "Encoding %d /%s put\n",
  642.                                          i, font_subset->glyph_names[i]);
  643.         } else {
  644.             _cairo_output_stream_printf (surface->final_stream,
  645.                                          "Encoding %d /g%d put\n", i, i);
  646.         }
  647.     }
  648.  
  649.     _cairo_output_stream_printf (surface->final_stream,
  650.                                  "/Glyphs [\n");
  651.  
  652.     for (i = 0; i < font_subset->num_glyphs; i++) {
  653.         _cairo_output_stream_printf (surface->final_stream,
  654.                                      "    { %% %d\n", i);
  655.         status = _cairo_type3_glyph_surface_emit_glyph (type3_surface,
  656.                                                         surface->final_stream,
  657.                                                         font_subset->glyphs[i],
  658.                                                         &bbox,
  659.                                                         &width);
  660.         if (unlikely (status))
  661.             break;
  662.  
  663.         _cairo_output_stream_printf (surface->final_stream,
  664.                                      "    }\n");
  665.         if (i == 0) {
  666.             font_bbox.p1.x = bbox.p1.x;
  667.             font_bbox.p1.y = bbox.p1.y;
  668.             font_bbox.p2.x = bbox.p2.x;
  669.             font_bbox.p2.y = bbox.p2.y;
  670.         } else {
  671.             if (bbox.p1.x < font_bbox.p1.x)
  672.                 font_bbox.p1.x = bbox.p1.x;
  673.             if (bbox.p1.y < font_bbox.p1.y)
  674.                 font_bbox.p1.y = bbox.p1.y;
  675.             if (bbox.p2.x > font_bbox.p2.x)
  676.                 font_bbox.p2.x = bbox.p2.x;
  677.             if (bbox.p2.y > font_bbox.p2.y)
  678.                 font_bbox.p2.y = bbox.p2.y;
  679.         }
  680.     }
  681.     cairo_surface_finish (type3_surface);
  682.     cairo_surface_destroy (type3_surface);
  683.     if (unlikely (status))
  684.         return status;
  685.  
  686.     _cairo_output_stream_printf (surface->final_stream,
  687.                                  "] def\n"
  688.                                  "/FontBBox [%f %f %f %f] def\n"
  689.                                  "/BuildChar {\n"
  690.                                  "  exch /Glyphs get\n"
  691.                                  "  exch get\n"
  692.                                  "  10 dict begin exec end\n"
  693.                                  "} bind def\n"
  694.                                  "currentdict\n"
  695.                                  "end\n"
  696.                                  "/f-%d-%d exch definefont pop\n",
  697.                                  _cairo_fixed_to_double (font_bbox.p1.x),
  698.                                  - _cairo_fixed_to_double (font_bbox.p2.y),
  699.                                  _cairo_fixed_to_double (font_bbox.p2.x),
  700.                                  - _cairo_fixed_to_double (font_bbox.p1.y),
  701.                                  font_subset->font_id,
  702.                                  font_subset->subset_id);
  703.  
  704.     return CAIRO_STATUS_SUCCESS;
  705. }
  706.  
  707. static cairo_int_status_t
  708. _cairo_ps_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset,
  709.                                             void                        *closure)
  710. {
  711.     cairo_ps_surface_t *surface = closure;
  712.     cairo_int_status_t status;
  713.  
  714.     status = _cairo_scaled_font_subset_create_glyph_names (font_subset);
  715.     if (_cairo_int_status_is_error (status))
  716.         return status;
  717.  
  718.     status = _cairo_ps_surface_emit_type1_font_subset (surface, font_subset);
  719.     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  720.         return status;
  721.  
  722.     status = _cairo_ps_surface_emit_truetype_font_subset (surface, font_subset);
  723.     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  724.         return status;
  725.  
  726.     status = _cairo_ps_surface_emit_type1_font_fallback (surface, font_subset);
  727.     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  728.         return status;
  729.  
  730.     ASSERT_NOT_REACHED;
  731.     return CAIRO_STATUS_SUCCESS;
  732. }
  733.  
  734. static cairo_int_status_t
  735. _cairo_ps_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset,
  736.                                            void                       *closure)
  737. {
  738.     cairo_ps_surface_t *surface = closure;
  739.     cairo_int_status_t status;
  740.  
  741.     status = _cairo_scaled_font_subset_create_glyph_names (font_subset);
  742.     if (_cairo_int_status_is_error (status))
  743.         return status;
  744.  
  745.     status = _cairo_ps_surface_emit_type3_font_subset (surface, font_subset);
  746.     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  747.         return status;
  748.  
  749.     ASSERT_NOT_REACHED;
  750.     return CAIRO_INT_STATUS_SUCCESS;
  751. }
  752.  
  753. static cairo_status_t
  754. _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface)
  755. {
  756.     cairo_status_t status;
  757.  
  758. #if DEBUG_PS
  759.     _cairo_output_stream_printf (surface->final_stream,
  760.                                  "%% _cairo_ps_surface_emit_font_subsets\n");
  761. #endif
  762.  
  763.     status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
  764.                                                       _cairo_ps_surface_analyze_user_font_subset,
  765.                                                       surface);
  766.     if (unlikely (status))
  767.         return status;
  768.  
  769.     status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
  770.                                                           _cairo_ps_surface_emit_unscaled_font_subset,
  771.                                                           surface);
  772.     if (unlikely (status))
  773.         return status;
  774.  
  775.     status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
  776.                                                         _cairo_ps_surface_emit_scaled_font_subset,
  777.                                                         surface);
  778.     if (unlikely (status))
  779.         return status;
  780.  
  781.     return _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
  782.                                                     _cairo_ps_surface_emit_scaled_font_subset,
  783.                                                     surface);
  784. }
  785.  
  786. static cairo_status_t
  787. _cairo_ps_surface_emit_body (cairo_ps_surface_t *surface)
  788. {
  789.     char    buf[4096];
  790.     int     n;
  791.  
  792.     if (ferror (surface->tmpfile) != 0)
  793.         return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
  794.  
  795. //    rewind (surface->tmpfile);
  796.     fseek(surface->tmpfile, 0, SEEK_SET);
  797.  
  798.     while ((n = fread (buf, 1, sizeof (buf), surface->tmpfile)) > 0)
  799.         _cairo_output_stream_write (surface->final_stream, buf, n);
  800.  
  801.     if (ferror (surface->tmpfile) != 0)
  802.         return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
  803.  
  804.     return CAIRO_STATUS_SUCCESS;
  805. }
  806.  
  807. static void
  808. _cairo_ps_surface_emit_footer (cairo_ps_surface_t *surface)
  809. {
  810.     _cairo_output_stream_printf (surface->final_stream,
  811.                                  "%%%%Trailer\n");
  812.  
  813.     if (surface->eps) {
  814.         _cairo_output_stream_printf (surface->final_stream,
  815.                                      "end restore\n");
  816.     }
  817.  
  818.     _cairo_output_stream_printf (surface->final_stream,
  819.                                  "%%%%EOF\n");
  820. }
  821.  
  822. static cairo_bool_t
  823. _path_covers_bbox (cairo_ps_surface_t *surface,
  824.                    cairo_path_fixed_t *path)
  825. {
  826.     cairo_box_t box;
  827.  
  828.     if (_cairo_path_fixed_is_box (path, &box)) {
  829.         cairo_rectangle_int_t rect;
  830.  
  831.         _cairo_box_round_to_rectangle (&box, &rect);
  832.  
  833.         /* skip trivial whole-page clips */
  834.         if (_cairo_rectangle_intersect (&rect, &surface->page_bbox)) {
  835.             if (rect.x == surface->page_bbox.x &&
  836.                 rect.width == surface->page_bbox.width &&
  837.                 rect.y == surface->page_bbox.y &&
  838.                 rect.height == surface->page_bbox.height)
  839.             {
  840.                 return TRUE;
  841.             }
  842.         }
  843.     }
  844.  
  845.     return FALSE;
  846. }
  847.  
  848. static cairo_status_t
  849. _cairo_ps_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
  850.                                                cairo_path_fixed_t *path,
  851.                                                cairo_fill_rule_t   fill_rule,
  852.                                                double               tolerance,
  853.                                                cairo_antialias_t   antialias)
  854. {
  855.     cairo_ps_surface_t *surface = cairo_container_of (clipper,
  856.                                                       cairo_ps_surface_t,
  857.                                                       clipper);
  858.     cairo_output_stream_t *stream = surface->stream;
  859.     cairo_status_t status;
  860.  
  861.     assert (surface->paginated_mode != CAIRO_PAGINATED_MODE_ANALYZE);
  862.  
  863. #if DEBUG_PS
  864.     _cairo_output_stream_printf (stream,
  865.                                  "%% _cairo_ps_surface_intersect_clip_path\n");
  866. #endif
  867.  
  868.     if (path == NULL) {
  869.         status = _cairo_pdf_operators_flush (&surface->pdf_operators);
  870.         if (unlikely (status))
  871.             return status;
  872.  
  873.         _cairo_output_stream_printf (stream, "Q q\n");
  874.  
  875.         surface->current_pattern_is_solid_color = FALSE;
  876.         _cairo_pdf_operators_reset (&surface->pdf_operators);
  877.  
  878.         return CAIRO_STATUS_SUCCESS;
  879.     }
  880.  
  881.     if (_path_covers_bbox (surface, path))
  882.         return CAIRO_STATUS_SUCCESS;
  883.  
  884.     return _cairo_pdf_operators_clip (&surface->pdf_operators,
  885.                                       path,
  886.                                       fill_rule);
  887. }
  888.  
  889. /* PLRM specifies a tolerance of 5 points when matching page sizes */
  890. static cairo_bool_t
  891. _ps_page_dimension_equal (int a, int b)
  892. {
  893.     return (abs (a - b) < 5);
  894. }
  895.  
  896. static const char *
  897. _cairo_ps_surface_get_page_media (cairo_ps_surface_t     *surface)
  898. {
  899.     int width, height, i;
  900.     char buf[50];
  901.     cairo_page_media_t *page;
  902.     const char *page_name;
  903.  
  904.     width = _cairo_lround (surface->width);
  905.     height = _cairo_lround (surface->height);
  906.  
  907.     /* search previously used page sizes */
  908.     cairo_list_foreach_entry (page, cairo_page_media_t, &surface->document_media, link) {
  909.         if (_ps_page_dimension_equal (width, page->width) &&
  910.             _ps_page_dimension_equal (height, page->height))
  911.             return page->name;
  912.     }
  913.  
  914.     /* search list of standard page sizes */
  915.     page_name = NULL;
  916.     for (i = 0; i < ARRAY_LENGTH (_cairo_page_standard_media); i++) {
  917.         if (_ps_page_dimension_equal (width, _cairo_page_standard_media[i].width) &&
  918.             _ps_page_dimension_equal (height, _cairo_page_standard_media[i].height))
  919.         {
  920.             page_name = _cairo_page_standard_media[i].name;
  921.             width = _cairo_page_standard_media[i].width;
  922.             height = _cairo_page_standard_media[i].height;
  923.             break;
  924.         }
  925.     }
  926.  
  927.     page = malloc (sizeof (cairo_page_media_t));
  928.     if (unlikely (page == NULL)) {
  929.         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
  930.         return NULL;
  931.     }
  932.  
  933.     if (page_name) {
  934.         page->name = strdup (page_name);
  935.     } else {
  936.         snprintf (buf, sizeof (buf), "%dx%dmm",
  937.                   (int) _cairo_lround (surface->width * 25.4/72),
  938.                   (int) _cairo_lround (surface->height * 25.4/72));
  939.         page->name = strdup (buf);
  940.     }
  941.  
  942.     if (unlikely (page->name == NULL)) {
  943.         free (page);
  944.         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
  945.         return NULL;
  946.     }
  947.  
  948.     page->width = width;
  949.     page->height = height;
  950.     cairo_list_add_tail (&page->link, &surface->document_media);
  951.  
  952.     return page->name;
  953. }
  954.  
  955. static cairo_surface_t *
  956. _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
  957.                                               double                 width,
  958.                                               double                 height)
  959. {
  960.     cairo_status_t status, status_ignored;
  961.     cairo_ps_surface_t *surface;
  962.  
  963.     surface = malloc (sizeof (cairo_ps_surface_t));
  964.     if (unlikely (surface == NULL)) {
  965.         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  966.         goto CLEANUP;
  967.     }
  968.  
  969.     _cairo_surface_init (&surface->base,
  970.                          &cairo_ps_surface_backend,
  971.                          NULL, /* device */
  972.                          CAIRO_CONTENT_COLOR_ALPHA);
  973.  
  974.     surface->final_stream = stream;
  975.  
  976.     surface->tmpfile = tmpfile ();
  977.     if (surface->tmpfile == NULL) {
  978.         switch (errno) {
  979.         case ENOMEM:
  980.             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  981.             break;
  982.         default:
  983.             status = _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR);
  984.             break;
  985.         }
  986.         goto CLEANUP_SURFACE;
  987.     }
  988.  
  989.     surface->stream = _cairo_output_stream_create_for_file (surface->tmpfile);
  990.     status = _cairo_output_stream_get_status (surface->stream);
  991.     if (unlikely (status))
  992.         goto CLEANUP_OUTPUT_STREAM;
  993.  
  994.     surface->font_subsets = _cairo_scaled_font_subsets_create_simple ();
  995.     if (unlikely (surface->font_subsets == NULL)) {
  996.         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  997.         goto CLEANUP_OUTPUT_STREAM;
  998.     }
  999.  
  1000.     _cairo_scaled_font_subsets_enable_latin_subset (surface->font_subsets, TRUE);
  1001.     surface->has_creation_date = FALSE;
  1002.     surface->eps = FALSE;
  1003.     surface->ps_level = CAIRO_PS_LEVEL_3;
  1004.     surface->ps_level_used = CAIRO_PS_LEVEL_2;
  1005.     surface->width  = width;
  1006.     surface->height = height;
  1007.     cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, height);
  1008.     surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
  1009.     surface->force_fallbacks = FALSE;
  1010.     surface->content = CAIRO_CONTENT_COLOR_ALPHA;
  1011.     surface->use_string_datasource = FALSE;
  1012.     surface->current_pattern_is_solid_color = FALSE;
  1013.  
  1014.     surface->page_bbox.x = 0;
  1015.     surface->page_bbox.y = 0;
  1016.     surface->page_bbox.width  = width;
  1017.     surface->page_bbox.height = height;
  1018.  
  1019.     _cairo_surface_clipper_init (&surface->clipper,
  1020.                                  _cairo_ps_surface_clipper_intersect_clip_path);
  1021.  
  1022.     _cairo_pdf_operators_init (&surface->pdf_operators,
  1023.                                surface->stream,
  1024.                                &surface->cairo_to_ps,
  1025.                                surface->font_subsets);
  1026.     surface->num_pages = 0;
  1027.  
  1028.     cairo_list_init (&surface->document_media);
  1029.     _cairo_array_init (&surface->dsc_header_comments, sizeof (char *));
  1030.     _cairo_array_init (&surface->dsc_setup_comments, sizeof (char *));
  1031.     _cairo_array_init (&surface->dsc_page_setup_comments, sizeof (char *));
  1032.  
  1033.     surface->dsc_comment_target = &surface->dsc_header_comments;
  1034.  
  1035.     surface->paginated_surface = _cairo_paginated_surface_create (
  1036.                                            &surface->base,
  1037.                                            CAIRO_CONTENT_COLOR_ALPHA,
  1038.                                            &cairo_ps_surface_paginated_backend);
  1039.     status = surface->paginated_surface->status;
  1040.     if (status == CAIRO_STATUS_SUCCESS) {
  1041.         /* paginated keeps the only reference to surface now, drop ours */
  1042.         cairo_surface_destroy (&surface->base);
  1043.         return surface->paginated_surface;
  1044.     }
  1045.  
  1046.     _cairo_scaled_font_subsets_destroy (surface->font_subsets);
  1047.  CLEANUP_OUTPUT_STREAM:
  1048.     status_ignored = _cairo_output_stream_destroy (surface->stream);
  1049.     fclose (surface->tmpfile);
  1050.  CLEANUP_SURFACE:
  1051.     free (surface);
  1052.  CLEANUP:
  1053.     /* destroy stream on behalf of caller */
  1054.     status_ignored = _cairo_output_stream_destroy (stream);
  1055.  
  1056.     return _cairo_surface_create_in_error (status);
  1057. }
  1058.  
  1059. /**
  1060.  * cairo_ps_surface_create:
  1061.  * @filename: a filename for the PS output (must be writable), %NULL may be
  1062.  *            used to specify no output. This will generate a PS surface that
  1063.  *            may be queried and used as a source, without generating a
  1064.  *            temporary file.
  1065.  * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
  1066.  * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
  1067.  *
  1068.  * Creates a PostScript surface of the specified size in points to be
  1069.  * written to @filename. See cairo_ps_surface_create_for_stream() for
  1070.  * a more flexible mechanism for handling the PostScript output than
  1071.  * simply writing it to a named file.
  1072.  *
  1073.  * Note that the size of individual pages of the PostScript output can
  1074.  * vary. See cairo_ps_surface_set_size().
  1075.  *
  1076.  * Return value: a pointer to the newly created surface. The caller
  1077.  * owns the surface and should call cairo_surface_destroy() when done
  1078.  * with it.
  1079.  *
  1080.  * This function always returns a valid pointer, but it will return a
  1081.  * pointer to a "nil" surface if an error such as out of memory
  1082.  * occurs. You can use cairo_surface_status() to check for this.
  1083.  *
  1084.  * Since: 1.2
  1085.  **/
  1086. cairo_surface_t *
  1087. cairo_ps_surface_create (const char             *filename,
  1088.                          double                  width_in_points,
  1089.                          double                  height_in_points)
  1090. {
  1091.     cairo_output_stream_t *stream;
  1092.  
  1093.     stream = _cairo_output_stream_create_for_filename (filename);
  1094.     if (_cairo_output_stream_get_status (stream))
  1095.         return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream));
  1096.  
  1097.     return _cairo_ps_surface_create_for_stream_internal (stream,
  1098.                                                          width_in_points,
  1099.                                                          height_in_points);
  1100. }
  1101.  
  1102. /**
  1103.  * cairo_ps_surface_create_for_stream:
  1104.  * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL
  1105.  *              to indicate a no-op @write_func. With a no-op @write_func,
  1106.  *              the surface may be queried or used as a source without
  1107.  *              generating any temporary files.
  1108.  * @closure: the closure argument for @write_func
  1109.  * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
  1110.  * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
  1111.  *
  1112.  * Creates a PostScript surface of the specified size in points to be
  1113.  * written incrementally to the stream represented by @write_func and
  1114.  * @closure. See cairo_ps_surface_create() for a more convenient way
  1115.  * to simply direct the PostScript output to a named file.
  1116.  *
  1117.  * Note that the size of individual pages of the PostScript
  1118.  * output can vary. See cairo_ps_surface_set_size().
  1119.  *
  1120.  * Return value: a pointer to the newly created surface. The caller
  1121.  * owns the surface and should call cairo_surface_destroy() when done
  1122.  * with it.
  1123.  *
  1124.  * This function always returns a valid pointer, but it will return a
  1125.  * pointer to a "nil" surface if an error such as out of memory
  1126.  * occurs. You can use cairo_surface_status() to check for this.
  1127.  *
  1128.  * Since: 1.2
  1129.  **/
  1130. cairo_surface_t *
  1131. cairo_ps_surface_create_for_stream (cairo_write_func_t  write_func,
  1132.                                     void               *closure,
  1133.                                     double              width_in_points,
  1134.                                     double              height_in_points)
  1135. {
  1136.     cairo_output_stream_t *stream;
  1137.  
  1138.     stream = _cairo_output_stream_create (write_func, NULL, closure);
  1139.     if (_cairo_output_stream_get_status (stream))
  1140.         return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream));
  1141.  
  1142.     return _cairo_ps_surface_create_for_stream_internal (stream,
  1143.                                                          width_in_points,
  1144.                                                          height_in_points);
  1145. }
  1146.  
  1147. static cairo_bool_t
  1148. _cairo_surface_is_ps (cairo_surface_t *surface)
  1149. {
  1150.     return surface->backend == &cairo_ps_surface_backend;
  1151. }
  1152.  
  1153. /* If the abstract_surface is a paginated surface, and that paginated
  1154.  * surface's target is a ps_surface, then set ps_surface to that
  1155.  * target. Otherwise return FALSE.
  1156.  */
  1157. static cairo_bool_t
  1158. _extract_ps_surface (cairo_surface_t     *surface,
  1159.                      cairo_bool_t         set_error_on_failure,
  1160.                      cairo_ps_surface_t **ps_surface)
  1161. {
  1162.     cairo_surface_t *target;
  1163.  
  1164.     if (surface->status)
  1165.         return FALSE;
  1166.     if (surface->finished) {
  1167.         if (set_error_on_failure)
  1168.             _cairo_surface_set_error (surface,
  1169.                                       _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
  1170.         return FALSE;
  1171.     }
  1172.  
  1173.     if (! _cairo_surface_is_paginated (surface)) {
  1174.         if (set_error_on_failure)
  1175.             _cairo_surface_set_error (surface,
  1176.                                       _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
  1177.         return FALSE;
  1178.     }
  1179.  
  1180.     target = _cairo_paginated_surface_get_target (surface);
  1181.     if (target->status) {
  1182.         if (set_error_on_failure)
  1183.             _cairo_surface_set_error (surface, target->status);
  1184.         return FALSE;
  1185.     }
  1186.     if (target->finished) {
  1187.         if (set_error_on_failure)
  1188.             _cairo_surface_set_error (surface,
  1189.                                       _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
  1190.         return FALSE;
  1191.     }
  1192.  
  1193.     if (! _cairo_surface_is_ps (target)) {
  1194.         if (set_error_on_failure)
  1195.             _cairo_surface_set_error (surface,
  1196.                                       _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
  1197.         return FALSE;
  1198.     }
  1199.  
  1200.     *ps_surface = (cairo_ps_surface_t *) target;
  1201.     return TRUE;
  1202. }
  1203.  
  1204. /**
  1205.  * cairo_ps_surface_restrict_to_level:
  1206.  * @surface: a PostScript #cairo_surface_t
  1207.  * @level: PostScript level
  1208.  *
  1209.  * Restricts the generated PostSript file to @level. See
  1210.  * cairo_ps_get_levels() for a list of available level values that
  1211.  * can be used here.
  1212.  *
  1213.  * This function should only be called before any drawing operations
  1214.  * have been performed on the given surface. The simplest way to do
  1215.  * this is to call this function immediately after creating the
  1216.  * surface.
  1217.  *
  1218.  * Since: 1.6
  1219.  **/
  1220. void
  1221. cairo_ps_surface_restrict_to_level (cairo_surface_t  *surface,
  1222.                                     cairo_ps_level_t  level)
  1223. {
  1224.     cairo_ps_surface_t *ps_surface = NULL;
  1225.  
  1226.     if (! _extract_ps_surface (surface, TRUE, &ps_surface))
  1227.         return;
  1228.  
  1229.     if (level < CAIRO_PS_LEVEL_LAST)
  1230.         ps_surface->ps_level = level;
  1231. }
  1232.  
  1233. /**
  1234.  * cairo_ps_get_levels:
  1235.  * @levels: supported level list
  1236.  * @num_levels: list length
  1237.  *
  1238.  * Used to retrieve the list of supported levels. See
  1239.  * cairo_ps_surface_restrict_to_level().
  1240.  *
  1241.  * Since: 1.6
  1242.  **/
  1243. void
  1244. cairo_ps_get_levels (cairo_ps_level_t const     **levels,
  1245.                      int                         *num_levels)
  1246. {
  1247.     if (levels != NULL)
  1248.         *levels = _cairo_ps_levels;
  1249.  
  1250.     if (num_levels != NULL)
  1251.         *num_levels = CAIRO_PS_LEVEL_LAST;
  1252. }
  1253.  
  1254. /**
  1255.  * cairo_ps_level_to_string:
  1256.  * @level: a level id
  1257.  *
  1258.  * Get the string representation of the given @level id. This function
  1259.  * will return %NULL if @level id isn't valid. See cairo_ps_get_levels()
  1260.  * for a way to get the list of valid level ids.
  1261.  *
  1262.  * Return value: the string associated to given level.
  1263.  *
  1264.  * Since: 1.6
  1265.  **/
  1266. const char *
  1267. cairo_ps_level_to_string (cairo_ps_level_t level)
  1268. {
  1269.     if (level >= CAIRO_PS_LEVEL_LAST)
  1270.         return NULL;
  1271.  
  1272.     return _cairo_ps_level_strings[level];
  1273. }
  1274.  
  1275. /**
  1276.  * cairo_ps_surface_set_eps:
  1277.  * @surface: a PostScript #cairo_surface_t
  1278.  * @eps: %TRUE to output EPS format PostScript
  1279.  *
  1280.  * If @eps is %TRUE, the PostScript surface will output Encapsulated
  1281.  * PostScript.
  1282.  *
  1283.  * This function should only be called before any drawing operations
  1284.  * have been performed on the current page. The simplest way to do
  1285.  * this is to call this function immediately after creating the
  1286.  * surface. An Encapsulated PostScript file should never contain more
  1287.  * than one page.
  1288.  *
  1289.  * Since: 1.6
  1290.  **/
  1291. void
  1292. cairo_ps_surface_set_eps (cairo_surface_t       *surface,
  1293.                           cairo_bool_t           eps)
  1294. {
  1295.     cairo_ps_surface_t *ps_surface = NULL;
  1296.  
  1297.     if (! _extract_ps_surface (surface, TRUE, &ps_surface))
  1298.         return;
  1299.  
  1300.     ps_surface->eps = eps;
  1301. }
  1302.  
  1303. /**
  1304.  * cairo_ps_surface_get_eps:
  1305.  * @surface: a PostScript #cairo_surface_t
  1306.  *
  1307.  * Check whether the PostScript surface will output Encapsulated PostScript.
  1308.  *
  1309.  * Return value: %TRUE if the surface will output Encapsulated PostScript.
  1310.  *
  1311.  * Since: 1.6
  1312.  **/
  1313. cairo_public cairo_bool_t
  1314. cairo_ps_surface_get_eps (cairo_surface_t       *surface)
  1315. {
  1316.     cairo_ps_surface_t *ps_surface = NULL;
  1317.  
  1318.     if (! _extract_ps_surface (surface, FALSE, &ps_surface))
  1319.         return FALSE;
  1320.  
  1321.     return ps_surface->eps;
  1322. }
  1323.  
  1324. /**
  1325.  * cairo_ps_surface_set_size:
  1326.  * @surface: a PostScript #cairo_surface_t
  1327.  * @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
  1328.  * @height_in_points: new surface height, in points (1 point == 1/72.0 inch)
  1329.  *
  1330.  * Changes the size of a PostScript surface for the current (and
  1331.  * subsequent) pages.
  1332.  *
  1333.  * This function should only be called before any drawing operations
  1334.  * have been performed on the current page. The simplest way to do
  1335.  * this is to call this function immediately after creating the
  1336.  * surface or immediately after completing a page with either
  1337.  * cairo_show_page() or cairo_copy_page().
  1338.  *
  1339.  * Since: 1.2
  1340.  **/
  1341. void
  1342. cairo_ps_surface_set_size (cairo_surface_t      *surface,
  1343.                            double                width_in_points,
  1344.                            double                height_in_points)
  1345. {
  1346.     cairo_ps_surface_t *ps_surface = NULL;
  1347.     cairo_status_t status;
  1348.  
  1349.     if (! _extract_ps_surface (surface, TRUE, &ps_surface))
  1350.         return;
  1351.  
  1352.     ps_surface->width = width_in_points;
  1353.     ps_surface->height = height_in_points;
  1354.     cairo_matrix_init (&ps_surface->cairo_to_ps, 1, 0, 0, -1, 0, height_in_points);
  1355.     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface->pdf_operators,
  1356.                                                   &ps_surface->cairo_to_ps);
  1357.     status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface,
  1358.                                                 width_in_points,
  1359.                                                 height_in_points);
  1360.     if (status)
  1361.         status = _cairo_surface_set_error (surface, status);
  1362. }
  1363.  
  1364. /**
  1365.  * cairo_ps_surface_dsc_comment:
  1366.  * @surface: a PostScript #cairo_surface_t
  1367.  * @comment: a comment string to be emitted into the PostScript output
  1368.  *
  1369.  * Emit a comment into the PostScript output for the given surface.
  1370.  *
  1371.  * The comment is expected to conform to the PostScript Language
  1372.  * Document Structuring Conventions (DSC). Please see that manual for
  1373.  * details on the available comments and their meanings. In
  1374.  * particular, the \%\%IncludeFeature comment allows a
  1375.  * device-independent means of controlling printer device features. So
  1376.  * the PostScript Printer Description Files Specification will also be
  1377.  * a useful reference.
  1378.  *
  1379.  * The comment string must begin with a percent character (\%) and the
  1380.  * total length of the string (including any initial percent
  1381.  * characters) must not exceed 255 characters. Violating either of
  1382.  * these conditions will place @surface into an error state. But
  1383.  * beyond these two conditions, this function will not enforce
  1384.  * conformance of the comment with any particular specification.
  1385.  *
  1386.  * The comment string should not have a trailing newline.
  1387.  *
  1388.  * The DSC specifies different sections in which particular comments
  1389.  * can appear. This function provides for comments to be emitted
  1390.  * within three sections: the header, the Setup section, and the
  1391.  * PageSetup section.  Comments appearing in the first two sections
  1392.  * apply to the entire document while comments in the BeginPageSetup
  1393.  * section apply only to a single page.
  1394.  *
  1395.  * For comments to appear in the header section, this function should
  1396.  * be called after the surface is created, but before a call to
  1397.  * cairo_ps_surface_dsc_begin_setup().
  1398.  *
  1399.  * For comments to appear in the Setup section, this function should
  1400.  * be called after a call to cairo_ps_surface_dsc_begin_setup() but
  1401.  * before a call to cairo_ps_surface_dsc_begin_page_setup().
  1402.  *
  1403.  * For comments to appear in the PageSetup section, this function
  1404.  * should be called after a call to
  1405.  * cairo_ps_surface_dsc_begin_page_setup().
  1406.  *
  1407.  * Note that it is only necessary to call
  1408.  * cairo_ps_surface_dsc_begin_page_setup() for the first page of any
  1409.  * surface. After a call to cairo_show_page() or cairo_copy_page()
  1410.  * comments are unambiguously directed to the PageSetup section of the
  1411.  * current page. But it doesn't hurt to call this function at the
  1412.  * beginning of every page as that consistency may make the calling
  1413.  * code simpler.
  1414.  *
  1415.  * As a final note, cairo automatically generates several comments on
  1416.  * its own. As such, applications must not manually generate any of
  1417.  * the following comments:
  1418.  *
  1419.  * Header section: \%!PS-Adobe-3.0, \%\%Creator, \%\%CreationDate, \%\%Pages,
  1420.  * \%\%BoundingBox, \%\%DocumentData, \%\%LanguageLevel, \%\%EndComments.
  1421.  *
  1422.  * Setup section: \%\%BeginSetup, \%\%EndSetup
  1423.  *
  1424.  * PageSetup section: \%\%BeginPageSetup, \%\%PageBoundingBox, \%\%EndPageSetup.
  1425.  *
  1426.  * Other sections: \%\%BeginProlog, \%\%EndProlog, \%\%Page, \%\%Trailer, \%\%EOF
  1427.  *
  1428.  * Here is an example sequence showing how this function might be used:
  1429.  *
  1430.  * <informalexample><programlisting>
  1431.  * cairo_surface_t *surface = cairo_ps_surface_create (filename, width, height);
  1432.  * ...
  1433.  * cairo_ps_surface_dsc_comment (surface, "%%Title: My excellent document");
  1434.  * cairo_ps_surface_dsc_comment (surface, "%%Copyright: Copyright (C) 2006 Cairo Lover")
  1435.  * ...
  1436.  * cairo_ps_surface_dsc_begin_setup (surface);
  1437.  * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor White");
  1438.  * ...
  1439.  * cairo_ps_surface_dsc_begin_page_setup (surface);
  1440.  * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A3");
  1441.  * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *InputSlot LargeCapacity");
  1442.  * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaType Glossy");
  1443.  * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor Blue");
  1444.  * ... draw to first page here ..
  1445.  * cairo_show_page (cr);
  1446.  * ...
  1447.  * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A5");
  1448.  * ...
  1449.  * </programlisting></informalexample>
  1450.  *
  1451.  * Since: 1.2
  1452.  **/
  1453. void
  1454. cairo_ps_surface_dsc_comment (cairo_surface_t   *surface,
  1455.                               const char        *comment)
  1456. {
  1457.     cairo_ps_surface_t *ps_surface = NULL;
  1458.     cairo_status_t status;
  1459.     char *comment_copy;
  1460.  
  1461.     if (! _extract_ps_surface (surface, TRUE, &ps_surface))
  1462.         return;
  1463.  
  1464.     /* A couple of sanity checks on the comment value. */
  1465.     if (comment == NULL) {
  1466.         status = _cairo_surface_set_error (surface, CAIRO_STATUS_NULL_POINTER);
  1467.         return;
  1468.     }
  1469.  
  1470.     if (comment[0] != '%' || strlen (comment) > 255) {
  1471.         status = _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_DSC_COMMENT);
  1472.         return;
  1473.     }
  1474.  
  1475.     /* Then, copy the comment and store it in the appropriate array. */
  1476.     comment_copy = strdup (comment);
  1477.     if (unlikely (comment_copy == NULL)) {
  1478.         status = _cairo_surface_set_error (surface, CAIRO_STATUS_NO_MEMORY);
  1479.         return;
  1480.     }
  1481.  
  1482.     status = _cairo_array_append (ps_surface->dsc_comment_target, &comment_copy);
  1483.     if (unlikely (status)) {
  1484.         free (comment_copy);
  1485.         status = _cairo_surface_set_error (surface, status);
  1486.         return;
  1487.     }
  1488. }
  1489.  
  1490. /**
  1491.  * cairo_ps_surface_dsc_begin_setup:
  1492.  * @surface: a PostScript #cairo_surface_t
  1493.  *
  1494.  * This function indicates that subsequent calls to
  1495.  * cairo_ps_surface_dsc_comment() should direct comments to the Setup
  1496.  * section of the PostScript output.
  1497.  *
  1498.  * This function should be called at most once per surface, and must
  1499.  * be called before any call to cairo_ps_surface_dsc_begin_page_setup()
  1500.  * and before any drawing is performed to the surface.
  1501.  *
  1502.  * See cairo_ps_surface_dsc_comment() for more details.
  1503.  *
  1504.  * Since: 1.2
  1505.  **/
  1506. void
  1507. cairo_ps_surface_dsc_begin_setup (cairo_surface_t *surface)
  1508. {
  1509.     cairo_ps_surface_t *ps_surface = NULL;
  1510.  
  1511.     if (! _extract_ps_surface (surface, TRUE, &ps_surface))
  1512.         return;
  1513.  
  1514.     if (ps_surface->dsc_comment_target == &ps_surface->dsc_header_comments)
  1515.         ps_surface->dsc_comment_target = &ps_surface->dsc_setup_comments;
  1516. }
  1517.  
  1518. /**
  1519.  * cairo_ps_surface_dsc_begin_page_setup:
  1520.  * @surface: a PostScript #cairo_surface_t
  1521.  *
  1522.  * This function indicates that subsequent calls to
  1523.  * cairo_ps_surface_dsc_comment() should direct comments to the
  1524.  * PageSetup section of the PostScript output.
  1525.  *
  1526.  * This function call is only needed for the first page of a
  1527.  * surface. It should be called after any call to
  1528.  * cairo_ps_surface_dsc_begin_setup() and before any drawing is
  1529.  * performed to the surface.
  1530.  *
  1531.  * See cairo_ps_surface_dsc_comment() for more details.
  1532.  *
  1533.  * Since: 1.2
  1534.  **/
  1535. void
  1536. cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface)
  1537. {
  1538.     cairo_ps_surface_t *ps_surface = NULL;
  1539.  
  1540.     if (! _extract_ps_surface (surface, TRUE, &ps_surface))
  1541.         return;
  1542.  
  1543.     if (ps_surface->dsc_comment_target == &ps_surface->dsc_header_comments ||
  1544.         ps_surface->dsc_comment_target == &ps_surface->dsc_setup_comments)
  1545.     {
  1546.         ps_surface->dsc_comment_target = &ps_surface->dsc_page_setup_comments;
  1547.     }
  1548. }
  1549.  
  1550. static cairo_status_t
  1551. _cairo_ps_surface_finish (void *abstract_surface)
  1552. {
  1553.     cairo_status_t status, status2;
  1554.     cairo_ps_surface_t *surface = abstract_surface;
  1555.     int i, num_comments;
  1556.     char **comments;
  1557.  
  1558.     status = surface->base.status;
  1559.     if (unlikely (status))
  1560.         goto CLEANUP;
  1561.  
  1562.     _cairo_ps_surface_emit_header (surface);
  1563.  
  1564.     status = _cairo_ps_surface_emit_font_subsets (surface);
  1565.     if (unlikely (status))
  1566.         goto CLEANUP;
  1567.  
  1568.     status = _cairo_ps_surface_emit_body (surface);
  1569.     if (unlikely (status))
  1570.         goto CLEANUP;
  1571.  
  1572.     _cairo_ps_surface_emit_footer (surface);
  1573.  
  1574. CLEANUP:
  1575.     _cairo_scaled_font_subsets_destroy (surface->font_subsets);
  1576.  
  1577.     status2 = _cairo_output_stream_destroy (surface->stream);
  1578.     if (status == CAIRO_STATUS_SUCCESS)
  1579.         status = status2;
  1580.  
  1581.     fclose (surface->tmpfile);
  1582.  
  1583.     status2 = _cairo_output_stream_destroy (surface->final_stream);
  1584.     if (status == CAIRO_STATUS_SUCCESS)
  1585.         status = status2;
  1586.  
  1587.     while (! cairo_list_is_empty (&surface->document_media)) {
  1588.         cairo_page_media_t *page;
  1589.  
  1590.         page = cairo_list_first_entry (&surface->document_media,
  1591.                                        cairo_page_media_t,
  1592.                                        link);
  1593.         cairo_list_del (&page->link);
  1594.         free (page->name);
  1595.         free (page);
  1596.     }
  1597.  
  1598.     num_comments = _cairo_array_num_elements (&surface->dsc_header_comments);
  1599.     comments = _cairo_array_index (&surface->dsc_header_comments, 0);
  1600.     for (i = 0; i < num_comments; i++)
  1601.         free (comments[i]);
  1602.     _cairo_array_fini (&surface->dsc_header_comments);
  1603.  
  1604.     num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
  1605.     comments = _cairo_array_index (&surface->dsc_setup_comments, 0);
  1606.     for (i = 0; i < num_comments; i++)
  1607.         free (comments[i]);
  1608.     _cairo_array_fini (&surface->dsc_setup_comments);
  1609.  
  1610.     num_comments = _cairo_array_num_elements (&surface->dsc_page_setup_comments);
  1611.     comments = _cairo_array_index (&surface->dsc_page_setup_comments, 0);
  1612.     for (i = 0; i < num_comments; i++)
  1613.         free (comments[i]);
  1614.     _cairo_array_fini (&surface->dsc_page_setup_comments);
  1615.  
  1616.     _cairo_surface_clipper_reset (&surface->clipper);
  1617.  
  1618.     return status;
  1619. }
  1620.  
  1621. static cairo_int_status_t
  1622. _cairo_ps_surface_start_page (void *abstract_surface)
  1623. {
  1624.     cairo_ps_surface_t *surface = abstract_surface;
  1625.  
  1626.     /* Increment before print so page numbers start at 1. */
  1627.     surface->num_pages++;
  1628.  
  1629.     return CAIRO_STATUS_SUCCESS;
  1630. }
  1631.  
  1632. static cairo_int_status_t
  1633. _cairo_ps_surface_show_page (void *abstract_surface)
  1634. {
  1635.     cairo_ps_surface_t *surface = abstract_surface;
  1636.     cairo_int_status_t status;
  1637.  
  1638.     if (surface->clipper.clip != NULL)
  1639.         _cairo_surface_clipper_reset (&surface->clipper);
  1640.  
  1641.     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
  1642.     if (unlikely (status))
  1643.         return status;
  1644.  
  1645.     _cairo_output_stream_printf (surface->stream,
  1646.                                  "Q Q\n"
  1647.                                  "showpage\n");
  1648.  
  1649.     return CAIRO_STATUS_SUCCESS;
  1650. }
  1651.  
  1652. static cairo_bool_t
  1653. color_is_gray (double red, double green, double blue)
  1654. {
  1655.     const double epsilon = 0.00001;
  1656.  
  1657.     return (fabs (red - green) < epsilon &&
  1658.             fabs (red - blue) < epsilon);
  1659. }
  1660.  
  1661. /**
  1662.  * _cairo_ps_surface_acquire_source_surface_from_pattern:
  1663.  * @surface: the ps surface
  1664.  * @pattern: A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source
  1665.  * @extents: extents of the operation that is using this source
  1666.  * @width: returns width of surface
  1667.  * @height: returns height of surface
  1668.  * @x_offset: returns x offset of surface
  1669.  * @y_offset: returns y offset of surface
  1670.  * @surface: returns surface of type image surface or recording surface
  1671.  * @image_extra: returns image extra for image type surface
  1672.  *
  1673.  * Acquire source surface or raster source pattern.
  1674.  **/
  1675. static cairo_status_t
  1676. _cairo_ps_surface_acquire_source_surface_from_pattern (cairo_ps_surface_t           *surface,
  1677.                                                        const cairo_pattern_t        *pattern,
  1678.                                                        const cairo_rectangle_int_t  *extents,
  1679.                                                        int                          *width,
  1680.                                                        int                          *height,
  1681.                                                        double                       *x_offset,
  1682.                                                        double                       *y_offset,
  1683.                                                        cairo_surface_t             **source_surface,
  1684.                                                        void                        **image_extra)
  1685. {
  1686.     cairo_status_t          status;
  1687.     cairo_image_surface_t  *image;
  1688.  
  1689.     *x_offset = *y_offset = 0;
  1690.     switch (pattern->type) {
  1691.     case CAIRO_PATTERN_TYPE_SURFACE: {
  1692.         cairo_surface_t *surf = ((cairo_surface_pattern_t *) pattern)->surface;
  1693.  
  1694.         if (surf->type == CAIRO_SURFACE_TYPE_RECORDING) {
  1695.             if (surf->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
  1696.                 cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surf;
  1697.  
  1698.                 *width  = sub->extents.width;
  1699.                 *height = sub->extents.height;
  1700.             } else {
  1701.                 cairo_surface_t *free_me = NULL;
  1702.                 cairo_recording_surface_t *recording_surface;
  1703.                 cairo_box_t bbox;
  1704.                 cairo_rectangle_int_t extents;
  1705.  
  1706.                 recording_surface = (cairo_recording_surface_t *) surf;
  1707.                 if (_cairo_surface_is_snapshot (&recording_surface->base)) {
  1708.                     free_me = _cairo_surface_snapshot_get_target (&recording_surface->base);
  1709.                     recording_surface = (cairo_recording_surface_t *) free_me;
  1710.                 }
  1711.  
  1712.                 status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
  1713.                 cairo_surface_destroy (free_me);
  1714.                 if (unlikely (status))
  1715.                     return status;
  1716.  
  1717.                 _cairo_box_round_to_rectangle (&bbox, &extents);
  1718.                 *width  = extents.width;
  1719.                 *height = extents.height;
  1720.             }
  1721.             *source_surface = surf;
  1722.  
  1723.             return CAIRO_STATUS_SUCCESS;
  1724.         } else {
  1725.             status =  _cairo_surface_acquire_source_image (surf, &image, image_extra);
  1726.             if (unlikely (status))
  1727.                 return status;
  1728.         }
  1729.     } break;
  1730.  
  1731.     case CAIRO_PATTERN_TYPE_RASTER_SOURCE: {
  1732.         cairo_surface_t *surf;
  1733.         cairo_box_t box;
  1734.         cairo_rectangle_int_t rect;
  1735.  
  1736.         /* get the operation extents in pattern space */
  1737.         _cairo_box_from_rectangle (&box, extents);
  1738.         _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &box, NULL);
  1739.         _cairo_box_round_to_rectangle (&box, &rect);
  1740.         surf = _cairo_raster_source_pattern_acquire (pattern, &surface->base, &rect);
  1741.         if (!surf)
  1742.             return CAIRO_INT_STATUS_UNSUPPORTED;
  1743.         assert (_cairo_surface_is_image (surf));
  1744.         image = (cairo_image_surface_t *) surf;
  1745.     } break;
  1746.  
  1747.     case CAIRO_PATTERN_TYPE_SOLID:
  1748.     case CAIRO_PATTERN_TYPE_LINEAR:
  1749.     case CAIRO_PATTERN_TYPE_RADIAL:
  1750.     case CAIRO_PATTERN_TYPE_MESH:
  1751.     default:
  1752.         ASSERT_NOT_REACHED;
  1753.         break;
  1754.     }
  1755.  
  1756.     *width = image->width;
  1757.     *height = image->height;
  1758.     *source_surface = &image->base;
  1759.     return CAIRO_STATUS_SUCCESS;
  1760. }
  1761.  
  1762. static void
  1763. _cairo_ps_surface_release_source_surface_from_pattern (cairo_ps_surface_t           *surface,
  1764.                                                        const cairo_pattern_t        *pattern,
  1765.                                                        cairo_surface_t              *source,
  1766.                                                        void                         *image_extra)
  1767. {
  1768.     switch (pattern->type) {
  1769.     case CAIRO_PATTERN_TYPE_SURFACE: {
  1770.         cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) pattern;
  1771.         if (surf_pat->surface->type != CAIRO_SURFACE_TYPE_RECORDING) {
  1772.             cairo_image_surface_t *image  = (cairo_image_surface_t *) source;
  1773.             _cairo_surface_release_source_image (surf_pat->surface, image, image_extra);
  1774.         }
  1775.     } break;
  1776.  
  1777.     case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
  1778.         _cairo_raster_source_pattern_release (pattern, source);
  1779.         break;
  1780.  
  1781.     case CAIRO_PATTERN_TYPE_SOLID:
  1782.     case CAIRO_PATTERN_TYPE_LINEAR:
  1783.     case CAIRO_PATTERN_TYPE_RADIAL:
  1784.     case CAIRO_PATTERN_TYPE_MESH:
  1785.     default:
  1786.  
  1787.         ASSERT_NOT_REACHED;
  1788.         break;
  1789.     }
  1790. }
  1791.  
  1792. /**
  1793.  * _cairo_ps_surface_create_padded_image_from_image:
  1794.  * @surface: the ps surface
  1795.  * @source: The source image
  1796.  * @extents: extents of the operation that is using this source
  1797.  * @width: returns width of padded image
  1798.  * @height: returns height of padded image
  1799.  * @x_offset: returns x offset of padded image
  1800.  * @y_offset: returns y offset of padded image
  1801.  * @image: returns the padded image or NULL if padding not required to fill @extents
  1802.  *
  1803.  * Creates a padded image if the source image does not fill the extents.
  1804.  **/
  1805. static cairo_status_t
  1806. _cairo_ps_surface_create_padded_image_from_image (cairo_ps_surface_t           *surface,
  1807.                                                   cairo_image_surface_t        *source,
  1808.                                                   const cairo_matrix_t         *source_matrix,
  1809.                                                   const cairo_rectangle_int_t  *extents,
  1810.                                                   int                          *width,
  1811.                                                   int                          *height,
  1812.                                                   double                       *x_offset,
  1813.                                                   double                       *y_offset,
  1814.                                                   cairo_image_surface_t       **image)
  1815. {
  1816.     cairo_box_t box;
  1817.     cairo_rectangle_int_t rect;
  1818.     cairo_surface_t        *pad_image;
  1819.     cairo_surface_pattern_t pad_pattern;
  1820.     int w, h;
  1821.     cairo_int_status_t      status;
  1822.  
  1823.     /* get the operation extents in pattern space */
  1824.     _cairo_box_from_rectangle (&box, extents);
  1825.     _cairo_matrix_transform_bounding_box_fixed (source_matrix, &box, NULL);
  1826.     _cairo_box_round_to_rectangle (&box, &rect);
  1827.  
  1828.     /* Check if image needs padding to fill extents. */
  1829.     w = source->width;
  1830.     h = source->height;
  1831.     if (_cairo_fixed_integer_ceil(box.p1.x) < 0 ||
  1832.         _cairo_fixed_integer_ceil(box.p1.y) < 0 ||
  1833.         _cairo_fixed_integer_floor(box.p2.y) > w ||
  1834.         _cairo_fixed_integer_floor(box.p2.y) > h)
  1835.     {
  1836.         pad_image =
  1837.             _cairo_image_surface_create_with_pixman_format (NULL,
  1838.                                                             source->pixman_format,
  1839.                                                             rect.width, rect.height,
  1840.                                                             0);
  1841.         if (pad_image->status)
  1842.             return pad_image->status;
  1843.  
  1844.         _cairo_pattern_init_for_surface (&pad_pattern, &source->base);
  1845.         cairo_matrix_init_translate (&pad_pattern.base.matrix, rect.x, rect.y);
  1846.         pad_pattern.base.extend = CAIRO_EXTEND_PAD;
  1847.         status = _cairo_surface_paint (pad_image,
  1848.                                        CAIRO_OPERATOR_SOURCE,
  1849.                                        &pad_pattern.base,
  1850.                                        NULL);
  1851.         _cairo_pattern_fini (&pad_pattern.base);
  1852.         *image = (cairo_image_surface_t *) pad_image;
  1853.         *width = rect.width;
  1854.         *height = rect.height;
  1855.         *x_offset = rect.x;
  1856.         *y_offset = rect.y;
  1857.     } else {
  1858.         *image = NULL;
  1859.         status = CAIRO_STATUS_SUCCESS;
  1860.     }
  1861.  
  1862.     return status;
  1863. }
  1864.  
  1865. static cairo_int_status_t
  1866. _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t            *surface,
  1867.                                                         const cairo_pattern_t         *pattern,
  1868.                                                         const cairo_rectangle_int_t   *extents)
  1869. {
  1870.     int width, height;
  1871.     double x_offset, y_offset;
  1872.     cairo_surface_t *source;
  1873.     cairo_image_surface_t *image;
  1874.     void *image_extra;
  1875.     cairo_int_status_t      status;
  1876.     cairo_image_transparency_t transparency;
  1877.  
  1878.     status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
  1879.                                                                     pattern,
  1880.                                                                     extents,
  1881.                                                                     &width,
  1882.                                                                     &height,
  1883.                                                                     &x_offset,
  1884.                                                                     &y_offset,
  1885.                                                                     &source,
  1886.                                                                     &image_extra);
  1887.     if (unlikely (status))
  1888.         return status;
  1889.  
  1890.     image = (cairo_image_surface_t *) source;
  1891.     if (image->base.status)
  1892.         return image->base.status;
  1893.  
  1894.     transparency = _cairo_image_analyze_transparency (image);
  1895.     switch (transparency) {
  1896.     case CAIRO_IMAGE_IS_OPAQUE:
  1897.         status = CAIRO_STATUS_SUCCESS;
  1898.         break;
  1899.  
  1900.     case CAIRO_IMAGE_HAS_BILEVEL_ALPHA:
  1901.         if (surface->ps_level == CAIRO_PS_LEVEL_2) {
  1902.             status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
  1903.         } else {
  1904.             surface->ps_level_used = CAIRO_PS_LEVEL_3;
  1905.             status = CAIRO_STATUS_SUCCESS;
  1906.         }
  1907.         break;
  1908.  
  1909.     case CAIRO_IMAGE_HAS_ALPHA:
  1910.         status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
  1911.         break;
  1912.  
  1913.     case CAIRO_IMAGE_UNKNOWN:
  1914.         ASSERT_NOT_REACHED;
  1915.     }
  1916.  
  1917.     _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
  1918.  
  1919.     return status;
  1920. }
  1921.  
  1922. static cairo_bool_t
  1923. surface_pattern_supported (const cairo_surface_pattern_t *pattern)
  1924. {
  1925.     if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
  1926.         return TRUE;
  1927.  
  1928.     if (pattern->surface->backend->acquire_source_image == NULL)
  1929.         return FALSE;
  1930.  
  1931.     /* Does an ALPHA-only source surface even make sense? Maybe, but I
  1932.      * don't think it's worth the extra code to support it. */
  1933.  
  1934. /* XXX: Need to write this function here...
  1935.     content = pattern->surface->content;
  1936.     if (content == CAIRO_CONTENT_ALPHA)
  1937.         return FALSE;
  1938. */
  1939.  
  1940.     return TRUE;
  1941. }
  1942.  
  1943. static cairo_bool_t
  1944. _gradient_pattern_supported (cairo_ps_surface_t    *surface,
  1945.                              const cairo_pattern_t *pattern)
  1946. {
  1947.     double min_alpha, max_alpha;
  1948.  
  1949.     if (surface->ps_level == CAIRO_PS_LEVEL_2)
  1950.         return FALSE;
  1951.  
  1952.     /* Alpha gradients are only supported (by flattening the alpha)
  1953.      * if there is no variation in the alpha across the gradient. */
  1954.     _cairo_pattern_alpha_range (pattern, &min_alpha, &max_alpha);
  1955.     if (min_alpha != max_alpha)
  1956.         return FALSE;
  1957.  
  1958.     surface->ps_level_used = CAIRO_PS_LEVEL_3;
  1959.  
  1960.     return TRUE;
  1961. }
  1962.  
  1963. static cairo_bool_t
  1964. pattern_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *pattern)
  1965. {
  1966.     switch (pattern->type) {
  1967.     case CAIRO_PATTERN_TYPE_SOLID:
  1968.         return TRUE;
  1969.  
  1970.     case CAIRO_PATTERN_TYPE_LINEAR:
  1971.     case CAIRO_PATTERN_TYPE_RADIAL:
  1972.     case CAIRO_PATTERN_TYPE_MESH:
  1973.         return _gradient_pattern_supported (surface, pattern);
  1974.  
  1975.     case CAIRO_PATTERN_TYPE_SURFACE:
  1976.         return surface_pattern_supported ((cairo_surface_pattern_t *) pattern);
  1977.  
  1978.     case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
  1979.         return TRUE;
  1980.  
  1981.     default:
  1982.         ASSERT_NOT_REACHED;
  1983.         return FALSE;
  1984.     }
  1985. }
  1986.  
  1987. static cairo_bool_t
  1988. mask_supported (cairo_ps_surface_t *surface,
  1989.                 const cairo_pattern_t *mask,
  1990.                 const cairo_rectangle_int_t *extents)
  1991. {
  1992.     if (surface->ps_level == CAIRO_PS_LEVEL_2)
  1993.         return FALSE;
  1994.  
  1995.     if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
  1996.         cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
  1997.         if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
  1998.             /* check if mask if opaque or bilevel alpha */
  1999.             if (_cairo_ps_surface_analyze_surface_pattern_transparency (surface, mask, extents) == CAIRO_INT_STATUS_SUCCESS) {
  2000.                 surface->ps_level_used = CAIRO_PS_LEVEL_3;
  2001.                 return TRUE;
  2002.             }
  2003.         }
  2004.     }
  2005.  
  2006.     return FALSE;
  2007. }
  2008.  
  2009. static cairo_int_status_t
  2010. _cairo_ps_surface_analyze_operation (cairo_ps_surface_t    *surface,
  2011.                                      cairo_operator_t       op,
  2012.                                      const cairo_pattern_t       *pattern,
  2013.                                      const cairo_pattern_t       *mask,
  2014.                                      const cairo_rectangle_int_t *extents)
  2015. {
  2016.     double min_alpha;
  2017.  
  2018.     if (surface->force_fallbacks &&
  2019.         surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
  2020.     {
  2021.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2022.     }
  2023.  
  2024.     if (! pattern_supported (surface, pattern))
  2025.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2026.  
  2027.     if (! (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
  2028.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2029.  
  2030.     /* Mask is only supported when the mask is an image with opaque or bilevel alpha. */
  2031.     if (mask && !mask_supported (surface, mask, extents))
  2032.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2033.  
  2034.     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
  2035.         cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
  2036.  
  2037.         if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
  2038.             if (pattern->extend == CAIRO_EXTEND_PAD) {
  2039.                 cairo_box_t box;
  2040.                 cairo_rectangle_int_t rect;
  2041.                 cairo_rectangle_int_t rec_extents;
  2042.  
  2043.                 /* get the operation extents in pattern space */
  2044.                 _cairo_box_from_rectangle (&box, extents);
  2045.                 _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &box, NULL);
  2046.                 _cairo_box_round_to_rectangle (&box, &rect);
  2047.  
  2048.                 /* Check if surface needs padding to fill extents */
  2049.                 if (_cairo_surface_get_extents (surface_pattern->surface, &rec_extents)) {
  2050.                     if (_cairo_fixed_integer_ceil(box.p1.x) < rec_extents.x ||
  2051.                         _cairo_fixed_integer_ceil(box.p1.y) < rec_extents.y ||
  2052.                         _cairo_fixed_integer_floor(box.p2.y) > rec_extents.x + rec_extents.width ||
  2053.                         _cairo_fixed_integer_floor(box.p2.y) > rec_extents.y + rec_extents.height)
  2054.                     {
  2055.                         return CAIRO_INT_STATUS_UNSUPPORTED;
  2056.                     }
  2057.                 }
  2058.             }
  2059.             return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
  2060.         }
  2061.     }
  2062.  
  2063.     if (op == CAIRO_OPERATOR_SOURCE) {
  2064.         if (mask)
  2065.             return CAIRO_INT_STATUS_UNSUPPORTED;
  2066.         else
  2067.             return CAIRO_STATUS_SUCCESS;
  2068.     }
  2069.  
  2070.     /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
  2071.      * the pattern contains transparency, we return
  2072.      * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
  2073.      * surface. If the analysis surface determines that there is
  2074.      * anything drawn under this operation, a fallback image will be
  2075.      * used. Otherwise the operation will be replayed during the
  2076.      * render stage and we blend the transparency into the white
  2077.      * background to convert the pattern to opaque.
  2078.      */
  2079.     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE || pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)
  2080.         return _cairo_ps_surface_analyze_surface_pattern_transparency (surface, pattern, extents);
  2081.  
  2082.     /* Patterns whose drawn part is opaque are directly supported;
  2083.        those whose drawn part is partially transparent can be
  2084.        supported by flattening the alpha. */
  2085.     _cairo_pattern_alpha_range (pattern, &min_alpha, NULL);
  2086.     if (CAIRO_ALPHA_IS_OPAQUE (min_alpha))
  2087.         return CAIRO_STATUS_SUCCESS;
  2088.  
  2089.     return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
  2090. }
  2091.  
  2092. static cairo_bool_t
  2093. _cairo_ps_surface_operation_supported (cairo_ps_surface_t    *surface,
  2094.                                        cairo_operator_t       op,
  2095.                                        const cairo_pattern_t       *pattern,
  2096.                                        const cairo_pattern_t       *mask,
  2097.                                        const cairo_rectangle_int_t *extents)
  2098. {
  2099.     return _cairo_ps_surface_analyze_operation (surface, op, pattern, mask, extents) != CAIRO_INT_STATUS_UNSUPPORTED;
  2100. }
  2101.  
  2102. /* The "standard" implementation limit for PostScript string sizes is
  2103.  * 65535 characters (see PostScript Language Reference, Appendix
  2104.  * B). We go one short of that because we sometimes need two
  2105.  * characters in a string to represent a single ASCII85 byte, (for the
  2106.  * escape sequences "\\", "\(", and "\)") and we must not split these
  2107.  * across two strings. So we'd be in trouble if we went right to the
  2108.  * limit and one of these escape sequences just happened to land at
  2109.  * the end.
  2110.  */
  2111. #define STRING_ARRAY_MAX_STRING_SIZE (65535-1)
  2112. #define STRING_ARRAY_MAX_COLUMN      72
  2113.  
  2114. typedef struct _string_array_stream {
  2115.     cairo_output_stream_t base;
  2116.     cairo_output_stream_t *output;
  2117.     int column;
  2118.     int string_size;
  2119.     cairo_bool_t use_strings;
  2120. } string_array_stream_t;
  2121.  
  2122. static cairo_status_t
  2123. _string_array_stream_write (cairo_output_stream_t *base,
  2124.                             const unsigned char   *data,
  2125.                             unsigned int           length)
  2126. {
  2127.     string_array_stream_t *stream = (string_array_stream_t *) base;
  2128.     unsigned char c;
  2129.     const unsigned char backslash = '\\';
  2130.  
  2131.     if (length == 0)
  2132.         return CAIRO_STATUS_SUCCESS;
  2133.  
  2134.     while (length--) {
  2135.         if (stream->string_size == 0 && stream->use_strings) {
  2136.             _cairo_output_stream_printf (stream->output, "(");
  2137.             stream->column++;
  2138.         }
  2139.  
  2140.         c = *data++;
  2141.         if (stream->use_strings) {
  2142.             switch (c) {
  2143.             case '\\':
  2144.             case '(':
  2145.             case ')':
  2146.                 _cairo_output_stream_write (stream->output, &backslash, 1);
  2147.                 stream->column++;
  2148.                 stream->string_size++;
  2149.                 break;
  2150.             }
  2151.         }
  2152.         /* Have to be careful to never split the final ~> sequence. */
  2153.         if (c == '~') {
  2154.             _cairo_output_stream_write (stream->output, &c, 1);
  2155.             stream->column++;
  2156.             stream->string_size++;
  2157.  
  2158.             if (length-- == 0)
  2159.                 break;
  2160.  
  2161.             c = *data++;
  2162.         }
  2163.         _cairo_output_stream_write (stream->output, &c, 1);
  2164.         stream->column++;
  2165.         stream->string_size++;
  2166.  
  2167.         if (stream->use_strings &&
  2168.             stream->string_size >= STRING_ARRAY_MAX_STRING_SIZE)
  2169.         {
  2170.             _cairo_output_stream_printf (stream->output, ")\n");
  2171.             stream->string_size = 0;
  2172.             stream->column = 0;
  2173.         }
  2174.         if (stream->column >= STRING_ARRAY_MAX_COLUMN) {
  2175.             _cairo_output_stream_printf (stream->output, "\n ");
  2176.             stream->string_size += 2;
  2177.             stream->column = 1;
  2178.         }
  2179.     }
  2180.  
  2181.     return _cairo_output_stream_get_status (stream->output);
  2182. }
  2183.  
  2184. static cairo_status_t
  2185. _string_array_stream_close (cairo_output_stream_t *base)
  2186. {
  2187.     cairo_status_t status;
  2188.     string_array_stream_t *stream = (string_array_stream_t *) base;
  2189.  
  2190.     if (stream->use_strings)
  2191.         _cairo_output_stream_printf (stream->output, ")\n");
  2192.  
  2193.     status = _cairo_output_stream_get_status (stream->output);
  2194.  
  2195.     return status;
  2196. }
  2197.  
  2198. /* A string_array_stream wraps an existing output stream. It takes the
  2199.  * data provided to it and output one or more consecutive string
  2200.  * objects, each within the standard PostScript implementation limit
  2201.  * of 65k characters.
  2202.  *
  2203.  * The strings are each separated by a space character for easy
  2204.  * inclusion within an array object, (but the array delimiters are not
  2205.  * added by the string_array_stream).
  2206.  *
  2207.  * The string array stream is also careful to wrap the output within
  2208.  * STRING_ARRAY_MAX_COLUMN columns (+/- 1). The stream also adds
  2209.  * necessary escaping for special characters within a string,
  2210.  * (specifically '\', '(', and ')').
  2211.  */
  2212. static cairo_output_stream_t *
  2213. _string_array_stream_create (cairo_output_stream_t *output)
  2214. {
  2215.     string_array_stream_t *stream;
  2216.  
  2217.     stream = malloc (sizeof (string_array_stream_t));
  2218.     if (unlikely (stream == NULL)) {
  2219.         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
  2220.         return (cairo_output_stream_t *) &_cairo_output_stream_nil;
  2221.     }
  2222.  
  2223.     _cairo_output_stream_init (&stream->base,
  2224.                                _string_array_stream_write,
  2225.                                NULL,
  2226.                                _string_array_stream_close);
  2227.     stream->output = output;
  2228.     stream->column = 0;
  2229.     stream->string_size = 0;
  2230.     stream->use_strings = TRUE;
  2231.  
  2232.     return &stream->base;
  2233. }
  2234.  
  2235. /* A base85_array_stream wraps an existing output stream. It wraps the
  2236.  * output within STRING_ARRAY_MAX_COLUMN columns (+/- 1). The output
  2237.  * is not enclosed in strings like string_array_stream.
  2238.  */
  2239. static cairo_output_stream_t *
  2240. _base85_array_stream_create (cairo_output_stream_t *output)
  2241. {
  2242.     string_array_stream_t *stream;
  2243.  
  2244.     stream = malloc (sizeof (string_array_stream_t));
  2245.     if (unlikely (stream == NULL)) {
  2246.         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
  2247.         return (cairo_output_stream_t *) &_cairo_output_stream_nil;
  2248.     }
  2249.  
  2250.     _cairo_output_stream_init (&stream->base,
  2251.                                _string_array_stream_write,
  2252.                                NULL,
  2253.                                _string_array_stream_close);
  2254.     stream->output = output;
  2255.     stream->column = 0;
  2256.     stream->string_size = 0;
  2257.     stream->use_strings = FALSE;
  2258.  
  2259.     return &stream->base;
  2260. }
  2261.  
  2262.  
  2263. /* PS Output - this section handles output of the parts of the recording
  2264.  * surface we can render natively in PS. */
  2265.  
  2266. static cairo_status_t
  2267. _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t    *surface,
  2268.                                               cairo_image_surface_t *image,
  2269.                                               cairo_image_surface_t **opaque_image)
  2270. {
  2271.     cairo_surface_t *opaque;
  2272.     cairo_surface_pattern_t pattern;
  2273.     cairo_status_t status;
  2274.  
  2275.     opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
  2276.                                          image->width,
  2277.                                          image->height);
  2278.     if (unlikely (opaque->status))
  2279.         return opaque->status;
  2280.  
  2281.     if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
  2282.         status = _cairo_surface_paint (opaque,
  2283.                                        CAIRO_OPERATOR_SOURCE,
  2284.                                        &_cairo_pattern_white.base,
  2285.                                        NULL);
  2286.         if (unlikely (status)) {
  2287.             cairo_surface_destroy (opaque);
  2288.             return status;
  2289.         }
  2290.     }
  2291.  
  2292.     _cairo_pattern_init_for_surface (&pattern, &image->base);
  2293.     pattern.base.filter = CAIRO_FILTER_NEAREST;
  2294.     status = _cairo_surface_paint (opaque, CAIRO_OPERATOR_OVER, &pattern.base, NULL);
  2295.     _cairo_pattern_fini (&pattern.base);
  2296.     if (unlikely (status)) {
  2297.         cairo_surface_destroy (opaque);
  2298.         return status;
  2299.     }
  2300.  
  2301.     *opaque_image = (cairo_image_surface_t *) opaque;
  2302.     return CAIRO_STATUS_SUCCESS;
  2303. }
  2304.  
  2305. static cairo_status_t
  2306. _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t    *surface,
  2307.                                       const unsigned char   *data,
  2308.                                       unsigned long          length,
  2309.                                       cairo_ps_compress_t    compress,
  2310.                                       cairo_bool_t           use_strings)
  2311. {
  2312.     cairo_output_stream_t *base85_stream, *string_array_stream, *deflate_stream;
  2313.     unsigned char *data_compressed;
  2314.     unsigned long data_compressed_size;
  2315.     cairo_status_t status, status2;
  2316.  
  2317.     if (use_strings)
  2318.         string_array_stream = _string_array_stream_create (surface->stream);
  2319.     else
  2320.         string_array_stream = _base85_array_stream_create (surface->stream);
  2321.  
  2322.     status = _cairo_output_stream_get_status (string_array_stream);
  2323.     if (unlikely (status))
  2324.         return _cairo_output_stream_destroy (string_array_stream);
  2325.  
  2326.     base85_stream = _cairo_base85_stream_create (string_array_stream);
  2327.     status = _cairo_output_stream_get_status (base85_stream);
  2328.     if (unlikely (status)) {
  2329.         status2 = _cairo_output_stream_destroy (string_array_stream);
  2330.         return _cairo_output_stream_destroy (base85_stream);
  2331.     }
  2332.  
  2333.     switch (compress) {
  2334.         case CAIRO_PS_COMPRESS_NONE:
  2335.             _cairo_output_stream_write (base85_stream, data, length);
  2336.             break;
  2337.  
  2338.         case CAIRO_PS_COMPRESS_LZW:
  2339.             /* XXX: Should fix cairo-lzw to provide a stream-based interface
  2340.              * instead. */
  2341.             data_compressed_size = length;
  2342.             data_compressed = _cairo_lzw_compress ((unsigned char*)data, &data_compressed_size);
  2343.             if (unlikely (data_compressed == NULL)) {
  2344.                 status = _cairo_output_stream_destroy (string_array_stream);
  2345.                 status = _cairo_output_stream_destroy (base85_stream);
  2346.                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  2347.             }
  2348.             _cairo_output_stream_write (base85_stream, data_compressed, data_compressed_size);
  2349.             free (data_compressed);
  2350.             break;
  2351.  
  2352.         case CAIRO_PS_COMPRESS_DEFLATE:
  2353.             deflate_stream = _cairo_deflate_stream_create (base85_stream);
  2354.             if (_cairo_output_stream_get_status (deflate_stream)) {
  2355.                 return _cairo_output_stream_destroy (deflate_stream);
  2356.             }
  2357.             _cairo_output_stream_write (deflate_stream, data, length);
  2358.             status = _cairo_output_stream_destroy (deflate_stream);
  2359.             if (unlikely (status)) {
  2360.                 status2 = _cairo_output_stream_destroy (string_array_stream);
  2361.                 status2 = _cairo_output_stream_destroy (base85_stream);
  2362.                 return _cairo_output_stream_destroy (deflate_stream);
  2363.             }
  2364.             break;
  2365.     }
  2366.     status = _cairo_output_stream_destroy (base85_stream);
  2367.  
  2368.     /* Mark end of base85 data */
  2369.     _cairo_output_stream_printf (string_array_stream, "~>");
  2370.     status2 = _cairo_output_stream_destroy (string_array_stream);
  2371.     if (status == CAIRO_STATUS_SUCCESS)
  2372.         status = status2;
  2373.  
  2374.     return status;
  2375. }
  2376.  
  2377. static cairo_status_t
  2378. _cairo_ps_surface_emit_image (cairo_ps_surface_t    *surface,
  2379.                               cairo_image_surface_t *image_surf,
  2380.                               cairo_operator_t       op,
  2381.                               cairo_filter_t         filter,
  2382.                               cairo_bool_t           stencil_mask)
  2383. {
  2384.     cairo_status_t status;
  2385.     unsigned char *data;
  2386.     unsigned long data_size;
  2387.     cairo_image_surface_t *ps_image;
  2388.     int x, y, i, a;
  2389.     cairo_image_transparency_t transparency;
  2390.     cairo_bool_t use_mask;
  2391.     uint32_t *pixel32;
  2392.     uint8_t *pixel8;
  2393.     int bit;
  2394.     cairo_image_color_t color;
  2395.     const char *interpolate;
  2396.     cairo_ps_compress_t compress;
  2397.     const char *compress_filter;
  2398.     cairo_image_surface_t *image;
  2399.  
  2400.     if (image_surf->base.status)
  2401.         return image_surf->base.status;
  2402.  
  2403.     image  = image_surf;
  2404.     if (image->format != CAIRO_FORMAT_RGB24 &&
  2405.         image->format != CAIRO_FORMAT_ARGB32 &&
  2406.         image->format != CAIRO_FORMAT_A8 &&
  2407.         image->format != CAIRO_FORMAT_A1)
  2408.     {
  2409.         cairo_surface_t *surf;
  2410.         cairo_surface_pattern_t pattern;
  2411.  
  2412.         surf = _cairo_image_surface_create_with_content (image_surf->base.content,
  2413.                                                          image_surf->width,
  2414.                                                          image_surf->height);
  2415.         image = (cairo_image_surface_t *) surf;
  2416.         if (surf->status) {
  2417.             status = surf->status;
  2418.             goto bail0;
  2419.         }
  2420.  
  2421.         _cairo_pattern_init_for_surface (&pattern, &image_surf->base);
  2422.         status = _cairo_surface_paint (surf,
  2423.                                        CAIRO_OPERATOR_SOURCE, &pattern.base,
  2424.                                        NULL);
  2425.         _cairo_pattern_fini (&pattern.base);
  2426.         if (unlikely (status))
  2427.             goto bail0;
  2428.     }
  2429.     ps_image = image;
  2430.  
  2431.     switch (filter) {
  2432.     default:
  2433.     case CAIRO_FILTER_GOOD:
  2434.     case CAIRO_FILTER_BEST:
  2435.     case CAIRO_FILTER_BILINEAR:
  2436.         interpolate = "true";
  2437.         break;
  2438.     case CAIRO_FILTER_FAST:
  2439.     case CAIRO_FILTER_NEAREST:
  2440.     case CAIRO_FILTER_GAUSSIAN:
  2441.         interpolate = "false";
  2442.         break;
  2443.     }
  2444.  
  2445.     if (stencil_mask) {
  2446.         use_mask = FALSE;
  2447.         color = CAIRO_IMAGE_IS_MONOCHROME;
  2448.         transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
  2449.     } else {
  2450.         transparency = _cairo_image_analyze_transparency (image);
  2451.  
  2452.         /* PostScript can not represent the alpha channel, so we blend the
  2453.            current image over a white (or black for CONTENT_COLOR
  2454.            surfaces) RGB surface to eliminate it. */
  2455.  
  2456.         if (op == CAIRO_OPERATOR_SOURCE ||
  2457.             transparency == CAIRO_IMAGE_HAS_ALPHA ||
  2458.             (transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA &&
  2459.              surface->ps_level == CAIRO_PS_LEVEL_2))
  2460.         {
  2461.             status = _cairo_ps_surface_flatten_image_transparency (surface,
  2462.                                                                    image,
  2463.                                                                    &ps_image);
  2464.             if (unlikely (status))
  2465.                 return status;
  2466.  
  2467.             use_mask = FALSE;
  2468.         } else if (transparency == CAIRO_IMAGE_IS_OPAQUE) {
  2469.             use_mask = FALSE;
  2470.         } else { /* transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA */
  2471.             use_mask = TRUE;
  2472.         }
  2473.  
  2474.         color = _cairo_image_analyze_color (ps_image);
  2475.     }
  2476.  
  2477.     /* Type 2 (mask and image interleaved) has the mask and image
  2478.      * samples interleaved by row.  The mask row is first, one bit per
  2479.      * pixel with (bit 7 first). The row is padded to byte
  2480.      * boundaries. The image data is 3 bytes per pixel RGB format. */
  2481.     switch (color) {
  2482.     default:
  2483.     case CAIRO_IMAGE_UNKNOWN_COLOR:
  2484.         ASSERT_NOT_REACHED;
  2485.     case CAIRO_IMAGE_IS_COLOR:
  2486.         data_size = ps_image->width * 3;
  2487.         break;
  2488.     case CAIRO_IMAGE_IS_GRAYSCALE:
  2489.         data_size = ps_image->width;
  2490.         break;
  2491.     case CAIRO_IMAGE_IS_MONOCHROME:
  2492.         data_size = (ps_image->width + 7)/8;
  2493.         break;
  2494.     }
  2495.     if (use_mask)
  2496.         data_size += (ps_image->width + 7)/8;
  2497.     data_size *= ps_image->height;
  2498.     data = malloc (data_size);
  2499.     if (unlikely (data == NULL)) {
  2500.         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  2501.         goto bail1;
  2502.     }
  2503.  
  2504.     i = 0;
  2505.     for (y = 0; y < ps_image->height; y++) {
  2506.         if (stencil_mask || use_mask) {
  2507.             /* mask row */
  2508.             if (ps_image->format == CAIRO_FORMAT_A1) {
  2509.                 pixel8 = (uint8_t *) (ps_image->data + y * ps_image->stride);
  2510.  
  2511.                 for (x = 0; x < (ps_image->width + 7) / 8; x++, pixel8++) {
  2512.                     a = *pixel8;
  2513.                     a = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (a);
  2514.                     data[i++] = a;
  2515.                 }
  2516.             } else {
  2517.                 pixel8 = (uint8_t *) (ps_image->data + y * ps_image->stride);
  2518.                 pixel32 = (uint32_t *) (ps_image->data + y * ps_image->stride);
  2519.                 bit = 7;
  2520.                 for (x = 0; x < ps_image->width; x++) {
  2521.                     if (ps_image->format == CAIRO_FORMAT_ARGB32) {
  2522.                         a = (*pixel32 & 0xff000000) >> 24;
  2523.                         pixel32++;
  2524.                     } else {
  2525.                         a = *pixel8;
  2526.                         pixel8++;
  2527.                     }
  2528.  
  2529.                     if (transparency == CAIRO_IMAGE_HAS_ALPHA) {
  2530.                         data[i++] = a;
  2531.                     } else { /* transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA or CAIRO_IMAGE_IS_OPAQUE */
  2532.                         if (bit == 7)
  2533.                             data[i] = 0;
  2534.                         if (a != 0)
  2535.                             data[i] |= (1 << bit);
  2536.                         bit--;
  2537.                         if (bit < 0) {
  2538.                             bit = 7;
  2539.                             i++;
  2540.                         }
  2541.                     }
  2542.                 }
  2543.                 if (bit != 7)
  2544.                     i++;
  2545.             }
  2546.         }
  2547.         if (stencil_mask)
  2548.             continue;
  2549.  
  2550.         /* image row*/
  2551.         pixel32 = (uint32_t *) (ps_image->data + y * ps_image->stride);
  2552.         bit = 7;
  2553.         for (x = 0; x < ps_image->width; x++, pixel32++) {
  2554.             int r, g, b;
  2555.  
  2556.             if (ps_image->format == CAIRO_FORMAT_ARGB32) {
  2557.                 /* At this point ARGB32 images are either opaque or
  2558.                  * bilevel alpha so we don't need to unpremultiply. */
  2559.                 if (((*pixel32 & 0xff000000) >> 24) == 0) {
  2560.                     r = g = b = 0;
  2561.                 } else {
  2562.                     r = (*pixel32 & 0x00ff0000) >> 16;
  2563.                     g = (*pixel32 & 0x0000ff00) >>  8;
  2564.                     b = (*pixel32 & 0x000000ff) >>  0;
  2565.                 }
  2566.             } else if (ps_image->format == CAIRO_FORMAT_RGB24) {
  2567.                 r = (*pixel32 & 0x00ff0000) >> 16;
  2568.                 g = (*pixel32 & 0x0000ff00) >>  8;
  2569.                 b = (*pixel32 & 0x000000ff) >>  0;
  2570.             } else {
  2571.                 r = g = b = 0;
  2572.             }
  2573.  
  2574.             switch (color) {
  2575.                 case CAIRO_IMAGE_IS_COLOR:
  2576.                 case CAIRO_IMAGE_UNKNOWN_COLOR:
  2577.                     data[i++] = r;
  2578.                     data[i++] = g;
  2579.                     data[i++] = b;
  2580.                     break;
  2581.  
  2582.                 case CAIRO_IMAGE_IS_GRAYSCALE:
  2583.                     data[i++] = r;
  2584.                     break;
  2585.  
  2586.                 case CAIRO_IMAGE_IS_MONOCHROME:
  2587.                     if (bit == 7)
  2588.                         data[i] = 0;
  2589.                     if (r != 0)
  2590.                         data[i] |= (1 << bit);
  2591.                     bit--;
  2592.                     if (bit < 0) {
  2593.                         bit = 7;
  2594.                         i++;
  2595.                     }
  2596.                     break;
  2597.             }
  2598.         }
  2599.         if (bit != 7)
  2600.             i++;
  2601.     }
  2602.  
  2603.     if (surface->ps_level == CAIRO_PS_LEVEL_2) {
  2604.         compress = CAIRO_PS_COMPRESS_LZW;
  2605.         compress_filter = "LZWDecode";
  2606.     } else {
  2607.         compress = CAIRO_PS_COMPRESS_DEFLATE;
  2608.         compress_filter = "FlateDecode";
  2609.         surface->ps_level_used = CAIRO_PS_LEVEL_3;
  2610.     }
  2611.  
  2612.     if (surface->use_string_datasource) {
  2613.         /* Emit the image data as a base85-encoded string which will
  2614.          * be used as the data source for the image operator later. */
  2615.         _cairo_output_stream_printf (surface->stream,
  2616.                                      "/CairoImageData [\n");
  2617.  
  2618.         status = _cairo_ps_surface_emit_base85_string (surface,
  2619.                                                        data,
  2620.                                                        data_size,
  2621.                                                        compress,
  2622.                                                        TRUE);
  2623.         if (unlikely (status))
  2624.             goto bail2;
  2625.  
  2626.         _cairo_output_stream_printf (surface->stream,
  2627.                                      "] def\n");
  2628.         _cairo_output_stream_printf (surface->stream,
  2629.                                      "/CairoImageDataIndex 0 def\n");
  2630.     }
  2631.  
  2632.     if (use_mask) {
  2633.         _cairo_output_stream_printf (surface->stream,
  2634.                                      "%s setcolorspace\n"
  2635.                                      "5 dict dup begin\n"
  2636.                                      "  /ImageType 3 def\n"
  2637.                                      "  /InterleaveType 2 def\n"
  2638.                                      "  /DataDict 8 dict def\n"
  2639.                                      "    DataDict begin\n"
  2640.                                      "    /ImageType 1 def\n"
  2641.                                      "    /Width %d def\n"
  2642.                                      "    /Height %d def\n"
  2643.                                      "    /Interpolate %s def\n"
  2644.                                      "    /BitsPerComponent %d def\n"
  2645.                                      "    /Decode [ %s ] def\n",
  2646.                                      color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray",
  2647.                                      ps_image->width,
  2648.                                      ps_image->height,
  2649.                                      interpolate,
  2650.                                      color == CAIRO_IMAGE_IS_MONOCHROME ? 1 : 8,
  2651.                                      color == CAIRO_IMAGE_IS_COLOR ? "0 1 0 1 0 1" : "0 1");
  2652.  
  2653.         if (surface->use_string_datasource) {
  2654.             _cairo_output_stream_printf (surface->stream,
  2655.                                          "    /DataSource {\n"
  2656.                                          "      CairoImageData CairoImageDataIndex get\n"
  2657.                                          "      /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
  2658.                                          "      CairoImageDataIndex CairoImageData length 1 sub gt\n"
  2659.                                          "       { /CairoImageDataIndex 0 def } if\n"
  2660.                                          "    } /ASCII85Decode filter /%s filter def\n",
  2661.                                          compress_filter);
  2662.         } else {
  2663.             _cairo_output_stream_printf (surface->stream,
  2664.                                          "    /DataSource currentfile /ASCII85Decode filter /%s filter def\n",
  2665.                                          compress_filter);
  2666.         }
  2667.  
  2668.         _cairo_output_stream_printf (surface->stream,
  2669.                                      "    /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
  2670.                                      "  end\n"
  2671.                                      "  /MaskDict 8 dict def\n"
  2672.                                      "     MaskDict begin\n"
  2673.                                      "    /ImageType 1 def\n"
  2674.                                      "    /Width %d def\n"
  2675.                                      "    /Height %d def\n"
  2676.                                      "    /Interpolate %s def\n"
  2677.                                      "    /BitsPerComponent 1 def\n"
  2678.                                      "    /Decode [ 1 0 ] def\n"
  2679.                                      "    /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
  2680.                                      "  end\n"
  2681.                                      "end\n"
  2682.                                      "image\n",
  2683.                                      ps_image->height,
  2684.                                      ps_image->width,
  2685.                                      ps_image->height,
  2686.                                      interpolate,
  2687.                                      ps_image->height);
  2688.     } else {
  2689.         if (!stencil_mask) {
  2690.             _cairo_output_stream_printf (surface->stream,
  2691.                                          "%s setcolorspace\n",
  2692.                                          color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray");
  2693.         }
  2694.         _cairo_output_stream_printf (surface->stream,
  2695.                                      "8 dict dup begin\n"
  2696.                                      "  /ImageType 1 def\n"
  2697.                                      "  /Width %d def\n"
  2698.                                      "  /Height %d def\n"
  2699.                                      "  /Interpolate %s def\n"
  2700.                                      "  /BitsPerComponent %d def\n"
  2701.                                      "  /Decode [ %s ] def\n",
  2702.                                      ps_image->width,
  2703.                                      ps_image->height,
  2704.                                      interpolate,
  2705.                                      color == CAIRO_IMAGE_IS_MONOCHROME ? 1 : 8,
  2706.                                      stencil_mask ? "1 0" : color == CAIRO_IMAGE_IS_COLOR ? "0 1 0 1 0 1" : "0 1");
  2707.         if (surface->use_string_datasource) {
  2708.             _cairo_output_stream_printf (surface->stream,
  2709.                                          "  /DataSource {\n"
  2710.                                          "    CairoImageData CairoImageDataIndex get\n"
  2711.                                          "    /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
  2712.                                          "    CairoImageDataIndex CairoImageData length 1 sub gt\n"
  2713.                                          "     { /CairoImageDataIndex 0 def } if\n"
  2714.                                          "  } /ASCII85Decode filter /%s filter def\n",
  2715.                                          compress_filter);
  2716.         } else {
  2717.             _cairo_output_stream_printf (surface->stream,
  2718.                                          "  /DataSource currentfile /ASCII85Decode filter /%s filter def\n",
  2719.                                          compress_filter);
  2720.         }
  2721.  
  2722.         _cairo_output_stream_printf (surface->stream,
  2723.                                      "  /Interpolate %s def\n"
  2724.                                      "  /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
  2725.                                      "end\n"
  2726.                                      "%s\n",
  2727.                                      interpolate,
  2728.                                      ps_image->height,
  2729.                                      stencil_mask ? "imagemask" : "image");
  2730.     }
  2731.  
  2732.     if (!surface->use_string_datasource) {
  2733.         /* Emit the image data as a base85-encoded string which will
  2734.          * be used as the data source for the image operator. */
  2735.         status = _cairo_ps_surface_emit_base85_string (surface,
  2736.                                                        data,
  2737.                                                        data_size,
  2738.                                                        compress,
  2739.                                                        FALSE);
  2740.         _cairo_output_stream_printf (surface->stream, "\n");
  2741.     } else {
  2742.         status = CAIRO_STATUS_SUCCESS;
  2743.     }
  2744.  
  2745. bail2:
  2746.     free (data);
  2747.  
  2748. bail1:
  2749.     if (!use_mask && ps_image != image)
  2750.         cairo_surface_destroy (&ps_image->base);
  2751.  
  2752. bail0:
  2753.     if (image != image_surf)
  2754.         cairo_surface_destroy (&image->base);
  2755.  
  2756.     return status;
  2757. }
  2758.  
  2759. static cairo_status_t
  2760. _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t    *surface,
  2761.                                    cairo_surface_t       *source,
  2762.                                    int                    width,
  2763.                                    int                    height)
  2764. {
  2765.     cairo_status_t status;
  2766.     const unsigned char *mime_data;
  2767.     unsigned long mime_data_length;
  2768.     cairo_image_info_t info;
  2769.     const char *colorspace;
  2770.     const char *decode;
  2771.  
  2772.     cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
  2773.                                  &mime_data, &mime_data_length);
  2774.     if (unlikely (source->status))
  2775.         return source->status;
  2776.     if (mime_data == NULL)
  2777.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2778.  
  2779.     status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length);
  2780.     if (unlikely (status))
  2781.         return status;
  2782.  
  2783.     switch (info.num_components) {
  2784.         case 1:
  2785.             colorspace = "/DeviceGray";
  2786.             decode = "0 1";
  2787.             break;
  2788.         case 3:
  2789.             colorspace = "/DeviceRGB";
  2790.             decode =  "0 1 0 1 0 1";
  2791.             break;
  2792.         case 4:
  2793.             colorspace = "/DeviceCMYK";
  2794.             decode =  "0 1 0 1 0 1 0 1";
  2795.             break;
  2796.         default:
  2797.             return CAIRO_INT_STATUS_UNSUPPORTED;
  2798.     }
  2799.  
  2800.     if (surface->use_string_datasource) {
  2801.         /* Emit the image data as a base85-encoded string which will
  2802.          * be used as the data source for the image operator later. */
  2803.         _cairo_output_stream_printf (surface->stream,
  2804.                                      "/CairoImageData [\n");
  2805.  
  2806.         status = _cairo_ps_surface_emit_base85_string (surface,
  2807.                                                        mime_data,
  2808.                                                        mime_data_length,
  2809.                                                        CAIRO_PS_COMPRESS_NONE,
  2810.                                                        TRUE);
  2811.         if (unlikely (status))
  2812.             return status;
  2813.  
  2814.         _cairo_output_stream_printf (surface->stream,
  2815.                                      "] def\n");
  2816.         _cairo_output_stream_printf (surface->stream,
  2817.                                      "/CairoImageDataIndex 0 def\n");
  2818.     }
  2819.  
  2820.     _cairo_output_stream_printf (surface->stream,
  2821.                                  "%s setcolorspace\n"
  2822.                                  "8 dict dup begin\n"
  2823.                                  "  /ImageType 1 def\n"
  2824.                                  "  /Width %d def\n"
  2825.                                  "  /Height %d def\n"
  2826.                                  "  /BitsPerComponent %d def\n"
  2827.                                  "  /Decode [ %s ] def\n",
  2828.                                  colorspace,
  2829.                                  info.width,
  2830.                                  info.height,
  2831.                                  info.bits_per_component,
  2832.                                  decode);
  2833.  
  2834.     if (surface->use_string_datasource) {
  2835.         _cairo_output_stream_printf (surface->stream,
  2836.                                      "  /DataSource {\n"
  2837.                                      "    CairoImageData CairoImageDataIndex get\n"
  2838.                                      "    /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
  2839.                                      "    CairoImageDataIndex CairoImageData length 1 sub gt\n"
  2840.                                      "     { /CairoImageDataIndex 0 def } if\n"
  2841.                                      "  } /ASCII85Decode filter /DCTDecode filter def\n");
  2842.     } else {
  2843.         _cairo_output_stream_printf (surface->stream,
  2844.                                      "  /DataSource currentfile /ASCII85Decode filter /DCTDecode filter def\n");
  2845.     }
  2846.  
  2847.     _cairo_output_stream_printf (surface->stream,
  2848.                                  "  /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
  2849.                                  "end\n"
  2850.                                  "image\n",
  2851.                                  info.height);
  2852.  
  2853.     if (!surface->use_string_datasource) {
  2854.         /* Emit the image data as a base85-encoded string which will
  2855.          * be used as the data source for the image operator. */
  2856.         status = _cairo_ps_surface_emit_base85_string (surface,
  2857.                                                        mime_data,
  2858.                                                        mime_data_length,
  2859.                                                        CAIRO_PS_COMPRESS_NONE,
  2860.                                                        FALSE);
  2861.     }
  2862.  
  2863.     return status;
  2864. }
  2865.  
  2866. static cairo_status_t
  2867. _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
  2868.                                           cairo_surface_t    *recording_surface)
  2869. {
  2870.     double old_width, old_height;
  2871.     cairo_matrix_t old_cairo_to_ps;
  2872.     cairo_content_t old_content;
  2873.     cairo_rectangle_int_t old_page_bbox;
  2874.     cairo_surface_t *free_me = NULL;
  2875.     cairo_surface_clipper_t old_clipper;
  2876.     cairo_box_t bbox;
  2877.     cairo_int_status_t status;
  2878.  
  2879.     old_content = surface->content;
  2880.     old_width = surface->width;
  2881.     old_height = surface->height;
  2882.     old_page_bbox = surface->page_bbox;
  2883.     old_cairo_to_ps = surface->cairo_to_ps;
  2884.     old_clipper = surface->clipper;
  2885.     _cairo_surface_clipper_init (&surface->clipper,
  2886.                                  _cairo_ps_surface_clipper_intersect_clip_path);
  2887.  
  2888.     if (_cairo_surface_is_snapshot (recording_surface))
  2889.         free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface);
  2890.  
  2891.     status =
  2892.         _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
  2893.                                            &bbox,
  2894.                                            NULL);
  2895.     if (unlikely (status))
  2896.         goto err;
  2897.  
  2898. #if DEBUG_PS
  2899.     _cairo_output_stream_printf (surface->stream,
  2900.                                  "%% _cairo_ps_surface_emit_recording_surface (%f, %f), (%f, %f)\n",
  2901.                                  _cairo_fixed_to_double (bbox.p1.x),
  2902.                                  _cairo_fixed_to_double (bbox.p1.y),
  2903.                                  _cairo_fixed_to_double (bbox.p2.x),
  2904.                                  _cairo_fixed_to_double (bbox.p2.y));
  2905. #endif
  2906.  
  2907.     surface->width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
  2908.     surface->height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
  2909.     _cairo_box_round_to_rectangle (&bbox, &surface->page_bbox);
  2910.  
  2911.     surface->current_pattern_is_solid_color = FALSE;
  2912.     _cairo_pdf_operators_reset (&surface->pdf_operators);
  2913.     cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
  2914.     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
  2915.                                                   &surface->cairo_to_ps);
  2916.     _cairo_output_stream_printf (surface->stream, "  q\n");
  2917.  
  2918.     if (recording_surface->content == CAIRO_CONTENT_COLOR) {
  2919.         surface->content = CAIRO_CONTENT_COLOR;
  2920.         _cairo_output_stream_printf (surface->stream,
  2921.                                      "  0 g %d %d %d %d rectfill\n",
  2922.                                      surface->page_bbox.x,
  2923.                                      surface->page_bbox.y,
  2924.                                      surface->page_bbox.width,
  2925.                                      surface->page_bbox.height);
  2926.     }
  2927.  
  2928.     status = _cairo_recording_surface_replay_region (recording_surface,
  2929.                                                      NULL,
  2930.                                                      &surface->base,
  2931.                                                      CAIRO_RECORDING_REGION_NATIVE);
  2932.     assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
  2933.     if (unlikely (status))
  2934.         goto err;
  2935.  
  2936.     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
  2937.     if (unlikely (status))
  2938.         goto err;
  2939.  
  2940.     _cairo_output_stream_printf (surface->stream, "  Q\n");
  2941.  
  2942.     _cairo_surface_clipper_reset (&surface->clipper);
  2943.     surface->clipper = old_clipper;
  2944.     surface->content = old_content;
  2945.     surface->width = old_width;
  2946.     surface->height = old_height;
  2947.     surface->page_bbox = old_page_bbox;
  2948.     surface->current_pattern_is_solid_color = FALSE;
  2949.     _cairo_pdf_operators_reset (&surface->pdf_operators);
  2950.     surface->cairo_to_ps = old_cairo_to_ps;
  2951.  
  2952.     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
  2953.                                                   &surface->cairo_to_ps);
  2954.  
  2955. err:
  2956.     cairo_surface_destroy (free_me);
  2957.     return status;
  2958. }
  2959.  
  2960. static cairo_int_status_t
  2961. _cairo_ps_surface_emit_recording_subsurface (cairo_ps_surface_t *surface,
  2962.                                              cairo_surface_t    *recording_surface,
  2963.                                              const cairo_rectangle_int_t *extents)
  2964. {
  2965.     double old_width, old_height;
  2966.     cairo_matrix_t old_cairo_to_ps;
  2967.     cairo_content_t old_content;
  2968.     cairo_rectangle_int_t old_page_bbox;
  2969.     cairo_surface_clipper_t old_clipper;
  2970.     cairo_surface_t *free_me = NULL;
  2971.     cairo_int_status_t status;
  2972.  
  2973.     old_content = surface->content;
  2974.     old_width = surface->width;
  2975.     old_height = surface->height;
  2976.     old_page_bbox = surface->page_bbox;
  2977.     old_cairo_to_ps = surface->cairo_to_ps;
  2978.     old_clipper = surface->clipper;
  2979.     _cairo_surface_clipper_init (&surface->clipper,
  2980.                                  _cairo_ps_surface_clipper_intersect_clip_path);
  2981.  
  2982. #if DEBUG_PS
  2983.     _cairo_output_stream_printf (surface->stream,
  2984.                                  "%% _cairo_ps_surface_emit_recording_subsurface (%d, %d), (%d, %d)\n",
  2985.                                  extents->x, extents->y,
  2986.                                  extents->width, extents->height);
  2987. #endif
  2988.  
  2989.     surface->page_bbox.x = surface->page_bbox.y = 0;
  2990.     surface->page_bbox.width = surface->width  = extents->width;
  2991.     surface->page_bbox.height = surface->height = extents->height;
  2992.  
  2993.     surface->current_pattern_is_solid_color = FALSE;
  2994.     _cairo_pdf_operators_reset (&surface->pdf_operators);
  2995.     cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
  2996.     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
  2997.                                                   &surface->cairo_to_ps);
  2998.     _cairo_output_stream_printf (surface->stream, "  q\n");
  2999.  
  3000.     if (_cairo_surface_is_snapshot (recording_surface))
  3001.         free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface);
  3002.  
  3003.     if (recording_surface->content == CAIRO_CONTENT_COLOR) {
  3004.         surface->content = CAIRO_CONTENT_COLOR;
  3005.         _cairo_output_stream_printf (surface->stream,
  3006.                                      "  0 g %d %d %d %d rectfill\n",
  3007.                                      surface->page_bbox.x,
  3008.                                      surface->page_bbox.y,
  3009.                                      surface->page_bbox.width,
  3010.                                      surface->page_bbox.height);
  3011.     }
  3012.  
  3013.     status = _cairo_recording_surface_replay_region (recording_surface,
  3014.                                                      extents,
  3015.                                                      &surface->base,
  3016.                                                      CAIRO_RECORDING_REGION_NATIVE);
  3017.     assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
  3018.     if (unlikely (status))
  3019.         goto err;
  3020.  
  3021.     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
  3022.     if (unlikely (status))
  3023.         goto err;
  3024.  
  3025.     _cairo_output_stream_printf (surface->stream, "  Q\n");
  3026.  
  3027.     _cairo_surface_clipper_reset (&surface->clipper);
  3028.     surface->clipper = old_clipper;
  3029.     surface->content = old_content;
  3030.     surface->width = old_width;
  3031.     surface->height = old_height;
  3032.     surface->page_bbox = old_page_bbox;
  3033.     surface->current_pattern_is_solid_color = FALSE;
  3034.     _cairo_pdf_operators_reset (&surface->pdf_operators);
  3035.     surface->cairo_to_ps = old_cairo_to_ps;
  3036.  
  3037.     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
  3038.                                                   &surface->cairo_to_ps);
  3039.  
  3040. err:
  3041.     cairo_surface_destroy (free_me);
  3042.     return status;
  3043. }
  3044.  
  3045. static void
  3046. _cairo_ps_surface_flatten_transparency (cairo_ps_surface_t      *surface,
  3047.                                         const cairo_color_t     *color,
  3048.                                         double                  *red,
  3049.                                         double                  *green,
  3050.                                         double                  *blue)
  3051. {
  3052.     *red   = color->red;
  3053.     *green = color->green;
  3054.     *blue  = color->blue;
  3055.  
  3056.     if (! CAIRO_COLOR_IS_OPAQUE (color)) {
  3057.         *red   *= color->alpha;
  3058.         *green *= color->alpha;
  3059.         *blue  *= color->alpha;
  3060.         if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
  3061.             double one_minus_alpha = 1. - color->alpha;
  3062.             *red   += one_minus_alpha;
  3063.             *green += one_minus_alpha;
  3064.             *blue  += one_minus_alpha;
  3065.         }
  3066.     }
  3067. }
  3068.  
  3069. static void
  3070. _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t    *surface,
  3071.                                       cairo_solid_pattern_t *pattern)
  3072. {
  3073.     double red, green, blue;
  3074.  
  3075.     _cairo_ps_surface_flatten_transparency (surface, &pattern->color, &red, &green, &blue);
  3076.  
  3077.     if (color_is_gray (red, green, blue))
  3078.         _cairo_output_stream_printf (surface->stream,
  3079.                                      "%f g\n",
  3080.                                      red);
  3081.     else
  3082.         _cairo_output_stream_printf (surface->stream,
  3083.                                      "%f %f %f rg\n",
  3084.                                      red, green, blue);
  3085. }
  3086.  
  3087. static cairo_status_t
  3088. _cairo_ps_surface_emit_surface (cairo_ps_surface_t      *surface,
  3089.                                 cairo_pattern_t         *source_pattern,
  3090.                                 cairo_surface_t         *source_surface,
  3091.                                 cairo_operator_t         op,
  3092.                                 int                      width,
  3093.                                 int                      height,
  3094.                                 cairo_bool_t             stencil_mask)
  3095. {
  3096.     cairo_int_status_t status;
  3097.  
  3098.     if (source_surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
  3099.         if (source_surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
  3100.             cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source_surface;
  3101.             status = _cairo_ps_surface_emit_recording_subsurface (surface, sub->target, &sub->extents);
  3102.         } else {
  3103.             status = _cairo_ps_surface_emit_recording_surface (surface, source_surface);
  3104.         }
  3105.     } else {
  3106.         cairo_image_surface_t *image = (cairo_image_surface_t *) source_surface;
  3107.         if (source_pattern->extend != CAIRO_EXTEND_PAD) {
  3108.             status = _cairo_ps_surface_emit_jpeg_image (surface, source_surface,
  3109.                                                         width, height);
  3110.             if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  3111.                 return status;
  3112.         }
  3113.  
  3114.         status = _cairo_ps_surface_emit_image (surface, image,
  3115.                                                op, source_pattern->filter, stencil_mask);
  3116.     }
  3117.  
  3118.     return status;
  3119. }
  3120.  
  3121.  
  3122. static void
  3123. _path_fixed_init_rectangle (cairo_path_fixed_t *path,
  3124.                             cairo_rectangle_int_t *rect)
  3125. {
  3126.     cairo_status_t status;
  3127.  
  3128.     _cairo_path_fixed_init (path);
  3129.  
  3130.     status = _cairo_path_fixed_move_to (path,
  3131.                                         _cairo_fixed_from_int (rect->x),
  3132.                                         _cairo_fixed_from_int (rect->y));
  3133.     assert (status == CAIRO_STATUS_SUCCESS);
  3134.     status = _cairo_path_fixed_rel_line_to (path,
  3135.                                             _cairo_fixed_from_int (rect->width),
  3136.                                             _cairo_fixed_from_int (0));
  3137.     assert (status == CAIRO_STATUS_SUCCESS);
  3138.     status = _cairo_path_fixed_rel_line_to (path,
  3139.                                             _cairo_fixed_from_int (0),
  3140.                                             _cairo_fixed_from_int (rect->height));
  3141.     assert (status == CAIRO_STATUS_SUCCESS);
  3142.     status = _cairo_path_fixed_rel_line_to (path,
  3143.                                             _cairo_fixed_from_int (-rect->width),
  3144.                                             _cairo_fixed_from_int (0));
  3145.     assert (status == CAIRO_STATUS_SUCCESS);
  3146.  
  3147.     status = _cairo_path_fixed_close_path (path);
  3148.     assert (status == CAIRO_STATUS_SUCCESS);
  3149. }
  3150.  
  3151. static cairo_status_t
  3152. _cairo_ps_surface_paint_surface (cairo_ps_surface_t     *surface,
  3153.                                  cairo_pattern_t        *pattern,
  3154.                                  cairo_rectangle_int_t  *extents,
  3155.                                  cairo_operator_t        op,
  3156.                                  cairo_bool_t            stencil_mask)
  3157. {
  3158.     cairo_status_t status;
  3159.     int width, height;
  3160.     cairo_matrix_t cairo_p2d, ps_p2d;
  3161.     cairo_path_fixed_t path;
  3162.     double x_offset, y_offset;
  3163.     cairo_surface_t *source;
  3164.     cairo_image_surface_t *image = NULL;
  3165.     void *image_extra;
  3166.  
  3167.     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
  3168.     if (unlikely (status))
  3169.         return status;
  3170.  
  3171.     status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
  3172.                                                                     pattern,
  3173.                                                                     extents,
  3174.                                                                     &width, &height,
  3175.                                                                     &x_offset, &y_offset,
  3176.                                                                     &source,
  3177.                                                                     &image_extra);
  3178.     if (unlikely (status))
  3179.         return status;
  3180.  
  3181.     if (pattern->extend == CAIRO_EXTEND_PAD &&
  3182.         pattern->type == CAIRO_PATTERN_TYPE_SURFACE &&
  3183.         ((cairo_surface_pattern_t *)pattern)->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
  3184.         cairo_image_surface_t *img;
  3185.  
  3186.         img = (cairo_image_surface_t *) source;
  3187.         status = _cairo_ps_surface_create_padded_image_from_image (surface,
  3188.                                                                    img,
  3189.                                                                    &pattern->matrix,
  3190.                                                                    extents,
  3191.                                                                    &width, &height,
  3192.                                                                    &x_offset, &y_offset,
  3193.                                                                    &image);
  3194.         if (unlikely (status))
  3195.             goto release_source;
  3196.     }
  3197.  
  3198.     _path_fixed_init_rectangle (&path, extents);
  3199.     status = _cairo_pdf_operators_clip (&surface->pdf_operators,
  3200.                                         &path,
  3201.                                         CAIRO_FILL_RULE_WINDING);
  3202.     _cairo_path_fixed_fini (&path);
  3203.     if (unlikely (status))
  3204.         goto release_source;
  3205.  
  3206.     cairo_p2d = pattern->matrix;
  3207.  
  3208.     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
  3209.         double x_scale = cairo_p2d.xx;
  3210.         double y_scale = cairo_p2d.yy;
  3211.  
  3212.         _cairo_output_stream_printf (surface->stream,
  3213.                                      "%% Fallback Image: x=%f y=%f w=%d h=%d ",
  3214.                                      -cairo_p2d.x0/x_scale,
  3215.                                      -cairo_p2d.y0/y_scale,
  3216.                                      (int)(width/x_scale),
  3217.                                      (int)(height/y_scale));
  3218.         if (x_scale == y_scale) {
  3219.             _cairo_output_stream_printf (surface->stream,
  3220.                                          "res=%fppi ",
  3221.                                          x_scale*72);
  3222.         } else {
  3223.             _cairo_output_stream_printf (surface->stream,
  3224.                                          "res=%fx%fppi ",
  3225.                                          x_scale*72,
  3226.                                          y_scale*72);
  3227.         }
  3228.         _cairo_output_stream_printf (surface->stream,
  3229.                                      "size=%ld\n",
  3230.                                      (long)width*height*3);
  3231.     } else {
  3232.         if (op == CAIRO_OPERATOR_SOURCE) {
  3233.             _cairo_output_stream_printf (surface->stream,
  3234.                                          "%d g 0 0 %f %f rectfill\n",
  3235.                                          surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
  3236.                                          surface->width,
  3237.                                          surface->height);
  3238.         }
  3239.     }
  3240.  
  3241.     status = cairo_matrix_invert (&cairo_p2d);
  3242.     /* cairo_pattern_set_matrix ensures the matrix is invertible */
  3243.     assert (status == CAIRO_STATUS_SUCCESS);
  3244.  
  3245.     ps_p2d = surface->cairo_to_ps;
  3246.     cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
  3247.     cairo_matrix_translate (&ps_p2d, x_offset, y_offset);
  3248.     cairo_matrix_translate (&ps_p2d, 0.0, height);
  3249.     cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
  3250.  
  3251.     if (! _cairo_matrix_is_identity (&ps_p2d)) {
  3252.         _cairo_output_stream_printf (surface->stream,
  3253.                                      "[ %f %f %f %f %f %f ] concat\n",
  3254.                                      ps_p2d.xx, ps_p2d.yx,
  3255.                                      ps_p2d.xy, ps_p2d.yy,
  3256.                                      ps_p2d.x0, ps_p2d.y0);
  3257.     }
  3258.  
  3259.     status = _cairo_ps_surface_emit_surface (surface,
  3260.                                              pattern,
  3261.                                              image ? &image->base : source,
  3262.                                              op,
  3263.                                              width, height,
  3264.                                              stencil_mask);
  3265.  
  3266.   release_source:
  3267.     if (image)
  3268.         cairo_surface_destroy (&image->base);
  3269.  
  3270.     _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
  3271.  
  3272.     return status;
  3273. }
  3274.  
  3275. static cairo_status_t
  3276. _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t      *surface,
  3277.                                         cairo_pattern_t         *pattern,
  3278.                                         cairo_rectangle_int_t   *extents,
  3279.                                         cairo_operator_t         op)
  3280. {
  3281.     cairo_status_t status;
  3282.     int pattern_width = 0; /* squelch bogus compiler warning */
  3283.     int pattern_height = 0; /* squelch bogus compiler warning */
  3284.     double xstep, ystep;
  3285.     cairo_matrix_t cairo_p2d, ps_p2d;
  3286.     cairo_bool_t old_use_string_datasource;
  3287.     double x_offset, y_offset;
  3288.     cairo_surface_t *source;
  3289.     cairo_image_surface_t *image = NULL;
  3290.     void *image_extra;
  3291.  
  3292.     cairo_p2d = pattern->matrix;
  3293.     status = cairo_matrix_invert (&cairo_p2d);
  3294.     /* cairo_pattern_set_matrix ensures the matrix is invertible */
  3295.     assert (status == CAIRO_STATUS_SUCCESS);
  3296.  
  3297.     status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
  3298.                                                                     pattern,
  3299.                                                                     extents,
  3300.                                                                     &pattern_width, &pattern_height,
  3301.                                                                     &x_offset, &y_offset,
  3302.                                                                     &source,
  3303.                                                                     &image_extra);
  3304.     if (unlikely (status))
  3305.         return status;
  3306.  
  3307.     if (pattern->extend == CAIRO_EXTEND_PAD) {
  3308.         cairo_image_surface_t *img;
  3309.  
  3310.         assert (source->type == CAIRO_SURFACE_TYPE_IMAGE);
  3311.         img = (cairo_image_surface_t *) source;
  3312.         status = _cairo_ps_surface_create_padded_image_from_image (surface,
  3313.                                                                    img,
  3314.                                                                    &pattern->matrix,
  3315.                                                                    extents,
  3316.                                                                    &pattern_width, &pattern_height,
  3317.                                                                    &x_offset, &y_offset,
  3318.                                                                    &image);
  3319.         if (unlikely (status))
  3320.             goto release_source;
  3321.     }
  3322.     if (unlikely (status))
  3323.         goto release_source;
  3324.  
  3325.     switch (pattern->extend) {
  3326.     case CAIRO_EXTEND_PAD:
  3327.     case CAIRO_EXTEND_NONE:
  3328.     {
  3329.         /* In PS/PDF, (as far as I can tell), all patterns are
  3330.          * repeating. So we support cairo's EXTEND_NONE semantics
  3331.          * by setting the repeat step size to a size large enough
  3332.          * to guarantee that no more than a single occurrence will
  3333.          * be visible.
  3334.          *
  3335.          * First, map the surface extents into pattern space (since
  3336.          * xstep and ystep are in pattern space).  Then use an upper
  3337.          * bound on the length of the diagonal of the pattern image
  3338.          * and the surface as repeat size.  This guarantees to never
  3339.          * repeat visibly.
  3340.          */
  3341.         double x1 = 0.0, y1 = 0.0;
  3342.         double x2 = surface->width, y2 = surface->height;
  3343.         _cairo_matrix_transform_bounding_box (&pattern->matrix,
  3344.                                               &x1, &y1, &x2, &y2,
  3345.                                               NULL);
  3346.  
  3347.         /* Rather than computing precise bounds of the union, just
  3348.          * add the surface extents unconditionally. We only
  3349.          * required an answer that's large enough, we don't really
  3350.          * care if it's not as tight as possible.*/
  3351.         xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
  3352.                               pattern_width + pattern_height);
  3353.         break;
  3354.     }
  3355.     case CAIRO_EXTEND_REPEAT:
  3356.         xstep = pattern_width;
  3357.         ystep = pattern_height;
  3358.         break;
  3359.     case CAIRO_EXTEND_REFLECT:
  3360.         xstep = pattern_width*2;
  3361.         ystep = pattern_height*2;
  3362.         break;
  3363.         /* All the rest (if any) should have been analyzed away, so these
  3364.          * cases should be unreachable. */
  3365.     default:
  3366.         ASSERT_NOT_REACHED;
  3367.         xstep = 0;
  3368.         ystep = 0;
  3369.     }
  3370.  
  3371.     _cairo_output_stream_printf (surface->stream,
  3372.                                  "/CairoPattern {\n");
  3373.  
  3374.     old_use_string_datasource = surface->use_string_datasource;
  3375.     surface->use_string_datasource = TRUE;
  3376.     if (op == CAIRO_OPERATOR_SOURCE) {
  3377.         _cairo_output_stream_printf (surface->stream,
  3378.                                      "%d g 0 0 %f %f rectfill\n",
  3379.                                      surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
  3380.                                      xstep, ystep);
  3381.     }
  3382.     status = _cairo_ps_surface_emit_surface (surface,
  3383.                                              pattern,
  3384.                                              image ? &image->base : source,
  3385.                                              op,
  3386.                                              pattern_width, pattern_height, FALSE);
  3387.     if (unlikely (status))
  3388.         goto release_source;
  3389.  
  3390.     surface->use_string_datasource = old_use_string_datasource;
  3391.     _cairo_output_stream_printf (surface->stream,
  3392.                                  "} bind def\n");
  3393.  
  3394.     _cairo_output_stream_printf (surface->stream,
  3395.                                  "<< /PatternType 1\n"
  3396.                                  "   /PaintType 1\n"
  3397.                                  "   /TilingType 1\n");
  3398.     _cairo_output_stream_printf (surface->stream,
  3399.                                  "   /XStep %f /YStep %f\n",
  3400.                                  xstep, ystep);
  3401.  
  3402.     if (pattern->extend == CAIRO_EXTEND_REFLECT) {
  3403.         _cairo_output_stream_printf (surface->stream,
  3404.                                      "   /BBox [0 0 %d %d]\n"
  3405.                                      "   /PaintProc {\n"
  3406.                                      "      CairoPattern\n"
  3407.                                      "      [-1 0 0  1 %d 0] concat CairoPattern\n"
  3408.                                      "      [ 1 0 0 -1 0 %d] concat CairoPattern\n"
  3409.                                      "      [-1 0 0  1 %d 0] concat CairoPattern\n"
  3410.                                      "      CairoPattern\n"
  3411.                                      "   } bind\n",
  3412.                                      pattern_width*2, pattern_height*2,
  3413.                                      pattern_width*2,
  3414.                                      pattern_height*2,
  3415.                                      pattern_width*2);
  3416.     } else {
  3417.         if (op == CAIRO_OPERATOR_SOURCE) {
  3418.             _cairo_output_stream_printf (surface->stream,
  3419.                                          "   /BBox [0 0 %f %f]\n",
  3420.                                          xstep, ystep);
  3421.         } else {
  3422.             _cairo_output_stream_printf (surface->stream,
  3423.                                          "   /BBox [0 0 %d %d]\n",
  3424.                                          pattern_width, pattern_height);
  3425.         }
  3426.         _cairo_output_stream_printf (surface->stream,
  3427.                                      "   /PaintProc { CairoPattern }\n");
  3428.     }
  3429.  
  3430.     _cairo_output_stream_printf (surface->stream,
  3431.                                  ">>\n");
  3432.  
  3433.     cairo_p2d = pattern->matrix;
  3434.     status = cairo_matrix_invert (&cairo_p2d);
  3435.     /* cairo_pattern_set_matrix ensures the matrix is invertible */
  3436.     assert (status == CAIRO_STATUS_SUCCESS);
  3437.  
  3438.     cairo_matrix_init_identity (&ps_p2d);
  3439.     cairo_matrix_translate (&ps_p2d, 0.0, surface->height);
  3440.     cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
  3441.     cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
  3442.     cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
  3443.     cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
  3444.  
  3445.     _cairo_output_stream_printf (surface->stream,
  3446.                                  "[ %f %f %f %f %f %f ]\n",
  3447.                                  ps_p2d.xx, ps_p2d.yx,
  3448.                                  ps_p2d.xy, ps_p2d.yy,
  3449.                                  ps_p2d.x0, ps_p2d.y0);
  3450.     _cairo_output_stream_printf (surface->stream,
  3451.                                  "makepattern setpattern\n");
  3452.  
  3453.   release_source:
  3454.     if (image)
  3455.         cairo_surface_destroy (&image->base);
  3456.  
  3457.     _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source, image_extra);
  3458.  
  3459.     return status;
  3460. }
  3461.  
  3462. typedef struct _cairo_ps_color_stop {
  3463.     double offset;
  3464.     double color[4];
  3465. } cairo_ps_color_stop_t;
  3466.  
  3467. static void
  3468. _cairo_ps_surface_emit_linear_colorgradient (cairo_ps_surface_t     *surface,
  3469.                                              cairo_ps_color_stop_t  *stop1,
  3470.                                              cairo_ps_color_stop_t  *stop2)
  3471. {
  3472.     _cairo_output_stream_printf (surface->stream,
  3473.                                  "   << /FunctionType 2\n"
  3474.                                  "      /Domain [ 0 1 ]\n"
  3475.                                  "      /C0 [ %f %f %f ]\n"
  3476.                                  "      /C1 [ %f %f %f ]\n"
  3477.                                  "      /N 1\n"
  3478.                                  "   >>\n",
  3479.                                  stop1->color[0],
  3480.                                  stop1->color[1],
  3481.                                  stop1->color[2],
  3482.                                  stop2->color[0],
  3483.                                  stop2->color[1],
  3484.                                  stop2->color[2]);
  3485. }
  3486.  
  3487. static void
  3488. _cairo_ps_surface_emit_stitched_colorgradient (cairo_ps_surface_t    *surface,
  3489.                                                unsigned int           n_stops,
  3490.                                                cairo_ps_color_stop_t  stops[])
  3491. {
  3492.     unsigned int i;
  3493.  
  3494.     _cairo_output_stream_printf (surface->stream,
  3495.                                  "<< /FunctionType 3\n"
  3496.                                  "   /Domain [ 0 1 ]\n"
  3497.                                  "   /Functions [\n");
  3498.     for (i = 0; i < n_stops - 1; i++)
  3499.         _cairo_ps_surface_emit_linear_colorgradient (surface, &stops[i], &stops[i+1]);
  3500.  
  3501.     _cairo_output_stream_printf (surface->stream, "   ]\n");
  3502.  
  3503.     _cairo_output_stream_printf (surface->stream, "   /Bounds [ ");
  3504.     for (i = 1; i < n_stops-1; i++)
  3505.         _cairo_output_stream_printf (surface->stream, "%f ", stops[i].offset);
  3506.     _cairo_output_stream_printf (surface->stream, "]\n");
  3507.  
  3508.     _cairo_output_stream_printf (surface->stream, "   /Encode [ 1 1 %d { pop 0 1 } for ]\n",
  3509.                                  n_stops - 1);
  3510.  
  3511.     _cairo_output_stream_printf (surface->stream, ">>\n");
  3512. }
  3513.  
  3514. static void
  3515. calc_gradient_color (cairo_ps_color_stop_t *new_stop,
  3516.                      cairo_ps_color_stop_t *stop1,
  3517.                      cairo_ps_color_stop_t *stop2)
  3518. {
  3519.     int i;
  3520.     double offset = stop1->offset / (stop1->offset + 1.0 - stop2->offset);
  3521.  
  3522.     for (i = 0; i < 4; i++)
  3523.         new_stop->color[i] = stop1->color[i] + offset*(stop2->color[i] - stop1->color[i]);
  3524. }
  3525.  
  3526. #define COLOR_STOP_EPSILON 1e-6
  3527.  
  3528. static cairo_status_t
  3529. _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t       *surface,
  3530.                                       cairo_gradient_pattern_t *pattern)
  3531. {
  3532.     cairo_ps_color_stop_t *allstops, *stops;
  3533.     unsigned int i, n_stops;
  3534.  
  3535.     allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_ps_color_stop_t));
  3536.     if (unlikely (allstops == NULL))
  3537.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  3538.  
  3539.     stops = &allstops[1];
  3540.     n_stops = pattern->n_stops;
  3541.  
  3542.     for (i = 0; i < n_stops; i++) {
  3543.         cairo_gradient_stop_t *stop = &pattern->stops[i];
  3544.  
  3545.         stops[i].color[0] = stop->color.red;
  3546.         stops[i].color[1] = stop->color.green;
  3547.         stops[i].color[2] = stop->color.blue;
  3548.         stops[i].color[3] = stop->color.alpha;
  3549.         stops[i].offset = pattern->stops[i].offset;
  3550.     }
  3551.  
  3552.     if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
  3553.         pattern->base.extend == CAIRO_EXTEND_REFLECT)
  3554.     {
  3555.         if (stops[0].offset > COLOR_STOP_EPSILON) {
  3556.             if (pattern->base.extend == CAIRO_EXTEND_REFLECT)
  3557.                 memcpy (allstops, stops, sizeof (cairo_ps_color_stop_t));
  3558.             else
  3559.                 calc_gradient_color (&allstops[0], &stops[0], &stops[n_stops-1]);
  3560.             stops = allstops;
  3561.             n_stops++;
  3562.         }
  3563.         stops[0].offset = 0.0;
  3564.  
  3565.         if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
  3566.             if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
  3567.                 memcpy (&stops[n_stops],
  3568.                         &stops[n_stops - 1],
  3569.                         sizeof (cairo_ps_color_stop_t));
  3570.             } else {
  3571.                 calc_gradient_color (&stops[n_stops], &stops[0], &stops[n_stops-1]);
  3572.             }
  3573.             n_stops++;
  3574.         }
  3575.         stops[n_stops-1].offset = 1.0;
  3576.     }
  3577.  
  3578.     for (i = 0; i < n_stops; i++) {
  3579.         double red, green, blue;
  3580.         cairo_color_t color;
  3581.  
  3582.         _cairo_color_init_rgba (&color,
  3583.                                 stops[i].color[0],
  3584.                                 stops[i].color[1],
  3585.                                 stops[i].color[2],
  3586.                                 stops[i].color[3]);
  3587.         _cairo_ps_surface_flatten_transparency (surface, &color,
  3588.                                                 &red, &green, &blue);
  3589.         stops[i].color[0] = red;
  3590.         stops[i].color[1] = green;
  3591.         stops[i].color[2] = blue;
  3592.     }
  3593.  
  3594.     _cairo_output_stream_printf (surface->stream,
  3595.                                  "/CairoFunction\n");
  3596.     if (stops[0].offset == stops[n_stops - 1].offset) {
  3597.         /*
  3598.          * The first and the last stops have the same offset, but we
  3599.          * don't want a function with an empty domain, because that
  3600.          * would provoke underdefined behaviour from rasterisers.
  3601.          * This can only happen with EXTEND_PAD, because EXTEND_NONE
  3602.          * is optimised into a clear pattern in cairo-gstate, and
  3603.          * REFLECT/REPEAT are always transformed to have the first
  3604.          * stop at t=0 and the last stop at t=1.  Thus we want a step
  3605.          * function going from the first color to the last one.
  3606.          *
  3607.          * This can be accomplished by stitching three functions:
  3608.          *  - a constant first color function,
  3609.          *  - a step from the first color to the last color (with empty domain)
  3610.          *  - a constant last color function
  3611.          */
  3612.         cairo_ps_color_stop_t pad_stops[4];
  3613.  
  3614.         assert (pattern->base.extend == CAIRO_EXTEND_PAD);
  3615.  
  3616.         pad_stops[0] = pad_stops[1] = stops[0];
  3617.         pad_stops[2] = pad_stops[3] = stops[n_stops - 1];
  3618.  
  3619.         pad_stops[0].offset = 0;
  3620.         pad_stops[3].offset = 1;
  3621.  
  3622.         _cairo_ps_surface_emit_stitched_colorgradient (surface, 4, pad_stops);
  3623.     } else if (n_stops == 2) {
  3624.         /* no need for stitched function */
  3625.         _cairo_ps_surface_emit_linear_colorgradient (surface, &stops[0], &stops[1]);
  3626.     } else {
  3627.         /* multiple stops: stitch. XXX possible optimization: regulary spaced
  3628.          * stops do not require stitching. XXX */
  3629.         _cairo_ps_surface_emit_stitched_colorgradient (surface, n_stops, stops);
  3630.     }
  3631.     _cairo_output_stream_printf (surface->stream,
  3632.                                  "def\n");
  3633.  
  3634.     free (allstops);
  3635.  
  3636.     return CAIRO_STATUS_SUCCESS;
  3637. }
  3638.  
  3639. static cairo_status_t
  3640. _cairo_ps_surface_emit_repeating_function (cairo_ps_surface_t       *surface,
  3641.                                            cairo_gradient_pattern_t *pattern,
  3642.                                            int                       begin,
  3643.                                            int                       end)
  3644. {
  3645.     _cairo_output_stream_printf (surface->stream,
  3646.                                  "/CairoFunction\n"
  3647.                                  "<< /FunctionType 3\n"
  3648.                                  "   /Domain [ %d %d ]\n"
  3649.                                  "   /Functions [ %d {CairoFunction} repeat ]\n"
  3650.                                  "   /Bounds [ %d 1 %d {} for ]\n",
  3651.                                  begin,
  3652.                                  end,
  3653.                                  end - begin,
  3654.                                  begin + 1,
  3655.                                  end - 1);
  3656.  
  3657.     if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
  3658.         _cairo_output_stream_printf (surface->stream, "   /Encode [ %d 1 %d { 2 mod 0 eq {0 1} {1 0} ifelse } for ]\n",
  3659.                                      begin,
  3660.                                      end - 1);
  3661.     } else {
  3662.         _cairo_output_stream_printf (surface->stream, "   /Encode [ %d 1 %d { pop 0 1 } for ]\n",
  3663.                                      begin,
  3664.                                      end - 1);
  3665.     }
  3666.  
  3667.     _cairo_output_stream_printf (surface->stream, ">> def\n");
  3668.  
  3669.     return CAIRO_STATUS_SUCCESS;
  3670. }
  3671.  
  3672. static cairo_status_t
  3673. _cairo_ps_surface_emit_gradient (cairo_ps_surface_t       *surface,
  3674.                                  cairo_gradient_pattern_t *pattern,
  3675.                                  cairo_bool_t              is_ps_pattern)
  3676. {
  3677.     cairo_matrix_t pat_to_ps;
  3678.     cairo_circle_double_t start, end;
  3679.     double domain[2];
  3680.     cairo_status_t status;
  3681.  
  3682.     assert (pattern->n_stops != 0);
  3683.  
  3684.     status = _cairo_ps_surface_emit_pattern_stops (surface, pattern);
  3685.     if (unlikely (status))
  3686.         return status;
  3687.  
  3688.     pat_to_ps = pattern->base.matrix;
  3689.     status = cairo_matrix_invert (&pat_to_ps);
  3690.     /* cairo_pattern_set_matrix ensures the matrix is invertible */
  3691.     assert (status == CAIRO_STATUS_SUCCESS);
  3692.     cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
  3693.  
  3694.     if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
  3695.         pattern->base.extend == CAIRO_EXTEND_REFLECT)
  3696.     {
  3697.         double bounds_x1, bounds_x2, bounds_y1, bounds_y2;
  3698.         double x_scale, y_scale, tolerance;
  3699.  
  3700.         /* TODO: use tighter extents */
  3701.         bounds_x1 = 0;
  3702.         bounds_y1 = 0;
  3703.         bounds_x2 = surface->width;
  3704.         bounds_y2 = surface->height;
  3705.         _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
  3706.                                               &bounds_x1, &bounds_y1,
  3707.                                               &bounds_x2, &bounds_y2,
  3708.                                               NULL);
  3709.  
  3710.         x_scale = surface->base.x_resolution / surface->base.x_fallback_resolution;
  3711.         y_scale = surface->base.y_resolution / surface->base.y_fallback_resolution;
  3712.  
  3713.         tolerance = fabs (_cairo_matrix_compute_determinant (&pattern->base.matrix));
  3714.         tolerance /= _cairo_matrix_transformed_circle_major_axis (&pattern->base.matrix, 1);
  3715.         tolerance *= MIN (x_scale, y_scale);
  3716.  
  3717.         _cairo_gradient_pattern_box_to_parameter (pattern,
  3718.                                                   bounds_x1, bounds_y1,
  3719.                                                   bounds_x2, bounds_y2,
  3720.                                                   tolerance, domain);
  3721.     } else if (pattern->stops[0].offset == pattern->stops[pattern->n_stops - 1].offset) {
  3722.         /*
  3723.          * If the first and the last stop offset are the same, then
  3724.          * the color function is a step function.
  3725.          * _cairo_ps_surface_emit_pattern_stops emits it as a stitched
  3726.          * function no matter how many stops the pattern has.  The
  3727.          * domain of the stitched function will be [0 1] in this case.
  3728.          *
  3729.          * This is done to avoid emitting degenerate gradients for
  3730.          * EXTEND_PAD patterns having a step color function.
  3731.          */
  3732.         domain[0] = 0.0;
  3733.         domain[1] = 1.0;
  3734.  
  3735.         assert (pattern->base.extend == CAIRO_EXTEND_PAD);
  3736.     } else {
  3737.         domain[0] = pattern->stops[0].offset;
  3738.         domain[1] = pattern->stops[pattern->n_stops - 1].offset;
  3739.     }
  3740.  
  3741.     /* PS requires the first and last stop to be the same as the
  3742.      * extreme coordinates. For repeating patterns this moves the
  3743.      * extreme coordinates out to the begin/end of the repeating
  3744.      * function. For non repeating patterns this may move the extreme
  3745.      * coordinates in if there are not stops at offset 0 and 1. */
  3746.     _cairo_gradient_pattern_interpolate (pattern, domain[0], &start);
  3747.     _cairo_gradient_pattern_interpolate (pattern, domain[1], &end);
  3748.  
  3749.     if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
  3750.         pattern->base.extend == CAIRO_EXTEND_REFLECT)
  3751.     {
  3752.         int repeat_begin, repeat_end;
  3753.  
  3754.         repeat_begin = floor (domain[0]);
  3755.         repeat_end = ceil (domain[1]);
  3756.  
  3757.         status = _cairo_ps_surface_emit_repeating_function (surface,
  3758.                                                             pattern,
  3759.                                                             repeat_begin,
  3760.                                                             repeat_end);
  3761.         if (unlikely (status))
  3762.             return status;
  3763.     } else if (pattern->n_stops <= 2) {
  3764.         /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a
  3765.          * Type 2 function is used by itself without a stitching
  3766.          * function. Type 2 functions always have the domain [0 1] */
  3767.         domain[0] = 0.0;
  3768.         domain[1] = 1.0;
  3769.     }
  3770.  
  3771.     if (is_ps_pattern) {
  3772.         _cairo_output_stream_printf (surface->stream,
  3773.                                      "<< /PatternType 2\n"
  3774.                                      "   /Shading\n");
  3775.     }
  3776.  
  3777.     if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
  3778.         _cairo_output_stream_printf (surface->stream,
  3779.                                      "   << /ShadingType 2\n"
  3780.                                      "      /ColorSpace /DeviceRGB\n"
  3781.                                      "      /Coords [ %f %f %f %f ]\n",
  3782.                                      start.center.x, start.center.y,
  3783.                                      end.center.x, end.center.y);
  3784.     } else {
  3785.         _cairo_output_stream_printf (surface->stream,
  3786.                                      "   << /ShadingType 3\n"
  3787.                                      "      /ColorSpace /DeviceRGB\n"
  3788.                                      "      /Coords [ %f %f %f %f %f %f ]\n",
  3789.                                      start.center.x, start.center.y,
  3790.                                      MAX (start.radius, 0),
  3791.                                      end.center.x, end.center.y,
  3792.                                      MAX (end.radius, 0));
  3793.     }
  3794.  
  3795.     if (pattern->base.extend != CAIRO_EXTEND_NONE) {
  3796.         _cairo_output_stream_printf (surface->stream,
  3797.                                      "      /Extend [ true true ]\n");
  3798.     } else {
  3799.         _cairo_output_stream_printf (surface->stream,
  3800.                                      "      /Extend [ false false ]\n");
  3801.     }
  3802.  
  3803.     if (domain[0] == 0.0 && domain[1] == 1.0) {
  3804.         _cairo_output_stream_printf (surface->stream,
  3805.                                      "      /Function CairoFunction\n");
  3806.     } else {
  3807.         _cairo_output_stream_printf (surface->stream,
  3808.                                      "      /Function <<\n"
  3809.                                      "         /FunctionType 3\n"
  3810.                                      "         /Domain [ 0 1 ]\n"
  3811.                                      "         /Bounds [ ]\n"
  3812.                                      "         /Encode [ %f %f ]\n"
  3813.                                      "         /Functions [ CairoFunction ]\n"
  3814.                                      "      >>\n",
  3815.                                      domain[0], domain[1]);
  3816.     }
  3817.  
  3818.     _cairo_output_stream_printf (surface->stream,
  3819.                                  "   >>\n");
  3820.  
  3821.     if (is_ps_pattern) {
  3822.         _cairo_output_stream_printf (surface->stream,
  3823.                                      ">>\n"
  3824.                                      "[ %f %f %f %f %f %f ]\n"
  3825.                                      "makepattern setpattern\n",
  3826.                                      pat_to_ps.xx, pat_to_ps.yx,
  3827.                                      pat_to_ps.xy, pat_to_ps.yy,
  3828.                                      pat_to_ps.x0, pat_to_ps.y0);
  3829.     } else {
  3830.         _cairo_output_stream_printf (surface->stream,
  3831.                                      "shfill\n");
  3832.     }
  3833.  
  3834.     return status;
  3835. }
  3836.  
  3837. static cairo_status_t
  3838. _cairo_ps_surface_emit_mesh_pattern (cairo_ps_surface_t     *surface,
  3839.                                      cairo_mesh_pattern_t   *pattern,
  3840.                                      cairo_bool_t            is_ps_pattern)
  3841. {
  3842.     cairo_matrix_t pat_to_ps;
  3843.     cairo_status_t status;
  3844.     cairo_pdf_shading_t shading;
  3845.     int i;
  3846.  
  3847.     if (_cairo_array_num_elements (&pattern->patches) == 0)
  3848.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  3849.  
  3850.     pat_to_ps = pattern->base.matrix;
  3851.     status = cairo_matrix_invert (&pat_to_ps);
  3852.     /* cairo_pattern_set_matrix ensures the matrix is invertible */
  3853.     assert (status == CAIRO_STATUS_SUCCESS);
  3854.  
  3855.     cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
  3856.  
  3857.     status = _cairo_pdf_shading_init_color (&shading, pattern);
  3858.     if (unlikely (status))
  3859.         return status;
  3860.  
  3861.     _cairo_output_stream_printf (surface->stream,
  3862.                                  "currentfile\n"
  3863.                                  "/ASCII85Decode filter /FlateDecode filter /ReusableStreamDecode filter\n");
  3864.  
  3865.     status = _cairo_ps_surface_emit_base85_string (surface,
  3866.                                                    shading.data,
  3867.                                                    shading.data_length,
  3868.                                                    CAIRO_PS_COMPRESS_DEFLATE,
  3869.                                                    FALSE);
  3870.     if (status)
  3871.         return status;
  3872.  
  3873.     _cairo_output_stream_printf (surface->stream,
  3874.                                  "\n"
  3875.                                  "/CairoData exch def\n");
  3876.  
  3877.     if (is_ps_pattern) {
  3878.         _cairo_output_stream_printf (surface->stream,
  3879.                                      "<< /PatternType 2\n"
  3880.                                      "   /Shading\n");
  3881.     }
  3882.  
  3883.     _cairo_output_stream_printf (surface->stream,
  3884.                                  "   << /ShadingType %d\n"
  3885.                                  "      /ColorSpace /DeviceRGB\n"
  3886.                                  "      /DataSource CairoData\n"
  3887.                                  "      /BitsPerCoordinate %d\n"
  3888.                                  "      /BitsPerComponent %d\n"
  3889.                                  "      /BitsPerFlag %d\n"
  3890.                                  "      /Decode [",
  3891.                                  shading.shading_type,
  3892.                                  shading.bits_per_coordinate,
  3893.                                  shading.bits_per_component,
  3894.                                  shading.bits_per_flag);
  3895.  
  3896.     for (i = 0; i < shading.decode_array_length; i++)
  3897.         _cairo_output_stream_printf (surface->stream, "%f ", shading.decode_array[i]);
  3898.  
  3899.     _cairo_output_stream_printf (surface->stream,
  3900.                                  "]\n"
  3901.                                  "   >>\n");
  3902.  
  3903.     if (is_ps_pattern) {
  3904.         _cairo_output_stream_printf (surface->stream,
  3905.                                      ">>\n"
  3906.                                      "[ %f %f %f %f %f %f ]\n",
  3907.                                      pat_to_ps.xx, pat_to_ps.yx,
  3908.                                      pat_to_ps.xy, pat_to_ps.yy,
  3909.                                      pat_to_ps.x0, pat_to_ps.y0);
  3910.         _cairo_output_stream_printf (surface->stream,
  3911.                                      "makepattern\n"
  3912.                                      "setpattern\n");
  3913.     } else {
  3914.         _cairo_output_stream_printf (surface->stream, "shfill\n");
  3915.     }
  3916.  
  3917.     _cairo_output_stream_printf (surface->stream,
  3918.                                  "currentdict /CairoData undef\n");
  3919.  
  3920.     _cairo_pdf_shading_fini (&shading);
  3921.  
  3922.     return status;
  3923. }
  3924.  
  3925. static cairo_status_t
  3926. _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
  3927.                                 const cairo_pattern_t *pattern,
  3928.                                 cairo_rectangle_int_t *extents,
  3929.                                 cairo_operator_t       op)
  3930. {
  3931.     cairo_status_t status;
  3932.  
  3933.     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
  3934.         cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
  3935.  
  3936.         if (surface->current_pattern_is_solid_color == FALSE ||
  3937.             ! _cairo_color_equal (&surface->current_color, &solid->color))
  3938.         {
  3939.             status = _cairo_pdf_operators_flush (&surface->pdf_operators);
  3940.             if (unlikely (status))
  3941.                 return status;
  3942.  
  3943.             _cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
  3944.  
  3945.             surface->current_pattern_is_solid_color = TRUE;
  3946.             surface->current_color = solid->color;
  3947.         }
  3948.  
  3949.         return CAIRO_STATUS_SUCCESS;
  3950.     }
  3951.  
  3952.     surface->current_pattern_is_solid_color = FALSE;
  3953.     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
  3954.     if (unlikely (status))
  3955.             return status;
  3956.  
  3957.     switch (pattern->type) {
  3958.     case CAIRO_PATTERN_TYPE_SOLID:
  3959.  
  3960.         _cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
  3961.         break;
  3962.  
  3963.     case CAIRO_PATTERN_TYPE_SURFACE:
  3964.     case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
  3965.         status = _cairo_ps_surface_emit_surface_pattern (surface,
  3966.                                                          (cairo_pattern_t *)pattern,
  3967.                                                          extents,
  3968.                                                          op);
  3969.         if (unlikely (status))
  3970.             return status;
  3971.         break;
  3972.  
  3973.     case CAIRO_PATTERN_TYPE_LINEAR:
  3974.     case CAIRO_PATTERN_TYPE_RADIAL:
  3975.         status = _cairo_ps_surface_emit_gradient (surface,
  3976.                                                   (cairo_gradient_pattern_t *) pattern,
  3977.                                                   TRUE);
  3978.         if (unlikely (status))
  3979.             return status;
  3980.         break;
  3981.  
  3982.     case CAIRO_PATTERN_TYPE_MESH:
  3983.         status = _cairo_ps_surface_emit_mesh_pattern (surface,
  3984.                                                       (cairo_mesh_pattern_t *) pattern,
  3985.                                                       TRUE);
  3986.         if (unlikely (status))
  3987.             return status;
  3988.         break;
  3989.     }
  3990.  
  3991.     return CAIRO_STATUS_SUCCESS;
  3992. }
  3993.  
  3994. static cairo_status_t
  3995. _cairo_ps_surface_paint_gradient (cairo_ps_surface_t          *surface,
  3996.                                   const cairo_pattern_t       *source,
  3997.                                   const cairo_rectangle_int_t *extents)
  3998. {
  3999.     cairo_matrix_t pat_to_ps;
  4000.     cairo_status_t status;
  4001.  
  4002.     pat_to_ps = source->matrix;
  4003.     status = cairo_matrix_invert (&pat_to_ps);
  4004.     /* cairo_pattern_set_matrix ensures the matrix is invertible */
  4005.     assert (status == CAIRO_STATUS_SUCCESS);
  4006.     cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
  4007.  
  4008.     if (! _cairo_matrix_is_identity (&pat_to_ps)) {
  4009.         _cairo_output_stream_printf (surface->stream,
  4010.                                      "[%f %f %f %f %f %f] concat\n",
  4011.                                      pat_to_ps.xx, pat_to_ps.yx,
  4012.                                      pat_to_ps.xy, pat_to_ps.yy,
  4013.                                      pat_to_ps.x0, pat_to_ps.y0);
  4014.     }
  4015.  
  4016.     if (source->type == CAIRO_PATTERN_TYPE_MESH) {
  4017.         status = _cairo_ps_surface_emit_mesh_pattern (surface,
  4018.                                                       (cairo_mesh_pattern_t *)source,
  4019.                                                       FALSE);
  4020.         if (unlikely (status))
  4021.             return status;
  4022.     } else {
  4023.         status = _cairo_ps_surface_emit_gradient (surface,
  4024.                                                   (cairo_gradient_pattern_t *)source,
  4025.                                                   FALSE);
  4026.         if (unlikely (status))
  4027.             return status;
  4028.     }
  4029.  
  4030.     return status;
  4031. }
  4032.  
  4033. static cairo_status_t
  4034. _cairo_ps_surface_paint_pattern (cairo_ps_surface_t           *surface,
  4035.                                  const cairo_pattern_t        *source,
  4036.                                  cairo_rectangle_int_t        *extents,
  4037.                                  cairo_operator_t              op,
  4038.                                  cairo_bool_t                  stencil_mask)
  4039. {
  4040.     switch (source->type) {
  4041.     case CAIRO_PATTERN_TYPE_SURFACE:
  4042.     case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
  4043.        return _cairo_ps_surface_paint_surface (surface,
  4044.                                                (cairo_pattern_t *)source,
  4045.                                                extents,
  4046.                                                op,
  4047.                                                stencil_mask);
  4048.  
  4049.     case CAIRO_PATTERN_TYPE_LINEAR:
  4050.     case CAIRO_PATTERN_TYPE_RADIAL:
  4051.     case CAIRO_PATTERN_TYPE_MESH:
  4052.         return _cairo_ps_surface_paint_gradient (surface,
  4053.                                                   source,
  4054.                                                   extents);
  4055.  
  4056.     case CAIRO_PATTERN_TYPE_SOLID:
  4057.     default:
  4058.        ASSERT_NOT_REACHED;
  4059.        return CAIRO_STATUS_SUCCESS;
  4060.     }
  4061. }
  4062.  
  4063. static cairo_bool_t
  4064. _can_paint_pattern (const cairo_pattern_t *pattern)
  4065. {
  4066.     switch (pattern->type) {
  4067.     case CAIRO_PATTERN_TYPE_SOLID:
  4068.         return FALSE;
  4069.  
  4070.     case CAIRO_PATTERN_TYPE_SURFACE:
  4071.     case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
  4072.         return (pattern->extend == CAIRO_EXTEND_NONE ||
  4073.                 pattern->extend == CAIRO_EXTEND_PAD);
  4074.  
  4075.     case CAIRO_PATTERN_TYPE_LINEAR:
  4076.     case CAIRO_PATTERN_TYPE_RADIAL:
  4077.     case CAIRO_PATTERN_TYPE_MESH:
  4078.         return TRUE;
  4079.  
  4080.     default:
  4081.         ASSERT_NOT_REACHED;
  4082.         return FALSE;
  4083.     }
  4084. }
  4085.  
  4086. static cairo_bool_t
  4087. _cairo_ps_surface_get_extents (void                    *abstract_surface,
  4088.                                cairo_rectangle_int_t   *rectangle)
  4089. {
  4090.     cairo_ps_surface_t *surface = abstract_surface;
  4091.  
  4092.     rectangle->x = 0;
  4093.     rectangle->y = 0;
  4094.  
  4095.     /* XXX: The conversion to integers here is pretty bogus, (not to
  4096.      * mention the aribitray limitation of width to a short(!). We
  4097.      * may need to come up with a better interface for get_extents.
  4098.      */
  4099.     rectangle->width  = ceil (surface->width);
  4100.     rectangle->height = ceil (surface->height);
  4101.  
  4102.     return TRUE;
  4103. }
  4104.  
  4105. static void
  4106. _cairo_ps_surface_get_font_options (void                  *abstract_surface,
  4107.                                     cairo_font_options_t  *options)
  4108. {
  4109.     _cairo_font_options_init_default (options);
  4110.  
  4111.     cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
  4112.     cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
  4113.     cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
  4114.     _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_OFF);
  4115. }
  4116.  
  4117. static cairo_int_status_t
  4118. _cairo_ps_surface_set_clip (cairo_ps_surface_t *surface,
  4119.                             cairo_composite_rectangles_t *composite)
  4120. {
  4121.     cairo_clip_t *clip = composite->clip;
  4122.  
  4123.     if (_cairo_composite_rectangles_can_reduce_clip (composite, clip))
  4124.         clip = NULL;
  4125.  
  4126.     if (clip == NULL) {
  4127.         if (_cairo_composite_rectangles_can_reduce_clip (composite,
  4128.                                                          surface->clipper.clip))
  4129.             return CAIRO_STATUS_SUCCESS;
  4130.     }
  4131.  
  4132.     return _cairo_surface_clipper_set_clip (&surface->clipper, clip);
  4133. }
  4134.  
  4135. static cairo_int_status_t
  4136. _cairo_ps_surface_paint (void                   *abstract_surface,
  4137.                          cairo_operator_t        op,
  4138.                          const cairo_pattern_t  *source,
  4139.                          const cairo_clip_t     *clip)
  4140. {
  4141.     cairo_ps_surface_t *surface = abstract_surface;
  4142.     cairo_output_stream_t *stream = surface->stream;
  4143.     cairo_composite_rectangles_t extents;
  4144.     cairo_status_t status;
  4145.  
  4146.     status = _cairo_composite_rectangles_init_for_paint (&extents,
  4147.                                                          &surface->base,
  4148.                                                          op, source, clip);
  4149.     if (unlikely (status))
  4150.         return status;
  4151.  
  4152.     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
  4153.         status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
  4154.         goto cleanup_composite;
  4155.     }
  4156.  
  4157.     assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
  4158.  
  4159. #if DEBUG_PS
  4160.     _cairo_output_stream_printf (stream,
  4161.                                  "%% _cairo_ps_surface_paint\n");
  4162. #endif
  4163.  
  4164.     status = _cairo_ps_surface_set_clip (surface, &extents);
  4165.     if (unlikely (status))
  4166.         goto cleanup_composite;
  4167.  
  4168.     if (_can_paint_pattern (source)) {
  4169.         status = _cairo_pdf_operators_flush (&surface->pdf_operators);
  4170.         if (unlikely (status))
  4171.             goto cleanup_composite;
  4172.  
  4173.         _cairo_output_stream_printf (stream, "q\n");
  4174.         status = _cairo_ps_surface_paint_pattern (surface,
  4175.                                                   source,
  4176.                                                   &extents.bounded, op, FALSE);
  4177.         if (unlikely (status))
  4178.             goto cleanup_composite;
  4179.  
  4180.         _cairo_output_stream_printf (stream, "Q\n");
  4181.     } else {
  4182.         status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
  4183.         if (unlikely (status))
  4184.             goto cleanup_composite;
  4185.  
  4186.         _cairo_output_stream_printf (stream, "0 0 %f %f rectfill\n",
  4187.                                      surface->width, surface->height);
  4188.     }
  4189.  
  4190. cleanup_composite:
  4191.     _cairo_composite_rectangles_fini (&extents);
  4192.     return status;
  4193. }
  4194.  
  4195. static cairo_int_status_t
  4196. _cairo_ps_surface_mask (void                    *abstract_surface,
  4197.                         cairo_operator_t         op,
  4198.                         const cairo_pattern_t   *source,
  4199.                         const cairo_pattern_t   *mask,
  4200.                         const cairo_clip_t      *clip)
  4201. {
  4202.     cairo_ps_surface_t *surface = abstract_surface;
  4203.     cairo_output_stream_t *stream = surface->stream;
  4204.     cairo_composite_rectangles_t extents;
  4205.     cairo_status_t status;
  4206.  
  4207.     status = _cairo_composite_rectangles_init_for_mask (&extents,
  4208.                                                         &surface->base,
  4209.                                                         op, source, mask, clip);
  4210.     if (unlikely (status))
  4211.         return status;
  4212.  
  4213.     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
  4214.         status = _cairo_ps_surface_analyze_operation (surface, op, source, mask, &extents.bounded);
  4215.         goto cleanup_composite;
  4216.     }
  4217.  
  4218.     assert (_cairo_ps_surface_operation_supported (surface, op, source, mask, &extents.bounded));
  4219.  
  4220. #if DEBUG_PS
  4221.     _cairo_output_stream_printf (stream,
  4222.                                  "%% _cairo_ps_surface_mask\n");
  4223. #endif
  4224.  
  4225.     status = _cairo_ps_surface_set_clip (surface, &extents);
  4226.     if (unlikely (status))
  4227.         goto cleanup_composite;
  4228.  
  4229.     status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
  4230.     if (unlikely (status))
  4231.         goto cleanup_composite;
  4232.  
  4233.     _cairo_output_stream_printf (stream, "q\n");
  4234.     status = _cairo_ps_surface_paint_pattern (surface,
  4235.                                               mask,
  4236.                                               &extents.bounded, op, TRUE);
  4237.     if (unlikely (status))
  4238.         goto cleanup_composite;
  4239.  
  4240.     _cairo_output_stream_printf (stream, "Q\n");
  4241.  
  4242. cleanup_composite:
  4243.     _cairo_composite_rectangles_fini (&extents);
  4244.     return status;
  4245. }
  4246.  
  4247. static cairo_int_status_t
  4248. _cairo_ps_surface_stroke (void                  *abstract_surface,
  4249.                           cairo_operator_t       op,
  4250.                           const cairo_pattern_t *source,
  4251.                           const cairo_path_fixed_t      *path,
  4252.                           const cairo_stroke_style_t    *style,
  4253.                           const cairo_matrix_t  *ctm,
  4254.                           const cairo_matrix_t  *ctm_inverse,
  4255.                           double                 tolerance,
  4256.                           cairo_antialias_t      antialias,
  4257.                           const cairo_clip_t            *clip)
  4258. {
  4259.     cairo_ps_surface_t *surface = abstract_surface;
  4260.     cairo_composite_rectangles_t extents;
  4261.     cairo_int_status_t status;
  4262.  
  4263.     status = _cairo_composite_rectangles_init_for_stroke (&extents,
  4264.                                                           &surface->base,
  4265.                                                           op, source,
  4266.                                                           path, style, ctm,
  4267.                                                           clip);
  4268.     if (unlikely (status))
  4269.         return status;
  4270.  
  4271.     /* use the more accurate extents */
  4272.     {
  4273.         cairo_rectangle_int_t r;
  4274.         cairo_box_t b;
  4275.  
  4276.         status = _cairo_path_fixed_stroke_extents (path, style,
  4277.                                                    ctm, ctm_inverse,
  4278.                                                    tolerance,
  4279.                                                    &r);
  4280.         if (unlikely (status))
  4281.             goto cleanup_composite;
  4282.  
  4283.         _cairo_box_from_rectangle (&b, &r);
  4284.         status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b);
  4285.         if (unlikely (status))
  4286.             goto cleanup_composite;
  4287.     }
  4288.  
  4289.     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
  4290.         status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
  4291.         goto cleanup_composite;
  4292.     }
  4293.  
  4294.     assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
  4295.  
  4296. #if DEBUG_PS
  4297.     _cairo_output_stream_printf (surface->stream,
  4298.                                  "%% _cairo_ps_surface_stroke\n");
  4299. #endif
  4300.  
  4301.     status = _cairo_ps_surface_set_clip (surface, &extents);
  4302.     if (unlikely (status))
  4303.         goto cleanup_composite;
  4304.  
  4305.     status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
  4306.     if (unlikely (status))
  4307.         goto cleanup_composite;
  4308.  
  4309.     status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
  4310.                                           path,
  4311.                                           style,
  4312.                                           ctm,
  4313.                                           ctm_inverse);
  4314.  
  4315. cleanup_composite:
  4316.     _cairo_composite_rectangles_fini (&extents);
  4317.     return status;
  4318. }
  4319.  
  4320. static cairo_int_status_t
  4321. _cairo_ps_surface_fill (void            *abstract_surface,
  4322.                         cairo_operator_t         op,
  4323.                         const cairo_pattern_t   *source,
  4324.                         const cairo_path_fixed_t*path,
  4325.                         cairo_fill_rule_t        fill_rule,
  4326.                         double                   tolerance,
  4327.                         cairo_antialias_t        antialias,
  4328.                         const cairo_clip_t              *clip)
  4329. {
  4330.     cairo_ps_surface_t *surface = abstract_surface;
  4331.     cairo_composite_rectangles_t extents;
  4332.     cairo_int_status_t status;
  4333.  
  4334.     status = _cairo_composite_rectangles_init_for_fill (&extents,
  4335.                                                         &surface->base,
  4336.                                                         op, source, path,
  4337.                                                         clip);
  4338.     if (unlikely (status))
  4339.         return status;
  4340.  
  4341.     /* use the more accurate extents */
  4342.     {
  4343.         cairo_rectangle_int_t r;
  4344.         cairo_box_t b;
  4345.  
  4346.         _cairo_path_fixed_fill_extents (path,
  4347.                                         fill_rule,
  4348.                                         tolerance,
  4349.                                         &r);
  4350.  
  4351.         _cairo_box_from_rectangle (&b, &r);
  4352.         status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b);
  4353.         if (unlikely (status))
  4354.             goto cleanup_composite;
  4355.     }
  4356.  
  4357.     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
  4358.         status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
  4359.         goto cleanup_composite;
  4360.     }
  4361.  
  4362.     assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
  4363.  
  4364. #if DEBUG_PS
  4365.     _cairo_output_stream_printf (surface->stream,
  4366.                                  "%% _cairo_ps_surface_fill\n");
  4367. #endif
  4368.  
  4369.     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
  4370.     if (unlikely (status))
  4371.         goto cleanup_composite;
  4372.  
  4373.     status = _cairo_ps_surface_set_clip (surface, &extents);
  4374.     if (unlikely (status))
  4375.         goto cleanup_composite;
  4376.  
  4377.     if (_can_paint_pattern (source)) {
  4378.         _cairo_output_stream_printf (surface->stream, "q\n");
  4379.  
  4380.         status =  _cairo_pdf_operators_clip (&surface->pdf_operators,
  4381.                                              path,
  4382.                                              fill_rule);
  4383.         if (unlikely (status))
  4384.             goto cleanup_composite;
  4385.  
  4386.         status = _cairo_ps_surface_paint_pattern (surface,
  4387.                                                   source,
  4388.                                                   &extents.bounded, op, FALSE);
  4389.         if (unlikely (status))
  4390.             goto cleanup_composite;
  4391.  
  4392.         _cairo_output_stream_printf (surface->stream, "Q\n");
  4393.         _cairo_pdf_operators_reset (&surface->pdf_operators);
  4394.     } else {
  4395.         status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
  4396.         if (unlikely (status))
  4397.             goto cleanup_composite;
  4398.  
  4399.         status = _cairo_pdf_operators_fill (&surface->pdf_operators,
  4400.                                             path,
  4401.                                             fill_rule);
  4402.     }
  4403.  
  4404. cleanup_composite:
  4405.     _cairo_composite_rectangles_fini (&extents);
  4406.     return status;
  4407. }
  4408.  
  4409. static cairo_bool_t
  4410. _cairo_ps_surface_has_show_text_glyphs  (void                   *abstract_surface)
  4411. {
  4412.     return TRUE;
  4413. }
  4414.  
  4415. static cairo_int_status_t
  4416. _cairo_ps_surface_show_text_glyphs (void                       *abstract_surface,
  4417.                                     cairo_operator_t            op,
  4418.                                     const cairo_pattern_t      *source,
  4419.                                     const char                 *utf8,
  4420.                                     int                         utf8_len,
  4421.                                     cairo_glyph_t              *glyphs,
  4422.                                     int                         num_glyphs,
  4423.                                     const cairo_text_cluster_t *clusters,
  4424.                                     int                         num_clusters,
  4425.                                     cairo_text_cluster_flags_t  cluster_flags,
  4426.                                     cairo_scaled_font_t        *scaled_font,
  4427.                                     const cairo_clip_t         *clip)
  4428. {
  4429.     cairo_ps_surface_t *surface = abstract_surface;
  4430.     cairo_composite_rectangles_t extents;
  4431.     cairo_bool_t overlap;
  4432.     cairo_status_t status;
  4433.  
  4434.     status = _cairo_composite_rectangles_init_for_glyphs (&extents,
  4435.                                                           &surface->base,
  4436.                                                           op, source,
  4437.                                                           scaled_font,
  4438.                                                           glyphs, num_glyphs,
  4439.                                                           clip,
  4440.                                                           &overlap);
  4441.     if (unlikely (status))
  4442.         return status;
  4443.  
  4444.     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
  4445.         status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
  4446.         goto cleanup_composite;
  4447.     }
  4448.  
  4449.     assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
  4450.  
  4451. #if DEBUG_PS
  4452.     _cairo_output_stream_printf (surface->stream,
  4453.                                  "%% _cairo_ps_surface_show_glyphs\n");
  4454. #endif
  4455.  
  4456.     status = _cairo_ps_surface_set_clip (surface, &extents);
  4457.     if (unlikely (status))
  4458.         goto cleanup_composite;
  4459.  
  4460.     status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
  4461.     if (unlikely (status))
  4462.         goto cleanup_composite;
  4463.  
  4464.     status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
  4465.                                                     utf8, utf8_len,
  4466.                                                     glyphs, num_glyphs,
  4467.                                                     clusters, num_clusters,
  4468.                                                     cluster_flags,
  4469.                                                     scaled_font);
  4470.  
  4471. cleanup_composite:
  4472.     _cairo_composite_rectangles_fini (&extents);
  4473.     return status;
  4474. }
  4475.  
  4476. static const char **
  4477. _cairo_ps_surface_get_supported_mime_types (void                 *abstract_surface)
  4478. {
  4479.     return _cairo_ps_supported_mime_types;
  4480. }
  4481.  
  4482. static void
  4483. _cairo_ps_surface_set_paginated_mode (void                      *abstract_surface,
  4484.                                       cairo_paginated_mode_t     paginated_mode)
  4485. {
  4486.     cairo_ps_surface_t *surface = abstract_surface;
  4487.     cairo_status_t status;
  4488.  
  4489.     surface->paginated_mode = paginated_mode;
  4490.  
  4491.     if (surface->clipper.clip != NULL) {
  4492.         status = _cairo_pdf_operators_flush (&surface->pdf_operators);
  4493.  
  4494.         _cairo_output_stream_printf (surface->stream, "Q q\n");
  4495.         _cairo_surface_clipper_reset (&surface->clipper);
  4496.     }
  4497. }
  4498.  
  4499. static cairo_int_status_t
  4500. _cairo_ps_surface_set_bounding_box (void                *abstract_surface,
  4501.                                     cairo_box_t         *bbox)
  4502. {
  4503.     cairo_ps_surface_t *surface = abstract_surface;
  4504.     int i, num_comments;
  4505.     char **comments;
  4506.     int x1, y1, x2, y2;
  4507.     cairo_bool_t has_page_media, has_page_bbox;
  4508.     const char *page_media;
  4509.  
  4510.     x1 = floor (_cairo_fixed_to_double (bbox->p1.x));
  4511.     y1 = floor (surface->height - _cairo_fixed_to_double (bbox->p2.y));
  4512.     x2 = ceil (_cairo_fixed_to_double (bbox->p2.x));
  4513.     y2 = ceil (surface->height - _cairo_fixed_to_double (bbox->p1.y));
  4514.  
  4515.     surface->page_bbox.x = x1;
  4516.     surface->page_bbox.y = y1;
  4517.     surface->page_bbox.width  = x2 - x1;
  4518.     surface->page_bbox.height = y2 - y1;
  4519.  
  4520.     _cairo_output_stream_printf (surface->stream,
  4521.                                  "%%%%Page: %d %d\n",
  4522.                                  surface->num_pages,
  4523.                                  surface->num_pages);
  4524.  
  4525.     _cairo_output_stream_printf (surface->stream,
  4526.                                  "%%%%BeginPageSetup\n");
  4527.  
  4528.     has_page_media = FALSE;
  4529.     has_page_bbox = FALSE;
  4530.     num_comments = _cairo_array_num_elements (&surface->dsc_page_setup_comments);
  4531.     comments = _cairo_array_index (&surface->dsc_page_setup_comments, 0);
  4532.     for (i = 0; i < num_comments; i++) {
  4533.         _cairo_output_stream_printf (surface->stream,
  4534.                                      "%s\n", comments[i]);
  4535.         if (strncmp (comments[i], "%%PageMedia:", 11) == 0)
  4536.             has_page_media = TRUE;
  4537.  
  4538.         if (strncmp (comments[i], "%%PageBoundingBox:", 18) == 0)
  4539.             has_page_bbox = TRUE;
  4540.  
  4541.         free (comments[i]);
  4542.         comments[i] = NULL;
  4543.     }
  4544.     _cairo_array_truncate (&surface->dsc_page_setup_comments, 0);
  4545.  
  4546.     if (!has_page_media && !surface->eps) {
  4547.         page_media = _cairo_ps_surface_get_page_media (surface);
  4548.         if (unlikely (page_media == NULL))
  4549.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  4550.  
  4551.         _cairo_output_stream_printf (surface->stream,
  4552.                                      "%%%%PageMedia: %s\n",
  4553.                                      page_media);
  4554.     }
  4555.  
  4556.     if (!has_page_bbox) {
  4557.         _cairo_output_stream_printf (surface->stream,
  4558.                                      "%%%%PageBoundingBox: %d %d %d %d\n",
  4559.                                      x1, y1, x2, y2);
  4560.     }
  4561.  
  4562.     _cairo_output_stream_printf (surface->stream,
  4563.                                  "%%%%EndPageSetup\n"
  4564.                                  "q %d %d %d %d rectclip q\n",
  4565.                                  surface->page_bbox.x,
  4566.                                  surface->page_bbox.y,
  4567.                                  surface->page_bbox.width,
  4568.                                  surface->page_bbox.height);
  4569.  
  4570.     if (surface->num_pages == 1) {
  4571.         surface->bbox_x1 = x1;
  4572.         surface->bbox_y1 = y1;
  4573.         surface->bbox_x2 = x2;
  4574.         surface->bbox_y2 = y2;
  4575.     } else {
  4576.         if (x1 < surface->bbox_x1)
  4577.             surface->bbox_x1 = x1;
  4578.         if (y1 < surface->bbox_y1)
  4579.             surface->bbox_y1 = y1;
  4580.         if (x2 > surface->bbox_x2)
  4581.             surface->bbox_x2 = x2;
  4582.         if (y2 > surface->bbox_y2)
  4583.             surface->bbox_y2 = y2;
  4584.     }
  4585.     surface->current_pattern_is_solid_color = FALSE;
  4586.     _cairo_pdf_operators_reset (&surface->pdf_operators);
  4587.  
  4588.     return _cairo_output_stream_get_status (surface->stream);
  4589. }
  4590.  
  4591. static cairo_bool_t
  4592. _cairo_ps_surface_supports_fine_grained_fallbacks (void     *abstract_surface)
  4593. {
  4594.     return TRUE;
  4595. }
  4596.  
  4597. static const cairo_surface_backend_t cairo_ps_surface_backend = {
  4598.     CAIRO_SURFACE_TYPE_PS,
  4599.     _cairo_ps_surface_finish,
  4600.  
  4601.     _cairo_default_context_create,
  4602.  
  4603.     NULL, /* create similar: handled by wrapper */
  4604.     NULL, /* create similar image */
  4605.     NULL, /* map to image */
  4606.     NULL, /* unmap image */
  4607.  
  4608.     _cairo_surface_default_source,
  4609.     NULL, /* acquire_source_image */
  4610.     NULL, /* release_source_image */
  4611.     NULL, /* snapshot */
  4612.  
  4613.     NULL, /* cairo_ps_surface_copy_page */
  4614.     _cairo_ps_surface_show_page,
  4615.  
  4616.     _cairo_ps_surface_get_extents,
  4617.     _cairo_ps_surface_get_font_options,
  4618.  
  4619.     NULL, /* flush */
  4620.     NULL, /* mark_dirty_rectangle */
  4621.  
  4622.     /* Here are the drawing functions */
  4623.  
  4624.     _cairo_ps_surface_paint, /* paint */
  4625.     _cairo_ps_surface_mask,
  4626.     _cairo_ps_surface_stroke,
  4627.     _cairo_ps_surface_fill,
  4628.     NULL, /* fill-stroke */
  4629.     NULL, /* show_glyphs */
  4630.     _cairo_ps_surface_has_show_text_glyphs,
  4631.     _cairo_ps_surface_show_text_glyphs,
  4632.     _cairo_ps_surface_get_supported_mime_types,
  4633. };
  4634.  
  4635. static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend = {
  4636.     _cairo_ps_surface_start_page,
  4637.     _cairo_ps_surface_set_paginated_mode,
  4638.     _cairo_ps_surface_set_bounding_box,
  4639.     NULL, /* _cairo_ps_surface_has_fallback_images, */
  4640.     _cairo_ps_surface_supports_fine_grained_fallbacks,
  4641. };
  4642.