--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -2,18 +2,18 @@ Snapshots of cairo and glitz for mozilla
We only include the relevant parts of each release (generally, src/*.[ch]),
as we have Makefile.in's that integrate into the Mozilla build system. For
documentation and similar, please see the official tarballs at
http://www.cairographics.org/.
VERSIONS:
- cairo (1.5.x - 1.5.8-30-g80e11a8)
- pixman (0.9.x - pixman-0.9.6-34-g787cc57)
+ cairo (1.5.x - 1.5.8-87-g21049a9)
+ pixman (0.9.x - pixman-0.9.6-37-g8d79c48)
glitz 0.5.2 (cvs - 2006-01-10)
***** NOTE FOR VISUAL C++ 6.0 *****
VC6 is not supported. Please upgrade to VC8.
==== Patches ====
--- a/gfx/cairo/cairo/src/Makefile.in
+++ b/gfx/cairo/cairo/src/Makefile.in
@@ -89,16 +89,17 @@ CSRCS = \
cairo-freelist.c \
cairo-gstate.c \
cairo-hash.c \
cairo-hull.c \
cairo-image-surface.c \
cairo-lzw.c \
cairo-matrix.c \
cairo-meta-surface.c \
+ cairo-misc.c \
cairo-mutex.c \
cairo-output-stream.c \
cairo-paginated-surface.c \
cairo-path.c \
cairo-path-bounds.c \
cairo-path-fill.c \
cairo-path-fixed.c \
cairo-path-stroke.c \
--- a/gfx/cairo/cairo/src/cairo-debug.c
+++ b/gfx/cairo/cairo/src/cairo-debug.c
@@ -64,10 +64,12 @@ cairo_debug_reset_static_data (void)
_cairo_font_reset_static_data ();
#if CAIRO_HAS_FT_FONT
_cairo_ft_font_reset_static_data ();
#endif
_cairo_pattern_reset_static_data ();
+ _cairo_scaled_font_reset_static_data ();
+
CAIRO_MUTEX_FINALIZE ();
}
--- a/gfx/cairo/cairo/src/cairo-font-face.c
+++ b/gfx/cairo/cairo/src/cairo-font-face.c
@@ -471,21 +471,19 @@ static cairo_status_t
{
cairo_toy_font_face_t *font_face = abstract_font_face;
const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT;
cairo_status_t status;
if (font_face->base.status)
return font_face->base.status;
- if (options != NULL) {
- status = cairo_font_options_status ((cairo_font_options_t *) options);
- if (status)
- return status;
- }
+ status = cairo_font_options_status ((cairo_font_options_t *) options);
+ if (status)
+ return status;
return _cairo_font_face_set_error (&font_face->base,
backend->create_toy (font_face,
font_matrix,
ctm,
options,
scaled_font));
}
--- a/gfx/cairo/cairo/src/cairo-font-options.c
+++ b/gfx/cairo/cairo/src/cairo-font-options.c
@@ -47,36 +47,30 @@ static const cairo_font_options_t _cairo
* _cairo_font_options_init_default:
* @options: a #cairo_font_options_t
*
* Initializes all fields of the font options object to default values.
**/
void
_cairo_font_options_init_default (cairo_font_options_t *options)
{
- if (cairo_font_options_status (options))
- return;
-
options->antialias = CAIRO_ANTIALIAS_DEFAULT;
options->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
options->hint_style = CAIRO_HINT_STYLE_DEFAULT;
options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT;
}
void
_cairo_font_options_init_copy (cairo_font_options_t *options,
const cairo_font_options_t *other)
{
- if (other != NULL) {
- options->antialias = other->antialias;
- options->subpixel_order = other->subpixel_order;
- options->hint_style = other->hint_style;
- options->hint_metrics = other->hint_metrics;
- } else
- _cairo_font_options_init_default (options);
+ options->antialias = other->antialias;
+ options->subpixel_order = other->subpixel_order;
+ options->hint_style = other->hint_style;
+ options->hint_metrics = other->hint_metrics;
}
/**
* cairo_font_options_create:
*
* Allocates a new font options object with all options initialized
* to default values.
*
@@ -116,21 +110,18 @@ slim_hidden_def (cairo_font_options_crea
* error object is returned where all operations on the object do nothing.
* You can check for this with cairo_font_options_status().
**/
cairo_font_options_t *
cairo_font_options_copy (const cairo_font_options_t *original)
{
cairo_font_options_t *options;
- if (original != NULL &&
- cairo_font_options_status ((cairo_font_options_t *) original))
- {
+ if (cairo_font_options_status ((cairo_font_options_t *) original))
return (cairo_font_options_t *) &_cairo_font_options_nil;
- }
options = malloc (sizeof (cairo_font_options_t));
if (!options) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_options_t *) &_cairo_font_options_nil;
}
_cairo_font_options_init_copy (options, original);
@@ -188,17 +179,16 @@ slim_hidden_def (cairo_font_options_stat
**/
void
cairo_font_options_merge (cairo_font_options_t *options,
const cairo_font_options_t *other)
{
if (cairo_font_options_status (options))
return;
- /* A NULL other maps to the defaults and would not overwrite options */
if (cairo_font_options_status ((cairo_font_options_t *) other))
return;
if (other->antialias != CAIRO_ANTIALIAS_DEFAULT)
options->antialias = other->antialias;
if (other->subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT)
options->subpixel_order = other->subpixel_order;
if (other->hint_style != CAIRO_HINT_STYLE_DEFAULT)
@@ -210,26 +200,28 @@ slim_hidden_def (cairo_font_options_merg
/**
* cairo_font_options_equal:
* @options: a #cairo_font_options_t
* @other: another #cairo_font_options_t
*
* Compares two font options objects for equality.
*
- * Return value: %TRUE if all fields of the two font options objects match
+ * Return value: %TRUE if all fields of the two font options objects match.
+ * Note that this function will return %FALSE if either object is in
+ * error.
**/
cairo_bool_t
cairo_font_options_equal (const cairo_font_options_t *options,
const cairo_font_options_t *other)
{
- if (options == NULL)
- options = &_cairo_font_options_nil;
- if (other == NULL)
- other = &_cairo_font_options_nil;
+ if (cairo_font_options_status ((cairo_font_options_t *) options))
+ return FALSE;
+ if (cairo_font_options_status ((cairo_font_options_t *) other))
+ return FALSE;
if (options == other)
return TRUE;
return (options->antialias == other->antialias &&
options->subpixel_order == other->subpixel_order &&
options->hint_style == other->hint_style &&
options->hint_metrics == other->hint_metrics);
@@ -246,18 +238,18 @@ slim_hidden_def (cairo_font_options_equa
*
* Return value: the hash value for the font options object.
* The return value can be cast to a 32-bit type if a
* 32-bit hash value is needed.
**/
unsigned long
cairo_font_options_hash (const cairo_font_options_t *options)
{
- if (options == NULL)
- options = &_cairo_font_options_nil;
+ if (cairo_font_options_status ((cairo_font_options_t *) options))
+ options = &_cairo_font_options_nil; /* force default values */
return ((options->antialias) |
(options->subpixel_order << 4) |
(options->hint_style << 8) |
(options->hint_metrics << 16));
}
slim_hidden_def (cairo_font_options_hash);
--- a/gfx/cairo/cairo/src/cairo-ft-font.c
+++ b/gfx/cairo/cairo/src/cairo-ft-font.c
@@ -940,17 +940,17 @@ static cairo_status_t
}
*surface = (cairo_image_surface_t *)
cairo_image_surface_create_for_data (data,
format,
width, height, stride);
if ((*surface)->base.status) {
free (data);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return (*surface)->base.status;
}
if (subpixel)
pixman_image_set_component_alpha ((*surface)->pixman_image, TRUE);
_cairo_image_surface_assume_ownership_of_data ((*surface));
return CAIRO_STATUS_SUCCESS;
@@ -1059,19 +1059,18 @@ static cairo_status_t
bitmap.num_grays = 256;
stride = (width * hmul + 3) & -4;
}
bitmap.pitch = stride;
bitmap.width = width * hmul;
bitmap.rows = height * vmul;
bitmap.buffer = calloc (stride, bitmap.rows);
- if (bitmap.buffer == NULL) {
+ if (bitmap.buffer == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
FT_Outline_Translate (outline, -cbox.xMin*hmul, -cbox.yMin*vmul);
if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
free (bitmap.buffer);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -1611,16 +1610,21 @@ static cairo_status_t
FcResult result;
int fcslant;
int fcweight;
cairo_matrix_t scale;
cairo_status_t status;
cairo_ft_font_transform_t sf;
cairo_ft_options_t ft_options;
+ cairo_matrix_multiply (&scale, font_matrix, ctm);
+ status = _compute_transform (&sf, &scale);
+ if (status)
+ return status;
+
pattern = FcPatternCreate ();
if (!pattern)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (!FcPatternAddString (pattern,
FC_FAMILY, (unsigned char *) toy_face->family))
{
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -1657,34 +1661,29 @@ static cairo_status_t
break;
}
if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FREE_PATTERN;
}
- cairo_matrix_multiply (&scale, font_matrix, ctm);
- _compute_transform (&sf, &scale);
-
if (! FcPatternAddDouble (pattern, FC_PIXEL_SIZE, sf.y_scale)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FREE_PATTERN;
}
if (! FcConfigSubstitute (NULL, pattern, FcMatchPattern)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FREE_PATTERN;
}
- if (font_options != NULL) {
- status = _cairo_ft_font_options_substitute (font_options, pattern);
- if (status)
- goto FREE_PATTERN;
- }
+ status = _cairo_ft_font_options_substitute (font_options, pattern);
+ if (status)
+ goto FREE_PATTERN;
FcDefaultSubstitute (pattern);
resolved = FcFontMatch (NULL, pattern, &result);
if (!resolved) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FREE_PATTERN;
}
@@ -2318,17 +2317,17 @@ static cairo_font_face_t *
for (font_face = unscaled->faces, prev_font_face = &unscaled->faces;
font_face;
prev_font_face = &font_face->next, font_face = font_face->next)
{
if (font_face->ft_options.load_flags == ft_options->load_flags &&
font_face->ft_options.extra_flags == ft_options->extra_flags &&
cairo_font_options_equal (&font_face->ft_options.base, &ft_options->base))
{
- if (! font_face->base.status)
+ if (font_face->base.status == CAIRO_STATUS_SUCCESS)
return cairo_font_face_reference (&font_face->base);
/* The font_face has been left in an error state, abandon it. */
*prev_font_face = font_face->next;
break;
}
}
--- a/gfx/cairo/cairo/src/cairo-gstate.c
+++ b/gfx/cairo/cairo/src/cairo-gstate.c
@@ -895,95 +895,16 @@ cairo_status_t
gstate->op,
&pattern.base);
_cairo_pattern_fini (&pattern.base);
return status;
}
-/**
- * _cairo_operator_bounded_by_mask:
- * @op: a #cairo_operator_t
- *
- * A bounded operator is one where mask pixel
- * of zero results in no effect on the destination image.
- *
- * Unbounded operators often require special handling; if you, for
- * example, draw trapezoids with an unbounded operator, the effect
- * extends past the bounding box of the trapezoids.
- *
- * Return value: %TRUE if the operator is bounded by the mask operand
- **/
-cairo_bool_t
-_cairo_operator_bounded_by_mask (cairo_operator_t op)
-{
- switch (op) {
- case CAIRO_OPERATOR_CLEAR:
- case CAIRO_OPERATOR_SOURCE:
- case CAIRO_OPERATOR_OVER:
- case CAIRO_OPERATOR_ATOP:
- case CAIRO_OPERATOR_DEST:
- case CAIRO_OPERATOR_DEST_OVER:
- case CAIRO_OPERATOR_DEST_OUT:
- case CAIRO_OPERATOR_XOR:
- case CAIRO_OPERATOR_ADD:
- case CAIRO_OPERATOR_SATURATE:
- return TRUE;
- case CAIRO_OPERATOR_OUT:
- case CAIRO_OPERATOR_IN:
- case CAIRO_OPERATOR_DEST_IN:
- case CAIRO_OPERATOR_DEST_ATOP:
- return FALSE;
- }
-
- ASSERT_NOT_REACHED;
- return FALSE;
-}
-
-/**
- * _cairo_operator_bounded_by_source:
- * @op: a #cairo_operator_t
- *
- * A bounded operator is one where source pixels of zero
- * (in all four components, r, g, b and a) effect no change
- * in the resulting destination image.
- *
- * Unbounded operators often require special handling; if you, for
- * example, copy a surface with the SOURCE operator, the effect
- * extends past the bounding box of the source surface.
- *
- * Return value: %TRUE if the operator is bounded by the source operand
- **/
-cairo_bool_t
-_cairo_operator_bounded_by_source (cairo_operator_t op)
-{
- switch (op) {
- case CAIRO_OPERATOR_OVER:
- case CAIRO_OPERATOR_ATOP:
- case CAIRO_OPERATOR_DEST:
- case CAIRO_OPERATOR_DEST_OVER:
- case CAIRO_OPERATOR_DEST_OUT:
- case CAIRO_OPERATOR_XOR:
- case CAIRO_OPERATOR_ADD:
- case CAIRO_OPERATOR_SATURATE:
- return TRUE;
- case CAIRO_OPERATOR_CLEAR:
- case CAIRO_OPERATOR_SOURCE:
- case CAIRO_OPERATOR_OUT:
- case CAIRO_OPERATOR_IN:
- case CAIRO_OPERATOR_DEST_IN:
- case CAIRO_OPERATOR_DEST_ATOP:
- return FALSE;
- }
-
- ASSERT_NOT_REACHED;
- return FALSE;
-}
-
cairo_status_t
_cairo_gstate_mask (cairo_gstate_t *gstate,
cairo_pattern_t *mask)
{
cairo_status_t status;
cairo_pattern_union_t source_pattern, mask_pattern;
if (mask->status)
--- a/gfx/cairo/cairo/src/cairo-meta-surface.c
+++ b/gfx/cairo/cairo/src/cairo-meta-surface.c
@@ -739,17 +739,22 @@ static cairo_status_t
command->stroke.antialias);
break;
}
case CAIRO_COMMAND_FILL:
{
cairo_command_t *stroke_command;
stroke_command = (i < num_elements - 1) ? elements[i + 1] : NULL;
-
+ if (stroke_command != NULL &&
+ type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL)
+ {
+ if (stroke_command->header.region != region)
+ stroke_command = NULL;
+ }
if (stroke_command != NULL &&
stroke_command->header.type == CAIRO_COMMAND_STROKE &&
_cairo_path_fixed_is_equal (dev_path, _cairo_command_get_path (stroke_command))) {
cairo_matrix_t dev_ctm;
cairo_matrix_t dev_ctm_inverse;
cairo_matrix_t tmp;
dev_ctm = stroke_command->stroke.ctm;
@@ -773,16 +778,24 @@ static cairo_status_t
stroke_command->stroke.op,
&stroke_command->stroke.source.base,
&stroke_command->stroke.style,
&dev_ctm,
&dev_ctm_inverse,
stroke_command->stroke.tolerance * tolerance_multiplier,
stroke_command->stroke.antialias);
i++;
+ if (type == CAIRO_META_CREATE_REGIONS) {
+ if (status == CAIRO_STATUS_SUCCESS) {
+ stroke_command->header.region = CAIRO_META_REGION_NATIVE;
+ } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
+ stroke_command->header.region = CAIRO_META_REGION_IMAGE_FALLBACK;
+ status = CAIRO_STATUS_SUCCESS;
+ }
+ }
} else
status = _cairo_surface_fill (target,
command->fill.op,
&command->fill.source.base,
dev_path,
command->fill.fill_rule,
command->fill.tolerance * tolerance_multiplier,
command->fill.antialias);
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/cairo/src/cairo-misc.c
@@ -0,0 +1,407 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * 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):
+ * Carl D. Worth <cworth@cworth.org>
+ */
+
+#include "cairoint.h"
+
+
+/**
+ * cairo_status_to_string:
+ * @status: a cairo status
+ *
+ * Provides a human-readable description of a #cairo_status_t.
+ *
+ * Returns: a string representation of the status
+ */
+const char *
+cairo_status_to_string (cairo_status_t status)
+{
+ switch (status) {
+ case CAIRO_STATUS_SUCCESS:
+ return "success";
+ case CAIRO_STATUS_NO_MEMORY:
+ return "out of memory";
+ case CAIRO_STATUS_INVALID_RESTORE:
+ return "cairo_restore without matching cairo_save";
+ case CAIRO_STATUS_INVALID_POP_GROUP:
+ return "cairo_pop_group without matching cairo_push_group";
+ case CAIRO_STATUS_NO_CURRENT_POINT:
+ return "no current point defined";
+ case CAIRO_STATUS_INVALID_MATRIX:
+ return "invalid matrix (not invertible)";
+ case CAIRO_STATUS_INVALID_STATUS:
+ return "invalid value for an input cairo_status_t";
+ case CAIRO_STATUS_NULL_POINTER:
+ return "NULL pointer";
+ case CAIRO_STATUS_INVALID_STRING:
+ return "input string not valid UTF-8";
+ case CAIRO_STATUS_INVALID_PATH_DATA:
+ return "input path data not valid";
+ case CAIRO_STATUS_READ_ERROR:
+ return "error while reading from input stream";
+ case CAIRO_STATUS_WRITE_ERROR:
+ return "error while writing to output stream";
+ case CAIRO_STATUS_SURFACE_FINISHED:
+ return "the target surface has been finished";
+ case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
+ return "the surface type is not appropriate for the operation";
+ case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
+ return "the pattern type is not appropriate for the operation";
+ case CAIRO_STATUS_INVALID_CONTENT:
+ return "invalid value for an input cairo_content_t";
+ case CAIRO_STATUS_INVALID_FORMAT:
+ return "invalid value for an input cairo_format_t";
+ case CAIRO_STATUS_INVALID_VISUAL:
+ return "invalid value for an input Visual*";
+ case CAIRO_STATUS_FILE_NOT_FOUND:
+ return "file not found";
+ case CAIRO_STATUS_INVALID_DASH:
+ return "invalid value for a dash setting";
+ case CAIRO_STATUS_INVALID_DSC_COMMENT:
+ return "invalid value for a DSC comment";
+ case CAIRO_STATUS_INVALID_INDEX:
+ return "invalid index passed to getter";
+ case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
+ return "clip region not representable in desired format";
+ case CAIRO_STATUS_TEMP_FILE_ERROR:
+ return "error creating or writing to a temporary file";
+ case CAIRO_STATUS_INVALID_STRIDE:
+ return "invalid value for stride";
+ }
+
+ return "<unknown error status>";
+}
+
+/**
+ * _cairo_operator_bounded_by_mask:
+ * @op: a #cairo_operator_t
+ *
+ * A bounded operator is one where mask pixel
+ * of zero results in no effect on the destination image.
+ *
+ * Unbounded operators often require special handling; if you, for
+ * example, draw trapezoids with an unbounded operator, the effect
+ * extends past the bounding box of the trapezoids.
+ *
+ * Return value: %TRUE if the operator is bounded by the mask operand
+ **/
+cairo_bool_t
+_cairo_operator_bounded_by_mask (cairo_operator_t op)
+{
+ switch (op) {
+ case CAIRO_OPERATOR_CLEAR:
+ case CAIRO_OPERATOR_SOURCE:
+ case CAIRO_OPERATOR_OVER:
+ case CAIRO_OPERATOR_ATOP:
+ case CAIRO_OPERATOR_DEST:
+ case CAIRO_OPERATOR_DEST_OVER:
+ case CAIRO_OPERATOR_DEST_OUT:
+ case CAIRO_OPERATOR_XOR:
+ case CAIRO_OPERATOR_ADD:
+ case CAIRO_OPERATOR_SATURATE:
+ return TRUE;
+ case CAIRO_OPERATOR_OUT:
+ case CAIRO_OPERATOR_IN:
+ case CAIRO_OPERATOR_DEST_IN:
+ case CAIRO_OPERATOR_DEST_ATOP:
+ return FALSE;
+ }
+
+ ASSERT_NOT_REACHED;
+ return FALSE;
+}
+
+/**
+ * _cairo_operator_bounded_by_source:
+ * @op: a #cairo_operator_t
+ *
+ * A bounded operator is one where source pixels of zero
+ * (in all four components, r, g, b and a) effect no change
+ * in the resulting destination image.
+ *
+ * Unbounded operators often require special handling; if you, for
+ * example, copy a surface with the SOURCE operator, the effect
+ * extends past the bounding box of the source surface.
+ *
+ * Return value: %TRUE if the operator is bounded by the source operand
+ **/
+cairo_bool_t
+_cairo_operator_bounded_by_source (cairo_operator_t op)
+{
+ switch (op) {
+ case CAIRO_OPERATOR_OVER:
+ case CAIRO_OPERATOR_ATOP:
+ case CAIRO_OPERATOR_DEST:
+ case CAIRO_OPERATOR_DEST_OVER:
+ case CAIRO_OPERATOR_DEST_OUT:
+ case CAIRO_OPERATOR_XOR:
+ case CAIRO_OPERATOR_ADD:
+ case CAIRO_OPERATOR_SATURATE:
+ return TRUE;
+ case CAIRO_OPERATOR_CLEAR:
+ case CAIRO_OPERATOR_SOURCE:
+ case CAIRO_OPERATOR_OUT:
+ case CAIRO_OPERATOR_IN:
+ case CAIRO_OPERATOR_DEST_IN:
+ case CAIRO_OPERATOR_DEST_ATOP:
+ return FALSE;
+ }
+
+ ASSERT_NOT_REACHED;
+ return FALSE;
+}
+
+
+void
+_cairo_restrict_value (double *value, double min, double max)
+{
+ if (*value < min)
+ *value = min;
+ else if (*value > max)
+ *value = max;
+}
+
+/* This function is identical to the C99 function lround(), except that it
+ * performs arithmetic rounding (instead of away-from-zero rounding) and
+ * has a valid input range of (INT_MIN, INT_MAX] instead of
+ * [INT_MIN, INT_MAX]. It is much faster on both x86 and FPU-less systems
+ * than other commonly used methods for rounding (lround, round, rint, lrint
+ * or float (d + 0.5)).
+ *
+ * The reason why this function is much faster on x86 than other
+ * methods is due to the fact that it avoids the fldcw instruction.
+ * This instruction incurs a large performance penalty on modern Intel
+ * processors due to how it prevents efficient instruction pipelining.
+ *
+ * The reason why this function is much faster on FPU-less systems is for
+ * an entirely different reason. All common rounding methods involve multiple
+ * floating-point operations. Each one of these operations has to be
+ * emulated in software, which adds up to be a large performance penalty.
+ * This function doesn't perform any floating-point calculations, and thus
+ * avoids this penalty.
+ */
+int
+_cairo_lround (double d)
+{
+ uint32_t top, shift_amount, output;
+ union {
+ double d;
+ uint64_t ui64;
+ uint32_t ui32[2];
+ } u;
+
+ u.d = d;
+
+ /* If the integer word order doesn't match the float word order, we swap
+ * the words of the input double. This is needed because we will be
+ * treating the whole double as a 64-bit unsigned integer. Notice that we
+ * use WORDS_BIGENDIAN to detect the integer word order, which isn't
+ * exactly correct because WORDS_BIGENDIAN refers to byte order, not word
+ * order. Thus, we are making the assumption that the byte order is the
+ * same as the integer word order which, on the modern machines that we
+ * care about, is OK.
+ */
+#if ( defined(FLOAT_WORDS_BIGENDIAN) && !defined(WORDS_BIGENDIAN)) || \
+ (!defined(FLOAT_WORDS_BIGENDIAN) && defined(WORDS_BIGENDIAN))
+ {
+ uint32_t temp = u.ui32[0];
+ u.ui32[0] = u.ui32[1];
+ u.ui32[1] = temp;
+ }
+#endif
+
+#ifdef WORDS_BIGENDIAN
+ #define MSW (0) /* Most Significant Word */
+ #define LSW (1) /* Least Significant Word */
+#else
+ #define MSW (1)
+ #define LSW (0)
+#endif
+
+ /* By shifting the most significant word of the input double to the
+ * right 20 places, we get the very "top" of the double where the exponent
+ * and sign bit lie.
+ */
+ top = u.ui32[MSW] >> 20;
+
+ /* Here, we calculate how much we have to shift the mantissa to normalize
+ * it to an integer value. We extract the exponent "top" by masking out the
+ * sign bit, then we calculate the shift amount by subtracting the exponent
+ * from the bias. Notice that the correct bias for 64-bit doubles is
+ * actually 1075, but we use 1053 instead for two reasons:
+ *
+ * 1) To perform rounding later on, we will first need the target
+ * value in a 31.1 fixed-point format. Thus, the bias needs to be one
+ * less: (1075 - 1: 1074).
+ *
+ * 2) To avoid shifting the mantissa as a full 64-bit integer (which is
+ * costly on certain architectures), we break the shift into two parts.
+ * First, the upper and lower parts of the mantissa are shifted
+ * individually by a constant amount that all valid inputs will require
+ * at the very least. This amount is chosen to be 21, because this will
+ * allow the two parts of the mantissa to later be combined into a
+ * single 32-bit representation, on which the remainder of the shift
+ * will be performed. Thus, we decrease the bias by an additional 21:
+ * (1074 - 21: 1053).
+ */
+ shift_amount = 1053 - (top & 0x7FF);
+
+ /* We are done with the exponent portion in "top", so here we shift it off
+ * the end.
+ */
+ top >>= 11;
+
+ /* Before we perform any operations on the mantissa, we need to OR in
+ * the implicit 1 at the top (see the IEEE-754 spec). We needn't mask
+ * off the sign bit nor the exponent bits because these higher bits won't
+ * make a bit of difference in the rest of our calculations.
+ */
+ u.ui32[MSW] |= 0x100000;
+
+ /* If the input double is negative, we have to decrease the mantissa
+ * by a hair. This is an important part of performing arithmetic rounding,
+ * as negative numbers must round towards positive infinity in the
+ * halfwase case of -x.5. Since "top" contains only the sign bit at this
+ * point, we can just decrease the mantissa by the value of "top".
+ */
+ u.ui64 -= top;
+
+ /* By decrementing "top", we create a bitmask with a value of either
+ * 0x0 (if the input was negative) or 0xFFFFFFFF (if the input was positive
+ * and thus the unsigned subtraction underflowed) that we'll use later.
+ */
+ top--;
+
+ /* Here, we shift the mantissa by the constant value as described above.
+ * We can emulate a 64-bit shift right by 21 through shifting the top 32
+ * bits left 11 places and ORing in the bottom 32 bits shifted 21 places
+ * to the right. Both parts of the mantissa are now packed into a single
+ * 32-bit integer. Although we severely truncate the lower part in the
+ * process, we still have enough significant bits to perform the conversion
+ * without error (for all valid inputs).
+ */
+ output = (u.ui32[MSW] << 11) | (u.ui32[LSW] >> 21);
+
+ /* Next, we perform the shift that converts the X.Y fixed-point number
+ * currently found in "output" to the desired 31.1 fixed-point format
+ * needed for the following rounding step. It is important to consider
+ * all possible values for "shift_amount" at this point:
+ *
+ * - {shift_amount < 0} Since shift_amount is an unsigned integer, it
+ * really can't have a value less than zero. But, if the shift_amount
+ * calculation above caused underflow (which would happen with
+ * input > INT_MAX or input <= INT_MIN) then shift_amount will now be
+ * a very large number, and so this shift will result in complete
+ * garbage. But that's OK, as the input was out of our range, so our
+ * output is undefined.
+ *
+ * - {shift_amount > 31} If the magnitude of the input was very small
+ * (i.e. |input| << 1.0), shift_amount will have a value greater than
+ * 31. Thus, this shift will also result in garbage. After performing
+ * the shift, we will zero-out "output" if this is the case.
+ *
+ * - {0 <= shift_amount < 32} In this case, the shift will properly convert
+ * the mantissa into a 31.1 fixed-point number.
+ */
+ output >>= shift_amount;
+
+ /* This is where we perform rounding with the 31.1 fixed-point number.
+ * Since what we're after is arithmetic rounding, we simply add the single
+ * fractional bit into the integer part of "output", and just keep the
+ * integer part.
+ */
+ output = (output >> 1) + (output & 1);
+
+ /* Here, we zero-out the result if the magnitude if the input was very small
+ * (as explained in the section above). Notice that all input out of the
+ * valid range is also caught by this condition, which means we produce 0
+ * for all invalid input, which is a nice side effect.
+ *
+ * The most straightforward way to do this would be:
+ *
+ * if (shift_amount > 31)
+ * output = 0;
+ *
+ * But we can use a little trick to avoid the potential branch. The
+ * expression (shift_amount > 31) will be either 1 or 0, which when
+ * decremented will be either 0x0 or 0xFFFFFFFF (unsigned underflow),
+ * which can be used to conditionally mask away all the bits in "output"
+ * (in the 0x0 case), effectively zeroing it out. Certain, compilers would
+ * have done this for us automatically.
+ */
+ output &= ((shift_amount > 31) - 1);
+
+ /* If the input double was a negative number, then we have to negate our
+ * output. The most straightforward way to do this would be:
+ *
+ * if (!top)
+ * output = -output;
+ *
+ * as "top" at this point is either 0x0 (if the input was negative) or
+ * 0xFFFFFFFF (if the input was positive). But, we can use a trick to
+ * avoid the branch. Observe that the following snippet of code has the
+ * same effect as the reference snippet above:
+ *
+ * if (!top)
+ * output = 0 - output;
+ * else
+ * output = output - 0;
+ *
+ * Armed with the bitmask found in "top", we can condense the two statements
+ * into the following:
+ *
+ * output = (output & top) - (output & ~top);
+ *
+ * where, in the case that the input double was negative, "top" will be 0,
+ * and the statement will be equivalent to:
+ *
+ * output = (0) - (output);
+ *
+ * and if the input double was positive, "top" will be 0xFFFFFFFF, and the
+ * statement will be equivalent to:
+ *
+ * output = (output) - (0);
+ *
+ * Which, as pointed out earlier, is equivalent to the original reference
+ * snippet.
+ */
+ output = (output & top) - (output & ~top);
+
+ return output;
+#undef MSW
+#undef LSW
+}
--- a/gfx/cairo/cairo/src/cairo-mutex-list-private.h
+++ b/gfx/cairo/cairo/src/cairo-mutex-list-private.h
@@ -32,16 +32,17 @@
*/
CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_pattern_cache_lock);
CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock);
CAIRO_MUTEX_DECLARE (_cairo_font_face_mutex);
CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex);
+CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex);
#if CAIRO_HAS_FT_FONT
CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex);
#endif
#if CAIRO_HAS_XLIB_SURFACE
CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex);
#endif
--- a/gfx/cairo/cairo/src/cairo-os2-surface.c
+++ b/gfx/cairo/cairo/src/cairo-os2-surface.c
@@ -101,18 +101,20 @@ cairo_os2_init (void)
{
/* This may initialize some stuffs, like create mutex semaphores etc.. */
cairo_os2_initialization_count++;
if (cairo_os2_initialization_count > 1) return;
DisableFPUException ();
+#if CAIRO_HAS_FT_FONT
/* Initialize FontConfig */
FcInit ();
+#endif
CAIRO_MUTEX_INITIALIZE ();
}
/**
* cairo_os2_fini:
*
* Uninitializes the Cairo library. This function is automatically called if
@@ -129,26 +131,28 @@ cairo_os2_fini (void)
if (cairo_os2_initialization_count <= 0) return;
cairo_os2_initialization_count--;
if (cairo_os2_initialization_count > 0) return;
DisableFPUException ();
/* Free allocated memories! */
- /* (Check cairo_debug_reset_static_date () for an example of this!) */
+ /* (Check cairo_debug_reset_static_data () for an example of this!) */
_cairo_font_reset_static_data ();
-#ifdef CAIRO_HAS_FT_FONT
+#if CAIRO_HAS_FT_FONT
_cairo_ft_font_reset_static_data ();
#endif
CAIRO_MUTEX_FINALIZE ();
+#if CAIRO_HAS_FT_FONT
/* Uninitialize FontConfig */
FcFini ();
+#endif
#ifdef __WATCOMC__
/* It can happen that the libraries we use have memory leaks,
* so there are still memory chunks allocated at this point.
* In these cases, Watcom might still have a bigger memory chunk,
* called "the heap" allocated from the OS.
* As we want to minimize the memory we lose from the point of
* view of the OS, we call this function to shrink that heap
--- a/gfx/cairo/cairo/src/cairo-output-stream-private.h
+++ b/gfx/cairo/cairo/src/cairo-output-stream-private.h
@@ -110,21 +110,23 @@ cairo_private void
const char *data,
size_t length);
cairo_private void
_cairo_dtostr (char *buffer, size_t size, double d);
cairo_private void
_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
- const char *fmt, va_list ap);
+ const char *fmt,
+ va_list ap) CAIRO_PRINTF_FORMAT ( 2, 0);
cairo_private void
_cairo_output_stream_printf (cairo_output_stream_t *stream,
- const char *fmt, ...);
+ const char *fmt,
+ ...) CAIRO_PRINTF_FORMAT (2, 3);
cairo_private long
_cairo_output_stream_get_position (cairo_output_stream_t *stream);
cairo_private cairo_status_t
_cairo_output_stream_get_status (cairo_output_stream_t *stream);
/* This function never returns %NULL. If an error occurs (NO_MEMORY or
--- a/gfx/cairo/cairo/src/cairo-path-stroke.c
+++ b/gfx/cairo/cairo/src/cairo-path-stroke.c
@@ -596,23 +596,33 @@ static inline cairo_bool_t
if (dx0 == 0.0 && dy0 == 0.0) {
if (mag_out)
*mag_out = 0.0;
return FALSE;
}
if (dx0 == 0.0) {
- mag = dy0;
*dx = 0.0;
- *dy = 1.0;
+ if (dy0 > 0.0) {
+ mag = dy0;
+ *dy = 1.0;
+ } else {
+ mag = -dy0;
+ *dy = -1.0;
+ }
} else if (dy0 == 0.0) {
- mag = dx0;
- *dx = 1.0;
*dy = 0.0;
+ if (dx0 > 0.0) {
+ mag = dx0;
+ *dx = 1.0;
+ } else {
+ mag = -dx0;
+ *dx = -1.0;
+ }
} else {
mag = sqrt (dx0 * dx0 + dy0 * dy0);
*dx = dx0 / mag;
*dy = dy0 / mag;
}
if (mag_out)
*mag_out = mag;
--- a/gfx/cairo/cairo/src/cairo-pdf-operators-private.h
+++ b/gfx/cairo/cairo/src/cairo-pdf-operators-private.h
@@ -55,17 +55,17 @@ typedef struct _cairo_pdf_operators {
cairo_scaled_font_subsets_t *font_subsets;
cairo_pdf_operators_use_font_subset_t use_font_subset;
void *use_font_subset_closure;
} cairo_pdf_operators_t;
cairo_private void
_cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream,
- cairo_matrix_t cairo_to_pdf,
+ cairo_matrix_t *cairo_to_pdf,
cairo_scaled_font_subsets_t *font_subsets);
cairo_private void
_cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators);
cairo_private void
_cairo_pdf_operators_set_font_subsets_callback (cairo_pdf_operators_t *pdf_operators,
cairo_pdf_operators_use_font_subset_t use_font_subset,
@@ -73,34 +73,42 @@ cairo_private void
cairo_private void
_cairo_pdf_operators_set_stream (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream);
cairo_private void
_cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators,
- cairo_matrix_t cairo_to_pdf);
+ cairo_matrix_t *cairo_to_pdf);
cairo_private cairo_int_status_t
_cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule);
cairo_private cairo_int_status_t
-_cairo_pdf_operator_stroke (cairo_pdf_operators_t *pdf_operators,
- cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse);
+_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
+ cairo_path_fixed_t *path,
+ cairo_stroke_style_t *style,
+ cairo_matrix_t *ctm,
+ cairo_matrix_t *ctm_inverse);
cairo_private cairo_int_status_t
_cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule);
+cairo_int_status_t
+_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ cairo_stroke_style_t *style,
+ cairo_matrix_t *ctm,
+ cairo_matrix_t *ctm_inverse);
+
cairo_private cairo_int_status_t
_cairo_pdf_operators_show_glyphs (cairo_pdf_operators_t *pdf_operators,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font);
#endif /* CAIRO_PDF_OPERATORS_H */
--- a/gfx/cairo/cairo/src/cairo-pdf-operators.c
+++ b/gfx/cairo/cairo/src/cairo-pdf-operators.c
@@ -1,14 +1,14 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc
* Copyright © 2006 Red Hat, Inc
- * Copyright © 2007 Adrian Johnson
+ * Copyright © 2007, 2008 Adrian Johnson
*
* 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.
@@ -40,24 +40,26 @@
*/
#include "cairoint.h"
#include "cairo-pdf-operators-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-scaled-font-subsets-private.h"
+#include <ctype.h>
+
void
_cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream,
- cairo_matrix_t cairo_to_pdf,
+ cairo_matrix_t *cairo_to_pdf,
cairo_scaled_font_subsets_t *font_subsets)
{
pdf_operators->stream = stream;
- pdf_operators->cairo_to_pdf = cairo_to_pdf;
+ pdf_operators->cairo_to_pdf = *cairo_to_pdf;
pdf_operators->font_subsets = font_subsets;
pdf_operators->use_font_subset = NULL;
pdf_operators->use_font_subset_closure = NULL;
}
void
_cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators)
{
@@ -76,57 +78,214 @@ void
_cairo_pdf_operators_set_stream (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream)
{
pdf_operators->stream = stream;
}
void
_cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators,
- cairo_matrix_t cairo_to_pdf)
+ cairo_matrix_t *cairo_to_pdf)
+{
+ pdf_operators->cairo_to_pdf = *cairo_to_pdf;
+}
+
+/* A word wrap stream can be used as a filter to do word wrapping on
+ * top of an existing output stream. The word wrapping is quite
+ * simple, using isspace to determine characters that separate
+ * words. Any word that will cause the column count exceed the given
+ * max_column will have a '\n' character emitted before it.
+ *
+ * The stream is careful to maintain integrity for words that cross
+ * the boundary from one call to write to the next.
+ *
+ * Note: This stream does not guarantee that the output will never
+ * exceed max_column. In particular, if a single word is larger than
+ * max_column it will not be broken up.
+ */
+typedef struct _word_wrap_stream {
+ cairo_output_stream_t base;
+ cairo_output_stream_t *output;
+ int max_column;
+ int column;
+ cairo_bool_t last_write_was_space;
+ cairo_bool_t in_hexstring;
+} word_wrap_stream_t;
+
+static int
+_count_word_up_to (const unsigned char *s, int length)
+{
+ int word = 0;
+
+ while (length--) {
+ if (! (isspace (*s) || *s == '<')) {
+ s++;
+ word++;
+ } else {
+ return word;
+ }
+ }
+
+ return word;
+}
+
+
+/* Count up to either the end of the ASCII hexstring or the number
+ * of columns remaining.
+ */
+static int
+_count_hexstring_up_to (const unsigned char *s, int length, int columns)
+{
+ int word = 0;
+
+ while (length-- && columns--) {
+ if (*s++ != '>')
+ word++;
+ else
+ return word;
+ }
+
+ return word;
+}
+
+static cairo_status_t
+_word_wrap_stream_write (cairo_output_stream_t *base,
+ const unsigned char *data,
+ unsigned int length)
{
- pdf_operators->cairo_to_pdf = cairo_to_pdf;
+ word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
+ cairo_bool_t newline;
+ int word;
+
+ while (length) {
+ if (*data == '<') {
+ stream->in_hexstring = TRUE;
+ data++;
+ length--;
+ _cairo_output_stream_printf (stream->output, "<");
+ } else if (*data == '>') {
+ stream->in_hexstring = FALSE;
+ data++;
+ length--;
+ _cairo_output_stream_printf (stream->output, ">");
+ } else if (isspace (*data)) {
+ newline = (*data == '\n' || *data == '\r');
+ if (! newline && stream->column >= stream->max_column) {
+ _cairo_output_stream_printf (stream->output, "\n");
+ stream->column = 0;
+ }
+ _cairo_output_stream_write (stream->output, data, 1);
+ data++;
+ length--;
+ if (newline)
+ stream->column = 0;
+ else
+ stream->column++;
+ stream->last_write_was_space = TRUE;
+ } else {
+ if (stream->in_hexstring) {
+ word = _count_hexstring_up_to (data, length,
+ MAX (stream->max_column - stream->column, 0));
+ } else {
+ word = _count_word_up_to (data, length);
+ }
+ /* Don't wrap if this word is a continuation of a non hex
+ * string word from a previous call to write. */
+ if (stream->column + word >= stream->max_column &&
+ (stream->last_write_was_space || stream->in_hexstring))
+ {
+ _cairo_output_stream_printf (stream->output, "\n");
+ stream->column = 0;
+ }
+ _cairo_output_stream_write (stream->output, data, word);
+ data += word;
+ length -= word;
+ stream->column += word;
+ stream->last_write_was_space = FALSE;
+ }
+ }
+
+ return _cairo_output_stream_get_status (stream->output);
+}
+
+static cairo_status_t
+_word_wrap_stream_close (cairo_output_stream_t *base)
+{
+ word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
+
+ return _cairo_output_stream_get_status (stream->output);
+}
+
+static cairo_output_stream_t *
+_word_wrap_stream_create (cairo_output_stream_t *output, int max_column)
+{
+ word_wrap_stream_t *stream;
+
+ if (output->status)
+ return _cairo_output_stream_create_in_error (output->status);
+
+ stream = malloc (sizeof (word_wrap_stream_t));
+ if (stream == NULL) {
+ _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+ return (cairo_output_stream_t *) &_cairo_output_stream_nil;
+ }
+
+ _cairo_output_stream_init (&stream->base,
+ _word_wrap_stream_write,
+ _word_wrap_stream_close);
+ stream->output = output;
+ stream->max_column = max_column;
+ stream->column = 0;
+ stream->last_write_was_space = FALSE;
+ stream->in_hexstring = FALSE;
+
+ return &stream->base;
}
typedef struct _pdf_path_info {
cairo_output_stream_t *output;
- cairo_matrix_t *cairo_to_pdf;
- cairo_matrix_t *ctm_inverse;
+ cairo_matrix_t *path_transform;
+ cairo_line_cap_t line_cap;
+ cairo_point_t last_move_to_point;
+ cairo_bool_t has_sub_path;
} pdf_path_info_t;
static cairo_status_t
_cairo_pdf_path_move_to (void *closure, cairo_point_t *point)
{
pdf_path_info_t *info = closure;
double x = _cairo_fixed_to_double (point->x);
double y = _cairo_fixed_to_double (point->y);
- if (info->cairo_to_pdf)
- cairo_matrix_transform_point (info->cairo_to_pdf, &x, &y);
- if (info->ctm_inverse)
- cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
-
+ info->last_move_to_point = *point;
+ info->has_sub_path = FALSE;
+ cairo_matrix_transform_point (info->path_transform, &x, &y);
_cairo_output_stream_printf (info->output,
"%f %f m ", x, y);
return _cairo_output_stream_get_status (info->output);
}
static cairo_status_t
_cairo_pdf_path_line_to (void *closure, cairo_point_t *point)
{
pdf_path_info_t *info = closure;
double x = _cairo_fixed_to_double (point->x);
double y = _cairo_fixed_to_double (point->y);
- if (info->cairo_to_pdf)
- cairo_matrix_transform_point (info->cairo_to_pdf, &x, &y);
- if (info->ctm_inverse)
- cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
+ if (info->line_cap != CAIRO_LINE_CAP_ROUND &&
+ ! info->has_sub_path &&
+ point->x == info->last_move_to_point.x &&
+ point->y == info->last_move_to_point.y)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+ info->has_sub_path = TRUE;
+ cairo_matrix_transform_point (info->path_transform, &x, &y);
_cairo_output_stream_printf (info->output,
"%f %f l ", x, y);
return _cairo_output_stream_get_status (info->output);
}
static cairo_status_t
_cairo_pdf_path_curve_to (void *closure,
@@ -137,69 +296,101 @@ static cairo_status_t
pdf_path_info_t *info = closure;
double bx = _cairo_fixed_to_double (b->x);
double by = _cairo_fixed_to_double (b->y);
double cx = _cairo_fixed_to_double (c->x);
double cy = _cairo_fixed_to_double (c->y);
double dx = _cairo_fixed_to_double (d->x);
double dy = _cairo_fixed_to_double (d->y);
- if (info->cairo_to_pdf) {
- cairo_matrix_transform_point (info->cairo_to_pdf, &bx, &by);
- cairo_matrix_transform_point (info->cairo_to_pdf, &cx, &cy);
- cairo_matrix_transform_point (info->cairo_to_pdf, &dx, &dy);
- }
- if (info->ctm_inverse) {
- cairo_matrix_transform_point (info->ctm_inverse, &bx, &by);
- cairo_matrix_transform_point (info->ctm_inverse, &cx, &cy);
- cairo_matrix_transform_point (info->ctm_inverse, &dx, &dy);
- }
-
+ info->has_sub_path = TRUE;
+ cairo_matrix_transform_point (info->path_transform, &bx, &by);
+ cairo_matrix_transform_point (info->path_transform, &cx, &cy);
+ cairo_matrix_transform_point (info->path_transform, &dx, &dy);
_cairo_output_stream_printf (info->output,
"%f %f %f %f %f %f c ",
bx, by, cx, cy, dx, dy);
return _cairo_output_stream_get_status (info->output);
}
static cairo_status_t
_cairo_pdf_path_close_path (void *closure)
{
pdf_path_info_t *info = closure;
+ if (info->line_cap != CAIRO_LINE_CAP_ROUND &&
+ ! info->has_sub_path)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
_cairo_output_stream_printf (info->output,
"h\r\n");
return _cairo_output_stream_get_status (info->output);
}
+/* The line cap value is needed to workaround the fact that PostScript
+ * and PDF semantics for stroking degenerate sub-paths do not match
+ * cairo semantics. (PostScript draws something for any line cap
+ * value, while cairo draws something only for round caps).
+ *
+ * When using this function to emit a path to be filled, rather than
+ * stroked, simply pass %CAIRO_LINE_CAP_ROUND which will guarantee that
+ * the stroke workaround will not modify the path being emitted.
+ */
+static cairo_status_t
+_cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators,
+ cairo_path_fixed_t *path,
+ cairo_matrix_t *path_transform,
+ cairo_line_cap_t line_cap)
+{
+ cairo_output_stream_t *word_wrap;
+ cairo_status_t status, status2;
+ pdf_path_info_t info;
+
+ word_wrap = _word_wrap_stream_create (pdf_operators->stream, 79);
+ status = _cairo_output_stream_get_status (word_wrap);
+ if (status)
+ return status;
+
+ info.output = word_wrap;
+ info.path_transform = path_transform;
+ info.line_cap = line_cap;
+ status = _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_pdf_path_move_to,
+ _cairo_pdf_path_line_to,
+ _cairo_pdf_path_curve_to,
+ _cairo_pdf_path_close_path,
+ &info);
+
+ status2 = _cairo_output_stream_destroy (word_wrap);
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = status2;
+
+ return status;
+}
+
cairo_int_status_t
_cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule)
{
const char *pdf_operator;
+ cairo_status_t status;
if (! path->has_current_point) {
/* construct an empty path */
_cairo_output_stream_printf (pdf_operators->stream, "0 0 m ");
} else {
- pdf_path_info_t info;
- cairo_status_t status;
-
- info.output = pdf_operators->stream;
- info.cairo_to_pdf = &pdf_operators->cairo_to_pdf;
- info.ctm_inverse = NULL;
-
- status = _cairo_path_fixed_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_pdf_path_move_to,
- _cairo_pdf_path_line_to,
- _cairo_pdf_path_curve_to,
- _cairo_pdf_path_close_path,
- &info);
+ status = _cairo_pdf_operators_emit_path (pdf_operators,
+ path,
+ &pdf_operators->cairo_to_pdf,
+ CAIRO_LINE_CAP_ROUND);
if (status)
return status;
}
switch (fill_rule) {
case CAIRO_FILL_RULE_WINDING:
pdf_operator = "W";
break;
@@ -248,106 +439,163 @@ static int
return 0;
}
}
static cairo_int_status_t
_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
cairo_stroke_style_t *style)
{
+ double *dash = style->dash;
+ int num_dashes = style->num_dashes;
+ double dash_offset = style->dash_offset;
+
+ /* PostScript has "special needs" when it comes to zero-length
+ * dash segments with butt caps. It apparently (at least
+ * according to ghostscript) draws hairlines for this
+ * case. That's not what the cairo semantics want, so we first
+ * touch up the array to eliminate any 0.0 values that will
+ * result in "on" segments.
+ */
+ if (num_dashes && style->line_cap == CAIRO_LINE_CAP_BUTT) {
+ int i;
+
+ /* If there's an odd number of dash values they will each get
+ * interpreted as both on and off. So we first explicitly
+ * expand the array to remove the duplicate usage so that we
+ * can modify some of the values.
+ */
+ if (num_dashes % 2) {
+ dash = _cairo_malloc_abc (num_dashes, 2, sizeof (double));
+ if (dash == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ memcpy (dash, style->dash, num_dashes * sizeof (double));
+ memcpy (dash + num_dashes, style->dash, num_dashes * sizeof (double));
+
+ num_dashes *= 2;
+ }
+
+ for (i = 0; i < num_dashes; i += 2) {
+ if (dash[i] == 0.0) {
+ /* If we're at the front of the list, we first rotate
+ * two elements from the end of the list to the front
+ * of the list before folding away the 0.0. Or, if
+ * there are only two dash elements, then there is
+ * nothing at all to draw.
+ */
+ if (i == 0) {
+ double last_two[2];
+
+ if (num_dashes == 2) {
+ if (dash != style->dash)
+ free (dash);
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
+ /* The cases of num_dashes == 0, 1, or 3 elements
+ * cannot exist, so the rotation of 2 elements
+ * will always be safe */
+ memcpy (last_two, dash + num_dashes - 2, sizeof (last_two));
+ memmove (dash + 2, dash, (num_dashes - 2) * sizeof (double));
+ memcpy (dash, last_two, sizeof (last_two));
+ dash_offset += dash[0] + dash[1];
+ i = 2;
+ }
+ dash[i-1] += dash[i+1];
+ num_dashes -= 2;
+ memmove (dash + i, dash + i + 2, (num_dashes - i) * sizeof (double));
+ /* If we might have just rotated, it's possible that
+ * we rotated a 0.0 value to the front of the list.
+ * Set i to -2 so it will get incremented to 0. */
+ if (i == 2)
+ i = -2;
+ }
+ }
+ }
+
_cairo_output_stream_printf (pdf_operators->stream,
"%f w\r\n",
style->line_width);
_cairo_output_stream_printf (pdf_operators->stream,
"%d J\r\n",
_cairo_pdf_line_cap (style->line_cap));
_cairo_output_stream_printf (pdf_operators->stream,
"%d j\r\n",
_cairo_pdf_line_join (style->line_join));
- if (style->num_dashes) {
- unsigned int d;
+ if (num_dashes) {
+ int d;
+
_cairo_output_stream_printf (pdf_operators->stream, "[");
- for (d = 0; d < style->num_dashes; d++)
- _cairo_output_stream_printf (pdf_operators->stream, " %f", style->dash[d]);
+ for (d = 0; d < num_dashes; d++)
+ _cairo_output_stream_printf (pdf_operators->stream, " %f", dash[d]);
_cairo_output_stream_printf (pdf_operators->stream, "] %f d\r\n",
- style->dash_offset);
+ dash_offset);
} else {
_cairo_output_stream_printf (pdf_operators->stream, "[] 0.0 d\r\n");
}
+ if (dash != style->dash)
+ free (dash);
_cairo_output_stream_printf (pdf_operators->stream,
"%f M ",
style->miter_limit < 1.0 ? 1.0 : style->miter_limit);
return _cairo_output_stream_get_status (pdf_operators->stream);
}
cairo_int_status_t
-_cairo_pdf_operator_stroke (cairo_pdf_operators_t *pdf_operators,
- cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse)
+_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
+ cairo_path_fixed_t *path,
+ cairo_stroke_style_t *style,
+ cairo_matrix_t *ctm,
+ cairo_matrix_t *ctm_inverse)
{
- pdf_path_info_t info;
cairo_status_t status;
cairo_matrix_t m;
status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style);
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
if (status)
return status;
- info.output = pdf_operators->stream;
- info.cairo_to_pdf = NULL;
- info.ctm_inverse = ctm_inverse;
-
cairo_matrix_multiply (&m, ctm, &pdf_operators->cairo_to_pdf);
_cairo_output_stream_printf (pdf_operators->stream,
"q %f %f %f %f %f %f cm\r\n",
m.xx, m.yx, m.xy, m.yy,
m.x0, m.y0);
- status = _cairo_path_fixed_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_pdf_path_move_to,
- _cairo_pdf_path_line_to,
- _cairo_pdf_path_curve_to,
- _cairo_pdf_path_close_path,
- &info);
+ status = _cairo_pdf_operators_emit_path (pdf_operators,
+ path,
+ ctm_inverse,
+ style->line_cap);
if (status)
return status;
_cairo_output_stream_printf (pdf_operators->stream, "S Q\r\n");
return _cairo_output_stream_get_status (pdf_operators->stream);
}
cairo_int_status_t
_cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule)
{
const char *pdf_operator;
cairo_status_t status;
- pdf_path_info_t info;
- info.output = pdf_operators->stream;
- info.cairo_to_pdf = &pdf_operators->cairo_to_pdf;
- info.ctm_inverse = NULL;
- status = _cairo_path_fixed_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_pdf_path_move_to,
- _cairo_pdf_path_line_to,
- _cairo_pdf_path_curve_to,
- _cairo_pdf_path_close_path,
- &info);
+ status = _cairo_pdf_operators_emit_path (pdf_operators,
+ path,
+ &pdf_operators->cairo_to_pdf,
+ CAIRO_LINE_CAP_ROUND);
if (status)
return status;
switch (fill_rule) {
case CAIRO_FILL_RULE_WINDING:
pdf_operator = "f";
break;
case CAIRO_FILL_RULE_EVEN_ODD:
@@ -359,36 +607,91 @@ cairo_int_status_t
_cairo_output_stream_printf (pdf_operators->stream,
"%s\r\n",
pdf_operator);
return _cairo_output_stream_get_status (pdf_operators->stream);
}
+cairo_int_status_t
+_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ cairo_stroke_style_t *style,
+ cairo_matrix_t *ctm,
+ cairo_matrix_t *ctm_inverse)
+{
+ const char *pdf_operator;
+ cairo_status_t status;
+ cairo_matrix_t m;
+
+ status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style);
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
+ if (status)
+ return status;
+
+ cairo_matrix_multiply (&m, ctm, &pdf_operators->cairo_to_pdf);
+ _cairo_output_stream_printf (pdf_operators->stream,
+ "q %f %f %f %f %f %f cm\r\n",
+ m.xx, m.yx, m.xy, m.yy,
+ m.x0, m.y0);
+
+ status = _cairo_pdf_operators_emit_path (pdf_operators,
+ path,
+ ctm_inverse,
+ style->line_cap);
+ if (status)
+ return status;
+
+ switch (fill_rule) {
+ case CAIRO_FILL_RULE_WINDING:
+ pdf_operator = "B";
+ break;
+ case CAIRO_FILL_RULE_EVEN_ODD:
+ pdf_operator = "B*";
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ }
+
+ _cairo_output_stream_printf (pdf_operators->stream,
+ "%s Q\r\n",
+ pdf_operator);
+
+ return _cairo_output_stream_get_status (pdf_operators->stream);
+}
+
#define GLYPH_POSITION_TOLERANCE 0.001
cairo_int_status_t
_cairo_pdf_operators_show_glyphs (cairo_pdf_operators_t *pdf_operators,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
{
unsigned int current_subset_id = (unsigned int)-1;
cairo_scaled_font_subsets_glyph_t subset_glyph;
cairo_bool_t diagonal, in_TJ;
cairo_status_t status;
double Tlm_x = 0, Tlm_y = 0;
double Tm_x = 0, y;
int i, hex_width;
+ cairo_output_stream_t *word_wrap_stream;
for (i = 0; i < num_glyphs; i++)
cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &glyphs[i].x, &glyphs[i].y);
- _cairo_output_stream_printf (pdf_operators->stream,
+ word_wrap_stream = _word_wrap_stream_create (pdf_operators->stream, 79);
+ status = _cairo_output_stream_get_status (word_wrap_stream);
+ if (status)
+ return status;
+
+ _cairo_output_stream_printf (word_wrap_stream,
"BT\r\n");
if (scaled_font->scale.xy == 0.0 &&
scaled_font->scale.yx == 0.0)
diagonal = TRUE;
else
diagonal = FALSE;
@@ -409,34 +712,34 @@ cairo_int_status_t
y = 0.0;
cairo_matrix_transform_distance (&scaled_font->scale,
&subset_glyph.x_advance,
&y);
}
if (subset_glyph.subset_id != current_subset_id) {
if (in_TJ) {
- _cairo_output_stream_printf (pdf_operators->stream, ">] TJ\r\n");
+ _cairo_output_stream_printf (word_wrap_stream, ">] TJ\r\n");
in_TJ = FALSE;
}
- _cairo_output_stream_printf (pdf_operators->stream,
+ _cairo_output_stream_printf (word_wrap_stream,
"/f-%d-%d 1 Tf\r\n",
subset_glyph.font_id,
subset_glyph.subset_id);
if (pdf_operators->use_font_subset) {
status = pdf_operators->use_font_subset (subset_glyph.font_id,
subset_glyph.subset_id,
pdf_operators->use_font_subset_closure);
if (status)
return status;
}
}
if (subset_glyph.subset_id != current_subset_id || !diagonal) {
- _cairo_output_stream_printf (pdf_operators->stream,
+ _cairo_output_stream_printf (word_wrap_stream,
"%f %f %f %f %f %f Tm\r\n",
scaled_font->scale.xx,
-scaled_font->scale.yx,
-scaled_font->scale.xy,
scaled_font->scale.yy,
glyphs[i].x,
glyphs[i].y);
current_subset_id = subset_glyph.subset_id;
@@ -447,86 +750,90 @@ cairo_int_status_t
if (diagonal) {
if (i < num_glyphs - 1 &&
fabs((glyphs[i].y - glyphs[i+1].y)/scaled_font->scale.yy) < GLYPH_POSITION_TOLERANCE &&
fabs((glyphs[i].x - glyphs[i+1].x)/scaled_font->scale.xx) < 10)
{
if (!in_TJ) {
if (i != 0) {
- _cairo_output_stream_printf (pdf_operators->stream,
+ _cairo_output_stream_printf (word_wrap_stream,
"%f %f Td\r\n",
(glyphs[i].x - Tlm_x)/scaled_font->scale.xx,
(glyphs[i].y - Tlm_y)/scaled_font->scale.yy);
Tlm_x = glyphs[i].x;
Tlm_y = glyphs[i].y;
Tm_x = Tlm_x;
}
- _cairo_output_stream_printf (pdf_operators->stream,
+ _cairo_output_stream_printf (word_wrap_stream,
"[<%0*x",
hex_width,
subset_glyph.subset_glyph_index);
Tm_x += subset_glyph.x_advance;
in_TJ = TRUE;
} else {
if (fabs((glyphs[i].x - Tm_x)/scaled_font->scale.xx) > GLYPH_POSITION_TOLERANCE) {
double delta = glyphs[i].x - Tm_x;
- _cairo_output_stream_printf (pdf_operators->stream,
+ _cairo_output_stream_printf (word_wrap_stream,
"> %f <",
-1000.0*delta/scaled_font->scale.xx);
Tm_x += delta;
}
- _cairo_output_stream_printf (pdf_operators->stream,
+ _cairo_output_stream_printf (word_wrap_stream,
"%0*x",
hex_width,
subset_glyph.subset_glyph_index);
Tm_x += subset_glyph.x_advance;
}
}
else
{
if (in_TJ) {
if (fabs((glyphs[i].x - Tm_x)/scaled_font->scale.xx) > GLYPH_POSITION_TOLERANCE) {
double delta = glyphs[i].x - Tm_x;
- _cairo_output_stream_printf (pdf_operators->stream,
+ _cairo_output_stream_printf (word_wrap_stream,
"> %f <",
-1000.0*delta/scaled_font->scale.xx);
Tm_x += delta;
}
- _cairo_output_stream_printf (pdf_operators->stream,
+ _cairo_output_stream_printf (word_wrap_stream,
"%0*x>] TJ\r\n",
hex_width,
subset_glyph.subset_glyph_index);
Tm_x += subset_glyph.x_advance;
in_TJ = FALSE;
} else {
if (i != 0) {
- _cairo_output_stream_printf (pdf_operators->stream,
+ _cairo_output_stream_printf (word_wrap_stream,
"%f %f Td ",
(glyphs[i].x - Tlm_x)/scaled_font->scale.xx,
(glyphs[i].y - Tlm_y)/-scaled_font->scale.yy);
Tlm_x = glyphs[i].x;
Tlm_y = glyphs[i].y;
Tm_x = Tlm_x;
}
- _cairo_output_stream_printf (pdf_operators->stream,
+ _cairo_output_stream_printf (word_wrap_stream,
"<%0*x> Tj ",
hex_width,
subset_glyph.subset_glyph_index);
Tm_x += subset_glyph.x_advance;
}
}
} else {
- _cairo_output_stream_printf (pdf_operators->stream,
+ _cairo_output_stream_printf (word_wrap_stream,
"<%0*x> Tj\r\n",
hex_width,
subset_glyph.subset_glyph_index);
}
}
- _cairo_output_stream_printf (pdf_operators->stream,
+ _cairo_output_stream_printf (word_wrap_stream,
"ET\r\n");
+ status = _cairo_output_stream_destroy (word_wrap_stream);
+ if (status)
+ return status;
+
return _cairo_output_stream_get_status (pdf_operators->stream);
}
--- a/gfx/cairo/cairo/src/cairo-pdf-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-pdf-surface-private.h
@@ -144,15 +144,16 @@ struct _cairo_pdf_surface {
cairo_output_stream_t *mem_stream;
cairo_output_stream_t *old_output;
cairo_pdf_resource_t resource;
cairo_bool_t is_knockout;
} group_stream;
cairo_pdf_operators_t pdf_operators;
cairo_paginated_mode_t paginated_mode;
+ cairo_bool_t select_pattern_gstate_saved;
cairo_bool_t force_fallbacks;
cairo_surface_t *paginated_surface;
};
#endif /* CAIRO_PDF_SURFACE_PRIVATE_H */
--- a/gfx/cairo/cairo/src/cairo-pdf-surface.c
+++ b/gfx/cairo/cairo/src/cairo-pdf-surface.c
@@ -52,35 +52,17 @@
#include <zlib.h>
/* 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.
*
- * - Images of other formats than 8 bit RGBA.
- *
* - Backend specific meta data.
- *
- * - Surface patterns.
- *
- * - Should/does cairo support drawing into a scratch surface and then
- * using that as a fill pattern? For this backend, that would involve
- * using a tiling pattern (4.6.2). How do you create such a scratch
- * surface? cairo_surface_create_similar() ?
- *
- * - What if you create a similar surface and does show_page and then
- * does show_surface on another surface?
- *
- * - Add test case for RGBA images.
- *
- * - Add test case for RGBA gradients.
- *
- * - Coordinate space for create_similar() args?
*/
/*
* Page Structure of the Generated PDF:
*
* Each page requiring fallbacks images contains a knockout group at
* the top level. The first operation of the knockout group paints a
* group containing all the supported drawing operations. Fallback
@@ -280,20 +262,21 @@ static cairo_surface_t *
surface->pdf_stream.old_output = NULL;
surface->group_stream.active = FALSE;
surface->group_stream.stream = NULL;
surface->group_stream.mem_stream = NULL;
surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
surface->force_fallbacks = FALSE;
+ surface->select_pattern_gstate_saved = FALSE;
_cairo_pdf_operators_init (&surface->pdf_operators,
surface->output,
- surface->cairo_to_pdf,
+ &surface->cairo_to_pdf,
surface->font_subsets);
_cairo_pdf_operators_set_font_subsets_callback (&surface->pdf_operators,
_cairo_pdf_surface_add_font,
surface);
/* Document header */
_cairo_output_stream_printf (surface->output,
"%%PDF-1.4\r\n");
@@ -452,17 +435,17 @@ cairo_pdf_surface_set_size (cairo_surfac
status = _cairo_surface_set_error (surface, status);
return;
}
pdf_surface->width = width_in_points;
pdf_surface->height = height_in_points;
cairo_matrix_init (&pdf_surface->cairo_to_pdf, 1, 0, 0, -1, 0, height_in_points);
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&pdf_surface->pdf_operators,
- pdf_surface->cairo_to_pdf);
+ &pdf_surface->cairo_to_pdf);
status = _cairo_paginated_surface_set_size (pdf_surface->paginated_surface,
width_in_points,
height_in_points);
if (status)
status = _cairo_surface_set_error (surface, status);
}
static void
@@ -1085,27 +1068,25 @@ static cairo_status_t
" /Type /Group\r\n"
" /S /Transparency\r\n"
" /CS /DeviceRGB\r\n"
" >>\r\n"
" /Resources %d 0 R\r\n",
surface->width,
surface->height,
surface->content_resources.id);
- if (status)
- return status;
} else {
status =
_cairo_pdf_surface_open_stream (surface,
NULL,
surface->compress_content,
NULL);
- if (status)
- return status;
}
+ if (status)
+ return status;
surface->content = surface->pdf_stream.self;
_cairo_output_stream_printf (surface->output, "q\r\n");
return _cairo_output_stream_get_status (surface->output);
}
@@ -1239,60 +1220,30 @@ static cairo_int_status_t
_cairo_pdf_group_resources_clear (&surface->resources);
status = _cairo_pdf_surface_open_content_stream (surface, TRUE);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
}
-static void *
-compress_dup (const void *data, unsigned long data_size,
- unsigned long *compressed_size)
-{
- void *compressed;
- unsigned long additional_size;
-
- /* Bound calculation taken from zlib. */
- additional_size = (data_size >> 12) + (data_size >> 14) + 11;
- if (INT32_MAX - data_size <= additional_size) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return NULL;
- }
-
- *compressed_size = data_size + additional_size;
- compressed = malloc (*compressed_size);
- if (compressed == NULL) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return NULL;
- }
-
- if (compress (compressed, compressed_size, data, data_size) != Z_OK) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- free (compressed);
- compressed = NULL;
- }
-
- return compressed;
-}
-
/* Emit alpha channel from the image into the given data, providing
* an id that can be used to reference the resulting SMask object.
*
* 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
_cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface,
cairo_image_surface_t *image,
cairo_pdf_resource_t *stream_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
- char *alpha, *alpha_compressed;
- unsigned long alpha_size, alpha_compressed_size;
+ char *alpha;
+ unsigned long alpha_size;
uint32_t *pixel32;
uint8_t *pixel8;
int i, x, y;
cairo_bool_t opaque;
uint8_t a;
int src_bit, dst_bit;
/* This is the only image format we support, which simplifies things. */
@@ -1363,71 +1314,55 @@ static cairo_status_t
}
}
}
/* Bail out without emitting smask if it's all opaque. */
if (opaque)
goto CLEANUP_ALPHA;
- alpha_compressed = compress_dup (alpha, alpha_size, &alpha_compressed_size);
- if (alpha_compressed == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto CLEANUP_ALPHA;
- }
-
status = _cairo_pdf_surface_open_stream (surface,
NULL,
- FALSE,
+ TRUE,
" /Type /XObject\r\n"
" /Subtype /Image\r\n"
" /Width %d\r\n"
" /Height %d\r\n"
" /ColorSpace /DeviceGray\r\n"
- " /BitsPerComponent %d\r\n"
- " /Filter /FlateDecode\r\n",
+ " /BitsPerComponent %d\r\n",
image->width, image->height,
image->format == CAIRO_FORMAT_A1 ? 1 : 8);
if (status)
- goto CLEANUP_ALPHA_COMPRESSED;
+ goto CLEANUP_ALPHA;
*stream_ret = surface->pdf_stream.self;
-
- _cairo_output_stream_write (surface->output, alpha_compressed, alpha_compressed_size);
- _cairo_output_stream_printf (surface->output, "\r\n");
+ _cairo_output_stream_write (surface->output, alpha, alpha_size);
status = _cairo_pdf_surface_close_stream (surface);
- CLEANUP_ALPHA_COMPRESSED:
- free (alpha_compressed);
CLEANUP_ALPHA:
free (alpha);
CLEANUP:
return status;
}
/* Emit image data into the given surface, providing a resource that
* can be used to reference the data in image_ret. */
static cairo_status_t
_cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
cairo_image_surface_t *image,
cairo_pdf_resource_t *image_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
- char *rgb, *compressed;
- unsigned long rgb_size, compressed_size;
+ char *rgb;
+ unsigned long rgb_size;
uint32_t *pixel;
int i, x, y;
cairo_pdf_resource_t smask = {0}; /* squelch bogus compiler warning */
cairo_bool_t need_smask;
- /* XXX: Need to rewrite this as a pdf_surface function with
- * pause/resume of content_stream, (currently the only caller does
- * the pause/resume already, but that is expected to change in the
- * future). */
-
/* These are the only image formats we currently support, (which
* makes things a lot simpler here). This is enforced through
* _cairo_pdf_surface_analyze_operation which only accept source surfaces of
* CONTENT_COLOR or CONTENT_COLOR_ALPHA.
*/
assert (image->format == CAIRO_FORMAT_RGB24 ||
image->format == CAIRO_FORMAT_ARGB32 ||
image->format == CAIRO_FORMAT_A8 ||
@@ -1469,69 +1404,58 @@ static cairo_status_t
} else {
rgb[i++] = 0;
rgb[i++] = 0;
rgb[i++] = 0;
}
}
}
- compressed = compress_dup (rgb, rgb_size, &compressed_size);
- if (compressed == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto CLEANUP_RGB;
- }
-
need_smask = FALSE;
if (image->format == CAIRO_FORMAT_ARGB32 ||
image->format == CAIRO_FORMAT_A8 ||
image->format == CAIRO_FORMAT_A1) {
status = _cairo_pdf_surface_emit_smask (surface, image, &smask);
if (status)
- goto CLEANUP_COMPRESSED;
+ goto CLEANUP_RGB;
if (smask.id)
need_smask = TRUE;
}
#define IMAGE_DICTIONARY " /Type /XObject\r\n" \
" /Subtype /Image\r\n" \
" /Width %d\r\n" \
" /Height %d\r\n" \
" /ColorSpace /DeviceRGB\r\n" \
- " /BitsPerComponent 8\r\n" \
- " /Filter /FlateDecode\r\n"
+ " /BitsPerComponent 8\r\n"
if (need_smask)
status = _cairo_pdf_surface_open_stream (surface,
NULL,
- FALSE,
+ TRUE,
IMAGE_DICTIONARY
" /SMask %d 0 R\r\n",
image->width, image->height,
smask.id);
else
status = _cairo_pdf_surface_open_stream (surface,
NULL,
- FALSE,
+ TRUE,
IMAGE_DICTIONARY,
image->width, image->height);
if (status)
- goto CLEANUP_COMPRESSED;
+ goto CLEANUP_RGB;
#undef IMAGE_DICTIONARY
*image_ret = surface->pdf_stream.self;
-
- _cairo_output_stream_write (surface->output, compressed, compressed_size);
- _cairo_output_stream_printf (surface->output, "\r\n");
+ _cairo_output_stream_write (surface->output, rgb, rgb_size);
status = _cairo_pdf_surface_close_stream (surface);
-CLEANUP_COMPRESSED:
- free (compressed);
CLEANUP_RGB:
free (rgb);
CLEANUP:
return status;
}
static cairo_status_t
_cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface,
@@ -1585,17 +1509,17 @@ static cairo_status_t
surface->height = meta_extents.height;
/* 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;
cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, surface->height);
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
- surface->cairo_to_pdf);
+ &surface->cairo_to_pdf);
_cairo_pdf_group_resources_clear (&surface->resources);
status = _cairo_pdf_surface_open_content_stream (surface, TRUE);
if (status)
return status;
*resource = surface->content;
if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
@@ -1619,17 +1543,17 @@ static cairo_status_t
status = _cairo_pdf_surface_close_content_stream (surface);
CLEANUP_GROUP:
surface->width = old_width;
surface->height = old_height;
surface->paginated_mode = old_paginated_mode;
surface->cairo_to_pdf = old_cairo_to_pdf;
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
- surface->cairo_to_pdf);
+ &surface->cairo_to_pdf);
return status;
}
static cairo_status_t
_cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
cairo_pdf_pattern_t *pdf_pattern)
{
@@ -2640,59 +2564,68 @@ static cairo_status_t
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *) pattern;
status = _cairo_pdf_surface_add_alpha (surface, solid_pattern->color.alpha, &alpha);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
- "q %f %f %f ",
+ "%f %f %f ",
solid_pattern->color.red,
solid_pattern->color.green,
solid_pattern->color.blue);
if (is_stroke)
_cairo_output_stream_printf (surface->output, "RG ");
else
_cairo_output_stream_printf (surface->output, "rg ");
_cairo_output_stream_printf (surface->output,
"/a%d gs\r\n",
alpha);
+ surface->select_pattern_gstate_saved = FALSE;
} else {
status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
if (status)
return status;
status = _cairo_pdf_surface_add_pattern (surface, pattern_res);
if (status)
return status;
+ /* 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 ");
+
if (is_stroke) {
_cairo_output_stream_printf (surface->output,
- "q /Pattern CS /p%d SCN ",
+ "/Pattern CS /p%d SCN ",
pattern_res.id);
} else {
_cairo_output_stream_printf (surface->output,
- "q /Pattern cs /p%d scn ",
+ "/Pattern cs /p%d scn ",
pattern_res.id);
}
_cairo_output_stream_printf (surface->output,
"/a%d gs\r\n",
alpha);
+ surface->select_pattern_gstate_saved = TRUE;
}
return _cairo_output_stream_get_status (surface->output);
}
static void
_cairo_pdf_surface_unselect_pattern (cairo_pdf_surface_t *surface)
{
- _cairo_output_stream_printf (surface->output, "Q\r\n");
+ if (surface->select_pattern_gstate_saved)
+ _cairo_output_stream_printf (surface->output, "Q\r\n");
+ surface->select_pattern_gstate_saved = FALSE;
}
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;
@@ -2877,21 +2810,21 @@ static cairo_int_status_t
if (i != 0 && i % 100 == 0) {
_cairo_output_stream_printf (surface->output,
"endbfchar\r\n"
"%d beginbfchar\r\n",
num_bfchar - i > 100 ? 100 : num_bfchar - i);
}
if (is_composite) {
_cairo_output_stream_printf (surface->output,
- "<%04x> <%04x>\r\n",
+ "<%04x> <%04lx>\r\n",
i + 1, font_subset->to_unicode[i + 1]);
} else {
_cairo_output_stream_printf (surface->output,
- "<%02x> <%04x>\r\n",
+ "<%02x> <%04lx>\r\n",
i + 1, font_subset->to_unicode[i + 1]);
}
}
_cairo_output_stream_printf (surface->output,
"endbfchar\r\n");
_cairo_output_stream_printf (surface->output,
"endcmap\r\n"
@@ -2906,52 +2839,38 @@ static cairo_int_status_t
static cairo_status_t
_cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface,
cairo_scaled_font_subset_t *font_subset,
cairo_cff_subset_t *subset)
{
cairo_pdf_resource_t stream, descriptor, cidfont_dict;
cairo_pdf_resource_t subset_resource, to_unicode_stream;
cairo_pdf_font_t font;
- unsigned long compressed_length;
- char *compressed;
unsigned int i;
cairo_status_t status;
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;
- compressed = compress_dup (subset->data, subset->data_length, &compressed_length);
- if (compressed == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- stream = _cairo_pdf_surface_new_object (surface);
- if (stream.id == 0) {
- free (compressed);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\r\n"
- "<< /Filter /FlateDecode\r\n"
- " /Length %lu\r\n"
- " /Subtype /CIDFontType0C\r\n"
- ">>\r\n"
- "stream\r\n",
- stream.id,
- compressed_length);
- _cairo_output_stream_write (surface->output, compressed, compressed_length);
- _cairo_output_stream_printf (surface->output,
- "\r\n"
- "endstream\r\n"
- "endobj\r\n");
- free (compressed);
+ status = _cairo_pdf_surface_open_stream (surface,
+ NULL,
+ TRUE,
+ " /Subtype /CIDFontType0C\r\n");
+ if (status)
+ return status;
+
+ 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;
status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
font_subset, TRUE,
&to_unicode_stream);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
descriptor = _cairo_pdf_surface_new_object (surface);
@@ -3087,57 +3006,43 @@ static cairo_status_t
static cairo_status_t
_cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface,
cairo_scaled_font_subset_t *font_subset,
cairo_type1_subset_t *subset)
{
cairo_pdf_resource_t stream, descriptor, subset_resource, to_unicode_stream;
cairo_pdf_font_t font;
cairo_status_t status;
- unsigned long length, compressed_length;
- char *compressed;
+ unsigned long length;
unsigned int i;
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;
/* We ignore the zero-trailer and set Length3 to 0. */
length = subset->header_length + subset->data_length;
- compressed = compress_dup (subset->data, length, &compressed_length);
- if (compressed == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- stream = _cairo_pdf_surface_new_object (surface);
- if (stream.id == 0) {
- free (compressed);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\r\n"
- "<< /Filter /FlateDecode\r\n"
- " /Length %lu\r\n"
- " /Length1 %lu\r\n"
- " /Length2 %lu\r\n"
- " /Length3 0\r\n"
- ">>\r\n"
- "stream\r\n",
- stream.id,
- compressed_length,
- subset->header_length,
- subset->data_length);
- _cairo_output_stream_write (surface->output, compressed, compressed_length);
- _cairo_output_stream_printf (surface->output,
- "\r\n"
- "endstream\r\n"
- "endobj\r\n");
- free (compressed);
+ status = _cairo_pdf_surface_open_stream (surface,
+ NULL,
+ TRUE,
+ " /Length1 %lu\r\n"
+ " /Length2 %lu\r\n"
+ " /Length3 0\r\n",
+ subset->header_length,
+ subset->data_length);
+ if (status)
+ return status;
+
+ 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;
status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
font_subset, FALSE,
&to_unicode_stream);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
descriptor = _cairo_pdf_surface_new_object (surface);
@@ -3255,59 +3160,46 @@ static cairo_status_t
_cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
cairo_scaled_font_subset_t *font_subset)
{
cairo_pdf_resource_t stream, descriptor, cidfont_dict;
cairo_pdf_resource_t subset_resource, to_unicode_stream;
cairo_status_t status;
cairo_pdf_font_t font;
cairo_truetype_subset_t subset;
- unsigned long compressed_length;
- char *compressed;
unsigned int i;
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;
status = _cairo_truetype_subset_init (&subset, font_subset);
if (status)
return status;
- compressed = compress_dup (subset.data, subset.data_length,
- &compressed_length);
- if (compressed == NULL) {
+ status = _cairo_pdf_surface_open_stream (surface,
+ NULL,
+ TRUE,
+ " /Length1 %lu\r\n",
+ subset.data_length);
+ if (status) {
_cairo_truetype_subset_fini (&subset);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- stream = _cairo_pdf_surface_new_object (surface);
- if (stream.id == 0) {
- free (compressed);
- _cairo_truetype_subset_fini (&subset);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return status;
}
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\r\n"
- "<< /Filter /FlateDecode\r\n"
- " /Length %lu\r\n"
- " /Length1 %lu\r\n"
- ">>\r\n"
- "stream\r\n",
- stream.id,
- compressed_length,
- subset.data_length);
- _cairo_output_stream_write (surface->output, compressed, compressed_length);
- _cairo_output_stream_printf (surface->output,
- "\r\n"
- "endstream\r\n"
- "endobj\r\n");
- free (compressed);
+
+ 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) {
+ _cairo_truetype_subset_fini (&subset);
+ return status;
+ }
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;
}
@@ -3938,17 +3830,17 @@ static cairo_status_t
old_width = surface->width;
old_height = surface->height;
old_cairo_to_pdf = surface->cairo_to_pdf;
surface->width = group->width;
surface->height = group->height;
cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, surface->height);
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
- surface->cairo_to_pdf);
+ &surface->cairo_to_pdf);
/* _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)
@@ -3971,21 +3863,21 @@ static cairo_status_t
ASSERT_NOT_REACHED;
break;
case PDF_FILL:
status = _cairo_pdf_operators_fill (&surface->pdf_operators,
&group->path,
group->fill_rule);
break;
case PDF_STROKE:
- status = _cairo_pdf_operator_stroke (&surface->pdf_operators,
- &group->path,
- group->style,
- &group->ctm,
- &group->ctm_inverse);
+ status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
+ &group->path,
+ group->style,
+ &group->ctm,
+ &group->ctm_inverse);
break;
case PDF_SHOW_GLYPHS:
status = _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
group->glyphs,
group->num_glyphs,
group->scaled_font);
break;
}
@@ -3994,17 +3886,17 @@ static cairo_status_t
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_close_group (surface, NULL);
surface->width = old_width;
surface->height = old_height;
surface->cairo_to_pdf = old_cairo_to_pdf;
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
- surface->cairo_to_pdf);
+ &surface->cairo_to_pdf);
return status;
}
static cairo_status_t
_cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface)
{
cairo_pdf_pattern_t pattern;
@@ -4472,21 +4364,21 @@ static cairo_int_status_t
"q /s%d gs /x%d Do Q\r\n",
gstate_res.id,
group->group_res.id);
} else {
status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, TRUE);
if (status)
return status;
- status = _cairo_pdf_operator_stroke (&surface->pdf_operators,
- path,
- style,
- ctm,
- ctm_inverse);
+ status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
+ path,
+ style,
+ ctm,
+ ctm_inverse);
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
}
return _cairo_output_stream_get_status (surface->output);
}
@@ -4569,16 +4461,107 @@ static cairo_int_status_t
_cairo_pdf_surface_unselect_pattern (surface);
}
return _cairo_output_stream_get_status (surface->output);
}
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;
+
+ /* Fill-stroke with patterns requiring an SMask are not currently
+ * implemented. Non opaque stroke patterns are not supported
+ * because the PDF fill-stroke operator does not blend a
+ * transparent stroke with the fill.
+ */
+ if (fill_source->type == CAIRO_PATTERN_TYPE_LINEAR ||
+ fill_source->type == CAIRO_PATTERN_TYPE_RADIAL)
+ {
+ if (!_cairo_pattern_is_opaque (fill_source))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ if (!_cairo_pattern_is_opaque (stroke_source))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ 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;
+
+ _cairo_pdf_surface_unselect_pattern (surface);
+
+ return _cairo_output_stream_get_status (surface->output);
+}
+
+static cairo_int_status_t
_cairo_pdf_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
{
cairo_pdf_surface_t *surface = abstract_surface;
@@ -4685,14 +4668,15 @@ static const cairo_surface_backend_t cai
_cairo_pdf_surface_mask,
_cairo_pdf_surface_stroke,
_cairo_pdf_surface_fill,
_cairo_pdf_surface_show_glyphs,
NULL, /* snapshot */
NULL, /* is_compatible */
NULL, /* reset */
+ _cairo_pdf_surface_fill_stroke,
};
static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend = {
_cairo_pdf_surface_start_page,
_cairo_pdf_surface_set_paginated_mode
};
--- a/gfx/cairo/cairo/src/cairo-png.c
+++ b/gfx/cairo/cairo/src/cairo-png.c
@@ -127,31 +127,33 @@ write_png (cairo_surface_t *surface,
png_color_16 white;
int png_color_type;
int depth;
status = _cairo_surface_acquire_source_image (surface,
&image,
&image_extra);
- if (status == CAIRO_STATUS_NO_MEMORY)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- else if (status != CAIRO_STATUS_SUCCESS)
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ else if (status)
+ return status;
+
+ /* PNG complains about "Image width or height is zero in IHDR" */
+ if (image->width == 0 || image->height == 0)
+ return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
- if (image->height && image->width) {
- rows = _cairo_malloc_ab (image->height, sizeof (png_byte*));
- if (rows == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL1;
- }
+ rows = _cairo_malloc_ab (image->height, sizeof (png_byte*));
+ if (rows == NULL) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL1;
+ }
- for (i = 0; i < image->height; i++)
- rows[i] = (png_byte *) image->data + i * image->stride;
- }
+ for (i = 0; i < image->height; i++)
+ rows[i] = (png_byte *) image->data + i * image->stride;
png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status,
png_simple_error_callback,
png_simple_warning_callback);
if (png == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL2;
}
--- a/gfx/cairo/cairo/src/cairo-ps-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-ps-surface-private.h
@@ -1,8 +1,9 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
* Copyright © 2005 Red Hat, Inc
*
* 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
@@ -38,16 +39,17 @@
*/
#ifndef CAIRO_PS_SURFACE_PRIVATE_H
#define CAIRO_PS_SURFACE_PRIVATE_H
#include "cairo-ps.h"
#include "cairo-surface-private.h"
+#include "cairo-pdf-operators-private.h"
typedef struct cairo_ps_surface {
cairo_surface_t base;
/* Here final_stream corresponds to the stream/file passed to
* cairo_ps_surface_create surface is built. Meanwhile stream is a
* temporary stream in which the file output is built, (so that
* the header can be built and inserted into the target stream
@@ -57,16 +59,20 @@ typedef struct cairo_ps_surface {
FILE *tmpfile;
cairo_output_stream_t *stream;
cairo_bool_t eps;
cairo_content_t content;
double width;
double height;
int bbox_x1, bbox_y1, bbox_x2, bbox_y2;
+ cairo_matrix_t cairo_to_ps;
+ cairo_image_surface_t *image;
+ void *image_extra;
+ cairo_bool_t use_string_datasource;
int num_pages;
cairo_paginated_mode_t paginated_mode;
cairo_bool_t force_fallbacks;
cairo_scaled_font_subsets_t *font_subsets;
@@ -75,12 +81,13 @@ typedef struct cairo_ps_surface {
cairo_array_t dsc_setup_comments;
cairo_array_t dsc_page_setup_comments;
cairo_array_t *dsc_comment_target;
cairo_ps_level_t ps_level;
cairo_ps_level_t ps_level_used;
+ cairo_pdf_operators_t pdf_operators;
cairo_surface_t *paginated_surface;
} cairo_ps_surface_t;
#endif /* CAIRO_PS_SURFACE_PRIVATE_H */
--- a/gfx/cairo/cairo/src/cairo-ps-surface.c
+++ b/gfx/cairo/cairo/src/cairo-ps-surface.c
@@ -1,14 +1,14 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
* Copyright © 2005 Red Hat, Inc
- * Copyright © 2007 Adrian Johnson
+ * Copyright © 2007,2008 Adrian Johnson
*
* 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.
@@ -38,16 +38,17 @@
* Kristian Høgsberg <krh@redhat.com>
* Keith Packard <keithp@keithp.com>
* Adrian Johnson <ajohnson@redneon.com>
*/
#include "cairoint.h"
#include "cairo-ps.h"
#include "cairo-ps-surface-private.h"
+#include "cairo-pdf-operators-private.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-paginated-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-output-stream-private.h"
#include <stdio.h>
#include <ctype.h>
#include <time.h>
@@ -78,258 +79,16 @@ static const cairo_ps_level_t _cairo_ps_
#define CAIRO_PS_LEVEL_LAST ARRAY_LENGTH (_cairo_ps_levels)
static const char * _cairo_ps_level_strings[CAIRO_PS_LEVEL_LAST] =
{
"PS Level 2",
"PS Level 3"
};
-/* A word wrap stream can be used as a filter to do word wrapping on
- * top of an existing output stream. The word wrapping is quite
- * simple, using isspace to determine characters that separate
- * words. Any word that will cause the column count exceed the given
- * max_column will have a '\n' character emitted before it.
- *
- * The stream is careful to maintain integrity for words that cross
- * the boundary from one call to write to the next.
- *
- * Note: This stream does not guarantee that the output will never
- * exceed max_column. In particular, if a single word is larger than
- * max_column it will not be broken up.
- */
-typedef struct _word_wrap_stream {
- cairo_output_stream_t base;
- cairo_output_stream_t *output;
- int max_column;
- int column;
- cairo_bool_t last_write_was_space;
-} word_wrap_stream_t;
-
-static int
-_count_word_up_to (const unsigned char *s, int length)
-{
- int word = 0;
-
- while (length--) {
- if (! isspace (*s++))
- word++;
- else
- return word;
- }
-
- return word;
-}
-
-static cairo_status_t
-_word_wrap_stream_write (cairo_output_stream_t *base,
- const unsigned char *data,
- unsigned int length)
-{
- word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
- cairo_bool_t newline;
- int word;
-
- while (length) {
- if (isspace (*data)) {
- newline = (*data == '\n' || *data == '\r');
- if (! newline && stream->column >= stream->max_column) {
- _cairo_output_stream_printf (stream->output, "\n");
- stream->column = 0;
- }
- _cairo_output_stream_write (stream->output, data, 1);
- data++;
- length--;
- if (newline)
- stream->column = 0;
- else
- stream->column++;
- stream->last_write_was_space = TRUE;
- } else {
- word = _count_word_up_to (data, length);
- /* Don't wrap if this word is a continuation of a word
- * from a previous call to write. */
- if (stream->column + word >= stream->max_column &&
- stream->last_write_was_space)
- {
- _cairo_output_stream_printf (stream->output, "\n");
- stream->column = 0;
- }
- _cairo_output_stream_write (stream->output, data, word);
- data += word;
- length -= word;
- stream->column += word;
- stream->last_write_was_space = FALSE;
- }
- }
-
- return _cairo_output_stream_get_status (stream->output);
-}
-
-static cairo_status_t
-_word_wrap_stream_close (cairo_output_stream_t *base)
-{
- word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
-
- return _cairo_output_stream_get_status (stream->output);
-}
-
-static cairo_output_stream_t *
-_word_wrap_stream_create (cairo_output_stream_t *output, int max_column)
-{
- word_wrap_stream_t *stream;
-
- if (output->status)
- return _cairo_output_stream_create_in_error (output->status);
-
- stream = malloc (sizeof (word_wrap_stream_t));
- if (stream == NULL) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return (cairo_output_stream_t *) &_cairo_output_stream_nil;
- }
-
- _cairo_output_stream_init (&stream->base,
- _word_wrap_stream_write,
- _word_wrap_stream_close);
- stream->output = output;
- stream->max_column = max_column;
- stream->column = 0;
- stream->last_write_was_space = FALSE;
-
- return &stream->base;
-}
-
-typedef struct _ps_path_info {
- cairo_ps_surface_t *surface;
- cairo_output_stream_t *stream;
- cairo_line_cap_t line_cap;
- cairo_point_t last_move_to_point;
- cairo_bool_t has_sub_path;
-} ps_path_info_t;
-
-static cairo_status_t
-_cairo_ps_surface_path_move_to (void *closure, cairo_point_t *point)
-{
- ps_path_info_t *path_info = closure;
-
- path_info->last_move_to_point = *point;
- path_info->has_sub_path = FALSE;
-
- _cairo_output_stream_printf (path_info->stream,
- "%f %f M ",
- _cairo_fixed_to_double (point->x),
- _cairo_fixed_to_double (point->y));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_line_to (void *closure, cairo_point_t *point)
-{
- ps_path_info_t *path_info = closure;
-
- if (path_info->line_cap != CAIRO_LINE_CAP_ROUND &&
- ! path_info->has_sub_path &&
- point->x == path_info->last_move_to_point.x &&
- point->y == path_info->last_move_to_point.y)
- {
- return CAIRO_STATUS_SUCCESS;
- }
-
- path_info->has_sub_path = TRUE;
-
- _cairo_output_stream_printf (path_info->stream,
- "%f %f L ",
- _cairo_fixed_to_double (point->x),
- _cairo_fixed_to_double (point->y));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d)
-{
- ps_path_info_t *path_info = closure;
-
- path_info->has_sub_path = TRUE;
-
- _cairo_output_stream_printf (path_info->stream,
- "%f %f %f %f %f %f C ",
- _cairo_fixed_to_double (b->x),
- _cairo_fixed_to_double (b->y),
- _cairo_fixed_to_double (c->x),
- _cairo_fixed_to_double (c->y),
- _cairo_fixed_to_double (d->x),
- _cairo_fixed_to_double (d->y));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_close_path (void *closure)
-{
- ps_path_info_t *path_info = closure;
-
- if (path_info->line_cap != CAIRO_LINE_CAP_ROUND &&
- ! path_info->has_sub_path)
- {
- return CAIRO_STATUS_SUCCESS;
- }
-
- _cairo_output_stream_printf (path_info->stream,
- "P\n");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* The line cap value is needed to workaround the fact that PostScript
- * semantics for stroking degenerate sub-paths do not match cairo
- * semantics. (PostScript draws something for any line cap value,
- * while cairo draws something only for round caps).
- *
- * When using this function to emit a path to be filled, rather than
- * stroked, simply pass %CAIRO_LINE_CAP_ROUND which will guarantee that
- * the stroke workaround will not modify the path being emitted.
- */
-static cairo_status_t
-_cairo_ps_surface_emit_path (cairo_ps_surface_t *surface,
- cairo_output_stream_t *stream,
- cairo_path_fixed_t *path,
- cairo_line_cap_t line_cap)
-{
- cairo_output_stream_t *word_wrap;
- cairo_status_t status, status2;
- ps_path_info_t path_info;
-
- word_wrap = _word_wrap_stream_create (stream, 79);
- status = _cairo_output_stream_get_status (word_wrap);
- if (status)
- return _cairo_output_stream_destroy (word_wrap);
-
- path_info.surface = surface;
- path_info.stream = word_wrap;
- path_info.line_cap = line_cap;
- status = _cairo_path_fixed_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_ps_surface_path_move_to,
- _cairo_ps_surface_path_line_to,
- _cairo_ps_surface_path_curve_to,
- _cairo_ps_surface_path_close_path,
- &path_info);
-
- status2 = _cairo_output_stream_destroy (word_wrap);
- if (status == CAIRO_STATUS_SUCCESS)
- status = status2;
-
- return status;
-}
-
static void
_cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
{
char ctime_buf[26];
time_t now;
char **comments;
int i, num_comments;
int level;
@@ -383,36 +142,61 @@ static void
if (surface->eps) {
_cairo_output_stream_printf (surface->final_stream,
"/cairo_eps_state save def\n"
"/dict_count countdictstack def\n"
"/op_count count 1 sub def\n"
"userdict begin\n");
} else {
_cairo_output_stream_printf (surface->final_stream,
- "/languagelevel where{pop languagelevel}{1}ifelse %d lt{/Helvetica\n"
- "findfont 12 scalefont setfont 50 500 moveto\n"
- "(This print job requires a PostScript Language Level %d printer.)show\n"
- "showpage quit}if\n",
+ "/languagelevel where\n"
+ "{ pop languagelevel } { 1 } ifelse\n"
+ "%d lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto\n"
+ " (This print job requires a PostScript Language Level %d printer.) show\n"
+ " showpage quit } if\n",
level,
level);
}
_cairo_output_stream_printf (surface->final_stream,
- "/C{curveto}bind def\n"
- "/F{fill}bind def\n"
- "/G{setgray}bind def\n"
- "/L{lineto}bind def\n"
- "/M{moveto}bind def\n"
- "/P{closepath}bind def\n"
- "/R{setrgbcolor}bind def\n"
- "/S{show}bind def\n"
- "/xS{xshow}bind def\n"
- "/yS{yshow}bind def\n"
- "/xyS{xyshow}bind def\n"
+ "/q { gsave } bind def\n"
+ "/Q { grestore } bind def\n"
+ "/cm { 6 array astore concat } bind def\n"
+ "/w { setlinewidth } bind def\n"
+ "/J { setlinecap } bind def\n"
+ "/j { setlinejoin } bind def\n"
+ "/M { setmiterlimit } bind def\n"
+ "/d { setdash } bind def\n"
+ "/m { moveto } bind def\n"
+ "/l { lineto } bind def\n"
+ "/c { curveto } bind def\n"
+ "/h { closepath } bind def\n"
+ "/S { stroke } bind def\n"
+ "/f { fill } bind def\n"
+ "/f* { eofill } bind def\n"
+ "/n { newpath } bind def\n"
+ "/W { clip } bind def\n"
+ "/W* { eoclip } bind def\n"
+ "/Tf { pop /cairo_font exch def } bind def\n"
+ "/BT { } bind def\n"
+ "/ET { } bind def\n"
+ "/Tj { show } bind def\n"
+ "/TJ {\n"
+ " {\n"
+ " dup\n"
+ " type /stringtype eq\n"
+ " { show } { -0.0001 mul 0 rmoveto } ifelse\n"
+ " } forall\n"
+ "} bind def\n"
+ "/Td { moveto } bind def\n"
+ "/Tm { 6 array astore cairo_font exch selectfont 0 0 moveto } bind def\n"
+ "/g { setgray } bind def\n"
+ "/rg { setrgbcolor } bind def\n");
+
+ _cairo_output_stream_printf (surface->final_stream,
"%%%%EndProlog\n");
num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments);
if (num_comments) {
_cairo_output_stream_printf (surface->final_stream,
"%%%%BeginSetup\n");
comments = _cairo_array_index (&surface->dsc_setup_comments, 0);
@@ -435,17 +219,17 @@ static cairo_status_t
{
cairo_type1_subset_t subset;
cairo_status_t status;
int length;
char name[64];
- snprintf (name, sizeof name, "CairoFont-%d-%d",
+ snprintf (name, sizeof name, "f-%d-%d",
font_subset->font_id, font_subset->subset_id);
status = _cairo_type1_subset_init (&subset, name, font_subset, TRUE);
if (status)
return status;
/* FIXME: Figure out document structure convention for fonts */
#if DEBUG_PS
@@ -466,17 +250,17 @@ static cairo_status_t
_cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t *surface,
cairo_scaled_font_subset_t *font_subset)
{
cairo_type1_subset_t subset;
cairo_status_t status;
int length;
char name[64];
- snprintf (name, sizeof name, "CairoFont-%d-%d",
+ snprintf (name, sizeof name, "f-%d-%d",
font_subset->font_id, font_subset->subset_id);
status = _cairo_type1_fallback_init_hex (&subset, name, font_subset);
if (status)
return status;
/* FIXME: Figure out document structure convention for fonts */
#if DEBUG_PS
@@ -511,17 +295,17 @@ static cairo_status_t
#if DEBUG_PS
_cairo_output_stream_printf (surface->final_stream,
"%% _cairo_ps_surface_emit_truetype_font_subset\n");
#endif
_cairo_output_stream_printf (surface->final_stream,
"11 dict begin\n"
"/FontType 42 def\n"
- "/FontName /CairoFont-%d-%d def\n"
+ "/FontName /f-%d-%d def\n"
"/PaintType 0 def\n"
"/FontMatrix [ 1 0 0 1 0 0 ] def\n"
"/FontBBox [ 0 0 0 0 ] def\n"
"/Encoding 256 array def\n"
"0 1 255 { Encoding exch /.notdef put } for\n",
font_subset->font_id,
font_subset->subset_id);
@@ -581,58 +365,19 @@ static cairo_status_t
"FontName currentdict end definefont pop\n");
_cairo_truetype_subset_fini (&subset);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
-_cairo_ps_surface_emit_outline_glyph_data (cairo_ps_surface_t *surface,
- cairo_scaled_font_t *scaled_font,
- unsigned long glyph_index,
- cairo_box_t *bbox)
-{
- cairo_scaled_glyph_t *scaled_glyph;
- cairo_status_t status;
-
- status = _cairo_scaled_glyph_lookup (scaled_font,
- glyph_index,
- CAIRO_SCALED_GLYPH_INFO_METRICS|
- CAIRO_SCALED_GLYPH_INFO_PATH,
- &scaled_glyph);
- if (status)
- return status;
-
- *bbox = scaled_glyph->bbox;
- _cairo_output_stream_printf (surface->final_stream,
- "0 0 %f %f %f %f setcachedevice\n",
- _cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
- -_cairo_fixed_to_double (scaled_glyph->bbox.p2.y),
- _cairo_fixed_to_double (scaled_glyph->bbox.p2.x),
- -_cairo_fixed_to_double (scaled_glyph->bbox.p1.y));
-
- /* We're filling not stroking, so we pass CAIRO_LINE_CAP_ROUND. */
- status = _cairo_ps_surface_emit_path (surface,
- surface->final_stream,
- scaled_glyph->path,
- CAIRO_LINE_CAP_ROUND);
- if (status)
- return status;
-
- _cairo_output_stream_printf (surface->final_stream,
- "F\n");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
_cairo_ps_surface_emit_bitmap_glyph_data (cairo_ps_surface_t *surface,
cairo_scaled_font_t *scaled_font,
- unsigned long glyph_index,
+ unsigned long glyph_index,
cairo_box_t *bbox)
{
cairo_scaled_glyph_t *scaled_glyph;
cairo_status_t status;
cairo_image_surface_t *image;
unsigned char *row, *byte;
int rows, cols;
double x_advance, y_advance;
@@ -713,25 +458,20 @@ static cairo_status_t
cairo_box_t *bbox)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
_cairo_output_stream_printf (surface->final_stream,
"\t\t{ %% %d\n", subset_glyph_index);
if (subset_glyph_index != 0) {
- status = _cairo_ps_surface_emit_outline_glyph_data (surface,
- scaled_font,
- scaled_font_glyph_index,
- bbox);
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
- status = _cairo_ps_surface_emit_bitmap_glyph_data (surface,
- scaled_font,
- scaled_font_glyph_index,
- bbox);
+ status = _cairo_ps_surface_emit_bitmap_glyph_data (surface,
+ scaled_font,
+ scaled_font_glyph_index,
+ bbox);
}
_cairo_output_stream_printf (surface->final_stream,
"\t\t}\n");
if (status)
status = _cairo_surface_set_error (&surface->base, status);
@@ -810,17 +550,17 @@ static cairo_status_t
"] def\n"
"/FontBBox [%f %f %f %f] def\n"
"/BuildChar {\n"
" exch /Glyphs get\n"
" exch get exec\n"
"} bind def\n"
"currentdict\n"
"end\n"
- "/CairoFont-%d-%d exch definefont pop\n",
+ "/f-%d-%d exch definefont pop\n",
_cairo_fixed_to_double (font_bbox.p1.x),
_cairo_fixed_to_double (font_bbox.p1.y),
_cairo_fixed_to_double (font_bbox.p2.x),
_cairo_fixed_to_double (font_bbox.p2.y),
font_subset->font_id,
font_subset->subset_id);
return CAIRO_STATUS_SUCCESS;
@@ -978,20 +718,26 @@ static cairo_surface_t *
goto CLEANUP_OUTPUT_STREAM;
}
surface->eps = FALSE;
surface->ps_level = CAIRO_PS_LEVEL_3;
surface->ps_level_used = CAIRO_PS_LEVEL_2;
surface->width = width;
surface->height = height;
+ cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, height);
surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
surface->force_fallbacks = FALSE;
surface->content = CAIRO_CONTENT_COLOR_ALPHA;
-
+ surface->use_string_datasource = FALSE;
+
+ _cairo_pdf_operators_init (&surface->pdf_operators,
+ surface->stream,
+ &surface->cairo_to_ps,
+ surface->font_subsets);
surface->num_pages = 0;
_cairo_array_init (&surface->dsc_header_comments, sizeof (char *));
_cairo_array_init (&surface->dsc_setup_comments, sizeof (char *));
_cairo_array_init (&surface->dsc_page_setup_comments, sizeof (char *));
surface->dsc_comment_target = &surface->dsc_header_comments;
@@ -1288,16 +1034,19 @@ cairo_ps_surface_set_size (cairo_surface
status = _extract_ps_surface (surface, &ps_surface);
if (status) {
status = _cairo_surface_set_error (surface, status);
return;
}
ps_surface->width = width_in_points;
ps_surface->height = height_in_points;
+ cairo_matrix_init (&ps_surface->cairo_to_ps, 1, 0, 0, -1, 0, height_in_points);
+ _cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface->pdf_operators,
+ &ps_surface->cairo_to_ps);
status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface,
width_in_points,
height_in_points);
if (status)
status = _cairo_surface_set_error (surface, status);
}
/**
@@ -1569,17 +1318,17 @@ static cairo_int_status_t
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_ps_surface_end_page (cairo_ps_surface_t *surface)
{
_cairo_output_stream_printf (surface->stream,
- "grestore grestore\n");
+ "grestore\n");
}
static cairo_int_status_t
_cairo_ps_surface_show_page (void *abstract_surface)
{
cairo_ps_surface_t *surface = abstract_surface;
_cairo_ps_surface_end_page (surface);
@@ -1593,53 +1342,48 @@ static cairo_bool_t
color_is_gray (double red, double green, double blue)
{
const double epsilon = 0.00001;
return (fabs (red - green) < epsilon &&
fabs (red - blue) < epsilon);
}
-static cairo_status_t
-_analyze_image_transparency (cairo_image_surface_t *image,
- cairo_image_transparency_t *transparency)
+static cairo_image_transparency_t
+_analyze_image_transparency (cairo_image_surface_t *image)
{
int x, y;
-
- if (image->format == CAIRO_FORMAT_RGB24) {
- *transparency = CAIRO_IMAGE_IS_OPAQUE;
- return CAIRO_STATUS_SUCCESS;
- }
+ cairo_image_transparency_t transparency;
+
+ if (image->format == CAIRO_FORMAT_RGB24)
+ return CAIRO_IMAGE_IS_OPAQUE;
if (image->format != CAIRO_FORMAT_ARGB32) {
/* If the PS surface does not support the image format, assume
* that it does have alpha. The image will be converted to
* rgb24 when the PS surface blends the image into the page
* color to remove the transparency. */
- *transparency = CAIRO_IMAGE_HAS_ALPHA;
- return CAIRO_STATUS_SUCCESS;
+ return CAIRO_IMAGE_HAS_ALPHA;
}
- *transparency = CAIRO_IMAGE_IS_OPAQUE;
+ transparency = CAIRO_IMAGE_IS_OPAQUE;
for (y = 0; y < image->height; y++) {
- int a;
uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
for (x = 0; x < image->width; x++, pixel++) {
- a = (*pixel & 0xff000000) >> 24;
+ int a = (*pixel & 0xff000000) >> 24;
if (a > 0 && a < 255) {
- *transparency = CAIRO_IMAGE_HAS_ALPHA;
- return CAIRO_STATUS_SUCCESS;
+ return CAIRO_IMAGE_HAS_ALPHA;
} else if (a == 0) {
- *transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
+ transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
}
}
}
- return CAIRO_STATUS_SUCCESS;
+ return transparency;
}
static cairo_int_status_t
_cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t *surface,
cairo_surface_pattern_t *pattern)
{
cairo_image_surface_t *image;
void *image_extra;
@@ -1650,20 +1394,17 @@ static cairo_int_status_t
&image,
&image_extra);
if (status)
return status;
if (image->base.status)
return image->base.status;
- status = _analyze_image_transparency (image, &transparency);
- if (status)
- goto RELEASE_SOURCE;
-
+ transparency = _analyze_image_transparency (image);
switch (transparency) {
case CAIRO_IMAGE_IS_OPAQUE:
status = CAIRO_STATUS_SUCCESS;
break;
case CAIRO_IMAGE_HAS_BILEVEL_ALPHA:
if (surface->ps_level == CAIRO_PS_LEVEL_2) {
status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
@@ -1673,17 +1414,16 @@ static cairo_int_status_t
}
break;
case CAIRO_IMAGE_HAS_ALPHA:
status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
break;
}
-RELEASE_SOURCE:
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
return status;
}
static cairo_bool_t
surface_pattern_supported (cairo_surface_pattern_t *pattern)
{
@@ -1850,59 +1590,64 @@ static cairo_bool_t
#define STRING_ARRAY_MAX_STRING_SIZE (65535-1)
#define STRING_ARRAY_MAX_COLUMN 72
typedef struct _string_array_stream {
cairo_output_stream_t base;
cairo_output_stream_t *output;
int column;
int string_size;
+ cairo_bool_t use_strings;
} string_array_stream_t;
static cairo_status_t
_string_array_stream_write (cairo_output_stream_t *base,
const unsigned char *data,
unsigned int length)
{
string_array_stream_t *stream = (string_array_stream_t *) base;
unsigned char c;
const unsigned char backslash = '\\';
if (length == 0)
return CAIRO_STATUS_SUCCESS;
while (length--) {
- if (stream->string_size == 0) {
+ if (stream->string_size == 0 && stream->use_strings) {
_cairo_output_stream_printf (stream->output, "(");
stream->column++;
}
c = *data++;
- switch (c) {
- case '\\':
- case '(':
- case ')':
- _cairo_output_stream_write (stream->output, &backslash, 1);
- stream->column++;
- stream->string_size++;
- break;
- /* Have to also be careful to never split the final ~> sequence. */
- case '~':
- _cairo_output_stream_write (stream->output, &c, 1);
- stream->column++;
- stream->string_size++;
- length--;
- c = *data++;
- break;
+ if (stream->use_strings) {
+ switch (c) {
+ case '\\':
+ case '(':
+ case ')':
+ _cairo_output_stream_write (stream->output, &backslash, 1);
+ stream->column++;
+ stream->string_size++;
+ break;
+ /* Have to also be careful to never split the final ~> sequence. */
+ case '~':
+ _cairo_output_stream_write (stream->output, &c, 1);
+ stream->column++;
+ stream->string_size++;
+ length--;
+ c = *data++;
+ break;
+ }
}
_cairo_output_stream_write (stream->output, &c, 1);
stream->column++;
stream->string_size++;
- if (stream->string_size >= STRING_ARRAY_MAX_STRING_SIZE) {
+ if (stream->use_strings &&
+ stream->string_size >= STRING_ARRAY_MAX_STRING_SIZE)
+ {
_cairo_output_stream_printf (stream->output, ")\n");
stream->string_size = 0;
stream->column = 0;
}
if (stream->column >= STRING_ARRAY_MAX_COLUMN) {
_cairo_output_stream_printf (stream->output, "\n ");
stream->string_size += 2;
stream->column = 1;
@@ -1913,17 +1658,18 @@ static cairo_status_t
}
static cairo_status_t
_string_array_stream_close (cairo_output_stream_t *base)
{
cairo_status_t status;
string_array_stream_t *stream = (string_array_stream_t *) base;
- _cairo_output_stream_printf (stream->output, ")\n");
+ if (stream->use_strings)
+ _cairo_output_stream_printf (stream->output, ")\n");
status = _cairo_output_stream_get_status (stream->output);
return status;
}
/* A string_array_stream wraps an existing output stream. It takes the
* data provided to it and output one or more consecutive string
@@ -1951,20 +1697,48 @@ static cairo_output_stream_t *
}
_cairo_output_stream_init (&stream->base,
_string_array_stream_write,
_string_array_stream_close);
stream->output = output;
stream->column = 0;
stream->string_size = 0;
+ stream->use_strings = TRUE;
return &stream->base;
}
+/* A base85_array_stream wraps an existing output stream. It wraps the
+ * output within STRING_ARRAY_MAX_COLUMN columns (+/- 1). The output
+ * is not enclosed in strings like string_array_stream.
+ */
+static cairo_output_stream_t *
+_base85_array_stream_create (cairo_output_stream_t *output)
+{
+ string_array_stream_t *stream;
+
+ stream = malloc (sizeof (string_array_stream_t));
+ if (stream == NULL) {
+ _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+ return (cairo_output_stream_t *) &_cairo_output_stream_nil;
+ }
+
+ _cairo_output_stream_init (&stream->base,
+ _string_array_stream_write,
+ _string_array_stream_close);
+ stream->output = output;
+ stream->column = 0;
+ stream->string_size = 0;
+ stream->use_strings = FALSE;
+
+ return &stream->base;
+}
+
+
/* PS Output - this section handles output of the parts of the meta
* surface we can render natively in PS. */
static cairo_status_t
_cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface,
cairo_image_surface_t *image,
cairo_image_surface_t **opaque_image)
{
@@ -2016,22 +1790,27 @@ fail:
cairo_surface_destroy (opaque);
return status;
}
static cairo_status_t
_cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface,
unsigned char *data,
- unsigned long length)
+ unsigned long length,
+ cairo_bool_t use_strings)
{
cairo_output_stream_t *base85_stream, *string_array_stream;
cairo_status_t status, status2;
- string_array_stream = _string_array_stream_create (surface->stream);
+ if (use_strings)
+ string_array_stream = _string_array_stream_create (surface->stream);
+ else
+ string_array_stream = _base85_array_stream_create (surface->stream);
+
status = _cairo_output_stream_get_status (string_array_stream);
if (status)
return _cairo_output_stream_destroy (string_array_stream);
base85_stream = _cairo_base85_stream_create (string_array_stream);
status = _cairo_output_stream_get_status (base85_stream);
if (status) {
status2 = _cairo_output_stream_destroy (string_array_stream);
@@ -2046,35 +1825,32 @@ static cairo_status_t
status = status2;
return status;
}
static cairo_status_t
_cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
cairo_image_surface_t *image,
- const char *name,
cairo_operator_t op)
{
cairo_status_t status;
- unsigned char *rgb, *rgb_compressed;
- unsigned long rgb_size, rgb_compressed_size;
- unsigned char *mask = NULL, *mask_compressed = NULL;
- unsigned long mask_size = 0, mask_compressed_size = 0;
+ unsigned char *data, *data_compressed;
+ unsigned long data_size, data_compressed_size;
cairo_image_surface_t *opaque_image = NULL;
int x, y, i;
cairo_image_transparency_t transparency;
cairo_bool_t use_mask;
+ uint32_t *pixel;
+ int bit;
if (image->base.status)
return image->base.status;
- status = _analyze_image_transparency (image, &transparency);
- if (status)
- return status;
+ transparency = _analyze_image_transparency (image);
/* PostScript can not represent the alpha channel, so we blend the
current image over a white (or black for CONTENT_COLOR
surfaces) RGB surface to eliminate it. */
if (op == CAIRO_OPERATOR_SOURCE ||
transparency == CAIRO_IMAGE_HAS_ALPHA ||
(transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA &&
@@ -2089,284 +1865,253 @@ static cairo_status_t
use_mask = FALSE;
} else if (transparency == CAIRO_IMAGE_IS_OPAQUE) {
opaque_image = image;
use_mask = FALSE;
} else {
use_mask = TRUE;
}
- rgb_size = 3 * image->width * image->height;
- rgb = _cairo_malloc_abc (image->width, image->height, 3);
- if (rgb == NULL) {
+ if (use_mask) {
+ /* Type 2 (mask and image interleaved) has the mask and image
+ * samples interleaved by row. The mask row is first, one bit
+ * per pixel with (bit 7 first). The row is padded to byte
+ * boundaries. The image data is 3 bytes per pixel RGB
+ * format. */
+ data_size = image->height * ((image->width + 7)/8 + 3*image->width);
+ } else {
+ data_size = image->height * image->width * 3;
+ }
+ data = malloc (data_size);
+ if (data == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto bail1;
}
if (use_mask) {
- mask_size = ((image->width+7) / 8) * image->height;
- mask = _cairo_malloc_ab ((image->width+7) / 8, image->height);
- if (mask == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto bail2;
- }
- }
-
- if (use_mask) {
- int byte = 0;
- int bit = 7;
i = 0;
for (y = 0; y < image->height; y++) {
- uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
+ /* mask row */
+ pixel = (uint32_t *) (image->data + y * image->stride);
+ bit = 7;
for (x = 0; x < image->width; x++, pixel++) {
if (bit == 7)
- mask[byte] = 0;
+ data[i] = 0;
if (((*pixel & 0xff000000) >> 24) > 0x80)
- mask[byte] |= (1 << bit);
+ data[i] |= (1 << bit);
bit--;
if (bit < 0) {
bit = 7;
- byte++;
+ i++;
}
- rgb[i++] = (*pixel & 0x00ff0000) >> 16;
- rgb[i++] = (*pixel & 0x0000ff00) >> 8;
- rgb[i++] = (*pixel & 0x000000ff) >> 0;
}
-
- if (bit != 7) {
- bit = 7;
- byte++;
+ if (bit != 7)
+ i++;
+
+ /* image row*/
+ pixel = (uint32_t *) (image->data + y * image->stride);
+ for (x = 0; x < image->width; x++, pixel++) {
+ data[i++] = (*pixel & 0x00ff0000) >> 16;
+ data[i++] = (*pixel & 0x0000ff00) >> 8;
+ data[i++] = (*pixel & 0x000000ff) >> 0;
}
}
} else {
i = 0;
for (y = 0; y < opaque_image->height; y++) {
- uint32_t *pixel = (uint32_t *) (opaque_image->data + y * opaque_image->stride);
+ pixel = (uint32_t *) (opaque_image->data + y * opaque_image->stride);
for (x = 0; x < opaque_image->width; x++, pixel++) {
- rgb[i++] = (*pixel & 0x00ff0000) >> 16;
- rgb[i++] = (*pixel & 0x0000ff00) >> 8;
- rgb[i++] = (*pixel & 0x000000ff) >> 0;
+ data[i++] = (*pixel & 0x00ff0000) >> 16;
+ data[i++] = (*pixel & 0x0000ff00) >> 8;
+ data[i++] = (*pixel & 0x000000ff) >> 0;
}
}
}
/* XXX: Should fix cairo-lzw to provide a stream-based interface
* instead. */
- rgb_compressed_size = rgb_size;
- rgb_compressed = _cairo_lzw_compress (rgb, &rgb_compressed_size);
- if (rgb_compressed == NULL) {
+ data_compressed_size = data_size;
+ data_compressed = _cairo_lzw_compress (data, &data_compressed_size);
+ if (data_compressed == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto bail3;
+ goto bail2;
}
- /* First emit the image data as a base85-encoded string which will
- * be used as the data source for the image operator later. */
- _cairo_output_stream_printf (surface->stream,
- "/%sData [\n", name);
-
- status = _cairo_ps_surface_emit_base85_string (surface,
- rgb_compressed,
- rgb_compressed_size);
- if (status)
- goto bail4;
-
- _cairo_output_stream_printf (surface->stream,
- "] def\n");
- _cairo_output_stream_printf (surface->stream,
- "/%sDataIndex 0 def\n", name);
-
- /* Emit the mask data as a base85-encoded string which will
- * be used as the mask source for the image operator later. */
- if (mask) {
- mask_compressed_size = mask_size;
- mask_compressed = _cairo_lzw_compress (mask, &mask_compressed_size);
- if (mask_compressed == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto bail4;
- }
-
+ if (surface->use_string_datasource) {
+ /* Emit the image data as a base85-encoded string which will
+ * be used as the data source for the image operator later. */
_cairo_output_stream_printf (surface->stream,
- "/%sMask [\n", name);
+ "/CairoImageData [\n");
status = _cairo_ps_surface_emit_base85_string (surface,
- mask_compressed,
- mask_compressed_size);
+ data_compressed,
+ data_compressed_size,
+ TRUE);
if (status)
- goto bail5;
+ goto bail3;
_cairo_output_stream_printf (surface->stream,
"] def\n");
_cairo_output_stream_printf (surface->stream,
- "/%sMaskIndex 0 def\n", name);
+ "/CairoImageDataIndex 0 def\n");
}
- if (mask) {
+ if (use_mask) {
_cairo_output_stream_printf (surface->stream,
- "/%s {\n"
- " /DeviceRGB setcolorspace\n"
- " <<\n"
- " /ImageType 3\n"
- " /InterleaveType 3\n"
- " /DataDict <<\n"
- " /ImageType 1\n"
- " /Width %d\n"
- " /Height %d\n"
- " /BitsPerComponent 8\n"
- " /Decode [ 0 1 0 1 0 1 ]\n"
- " /DataSource {\n"
- " %sData %sDataIndex get\n"
- " /%sDataIndex %sDataIndex 1 add def\n"
- " %sDataIndex %sData length 1 sub gt { /%sDataIndex 0 def } if\n"
- " } /ASCII85Decode filter /LZWDecode filter\n"
- " /ImageMatrix [ 1 0 0 1 0 0 ]\n"
- " >>\n"
- " /MaskDict <<\n"
- " /ImageType 1\n"
- " /Width %d\n"
- " /Height %d\n"
- " /BitsPerComponent 1\n"
- " /Decode [ 1 0 ]\n"
- " /DataSource {\n"
- " %sMask %sMaskIndex get\n"
- " /%sMaskIndex %sMaskIndex 1 add def\n"
- " %sMaskIndex %sMask length 1 sub gt { /%sMaskIndex 0 def } if\n"
- " } /ASCII85Decode filter /LZWDecode filter\n"
- " /ImageMatrix [ 1 0 0 1 0 0 ]\n"
- " >>\n"
- " >>\n"
- " image\n"
- "} def\n",
- name,
+ "/DeviceRGB setcolorspace\n"
+ "5 dict dup begin\n"
+ " /ImageType 3 def\n"
+ " /InterleaveType 2 def\n"
+ " /DataDict 8 dict def\n"
+ " DataDict begin\n"
+ " /ImageType 1 def\n"
+ " /Width %d def\n"
+ " /Height %d def\n"
+ " /BitsPerComponent 8 def\n"
+ " /Decode [ 0 1 0 1 0 1 ] def\n",
+ image->width,
+ image->height);
+
+ if (surface->use_string_datasource) {
+ _cairo_output_stream_printf (surface->stream,
+ " /DataSource {\n"
+ " CairoImageData CairoImageDataIndex get\n"
+ " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
+ " CairoImageDataIndex CairoImageData length 1 sub gt\n"
+ " { /CairoImageDataIndex 0 def } if\n"
+ " } /ASCII85Decode filter /LZWDecode filter def\n");
+ } else {
+ _cairo_output_stream_printf (surface->stream,
+ " /DataSource currentfile /ASCII85Decode filter /LZWDecode filter def\n");
+ }
+
+ _cairo_output_stream_printf (surface->stream,
+ " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
+ " end\n"
+ " /MaskDict 8 dict def\n"
+ " MaskDict begin\n"
+ " /ImageType 1 def\n"
+ " /Width %d def\n"
+ " /Height %d def\n"
+ " /BitsPerComponent 1 def\n"
+ " /Decode [ 1 0 ] def\n"
+ " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
+ " end\n"
+ "end\n"
+ "image\n",
+ image->height,
image->width,
image->height,
- name, name, name, name, name, name, name,
- image->width,
- image->height,
- name, name, name, name, name, name, name);
+ image->height);
} else {
_cairo_output_stream_printf (surface->stream,
- "/%s {\n"
- " /DeviceRGB setcolorspace\n"
- " <<\n"
- " /ImageType 1\n"
- " /Width %d\n"
- " /Height %d\n"
- " /BitsPerComponent 8\n"
- " /Decode [ 0 1 0 1 0 1 ]\n"
- " /DataSource {\n"
- " %sData %sDataIndex get\n"
- " /%sDataIndex %sDataIndex 1 add def\n"
- " %sDataIndex %sData length 1 sub gt { /%sDataIndex 0 def } if\n"
- " } /ASCII85Decode filter /LZWDecode filter\n"
- " /ImageMatrix [ 1 0 0 1 0 0 ]\n"
- " >>\n"
- " image\n"
- "} def\n",
- name,
+ "/DeviceRGB setcolorspace\n"
+ "8 dict dup begin\n"
+ " /ImageType 1 def\n"
+ " /Width %d def\n"
+ " /Height %d def\n"
+ " /BitsPerComponent 8 def\n"
+ " /Decode [ 0 1 0 1 0 1 ] def\n",
opaque_image->width,
- opaque_image->height,
- name, name, name, name, name, name, name);
+ opaque_image->height);
+ if (surface->use_string_datasource) {
+ _cairo_output_stream_printf (surface->stream,
+ " /DataSource {\n"
+ " CairoImageData CairoImageDataIndex get\n"
+ " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
+ " CairoImageDataIndex CairoImageData length 1 sub gt\n"
+ " { /CairoImageDataIndex 0 def } if\n"
+ " } /ASCII85Decode filter /LZWDecode filter def\n");
+ } else {
+ _cairo_output_stream_printf (surface->stream,
+ " /DataSource currentfile /ASCII85Decode filter /LZWDecode filter def\n");
+ }
+
+ _cairo_output_stream_printf (surface->stream,
+ " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
+ "end\n"
+ "image\n",
+ opaque_image->height);
}
- status = CAIRO_STATUS_SUCCESS;
-
-bail5:
- if (use_mask)
- free (mask_compressed);
-bail4:
- free (rgb_compressed);
+ if (!surface->use_string_datasource) {
+ /* Emit the image data as a base85-encoded string which will
+ * be used as the data source for the image operator. */
+ status = _cairo_ps_surface_emit_base85_string (surface,
+ data_compressed,
+ data_compressed_size,
+ FALSE);
+ } else {
+ status = CAIRO_STATUS_SUCCESS;
+ }
bail3:
- if (use_mask)
- free (mask);
+ free (data_compressed);
+
bail2:
- free (rgb);
+ free (data);
bail1:
if (!use_mask && opaque_image != image)
cairo_surface_destroy (&opaque_image->base);
return status;
}
static cairo_status_t
-_cairo_ps_surface_emit_image_surface (cairo_ps_surface_t *surface,
- cairo_surface_pattern_t *pattern,
- int *width,
- int *height,
- cairo_operator_t op)
-{
- cairo_image_surface_t *image;
- void *image_extra;
- cairo_status_t status;
-
- status = _cairo_surface_acquire_source_image (pattern->surface,
- &image,
- &image_extra);
- if (status)
- return status;
-
- status = _cairo_ps_surface_emit_image (surface, image, "CairoPattern", op);
- if (status)
- goto fail;
-
- *width = image->width;
- *height = image->height;
-
-fail:
- _cairo_surface_release_source_image (pattern->surface, image, image_extra);
-
- return status;
-}
-
-static cairo_status_t
_cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
cairo_surface_t *meta_surface)
{
double old_width, old_height;
+ cairo_matrix_t old_cairo_to_ps;
cairo_content_t old_content;
cairo_rectangle_int_t meta_extents;
cairo_status_t status;
status = _cairo_surface_get_extents (meta_surface, &meta_extents);
if (status)
return status;
old_content = surface->content;
old_width = surface->width;
old_height = surface->height;
+ old_cairo_to_ps = surface->cairo_to_ps;
surface->width = meta_extents.width;
surface->height = meta_extents.height;
+ cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
+ _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
+ &surface->cairo_to_ps);
_cairo_output_stream_printf (surface->stream,
- "/CairoPattern {\n"
" gsave\n"
" 0 0 %f %f rectclip\n",
surface->width,
surface->height);
if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
surface->content = CAIRO_CONTENT_COLOR;
_cairo_output_stream_printf (surface->stream,
- " 0 G 0 0 %f %f rectfill\n",
+ " 0 g 0 0 %f %f rectfill\n",
surface->width,
surface->height);
}
status = _cairo_meta_surface_replay_region (meta_surface, &surface->base,
CAIRO_META_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
if (status)
return status;
_cairo_output_stream_printf (surface->stream,
- " grestore\n"
- "} bind def\n");
+ " grestore\n");
surface->content = old_content;
surface->width = old_width;
surface->height = old_height;
+ surface->cairo_to_ps = old_cairo_to_ps;
+ _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
+ &surface->cairo_to_ps);
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_ps_surface_flatten_transparency (cairo_ps_surface_t *surface,
const cairo_color_t *color,
double *red,
@@ -2397,63 +2142,148 @@ static void
cairo_solid_pattern_t *pattern)
{
double red, green, blue;
_cairo_ps_surface_flatten_transparency (surface, &pattern->color, &red, &green, &blue);
if (color_is_gray (red, green, blue))
_cairo_output_stream_printf (surface->stream,
- "%f G\n",
+ "%f g\n",
red);
else
_cairo_output_stream_printf (surface->stream,
- "%f %f %f R\n",
+ "%f %f %f rg\n",
red, green, blue);
}
static cairo_status_t
+_cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
+ cairo_surface_pattern_t *pattern,
+ int *width,
+ int *height,
+ cairo_operator_t op)
+{
+ cairo_status_t status;
+
+ if (_cairo_surface_is_meta (pattern->surface)) {
+ cairo_surface_t *meta_surface = pattern->surface;
+ cairo_rectangle_int_t pattern_extents;
+
+ status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
+ *width = pattern_extents.width;
+ *height = pattern_extents.height;
+ } else {
+ status = _cairo_surface_acquire_source_image (pattern->surface,
+ &surface->image,
+ &surface->image_extra);
+ *width = surface->image->width;
+ *height = surface->image->height;
+ }
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
+ cairo_surface_pattern_t *pattern,
+ cairo_operator_t op)
+{
+ cairo_status_t status;
+
+ if (_cairo_surface_is_meta (pattern->surface)) {
+ cairo_surface_t *meta_surface = pattern->surface;
+
+ status = _cairo_ps_surface_emit_meta_surface (surface,
+ meta_surface);
+ } else {
+ status = _cairo_ps_surface_emit_image (surface, surface->image, op);
+ }
+
+ return status;
+}
+
+static void
+_cairo_ps_surface_release_surface (cairo_ps_surface_t *surface,
+ cairo_surface_pattern_t *pattern)
+{
+ if (!_cairo_surface_is_meta (pattern->surface))
+ _cairo_surface_release_source_image (pattern->surface, surface->image,
+ surface->image_extra);
+}
+
+static cairo_status_t
+_cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
+ cairo_surface_pattern_t *pattern,
+ cairo_operator_t op)
+{
+ cairo_status_t status;
+ int width, height;
+ cairo_matrix_t cairo_p2d, ps_p2d;
+
+ status = _cairo_ps_surface_acquire_surface (surface,
+ pattern,
+ &width,
+ &height,
+ op);
+ if (status)
+ return status;
+
+ cairo_p2d = pattern->base.matrix;
+ status = cairo_matrix_invert (&cairo_p2d);
+ /* cairo_pattern_set_matrix ensures the matrix is invertible */
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ ps_p2d = surface->cairo_to_ps;
+ cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
+ cairo_matrix_translate (&ps_p2d, 0.0, height);
+ cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+
+ _cairo_output_stream_printf (surface->stream,
+ "[ %f %f %f %f %f %f ] concat\n",
+ ps_p2d.xx, ps_p2d.yx,
+ ps_p2d.xy, ps_p2d.yy,
+ ps_p2d.x0, ps_p2d.y0);
+
+ status = _cairo_ps_surface_emit_surface (surface, pattern, op);
+ _cairo_ps_surface_release_surface (surface, pattern);
+
+ return status;
+}
+
+static cairo_status_t
_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
cairo_surface_pattern_t *pattern,
cairo_operator_t op)
{
cairo_status_t status;
int pattern_width = 0; /* squelch bogus compiler warning */
int pattern_height = 0; /* squelch bogus compiler warning */
double xstep, ystep;
- cairo_matrix_t inverse = pattern->base.matrix;
-
- status = cairo_matrix_invert (&inverse);
+ cairo_matrix_t cairo_p2d, ps_p2d;
+ cairo_rectangle_int16_t surface_extents;
+ cairo_bool_t old_use_string_datasource;
+
+ cairo_p2d = pattern->base.matrix;
+ status = cairo_matrix_invert (&cairo_p2d);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
- if (_cairo_surface_is_meta (pattern->surface)) {
- cairo_surface_t *meta_surface = pattern->surface;
- cairo_rectangle_int_t pattern_extents;
-
- status = _cairo_ps_surface_emit_meta_surface (surface,
- meta_surface);
- if (status)
- return status;
-
- status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
- if (status)
- return status;
-
- pattern_width = pattern_extents.width;
- pattern_height = pattern_extents.height;
- } else {
- status = _cairo_ps_surface_emit_image_surface (surface,
- pattern,
- &pattern_width,
- &pattern_height,
- op);
- if (status)
- return status;
- }
+ ps_p2d = surface->cairo_to_ps;
+ cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
+ cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
+ cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+
+ status = _cairo_ps_surface_acquire_surface (surface,
+ pattern,
+ &pattern_width,
+ &pattern_height,
+ op);
+ if (status)
+ return status;
switch (pattern->base.extend) {
/* We implement EXTEND_PAD like EXTEND_NONE for now */
case CAIRO_EXTEND_PAD:
case CAIRO_EXTEND_NONE:
{
/* In PS/PDF, (as far as I can tell), all patterns are
* repeating. So we support cairo's EXTEND_NONE semantics
@@ -2493,16 +2323,29 @@ static cairo_status_t
* cases should be unreachable. */
default:
ASSERT_NOT_REACHED;
xstep = 0;
ystep = 0;
}
_cairo_output_stream_printf (surface->stream,
+ "/CairoPattern {\n");
+
+ old_use_string_datasource = surface->use_string_datasource;
+ surface->use_string_datasource = TRUE;
+ status = _cairo_ps_surface_emit_surface (surface, pattern, op);
+ if (status)
+ return status;
+
+ surface->use_string_datasource = old_use_string_datasource;
+ _cairo_output_stream_printf (surface->stream,
+ "} bind def\n");
+
+ _cairo_output_stream_printf (surface->stream,
"<< /PatternType 1\n"
" /PaintType 1\n"
" /TilingType 1\n");
_cairo_output_stream_printf (surface->stream,
" /XStep %f /YStep %f\n",
xstep, ystep);
if (pattern->base.extend == CAIRO_EXTEND_REFLECT) {
@@ -2517,28 +2360,44 @@ static cairo_status_t
" } bind\n",
pattern_width*2, pattern_height*2,
pattern_width*2,
pattern_height*2,
pattern_width*2);
} else {
_cairo_output_stream_printf (surface->stream,
" /BBox [0 0 %d %d]\n"
- " /PaintProc { CairoPattern } bind\n",
+ " /PaintProc { CairoPattern }\n",
pattern_width, pattern_height);
}
_cairo_output_stream_printf (surface->stream,
">>\n");
+ status = _cairo_surface_get_extents (&surface->base, &surface_extents);
+ if (status)
+ return status;
+
+ cairo_p2d = pattern->base.matrix;
+ status = cairo_matrix_invert (&cairo_p2d);
+ /* cairo_pattern_set_matrix ensures the matrix is invertible */
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ cairo_matrix_init_identity (&ps_p2d);
+ cairo_matrix_translate (&ps_p2d, 0.0, surface_extents.height);
+ cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+ cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
+ cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
+ cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+
_cairo_output_stream_printf (surface->stream,
"[ %f %f %f %f %f %f ]\n",
- inverse.xx, inverse.yx,
- inverse.xy, inverse.yy,
- inverse.x0, inverse.y0);
+ ps_p2d.xx, ps_p2d.yx,
+ ps_p2d.xy, ps_p2d.yy,
+ ps_p2d.x0, ps_p2d.y0);
_cairo_output_stream_printf (surface->stream,
"makepattern setpattern\n");
return CAIRO_STATUS_SUCCESS;
}
typedef struct _cairo_ps_color_stop {
double offset;
@@ -2740,16 +2599,17 @@ static cairo_status_t
extend = cairo_pattern_get_extend (&pattern->base.base);
pat_to_ps = pattern->base.base.matrix;
status = cairo_matrix_invert (&pat_to_ps);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
+ cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
first_stop = _cairo_fixed_to_double (gradient->stops[0].x);
last_stop = _cairo_fixed_to_double (gradient->stops[gradient->n_stops - 1].x);
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;
@@ -2852,65 +2712,68 @@ static cairo_status_t
return status;
}
static cairo_status_t
_cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface,
cairo_radial_pattern_t *pattern)
{
double x1, y1, x2, y2, r1, r2;
+ cairo_matrix_t pat_to_ps;
cairo_extend_t extend;
cairo_status_t status;
- cairo_matrix_t inverse = pattern->base.base.matrix;
if (pattern->base.n_stops == 0)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
extend = cairo_pattern_get_extend (&pattern->base.base);
- status = cairo_matrix_invert (&inverse);
- if (status)
- return status;
-
+ pat_to_ps = pattern->base.base.matrix;
+ status = cairo_matrix_invert (&pat_to_ps);
+ /* cairo_pattern_set_matrix ensures the matrix is invertible */
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
x1 = _cairo_fixed_to_double (pattern->c1.x);
y1 = _cairo_fixed_to_double (pattern->c1.y);
r1 = _cairo_fixed_to_double (pattern->r1);
x2 = _cairo_fixed_to_double (pattern->c2.x);
y2 = _cairo_fixed_to_double (pattern->c2.y);
r2 = _cairo_fixed_to_double (pattern->r2);
- _cairo_output_stream_printf (surface->stream,
+ status = _cairo_ps_surface_emit_pattern_stops (surface, &pattern->base);
+ if (status)
+ return status;
+
+ _cairo_output_stream_printf (surface->stream,
"<< /PatternType 2\n"
" /Shading\n"
" << /ShadingType 3\n"
" /ColorSpace /DeviceRGB\n"
" /Coords [ %f %f %f %f %f %f ]\n"
- " /Function\n",
+ " /Function CairoFunction\n",
x1, y1, r1, x2, y2, r2);
- status = _cairo_ps_surface_emit_pattern_stops (surface, &pattern->base);
- if (status)
- return status;
-
if (extend == CAIRO_EXTEND_PAD) {
_cairo_output_stream_printf (surface->stream,
" /Extend [ true true ]\r\n");
} else {
_cairo_output_stream_printf (surface->stream,
" /Extend [ false false ]\r\n");
}
_cairo_output_stream_printf (surface->stream,
" >>\n"
">>\n");
+
_cairo_output_stream_printf (surface->stream,
"[ %f %f %f %f %f %f ]\n",
- inverse.xx, inverse.yx,
- inverse.xy, inverse.yy,
- inverse.x0, inverse.y0);
+ pat_to_ps.xx, pat_to_ps.yx,
+ pat_to_ps.xy, pat_to_ps.yy,
+ pat_to_ps.x0, pat_to_ps.y0);
_cairo_output_stream_printf (surface->stream,
"makepattern setpattern\n");
return status;
}
static cairo_status_t
_cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
@@ -2957,52 +2820,33 @@ static cairo_int_status_t
_cairo_ps_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_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
- cairo_status_t status;
- const char *ps_operator;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
#if DEBUG_PS
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_intersect_clip_path\n");
#endif
if (path == NULL) {
- _cairo_output_stream_printf (stream, "grestore gsave\n");
+ _cairo_output_stream_printf (stream, "Q q\n");
return CAIRO_STATUS_SUCCESS;
}
- /* We're "filling" not stroking, so we pass CAIRO_LINE_CAP_ROUND. */
- status = _cairo_ps_surface_emit_path (surface, stream, path,
- CAIRO_LINE_CAP_ROUND);
-
- switch (fill_rule) {
- case CAIRO_FILL_RULE_WINDING:
- ps_operator = "clip";
- break;
- case CAIRO_FILL_RULE_EVEN_ODD:
- ps_operator = "eoclip";
- break;
- default:
- ASSERT_NOT_REACHED;
- }
-
- _cairo_output_stream_printf (stream,
- "%s newpath\n",
- ps_operator);
-
- return status;
+ return _cairo_pdf_operators_clip (&surface->pdf_operators,
+ path,
+ fill_rule);
}
static cairo_int_status_t
_cairo_ps_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_ps_surface_t *surface = abstract_surface;
@@ -3032,457 +2876,199 @@ static void
static cairo_int_status_t
_cairo_ps_surface_paint (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
- cairo_rectangle_int_t extents, pattern_extents;
+ cairo_rectangle_int_t extents, surface_extents;
cairo_status_t status;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_ps_surface_analyze_operation (surface, op, source);
assert (_cairo_ps_surface_operation_supported (surface, op, source));
#if DEBUG_PS
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_paint\n");
#endif
- status = _cairo_surface_get_extents (&surface->base, &extents);
+ status = _cairo_surface_get_extents (&surface->base, &surface_extents);
if (status)
return status;
- status = _cairo_pattern_get_extents (source, &pattern_extents);
+ status = _cairo_pattern_get_extents (source, &extents);
if (status)
return status;
- _cairo_rectangle_intersect (&extents, &pattern_extents);
-
- status = _cairo_ps_surface_emit_pattern (surface, source, op);
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- return CAIRO_STATUS_SUCCESS;
-
- if (status)
- return status;
-
- _cairo_output_stream_printf (stream, "%d %d M\n",
- extents.x, extents.y);
- _cairo_output_stream_printf (stream, "%d %d L\n",
- extents.x + extents.width,
- extents.y);
- _cairo_output_stream_printf (stream, "%d %d L\n",
- extents.x + extents.width,
- extents.y + extents.height);
- _cairo_output_stream_printf (stream, "%d %d L\n",
- extents.x,
- extents.y + extents.height);
- _cairo_output_stream_printf (stream, "P F\n");
+ _cairo_rectangle_intersect (&extents, &surface_extents);
+
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
+ source->extend == CAIRO_EXTEND_NONE)
+ {
+ _cairo_output_stream_printf (stream, "q %d %d %d %d rectclip\n",
+ extents.x,
+ surface_extents.height - extents.y - extents.height,
+ extents.width,
+ extents.height);
+
+ status = _cairo_ps_surface_paint_surface (surface,
+ (cairo_surface_pattern_t *) source,
+ op);
+ if (status)
+ return status;
+
+ _cairo_output_stream_printf (stream, "Q\n");
+ } else {
+ status = _cairo_ps_surface_emit_pattern (surface, source, op);
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (status)
+ return status;
+
+ _cairo_output_stream_printf (stream, "%d %d %d %d rectfill\n",
+ extents.x,
+ surface_extents.height - extents.y - extents.height,
+ extents.width,
+ extents.height);
+ }
return CAIRO_STATUS_SUCCESS;
}
-static int
-_cairo_ps_line_cap (cairo_line_cap_t cap)
-{
- switch (cap) {
- case CAIRO_LINE_CAP_BUTT:
- return 0;
- case CAIRO_LINE_CAP_ROUND:
- return 1;
- case CAIRO_LINE_CAP_SQUARE:
- return 2;
- default:
- ASSERT_NOT_REACHED;
- return 0;
- }
-}
-
-static int
-_cairo_ps_line_join (cairo_line_join_t join)
-{
- switch (join) {
- case CAIRO_LINE_JOIN_MITER:
- return 0;
- case CAIRO_LINE_JOIN_ROUND:
- return 1;
- case CAIRO_LINE_JOIN_BEVEL:
- return 2;
- default:
- ASSERT_NOT_REACHED;
- return 0;
- }
-}
-
static cairo_int_status_t
_cairo_ps_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)
{
cairo_ps_surface_t *surface = abstract_surface;
- cairo_output_stream_t *stream = surface->stream;
cairo_int_status_t status;
- double *dash = style->dash;
- int num_dashes = style->num_dashes;
- double dash_offset = style->dash_offset;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_ps_surface_analyze_operation (surface, op, source);
assert (_cairo_ps_surface_operation_supported (surface, op, source));
#if DEBUG_PS
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_stroke\n");
#endif
- /* PostScript has "special needs" when it comes to zero-length
- * dash segments with butt caps. It apparently (at least
- * according to ghostscript) draws hairlines for this
- * case. That's not what the cairo semantics want, so we first
- * touch up the array to eliminate any 0.0 values that will
- * result in "on" segments.
- */
- if (num_dashes && style->line_cap == CAIRO_LINE_CAP_BUTT) {
- int i;
-
- /* If there's an odd number of dash values they will each get
- * interpreted as both on and off. So we first explicitly
- * expand the array to remove the duplicate usage so that we
- * can modify some of the values.
- */
- if (num_dashes % 2) {
- dash = _cairo_malloc_abc (num_dashes, 2, sizeof (double));
- if (dash == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- memcpy (dash, style->dash, num_dashes * sizeof (double));
- memcpy (dash + num_dashes, style->dash, num_dashes * sizeof (double));
-
- num_dashes *= 2;
- }
-
- for (i = 0; i < num_dashes; i += 2) {
- if (dash[i] == 0.0) {
- /* If we're at the front of the list, we first rotate
- * two elements from the end of the list to the front
- * of the list before folding away the 0.0. Or, if
- * there are only two dash elements, then there is
- * nothing at all to draw.
- */
- if (i == 0) {
- double last_two[2];
-
- if (num_dashes == 2) {
- if (dash != style->dash)
- free (dash);
- return CAIRO_STATUS_SUCCESS;
- }
- /* The cases of num_dashes == 0, 1, or 3 elements
- * cannot exist, so the rotation of 2 elements
- * will always be safe */
- memcpy (last_two, dash + num_dashes - 2, sizeof (last_two));
- memmove (dash + 2, dash, (num_dashes - 2) * sizeof (double));
- memcpy (dash, last_two, sizeof (last_two));
- dash_offset += dash[0] + dash[1];
- i = 2;
- }
- dash[i-1] += dash[i+1];
- num_dashes -= 2;
- memmove (dash + i, dash + i + 2, (num_dashes - i) * sizeof (double));
- /* If we might have just rotated, it's possible that
- * we rotated a 0.0 value to the front of the list.
- * Set i to -2 so it will get incremented to 0. */
- if (i == 2)
- i = -2;
- }
- }
- }
-
status = _cairo_ps_surface_emit_pattern (surface, source, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
- if (status) {
- if (dash != style->dash)
- free (dash);
- return status;
- }
-
- _cairo_output_stream_printf (stream,
- "gsave\n");
- status = _cairo_ps_surface_emit_path (surface, stream, path,
- style->line_cap);
- if (status) {
- if (dash != style->dash)
- free (dash);
- return status;
- }
-
- /*
- * Switch to user space to set line parameters
- */
- _cairo_output_stream_printf (stream,
- "[%f %f %f %f 0 0] concat\n",
- ctm->xx, ctm->yx, ctm->xy, ctm->yy);
- /* line width */
- _cairo_output_stream_printf (stream, "%f setlinewidth\n",
- style->line_width);
- /* line cap */
- _cairo_output_stream_printf (stream, "%d setlinecap\n",
- _cairo_ps_line_cap (style->line_cap));
- /* line join */
- _cairo_output_stream_printf (stream, "%d setlinejoin\n",
- _cairo_ps_line_join (style->line_join));
- /* dashes */
- if (num_dashes) {
- int d;
-
- _cairo_output_stream_printf (stream, "[");
- for (d = 0; d < num_dashes; d++)
- _cairo_output_stream_printf (stream, " %f", dash[d]);
- _cairo_output_stream_printf (stream, "] %f setdash\n",
- dash_offset);
- }
- if (dash != style->dash)
- free (dash);
-
- /* miter limit */
- _cairo_output_stream_printf (stream, "%f setmiterlimit\n",
- style->miter_limit < 1.0 ? 1.0 : style->miter_limit);
- _cairo_output_stream_printf (stream,
- "stroke\n");
- _cairo_output_stream_printf (stream,
- "grestore\n");
-
- return CAIRO_STATUS_SUCCESS;
+ return _cairo_pdf_operators_stroke (&surface->pdf_operators,
+ path,
+ style,
+ ctm,
+ ctm_inverse);
}
static cairo_int_status_t
_cairo_ps_surface_fill (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_ps_surface_t *surface = abstract_surface;
- cairo_output_stream_t *stream = surface->stream;
cairo_int_status_t status;
- const char *ps_operator;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_ps_surface_analyze_operation (surface, op, source);
assert (_cairo_ps_surface_operation_supported (surface, op, source));
#if DEBUG_PS
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_fill\n");
#endif
- status = _cairo_ps_surface_emit_pattern (surface, source, op);
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- return CAIRO_STATUS_SUCCESS;
-
- if (status)
- return status;
-
- /* We're filling not stroking, so we pass CAIRO_LINE_CAP_ROUND. */
- status = _cairo_ps_surface_emit_path (surface, stream, path,
- CAIRO_LINE_CAP_ROUND);
- if (status)
- return status;
-
- switch (fill_rule) {
- case CAIRO_FILL_RULE_WINDING:
- ps_operator = "F";
- break;
- case CAIRO_FILL_RULE_EVEN_ODD:
- ps_operator = "eofill";
- break;
- default:
- ASSERT_NOT_REACHED;
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
+ source->extend == CAIRO_EXTEND_NONE)
+ {
+ _cairo_output_stream_printf (surface->stream, "q\n");
+
+ status = _cairo_pdf_operators_clip (&surface->pdf_operators,
+ path,
+ fill_rule);
+ if (status)
+ return status;
+
+ status = _cairo_ps_surface_paint_surface (surface,
+ (cairo_surface_pattern_t *) source,
+ op);
+ if (status)
+ return status;
+
+ _cairo_output_stream_printf (surface->stream, "Q\n");
+ } else {
+ status = _cairo_ps_surface_emit_pattern (surface, source, op);
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (status)
+ return status;
+
+ status = _cairo_pdf_operators_fill (&surface->pdf_operators,
+ path,
+ fill_rule);
}
- _cairo_output_stream_printf (stream,
- "%s\n", ps_operator);
-
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
-/* This size keeps the length of the hex encoded string of glyphs
- * within 80 columns. */
-#define MAX_GLYPHS_PER_SHOW 36
-
-typedef struct _cairo_ps_glyph_id {
- unsigned int subset_id;
- unsigned int glyph_id;
-} cairo_ps_glyph_id_t;
-
static cairo_int_status_t
_cairo_ps_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
{
cairo_ps_surface_t *surface = abstract_surface;
- cairo_output_stream_t *stream = surface->stream;
- unsigned int current_subset_id = -1;
- cairo_scaled_font_subsets_glyph_t subset_glyph;
- cairo_ps_glyph_id_t *glyph_ids;
cairo_status_t status;
- unsigned int num_glyphs_unsigned, i, j, last, end;
- cairo_bool_t vertical, horizontal;
- cairo_output_stream_t *word_wrap;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_ps_surface_analyze_operation (surface, op, source);
assert (_cairo_ps_surface_operation_supported (surface, op, source));
#if DEBUG_PS
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_show_glyphs\n");
#endif
if (num_glyphs <= 0)
return CAIRO_STATUS_SUCCESS;
- num_glyphs_unsigned = num_glyphs;
-
status = _cairo_ps_surface_emit_pattern (surface, source, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
if (status)
return status;
- glyph_ids = _cairo_malloc_ab (num_glyphs_unsigned, sizeof (cairo_ps_glyph_id_t));
- if (glyph_ids == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- for (i = 0; i < num_glyphs_unsigned; i++) {
- status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
- scaled_font, glyphs[i].index,
- &subset_glyph);
- if (status)
- goto fail;
-
- glyph_ids[i].subset_id = subset_glyph.subset_id;
- glyph_ids[i].glyph_id = subset_glyph.subset_glyph_index;
- }
-
- i = 0;
- while (i < num_glyphs_unsigned) {
- if (glyph_ids[i].subset_id != current_subset_id) {
- _cairo_output_stream_printf (surface->stream,
- "/CairoFont-%d-%d "
- "[ %f %f %f %f 0 0 ] selectfont\n",
- subset_glyph.font_id,
- glyph_ids[i].subset_id,
- scaled_font->scale.xx,
- scaled_font->scale.yx,
- -scaled_font->scale.xy,
- -scaled_font->scale.yy);
- current_subset_id = glyph_ids[i].subset_id;
- }
-
- if (i == 0)
- _cairo_output_stream_printf (stream,
- "%f %f M\n",
- glyphs[i].x,
- glyphs[i].y);
-
- horizontal = TRUE;
- vertical = TRUE;
- end = num_glyphs_unsigned;
- if (end - i > MAX_GLYPHS_PER_SHOW)
- end = i + MAX_GLYPHS_PER_SHOW;
- last = end - 1;
- for (j = i; j < end - 1; j++) {
- if ((glyphs[j].y != glyphs[j + 1].y))
- horizontal = FALSE;
- if ((glyphs[j].x != glyphs[j + 1].x))
- vertical = FALSE;
- if (glyph_ids[j].subset_id != glyph_ids[j + 1].subset_id) {
- last = j;
- break;
- }
- }
-
- if (i == last) {
- _cairo_output_stream_printf (surface->stream, "<%02x> S\n", glyph_ids[i].glyph_id);
- } else {
- word_wrap = _word_wrap_stream_create (surface->stream, 79);
- if (_cairo_output_stream_get_status (word_wrap)) {
- status = _cairo_output_stream_destroy (word_wrap);
- goto fail;
- }
-
- _cairo_output_stream_printf (word_wrap, "<");
- for (j = i; j < last+1; j++)
- _cairo_output_stream_printf (word_wrap, "%02x", glyph_ids[j].glyph_id);
- _cairo_output_stream_printf (word_wrap, ">\n[");
-
- if (horizontal) {
- for (j = i; j < last+1; j++) {
- if (j == num_glyphs_unsigned - 1)
- _cairo_output_stream_printf (word_wrap, "0 ");
- else
- _cairo_output_stream_printf (word_wrap,
- "%f ", glyphs[j + 1].x - glyphs[j].x);
- }
- _cairo_output_stream_printf (word_wrap, "] xS\n");
- } else if (vertical) {
- for (j = i; j < last+1; j++) {
- if (j == num_glyphs_unsigned - 1)
- _cairo_output_stream_printf (word_wrap, "0 ");
- else
- _cairo_output_stream_printf (word_wrap,
- "%f ", glyphs[j + 1].y - glyphs[j].y);
- }
- _cairo_output_stream_printf (word_wrap, "] yS\n");
- } else {
- for (j = i; j < last+1; j++) {
- if (j == num_glyphs_unsigned - 1)
- _cairo_output_stream_printf (word_wrap, "0 0 ");
- else
- _cairo_output_stream_printf (word_wrap,
- "%f %f ",
- glyphs[j + 1].x - glyphs[j].x,
- glyphs[j + 1].y - glyphs[j].y);
- }
- _cairo_output_stream_printf (word_wrap, "] xyS\n");
- }
-
- status = _cairo_output_stream_destroy (word_wrap);
- if (status)
- goto fail;
- }
- i = last + 1;
- }
-
- status = _cairo_output_stream_get_status (surface->stream);
-fail:
- free (glyph_ids);
-
- return status;
+ return _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
+ glyphs,
+ num_glyphs,
+ scaled_font);
}
static void
_cairo_ps_surface_set_paginated_mode (void *abstract_surface,
cairo_paginated_mode_t paginated_mode)
{
cairo_ps_surface_t *surface = abstract_surface;
@@ -3524,23 +3110,22 @@ static cairo_int_status_t
_cairo_output_stream_printf (surface->stream,
"%s\n", comments[i]);
free (comments[i]);
comments[i] = NULL;
}
_cairo_array_truncate (&surface->dsc_page_setup_comments, 0);
_cairo_output_stream_printf (surface->stream,
- "%%%%PageBoundingBox: %d %d %d %d\n"
- "gsave %f %f translate 1.0 -1.0 scale gsave\n",
- x1, y1, x2, y2,
- 0.0, surface->height);
+ "%%%%PageBoundingBox: %d %d %d %d\n",
+ x1, y1, x2, y2);
_cairo_output_stream_printf (surface->stream,
- "%%%%EndPageSetup\n");
+ "%%%%EndPageSetup\n"
+ "gsave\n");
if (surface->num_pages == 1) {
surface->bbox_x1 = x1;
surface->bbox_y1 = y1;
surface->bbox_x2 = x2;
surface->bbox_y2 = y2;
} else {
if (x1 < surface->bbox_x1)
--- a/gfx/cairo/cairo/src/cairo-scaled-font.c
+++ b/gfx/cairo/cairo/src/cairo-scaled-font.c
@@ -173,17 +173,17 @@ static void
_cairo_scaled_glyph_destroy (void *abstract_glyph)
{
cairo_scaled_glyph_t *scaled_glyph = abstract_glyph;
_cairo_scaled_glyph_fini (scaled_glyph);
free (scaled_glyph);
}
#define ZOMBIE 0
-const cairo_scaled_font_t _cairo_scaled_font_nil = {
+static const cairo_scaled_font_t _cairo_scaled_font_nil = {
{ ZOMBIE }, /* hash_entry */
CAIRO_STATUS_NO_MEMORY, /* status */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */
NULL, /* font_face */
{ 1., 0., 0., 1., 0, 0}, /* font_matrix */
{ 1., 0., 0., 1., 0, 0}, /* ctm */
{ CAIRO_ANTIALIAS_DEFAULT, /* options */
@@ -461,21 +461,19 @@ cairo_status_t
cairo_font_face_t *font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
const cairo_scaled_font_backend_t *backend)
{
cairo_status_t status;
- if (options != NULL) {
- status = cairo_font_options_status ((cairo_font_options_t *) options);
- if (status)
- return status;
- }
+ status = cairo_font_options_status ((cairo_font_options_t *) options);
+ if (status)
+ return status;
_cairo_scaled_font_init_key (scaled_font, font_face,
font_matrix, ctm, options);
cairo_matrix_multiply (&scaled_font->scale,
&scaled_font->font_matrix,
&scaled_font->ctm);
@@ -618,30 +616,28 @@ cairo_scaled_font_create (cairo_font_fac
const cairo_matrix_t *ctm,
const cairo_font_options_t *options)
{
cairo_status_t status;
cairo_scaled_font_map_t *font_map;
cairo_scaled_font_t key, *scaled_font = NULL;
if (font_face->status)
- return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
+ return _cairo_scaled_font_create_in_error (font_face->status);
- if (options != NULL &&
- cairo_font_options_status ((cairo_font_options_t *) options))
- {
- return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
- }
+ status = cairo_font_options_status ((cairo_font_options_t *) options);
+ if (status)
+ return _cairo_scaled_font_create_in_error (status);
/* Note that degenerate ctm or font_matrix *are* allowed.
* We want to support a font size of 0. */
font_map = _cairo_scaled_font_map_lock ();
if (font_map == NULL)
- return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
+ return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_scaled_font_init_key (&key, font_face,
font_matrix, ctm, options);
/* Return existing scaled_font if it exists in the hash table. */
if (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry,
(cairo_hash_entry_t**) &scaled_font))
{
@@ -682,36 +678,86 @@ cairo_scaled_font_create (cairo_font_fac
}
/* Otherwise create it and insert it into the hash table. */
status = font_face->backend->scaled_font_create (font_face, font_matrix,
ctm, options, &scaled_font);
if (status) {
_cairo_scaled_font_map_unlock ();
status = _cairo_font_face_set_error (font_face, status);
- return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
+ return _cairo_scaled_font_create_in_error (status);
}
status = _cairo_hash_table_insert (font_map->hash_table,
&scaled_font->hash_entry);
_cairo_scaled_font_map_unlock ();
if (status) {
/* We can't call _cairo_scaled_font_destroy here since it expects
* that the font has already been successfully inserted into the
* hash table. */
_cairo_scaled_font_fini (scaled_font);
free (scaled_font);
- return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
+ return _cairo_scaled_font_create_in_error (status);
}
return scaled_font;
}
slim_hidden_def (cairo_scaled_font_create);
+static cairo_scaled_font_t *_cairo_scaled_font_nil_objects[CAIRO_STATUS_LAST_STATUS + 1];
+
+/* XXX This should disappear in favour of a common pool of error objects. */
+cairo_scaled_font_t *
+_cairo_scaled_font_create_in_error (cairo_status_t status)
+{
+ cairo_scaled_font_t *scaled_font;
+
+ assert (status != CAIRO_STATUS_SUCCESS);
+
+ if (status == CAIRO_STATUS_NO_MEMORY)
+ return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
+
+ CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
+ scaled_font = _cairo_scaled_font_nil_objects[status];
+ if (scaled_font == NULL) {
+ scaled_font = malloc (sizeof (cairo_scaled_font_t));
+ if (scaled_font == NULL) {
+ CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
+ _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+ return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
+ }
+
+ *scaled_font = _cairo_scaled_font_nil;
+ scaled_font->status = status;
+ _cairo_scaled_font_nil_objects[status] = scaled_font;
+ }
+ CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
+
+ return scaled_font;
+}
+
+void
+_cairo_scaled_font_reset_static_data (void)
+{
+ int status;
+
+ CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
+ for (status = CAIRO_STATUS_SUCCESS;
+ status <= CAIRO_STATUS_LAST_STATUS;
+ status++)
+ {
+ if (_cairo_scaled_font_nil_objects[status] != NULL) {
+ free (_cairo_scaled_font_nil_objects[status]);
+ _cairo_scaled_font_nil_objects[status] = NULL;
+ }
+ }
+ CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
+}
+
/**
* cairo_scaled_font_reference:
* @scaled_font: a #cairo_scaled_font_t, (may be %NULL in which case
* this function does nothing)
*
* Increases the reference count on @scaled_font by one. This prevents
* @scaled_font from being destroyed until a matching call to
* cairo_scaled_font_destroy() is made.
--- a/gfx/cairo/cairo/src/cairo-surface.c
+++ b/gfx/cairo/cairo/src/cairo-surface.c
@@ -1657,63 +1657,69 @@ cairo_status_t
* be retained for the next page. Use cairo_surface_show_page() if you
* want to get an empty page after the emission.
*
* Since: 1.6
*/
void
cairo_surface_copy_page (cairo_surface_t *surface)
{
+ cairo_status_t status_ignored;
+
assert (! surface->is_snapshot);
if (surface->status)
return;
if (surface->finished) {
- _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
+ status_ignored = _cairo_surface_set_error (surface,
+ CAIRO_STATUS_SURFACE_FINISHED);
return;
}
/* It's fine if some backends don't implement copy_page */
if (surface->backend->copy_page == NULL)
return;
- _cairo_surface_set_error (surface,
- surface->backend->copy_page (surface));
+ status_ignored = _cairo_surface_set_error (surface,
+ surface->backend->copy_page (surface));
}
slim_hidden_def (cairo_surface_copy_page);
/**
* cairo_surface_show_page:
* @surface: a #cairo_Surface_t
*
* Emits and clears the current page for backends that support multiple
* pages. Use cairo_surface_copy_page() if you don't want to clear the page.
*
* Since: 1.6
**/
void
cairo_surface_show_page (cairo_surface_t *surface)
{
+ cairo_status_t status_ignored;
+
assert (! surface->is_snapshot);
if (surface->status)
return;
if (surface->finished) {
- _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
+ status_ignored = _cairo_surface_set_error (surface,
+ CAIRO_STATUS_SURFACE_FINISHED);
return;
}
/* It's fine if some backends don't implement show_page */
if (surface->backend->show_page == NULL)
return;
- _cairo_surface_set_error (surface,
- surface->backend->show_page (surface));
+ status_ignored = _cairo_surface_set_error (surface,
+ surface->backend->show_page (surface));
}
slim_hidden_def (cairo_surface_show_page);
/**
* _cairo_surface_get_current_clip_serial:
* @surface: the #cairo_surface_t to return the serial number for
*
* Returns: the serial number associated with the current
--- a/gfx/cairo/cairo/src/cairo-win32-font.c
+++ b/gfx/cairo/cairo/src/cairo-win32-font.c
@@ -272,17 +272,17 @@ static cairo_status_t
/* We don't have any control over the hinting style or subpixel
* order in the Win32 font API, so we ignore those parts of
* cairo_font_options_t. We use the 'antialias' field to set
* the 'quality'.
*
* XXX: The other option we could pay attention to, but don't
* here is the hint_metrics options.
*/
- if (options == NULL || options->antialias == CAIRO_ANTIALIAS_DEFAULT)
+ if (options->antialias == CAIRO_ANTIALIAS_DEFAULT)
f->quality = _get_system_quality ();
else {
switch (options->antialias) {
case CAIRO_ANTIALIAS_NONE:
f->quality = NONANTIALIASED_QUALITY;
break;
case CAIRO_ANTIALIAS_GRAY:
f->quality = ANTIALIASED_QUALITY;
@@ -299,17 +299,17 @@ static cairo_status_t
}
f->em_square = 0;
f->scaled_hfont = NULL;
f->unscaled_hfont = NULL;
if (f->quality == logfont->lfQuality ||
(logfont->lfQuality == DEFAULT_QUALITY &&
- (options == NULL || options->antialias == CAIRO_ANTIALIAS_DEFAULT))) {
+ options->antialias == CAIRO_ANTIALIAS_DEFAULT)) {
/* If face_hfont is non-NULL, then we can use it to avoid creating our
* own --- because the constraints on face_hfont mentioned above
* guarantee it was created in exactly the same way that
* _win32_scaled_font_get_scaled_hfont would create it.
*/
f->scaled_hfont = face_hfont;
}
/* don't delete the hfont if we're using the one passed in to us */
--- a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c
+++ b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c
@@ -196,43 +196,46 @@ pattern_supported (cairo_win32_surface_t
static cairo_int_status_t
_cairo_win32_printing_surface_analyze_operation (cairo_win32_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *pattern)
{
if (! pattern_supported (surface, pattern))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (!(op == CAIRO_OPERATOR_SOURCE ||
+ op == CAIRO_OPERATOR_OVER ||
+ op == CAIRO_OPERATOR_CLEAR))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
+
+ if ( _cairo_surface_is_meta (surface_pattern->surface))
+ return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
+ }
+
if (op == CAIRO_OPERATOR_SOURCE ||
op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
- /* If the operation is anything other than CLEAR, SOURCE, or
- * OVER, we have to go to fallback.
- */
- if (op != CAIRO_OPERATOR_OVER)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
/* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
* the pattern contains transparency, we return
* CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
* surface. If the analysis surface determines that there is
* anything drawn under this operation, a fallback image will be
* used. Otherwise the operation will be replayed during the
* render stage and we blend the transarency into the white
* background to convert the pattern to opaque.
*/
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
- if ( _cairo_surface_is_meta (surface_pattern->surface))
- return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
- else
- return analyze_surface_pattern_transparency (surface_pattern);
+ return analyze_surface_pattern_transparency (surface_pattern);
}
if (_cairo_pattern_is_opaque (pattern))
return CAIRO_STATUS_SUCCESS;
else
return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
}
@@ -456,18 +459,19 @@ static cairo_status_t
cairo_matrix_transform_point (&surface->ctm, &x, &y);
LineTo (surface->dc, (int) x, (int) y);
CloseFigure (surface->dc);
EndPath (surface->dc);
SelectClipPath (surface->dc, RGN_AND);
SaveDC (surface->dc); /* Allow clip path to be reset during replay */
- status = _cairo_meta_surface_replay (meta_surface, &surface->base);
-
+ status = _cairo_meta_surface_replay_region (meta_surface, &surface->base,
+ CAIRO_META_REGION_NATIVE);
+ assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
/* Restore both the clip save and our earlier path SaveDC */
RestoreDC (surface->dc, -2);
if (status)
return status;
}
}
--- a/gfx/cairo/cairo/src/cairo-xlib-surface.c
+++ b/gfx/cairo/cairo/src/cairo-xlib-surface.c
@@ -1941,16 +1941,18 @@ static cairo_surface_t *
XRenderPictFormat *xrender_format,
int width,
int height,
int depth)
{
cairo_xlib_surface_t *surface;
cairo_xlib_screen_info_t *screen_info;
+ CAIRO_MUTEX_INITIALIZE ();
+
screen_info = _cairo_xlib_screen_info_get (dpy, screen);
if (screen_info == NULL)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL) {
_cairo_xlib_screen_info_destroy (screen_info);
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
@@ -2088,18 +2090,16 @@ cairo_xlib_surface_create (Display *
int width,
int height)
{
Screen *screen = _cairo_xlib_screen_from_visual (dpy, visual);
if (screen == NULL)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
- CAIRO_MUTEX_INITIALIZE ();
-
return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
visual, NULL, width, height, 0);
}
/**
* cairo_xlib_surface_create_for_bitmap:
* @dpy: an X Display
* @bitmap: an X Drawable, (a depth-1 Pixmap)
@@ -2114,18 +2114,16 @@ cairo_xlib_surface_create (Display *
**/
cairo_surface_t *
cairo_xlib_surface_create_for_bitmap (Display *dpy,
Pixmap bitmap,
Screen *screen,
int width,
int height)
{
- CAIRO_MUTEX_INITIALIZE ();
-
return _cairo_xlib_surface_create_internal (dpy, bitmap, screen,
NULL, NULL, width, height, 1);
}
#if CAIRO_HAS_XLIB_XRENDER_SURFACE
/**
* cairo_xlib_surface_create_with_xrender_format:
* @dpy: an X Display
@@ -2149,18 +2147,16 @@ cairo_xlib_surface_create_for_bitmap (Di
cairo_surface_t *
cairo_xlib_surface_create_with_xrender_format (Display *dpy,
Drawable drawable,
Screen *screen,
XRenderPictFormat *format,
int width,
int height)
{
- CAIRO_MUTEX_INITIALIZE ();
-
return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
NULL, format, width, height, 0);
}
slim_hidden_def (cairo_xlib_surface_create_with_xrender_format);
/**
* cairo_xlib_surface_get_xrender_format:
* @surface: an xlib surface
--- a/gfx/cairo/cairo/src/cairo.c
+++ b/gfx/cairo/cairo/src/cairo.c
@@ -58,22 +58,16 @@ static const cairo_t _cairo_nil = {
FALSE, /* has_current_point */
FALSE, /* has_curve_to */
NULL, {{NULL}} /* buf_tail, buf_head */
}}
};
#include <assert.h>
-/* This has to be updated whenever #cairo_status_t is extended. That's
- * a bit of a pain, but it should be easy to always catch as long as
- * one adds a new test case to test a trigger of the new status value.
- */
-#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_INVALID_STRIDE
-
/**
* _cairo_error:
* @status: a status value indicating an error, (eg. not
* CAIRO_STATUS_SUCCESS)
*
* Checks that status is an error status, but does nothing else.
*
* All assignments of an error status to any user-visible object
@@ -2759,22 +2753,20 @@ void
cairo_set_font_options (cairo_t *cr,
const cairo_font_options_t *options)
{
cairo_status_t status;
if (cr->status)
return;
- if (options != NULL) {
- status = cairo_font_options_status ((cairo_font_options_t *) options);
- if (status) {
- _cairo_set_error (cr, status);
- return;
- }
+ status = cairo_font_options_status ((cairo_font_options_t *) options);
+ if (status) {
+ _cairo_set_error (cr, status);
+ return;
}
_cairo_gstate_set_font_options (cr->gstate, options);
}
/**
* cairo_get_font_options:
* @cr: a #cairo_t
@@ -2866,22 +2858,22 @@ BAIL:
**/
cairo_scaled_font_t *
cairo_get_scaled_font (cairo_t *cr)
{
cairo_status_t status;
cairo_scaled_font_t *scaled_font;
if (cr->status)
- return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
+ return _cairo_scaled_font_create_in_error (cr->status);
status = _cairo_gstate_get_scaled_font (cr->gstate, &scaled_font);
if (status) {
_cairo_set_error (cr, status);
- return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
+ return _cairo_scaled_font_create_in_error (status);
}
return scaled_font;
}
/**
* cairo_text_extents:
* @cr: a #cairo_t
@@ -3619,295 +3611,8 @@ cairo_append_path (cairo_t *cr,
* Returns: the current status of this context, see #cairo_status_t
**/
cairo_status_t
cairo_status (cairo_t *cr)
{
return cr->status;
}
slim_hidden_def (cairo_status);
-
-/**
- * cairo_status_to_string:
- * @status: a cairo status
- *
- * Provides a human-readable description of a #cairo_status_t.
- *
- * Returns: a string representation of the status
- */
-const char *
-cairo_status_to_string (cairo_status_t status)
-{
- switch (status) {
- case CAIRO_STATUS_SUCCESS:
- return "success";
- case CAIRO_STATUS_NO_MEMORY:
- return "out of memory";
- case CAIRO_STATUS_INVALID_RESTORE:
- return "cairo_restore without matching cairo_save";
- case CAIRO_STATUS_INVALID_POP_GROUP:
- return "cairo_pop_group without matching cairo_push_group";
- case CAIRO_STATUS_NO_CURRENT_POINT:
- return "no current point defined";
- case CAIRO_STATUS_INVALID_MATRIX:
- return "invalid matrix (not invertible)";
- case CAIRO_STATUS_INVALID_STATUS:
- return "invalid value for an input cairo_status_t";
- case CAIRO_STATUS_NULL_POINTER:
- return "NULL pointer";
- case CAIRO_STATUS_INVALID_STRING:
- return "input string not valid UTF-8";
- case CAIRO_STATUS_INVALID_PATH_DATA:
- return "input path data not valid";
- case CAIRO_STATUS_READ_ERROR:
- return "error while reading from input stream";
- case CAIRO_STATUS_WRITE_ERROR:
- return "error while writing to output stream";
- case CAIRO_STATUS_SURFACE_FINISHED:
- return "the target surface has been finished";
- case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
- return "the surface type is not appropriate for the operation";
- case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
- return "the pattern type is not appropriate for the operation";
- case CAIRO_STATUS_INVALID_CONTENT:
- return "invalid value for an input cairo_content_t";
- case CAIRO_STATUS_INVALID_FORMAT:
- return "invalid value for an input cairo_format_t";
- case CAIRO_STATUS_INVALID_VISUAL:
- return "invalid value for an input Visual*";
- case CAIRO_STATUS_FILE_NOT_FOUND:
- return "file not found";
- case CAIRO_STATUS_INVALID_DASH:
- return "invalid value for a dash setting";
- case CAIRO_STATUS_INVALID_DSC_COMMENT:
- return "invalid value for a DSC comment";
- case CAIRO_STATUS_INVALID_INDEX:
- return "invalid index passed to getter";
- case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
- return "clip region not representable in desired format";
- case CAIRO_STATUS_TEMP_FILE_ERROR:
- return "error creating or writing to a temporary file";
- case CAIRO_STATUS_INVALID_STRIDE:
- return "invalid value for stride";
- }
-
- return "<unknown error status>";
-}
-
-void
-_cairo_restrict_value (double *value, double min, double max)
-{
- if (*value < min)
- *value = min;
- else if (*value > max)
- *value = max;
-}
-
-/* This function is identical to the C99 function lround(), except that it
- * performs arithmetic rounding (instead of away-from-zero rounding) and
- * has a valid input range of (INT_MIN, INT_MAX] instead of
- * [INT_MIN, INT_MAX]. It is much faster on both x86 and FPU-less systems
- * than other commonly used methods for rounding (lround, round, rint, lrint
- * or float (d + 0.5)).
- *
- * The reason why this function is much faster on x86 than other
- * methods is due to the fact that it avoids the fldcw instruction.
- * This instruction incurs a large performance penalty on modern Intel
- * processors due to how it prevents efficient instruction pipelining.
- *
- * The reason why this function is much faster on FPU-less systems is for
- * an entirely different reason. All common rounding methods involve multiple
- * floating-point operations. Each one of these operations has to be
- * emulated in software, which adds up to be a large performance penalty.
- * This function doesn't perform any floating-point calculations, and thus
- * avoids this penalty.
- */
-int
-_cairo_lround (double d)
-{
- uint32_t top, shift_amount, output;
- union {
- double d;
- uint64_t ui64;
- uint32_t ui32[2];
- } u;
-
- u.d = d;
-
- /* If the integer word order doesn't match the float word order, we swap
- * the words of the input double. This is needed because we will be
- * treating the whole double as a 64-bit unsigned integer. Notice that we
- * use WORDS_BIGENDIAN to detect the integer word order, which isn't
- * exactly correct because WORDS_BIGENDIAN refers to byte order, not word
- * order. Thus, we are making the assumption that the byte order is the
- * same as the integer word order which, on the modern machines that we
- * care about, is OK.
- */
-#if ( defined(FLOAT_WORDS_BIGENDIAN) && !defined(WORDS_BIGENDIAN)) || \
- (!defined(FLOAT_WORDS_BIGENDIAN) && defined(WORDS_BIGENDIAN))
- {
- uint32_t temp = u.ui32[0];
- u.ui32[0] = u.ui32[1];
- u.ui32[1] = temp;
- }
-#endif
-
-#ifdef WORDS_BIGENDIAN
- #define MSW (0) /* Most Significant Word */
- #define LSW (1) /* Least Significant Word */
-#else
- #define MSW (1)
- #define LSW (0)
-#endif
-
- /* By shifting the most significant word of the input double to the
- * right 20 places, we get the very "top" of the double where the exponent
- * and sign bit lie.
- */
- top = u.ui32[MSW] >> 20;
-
- /* Here, we calculate how much we have to shift the mantissa to normalize
- * it to an integer value. We extract the exponent "top" by masking out the
- * sign bit, then we calculate the shift amount by subtracting the exponent
- * from the bias. Notice that the correct bias for 64-bit doubles is
- * actually 1075, but we use 1053 instead for two reasons:
- *
- * 1) To perform rounding later on, we will first need the target
- * value in a 31.1 fixed-point format. Thus, the bias needs to be one
- * less: (1075 - 1: 1074).
- *
- * 2) To avoid shifting the mantissa as a full 64-bit integer (which is
- * costly on certain architectures), we break the shift into two parts.
- * First, the upper and lower parts of the mantissa are shifted
- * individually by a constant amount that all valid inputs will require
- * at the very least. This amount is chosen to be 21, because this will
- * allow the two parts of the mantissa to later be combined into a
- * single 32-bit representation, on which the remainder of the shift
- * will be performed. Thus, we decrease the bias by an additional 21:
- * (1074 - 21: 1053).
- */
- shift_amount = 1053 - (top & 0x7FF);
-
- /* We are done with the exponent portion in "top", so here we shift it off
- * the end.
- */
- top >>= 11;
-
- /* Before we perform any operations on the mantissa, we need to OR in
- * the implicit 1 at the top (see the IEEE-754 spec). We needn't mask
- * off the sign bit nor the exponent bits because these higher bits won't
- * make a bit of difference in the rest of our calculations.
- */
- u.ui32[MSW] |= 0x100000;
-
- /* If the input double is negative, we have to decrease the mantissa
- * by a hair. This is an important part of performing arithmetic rounding,
- * as negative numbers must round towards positive infinity in the
- * halfwase case of -x.5. Since "top" contains only the sign bit at this
- * point, we can just decrease the mantissa by the value of "top".
- */
- u.ui64 -= top;
-
- /* By decrementing "top", we create a bitmask with a value of either
- * 0x0 (if the input was negative) or 0xFFFFFFFF (if the input was positive
- * and thus the unsigned subtraction underflowed) that we'll use later.
- */
- top--;
-
- /* Here, we shift the mantissa by the constant value as described above.
- * We can emulate a 64-bit shift right by 21 through shifting the top 32
- * bits left 11 places and ORing in the bottom 32 bits shifted 21 places
- * to the right. Both parts of the mantissa are now packed into a single
- * 32-bit integer. Although we severely truncate the lower part in the
- * process, we still have enough significant bits to perform the conversion
- * without error (for all valid inputs).
- */
- output = (u.ui32[MSW] << 11) | (u.ui32[LSW] >> 21);
-
- /* Next, we perform the shift that converts the X.Y fixed-point number
- * currently found in "output" to the desired 31.1 fixed-point format
- * needed for the following rounding step. It is important to consider
- * all possible values for "shift_amount" at this point:
- *
- * - {shift_amount < 0} Since shift_amount is an unsigned integer, it
- * really can't have a value less than zero. But, if the shift_amount
- * calculation above caused underflow (which would happen with
- * input > INT_MAX or input <= INT_MIN) then shift_amount will now be
- * a very large number, and so this shift will result in complete
- * garbage. But that's OK, as the input was out of our range, so our
- * output is undefined.
- *
- * - {shift_amount > 31} If the magnitude of the input was very small
- * (i.e. |input| << 1.0), shift_amount will have a value greater than
- * 31. Thus, this shift will also result in garbage. After performing
- * the shift, we will zero-out "output" if this is the case.
- *
- * - {0 <= shift_amount < 32} In this case, the shift will properly convert
- * the mantissa into a 31.1 fixed-point number.
- */
- output >>= shift_amount;
-
- /* This is where we perform rounding with the 31.1 fixed-point number.
- * Since what we're after is arithmetic rounding, we simply add the single
- * fractional bit into the integer part of "output", and just keep the
- * integer part.
- */
- output = (output >> 1) + (output & 1);
-
- /* Here, we zero-out the result if the magnitude if the input was very small
- * (as explained in the section above). Notice that all input out of the
- * valid range is also caught by this condition, which means we produce 0
- * for all invalid input, which is a nice side effect.
- *
- * The most straightforward way to do this would be:
- *
- * if (shift_amount > 31)
- * output = 0;
- *
- * But we can use a little trick to avoid the potential branch. The
- * expression (shift_amount > 31) will be either 1 or 0, which when
- * decremented will be either 0x0 or 0xFFFFFFFF (unsigned underflow),
- * which can be used to conditionally mask away all the bits in "output"
- * (in the 0x0 case), effectively zeroing it out. Certain, compilers would
- * have done this for us automatically.
- */
- output &= ((shift_amount > 31) - 1);
-
- /* If the input double was a negative number, then we have to negate our
- * output. The most straightforward way to do this would be:
- *
- * if (!top)
- * output = -output;
- *
- * as "top" at this point is either 0x0 (if the input was negative) or
- * 0xFFFFFFFF (if the input was positive). But, we can use a trick to
- * avoid the branch. Observe that the following snippet of code has the
- * same effect as the reference snippet above:
- *
- * if (!top)
- * output = 0 - output;
- * else
- * output = output - 0;
- *
- * Armed with the bitmask found in "top", we can condense the two statements
- * into the following:
- *
- * output = (output & top) - (output & ~top);
- *
- * where, in the case that the input double was negative, "top" will be 0,
- * and the statement will be equivalent to:
- *
- * output = (0) - (output);
- *
- * and if the input double was positive, "top" will be 0xFFFFFFFF, and the
- * statement will be equivalent to:
- *
- * output = (output) - (0);
- *
- * Which, as pointed out earlier, is equivalent to the original reference
- * snippet.
- */
- output = (output & top) - (output & ~top);
-
- return output;
-#undef MSW
-#undef LSW
-}
--- a/gfx/cairo/cairo/src/cairo.h
+++ b/gfx/cairo/cairo/src/cairo.h
@@ -233,17 +233,17 @@ typedef enum _cairo_status {
CAIRO_STATUS_INVALID_VISUAL,
CAIRO_STATUS_FILE_NOT_FOUND,
CAIRO_STATUS_INVALID_DASH,
CAIRO_STATUS_INVALID_DSC_COMMENT,
CAIRO_STATUS_INVALID_INDEX,
CAIRO_STATUS_CLIP_NOT_REPRESENTABLE,
CAIRO_STATUS_TEMP_FILE_ERROR,
CAIRO_STATUS_INVALID_STRIDE
- /* after adding a new error: update CAIRO_STATUS_LAST_STATUS in cairo.c */
+ /* after adding a new error: update CAIRO_STATUS_LAST_STATUS in cairoint.h */
} cairo_status_t;
/**
* cairo_content_t:
* @CAIRO_CONTENT_COLOR: The surface will hold color content only.
* @CAIRO_CONTENT_ALPHA: The surface will hold alpha content only.
* @CAIRO_CONTENT_COLOR_ALPHA: The surface will hold color and alpha content.
*
--- a/gfx/cairo/cairo/src/cairoint.h
+++ b/gfx/cairo/cairo/src/cairoint.h
@@ -107,16 +107,24 @@ cairo_private FILE *
#ifndef M_SQRT1_2
#define M_SQRT1_2 0.707106781186547524400844362104849039
#endif
#undef ARRAY_LENGTH
#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0])))
+
+/* This has to be updated whenever #cairo_status_t is extended. That's
+ * a bit of a pain, but it should be easy to always catch as long as
+ * one adds a new test case to test a trigger of the new status value.
+ */
+#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_INVALID_STRIDE
+
+
/* Size in bytes of buffer to use off the stack per functions.
* Mostly used by text functions. For larger allocations, they'll
* malloc(). */
#ifndef CAIRO_STACK_BUFFER_SIZE
#define CAIRO_STACK_BUFFER_SIZE (512 * sizeof (int))
#endif
#define CAIRO_STACK_ARRAY_LENGTH(T) (CAIRO_STACK_BUFFER_SIZE / sizeof(T))
@@ -1229,18 +1237,23 @@ cairo_private void
cairo_private void
_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font);
cairo_private cairo_status_t
_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
cairo_status_t status);
+cairo_private cairo_scaled_font_t *
+_cairo_scaled_font_create_in_error (cairo_status_t status);
+
+cairo_private void
+_cairo_scaled_font_reset_static_data (void);
+
extern const cairo_private cairo_font_face_t _cairo_font_face_nil;
-extern const cairo_private cairo_scaled_font_t _cairo_scaled_font_nil;
cairo_private void
_cairo_font_face_init (cairo_font_face_t *font_face,
const cairo_font_face_backend_t *backend);
cairo_private cairo_status_t
_cairo_font_face_set_error (cairo_font_face_t *font_face,
cairo_status_t status);
--- a/gfx/cairo/libpixman/src/pixman-compose.c
+++ b/gfx/cairo/libpixman/src/pixman-compose.c
@@ -3673,42 +3673,539 @@ static void pixmanFetchSourcePict(source
ry += cy;
rz += cz;
}
}
}
}
}
-static void fbFetchTransformed(bits_image_t * pict, int x, int y, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits)
+/*
+ * Fetch from region strategies
+ */
+typedef FASTCALL uint32_t (*fetchFromRegionProc)(bits_image_t *pict, int x, int y, uint32_t *buffer, fetchPixelProc fetch, pixman_box16_t *box);
+
+static inline uint32_t
+fbFetchFromNoRegion(bits_image_t *pict, int x, int y, uint32_t *buffer, fetchPixelProc fetch, pixman_box16_t *box)
+{
+ return fetch (pict, x, y);
+}
+
+static uint32_t
+fbFetchFromNRectangles(bits_image_t *pict, int x, int y, uint32_t *buffer, fetchPixelProc fetch, pixman_box16_t *box)
+{
+ pixman_box16_t box2;
+ if (pixman_region_contains_point (pict->common.src_clip, x, y, &box2))
+ return fbFetchFromNoRegion(pict, x, y, buffer, fetch, box);
+ else
+ return 0;
+}
+
+static uint32_t
+fbFetchFromOneRectangle(bits_image_t *pict, int x, int y, uint32_t *buffer, fetchPixelProc fetch, pixman_box16_t *box)
+{
+ pixman_box16_t box2 = *box;
+ return ((x < box2.x1) | (x >= box2.x2) | (y < box2.y1) | (y >= box2.y2)) ?
+ 0 : fbFetchFromNoRegion(pict, x, y, buffer, fetch, box);
+}
+
+/*
+ * Fetching Algorithms
+ */
+static void
+fbFetchTransformed_Nearest_Normal(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+ pixman_box16_t* box = NULL;
+ fetchPixelProc fetch;
+ fetchFromRegionProc fetchFromRegion;
+ int x, y, i;
+
+ /* initialize the two function pointers */
+ fetch = fetchPixelProcForPicture(pict);
+
+ if(pixman_region_n_rects (pict->common.src_clip) == 1)
+ fetchFromRegion = fbFetchFromNoRegion;
+ else
+ fetchFromRegion = fbFetchFromNRectangles;
+
+ for ( i = 0; i < width; ++i)
+ {
+ if (!mask || mask[i] & maskBits)
+ {
+ if (!v.vector[2])
+ {
+ *(buffer + i) = 0;
+ }
+ else
+ {
+ if (!affine)
+ {
+ y = MOD(DIV(v.vector[1],v.vector[2]), pict->height);
+ x = MOD(DIV(v.vector[0],v.vector[2]), pict->width);
+ }
+ else
+ {
+ y = MOD(v.vector[1]>>16, pict->height);
+ x = MOD(v.vector[0]>>16, pict->width);
+ }
+ *(buffer + i) = fetchFromRegion(pict, x, y, buffer, fetch, box);
+ }
+ }
+
+ v.vector[0] += unit.vector[0];
+ v.vector[1] += unit.vector[1];
+ v.vector[2] += unit.vector[2];
+ }
+}
+
+static void
+fbFetchTransformed_Nearest_Pad(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+ pixman_box16_t *box = NULL;
+ fetchPixelProc fetch;
+ fetchFromRegionProc fetchFromRegion;
+ int x, y, i;
+
+ /* initialize the two function pointers */
+ fetch = fetchPixelProcForPicture(pict);
+
+ if(pixman_region_n_rects (pict->common.src_clip) == 1)
+ fetchFromRegion = fbFetchFromNoRegion;
+ else
+ fetchFromRegion = fbFetchFromNRectangles;
+
+ for (i = 0; i < width; ++i)
+ {
+ if (!mask || mask[i] & maskBits)
+ {
+ if (!v.vector[2])
+ {
+ *(buffer + i) = 0;
+ }
+ else
+ {
+ if (!affine)
+ {
+ y = CLIP(DIV(v.vector[1], v.vector[2]), 0, pict->height-1);
+ x = CLIP(DIV(v.vector[0], v.vector[2]), 0, pict->width-1);
+ }
+ else
+ {
+ y = CLIP(v.vector[1]>>16, 0, pict->height-1);
+ x = CLIP(v.vector[0]>>16, 0, pict->width-1);
+ }
+
+ *(buffer + i) = fetchFromRegion(pict, x, y, buffer, fetch, box);
+ }
+ }
+
+ v.vector[0] += unit.vector[0];
+ v.vector[1] += unit.vector[1];
+ v.vector[2] += unit.vector[2];
+ }
+}
+
+static void
+fbFetchTransformed_Nearest_General(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+ pixman_box16_t *box = NULL;
+ fetchPixelProc fetch;
+ fetchFromRegionProc fetchFromRegion;
+ int x, y, i;
+
+ /* initialize the two function pointers */
+ fetch = fetchPixelProcForPicture(pict);
+
+ if(pixman_region_n_rects (pict->common.src_clip) == 1)
+ {
+ box = &(pict->common.src_clip->extents);
+ fetchFromRegion = fbFetchFromOneRectangle;
+ }
+ else
+ {
+ fetchFromRegion = fbFetchFromNRectangles;
+ }
+
+ for (i = 0; i < width; ++i) {
+ if (!mask || mask[i] & maskBits)
+ {
+ if (!v.vector[2]) {
+ *(buffer + i) = 0;
+ } else {
+ if (!affine) {
+ y = DIV(v.vector[1],v.vector[2]);
+ x = DIV(v.vector[0],v.vector[2]);
+ } else {
+ y = v.vector[1]>>16;
+ x = v.vector[0]>>16;
+ }
+ *(buffer + i) = fetchFromRegion(pict, x, y, buffer, fetch, box);
+ }
+ }
+ v.vector[0] += unit.vector[0];
+ v.vector[1] += unit.vector[1];
+ v.vector[2] += unit.vector[2];
+ }
+}
+
+static void
+fbFetchTransformed_Bilinear_Normal(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+ pixman_box16_t *box = NULL;
+ fetchPixelProc fetch;
+ fetchFromRegionProc fetchFromRegion;
+ int i;
+
+ /* initialize the two function pointers */
+ fetch = fetchPixelProcForPicture(pict);
+
+ if(pixman_region_n_rects (pict->common.src_clip) == 1)
+ fetchFromRegion = fbFetchFromNoRegion;
+ else
+ fetchFromRegion = fbFetchFromNRectangles;
+
+ for (i = 0; i < width; ++i) {
+ if (!mask || mask[i] & maskBits)
+ {
+ if (!v.vector[2]) {
+ *(buffer + i) = 0;
+ } else {
+ int x1, x2, y1, y2, distx, idistx, disty, idisty;
+ uint32_t tl, tr, bl, br, r;
+ uint32_t ft, fb;
+
+ if (!affine) {
+ pixman_fixed_48_16_t div;
+ div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
+ x1 = div >> 16;
+ distx = ((pixman_fixed_t)div >> 8) & 0xff;
+ div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
+ y1 = div >> 16;
+ disty = ((pixman_fixed_t)div >> 8) & 0xff;
+ } else {
+ x1 = v.vector[0] >> 16;
+ distx = (v.vector[0] >> 8) & 0xff;
+ y1 = v.vector[1] >> 16;
+ disty = (v.vector[1] >> 8) & 0xff;
+ }
+ x2 = x1 + 1;
+ y2 = y1 + 1;
+
+ idistx = 256 - distx;
+ idisty = 256 - disty;
+
+ x1 = MOD (x1, pict->width);
+ x2 = MOD (x2, pict->width);
+ y1 = MOD (y1, pict->height);
+ y2 = MOD (y2, pict->height);
+
+ tl = fetchFromRegion(pict, x1, y1, buffer, fetch, box);
+ tr = fetchFromRegion(pict, x2, y1, buffer, fetch, box);
+ bl = fetchFromRegion(pict, x1, y2, buffer, fetch, box);
+ br = fetchFromRegion(pict, x2, y2, buffer, fetch, box);
+
+ ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
+ fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
+ r = (((ft * idisty + fb * disty) >> 16) & 0xff);
+ ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
+ fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
+ r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
+ ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
+ fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
+ r |= (((ft * idisty + fb * disty)) & 0xff0000);
+ ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
+ fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
+ r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
+ *(buffer + i) = r;
+ }
+ }
+ v.vector[0] += unit.vector[0];
+ v.vector[1] += unit.vector[1];
+ v.vector[2] += unit.vector[2];
+ }
+}
+
+static void
+fbFetchTransformed_Bilinear_Pad(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+ pixman_box16_t *box = NULL;
+ fetchPixelProc fetch;
+ fetchFromRegionProc fetchFromRegion;
+ int i;
+
+ /* initialize the two function pointers */
+ fetch = fetchPixelProcForPicture(pict);
+
+ if(pixman_region_n_rects (pict->common.src_clip) == 1)
+ fetchFromRegion = fbFetchFromNoRegion;
+ else
+ fetchFromRegion = fbFetchFromNRectangles;
+
+ for (i = 0; i < width; ++i) {
+ if (!mask || mask[i] & maskBits)
+ {
+ if (!v.vector[2]) {
+ *(buffer + i) = 0;
+ } else {
+ int x1, x2, y1, y2, distx, idistx, disty, idisty;
+ uint32_t tl, tr, bl, br, r;
+ uint32_t ft, fb;
+
+ if (!affine) {
+ pixman_fixed_48_16_t div;
+ div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
+ x1 = div >> 16;
+ distx = ((pixman_fixed_t)div >> 8) & 0xff;
+ div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
+ y1 = div >> 16;
+ disty = ((pixman_fixed_t)div >> 8) & 0xff;
+ } else {
+ x1 = v.vector[0] >> 16;
+ distx = (v.vector[0] >> 8) & 0xff;
+ y1 = v.vector[1] >> 16;
+ disty = (v.vector[1] >> 8) & 0xff;
+ }
+ x2 = x1 + 1;
+ y2 = y1 + 1;
+
+ idistx = 256 - distx;
+ idisty = 256 - disty;
+
+ x1 = CLIP (x1, 0, pict->width-1);
+ x2 = CLIP (x2, 0, pict->width-1);
+ y1 = CLIP (y1, 0, pict->height-1);
+ y2 = CLIP (y2, 0, pict->height-1);
+
+ tl = fetchFromRegion(pict, x1, y1, buffer, fetch, box);
+ tr = fetchFromRegion(pict, x2, y1, buffer, fetch, box);
+ bl = fetchFromRegion(pict, x1, y2, buffer, fetch, box);
+ br = fetchFromRegion(pict, x2, y2, buffer, fetch, box);
+
+ ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
+ fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
+ r = (((ft * idisty + fb * disty) >> 16) & 0xff);
+ ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
+ fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
+ r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
+ ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
+ fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
+ r |= (((ft * idisty + fb * disty)) & 0xff0000);
+ ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
+ fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
+ r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
+ *(buffer + i) = r;
+ }
+ }
+ v.vector[0] += unit.vector[0];
+ v.vector[1] += unit.vector[1];
+ v.vector[2] += unit.vector[2];
+ }
+}
+
+static void
+fbFetchTransformed_Bilinear_General(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+ pixman_box16_t *box = NULL;
+ fetchPixelProc fetch;
+ fetchFromRegionProc fetchFromRegion;
+ int i;
+
+ /* initialize the two function pointers */
+ fetch = fetchPixelProcForPicture(pict);
+
+ if(pixman_region_n_rects (pict->common.src_clip) == 1)
+ {
+ box = &(pict->common.src_clip->extents);
+ fetchFromRegion = fbFetchFromOneRectangle;
+ }
+ else
+ {
+ fetchFromRegion = fbFetchFromNRectangles;
+ }
+
+ for (i = 0; i < width; ++i)
+ {
+ if (!mask || mask[i] & maskBits)
+ {
+ if (!v.vector[2]) {
+ *(buffer + i) = 0;
+ } else {
+ int x1, x2, y1, y2, distx, idistx, disty, idisty;
+ uint32_t tl, tr, bl, br, r;
+ uint32_t ft, fb;
+
+ if (!affine) {
+ pixman_fixed_48_16_t div;
+ div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
+ x1 = div >> 16;
+ distx = ((pixman_fixed_t)div >> 8) & 0xff;
+ div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
+ y1 = div >> 16;
+ disty = ((pixman_fixed_t)div >> 8) & 0xff;
+ } else {
+ x1 = v.vector[0] >> 16;
+ distx = (v.vector[0] >> 8) & 0xff;
+ y1 = v.vector[1] >> 16;
+ disty = (v.vector[1] >> 8) & 0xff;
+ }
+ x2 = x1 + 1;
+ y2 = y1 + 1;
+
+ idistx = 256 - distx;
+ idisty = 256 - disty;
+
+ tl = fetchFromRegion(pict, x1, y1, buffer, fetch, box);
+ tr = fetchFromRegion(pict, x2, y1, buffer, fetch, box);
+ bl = fetchFromRegion(pict, x1, y2, buffer, fetch, box);
+ br = fetchFromRegion(pict, x2, y2, buffer, fetch, box);
+
+ ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
+ fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
+ r = (((ft * idisty + fb * disty) >> 16) & 0xff);
+ ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
+ fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
+ r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
+ ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
+ fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
+ r |= (((ft * idisty + fb * disty)) & 0xff0000);
+ ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
+ fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
+ r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
+ *(buffer + i) = r;
+ }
+ }
+
+ v.vector[0] += unit.vector[0];
+ v.vector[1] += unit.vector[1];
+ v.vector[2] += unit.vector[2];
+ }
+}
+
+static void
+fbFetchTransformed_Convolution(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+ pixman_box16_t *box = NULL;
+ fetchPixelProc fetch;
+ int i;
+
+ pixman_fixed_t *params = pict->common.filter_params;
+ int32_t cwidth = pixman_fixed_to_int(params[0]);
+ int32_t cheight = pixman_fixed_to_int(params[1]);
+ int xoff = (params[0] - pixman_fixed_1) >> 1;
+ int yoff = (params[1] - pixman_fixed_1) >> 1;
+ fetch = fetchPixelProcForPicture(pict);
+
+ params += 2;
+ for (i = 0; i < width; ++i) {
+ if (!mask || mask[i] & maskBits)
+ {
+ if (!v.vector[2]) {
+ *(buffer + i) = 0;
+ } else {
+ int x1, x2, y1, y2, x, y;
+ int32_t srtot, sgtot, sbtot, satot;
+ pixman_fixed_t *p = params;
+
+ if (!affine) {
+ pixman_fixed_48_16_t tmp;
+ tmp = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2] - xoff;
+ x1 = pixman_fixed_to_int(tmp);
+ tmp = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2] - yoff;
+ y1 = pixman_fixed_to_int(tmp);
+ } else {
+ x1 = pixman_fixed_to_int(v.vector[0] - xoff);
+ y1 = pixman_fixed_to_int(v.vector[1] - yoff);
+ }
+ x2 = x1 + cwidth;
+ y2 = y1 + cheight;
+
+ srtot = sgtot = sbtot = satot = 0;
+
+ for (y = y1; y < y2; y++) {
+ int ty;
+ switch (pict->common.repeat) {
+ case PIXMAN_REPEAT_NORMAL:
+ ty = MOD (y, pict->height);
+ break;
+ case PIXMAN_REPEAT_PAD:
+ ty = CLIP (y, 0, pict->height-1);
+ break;
+ default:
+ ty = y;
+ }
+ for (x = x1; x < x2; x++) {
+ if (*p) {
+ int tx;
+ switch (pict->common.repeat) {
+ case PIXMAN_REPEAT_NORMAL:
+ tx = MOD (x, pict->width);
+ break;
+ case PIXMAN_REPEAT_PAD:
+ tx = CLIP (x, 0, pict->width-1);
+ break;
+ default:
+ tx = x;
+ }
+ if (pixman_region_contains_point (pict->common.src_clip, tx, ty, box)) {
+ uint32_t c = fetch(pict, tx, ty);
+
+ srtot += Red(c) * *p;
+ sgtot += Green(c) * *p;
+ sbtot += Blue(c) * *p;
+ satot += Alpha(c) * *p;
+ }
+ }
+ p++;
+ }
+ }
+
+ satot >>= 16;
+ srtot >>= 16;
+ sgtot >>= 16;
+ sbtot >>= 16;
+
+ if (satot < 0) satot = 0; else if (satot > 0xff) satot = 0xff;
+ if (srtot < 0) srtot = 0; else if (srtot > 0xff) srtot = 0xff;
+ if (sgtot < 0) sgtot = 0; else if (sgtot > 0xff) sgtot = 0xff;
+ if (sbtot < 0) sbtot = 0; else if (sbtot > 0xff) sbtot = 0xff;
+
+ *(buffer + i) = ((satot << 24) |
+ (srtot << 16) |
+ (sgtot << 8) |
+ (sbtot ));
+ }
+ }
+ v.vector[0] += unit.vector[0];
+ v.vector[1] += unit.vector[1];
+ v.vector[2] += unit.vector[2];
+ }
+}
+
+static void
+fbFetchTransformed(bits_image_t * pict, int x, int y, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits)
{
uint32_t *bits;
int32_t stride;
- fetchPixelProc fetch;
- pixman_vector_t v;
- pixman_vector_t unit;
- int i;
- pixman_box16_t box;
+ pixman_vector_t v;
+ pixman_vector_t unit;
pixman_bool_t affine = TRUE;
- fetch = fetchPixelProcForPicture(pict);
-
bits = pict->bits;
stride = pict->rowstride;
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed(x) + pixman_fixed_1 / 2 - 1;
v.vector[1] = pixman_int_to_fixed(y) + pixman_fixed_1 / 2 - 1;
v.vector[2] = pixman_fixed_1;
/* when using convolution filters one might get here without a transform */
if (pict->common.transform)
{
if (!pixman_transform_point_3d (pict->common.transform, &v))
- {
+ {
fbFinishAccess (pict->pDrawable);
return;
}
unit.vector[0] = pict->common.transform->matrix[0][0];
unit.vector[1] = pict->common.transform->matrix[1][0];
unit.vector[2] = pict->common.transform->matrix[2][0];
affine = v.vector[2] == pixman_fixed_1 && unit.vector[2] == 0;
}
@@ -3716,455 +4213,63 @@ static void fbFetchTransformed(bits_imag
{
unit.vector[0] = pixman_fixed_1;
unit.vector[1] = 0;
unit.vector[2] = 0;
}
if (pict->common.filter == PIXMAN_FILTER_NEAREST || pict->common.filter == PIXMAN_FILTER_FAST)
{
- if (pict->common.repeat == PIXMAN_REPEAT_NORMAL) {
- if (pixman_region_n_rects (pict->common.src_clip) == 1) {
- for (i = 0; i < width; ++i) {
- if (!mask || mask[i] & maskBits)
- {
- if (!v.vector[2]) {
- *(buffer + i) = 0;
- } else {
- if (!affine) {
- y = MOD(DIV(v.vector[1],v.vector[2]), pict->height);
- x = MOD(DIV(v.vector[0],v.vector[2]), pict->width);
- } else {
- y = MOD(v.vector[1]>>16, pict->height);
- x = MOD(v.vector[0]>>16, pict->width);
- }
- *(buffer + i) = fetch(pict, x, y);
- }
- }
-
- v.vector[0] += unit.vector[0];
- v.vector[1] += unit.vector[1];
- v.vector[2] += unit.vector[2];
- }
- } else {
- for (i = 0; i < width; ++i) {
- if (!mask || mask[i] & maskBits)
- {
- if (!v.vector[2]) {
- *(buffer + i) = 0;
- } else {
- if (!affine) {
- y = MOD(DIV(v.vector[1],v.vector[2]), pict->height);
- x = MOD(DIV(v.vector[0],v.vector[2]), pict->width);
- } else {
- y = MOD(v.vector[1]>>16, pict->height);
- x = MOD(v.vector[0]>>16, pict->width);
- }
- if (pixman_region_contains_point (pict->common.src_clip, x, y, &box))
- *(buffer + i) = fetch (pict, x, y);
- else
- *(buffer + i) = 0;
- }
- }
-
- v.vector[0] += unit.vector[0];
- v.vector[1] += unit.vector[1];
- v.vector[2] += unit.vector[2];
- }
- }
- } else {
- if (pixman_region_n_rects(pict->common.src_clip) == 1) {
- box = pict->common.src_clip->extents;
- for (i = 0; i < width; ++i) {
- if (!mask || mask[i] & maskBits)
- {
- if (!v.vector[2]) {
- *(buffer + i) = 0;
- } else {
- if (!affine) {
- y = DIV(v.vector[1],v.vector[2]);
- x = DIV(v.vector[0],v.vector[2]);
- } else {
- y = v.vector[1]>>16;
- x = v.vector[0]>>16;
- }
- *(buffer + i) = ((x < box.x1) | (x >= box.x2) | (y < box.y1) | (y >= box.y2)) ?
- 0 : fetch(pict, x, y);
- }
- }
- v.vector[0] += unit.vector[0];
- v.vector[1] += unit.vector[1];
- v.vector[2] += unit.vector[2];
- }
- } else {
- for (i = 0; i < width; ++i) {
- if (!mask || mask[i] & maskBits)
- {
- if (!v.vector[2]) {
- *(buffer + i) = 0;
- } else {
- if (!affine) {
- y = DIV(v.vector[1],v.vector[2]);
- x = DIV(v.vector[0],v.vector[2]);
- } else {
- y = v.vector[1]>>16;
- x = v.vector[0]>>16;
- }
- if (pixman_region_contains_point (pict->common.src_clip, x, y, &box))
- *(buffer + i) = fetch(pict, x, y);
- else
- *(buffer + i) = 0;
- }
- }
- v.vector[0] += unit.vector[0];
- v.vector[1] += unit.vector[1];
- v.vector[2] += unit.vector[2];
- }
- }
+ if (pict->common.repeat == PIXMAN_REPEAT_NORMAL)
+ {
+ fbFetchTransformed_Nearest_Normal(pict, width, buffer, mask, maskBits, affine, v, unit);
+
+ }
+ else if (pict->common.repeat == PIXMAN_REPEAT_PAD)
+ {
+ fbFetchTransformed_Nearest_Pad(pict, width, buffer, mask, maskBits, affine, v, unit);
+ }
+ else
+ {
+ fbFetchTransformed_Nearest_General(pict, width, buffer, mask, maskBits, affine, v, unit);
}
} else if (pict->common.filter == PIXMAN_FILTER_BILINEAR ||
pict->common.filter == PIXMAN_FILTER_GOOD ||
pict->common.filter == PIXMAN_FILTER_BEST)
{
/* adjust vector for maximum contribution at 0.5, 0.5 of each texel. */
v.vector[0] -= v.vector[2] / 2;
v.vector[1] -= v.vector[2] / 2;
unit.vector[0] -= unit.vector[2] / 2;
unit.vector[1] -= unit.vector[2] / 2;
- if (pict->common.repeat == PIXMAN_REPEAT_NORMAL) {
- if (pixman_region_n_rects(pict->common.src_clip) == 1) {
- for (i = 0; i < width; ++i) {
- if (!mask || mask[i] & maskBits)
- {
- if (!v.vector[2]) {
- *(buffer + i) = 0;
- } else {
- int x1, x2, y1, y2, distx, idistx, disty, idisty;
- uint32_t tl, tr, bl, br, r;
- uint32_t ft, fb;
-
- if (!affine) {
- pixman_fixed_48_16_t div;
- div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
- x1 = div >> 16;
- distx = ((pixman_fixed_t)div >> 8) & 0xff;
- div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
- y1 = div >> 16;
- disty = ((pixman_fixed_t)div >> 8) & 0xff;
- } else {
- x1 = v.vector[0] >> 16;
- distx = (v.vector[0] >> 8) & 0xff;
- y1 = v.vector[1] >> 16;
- disty = (v.vector[1] >> 8) & 0xff;
- }
- x2 = x1 + 1;
- y2 = y1 + 1;
-
- idistx = 256 - distx;
- idisty = 256 - disty;
-
- x1 = MOD (x1, pict->width);
- x2 = MOD (x2, pict->width);
- y1 = MOD (y1, pict->height);
- y2 = MOD (y2, pict->height);
-
- tl = fetch(pict, x1, y1);
- tr = fetch(pict, x2, y1);
- bl = fetch(pict, x1, y2);
- br = fetch(pict, x2, y2);
-
- ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
- fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
- r = (((ft * idisty + fb * disty) >> 16) & 0xff);
- ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
- fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
- r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
- ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
- fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
- r |= (((ft * idisty + fb * disty)) & 0xff0000);
- ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
- fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
- r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
- *(buffer + i) = r;
- }
- }
- v.vector[0] += unit.vector[0];
- v.vector[1] += unit.vector[1];
- v.vector[2] += unit.vector[2];
- }
- } else {
- for (i = 0; i < width; ++i) {
- if (!mask || mask[i] & maskBits)
- {
- if (!v.vector[2]) {
- *(buffer + i) = 0;
- } else {
- int x1, x2, y1, y2, distx, idistx, disty, idisty;
- uint32_t tl, tr, bl, br, r;
- uint32_t ft, fb;
-
- if (!affine) {
- pixman_fixed_48_16_t div;
- div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
- x1 = div >> 16;
- distx = ((pixman_fixed_t)div >> 8) & 0xff;
- div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
- y1 = div >> 16;
- disty = ((pixman_fixed_t)div >> 8) & 0xff;
- } else {
- x1 = v.vector[0] >> 16;
- distx = (v.vector[0] >> 8) & 0xff;
- y1 = v.vector[1] >> 16;
- disty = (v.vector[1] >> 8) & 0xff;
- }
- x2 = x1 + 1;
- y2 = y1 + 1;
-
- idistx = 256 - distx;
- idisty = 256 - disty;
-
- x1 = MOD (x1, pict->width);
- x2 = MOD (x2, pict->width);
- y1 = MOD (y1, pict->height);
- y2 = MOD (y2, pict->height);
-
- tl = pixman_region_contains_point(pict->common.src_clip, x1, y1, &box)
- ? fetch(pict, x1, y1) : 0;
- tr = pixman_region_contains_point(pict->common.src_clip, x2, y1, &box)
- ? fetch(pict, x2, y1) : 0;
- bl = pixman_region_contains_point(pict->common.src_clip, x1, y2, &box)
- ? fetch(pict, x1, y2) : 0;
- br = pixman_region_contains_point(pict->common.src_clip, x2, y2, &box)
- ? fetch(pict, x2, y2) : 0;
-
- ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
- fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
- r = (((ft * idisty + fb * disty) >> 16) & 0xff);
- ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
- fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
- r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
- ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
- fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
- r |= (((ft * idisty + fb * disty)) & 0xff0000);
- ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
- fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
- r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
- *(buffer + i) = r;
- }
- }
-
- v.vector[0] += unit.vector[0];
- v.vector[1] += unit.vector[1];
- v.vector[2] += unit.vector[2];
- }
- }
- } else {
- if (pixman_region_n_rects(pict->common.src_clip) == 1) {
- box = pict->common.src_clip->extents;
- for (i = 0; i < width; ++i) {
- if (!mask || mask[i] & maskBits)
- {
- if (!v.vector[2]) {
- *(buffer + i) = 0;
- } else {
- int x1, x2, y1, y2, distx, idistx, disty, idisty;
- uint32_t tl, tr, bl, br, r;
- pixman_bool_t x1_out, x2_out, y1_out, y2_out;
- uint32_t ft, fb;
-
- if (!affine) {
- pixman_fixed_48_16_t div;
- div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
- x1 = div >> 16;
- distx = ((pixman_fixed_t)div >> 8) & 0xff;
- div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
- y1 = div >> 16;
- disty = ((pixman_fixed_t)div >> 8) & 0xff;
- } else {
- x1 = v.vector[0] >> 16;
- distx = (v.vector[0] >> 8) & 0xff;
- y1 = v.vector[1] >> 16;
- disty = (v.vector[1] >> 8) & 0xff;
- }
- x2 = x1 + 1;
- y2 = y1 + 1;
-
- idistx = 256 - distx;
- idisty = 256 - disty;
-
- x1_out = (x1 < box.x1) | (x1 >= box.x2);
- x2_out = (x2 < box.x1) | (x2 >= box.x2);
- y1_out = (y1 < box.y1) | (y1 >= box.y2);
- y2_out = (y2 < box.y1) | (y2 >= box.y2);
-
- tl = x1_out|y1_out ? 0 : fetch(pict, x1, y1);
- tr = x2_out|y1_out ? 0 : fetch(pict, x2, y1);
- bl = x1_out|y2_out ? 0 : fetch(pict, x1, y2);
- br = x2_out|y2_out ? 0 : fetch(pict, x2, y2);
-
- ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
- fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
- r = (((ft * idisty + fb * disty) >> 16) & 0xff);
- ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
- fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
- r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
- ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
- fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
- r |= (((ft * idisty + fb * disty)) & 0xff0000);
- ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
- fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
- r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
- *(buffer + i) = r;
- }
- }
-
- v.vector[0] += unit.vector[0];
- v.vector[1] += unit.vector[1];
- v.vector[2] += unit.vector[2];
- }
- } else {
- for (i = 0; i < width; ++i) {
- if (!mask || mask[i] & maskBits)
- {
- if (!v.vector[2]) {
- *(buffer + i) = 0;
- } else {
- int x1, x2, y1, y2, distx, idistx, disty, idisty;
- uint32_t tl, tr, bl, br, r;
- uint32_t ft, fb;
-
- if (!affine) {
- pixman_fixed_48_16_t div;
- div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
- x1 = div >> 16;
- distx = ((pixman_fixed_t)div >> 8) & 0xff;
- div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
- y1 = div >> 16;
- disty = ((pixman_fixed_t)div >> 8) & 0xff;
- } else {
- x1 = v.vector[0] >> 16;
- distx = (v.vector[0] >> 8) & 0xff;
- y1 = v.vector[1] >> 16;
- disty = (v.vector[1] >> 8) & 0xff;
- }
- x2 = x1 + 1;
- y2 = y1 + 1;
-
- idistx = 256 - distx;
- idisty = 256 - disty;
-
- tl = pixman_region_contains_point(pict->common.src_clip, x1, y1, &box)
- ? fetch(pict, x1, y1) : 0;
- tr = pixman_region_contains_point(pict->common.src_clip, x2, y1, &box)
- ? fetch(pict, x2, y1) : 0;
- bl = pixman_region_contains_point(pict->common.src_clip, x1, y2, &box)
- ? fetch(pict, x1, y2) : 0;
- br = pixman_region_contains_point(pict->common.src_clip, x2, y2, &box)
- ? fetch(pict, x2, y2) : 0;
-
- ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
- fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
- r = (((ft * idisty + fb * disty) >> 16) & 0xff);
- ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
- fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
- r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
- ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
- fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
- r |= (((ft * idisty + fb * disty)) & 0xff0000);
- ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
- fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
- r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
- *(buffer + i) = r;
- }
- }
-
- v.vector[0] += unit.vector[0];
- v.vector[1] += unit.vector[1];
- v.vector[2] += unit.vector[2];
- }
- }
+ if (pict->common.repeat == PIXMAN_REPEAT_NORMAL)
+ {
+ fbFetchTransformed_Bilinear_Normal(pict, width, buffer, mask, maskBits, affine, v, unit);
+ }
+ else if (pict->common.repeat == PIXMAN_REPEAT_PAD)
+ {
+ fbFetchTransformed_Bilinear_Pad(pict, width, buffer, mask, maskBits, affine, v, unit);
}
- } else if (pict->common.filter == PIXMAN_FILTER_CONVOLUTION) {
- pixman_fixed_t *params = pict->common.filter_params;
- int32_t cwidth = pixman_fixed_to_int(params[0]);
- int32_t cheight = pixman_fixed_to_int(params[1]);
- int xoff = (params[0] - pixman_fixed_1) >> 1;
- int yoff = (params[1] - pixman_fixed_1) >> 1;
- params += 2;
- for (i = 0; i < width; ++i) {
- if (!mask || mask[i] & maskBits)
- {
- if (!v.vector[2]) {
- *(buffer + i) = 0;
- } else {
- int x1, x2, y1, y2, x, y;
- int32_t srtot, sgtot, sbtot, satot;
- pixman_fixed_t *p = params;
-
- if (!affine) {
- pixman_fixed_48_16_t tmp;
- tmp = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2] - xoff;
- x1 = pixman_fixed_to_int(tmp);
- tmp = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2] - yoff;
- y1 = pixman_fixed_to_int(tmp);
- } else {
- x1 = pixman_fixed_to_int(v.vector[0] - xoff);
- y1 = pixman_fixed_to_int(v.vector[1] - yoff);
- }
- x2 = x1 + cwidth;
- y2 = y1 + cheight;
-
- srtot = sgtot = sbtot = satot = 0;
-
- for (y = y1; y < y2; y++) {
- int ty = (pict->common.repeat == PIXMAN_REPEAT_NORMAL) ? MOD (y, pict->height) : y;
- for (x = x1; x < x2; x++) {
- if (*p) {
- int tx = (pict->common.repeat == PIXMAN_REPEAT_NORMAL) ? MOD (x, pict->width) : x;
- if (pixman_region_contains_point (pict->common.src_clip, tx, ty, &box)) {
- uint32_t c = fetch(pict, tx, ty);
-
- srtot += Red(c) * *p;
- sgtot += Green(c) * *p;
- sbtot += Blue(c) * *p;
- satot += Alpha(c) * *p;
- }
- }
- p++;
- }
- }
-
- satot >>= 16;
- srtot >>= 16;
- sgtot >>= 16;
- sbtot >>= 16;
-
- if (satot < 0) satot = 0; else if (satot > 0xff) satot = 0xff;
- if (srtot < 0) srtot = 0; else if (srtot > 0xff) srtot = 0xff;
- if (sgtot < 0) sgtot = 0; else if (sgtot > 0xff) sgtot = 0xff;
- if (sbtot < 0) sbtot = 0; else if (sbtot > 0xff) sbtot = 0xff;
-
- *(buffer + i) = ((satot << 24) |
- (srtot << 16) |
- (sgtot << 8) |
- (sbtot ));
- }
- }
- v.vector[0] += unit.vector[0];
- v.vector[1] += unit.vector[1];
- v.vector[2] += unit.vector[2];
+ else
+ {
+ fbFetchTransformed_Bilinear_General(pict, width, buffer, mask, maskBits, affine, v, unit);
}
}
+ else if (pict->common.filter == PIXMAN_FILTER_CONVOLUTION)
+ {
+ fbFetchTransformed_Convolution(pict, width, buffer, mask, maskBits, affine, v, unit);
+ }
fbFinishAccess (pict->pDrawable);
}
-static void fbFetchExternalAlpha(bits_image_t * pict, int x, int y, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits)
+static void
+fbFetchExternalAlpha(bits_image_t * pict, int x, int y, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits)
{
int i;
uint32_t _alpha_buffer[SCANLINE_BUFFER_LENGTH];
uint32_t *alpha_buffer = _alpha_buffer;
if (!pict->common.alpha_map) {
fbFetchTransformed (pict, x, y, width, buffer, mask, maskBits);
return;
@@ -4186,31 +4291,33 @@ static void fbFetchExternalAlpha(bits_im
| (div_255(Blue(*(buffer + i)) * a));
}
}
if (alpha_buffer != _alpha_buffer)
free(alpha_buffer);
}
-static void fbStore(bits_image_t * pict, int x, int y, int width, uint32_t *buffer)
+static void
+fbStore(bits_image_t * pict, int x, int y, int width, uint32_t *buffer)
{
uint32_t *bits;
int32_t stride;
storeProc store = storeProcForPicture(pict);
const pixman_indexed_t * indexed = pict->indexed;
bits = pict->bits;
stride = pict->rowstride;
bits += y*stride;
store((pixman_image_t *)pict, bits, buffer, x, width, indexed);
fbFinishAccess (pict->pDrawable);
}
-static void fbStoreExternalAlpha(bits_image_t * pict, int x, int y, int width, uint32_t *buffer)
+static void
+fbStoreExternalAlpha(bits_image_t * pict, int x, int y, int width, uint32_t *buffer)
{
uint32_t *bits, *alpha_bits;
int32_t stride, astride;
int ax, ay;
storeProc store;
storeProc astore;
const pixman_indexed_t * indexed = pict->indexed;
const pixman_indexed_t * aindexed;
@@ -4279,17 +4386,17 @@ PIXMAN_COMPOSITE_RECT_GENERAL (const FbC
else
{
bits_image_t *bits = (bits_image_t *)data->src;
if (bits->common.alpha_map)
{
fetchSrc = (scanFetchProc)fbFetchExternalAlpha;
}
- else if (bits->common.repeat == PIXMAN_REPEAT_NORMAL &&
+ else if ((bits->common.repeat == PIXMAN_REPEAT_NORMAL || bits->common.repeat == PIXMAN_REPEAT_PAD) &&
bits->width == 1 &&
bits->height == 1)
{
fetchSrc = (scanFetchProc)fbFetchSolid;
srcClass = SOURCE_IMAGE_CLASS_HORIZONTAL;
}
else if (!bits->common.transform && bits->common.filter != PIXMAN_FILTER_CONVOLUTION)
{
@@ -4317,17 +4424,17 @@ PIXMAN_COMPOSITE_RECT_GENERAL (const FbC
else
{
bits_image_t *bits = (bits_image_t *)data->mask;
if (bits->common.alpha_map)
{
fetchMask = (scanFetchProc)fbFetchExternalAlpha;
}
- else if (bits->common.repeat == PIXMAN_REPEAT_NORMAL &&
+ else if ((bits->common.repeat == PIXMAN_REPEAT_NORMAL || bits->common.repeat == PIXMAN_REPEAT_PAD) &&
bits->width == 1 && bits->height == 1)
{
fetchMask = (scanFetchProc)fbFetchSolid;
maskClass = SOURCE_IMAGE_CLASS_HORIZONTAL;
}
else if (!bits->common.transform && bits->common.filter != PIXMAN_FILTER_CONVOLUTION)
fetchMask = (scanFetchProc)fbFetch;
else
--- a/gfx/cairo/libpixman/src/pixman-private.h
+++ b/gfx/cairo/libpixman/src/pixman-private.h
@@ -597,16 +597,18 @@ union pixman_image
#define div_255(x) (((x) + 0x80 + (((x) + 0x80) >> 8)) >> 8)
#define MOD(a,b) ((a) < 0 ? ((b) - ((-(a) - 1) % (b))) - 1 : (a) % (b))
#define DIV(a,b) ((((a) < 0) == ((b) < 0)) ? (a) / (b) : \
((a) - (b) + 1 - (((b) < 0) << 1)) / (b))
+#define CLIP(a,b,c) ((a) < (b) ? (b) : ((a) > (c) ? (c) : (a)))
+
#if 0
/* FIXME: the MOD macro above is equivalent, but faster I think */
#define mod(a,b) ((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
#endif
/* FIXME: the (void)__read_func hides lots of warnings (which is what they
* are supposed to do), but some of them are real. For example the one
* where Fetch4 doesn't have a READ