2008-01-07 20:55:56 +10:30
|
|
|
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
|
2005-01-05 14:29:31 +00:00
|
|
|
/* cairo - a vector graphics library with display and print output
|
|
|
|
|
*
|
|
|
|
|
* Copyright © 2004 Red Hat, Inc
|
2006-04-18 16:53:23 -07:00
|
|
|
* Copyright © 2006 Red Hat, Inc
|
2008-01-07 20:55:56 +10:30
|
|
|
* Copyright © 2007, 2008 Adrian Johnson
|
2005-01-05 14:29:31 +00:00
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it either under the terms of the GNU Lesser General Public
|
|
|
|
|
* License version 2.1 as published by the Free Software Foundation
|
|
|
|
|
* (the "LGPL") or, at your option, under the terms of the Mozilla
|
|
|
|
|
* Public License Version 1.1 (the "MPL"). If you do not alter this
|
|
|
|
|
* notice, a recipient may use your version of this file under either
|
|
|
|
|
* the MPL or the LGPL.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the LGPL along with this library
|
|
|
|
|
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
* You should have received a copy of the MPL along with this library
|
|
|
|
|
* in the file COPYING-MPL-1.1
|
|
|
|
|
*
|
|
|
|
|
* The contents of this file are subject to the Mozilla Public License
|
|
|
|
|
* Version 1.1 (the "License"); you may not use this file except in
|
|
|
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
|
*
|
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
|
|
|
|
|
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
|
|
|
|
|
* the specific language governing rights and limitations.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is the cairo graphics library.
|
|
|
|
|
*
|
|
|
|
|
* The Initial Developer of the Original Code is University of Southern
|
|
|
|
|
* California.
|
|
|
|
|
*
|
|
|
|
|
* Contributor(s):
|
|
|
|
|
* Kristian Høgsberg <krh@redhat.com>
|
2006-04-18 16:53:23 -07:00
|
|
|
* Carl Worth <cworth@cworth.org>
|
2007-08-25 06:44:08 +09:30
|
|
|
* Adrian Johnson <ajohnson@redneon.com>
|
2005-01-05 14:29:31 +00:00
|
|
|
*/
|
|
|
|
|
|
2008-03-12 17:52:16 +00:00
|
|
|
#define _BSD_SOURCE /* for snprintf() */
|
2005-01-05 14:29:31 +00:00
|
|
|
#include "cairoint.h"
|
2005-01-20 08:28:54 +00:00
|
|
|
#include "cairo-pdf.h"
|
2007-04-20 02:37:15 -04:00
|
|
|
#include "cairo-pdf-surface-private.h"
|
2008-01-07 20:36:32 +10:30
|
|
|
#include "cairo-pdf-operators-private.h"
|
2006-05-15 10:04:53 -07:00
|
|
|
#include "cairo-scaled-font-subsets-private.h"
|
2007-04-21 02:25:51 -04:00
|
|
|
#include "cairo-paginated-private.h"
|
2006-06-12 03:07:19 -04:00
|
|
|
#include "cairo-output-stream-private.h"
|
2007-09-05 22:26:16 +09:30
|
|
|
#include "cairo-meta-surface-private.h"
|
2008-06-08 17:11:39 +09:30
|
|
|
#include "cairo-type3-glyph-surface-private.h"
|
2005-01-05 14:29:31 +00:00
|
|
|
|
|
|
|
|
#include <time.h>
|
2005-01-05 17:46:31 +00:00
|
|
|
#include <zlib.h>
|
2005-01-05 14:29:31 +00:00
|
|
|
|
|
|
|
|
/* Issues:
|
|
|
|
|
*
|
|
|
|
|
* - We embed an image in the stream each time it's composited. We
|
|
|
|
|
* could add generation counters to surfaces and remember the stream
|
|
|
|
|
* ID for a particular generation for a particular surface.
|
|
|
|
|
*
|
|
|
|
|
* - Backend specific meta data.
|
2007-08-25 06:44:08 +09:30
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Page Structure of the Generated PDF:
|
|
|
|
|
*
|
|
|
|
|
* Each page requiring fallbacks images contains a knockout group at
|
2007-08-28 20:35:23 +09:30
|
|
|
* the top level. The first operation of the knockout group paints a
|
|
|
|
|
* group containing all the supported drawing operations. Fallback
|
|
|
|
|
* images (if any) are painted in the knockout group. This ensures
|
|
|
|
|
* that fallback images do not composite with any content under the
|
2007-08-25 06:44:08 +09:30
|
|
|
* fallback images.
|
|
|
|
|
*
|
|
|
|
|
* Streams:
|
|
|
|
|
*
|
|
|
|
|
* This PDF surface has three types of streams:
|
|
|
|
|
* - PDF Stream
|
|
|
|
|
* - Content Stream
|
|
|
|
|
* - Group Stream
|
|
|
|
|
*
|
|
|
|
|
* Calling _cairo_output_stream_printf (surface->output, ...) will
|
|
|
|
|
* write to the currently open stream.
|
2005-01-05 14:29:31 +00:00
|
|
|
*
|
2007-08-25 06:44:08 +09:30
|
|
|
* PDF Stream:
|
|
|
|
|
* A PDF Stream may be opened and closed with the following functions:
|
2008-01-07 21:04:06 +10:30
|
|
|
* _cairo_pdf_surface_open stream ()
|
2007-08-25 06:44:08 +09:30
|
|
|
* _cairo_pdf_surface_close_stream ()
|
|
|
|
|
*
|
|
|
|
|
* PDF Streams are written directly to the PDF file. They are used for
|
|
|
|
|
* fonts, images and patterns.
|
|
|
|
|
*
|
|
|
|
|
* Content Stream:
|
|
|
|
|
* The Content Stream is opened and closed with the following functions:
|
2008-01-07 21:19:35 +10:30
|
|
|
* _cairo_pdf_surface_open_content_stream ()
|
|
|
|
|
* _cairo_pdf_surface_close_content_stream ()
|
2007-08-25 06:44:08 +09:30
|
|
|
*
|
2008-01-07 21:19:35 +10:30
|
|
|
* The Content Stream contains the text and graphics operators.
|
2007-08-25 06:44:08 +09:30
|
|
|
*
|
|
|
|
|
* Group Stream:
|
|
|
|
|
* A Group Stream may be opened and closed with the following functions:
|
|
|
|
|
* _cairo_pdf_surface_open_group ()
|
|
|
|
|
* _cairo_pdf_surface_close_group ()
|
|
|
|
|
*
|
2008-01-07 21:19:35 +10:30
|
|
|
* A Group Stream is a Form XObject. It is used for short sequences
|
|
|
|
|
* of operators. As the content is very short the group is stored in
|
|
|
|
|
* memory until it is closed. This allows some optimization such as
|
|
|
|
|
* including the Resource dictionary and stream length inside the
|
|
|
|
|
* XObject instead of using an indirect object.
|
2005-01-05 14:29:31 +00:00
|
|
|
*/
|
|
|
|
|
|
2006-05-15 09:52:57 -07:00
|
|
|
typedef struct _cairo_pdf_object {
|
2005-01-05 14:29:31 +00:00
|
|
|
long offset;
|
2006-05-15 09:52:57 -07:00
|
|
|
} cairo_pdf_object_t;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-15 10:04:53 -07:00
|
|
|
typedef struct _cairo_pdf_font {
|
|
|
|
|
unsigned int font_id;
|
|
|
|
|
unsigned int subset_id;
|
|
|
|
|
cairo_pdf_resource_t subset_resource;
|
|
|
|
|
} cairo_pdf_font_t;
|
|
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
typedef struct _cairo_pdf_rgb_linear_function {
|
|
|
|
|
cairo_pdf_resource_t resource;
|
|
|
|
|
double color1[3];
|
|
|
|
|
double color2[3];
|
|
|
|
|
} cairo_pdf_rgb_linear_function_t;
|
|
|
|
|
|
|
|
|
|
typedef struct _cairo_pdf_alpha_linear_function {
|
|
|
|
|
cairo_pdf_resource_t resource;
|
|
|
|
|
double alpha1;
|
|
|
|
|
double alpha2;
|
|
|
|
|
} cairo_pdf_alpha_linear_function_t;
|
|
|
|
|
|
2006-05-12 13:31:12 -07:00
|
|
|
static cairo_pdf_resource_t
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
static void
|
|
|
|
|
_cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group);
|
|
|
|
|
|
2008-01-07 20:36:32 +10:30
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_add_font (unsigned int font_id,
|
|
|
|
|
unsigned int subset_id,
|
2008-01-10 15:53:54 +00:00
|
|
|
void *closure);
|
2008-01-07 20:36:32 +10:30
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
static void
|
|
|
|
|
_cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res);
|
|
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
static cairo_status_t
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface,
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_pdf_resource_t *resource,
|
2006-09-24 00:55:20 +09:30
|
|
|
cairo_bool_t compressed,
|
2006-05-12 14:56:11 -07:00
|
|
|
const char *fmt,
|
2008-01-07 20:55:56 +10:30
|
|
|
...) CAIRO_PRINTF_FORMAT(4, 5);
|
2007-04-10 13:51:46 -07:00
|
|
|
static cairo_status_t
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface);
|
2005-06-21 15:38:51 +00:00
|
|
|
|
2007-09-05 22:26:16 +09:30
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
static void
|
|
|
|
|
_cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface);
|
|
|
|
|
|
|
|
|
|
static cairo_pdf_resource_t
|
|
|
|
|
_cairo_pdf_surface_write_info (cairo_pdf_surface_t *surface);
|
|
|
|
|
|
|
|
|
|
static cairo_pdf_resource_t
|
|
|
|
|
_cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface);
|
|
|
|
|
|
|
|
|
|
static long
|
|
|
|
|
_cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface);
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
|
|
|
|
|
|
2006-05-15 10:04:53 -07:00
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface);
|
|
|
|
|
|
2005-01-05 14:29:31 +00:00
|
|
|
static const cairo_surface_backend_t cairo_pdf_surface_backend;
|
2006-04-14 11:33:48 -07:00
|
|
|
static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 13:31:12 -07:00
|
|
|
static cairo_pdf_resource_t
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface)
|
2005-01-05 14:29:31 +00:00
|
|
|
{
|
2006-05-12 13:31:12 -07:00
|
|
|
cairo_pdf_resource_t resource;
|
2005-11-04 16:13:30 +00:00
|
|
|
cairo_status_t status;
|
2005-01-05 14:29:31 +00:00
|
|
|
cairo_pdf_object_t object;
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
object.offset = _cairo_output_stream_get_position (surface->output);
|
2005-11-04 16:13:30 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
status = _cairo_array_append (&surface->objects, &object);
|
2006-05-12 13:31:12 -07:00
|
|
|
if (status) {
|
|
|
|
|
resource.id = 0;
|
|
|
|
|
return resource;
|
|
|
|
|
}
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
resource = surface->next_available_resource;
|
|
|
|
|
surface->next_available_resource.id++;
|
2006-05-12 13:31:12 -07:00
|
|
|
|
|
|
|
|
return resource;
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
2005-01-17 09:40:00 +00:00
|
|
|
static void
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_update_object (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_pdf_resource_t resource)
|
2005-01-17 09:40:00 +00:00
|
|
|
{
|
|
|
|
|
cairo_pdf_object_t *object;
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
object = _cairo_array_index (&surface->objects, resource.id - 1);
|
|
|
|
|
object->offset = _cairo_output_stream_get_position (surface->output);
|
2005-01-17 09:40:00 +00:00
|
|
|
}
|
|
|
|
|
|
2008-04-06 19:04:27 +09:30
|
|
|
static void
|
2008-04-07 13:03:58 -07:00
|
|
|
_cairo_pdf_surface_set_size_internal (cairo_pdf_surface_t *surface,
|
|
|
|
|
double width,
|
|
|
|
|
double height)
|
2008-04-06 19:04:27 +09:30
|
|
|
{
|
|
|
|
|
surface->width = width;
|
|
|
|
|
surface->height = height;
|
|
|
|
|
cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, height);
|
|
|
|
|
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
|
|
|
|
|
&surface->cairo_to_pdf);
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-16 12:08:41 +00:00
|
|
|
static cairo_surface_t *
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
|
Big change to the test infrastructure and supporting internals. The goal now is to test both a COLOR_ALPHA and a COLOR content for each surface backend, (since the semantics are different and we probably need to support both in each backend.
The PS/PDF backends don't allow a content to be passed in right now, so they fail against the rgb24 tests, but the trivial addition to the constructors will allow them to pass all tests with both content values.
And new constructors (currently internal only) to create an image surface with a cairo_content_t rather than a cairo_format_t.
Add a cairo_content_t argument to the constructor.
Add a cairo_content_t to the constructor and use this content value when constructing intermediate image surfaces in acquire_source, show_page, copy_page, and snapshot.
Add image flattening by compositing over white, as is done in cairo-ps-surface.c.
Track changes to cairo-paginates-surface which now requires a cairo_content_t value (no change to public PS/PDF constructors yet).
Track change in meta-surface and paginated-surface interfaces by now accepting a cairo_content_t rather than a cairo_format_t.
Ignore new output files (argb32 from pdf and ps as well as rgb24 from test-fallback, test-meta, and test-paginated).
Add new utility for flattening PNG images in order to generate the -argbf-ref.png images.
Add image_diff_flattened for comparing flattened output from PS and PDF backend with ARGB reference images by first blending the reference images over white.
Get rid of conditional, format-specific background-color initialization before running tests. Now uses ARGB(0,0,0,0) in all cases. Switch from specifying tests with a format value to specifying tests with a content value. Add support for a 'fake' COLOR_ALPHA_FLATTENED content for testing the PS and PDF output against a flattened version of the argb32 reference images (first blended over white).
Track change in cairo_ps_surface_create (now requires cairo_content_t value).
Adjust tests that draw in default (black) to first paint white so that the results are visible.
Adjust ARGB32 reference images for new white background for changed tests.
Adjust RGB24 reference images for new black background due to changed initialization (and the tests themselves being unchanged).
2006-01-17 16:59:08 +00:00
|
|
|
double width,
|
|
|
|
|
double height)
|
2005-01-05 14:29:31 +00:00
|
|
|
{
|
2006-05-12 14:56:11 -07:00
|
|
|
cairo_pdf_surface_t *surface;
|
2008-01-16 16:33:22 +00:00
|
|
|
cairo_status_t status, status_ignored;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
surface = malloc (sizeof (cairo_pdf_surface_t));
|
|
|
|
|
if (surface == NULL) {
|
2007-10-05 12:16:23 +01:00
|
|
|
/* destroy stream on behalf of caller */
|
|
|
|
|
status = _cairo_output_stream_destroy (output);
|
2008-01-16 16:23:23 +00:00
|
|
|
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
|
2005-07-27 15:39:34 +00:00
|
|
|
}
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-24 17:05:51 -07:00
|
|
|
_cairo_surface_init (&surface->base, &cairo_pdf_surface_backend,
|
|
|
|
|
CAIRO_CONTENT_COLOR_ALPHA);
|
2006-05-12 14:56:11 -07:00
|
|
|
|
|
|
|
|
surface->output = output;
|
|
|
|
|
surface->width = width;
|
|
|
|
|
surface->height = height;
|
2007-04-27 16:01:56 -07:00
|
|
|
cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, height);
|
2006-05-12 14:56:11 -07:00
|
|
|
|
|
|
|
|
_cairo_array_init (&surface->objects, sizeof (cairo_pdf_object_t));
|
|
|
|
|
_cairo_array_init (&surface->pages, sizeof (cairo_pdf_resource_t));
|
2007-04-27 09:49:45 -07:00
|
|
|
_cairo_array_init (&surface->rgb_linear_functions, sizeof (cairo_pdf_rgb_linear_function_t));
|
|
|
|
|
_cairo_array_init (&surface->alpha_linear_functions, sizeof (cairo_pdf_alpha_linear_function_t));
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
|
2008-01-07 20:55:56 +10:30
|
|
|
_cairo_array_init (&surface->patterns, sizeof (cairo_pdf_pattern_t));
|
|
|
|
|
_cairo_array_init (&surface->smask_groups, sizeof (cairo_pdf_smask_group_t *));
|
2008-01-07 21:15:18 +10:30
|
|
|
_cairo_array_init (&surface->knockout_group, sizeof (cairo_pdf_resource_t));
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_pdf_group_resources_init (&surface->resources);
|
2006-05-12 14:56:11 -07:00
|
|
|
|
2007-04-20 22:44:04 +09:30
|
|
|
surface->font_subsets = _cairo_scaled_font_subsets_create_composite ();
|
2006-05-15 10:04:53 -07:00
|
|
|
if (! surface->font_subsets) {
|
2008-01-16 16:33:22 +00:00
|
|
|
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2007-10-05 12:16:23 +01:00
|
|
|
goto BAIL0;
|
2006-05-15 10:04:53 -07:00
|
|
|
}
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
surface->next_available_resource.id = 1;
|
|
|
|
|
surface->pages_resource = _cairo_pdf_surface_new_object (surface);
|
2008-01-16 16:33:22 +00:00
|
|
|
if (surface->pages_resource.id == 0) {
|
|
|
|
|
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2007-10-05 12:16:23 +01:00
|
|
|
goto BAIL1;
|
2008-01-16 16:33:22 +00:00
|
|
|
}
|
2006-05-12 14:56:11 -07:00
|
|
|
|
2008-07-08 21:51:41 +09:30
|
|
|
surface->compress_content = TRUE;
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->pdf_stream.active = FALSE;
|
2007-10-04 21:17:31 +01:00
|
|
|
surface->pdf_stream.old_output = NULL;
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->group_stream.active = FALSE;
|
|
|
|
|
surface->group_stream.stream = NULL;
|
2007-09-25 23:04:03 +09:30
|
|
|
surface->group_stream.mem_stream = NULL;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
|
|
|
|
|
|
2007-04-21 02:50:53 -04:00
|
|
|
surface->force_fallbacks = FALSE;
|
2008-02-17 19:48:01 +10:30
|
|
|
surface->select_pattern_gstate_saved = FALSE;
|
2008-06-03 20:55:30 +09:30
|
|
|
surface->current_pattern_is_solid_color = FALSE;
|
2007-04-21 02:50:53 -04:00
|
|
|
|
2008-01-07 20:36:32 +10:30
|
|
|
_cairo_pdf_operators_init (&surface->pdf_operators,
|
|
|
|
|
surface->output,
|
2008-02-16 22:47:31 -05:00
|
|
|
&surface->cairo_to_pdf,
|
2008-01-07 20:36:32 +10:30
|
|
|
surface->font_subsets);
|
|
|
|
|
_cairo_pdf_operators_set_font_subsets_callback (&surface->pdf_operators,
|
|
|
|
|
_cairo_pdf_surface_add_font,
|
|
|
|
|
surface);
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
/* Document header */
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%%PDF-1.4\n");
|
2006-08-04 16:39:40 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%%%c%c%c%c\n", 181, 237, 174, 251);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2007-10-05 12:16:23 +01:00
|
|
|
surface->paginated_surface = _cairo_paginated_surface_create (
|
|
|
|
|
&surface->base,
|
|
|
|
|
CAIRO_CONTENT_COLOR_ALPHA,
|
|
|
|
|
width, height,
|
|
|
|
|
&cairo_pdf_surface_paginated_backend);
|
2008-05-09 13:25:16 +02:00
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
status = surface->paginated_surface->status;
|
2008-05-09 13:25:16 +02:00
|
|
|
if (status == CAIRO_STATUS_SUCCESS) {
|
|
|
|
|
/* paginated keeps the only reference to surface now, drop ours */
|
|
|
|
|
cairo_surface_destroy (&surface->base);
|
2007-10-05 12:16:23 +01:00
|
|
|
return surface->paginated_surface;
|
2008-05-09 13:25:16 +02:00
|
|
|
}
|
2007-10-05 12:16:23 +01:00
|
|
|
|
|
|
|
|
BAIL1:
|
|
|
|
|
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
|
|
|
|
|
BAIL0:
|
|
|
|
|
_cairo_array_fini (&surface->objects);
|
2007-04-27 09:49:45 -07:00
|
|
|
free (surface);
|
2007-08-25 06:44:08 +09:30
|
|
|
|
2007-10-05 12:16:23 +01:00
|
|
|
/* destroy stream on behalf of caller */
|
2008-01-16 16:33:22 +00:00
|
|
|
status_ignored = _cairo_output_stream_destroy (output);
|
2007-10-05 12:16:23 +01:00
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
return _cairo_surface_create_in_error (status);
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
2006-01-18 16:40:17 +00:00
|
|
|
/**
|
|
|
|
|
* cairo_pdf_surface_create_for_stream:
|
2006-06-30 00:46:48 +02:00
|
|
|
* @write_func: a #cairo_write_func_t to accept the output data
|
|
|
|
|
* @closure: the closure argument for @write_func
|
2006-01-18 16:40:17 +00:00
|
|
|
* @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
|
|
|
|
|
* @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
|
2006-05-12 14:56:11 -07:00
|
|
|
*
|
2006-01-18 16:40:17 +00:00
|
|
|
* Creates a PDF surface of the specified size in points to be written
|
2006-06-30 00:46:48 +02:00
|
|
|
* incrementally to the stream represented by @write_func and @closure.
|
2006-01-18 16:40:17 +00:00
|
|
|
*
|
|
|
|
|
* Return value: a pointer to the newly created surface. The caller
|
2008-01-28 21:49:57 -05:00
|
|
|
* owns the surface and should call cairo_surface_destroy() when done
|
2006-01-18 16:40:17 +00:00
|
|
|
* with it.
|
|
|
|
|
*
|
|
|
|
|
* This function always returns a valid pointer, but it will return a
|
|
|
|
|
* pointer to a "nil" surface if an error such as out of memory
|
|
|
|
|
* occurs. You can use cairo_surface_status() to check for this.
|
2006-06-29 18:36:53 +02:00
|
|
|
*
|
|
|
|
|
* Since: 1.2
|
2006-01-18 16:40:17 +00:00
|
|
|
*/
|
2005-03-16 12:08:41 +00:00
|
|
|
cairo_surface_t *
|
2006-06-30 00:46:48 +02:00
|
|
|
cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func,
|
2005-05-13 09:26:20 +00:00
|
|
|
void *closure,
|
2006-01-18 16:40:17 +00:00
|
|
|
double width_in_points,
|
|
|
|
|
double height_in_points)
|
2005-03-16 12:08:41 +00:00
|
|
|
{
|
2006-05-12 14:56:11 -07:00
|
|
|
cairo_output_stream_t *output;
|
2005-03-16 12:08:41 +00:00
|
|
|
|
2006-06-30 00:46:48 +02:00
|
|
|
output = _cairo_output_stream_create (write_func, NULL, closure);
|
2008-01-16 16:33:22 +00:00
|
|
|
if (_cairo_output_stream_get_status (output))
|
|
|
|
|
return _cairo_surface_create_in_error (_cairo_output_stream_destroy (output));
|
2005-03-16 12:08:41 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
return _cairo_pdf_surface_create_for_stream_internal (output,
|
2006-01-18 16:44:19 +00:00
|
|
|
width_in_points,
|
|
|
|
|
height_in_points);
|
2005-03-16 12:08:41 +00:00
|
|
|
}
|
|
|
|
|
|
2006-01-18 16:40:17 +00:00
|
|
|
/**
|
|
|
|
|
* cairo_pdf_surface_create:
|
|
|
|
|
* @filename: a filename for the PDF output (must be writable)
|
|
|
|
|
* @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
|
|
|
|
|
* @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
|
2006-05-12 14:56:11 -07:00
|
|
|
*
|
2006-01-18 16:40:17 +00:00
|
|
|
* Creates a PDF surface of the specified size in points to be written
|
|
|
|
|
* to @filename.
|
2006-05-12 14:56:11 -07:00
|
|
|
*
|
2006-01-18 16:40:17 +00:00
|
|
|
* Return value: a pointer to the newly created surface. The caller
|
2008-01-28 21:49:57 -05:00
|
|
|
* owns the surface and should call cairo_surface_destroy() when done
|
2006-01-18 16:40:17 +00:00
|
|
|
* with it.
|
|
|
|
|
*
|
|
|
|
|
* This function always returns a valid pointer, but it will return a
|
|
|
|
|
* pointer to a "nil" surface if an error such as out of memory
|
|
|
|
|
* occurs. You can use cairo_surface_status() to check for this.
|
2006-06-29 18:36:53 +02:00
|
|
|
*
|
|
|
|
|
* Since: 1.2
|
2006-01-18 16:40:17 +00:00
|
|
|
**/
|
2005-03-16 12:08:41 +00:00
|
|
|
cairo_surface_t *
|
Big change to the test infrastructure and supporting internals. The goal now is to test both a COLOR_ALPHA and a COLOR content for each surface backend, (since the semantics are different and we probably need to support both in each backend.
The PS/PDF backends don't allow a content to be passed in right now, so they fail against the rgb24 tests, but the trivial addition to the constructors will allow them to pass all tests with both content values.
And new constructors (currently internal only) to create an image surface with a cairo_content_t rather than a cairo_format_t.
Add a cairo_content_t argument to the constructor.
Add a cairo_content_t to the constructor and use this content value when constructing intermediate image surfaces in acquire_source, show_page, copy_page, and snapshot.
Add image flattening by compositing over white, as is done in cairo-ps-surface.c.
Track changes to cairo-paginates-surface which now requires a cairo_content_t value (no change to public PS/PDF constructors yet).
Track change in meta-surface and paginated-surface interfaces by now accepting a cairo_content_t rather than a cairo_format_t.
Ignore new output files (argb32 from pdf and ps as well as rgb24 from test-fallback, test-meta, and test-paginated).
Add new utility for flattening PNG images in order to generate the -argbf-ref.png images.
Add image_diff_flattened for comparing flattened output from PS and PDF backend with ARGB reference images by first blending the reference images over white.
Get rid of conditional, format-specific background-color initialization before running tests. Now uses ARGB(0,0,0,0) in all cases. Switch from specifying tests with a format value to specifying tests with a content value. Add support for a 'fake' COLOR_ALPHA_FLATTENED content for testing the PS and PDF output against a flattened version of the argb32 reference images (first blended over white).
Track change in cairo_ps_surface_create (now requires cairo_content_t value).
Adjust tests that draw in default (black) to first paint white so that the results are visible.
Adjust ARGB32 reference images for new white background for changed tests.
Adjust RGB24 reference images for new black background due to changed initialization (and the tests themselves being unchanged).
2006-01-17 16:59:08 +00:00
|
|
|
cairo_pdf_surface_create (const char *filename,
|
2006-01-18 16:40:17 +00:00
|
|
|
double width_in_points,
|
|
|
|
|
double height_in_points)
|
2005-03-16 12:08:41 +00:00
|
|
|
{
|
2006-05-12 14:56:11 -07:00
|
|
|
cairo_output_stream_t *output;
|
2005-03-16 12:08:41 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
output = _cairo_output_stream_create_for_filename (filename);
|
2008-01-16 16:33:22 +00:00
|
|
|
if (_cairo_output_stream_get_status (output))
|
|
|
|
|
return _cairo_surface_create_in_error (_cairo_output_stream_destroy (output));
|
2005-03-16 12:08:41 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
return _cairo_pdf_surface_create_for_stream_internal (output,
|
2006-01-18 16:44:19 +00:00
|
|
|
width_in_points,
|
|
|
|
|
height_in_points);
|
2005-05-13 09:26:20 +00:00
|
|
|
}
|
|
|
|
|
|
2006-01-11 11:53:33 +00:00
|
|
|
static cairo_bool_t
|
|
|
|
|
_cairo_surface_is_pdf (cairo_surface_t *surface)
|
|
|
|
|
{
|
|
|
|
|
return surface->backend == &cairo_pdf_surface_backend;
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-03 12:39:23 -07:00
|
|
|
/* If the abstract_surface is a paginated surface, and that paginated
|
|
|
|
|
* surface's target is a pdf_surface, then set pdf_surface to that
|
2008-01-28 20:48:48 -05:00
|
|
|
* target. Otherwise return %CAIRO_STATUS_SURFACE_TYPE_MISMATCH.
|
2006-05-03 12:39:23 -07:00
|
|
|
*/
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_extract_pdf_surface (cairo_surface_t *surface,
|
|
|
|
|
cairo_pdf_surface_t **pdf_surface)
|
|
|
|
|
{
|
|
|
|
|
cairo_surface_t *target;
|
|
|
|
|
|
2008-03-31 14:25:17 +01:00
|
|
|
if (surface->status)
|
|
|
|
|
return surface->status;
|
|
|
|
|
|
2006-05-03 12:39:23 -07:00
|
|
|
if (! _cairo_surface_is_paginated (surface))
|
2007-10-04 13:15:46 +01:00
|
|
|
return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
|
2006-05-03 12:39:23 -07:00
|
|
|
|
|
|
|
|
target = _cairo_paginated_surface_get_target (surface);
|
2008-03-31 14:25:17 +01:00
|
|
|
if (target->status)
|
|
|
|
|
return target->status;
|
2006-05-03 12:39:23 -07:00
|
|
|
|
|
|
|
|
if (! _cairo_surface_is_pdf (target))
|
2007-10-04 13:15:46 +01:00
|
|
|
return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
|
2006-05-03 12:39:23 -07:00
|
|
|
|
|
|
|
|
*pdf_surface = (cairo_pdf_surface_t *) target;
|
|
|
|
|
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* cairo_pdf_surface_set_size:
|
2008-01-28 20:49:44 -05:00
|
|
|
* @surface: a PDF #cairo_surface_t
|
2006-05-03 12:39:23 -07:00
|
|
|
* @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
|
|
|
|
|
* @height_in_points: new surface height, in points (1 point == 1/72.0 inch)
|
2006-05-12 14:56:11 -07:00
|
|
|
*
|
2006-05-03 12:39:23 -07:00
|
|
|
* Changes the size of a PDF surface for the current (and
|
|
|
|
|
* subsequent) pages.
|
|
|
|
|
*
|
|
|
|
|
* This function should only be called before any drawing operations
|
|
|
|
|
* have been performed on the current page. The simplest way to do
|
|
|
|
|
* this is to call this function immediately after creating the
|
|
|
|
|
* surface or immediately after completing a page with either
|
|
|
|
|
* cairo_show_page() or cairo_copy_page().
|
2006-06-29 18:36:53 +02:00
|
|
|
*
|
|
|
|
|
* Since: 1.2
|
2006-05-03 12:39:23 -07:00
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
cairo_pdf_surface_set_size (cairo_surface_t *surface,
|
|
|
|
|
double width_in_points,
|
|
|
|
|
double height_in_points)
|
|
|
|
|
{
|
2007-10-04 13:15:46 +01:00
|
|
|
cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */
|
2006-05-03 12:39:23 -07:00
|
|
|
cairo_status_t status;
|
|
|
|
|
|
|
|
|
|
status = _extract_pdf_surface (surface, &pdf_surface);
|
|
|
|
|
if (status) {
|
2007-10-04 13:15:46 +01:00
|
|
|
status = _cairo_surface_set_error (surface, status);
|
2006-01-11 11:53:33 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2008-04-07 13:03:58 -07:00
|
|
|
_cairo_pdf_surface_set_size_internal (pdf_surface,
|
|
|
|
|
width_in_points,
|
|
|
|
|
height_in_points);
|
2007-09-16 19:43:28 +09:30
|
|
|
status = _cairo_paginated_surface_set_size (pdf_surface->paginated_surface,
|
|
|
|
|
width_in_points,
|
|
|
|
|
height_in_points);
|
|
|
|
|
if (status)
|
2007-10-04 13:15:46 +01:00
|
|
|
status = _cairo_surface_set_error (surface, status);
|
2005-03-16 12:08:41 +00:00
|
|
|
}
|
|
|
|
|
|
2005-01-05 14:29:31 +00:00
|
|
|
static void
|
|
|
|
|
_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
|
|
|
|
|
{
|
2008-01-07 20:55:56 +10:30
|
|
|
int i, size;
|
|
|
|
|
cairo_pdf_pattern_t *pattern;
|
|
|
|
|
cairo_pdf_smask_group_t *group;
|
|
|
|
|
|
|
|
|
|
size = _cairo_array_num_elements (&surface->patterns);
|
|
|
|
|
for (i = 0; i < size; i++) {
|
|
|
|
|
pattern = (cairo_pdf_pattern_t *) _cairo_array_index (&surface->patterns, i);
|
|
|
|
|
cairo_pattern_destroy (pattern->pattern);
|
|
|
|
|
}
|
|
|
|
|
_cairo_array_truncate (&surface->patterns, 0);
|
|
|
|
|
|
|
|
|
|
size = _cairo_array_num_elements (&surface->smask_groups);
|
|
|
|
|
for (i = 0; i < size; i++) {
|
|
|
|
|
_cairo_array_copy_element (&surface->smask_groups, i, &group);
|
|
|
|
|
_cairo_pdf_smask_group_destroy (group);
|
|
|
|
|
}
|
|
|
|
|
_cairo_array_truncate (&surface->smask_groups, 0);
|
2008-01-07 21:15:18 +10:30
|
|
|
_cairo_array_truncate (&surface->knockout_group, 0);
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
static void
|
|
|
|
|
_cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res)
|
|
|
|
|
{
|
|
|
|
|
_cairo_array_init (&res->alphas, sizeof (double));
|
|
|
|
|
_cairo_array_init (&res->smasks, sizeof (cairo_pdf_resource_t));
|
|
|
|
|
_cairo_array_init (&res->patterns, sizeof (cairo_pdf_resource_t));
|
|
|
|
|
_cairo_array_init (&res->xobjects, sizeof (cairo_pdf_resource_t));
|
|
|
|
|
_cairo_array_init (&res->fonts, sizeof (cairo_pdf_font_t));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_cairo_pdf_group_resources_fini (cairo_pdf_group_resources_t *res)
|
|
|
|
|
{
|
|
|
|
|
_cairo_array_fini (&res->alphas);
|
|
|
|
|
_cairo_array_fini (&res->smasks);
|
|
|
|
|
_cairo_array_fini (&res->patterns);
|
|
|
|
|
_cairo_array_fini (&res->xobjects);
|
|
|
|
|
_cairo_array_fini (&res->fonts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_cairo_pdf_group_resources_clear (cairo_pdf_group_resources_t *res)
|
|
|
|
|
{
|
|
|
|
|
_cairo_array_truncate (&res->alphas, 0);
|
|
|
|
|
_cairo_array_truncate (&res->smasks, 0);
|
|
|
|
|
_cairo_array_truncate (&res->patterns, 0);
|
|
|
|
|
_cairo_array_truncate (&res->xobjects, 0);
|
|
|
|
|
_cairo_array_truncate (&res->fonts, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface,
|
|
|
|
|
double alpha,
|
|
|
|
|
int *index)
|
|
|
|
|
{
|
|
|
|
|
int num_alphas, i;
|
|
|
|
|
double other;
|
|
|
|
|
cairo_status_t status;
|
2008-01-07 21:04:06 +10:30
|
|
|
cairo_pdf_group_resources_t *res = &surface->resources;
|
2007-08-25 06:44:08 +09:30
|
|
|
|
|
|
|
|
num_alphas = _cairo_array_num_elements (&res->alphas);
|
|
|
|
|
for (i = 0; i < num_alphas; i++) {
|
|
|
|
|
_cairo_array_copy_element (&res->alphas, i, &other);
|
|
|
|
|
if (alpha == other) {
|
|
|
|
|
*index = i;
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = _cairo_array_append (&res->alphas, &alpha);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
*index = _cairo_array_num_elements (&res->alphas) - 1;
|
|
|
|
|
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_add_smask (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_pdf_resource_t smask)
|
|
|
|
|
{
|
2008-01-07 21:04:06 +10:30
|
|
|
return _cairo_array_append (&(surface->resources.smasks), &smask);
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_add_pattern (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_pdf_resource_t pattern)
|
|
|
|
|
{
|
2008-01-07 21:04:06 +10:30
|
|
|
return _cairo_array_append (&(surface->resources.patterns), &pattern);
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_add_xobject (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_pdf_resource_t xobject)
|
|
|
|
|
{
|
2008-01-07 21:04:06 +10:30
|
|
|
return _cairo_array_append (&(surface->resources.xobjects), &xobject);
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
2008-01-07 20:36:32 +10:30
|
|
|
_cairo_pdf_surface_add_font (unsigned int font_id,
|
|
|
|
|
unsigned int subset_id,
|
2008-01-10 15:53:54 +00:00
|
|
|
void *closure)
|
2007-08-25 06:44:08 +09:30
|
|
|
{
|
2008-01-07 20:36:32 +10:30
|
|
|
cairo_pdf_surface_t *surface = closure;
|
2007-08-25 06:44:08 +09:30
|
|
|
cairo_pdf_font_t font;
|
|
|
|
|
int num_fonts, i;
|
|
|
|
|
cairo_status_t status;
|
2008-01-07 21:04:06 +10:30
|
|
|
cairo_pdf_group_resources_t *res = &surface->resources;
|
2007-08-25 06:44:08 +09:30
|
|
|
|
2007-09-26 22:21:07 +09:30
|
|
|
num_fonts = _cairo_array_num_elements (&res->fonts);
|
2007-08-25 06:44:08 +09:30
|
|
|
for (i = 0; i < num_fonts; i++) {
|
2007-10-03 19:55:05 +09:30
|
|
|
_cairo_array_copy_element (&res->fonts, i, &font);
|
2007-08-25 06:44:08 +09:30
|
|
|
if (font.font_id == font_id &&
|
2007-09-25 21:57:46 +09:30
|
|
|
font.subset_id == subset_id)
|
2007-08-25 06:44:08 +09:30
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2007-09-26 22:21:07 +09:30
|
|
|
num_fonts = _cairo_array_num_elements (&surface->fonts);
|
|
|
|
|
for (i = 0; i < num_fonts; i++) {
|
|
|
|
|
_cairo_array_copy_element (&surface->fonts, i, &font);
|
|
|
|
|
if (font.font_id == font_id &&
|
|
|
|
|
font.subset_id == subset_id)
|
|
|
|
|
return _cairo_array_append (&res->fonts, &font);
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
font.font_id = font_id;
|
|
|
|
|
font.subset_id = subset_id;
|
|
|
|
|
font.subset_resource = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (font.subset_resource.id == 0)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2007-08-25 06:44:08 +09:30
|
|
|
|
2007-09-26 22:21:07 +09:30
|
|
|
status = _cairo_array_append (&surface->fonts, &font);
|
2007-08-25 06:44:08 +09:30
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2007-09-26 22:21:07 +09:30
|
|
|
return _cairo_array_append (&res->fonts, &font);
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_pdf_resource_t
|
|
|
|
|
_cairo_pdf_surface_get_font_resource (cairo_pdf_surface_t *surface,
|
|
|
|
|
unsigned int font_id,
|
|
|
|
|
unsigned int subset_id)
|
|
|
|
|
{
|
|
|
|
|
cairo_pdf_font_t font;
|
|
|
|
|
int num_fonts, i;
|
|
|
|
|
|
|
|
|
|
num_fonts = _cairo_array_num_elements (&surface->fonts);
|
|
|
|
|
for (i = 0; i < num_fonts; i++) {
|
|
|
|
|
_cairo_array_copy_element (&surface->fonts, i, &font);
|
|
|
|
|
if (font.font_id == font_id && font.subset_id == subset_id)
|
|
|
|
|
return font.subset_resource;
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-10 15:53:54 +00:00
|
|
|
font.subset_resource.id = 0;
|
|
|
|
|
return font.subset_resource;
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_pdf_group_resources_t *res)
|
|
|
|
|
{
|
|
|
|
|
int num_alphas, num_smasks, num_resources, i;
|
|
|
|
|
double alpha;
|
|
|
|
|
cairo_pdf_resource_t *smask, *pattern, *xobject;
|
|
|
|
|
cairo_pdf_font_t *font;
|
|
|
|
|
|
2008-02-20 21:05:23 +10:30
|
|
|
_cairo_output_stream_printf (surface->output, "<<\n");
|
2007-08-25 06:44:08 +09:30
|
|
|
|
|
|
|
|
num_alphas = _cairo_array_num_elements (&res->alphas);
|
|
|
|
|
num_smasks = _cairo_array_num_elements (&res->smasks);
|
|
|
|
|
if (num_alphas > 0 || num_smasks > 0) {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /ExtGState <<\n");
|
2007-08-25 06:44:08 +09:30
|
|
|
|
|
|
|
|
for (i = 0; i < num_alphas; i++) {
|
|
|
|
|
_cairo_array_copy_element (&res->alphas, i, &alpha);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /a%d << /CA %f /ca %f >>\n",
|
2007-08-25 06:44:08 +09:30
|
|
|
i, alpha, alpha);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < num_smasks; i++) {
|
|
|
|
|
smask = _cairo_array_index (&res->smasks, i);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /s%d %d 0 R\n",
|
2007-08-25 06:44:08 +09:30
|
|
|
smask->id, smask->id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" >>\n");
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
num_resources = _cairo_array_num_elements (&res->patterns);
|
|
|
|
|
if (num_resources > 0) {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-01-07 21:04:06 +10:30
|
|
|
" /Pattern <<");
|
2007-08-25 06:44:08 +09:30
|
|
|
for (i = 0; i < num_resources; i++) {
|
|
|
|
|
pattern = _cairo_array_index (&res->patterns, i);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
" /p%d %d 0 R",
|
|
|
|
|
pattern->id, pattern->id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" >>\n");
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
num_resources = _cairo_array_num_elements (&res->xobjects);
|
|
|
|
|
if (num_resources > 0) {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-01-07 21:04:06 +10:30
|
|
|
" /XObject <<");
|
2007-08-25 06:44:08 +09:30
|
|
|
|
|
|
|
|
for (i = 0; i < num_resources; i++) {
|
|
|
|
|
xobject = _cairo_array_index (&res->xobjects, i);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
" /x%d %d 0 R",
|
|
|
|
|
xobject->id, xobject->id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" >>\n");
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
num_resources = _cairo_array_num_elements (&res->fonts);
|
|
|
|
|
if (num_resources > 0) {
|
2008-02-20 21:05:23 +10:30
|
|
|
_cairo_output_stream_printf (surface->output," /Font <<\n");
|
2007-08-25 06:44:08 +09:30
|
|
|
for (i = 0; i < num_resources; i++) {
|
|
|
|
|
font = _cairo_array_index (&res->fonts, i);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /f-%d-%d %d 0 R\n",
|
2007-08-25 06:44:08 +09:30
|
|
|
font->font_id,
|
|
|
|
|
font->subset_id,
|
|
|
|
|
font->subset_resource.id);
|
|
|
|
|
}
|
2008-02-20 21:05:23 +10:30
|
|
|
_cairo_output_stream_printf (surface->output, " >>\n");
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
">>\n");
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
static cairo_pdf_smask_group_t *
|
2008-01-10 15:53:54 +00:00
|
|
|
_cairo_pdf_surface_create_smask_group (cairo_pdf_surface_t *surface)
|
2008-01-07 20:55:56 +10:30
|
|
|
{
|
2008-01-10 15:53:54 +00:00
|
|
|
cairo_pdf_smask_group_t *group;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
group = calloc (1, sizeof (cairo_pdf_smask_group_t));
|
|
|
|
|
if (group == NULL) {
|
|
|
|
|
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
group->group_res = _cairo_pdf_surface_new_object (surface);
|
|
|
|
|
if (group->group_res.id == 0) {
|
|
|
|
|
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
free (group);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2008-02-02 20:59:56 +10:30
|
|
|
group->width = surface->width;
|
|
|
|
|
group->height = surface->height;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
return group;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group)
|
|
|
|
|
{
|
|
|
|
|
if (group->operation == PDF_FILL || group->operation == PDF_STROKE)
|
|
|
|
|
_cairo_path_fixed_fini (&group->path);
|
|
|
|
|
if (group->source)
|
|
|
|
|
cairo_pattern_destroy (group->source);
|
|
|
|
|
if (group->mask)
|
|
|
|
|
cairo_pattern_destroy (group->mask);
|
2008-06-29 19:55:41 +09:30
|
|
|
if (group->utf8)
|
|
|
|
|
free (group->utf8);
|
2008-04-04 12:53:13 +01:00
|
|
|
if (group->glyphs)
|
|
|
|
|
free (group->glyphs);
|
2008-06-29 19:55:41 +09:30
|
|
|
if (group->clusters)
|
|
|
|
|
free (group->clusters);
|
2008-01-07 20:55:56 +10:30
|
|
|
if (group->scaled_font)
|
|
|
|
|
cairo_scaled_font_destroy (group->scaled_font);
|
|
|
|
|
free (group);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_add_smask_group (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_pdf_smask_group_t *group)
|
|
|
|
|
{
|
|
|
|
|
return _cairo_array_append (&surface->smask_groups, &group);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
2008-01-10 15:53:54 +00:00
|
|
|
_cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_pattern_t *pattern,
|
|
|
|
|
cairo_pdf_resource_t *pattern_res,
|
|
|
|
|
cairo_pdf_resource_t *gstate_res)
|
2008-01-07 20:55:56 +10:30
|
|
|
{
|
|
|
|
|
cairo_pdf_pattern_t pdf_pattern;
|
2008-01-10 15:53:54 +00:00
|
|
|
cairo_status_t status;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
/* Solid colors are emitted into the content stream */
|
|
|
|
|
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
|
|
|
|
|
pattern_res->id = 0;
|
|
|
|
|
gstate_res->id = 0;
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
|
|
|
|
|
pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
|
|
|
|
|
{
|
|
|
|
|
cairo_gradient_pattern_t *gradient;
|
|
|
|
|
|
|
|
|
|
gradient = (cairo_gradient_pattern_t *) pattern;
|
2008-04-27 17:32:41 +09:30
|
|
|
|
|
|
|
|
/* Gradients with zero stops do not produce any output */
|
2008-01-07 20:55:56 +10:30
|
|
|
if (gradient->n_stops == 0)
|
|
|
|
|
return CAIRO_INT_STATUS_NOTHING_TO_DO;
|
2008-04-27 17:32:41 +09:30
|
|
|
|
|
|
|
|
/* Gradients with one stop are the same as solid colors */
|
|
|
|
|
if (gradient->n_stops == 1) {
|
|
|
|
|
pattern_res->id = 0;
|
|
|
|
|
gstate_res->id = 0;
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
2008-01-07 20:55:56 +10:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pdf_pattern.pattern = cairo_pattern_reference (pattern);
|
|
|
|
|
pdf_pattern.pattern_res = _cairo_pdf_surface_new_object (surface);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (pdf_pattern.pattern_res.id == 0) {
|
|
|
|
|
cairo_pattern_destroy (pattern);
|
2008-01-07 20:55:56 +10:30
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2008-01-10 15:53:54 +00:00
|
|
|
}
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
pdf_pattern.gstate_res.id = 0;
|
|
|
|
|
|
|
|
|
|
/* gradient patterns require an smask object to implement transparency */
|
|
|
|
|
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
|
|
|
|
|
pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
|
|
|
|
|
if (_cairo_pattern_is_opaque (pattern) == FALSE) {
|
|
|
|
|
pdf_pattern.gstate_res = _cairo_pdf_surface_new_object (surface);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (pdf_pattern.gstate_res.id == 0) {
|
|
|
|
|
cairo_pattern_destroy (pattern);
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
}
|
2008-01-07 20:55:56 +10:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-02 20:59:56 +10:30
|
|
|
pdf_pattern.width = surface->width;
|
|
|
|
|
pdf_pattern.height = surface->height;
|
2008-01-07 20:55:56 +10:30
|
|
|
*pattern_res = pdf_pattern.pattern_res;
|
|
|
|
|
*gstate_res = pdf_pattern.gstate_res;
|
|
|
|
|
|
2008-01-10 15:53:54 +00:00
|
|
|
status = _cairo_array_append (&surface->patterns, &pdf_pattern);
|
|
|
|
|
if (status) {
|
|
|
|
|
cairo_pattern_destroy (pattern);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2008-01-07 20:55:56 +10:30
|
|
|
}
|
|
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
static cairo_status_t
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface,
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_pdf_resource_t *resource,
|
2007-08-25 06:44:08 +09:30
|
|
|
cairo_bool_t compressed,
|
2006-05-12 14:56:11 -07:00
|
|
|
const char *fmt,
|
|
|
|
|
...)
|
2005-01-05 14:29:31 +00:00
|
|
|
{
|
2005-05-13 14:04:22 +00:00
|
|
|
va_list ap;
|
2007-10-04 21:17:31 +01:00
|
|
|
cairo_pdf_resource_t self, length;
|
|
|
|
|
cairo_output_stream_t *output = NULL;
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
if (resource) {
|
|
|
|
|
self = *resource;
|
|
|
|
|
_cairo_pdf_surface_update_object (surface, self);
|
|
|
|
|
} else {
|
|
|
|
|
self = _cairo_pdf_surface_new_object (surface);
|
|
|
|
|
if (self.id == 0)
|
2008-01-16 16:33:22 +00:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2008-01-07 20:55:56 +10:30
|
|
|
}
|
2007-10-04 21:17:31 +01:00
|
|
|
|
|
|
|
|
length = _cairo_pdf_surface_new_object (surface);
|
|
|
|
|
if (length.id == 0)
|
2008-01-16 16:33:22 +00:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2007-10-04 21:17:31 +01:00
|
|
|
|
|
|
|
|
if (compressed) {
|
|
|
|
|
output = _cairo_deflate_stream_create (surface->output);
|
2008-01-16 16:33:22 +00:00
|
|
|
if (_cairo_output_stream_get_status (output))
|
|
|
|
|
return _cairo_output_stream_destroy (output);
|
2007-10-04 21:17:31 +01:00
|
|
|
}
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->pdf_stream.active = TRUE;
|
2007-10-04 21:17:31 +01:00
|
|
|
surface->pdf_stream.self = self;
|
|
|
|
|
surface->pdf_stream.length = length;
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->pdf_stream.compressed = compressed;
|
2008-06-03 20:55:30 +09:30
|
|
|
surface->current_pattern_is_solid_color = FALSE;
|
2008-07-08 22:00:15 +09:30
|
|
|
_cairo_pdf_operators_reset (&surface->pdf_operators);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Length %d 0 R\n",
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->pdf_stream.self.id,
|
|
|
|
|
surface->pdf_stream.length.id);
|
2006-09-24 00:55:20 +09:30
|
|
|
if (compressed)
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Filter /FlateDecode\n");
|
2005-05-13 14:04:22 +00:00
|
|
|
|
|
|
|
|
if (fmt != NULL) {
|
|
|
|
|
va_start (ap, fmt);
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_vprintf (surface->output, fmt, ap);
|
2005-05-13 14:04:22 +00:00
|
|
|
va_end (ap);
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
">>\n"
|
|
|
|
|
"stream\n");
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->pdf_stream.start_offset = _cairo_output_stream_get_position (surface->output);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-09-24 00:55:20 +09:30
|
|
|
if (compressed) {
|
2007-10-04 21:17:31 +01:00
|
|
|
assert (surface->pdf_stream.old_output == NULL);
|
|
|
|
|
surface->pdf_stream.old_output = surface->output;
|
|
|
|
|
surface->output = output;
|
2008-01-07 20:36:32 +10:30
|
|
|
_cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
|
2006-09-24 00:55:20 +09:30
|
|
|
}
|
|
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
2007-04-10 13:51:46 -07:00
|
|
|
static cairo_status_t
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
|
2005-01-05 14:29:31 +00:00
|
|
|
{
|
2007-04-10 13:51:46 -07:00
|
|
|
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
2005-01-05 14:29:31 +00:00
|
|
|
long length;
|
|
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
if (! surface->pdf_stream.active)
|
2007-04-10 13:51:46 -07:00
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
if (surface->pdf_stream.compressed) {
|
|
|
|
|
status = _cairo_output_stream_destroy (surface->output);
|
|
|
|
|
surface->output = surface->pdf_stream.old_output;
|
2008-01-07 20:36:32 +10:30
|
|
|
_cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
|
2007-10-04 21:17:31 +01:00
|
|
|
surface->pdf_stream.old_output = NULL;
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"\n");
|
2006-09-24 00:55:20 +09:30
|
|
|
}
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
length = _cairo_output_stream_get_position (surface->output) -
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->pdf_stream.start_offset;
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"endstream\n"
|
|
|
|
|
"endobj\n");
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_update_object (surface,
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->pdf_stream.length);
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
" %ld\n"
|
|
|
|
|
"endobj\n",
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->pdf_stream.length.id,
|
2005-03-16 12:08:41 +00:00
|
|
|
length);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->pdf_stream.active = FALSE;
|
2007-04-10 13:51:46 -07:00
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
|
|
|
status = _cairo_output_stream_get_status (surface->output);
|
|
|
|
|
|
2007-04-10 13:51:46 -07:00
|
|
|
return status;
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
static void
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_pdf_surface_write_memory_stream (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_output_stream_t *mem_stream,
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_pdf_resource_t resource,
|
2007-08-25 06:44:08 +09:30
|
|
|
cairo_pdf_group_resources_t *resources,
|
|
|
|
|
cairo_bool_t is_knockout_group)
|
|
|
|
|
{
|
2008-01-07 20:55:56 +10:30
|
|
|
_cairo_pdf_surface_update_object (surface, resource);
|
2007-10-04 21:17:31 +01:00
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /XObject\n"
|
|
|
|
|
" /Length %d\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
resource.id,
|
2007-09-25 23:04:03 +09:30
|
|
|
_cairo_memory_stream_length (mem_stream));
|
|
|
|
|
|
|
|
|
|
if (surface->compress_content) {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Filter /FlateDecode\n");
|
2007-09-25 23:04:03 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Subtype /Form\n"
|
|
|
|
|
" /BBox [ 0 0 %f %f ]\n"
|
|
|
|
|
" /Group <<\n"
|
|
|
|
|
" /Type /Group\n"
|
|
|
|
|
" /S /Transparency\n"
|
|
|
|
|
" /CS /DeviceRGB\n",
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->width,
|
|
|
|
|
surface->height);
|
|
|
|
|
|
|
|
|
|
if (is_knockout_group)
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /K true\n");
|
2007-08-25 06:44:08 +09:30
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" >>\n"
|
|
|
|
|
" /Resources\n");
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_pdf_surface_emit_group_resources (surface, resources);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
">>\n"
|
|
|
|
|
"stream\n");
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_memory_stream_copy (mem_stream, surface->output);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"endstream\n"
|
|
|
|
|
"endobj\n");
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
2007-10-04 23:15:21 +01:00
|
|
|
static cairo_status_t
|
2008-01-07 20:55:56 +10:30
|
|
|
_cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_pdf_resource_t *resource)
|
2007-08-25 06:44:08 +09:30
|
|
|
{
|
2007-10-04 23:15:21 +01:00
|
|
|
cairo_status_t status;
|
|
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
assert (surface->pdf_stream.active == FALSE);
|
|
|
|
|
assert (surface->group_stream.active == FALSE);
|
|
|
|
|
|
|
|
|
|
surface->group_stream.active = TRUE;
|
2008-06-03 20:55:30 +09:30
|
|
|
surface->current_pattern_is_solid_color = FALSE;
|
2008-07-08 22:00:15 +09:30
|
|
|
_cairo_pdf_operators_reset (&surface->pdf_operators);
|
2007-09-25 23:04:03 +09:30
|
|
|
|
|
|
|
|
surface->group_stream.mem_stream = _cairo_memory_stream_create ();
|
2007-10-04 23:15:21 +01:00
|
|
|
|
2007-09-25 23:04:03 +09:30
|
|
|
if (surface->compress_content) {
|
|
|
|
|
surface->group_stream.stream =
|
|
|
|
|
_cairo_deflate_stream_create (surface->group_stream.mem_stream);
|
|
|
|
|
} else {
|
|
|
|
|
surface->group_stream.stream = surface->group_stream.mem_stream;
|
|
|
|
|
}
|
2007-10-04 23:15:21 +01:00
|
|
|
status = _cairo_output_stream_get_status (surface->group_stream.stream);
|
2007-09-25 23:04:03 +09:30
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->group_stream.old_output = surface->output;
|
|
|
|
|
surface->output = surface->group_stream.stream;
|
2008-01-07 20:36:32 +10:30
|
|
|
_cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_pdf_group_resources_clear (&surface->resources);
|
2007-10-04 23:15:21 +01:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
if (resource) {
|
|
|
|
|
surface->group_stream.resource = *resource;
|
|
|
|
|
} else {
|
|
|
|
|
surface->group_stream.resource = _cairo_pdf_surface_new_object (surface);
|
|
|
|
|
if (surface->group_stream.resource.id == 0)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
}
|
2008-01-07 21:04:06 +10:30
|
|
|
surface->group_stream.is_knockout = FALSE;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
2007-10-09 23:24:35 +01:00
|
|
|
return status;
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
2007-10-04 23:15:21 +01:00
|
|
|
static cairo_status_t
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t *surface)
|
2007-08-25 06:44:08 +09:30
|
|
|
{
|
2007-10-04 23:15:21 +01:00
|
|
|
cairo_status_t status;
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_open_group (surface, NULL);
|
2007-10-04 23:15:21 +01:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->group_stream.is_knockout = TRUE;
|
2007-10-04 23:15:21 +01:00
|
|
|
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_pdf_resource_t *group)
|
|
|
|
|
{
|
2008-01-10 15:53:54 +00:00
|
|
|
cairo_status_t status = CAIRO_STATUS_SUCCESS, status2;
|
2007-09-25 23:04:03 +09:30
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
assert (surface->pdf_stream.active == FALSE);
|
|
|
|
|
assert (surface->group_stream.active == TRUE);
|
|
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2007-09-25 23:04:03 +09:30
|
|
|
if (surface->compress_content) {
|
|
|
|
|
status = _cairo_output_stream_destroy (surface->group_stream.stream);
|
2007-10-09 23:24:35 +01:00
|
|
|
surface->group_stream.stream = NULL;
|
2007-09-25 23:04:03 +09:30
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->group_stream.mem_stream,
|
2008-02-20 21:05:23 +10:30
|
|
|
"\n");
|
2007-09-25 23:04:03 +09:30
|
|
|
}
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->output = surface->group_stream.old_output;
|
2008-01-07 20:36:32 +10:30
|
|
|
_cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->group_stream.active = FALSE;
|
2008-01-07 20:55:56 +10:30
|
|
|
_cairo_pdf_surface_write_memory_stream (surface,
|
|
|
|
|
surface->group_stream.mem_stream,
|
|
|
|
|
surface->group_stream.resource,
|
2008-01-07 21:04:06 +10:30
|
|
|
&surface->resources,
|
2008-01-07 20:55:56 +10:30
|
|
|
surface->group_stream.is_knockout);
|
|
|
|
|
if (group)
|
|
|
|
|
*group = surface->group_stream.resource;
|
2007-10-05 12:45:36 +01:00
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
status2 = _cairo_output_stream_destroy (surface->group_stream.mem_stream);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
|
|
|
status = status2;
|
|
|
|
|
|
2007-10-09 23:24:35 +01:00
|
|
|
surface->group_stream.mem_stream = NULL;
|
2008-01-07 20:55:56 +10:30
|
|
|
surface->group_stream.stream = NULL;
|
2007-10-09 23:24:35 +01:00
|
|
|
|
|
|
|
|
return status;
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
2007-10-05 12:08:40 +01:00
|
|
|
static cairo_status_t
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_bool_t is_form)
|
2007-08-25 06:44:08 +09:30
|
|
|
{
|
2008-01-16 16:33:22 +00:00
|
|
|
cairo_status_t status;
|
|
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
assert (surface->pdf_stream.active == FALSE);
|
|
|
|
|
assert (surface->group_stream.active == FALSE);
|
|
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
surface->content_resources = _cairo_pdf_surface_new_object (surface);
|
|
|
|
|
if (surface->content_resources.id == 0)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2007-10-04 23:15:21 +01:00
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
if (is_form) {
|
2008-01-16 16:33:22 +00:00
|
|
|
status =
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_pdf_surface_open_stream (surface,
|
|
|
|
|
NULL,
|
|
|
|
|
surface->compress_content,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Type /XObject\n"
|
|
|
|
|
" /Subtype /Form\n"
|
|
|
|
|
" /BBox [ 0 0 %f %f ]\n"
|
|
|
|
|
" /Group <<\n"
|
|
|
|
|
" /Type /Group\n"
|
|
|
|
|
" /S /Transparency\n"
|
|
|
|
|
" /CS /DeviceRGB\n"
|
|
|
|
|
" >>\n"
|
|
|
|
|
" /Resources %d 0 R\n",
|
2008-01-07 21:04:06 +10:30
|
|
|
surface->width,
|
|
|
|
|
surface->height,
|
|
|
|
|
surface->content_resources.id);
|
2007-09-25 23:04:03 +09:30
|
|
|
} else {
|
2008-01-16 16:33:22 +00:00
|
|
|
status =
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_pdf_surface_open_stream (surface,
|
|
|
|
|
NULL,
|
|
|
|
|
surface->compress_content,
|
|
|
|
|
NULL);
|
2007-09-25 23:04:03 +09:30
|
|
|
}
|
2008-01-18 14:34:41 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-10-04 23:15:21 +01:00
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
surface->content = surface->pdf_stream.self;
|
|
|
|
|
|
2008-02-20 21:05:23 +10:30
|
|
|
_cairo_output_stream_printf (surface->output, "q\n");
|
2008-01-07 20:59:22 +10:30
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface)
|
2007-08-25 06:44:08 +09:30
|
|
|
{
|
2007-09-25 23:04:03 +09:30
|
|
|
cairo_status_t status;
|
2007-08-25 06:44:08 +09:30
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
assert (surface->pdf_stream.active == TRUE);
|
|
|
|
|
assert (surface->group_stream.active == FALSE);
|
2007-08-25 06:44:08 +09:30
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-02-20 21:05:23 +10:30
|
|
|
_cairo_output_stream_printf (surface->output, "Q\n");
|
2008-01-07 21:04:06 +10:30
|
|
|
status = _cairo_pdf_surface_close_stream (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:59:22 +10:30
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_pdf_surface_update_object (surface, surface->content_resources);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n",
|
2008-01-07 21:04:06 +10:30
|
|
|
surface->content_resources.id);
|
|
|
|
|
_cairo_pdf_surface_emit_group_resources (surface, &surface->resources);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"endobj\n");
|
2007-08-25 06:44:08 +09:30
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
2007-09-05 22:26:16 +09:30
|
|
|
static cairo_surface_t *
|
|
|
|
|
_cairo_pdf_surface_create_similar (void *abstract_surface,
|
|
|
|
|
cairo_content_t content,
|
|
|
|
|
int width,
|
|
|
|
|
int height)
|
|
|
|
|
{
|
|
|
|
|
return _cairo_meta_surface_create (content, width, height);
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-16 12:08:41 +00:00
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_finish (void *abstract_surface)
|
2005-01-05 14:29:31 +00:00
|
|
|
{
|
|
|
|
|
cairo_pdf_surface_t *surface = abstract_surface;
|
2006-05-12 14:56:11 -07:00
|
|
|
long offset;
|
|
|
|
|
cairo_pdf_resource_t info, catalog;
|
2008-01-10 15:53:54 +00:00
|
|
|
cairo_status_t status, status2;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2008-01-10 15:53:54 +00:00
|
|
|
status = surface->base.status;
|
|
|
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
|
|
|
status = _cairo_pdf_surface_emit_font_subsets (surface);
|
2006-05-15 10:04:53 -07:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_write_pages (surface);
|
2005-03-16 12:08:41 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
info = _cairo_pdf_surface_write_info (surface);
|
2007-10-05 12:45:36 +01:00
|
|
|
if (info.id == 0 && status == CAIRO_STATUS_SUCCESS)
|
|
|
|
|
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
catalog = _cairo_pdf_surface_write_catalog (surface);
|
2007-10-05 12:45:36 +01:00
|
|
|
if (catalog.id == 0 && status == CAIRO_STATUS_SUCCESS)
|
|
|
|
|
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
offset = _cairo_pdf_surface_write_xref (surface);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"trailer\n"
|
|
|
|
|
"<< /Size %d\n"
|
|
|
|
|
" /Root %d 0 R\n"
|
|
|
|
|
" /Info %d 0 R\n"
|
|
|
|
|
">>\n",
|
2006-05-12 14:56:11 -07:00
|
|
|
surface->next_available_resource.id,
|
|
|
|
|
catalog.id,
|
|
|
|
|
info.id);
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"startxref\n"
|
|
|
|
|
"%ld\n"
|
|
|
|
|
"%%%%EOF\n",
|
2006-05-12 14:56:11 -07:00
|
|
|
offset);
|
|
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status2 = _cairo_pdf_operators_fini (&surface->pdf_operators);
|
|
|
|
|
/* pdf_operators has already been flushed when the last stream was
|
|
|
|
|
* closed so we should never be writing anything here. */
|
|
|
|
|
assert(status2 == CAIRO_STATUS_SUCCESS);
|
2008-01-07 20:36:32 +10:30
|
|
|
|
2007-10-09 23:24:35 +01:00
|
|
|
/* close any active streams still open due to fatal errors */
|
|
|
|
|
status2 = _cairo_pdf_surface_close_stream (surface);
|
|
|
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
|
|
|
status = status2;
|
|
|
|
|
|
|
|
|
|
if (surface->group_stream.stream != NULL) {
|
|
|
|
|
status2 = _cairo_output_stream_destroy (surface->group_stream.stream);
|
|
|
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
|
|
|
status = status2;
|
|
|
|
|
}
|
|
|
|
|
if (surface->group_stream.mem_stream != NULL) {
|
|
|
|
|
status2 = _cairo_output_stream_destroy (surface->group_stream.mem_stream);
|
|
|
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
|
|
|
status = status2;
|
|
|
|
|
}
|
2008-01-07 21:04:06 +10:30
|
|
|
if (surface->pdf_stream.active)
|
|
|
|
|
surface->output = surface->pdf_stream.old_output;
|
2007-10-09 23:24:35 +01:00
|
|
|
if (surface->group_stream.active)
|
|
|
|
|
surface->output = surface->group_stream.old_output;
|
|
|
|
|
|
|
|
|
|
/* and finish the pdf surface */
|
2007-04-10 13:51:46 -07:00
|
|
|
status2 = _cairo_output_stream_destroy (surface->output);
|
|
|
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
|
|
|
status = status2;
|
2006-05-12 14:56:11 -07:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
_cairo_pdf_surface_clear (surface);
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_pdf_group_resources_fini (&surface->resources);
|
2008-01-07 20:55:56 +10:30
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_array_fini (&surface->objects);
|
|
|
|
|
_cairo_array_fini (&surface->pages);
|
2007-04-27 09:49:45 -07:00
|
|
|
_cairo_array_fini (&surface->rgb_linear_functions);
|
|
|
|
|
_cairo_array_fini (&surface->alpha_linear_functions);
|
2008-01-07 20:55:56 +10:30
|
|
|
_cairo_array_fini (&surface->patterns);
|
|
|
|
|
_cairo_array_fini (&surface->smask_groups);
|
|
|
|
|
_cairo_array_fini (&surface->fonts);
|
2008-01-07 21:15:18 +10:30
|
|
|
_cairo_array_fini (&surface->knockout_group);
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
if (surface->font_subsets) {
|
|
|
|
|
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
|
|
|
|
|
surface->font_subsets = NULL;
|
|
|
|
|
}
|
2007-04-27 09:49:45 -07:00
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-12 13:31:12 -07:00
|
|
|
static cairo_int_status_t
|
|
|
|
|
_cairo_pdf_surface_start_page (void *abstract_surface)
|
|
|
|
|
{
|
|
|
|
|
cairo_pdf_surface_t *surface = abstract_surface;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_pdf_group_resources_clear (&surface->resources);
|
2008-07-08 21:18:45 +09:30
|
|
|
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_int_status_t
|
|
|
|
|
_cairo_pdf_surface_has_fallback_images (void *abstract_surface,
|
|
|
|
|
cairo_bool_t has_fallbacks)
|
|
|
|
|
{
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
cairo_pdf_surface_t *surface = abstract_surface;
|
|
|
|
|
|
|
|
|
|
surface->has_fallback_images = has_fallbacks;
|
|
|
|
|
status = _cairo_pdf_surface_open_content_stream (surface, has_fallbacks);
|
2007-10-04 23:15:21 +01:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2006-05-12 13:31:12 -07:00
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
2006-04-25 03:45:37 -07:00
|
|
|
/* Emit alpha channel from the image into the given data, providing
|
2007-01-07 02:03:30 +00:00
|
|
|
* an id that can be used to reference the resulting SMask object.
|
2006-04-25 03:45:37 -07:00
|
|
|
*
|
|
|
|
|
* In the case that the alpha channel happens to be all opaque, then
|
|
|
|
|
* no SMask object will be emitted and *id_ret will be set to 0.
|
|
|
|
|
*/
|
|
|
|
|
static cairo_status_t
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_image_surface_t *image,
|
|
|
|
|
cairo_pdf_resource_t *stream_ret)
|
2006-04-25 03:45:37 -07:00
|
|
|
{
|
|
|
|
|
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
2008-02-11 13:44:48 -05:00
|
|
|
char *alpha;
|
|
|
|
|
unsigned long alpha_size;
|
2007-09-20 22:51:39 +09:30
|
|
|
uint32_t *pixel32;
|
|
|
|
|
uint8_t *pixel8;
|
2006-04-25 03:45:37 -07:00
|
|
|
int i, x, y;
|
|
|
|
|
cairo_bool_t opaque;
|
|
|
|
|
uint8_t a;
|
|
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
/* This is the only image format we support, which simplifies things. */
|
2007-09-20 22:51:39 +09:30
|
|
|
assert (image->format == CAIRO_FORMAT_ARGB32 ||
|
2007-10-14 19:05:06 +09:30
|
|
|
image->format == CAIRO_FORMAT_A8 ||
|
|
|
|
|
image->format == CAIRO_FORMAT_A1 );
|
2006-04-25 03:45:37 -07:00
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
stream_ret->id = 0;
|
|
|
|
|
|
2008-02-06 13:52:33 -08:00
|
|
|
if (image->format == CAIRO_FORMAT_A1) {
|
2008-04-03 14:53:17 +01:00
|
|
|
alpha_size = (image->width + 7) / 8 * image->height;
|
2008-02-06 13:52:33 -08:00
|
|
|
alpha = _cairo_malloc_ab ((image->width+7) / 8, image->height);
|
|
|
|
|
} else {
|
2007-10-14 19:05:06 +09:30
|
|
|
alpha_size = image->height * image->width;
|
2008-02-06 13:52:33 -08:00
|
|
|
alpha = _cairo_malloc_ab (image->height, image->width);
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-25 03:45:37 -07:00
|
|
|
if (alpha == NULL) {
|
2007-10-04 13:15:46 +01:00
|
|
|
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2006-04-25 03:45:37 -07:00
|
|
|
goto CLEANUP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
opaque = TRUE;
|
|
|
|
|
i = 0;
|
|
|
|
|
for (y = 0; y < image->height; y++) {
|
2007-09-20 22:51:39 +09:30
|
|
|
if (image->format == CAIRO_FORMAT_ARGB32) {
|
|
|
|
|
pixel32 = (uint32_t *) (image->data + y * image->stride);
|
|
|
|
|
|
|
|
|
|
for (x = 0; x < image->width; x++, pixel32++) {
|
|
|
|
|
a = (*pixel32 & 0xff000000) >> 24;
|
|
|
|
|
alpha[i++] = a;
|
|
|
|
|
if (a != 0xff)
|
|
|
|
|
opaque = FALSE;
|
|
|
|
|
}
|
2007-10-14 19:05:06 +09:30
|
|
|
} else if (image->format == CAIRO_FORMAT_A8){
|
2007-09-20 22:51:39 +09:30
|
|
|
pixel8 = (uint8_t *) (image->data + y * image->stride);
|
|
|
|
|
|
|
|
|
|
for (x = 0; x < image->width; x++, pixel8++) {
|
|
|
|
|
a = *pixel8;
|
|
|
|
|
alpha[i++] = a;
|
|
|
|
|
if (a != 0xff)
|
|
|
|
|
opaque = FALSE;
|
|
|
|
|
}
|
2007-10-14 19:05:06 +09:30
|
|
|
} else { /* image->format == CAIRO_FORMAT_A1 */
|
|
|
|
|
pixel8 = (uint8_t *) (image->data + y * image->stride);
|
|
|
|
|
|
2008-04-03 14:53:17 +01:00
|
|
|
for (x = 0; x < (image->width + 7) / 8; x++, pixel8++) {
|
|
|
|
|
a = *pixel8;
|
|
|
|
|
a = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (a);
|
|
|
|
|
alpha[i++] = a;
|
|
|
|
|
if (a != 0xff)
|
|
|
|
|
opaque = FALSE;
|
2007-10-14 19:05:06 +09:30
|
|
|
}
|
2006-04-25 03:45:37 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Bail out without emitting smask if it's all opaque. */
|
2008-01-16 16:33:22 +00:00
|
|
|
if (opaque)
|
2006-04-25 03:45:37 -07:00
|
|
|
goto CLEANUP_ALPHA;
|
|
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
status = _cairo_pdf_surface_open_stream (surface,
|
|
|
|
|
NULL,
|
2008-02-11 13:44:48 -05:00
|
|
|
TRUE,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Type /XObject\n"
|
|
|
|
|
" /Subtype /Image\n"
|
|
|
|
|
" /Width %d\n"
|
|
|
|
|
" /Height %d\n"
|
|
|
|
|
" /ColorSpace /DeviceGray\n"
|
|
|
|
|
" /BitsPerComponent %d\n",
|
2008-01-16 16:33:22 +00:00
|
|
|
image->width, image->height,
|
|
|
|
|
image->format == CAIRO_FORMAT_A1 ? 1 : 8);
|
|
|
|
|
if (status)
|
2008-02-11 13:44:48 -05:00
|
|
|
goto CLEANUP_ALPHA;
|
2008-01-16 16:33:22 +00:00
|
|
|
|
|
|
|
|
*stream_ret = surface->pdf_stream.self;
|
2008-02-11 13:44:48 -05:00
|
|
|
_cairo_output_stream_write (surface->output, alpha, alpha_size);
|
2007-04-10 13:51:46 -07:00
|
|
|
status = _cairo_pdf_surface_close_stream (surface);
|
2006-04-25 03:45:37 -07:00
|
|
|
|
|
|
|
|
CLEANUP_ALPHA:
|
|
|
|
|
free (alpha);
|
|
|
|
|
CLEANUP:
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
/* Emit image data into the given surface, providing a resource that
|
|
|
|
|
* can be used to reference the data in image_ret. */
|
2006-04-20 10:01:45 -07:00
|
|
|
static cairo_status_t
|
2007-04-27 09:49:45 -07:00
|
|
|
_cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_image_surface_t *image,
|
|
|
|
|
cairo_pdf_resource_t *image_ret)
|
2005-01-05 14:29:31 +00:00
|
|
|
{
|
2006-04-25 03:45:37 -07:00
|
|
|
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
2008-02-11 13:44:48 -05:00
|
|
|
char *rgb;
|
|
|
|
|
unsigned long rgb_size;
|
2007-06-13 00:15:34 -04:00
|
|
|
uint32_t *pixel;
|
2006-04-25 03:45:37 -07:00
|
|
|
int i, x, y;
|
2006-05-18 21:48:38 -07:00
|
|
|
cairo_pdf_resource_t smask = {0}; /* squelch bogus compiler warning */
|
2006-04-25 03:45:37 -07:00
|
|
|
cairo_bool_t need_smask;
|
|
|
|
|
|
|
|
|
|
/* These are the only image formats we currently support, (which
|
2006-05-24 14:02:30 -07:00
|
|
|
* makes things a lot simpler here). This is enforced through
|
2007-03-07 15:54:20 -05:00
|
|
|
* _cairo_pdf_surface_analyze_operation which only accept source surfaces of
|
2006-05-12 14:56:11 -07:00
|
|
|
* CONTENT_COLOR or CONTENT_COLOR_ALPHA.
|
2006-04-25 03:45:37 -07:00
|
|
|
*/
|
2007-09-20 22:51:39 +09:30
|
|
|
assert (image->format == CAIRO_FORMAT_RGB24 ||
|
|
|
|
|
image->format == CAIRO_FORMAT_ARGB32 ||
|
2007-10-14 19:05:06 +09:30
|
|
|
image->format == CAIRO_FORMAT_A8 ||
|
|
|
|
|
image->format == CAIRO_FORMAT_A1);
|
2005-01-05 17:46:31 +00:00
|
|
|
|
|
|
|
|
rgb_size = image->height * image->width * 3;
|
2008-02-06 13:52:33 -08:00
|
|
|
rgb = _cairo_malloc_abc (image->width, image->height, 3);
|
2006-04-25 03:45:37 -07:00
|
|
|
if (rgb == NULL) {
|
2007-10-04 13:15:46 +01:00
|
|
|
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2006-04-25 03:45:37 -07:00
|
|
|
goto CLEANUP;
|
Big change to the test infrastructure and supporting internals. The goal now is to test both a COLOR_ALPHA and a COLOR content for each surface backend, (since the semantics are different and we probably need to support both in each backend.
The PS/PDF backends don't allow a content to be passed in right now, so they fail against the rgb24 tests, but the trivial addition to the constructors will allow them to pass all tests with both content values.
And new constructors (currently internal only) to create an image surface with a cairo_content_t rather than a cairo_format_t.
Add a cairo_content_t argument to the constructor.
Add a cairo_content_t to the constructor and use this content value when constructing intermediate image surfaces in acquire_source, show_page, copy_page, and snapshot.
Add image flattening by compositing over white, as is done in cairo-ps-surface.c.
Track changes to cairo-paginates-surface which now requires a cairo_content_t value (no change to public PS/PDF constructors yet).
Track change in meta-surface and paginated-surface interfaces by now accepting a cairo_content_t rather than a cairo_format_t.
Ignore new output files (argb32 from pdf and ps as well as rgb24 from test-fallback, test-meta, and test-paginated).
Add new utility for flattening PNG images in order to generate the -argbf-ref.png images.
Add image_diff_flattened for comparing flattened output from PS and PDF backend with ARGB reference images by first blending the reference images over white.
Get rid of conditional, format-specific background-color initialization before running tests. Now uses ARGB(0,0,0,0) in all cases. Switch from specifying tests with a format value to specifying tests with a content value. Add support for a 'fake' COLOR_ALPHA_FLATTENED content for testing the PS and PDF output against a flattened version of the argb32 reference images (first blended over white).
Track change in cairo_ps_surface_create (now requires cairo_content_t value).
Adjust tests that draw in default (black) to first paint white so that the results are visible.
Adjust ARGB32 reference images for new white background for changed tests.
Adjust RGB24 reference images for new black background due to changed initialization (and the tests themselves being unchanged).
2006-01-17 16:59:08 +00:00
|
|
|
}
|
|
|
|
|
|
2005-01-05 17:46:31 +00:00
|
|
|
i = 0;
|
|
|
|
|
for (y = 0; y < image->height; y++) {
|
2007-06-13 00:15:34 -04:00
|
|
|
pixel = (uint32_t *) (image->data + y * image->stride);
|
2006-04-25 03:45:37 -07:00
|
|
|
|
|
|
|
|
for (x = 0; x < image->width; x++, pixel++) {
|
|
|
|
|
/* XXX: We're un-premultiplying alpha here. My reading of the PDF
|
|
|
|
|
* specification suggests that we should be able to avoid having
|
|
|
|
|
* to do this by filling in the SMask's Matte dictionary
|
|
|
|
|
* appropriately, but my attempts to do that so far have
|
|
|
|
|
* failed. */
|
|
|
|
|
if (image->format == CAIRO_FORMAT_ARGB32) {
|
|
|
|
|
uint8_t a;
|
|
|
|
|
a = (*pixel & 0xff000000) >> 24;
|
|
|
|
|
if (a == 0) {
|
|
|
|
|
rgb[i++] = 0;
|
|
|
|
|
rgb[i++] = 0;
|
|
|
|
|
rgb[i++] = 0;
|
|
|
|
|
} else {
|
|
|
|
|
rgb[i++] = (((*pixel & 0xff0000) >> 16) * 255 + a / 2) / a;
|
|
|
|
|
rgb[i++] = (((*pixel & 0x00ff00) >> 8) * 255 + a / 2) / a;
|
|
|
|
|
rgb[i++] = (((*pixel & 0x0000ff) >> 0) * 255 + a / 2) / a;
|
|
|
|
|
}
|
2007-09-20 22:51:39 +09:30
|
|
|
} else if (image->format == CAIRO_FORMAT_RGB24) {
|
2006-04-25 03:45:37 -07:00
|
|
|
rgb[i++] = (*pixel & 0x00ff0000) >> 16;
|
|
|
|
|
rgb[i++] = (*pixel & 0x0000ff00) >> 8;
|
|
|
|
|
rgb[i++] = (*pixel & 0x000000ff) >> 0;
|
2007-09-20 22:51:39 +09:30
|
|
|
} else {
|
|
|
|
|
rgb[i++] = 0;
|
|
|
|
|
rgb[i++] = 0;
|
|
|
|
|
rgb[i++] = 0;
|
2006-04-25 03:45:37 -07:00
|
|
|
}
|
2005-01-05 17:46:31 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-25 03:45:37 -07:00
|
|
|
need_smask = FALSE;
|
2007-09-20 22:51:39 +09:30
|
|
|
if (image->format == CAIRO_FORMAT_ARGB32 ||
|
2007-10-14 19:05:06 +09:30
|
|
|
image->format == CAIRO_FORMAT_A8 ||
|
|
|
|
|
image->format == CAIRO_FORMAT_A1) {
|
2007-03-07 15:54:20 -05:00
|
|
|
status = _cairo_pdf_surface_emit_smask (surface, image, &smask);
|
2006-04-25 03:45:37 -07:00
|
|
|
if (status)
|
2008-02-11 13:44:48 -05:00
|
|
|
goto CLEANUP_RGB;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 13:31:12 -07:00
|
|
|
if (smask.id)
|
2006-04-25 03:45:37 -07:00
|
|
|
need_smask = TRUE;
|
|
|
|
|
}
|
2005-05-13 14:04:22 +00:00
|
|
|
|
2008-02-20 21:05:23 +10:30
|
|
|
#define IMAGE_DICTIONARY " /Type /XObject\n" \
|
|
|
|
|
" /Subtype /Image\n" \
|
|
|
|
|
" /Width %d\n" \
|
|
|
|
|
" /Height %d\n" \
|
|
|
|
|
" /ColorSpace /DeviceRGB\n" \
|
|
|
|
|
" /BitsPerComponent 8\n"
|
2006-04-25 03:45:37 -07:00
|
|
|
|
|
|
|
|
if (need_smask)
|
2008-01-16 16:33:22 +00:00
|
|
|
status = _cairo_pdf_surface_open_stream (surface,
|
|
|
|
|
NULL,
|
2008-02-11 13:44:48 -05:00
|
|
|
TRUE,
|
2008-01-16 16:33:22 +00:00
|
|
|
IMAGE_DICTIONARY
|
2008-02-20 21:05:23 +10:30
|
|
|
" /SMask %d 0 R\n",
|
2008-01-16 16:33:22 +00:00
|
|
|
image->width, image->height,
|
|
|
|
|
smask.id);
|
2006-04-25 03:45:37 -07:00
|
|
|
else
|
2008-01-16 16:33:22 +00:00
|
|
|
status = _cairo_pdf_surface_open_stream (surface,
|
|
|
|
|
NULL,
|
2008-02-11 13:44:48 -05:00
|
|
|
TRUE,
|
2008-01-16 16:33:22 +00:00
|
|
|
IMAGE_DICTIONARY,
|
|
|
|
|
image->width, image->height);
|
|
|
|
|
if (status)
|
2008-02-11 13:44:48 -05:00
|
|
|
goto CLEANUP_RGB;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-04-25 03:45:37 -07:00
|
|
|
#undef IMAGE_DICTIONARY
|
2005-01-05 17:46:31 +00:00
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
*image_ret = surface->pdf_stream.self;
|
2008-02-11 13:44:48 -05:00
|
|
|
_cairo_output_stream_write (surface->output, rgb, rgb_size);
|
2007-04-10 13:51:46 -07:00
|
|
|
status = _cairo_pdf_surface_close_stream (surface);
|
Big change to the test infrastructure and supporting internals. The goal now is to test both a COLOR_ALPHA and a COLOR content for each surface backend, (since the semantics are different and we probably need to support both in each backend.
The PS/PDF backends don't allow a content to be passed in right now, so they fail against the rgb24 tests, but the trivial addition to the constructors will allow them to pass all tests with both content values.
And new constructors (currently internal only) to create an image surface with a cairo_content_t rather than a cairo_format_t.
Add a cairo_content_t argument to the constructor.
Add a cairo_content_t to the constructor and use this content value when constructing intermediate image surfaces in acquire_source, show_page, copy_page, and snapshot.
Add image flattening by compositing over white, as is done in cairo-ps-surface.c.
Track changes to cairo-paginates-surface which now requires a cairo_content_t value (no change to public PS/PDF constructors yet).
Track change in meta-surface and paginated-surface interfaces by now accepting a cairo_content_t rather than a cairo_format_t.
Ignore new output files (argb32 from pdf and ps as well as rgb24 from test-fallback, test-meta, and test-paginated).
Add new utility for flattening PNG images in order to generate the -argbf-ref.png images.
Add image_diff_flattened for comparing flattened output from PS and PDF backend with ARGB reference images by first blending the reference images over white.
Get rid of conditional, format-specific background-color initialization before running tests. Now uses ARGB(0,0,0,0) in all cases. Switch from specifying tests with a format value to specifying tests with a content value. Add support for a 'fake' COLOR_ALPHA_FLATTENED content for testing the PS and PDF output against a flattened version of the argb32 reference images (first blended over white).
Track change in cairo_ps_surface_create (now requires cairo_content_t value).
Adjust tests that draw in default (black) to first paint white so that the results are visible.
Adjust ARGB32 reference images for new white background for changed tests.
Adjust RGB24 reference images for new black background due to changed initialization (and the tests themselves being unchanged).
2006-01-17 16:59:08 +00:00
|
|
|
|
2007-09-05 22:26:16 +09:30
|
|
|
CLEANUP_RGB:
|
2006-04-25 03:45:37 -07:00
|
|
|
free (rgb);
|
2007-09-05 22:26:16 +09:30
|
|
|
CLEANUP:
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_surface_pattern_t *pattern,
|
|
|
|
|
cairo_pdf_resource_t *resource,
|
|
|
|
|
int *width,
|
|
|
|
|
int *height)
|
|
|
|
|
{
|
|
|
|
|
cairo_image_surface_t *image;
|
|
|
|
|
void *image_extra;
|
2008-01-16 16:33:22 +00:00
|
|
|
cairo_status_t status;
|
2007-09-05 22:26:16 +09:30
|
|
|
|
2008-01-19 12:46:24 +10:30
|
|
|
status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
|
2007-09-05 22:26:16 +09:30
|
|
|
if (status)
|
2008-01-19 12:46:24 +10:30
|
|
|
goto BAIL;
|
2007-09-05 22:26:16 +09:30
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_emit_image (surface, image, resource);
|
|
|
|
|
if (status)
|
|
|
|
|
goto BAIL;
|
|
|
|
|
|
|
|
|
|
*width = image->width;
|
|
|
|
|
*height = image->height;
|
|
|
|
|
|
|
|
|
|
BAIL:
|
2008-01-19 12:46:24 +10:30
|
|
|
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
|
2007-09-05 22:26:16 +09:30
|
|
|
|
2006-04-25 03:45:37 -07:00
|
|
|
return status;
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
2007-09-05 22:26:16 +09:30
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_surface_t *meta_surface,
|
|
|
|
|
cairo_pdf_resource_t *resource)
|
|
|
|
|
{
|
|
|
|
|
double old_width, old_height;
|
2008-01-07 21:09:04 +10:30
|
|
|
cairo_paginated_mode_t old_paginated_mode;
|
2008-03-29 01:07:30 +10:30
|
|
|
cairo_clip_t *old_clip;
|
2008-01-22 15:32:11 -08:00
|
|
|
cairo_rectangle_int_t meta_extents;
|
2008-07-08 20:57:57 +09:30
|
|
|
cairo_status_t status;
|
2007-09-05 22:26:16 +09:30
|
|
|
int alpha = 0;
|
|
|
|
|
|
|
|
|
|
status = _cairo_surface_get_extents (meta_surface, &meta_extents);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
old_width = surface->width;
|
|
|
|
|
old_height = surface->height;
|
2008-01-07 21:09:04 +10:30
|
|
|
old_paginated_mode = surface->paginated_mode;
|
2008-03-29 01:07:30 +10:30
|
|
|
old_clip = _cairo_surface_get_clip (&surface->base);
|
2008-04-07 13:03:58 -07:00
|
|
|
_cairo_pdf_surface_set_size_internal (surface,
|
|
|
|
|
meta_extents.width,
|
|
|
|
|
meta_extents.height);
|
2008-01-07 21:09:04 +10:30
|
|
|
/* Patterns are emitted after fallback images. The paginated mode
|
|
|
|
|
* needs to be set to _RENDER while the meta surface is replayed
|
|
|
|
|
* back to this surface.
|
|
|
|
|
*/
|
|
|
|
|
surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER;
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_pdf_group_resources_clear (&surface->resources);
|
2008-01-16 16:33:22 +00:00
|
|
|
status = _cairo_pdf_surface_open_content_stream (surface, TRUE);
|
2007-10-04 23:15:21 +01:00
|
|
|
if (status)
|
2008-01-07 21:04:06 +10:30
|
|
|
return status;
|
2007-09-05 22:26:16 +09:30
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
*resource = surface->content;
|
2007-09-05 22:26:16 +09:30
|
|
|
if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
|
|
|
|
|
status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
|
|
|
|
|
if (status)
|
2008-07-08 20:55:38 +09:30
|
|
|
return status;
|
2007-10-09 23:36:52 +01:00
|
|
|
|
2007-09-05 22:26:16 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"q /a%d gs 0 0 0 rg 0 0 %f %f re f Q\n",
|
2007-09-05 22:26:16 +09:30
|
|
|
alpha,
|
|
|
|
|
surface->width,
|
|
|
|
|
surface->height);
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-29 00:26:11 +10:30
|
|
|
status = _cairo_meta_surface_replay_region (meta_surface, &surface->base,
|
|
|
|
|
CAIRO_META_REGION_NATIVE);
|
|
|
|
|
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
|
2007-09-05 22:26:16 +09:30
|
|
|
if (status)
|
2008-07-08 20:55:38 +09:30
|
|
|
return status;
|
2007-10-09 23:36:52 +01:00
|
|
|
|
2008-07-08 20:57:57 +09:30
|
|
|
status = _cairo_surface_set_clip (&surface->base, old_clip);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
status = _cairo_pdf_surface_close_content_stream (surface);
|
2007-09-05 22:26:16 +09:30
|
|
|
|
2008-04-07 13:03:58 -07:00
|
|
|
_cairo_pdf_surface_set_size_internal (surface,
|
|
|
|
|
old_width,
|
|
|
|
|
old_height);
|
2008-01-07 21:09:04 +10:30
|
|
|
surface->paginated_mode = old_paginated_mode;
|
2008-03-29 01:07:30 +10:30
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
return status;
|
2007-09-05 22:26:16 +09:30
|
|
|
}
|
|
|
|
|
|
2005-10-07 13:21:01 +00:00
|
|
|
static cairo_status_t
|
2008-01-07 20:55:56 +10:30
|
|
|
_cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
|
2008-01-10 15:53:54 +00:00
|
|
|
cairo_pdf_pattern_t *pdf_pattern)
|
2005-01-05 14:29:31 +00:00
|
|
|
{
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern;
|
2008-01-16 16:33:22 +00:00
|
|
|
cairo_status_t status;
|
2007-09-05 22:26:16 +09:30
|
|
|
cairo_pdf_resource_t pattern_resource = {0}; /* squelch bogus compiler warning */
|
2006-04-24 16:11:21 -07:00
|
|
|
cairo_matrix_t cairo_p2d, pdf_p2d;
|
|
|
|
|
cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base);
|
2007-02-27 18:47:47 -05:00
|
|
|
double xstep, ystep;
|
2008-01-22 15:32:11 -08:00
|
|
|
cairo_rectangle_int_t surface_extents;
|
2007-09-05 22:26:16 +09:30
|
|
|
int pattern_width = 0; /* squelch bogus compiler warning */
|
|
|
|
|
int pattern_height = 0; /* squelch bogus compiler warning */
|
2007-10-22 23:05:25 +09:30
|
|
|
int bbox_x, bbox_y;
|
2008-01-19 12:46:24 +10:30
|
|
|
char draw_surface[200];
|
2005-01-31 08:50:22 +00:00
|
|
|
|
2007-09-05 22:26:16 +09:30
|
|
|
if (_cairo_surface_is_meta (pattern->surface)) {
|
|
|
|
|
cairo_surface_t *meta_surface = pattern->surface;
|
2008-01-22 15:32:11 -08:00
|
|
|
cairo_rectangle_int_t pattern_extents;
|
2007-02-22 13:40:55 -05:00
|
|
|
|
2007-09-05 22:26:16 +09:30
|
|
|
status = _cairo_pdf_surface_emit_meta_surface (surface,
|
|
|
|
|
meta_surface,
|
|
|
|
|
&pattern_resource);
|
2007-10-09 09:28:35 +01:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2007-09-05 22:26:16 +09:30
|
|
|
status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-10-09 09:28:35 +01:00
|
|
|
|
2007-09-05 22:26:16 +09:30
|
|
|
pattern_width = pattern_extents.width;
|
|
|
|
|
pattern_height = pattern_extents.height;
|
|
|
|
|
} else {
|
|
|
|
|
status = _cairo_pdf_surface_emit_image_surface (surface,
|
|
|
|
|
pattern,
|
|
|
|
|
&pattern_resource,
|
|
|
|
|
&pattern_width,
|
|
|
|
|
&pattern_height);
|
2007-10-09 09:28:35 +01:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-09-05 22:26:16 +09:30
|
|
|
}
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2007-04-08 21:26:33 +01:00
|
|
|
status = _cairo_surface_get_extents (&surface->base, &surface_extents);
|
|
|
|
|
if (status)
|
2007-09-05 22:26:16 +09:30
|
|
|
return status;
|
2006-04-24 16:11:21 -07:00
|
|
|
|
2007-10-22 23:05:25 +09:30
|
|
|
bbox_x = pattern_width;
|
|
|
|
|
bbox_y = pattern_height;
|
2006-04-24 16:11:21 -07:00
|
|
|
switch (extend) {
|
2007-09-05 22:26:16 +09:30
|
|
|
/* We implement EXTEND_PAD like EXTEND_NONE for now */
|
2007-03-01 19:14:40 -05:00
|
|
|
case CAIRO_EXTEND_PAD:
|
2006-04-24 16:11:21 -07:00
|
|
|
case CAIRO_EXTEND_NONE:
|
2007-09-05 22:26:16 +09:30
|
|
|
{
|
|
|
|
|
/* In PS/PDF, (as far as I can tell), all patterns are
|
|
|
|
|
* repeating. So we support cairo's EXTEND_NONE semantics
|
|
|
|
|
* by setting the repeat step size to a size large enough
|
|
|
|
|
* to guarantee that no more than a single occurrence will
|
|
|
|
|
* be visible.
|
|
|
|
|
*
|
|
|
|
|
* First, map the surface extents into pattern space (since
|
|
|
|
|
* xstep and ystep are in pattern space). Then use an upper
|
|
|
|
|
* bound on the length of the diagonal of the pattern image
|
|
|
|
|
* and the surface as repeat size. This guarantees to never
|
|
|
|
|
* repeat visibly.
|
|
|
|
|
*/
|
|
|
|
|
double x1 = 0.0, y1 = 0.0;
|
|
|
|
|
double x2 = surface->width, y2 = surface->height;
|
|
|
|
|
_cairo_matrix_transform_bounding_box (&pattern->base.matrix,
|
|
|
|
|
&x1, &y1, &x2, &y2,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
/* Rather than computing precise bounds of the union, just
|
|
|
|
|
* add the surface extents unconditionally. We only
|
|
|
|
|
* required an answer that's large enough, we don't really
|
|
|
|
|
* care if it's not as tight as possible.*/
|
|
|
|
|
xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
|
|
|
|
|
pattern_width + pattern_height);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2006-04-24 16:11:21 -07:00
|
|
|
case CAIRO_EXTEND_REPEAT:
|
2007-09-05 22:26:16 +09:30
|
|
|
xstep = pattern_width;
|
|
|
|
|
ystep = pattern_height;
|
2006-04-24 16:11:21 -07:00
|
|
|
break;
|
2007-10-22 23:05:25 +09:30
|
|
|
case CAIRO_EXTEND_REFLECT:
|
|
|
|
|
bbox_x = pattern_width*2;
|
|
|
|
|
bbox_y = pattern_height*2;
|
|
|
|
|
xstep = bbox_x;
|
|
|
|
|
ystep = bbox_y;
|
|
|
|
|
break;
|
2007-09-05 22:26:16 +09:30
|
|
|
/* All the rest (if any) should have been analyzed away, so this
|
|
|
|
|
* case should be unreachable. */
|
2006-04-24 16:11:21 -07:00
|
|
|
default:
|
2006-07-31 11:47:45 -07:00
|
|
|
ASSERT_NOT_REACHED;
|
2006-04-24 16:11:21 -07:00
|
|
|
xstep = 0;
|
|
|
|
|
ystep = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* At this point, (that is, within the surface backend interface),
|
|
|
|
|
* the pattern's matrix maps from cairo's device space to cairo's
|
|
|
|
|
* pattern space, (both with their origin at the upper-left, and
|
|
|
|
|
* cairo's pattern space of size width,height).
|
|
|
|
|
*
|
|
|
|
|
* Then, we must emit a PDF pattern object that maps from its own
|
|
|
|
|
* pattern space, (which has a size that we establish in the BBox
|
|
|
|
|
* dictionary entry), to the PDF page's *initial* space, (which
|
|
|
|
|
* does not benefit from the Y-axis flipping matrix that we emit
|
2007-09-15 04:02:39 -04:00
|
|
|
* on each page). So the PDF patterns matrix maps from a
|
2006-04-24 16:11:21 -07:00
|
|
|
* (width,height) pattern space to a device space with the origin
|
|
|
|
|
* in the lower-left corner.
|
|
|
|
|
*
|
|
|
|
|
* So to handle all of that, we start with an identity matrix for
|
|
|
|
|
* the PDF pattern to device matrix. We translate it up by the
|
|
|
|
|
* image height then flip it in the Y direction, (moving us from
|
|
|
|
|
* the PDF origin to cairo's origin). We then multiply in the
|
|
|
|
|
* inverse of the cairo pattern matrix, (since it maps from device
|
|
|
|
|
* to pattern, while we're setting up pattern to device). Finally,
|
|
|
|
|
* we translate back down by the image height and flip again to
|
|
|
|
|
* end up at the lower-left origin that PDF expects.
|
|
|
|
|
*
|
|
|
|
|
* Additionally, within the stream that paints the pattern itself,
|
|
|
|
|
* we are using a PDF image object that has a size of (1,1) so we
|
|
|
|
|
* have to scale it up by the image width and height to fill our
|
|
|
|
|
* pattern cell.
|
|
|
|
|
*/
|
|
|
|
|
cairo_p2d = pattern->base.matrix;
|
2007-04-11 01:35:11 -07:00
|
|
|
status = cairo_matrix_invert (&cairo_p2d);
|
|
|
|
|
/* cairo_pattern_set_matrix ensures the matrix is invertible */
|
|
|
|
|
assert (status == CAIRO_STATUS_SUCCESS);
|
2006-04-24 16:11:21 -07:00
|
|
|
|
|
|
|
|
cairo_matrix_init_identity (&pdf_p2d);
|
2006-05-12 14:56:11 -07:00
|
|
|
cairo_matrix_translate (&pdf_p2d, 0.0, surface_extents.height);
|
2006-04-24 16:11:21 -07:00
|
|
|
cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
|
|
|
|
|
cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d);
|
2007-09-05 22:26:16 +09:30
|
|
|
cairo_matrix_translate (&pdf_p2d, 0.0, pattern_height);
|
2006-04-24 16:11:21 -07:00
|
|
|
cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
_cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
|
2008-01-16 16:33:22 +00:00
|
|
|
status = _cairo_pdf_surface_open_stream (surface,
|
|
|
|
|
&pdf_pattern->pattern_res,
|
|
|
|
|
FALSE,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /PatternType 1\n"
|
|
|
|
|
" /BBox [0 0 %d %d]\n"
|
|
|
|
|
" /XStep %f\n"
|
|
|
|
|
" /YStep %f\n"
|
|
|
|
|
" /TilingType 1\n"
|
|
|
|
|
" /PaintType 1\n"
|
|
|
|
|
" /Matrix [ %f %f %f %f %f %f ]\n"
|
|
|
|
|
" /Resources << /XObject << /x%d %d 0 R >> >>\n",
|
2008-01-16 16:33:22 +00:00
|
|
|
bbox_x, bbox_y,
|
|
|
|
|
xstep, ystep,
|
|
|
|
|
pdf_p2d.xx, pdf_p2d.yx,
|
|
|
|
|
pdf_p2d.xy, pdf_p2d.yy,
|
|
|
|
|
pdf_p2d.x0, pdf_p2d.y0,
|
|
|
|
|
pattern_resource.id,
|
|
|
|
|
pattern_resource.id);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2006-05-12 14:56:11 -07:00
|
|
|
|
2007-09-05 22:26:16 +09:30
|
|
|
if (_cairo_surface_is_meta (pattern->surface)) {
|
2008-01-19 12:46:24 +10:30
|
|
|
snprintf(draw_surface,
|
|
|
|
|
sizeof (draw_surface),
|
2008-02-20 21:05:23 +10:30
|
|
|
"/x%d Do\n",
|
2008-01-19 12:46:24 +10:30
|
|
|
pattern_resource.id);
|
2007-09-05 22:26:16 +09:30
|
|
|
} else {
|
2008-01-19 12:46:24 +10:30
|
|
|
snprintf(draw_surface,
|
|
|
|
|
sizeof (draw_surface),
|
|
|
|
|
"q %d 0 0 %d 0 0 cm /x%d Do Q",
|
|
|
|
|
pattern_width,
|
|
|
|
|
pattern_height,
|
|
|
|
|
pattern_resource.id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (extend == CAIRO_EXTEND_REFLECT) {
|
2007-09-05 22:26:16 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"q 0 0 %d %d re W n %s Q\n"
|
|
|
|
|
"q -1 0 0 1 %d 0 cm 0 0 %d %d re W n %s Q\n"
|
|
|
|
|
"q 1 0 0 -1 0 %d cm 0 0 %d %d re W n %s Q\n"
|
|
|
|
|
"q -1 0 0 -1 %d %d cm 0 0 %d %d re W n %s Q\n",
|
2007-09-05 22:26:16 +09:30
|
|
|
pattern_width, pattern_height,
|
2008-01-19 12:46:24 +10:30
|
|
|
draw_surface,
|
|
|
|
|
pattern_width*2, pattern_width, pattern_height,
|
|
|
|
|
draw_surface,
|
|
|
|
|
pattern_height*2, pattern_width, pattern_height,
|
|
|
|
|
draw_surface,
|
|
|
|
|
pattern_width*2, pattern_height*2, pattern_width, pattern_height,
|
|
|
|
|
draw_surface);
|
|
|
|
|
} else {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" %s \n",
|
2008-01-19 12:46:24 +10:30
|
|
|
draw_surface);
|
2007-09-05 22:26:16 +09:30
|
|
|
}
|
2005-02-01 20:47:43 +00:00
|
|
|
|
2007-04-10 13:51:46 -07:00
|
|
|
status = _cairo_pdf_surface_close_stream (surface);
|
2007-04-11 01:55:59 -07:00
|
|
|
if (status)
|
2007-09-05 22:26:16 +09:30
|
|
|
return status;
|
2006-05-12 13:31:12 -07:00
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
2005-10-07 13:21:01 +00:00
|
|
|
typedef struct _cairo_pdf_color_stop {
|
2007-04-27 09:49:45 -07:00
|
|
|
double offset;
|
|
|
|
|
double color[4];
|
|
|
|
|
cairo_pdf_resource_t resource;
|
2005-10-07 13:21:01 +00:00
|
|
|
} cairo_pdf_color_stop_t;
|
|
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
static cairo_status_t
|
|
|
|
|
cairo_pdf_surface_emit_rgb_linear_function (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_pdf_color_stop_t *stop1,
|
|
|
|
|
cairo_pdf_color_stop_t *stop2,
|
|
|
|
|
cairo_pdf_resource_t *function)
|
|
|
|
|
{
|
|
|
|
|
int num_elems, i;
|
|
|
|
|
cairo_pdf_rgb_linear_function_t elem;
|
|
|
|
|
cairo_pdf_resource_t res;
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
|
|
|
|
|
num_elems = _cairo_array_num_elements (&surface->rgb_linear_functions);
|
|
|
|
|
for (i = 0; i < num_elems; i++) {
|
|
|
|
|
_cairo_array_copy_element (&surface->rgb_linear_functions, i, &elem);
|
|
|
|
|
if (memcmp (&elem.color1[0], &stop1->color[0], sizeof (double)*3) != 0)
|
|
|
|
|
continue;
|
|
|
|
|
if (memcmp (&elem.color2[0], &stop2->color[0], sizeof (double)*3) != 0)
|
|
|
|
|
continue;
|
|
|
|
|
*function = elem.resource;
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (res.id == 0)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2006-05-12 14:56:11 -07:00
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /FunctionType 2\n"
|
|
|
|
|
" /Domain [ 0 1 ]\n"
|
|
|
|
|
" /C0 [ %f %f %f ]\n"
|
|
|
|
|
" /C1 [ %f %f %f ]\n"
|
|
|
|
|
" /N 1\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n",
|
2007-04-27 09:49:45 -07:00
|
|
|
res.id,
|
|
|
|
|
stop1->color[0],
|
|
|
|
|
stop1->color[1],
|
|
|
|
|
stop1->color[2],
|
|
|
|
|
stop2->color[0],
|
|
|
|
|
stop2->color[1],
|
|
|
|
|
stop2->color[2]);
|
|
|
|
|
|
|
|
|
|
elem.resource = res;
|
|
|
|
|
memcpy (&elem.color1[0], &stop1->color[0], sizeof (double)*3);
|
|
|
|
|
memcpy (&elem.color2[0], &stop2->color[0], sizeof (double)*3);
|
|
|
|
|
|
|
|
|
|
status = _cairo_array_append (&surface->rgb_linear_functions, &elem);
|
|
|
|
|
*function = res;
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
cairo_pdf_surface_emit_alpha_linear_function (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_pdf_color_stop_t *stop1,
|
|
|
|
|
cairo_pdf_color_stop_t *stop2,
|
|
|
|
|
cairo_pdf_resource_t *function)
|
|
|
|
|
{
|
|
|
|
|
int num_elems, i;
|
|
|
|
|
cairo_pdf_alpha_linear_function_t elem;
|
|
|
|
|
cairo_pdf_resource_t res;
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
|
|
|
|
|
num_elems = _cairo_array_num_elements (&surface->alpha_linear_functions);
|
|
|
|
|
for (i = 0; i < num_elems; i++) {
|
|
|
|
|
_cairo_array_copy_element (&surface->alpha_linear_functions, i, &elem);
|
|
|
|
|
if (elem.alpha1 != stop1->color[3])
|
|
|
|
|
continue;
|
|
|
|
|
if (elem.alpha2 != stop2->color[3])
|
|
|
|
|
continue;
|
|
|
|
|
*function = elem.resource;
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (res.id == 0)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2005-10-07 13:21:01 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /FunctionType 2\n"
|
|
|
|
|
" /Domain [ 0 1 ]\n"
|
|
|
|
|
" /C0 [ %f ]\n"
|
|
|
|
|
" /C1 [ %f ]\n"
|
|
|
|
|
" /N 1\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n",
|
2007-04-27 09:49:45 -07:00
|
|
|
res.id,
|
|
|
|
|
stop1->color[3],
|
|
|
|
|
stop2->color[3]);
|
|
|
|
|
|
|
|
|
|
elem.resource = res;
|
|
|
|
|
elem.alpha1 = stop1->color[3];
|
|
|
|
|
elem.alpha2 = stop2->color[3];
|
|
|
|
|
|
|
|
|
|
status = _cairo_array_append (&surface->alpha_linear_functions, &elem);
|
|
|
|
|
*function = res;
|
2006-05-12 14:56:11 -07:00
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
return status;
|
2005-10-11 13:20:44 +00:00
|
|
|
}
|
|
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_emit_stitched_colorgradient (cairo_pdf_surface_t *surface,
|
2008-01-10 15:53:54 +00:00
|
|
|
unsigned int n_stops,
|
2007-04-27 09:49:45 -07:00
|
|
|
cairo_pdf_color_stop_t *stops,
|
|
|
|
|
cairo_bool_t is_alpha,
|
|
|
|
|
cairo_pdf_resource_t *function)
|
2005-10-11 13:20:44 +00:00
|
|
|
{
|
2007-04-27 09:49:45 -07:00
|
|
|
cairo_pdf_resource_t res;
|
2005-10-11 13:20:44 +00:00
|
|
|
unsigned int i;
|
2007-04-27 09:49:45 -07:00
|
|
|
cairo_status_t status;
|
2006-05-12 14:56:11 -07:00
|
|
|
|
2005-10-11 13:20:44 +00:00
|
|
|
/* emit linear gradients between pairs of subsequent stops... */
|
|
|
|
|
for (i = 0; i < n_stops-1; i++) {
|
2007-04-27 09:49:45 -07:00
|
|
|
if (is_alpha) {
|
|
|
|
|
status = cairo_pdf_surface_emit_alpha_linear_function (surface,
|
2007-08-28 23:40:18 +09:30
|
|
|
&stops[i],
|
|
|
|
|
&stops[i+1],
|
|
|
|
|
&stops[i].resource);
|
2007-04-27 09:49:45 -07:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
} else {
|
|
|
|
|
status = cairo_pdf_surface_emit_rgb_linear_function (surface,
|
|
|
|
|
&stops[i],
|
|
|
|
|
&stops[i+1],
|
|
|
|
|
&stops[i].resource);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
}
|
2005-10-11 13:20:44 +00:00
|
|
|
}
|
2006-05-12 14:56:11 -07:00
|
|
|
|
2007-01-07 02:03:30 +00:00
|
|
|
/* ... and stitch them together */
|
2007-04-27 09:49:45 -07:00
|
|
|
res = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (res.id == 0)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /FunctionType 3\n"
|
|
|
|
|
" /Domain [ %f %f ]\n",
|
2007-08-28 23:40:18 +09:30
|
|
|
res.id,
|
|
|
|
|
stops[0].offset,
|
|
|
|
|
stops[n_stops - 1].offset);
|
2006-05-12 14:56:11 -07:00
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
" /Functions [ ");
|
2005-10-11 13:20:44 +00:00
|
|
|
for (i = 0; i < n_stops-1; i++)
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2007-04-27 09:49:45 -07:00
|
|
|
"%d 0 R ", stops[i].resource.id);
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"]\n");
|
2006-05-12 14:56:11 -07:00
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2005-10-11 13:20:44 +00:00
|
|
|
" /Bounds [ ");
|
|
|
|
|
for (i = 1; i < n_stops-1; i++)
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
"%f ", stops[i].offset);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"]\n");
|
2006-05-12 14:56:11 -07:00
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2005-10-11 13:20:44 +00:00
|
|
|
" /Encode [ ");
|
|
|
|
|
for (i = 1; i < n_stops; i++)
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
"0 1 ");
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"]\n");
|
2006-05-12 14:56:11 -07:00
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2005-10-11 13:20:44 +00:00
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
*function = res;
|
|
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2005-10-11 13:20:44 +00:00
|
|
|
}
|
|
|
|
|
|
2007-10-14 19:04:33 +09:30
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
calc_gradient_color (cairo_pdf_color_stop_t *new_stop,
|
|
|
|
|
cairo_pdf_color_stop_t *stop1,
|
|
|
|
|
cairo_pdf_color_stop_t *stop2)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
double offset = stop1->offset / (stop1->offset + 1.0 - stop2->offset);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
|
new_stop->color[i] = stop1->color[i] + offset*(stop2->color[i] - stop1->color[i]);
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-07 02:03:30 +00:00
|
|
|
#define COLOR_STOP_EPSILON 1e-6
|
2005-10-11 13:20:44 +00:00
|
|
|
|
2007-05-16 13:10:58 +01:00
|
|
|
static cairo_status_t
|
2007-04-27 09:49:45 -07:00
|
|
|
_cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_gradient_pattern_t *pattern,
|
|
|
|
|
cairo_pdf_resource_t *color_function,
|
|
|
|
|
cairo_pdf_resource_t *alpha_function)
|
2005-10-11 13:20:44 +00:00
|
|
|
{
|
|
|
|
|
cairo_pdf_color_stop_t *allstops, *stops;
|
2007-04-27 09:49:45 -07:00
|
|
|
unsigned int n_stops;
|
|
|
|
|
unsigned int i;
|
|
|
|
|
cairo_bool_t emit_alpha = FALSE;
|
|
|
|
|
cairo_status_t status;
|
2005-10-11 13:20:44 +00:00
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
color_function->id = 0;
|
|
|
|
|
alpha_function->id = 0;
|
2005-10-11 13:20:44 +00:00
|
|
|
|
2007-06-19 13:15:21 -07:00
|
|
|
allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_pdf_color_stop_t));
|
2007-10-04 13:15:46 +01:00
|
|
|
if (allstops == NULL)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2005-10-11 13:20:44 +00:00
|
|
|
stops = &allstops[1];
|
|
|
|
|
n_stops = pattern->n_stops;
|
2006-05-12 14:56:11 -07:00
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
for (i = 0; i < n_stops; i++) {
|
2007-08-05 00:50:23 +09:30
|
|
|
stops[i].color[0] = pattern->stops[i].color.red;
|
|
|
|
|
stops[i].color[1] = pattern->stops[i].color.green;
|
|
|
|
|
stops[i].color[2] = pattern->stops[i].color.blue;
|
|
|
|
|
stops[i].color[3] = pattern->stops[i].color.alpha;
|
2007-04-27 09:49:45 -07:00
|
|
|
if (!CAIRO_ALPHA_IS_OPAQUE (stops[i].color[3]))
|
|
|
|
|
emit_alpha = TRUE;
|
2008-03-26 11:31:04 -07:00
|
|
|
stops[i].offset = pattern->stops[i].offset;
|
2005-10-07 13:21:01 +00:00
|
|
|
}
|
2005-10-11 13:20:44 +00:00
|
|
|
|
2007-10-14 19:04:33 +09:30
|
|
|
if (pattern->base.extend == CAIRO_EXTEND_REPEAT ||
|
|
|
|
|
pattern->base.extend == CAIRO_EXTEND_REFLECT) {
|
|
|
|
|
if (stops[0].offset > COLOR_STOP_EPSILON) {
|
|
|
|
|
if (pattern->base.extend == CAIRO_EXTEND_REFLECT)
|
|
|
|
|
memcpy (allstops, stops, sizeof (cairo_pdf_color_stop_t));
|
|
|
|
|
else
|
|
|
|
|
calc_gradient_color (&allstops[0], &stops[0], &stops[n_stops-1]);
|
|
|
|
|
stops = allstops;
|
|
|
|
|
n_stops++;
|
|
|
|
|
}
|
|
|
|
|
stops[0].offset = 0.0;
|
|
|
|
|
|
|
|
|
|
if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
|
|
|
|
|
if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
|
|
|
|
|
memcpy (&stops[n_stops],
|
|
|
|
|
&stops[n_stops - 1],
|
|
|
|
|
sizeof (cairo_pdf_color_stop_t));
|
|
|
|
|
} else {
|
|
|
|
|
calc_gradient_color (&stops[n_stops], &stops[0], &stops[n_stops-1]);
|
|
|
|
|
}
|
|
|
|
|
n_stops++;
|
|
|
|
|
}
|
|
|
|
|
stops[n_stops-1].offset = 1.0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-10-11 13:20:44 +00:00
|
|
|
if (n_stops == 2) {
|
2007-04-27 09:49:45 -07:00
|
|
|
/* no need for stitched function */
|
|
|
|
|
status = cairo_pdf_surface_emit_rgb_linear_function (surface,
|
|
|
|
|
&stops[0],
|
|
|
|
|
&stops[1],
|
|
|
|
|
color_function);
|
|
|
|
|
if (status)
|
2007-05-16 13:10:58 +01:00
|
|
|
goto BAIL;
|
2007-04-27 09:49:45 -07:00
|
|
|
|
|
|
|
|
if (emit_alpha) {
|
|
|
|
|
status = cairo_pdf_surface_emit_alpha_linear_function (surface,
|
|
|
|
|
&stops[0],
|
|
|
|
|
&stops[1],
|
|
|
|
|
alpha_function);
|
|
|
|
|
if (status)
|
2007-05-16 13:10:58 +01:00
|
|
|
goto BAIL;
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
2005-10-11 13:20:44 +00:00
|
|
|
} else {
|
2008-01-16 16:33:22 +00:00
|
|
|
/* multiple stops: stitch. XXX possible optimization: regularly spaced
|
2007-04-27 09:49:45 -07:00
|
|
|
* stops do not require stitching. XXX */
|
|
|
|
|
status = _cairo_pdf_surface_emit_stitched_colorgradient (surface,
|
|
|
|
|
n_stops,
|
|
|
|
|
stops,
|
|
|
|
|
FALSE,
|
|
|
|
|
color_function);
|
|
|
|
|
if (status)
|
2007-05-16 13:10:58 +01:00
|
|
|
goto BAIL;
|
2005-03-16 12:08:41 +00:00
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
if (emit_alpha) {
|
|
|
|
|
status = _cairo_pdf_surface_emit_stitched_colorgradient (surface,
|
|
|
|
|
n_stops,
|
|
|
|
|
stops,
|
|
|
|
|
TRUE,
|
|
|
|
|
alpha_function);
|
|
|
|
|
if (status)
|
2007-05-16 13:10:58 +01:00
|
|
|
goto BAIL;
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
|
|
|
|
}
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2007-05-16 13:10:58 +01:00
|
|
|
BAIL:
|
|
|
|
|
free (allstops);
|
|
|
|
|
return status;
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
|
|
|
|
|
2007-10-14 19:04:33 +09:30
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_emit_repeating_function (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_gradient_pattern_t *pattern,
|
|
|
|
|
cairo_pdf_resource_t *function,
|
|
|
|
|
int begin,
|
|
|
|
|
int end)
|
|
|
|
|
{
|
|
|
|
|
cairo_pdf_resource_t res;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
res = _cairo_pdf_surface_new_object (surface);
|
|
|
|
|
if (res.id == 0)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /FunctionType 3\n"
|
|
|
|
|
" /Domain [ %d %d ]\n",
|
2007-10-14 19:04:33 +09:30
|
|
|
res.id,
|
|
|
|
|
begin,
|
|
|
|
|
end);
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
" /Functions [ ");
|
|
|
|
|
for (i = begin; i < end; i++)
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
"%d 0 R ", function->id);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"]\n");
|
2007-10-14 19:04:33 +09:30
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
" /Bounds [ ");
|
|
|
|
|
for (i = begin + 1; i < end; i++)
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
"%d ", i);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"]\n");
|
2007-10-14 19:04:33 +09:30
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
" /Encode [ ");
|
|
|
|
|
for (i = begin; i < end; i++) {
|
|
|
|
|
if ((i % 2) && pattern->base.extend == CAIRO_EXTEND_REFLECT) {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
"1 0 ");
|
|
|
|
|
} else {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
"0 1 ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"]\n");
|
2007-10-14 19:04:33 +09:30
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2007-10-14 19:04:33 +09:30
|
|
|
|
|
|
|
|
*function = res;
|
|
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2007-10-14 19:04:33 +09:30
|
|
|
}
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
static cairo_status_t
|
2007-04-27 09:49:45 -07:00
|
|
|
cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t *surface,
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_pdf_resource_t gstate_resource,
|
|
|
|
|
cairo_pdf_resource_t gradient_mask)
|
2007-04-27 09:49:45 -07:00
|
|
|
{
|
2008-01-16 16:33:22 +00:00
|
|
|
cairo_pdf_resource_t smask_resource;
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_status_t status;
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
status = _cairo_pdf_surface_open_stream (surface,
|
|
|
|
|
NULL,
|
|
|
|
|
surface->compress_content,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Type /XObject\n"
|
|
|
|
|
" /Subtype /Form\n"
|
|
|
|
|
" /FormType 1\n"
|
|
|
|
|
" /BBox [ 0 0 %f %f ]\n"
|
|
|
|
|
" /Resources\n"
|
|
|
|
|
" << /ExtGState\n"
|
2008-01-16 16:33:22 +00:00
|
|
|
" << /a0 << /ca 1 /CA 1 >>"
|
2008-02-20 21:05:23 +10:30
|
|
|
" >>\n"
|
|
|
|
|
" /Pattern\n"
|
|
|
|
|
" << /p%d %d 0 R >>\n"
|
|
|
|
|
" >>\n"
|
|
|
|
|
" /Group\n"
|
|
|
|
|
" << /Type /Group\n"
|
|
|
|
|
" /S /Transparency\n"
|
|
|
|
|
" /CS /DeviceGray\n"
|
|
|
|
|
" >>\n",
|
2008-01-16 16:33:22 +00:00
|
|
|
surface->width,
|
|
|
|
|
surface->height,
|
|
|
|
|
gradient_mask.id,
|
|
|
|
|
gradient_mask.id);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-04-27 09:49:45 -07:00
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"q\n"
|
|
|
|
|
"/a0 gs\n"
|
|
|
|
|
"/Pattern cs /p%d scn\n"
|
|
|
|
|
"0 0 %f %f re\n"
|
|
|
|
|
"f\n"
|
|
|
|
|
"Q\n",
|
2007-04-27 09:49:45 -07:00
|
|
|
gradient_mask.id,
|
|
|
|
|
surface->width,
|
|
|
|
|
surface->height);
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_close_stream (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-04-27 09:49:45 -07:00
|
|
|
|
|
|
|
|
smask_resource = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (smask_resource.id == 0)
|
2008-01-07 20:55:56 +10:30
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2007-10-04 21:17:31 +01:00
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Mask\n"
|
|
|
|
|
" /S /Luminosity\n"
|
|
|
|
|
" /G %d 0 R\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n",
|
2007-04-27 09:49:45 -07:00
|
|
|
smask_resource.id,
|
2008-01-16 16:33:22 +00:00
|
|
|
surface->pdf_stream.self.id);
|
2007-04-27 09:49:45 -07:00
|
|
|
|
|
|
|
|
/* Create GState which uses the transparency group as an SMask. */
|
2008-01-07 20:55:56 +10:30
|
|
|
_cairo_pdf_surface_update_object (surface, gstate_resource);
|
2007-10-04 21:17:31 +01:00
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /ExtGState\n"
|
|
|
|
|
" /SMask %d 0 R\n"
|
|
|
|
|
" /ca 1\n"
|
|
|
|
|
" /CA 1\n"
|
|
|
|
|
" /AIS false\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n",
|
2007-04-27 09:49:45 -07:00
|
|
|
gstate_resource.id,
|
|
|
|
|
smask_resource.id);
|
|
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
2005-10-07 13:21:01 +00:00
|
|
|
static cairo_status_t
|
2007-04-27 09:49:45 -07:00
|
|
|
_cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_pdf_pattern_t *pdf_pattern)
|
2005-01-05 14:29:31 +00:00
|
|
|
{
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_linear_pattern_t *pattern = (cairo_linear_pattern_t *) pdf_pattern->pattern;
|
2007-04-27 09:49:45 -07:00
|
|
|
cairo_pdf_resource_t color_function, alpha_function;
|
2007-04-27 16:01:56 -07:00
|
|
|
double x1, y1, x2, y2;
|
2007-10-14 19:04:33 +09:30
|
|
|
double _x1, _y1, _x2, _y2;
|
2007-04-27 16:01:56 -07:00
|
|
|
cairo_matrix_t pat_to_pdf;
|
2007-04-27 09:49:45 -07:00
|
|
|
cairo_extend_t extend;
|
2007-03-28 15:50:12 +01:00
|
|
|
cairo_status_t status;
|
2007-08-28 23:40:18 +09:30
|
|
|
cairo_gradient_pattern_t *gradient = &pattern->base;
|
|
|
|
|
double first_stop, last_stop;
|
2007-10-14 19:04:33 +09:30
|
|
|
int repeat_begin = 0, repeat_end = 1;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
assert (pattern->base.n_stops != 0);
|
2008-01-06 16:15:32 +10:30
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
extend = cairo_pattern_get_extend (pdf_pattern->pattern);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2007-04-27 16:01:56 -07:00
|
|
|
pat_to_pdf = pattern->base.base.matrix;
|
|
|
|
|
status = cairo_matrix_invert (&pat_to_pdf);
|
2007-07-16 09:36:54 +01:00
|
|
|
/* cairo_pattern_set_matrix ensures the matrix is invertible */
|
|
|
|
|
assert (status == CAIRO_STATUS_SUCCESS);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2007-04-27 16:01:56 -07:00
|
|
|
cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
|
2008-03-26 11:31:04 -07:00
|
|
|
first_stop = gradient->stops[0].offset;
|
|
|
|
|
last_stop = gradient->stops[gradient->n_stops - 1].offset;
|
2007-08-28 23:40:18 +09:30
|
|
|
|
2007-10-14 19:04:33 +09:30
|
|
|
if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
|
|
|
|
|
pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
|
|
|
|
|
double dx, dy;
|
|
|
|
|
int x_rep = 0, y_rep = 0;
|
|
|
|
|
|
|
|
|
|
x1 = _cairo_fixed_to_double (pattern->p1.x);
|
|
|
|
|
y1 = _cairo_fixed_to_double (pattern->p1.y);
|
|
|
|
|
cairo_matrix_transform_point (&pat_to_pdf, &x1, &y1);
|
|
|
|
|
|
|
|
|
|
x2 = _cairo_fixed_to_double (pattern->p2.x);
|
|
|
|
|
y2 = _cairo_fixed_to_double (pattern->p2.y);
|
|
|
|
|
cairo_matrix_transform_point (&pat_to_pdf, &x2, &y2);
|
|
|
|
|
|
|
|
|
|
dx = fabs (x2 - x1);
|
|
|
|
|
dy = fabs (y2 - y1);
|
|
|
|
|
if (dx > 1e-6)
|
|
|
|
|
x_rep = (int) ceil (surface->width/dx);
|
|
|
|
|
if (dy > 1e-6)
|
|
|
|
|
y_rep = (int) ceil (surface->height/dy);
|
|
|
|
|
|
|
|
|
|
repeat_end = MAX (x_rep, y_rep);
|
|
|
|
|
repeat_begin = -repeat_end;
|
|
|
|
|
first_stop = repeat_begin;
|
|
|
|
|
last_stop = repeat_end;
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-28 23:40:18 +09:30
|
|
|
/* PDF requires the first and last stop to be the same as the line
|
2007-10-14 19:04:33 +09:30
|
|
|
* coordinates. For repeating patterns this moves the line
|
|
|
|
|
* coordinates out to the begin/end of the repeating function. For
|
|
|
|
|
* non repeating patterns this may move the line coordinates in if
|
|
|
|
|
* there are not stops at offset 0 and 1. */
|
|
|
|
|
x1 = _cairo_fixed_to_double (pattern->p1.x);
|
|
|
|
|
y1 = _cairo_fixed_to_double (pattern->p1.y);
|
|
|
|
|
x2 = _cairo_fixed_to_double (pattern->p2.x);
|
|
|
|
|
y2 = _cairo_fixed_to_double (pattern->p2.y);
|
2007-08-28 23:40:18 +09:30
|
|
|
|
2007-10-14 19:04:33 +09:30
|
|
|
_x1 = x1 + (x2 - x1)*first_stop;
|
|
|
|
|
_y1 = y1 + (y2 - y1)*first_stop;
|
|
|
|
|
_x2 = x1 + (x2 - x1)*last_stop;
|
|
|
|
|
_y2 = y1 + (y2 - y1)*last_stop;
|
|
|
|
|
|
|
|
|
|
x1 = _x1;
|
|
|
|
|
x2 = _x2;
|
|
|
|
|
y1 = _y1;
|
|
|
|
|
y2 = _y2;
|
|
|
|
|
|
|
|
|
|
/* For EXTEND_NONE and EXTEND_PAD if there are only two stops a
|
|
|
|
|
* Type 2 function is used by itself without a stitching
|
|
|
|
|
* function. Type 2 functions always have the domain [0 1] */
|
|
|
|
|
if ((pattern->base.base.extend == CAIRO_EXTEND_NONE ||
|
|
|
|
|
pattern->base.base.extend == CAIRO_EXTEND_PAD) &&
|
|
|
|
|
gradient->n_stops == 2) {
|
|
|
|
|
first_stop = 0.0;
|
|
|
|
|
last_stop = 1.0;
|
|
|
|
|
}
|
2007-08-28 23:40:18 +09:30
|
|
|
|
2007-10-14 19:04:33 +09:30
|
|
|
status = _cairo_pdf_surface_emit_pattern_stops (surface,
|
|
|
|
|
&pattern->base,
|
|
|
|
|
&color_function,
|
|
|
|
|
&alpha_function);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-08-28 23:40:18 +09:30
|
|
|
|
2007-10-14 19:04:33 +09:30
|
|
|
if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
|
|
|
|
|
pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
|
|
|
|
|
status = _cairo_pdf_surface_emit_repeating_function (surface,
|
|
|
|
|
&pattern->base,
|
|
|
|
|
&color_function,
|
|
|
|
|
repeat_begin,
|
|
|
|
|
repeat_end);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-08-28 23:40:18 +09:30
|
|
|
|
2007-10-14 19:04:33 +09:30
|
|
|
if (alpha_function.id != 0) {
|
|
|
|
|
status = _cairo_pdf_surface_emit_repeating_function (surface,
|
|
|
|
|
&pattern->base,
|
|
|
|
|
&alpha_function,
|
|
|
|
|
repeat_begin,
|
|
|
|
|
repeat_end);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
}
|
2007-08-28 23:40:18 +09:30
|
|
|
}
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
_cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Pattern\n"
|
|
|
|
|
" /PatternType 2\n"
|
|
|
|
|
" /Matrix [ %f %f %f %f %f %f ]\n"
|
|
|
|
|
" /Shading\n"
|
|
|
|
|
" << /ShadingType 2\n"
|
|
|
|
|
" /ColorSpace /DeviceRGB\n"
|
|
|
|
|
" /Coords [ %f %f %f %f ]\n"
|
|
|
|
|
" /Domain [ %f %f ]\n"
|
|
|
|
|
" /Function %d 0 R\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
pdf_pattern->pattern_res.id,
|
2007-04-27 16:01:56 -07:00
|
|
|
pat_to_pdf.xx, pat_to_pdf.yx,
|
|
|
|
|
pat_to_pdf.xy, pat_to_pdf.yy,
|
|
|
|
|
pat_to_pdf.x0, pat_to_pdf.y0,
|
|
|
|
|
x1, y1, x2, y2,
|
2007-08-28 23:40:18 +09:30
|
|
|
first_stop, last_stop,
|
2007-04-27 09:49:45 -07:00
|
|
|
color_function.id);
|
|
|
|
|
|
|
|
|
|
if (extend == CAIRO_EXTEND_PAD) {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Extend [ true true ]\n");
|
2007-04-27 09:49:45 -07:00
|
|
|
} else {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Extend [ false false ]\n");
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
2006-05-12 14:56:11 -07:00
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" >>\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
if (alpha_function.id != 0) {
|
|
|
|
|
cairo_pdf_resource_t mask_resource;
|
|
|
|
|
|
|
|
|
|
assert (pdf_pattern->gstate_res.id != 0);
|
2007-04-27 09:49:45 -07:00
|
|
|
|
|
|
|
|
/* Create pattern for SMask. */
|
|
|
|
|
mask_resource = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (mask_resource.id == 0)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Pattern\n"
|
|
|
|
|
" /PatternType 2\n"
|
|
|
|
|
" /Matrix [ %f %f %f %f %f %f ]\n"
|
|
|
|
|
" /Shading\n"
|
|
|
|
|
" << /ShadingType 2\n"
|
|
|
|
|
" /ColorSpace /DeviceGray\n"
|
|
|
|
|
" /Coords [ %f %f %f %f ]\n"
|
|
|
|
|
" /Domain [ %f %f ]\n"
|
|
|
|
|
" /Function %d 0 R\n",
|
2007-04-27 09:49:45 -07:00
|
|
|
mask_resource.id,
|
2007-04-27 16:01:56 -07:00
|
|
|
pat_to_pdf.xx, pat_to_pdf.yx,
|
|
|
|
|
pat_to_pdf.xy, pat_to_pdf.yy,
|
|
|
|
|
pat_to_pdf.x0, pat_to_pdf.y0,
|
|
|
|
|
x1, y1, x2, y2,
|
2007-10-14 19:04:33 +09:30
|
|
|
first_stop, last_stop,
|
2007-04-27 09:49:45 -07:00
|
|
|
alpha_function.id);
|
|
|
|
|
|
|
|
|
|
if (extend == CAIRO_EXTEND_PAD) {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Extend [ true true ]\n");
|
2007-04-27 09:49:45 -07:00
|
|
|
} else {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Extend [ false false ]\n");
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" >>\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2007-04-27 09:49:45 -07:00
|
|
|
status = _cairo_pdf_surface_add_pattern (surface, mask_resource);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2008-01-10 15:53:54 +00:00
|
|
|
status = cairo_pdf_surface_emit_transparency_group (surface,
|
|
|
|
|
pdf_pattern->gstate_res,
|
|
|
|
|
mask_resource);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
2008-01-10 15:53:54 +00:00
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
2006-05-12 14:56:11 -07:00
|
|
|
|
2005-10-07 13:21:01 +00:00
|
|
|
static cairo_status_t
|
2007-04-27 09:49:45 -07:00
|
|
|
_cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface,
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_pdf_pattern_t *pdf_pattern)
|
2005-01-05 14:29:31 +00:00
|
|
|
{
|
2007-04-27 09:49:45 -07:00
|
|
|
cairo_pdf_resource_t color_function, alpha_function;
|
2007-04-27 16:01:56 -07:00
|
|
|
double x1, y1, x2, y2, r1, r2;
|
|
|
|
|
cairo_matrix_t pat_to_pdf;
|
2007-04-27 09:49:45 -07:00
|
|
|
cairo_extend_t extend;
|
2007-04-08 21:26:33 +01:00
|
|
|
cairo_status_t status;
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_radial_pattern_t *pattern = (cairo_radial_pattern_t *) pdf_pattern->pattern;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
assert (pattern->base.n_stops != 0);
|
2008-01-06 16:15:32 +10:30
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
extend = cairo_pattern_get_extend (pdf_pattern->pattern);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
status = _cairo_pdf_surface_emit_pattern_stops (surface,
|
|
|
|
|
&pattern->base,
|
|
|
|
|
&color_function,
|
|
|
|
|
&alpha_function);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2007-04-27 16:01:56 -07:00
|
|
|
pat_to_pdf = pattern->base.base.matrix;
|
|
|
|
|
status = cairo_matrix_invert (&pat_to_pdf);
|
2007-07-16 09:36:54 +01:00
|
|
|
/* cairo_pattern_set_matrix ensures the matrix is invertible */
|
|
|
|
|
assert (status == CAIRO_STATUS_SUCCESS);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2007-04-27 16:01:56 -07:00
|
|
|
cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
|
2007-06-13 00:15:34 -04:00
|
|
|
x1 = _cairo_fixed_to_double (pattern->c1.x);
|
|
|
|
|
y1 = _cairo_fixed_to_double (pattern->c1.y);
|
2007-06-18 17:29:04 -07:00
|
|
|
r1 = _cairo_fixed_to_double (pattern->r1);
|
2007-06-13 00:15:34 -04:00
|
|
|
x2 = _cairo_fixed_to_double (pattern->c2.x);
|
|
|
|
|
y2 = _cairo_fixed_to_double (pattern->c2.y);
|
2007-06-18 17:29:04 -07:00
|
|
|
r2 = _cairo_fixed_to_double (pattern->r2);
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
_cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
|
2007-10-04 21:17:31 +01:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Pattern\n"
|
|
|
|
|
" /PatternType 2\n"
|
|
|
|
|
" /Matrix [ %f %f %f %f %f %f ]\n"
|
|
|
|
|
" /Shading\n"
|
|
|
|
|
" << /ShadingType 3\n"
|
|
|
|
|
" /ColorSpace /DeviceRGB\n"
|
|
|
|
|
" /Coords [ %f %f %f %f %f %f ]\n"
|
|
|
|
|
" /Function %d 0 R\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
pdf_pattern->pattern_res.id,
|
2007-04-27 16:01:56 -07:00
|
|
|
pat_to_pdf.xx, pat_to_pdf.yx,
|
|
|
|
|
pat_to_pdf.xy, pat_to_pdf.yy,
|
|
|
|
|
pat_to_pdf.x0, pat_to_pdf.y0,
|
|
|
|
|
x1, y1, r1, x2, y2, r2,
|
2007-04-27 09:49:45 -07:00
|
|
|
color_function.id);
|
|
|
|
|
|
|
|
|
|
if (extend == CAIRO_EXTEND_PAD) {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Extend [ true true ]\n");
|
2007-04-27 09:49:45 -07:00
|
|
|
} else {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Extend [ false false ]\n");
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
2006-05-12 14:56:11 -07:00
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" >>\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
if (alpha_function.id != 0) {
|
|
|
|
|
cairo_pdf_resource_t mask_resource;
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
assert (pdf_pattern->gstate_res.id != 0);
|
|
|
|
|
|
|
|
|
|
/* Create pattern for SMask. */
|
2007-04-27 09:49:45 -07:00
|
|
|
mask_resource = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (mask_resource.id == 0)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Pattern\n"
|
|
|
|
|
" /PatternType 2\n"
|
|
|
|
|
" /Matrix [ %f %f %f %f %f %f ]\n"
|
|
|
|
|
" /Shading\n"
|
|
|
|
|
" << /ShadingType 3\n"
|
|
|
|
|
" /ColorSpace /DeviceGray\n"
|
|
|
|
|
" /Coords [ %f %f %f %f %f %f ]\n"
|
|
|
|
|
" /Function %d 0 R\n",
|
2007-04-27 09:49:45 -07:00
|
|
|
mask_resource.id,
|
2007-04-27 16:01:56 -07:00
|
|
|
pat_to_pdf.xx, pat_to_pdf.yx,
|
|
|
|
|
pat_to_pdf.xy, pat_to_pdf.yy,
|
|
|
|
|
pat_to_pdf.x0, pat_to_pdf.y0,
|
|
|
|
|
x1, y1, r1, x2, y2, r2,
|
2007-04-27 09:49:45 -07:00
|
|
|
alpha_function.id);
|
|
|
|
|
|
|
|
|
|
if (extend == CAIRO_EXTEND_PAD) {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Extend [ true true ]\n");
|
2007-04-27 09:49:45 -07:00
|
|
|
} else {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Extend [ false false ]\n");
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" >>\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2008-01-10 15:53:54 +00:00
|
|
|
status = cairo_pdf_surface_emit_transparency_group (surface,
|
|
|
|
|
pdf_pattern->gstate_res,
|
|
|
|
|
mask_resource);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
|
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
2006-04-18 16:53:23 -07:00
|
|
|
|
2005-10-07 13:21:01 +00:00
|
|
|
static cairo_status_t
|
2008-01-07 20:55:56 +10:30
|
|
|
_cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern_t *pdf_pattern)
|
2005-02-01 20:47:43 +00:00
|
|
|
{
|
2008-02-02 20:59:56 +10:30
|
|
|
double old_width, old_height;
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
|
|
|
|
|
old_width = surface->width;
|
|
|
|
|
old_height = surface->height;
|
2008-04-07 13:03:58 -07:00
|
|
|
_cairo_pdf_surface_set_size_internal (surface,
|
|
|
|
|
pdf_pattern->width,
|
|
|
|
|
pdf_pattern->height);
|
2008-02-02 20:59:56 +10:30
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
switch (pdf_pattern->pattern->type) {
|
2006-02-24 15:25:19 -08:00
|
|
|
case CAIRO_PATTERN_TYPE_SOLID:
|
2008-01-07 20:55:56 +10:30
|
|
|
ASSERT_NOT_REACHED;
|
2008-02-02 20:59:56 +10:30
|
|
|
status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
|
2008-01-07 20:55:56 +10:30
|
|
|
break;
|
2005-02-01 20:47:43 +00:00
|
|
|
|
2006-02-24 15:25:19 -08:00
|
|
|
case CAIRO_PATTERN_TYPE_SURFACE:
|
2008-02-02 20:59:56 +10:30
|
|
|
status = _cairo_pdf_surface_emit_surface_pattern (surface, pdf_pattern);
|
|
|
|
|
break;
|
2005-02-01 20:47:43 +00:00
|
|
|
|
2006-02-24 15:25:19 -08:00
|
|
|
case CAIRO_PATTERN_TYPE_LINEAR:
|
2008-02-02 20:59:56 +10:30
|
|
|
status = _cairo_pdf_surface_emit_linear_pattern (surface, pdf_pattern);
|
|
|
|
|
break;
|
2005-02-01 20:47:43 +00:00
|
|
|
|
2006-02-24 15:25:19 -08:00
|
|
|
case CAIRO_PATTERN_TYPE_RADIAL:
|
2008-02-02 20:59:56 +10:30
|
|
|
status = _cairo_pdf_surface_emit_radial_pattern (surface, pdf_pattern);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ASSERT_NOT_REACHED;
|
|
|
|
|
status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
|
|
|
|
|
break;
|
2005-02-01 20:47:43 +00:00
|
|
|
}
|
2005-10-07 13:21:01 +00:00
|
|
|
|
2008-04-07 13:03:58 -07:00
|
|
|
_cairo_pdf_surface_set_size_internal (surface,
|
|
|
|
|
old_width,
|
|
|
|
|
old_height);
|
2008-02-02 20:59:56 +10:30
|
|
|
|
|
|
|
|
return status;
|
2005-02-01 20:47:43 +00:00
|
|
|
}
|
|
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_pattern_t *pattern,
|
|
|
|
|
cairo_pdf_resource_t pattern_res,
|
|
|
|
|
cairo_bool_t is_stroke)
|
2007-04-27 09:49:45 -07:00
|
|
|
{
|
2007-08-25 06:44:08 +09:30
|
|
|
cairo_status_t status;
|
|
|
|
|
int alpha;
|
2008-04-27 17:32:41 +09:30
|
|
|
cairo_bool_t is_solid_color = FALSE;
|
|
|
|
|
cairo_color_t *solid_color;
|
2007-08-25 06:44:08 +09:30
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
|
2008-04-27 17:32:41 +09:30
|
|
|
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
|
|
|
|
|
|
|
|
|
|
is_solid_color = TRUE;
|
|
|
|
|
solid_color = &solid->color;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
|
|
|
|
|
pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
|
|
|
|
|
{
|
|
|
|
|
cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
|
|
|
|
|
|
|
|
|
|
if (gradient->n_stops == 1) {
|
|
|
|
|
is_solid_color = TRUE;
|
|
|
|
|
solid_color = &gradient->stops[0].color;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-01-07 20:55:56 +10:30
|
|
|
|
2008-04-27 17:32:41 +09:30
|
|
|
if (is_solid_color) {
|
2008-06-03 20:55:30 +09:30
|
|
|
if (surface->current_pattern_is_solid_color == FALSE ||
|
|
|
|
|
surface->current_color_red != solid_color->red ||
|
|
|
|
|
surface->current_color_green != solid_color->green ||
|
|
|
|
|
surface->current_color_blue != solid_color->blue ||
|
|
|
|
|
surface->current_color_is_stroke != is_stroke)
|
|
|
|
|
{
|
|
|
|
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-10-04 23:18:33 +01:00
|
|
|
|
2008-06-03 20:55:30 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
"%f %f %f ",
|
|
|
|
|
solid_color->red,
|
|
|
|
|
solid_color->green,
|
|
|
|
|
solid_color->blue);
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2008-06-03 20:55:30 +09:30
|
|
|
if (is_stroke)
|
|
|
|
|
_cairo_output_stream_printf (surface->output, "RG ");
|
|
|
|
|
else
|
|
|
|
|
_cairo_output_stream_printf (surface->output, "rg ");
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2008-06-03 20:55:30 +09:30
|
|
|
surface->current_color_red = solid_color->red;
|
|
|
|
|
surface->current_color_green = solid_color->green;
|
|
|
|
|
surface->current_color_blue = solid_color->blue;
|
|
|
|
|
surface->current_color_is_stroke = is_stroke;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (surface->current_pattern_is_solid_color == FALSE ||
|
|
|
|
|
surface->current_color_alpha != solid_color->alpha)
|
|
|
|
|
{
|
|
|
|
|
status = _cairo_pdf_surface_add_alpha (surface, solid_color->alpha, &alpha);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
"/a%d gs\n",
|
|
|
|
|
alpha);
|
|
|
|
|
surface->current_color_alpha = solid_color->alpha;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
surface->current_pattern_is_solid_color = TRUE;
|
2007-04-27 09:49:45 -07:00
|
|
|
} else {
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
|
2007-10-04 23:18:33 +01:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_pattern (surface, pattern_res);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2008-06-03 20:55:30 +09:30
|
|
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-02-17 19:48:01 +10:30
|
|
|
/* fill-stroke calls select_pattern twice. Don't save if the
|
|
|
|
|
* gstate is already saved. */
|
|
|
|
|
if (!surface->select_pattern_gstate_saved)
|
|
|
|
|
_cairo_output_stream_printf (surface->output, "q ");
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
if (is_stroke) {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-17 19:48:01 +10:30
|
|
|
"/Pattern CS /p%d SCN ",
|
2008-01-07 20:55:56 +10:30
|
|
|
pattern_res.id);
|
|
|
|
|
} else {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-17 19:48:01 +10:30
|
|
|
"/Pattern cs /p%d scn ",
|
2008-01-07 20:55:56 +10:30
|
|
|
pattern_res.id);
|
|
|
|
|
}
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"/a%d gs\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
alpha);
|
2008-02-17 19:45:45 +10:30
|
|
|
surface->select_pattern_gstate_saved = TRUE;
|
2008-06-03 20:55:30 +09:30
|
|
|
surface->current_pattern_is_solid_color = FALSE;
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
|
|
|
|
|
2007-10-04 23:18:33 +01:00
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
|
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
static cairo_int_status_t
|
2008-01-07 20:55:56 +10:30
|
|
|
_cairo_pdf_surface_unselect_pattern (cairo_pdf_surface_t *surface)
|
|
|
|
|
{
|
2008-06-03 20:55:03 +09:30
|
|
|
cairo_int_status_t status;
|
|
|
|
|
|
|
|
|
|
if (surface->select_pattern_gstate_saved) {
|
|
|
|
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-02-20 21:05:23 +10:30
|
|
|
_cairo_output_stream_printf (surface->output, "Q\n");
|
2008-07-08 22:00:15 +09:30
|
|
|
_cairo_pdf_operators_reset (&surface->pdf_operators);
|
2008-06-03 20:55:03 +09:30
|
|
|
}
|
2008-02-17 19:48:01 +10:30
|
|
|
surface->select_pattern_gstate_saved = FALSE;
|
2008-06-03 20:55:03 +09:30
|
|
|
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2008-01-07 20:55:56 +10:30
|
|
|
}
|
|
|
|
|
|
2005-01-05 14:29:31 +00:00
|
|
|
static cairo_int_status_t
|
|
|
|
|
_cairo_pdf_surface_show_page (void *abstract_surface)
|
|
|
|
|
{
|
|
|
|
|
cairo_pdf_surface_t *surface = abstract_surface;
|
|
|
|
|
cairo_int_status_t status;
|
|
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
status = _cairo_pdf_surface_close_content_stream (surface);
|
2007-10-04 23:15:21 +01:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-08-25 06:44:08 +09:30
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
status = _cairo_pdf_surface_write_page (surface);
|
2005-06-10 12:46:49 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2005-06-10 12:46:49 +00:00
|
|
|
_cairo_pdf_surface_clear (surface);
|
|
|
|
|
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-19 16:29:04 +00:00
|
|
|
static cairo_int_status_t
|
2006-05-04 03:43:34 -07:00
|
|
|
_cairo_pdf_surface_get_extents (void *abstract_surface,
|
2007-06-18 16:56:24 -07:00
|
|
|
cairo_rectangle_int_t *rectangle)
|
2005-04-19 16:29:04 +00:00
|
|
|
{
|
|
|
|
|
cairo_pdf_surface_t *surface = abstract_surface;
|
|
|
|
|
|
|
|
|
|
rectangle->x = 0;
|
|
|
|
|
rectangle->y = 0;
|
|
|
|
|
|
|
|
|
|
/* XXX: The conversion to integers here is pretty bogus, (not to
|
2008-01-16 16:33:22 +00:00
|
|
|
* mention the arbitrary limitation of width to a short(!). We
|
2005-04-19 16:29:04 +00:00
|
|
|
* may need to come up with a better interface for get_size.
|
|
|
|
|
*/
|
2005-05-13 09:26:20 +00:00
|
|
|
rectangle->width = (int) ceil (surface->width);
|
|
|
|
|
rectangle->height = (int) ceil (surface->height);
|
2005-04-19 16:29:04 +00:00
|
|
|
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
static cairo_int_status_t
|
|
|
|
|
_cairo_pdf_surface_intersect_clip_path (void *abstract_surface,
|
|
|
|
|
cairo_path_fixed_t *path,
|
|
|
|
|
cairo_fill_rule_t fill_rule,
|
|
|
|
|
double tolerance,
|
|
|
|
|
cairo_antialias_t antialias)
|
|
|
|
|
{
|
|
|
|
|
cairo_pdf_surface_t *surface = abstract_surface;
|
2008-06-03 20:55:03 +09:30
|
|
|
cairo_int_status_t status;
|
2005-06-14 19:45:22 +00:00
|
|
|
|
2008-01-07 20:59:22 +10:30
|
|
|
if (path == NULL) {
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-02-20 21:05:23 +10:30
|
|
|
_cairo_output_stream_printf (surface->output, "Q q\n");
|
2008-06-03 20:55:30 +09:30
|
|
|
surface->current_pattern_is_solid_color = FALSE;
|
2008-07-08 22:00:15 +09:30
|
|
|
_cairo_pdf_operators_reset (&surface->pdf_operators);
|
2008-06-03 20:55:30 +09:30
|
|
|
|
2008-01-07 20:59:22 +10:30
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule);
|
2005-06-14 19:45:22 +00:00
|
|
|
}
|
|
|
|
|
|
2005-07-21 06:52:13 +00:00
|
|
|
static void
|
|
|
|
|
_cairo_pdf_surface_get_font_options (void *abstract_surface,
|
|
|
|
|
cairo_font_options_t *options)
|
|
|
|
|
{
|
2006-04-25 05:44:08 -07:00
|
|
|
_cairo_font_options_init_default (options);
|
2005-07-21 06:52:13 +00:00
|
|
|
|
2006-04-25 05:44:08 -07:00
|
|
|
cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
|
|
|
|
|
cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
|
2006-08-08 06:04:01 -04:00
|
|
|
cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
|
2005-07-21 06:52:13 +00:00
|
|
|
}
|
|
|
|
|
|
2006-05-12 13:31:12 -07:00
|
|
|
static cairo_pdf_resource_t
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_write_info (cairo_pdf_surface_t *surface)
|
2005-01-05 14:29:31 +00:00
|
|
|
{
|
2006-05-12 13:31:12 -07:00
|
|
|
cairo_pdf_resource_t info;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
info = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (info.id == 0)
|
|
|
|
|
return info;
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Creator (cairo %s (http://cairographics.org))\n"
|
|
|
|
|
" /Producer (cairo %s (http://cairographics.org))\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n",
|
2006-10-15 23:11:30 +09:30
|
|
|
info.id,
|
|
|
|
|
cairo_version_string (),
|
|
|
|
|
cairo_version_string ());
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 13:31:12 -07:00
|
|
|
return info;
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface)
|
2005-01-05 14:29:31 +00:00
|
|
|
{
|
2007-08-25 06:44:08 +09:30
|
|
|
cairo_pdf_resource_t page;
|
|
|
|
|
int num_pages, i;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_update_object (surface, surface->pages_resource);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Pages\n"
|
2005-03-16 12:08:41 +00:00
|
|
|
" /Kids [ ",
|
2006-05-12 14:56:11 -07:00
|
|
|
surface->pages_resource.id);
|
|
|
|
|
|
|
|
|
|
num_pages = _cairo_array_num_elements (&surface->pages);
|
2005-01-05 14:29:31 +00:00
|
|
|
for (i = 0; i < num_pages; i++) {
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_array_copy_element (&surface->pages, i, &page);
|
|
|
|
|
_cairo_output_stream_printf (surface->output, "%d 0 R ", page.id);
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
2008-02-20 21:05:23 +10:30
|
|
|
_cairo_output_stream_printf (surface->output, "]\n");
|
|
|
|
|
_cairo_output_stream_printf (surface->output, " /Count %d\n", num_pages);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-15 10:00:18 -07:00
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
/* TODO: Figure out which other defaults to be inherited by /Page
|
2005-01-05 14:29:31 +00:00
|
|
|
* objects. */
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
2008-06-29 19:35:12 +09:30
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_emit_unicode_for_glyph (cairo_pdf_surface_t *surface,
|
|
|
|
|
const char *utf8)
|
|
|
|
|
{
|
|
|
|
|
uint16_t *utf16 = NULL;
|
|
|
|
|
int utf16_len = 0;
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (utf8 && *utf8) {
|
|
|
|
|
status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
|
2008-08-06 20:38:29 -04:00
|
|
|
if (status)
|
2008-06-29 19:35:12 +09:30
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output, "<");
|
|
|
|
|
if (utf16 == NULL || utf16_len == 0) {
|
|
|
|
|
/* According to the "ToUnicode Mapping File Tutorial"
|
|
|
|
|
* http://www.adobe.com/devnet/acrobat/pdfs/5411.ToUnicode.pdf
|
|
|
|
|
*
|
|
|
|
|
* Glyphs that do not map to a Unicode code point must be
|
|
|
|
|
* mapped to 0xfffd "REPLACEMENT CHARACTER".
|
|
|
|
|
*/
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
"fffd");
|
|
|
|
|
} else {
|
|
|
|
|
for (i = 0; i < utf16_len; i++)
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
"%04x", (int) (utf16[i]));
|
|
|
|
|
}
|
|
|
|
|
_cairo_output_stream_printf (surface->output, ">");
|
|
|
|
|
|
|
|
|
|
if (utf16)
|
|
|
|
|
free (utf16);
|
|
|
|
|
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-11 14:01:20 +01:00
|
|
|
static cairo_int_status_t
|
2007-04-10 13:53:58 -07:00
|
|
|
_cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
|
2007-04-20 22:44:04 +09:30
|
|
|
cairo_scaled_font_subset_t *font_subset,
|
2007-10-11 14:01:20 +01:00
|
|
|
cairo_bool_t is_composite,
|
|
|
|
|
cairo_pdf_resource_t *stream)
|
2007-02-07 22:35:59 +10:30
|
|
|
{
|
2007-04-20 22:44:04 +09:30
|
|
|
unsigned int i, num_bfchar;
|
2007-12-18 09:23:29 +00:00
|
|
|
cairo_int_status_t status;
|
2007-02-07 22:35:59 +10:30
|
|
|
|
2007-10-11 14:01:20 +01:00
|
|
|
stream->id = 0;
|
2007-02-07 22:35:59 +10:30
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
status = _cairo_pdf_surface_open_stream (surface,
|
2008-01-07 20:55:56 +10:30
|
|
|
NULL,
|
|
|
|
|
surface->compress_content,
|
|
|
|
|
NULL);
|
2008-01-16 16:33:22 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-10-04 21:17:31 +01:00
|
|
|
|
2007-02-07 22:35:59 +10:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"/CIDInit /ProcSet findresource begin\n"
|
|
|
|
|
"12 dict begin\n"
|
|
|
|
|
"begincmap\n"
|
|
|
|
|
"/CIDSystemInfo\n"
|
|
|
|
|
"<< /Registry (Adobe)\n"
|
|
|
|
|
" /Ordering (UCS)\n"
|
|
|
|
|
" /Supplement 0\n"
|
|
|
|
|
">> def\n"
|
|
|
|
|
"/CMapName /Adobe-Identity-UCS def\n"
|
|
|
|
|
"/CMapType 2 def\n"
|
|
|
|
|
"1 begincodespacerange\n");
|
2007-04-20 22:44:04 +09:30
|
|
|
|
|
|
|
|
if (is_composite) {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"<0000> <ffff>\n");
|
2007-04-20 22:44:04 +09:30
|
|
|
} else {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"<00> <ff>\n");
|
2007-04-20 22:44:04 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"endcodespacerange\n");
|
2007-02-07 22:35:59 +10:30
|
|
|
|
2007-04-20 22:44:04 +09:30
|
|
|
num_bfchar = font_subset->num_glyphs - 1;
|
2008-06-29 19:35:12 +09:30
|
|
|
|
2007-02-07 22:35:59 +10:30
|
|
|
/* The CMap specification has a limit of 100 characters per beginbfchar operator */
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d beginbfchar\n",
|
2007-04-20 22:44:04 +09:30
|
|
|
num_bfchar > 100 ? 100 : num_bfchar);
|
2008-06-29 19:35:12 +09:30
|
|
|
|
2007-04-20 22:44:04 +09:30
|
|
|
for (i = 0; i < num_bfchar; i++) {
|
2007-02-07 22:35:59 +10:30
|
|
|
if (i != 0 && i % 100 == 0) {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"endbfchar\n"
|
|
|
|
|
"%d beginbfchar\n",
|
2007-04-20 22:44:04 +09:30
|
|
|
num_bfchar - i > 100 ? 100 : num_bfchar - i);
|
|
|
|
|
}
|
|
|
|
|
if (is_composite) {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-06-29 19:35:12 +09:30
|
|
|
"<%04x> ",
|
|
|
|
|
i + 1);
|
2007-04-20 22:44:04 +09:30
|
|
|
} else {
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-06-29 19:35:12 +09:30
|
|
|
"<%02x> ",
|
|
|
|
|
i + 1);
|
2007-02-07 22:35:59 +10:30
|
|
|
}
|
2008-06-29 19:35:12 +09:30
|
|
|
_cairo_pdf_surface_emit_unicode_for_glyph (surface, font_subset->utf8[i + 1]);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
"\n");
|
2007-02-07 22:35:59 +10:30
|
|
|
}
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"endbfchar\n");
|
2007-02-07 22:35:59 +10:30
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"endcmap\n"
|
|
|
|
|
"CMapName currentdict /CMap defineresource pop\n"
|
|
|
|
|
"end\n"
|
|
|
|
|
"end\n");
|
2007-02-07 22:35:59 +10:30
|
|
|
|
2008-01-16 16:33:22 +00:00
|
|
|
*stream = surface->pdf_stream.self;
|
2007-10-11 14:01:20 +01:00
|
|
|
return _cairo_pdf_surface_close_stream (surface);
|
2007-02-07 22:35:59 +10:30
|
|
|
}
|
|
|
|
|
|
2006-10-27 00:00:24 +09:30
|
|
|
static cairo_status_t
|
2007-04-20 22:44:04 +09:30
|
|
|
_cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_scaled_font_subset_t *font_subset,
|
|
|
|
|
cairo_cff_subset_t *subset)
|
2006-10-27 00:00:24 +09:30
|
|
|
{
|
2007-04-20 22:44:04 +09:30
|
|
|
cairo_pdf_resource_t stream, descriptor, cidfont_dict;
|
|
|
|
|
cairo_pdf_resource_t subset_resource, to_unicode_stream;
|
2006-10-27 00:00:24 +09:30
|
|
|
cairo_pdf_font_t font;
|
|
|
|
|
unsigned int i;
|
2007-04-20 22:44:04 +09:30
|
|
|
cairo_status_t status;
|
2006-10-27 00:00:24 +09:30
|
|
|
|
2008-01-08 14:14:33 +00:00
|
|
|
subset_resource = _cairo_pdf_surface_get_font_resource (surface,
|
|
|
|
|
font_subset->font_id,
|
|
|
|
|
font_subset->subset_id);
|
|
|
|
|
if (subset_resource.id == 0)
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
|
2008-02-11 13:44:48 -05:00
|
|
|
status = _cairo_pdf_surface_open_stream (surface,
|
|
|
|
|
NULL,
|
|
|
|
|
TRUE,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Subtype /CIDFontType0C\n");
|
2008-02-11 13:44:48 -05:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-10-04 21:17:31 +01:00
|
|
|
|
2008-02-11 13:44:48 -05:00
|
|
|
stream = surface->pdf_stream.self;
|
|
|
|
|
_cairo_output_stream_write (surface->output,
|
|
|
|
|
subset->data, subset->data_length);
|
|
|
|
|
status = _cairo_pdf_surface_close_stream (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2006-10-27 00:00:24 +09:30
|
|
|
|
2007-10-11 14:01:20 +01:00
|
|
|
status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
|
|
|
|
|
font_subset, TRUE,
|
|
|
|
|
&to_unicode_stream);
|
|
|
|
|
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
|
|
|
|
|
return status;
|
2007-02-07 22:35:59 +10:30
|
|
|
|
2006-10-27 00:00:24 +09:30
|
|
|
descriptor = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (descriptor.id == 0)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
|
2006-10-27 00:00:24 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /FontDescriptor\n"
|
|
|
|
|
" /FontName /%s\n"
|
|
|
|
|
" /Flags 4\n"
|
|
|
|
|
" /FontBBox [ %ld %ld %ld %ld ]\n"
|
|
|
|
|
" /ItalicAngle 0\n"
|
|
|
|
|
" /Ascent %ld\n"
|
|
|
|
|
" /Descent %ld\n"
|
|
|
|
|
" /CapHeight 500\n"
|
|
|
|
|
" /StemV 80\n"
|
|
|
|
|
" /StemH 80\n"
|
|
|
|
|
" /FontFile3 %u 0 R\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n",
|
2006-10-27 00:00:24 +09:30
|
|
|
descriptor.id,
|
2007-04-20 22:44:04 +09:30
|
|
|
subset->base_font,
|
|
|
|
|
subset->x_min,
|
|
|
|
|
subset->y_min,
|
|
|
|
|
subset->x_max,
|
|
|
|
|
subset->y_max,
|
|
|
|
|
subset->ascent,
|
|
|
|
|
subset->descent,
|
2006-10-27 00:00:24 +09:30
|
|
|
stream.id);
|
|
|
|
|
|
2007-04-20 22:44:04 +09:30
|
|
|
cidfont_dict = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (cidfont_dict.id == 0)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
|
2006-10-27 00:00:24 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Font\n"
|
|
|
|
|
" /Subtype /CIDFontType0\n"
|
|
|
|
|
" /BaseFont /%s\n"
|
|
|
|
|
" /CIDSystemInfo\n"
|
|
|
|
|
" << /Registry (Adobe)\n"
|
|
|
|
|
" /Ordering (Identity)\n"
|
|
|
|
|
" /Supplement 0\n"
|
|
|
|
|
" >>\n"
|
|
|
|
|
" /FontDescriptor %d 0 R\n"
|
2007-04-20 22:44:04 +09:30
|
|
|
" /W [0 [",
|
|
|
|
|
cidfont_dict.id,
|
|
|
|
|
subset->base_font,
|
|
|
|
|
descriptor.id);
|
2006-10-27 00:00:24 +09:30
|
|
|
|
|
|
|
|
for (i = 0; i < font_subset->num_glyphs; i++)
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
" %d",
|
2007-04-20 22:44:04 +09:30
|
|
|
subset->widths[i]);
|
2006-10-27 00:00:24 +09:30
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" ]]\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2007-04-20 22:44:04 +09:30
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_pdf_surface_update_object (surface, subset_resource);
|
2007-04-20 22:44:04 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Font\n"
|
|
|
|
|
" /Subtype /Type0\n"
|
|
|
|
|
" /BaseFont /%s\n"
|
|
|
|
|
" /Encoding /Identity-H\n"
|
|
|
|
|
" /DescendantFonts [ %d 0 R]\n",
|
2007-04-20 22:44:04 +09:30
|
|
|
subset_resource.id,
|
|
|
|
|
subset->base_font,
|
|
|
|
|
cidfont_dict.id);
|
2007-02-07 22:35:59 +10:30
|
|
|
|
|
|
|
|
if (to_unicode_stream.id != 0)
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /ToUnicode %d 0 R\n",
|
2007-02-07 22:35:59 +10:30
|
|
|
to_unicode_stream.id);
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2006-10-27 00:00:24 +09:30
|
|
|
|
|
|
|
|
font.font_id = font_subset->font_id;
|
|
|
|
|
font.subset_id = font_subset->subset_id;
|
|
|
|
|
font.subset_resource = subset_resource;
|
2007-04-08 21:26:33 +01:00
|
|
|
status = _cairo_array_append (&surface->fonts, &font);
|
2006-10-27 00:00:24 +09:30
|
|
|
|
2007-04-20 22:44:04 +09:30
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_scaled_font_subset_t *font_subset)
|
|
|
|
|
{
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
cairo_cff_subset_t subset;
|
|
|
|
|
char name[64];
|
|
|
|
|
|
|
|
|
|
snprintf (name, sizeof name, "CairoFont-%d-%d",
|
|
|
|
|
font_subset->font_id, font_subset->subset_id);
|
|
|
|
|
status = _cairo_cff_subset_init (&subset, name, font_subset);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset);
|
|
|
|
|
|
2006-10-27 00:00:24 +09:30
|
|
|
_cairo_cff_subset_fini (&subset);
|
|
|
|
|
|
2007-04-08 21:26:33 +01:00
|
|
|
return status;
|
2006-10-27 00:00:24 +09:30
|
|
|
}
|
|
|
|
|
|
2007-04-20 22:44:04 +09:30
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_emit_cff_fallback_font (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_scaled_font_subset_t *font_subset)
|
|
|
|
|
{
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
cairo_cff_subset_t subset;
|
|
|
|
|
char name[64];
|
|
|
|
|
|
|
|
|
|
snprintf (name, sizeof name, "CairoFont-%d-%d",
|
|
|
|
|
font_subset->font_id, font_subset->subset_id);
|
|
|
|
|
status = _cairo_cff_fallback_init (&subset, name, font_subset);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset);
|
|
|
|
|
|
|
|
|
|
_cairo_cff_fallback_fini (&subset);
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-17 17:17:02 -04:00
|
|
|
static cairo_status_t
|
2006-09-05 15:57:47 -04:00
|
|
|
_cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_scaled_font_subset_t *font_subset,
|
|
|
|
|
cairo_type1_subset_t *subset)
|
2006-05-17 17:17:02 -04:00
|
|
|
{
|
2007-02-07 22:35:59 +10:30
|
|
|
cairo_pdf_resource_t stream, descriptor, subset_resource, to_unicode_stream;
|
2006-05-17 17:17:02 -04:00
|
|
|
cairo_pdf_font_t font;
|
2007-10-11 14:01:20 +01:00
|
|
|
cairo_status_t status;
|
2008-02-11 13:44:48 -05:00
|
|
|
unsigned long length;
|
2006-08-07 15:18:38 -07:00
|
|
|
unsigned int i;
|
2006-05-17 17:17:02 -04:00
|
|
|
|
2008-01-08 14:14:33 +00:00
|
|
|
subset_resource = _cairo_pdf_surface_get_font_resource (surface,
|
|
|
|
|
font_subset->font_id,
|
|
|
|
|
font_subset->subset_id);
|
|
|
|
|
if (subset_resource.id == 0)
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2006-05-17 17:17:02 -04:00
|
|
|
|
|
|
|
|
/* We ignore the zero-trailer and set Length3 to 0. */
|
2008-02-12 20:19:03 +10:30
|
|
|
length = subset->header_length + subset->data_length;
|
2008-02-11 13:44:48 -05:00
|
|
|
status = _cairo_pdf_surface_open_stream (surface,
|
|
|
|
|
NULL,
|
|
|
|
|
TRUE,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Length1 %lu\n"
|
|
|
|
|
" /Length2 %lu\n"
|
|
|
|
|
" /Length3 0\n",
|
2008-02-11 13:44:48 -05:00
|
|
|
subset->header_length,
|
|
|
|
|
subset->data_length);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-10-04 21:17:31 +01:00
|
|
|
|
2008-02-11 13:44:48 -05:00
|
|
|
stream = surface->pdf_stream.self;
|
|
|
|
|
_cairo_output_stream_write (surface->output, subset->data, length);
|
|
|
|
|
status = _cairo_pdf_surface_close_stream (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2006-05-17 17:17:02 -04:00
|
|
|
|
2007-10-11 14:01:20 +01:00
|
|
|
status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
|
|
|
|
|
font_subset, FALSE,
|
|
|
|
|
&to_unicode_stream);
|
|
|
|
|
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
|
|
|
|
|
return status;
|
2007-02-07 22:35:59 +10:30
|
|
|
|
2006-05-17 17:17:02 -04:00
|
|
|
descriptor = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (descriptor.id == 0)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
|
2006-05-17 17:17:02 -04:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /FontDescriptor\n"
|
|
|
|
|
" /FontName /%s\n"
|
|
|
|
|
" /Flags 4\n"
|
|
|
|
|
" /FontBBox [ %ld %ld %ld %ld ]\n"
|
|
|
|
|
" /ItalicAngle 0\n"
|
|
|
|
|
" /Ascent %ld\n"
|
|
|
|
|
" /Descent %ld\n"
|
|
|
|
|
" /CapHeight 500\n"
|
|
|
|
|
" /StemV 80\n"
|
|
|
|
|
" /StemH 80\n"
|
|
|
|
|
" /FontFile %u 0 R\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n",
|
2006-05-17 17:17:02 -04:00
|
|
|
descriptor.id,
|
2006-09-05 15:57:47 -04:00
|
|
|
subset->base_font,
|
|
|
|
|
subset->x_min,
|
|
|
|
|
subset->y_min,
|
|
|
|
|
subset->x_max,
|
|
|
|
|
subset->y_max,
|
|
|
|
|
subset->ascent,
|
|
|
|
|
subset->descent,
|
2006-05-17 17:17:02 -04:00
|
|
|
stream.id);
|
|
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_pdf_surface_update_object (surface, subset_resource);
|
2006-05-17 17:17:02 -04:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Font\n"
|
|
|
|
|
" /Subtype /Type1\n"
|
|
|
|
|
" /BaseFont /%s\n"
|
|
|
|
|
" /FirstChar 0\n"
|
|
|
|
|
" /LastChar %d\n"
|
|
|
|
|
" /FontDescriptor %d 0 R\n"
|
2006-05-17 17:17:02 -04:00
|
|
|
" /Widths [",
|
|
|
|
|
subset_resource.id,
|
2006-09-05 15:57:47 -04:00
|
|
|
subset->base_font,
|
2006-09-05 14:19:48 -04:00
|
|
|
font_subset->num_glyphs - 1,
|
2006-05-17 17:17:02 -04:00
|
|
|
descriptor.id);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < font_subset->num_glyphs; i++)
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
" %d",
|
2006-09-05 15:57:47 -04:00
|
|
|
subset->widths[i]);
|
2006-05-17 17:17:02 -04:00
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" ]\n");
|
2007-02-07 22:35:59 +10:30
|
|
|
|
|
|
|
|
if (to_unicode_stream.id != 0)
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /ToUnicode %d 0 R\n",
|
2007-02-07 22:35:59 +10:30
|
|
|
to_unicode_stream.id);
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2006-05-17 17:17:02 -04:00
|
|
|
|
|
|
|
|
font.font_id = font_subset->font_id;
|
|
|
|
|
font.subset_id = font_subset->subset_id;
|
|
|
|
|
font.subset_resource = subset_resource;
|
2007-04-08 21:26:33 +01:00
|
|
|
return _cairo_array_append (&surface->fonts, &font);
|
2006-05-17 17:17:02 -04:00
|
|
|
}
|
2006-09-05 15:57:47 -04:00
|
|
|
|
|
|
|
|
#if CAIRO_HAS_FT_FONT
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_emit_type1_font_subset (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_scaled_font_subset_t *font_subset)
|
|
|
|
|
{
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
cairo_type1_subset_t subset;
|
|
|
|
|
char name[64];
|
|
|
|
|
|
|
|
|
|
snprintf (name, sizeof name, "CairoFont-%d-%d",
|
2008-01-10 15:53:54 +00:00
|
|
|
font_subset->font_id, font_subset->subset_id);
|
2006-09-05 15:57:47 -04:00
|
|
|
status = _cairo_type1_subset_init (&subset, name, font_subset, FALSE);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset);
|
|
|
|
|
|
|
|
|
|
_cairo_type1_subset_fini (&subset);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
2006-08-02 19:12:51 -04:00
|
|
|
#endif
|
2006-05-17 17:17:02 -04:00
|
|
|
|
2006-09-05 15:57:47 -04:00
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_emit_type1_fallback_font (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_scaled_font_subset_t *font_subset)
|
|
|
|
|
{
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
cairo_type1_subset_t subset;
|
|
|
|
|
char name[64];
|
|
|
|
|
|
|
|
|
|
snprintf (name, sizeof name, "CairoFont-%d-%d",
|
|
|
|
|
font_subset->font_id, font_subset->subset_id);
|
2006-10-15 23:07:38 +09:30
|
|
|
status = _cairo_type1_fallback_init_binary (&subset, name, font_subset);
|
2006-09-05 15:57:47 -04:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset);
|
|
|
|
|
|
|
|
|
|
_cairo_type1_fallback_fini (&subset);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2007-02-07 23:10:47 +10:30
|
|
|
#define PDF_UNITS_PER_EM 1000
|
2007-02-04 23:47:28 +10:30
|
|
|
|
2006-05-16 16:42:44 -04:00
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_scaled_font_subset_t *font_subset)
|
|
|
|
|
{
|
2007-04-20 22:44:04 +09:30
|
|
|
cairo_pdf_resource_t stream, descriptor, cidfont_dict;
|
|
|
|
|
cairo_pdf_resource_t subset_resource, to_unicode_stream;
|
2006-05-16 19:01:15 -04:00
|
|
|
cairo_status_t status;
|
|
|
|
|
cairo_pdf_font_t font;
|
|
|
|
|
cairo_truetype_subset_t subset;
|
2006-08-07 15:18:38 -07:00
|
|
|
unsigned int i;
|
2006-05-16 19:01:15 -04:00
|
|
|
|
2008-01-08 14:14:33 +00:00
|
|
|
subset_resource = _cairo_pdf_surface_get_font_resource (surface,
|
|
|
|
|
font_subset->font_id,
|
|
|
|
|
font_subset->subset_id);
|
|
|
|
|
if (subset_resource.id == 0)
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
|
2006-05-16 19:01:15 -04:00
|
|
|
status = _cairo_truetype_subset_init (&subset, font_subset);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-02-11 13:44:48 -05:00
|
|
|
status = _cairo_pdf_surface_open_stream (surface,
|
|
|
|
|
NULL,
|
|
|
|
|
TRUE,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Length1 %lu\n",
|
2008-02-11 13:44:48 -05:00
|
|
|
subset.data_length);
|
|
|
|
|
if (status) {
|
2006-05-16 19:01:15 -04:00
|
|
|
_cairo_truetype_subset_fini (&subset);
|
2008-02-11 13:44:48 -05:00
|
|
|
return status;
|
2006-05-16 19:01:15 -04:00
|
|
|
}
|
|
|
|
|
|
2008-02-11 13:44:48 -05:00
|
|
|
stream = surface->pdf_stream.self;
|
|
|
|
|
_cairo_output_stream_write (surface->output,
|
|
|
|
|
subset.data, subset.data_length);
|
|
|
|
|
status = _cairo_pdf_surface_close_stream (surface);
|
|
|
|
|
if (status) {
|
2007-10-04 21:17:31 +01:00
|
|
|
_cairo_truetype_subset_fini (&subset);
|
2008-02-11 13:44:48 -05:00
|
|
|
return status;
|
2007-10-04 21:17:31 +01:00
|
|
|
}
|
2006-05-16 19:01:15 -04:00
|
|
|
|
2007-10-11 14:01:20 +01:00
|
|
|
status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
|
|
|
|
|
font_subset, TRUE,
|
|
|
|
|
&to_unicode_stream);
|
|
|
|
|
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED) {
|
|
|
|
|
_cairo_truetype_subset_fini (&subset);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
2007-02-07 22:35:59 +10:30
|
|
|
|
2006-05-16 19:01:15 -04:00
|
|
|
descriptor = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (descriptor.id == 0) {
|
|
|
|
|
_cairo_truetype_subset_fini (&subset);
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-16 19:01:15 -04:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /FontDescriptor\n"
|
|
|
|
|
" /FontName /%s\n"
|
|
|
|
|
" /Flags 4\n"
|
|
|
|
|
" /FontBBox [ %ld %ld %ld %ld ]\n"
|
|
|
|
|
" /ItalicAngle 0\n"
|
|
|
|
|
" /Ascent %ld\n"
|
|
|
|
|
" /Descent %ld\n"
|
|
|
|
|
" /CapHeight %ld\n"
|
|
|
|
|
" /StemV 80\n"
|
|
|
|
|
" /StemH 80\n"
|
|
|
|
|
" /FontFile2 %u 0 R\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n",
|
2006-05-16 19:01:15 -04:00
|
|
|
descriptor.id,
|
|
|
|
|
subset.base_font,
|
2007-02-07 23:10:47 +10:30
|
|
|
(long)(subset.x_min*PDF_UNITS_PER_EM),
|
|
|
|
|
(long)(subset.y_min*PDF_UNITS_PER_EM),
|
|
|
|
|
(long)(subset.x_max*PDF_UNITS_PER_EM),
|
|
|
|
|
(long)(subset.y_max*PDF_UNITS_PER_EM),
|
|
|
|
|
(long)(subset.ascent*PDF_UNITS_PER_EM),
|
|
|
|
|
(long)(subset.descent*PDF_UNITS_PER_EM),
|
|
|
|
|
(long)(subset.y_max*PDF_UNITS_PER_EM),
|
2006-05-16 19:01:15 -04:00
|
|
|
stream.id);
|
|
|
|
|
|
2007-04-20 22:44:04 +09:30
|
|
|
cidfont_dict = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (cidfont_dict.id == 0) {
|
|
|
|
|
_cairo_truetype_subset_fini (&subset);
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
}
|
|
|
|
|
|
2007-02-04 19:00:16 +10:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Font\n"
|
|
|
|
|
" /Subtype /CIDFontType2\n"
|
|
|
|
|
" /BaseFont /%s\n"
|
|
|
|
|
" /CIDSystemInfo\n"
|
|
|
|
|
" << /Registry (Adobe)\n"
|
|
|
|
|
" /Ordering (Identity)\n"
|
|
|
|
|
" /Supplement 0\n"
|
|
|
|
|
" >>\n"
|
|
|
|
|
" /FontDescriptor %d 0 R\n"
|
2007-04-20 22:44:04 +09:30
|
|
|
" /W [0 [",
|
|
|
|
|
cidfont_dict.id,
|
|
|
|
|
subset.base_font,
|
|
|
|
|
descriptor.id);
|
2007-02-04 19:00:16 +10:30
|
|
|
|
|
|
|
|
for (i = 0; i < font_subset->num_glyphs; i++)
|
2007-04-20 22:44:04 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
" %ld",
|
|
|
|
|
(long)(subset.widths[i]*PDF_UNITS_PER_EM));
|
2007-02-04 19:00:16 +10:30
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" ]]\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2007-02-04 19:00:16 +10:30
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_pdf_surface_update_object (surface, subset_resource);
|
2006-05-16 19:01:15 -04:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Font\n"
|
|
|
|
|
" /Subtype /Type0\n"
|
|
|
|
|
" /BaseFont /%s\n"
|
|
|
|
|
" /Encoding /Identity-H\n"
|
|
|
|
|
" /DescendantFonts [ %d 0 R]\n",
|
2006-05-16 19:01:15 -04:00
|
|
|
subset_resource.id,
|
|
|
|
|
subset.base_font,
|
2007-04-20 22:44:04 +09:30
|
|
|
cidfont_dict.id);
|
2007-02-07 22:35:59 +10:30
|
|
|
|
|
|
|
|
if (to_unicode_stream.id != 0)
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /ToUnicode %d 0 R\n",
|
2007-02-07 22:35:59 +10:30
|
|
|
to_unicode_stream.id);
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2006-05-16 19:01:15 -04:00
|
|
|
|
|
|
|
|
font.font_id = font_subset->font_id;
|
|
|
|
|
font.subset_id = font_subset->subset_id;
|
|
|
|
|
font.subset_resource = subset_resource;
|
2007-04-08 21:26:33 +01:00
|
|
|
status = _cairo_array_append (&surface->fonts, &font);
|
2006-05-16 19:01:15 -04:00
|
|
|
|
|
|
|
|
_cairo_truetype_subset_fini (&subset);
|
|
|
|
|
|
2007-04-08 21:26:33 +01:00
|
|
|
return status;
|
2006-05-16 16:42:44 -04:00
|
|
|
}
|
|
|
|
|
|
2008-06-08 17:03:05 +09:30
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_emit_imagemask (cairo_image_surface_t *image,
|
|
|
|
|
cairo_output_stream_t *stream)
|
|
|
|
|
{
|
|
|
|
|
unsigned char *byte, output_byte;
|
|
|
|
|
int row, col, num_cols;
|
|
|
|
|
|
|
|
|
|
/* The only image type supported by Type 3 fonts are 1-bit image
|
|
|
|
|
* masks */
|
|
|
|
|
assert (image->format == CAIRO_FORMAT_A1);
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (stream,
|
|
|
|
|
"BI\n"
|
|
|
|
|
"/IM true\n"
|
|
|
|
|
"/W %d\n"
|
|
|
|
|
"/H %d\n"
|
|
|
|
|
"/BPC 1\n"
|
|
|
|
|
"/D [1 0]\n",
|
|
|
|
|
image->width,
|
|
|
|
|
image->height);
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (stream,
|
|
|
|
|
"ID ");
|
|
|
|
|
|
|
|
|
|
num_cols = (image->width + 7) / 8;
|
|
|
|
|
for (row = 0; row < image->height; row++) {
|
|
|
|
|
byte = image->data + row * image->stride;
|
|
|
|
|
for (col = 0; col < num_cols; col++) {
|
|
|
|
|
output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
|
|
|
|
|
_cairo_output_stream_write (stream, &output_byte, 1);
|
|
|
|
|
byte++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (stream,
|
|
|
|
|
"\nEI\n");
|
|
|
|
|
|
|
|
|
|
return _cairo_output_stream_get_status (stream);
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-16 16:42:44 -04:00
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_scaled_font_subset_t *font_subset)
|
2006-05-15 10:04:53 -07:00
|
|
|
{
|
2008-01-03 14:46:40 +00:00
|
|
|
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
2007-02-07 22:35:59 +10:30
|
|
|
cairo_pdf_resource_t *glyphs, encoding, char_procs, subset_resource, to_unicode_stream;
|
2006-05-15 10:04:53 -07:00
|
|
|
cairo_pdf_font_t font;
|
2007-02-11 21:50:46 +10:30
|
|
|
double *widths;
|
2006-08-07 15:18:38 -07:00
|
|
|
unsigned int i;
|
2007-02-11 21:50:46 +10:30
|
|
|
cairo_box_t font_bbox = {{0,0},{0,0}};
|
|
|
|
|
cairo_box_t bbox = {{0,0},{0,0}};
|
2008-06-08 17:11:39 +09:30
|
|
|
cairo_surface_t *type3_surface;
|
2006-05-15 10:04:53 -07:00
|
|
|
|
2008-01-03 14:46:40 +00:00
|
|
|
if (font_subset->num_glyphs == 0)
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
|
2008-01-08 14:14:33 +00:00
|
|
|
subset_resource = _cairo_pdf_surface_get_font_resource (surface,
|
|
|
|
|
font_subset->font_id,
|
|
|
|
|
font_subset->subset_id);
|
|
|
|
|
if (subset_resource.id == 0)
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
|
2007-06-19 13:15:21 -07:00
|
|
|
glyphs = _cairo_malloc_ab (font_subset->num_glyphs, sizeof (cairo_pdf_resource_t));
|
2007-10-04 13:15:46 +01:00
|
|
|
if (glyphs == NULL)
|
2008-01-10 15:53:54 +00:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2006-05-15 10:04:53 -07:00
|
|
|
|
2007-06-19 13:15:21 -07:00
|
|
|
widths = _cairo_malloc_ab (font_subset->num_glyphs, sizeof (double));
|
2007-02-11 21:50:46 +10:30
|
|
|
if (widths == NULL) {
|
|
|
|
|
free (glyphs);
|
2008-01-10 15:53:54 +00:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2007-02-11 21:50:46 +10:30
|
|
|
}
|
|
|
|
|
|
2008-06-08 17:03:05 +09:30
|
|
|
type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
|
|
|
|
|
NULL,
|
|
|
|
|
_cairo_pdf_emit_imagemask);
|
2008-06-08 17:11:39 +09:30
|
|
|
|
2006-05-15 10:04:53 -07:00
|
|
|
for (i = 0; i < font_subset->num_glyphs; i++) {
|
2008-06-08 17:11:39 +09:30
|
|
|
status = _cairo_pdf_surface_open_stream (surface,
|
|
|
|
|
NULL,
|
|
|
|
|
surface->compress_content,
|
|
|
|
|
NULL);
|
|
|
|
|
glyphs[i] = surface->pdf_stream.self;
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
status = _cairo_type3_glyph_surface_emit_notdef_glyph (type3_surface,
|
|
|
|
|
surface->output,
|
|
|
|
|
&bbox,
|
|
|
|
|
&widths[i]);
|
|
|
|
|
} else {
|
|
|
|
|
status = _cairo_type3_glyph_surface_emit_glyph (type3_surface,
|
|
|
|
|
surface->output,
|
|
|
|
|
font_subset->glyphs[i],
|
|
|
|
|
&bbox,
|
|
|
|
|
&widths[i]);
|
|
|
|
|
}
|
|
|
|
|
status = _cairo_pdf_surface_close_stream (surface);
|
2008-01-03 14:46:40 +00:00
|
|
|
if (status)
|
|
|
|
|
break;
|
|
|
|
|
|
2007-02-11 21:50:46 +10:30
|
|
|
if (i == 0) {
|
|
|
|
|
font_bbox.p1.x = bbox.p1.x;
|
|
|
|
|
font_bbox.p1.y = bbox.p1.y;
|
|
|
|
|
font_bbox.p2.x = bbox.p2.x;
|
|
|
|
|
font_bbox.p2.y = bbox.p2.y;
|
|
|
|
|
} else {
|
|
|
|
|
if (bbox.p1.x < font_bbox.p1.x)
|
|
|
|
|
font_bbox.p1.x = bbox.p1.x;
|
|
|
|
|
if (bbox.p1.y < font_bbox.p1.y)
|
|
|
|
|
font_bbox.p1.y = bbox.p1.y;
|
|
|
|
|
if (bbox.p2.x > font_bbox.p2.x)
|
|
|
|
|
font_bbox.p2.x = bbox.p2.x;
|
|
|
|
|
if (bbox.p2.y > font_bbox.p2.y)
|
|
|
|
|
font_bbox.p2.y = bbox.p2.y;
|
|
|
|
|
}
|
2006-05-15 10:04:53 -07:00
|
|
|
}
|
2008-06-08 17:11:39 +09:30
|
|
|
cairo_surface_destroy (type3_surface);
|
2008-01-03 14:46:40 +00:00
|
|
|
if (status) {
|
|
|
|
|
free (glyphs);
|
|
|
|
|
free (widths);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
2006-05-15 10:04:53 -07:00
|
|
|
|
|
|
|
|
encoding = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (encoding.id == 0) {
|
|
|
|
|
free (glyphs);
|
|
|
|
|
free (widths);
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-15 10:04:53 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Encoding\n"
|
2006-05-15 10:04:53 -07:00
|
|
|
" /Differences [0", encoding.id);
|
|
|
|
|
for (i = 0; i < font_subset->num_glyphs; i++)
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
" /%d", i);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"]\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2006-05-15 10:04:53 -07:00
|
|
|
|
|
|
|
|
char_procs = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (char_procs.id == 0) {
|
|
|
|
|
free (glyphs);
|
|
|
|
|
free (widths);
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-15 10:04:53 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<<\n", char_procs.id);
|
2006-05-15 10:04:53 -07:00
|
|
|
for (i = 0; i < font_subset->num_glyphs; i++)
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /%d %d 0 R\n",
|
2006-05-15 10:04:53 -07:00
|
|
|
i, glyphs[i].id);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2006-05-15 10:04:53 -07:00
|
|
|
|
2006-08-08 15:30:56 -04:00
|
|
|
free (glyphs);
|
|
|
|
|
|
2007-10-11 14:01:20 +01:00
|
|
|
status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
|
|
|
|
|
font_subset, FALSE,
|
|
|
|
|
&to_unicode_stream);
|
|
|
|
|
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED) {
|
|
|
|
|
free (widths);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
2007-02-07 22:35:59 +10:30
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_pdf_surface_update_object (surface, subset_resource);
|
2006-05-15 10:04:53 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Font\n"
|
|
|
|
|
" /Subtype /Type3\n"
|
|
|
|
|
" /FontBBox [%f %f %f %f]\n"
|
2008-06-08 17:11:39 +09:30
|
|
|
" /FontMatrix [ 1 0 0 1 0 0 ]\n"
|
2008-02-20 21:05:23 +10:30
|
|
|
" /Encoding %d 0 R\n"
|
|
|
|
|
" /CharProcs %d 0 R\n"
|
|
|
|
|
" /FirstChar 0\n"
|
|
|
|
|
" /LastChar %d\n",
|
2006-05-15 10:04:53 -07:00
|
|
|
subset_resource.id,
|
2007-02-11 21:50:46 +10:30
|
|
|
_cairo_fixed_to_double (font_bbox.p1.x),
|
2008-06-08 17:11:39 +09:30
|
|
|
- _cairo_fixed_to_double (font_bbox.p2.y),
|
2007-02-11 21:50:46 +10:30
|
|
|
_cairo_fixed_to_double (font_bbox.p2.x),
|
2008-06-08 17:11:39 +09:30
|
|
|
- _cairo_fixed_to_double (font_bbox.p1.y),
|
2006-05-15 10:04:53 -07:00
|
|
|
encoding.id,
|
|
|
|
|
char_procs.id,
|
|
|
|
|
font_subset->num_glyphs - 1);
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
|
|
|
|
" /Widths [");
|
|
|
|
|
for (i = 0; i < font_subset->num_glyphs; i++)
|
2007-02-11 21:50:46 +10:30
|
|
|
_cairo_output_stream_printf (surface->output, " %f", widths[i]);
|
2006-05-15 10:04:53 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"]\n");
|
2007-02-11 21:50:46 +10:30
|
|
|
free (widths);
|
2006-05-15 10:04:53 -07:00
|
|
|
|
2007-02-07 22:35:59 +10:30
|
|
|
if (to_unicode_stream.id != 0)
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
" /ToUnicode %d 0 R\n",
|
2007-02-07 22:35:59 +10:30
|
|
|
to_unicode_stream.id);
|
|
|
|
|
|
2006-05-15 10:04:53 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
">>\n"
|
|
|
|
|
"endobj\n");
|
2006-05-15 10:04:53 -07:00
|
|
|
|
|
|
|
|
font.font_id = font_subset->font_id;
|
|
|
|
|
font.subset_id = font_subset->subset_id;
|
|
|
|
|
font.subset_resource = subset_resource;
|
2007-04-08 21:26:33 +01:00
|
|
|
return _cairo_array_append (&surface->fonts, &font);
|
2006-05-16 16:42:44 -04:00
|
|
|
}
|
|
|
|
|
|
2007-10-05 10:23:13 +01:00
|
|
|
static cairo_status_t
|
2007-02-21 00:32:07 +10:30
|
|
|
_cairo_pdf_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset,
|
|
|
|
|
void *closure)
|
2006-05-16 16:42:44 -04:00
|
|
|
{
|
|
|
|
|
cairo_pdf_surface_t *surface = closure;
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
|
2007-04-20 22:45:12 +09:30
|
|
|
if (font_subset->is_composite) {
|
|
|
|
|
status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset);
|
|
|
|
|
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
2007-10-05 10:23:13 +01:00
|
|
|
return status;
|
2007-04-20 22:45:12 +09:30
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_emit_truetype_font_subset (surface, font_subset);
|
|
|
|
|
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
2007-10-05 10:23:13 +01:00
|
|
|
return status;
|
2007-04-20 22:45:12 +09:30
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_emit_cff_fallback_font (surface, font_subset);
|
|
|
|
|
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
2007-10-05 10:23:13 +01:00
|
|
|
return status;
|
2007-04-20 22:45:12 +09:30
|
|
|
} else {
|
2006-08-02 19:12:51 -04:00
|
|
|
#if CAIRO_HAS_FT_FONT
|
2007-04-20 22:45:12 +09:30
|
|
|
status = _cairo_pdf_surface_emit_type1_font_subset (surface, font_subset);
|
|
|
|
|
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
2007-10-05 10:23:13 +01:00
|
|
|
return status;
|
2006-08-02 19:12:51 -04:00
|
|
|
#endif
|
2006-05-17 17:17:02 -04:00
|
|
|
|
2007-04-20 22:45:12 +09:30
|
|
|
status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset);
|
|
|
|
|
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
2007-10-05 10:23:13 +01:00
|
|
|
return status;
|
2008-06-08 17:11:39 +09:30
|
|
|
|
2007-04-20 22:45:12 +09:30
|
|
|
}
|
2007-10-05 10:23:13 +01:00
|
|
|
|
2008-01-17 15:34:51 +00:00
|
|
|
ASSERT_NOT_REACHED;
|
2007-10-05 10:23:13 +01:00
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2007-02-21 00:32:07 +10:30
|
|
|
}
|
|
|
|
|
|
2007-10-05 10:23:13 +01:00
|
|
|
static cairo_status_t
|
2007-02-21 00:32:07 +10:30
|
|
|
_cairo_pdf_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset,
|
|
|
|
|
void *closure)
|
|
|
|
|
{
|
|
|
|
|
cairo_pdf_surface_t *surface = closure;
|
|
|
|
|
cairo_status_t status;
|
2006-09-05 15:57:47 -04:00
|
|
|
|
2006-05-16 16:42:44 -04:00
|
|
|
status = _cairo_pdf_surface_emit_type3_font_subset (surface, font_subset);
|
|
|
|
|
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
2007-10-05 10:23:13 +01:00
|
|
|
return status;
|
|
|
|
|
|
2008-01-17 15:34:51 +00:00
|
|
|
ASSERT_NOT_REACHED;
|
2007-10-05 10:23:13 +01:00
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2006-05-15 10:04:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface)
|
|
|
|
|
{
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
|
2007-02-21 00:32:07 +10:30
|
|
|
status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
|
|
|
|
|
_cairo_pdf_surface_emit_unscaled_font_subset,
|
|
|
|
|
surface);
|
2007-10-04 23:30:21 +01:00
|
|
|
if (status)
|
|
|
|
|
goto BAIL;
|
|
|
|
|
|
2007-02-21 00:32:07 +10:30
|
|
|
status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
|
|
|
|
|
_cairo_pdf_surface_emit_scaled_font_subset,
|
|
|
|
|
surface);
|
2007-10-04 23:30:21 +01:00
|
|
|
|
|
|
|
|
BAIL:
|
2006-05-15 10:04:53 -07:00
|
|
|
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
|
|
|
|
|
surface->font_subsets = NULL;
|
|
|
|
|
|
2007-10-04 23:30:21 +01:00
|
|
|
return status;
|
2006-05-15 10:04:53 -07:00
|
|
|
}
|
|
|
|
|
|
2006-05-12 13:31:12 -07:00
|
|
|
static cairo_pdf_resource_t
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface)
|
2005-01-05 14:29:31 +00:00
|
|
|
{
|
2006-05-12 13:31:12 -07:00
|
|
|
cairo_pdf_resource_t catalog;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
catalog = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (catalog.id == 0)
|
|
|
|
|
return catalog;
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Catalog\n"
|
|
|
|
|
" /Pages %d 0 R\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n",
|
2006-05-12 13:31:12 -07:00
|
|
|
catalog.id,
|
2006-05-12 14:56:11 -07:00
|
|
|
surface->pages_resource.id);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 13:31:12 -07:00
|
|
|
return catalog;
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static long
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface)
|
2005-01-05 14:29:31 +00:00
|
|
|
{
|
|
|
|
|
cairo_pdf_object_t *object;
|
|
|
|
|
int num_objects, i;
|
|
|
|
|
long offset;
|
2005-05-13 14:04:22 +00:00
|
|
|
char buffer[11];
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
num_objects = _cairo_array_num_elements (&surface->objects);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
offset = _cairo_output_stream_get_position (surface->output);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"xref\n"
|
|
|
|
|
"%d %d\n",
|
2005-03-16 12:08:41 +00:00
|
|
|
0, num_objects + 1);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"0000000000 65535 f \n");
|
2005-01-05 14:29:31 +00:00
|
|
|
for (i = 0; i < num_objects; i++) {
|
2006-05-12 14:56:11 -07:00
|
|
|
object = _cairo_array_index (&surface->objects, i);
|
2005-05-13 14:04:22 +00:00
|
|
|
snprintf (buffer, sizeof buffer, "%010ld", object->offset);
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%s 00000 n \n", buffer);
|
2005-01-05 14:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return offset;
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
static cairo_status_t
|
2008-01-10 15:53:54 +00:00
|
|
|
_cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_pdf_smask_group_t *group)
|
2008-01-07 20:55:56 +10:30
|
|
|
{
|
|
|
|
|
cairo_pdf_resource_t mask_group;
|
|
|
|
|
cairo_pdf_resource_t smask;
|
|
|
|
|
cairo_pdf_smask_group_t *smask_group;
|
|
|
|
|
cairo_pdf_resource_t pattern_res, gstate_res;
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
|
|
|
|
|
/* Create mask group */
|
|
|
|
|
status = _cairo_pdf_surface_open_group (surface, NULL);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
pattern_res.id = 0;
|
|
|
|
|
gstate_res.id = 0;
|
|
|
|
|
status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask, &pattern_res, &gstate_res);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
if (gstate_res.id != 0) {
|
|
|
|
|
smask_group = _cairo_pdf_surface_create_smask_group (surface);
|
|
|
|
|
if (smask_group == NULL)
|
2008-01-10 15:53:54 +00:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
smask_group->operation = PDF_PAINT;
|
|
|
|
|
smask_group->source = cairo_pattern_reference (group->mask);
|
|
|
|
|
smask_group->source_res = pattern_res;
|
|
|
|
|
status = _cairo_pdf_surface_add_smask_group (surface, smask_group);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status) {
|
|
|
|
|
_cairo_pdf_smask_group_destroy (smask_group);
|
2008-01-07 20:55:56 +10:30
|
|
|
return status;
|
2008-01-10 15:53:54 +00:00
|
|
|
}
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_add_smask (surface, gstate_res);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"q /s%d gs /x%d Do Q\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
gstate_res.id,
|
|
|
|
|
smask_group->group_res.id);
|
|
|
|
|
} else {
|
|
|
|
|
status = _cairo_pdf_surface_select_pattern (surface, group->mask, pattern_res, FALSE);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"0 0 %f %f re f\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
surface->width, surface->height);
|
|
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_surface_unselect_pattern (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_close_group (surface, &mask_group);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
/* Create source group */
|
|
|
|
|
status = _cairo_pdf_surface_open_group (surface, &group->source_res);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
pattern_res.id = 0;
|
|
|
|
|
gstate_res.id = 0;
|
|
|
|
|
status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source, &pattern_res, &gstate_res);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
if (gstate_res.id != 0) {
|
|
|
|
|
smask_group = _cairo_pdf_surface_create_smask_group (surface);
|
|
|
|
|
if (smask_group == NULL)
|
2008-01-10 15:53:54 +00:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
smask_group->operation = PDF_PAINT;
|
|
|
|
|
smask_group->source = cairo_pattern_reference (group->source);
|
|
|
|
|
smask_group->source_res = pattern_res;
|
|
|
|
|
status = _cairo_pdf_surface_add_smask_group (surface, smask_group);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status) {
|
|
|
|
|
_cairo_pdf_smask_group_destroy (smask_group);
|
2008-01-07 20:55:56 +10:30
|
|
|
return status;
|
2008-01-10 15:53:54 +00:00
|
|
|
}
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_add_smask (surface, gstate_res);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"q /s%d gs /x%d Do Q\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
gstate_res.id,
|
|
|
|
|
smask_group->group_res.id);
|
|
|
|
|
} else {
|
|
|
|
|
status = _cairo_pdf_surface_select_pattern (surface, group->source, pattern_res, FALSE);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"0 0 %f %f re f\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
surface->width, surface->height);
|
|
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_surface_unselect_pattern (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_close_group (surface, NULL);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
/* Create an smask based on the alpha component of mask_group */
|
|
|
|
|
smask = _cairo_pdf_surface_new_object (surface);
|
|
|
|
|
if (smask.id == 0)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Mask\n"
|
|
|
|
|
" /S /Alpha\n"
|
|
|
|
|
" /G %d 0 R\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
smask.id,
|
|
|
|
|
mask_group.id);
|
|
|
|
|
|
|
|
|
|
/* Create a GState that uses the smask */
|
|
|
|
|
_cairo_pdf_surface_update_object (surface, group->group_res);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /ExtGState\n"
|
|
|
|
|
" /SMask %d 0 R\n"
|
|
|
|
|
" /ca 1\n"
|
|
|
|
|
" /CA 1\n"
|
|
|
|
|
" /AIS false\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
group->group_res.id,
|
|
|
|
|
smask.id);
|
|
|
|
|
|
|
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_pdf_smask_group_t *group)
|
|
|
|
|
{
|
2008-02-02 20:59:56 +10:30
|
|
|
double old_width, old_height;
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_status_t status;
|
|
|
|
|
|
2008-02-02 20:59:56 +10:30
|
|
|
old_width = surface->width;
|
|
|
|
|
old_height = surface->height;
|
2008-04-07 13:03:58 -07:00
|
|
|
_cairo_pdf_surface_set_size_internal (surface,
|
|
|
|
|
group->width,
|
|
|
|
|
group->height);
|
2008-01-07 20:55:56 +10:30
|
|
|
/* _mask is a special case that requires two groups - source
|
|
|
|
|
* and mask as well as a smask and gstate dictionary */
|
|
|
|
|
if (group->operation == PDF_MASK)
|
|
|
|
|
return _cairo_pdf_surface_write_mask_group (surface, group);
|
|
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_open_group (surface, &group->group_res);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_select_pattern (surface,
|
|
|
|
|
group->source,
|
|
|
|
|
group->source_res,
|
|
|
|
|
group->operation == PDF_STROKE);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
switch (group->operation) {
|
|
|
|
|
case PDF_PAINT:
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"0 0 %f %f re f\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
surface->width, surface->height);
|
|
|
|
|
break;
|
|
|
|
|
case PDF_MASK:
|
|
|
|
|
ASSERT_NOT_REACHED;
|
|
|
|
|
break;
|
|
|
|
|
case PDF_FILL:
|
|
|
|
|
status = _cairo_pdf_operators_fill (&surface->pdf_operators,
|
|
|
|
|
&group->path,
|
|
|
|
|
group->fill_rule);
|
|
|
|
|
break;
|
|
|
|
|
case PDF_STROKE:
|
2008-02-17 19:49:39 +10:30
|
|
|
status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
|
|
|
|
|
&group->path,
|
|
|
|
|
group->style,
|
|
|
|
|
&group->ctm,
|
|
|
|
|
&group->ctm_inverse);
|
2008-01-07 20:55:56 +10:30
|
|
|
break;
|
|
|
|
|
case PDF_SHOW_GLYPHS:
|
2008-06-29 19:38:13 +09:30
|
|
|
status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
|
2008-06-29 19:55:41 +09:30
|
|
|
group->utf8, group->utf8_len,
|
2008-06-29 19:38:13 +09:30
|
|
|
group->glyphs, group->num_glyphs,
|
2008-06-29 19:55:41 +09:30
|
|
|
group->clusters, group->num_clusters,
|
|
|
|
|
group->backward,
|
2008-06-29 19:38:13 +09:30
|
|
|
group->scaled_font);
|
2008-01-07 20:55:56 +10:30
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_surface_unselect_pattern (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-02-02 20:59:56 +10:30
|
|
|
status = _cairo_pdf_surface_close_group (surface, NULL);
|
|
|
|
|
|
2008-04-07 13:03:58 -07:00
|
|
|
_cairo_pdf_surface_set_size_internal (surface,
|
|
|
|
|
old_width,
|
|
|
|
|
old_height);
|
2008-01-07 20:55:56 +10:30
|
|
|
|
2008-02-02 20:59:56 +10:30
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface)
|
|
|
|
|
{
|
|
|
|
|
cairo_pdf_pattern_t pattern;
|
|
|
|
|
cairo_pdf_smask_group_t *group;
|
|
|
|
|
int pattern_index, group_index;
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
|
|
|
|
|
/* Writing out PDF_MASK groups will cause additional smask groups
|
|
|
|
|
* to be appended to surface->smask_groups. Additional patterns
|
|
|
|
|
* may also be appended to surface->patterns.
|
|
|
|
|
*
|
|
|
|
|
* Writing meta surface patterns will cause additional patterns
|
|
|
|
|
* and groups to be appended.
|
|
|
|
|
*/
|
|
|
|
|
pattern_index = 0;
|
|
|
|
|
group_index = 0;
|
|
|
|
|
while ((pattern_index < _cairo_array_num_elements (&surface->patterns)) ||
|
|
|
|
|
(group_index < _cairo_array_num_elements (&surface->smask_groups)))
|
|
|
|
|
{
|
|
|
|
|
for (; group_index < _cairo_array_num_elements (&surface->smask_groups); group_index++) {
|
|
|
|
|
_cairo_array_copy_element (&surface->smask_groups, group_index, &group);
|
|
|
|
|
status = _cairo_pdf_surface_write_smask_group (surface, group);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (; pattern_index < _cairo_array_num_elements (&surface->patterns); pattern_index++) {
|
|
|
|
|
_cairo_array_copy_element (&surface->patterns, pattern_index, &pattern);
|
|
|
|
|
status = _cairo_pdf_surface_emit_pattern (surface, &pattern);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
|
|
|
|
|
{
|
2008-01-07 21:15:18 +10:30
|
|
|
cairo_pdf_resource_t page, knockout, res;
|
2007-08-25 06:44:08 +09:30
|
|
|
cairo_status_t status;
|
2008-01-07 21:15:18 +10:30
|
|
|
int i, len;
|
2007-08-25 06:44:08 +09:30
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_pdf_group_resources_clear (&surface->resources);
|
|
|
|
|
if (surface->has_fallback_images) {
|
|
|
|
|
status = _cairo_pdf_surface_open_knockout_group (surface);
|
2007-10-04 23:15:21 +01:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-01-07 21:15:18 +10:30
|
|
|
len = _cairo_array_num_elements (&surface->knockout_group);
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
_cairo_array_copy_element (&surface->knockout_group, i, &res);
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"/x%d Do\n",
|
2008-01-07 21:15:18 +10:30
|
|
|
res.id);
|
2008-01-10 15:53:54 +00:00
|
|
|
status = _cairo_pdf_surface_add_xobject (surface, res);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 21:15:18 +10:30
|
|
|
}
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"/x%d Do\n",
|
2008-01-07 21:15:18 +10:30
|
|
|
surface->content.id);
|
2008-01-10 15:53:54 +00:00
|
|
|
status = _cairo_pdf_surface_add_xobject (surface, surface->content);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 21:15:18 +10:30
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
status = _cairo_pdf_surface_close_group (surface, &knockout);
|
2007-10-05 12:08:40 +01:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_pdf_group_resources_clear (&surface->resources);
|
2008-01-16 16:33:22 +00:00
|
|
|
status = _cairo_pdf_surface_open_content_stream (surface, FALSE);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"/x%d Do\n",
|
2008-01-07 21:04:06 +10:30
|
|
|
knockout.id);
|
2008-01-10 15:53:54 +00:00
|
|
|
status = _cairo_pdf_surface_add_xobject (surface, knockout);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_close_content_stream (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-08-25 06:44:08 +09:30
|
|
|
}
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
page = _cairo_pdf_surface_new_object (surface);
|
2007-10-04 21:17:31 +01:00
|
|
|
if (page.id == 0)
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"%d 0 obj\n"
|
|
|
|
|
"<< /Type /Page\n"
|
|
|
|
|
" /Parent %d 0 R\n"
|
|
|
|
|
" /MediaBox [ 0 0 %f %f ]\n"
|
|
|
|
|
" /Contents %d 0 R\n"
|
|
|
|
|
" /Group <<\n"
|
|
|
|
|
" /Type /Group\n"
|
|
|
|
|
" /S /Transparency\n"
|
|
|
|
|
" /CS /DeviceRGB\n"
|
|
|
|
|
" >>\n"
|
|
|
|
|
" /Resources %d 0 R\n"
|
|
|
|
|
">>\n"
|
|
|
|
|
"endobj\n",
|
2006-05-12 13:31:12 -07:00
|
|
|
page.id,
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->pages_resource.id,
|
2006-05-16 01:04:16 -07:00
|
|
|
surface->width,
|
2007-08-25 06:44:08 +09:30
|
|
|
surface->height,
|
2008-01-07 21:04:06 +10:30
|
|
|
surface->content.id,
|
|
|
|
|
surface->content_resources.id);
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2006-05-12 14:56:11 -07:00
|
|
|
status = _cairo_array_append (&surface->pages, &page);
|
2005-11-04 16:13:30 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2005-01-05 14:29:31 +00:00
|
|
|
|
2008-01-10 15:53:54 +00:00
|
|
|
status = _cairo_pdf_surface_write_patterns_and_smask_groups (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
2005-01-05 14:29:31 +00:00
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
2006-03-24 11:48:35 -08:00
|
|
|
|
2008-03-10 17:18:07 +10:30
|
|
|
static cairo_int_status_t
|
|
|
|
|
_cairo_pdf_surface_analyze_surface_pattern_transparency (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_surface_pattern_t *pattern)
|
|
|
|
|
{
|
|
|
|
|
cairo_image_surface_t *image;
|
|
|
|
|
void *image_extra;
|
|
|
|
|
cairo_int_status_t status;
|
|
|
|
|
cairo_image_transparency_t transparency;
|
|
|
|
|
|
|
|
|
|
status = _cairo_surface_acquire_source_image (pattern->surface,
|
|
|
|
|
&image,
|
|
|
|
|
&image_extra);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
if (image->base.status)
|
|
|
|
|
return image->base.status;
|
|
|
|
|
|
|
|
|
|
transparency = _cairo_image_analyze_transparency (image);
|
|
|
|
|
if (transparency == CAIRO_IMAGE_IS_OPAQUE)
|
|
|
|
|
status = CAIRO_STATUS_SUCCESS;
|
|
|
|
|
else
|
|
|
|
|
status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
|
|
|
|
|
|
|
|
|
|
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-18 11:31:59 -07:00
|
|
|
static cairo_bool_t
|
2006-04-25 03:45:37 -07:00
|
|
|
_surface_pattern_supported (cairo_surface_pattern_t *pattern)
|
2006-04-18 11:31:59 -07:00
|
|
|
{
|
2006-04-25 03:45:37 -07:00
|
|
|
cairo_extend_t extend;
|
|
|
|
|
|
2007-09-05 22:26:16 +09:30
|
|
|
if (_cairo_surface_is_meta (pattern->surface))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
2006-04-25 03:45:37 -07:00
|
|
|
if (pattern->surface->backend->acquire_source_image == NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Does an ALPHA-only source surface even make sense? Maybe, but I
|
|
|
|
|
* don't think it's worth the extra code to support it. */
|
|
|
|
|
|
|
|
|
|
/* XXX: Need to write this function here...
|
|
|
|
|
content = cairo_surface_get_content (pattern->surface);
|
|
|
|
|
if (content == CAIRO_CONTENT_ALPHA)
|
|
|
|
|
return FALSE;
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
extend = cairo_pattern_get_extend (&pattern->base);
|
|
|
|
|
switch (extend) {
|
|
|
|
|
case CAIRO_EXTEND_NONE:
|
|
|
|
|
case CAIRO_EXTEND_REPEAT:
|
|
|
|
|
case CAIRO_EXTEND_REFLECT:
|
2007-03-01 19:14:40 -05:00
|
|
|
/* There's no point returning FALSE for EXTEND_PAD, as the image
|
|
|
|
|
* surface does not currently implement it either */
|
2006-04-25 03:45:37 -07:00
|
|
|
case CAIRO_EXTEND_PAD:
|
2007-03-01 19:14:40 -05:00
|
|
|
return TRUE;
|
2006-04-25 03:45:37 -07:00
|
|
|
}
|
2006-04-18 11:31:59 -07:00
|
|
|
|
2006-04-25 03:45:37 -07:00
|
|
|
ASSERT_NOT_REACHED;
|
2006-04-18 11:31:59 -07:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
static cairo_bool_t
|
|
|
|
|
_gradient_pattern_supported (cairo_pattern_t *pattern)
|
|
|
|
|
{
|
|
|
|
|
cairo_extend_t extend;
|
|
|
|
|
|
|
|
|
|
extend = cairo_pattern_get_extend (pattern);
|
|
|
|
|
|
|
|
|
|
|
2007-10-14 19:04:33 +09:30
|
|
|
/* Radial gradients are currently only supported with EXTEND_NONE
|
|
|
|
|
* and EXTEND_PAD and when one circle is inside the other. */
|
2007-04-27 09:49:45 -07:00
|
|
|
if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
|
|
|
|
|
double x1, y1, x2, y2, r1, r2, d;
|
|
|
|
|
cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
|
|
|
|
|
|
2007-10-14 19:04:33 +09:30
|
|
|
if (extend == CAIRO_EXTEND_REPEAT ||
|
|
|
|
|
extend == CAIRO_EXTEND_REFLECT) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
x1 = _cairo_fixed_to_double (radial->c1.x);
|
2007-06-13 00:15:34 -04:00
|
|
|
y1 = _cairo_fixed_to_double (radial->c1.y);
|
2007-06-18 17:29:04 -07:00
|
|
|
r1 = _cairo_fixed_to_double (radial->r1);
|
2007-06-13 00:15:34 -04:00
|
|
|
x2 = _cairo_fixed_to_double (radial->c2.x);
|
|
|
|
|
y2 = _cairo_fixed_to_double (radial->c2.y);
|
2007-06-18 17:29:04 -07:00
|
|
|
r2 = _cairo_fixed_to_double (radial->r2);
|
2007-04-27 09:49:45 -07:00
|
|
|
|
|
|
|
|
d = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
|
|
|
|
|
if (d > fabs(r2 - r1)) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-18 11:31:59 -07:00
|
|
|
static cairo_bool_t
|
2006-04-25 03:45:37 -07:00
|
|
|
_pattern_supported (cairo_pattern_t *pattern)
|
2006-04-18 11:31:59 -07:00
|
|
|
{
|
|
|
|
|
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
2007-04-27 09:49:45 -07:00
|
|
|
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
|
|
|
|
|
pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
|
|
|
|
|
return _gradient_pattern_supported (pattern);
|
|
|
|
|
|
2006-04-18 11:31:59 -07:00
|
|
|
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
|
2006-04-25 03:45:37 -07:00
|
|
|
return _surface_pattern_supported ((cairo_surface_pattern_t *) pattern);
|
2006-05-12 14:56:11 -07:00
|
|
|
|
2006-04-18 11:31:59 -07:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_int_status_t
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_operator_t op,
|
|
|
|
|
cairo_pattern_t *pattern)
|
2006-04-18 11:31:59 -07:00
|
|
|
{
|
2007-08-25 06:44:08 +09:30
|
|
|
if (surface->force_fallbacks && surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
|
|
|
|
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
2006-05-24 14:02:30 -07:00
|
|
|
|
2006-04-18 11:31:59 -07:00
|
|
|
if (! _pattern_supported (pattern))
|
2007-08-25 06:44:08 +09:30
|
|
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
2006-04-18 11:31:59 -07:00
|
|
|
|
2008-03-29 23:45:31 +10:30
|
|
|
if (op == CAIRO_OPERATOR_OVER) {
|
2007-09-05 22:26:16 +09:30
|
|
|
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
|
|
|
|
|
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
|
2008-03-29 23:45:31 +10:30
|
|
|
|
2007-09-05 22:26:16 +09:30
|
|
|
if ( _cairo_surface_is_meta (surface_pattern->surface))
|
2008-01-07 21:09:04 +10:30
|
|
|
return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
|
2007-09-05 22:26:16 +09:30
|
|
|
}
|
|
|
|
|
}
|
2006-04-18 11:31:59 -07:00
|
|
|
|
2008-01-07 21:09:04 +10:30
|
|
|
if (op == CAIRO_OPERATOR_OVER)
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
|
2008-03-10 17:18:07 +10:30
|
|
|
/* The SOURCE operator is supported if the pattern is opaque or if
|
2008-02-25 21:50:37 +10:30
|
|
|
* there is nothing painted underneath. */
|
|
|
|
|
if (op == CAIRO_OPERATOR_SOURCE) {
|
2008-03-10 17:18:07 +10:30
|
|
|
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
|
|
|
|
|
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
|
|
|
|
|
|
2008-03-29 23:45:31 +10:30
|
|
|
if (_cairo_surface_is_meta (surface_pattern->surface)) {
|
2008-04-27 22:59:22 +09:30
|
|
|
if (_cairo_pattern_is_opaque (pattern)) {
|
2008-03-29 23:45:31 +10:30
|
|
|
return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
|
2008-04-27 22:59:22 +09:30
|
|
|
} else {
|
|
|
|
|
/* FIXME: The analysis surface does not yet have
|
|
|
|
|
* the capability to analyze a non opaque meta
|
|
|
|
|
* surface and mark it supported if there is
|
|
|
|
|
* nothing underneath. For now meta surfaces of
|
|
|
|
|
* type CONTENT_COLOR_ALPHA painted with
|
|
|
|
|
* OPERATOR_SOURCE will result in a fallback
|
|
|
|
|
* image. */
|
|
|
|
|
|
|
|
|
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
|
|
}
|
2008-03-29 23:45:31 +10:30
|
|
|
} else {
|
|
|
|
|
return _cairo_pdf_surface_analyze_surface_pattern_transparency (surface,
|
|
|
|
|
surface_pattern);
|
|
|
|
|
}
|
2008-03-10 17:18:07 +10:30
|
|
|
}
|
|
|
|
|
|
2008-02-25 21:50:37 +10:30
|
|
|
if (_cairo_pattern_is_opaque (pattern))
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
else
|
|
|
|
|
return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
|
|
|
|
|
}
|
2007-08-25 06:44:08 +09:30
|
|
|
|
|
|
|
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_bool_t
|
|
|
|
|
_cairo_pdf_surface_operation_supported (cairo_pdf_surface_t *surface,
|
|
|
|
|
cairo_operator_t op,
|
|
|
|
|
cairo_pattern_t *pattern)
|
|
|
|
|
{
|
|
|
|
|
if (_cairo_pdf_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED)
|
|
|
|
|
return TRUE;
|
|
|
|
|
else
|
|
|
|
|
return FALSE;
|
2006-04-18 11:31:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_int_status_t
|
2008-01-07 21:08:09 +10:30
|
|
|
_cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
|
2006-04-18 11:31:59 -07:00
|
|
|
{
|
2007-10-04 23:15:21 +01:00
|
|
|
cairo_status_t status;
|
|
|
|
|
|
2008-01-07 21:08:09 +10:30
|
|
|
status = _cairo_pdf_surface_close_content_stream (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-08-25 06:44:08 +09:30
|
|
|
|
2008-01-07 21:15:18 +10:30
|
|
|
status = _cairo_array_append (&surface->knockout_group, &surface->content);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-01-07 21:08:09 +10:30
|
|
|
_cairo_pdf_group_resources_clear (&surface->resources);
|
2008-01-16 16:33:22 +00:00
|
|
|
return _cairo_pdf_surface_open_content_stream (surface, TRUE);
|
2006-04-18 11:31:59 -07:00
|
|
|
}
|
|
|
|
|
|
2006-04-14 15:23:30 -07:00
|
|
|
static cairo_int_status_t
|
|
|
|
|
_cairo_pdf_surface_paint (void *abstract_surface,
|
|
|
|
|
cairo_operator_t op,
|
|
|
|
|
cairo_pattern_t *source)
|
|
|
|
|
{
|
2006-04-14 16:50:16 -07:00
|
|
|
cairo_pdf_surface_t *surface = abstract_surface;
|
2006-04-18 23:24:14 -07:00
|
|
|
cairo_status_t status;
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_pdf_smask_group_t *group;
|
|
|
|
|
cairo_pdf_resource_t pattern_res, gstate_res;
|
2006-04-14 16:50:16 -07:00
|
|
|
|
2008-01-07 21:08:09 +10:30
|
|
|
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
|
2007-03-07 15:54:20 -05:00
|
|
|
return _cairo_pdf_surface_analyze_operation (surface, op, source);
|
2008-01-07 21:08:09 +10:30
|
|
|
} else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
|
|
|
|
|
status = _cairo_pdf_surface_start_fallback (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
}
|
2006-04-18 23:24:14 -07:00
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
|
2006-04-18 23:24:14 -07:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
pattern_res.id = 0;
|
|
|
|
|
gstate_res.id = 0;
|
|
|
|
|
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res);
|
|
|
|
|
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2007-10-04 23:18:33 +01:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
if (gstate_res.id != 0) {
|
|
|
|
|
group = _cairo_pdf_surface_create_smask_group (surface);
|
|
|
|
|
if (group == NULL)
|
2008-01-10 15:53:54 +00:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2006-04-14 16:50:16 -07:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
group->operation = PDF_PAINT;
|
|
|
|
|
group->source = cairo_pattern_reference (source);
|
|
|
|
|
group->source_res = pattern_res;
|
|
|
|
|
status = _cairo_pdf_surface_add_smask_group (surface, group);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status) {
|
|
|
|
|
_cairo_pdf_smask_group_destroy (group);
|
2007-10-04 23:15:21 +01:00
|
|
|
return status;
|
2008-01-10 15:53:54 +00:00
|
|
|
}
|
2007-10-04 23:15:21 +01:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_smask (surface, gstate_res);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"q /s%d gs /x%d Do Q\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
gstate_res.id,
|
|
|
|
|
group->group_res.id);
|
|
|
|
|
} else {
|
|
|
|
|
status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
|
2007-08-25 06:44:08 +09:30
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"0 0 %f %f re f\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
surface->width, surface->height);
|
|
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_surface_unselect_pattern (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
|
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2006-04-14 15:23:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_int_status_t
|
|
|
|
|
_cairo_pdf_surface_mask (void *abstract_surface,
|
|
|
|
|
cairo_operator_t op,
|
|
|
|
|
cairo_pattern_t *source,
|
|
|
|
|
cairo_pattern_t *mask)
|
|
|
|
|
{
|
2006-04-14 16:50:16 -07:00
|
|
|
cairo_pdf_surface_t *surface = abstract_surface;
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_pdf_smask_group_t *group;
|
2007-09-09 11:20:02 +09:30
|
|
|
cairo_status_t status, status2;
|
2006-04-14 16:50:16 -07:00
|
|
|
|
2007-09-09 11:20:02 +09:30
|
|
|
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
|
|
|
|
|
status = _cairo_pdf_surface_analyze_operation (surface, op, source);
|
|
|
|
|
if (status != CAIRO_STATUS_SUCCESS &&
|
|
|
|
|
status != CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
|
|
|
|
|
return status;
|
2006-04-14 16:50:16 -07:00
|
|
|
|
2007-09-09 11:20:02 +09:30
|
|
|
status2 = _cairo_pdf_surface_analyze_operation (surface, op, mask);
|
|
|
|
|
if (status2 != CAIRO_STATUS_SUCCESS)
|
|
|
|
|
return status2;
|
2006-04-14 16:50:16 -07:00
|
|
|
|
2007-09-09 11:20:02 +09:30
|
|
|
return status;
|
2008-01-07 21:08:09 +10:30
|
|
|
} else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
|
|
|
|
|
status = _cairo_pdf_surface_start_fallback (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-09-09 11:20:02 +09:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
|
|
|
|
|
assert (_cairo_pdf_surface_operation_supported (surface, op, mask));
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
group = _cairo_pdf_surface_create_smask_group (surface);
|
|
|
|
|
if (group == NULL)
|
2008-01-10 15:53:54 +00:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2008-01-06 16:15:32 +10:30
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
group->operation = PDF_MASK;
|
|
|
|
|
group->source = cairo_pattern_reference (source);
|
|
|
|
|
group->mask = cairo_pattern_reference (mask);
|
|
|
|
|
group->source_res = _cairo_pdf_surface_new_object (surface);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (group->source_res.id == 0) {
|
|
|
|
|
_cairo_pdf_smask_group_destroy (group);
|
2008-01-07 20:55:56 +10:30
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2008-01-10 15:53:54 +00:00
|
|
|
}
|
2007-10-04 23:18:33 +01:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_smask_group (surface, group);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status) {
|
|
|
|
|
_cairo_pdf_smask_group_destroy (group);
|
2007-10-04 23:15:21 +01:00
|
|
|
return status;
|
2008-01-10 15:53:54 +00:00
|
|
|
}
|
2007-09-09 11:20:02 +09:30
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_smask (surface, group->group_res);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_xobject (surface, group->source_res);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-09-09 11:20:02 +09:30
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2007-09-09 11:20:02 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"q /s%d gs /x%d Do Q\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
group->group_res.id,
|
|
|
|
|
group->source_res.id);
|
2007-09-09 11:20:02 +09:30
|
|
|
|
|
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2006-04-14 15:23:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_int_status_t
|
|
|
|
|
_cairo_pdf_surface_stroke (void *abstract_surface,
|
|
|
|
|
cairo_operator_t op,
|
|
|
|
|
cairo_pattern_t *source,
|
|
|
|
|
cairo_path_fixed_t *path,
|
|
|
|
|
cairo_stroke_style_t *style,
|
|
|
|
|
cairo_matrix_t *ctm,
|
|
|
|
|
cairo_matrix_t *ctm_inverse,
|
|
|
|
|
double tolerance,
|
|
|
|
|
cairo_antialias_t antialias)
|
|
|
|
|
{
|
2006-04-14 16:50:16 -07:00
|
|
|
cairo_pdf_surface_t *surface = abstract_surface;
|
2006-04-18 16:53:23 -07:00
|
|
|
cairo_status_t status;
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_pdf_smask_group_t *group;
|
|
|
|
|
cairo_pdf_resource_t pattern_res, gstate_res;
|
2006-04-14 16:50:16 -07:00
|
|
|
|
2006-06-19 11:03:32 -07:00
|
|
|
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
|
2007-03-07 15:54:20 -05:00
|
|
|
return _cairo_pdf_surface_analyze_operation (surface, op, source);
|
2006-04-14 16:50:16 -07:00
|
|
|
|
2007-04-20 02:57:12 -04:00
|
|
|
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
|
2006-04-14 16:50:16 -07:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
pattern_res.id = 0;
|
|
|
|
|
gstate_res.id = 0;
|
|
|
|
|
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res);
|
2008-01-06 16:15:32 +10:30
|
|
|
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
|
2008-01-07 20:55:56 +10:30
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2006-04-18 16:53:23 -07:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
if (gstate_res.id != 0) {
|
|
|
|
|
group = _cairo_pdf_surface_create_smask_group (surface);
|
|
|
|
|
if (group == NULL)
|
2008-01-10 15:53:54 +00:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
group->operation = PDF_STROKE;
|
|
|
|
|
group->source = cairo_pattern_reference (source);
|
|
|
|
|
group->source_res = pattern_res;
|
|
|
|
|
status = _cairo_path_fixed_init_copy (&group->path, path);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status) {
|
|
|
|
|
_cairo_pdf_smask_group_destroy (group);
|
2007-10-04 23:15:21 +01:00
|
|
|
return status;
|
2008-01-10 15:53:54 +00:00
|
|
|
}
|
2006-05-12 14:56:11 -07:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
group->style = style;
|
|
|
|
|
group->ctm = *ctm;
|
|
|
|
|
group->ctm_inverse = *ctm_inverse;
|
|
|
|
|
status = _cairo_pdf_surface_add_smask_group (surface, group);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status) {
|
|
|
|
|
_cairo_pdf_smask_group_destroy (group);
|
2007-10-04 23:15:21 +01:00
|
|
|
return status;
|
2008-01-10 15:53:54 +00:00
|
|
|
}
|
2007-10-04 23:15:21 +01:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_smask (surface, gstate_res);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"q /s%d gs /x%d Do Q\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
gstate_res.id,
|
|
|
|
|
group->group_res.id);
|
|
|
|
|
} else {
|
|
|
|
|
status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, TRUE);
|
2007-08-25 06:44:08 +09:30
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
2008-02-17 19:49:39 +10:30
|
|
|
status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
|
|
|
|
|
path,
|
|
|
|
|
style,
|
|
|
|
|
ctm,
|
|
|
|
|
ctm_inverse);
|
2007-08-25 06:44:08 +09:30
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_surface_unselect_pattern (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
|
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2006-04-14 15:23:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_int_status_t
|
|
|
|
|
_cairo_pdf_surface_fill (void *abstract_surface,
|
|
|
|
|
cairo_operator_t op,
|
2006-04-14 16:50:16 -07:00
|
|
|
cairo_pattern_t *source,
|
2006-04-14 15:23:30 -07:00
|
|
|
cairo_path_fixed_t *path,
|
|
|
|
|
cairo_fill_rule_t fill_rule,
|
|
|
|
|
double tolerance,
|
|
|
|
|
cairo_antialias_t antialias)
|
|
|
|
|
{
|
|
|
|
|
cairo_pdf_surface_t *surface = abstract_surface;
|
|
|
|
|
cairo_status_t status;
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_pdf_smask_group_t *group;
|
|
|
|
|
cairo_pdf_resource_t pattern_res, gstate_res;
|
2006-04-14 15:23:30 -07:00
|
|
|
|
2008-01-07 21:08:09 +10:30
|
|
|
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
|
2007-03-07 15:54:20 -05:00
|
|
|
return _cairo_pdf_surface_analyze_operation (surface, op, source);
|
2008-01-07 21:08:09 +10:30
|
|
|
} else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
|
|
|
|
|
status = _cairo_pdf_surface_start_fallback (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
}
|
2006-04-18 11:31:59 -07:00
|
|
|
|
2007-04-20 02:57:12 -04:00
|
|
|
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
|
2006-04-14 15:23:30 -07:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
pattern_res.id = 0;
|
|
|
|
|
gstate_res.id = 0;
|
|
|
|
|
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res);
|
2008-01-06 16:15:32 +10:30
|
|
|
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
|
2008-01-07 20:55:56 +10:30
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2006-04-14 15:23:30 -07:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
if (gstate_res.id != 0) {
|
|
|
|
|
group = _cairo_pdf_surface_create_smask_group (surface);
|
|
|
|
|
if (group == NULL)
|
2008-01-10 15:53:54 +00:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
group->operation = PDF_FILL;
|
|
|
|
|
group->source = cairo_pattern_reference (source);
|
|
|
|
|
group->source_res = pattern_res;
|
|
|
|
|
status = _cairo_path_fixed_init_copy (&group->path, path);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status) {
|
|
|
|
|
_cairo_pdf_smask_group_destroy (group);
|
2007-10-04 23:15:21 +01:00
|
|
|
return status;
|
2008-01-10 15:53:54 +00:00
|
|
|
}
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
group->fill_rule = fill_rule;
|
|
|
|
|
status = _cairo_pdf_surface_add_smask_group (surface, group);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status) {
|
|
|
|
|
_cairo_pdf_smask_group_destroy (group);
|
2007-10-04 23:15:21 +01:00
|
|
|
return status;
|
2008-01-10 15:53:54 +00:00
|
|
|
}
|
2007-10-04 23:15:21 +01:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_smask (surface, gstate_res);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"q /s%d gs /x%d Do Q\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
gstate_res.id,
|
|
|
|
|
group->group_res.id);
|
|
|
|
|
} else {
|
|
|
|
|
status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
|
2007-08-25 06:44:08 +09:30
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
status = _cairo_pdf_operators_fill (&surface->pdf_operators,
|
|
|
|
|
path,
|
|
|
|
|
fill_rule);
|
2007-08-25 06:44:08 +09:30
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_surface_unselect_pattern (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
|
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2006-04-14 15:23:30 -07:00
|
|
|
}
|
|
|
|
|
|
2008-02-17 16:45:15 +10:30
|
|
|
static cairo_int_status_t
|
|
|
|
|
_cairo_pdf_surface_fill_stroke (void *abstract_surface,
|
|
|
|
|
cairo_operator_t fill_op,
|
|
|
|
|
cairo_pattern_t *fill_source,
|
|
|
|
|
cairo_fill_rule_t fill_rule,
|
|
|
|
|
double fill_tolerance,
|
|
|
|
|
cairo_antialias_t fill_antialias,
|
|
|
|
|
cairo_path_fixed_t *path,
|
|
|
|
|
cairo_operator_t stroke_op,
|
|
|
|
|
cairo_pattern_t *stroke_source,
|
|
|
|
|
cairo_stroke_style_t *stroke_style,
|
|
|
|
|
cairo_matrix_t *stroke_ctm,
|
|
|
|
|
cairo_matrix_t *stroke_ctm_inverse,
|
|
|
|
|
double stroke_tolerance,
|
|
|
|
|
cairo_antialias_t stroke_antialias)
|
|
|
|
|
{
|
|
|
|
|
cairo_pdf_surface_t *surface = abstract_surface;
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
cairo_pdf_resource_t fill_pattern_res, stroke_pattern_res, gstate_res;
|
|
|
|
|
|
|
|
|
|
/* During analysis we return unsupported and let the _fill and
|
|
|
|
|
* _stroke functions that are on the fallback path do the analysis
|
|
|
|
|
* for us. During render we may still encounter unsupported
|
|
|
|
|
* combinations of fill/stroke patterns. However we can return
|
|
|
|
|
* unsupported anytime to let the _fill and _stroke functions take
|
|
|
|
|
* over.
|
|
|
|
|
*/
|
|
|
|
|
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
|
|
|
|
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
|
|
|
2008-03-14 21:26:04 +10:30
|
|
|
/* PDF rendering of fill-stroke is not the same as cairo when
|
|
|
|
|
* either the fill or stroke is not opaque.
|
2008-02-17 16:45:15 +10:30
|
|
|
*/
|
2008-03-14 21:26:04 +10:30
|
|
|
if ( !_cairo_pattern_is_opaque (fill_source) ||
|
|
|
|
|
!_cairo_pattern_is_opaque (stroke_source))
|
2008-02-17 16:45:15 +10:30
|
|
|
{
|
|
|
|
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
2008-03-14 21:26:04 +10:30
|
|
|
}
|
2008-02-17 16:45:15 +10:30
|
|
|
|
|
|
|
|
fill_pattern_res.id = 0;
|
|
|
|
|
gstate_res.id = 0;
|
|
|
|
|
status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source,
|
|
|
|
|
&fill_pattern_res,
|
|
|
|
|
&gstate_res);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
assert (gstate_res.id == 0);
|
|
|
|
|
|
|
|
|
|
stroke_pattern_res.id = 0;
|
|
|
|
|
gstate_res.id = 0;
|
|
|
|
|
status = _cairo_pdf_surface_add_pdf_pattern (surface,
|
|
|
|
|
stroke_source,
|
|
|
|
|
&stroke_pattern_res,
|
|
|
|
|
&gstate_res);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
assert (gstate_res.id == 0);
|
|
|
|
|
|
|
|
|
|
/* As PDF has separate graphics state for fill and stroke we can
|
|
|
|
|
* select both at the same time */
|
|
|
|
|
status = _cairo_pdf_surface_select_pattern (surface, fill_source,
|
|
|
|
|
fill_pattern_res, FALSE);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
status = _cairo_pdf_surface_select_pattern (surface, stroke_source,
|
|
|
|
|
stroke_pattern_res, TRUE);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
status = _cairo_pdf_operators_fill_stroke (&surface->pdf_operators,
|
|
|
|
|
path,
|
|
|
|
|
fill_rule,
|
|
|
|
|
stroke_style,
|
|
|
|
|
stroke_ctm,
|
|
|
|
|
stroke_ctm_inverse);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_surface_unselect_pattern (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-02-17 16:45:15 +10:30
|
|
|
|
|
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-29 19:55:41 +09:30
|
|
|
static cairo_bool_t
|
|
|
|
|
_cairo_pdf_surface_has_show_text_glyphs (void *abstract_surface)
|
|
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-14 15:23:30 -07:00
|
|
|
static cairo_int_status_t
|
2008-06-29 19:55:41 +09:30
|
|
|
_cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
|
|
|
|
|
cairo_operator_t op,
|
|
|
|
|
cairo_pattern_t *source,
|
|
|
|
|
const char *utf8,
|
|
|
|
|
int utf8_len,
|
|
|
|
|
cairo_glyph_t *glyphs,
|
|
|
|
|
int num_glyphs,
|
|
|
|
|
const cairo_text_cluster_t *clusters,
|
|
|
|
|
int num_clusters,
|
|
|
|
|
cairo_bool_t backward,
|
|
|
|
|
cairo_scaled_font_t *scaled_font)
|
2006-04-14 15:23:30 -07:00
|
|
|
{
|
2006-04-14 16:50:16 -07:00
|
|
|
cairo_pdf_surface_t *surface = abstract_surface;
|
2006-04-19 11:04:37 -07:00
|
|
|
cairo_status_t status;
|
2008-01-07 20:55:56 +10:30
|
|
|
cairo_pdf_smask_group_t *group;
|
|
|
|
|
cairo_pdf_resource_t pattern_res, gstate_res;
|
2006-04-14 16:50:16 -07:00
|
|
|
|
|
|
|
|
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
|
2007-03-07 15:54:20 -05:00
|
|
|
return _cairo_pdf_surface_analyze_operation (surface, op, source);
|
2006-04-14 16:50:16 -07:00
|
|
|
|
2007-04-20 02:57:12 -04:00
|
|
|
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
|
2006-04-14 16:50:16 -07:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
pattern_res.id = 0;
|
|
|
|
|
gstate_res.id = 0;
|
|
|
|
|
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res);
|
2008-01-06 16:15:32 +10:30
|
|
|
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
|
2008-01-07 20:55:56 +10:30
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2008-01-07 20:36:32 +10:30
|
|
|
if (status)
|
|
|
|
|
return status;
|
2006-05-16 22:53:05 -04:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
if (gstate_res.id != 0) {
|
|
|
|
|
group = _cairo_pdf_surface_create_smask_group (surface);
|
|
|
|
|
if (group == NULL)
|
2008-01-10 15:53:54 +00:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2008-01-07 20:55:56 +10:30
|
|
|
|
|
|
|
|
group->operation = PDF_SHOW_GLYPHS;
|
|
|
|
|
group->source = cairo_pattern_reference (source);
|
|
|
|
|
group->source_res = pattern_res;
|
2008-06-29 19:55:41 +09:30
|
|
|
|
|
|
|
|
if (utf8_len) {
|
2008-08-06 10:51:34 +01:00
|
|
|
group->utf8 = malloc (utf8_len);
|
|
|
|
|
if (group->utf8 == NULL) {
|
2008-06-29 19:55:41 +09:30
|
|
|
_cairo_pdf_smask_group_destroy (group);
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
}
|
|
|
|
|
memcpy (group->utf8, utf8, utf8_len);
|
|
|
|
|
}
|
|
|
|
|
group->utf8_len = utf8_len;
|
|
|
|
|
|
|
|
|
|
if (num_glyphs) {
|
|
|
|
|
group->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
|
|
|
|
|
if (group->glyphs == NULL) {
|
|
|
|
|
_cairo_pdf_smask_group_destroy (group);
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
}
|
|
|
|
|
memcpy (group->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
|
2008-04-04 12:53:13 +01:00
|
|
|
}
|
2008-01-07 20:55:56 +10:30
|
|
|
group->num_glyphs = num_glyphs;
|
2008-06-29 19:55:41 +09:30
|
|
|
|
|
|
|
|
if (num_clusters) {
|
|
|
|
|
group->clusters = _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t));
|
2008-08-06 10:51:34 +01:00
|
|
|
if (group->clusters == NULL) {
|
2008-06-29 19:55:41 +09:30
|
|
|
_cairo_pdf_smask_group_destroy (group);
|
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
|
}
|
|
|
|
|
memcpy (group->clusters, clusters, sizeof (cairo_text_cluster_t) * num_clusters);
|
|
|
|
|
}
|
|
|
|
|
group->num_clusters = num_clusters;
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
group->scaled_font = cairo_scaled_font_reference (scaled_font);
|
|
|
|
|
status = _cairo_pdf_surface_add_smask_group (surface, group);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status) {
|
|
|
|
|
_cairo_pdf_smask_group_destroy (group);
|
2007-10-04 23:15:21 +01:00
|
|
|
return status;
|
2008-01-10 15:53:54 +00:00
|
|
|
}
|
2007-10-04 23:15:21 +01:00
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_smask (surface, gstate_res);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2008-01-07 20:55:56 +10:30
|
|
|
status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
|
2008-01-10 15:53:54 +00:00
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-04-27 09:49:45 -07:00
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2007-08-25 06:44:08 +09:30
|
|
|
_cairo_output_stream_printf (surface->output,
|
2008-02-20 21:05:23 +10:30
|
|
|
"q /s%d gs /x%d Do Q\n",
|
2008-01-07 20:55:56 +10:30
|
|
|
gstate_res.id,
|
|
|
|
|
group->group_res.id);
|
|
|
|
|
} else {
|
|
|
|
|
status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
|
2007-08-25 06:44:08 +09:30
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
2008-06-03 20:56:11 +09:30
|
|
|
/* Each call to show_glyphs() with a transclucent pattern must
|
|
|
|
|
* be in a separate text object otherwise overlapping text
|
|
|
|
|
* from separate calls to show_glyphs will not composite with
|
|
|
|
|
* each other. */
|
|
|
|
|
if (! _cairo_pattern_is_opaque (source)) {
|
|
|
|
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-29 19:38:13 +09:30
|
|
|
status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
|
2008-06-29 19:55:41 +09:30
|
|
|
utf8, utf8_len,
|
2008-06-29 19:38:13 +09:30
|
|
|
glyphs, num_glyphs,
|
2008-06-29 19:55:41 +09:30
|
|
|
clusters, num_clusters,
|
|
|
|
|
backward,
|
2008-06-29 19:38:13 +09:30
|
|
|
scaled_font);
|
2007-08-25 06:44:08 +09:30
|
|
|
if (status)
|
|
|
|
|
return status;
|
2008-01-07 20:55:56 +10:30
|
|
|
|
2008-06-03 20:55:03 +09:30
|
|
|
status = _cairo_pdf_surface_unselect_pattern (surface);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
2007-04-27 09:49:45 -07:00
|
|
|
}
|
|
|
|
|
|
2008-01-07 21:04:06 +10:30
|
|
|
return _cairo_output_stream_get_status (surface->output);
|
2006-04-14 15:23:30 -07:00
|
|
|
}
|
|
|
|
|
|
2008-06-29 19:55:41 +09:30
|
|
|
|
2006-03-24 11:48:35 -08:00
|
|
|
static void
|
2006-04-14 11:33:48 -07:00
|
|
|
_cairo_pdf_surface_set_paginated_mode (void *abstract_surface,
|
|
|
|
|
cairo_paginated_mode_t paginated_mode)
|
2006-03-24 11:48:35 -08:00
|
|
|
{
|
2006-04-14 11:33:48 -07:00
|
|
|
cairo_pdf_surface_t *surface = abstract_surface;
|
2006-03-24 11:48:35 -08:00
|
|
|
|
|
|
|
|
surface->paginated_mode = paginated_mode;
|
|
|
|
|
}
|
2006-04-13 12:56:58 -07:00
|
|
|
|
|
|
|
|
static const cairo_surface_backend_t cairo_pdf_surface_backend = {
|
|
|
|
|
CAIRO_SURFACE_TYPE_PDF,
|
2007-09-05 22:26:16 +09:30
|
|
|
_cairo_pdf_surface_create_similar,
|
2006-04-13 12:56:58 -07:00
|
|
|
_cairo_pdf_surface_finish,
|
|
|
|
|
NULL, /* acquire_source_image */
|
|
|
|
|
NULL, /* release_source_image */
|
|
|
|
|
NULL, /* acquire_dest_image */
|
|
|
|
|
NULL, /* release_dest_image */
|
|
|
|
|
NULL, /* clone_similar */
|
2006-04-25 02:33:18 -07:00
|
|
|
NULL, /* composite */
|
|
|
|
|
NULL, /* fill_rectangles */
|
|
|
|
|
NULL, /* composite_trapezoids */
|
2008-01-07 21:17:26 +10:30
|
|
|
NULL, /* _cairo_pdf_surface_copy_page */
|
2006-04-13 12:56:58 -07:00
|
|
|
_cairo_pdf_surface_show_page,
|
|
|
|
|
NULL, /* set_clip_region */
|
|
|
|
|
_cairo_pdf_surface_intersect_clip_path,
|
|
|
|
|
_cairo_pdf_surface_get_extents,
|
2006-04-25 02:33:18 -07:00
|
|
|
NULL, /* old_show_glyphs */
|
2006-04-13 12:56:58 -07:00
|
|
|
_cairo_pdf_surface_get_font_options,
|
|
|
|
|
NULL, /* flush */
|
|
|
|
|
NULL, /* mark_dirty_rectangle */
|
|
|
|
|
NULL, /* scaled_font_fini */
|
|
|
|
|
NULL, /* scaled_glyph_fini */
|
|
|
|
|
|
|
|
|
|
/* Here are the drawing functions */
|
|
|
|
|
|
2006-04-14 15:23:30 -07:00
|
|
|
_cairo_pdf_surface_paint,
|
|
|
|
|
_cairo_pdf_surface_mask,
|
|
|
|
|
_cairo_pdf_surface_stroke,
|
2006-04-13 12:56:58 -07:00
|
|
|
_cairo_pdf_surface_fill,
|
2008-06-29 13:56:14 -04:00
|
|
|
NULL, /* show_glyphs */
|
2006-04-14 15:23:30 -07:00
|
|
|
NULL, /* snapshot */
|
2007-05-02 10:00:22 +01:00
|
|
|
|
|
|
|
|
NULL, /* is_compatible */
|
|
|
|
|
NULL, /* reset */
|
2008-02-17 16:45:15 +10:30
|
|
|
_cairo_pdf_surface_fill_stroke,
|
2008-06-29 19:55:41 +09:30
|
|
|
NULL, /* create_solid_pattern_surface */
|
|
|
|
|
_cairo_pdf_surface_has_show_text_glyphs,
|
|
|
|
|
_cairo_pdf_surface_show_text_glyphs,
|
2006-04-13 12:56:58 -07:00
|
|
|
};
|
2006-04-14 11:33:48 -07:00
|
|
|
|
|
|
|
|
static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend = {
|
2006-05-12 13:31:12 -07:00
|
|
|
_cairo_pdf_surface_start_page,
|
2008-07-08 21:18:45 +09:30
|
|
|
_cairo_pdf_surface_set_paginated_mode,
|
|
|
|
|
NULL, /* set_bounding_box */
|
|
|
|
|
_cairo_pdf_surface_has_fallback_images,
|
2006-04-14 11:33:48 -07:00
|
|
|
};
|