Back to index

lightning-sunbird  0.9+nobinonly
cairo-pdf-surface.c
Go to the documentation of this file.
00001 /* cairo - a vector graphics library with display and print output
00002  *
00003  * Copyright © 2004 Red Hat, Inc
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it either under the terms of the GNU Lesser General Public
00007  * License version 2.1 as published by the Free Software Foundation
00008  * (the "LGPL") or, at your option, under the terms of the Mozilla
00009  * Public License Version 1.1 (the "MPL"). If you do not alter this
00010  * notice, a recipient may use your version of this file under either
00011  * the MPL or the LGPL.
00012  *
00013  * You should have received a copy of the LGPL along with this library
00014  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
00015  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00016  * You should have received a copy of the MPL along with this library
00017  * in the file COPYING-MPL-1.1
00018  *
00019  * The contents of this file are subject to the Mozilla Public License
00020  * Version 1.1 (the "License"); you may not use this file except in
00021  * compliance with the License. You may obtain a copy of the License at
00022  * http://www.mozilla.org/MPL/
00023  *
00024  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
00025  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
00026  * the specific language governing rights and limitations.
00027  *
00028  * The Original Code is the cairo graphics library.
00029  *
00030  * The Initial Developer of the Original Code is University of Southern
00031  * California.
00032  *
00033  * Contributor(s):
00034  *     Kristian Høgsberg <krh@redhat.com>
00035  */
00036 
00037 #include "cairoint.h"
00038 #include "cairo-pdf.h"
00039 #include "cairo-font-subset-private.h"
00040 #include "cairo-ft-private.h"
00041 
00042 #include <time.h>
00043 #include <zlib.h>
00044 
00045 /* Issues:
00046  *
00047  * - Why doesn't pages inherit /alpha%d GS dictionaries from the Pages
00048  *   object?
00049  *
00050  * - We embed an image in the stream each time it's composited.  We
00051  *   could add generation counters to surfaces and remember the stream
00052  *   ID for a particular generation for a particular surface.
00053  *
00054  * - Multi stop gradients.  What are the exponential interpolation
00055  *   functions, could they be used for gradients?
00056  *
00057  * - Clipping: must be able to reset clipping
00058  *
00059  * - Images of other formats than 8 bit RGBA.
00060  *
00061  * - Backend specific meta data.
00062  *
00063  * - Surface patterns.
00064  *
00065  * - Alpha channels in gradients.
00066  *
00067  * - Should/does cairo support drawing into a scratch surface and then
00068  *   using that as a fill pattern?  For this backend, that would involve
00069  *   using a tiling pattern (4.6.2).  How do you create such a scratch
00070  *   surface?  cairo_surface_create_similar() ?
00071  *
00072  * - What if you create a similiar surface and does show_page and then
00073  *   does show_surface on another surface?
00074  *
00075  * - Output TM so page scales to the right size - PDF default user
00076  *   space has 1 unit = 1 / 72 inch.
00077  *
00078  * - Add test case for RGBA images.
00079  *
00080  * - Add test case for RGBA gradients.
00081  *
00082  * - Pattern extend isn't honoured by image backend.
00083  *
00084  * - Coordinate space for create_similar() args?
00085  *
00086  * - Investigate /Matrix entry in content stream dicts for pages
00087  *   instead of outputting the cm operator in every page.
00088  */
00089 
00090 typedef struct cairo_pdf_object cairo_pdf_object_t;
00091 typedef struct cairo_pdf_resource cairo_pdf_resource_t;
00092 typedef struct cairo_pdf_stream cairo_pdf_stream_t;
00093 typedef struct cairo_pdf_document cairo_pdf_document_t;
00094 typedef struct cairo_pdf_surface cairo_pdf_surface_t;
00095 
00096 struct cairo_pdf_object {
00097     long offset;
00098 };
00099 
00100 struct cairo_pdf_resource {
00101     unsigned int id;
00102 };
00103 
00104 struct cairo_pdf_stream {
00105     unsigned int id;
00106     unsigned int length_id;
00107     long start_offset;
00108 };
00109 
00110 struct cairo_pdf_document {
00111     cairo_output_stream_t *output_stream;
00112     unsigned long ref_count;
00113     cairo_surface_t *owner;
00114     cairo_bool_t finished;
00115 
00116     double width;
00117     double height;
00118     double x_dpi;
00119     double y_dpi;
00120 
00121     unsigned int next_available_id;
00122     unsigned int pages_id;
00123 
00124     cairo_pdf_stream_t *current_stream;
00125 
00126     cairo_array_t objects;
00127     cairo_array_t pages;
00128 
00129     cairo_array_t fonts;
00130 };
00131 
00132 struct cairo_pdf_surface {
00133     cairo_surface_t base;
00134 
00135     double width;
00136     double height;
00137 
00138     cairo_pdf_document_t *document;
00139     cairo_pdf_stream_t *current_stream;
00140 
00141     cairo_array_t patterns;
00142     cairo_array_t xobjects;
00143     cairo_array_t streams;
00144     cairo_array_t alphas;
00145     cairo_array_t fonts;
00146     cairo_bool_t has_clip;
00147 };
00148 
00149 #define DEFAULT_DPI 300
00150 
00151 static cairo_pdf_document_t *
00152 _cairo_pdf_document_create (cairo_output_stream_t       *stream,
00153                          double                  width,
00154                          double                  height);
00155 
00156 static void
00157 _cairo_pdf_document_destroy (cairo_pdf_document_t *document);
00158 
00159 static cairo_status_t
00160 _cairo_pdf_document_finish (cairo_pdf_document_t *document);
00161 
00162 static cairo_pdf_document_t *
00163 _cairo_pdf_document_reference (cairo_pdf_document_t *document);
00164 
00165 static unsigned int
00166 _cairo_pdf_document_new_object (cairo_pdf_document_t *document);
00167 
00168 static cairo_status_t
00169 _cairo_pdf_document_add_page (cairo_pdf_document_t *document,
00170                            cairo_pdf_surface_t *surface);
00171 
00172 static void
00173 _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
00174 
00175 static cairo_pdf_stream_t *
00176 _cairo_pdf_document_open_stream (cairo_pdf_document_t   *document,
00177                              const char          *fmt,
00178                              ...);
00179 static void
00180 _cairo_pdf_document_close_stream (cairo_pdf_document_t  *document);
00181 
00182 static cairo_surface_t *
00183 _cairo_pdf_surface_create_for_document (cairo_pdf_document_t   *document,
00184                                    double               width,
00185                                    double               height);
00186 static void
00187 _cairo_pdf_surface_add_stream (cairo_pdf_surface_t      *surface,
00188                             cairo_pdf_stream_t   *stream);
00189 static void
00190 _cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t   *surface);
00191 
00192 static const cairo_surface_backend_t cairo_pdf_surface_backend;
00193 
00194 static unsigned int
00195 _cairo_pdf_document_new_object (cairo_pdf_document_t *document)
00196 {
00197     cairo_pdf_object_t object;
00198 
00199     object.offset = _cairo_output_stream_get_position (document->output_stream);
00200     if (_cairo_array_append (&document->objects, &object, 1) == NULL)
00201        return 0;
00202 
00203     return document->next_available_id++;
00204 }
00205 
00206 static void
00207 _cairo_pdf_document_update_object (cairo_pdf_document_t *document,
00208                                unsigned int id)
00209 {
00210     cairo_pdf_object_t *object;
00211 
00212     object = _cairo_array_index (&document->objects, id - 1);
00213     object->offset = _cairo_output_stream_get_position (document->output_stream);
00214 }
00215 
00216 static void
00217 _cairo_pdf_surface_add_stream (cairo_pdf_surface_t      *surface,
00218                             cairo_pdf_stream_t   *stream)
00219 {
00220     _cairo_array_append (&surface->streams, &stream, 1);
00221     surface->current_stream = stream;
00222 }
00223 
00224 static void
00225 _cairo_pdf_surface_add_pattern (cairo_pdf_surface_t *surface, unsigned int id)
00226 {
00227     cairo_pdf_resource_t resource;
00228 
00229     resource.id = id;
00230     _cairo_array_append (&surface->patterns, &resource, 1);
00231 }
00232 
00233 static void
00234 _cairo_pdf_surface_add_xobject (cairo_pdf_surface_t *surface, unsigned int id)
00235 {
00236     cairo_pdf_resource_t resource;
00237     int i, num_resources;
00238 
00239     num_resources = _cairo_array_num_elements (&surface->xobjects);
00240     for (i = 0; i < num_resources; i++) {
00241        _cairo_array_copy_element (&surface->xobjects, i, &resource);
00242        if (resource.id == id)
00243            return;
00244     }
00245 
00246     resource.id = id;
00247     _cairo_array_append (&surface->xobjects, &resource, 1);
00248 }
00249 
00250 static unsigned int
00251 _cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface, double alpha)
00252 {
00253     int num_alphas, i;
00254     double other;
00255 
00256     num_alphas = _cairo_array_num_elements (&surface->alphas);
00257     for (i = 0; i < num_alphas; i++) {
00258        _cairo_array_copy_element (&surface->alphas, i, &other);
00259        if (alpha == other)
00260            return i;
00261     }
00262 
00263     _cairo_array_append (&surface->alphas, &alpha, 1);
00264     return _cairo_array_num_elements (&surface->alphas) - 1;
00265 }
00266 
00267 static void
00268 _cairo_pdf_surface_add_font (cairo_pdf_surface_t *surface, unsigned int id)
00269 {
00270     cairo_pdf_resource_t resource;
00271     int i, num_fonts;
00272 
00273     num_fonts = _cairo_array_num_elements (&surface->fonts);
00274     for (i = 0; i < num_fonts; i++) {
00275        _cairo_array_copy_element (&surface->fonts, i, &resource);
00276        if (resource.id == id)
00277            return;
00278     }
00279 
00280     resource.id = id;
00281     _cairo_array_append (&surface->fonts, &resource, 1);
00282 }
00283 
00284 static cairo_surface_t *
00285 _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t  *stream,
00286                                           double               width,
00287                                           double               height)
00288 {
00289     cairo_pdf_document_t *document;
00290     cairo_surface_t *surface;
00291 
00292     document = _cairo_pdf_document_create (stream, width, height);
00293     if (document == NULL) {
00294        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00295        return (cairo_surface_t*) &_cairo_surface_nil;
00296     }
00297 
00298     surface = _cairo_pdf_surface_create_for_document (document, width, height);
00299 
00300     document->owner = surface;
00301     _cairo_pdf_document_destroy (document);
00302 
00303     return surface;
00304 }
00305 
00306 cairo_surface_t *
00307 cairo_pdf_surface_create_for_stream (cairo_write_func_t        write,
00308                                  void                   *closure,
00309                                  double                 width,
00310                                  double                 height)
00311 {
00312     cairo_output_stream_t *stream;
00313 
00314     stream = _cairo_output_stream_create (write, closure);
00315     if (stream == NULL) {
00316        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00317        return (cairo_surface_t*) &_cairo_surface_nil;
00318     }
00319 
00320     return _cairo_pdf_surface_create_for_stream_internal (stream, width, height);
00321 }
00322 
00323 cairo_surface_t *
00324 cairo_pdf_surface_create (const char      *filename,
00325                        double      width,
00326                        double      height)
00327 {
00328     cairo_output_stream_t *stream;
00329 
00330     stream = _cairo_output_stream_create_for_file (filename);
00331     if (stream == NULL) {
00332        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00333        return (cairo_surface_t*) &_cairo_surface_nil;
00334     }
00335 
00336     return _cairo_pdf_surface_create_for_stream_internal (stream, width, height);
00337 }
00338 
00349 void
00350 cairo_pdf_surface_set_dpi (cairo_surface_t       *surface,
00351                         double            x_dpi,
00352                         double            y_dpi)
00353 {
00354     cairo_pdf_surface_t *pdf_surface = (cairo_pdf_surface_t *) surface;
00355 
00356     pdf_surface->document->x_dpi = x_dpi;    
00357     pdf_surface->document->y_dpi = y_dpi;    
00358 }
00359 
00360 static cairo_surface_t *
00361 _cairo_pdf_surface_create_for_document (cairo_pdf_document_t   *document,
00362                                    double               width,
00363                                    double               height)
00364 {
00365     cairo_pdf_surface_t *surface;
00366 
00367     surface = malloc (sizeof (cairo_pdf_surface_t));
00368     if (surface == NULL) {
00369        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00370        return (cairo_surface_t*) &_cairo_surface_nil;
00371     }
00372 
00373     _cairo_surface_init (&surface->base, &cairo_pdf_surface_backend);
00374 
00375     surface->width = width;
00376     surface->height = height;
00377 
00378     surface->document = _cairo_pdf_document_reference (document);
00379     _cairo_array_init (&surface->streams, sizeof (cairo_pdf_stream_t *));
00380     _cairo_array_init (&surface->patterns, sizeof (cairo_pdf_resource_t));
00381     _cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t));
00382     _cairo_array_init (&surface->alphas, sizeof (double));
00383     _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_resource_t));
00384     surface->has_clip = FALSE;
00385 
00386     return &surface->base;
00387 }
00388 
00389 static void
00390 _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
00391 {
00392     int num_streams, i;
00393     cairo_pdf_stream_t *stream;
00394 
00395     num_streams = _cairo_array_num_elements (&surface->streams);
00396     for (i = 0; i < num_streams; i++) {
00397        _cairo_array_copy_element (&surface->streams, i, &stream);
00398        free (stream);
00399     }
00400 
00401     _cairo_array_truncate (&surface->streams, 0);
00402     _cairo_array_truncate (&surface->patterns, 0);
00403     _cairo_array_truncate (&surface->xobjects, 0);
00404     _cairo_array_truncate (&surface->alphas, 0);
00405     _cairo_array_truncate (&surface->fonts, 0);
00406 }
00407 
00408 static cairo_surface_t *
00409 _cairo_pdf_surface_create_similar (void                 *abstract_src,
00410                                cairo_content_t   content,
00411                                int               width,
00412                                int               height)
00413 {
00414     cairo_pdf_surface_t *template = abstract_src;
00415 
00416     return _cairo_pdf_surface_create_for_document (template->document,
00417                                              width, height);
00418 }
00419 
00420 static cairo_pdf_stream_t *
00421 _cairo_pdf_document_open_stream (cairo_pdf_document_t   *document,
00422                              const char          *fmt,
00423                              ...)
00424 {
00425     cairo_output_stream_t *output_stream = document->output_stream;
00426     cairo_pdf_stream_t *stream;
00427     va_list ap;
00428 
00429     stream = malloc (sizeof (cairo_pdf_stream_t));
00430     if (stream == NULL) {
00431        return NULL;
00432     }
00433 
00434     stream->id = _cairo_pdf_document_new_object (document);
00435     stream->length_id = _cairo_pdf_document_new_object (document);
00436 
00437     _cairo_output_stream_printf (output_stream,
00438                              "%d 0 obj\r\n"
00439                              "<< /Length %d 0 R\r\n",
00440                              stream->id,
00441                              stream->length_id);
00442 
00443     if (fmt != NULL) {
00444        va_start (ap, fmt);
00445        _cairo_output_stream_vprintf (output_stream, fmt, ap);
00446        va_end (ap);
00447     }
00448 
00449     _cairo_output_stream_printf (output_stream,
00450                              ">>\r\n"
00451                              "stream\r\n");
00452 
00453     stream->start_offset = _cairo_output_stream_get_position (output_stream);
00454 
00455     document->current_stream = stream;
00456 
00457     return stream;
00458 }
00459 
00460 static void
00461 _cairo_pdf_document_close_stream (cairo_pdf_document_t  *document)
00462 {
00463     cairo_output_stream_t *output_stream = document->output_stream;
00464     long length;
00465     cairo_pdf_stream_t *stream;
00466 
00467     stream = document->current_stream;
00468     if (stream == NULL)
00469        return;
00470 
00471     length = _cairo_output_stream_get_position (output_stream) -
00472        stream->start_offset;
00473     _cairo_output_stream_printf (output_stream,
00474                              "endstream\r\n"
00475                              "endobj\r\n");
00476 
00477     _cairo_pdf_document_update_object (document, stream->length_id);
00478     _cairo_output_stream_printf (output_stream,
00479                              "%d 0 obj\r\n"
00480                              "   %ld\r\n"
00481                              "endobj\r\n",
00482                              stream->length_id,
00483                              length);
00484 
00485     document->current_stream = NULL;
00486 }
00487 
00488 static cairo_status_t
00489 _cairo_pdf_surface_finish (void *abstract_surface)
00490 {
00491     cairo_status_t status;
00492     cairo_pdf_surface_t *surface = abstract_surface;
00493     cairo_pdf_document_t *document = surface->document;
00494 
00495     if (surface->current_stream == document->current_stream)
00496        _cairo_pdf_document_close_stream (document);
00497 
00498     if (document->owner == &surface->base)
00499        status = _cairo_pdf_document_finish (document);
00500     else
00501        status = CAIRO_STATUS_SUCCESS;
00502 
00503     _cairo_pdf_document_destroy (document);
00504 
00505     _cairo_array_fini (&surface->streams);
00506     _cairo_array_fini (&surface->patterns);
00507     _cairo_array_fini (&surface->xobjects);
00508     _cairo_array_fini (&surface->alphas);
00509     _cairo_array_fini (&surface->fonts);
00510 
00511     return status;
00512 }
00513 
00514 static void
00515 _cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface)
00516 {
00517     cairo_pdf_document_t *document = surface->document;
00518     cairo_pdf_stream_t *stream;
00519     cairo_output_stream_t *output = document->output_stream;
00520 
00521     if (document->current_stream == NULL ||
00522        document->current_stream != surface->current_stream) {
00523        _cairo_pdf_document_close_stream (document);
00524        stream = _cairo_pdf_document_open_stream (document,
00525                                             "   /Type /XObject\r\n"
00526                                             "   /Subtype /Form\r\n"
00527                                             "   /BBox [ 0 0 %f %f ]\r\n",
00528                                             surface->width,
00529                                             surface->height);
00530 
00531        _cairo_pdf_surface_add_stream (surface, stream);
00532 
00533        /* If this is the first stream we open for this surface,
00534         * output the cairo to PDF transformation matrix. */
00535        if (_cairo_array_num_elements (&surface->streams) == 1)
00536            _cairo_output_stream_printf (output,
00537                                     "1 0 0 -1 0 %f cm\r\n",
00538                                     document->height);
00539     }
00540 }
00541 
00542 static void *
00543 compress_dup (const void *data, unsigned long data_size,
00544              unsigned long *compressed_size)
00545 {
00546     void *compressed;
00547 
00548     /* Bound calculation taken from zlib. */
00549     *compressed_size = data_size + (data_size >> 12) + (data_size >> 14) + 11;
00550     compressed = malloc (*compressed_size);
00551     if (compressed == NULL)
00552        return NULL;
00553 
00554     compress (compressed, compressed_size, data, data_size);
00555 
00556     return compressed;
00557 }
00558 
00559 static unsigned int
00560 emit_image_data (cairo_pdf_document_t *document,
00561                cairo_image_surface_t *image)
00562 {
00563     cairo_output_stream_t *output = document->output_stream;
00564     cairo_pdf_stream_t *stream;
00565     char *rgb, *compressed;
00566     int i, x, y;
00567     unsigned long rgb_size, compressed_size;
00568     pixman_bits_t *pixel;
00569 
00570     rgb_size = image->height * image->width * 3;
00571     rgb = malloc (rgb_size);
00572     if (rgb == NULL)
00573        return 0;
00574 
00575     i = 0;
00576     for (y = 0; y < image->height; y++) {
00577        pixel = (pixman_bits_t *) (image->data + y * image->stride);
00578 
00579        for (x = 0; x < image->width; x++, pixel++) {
00580            rgb[i++] = (*pixel & 0x00ff0000) >> 16;
00581            rgb[i++] = (*pixel & 0x0000ff00) >>  8;
00582            rgb[i++] = (*pixel & 0x000000ff) >>  0;
00583        }
00584     }
00585 
00586     compressed = compress_dup (rgb, rgb_size, &compressed_size);
00587     if (compressed == NULL) {
00588        free (rgb);
00589        return 0;
00590     }
00591 
00592     _cairo_pdf_document_close_stream (document);
00593 
00594     stream = _cairo_pdf_document_open_stream (document, 
00595                                          "   /Type /XObject\r\n"
00596                                          "   /Subtype /Image\r\n"
00597                                          "   /Width %d\r\n"
00598                                          "   /Height %d\r\n"
00599                                          "   /ColorSpace /DeviceRGB\r\n"
00600                                          "   /BitsPerComponent 8\r\n"
00601                                          "   /Filter /FlateDecode\r\n",
00602                                          image->width, image->height);
00603 
00604     _cairo_output_stream_write (output, compressed, compressed_size);
00605     _cairo_output_stream_printf (output,
00606                              "\r\n");
00607     _cairo_pdf_document_close_stream (document);
00608 
00609     free (rgb);
00610     free (compressed);
00611 
00612     return stream->id;
00613 }
00614 
00615 static cairo_int_status_t
00616 _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
00617                                 cairo_surface_pattern_t *pattern)
00618 {
00619     cairo_pdf_document_t *document = dst->document;
00620     cairo_output_stream_t *output = document->output_stream;
00621     unsigned id;
00622     cairo_matrix_t i2u;
00623     cairo_status_t status;
00624     cairo_image_surface_t *image;
00625     cairo_surface_t *src;
00626     void *image_extra;
00627 
00628     src = pattern->surface;
00629     status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
00630     if (status)
00631        return status;
00632 
00633     id = emit_image_data (dst->document, image);
00634     if (id == 0) {
00635        status = CAIRO_STATUS_NO_MEMORY;
00636        goto bail;
00637     }
00638 
00639     _cairo_pdf_surface_add_xobject (dst, id);
00640 
00641     _cairo_pdf_surface_ensure_stream (dst);
00642 
00643     i2u = pattern->base.matrix;
00644     cairo_matrix_invert (&i2u);
00645     cairo_matrix_translate (&i2u, 0, image->height);
00646     cairo_matrix_scale (&i2u, image->width, -image->height);
00647 
00648     _cairo_output_stream_printf (output,
00649                              "q %f %f %f %f %f %f cm /res%d Do Q\r\n",
00650                              i2u.xx, i2u.yx,
00651                              i2u.xy, i2u.yy,
00652                              i2u.x0, i2u.y0,
00653                              id);
00654 
00655  bail:
00656     _cairo_surface_release_source_image (src, image, image_extra);
00657 
00658     return status;
00659 }
00660 
00661 /* The contents of the surface is already transformed into PDF units,
00662  * but when we composite the surface we may want to use a different
00663  * space.  The problem I see now is that the show_surface snippet
00664  * creates a surface 1x1, which in the snippet environment is the
00665  * entire surface.  When compositing the surface, cairo gives us the
00666  * 1x1 to 256x256 matrix.  This would be fine if cairo didn't actually
00667  * also transform the drawing to the surface.  Should the CTM be part
00668  * of the current target surface?
00669  */
00670 
00671 static cairo_int_status_t
00672 _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst,
00673                               cairo_surface_pattern_t *pattern)
00674 {
00675     cairo_pdf_document_t *document = dst->document;
00676     cairo_output_stream_t *output = document->output_stream;
00677     cairo_matrix_t i2u;
00678     cairo_pdf_stream_t *stream;
00679     int num_streams, i;
00680     cairo_pdf_surface_t *src;
00681 
00682     _cairo_pdf_surface_ensure_stream (dst);
00683 
00684     src = (cairo_pdf_surface_t *) pattern->surface;
00685 
00686     i2u = pattern->base.matrix;
00687     cairo_matrix_invert (&i2u);
00688     cairo_matrix_scale (&i2u, 1.0 / src->width, 1.0 / src->height);
00689 
00690     _cairo_output_stream_printf (output,
00691                              "q %f %f %f %f %f %f cm",
00692                              i2u.xx, i2u.yx,
00693                              i2u.xy, i2u.yy,
00694                              i2u.x0, i2u.y0);
00695 
00696     num_streams = _cairo_array_num_elements (&src->streams);
00697     for (i = 0; i < num_streams; i++) {
00698        _cairo_array_copy_element (&src->streams, i, &stream);
00699        _cairo_output_stream_printf (output,
00700                                  " /res%d Do",
00701                                  stream->id);
00702 
00703        _cairo_pdf_surface_add_xobject (dst, stream->id);
00704 
00705     }
00706        
00707     _cairo_output_stream_printf (output, " Q\r\n");
00708 
00709     return CAIRO_STATUS_SUCCESS;
00710 }
00711 
00712 static cairo_int_status_t
00713 _cairo_pdf_surface_composite (cairo_operator_t   operator,
00714                            cairo_pattern_t       *src_pattern,
00715                            cairo_pattern_t       *mask_pattern,
00716                            void           *abstract_dst,
00717                            int            src_x,
00718                            int            src_y,
00719                            int            mask_x,
00720                            int            mask_y,
00721                            int            dst_x,
00722                            int            dst_y,
00723                            unsigned int   width,
00724                            unsigned int   height)
00725 {
00726     cairo_pdf_surface_t *dst = abstract_dst;
00727     cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) src_pattern;
00728 
00729     if (mask_pattern)
00730        return CAIRO_STATUS_SUCCESS;
00731     
00732     if (src_pattern->type != CAIRO_PATTERN_SURFACE)
00733        return CAIRO_STATUS_SUCCESS;
00734 
00735     if (src->surface->backend == &cairo_pdf_surface_backend)
00736        return _cairo_pdf_surface_composite_pdf (dst, src);
00737     else
00738        return _cairo_pdf_surface_composite_image (dst, src);
00739 }
00740 
00741 static cairo_int_status_t
00742 _cairo_pdf_surface_fill_rectangles (void         *abstract_surface,
00743                                 cairo_operator_t operator,
00744                                 const cairo_color_t     *color,
00745                                 cairo_rectangle_t       *rects,
00746                                 int                     num_rects)
00747 {
00748     cairo_pdf_surface_t *surface = abstract_surface;
00749     cairo_pdf_document_t *document = surface->document;
00750     cairo_output_stream_t *output = document->output_stream;
00751     int i;
00752 
00753     _cairo_pdf_surface_ensure_stream (surface);
00754 
00755     _cairo_output_stream_printf (output,
00756                              "%f %f %f rg\r\n",
00757                              color->red, color->green, color->blue);
00758 
00759     for (i = 0; i < num_rects; i++) {
00760        _cairo_output_stream_printf (output,
00761                                  "%d %d %d %d re f\r\n",
00762                                  rects[i].x, rects[i].y,
00763                                  rects[i].width, rects[i].height);
00764     }
00765 
00766     return CAIRO_STATUS_SUCCESS;
00767 }
00768 
00769 static void
00770 emit_solid_pattern (cairo_pdf_surface_t *surface,
00771                   cairo_solid_pattern_t *pattern)
00772 {
00773     cairo_pdf_document_t *document = surface->document;
00774     cairo_output_stream_t *output = document->output_stream;
00775     unsigned int alpha;
00776     
00777     alpha = _cairo_pdf_surface_add_alpha (surface, pattern->color.alpha);
00778     _cairo_pdf_surface_ensure_stream (surface);
00779     _cairo_output_stream_printf (output,
00780                              "%f %f %f rg /a%d gs\r\n",
00781                              pattern->color.red,
00782                              pattern->color.green,
00783                              pattern->color.blue,
00784                              alpha);
00785 }
00786 
00787 static void
00788 emit_surface_pattern (cairo_pdf_surface_t *dst,
00789                     cairo_surface_pattern_t             *pattern)
00790 {
00791     cairo_pdf_document_t *document = dst->document;
00792     cairo_output_stream_t *output = document->output_stream;
00793     cairo_pdf_stream_t *stream;
00794     cairo_image_surface_t *image;
00795     void *image_extra;
00796     cairo_status_t status;
00797     unsigned int id, alpha;
00798     cairo_matrix_t pm;
00799 
00800     if (pattern->surface->backend == &cairo_pdf_surface_backend) {
00801        return;
00802     }
00803 
00804     status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
00805     if (status)
00806        return;
00807 
00808     _cairo_pdf_document_close_stream (document);
00809 
00810     id = emit_image_data (dst->document, image);
00811 
00812     /* BBox must be smaller than XStep by YStep or acroread wont
00813      * display the pattern. */
00814 
00815     cairo_matrix_init_identity (&pm);
00816     cairo_matrix_scale (&pm, image->width, image->height);
00817     pm = pattern->base.matrix;
00818     cairo_matrix_invert (&pm);
00819 
00820     stream = _cairo_pdf_document_open_stream (document,
00821                                          "   /BBox [ 0 0 256 256 ]\r\n"
00822                                          "   /XStep 256\r\n"
00823                                          "   /YStep 256\r\n"
00824                                          "   /PatternType 1\r\n"
00825                                          "   /TilingType 1\r\n"
00826                                          "   /PaintType 1\r\n"
00827                                          "   /Resources << /XObject << /res%d %d 0 R >> >>\r\n",
00828                                          id, id);
00829 
00830 
00831     _cairo_output_stream_printf (output,
00832                              " /res%d Do\r\n",
00833                              id);
00834 
00835     _cairo_pdf_surface_add_pattern (dst, stream->id);
00836 
00837     _cairo_pdf_surface_ensure_stream (dst);
00838     alpha = _cairo_pdf_surface_add_alpha (dst, 1.0);
00839     _cairo_output_stream_printf (output,
00840                              "/Pattern cs /res%d scn /a%d gs\r\n",
00841                              stream->id, alpha);
00842 
00843     _cairo_surface_release_source_image (pattern->surface, image, image_extra);
00844 }
00845 
00846 static unsigned int
00847 emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern)
00848 {
00849     cairo_pdf_document_t *document = surface->document;
00850     cairo_output_stream_t *output = document->output_stream;
00851     unsigned int function_id;
00852     char stops[2][3];
00853 
00854     function_id = _cairo_pdf_document_new_object (document);
00855 
00856     _cairo_output_stream_printf (output,
00857                              "%d 0 obj\r\n"
00858                              "<< /FunctionType 0\r\n"
00859                              "   /Domain [ 0.0 1.0 ]\r\n"
00860                              "   /Size [ 2 ]\r\n"
00861                              "   /BitsPerSample 8\r\n"
00862                              "   /Range [ 0.0 1.0 0.0 1.0 0.0 1.0 ]\r\n"
00863                              "   /Length 6\r\n"
00864                              ">>\r\n"
00865                              "stream\r\n",
00866                              function_id);
00867 
00868     stops[0][0] = pattern->stops[0].color.red   * 0xff + 0.5;
00869     stops[0][1] = pattern->stops[0].color.green * 0xff + 0.5;
00870     stops[0][2] = pattern->stops[0].color.blue  * 0xff + 0.5;
00871     stops[1][0] = pattern->stops[1].color.red   * 0xff + 0.5;
00872     stops[1][1] = pattern->stops[1].color.green * 0xff + 0.5;
00873     stops[1][2] = pattern->stops[1].color.blue  * 0xff + 0.5;
00874 
00875     _cairo_output_stream_write (output, stops, sizeof (stops));
00876 
00877     _cairo_output_stream_printf (output,
00878                              "\r\n"
00879                              "endstream\r\n"
00880                              "endobj\r\n");
00881 
00882     return function_id;
00883 }
00884 
00885 static void
00886 emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern)
00887 {
00888     cairo_pdf_document_t *document = surface->document;
00889     cairo_output_stream_t *output = document->output_stream;
00890     unsigned int function_id, pattern_id, alpha;
00891     double x0, y0, x1, y1;
00892     cairo_matrix_t p2u;
00893 
00894     _cairo_pdf_document_close_stream (document);
00895 
00896     function_id = emit_pattern_stops (surface, &pattern->base);
00897 
00898     p2u = pattern->base.base.matrix;
00899     cairo_matrix_invert (&p2u);
00900 
00901     x0 = pattern->point0.x;
00902     y0 = pattern->point0.y;
00903     cairo_matrix_transform_point (&p2u, &x0, &y0);
00904     x1 = pattern->point1.x;
00905     y1 = pattern->point1.y;
00906     cairo_matrix_transform_point (&p2u, &x1, &y1);
00907 
00908     pattern_id = _cairo_pdf_document_new_object (document);
00909     _cairo_output_stream_printf (output,
00910                              "%d 0 obj\r\n"
00911                              "<< /Type /Pattern\r\n"
00912                              "   /PatternType 2\r\n"
00913                              "   /Matrix [ 1 0 0 -1 0 %f ]\r\n"
00914                              "   /Shading\r\n"
00915                              "      << /ShadingType 2\r\n"
00916                              "         /ColorSpace /DeviceRGB\r\n"
00917                              "         /Coords [ %f %f %f %f ]\r\n"
00918                              "         /Function %d 0 R\r\n"
00919                              "         /Extend [ true true ]\r\n"
00920                              "      >>\r\n"
00921                              ">>\r\n"
00922                              "endobj\r\n",
00923                              pattern_id,
00924                              document->height,
00925                              x0, y0, x1, y1,
00926                              function_id);
00927     
00928     _cairo_pdf_surface_add_pattern (surface, pattern_id);
00929 
00930     _cairo_pdf_surface_ensure_stream (surface);
00931     alpha = _cairo_pdf_surface_add_alpha (surface, 1.0);
00932 
00933     /* Use pattern */
00934     _cairo_output_stream_printf (output,
00935                              "/Pattern cs /res%d scn /a%d gs\r\n",
00936                              pattern_id, alpha);
00937 }
00938        
00939 static void
00940 emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern)
00941 {
00942     cairo_pdf_document_t *document = surface->document;
00943     cairo_output_stream_t *output = document->output_stream;
00944     unsigned int function_id, pattern_id, alpha;
00945     double x0, y0, x1, y1, r0, r1;
00946     cairo_matrix_t p2u;
00947 
00948     _cairo_pdf_document_close_stream (document);
00949 
00950     function_id = emit_pattern_stops (surface, &pattern->base);
00951 
00952     p2u = pattern->base.base.matrix;
00953     cairo_matrix_invert (&p2u);
00954 
00955     x0 = pattern->center0.x;
00956     y0 = pattern->center0.y;
00957     r0 = pattern->radius0;
00958     cairo_matrix_transform_point (&p2u, &x0, &y0);
00959     x1 = pattern->center1.x;
00960     y1 = pattern->center1.y;
00961     r1 = pattern->radius1;
00962     cairo_matrix_transform_point (&p2u, &x1, &y1);
00963 
00964     /* FIXME: This is surely crack, but how should you scale a radius
00965      * in a non-orthogonal coordinate system? */
00966     cairo_matrix_transform_distance (&p2u, &r0, &r1);
00967 
00968     /* FIXME: There is a difference between the cairo gradient extend
00969      * semantics and PDF extend semantics. PDFs extend=false means
00970      * that nothing is painted outside the gradient boundaries,
00971      * whereas cairo takes this to mean that the end color is padded
00972      * to infinity. Setting extend=true in PDF gives the cairo default
00973      * behavoir, not yet sure how to implement the cairo mirror and
00974      * repeat behaviour. */
00975     pattern_id = _cairo_pdf_document_new_object (document);
00976     _cairo_output_stream_printf (output,
00977                              "%d 0 obj\r\n"
00978                              "<< /Type /Pattern\r\n"
00979                              "   /PatternType 2\r\n"
00980                              "   /Matrix [ 1 0 0 -1 0 %f ]\r\n"
00981                              "   /Shading\r\n"
00982                              "      << /ShadingType 3\r\n"
00983                              "         /ColorSpace /DeviceRGB\r\n"
00984                              "         /Coords [ %f %f %f %f %f %f ]\r\n"
00985                              "         /Function %d 0 R\r\n"
00986                              "         /Extend [ true true ]\r\n"
00987                              "      >>\r\n"
00988                              ">>\r\n"
00989                              "endobj\r\n",
00990                              pattern_id,
00991                              document->height,
00992                              x0, y0, r0, x1, y1, r1,
00993                              function_id);
00994     
00995     _cairo_pdf_surface_add_pattern (surface, pattern_id);
00996 
00997     _cairo_pdf_surface_ensure_stream (surface);
00998     alpha = _cairo_pdf_surface_add_alpha (surface, 1.0);
00999 
01000     /* Use pattern */
01001     _cairo_output_stream_printf (output,
01002                              "/Pattern cs /res%d scn /a%d gs\r\n",
01003                              pattern_id, alpha);
01004 }
01005        
01006 static void
01007 emit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
01008 {
01009     switch (pattern->type) {
01010     case CAIRO_PATTERN_SOLID:      
01011        emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
01012        break;
01013 
01014     case CAIRO_PATTERN_SURFACE:
01015        emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern);
01016        break;
01017 
01018     case CAIRO_PATTERN_LINEAR:
01019        emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
01020        break;
01021 
01022     case CAIRO_PATTERN_RADIAL:
01023        emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern);
01024        break;     
01025     }
01026 }
01027 
01028 static double
01029 intersect (cairo_line_t *line, cairo_fixed_t y)
01030 {
01031     return _cairo_fixed_to_double (line->p1.x) +
01032        _cairo_fixed_to_double (line->p2.x - line->p1.x) *
01033        _cairo_fixed_to_double (y - line->p1.y) /
01034        _cairo_fixed_to_double (line->p2.y - line->p1.y);
01035 }
01036 
01037 typedef struct
01038 {
01039     cairo_output_stream_t *output_stream;
01040     cairo_bool_t has_current_point;
01041 } pdf_path_info_t;
01042 
01043 static cairo_status_t
01044 _cairo_pdf_path_move_to (void *closure, cairo_point_t *point)
01045 {
01046     pdf_path_info_t *info = closure;
01047 
01048     _cairo_output_stream_printf (info->output_stream,
01049                              "%f %f m ",
01050                              _cairo_fixed_to_double (point->x),
01051                              _cairo_fixed_to_double (point->y));
01052     info->has_current_point = TRUE;
01053     
01054     return CAIRO_STATUS_SUCCESS;
01055 }
01056 
01057 static cairo_status_t
01058 _cairo_pdf_path_line_to (void *closure, cairo_point_t *point)
01059 {
01060     pdf_path_info_t *info = closure;
01061     const char *pdf_operator;
01062 
01063     if (info->has_current_point)
01064        pdf_operator = "l";
01065     else
01066        pdf_operator = "m";
01067     
01068     _cairo_output_stream_printf (info->output_stream,
01069                              "%f %f %s ",
01070                              _cairo_fixed_to_double (point->x),
01071                              _cairo_fixed_to_double (point->y),
01072                              pdf_operator);
01073     info->has_current_point = TRUE;
01074 
01075     return CAIRO_STATUS_SUCCESS;
01076 }
01077 
01078 static cairo_status_t
01079 _cairo_pdf_path_curve_to (void          *closure,
01080                        cairo_point_t *b,
01081                        cairo_point_t *c,
01082                        cairo_point_t *d)
01083 {
01084     pdf_path_info_t *info = closure;
01085 
01086     _cairo_output_stream_printf (info->output_stream,
01087                              "%f %f %f %f %f %f c ",
01088                              _cairo_fixed_to_double (b->x),
01089                              _cairo_fixed_to_double (b->y),
01090                              _cairo_fixed_to_double (c->x),
01091                              _cairo_fixed_to_double (c->y),
01092                              _cairo_fixed_to_double (d->x),
01093                              _cairo_fixed_to_double (d->y));
01094     
01095     return CAIRO_STATUS_SUCCESS;
01096 }
01097 
01098 static cairo_status_t
01099 _cairo_pdf_path_close_path (void *closure)
01100 {
01101     pdf_path_info_t *info = closure;
01102     
01103     _cairo_output_stream_printf (info->output_stream,
01104                              "h\r\n");
01105     info->has_current_point = FALSE;
01106 
01107     return CAIRO_STATUS_SUCCESS;
01108 }
01109 
01110 static cairo_int_status_t
01111 _cairo_pdf_surface_fill_path (cairo_operator_t          operator,
01112                            cairo_pattern_t              *pattern,
01113                            void                  *abstract_dst,
01114                            cairo_path_fixed_t    *path,
01115                            cairo_fill_rule_t            fill_rule,
01116                            double                tolerance)
01117 {
01118     cairo_pdf_surface_t *surface = abstract_dst;
01119     cairo_pdf_document_t *document = surface->document;
01120     const char *pdf_operator;
01121     cairo_status_t status;
01122     pdf_path_info_t info;
01123 
01124     emit_pattern (surface, pattern);
01125 
01126     /* After the above switch the current stream should belong to this
01127      * surface, so no need to _cairo_pdf_surface_ensure_stream() */
01128     assert (document->current_stream != NULL &&
01129            document->current_stream == surface->current_stream);
01130 
01131     info.output_stream = document->output_stream;
01132     info.has_current_point = FALSE;
01133 
01134     status = _cairo_path_fixed_interpret (path,
01135                                      CAIRO_DIRECTION_FORWARD,
01136                                      _cairo_pdf_path_move_to,
01137                                      _cairo_pdf_path_line_to,
01138                                      _cairo_pdf_path_curve_to,
01139                                      _cairo_pdf_path_close_path,
01140                                      &info);
01141 
01142     switch (fill_rule) {
01143     case CAIRO_FILL_RULE_WINDING:
01144        pdf_operator = "f";
01145        break;
01146     case CAIRO_FILL_RULE_EVEN_ODD:
01147        pdf_operator = "f*";
01148        break;
01149     default:
01150        ASSERT_NOT_REACHED;
01151     }
01152 
01153     _cairo_output_stream_printf (document->output_stream,
01154                              "%s\r\n",
01155                              pdf_operator);
01156 
01157     return status;
01158 }
01159   
01160 static cairo_int_status_t
01161 _cairo_pdf_surface_composite_trapezoids (cairo_operator_t      operator,
01162                                     cairo_pattern_t     *pattern,
01163                                     void                *abstract_dst,
01164                                     cairo_antialias_t   antialias,
01165                                     int                 x_src,
01166                                     int                 y_src,
01167                                     int                 x_dst,
01168                                     int                 y_dst,
01169                                     unsigned int        width,
01170                                     unsigned int        height,
01171                                     cairo_trapezoid_t   *traps,
01172                                     int                 num_traps)
01173 {
01174     cairo_pdf_surface_t *surface = abstract_dst;
01175     cairo_pdf_document_t *document = surface->document;
01176     cairo_output_stream_t *output = document->output_stream;
01177     int i;
01178 
01179     emit_pattern (surface, pattern);
01180 
01181     /* After the above switch the current stream should belong to this
01182      * surface, so no need to _cairo_pdf_surface_ensure_stream() */
01183     assert (document->current_stream != NULL &&
01184            document->current_stream == surface->current_stream);
01185 
01186     for (i = 0; i < num_traps; i++) {
01187        double left_x1, left_x2, right_x1, right_x2;
01188 
01189        left_x1  = intersect (&traps[i].left, traps[i].top);
01190        left_x2  = intersect (&traps[i].left, traps[i].bottom);
01191        right_x1 = intersect (&traps[i].right, traps[i].top);
01192        right_x2 = intersect (&traps[i].right, traps[i].bottom);
01193 
01194        _cairo_output_stream_printf (output,
01195                                  "%f %f m %f %f l %f %f l %f %f l h\r\n",
01196                                  left_x1, _cairo_fixed_to_double (traps[i].top),
01197                                  left_x2, _cairo_fixed_to_double (traps[i].bottom),
01198                                  right_x2, _cairo_fixed_to_double (traps[i].bottom),
01199                                  right_x1, _cairo_fixed_to_double (traps[i].top));
01200     }
01201 
01202     _cairo_output_stream_printf (output,
01203                              "f\r\n");
01204 
01205     return CAIRO_STATUS_SUCCESS;
01206 }
01207 
01208 static cairo_int_status_t
01209 _cairo_pdf_surface_copy_page (void *abstract_surface)
01210 {
01211     cairo_pdf_surface_t *surface = abstract_surface;
01212     cairo_pdf_document_t *document = surface->document;
01213 
01214     return _cairo_pdf_document_add_page (document, surface);
01215 }
01216 
01217 static cairo_int_status_t
01218 _cairo_pdf_surface_show_page (void *abstract_surface)
01219 {
01220     cairo_pdf_surface_t *surface = abstract_surface;
01221     cairo_pdf_document_t *document = surface->document;
01222     cairo_int_status_t status;
01223 
01224     status = _cairo_pdf_document_add_page (document, surface);
01225     if (status)
01226        return status;
01227 
01228     _cairo_pdf_surface_clear (surface);
01229 
01230     return CAIRO_STATUS_SUCCESS;
01231 }
01232 
01233 static cairo_int_status_t
01234 _cairo_pdf_surface_get_extents (void               *abstract_surface,
01235                             cairo_rectangle_t *rectangle)
01236 {
01237     cairo_pdf_surface_t *surface = abstract_surface;
01238 
01239     rectangle->x = 0;
01240     rectangle->y = 0;
01241 
01242     /* XXX: The conversion to integers here is pretty bogus, (not to
01243      * mention the aribitray limitation of width to a short(!). We
01244      * may need to come up with a better interface for get_size.
01245      */
01246     rectangle->width  = (int) ceil (surface->width);
01247     rectangle->height = (int) ceil (surface->height);
01248 
01249     return CAIRO_STATUS_SUCCESS;
01250 }
01251 
01252 static cairo_font_subset_t *
01253 _cairo_pdf_document_get_font (cairo_pdf_document_t      *document,
01254                            cairo_scaled_font_t   *scaled_font)
01255 {
01256     cairo_unscaled_font_t *unscaled_font;
01257     cairo_font_subset_t *pdf_font;
01258     unsigned int num_fonts, i;
01259 
01260     /* XXX: Need to fix this to work with a general cairo_scaled_font_t. */
01261     if (! _cairo_scaled_font_is_ft (scaled_font))
01262        return NULL;
01263 
01264     /* XXX Why is this an ft specific function? */
01265     unscaled_font = _cairo_ft_scaled_font_get_unscaled_font (scaled_font);
01266 
01267     num_fonts = _cairo_array_num_elements (&document->fonts);
01268     for (i = 0; i < num_fonts; i++) {
01269        _cairo_array_copy_element (&document->fonts, i, &pdf_font);
01270        if (pdf_font->unscaled_font == unscaled_font)
01271            return pdf_font;
01272     }
01273 
01274     /* FIXME: Figure out here which font backend is in use and call
01275      * the appropriate constructor. */
01276     pdf_font = _cairo_font_subset_create (unscaled_font);
01277     if (pdf_font == NULL)
01278        return NULL;
01279 
01280     pdf_font->font_id = _cairo_pdf_document_new_object (document);
01281 
01282     if (_cairo_array_append (&document->fonts, &pdf_font, 1) == NULL) {
01283        _cairo_font_subset_destroy (pdf_font);
01284        return NULL;
01285     }
01286 
01287     return pdf_font;
01288 }
01289 
01290 static cairo_int_status_t
01291 _cairo_pdf_surface_show_glyphs (cairo_scaled_font_t     *scaled_font,
01292                             cairo_operator_t     operator,
01293                             cairo_pattern_t             *pattern,
01294                             void                 *abstract_surface,
01295                             int                  source_x,
01296                             int                  source_y,
01297                             int                  dest_x,
01298                             int                  dest_y,
01299                             unsigned int         width,
01300                             unsigned int         height,
01301                             const cairo_glyph_t  *glyphs,
01302                             int                  num_glyphs)
01303 {
01304     cairo_pdf_surface_t *surface = abstract_surface;
01305     cairo_pdf_document_t *document = surface->document;
01306     cairo_output_stream_t *output = document->output_stream;
01307     cairo_font_subset_t *pdf_font;
01308     int i, index;
01309     double det;
01310 
01311     /* XXX: Need to fix this to work with a general cairo_scaled_font_t. */
01312     if (! _cairo_scaled_font_is_ft (scaled_font))
01313        return CAIRO_INT_STATUS_UNSUPPORTED;
01314 
01315     pdf_font = _cairo_pdf_document_get_font (document, scaled_font);
01316     if (pdf_font == NULL)
01317        return CAIRO_STATUS_NO_MEMORY;
01318 
01319     /* Some PDF viewers (at least older versions of xpdf) have trouble with
01320      * size 0 fonts. If the font size is less than 1/1000pt, ignore the
01321      * font */
01322     _cairo_matrix_compute_determinant (&scaled_font->scale, &det);
01323     if (fabs (det) < 0.000001)
01324        return CAIRO_STATUS_SUCCESS;
01325     
01326     emit_pattern (surface, pattern);
01327 
01328     _cairo_output_stream_printf (output,
01329                              "BT /res%u 1 Tf", pdf_font->font_id);
01330     for (i = 0; i < num_glyphs; i++) {
01331 
01332        index = _cairo_font_subset_use_glyph (pdf_font, glyphs[i].index);
01333 
01334        _cairo_output_stream_printf (output,
01335                                  " %f %f %f %f %f %f Tm (\\%o) Tj",
01336                                  scaled_font->scale.xx,
01337                                  scaled_font->scale.yx,
01338                                  -scaled_font->scale.xy,
01339                                  -scaled_font->scale.yy,
01340                                  glyphs[i].x,
01341                                  glyphs[i].y,
01342                                  index);
01343     }
01344     _cairo_output_stream_printf (output,
01345                              " ET\r\n");
01346 
01347     _cairo_pdf_surface_add_font (surface, pdf_font->font_id);
01348 
01349     return CAIRO_STATUS_SUCCESS;
01350 }
01351 
01352 static cairo_int_status_t
01353 _cairo_pdf_surface_intersect_clip_path (void                   *dst,
01354                                    cairo_path_fixed_t   *path,
01355                                    cairo_fill_rule_t    fill_rule,
01356                                    double               tolerance,
01357                                    cairo_antialias_t    antialias)
01358 {
01359     cairo_pdf_surface_t *surface = dst;
01360     cairo_pdf_document_t *document = surface->document;
01361     cairo_output_stream_t *output = document->output_stream;
01362     cairo_status_t status;
01363     pdf_path_info_t info;
01364     const char *pdf_operator;
01365 
01366     _cairo_pdf_surface_ensure_stream (surface);
01367 
01368     if (path == NULL) {
01369        if (surface->has_clip)
01370            _cairo_output_stream_printf (output, "Q\r\n");
01371        surface->has_clip = FALSE;
01372        return CAIRO_STATUS_SUCCESS;
01373     }
01374 
01375     if (!surface->has_clip) {
01376        _cairo_output_stream_printf (output, "q ");
01377        surface->has_clip = TRUE;
01378     }
01379 
01380     info.output_stream = document->output_stream;
01381     info.has_current_point = FALSE;
01382 
01383     status = _cairo_path_fixed_interpret (path,
01384                                      CAIRO_DIRECTION_FORWARD,
01385                                      _cairo_pdf_path_move_to,
01386                                      _cairo_pdf_path_line_to,
01387                                      _cairo_pdf_path_curve_to,
01388                                      _cairo_pdf_path_close_path,
01389                                      &info);
01390 
01391     switch (fill_rule) {
01392     case CAIRO_FILL_RULE_WINDING:
01393        pdf_operator = "W";
01394        break;
01395     case CAIRO_FILL_RULE_EVEN_ODD:
01396        pdf_operator = "W*";
01397        break;
01398     default:
01399        ASSERT_NOT_REACHED;
01400     }
01401 
01402     _cairo_output_stream_printf (document->output_stream,
01403                              "%s n\r\n",
01404                              pdf_operator);
01405 
01406     return status;
01407 }
01408 
01409 static void
01410 _cairo_pdf_surface_get_font_options (void                  *abstract_surface,
01411                                  cairo_font_options_t  *options)
01412 {
01413   _cairo_font_options_init_default (options);
01414 
01415   cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
01416   cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
01417 }
01418 
01419 static const cairo_surface_backend_t cairo_pdf_surface_backend = {
01420     _cairo_pdf_surface_create_similar,
01421     _cairo_pdf_surface_finish,
01422     NULL, /* acquire_source_image */
01423     NULL, /* release_source_image */
01424     NULL, /* acquire_dest_image */
01425     NULL, /* release_dest_image */
01426     NULL, /* clone_similar */
01427     _cairo_pdf_surface_composite,
01428     _cairo_pdf_surface_fill_rectangles,
01429     _cairo_pdf_surface_composite_trapezoids,
01430     _cairo_pdf_surface_copy_page,
01431     _cairo_pdf_surface_show_page,
01432     NULL, /* set_clip_region */
01433     _cairo_pdf_surface_intersect_clip_path,
01434     _cairo_pdf_surface_get_extents,
01435     _cairo_pdf_surface_show_glyphs,
01436     _cairo_pdf_surface_fill_path,
01437     _cairo_pdf_surface_get_font_options
01438 };
01439 
01440 static cairo_pdf_document_t *
01441 _cairo_pdf_document_create (cairo_output_stream_t       *output_stream,
01442                          double                  width,
01443                          double                  height)
01444 {
01445     cairo_pdf_document_t *document;
01446 
01447     document = malloc (sizeof (cairo_pdf_document_t));
01448     if (document == NULL)
01449        return NULL;
01450 
01451     document->output_stream = output_stream;
01452     document->ref_count = 1;
01453     document->owner = NULL;
01454     document->finished = FALSE;
01455     document->width = width;
01456     document->height = height;
01457     document->x_dpi = DEFAULT_DPI;
01458     document->y_dpi = DEFAULT_DPI;
01459 
01460     _cairo_array_init (&document->objects, sizeof (cairo_pdf_object_t));
01461     _cairo_array_init (&document->pages, sizeof (unsigned int));
01462     document->next_available_id = 1;
01463 
01464     document->current_stream = NULL;
01465 
01466     document->pages_id = _cairo_pdf_document_new_object (document);
01467 
01468     _cairo_array_init (&document->fonts, sizeof (cairo_font_subset_t *));
01469 
01470     /* Document header */
01471     _cairo_output_stream_printf (output_stream,
01472                              "%%PDF-1.4\r\n");
01473 
01474     return document;
01475 }
01476 
01477 static unsigned int
01478 _cairo_pdf_document_write_info (cairo_pdf_document_t *document)
01479 {
01480     cairo_output_stream_t *output = document->output_stream;
01481     unsigned int id;
01482 
01483     id = _cairo_pdf_document_new_object (document);
01484     _cairo_output_stream_printf (output,
01485                              "%d 0 obj\r\n"
01486                              "<< /Creator (cairographics.org)\r\n"
01487                              "   /Producer (cairographics.org)\r\n"
01488                              ">>\r\n"
01489                              "endobj\r\n",
01490                              id);
01491 
01492     return id;
01493 }
01494 
01495 static void
01496 _cairo_pdf_document_write_pages (cairo_pdf_document_t *document)
01497 {
01498     cairo_output_stream_t *stream = document->output_stream;
01499     unsigned int page_id;
01500     int num_pages, i;
01501 
01502     _cairo_pdf_document_update_object (document, document->pages_id);
01503     _cairo_output_stream_printf (stream,
01504                              "%d 0 obj\r\n"
01505                              "<< /Type /Pages\r\n"
01506                              "   /Kids [ ",
01507                              document->pages_id);
01508     
01509     num_pages = _cairo_array_num_elements (&document->pages);
01510     for (i = 0; i < num_pages; i++) {
01511        _cairo_array_copy_element (&document->pages, i, &page_id);
01512        _cairo_output_stream_printf (stream, "%d 0 R ", page_id);
01513     }
01514 
01515     _cairo_output_stream_printf (stream, "]\r\n"); 
01516     _cairo_output_stream_printf (stream, "   /Count %d\r\n", num_pages);
01517 
01518     /* TODO: Figure out wich other defaults to be inherited by /Page
01519      * objects. */
01520     _cairo_output_stream_printf (stream,
01521                              "   /MediaBox [ 0 0 %f %f ]\r\n"
01522                              ">>\r\n"
01523                              "endobj\r\n",
01524                              document->width,
01525                              document->height);
01526 }
01527 
01528 static cairo_status_t
01529 _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
01530 {
01531     cairo_output_stream_t *output = document->output_stream;
01532     cairo_font_subset_t *font;
01533     int num_fonts, i, j;
01534     const char *data;
01535     char *compressed;
01536     unsigned long data_size, compressed_size;
01537     unsigned int stream_id, descriptor_id;
01538     cairo_status_t status = CAIRO_STATUS_SUCCESS;
01539 
01540     num_fonts = _cairo_array_num_elements (&document->fonts);
01541     for (i = 0; i < num_fonts; i++) {
01542        _cairo_array_copy_element (&document->fonts, i, &font);
01543 
01544        status = _cairo_font_subset_generate (font, &data, &data_size);
01545        if (status)
01546            goto fail;
01547 
01548        compressed = compress_dup (data, data_size, &compressed_size);
01549        if (compressed == NULL) {
01550            status = CAIRO_STATUS_NO_MEMORY;
01551            goto fail;
01552        }
01553 
01554        stream_id = _cairo_pdf_document_new_object (document);
01555        _cairo_output_stream_printf (output,
01556                                  "%d 0 obj\r\n"
01557                                  "<< /Filter /FlateDecode\r\n"
01558                                  "   /Length %lu\r\n"
01559                                  "   /Length1 %lu\r\n"
01560                                  ">>\r\n"
01561                                  "stream\r\n",
01562                                  stream_id,
01563                                  compressed_size,
01564                                  data_size);
01565        _cairo_output_stream_write (output, compressed, compressed_size);
01566        _cairo_output_stream_printf (output,
01567                                  "\r\n"
01568                                  "endstream\r\n"
01569                                  "endobj\r\n");
01570        free (compressed);
01571 
01572        descriptor_id = _cairo_pdf_document_new_object (document);
01573        _cairo_output_stream_printf (output,
01574                                  "%d 0 obj\r\n"
01575                                  "<< /Type /FontDescriptor\r\n"
01576                                  "   /FontName /7%s\r\n"
01577                                  "   /Flags 4\r\n"
01578                                  "   /FontBBox [ %ld %ld %ld %ld ]\r\n"
01579                                  "   /ItalicAngle 0\r\n"
01580                                  "   /Ascent %ld\r\n"
01581                                  "   /Descent %ld\r\n"
01582                                  "   /CapHeight 500\r\n"
01583                                  "   /StemV 80\r\n"
01584                                  "   /StemH 80\r\n"
01585                                  "   /FontFile2 %u 0 R\r\n"
01586                                  ">>\r\n"
01587                                  "endobj\r\n",
01588                                  descriptor_id,
01589                                  font->base_font,
01590                                  font->x_min,
01591                                  font->y_min,
01592                                  font->x_max,
01593                                  font->y_max,
01594                                  font->ascent,
01595                                  font->descent,
01596                                  stream_id);
01597 
01598        _cairo_pdf_document_update_object (document, font->font_id);
01599        _cairo_output_stream_printf (output,
01600                                  "%d 0 obj\r\n"
01601                                  "<< /Type /Font\r\n"
01602                                  "   /Subtype /TrueType\r\n"
01603                                  "   /BaseFont /%s\r\n"
01604                                  "   /FirstChar 0\r\n"
01605                                  "   /LastChar %d\r\n"
01606                                  "   /FontDescriptor %d 0 R\r\n"
01607                                  "   /Widths ",
01608                                  font->font_id,
01609                                  font->base_font,
01610                                  font->num_glyphs,
01611                                  descriptor_id);
01612 
01613        _cairo_output_stream_printf (output,
01614                                  "[");
01615 
01616        for (j = 0; j < font->num_glyphs; j++)
01617            _cairo_output_stream_printf (output,
01618                                     " %d",
01619                                     font->widths[j]);
01620 
01621        _cairo_output_stream_printf (output,
01622                                  " ]\r\n"
01623                                  ">>\r\n"
01624                                  "endobj\r\n");
01625 
01626     fail:
01627        _cairo_font_subset_destroy (font);
01628     }
01629 
01630     return status;
01631 }
01632 
01633 static unsigned int
01634 _cairo_pdf_document_write_catalog (cairo_pdf_document_t *document)
01635 {
01636     cairo_output_stream_t *output = document->output_stream;
01637     unsigned int id;
01638 
01639     id = _cairo_pdf_document_new_object (document);
01640     _cairo_output_stream_printf (output,
01641                              "%d 0 obj\r\n"
01642                              "<< /Type /Catalog\r\n"
01643                              "   /Pages %d 0 R\r\n" 
01644                              ">>\r\n"
01645                              "endobj\r\n",
01646                              id, document->pages_id);
01647 
01648     return id;
01649 }
01650 
01651 static long
01652 _cairo_pdf_document_write_xref (cairo_pdf_document_t *document)
01653 {
01654     cairo_output_stream_t *output = document->output_stream;
01655     cairo_pdf_object_t *object;
01656     int num_objects, i;
01657     long offset;
01658     char buffer[11];
01659 
01660     num_objects = _cairo_array_num_elements (&document->objects);
01661 
01662     offset = _cairo_output_stream_get_position (output);
01663     _cairo_output_stream_printf (output,
01664                              "xref\r\n"
01665                              "%d %d\r\n",
01666                              0, num_objects + 1);
01667 
01668     _cairo_output_stream_printf (output,
01669                              "0000000000 65535 f\r\n");
01670     for (i = 0; i < num_objects; i++) {
01671        object = _cairo_array_index (&document->objects, i);
01672        snprintf (buffer, sizeof buffer, "%010ld", object->offset);
01673        _cairo_output_stream_printf (output,
01674                                  "%s 00000 n\r\n", buffer);
01675     }
01676 
01677     return offset;
01678 }
01679 
01680 static cairo_pdf_document_t *
01681 _cairo_pdf_document_reference (cairo_pdf_document_t *document)
01682 {
01683     document->ref_count++;
01684 
01685     return document;
01686 }
01687 
01688 static void
01689 _cairo_pdf_document_destroy (cairo_pdf_document_t *document)
01690 {
01691     document->ref_count--;
01692     if (document->ref_count > 0)
01693       return;
01694 
01695     _cairo_pdf_document_finish (document);
01696 
01697     free (document);
01698 }
01699     
01700 static cairo_status_t
01701 _cairo_pdf_document_finish (cairo_pdf_document_t *document)
01702 {
01703     cairo_status_t status;
01704     cairo_output_stream_t *output = document->output_stream;
01705     long offset;
01706     unsigned int info_id, catalog_id;
01707 
01708     if (document->finished)
01709        return CAIRO_STATUS_SUCCESS;
01710 
01711     _cairo_pdf_document_close_stream (document);
01712     _cairo_pdf_document_write_pages (document);
01713     _cairo_pdf_document_write_fonts (document);
01714     info_id = _cairo_pdf_document_write_info (document);
01715     catalog_id = _cairo_pdf_document_write_catalog (document);
01716     offset = _cairo_pdf_document_write_xref (document);
01717     
01718     _cairo_output_stream_printf (output,
01719                              "trailer\r\n"
01720                              "<< /Size %d\r\n"
01721                              "   /Root %d 0 R\r\n"
01722                              "   /Info %d 0 R\r\n"
01723                              ">>\r\n",
01724                              document->next_available_id,
01725                              catalog_id,
01726                              info_id);
01727 
01728     _cairo_output_stream_printf (output,
01729                              "startxref\r\n"
01730                              "%ld\r\n"
01731                              "%%%%EOF\r\n",
01732                              offset);
01733 
01734     status = _cairo_output_stream_get_status (output);
01735     _cairo_output_stream_destroy (output);
01736 
01737     _cairo_array_fini (&document->objects);
01738     _cairo_array_fini (&document->pages);
01739     _cairo_array_fini (&document->fonts);
01740 
01741     document->finished = TRUE;
01742 
01743     return status;
01744 }
01745 
01746 static cairo_status_t
01747 _cairo_pdf_document_add_page (cairo_pdf_document_t      *document,
01748                            cairo_pdf_surface_t   *surface)
01749 {
01750     cairo_pdf_stream_t *stream;
01751     cairo_pdf_resource_t *res;
01752     cairo_output_stream_t *output = document->output_stream;
01753     unsigned int page_id;
01754     double alpha;
01755     int num_streams, num_alphas, num_resources, i;
01756 
01757     assert (!document->finished);
01758 
01759     _cairo_pdf_surface_ensure_stream (surface);
01760 
01761     if (surface->has_clip)
01762        _cairo_output_stream_printf (output, "Q\r\n");
01763 
01764     _cairo_pdf_document_close_stream (document);
01765 
01766     page_id = _cairo_pdf_document_new_object (document);
01767     _cairo_output_stream_printf (output,
01768                              "%d 0 obj\r\n"
01769                              "<< /Type /Page\r\n"
01770                              "   /Parent %d 0 R\r\n"
01771                              "   /Contents [",
01772                              page_id,
01773                              document->pages_id);
01774 
01775     num_streams = _cairo_array_num_elements (&surface->streams);
01776     for (i = 0; i < num_streams; i++) {
01777        _cairo_array_copy_element (&surface->streams, i, &stream);     
01778        _cairo_output_stream_printf (output,
01779                                  " %d 0 R",
01780                                  stream->id);
01781     }
01782 
01783     _cairo_output_stream_printf (output,
01784                              " ]\r\n"
01785                              "   /Resources <<\r\n");
01786 
01787     num_resources =  _cairo_array_num_elements (&surface->fonts);
01788     if (num_resources > 0) {
01789        _cairo_output_stream_printf (output,
01790                                  "      /Font <<");
01791 
01792        for (i = 0; i < num_resources; i++) {
01793            res = _cairo_array_index (&surface->fonts, i);
01794            _cairo_output_stream_printf (output,
01795                                     " /res%d %d 0 R",
01796                                     res->id, res->id);
01797        }
01798 
01799        _cairo_output_stream_printf (output,
01800                                  " >>\r\n");
01801     }
01802     
01803     num_alphas =  _cairo_array_num_elements (&surface->alphas);
01804     if (num_alphas > 0) {
01805        _cairo_output_stream_printf (output,
01806                                  "      /ExtGState <<\r\n");
01807 
01808        for (i = 0; i < num_alphas; i++) {
01809            _cairo_array_copy_element (&surface->alphas, i, &alpha);
01810            _cairo_output_stream_printf (output,
01811                                     "         /a%d << /ca %f >>\r\n",
01812                                     i, alpha);
01813        }
01814 
01815        _cairo_output_stream_printf (output,
01816                                  "      >>\r\n");
01817     }
01818     
01819     num_resources = _cairo_array_num_elements (&surface->patterns);
01820     if (num_resources > 0) {
01821        _cairo_output_stream_printf (output,
01822                                  "      /Pattern <<");
01823        for (i = 0; i < num_resources; i++) {
01824            res = _cairo_array_index (&surface->patterns, i);
01825            _cairo_output_stream_printf (output,
01826                                     " /res%d %d 0 R",
01827                                     res->id, res->id);
01828        }
01829 
01830        _cairo_output_stream_printf (output,
01831                                  " >>\r\n");
01832     }
01833 
01834     num_resources = _cairo_array_num_elements (&surface->xobjects);
01835     if (num_resources > 0) {
01836        _cairo_output_stream_printf (output,
01837                                  "      /XObject <<");
01838 
01839        for (i = 0; i < num_resources; i++) {
01840            res = _cairo_array_index (&surface->xobjects, i);
01841            _cairo_output_stream_printf (output,
01842                                     " /res%d %d 0 R",
01843                                     res->id, res->id);
01844        }
01845 
01846        _cairo_output_stream_printf (output,
01847                                  " >>\r\n");
01848     }
01849 
01850     _cairo_output_stream_printf (output,
01851                              "   >>\r\n"
01852                              ">>\r\n"
01853                              "endobj\r\n");
01854 
01855     _cairo_array_append (&document->pages, &page_id, 1);
01856 
01857     return CAIRO_STATUS_SUCCESS;
01858 }