b=446323, Upgrade cairo to 1.6.4-350-g1a9809b; r=vlad

This commit is contained in:
Vladimir Vukicevic 2008-07-20 14:15:22 -07:00
parent a7a7988949
commit 87718e129a
138 changed files with 16988 additions and 3916 deletions

View File

@ -196,6 +196,7 @@ FixMath.h
float.h
Folders.h
fontconfig/fontconfig.h
fontconfig/fcfreetype.h
Font.h
Fonts.h
fp.h

View File

@ -7,9 +7,8 @@ http://www.cairographics.org/.
VERSIONS:
cairo (1.6.4 - 1.6.4)
pixman (0.10.x - pixman-0.10.0-8-g0b207ae)
glitz 0.5.2 (cvs - 2006-01-10)
cairo (1.6.4-350-g1a9809b)
pixman (pixman-0.11.8-7-gdb3fb5e)
***** NOTE FOR VISUAL C++ 6.0 *****
@ -19,21 +18,6 @@ VC6 is not supported. Please upgrade to VC8.
Some specific things:
cairo git commit ea6dbfd36f2182fda16cb82bca92007e0f7b8d77 -
[cairo-meta-surface] Save and restore the original clip.
cairo git commit d96fdd58abf8d6c8692dbb08ec54cdd80accba79 -
win32: Fix broken printing of type1 fonts
cairo git commit 547e2f552cff264b943803d3a1ff03d05bde35c0
Fix win32-printing show_glyphs analysis for Type 1 fonts
cairo git commit 158d24412bba99a4f57907d7fd22a86aae6e87af
Make win32-printing surface work with bitmap fonts
cairo git commit d35d6eec24c1b7ab0a49149a51bf65ea8e223203
Fix win32 bitmap font metrics when device scale != 1
max-font-size.patch: Clamp freetype font size to 1000 to avoid overflow issues
win32-logical-font-scale.patch: set CAIRO_WIN32_LOGICAL_FONT_SCALE to 1
@ -42,10 +26,6 @@ nonfatal-assertions.patch: Make assertions non-fatal
buggy-repeat.patch: Unconditionally turn on buggy-repeat handling to bandaid bug 413583.
clip-clone.patch: _cairo_clip_init_deep_copy should pass 0,0 as the
source coordinates to clone from since it wants an exact copy of the
source's clipping surface
==== pixman patches ====
endian.patch: include cairo-platform.h for endian macros

View File

@ -118,6 +118,7 @@ CSRCS = \
cairo-surface-fallback.c \
cairo-traps.c \
cairo-unicode.c \
cairo-user-font.c \
cairo-wideint.c \
$(NULL)
@ -128,6 +129,7 @@ EXPORTS = cairo.h cairo-features.h cairo-platform.h cairo-deprecated.h cairo-ren
PSPDF_BASE_CSRCS = \
cairo-base85-stream.c \
cairo-type1-fallback.c \
cairo-type3-glyph-surface.c \
cairo-truetype-subset.c \
cairo-cff-subset.c \
$(NULL)

View File

@ -42,6 +42,14 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
int width,
int height);
cairo_private void
_cairo_analysis_surface_set_ctm (cairo_surface_t *surface,
cairo_matrix_t *ctm);
cairo_private void
_cairo_analysis_surface_get_ctm (cairo_surface_t *surface,
cairo_matrix_t *ctm);
cairo_private cairo_region_t *
_cairo_analysis_surface_get_supported (cairo_surface_t *surface);
@ -58,4 +66,8 @@ cairo_private void
_cairo_analysis_surface_get_bounding_box (cairo_surface_t *surface,
cairo_box_t *bbox);
cairo_private cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content);
#endif /* CAIRO_ANALYSIS_SURFACE_H */

View File

@ -84,7 +84,7 @@ _cairo_analysis_surface_analyze_meta_surface_pattern (cairo_analysis_surface_t *
old_height = surface->height;
old_clip = surface->current_clip;
status = _cairo_surface_get_extents (surface_pattern->surface, &meta_extents);
if (status)
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
surface->width = meta_extents.width;
@ -140,22 +140,13 @@ _cairo_analysis_surface_add_operation (cairo_analysis_surface_t *surface,
}
}
_cairo_box_from_rectangle (&bbox, rect);
if (surface->has_ctm) {
double x1, y1, x2, y2;
x1 = rect->x;
y1 = rect->y;
x2 = rect->x + rect->width;
y2 = rect->y + rect->height;
_cairo_matrix_transform_bounding_box (&surface->ctm,
&x1, &y1, &x2, &y2,
NULL);
rect->x = floor (x1);
rect->y = floor (y1);
_cairo_matrix_transform_bounding_box_fixed (&surface->ctm, &bbox, NULL);
x2 = ceil (x2) - rect->x;
y2 = ceil (y2) - rect->y;
if (x2 <= 0 || y2 <= 0) {
if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
/* Even though the operation is not visible we must be
* careful to not allow unsupported operations to be
* replayed to the backend during
@ -171,15 +162,9 @@ _cairo_analysis_surface_add_operation (cairo_analysis_surface_t *surface,
}
}
rect->width = x2;
rect->height = y2;
_cairo_box_round_to_rectangle (&bbox, rect);
}
bbox.p1.x = _cairo_fixed_from_int (rect->x);
bbox.p1.y = _cairo_fixed_from_int (rect->y);
bbox.p2.x = _cairo_fixed_from_int (rect->x + rect->width);
bbox.p2.y = _cairo_fixed_from_int (rect->y + rect->height);
if (surface->first_op) {
surface->first_op = FALSE;
surface->page_bbox = bbox;
@ -253,6 +238,8 @@ _cairo_analysis_surface_finish (void *abstract_surface)
_cairo_region_fini (&surface->supported_region);
_cairo_region_fini (&surface->fallback_region);
cairo_surface_destroy (surface->target);
return CAIRO_STATUS_SUCCESS;
}
@ -319,7 +306,7 @@ _cairo_analysis_surface_paint (void *abstract_surface,
source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status)
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
@ -377,7 +364,7 @@ _cairo_analysis_surface_mask (void *abstract_surface,
}
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status)
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
@ -432,7 +419,7 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status)
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
@ -511,7 +498,7 @@ _cairo_analysis_surface_fill (void *abstract_surface,
source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status)
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
@ -569,26 +556,120 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_rectangle_int_t extents, glyph_extents;
if (!surface->target->backend->show_glyphs)
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
/* Adapted from _cairo_surface_show_glyphs */
if (surface->target->backend->show_glyphs)
backend_status = (*surface->target->backend->show_glyphs) (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font);
source,
glyphs, num_glyphs,
scaled_font,
remaining_glyphs);
else if (surface->target->backend->show_text_glyphs)
backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
source,
NULL, 0,
glyphs, num_glyphs,
NULL, 0,
FALSE,
scaled_font);
else
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status)
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (status)
return status;
_cairo_rectangle_intersect (&extents, &source_extents);
}
_cairo_rectangle_intersect (&extents, &surface->current_clip);
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs,
num_glyphs,
&glyph_extents);
if (status)
return status;
_cairo_rectangle_intersect (&extents, &glyph_extents);
}
status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
return status;
}
static cairo_bool_t
_cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface)
{
cairo_analysis_surface_t *surface = abstract_surface;
return _cairo_surface_has_show_text_glyphs (surface->target);
}
static cairo_int_status_t
_cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_rectangle_int_t extents, glyph_extents;
/* Adapted from _cairo_surface_show_glyphs */
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->target->backend->show_text_glyphs)
backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
backward,
scaled_font);
if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && surface->target->backend->show_glyphs) {
int remaining_glyphs = num_glyphs;
backend_status = surface->target->backend->show_glyphs (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
&remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
backend_status = CAIRO_STATUS_SUCCESS;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
@ -650,6 +731,9 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
_cairo_analysis_surface_has_show_text_glyphs,
_cairo_analysis_surface_show_text_glyphs
};
cairo_surface_t *
@ -673,21 +757,54 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
cairo_matrix_init_identity (&surface->ctm);
surface->has_ctm = FALSE;
surface->target = target;
surface->target = cairo_surface_reference (target);
surface->first_op = TRUE;
surface->has_supported = FALSE;
surface->has_unsupported = FALSE;
surface->page_bbox.p1.x = 0;
surface->page_bbox.p1.y = 0;
surface->page_bbox.p2.x = 0;
surface->page_bbox.p2.y = 0;
_cairo_region_init (&surface->supported_region);
_cairo_region_init (&surface->fallback_region);
surface->current_clip.x = 0;
surface->current_clip.y = 0;
surface->current_clip.width = width;
surface->current_clip.height = height;
if (width == -1 && height == -1) {
surface->current_clip.x = CAIRO_RECT_INT_MIN;
surface->current_clip.y = CAIRO_RECT_INT_MIN;
surface->current_clip.width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
surface->current_clip.height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
} else {
surface->current_clip.x = 0;
surface->current_clip.y = 0;
surface->current_clip.width = width;
surface->current_clip.height = height;
}
return &surface->base;
}
cairo_private void
_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
cairo_matrix_t *ctm)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
surface->ctm = *ctm;
surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
}
cairo_private void
_cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface,
cairo_matrix_t *ctm)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
*ctm = surface->ctm;
}
cairo_region_t *
_cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
{
@ -728,3 +845,108 @@ _cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
*bbox = surface->page_bbox;
}
/* null surface type: a surface that does nothing (has no side effects, yay!) */
static cairo_int_status_t
_return_success (void)
{
return CAIRO_STATUS_SUCCESS;
}
/* These typedefs are just to silence the compiler... */
typedef cairo_int_status_t
(*_set_clip_region_func) (void *surface,
cairo_region_t *region);
typedef cairo_int_status_t
(*_paint_func) (void *surface,
cairo_operator_t op,
cairo_pattern_t *source);
typedef cairo_int_status_t
(*_mask_func) (void *surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_pattern_t *mask);
typedef cairo_int_status_t
(*_stroke_func) (void *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);
typedef cairo_int_status_t
(*_fill_func) (void *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);
typedef cairo_int_status_t
(*_show_glyphs_func) (void *surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs);
static const cairo_surface_backend_t cairo_null_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
NULL, /* create_similar */
NULL, /* finish */
NULL, /* acquire_source_image */
NULL, /* release_source_image */
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* copy_page */
NULL, /* show_page */
(_set_clip_region_func) _return_success, /* set_clip_region */
NULL, /* intersect_clip_path */
NULL, /* get_extents */
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
(_paint_func) _return_success, /* paint */
(_mask_func) _return_success, /* mask */
(_stroke_func) _return_success, /* stroke */
(_fill_func) _return_success, /* fill */
(_show_glyphs_func) _return_success, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* has_show_text_glyphs */
NULL /* show_text_glyphs */
};
cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content)
{
cairo_surface_t *surface;
surface = malloc (sizeof (cairo_surface_t));
if (surface == NULL) {
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
_cairo_surface_init (surface, &cairo_null_surface_backend, content);
return surface;
}

View File

@ -181,13 +181,15 @@ _cairo_arc_in_direction (cairo_t *cr,
double angle_max,
cairo_direction_t dir)
{
if (cairo_status (cr))
return;
while (angle_max - angle_min > 4 * M_PI)
angle_max -= 2 * M_PI;
/* Recurse if drawing arc larger than pi */
if (angle_max - angle_min > M_PI) {
double angle_mid = angle_min + (angle_max - angle_min) / 2.0;
/* XXX: Something tells me this block could be condensed. */
if (dir == CAIRO_DIRECTION_FORWARD) {
_cairo_arc_in_direction (cr, xc, yc, radius,
angle_min, angle_mid,
@ -205,7 +207,7 @@ _cairo_arc_in_direction (cairo_t *cr,
angle_min, angle_mid,
dir);
}
} else {
} else if (angle_max != angle_min) {
cairo_matrix_t ctm;
int i, segments;
double angle, angle_step;

View File

@ -236,7 +236,7 @@ _cairo_array_copy_element (cairo_array_t *array, int index, void *dst)
* _cairo_array_index (array, _cairo_array_num_elements (array) - 1);
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t
@ -256,7 +256,7 @@ _cairo_array_append (cairo_array_t *array,
* @elements into the array.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t
@ -287,7 +287,7 @@ _cairo_array_append_multiple (cairo_array_t *array,
* for in the return value of _cairo_array_num_elements().
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t

View File

@ -1,4 +1,5 @@
/* cairo_output_stream.c: Output stream abstraction
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*

View File

@ -508,7 +508,7 @@ det64_128 (cairo_int64_t a,
* result is provided as a coordinate pair of 128-bit integers.
*
* Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or
* CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel.
* %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel.
*/
static cairo_bo_status_t
intersect_lines (cairo_bo_edge_t *a,
@ -1214,7 +1214,7 @@ _active_edges_to_traps (cairo_bo_edge_t *head,
int in_out = 0;
cairo_bo_edge_t *edge;
for (edge = head; edge && edge->next; edge = edge->next) {
for (edge = head; edge; edge = edge->next) {
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
if (edge->reversed)
in_out++;
@ -1415,9 +1415,9 @@ update_minmax(cairo_fixed_t *inout_min,
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule)
_cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
const cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule)
{
int intersections;
cairo_status_t status;

View File

@ -36,7 +36,7 @@
#ifndef CAIRO_BEOS_H
#define CAIRO_BEOS_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_BEOS_SURFACE

View File

@ -296,7 +296,7 @@ _cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
* entry_destroy() callback will be called on it).
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
**/
cairo_status_t
_cairo_cache_insert (cairo_cache_t *cache,

View File

@ -274,13 +274,13 @@ _cairo_clip_combine_to_surface (cairo_clip_t *clip,
int dst_y,
const cairo_rectangle_int_t *extents)
{
cairo_pattern_union_t pattern;
cairo_surface_pattern_t pattern;
cairo_status_t status;
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
_cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
_cairo_pattern_init_for_surface (&pattern, clip->surface);
status = _cairo_surface_composite (op,
&pattern.base,
@ -485,8 +485,7 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip,
CAIRO_CONTENT_ALPHA,
surface_rect.width,
surface_rect.height,
CAIRO_COLOR_TRANSPARENT,
&pattern.base);
CAIRO_COLOR_TRANSPARENT);
if (surface->status) {
_cairo_pattern_fini (&pattern.base);
return surface->status;
@ -630,7 +629,7 @@ _cairo_clip_translate (cairo_clip_t *clip,
_cairo_fixed_to_double (ty));
while (clip_path) {
_cairo_path_fixed_device_transform (&clip_path->path, &matrix);
_cairo_path_fixed_transform (&clip_path->path, &matrix);
clip_path = clip_path->prev;
}
}
@ -678,7 +677,8 @@ _cairo_clip_init_deep_copy (cairo_clip_t *clip,
if (other->surface) {
status = _cairo_surface_clone_similar (target, other->surface,
0, 0,
0,
0,
other->surface_rect.width,
other->surface_rect.height,
&clip->surface);

View File

@ -111,7 +111,7 @@ CAIRO_BEGIN_DECLS
#define __attribute__(x)
#endif
#if defined(__WIN32__) || defined(_MSC_VER)
#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
#define snprintf _snprintf
#endif

View File

@ -61,15 +61,15 @@ cairo_debug_reset_static_data (void)
{
CAIRO_MUTEX_INITIALIZE ();
_cairo_font_reset_static_data ();
_cairo_font_face_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_pattern_reset_static_data ();
CAIRO_MUTEX_FINALIZE ();
}

View File

@ -1,4 +1,5 @@
/* cairo_deflate_stream.c: Output stream abstraction
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006 Adrian Johnson
*

View File

@ -52,8 +52,6 @@
#define CAIRO_FONT_TYPE_ATSUI CAIRO_FONT_TYPE_QUARTZ
#ifndef _CAIROINT_H_
/* Obsolete functions. These definitions exist to coerce the compiler
* into providing a little bit of guidance with its error
* messages. The idea is to help users port their old code without
@ -137,6 +135,4 @@
#define cairo_get_status_string cairo_get_status_string_DEPRECATED_BY_cairo_status_AND_cairo_status_to_string
#define cairo_status_string cairo_status_string_DEPRECATED_BY_cairo_status_AND_cairo_status_to_string
#endif
#endif /* CAIRO_DEPRECATED_H */

View File

@ -1606,7 +1606,8 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst,
cairo_pattern_t *pattern,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs)
{
cairo_directfb_surface_t *dst = abstract_dst;
cairo_directfb_font_cache_t *cache;

View File

@ -47,7 +47,7 @@
#ifndef CAIRO_DIRECTFB_H
#define CAIRO_DIRECTFB_H
#include <cairo.h>
#include "cairo.h"
#ifdef CAIRO_HAS_DIRECTFB_SURFACE

View File

@ -226,6 +226,17 @@ _cairo_fixed_mul (cairo_fixed_t a, cairo_fixed_t b)
return _cairo_int64_to_int32(_cairo_int64_rsl (temp, CAIRO_FIXED_FRAC_BITS));
}
/* computes a * b / c */
static inline cairo_fixed_t
_cairo_fixed_mul_div (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
{
cairo_int64_t ab = _cairo_int32x32_64_mul (a, b);
cairo_int64_t c64 = _cairo_int32_to_int64 (c);
cairo_int64_t quo = _cairo_int64_divrem (ab, c64).quo;
return _cairo_int64_to_int32(quo);
}
#else
# error Please define multiplication and other operands for your fixed-point type size
#endif

View File

@ -63,6 +63,8 @@ _cairo_font_face_set_error (cairo_font_face_t *font_face,
if (status == CAIRO_STATUS_SUCCESS)
return status;
/* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&font_face->status, status);
return _cairo_error (status);
@ -132,7 +134,8 @@ cairo_font_face_destroy (cairo_font_face_t *font_face)
if (! _cairo_reference_count_dec_and_test (&font_face->ref_count))
return;
font_face->backend->destroy (font_face);
if (font_face->backend->destroy)
font_face->backend->destroy (font_face);
/* We allow resurrection to deal with some memory management for the
* FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t
@ -534,7 +537,7 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font)
}
void
_cairo_font_reset_static_data (void)
_cairo_font_face_reset_static_data (void)
{
_cairo_scaled_font_map_destroy ();

View File

@ -95,7 +95,6 @@ cairo_font_options_create (void)
return options;
}
slim_hidden_def (cairo_font_options_create);
/**
* cairo_font_options_copy:
@ -144,7 +143,6 @@ cairo_font_options_destroy (cairo_font_options_t *options)
free (options);
}
slim_hidden_def (cairo_font_options_destroy);
/**
* cairo_font_options_status:

View File

@ -1,3 +1,4 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2000 Keith Packard
@ -91,7 +92,7 @@ typedef struct _cairo_ft_font_face cairo_ft_font_face_t;
struct _cairo_ft_unscaled_font {
cairo_unscaled_font_t base;
cairo_bool_t from_face; /* from cairo_ft_font_face_create_for_ft_face()? */
cairo_bool_t from_face; /* was the FT_Face provided by user? */
FT_Face face; /* provided or cached face */
/* only set if from_face is false */
@ -282,17 +283,22 @@ _cairo_ft_unscaled_font_map_unlock (void)
static void
_cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key,
cairo_bool_t from_face,
char *filename,
int id)
int id,
FT_Face face)
{
unsigned long hash;
key->from_face = from_face;
key->filename = filename;
key->id = id;
key->face = face;
/* 1607 is just an arbitrary prime. */
hash = _cairo_hash_string (filename);
/* the constants are just arbitrary primes */
hash += ((unsigned long) id) * 1607;
hash += ((unsigned long) face) * 2137;
key->base.hash_entry.hash = hash;
}
@ -320,6 +326,7 @@ _cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key,
**/
static cairo_status_t
_cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
cairo_bool_t from_face,
const char *filename,
int id,
FT_Face face)
@ -327,11 +334,9 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
_cairo_unscaled_font_init (&unscaled->base,
&cairo_ft_unscaled_font_backend);
if (face) {
if (from_face) {
unscaled->from_face = TRUE;
unscaled->face = face;
unscaled->filename = NULL;
unscaled->id = 0;
_cairo_ft_unscaled_font_init_key (unscaled, TRUE, NULL, 0, face);
} else {
char *filename_copy;
@ -341,8 +346,7 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
filename_copy = strdup (filename);
if (filename_copy == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_ft_unscaled_font_init_key (unscaled, filename_copy, id);
_cairo_ft_unscaled_font_init_key (unscaled, FALSE, filename_copy, id, NULL);
}
unscaled->have_scale = FALSE;
@ -354,12 +358,6 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
return CAIRO_STATUS_SUCCESS;
}
cairo_bool_t
_cairo_unscaled_font_is_ft (cairo_unscaled_font_t *unscaled_font)
{
return unscaled_font->backend == &cairo_ft_unscaled_font_backend;
}
/**
* _cairo_ft_unscaled_font_fini:
*
@ -391,35 +389,41 @@ _cairo_ft_unscaled_font_keys_equal (const void *key_a,
const cairo_ft_unscaled_font_t *unscaled_a = key_a;
const cairo_ft_unscaled_font_t *unscaled_b = key_b;
return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0 &&
unscaled_a->id == unscaled_b->id);
if (unscaled_a->id == unscaled_b->id &&
unscaled_a->from_face == unscaled_b->from_face)
{
if (unscaled_a->from_face)
return unscaled_a->face == unscaled_b->face;
if (unscaled_a->filename == NULL && unscaled_b->filename == NULL)
return TRUE;
else if (unscaled_a->filename == NULL || unscaled_b->filename == NULL)
return FALSE;
else
return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0);
}
return FALSE;
}
/* Finds or creates a #cairo_ft_unscaled_font_t for the filename/id from
* pattern. Returns a new reference to the unscaled font.
*/
static cairo_ft_unscaled_font_t *
_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern)
_cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face,
char *filename,
int id,
FT_Face font_face)
{
cairo_ft_unscaled_font_t key, *unscaled;
cairo_ft_unscaled_font_map_t *font_map;
cairo_status_t status;
FcChar8 *fc_filename;
char *filename;
int id;
if (FcPatternGetString (pattern, FC_FILE, 0, &fc_filename) != FcResultMatch)
goto UNWIND;
filename = (char *) fc_filename;
if (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch)
goto UNWIND;
font_map = _cairo_ft_unscaled_font_map_lock ();
if (font_map == NULL)
goto UNWIND;
_cairo_ft_unscaled_font_init_key (&key, filename, id);
_cairo_ft_unscaled_font_init_key (&key, from_face, filename, id, font_face);
/* Return existing unscaled font if it exists in the hash table. */
if (_cairo_hash_table_lookup (font_map->hash_table, &key.base.hash_entry,
@ -437,7 +441,7 @@ _cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern)
goto UNWIND_FONT_MAP_LOCK;
}
status = _cairo_ft_unscaled_font_init (unscaled, filename, id, NULL);
status = _cairo_ft_unscaled_font_init (unscaled, from_face, filename, id, font_face);
if (status)
goto UNWIND_UNSCALED_MALLOC;
@ -460,57 +464,66 @@ UNWIND:
return NULL;
}
static cairo_ft_unscaled_font_t *
_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern)
{
FT_Face font_face = NULL;
char *filename = NULL;
int id = 0;
if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &font_face) != FcResultMatch) {
FcChar8 *fc_filename = NULL;
if (FcPatternGetString (pattern, FC_FILE, 0, &fc_filename) != FcResultMatch)
goto UNWIND;
filename = (char *) fc_filename;
if (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch)
goto UNWIND;
}
return _cairo_ft_unscaled_font_create_internal (font_face != NULL, filename, id, font_face);
UNWIND:
return NULL;
}
static cairo_ft_unscaled_font_t *
_cairo_ft_unscaled_font_create_from_face (FT_Face face)
{
cairo_status_t status;
cairo_ft_unscaled_font_t *unscaled;
unscaled = malloc (sizeof (cairo_ft_unscaled_font_t));
if (unscaled == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
status = _cairo_ft_unscaled_font_init (unscaled, NULL, 0, face);
if (status) {
free (unscaled);
return NULL;
}
return unscaled;
return _cairo_ft_unscaled_font_create_internal (TRUE, NULL, 0, face);
}
static void
_cairo_ft_unscaled_font_destroy (void *abstract_font)
{
cairo_ft_unscaled_font_t *unscaled = abstract_font;
cairo_ft_unscaled_font_map_t *font_map;
if (unscaled == NULL)
return;
font_map = _cairo_ft_unscaled_font_map_lock ();
/* All created objects must have been mapped in the font map. */
assert (font_map != NULL);
_cairo_hash_table_remove (font_map->hash_table,
&unscaled->base.hash_entry);
if (unscaled->from_face) {
/* See comments in _ft_font_face_destroy about the "zombie" state
* for a _ft_font_face.
*/
if (unscaled->faces && !unscaled->faces->unscaled)
cairo_font_face_destroy (&unscaled->faces->base);
unscaled->face = NULL;
} else {
cairo_ft_unscaled_font_map_t *font_map;
font_map = _cairo_ft_unscaled_font_map_lock ();
/* All created objects must have been mapped in the font map. */
assert (font_map != NULL);
_cairo_hash_table_remove (font_map->hash_table,
&unscaled->base.hash_entry);
_font_map_release_face_lock_held (font_map, unscaled);
_cairo_ft_unscaled_font_map_unlock ();
}
unscaled->face = NULL;
_cairo_ft_unscaled_font_map_unlock ();
_cairo_ft_unscaled_font_fini (unscaled);
}
@ -579,7 +592,7 @@ _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled)
return face;
}
slim_hidden_def (cairo_ft_scaled_font_lock_face);
/* Unlock unscaled font locked with _cairo_ft_unscaled_font_lock_face
*/
@ -592,7 +605,7 @@ _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled)
CAIRO_MUTEX_UNLOCK (unscaled->mutex);
}
slim_hidden_def (cairo_ft_scaled_font_unlock_face);
static cairo_status_t
_compute_transform (cairo_ft_font_transform_t *sf,
@ -611,7 +624,7 @@ _compute_transform (cairo_ft_font_transform_t *sf,
status = _cairo_matrix_compute_scale_factors (scale,
&x_scale, &y_scale,
/* XXX */ 1);
1);
if (status)
return status;
@ -1274,7 +1287,7 @@ typedef struct _cairo_ft_scaled_font {
cairo_ft_options_t ft_options;
} cairo_ft_scaled_font_t;
const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend;
const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend;
/* The load flags passed to FT_Load_Glyph control aspects like hinting and
* antialiasing. Here we compute them from the fields of a FcPattern.
@ -1519,7 +1532,7 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled,
status = _cairo_scaled_font_init (&scaled_font->base,
font_face,
font_matrix, ctm, options,
&cairo_ft_scaled_font_backend);
&_cairo_ft_scaled_font_backend);
if (status) {
_cairo_unscaled_font_destroy (&unscaled->base);
free (scaled_font);
@ -1597,7 +1610,7 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled,
cairo_bool_t
_cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font)
{
return scaled_font->backend == &cairo_ft_scaled_font_backend;
return scaled_font->backend == &_cairo_ft_scaled_font_backend;
}
static cairo_status_t
@ -2169,40 +2182,36 @@ _cairo_ft_load_truetype_table (void *abstract_font,
}
static cairo_int_status_t
_cairo_ft_map_glyphs_to_unicode (void *abstract_font,
cairo_scaled_font_subset_t *font_subset)
_cairo_ft_index_to_ucs4(void *abstract_font,
unsigned long index,
uint32_t *ucs4)
{
cairo_ft_scaled_font_t *scaled_font = abstract_font;
cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
FT_Face face;
FT_UInt glyph;
unsigned long charcode;
unsigned int i;
int count;
FT_ULong charcode;
FT_UInt gindex;
face = _cairo_ft_unscaled_font_lock_face (unscaled);
if (!face)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
count = font_subset->num_glyphs;
charcode = FT_Get_First_Char( face, &glyph);
while (glyph != 0 && count > 0)
{
for (i = 0; i < font_subset->num_glyphs; i++) {
if (font_subset->glyphs[i] == glyph) {
font_subset->to_unicode[i] = charcode;
count--;
break;
}
}
charcode = FT_Get_Next_Char (face, charcode, &glyph);
*ucs4 = (uint32_t) -1;
charcode = FT_Get_First_Char(face, &gindex);
while (gindex != 0) {
charcode = FT_Get_Next_Char (face, charcode, &gindex);
if (gindex == index) {
*ucs4 = charcode;
break;
}
}
_cairo_ft_unscaled_font_unlock_face (unscaled);
return CAIRO_STATUS_SUCCESS;
}
const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = {
const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = {
CAIRO_FONT_TYPE_FT,
_cairo_ft_scaled_font_create_toy,
_cairo_ft_scaled_font_fini,
@ -2211,7 +2220,7 @@ const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = {
_cairo_ft_ucs4_to_index,
NULL, /* show_glyphs */
_cairo_ft_load_truetype_table,
_cairo_ft_map_glyphs_to_unicode,
_cairo_ft_index_to_ucs4
};
/* #cairo_ft_font_face_t */
@ -2292,6 +2301,10 @@ _cairo_ft_font_face_scaled_font_create (void *abstract_face,
* derived from a pattern where the user has called
* cairo_ft_font_options_substitute(), so *just* use those load
* flags and ignore the options.
*
* XXX two points about the above comment:
* 1. I don't see how the comment is relevant here,
* 2. What if the face is coming from FC_FT_FACE of a pattern?
*/
ft_options = font_face->ft_options;
@ -2487,7 +2500,7 @@ cairo_ft_font_options_substitute (const cairo_font_options_t *options,
* cairo_set_font_face() or cairo_scaled_font_create(). The
* #cairo_scaled_font_t returned from cairo_scaled_font_create() is
* also for the FreeType backend and can be used with functions such
* as cairo_ft_font_lock_face().
* as cairo_ft_scaled_font_lock_face().
*
* Font rendering options are represented both here and when you
* call cairo_scaled_font_create(). Font options that have a representation
@ -2495,6 +2508,17 @@ cairo_ft_font_options_substitute (const cairo_font_options_t *options,
* appropriately to reflect the options in a #cairo_font_options_t, call
* cairo_ft_font_options_substitute().
*
* The pattern's FC_FT_FACE element is inspected first and if that is set,
* that will be the FreeType font face associated with the returned cairo
* font face. Otherwise the FC_FILE and FC_INDEX elements of @pattern are
* used to load a font face from file.
*
* If the FC_FT_FACE element of @pattern is set, the user is responsible
* for making sure that the referenced FT_Face remains valid for the life
* time of the returned #cairo_font_face_t. See
* cairo_ft_font_face_create_for_ft_face() for an exmaple of how to couple
* the life time of the FT_Face to that of the cairo font-face.
*
* Return value: a newly created #cairo_font_face_t. Free with
* cairo_font_face_destroy() when you are done using it.
**/
@ -2539,7 +2563,23 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
* cairo_set_font_face() or cairo_scaled_font_create(). The
* #cairo_scaled_font_t returned from cairo_scaled_font_create() is
* also for the FreeType backend and can be used with functions such
* as cairo_ft_font_lock_face().
* as cairo_ft_scaled_font_lock_face().
*
* As an example, here is how one might correctly couple the lifetime of
* the FreeType face object to the #cairo_font_face_t:
*
* <informalexample><programlisting>
* static const cairo_user_data_key_t key;
*
* font_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
* status = cairo_font_face_set_user_data (font_face, &key,
* ft_face, (cairo_destroy_func_t) FT_Done_Face);
* if (status) {
* cairo_font_face_destroy (font_face);
* FT_Done_Face (ft_face);
* return ERROR;
* }
* </programlisting></informalexample>
*
* Return value: a newly created #cairo_font_face_t. Free with
* cairo_font_face_destroy() when you are done using it.
@ -2573,16 +2613,16 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face,
* @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an
* object can be created by calling cairo_scaled_font_create() on a
* FreeType backend font face (see cairo_ft_font_face_create_for_pattern(),
* cairo_ft_font_face_create_for_face()).
* cairo_ft_font_face_create_for_ft_face()).
*
* cairo_ft_font_lock_face() gets the #FT_Face object from a FreeType
* cairo_ft_scaled_font_lock_face() gets the #FT_Face object from a FreeType
* backend font and scales it appropriately for the font. You must
* release the face with cairo_ft_font_unlock_face()
* release the face with cairo_ft_scaled_font_unlock_face()
* when you are done using it. Since the #FT_Face object can be
* shared between multiple #cairo_scaled_font_t objects, you must not
* lock any other font objects until you unlock this one. A count is
* kept of the number of times cairo_ft_font_lock_face() is
* called. cairo_ft_font_unlock_face() must be called the same number
* kept of the number of times cairo_ft_scaled_font_lock_face() is
* called. cairo_ft_scaled_font_unlock_face() must be called the same number
* of times.
*
* You must be careful when using this function in a library or in a
@ -2605,6 +2645,11 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font)
FT_Face face;
cairo_status_t status;
if (! _cairo_scaled_font_is_ft (abstract_font)) {
_cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH);
return NULL;
}
if (scaled_font->base.status)
return NULL;
@ -2647,6 +2692,11 @@ cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *abstract_font)
{
cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
if (! _cairo_scaled_font_is_ft (abstract_font)) {
_cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH);
return;
}
if (scaled_font->base.status)
return;

View File

@ -37,8 +37,8 @@
#ifndef CAIRO_FT_PRIVATE_H
#define CAIRO_FT_PRIVATE_H
#include <cairo-ft.h>
#include <cairoint.h>
#include "cairo-ft.h"
#include "cairoint.h"
#if CAIRO_HAS_FT_FONT
@ -46,9 +46,6 @@ CAIRO_BEGIN_DECLS
typedef struct _cairo_ft_unscaled_font cairo_ft_unscaled_font_t;
cairo_private cairo_bool_t
_cairo_unscaled_font_is_ft (cairo_unscaled_font_t *unscaled_font);
cairo_private cairo_bool_t
_cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font);
@ -67,9 +64,6 @@ _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled);
cairo_private cairo_bool_t
_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font);
slim_hidden_proto (cairo_ft_scaled_font_lock_face);
slim_hidden_proto (cairo_ft_scaled_font_unlock_face);
CAIRO_END_DECLS
#endif /* CAIRO_HAS_FT_FONT */

View File

@ -37,7 +37,7 @@
#ifndef CAIRO_FT_H
#define CAIRO_FT_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_FT_FONT

View File

@ -958,7 +958,7 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src,
cairo_glitz_surface_attributes_t *mattr)
{
cairo_int_status_t status;
cairo_pattern_union_t tmp;
cairo_solid_pattern_t tmp;
/* If src and mask are both solid, then the mask alpha can be
* combined into src and mask can be ignored. */
@ -977,10 +977,7 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src,
combined = src_solid->color;
_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
_cairo_pattern_init_solid (&tmp.solid, &combined,
CAIRO_COLOR_IS_OPAQUE (&combined) ?
CAIRO_CONTENT_COLOR :
CAIRO_CONTENT_COLOR_ALPHA);
_cairo_pattern_init_solid (&tmp, &combined, CAIRO_CONTENT_COLOR_ALPHA);
mask = NULL;
} else {
@ -1164,8 +1161,7 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
_cairo_surface_create_similar_solid (&dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
1, 1,
(cairo_color_t *) color,
NULL);
(cairo_color_t *) color);
if (src->base.status)
return src->base.status;

View File

@ -37,7 +37,7 @@
#ifndef CAIRO_GLITZ_H
#define CAIRO_GLITZ_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_GLITZ_SURFACE

View File

@ -64,7 +64,8 @@ static void
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_glyph_t *transformed_glyphs);
cairo_glyph_t *transformed_glyphs,
int *num_transformed_glyphs);
cairo_status_t
_cairo_gstate_init (cairo_gstate_t *gstate,
@ -203,47 +204,6 @@ _cairo_gstate_fini (cairo_gstate_t *gstate)
gstate->source = NULL;
}
static void
_cairo_gstate_destroy (cairo_gstate_t *gstate)
{
_cairo_gstate_fini (gstate);
free (gstate);
}
/**
* _cairo_gstate_clone:
* @other: a #cairo_gstate_t to be copied, not %NULL.
*
* Create a new #cairo_gstate_t setting all graphics state parameters
* to the same values as contained in @other. gstate->next will be set
* to %NULL and may be used by the caller to chain #cairo_gstate_t
* objects together.
*
* Return value: a new #cairo_gstate_t or %NULL if there is insufficient
* memory.
**/
static cairo_status_t
_cairo_gstate_clone (cairo_gstate_t *other, cairo_gstate_t **out)
{
cairo_status_t status;
cairo_gstate_t *gstate;
assert (other != NULL);
gstate = malloc (sizeof (cairo_gstate_t));
if (gstate == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_gstate_init_copy (gstate, other);
if (status) {
free (gstate);
return status;
}
*out = gstate;
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_gstate_save:
* @gstate: input/output gstate pointer
@ -253,14 +213,25 @@ _cairo_gstate_clone (cairo_gstate_t *other, cairo_gstate_t **out)
* copy into @gstate. _cairo_gstate_restore() reverses this.
**/
cairo_status_t
_cairo_gstate_save (cairo_gstate_t **gstate)
_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
{
cairo_gstate_t *top = NULL;
cairo_gstate_t *top;
cairo_status_t status;
status = _cairo_gstate_clone (*gstate, &top);
if (status)
top = *freelist;
if (top == NULL) {
top = malloc (sizeof (cairo_gstate_t));
if (top == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else
*freelist = top->next;
status = _cairo_gstate_init_copy (top, *gstate);
if (status) {
top->next = *freelist;
*freelist = top;
return status;
}
top->next = *gstate;
*gstate = top;
@ -275,7 +246,7 @@ _cairo_gstate_save (cairo_gstate_t **gstate)
* Reverses the effects of one _cairo_gstate_save() call.
**/
cairo_status_t
_cairo_gstate_restore (cairo_gstate_t **gstate)
_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
{
cairo_gstate_t *top;
@ -285,7 +256,9 @@ _cairo_gstate_restore (cairo_gstate_t **gstate)
*gstate = top->next;
_cairo_gstate_destroy (top);
_cairo_gstate_fini (top);
top->next = *freelist;
*freelist = top;
return CAIRO_STATUS_SUCCESS;
}
@ -822,8 +795,7 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
if (status)
return status;
_cairo_pattern_transform (pattern, ctm_inverse);
/* apply device_transform first so that it is transformed by ctm_inverse */
if (cairo_pattern_get_type (original) == CAIRO_PATTERN_TYPE_SURFACE) {
surface_pattern = (cairo_surface_pattern_t *) original;
surface = surface_pattern->surface;
@ -831,6 +803,8 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
_cairo_pattern_transform (pattern, &surface->device_transform);
}
_cairo_pattern_transform (pattern, ctm_inverse);
return CAIRO_STATUS_SUCCESS;
}
@ -1174,6 +1148,21 @@ _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
gstate->antialias, gstate->target);
}
static cairo_status_t
_cairo_gstate_int_clip_extents (cairo_gstate_t *gstate,
cairo_rectangle_int_t *extents)
{
cairo_status_t status;
status = _cairo_surface_get_extents (gstate->target, extents);
if (status)
return status;
status = _cairo_clip_intersect_to_rectangle (&gstate->clip, extents);
return status;
}
cairo_status_t
_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
double *x1,
@ -1184,11 +1173,7 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate,
cairo_rectangle_int_t extents;
cairo_status_t status;
status = _cairo_surface_get_extents (gstate->target, &extents);
if (status)
return status;
status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &extents);
status = _cairo_gstate_int_clip_extents (gstate, &extents);
if (status)
return status;
@ -1513,10 +1498,21 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
return cairo_scaled_font_status (gstate->scaled_font);
}
cairo_bool_t
_cairo_gstate_has_show_text_glyphs (cairo_gstate_t *gstate)
{
return _cairo_surface_has_show_text_glyphs (gstate->target);
}
cairo_status_t
_cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs)
_cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
const char *utf8,
int utf8_len,
const cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward)
{
cairo_status_t status;
cairo_pattern_union_t source_pattern;
@ -1543,18 +1539,57 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
}
_cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs,
transformed_glyphs);
transformed_glyphs, &num_glyphs);
if (!num_glyphs)
goto CLEANUP_GLYPHS;
status = _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
if (status)
goto CLEANUP_GLYPHS;
status = _cairo_surface_show_glyphs (gstate->target,
gstate->op,
&source_pattern.base,
transformed_glyphs,
num_glyphs,
gstate->scaled_font);
/* For really huge font sizes, we can just do path;fill instead of
* show_glyphs, as show_glyphs would put excess pressure on the cache,
* and moreover, not all components below us correctly handle huge font
* sizes. I wanted to set the limit at 256. But alas, seems like cairo's
* rasterizer is something like ten times slower than freetype's for huge
* sizes. So, no win just yet. For now, do it for insanely-huge sizes,
* just to make sure we don't make anyone unhappy. When we get a really
* fast rasterizer in cairo, we may want to readjust this.
*
* Needless to say, do this only if show_text_glyphs is not available. */
if (_cairo_gstate_has_show_text_glyphs (gstate) ||
_cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240) {
status = _cairo_surface_show_text_glyphs (gstate->target,
gstate->op,
&source_pattern.base,
utf8, utf8_len,
transformed_glyphs, num_glyphs,
clusters, num_clusters,
backward,
gstate->scaled_font);
} else {
cairo_path_fixed_t path;
_cairo_path_fixed_init (&path);
CAIRO_MUTEX_LOCK (gstate->scaled_font->mutex);
status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
transformed_glyphs, num_glyphs,
&path);
CAIRO_MUTEX_UNLOCK (gstate->scaled_font->mutex);
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_surface_fill (gstate->target,
gstate->op,
&source_pattern.base,
&path,
CAIRO_FILL_RULE_WINDING,
gstate->tolerance,
gstate->scaled_font->options.antialias);
_cairo_path_fixed_fini (&path);
}
_cairo_pattern_fini (&source_pattern.base);
@ -1587,7 +1622,7 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs,
transformed_glyphs);
transformed_glyphs, NULL);
CAIRO_MUTEX_LOCK (gstate->scaled_font->mutex);
status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
@ -1623,39 +1658,99 @@ _cairo_gstate_get_antialias (cairo_gstate_t *gstate)
* @num_glyphs: the number of elements in @glyphs
* @transformed_glyphs: a pre-allocated array of at least @num_glyphs
* #cairo_glyph_t objects
* @num_transformed_glyphs: the number of elements in @transformed_glyphs
* after dropping out of bounds glyphs, or %NULL if glyphs shouldn't be
* dropped
*
* Transform an array of glyphs to backend space by first adding the offset
* of the font matrix, then transforming from user space to backend space.
* The result of the transformation is placed in @transformed_glyphs.
*
* This also uses information from the scaled font and the surface to
* cull/drop glyphs that will not be visible.
**/
static void
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_glyph_t *transformed_glyphs)
cairo_glyph_t *transformed_glyphs,
int *num_transformed_glyphs)
{
int i;
int i, j;
cairo_matrix_t *ctm = &gstate->ctm;
cairo_matrix_t *font_matrix = &gstate->font_matrix;
cairo_matrix_t *device_transform = &gstate->target->device_transform;
cairo_bool_t drop = FALSE;
double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
if (num_transformed_glyphs != NULL) {
cairo_rectangle_int_t surface_extents;
double scale = _cairo_scaled_font_get_max_scale (gstate->scaled_font);
drop = TRUE;
if (_cairo_gstate_int_clip_extents (gstate, &surface_extents))
drop = FALSE; /* unbounded surface */
else {
if (surface_extents.width == 0 || surface_extents.height == 0) {
/* No visible area. Don't draw anything */
*num_transformed_glyphs = 0;
return;
}
/* XXX We currently drop any glyphs that has its position outside
* of the surface boundaries by a safety margin depending on the
* font scale. This however can fail in extreme cases where the
* font has really long swashes for example... We can correctly
* handle that by looking the glyph up and using its device bbox
* to device if it's going to be visible, but I'm not inclined to
* do that now.
*/
x1 = surface_extents.x - 2*scale;
y1 = surface_extents.y - 2*scale;
x2 = surface_extents.x + surface_extents.width + scale;
y2 = surface_extents.y + surface_extents.height + scale;
}
if (!drop)
*num_transformed_glyphs = num_glyphs;
} else
num_transformed_glyphs = &j;
#define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2)
if (_cairo_matrix_is_identity (ctm) &&
_cairo_matrix_is_identity (device_transform) &&
gstate->font_matrix.x0 == 0 && gstate->font_matrix.y0 == 0)
font_matrix->x0 == 0 && font_matrix->y0 == 0)
{
memcpy (transformed_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
if (!drop)
memcpy (transformed_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
else {
for (j = 0, i = 0; i < num_glyphs; i++)
{
transformed_glyphs[j].index = glyphs[i].index;
transformed_glyphs[j].x = glyphs[i].x;
transformed_glyphs[j].y = glyphs[i].y;
if (KEEP_GLYPH (transformed_glyphs[j]))
j++;
}
*num_transformed_glyphs = j;
}
}
else if (_cairo_matrix_is_translation (ctm) &&
_cairo_matrix_is_translation (device_transform))
{
double tx = gstate->font_matrix.x0 + ctm->x0 + device_transform->x0;
double ty = gstate->font_matrix.y0 + ctm->y0 + device_transform->y0;
double tx = font_matrix->x0 + ctm->x0 + device_transform->x0;
double ty = font_matrix->y0 + ctm->y0 + device_transform->y0;
for (i = 0; i < num_glyphs; i++)
for (j = 0, i = 0; i < num_glyphs; i++)
{
transformed_glyphs[i].index = glyphs[i].index;
transformed_glyphs[i].x = glyphs[i].x + tx;
transformed_glyphs[i].y = glyphs[i].y + ty;
transformed_glyphs[j].index = glyphs[i].index;
transformed_glyphs[j].x = glyphs[i].x + tx;
transformed_glyphs[j].y = glyphs[i].y + ty;
if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
j++;
}
*num_transformed_glyphs = j;
}
else
{
@ -1669,12 +1764,15 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
cairo_matrix_multiply (&aggregate_transform,
&aggregate_transform, device_transform);
for (i = 0; i < num_glyphs; i++)
for (j = 0, i = 0; i < num_glyphs; i++)
{
transformed_glyphs[i] = glyphs[i];
transformed_glyphs[j] = glyphs[i];
cairo_matrix_transform_point (&aggregate_transform,
&transformed_glyphs[i].x,
&transformed_glyphs[i].y);
&transformed_glyphs[j].x,
&transformed_glyphs[j].y);
if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
j++;
}
*num_transformed_glyphs = j;
}
}

View File

@ -296,7 +296,7 @@ _cairo_hash_table_lookup_internal (cairo_hash_table_t *hash_table,
* size.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* CAIRO_STATUS_NO_MEMORY if out of memory.
* %CAIRO_STATUS_NO_MEMORY if out of memory.
**/
static cairo_status_t
_cairo_hash_table_resize (cairo_hash_table_t *hash_table)
@ -401,7 +401,7 @@ _cairo_hash_table_lookup (cairo_hash_table_t *hash_table,
*
* Return value: a random live entry or %NULL if there are no entries
* that match the given predicate. In particular, if predicate is
* NULL, a %NULL return value indicates that the table is empty.
* %NULL, a %NULL return value indicates that the table is empty.
**/
void *
_cairo_hash_table_random_entry (cairo_hash_table_t *hash_table,
@ -459,7 +459,7 @@ _cairo_hash_table_random_entry (cairo_hash_table_t *hash_table,
* necessary, use _cairo_hash_table_remove first.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
**/
cairo_status_t
_cairo_hash_table_insert (cairo_hash_table_t *hash_table,
@ -504,7 +504,7 @@ _cairo_hash_table_insert (cairo_hash_table_t *hash_table,
* _cairo_hash_table_create).
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* CAIRO_STATUS_NO_MEMORY if out of memory.
* %CAIRO_STATUS_NO_MEMORY if out of memory.
**/
void
_cairo_hash_table_remove (cairo_hash_table_t *hash_table,

View File

@ -36,22 +36,20 @@
#include "cairoint.h"
typedef struct cairo_hull
{
typedef struct cairo_hull {
cairo_point_t point;
cairo_slope_t slope;
int discard;
int id;
} cairo_hull_t;
static cairo_status_t
_cairo_hull_create (cairo_pen_vertex_t *vertices,
int num_vertices,
cairo_hull_t **out)
static void
_cairo_hull_init (cairo_hull_t *hull,
cairo_pen_vertex_t *vertices,
int num_vertices)
{
int i;
cairo_hull_t *hull;
cairo_point_t *p, *extremum, tmp;
int i;
extremum = &vertices[0].point;
for (i = 1; i < num_vertices; i++) {
@ -64,10 +62,6 @@ _cairo_hull_create (cairo_pen_vertex_t *vertices,
*extremum = vertices[0].point;
vertices[0].point = tmp;
hull = _cairo_malloc_ab (num_vertices, sizeof (cairo_hull_t));
if (hull == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
for (i = 0; i < num_vertices; i++) {
hull[i].point = vertices[i].point;
_cairo_slope_init (&hull[i].slope, &hull[0].point, &hull[i].point);
@ -82,9 +76,6 @@ _cairo_hull_create (cairo_pen_vertex_t *vertices,
if (i != 0 && hull[i].slope.dx == 0 && hull[i].slope.dy == 0)
hull[i].discard = 1;
}
*out = hull;
return CAIRO_STATUS_SUCCESS;
}
static int
@ -196,13 +187,19 @@ _cairo_hull_to_pen (cairo_hull_t *hull, cairo_pen_vertex_t *vertices, int *num_v
cairo_status_t
_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
{
cairo_status_t status;
cairo_hull_t *hull = NULL;
cairo_hull_t hull_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_hull_t)];
cairo_hull_t *hull;
int num_hull = *num_vertices;
status = _cairo_hull_create (vertices, num_hull, &hull);
if (status)
return status;
if (num_hull > ARRAY_LENGTH (hull_stack)) {
hull = _cairo_malloc_ab (num_hull, sizeof (cairo_hull_t));
if (hull == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else {
hull = hull_stack;
}
_cairo_hull_init (hull, vertices, num_hull);
qsort (hull + 1, num_hull - 1,
sizeof (cairo_hull_t), _cairo_hull_vertex_compare);
@ -211,7 +208,8 @@ _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
_cairo_hull_to_pen (hull, vertices, num_vertices);
free (hull);
if (hull != hull_stack)
free (hull);
return CAIRO_STATUS_SUCCESS;
}

View File

@ -124,7 +124,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
if (surface == NULL)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&surface->base, &cairo_image_surface_backend,
_cairo_surface_init (&surface->base, &_cairo_image_surface_backend,
_cairo_content_from_pixman_format (pixman_format));
surface->pixman_image = pixman_image;
@ -392,7 +392,8 @@ _cairo_image_surface_create_with_content (cairo_content_t content,
* stride = cairo_format_stride_for_width (format, width);
* data = malloc (stride * height);
* surface = cairo_image_surface_create_for_data (data, format,
* width, height);
* width, height,
* stride);
* </programlisting></informalexample>
*
* Return value: the appropriate stride to use given the desired
@ -1192,7 +1193,7 @@ _cairo_image_surface_set_clip_region (void *abstract_surface,
{
cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface;
if (! pixman_image_set_clip_region (surface->pixman_image, &region->rgn))
if (! pixman_image_set_clip_region32 (surface->pixman_image, &region->rgn))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
surface->has_clip = region != NULL;
@ -1246,10 +1247,10 @@ _cairo_image_surface_reset (void *abstract_surface)
cairo_bool_t
_cairo_surface_is_image (const cairo_surface_t *surface)
{
return surface->backend == &cairo_image_surface_backend;
return surface->backend == &_cairo_image_surface_backend;
}
const cairo_surface_backend_t cairo_image_surface_backend = {
const cairo_surface_backend_t _cairo_image_surface_backend = {
CAIRO_SURFACE_TYPE_IMAGE,
_cairo_image_surface_create_similar,
_cairo_image_surface_finish,

View File

@ -82,7 +82,7 @@ _lzw_buf_init (lzw_buf_t *buf, int size)
/* Increase the buffer size by doubling.
*
* Returns %CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
* Returns %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
*/
static cairo_status_t
_lzw_buf_grow (lzw_buf_t *buf)

View File

@ -423,6 +423,18 @@ _cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
}
}
cairo_private void
_cairo_matrix_transform_bounding_box_fixed (const cairo_matrix_t *matrix,
cairo_box_t *bbox,
cairo_bool_t *is_tight)
{
double x1, y1, x2, y2;
_cairo_box_to_doubles (bbox, &x1, &y1, &x2, &y2);
_cairo_matrix_transform_bounding_box (matrix, &x1, &y1, &x2, &y2, is_tight);
_cairo_box_from_doubles (bbox, &x1, &y1, &x2, &y2);
}
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
{
@ -478,10 +490,10 @@ cairo_matrix_invert (cairo_matrix_t *matrix)
_cairo_matrix_compute_determinant (matrix, &det);
if (det == 0)
if (! ISFINITE (det))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
if (! ISFINITE (det))
if (det == 0)
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
_cairo_matrix_compute_adjoint (matrix);
@ -498,7 +510,7 @@ _cairo_matrix_is_invertible (const cairo_matrix_t *matrix)
_cairo_matrix_compute_determinant (matrix, &det);
return det != 0. && ISFINITE (det);
return ISFINITE (det) && det != 0.;
}
void
@ -713,6 +725,10 @@ _cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix,
(Note that the minor axis length is at the minimum of the above solution,
which is just sqrt ( f - sqrt(g² + h²) ) given the symmetry of (D)).
For another derivation of the same result, using Singular Value Decomposition,
see doc/tutorial/src/singular.c.
*/
/* determine the length of the major axis of a circle of the given radius

View File

@ -46,7 +46,7 @@ typedef enum {
CAIRO_COMMAND_MASK,
CAIRO_COMMAND_STROKE,
CAIRO_COMMAND_FILL,
CAIRO_COMMAND_SHOW_GLYPHS,
CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
/* Other junk. For most of these, we should be able to assert that
* they never get called except as part of fallbacks for the 5
@ -104,14 +104,19 @@ typedef struct _cairo_command_fill {
cairo_antialias_t antialias;
} cairo_command_fill_t;
typedef struct _cairo_command_show_glyphs {
typedef struct _cairo_command_show_text_glyphs {
cairo_command_header_t header;
cairo_operator_t op;
cairo_pattern_union_t source;
char *utf8;
int utf8_len;
cairo_glyph_t *glyphs;
unsigned int num_glyphs;
cairo_text_cluster_t *clusters;
int num_clusters;
cairo_bool_t backward;
cairo_scaled_font_t *scaled_font;
} cairo_command_show_glyphs_t;
} cairo_command_show_text_glyphs_t;
typedef struct _cairo_command_intersect_clip_path {
cairo_command_header_t header;
@ -130,7 +135,7 @@ typedef union _cairo_command {
cairo_command_mask_t mask;
cairo_command_stroke_t stroke;
cairo_command_fill_t fill;
cairo_command_show_glyphs_t show_glyphs;
cairo_command_show_text_glyphs_t show_text_glyphs;
/* The other junk. */
cairo_command_intersect_clip_path_t intersect_clip_path;
@ -159,6 +164,10 @@ _cairo_meta_surface_create (cairo_content_t content,
int width_pixels,
int height_pixels);
cairo_private cairo_int_status_t
_cairo_meta_surface_get_path (cairo_surface_t *surface,
cairo_path_fixed_t *path);
cairo_private cairo_status_t
_cairo_meta_surface_replay (cairo_surface_t *surface,
cairo_surface_t *target);

View File

@ -39,7 +39,7 @@
/* A meta surface is a surface that records all drawing operations at
* the highest level of the surface backend interface, (that is, the
* level of paint, mask, stroke, fill, and show_glyphs). The meta
* level of paint, mask, stroke, fill, and show_text_glyphs). The meta
* surface can then be "replayed" against any target surface with:
*
* _cairo_meta_surface_replay (meta, target);
@ -157,10 +157,12 @@ _cairo_meta_surface_finish (void *abstract_surface)
free (command);
break;
case CAIRO_COMMAND_SHOW_GLYPHS:
_cairo_pattern_fini (&command->show_glyphs.source.base);
free (command->show_glyphs.glyphs);
cairo_scaled_font_destroy (command->show_glyphs.scaled_font);
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
_cairo_pattern_fini (&command->show_text_glyphs.source.base);
free (command->show_text_glyphs.utf8);
free (command->show_text_glyphs.glyphs);
free (command->show_text_glyphs.clusters);
cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font);
free (command);
break;
@ -426,23 +428,34 @@ _cairo_meta_surface_fill (void *abstract_surface,
return status;
}
static cairo_bool_t
_cairo_meta_surface_has_show_text_glyphs (void *abstract_surface)
{
return TRUE;
}
static cairo_int_status_t
_cairo_meta_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_meta_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
cairo_command_show_glyphs_t *command;
cairo_command_show_text_glyphs_t *command;
command = malloc (sizeof (cairo_command_show_glyphs_t));
command = malloc (sizeof (cairo_command_show_text_glyphs_t));
if (command == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
command->header.type = CAIRO_COMMAND_SHOW_GLYPHS;
command->header.type = CAIRO_COMMAND_SHOW_TEXT_GLYPHS;
command->header.region = CAIRO_META_REGION_ALL;
command->op = op;
@ -450,14 +463,39 @@ _cairo_meta_surface_show_glyphs (void *abstract_surface,
if (status)
goto CLEANUP_COMMAND;
command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (command->glyphs == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_SOURCE;
}
memcpy (command->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
command->utf8 = NULL;
command->utf8_len = utf8_len;
command->glyphs = NULL;
command->num_glyphs = num_glyphs;
command->clusters = NULL;
command->num_clusters = num_clusters;
if (utf8_len) {
command->utf8 = malloc (utf8_len);
if (command->utf8 == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_ARRAYS;
}
memcpy (command->utf8, utf8, utf8_len);
}
if (num_glyphs) {
command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0]));
if (command->glyphs == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_ARRAYS;
}
memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs);
}
if (num_clusters) {
command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0]));
if (command->clusters == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_ARRAYS;
}
memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters);
}
command->backward = backward;
command->scaled_font = cairo_scaled_font_reference (scaled_font);
@ -469,8 +507,11 @@ _cairo_meta_surface_show_glyphs (void *abstract_surface,
CLEANUP_SCALED_FONT:
cairo_scaled_font_destroy (command->scaled_font);
CLEANUP_ARRAYS:
free (command->utf8);
free (command->glyphs);
CLEANUP_SOURCE:
free (command->clusters);
_cairo_pattern_fini (&command->source.base);
CLEANUP_COMMAND:
free (command);
@ -485,7 +526,7 @@ _cairo_meta_surface_show_glyphs (void *abstract_surface,
* surface-modifying function on the result of this function.
*
* The caller owns the return value and should call
* cairo_surface_destroy when finished with it. This function will not
* cairo_surface_destroy() when finished with it. This function will not
* return %NULL, but will return a nil surface instead.
*
* Return value: The snapshot surface.
@ -570,6 +611,9 @@ _cairo_meta_surface_get_extents (void *abstract_surface,
{
cairo_meta_surface_t *surface = abstract_surface;
if (surface->width_pixels == -1 && surface->height_pixels == -1)
return CAIRO_INT_STATUS_UNSUPPORTED;
rectangle->x = 0;
rectangle->y = 0;
rectangle->width = surface->width_pixels;
@ -618,15 +662,24 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = {
/* Here are the 5 basic drawing operations, (which are in some
* sense the only things that cairo_meta_surface should need to
* implement). */
* implement). However, we implement the more generic show_text_glyphs
* instead of show_glyphs. One or the other is eough. */
_cairo_meta_surface_paint,
_cairo_meta_surface_mask,
_cairo_meta_surface_stroke,
_cairo_meta_surface_fill,
_cairo_meta_surface_show_glyphs,
NULL,
_cairo_meta_surface_snapshot
_cairo_meta_surface_snapshot,
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
_cairo_meta_surface_has_show_text_glyphs,
_cairo_meta_surface_show_text_glyphs
};
static cairo_path_fixed_t *
@ -635,7 +688,7 @@ _cairo_command_get_path (cairo_command_t *command)
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
case CAIRO_COMMAND_MASK:
case CAIRO_COMMAND_SHOW_GLYPHS:
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
return NULL;
case CAIRO_COMMAND_STROKE:
return &command->stroke.path;
@ -649,6 +702,78 @@ _cairo_command_get_path (cairo_command_t *command)
return NULL;
}
cairo_int_status_t
_cairo_meta_surface_get_path (cairo_surface_t *surface,
cairo_path_fixed_t *path)
{
cairo_meta_surface_t *meta;
cairo_command_t *command, **elements;
int i, num_elements;
cairo_int_status_t status;
if (surface->status)
return surface->status;
meta = (cairo_meta_surface_t *) surface;
status = CAIRO_STATUS_SUCCESS;
num_elements = meta->commands.num_elements;
elements = _cairo_array_index (&meta->commands, 0);
for (i = meta->replay_start_idx; i < num_elements; i++) {
command = elements[i];
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
case CAIRO_COMMAND_MASK:
case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
status = CAIRO_INT_STATUS_UNSUPPORTED;
break;
case CAIRO_COMMAND_STROKE:
{
cairo_traps_t traps;
_cairo_traps_init (&traps);
/* XXX call cairo_stroke_to_path() when that is implemented */
status = _cairo_path_fixed_stroke_to_traps (&command->stroke.path,
&command->stroke.style,
&command->stroke.ctm,
&command->stroke.ctm_inverse,
command->stroke.tolerance,
&traps);
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_traps_path (&traps, path);
_cairo_traps_fini (&traps);
break;
}
case CAIRO_COMMAND_FILL:
{
status = _cairo_path_fixed_append (path, &command->fill.path, CAIRO_DIRECTION_FORWARD);
break;
}
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
{
status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font,
command->show_text_glyphs.glyphs,
command->show_text_glyphs.num_glyphs,
path);
break;
}
default:
ASSERT_NOT_REACHED;
}
if (status)
break;
}
return _cairo_surface_set_error (surface, status);
}
static cairo_status_t
_cairo_meta_surface_replay_internal (cairo_surface_t *surface,
cairo_surface_t *target,
@ -699,7 +824,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (status)
break;
_cairo_path_fixed_device_transform (&path_copy, device_transform);
_cairo_path_fixed_transform (&path_copy, device_transform);
dev_path = &path_copy;
}
@ -798,13 +923,13 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
command->fill.antialias);
break;
}
case CAIRO_COMMAND_SHOW_GLYPHS:
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
{
cairo_glyph_t *glyphs = command->show_glyphs.glyphs;
cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
cairo_glyph_t *dev_glyphs;
int i, num_glyphs = command->show_glyphs.num_glyphs;
int i, num_glyphs = command->show_text_glyphs.num_glyphs;
/* show_glyphs is special because _cairo_surface_show_glyphs is allowed
/* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
* to modify the glyph array that's passed in. We must always
* copy the array before handing it to the backend.
*/
@ -825,11 +950,14 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
}
status = _cairo_surface_show_glyphs (target,
command->show_glyphs.op,
&command->show_glyphs.source.base,
dev_glyphs, num_glyphs,
command->show_glyphs.scaled_font);
status = _cairo_surface_show_text_glyphs (target,
command->show_text_glyphs.op,
&command->show_text_glyphs.source.base,
command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
dev_glyphs, num_glyphs,
command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
command->show_text_glyphs.backward,
command->show_text_glyphs.scaled_font);
free (dev_glyphs);
break;
@ -887,7 +1015,7 @@ _cairo_meta_surface_replay (cairo_surface_t *surface,
/* Replay meta to surface. When the return status of each operation is
* one of %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED, or
* CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation
* %CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation
* will be stored in the meta surface. Any other status will abort the
* replay and return the status.
*/

View File

@ -38,6 +38,8 @@
#include "cairoint.h"
COMPILE_TIME_ASSERT (CAIRO_STATUS_LAST_STATUS < CAIRO_INT_STATUS_UNSUPPORTED);
COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127);
/**
* cairo_status_to_string:
@ -101,6 +103,16 @@ cairo_status_to_string (cairo_status_t status)
return "error creating or writing to a temporary file";
case CAIRO_STATUS_INVALID_STRIDE:
return "invalid value for stride";
case CAIRO_STATUS_FONT_TYPE_MISMATCH:
return "the font type is not appropriate for the operation";
case CAIRO_STATUS_USER_FONT_IMMUTABLE:
return "the user-font is immutable";
case CAIRO_STATUS_USER_FONT_ERROR:
return "error occurred in a user-font callback function";
case CAIRO_STATUS_NEGATIVE_COUNT:
return "negative number used where it is not allowed";
case CAIRO_STATUS_INVALID_CLUSTERS:
return "input clusters do not represent the accompanying text and glyph arrays";
}
return "<unknown error status>";

View File

@ -0,0 +1,226 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005,2007 Red Hat, Inc.
* Copyright © 2007 Mathias Hasselmann
*
* 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>
* Mathias Hasselmann <mathias.hasselmann@gmx.de>
* Behdad Esfahbod <behdad@behdad.org>
*/
#ifndef CAIRO_MUTEX_IMPL_PRIVATE_H
#define CAIRO_MUTEX_IMPL_PRIVATE_H
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "cairo-features.h"
CAIRO_BEGIN_DECLS
/* A fully qualified no-operation statement */
#define CAIRO_MUTEX_IMPL_NOOP do {/*no-op*/} while (0)
/* And one that evaluates it's argument once */
#define CAIRO_MUTEX_IMPL_NOOP1(expr) do { if (expr) ; } while (0)
/* Cairo mutex implementation:
*
* Any new mutex implementation needs to do the following:
*
* - Condition on the right header or feature. Headers are
* preferred as eg. you still can use win32 mutex implementation
* on a win32 system even if you do not compile the win32
* surface/backend.
*
* - typedef #cairo_mutex_impl_t to the proper mutex type on your target
* system. Note that you may or may not need to use a pointer,
* depending on what kinds of initialization your mutex
* implementation supports. No trailing semicolon needed.
* You should be able to compile the following snippet (don't try
* running it):
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex;
* </programlisting>
*
* - #define CAIRO_MUTEX_IMPL_LOCK(mutex) and CAIRO_MUTEX_IMPL_UNLOCK(mutex) to
* proper statement to lock/unlock the mutex object passed in.
* You can (and should) assume that the mutex is already
* initialized, and is-not-already-locked/is-locked,
* respectively. Use the "do { ... } while (0)" idiom if necessary.
* No trailing semicolons are needed (in any macro you define here).
* You should be able to compile the following snippet:
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex;
*
* if (1)
* CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
* else
* CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
* </programlisting>
*
* - #define %CAIRO_MUTEX_IMPL_NIL_INITIALIZER to something that can
* initialize the #cairo_mutex_impl_t type you defined. Most of the
* time one of 0, %NULL, or {} works. At this point
* you should be able to compile the following snippet:
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER;
*
* if (1)
* CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
* else
* CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
* </programlisting>
*
* - If the above code is not enough to initialize a mutex on
* your platform, #define CAIRO_MUTEX_IMPL_INIT(mutex) to statement
* to initialize the mutex (allocate resources, etc). Such that
* you should be able to compile AND RUN the following snippet:
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER;
*
* CAIRO_MUTEX_IMPL_INIT (_cairo_some_mutex);
*
* if (1)
* CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
* else
* CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
* </programlisting>
*
* - If you define CAIRO_MUTEX_IMPL_INIT(mutex), cairo will use it to
* initialize all static mutex'es. If for any reason that should
* not happen (eg. %CAIRO_MUTEX_IMPL_INIT is just a faster way than
* what cairo does using %CAIRO_MUTEX_IMPL_NIL_INITIALIZER), then
* <programlisting>
* #define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
* </programlisting>
*
* - If your system supports freeing a mutex object (deallocating
* resources, etc), then #define CAIRO_MUTEX_IMPL_FINI(mutex) to do
* that.
*
* - If you define CAIRO_MUTEX_IMPL_FINI(mutex), cairo will use it to
* define a finalizer function to finalize all static mutex'es.
* However, it's up to you to call CAIRO_MUTEX_IMPL_FINALIZE() at
* proper places, eg. when the system is unloading the cairo library.
* So, if for any reason finalizing static mutex'es is not needed
* (eg. you never call CAIRO_MUTEX_IMPL_FINALIZE()), then
* <programlisting>
* #define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
* </programlisting>
*
* - That is all. If for any reason you think the above API is
* not enough to implement #cairo_mutex_impl_t on your system, please
* stop and write to the cairo mailing list about it. DO NOT
* poke around cairo-mutex-private.h for possible solutions.
*/
#ifndef CAIRO_MUTEX_TYPE_PRIVATE_H
#error "Do not include cairo-mutex-impl-private.h directly. Include cairo-mutex-type-private.h instead."
#endif
#if CAIRO_NO_MUTEX
/* No mutexes */
typedef int cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
# define CAIRO_MUTEX_IMPL_LOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0
#elif HAVE_PTHREAD_H /*******************************************************/
# include <pthread.h>
typedef pthread_mutex_t cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_LOCK(mutex) pthread_mutex_lock (&(mutex))
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) pthread_mutex_unlock (&(mutex))
# define CAIRO_MUTEX_IMPL_FINI(mutex) pthread_mutex_destroy (&(mutex))
# define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#elif HAVE_WINDOWS_H /*******************************************************/
# include <windows.h>
typedef CRITICAL_SECTION cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_LOCK(mutex) EnterCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) LeaveCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_INIT(mutex) InitializeCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_FINI(mutex) DeleteCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER { NULL, 0, 0, NULL, NULL, 0 }
#elif defined __OS2__ /******************************************************/
# define INCL_BASE
# define INCL_PM
# include <os2.h>
typedef HMTX cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_LOCK(mutex) DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT)
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) DosReleaseMutexSem(mutex)
# define CAIRO_MUTEX_IMPL_INIT(mutex) DosCreateMutexSem (NULL, &(mutex), 0L, FALSE)
# define CAIRO_MUTEX_IMPL_FINI(mutex) DosCloseMutexSem (mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0
#elif CAIRO_HAS_BEOS_SURFACE /***********************************************/
typedef BLocker* cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_LOCK(mutex) (mutex)->Lock()
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) (mutex)->Unlock()
# define CAIRO_MUTEX_IMPL_INIT(mutex) (mutex) = new BLocker()
# define CAIRO_MUTEX_IMPL_FINI(mutex) delete (mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER NULL
#else /**********************************************************************/
# error "XXX: No mutex implementation found. Cairo will not work with multiple threads. Define CAIRO_NO_MUTEX to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support."
#endif
CAIRO_END_DECLS
#endif

View File

@ -41,136 +41,27 @@
#ifndef CAIRO_MUTEX_PRIVATE_H
#define CAIRO_MUTEX_PRIVATE_H
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <cairo-features.h>
#include "cairo-compiler-private.h"
#include "cairo-mutex-type-private.h"
/* Only the following three are mandatory at this point */
#ifndef CAIRO_MUTEX_LOCK
# error "CAIRO_MUTEX_LOCK not defined. Check cairo-mutex-type-private.h."
#endif
#ifndef CAIRO_MUTEX_UNLOCK
# error "CAIRO_MUTEX_UNLOCK not defined. Check cairo-mutex-type-private.h."
#endif
#ifndef CAIRO_MUTEX_NIL_INITIALIZER
# error "CAIRO_MUTEX_NIL_INITIALIZER not defined. Check cairo-mutex-type-private.h."
#endif
CAIRO_BEGIN_DECLS
#define CAIRO_MUTEX_DECLARE(mutex) extern cairo_mutex_t mutex
#include "cairo-mutex-list-private.h"
#undef CAIRO_MUTEX_DECLARE
/* make sure implementations don't fool us: we decide these ourself */
#undef _CAIRO_MUTEX_USE_STATIC_INITIALIZER
#undef _CAIRO_MUTEX_USE_STATIC_FINALIZER
#ifdef CAIRO_MUTEX_INIT
/* If %CAIRO_MUTEX_INIT is defined, we may need to initialize all
* static mutex'es. */
# ifndef CAIRO_MUTEX_INITIALIZE
# define CAIRO_MUTEX_INITIALIZE() do { \
if (!_cairo_mutex_initialized) \
_cairo_mutex_initialize (); \
} while(0)
cairo_private void _cairo_mutex_initialize (void);
/* and make sure we implement the above */
# define _CAIRO_MUTEX_USE_STATIC_INITIALIZER 1
# endif /* CAIRO_MUTEX_INITIALIZE */
#else /* no CAIRO_MUTEX_INIT */
/* Otherwise we probably don't need to initialize static mutex'es, */
# ifndef CAIRO_MUTEX_INITIALIZE
# define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP
# endif /* CAIRO_MUTEX_INITIALIZE */
/* and dynamic ones can be initialized using the static initializer. */
# define CAIRO_MUTEX_INIT(mutex) do { \
cairo_mutex_t _tmp_mutex = CAIRO_MUTEX_NIL_INITIALIZER; \
memcpy (&(mutex), &_tmp_mutex, sizeof (_tmp_mutex)); \
} while (0)
#endif /* CAIRO_MUTEX_INIT */
#ifdef CAIRO_MUTEX_FINI
/* If %CAIRO_MUTEX_FINI is defined, we may need to finalize all
* static mutex'es. */
# ifndef CAIRO_MUTEX_FINALIZE
# define CAIRO_MUTEX_FINALIZE() do { \
if (_cairo_mutex_initialized) \
_cairo_mutex_finalize (); \
} while(0)
cairo_private void _cairo_mutex_finalize (void);
/* and make sure we implement the above */
# define _CAIRO_MUTEX_USE_STATIC_FINALIZER 1
# endif /* CAIRO_MUTEX_FINALIZE */
#else /* no CAIRO_MUTEX_FINI */
/* Otherwise we probably don't need to finalize static mutex'es, */
# ifndef CAIRO_MUTEX_FINALIZE
# define CAIRO_MUTEX_FINALIZE() CAIRO_MUTEX_NOOP
# endif /* CAIRO_MUTEX_FINALIZE */
/* neither do the dynamic ones. */
# define CAIRO_MUTEX_FINI(mutex) CAIRO_MUTEX_NOOP1(mutex)
#endif /* CAIRO_MUTEX_FINI */
#ifndef _CAIRO_MUTEX_USE_STATIC_INITIALIZER
#define _CAIRO_MUTEX_USE_STATIC_INITIALIZER 0
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
cairo_private void _cairo_mutex_initialize (void);
#endif
#ifndef _CAIRO_MUTEX_USE_STATIC_FINALIZER
#define _CAIRO_MUTEX_USE_STATIC_FINALIZER 0
#if _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
cairo_private void _cairo_mutex_finalize (void);
#endif
/* only if using static initializer and/or finalizer define the boolean */
#if _CAIRO_MUTEX_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_USE_STATIC_FINALIZER
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
cairo_private extern cairo_bool_t _cairo_mutex_initialized;
#endif
/* Finally, extern the static mutexes and undef */
#define CAIRO_MUTEX_DECLARE(mutex) cairo_private extern cairo_mutex_t mutex
#include "cairo-mutex-list-private.h"
#undef CAIRO_MUTEX_DECLARE
CAIRO_END_DECLS
/* Make sure everything we want is defined */
#ifndef CAIRO_MUTEX_INITIALIZE
# error "CAIRO_MUTEX_INITIALIZE not defined"
#endif
#ifndef CAIRO_MUTEX_FINALIZE
# error "CAIRO_MUTEX_FINALIZE not defined"
#endif
#ifndef CAIRO_MUTEX_LOCK
# error "CAIRO_MUTEX_LOCK not defined"
#endif
#ifndef CAIRO_MUTEX_UNLOCK
# error "CAIRO_MUTEX_UNLOCK not defined"
#endif
#ifndef CAIRO_MUTEX_INIT
# error "CAIRO_MUTEX_INIT not defined"
#endif
#ifndef CAIRO_MUTEX_FINI
# error "CAIRO_MUTEX_FINI not defined"
#endif
#ifndef CAIRO_MUTEX_NIL_INITIALIZER
# error "CAIRO_MUTEX_NIL_INITIALIZER not defined"
#endif
#endif

View File

@ -45,166 +45,144 @@
#include "config.h"
#endif
#include <cairo-features.h>
CAIRO_BEGIN_DECLS
/* A fully qualified no-operation statement */
#define CAIRO_MUTEX_NOOP do {/*no-op*/} while (0)
/* And one that evaluates it's argument once */
#define CAIRO_MUTEX_NOOP1(expr) do { if (expr) ; } while (0)
/* Cairo mutex implementation:
*
* Any new mutex implementation needs to do the following:
*
* - Condition on the right header or feature. Headers are
* preferred as eg. you still can use win32 mutex implementation
* on a win32 system even if you do not compile the win32
* surface/backend.
*
* - typedef #cairo_mutex_t to the proper mutex type on your target
* system. Note that you may or may not need to use a pointer,
* depending on what kinds of initialization your mutex
* implementation supports. No trailing semicolon needed.
* You should be able to compile the following snippet (don't try
* running it):
*
* cairo_mutex_t _cairo_some_mutex;
*
* - #define CAIRO_MUTEX_LOCK(mutex) and CAIRO_MUTEX_UNLOCK(mutex) to
* proper statement to lock/unlock the mutex object passed in.
* You can (and should) assume that the mutex is already
* initialized, and is-not-already-locked/is-locked,
* respectively. Use the "do { ... } while (0)" idiom if necessary.
* No trailing semicolons are needed (in any macro you define here).
* You should be able to compile the following snippet:
*
* cairo_mutex_t _cairo_some_mutex;
*
* if (1)
* %CAIRO_MUTEX_LOCK (_cairo_some_mutex);
* else
* %CAIRO_MUTEX_UNLOCK (_cairo_some_mutex);
*
* - #define %CAIRO_MUTEX_NIL_INITIALIZER to something that can
* initialize the #cairo_mutex_t type you defined. Most of the
* time one of 0, %NULL, or {} works. At this point
* you should be able to compile the following snippet:
*
* cairo_mutex_t _cairo_some_mutex = CAIRO_MUTEX_NIL_INITIALIZER;
*
* if (1)
* %CAIRO_MUTEX_LOCK (_cairo_some_mutex);
* else
* %CAIRO_MUTEX_UNLOCK (_cairo_some_mutex);
*
* - If the above code is not enough to initialize a mutex on
* your platform, #define CAIRO_MUTEX_INIT(mutex) to statement
* to initialize the mutex (allocate resources, etc). Such that
* you should be able to compile AND RUN the following snippet:
*
* cairo_mutex_t _cairo_some_mutex = CAIRO_MUTEX_NIL_INITIALIZER;
*
* %CAIRO_MUTEX_INIT (_cairo_some_mutex);
*
* if (1)
* %CAIRO_MUTEX_LOCK (_cairo_some_mutex);
* else
* %CAIRO_MUTEX_UNLOCK (_cairo_some_mutex);
*
* - If you define CAIRO_MUTEX_INIT(mutex), cairo will use it to
* initialize all static mutex'es. If for any reason that should
* not happen (eg. %CAIRO_MUTEX_INIT is just a faster way than
* what cairo does using %CAIRO_MUTEX_NIL_INITIALIZER), then
* #define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP
*
* - If your system supports freeing a mutex object (deallocating
* resources, etc), then #define CAIRO_MUTEX_FINI(mutex) to do
* that.
*
* - If you define CAIRO_MUTEX_FINI(mutex), cairo will use it to
* define a finalizer function to finalize all static mutex'es.
* However, it's up to you to call CAIRO_MUTEX_FINALIZE() at
* proper places, eg. when the system is unloading the cairo library.
* So, if for any reason finalizing static mutex'es is not needed
* (eg. you never call %CAIRO_MUTEX_FINALIZE), then
* #define CAIRO_MUTEX_FINALIZE() CAIRO_MUTEX_NOOP
*
* - That is all. If for any reason you think the above API is
* not enough to implement #cairo_mutex_t on your system, please
* stop and write to the cairo mailing list about it. DO NOT
* poke around cairo-mutex-private.h for possible solutions.
*/
#if CAIRO_NO_MUTEX
/* No mutexes */
typedef int cairo_mutex_t;
# define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP
# define CAIRO_MUTEX_LOCK(mutex) CAIRO_MUTEX_NOOP1(mutex)
# define CAIRO_MUTEX_UNLOCK(mutex) CAIRO_MUTEX_NOOP1(mutex)
# define CAIRO_MUTEX_NIL_INITIALIZER 0
#elif HAVE_PTHREAD_H /*******************************************************/
# include <pthread.h>
typedef pthread_mutex_t cairo_mutex_t;
# define CAIRO_MUTEX_LOCK(mutex) pthread_mutex_lock (&(mutex))
# define CAIRO_MUTEX_UNLOCK(mutex) pthread_mutex_unlock (&(mutex))
# define CAIRO_MUTEX_FINI(mutex) pthread_mutex_destroy (&(mutex))
# define CAIRO_MUTEX_FINALIZE() CAIRO_MUTEX_NOOP
# define CAIRO_MUTEX_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#elif HAVE_WINDOWS_H /*******************************************************/
# include <windows.h>
typedef CRITICAL_SECTION cairo_mutex_t;
# define CAIRO_MUTEX_LOCK(mutex) EnterCriticalSection (&(mutex))
# define CAIRO_MUTEX_UNLOCK(mutex) LeaveCriticalSection (&(mutex))
# define CAIRO_MUTEX_INIT(mutex) InitializeCriticalSection (&(mutex))
# define CAIRO_MUTEX_FINI(mutex) DeleteCriticalSection (&(mutex))
# define CAIRO_MUTEX_NIL_INITIALIZER { NULL, 0, 0, NULL, NULL, 0 }
#elif defined __OS2__ /******************************************************/
# define INCL_BASE
# define INCL_PM
# include <os2.h>
typedef HMTX cairo_mutex_t;
# define CAIRO_MUTEX_LOCK(mutex) DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT)
# define CAIRO_MUTEX_UNLOCK(mutex) DosReleaseMutexSem(mutex)
# define CAIRO_MUTEX_INIT(mutex) DosCreateMutexSem (NULL, &(mutex), 0L, FALSE)
# define CAIRO_MUTEX_FINI(mutex) DosCloseMutexSem (mutex)
# define CAIRO_MUTEX_NIL_INITIALIZER 0
#elif CAIRO_HAS_BEOS_SURFACE /***********************************************/
typedef BLocker* cairo_mutex_t;
# define CAIRO_MUTEX_LOCK(mutex) (mutex)->Lock()
# define CAIRO_MUTEX_UNLOCK(mutex) (mutex)->Unlock()
# define CAIRO_MUTEX_INIT(mutex) (mutex) = new BLocker()
# define CAIRO_MUTEX_FINI(mutex) delete (mutex)
# define CAIRO_MUTEX_NIL_INITIALIZER NULL
#else /**********************************************************************/
# error "XXX: No mutex implementation found. Cairo will not work with multiple threads. Define CAIRO_NO_MUTEX to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support."
#include "cairo-features.h"
#include "cairo-compiler-private.h"
#include "cairo-mutex-impl-private.h"
/* Only the following three are mandatory at this point */
#ifndef CAIRO_MUTEX_IMPL_LOCK
# error "CAIRO_MUTEX_IMPL_LOCK not defined. Check cairo-mutex-impl-private.h."
#endif
#ifndef CAIRO_MUTEX_IMPL_UNLOCK
# error "CAIRO_MUTEX_IMPL_UNLOCK not defined. Check cairo-mutex-impl-private.h."
#endif
#ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER
# error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined. Check cairo-mutex-impl-private.h."
#endif
CAIRO_END_DECLS
/* make sure implementations don't fool us: we decide these ourself */
#undef _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
#undef _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
#ifdef CAIRO_MUTEX_IMPL_INIT
/* If %CAIRO_MUTEX_IMPL_INIT is defined, we may need to initialize all
* static mutex'es. */
# ifndef CAIRO_MUTEX_IMPL_INITIALIZE
# define CAIRO_MUTEX_IMPL_INITIALIZE() do { \
if (!_cairo_mutex_initialized) \
_cairo_mutex_initialize (); \
} while(0)
/* and make sure we implement the above */
# define _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER 1
# endif /* CAIRO_MUTEX_IMPL_INITIALIZE */
#else /* no CAIRO_MUTEX_IMPL_INIT */
/* Otherwise we probably don't need to initialize static mutex'es, */
# ifndef CAIRO_MUTEX_IMPL_INITIALIZE
# define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
# endif /* CAIRO_MUTEX_IMPL_INITIALIZE */
/* and dynamic ones can be initialized using the static initializer. */
# define CAIRO_MUTEX_IMPL_INIT(mutex) do { \
cairo_mutex_t _tmp_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER; \
memcpy (&(mutex), &_tmp_mutex, sizeof (_tmp_mutex)); \
} while (0)
#endif /* CAIRO_MUTEX_IMPL_INIT */
#ifdef CAIRO_MUTEX_IMPL_FINI
/* If %CAIRO_MUTEX_IMPL_FINI is defined, we may need to finalize all
* static mutex'es. */
# ifndef CAIRO_MUTEX_IMPL_FINALIZE
# define CAIRO_MUTEX_IMPL_FINALIZE() do { \
if (_cairo_mutex_initialized) \
_cairo_mutex_finalize (); \
} while(0)
/* and make sure we implement the above */
# define _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER 1
# endif /* CAIRO_MUTEX_IMPL_FINALIZE */
#else /* no CAIRO_MUTEX_IMPL_FINI */
/* Otherwise we probably don't need to finalize static mutex'es, */
# ifndef CAIRO_MUTEX_IMPL_FINALIZE
# define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
# endif /* CAIRO_MUTEX_IMPL_FINALIZE */
/* neither do the dynamic ones. */
# define CAIRO_MUTEX_IMPL_FINI(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
#endif /* CAIRO_MUTEX_IMPL_FINI */
#ifndef _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
#define _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER 0
#endif
#ifndef _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
#define _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER 0
#endif
/* Make sure everything we want is defined */
#ifndef CAIRO_MUTEX_IMPL_INITIALIZE
# error "CAIRO_MUTEX_IMPL_INITIALIZE not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_FINALIZE
# error "CAIRO_MUTEX_IMPL_FINALIZE not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_LOCK
# error "CAIRO_MUTEX_IMPL_LOCK not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_UNLOCK
# error "CAIRO_MUTEX_IMPL_UNLOCK not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_INIT
# error "CAIRO_MUTEX_IMPL_INIT not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_FINI
# error "CAIRO_MUTEX_IMPL_FINI not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER
# error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined"
#endif
/* Public interface. */
/* By default it simply uses the implementation provided.
* But we can provide for debugging features by overriding them */
#ifndef CAIRO_MUTEX_DEBUG
typedef cairo_mutex_impl_t cairo_mutex_t;
#else
# define cairo_mutex_t cairo_mutex_impl_t
#endif
#define CAIRO_MUTEX_INITIALIZE CAIRO_MUTEX_IMPL_INITIALIZE
#define CAIRO_MUTEX_FINALIZE CAIRO_MUTEX_IMPL_FINALIZE
#define CAIRO_MUTEX_LOCK CAIRO_MUTEX_IMPL_LOCK
#define CAIRO_MUTEX_UNLOCK CAIRO_MUTEX_IMPL_UNLOCK
#define CAIRO_MUTEX_INIT CAIRO_MUTEX_IMPL_INIT
#define CAIRO_MUTEX_FINI CAIRO_MUTEX_IMPL_FINI
#define CAIRO_MUTEX_NIL_INITIALIZER CAIRO_MUTEX_IMPL_NIL_INITIALIZER
/* Debugging support */
#ifdef CAIRO_MUTEX_DEBUG
/* TODO add mutex debugging facilities here (eg deadlock detection) */
#endif /* CAIRO_MUTEX_DEBUG */
#endif

View File

@ -33,25 +33,27 @@
#include "cairoint.h"
#include "cairo-mutex-private.h"
#define CAIRO_MUTEX_DECLARE(mutex) cairo_mutex_t mutex = CAIRO_MUTEX_NIL_INITIALIZER
#include "cairo-mutex-list-private.h"
#undef CAIRO_MUTEX_DECLARE
#if _CAIRO_MUTEX_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_USE_STATIC_FINALIZER
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
# if _CAIRO_MUTEX_USE_STATIC_INITIALIZER
# define _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE FALSE
# if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
# define _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE FALSE
# else
# define _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE TRUE
# define _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE TRUE
# endif
cairo_bool_t _cairo_mutex_initialized = _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE;
cairo_bool_t _cairo_mutex_initialized = _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE;
# undef _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE
# undef _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE
#endif
#if _CAIRO_MUTEX_USE_STATIC_INITIALIZER
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
void _cairo_mutex_initialize (void)
{
if (_cairo_mutex_initialized)
@ -65,7 +67,7 @@ void _cairo_mutex_initialize (void)
}
#endif
#if _CAIRO_MUTEX_USE_STATIC_FINALIZER
#if _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
void _cairo_mutex_finalize (void)
{
if (!_cairo_mutex_initialized)

View File

@ -49,7 +49,7 @@
# include <os2emx.h>
#endif
#include <cairo-os2.h>
#include "cairo-os2.h"
#include "cairoint.h"
typedef struct _cairo_os2_surface

View File

@ -56,8 +56,8 @@
/*
* Here comes the extra API for the OS/2 platform. Currently it consists
* of two extra functions, the cairo_os2_init () and the
* cairo_os2_fini (). Both of them are called automatically if
* of two extra functions, the cairo_os2_init() and the
* cairo_os2_fini(). Both of them are called automatically if
* Cairo is compiled to be a DLL file, but you have to call them before
* using the Cairo API if you link to Cairo statically!
*
@ -145,8 +145,10 @@ cairo_os2_fini (void)
CAIRO_MUTEX_FINALIZE ();
#if CAIRO_HAS_FT_FONT
# if HAVE_FCFINI
/* Uninitialize FontConfig */
FcFini ();
# endif
#endif
#ifdef __WATCOMC__

View File

@ -38,7 +38,7 @@
#ifndef _CAIRO_OS2_H_
#define _CAIRO_OS2_H_
#include <cairo.h>
#include "cairo.h"
CAIRO_BEGIN_DECLS

View File

@ -157,11 +157,11 @@ _cairo_memory_stream_copy (cairo_output_stream_t *base,
cairo_private int
_cairo_memory_stream_length (cairo_output_stream_t *stream);
/* cairo_base85_stream.c */
/* cairo-base85-stream.c */
cairo_private cairo_output_stream_t *
_cairo_base85_stream_create (cairo_output_stream_t *output);
/* cairo_deflate_stream.c */
/* cairo-deflate-stream.c */
cairo_private cairo_output_stream_t *
_cairo_deflate_stream_create (cairo_output_stream_t *output);

View File

@ -49,7 +49,7 @@
*/
#define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6
/* Numbers printed with %g are assumed to only have CAIRO_FIXED_FRAC_BITS
/* Numbers printed with %g are assumed to only have %CAIRO_FIXED_FRAC_BITS
* bits of precision available after the decimal point.
*
* FIXED_POINT_DECIMAL_DIGITS specifies the minimum number of decimal
@ -58,10 +58,12 @@
*
* The conversion is:
*
* <programlisting>
* FIXED_POINT_DECIMAL_DIGITS = ceil( CAIRO_FIXED_FRAC_BITS * ln(2)/ln(10) )
* </programlisting>
*
* We can replace ceil(x) with (int)(x+1) since x will never be an
* integer for any likely value of CAIRO_FIXED_FRAC_BITS.
* integer for any likely value of %CAIRO_FIXED_FRAC_BITS.
*/
#define FIXED_POINT_DECIMAL_DIGITS ((int)(CAIRO_FIXED_FRAC_BITS*0.301029996 + 1))

View File

@ -67,6 +67,14 @@ struct _cairo_paginated_surface_backend {
cairo_warn cairo_int_status_t
(*set_bounding_box) (void *surface,
cairo_box_t *bbox);
/* Optional. Indicates whether the page requires fallback images.
* Will be called at the end of the ANALYZE phase but before the
* mode is changed to RENDER.
*/
cairo_warn cairo_int_status_t
(*set_fallback_images_required)(void *surface,
cairo_bool_t fallbacks_required);
};
/* A #cairo_paginated_surface_t provides a very convenient wrapper that
@ -80,7 +88,7 @@ struct _cairo_paginated_surface_backend {
* _cairo_paginated_surface_create which takes its own, much simpler,
* #cairo_paginated_surface_backend_t. You are free to return the result
* of _cairo_paginated_surface_create() from your public
* cairo_<foo>_surface_create. The paginated backend will be careful
* cairo_<foo>_surface_create(). The paginated backend will be careful
* to not let the user see that they really got a "wrapped"
* surface. See test-paginated-surface.c for a fairly minimal example
* of a paginated-using surface. That should be a reasonable example
@ -88,29 +96,29 @@ struct _cairo_paginated_surface_backend {
*
* What the paginated surface does is first save all drawing
* operations for a page into a meta-surface. Then when the user calls
* cairo_show_page, the paginated surface performs the following
* cairo_show_page(), the paginated surface performs the following
* sequence of operations (using the backend functions passed to
* cairo_paginated_surface_create):
* cairo_paginated_surface_create()):
*
* 1. Calls start_page (if non %NULL). At this point, it is appropriate
* 1. Calls start_page() (if not %NULL). At this point, it is appropriate
* for the target to emit any page-specific header information into
* its output.
*
* 2. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_ANALYZE
* 2. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_ANALYZE
*
* 3. Replays the meta-surface to the target surface, (with an
* analysis surface inserted between which watches the return value
* from each operation). This analysis stage is used to decide which
* operations will require fallbacks.
*
* 4. Calls set_bounding_box to provide the target surface with the
* 4. Calls set_bounding_box() to provide the target surface with the
* tight bounding box of the page.
*
* 5. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_RENDER
* 5. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_RENDER
*
* 6. Replays a subset of the meta-surface operations to the target surface
*
* 7. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_FALLBACK
* 7. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_FALLBACK
*
* 8. Replays the remaining operations to an image surface, sets an
* appropriate clip on the target, then paints the resulting image

View File

@ -89,7 +89,7 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
* evidence of the paginated wrapper out to the user. */
surface->base.type = cairo_surface_get_type (target);
surface->target = target;
surface->target = cairo_surface_reference (target);
surface->content = content;
surface->width = width;
@ -316,6 +316,15 @@ _paint_page (cairo_paginated_surface_t *surface)
goto FAIL;
}
if (surface->backend->set_fallback_images_required) {
cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis);
status = surface->backend->set_fallback_images_required (surface->target,
has_fallbacks);
if (status)
goto FAIL;
}
surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER);
/* Finer grained fallbacks are currently only supported for some
@ -595,13 +604,26 @@ _cairo_paginated_surface_fill (void *abstract_surface,
tolerance, antialias);
}
static cairo_bool_t
_cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface)
{
cairo_paginated_surface_t *surface = abstract_surface;
return _cairo_surface_has_show_text_glyphs (surface->target);
}
static cairo_int_status_t
_cairo_paginated_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_paginated_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_int_status_t status;
@ -613,8 +635,8 @@ _cairo_paginated_surface_show_glyphs (void *abstract_surface,
surface->page_is_blank = FALSE;
/* Since this is a "wrapping" surface, we're calling back into
* _cairo_surface_show_glyphs from within a call to the same.
* Since _cairo_surface_show_glyphs acquires a mutex, we release
* _cairo_surface_show_text_glyphs from within a call to the same.
* Since _cairo_surface_show_text_glyphs acquires a mutex, we release
* and re-acquire the mutex around this nested call.
*
* Yes, this is ugly, but we consider it pragmatic as compared to
@ -623,9 +645,12 @@ _cairo_paginated_surface_show_glyphs (void *abstract_surface,
* lead to bugs).
*/
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
status = _cairo_surface_show_glyphs (surface->meta, op, source,
glyphs, num_glyphs,
scaled_font);
status = _cairo_surface_show_text_glyphs (surface->meta, op, source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
backward,
scaled_font);
CAIRO_MUTEX_LOCK (scaled_font->mutex);
return status;
@ -666,6 +691,12 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
_cairo_paginated_surface_mask,
_cairo_paginated_surface_stroke,
_cairo_paginated_surface_fill,
_cairo_paginated_surface_show_glyphs,
_cairo_paginated_surface_snapshot
NULL, /* show_glyphs */
_cairo_paginated_surface_snapshot,
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
_cairo_paginated_surface_has_show_text_glyphs,
_cairo_paginated_surface_show_text_glyphs
};

View File

@ -476,7 +476,7 @@ static int const num_args[] =
};
cairo_status_t
_cairo_path_fixed_interpret (cairo_path_fixed_t *path,
_cairo_path_fixed_interpret (const cairo_path_fixed_t *path,
cairo_direction_t dir,
cairo_path_fixed_move_to_func_t *move_to,
cairo_path_fixed_line_to_func_t *line_to,
@ -485,7 +485,7 @@ _cairo_path_fixed_interpret (cairo_path_fixed_t *path,
void *closure)
{
cairo_status_t status;
cairo_path_buf_t *buf;
const cairo_path_buf_t *buf;
cairo_path_op_t op;
cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD);
int step = forward ? 1 : -1;
@ -541,6 +541,52 @@ _cairo_path_fixed_interpret (cairo_path_fixed_t *path,
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_append_move_to (void *closure,
cairo_point_t *point)
{
cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
return _cairo_path_fixed_move_to (path, point->x, point->y);
}
static cairo_status_t
_append_line_to (void *closure,
cairo_point_t *point)
{
cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
return _cairo_path_fixed_line_to (path, point->x, point->y);
}
static cairo_status_t
_append_curve_to (void *closure,
cairo_point_t *p0,
cairo_point_t *p1,
cairo_point_t *p2)
{
cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
return _cairo_path_fixed_curve_to (path, p0->x, p0->y, p1->x, p1->y, p2->x, p2->y);
}
static cairo_status_t
_append_close_path (void *closure)
{
cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
return _cairo_path_fixed_close_path (path);
}
cairo_private cairo_status_t
_cairo_path_fixed_append (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other,
cairo_direction_t dir)
{
return _cairo_path_fixed_interpret (other, dir,
_append_move_to,
_append_line_to,
_append_curve_to,
_append_close_path,
path);
}
static void
_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
cairo_fixed_t offx,
@ -566,29 +612,47 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
}
}
/**
* _cairo_path_fixed_device_transform:
* _cairo_path_fixed_transform:
* @path: a #cairo_path_fixed_t to be transformed
* @device_transform: a matrix with only scaling/translation (no rotation or shear)
* @matrix: a #cairo_matrix_t
*
* Transform the fixed-point path according to the scaling and
* translation of the given matrix. This function assert()s that the
* given matrix has no rotation or shear elements, (that is, xy and yx
* are 0.0).
* Transform the fixed-point path according to the given matrix.
* There is a fast path for the case where @matrix has no rotation
* or shear.
**/
void
_cairo_path_fixed_device_transform (cairo_path_fixed_t *path,
cairo_matrix_t *device_transform)
_cairo_path_fixed_transform (cairo_path_fixed_t *path,
cairo_matrix_t *matrix)
{
assert (device_transform->yx == 0.0 && device_transform->xy == 0.0);
/* XXX: Support freeform matrices someday (right now, only translation and scale
* work. */
_cairo_path_fixed_offset_and_scale (path,
_cairo_fixed_from_double (device_transform->x0),
_cairo_fixed_from_double (device_transform->y0),
_cairo_fixed_from_double (device_transform->xx),
_cairo_fixed_from_double (device_transform->yy));
cairo_path_buf_t *buf;
int i;
double dx, dy;
if (matrix->yx == 0.0 && matrix->xy == 0.0) {
/* Fast path for the common case of scale+transform */
_cairo_path_fixed_offset_and_scale (path,
_cairo_fixed_from_double (matrix->x0),
_cairo_fixed_from_double (matrix->y0),
_cairo_fixed_from_double (matrix->xx),
_cairo_fixed_from_double (matrix->yy));
return;
}
buf = &path->buf_head.base;
while (buf) {
for (i = 0; i < buf->num_points; i++) {
dx = _cairo_fixed_to_double (buf->points[i].x);
dy = _cairo_fixed_to_double (buf->points[i].y);
cairo_matrix_transform_point (matrix, &dx, &dy);
buf->points[i].x = _cairo_fixed_from_double (dx);
buf->points[i].y = _cairo_fixed_from_double (dy);
}
buf = buf->next;
}
}
cairo_bool_t
@ -701,7 +765,7 @@ _cpf_close_path (void *closure)
cairo_status_t
_cairo_path_fixed_interpret_flat (cairo_path_fixed_t *path,
_cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path,
cairo_direction_t dir,
cairo_path_fixed_move_to_func_t *move_to,
cairo_path_fixed_line_to_func_t *line_to,
@ -805,14 +869,16 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
return FALSE;
}
/**
/*
* Check whether the given path contains a single rectangle
* that is logically equivalent to:
* <informalexample><programlisting>
* cairo_move_to (cr, x, y);
* cairo_rel_line_to (cr, width, 0);
* cairo_rel_line_to (cr, 0, height);
* cairo_rel_line_to (cr, -width, 0);
* cairo_close_path (cr);
* </programlisting></informalexample>
*/
cairo_bool_t
_cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,

View File

@ -1191,9 +1191,10 @@ typedef struct _cairo_rectilinear_stroker
cairo_point_t current_point;
cairo_point_t first_point;
cairo_bool_t open_sub_path;
cairo_line_t *segments;
int segments_size;
int num_segments;
int segments_size;
cairo_line_t *segments;
cairo_line_t segments_embedded[8]; /* common case is a single rectangle */
} cairo_rectilinear_stroker_t;
static void
@ -1206,15 +1207,16 @@ _cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t *stroker,
_cairo_fixed_from_double (stroke_style->line_width / 2.0);
stroker->traps = traps;
stroker->open_sub_path = FALSE;
stroker->segments = NULL;
stroker->segments_size = 0;
stroker->segments = stroker->segments_embedded;
stroker->segments_size = ARRAY_LENGTH (stroker->segments_embedded);
stroker->num_segments = 0;
}
static void
_cairo_rectilinear_stroker_fini (cairo_rectilinear_stroker_t *stroker)
{
free (stroker->segments);
if (stroker->segments != stroker->segments_embedded)
free (stroker->segments);
}
static cairo_status_t
@ -1222,18 +1224,24 @@ _cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker,
cairo_point_t *p1,
cairo_point_t *p2)
{
int new_size;
cairo_line_t *new_segments;
if (stroker->num_segments == stroker->segments_size) {
new_size = stroker->segments_size * 2;
/* Common case is one rectangle of exactly 4 segments. */
if (new_size == 0)
new_size = 4;
new_segments = _cairo_realloc_ab (stroker->segments,
new_size, sizeof (cairo_line_t));
if (new_segments == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
int new_size = stroker->segments_size * 2;
cairo_line_t *new_segments;
if (stroker->segments == stroker->segments_embedded) {
new_segments = _cairo_malloc_ab (new_size, sizeof (cairo_line_t));
if (new_segments == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (new_segments, stroker->segments,
stroker->num_segments * sizeof (cairo_line_t));
} else {
new_segments = _cairo_realloc_ab (stroker->segments,
new_size, sizeof (cairo_line_t));
if (new_segments == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
stroker->segments_size = new_size;
stroker->segments = new_segments;
@ -1390,8 +1398,7 @@ _cairo_rectilinear_stroker_line_to (void *closure,
if (a->x == b->x && a->y == b->y)
return CAIRO_STATUS_SUCCESS;
status = _cairo_rectilinear_stroker_add_segment (stroker,
a, b);
status = _cairo_rectilinear_stroker_add_segment (stroker, a, b);
stroker->current_point = *point;
stroker->open_sub_path = TRUE;

View File

@ -50,7 +50,7 @@ static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = {
CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */
};
const cairo_solid_pattern_t cairo_pattern_none = {
const cairo_solid_pattern_t _cairo_pattern_none = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_SUCCESS, /* status */
@ -63,10 +63,10 @@ const cairo_solid_pattern_t cairo_pattern_none = {
/**
* _cairo_pattern_set_error:
* @pattern: a pattern
* @status: a status value indicating an error, (eg. not
* CAIRO_STATUS_SUCCESS)
* @status: a status value indicating an error
*
* Atomically sets pattern->status to @status and calls _cairo_error;
* Does nothing if status is %CAIRO_STATUS_SUCCESS.
*
* All assignments of an error status to pattern->status should happen
* through _cairo_pattern_set_error(). Note that due to the nature of
@ -81,6 +81,9 @@ static cairo_status_t
_cairo_pattern_set_error (cairo_pattern_t *pattern,
cairo_status_t status)
{
if (status == CAIRO_STATUS_SUCCESS)
return status;
/* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&pattern->status, status);
@ -252,6 +255,9 @@ _cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
const cairo_color_t *color,
cairo_content_t content)
{
if (content == CAIRO_CONTENT_COLOR_ALPHA && CAIRO_COLOR_IS_OPAQUE (color))
content = CAIRO_CONTENT_COLOR;
_cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID);
pattern->color = *color;
pattern->content = content;
@ -358,7 +364,8 @@ _cairo_pattern_reset_solid_pattern_cache (void)
CAIRO_MUTEX_LOCK (_cairo_pattern_solid_pattern_cache_lock);
for (i = 0; i < MIN (ARRAY_LENGTH (solid_pattern_cache.patterns), solid_pattern_cache.size); i++) {
free (solid_pattern_cache.patterns[i]);
if (solid_pattern_cache.patterns[i])
free (solid_pattern_cache.patterns[i]);
solid_pattern_cache.patterns[i] = NULL;
}
solid_pattern_cache.size = 0;
@ -376,8 +383,7 @@ _cairo_pattern_create_in_error (cairo_status_t status)
CAIRO_MUTEX_INITIALIZE ();
pattern = _cairo_pattern_create_solid (_cairo_stock_color (CAIRO_STOCK_BLACK),
CAIRO_CONTENT_COLOR);
pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK, CAIRO_CONTENT_COLOR);
if (pattern->status == CAIRO_STATUS_SUCCESS)
status = _cairo_pattern_set_error (pattern, status);
@ -1364,6 +1370,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
#define MAX_SURFACE_CACHE_SIZE 16
static struct {
struct _cairo_pattern_solid_surface_cache{
cairo_content_t content;
cairo_color_t color;
cairo_surface_t *surface;
} cache[MAX_SURFACE_CACHE_SIZE];
@ -1376,10 +1383,10 @@ _cairo_pattern_solid_surface_matches (
const cairo_solid_pattern_t *pattern,
cairo_surface_t *dst)
{
if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
if (cache->content != pattern->content)
return FALSE;
if (! _cairo_color_equal (&cache->color, &pattern->color))
if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
return FALSE;
if (! _cairo_surface_is_similar (cache->surface, dst, pattern->content))
@ -1388,6 +1395,18 @@ _cairo_pattern_solid_surface_matches (
return TRUE;
}
static cairo_bool_t
_cairo_pattern_solid_surface_matches_color (
const struct _cairo_pattern_solid_surface_cache *cache,
const cairo_solid_pattern_t *pattern,
cairo_surface_t *dst)
{
if (! _cairo_color_equal (&cache->color, &pattern->color))
return FALSE;
return _cairo_pattern_solid_surface_matches (cache, pattern, dst);
}
static cairo_int_status_t
_cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
cairo_surface_t *dst,
@ -1400,61 +1419,89 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
{
static int i;
cairo_surface_t *surface;
cairo_surface_t *surface, *to_destroy = NULL;
cairo_status_t status;
CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
/* Check cache first */
if (i < solid_surface_cache.size &&
_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
pattern,
dst))
_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
pattern,
dst))
{
if (! _cairo_surface_reset (solid_surface_cache.cache[i].surface))
goto DONE;
status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
if (status)
goto UNLOCK;
goto DONE;
}
for (i = 0 ; i < solid_surface_cache.size; i++) {
if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
pattern,
dst))
if (_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
pattern,
dst))
{
if (! _cairo_surface_reset (solid_surface_cache.cache[i].surface))
goto DONE;
status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
if (status)
goto UNLOCK;
goto DONE;
}
}
/* Not cached, need to create new */
surface = _cairo_surface_create_similar_solid (dst,
pattern->content,
1, 1,
&pattern->color,
&pattern->base);
if (surface->status) {
status = surface->status;
goto UNLOCK;
}
if (! _cairo_surface_is_similar (surface, dst, pattern->content)) {
/* in the rare event of a substitute surface being returned (e.g.
* malloc failure) don't cache the fallback surface */
*out = surface;
goto NOCACHE;
}
/* Cache new */
if (solid_surface_cache.size < MAX_SURFACE_CACHE_SIZE) {
solid_surface_cache.size++;
} else {
/* Choose a surface to repaint/evict */
surface = NULL;
if (solid_surface_cache.size == MAX_SURFACE_CACHE_SIZE) {
i = rand () % MAX_SURFACE_CACHE_SIZE;
surface = solid_surface_cache.cache[i].surface;
/* Evict old */
cairo_surface_destroy (solid_surface_cache.cache[i].surface);
if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
pattern,
dst))
{
/* Reuse the surface instead of evicting */
status = _cairo_surface_reset (surface);
if (status)
goto EVICT;
status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern);
if (status)
goto EVICT;
cairo_surface_reference (surface);
}
else
{
EVICT:
surface = NULL;
}
}
solid_surface_cache.cache[i].color = pattern->color;
if (surface == NULL) {
/* Not cached, need to create new */
surface = _cairo_surface_create_solid_pattern_surface (dst, pattern);
if (surface->status) {
status = surface->status;
goto UNLOCK;
}
if (! _cairo_surface_is_similar (surface, dst, pattern->content)) {
/* in the rare event of a substitute surface being returned (e.g.
* malloc failure) don't cache the fallback surface */
*out = surface;
goto NOCACHE;
}
}
if (i == solid_surface_cache.size)
solid_surface_cache.size++;
to_destroy = solid_surface_cache.cache[i].surface;
solid_surface_cache.cache[i].surface = surface;
solid_surface_cache.cache[i].color = pattern->color;
solid_surface_cache.cache[i].content = pattern->content;
DONE:
*out = cairo_surface_reference (solid_surface_cache.cache[i].surface);
@ -1471,19 +1518,32 @@ NOCACHE:
UNLOCK:
CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
if (to_destroy)
cairo_surface_destroy (to_destroy);
return status;
}
static void
_cairo_pattern_reset_solid_surface_cache (void)
{
int i;
CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
for (i = 0; i < solid_surface_cache.size; i++)
cairo_surface_destroy (solid_surface_cache.cache[i].surface);
solid_surface_cache.size = 0;
/* remove surfaces starting from the end so that solid_surface_cache.cache
* is always in a consistent state when we release the mutex. */
while (solid_surface_cache.size) {
cairo_surface_t *surface;
solid_surface_cache.size--;
surface = solid_surface_cache.cache[solid_surface_cache.size].surface;
solid_surface_cache.cache[solid_surface_cache.size].surface = NULL;
/* release the lock to avoid the possibility of a recursive
* deadlock when the scaled font destroy closure gets called */
CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
cairo_surface_destroy (surface);
CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
}
CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
}
@ -1793,18 +1853,11 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
src->stops->color.blue,
src->stops->color.alpha);
_cairo_pattern_init_solid (&solid, &color,
CAIRO_COLOR_IS_OPAQUE (&color) ?
CAIRO_CONTENT_COLOR :
CAIRO_CONTENT_COLOR_ALPHA);
_cairo_pattern_init_solid (&solid, &color, CAIRO_CONTENT_COLOR_ALPHA);
}
else
{
const cairo_color_t *color;
color = _cairo_stock_color (CAIRO_STOCK_TRANSPARENT);
_cairo_pattern_init_solid (&solid, color,
CAIRO_CONTENT_ALPHA);
_cairo_pattern_init_solid (&solid, CAIRO_COLOR_TRANSPARENT, CAIRO_CONTENT_ALPHA);
}
status = _cairo_pattern_acquire_surface_for_solid (&solid, dst,
@ -1907,10 +1960,7 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src,
combined = src_solid->color;
_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
_cairo_pattern_init_solid (&src_tmp.solid, &combined,
CAIRO_COLOR_IS_OPAQUE (&combined) ?
CAIRO_CONTENT_COLOR :
CAIRO_CONTENT_COLOR_ALPHA);
_cairo_pattern_init_solid (&src_tmp.solid, &combined, CAIRO_CONTENT_COLOR_ALPHA);
mask = NULL;
}
@ -2028,15 +2078,10 @@ _cairo_pattern_get_extents (cairo_pattern_t *pattern,
* horizontal/vertical linear gradients).
*/
/* XXX: because extents are represented as x, y, w, h we can't
* actually have a rectangle that covers our entire valid
* coordinate space, since we'd need width/height to be 2*INT_MAX.
*/
extents->x = 0;
extents->y = 0;
extents->width = CAIRO_RECT_INT_MAX;
extents->height = CAIRO_RECT_INT_MAX;
extents->x = CAIRO_RECT_INT_MIN;
extents->y = CAIRO_RECT_INT_MIN;
extents->width = CAIRO_RECT_INT_MIN + CAIRO_RECT_INT_MAX;
extents->height = CAIRO_RECT_INT_MIN + CAIRO_RECT_INT_MAX;
return CAIRO_STATUS_SUCCESS;
}

View File

@ -45,16 +45,51 @@
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
/* The glyph buffer size is based on the expected maximum glyphs in a
* line so that an entire line can be emitted in as one string. If the
* glyphs in a line exceeds this size the only downside is the slight
* overhead of emitting two strings.
*/
#define PDF_GLYPH_BUFFER_SIZE 200
typedef cairo_status_t (*cairo_pdf_operators_use_font_subset_t) (unsigned int font_id,
unsigned int subset_id,
void *closure);
typedef struct _cairo_pdf_glyph {
unsigned int glyph_index;
double x_position;
double x_advance;
} cairo_pdf_glyph_t;
typedef struct _cairo_pdf_operators {
cairo_output_stream_t *stream;
cairo_matrix_t cairo_to_pdf;
cairo_scaled_font_subsets_t *font_subsets;
cairo_pdf_operators_use_font_subset_t use_font_subset;
void *use_font_subset_closure;
cairo_bool_t in_text_object; /* inside BT/ET pair */
/* PDF text state */
cairo_bool_t is_new_text_object; /* text object started but matrix and font not yet selected */
unsigned int font_id;
unsigned int subset_id;
cairo_matrix_t text_matrix; /* PDF text matrix (Tlm in the PDF reference) */
cairo_matrix_t cairo_to_pdftext; /* translate cairo coords to PDF text space */
cairo_matrix_t font_matrix_inverse;
double cur_x; /* Current position in PDF text space (Tm in the PDF reference) */
double cur_y;
int hex_width;
int num_glyphs;
cairo_pdf_glyph_t glyphs[PDF_GLYPH_BUFFER_SIZE];
/* PDF line style */
cairo_bool_t has_line_style;
double line_width;
cairo_line_cap_t line_cap;
cairo_line_join_t line_join;
double miter_limit;
cairo_bool_t has_dashes;
} cairo_pdf_operators_t;
cairo_private void
@ -63,7 +98,7 @@ _cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators,
cairo_matrix_t *cairo_to_pdf,
cairo_scaled_font_subsets_t *font_subsets);
cairo_private void
cairo_private cairo_status_t
_cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators);
cairo_private void
@ -80,11 +115,22 @@ cairo_private void
_cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators,
cairo_matrix_t *cairo_to_pdf);
cairo_private cairo_status_t
_cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators);
cairo_private void
_cairo_pdf_operators_reset (cairo_pdf_operators_t *pdf_operators);
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_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
cairo_stroke_style_t *style,
double scale);
cairo_private cairo_int_status_t
_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
@ -106,9 +152,15 @@ _cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
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);
_cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font);
#endif /* CAIRO_PDF_OPERATORS_H */

View File

@ -47,6 +47,10 @@
#include <ctype.h>
static cairo_status_t
_cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators);
void
_cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream,
@ -58,11 +62,15 @@ _cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators,
pdf_operators->font_subsets = font_subsets;
pdf_operators->use_font_subset = NULL;
pdf_operators->use_font_subset_closure = NULL;
pdf_operators->in_text_object = FALSE;
pdf_operators->num_glyphs = 0;
pdf_operators->has_line_style = FALSE;
}
void
cairo_status_t
_cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators)
{
return _cairo_pdf_operators_flush (pdf_operators);
}
void
@ -74,11 +82,16 @@ _cairo_pdf_operators_set_font_subsets_callback (cairo_pdf_operators_t *pdf
pdf_operators->use_font_subset_closure = closure;
}
/* Change the output stream to a different stream.
* _cairo_pdf_operators_flush() should always be called before calling
* this function.
*/
void
_cairo_pdf_operators_set_stream (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream)
{
pdf_operators->stream = stream;
pdf_operators->has_line_style = FALSE;
}
void
@ -86,6 +99,45 @@ _cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operato
cairo_matrix_t *cairo_to_pdf)
{
pdf_operators->cairo_to_pdf = *cairo_to_pdf;
pdf_operators->has_line_style = FALSE;
}
/* Finish writing out any pending commands to the stream. This
* function must be called by the surface before emitting anything
* into the PDF stream.
*
* pdf_operators may leave the emitted PDF for some operations
* unfinished in case subsequent operations can be merged. This
* function will finish off any incomplete operation so the stream
* will be in a state where the surface may emit it's own PDF
* operations (eg changing patterns).
*
*/
cairo_status_t
_cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
if (pdf_operators->in_text_object)
status = _cairo_pdf_operators_end_text (pdf_operators);
return status;
}
/* Reset the known graphics state of the PDF consumer. ie no
* assumptions will be made about the state. The next time a
* particular graphics state is required (eg line width) the state
* operator is always emitted and then remembered for subsequent
* operatations.
*
* This should be called when starting a new stream or after emitting
* the 'Q' operator (where pdf-operators functions were called inside
* the q/Q pair).
*/
void
_cairo_pdf_operators_reset (cairo_pdf_operators_t *pdf_operators)
{
pdf_operators->has_line_style = FALSE;
}
/* A word wrap stream can be used as a filter to do word wrapping on
@ -478,7 +530,7 @@ _cairo_pdf_line_join (cairo_line_join_t join)
}
}
static cairo_int_status_t
cairo_int_status_t
_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
cairo_stroke_style_t *style,
double scale)
@ -486,6 +538,7 @@ _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
double *dash = style->dash;
int num_dashes = style->num_dashes;
double dash_offset = style->dash_offset;
double line_width = style->line_width * scale;
/* PostScript has "special needs" when it comes to zero-length
* dash segments with butt caps. It apparently (at least
@ -550,17 +603,26 @@ _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
}
}
_cairo_output_stream_printf (pdf_operators->stream,
"%f w\n",
style->line_width * scale);
if (!pdf_operators->has_line_style || pdf_operators->line_width != line_width) {
_cairo_output_stream_printf (pdf_operators->stream,
"%f w\n",
line_width);
pdf_operators->line_width = line_width;
}
_cairo_output_stream_printf (pdf_operators->stream,
"%d J\n",
_cairo_pdf_line_cap (style->line_cap));
if (!pdf_operators->has_line_style || pdf_operators->line_cap != style->line_cap) {
_cairo_output_stream_printf (pdf_operators->stream,
"%d J\n",
_cairo_pdf_line_cap (style->line_cap));
pdf_operators->line_cap = style->line_cap;
}
_cairo_output_stream_printf (pdf_operators->stream,
"%d j\n",
_cairo_pdf_line_join (style->line_join));
if (!pdf_operators->has_line_style || pdf_operators->line_join != style->line_join) {
_cairo_output_stream_printf (pdf_operators->stream,
"%d j\n",
_cairo_pdf_line_join (style->line_join));
pdf_operators->line_join = style->line_join;
}
if (num_dashes) {
int d;
@ -570,15 +632,21 @@ _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
_cairo_output_stream_printf (pdf_operators->stream, " %f", dash[d] * scale);
_cairo_output_stream_printf (pdf_operators->stream, "] %f d\n",
dash_offset * scale);
} else {
pdf_operators->has_dashes = TRUE;
} else if (!pdf_operators->has_line_style || pdf_operators->has_dashes) {
_cairo_output_stream_printf (pdf_operators->stream, "[] 0.0 d\n");
pdf_operators->has_dashes = FALSE;
}
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);
if (!pdf_operators->has_line_style || pdf_operators->miter_limit != style->miter_limit) {
_cairo_output_stream_printf (pdf_operators->stream,
"%f M ",
style->miter_limit < 1.0 ? 1.0 : style->miter_limit);
pdf_operators->miter_limit = style->miter_limit;
}
pdf_operators->has_line_style = TRUE;
return _cairo_output_stream_get_status (pdf_operators->stream);
}
@ -622,6 +690,9 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_bool_t has_ctm = TRUE;
double scale = 1.0;
if (pdf_operators->in_text_object)
status = _cairo_pdf_operators_end_text (pdf_operators);
/* Optimize away the stroke ctm when it does not affect the
* stroke. There are other ctm cases that could be optimized
* however this is the most common.
@ -717,6 +788,9 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
const char *pdf_operator;
cairo_status_t status;
if (pdf_operators->in_text_object)
status = _cairo_pdf_operators_end_text (pdf_operators);
status = _cairo_pdf_operators_emit_path (pdf_operators,
path,
&pdf_operators->cairo_to_pdf,
@ -773,205 +847,567 @@ _cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
#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)
/* Emit the string of glyphs using the 'Tj' operator. This requires
* that the glyphs are positioned at their natural glyph advances. */
static cairo_status_t
_cairo_pdf_operators_emit_glyph_string (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream)
{
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, status_ignored;
double Tlm_x = 0, Tlm_y = 0;
double Tm_x = 0, y;
int i, hex_width;
cairo_output_stream_t *word_wrap_stream;
int i;
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 (stream, "<");
for (i = 0; i < pdf_operators->num_glyphs; i++) {
_cairo_output_stream_printf (stream,
"%0*x",
pdf_operators->hex_width,
pdf_operators->glyphs[i].glyph_index);
pdf_operators->cur_x += pdf_operators->glyphs[i].x_advance;
}
_cairo_output_stream_printf (stream, ">Tj\n");
return _cairo_output_stream_get_status (stream);
}
/* Emit the string of glyphs using the 'TJ' operator.
*
* The TJ operator takes an array of strings of glyphs. Each string of
* glyphs is displayed using the glyph advances of each glyph to
* position the glyphs. A relative adjustment to the glyph advance may
* be specified by including the adjustment between two strings. The
* adjustment is in units of text space * -1000.
*/
static cairo_status_t
_cairo_pdf_operators_emit_glyph_string_with_positioning (
cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream)
{
int i;
_cairo_output_stream_printf (stream, "[<");
for (i = 0; i < pdf_operators->num_glyphs; i++) {
if (pdf_operators->glyphs[i].x_position != pdf_operators->cur_x)
{
double delta = pdf_operators->glyphs[i].x_position - pdf_operators->cur_x;
int rounded_delta;
delta = -1000.0*delta;
/* As the delta is in 1/1000 of a unit of text space,
* rounding to an integer should still provide sufficient
* precision. We round the delta before adding to Tm_x so
* that we keep track of the accumulated rounding error in
* the PDF interpreter and compensate for it when
* calculating subsequent deltas.
*/
rounded_delta = _cairo_lround (delta);
if (rounded_delta != 0) {
_cairo_output_stream_printf (stream,
">%d<",
rounded_delta);
}
/* Convert the rounded delta back to text
* space before adding to the current text
* position. */
delta = rounded_delta/-1000.0;
pdf_operators->cur_x += delta;
}
_cairo_output_stream_printf (stream,
"%0*x",
pdf_operators->hex_width,
pdf_operators->glyphs[i].glyph_index);
pdf_operators->cur_x += pdf_operators->glyphs[i].x_advance;
}
_cairo_output_stream_printf (stream, ">]TJ\n");
return _cairo_output_stream_get_status (stream);
}
static cairo_status_t
_cairo_pdf_operators_flush_glyphs (cairo_pdf_operators_t *pdf_operators)
{
cairo_output_stream_t *word_wrap_stream;
cairo_status_t status;
int i;
double x;
if (pdf_operators->num_glyphs == 0)
return 0;
word_wrap_stream = _word_wrap_stream_create (pdf_operators->stream, 72);
status = _cairo_output_stream_get_status (word_wrap_stream);
if (status)
return _cairo_output_stream_destroy (word_wrap_stream);
_cairo_output_stream_printf (word_wrap_stream,
"BT\n");
if (scaled_font->scale.xy == 0.0 &&
scaled_font->scale.yx == 0.0)
diagonal = TRUE;
else
diagonal = FALSE;
in_TJ = FALSE;
for (i = 0; i < num_glyphs; i++) {
status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
scaled_font, glyphs[i].index,
&subset_glyph);
if (status) {
status_ignored = _cairo_output_stream_destroy (word_wrap_stream);
return status;
}
if (subset_glyph.is_composite)
hex_width = 4;
else
hex_width = 2;
if (subset_glyph.is_scaled == FALSE) {
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 (word_wrap_stream, ">] TJ\n");
in_TJ = FALSE;
}
_cairo_output_stream_printf (word_wrap_stream,
"/f-%d-%d 1 Tf\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) {
status_ignored = _cairo_output_stream_destroy (word_wrap_stream);
return status;
}
}
}
if (subset_glyph.subset_id != current_subset_id || !diagonal) {
_cairo_output_stream_printf (word_wrap_stream,
"%f %f %f %f %f %f Tm\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;
Tlm_x = glyphs[i].x;
Tlm_y = glyphs[i].y;
Tm_x = Tlm_x;
}
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 (word_wrap_stream,
"%f %f Td\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 (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;
int rounded_delta;
delta = -1000.0*delta/scaled_font->scale.xx;
/* As the delta is in 1/1000 of a unit of text
* space, rounding to an integer should still
* provide sufficient precision. We round the
* delta before adding to Tm_x so that we keep
* track of the accumulated rounding error in
* the PDF interpreter and compensate for it
* when calculating subsequent deltas.
*/
rounded_delta = _cairo_lround (delta);
if (rounded_delta != 0) {
_cairo_output_stream_printf (word_wrap_stream,
"> %d <",
rounded_delta);
}
/* Convert the rounded delta back to cairo
* space before adding to the current text
* position. */
delta = rounded_delta*scaled_font->scale.xx/-1000.0;
Tm_x += delta;
}
_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;
int rounded_delta;
delta = -1000.0*delta/scaled_font->scale.xx;
rounded_delta = _cairo_lround (delta);
if (rounded_delta != 0) {
_cairo_output_stream_printf (word_wrap_stream,
"> %d <",
rounded_delta);
}
delta = rounded_delta*scaled_font->scale.xx/-1000.0;
Tm_x += delta;
}
_cairo_output_stream_printf (word_wrap_stream,
"%0*x>] TJ\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 (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 (word_wrap_stream,
"<%0*x> Tj ",
hex_width,
subset_glyph.subset_glyph_index);
Tm_x += subset_glyph.x_advance;
}
}
} else {
_cairo_output_stream_printf (word_wrap_stream,
"<%0*x> Tj\n",
hex_width,
subset_glyph.subset_glyph_index);
}
/* Check if glyph advance used to position every glyph */
x = pdf_operators->cur_x;
for (i = 0; i < pdf_operators->num_glyphs; i++) {
if (fabs(pdf_operators->glyphs[i].x_position - x) > GLYPH_POSITION_TOLERANCE)
break;
x += pdf_operators->glyphs[i].x_advance;
}
if (i == pdf_operators->num_glyphs) {
status = _cairo_pdf_operators_emit_glyph_string (pdf_operators,
word_wrap_stream);
} else {
status = _cairo_pdf_operators_emit_glyph_string_with_positioning (
pdf_operators, word_wrap_stream);
}
_cairo_output_stream_printf (word_wrap_stream,
"ET\n");
pdf_operators->num_glyphs = 0;
status = _cairo_output_stream_destroy (word_wrap_stream);
if (status)
return status;
return status;
}
static cairo_status_t
_cairo_pdf_operators_add_glyph (cairo_pdf_operators_t *pdf_operators,
cairo_scaled_font_subsets_glyph_t *glyph,
double x_position)
{
double x, y;
x = glyph->x_advance;
y = glyph->y_advance;
if (glyph->is_scaled)
cairo_matrix_transform_distance (&pdf_operators->font_matrix_inverse, &x, &y);
pdf_operators->glyphs[pdf_operators->num_glyphs].x_position = x_position;
pdf_operators->glyphs[pdf_operators->num_glyphs].glyph_index = glyph->subset_glyph_index;
pdf_operators->glyphs[pdf_operators->num_glyphs].x_advance = x;
pdf_operators->num_glyphs++;
if (pdf_operators->num_glyphs == PDF_GLYPH_BUFFER_SIZE)
return _cairo_pdf_operators_flush_glyphs (pdf_operators);
return CAIRO_STATUS_SUCCESS;
}
/* Use 'Tm' operator to set the PDF text matrix. */
static cairo_status_t
_cairo_pdf_operators_set_text_matrix (cairo_pdf_operators_t *pdf_operators,
cairo_matrix_t *matrix)
{
cairo_matrix_t inverse;
cairo_status_t status;
/* We require the matrix to be invertable. */
inverse = *matrix;
status = cairo_matrix_invert (&inverse);
if (status)
return status;
pdf_operators->text_matrix = *matrix;
pdf_operators->cur_x = 0;
pdf_operators->cur_y = 0;
_cairo_output_stream_printf (pdf_operators->stream,
"%f %f %f %f %f %f Tm\n",
pdf_operators->text_matrix.xx,
pdf_operators->text_matrix.yx,
pdf_operators->text_matrix.xy,
pdf_operators->text_matrix.yy,
pdf_operators->text_matrix.x0,
pdf_operators->text_matrix.y0);
pdf_operators->cairo_to_pdftext = *matrix;
status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext);
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&pdf_operators->cairo_to_pdftext,
&pdf_operators->cairo_to_pdf,
&pdf_operators->cairo_to_pdftext);
return _cairo_output_stream_get_status (pdf_operators->stream);
}
#define TEXT_MATRIX_TOLERANCE 1e-6
/* Set the translation components of the PDF text matrix to x, y. The
* 'Td' operator is used to transform the text matrix.
*/
static cairo_status_t
_cairo_pdf_operators_set_text_position (cairo_pdf_operators_t *pdf_operators,
double x,
double y)
{
cairo_matrix_t translate, inverse;
cairo_status_t status;
/* The Td operator transforms the text_matrix with:
*
* text_matrix' = T x text_matrix
*
* where T is a translation matrix with the translation components
* set to the Td operands tx and ty.
*/
inverse = pdf_operators->text_matrix;
status = cairo_matrix_invert (&inverse);
assert (status == CAIRO_STATUS_SUCCESS);
pdf_operators->text_matrix.x0 = x;
pdf_operators->text_matrix.y0 = y;
cairo_matrix_multiply (&translate, &pdf_operators->text_matrix, &inverse);
if (fabs(translate.x0) < TEXT_MATRIX_TOLERANCE)
translate.x0 = 0.0;
if (fabs(translate.y0) < TEXT_MATRIX_TOLERANCE)
translate.y0 = 0.0;
_cairo_output_stream_printf (pdf_operators->stream,
"%f %f Td\n",
translate.x0,
translate.y0);
pdf_operators->cur_x = 0;
pdf_operators->cur_y = 0;
pdf_operators->cairo_to_pdftext = pdf_operators->text_matrix;
status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext);
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&pdf_operators->cairo_to_pdftext,
&pdf_operators->cairo_to_pdf,
&pdf_operators->cairo_to_pdftext);
return _cairo_output_stream_get_status (pdf_operators->stream);
}
/* Select the font using the 'Tf' operator. The font size is set to 1
* as we use the 'Tm' operator to set the font scale.
*/
static cairo_status_t
_cairo_pdf_operators_set_font_subset (cairo_pdf_operators_t *pdf_operators,
cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
cairo_status_t status;
_cairo_output_stream_printf (pdf_operators->stream,
"/f-%d-%d 1 Tf\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;
}
pdf_operators->font_id = subset_glyph->font_id;
pdf_operators->subset_id = subset_glyph->subset_id;
if (subset_glyph->is_composite)
pdf_operators->hex_width = 4;
else
pdf_operators->hex_width = 2;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_pdf_operators_begin_text (cairo_pdf_operators_t *pdf_operators)
{
_cairo_output_stream_printf (pdf_operators->stream, "BT\n");
pdf_operators->in_text_object = TRUE;
pdf_operators->num_glyphs = 0;
return _cairo_output_stream_get_status (pdf_operators->stream);
}
static cairo_status_t
_cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators)
{
cairo_status_t status;
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (pdf_operators->stream, "ET\n");
pdf_operators->in_text_object = FALSE;
return _cairo_output_stream_get_status (pdf_operators->stream);
}
/* Compare the scale components of two matrices. The translation
* components are ignored. */
static cairo_bool_t
_cairo_matrix_scale_equal (cairo_matrix_t *a, cairo_matrix_t *b)
{
return (a->xx == b->xx &&
a->xy == b->xy &&
a->yx == b->yx &&
a->yy == b->yy);
}
static cairo_status_t
_cairo_pdf_operators_begin_actualtext (cairo_pdf_operators_t *pdf_operators,
const char *utf8,
int utf8_len)
{
uint16_t *utf16;
int utf16_len;
cairo_status_t status;
int i;
_cairo_output_stream_printf (pdf_operators->stream, "/Span << /ActualText <feff");
if (utf8_len) {
status = _cairo_utf8_to_utf16 (utf8, utf8_len, &utf16, &utf16_len);
if (status)
return status;
for (i = 0; i < utf16_len; i++) {
_cairo_output_stream_printf (pdf_operators->stream,
"%04x", (int) (utf16[i]));
}
free (utf16);
}
_cairo_output_stream_printf (pdf_operators->stream, "> >> BDC\n");
return _cairo_output_stream_get_status (pdf_operators->stream);
}
static cairo_status_t
_cairo_pdf_operators_end_actualtext (cairo_pdf_operators_t *pdf_operators)
{
_cairo_output_stream_printf (pdf_operators->stream, "EMC\n");
return _cairo_output_stream_get_status (pdf_operators->stream);
}
static cairo_status_t
_cairo_pdf_operators_emit_glyph (cairo_pdf_operators_t *pdf_operators,
cairo_glyph_t *glyph,
cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
double x, y;
cairo_status_t status;
if (pdf_operators->is_new_text_object ||
pdf_operators->font_id != subset_glyph->font_id ||
pdf_operators->subset_id != subset_glyph->subset_id)
{
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
if (status)
return status;
status = _cairo_pdf_operators_set_font_subset (pdf_operators, subset_glyph);
if (status)
return status;
pdf_operators->is_new_text_object = FALSE;
}
x = glyph->x;
y = glyph->y;
cairo_matrix_transform_point (&pdf_operators->cairo_to_pdftext, &x, &y);
/* The TJ operator for displaying text strings can only set
* the horizontal position of the glyphs. If the y position
* (in text space) changes, use the Td operator to change the
* current position to the next glyph. We also use the Td
* operator to move the current position if the horizontal
* position changes by more than 10 (in text space
* units). This is becauses the horizontal glyph positioning
* in the TJ operator is intended for kerning and there may be
* PDF consumers that do not handle very large position
* adjustments in TJ.
*/
if (fabs(x - pdf_operators->cur_x) > 10 ||
fabs(y - pdf_operators->cur_y) > GLYPH_POSITION_TOLERANCE)
{
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
if (status)
return status;
x = glyph->x;
y = glyph->y;
cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y);
status = _cairo_pdf_operators_set_text_position (pdf_operators, x, y);
if (status)
return status;
x = 0.0;
y = 0.0;
}
status = _cairo_pdf_operators_add_glyph (pdf_operators,
subset_glyph,
x);
return status;
}
/* A utf8_len of -1 indicates no unicode text. A utf8_len = 0 is an
* empty string.
*/
static cairo_int_status_t
_cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font)
{
cairo_scaled_font_subsets_glyph_t subset_glyph;
cairo_glyph_t *cur_glyph;
cairo_status_t status;
int i;
/* If the cluster maps 1 glyph to 1 or more unicode characters, we
* first try _map_glyph() with the unicode string to see if it can
* use toUnicode to map our glyph to the unicode. This will fail
* if the glyph is already mapped to a different unicode string.
*
* We also go through this path if no unicode mapping was
* supplied (utf8_len < 0).
*
* Mapping a glyph to a zero length unicode string requires the
* use of ActualText.
*/
if (num_glyphs == 1 && utf8_len != 0) {
status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
scaled_font,
glyphs->index,
utf8,
utf8_len < 0 ? 0 : utf8_len,
&subset_glyph);
if (status)
return status;
if (subset_glyph.utf8_is_mapped || utf8_len < 0) {
status = _cairo_pdf_operators_emit_glyph (pdf_operators,
glyphs,
&subset_glyph);
return 0;
}
}
/* Fallback to using ActualText to map zero or more glyphs to a
* unicode string. */
_cairo_pdf_operators_flush_glyphs (pdf_operators);
status = _cairo_pdf_operators_begin_actualtext (pdf_operators, utf8, utf8_len);
cur_glyph = glyphs;
for (i = 0; i < num_glyphs; i++) {
status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
scaled_font,
cur_glyph->index,
NULL, 0,
&subset_glyph);
if (status)
return status;
status = _cairo_pdf_operators_emit_glyph (pdf_operators,
cur_glyph,
&subset_glyph);
if (status)
return status;
if (backward)
cur_glyph--;
else
cur_glyph++;
}
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
if (status)
return status;
status = _cairo_pdf_operators_end_actualtext (pdf_operators);
return status;
}
cairo_int_status_t
_cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font)
{
cairo_status_t status;
int i;
cairo_matrix_t text_matrix, invert_y_axis;
double x, y;
const char *cur_text;
cairo_glyph_t *cur_glyph;
pdf_operators->font_matrix_inverse = scaled_font->font_matrix;
status = cairo_matrix_invert (&pdf_operators->font_matrix_inverse);
if (status == CAIRO_STATUS_INVALID_MATRIX)
return CAIRO_STATUS_SUCCESS;
if (status)
return status;
pdf_operators->is_new_text_object = FALSE;
if (pdf_operators->in_text_object == FALSE) {
_cairo_pdf_operators_begin_text (pdf_operators);
/* Force Tm and Tf to be emitted when starting a new text
* object.*/
pdf_operators->is_new_text_object = TRUE;
}
cairo_matrix_init_scale (&invert_y_axis, 1, -1);
text_matrix = scaled_font->scale;
/* Invert y axis in font space */
cairo_matrix_multiply (&text_matrix, &text_matrix, &invert_y_axis);
/* Invert y axis in device space */
cairo_matrix_multiply (&text_matrix, &invert_y_axis, &text_matrix);
if (pdf_operators->is_new_text_object ||
! _cairo_matrix_scale_equal (&pdf_operators->text_matrix, &text_matrix))
{
_cairo_pdf_operators_flush_glyphs (pdf_operators);
x = glyphs[0].x;
y = glyphs[0].y;
cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y);
text_matrix.x0 = x;
text_matrix.y0 = y;
status = _cairo_pdf_operators_set_text_matrix (pdf_operators, &text_matrix);
if (status == CAIRO_STATUS_INVALID_MATRIX)
return CAIRO_STATUS_SUCCESS;
if (status)
return status;
}
if (num_clusters > 0) {
cur_text = utf8;
if (backward)
cur_glyph = glyphs + num_glyphs;
else
cur_glyph = glyphs;
for (i = 0; i < num_clusters; i++) {
if (backward)
cur_glyph -= clusters[i].num_glyphs;
status = _cairo_pdf_operators_emit_cluster (pdf_operators,
cur_text,
clusters[i].num_bytes,
cur_glyph,
clusters[i].num_glyphs,
backward,
scaled_font);
if (status)
return status;
cur_text += clusters[i].num_bytes;
if (!backward)
cur_glyph += clusters[i].num_glyphs;
}
} else {
for (i = 0; i < num_glyphs; i++) {
status = _cairo_pdf_operators_emit_cluster (pdf_operators,
NULL,
-1, /* no unicode string available */
&glyphs[i],
1,
FALSE,
scaled_font);
if (status)
return status;
}
}
return _cairo_output_stream_get_status (pdf_operators->stream);
}

View File

@ -90,8 +90,13 @@ typedef struct _cairo_pdf_smask_group
cairo_stroke_style_t *style;
cairo_matrix_t ctm;
cairo_matrix_t ctm_inverse;
char *utf8;
int utf8_len;
cairo_glyph_t *glyphs;
int num_glyphs;
cairo_text_cluster_t *clusters;
int num_clusters;
cairo_bool_t backward;
cairo_scaled_font_t *scaled_font;
} cairo_pdf_smask_group_t;
@ -153,6 +158,13 @@ struct _cairo_pdf_surface {
cairo_bool_t force_fallbacks;
cairo_bool_t current_pattern_is_solid_color;
cairo_bool_t current_color_is_stroke;
double current_color_red;
double current_color_green;
double current_color_blue;
double current_color_alpha;
cairo_surface_t *paginated_surface;
};

View File

@ -48,6 +48,7 @@
#include "cairo-paginated-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-type3-glyph-surface-private.h"
#include <time.h>
#include <zlib.h>
@ -281,6 +282,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->force_fallbacks = FALSE;
surface->select_pattern_gstate_saved = FALSE;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_init (&surface->pdf_operators,
surface->output,
@ -301,9 +303,13 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
CAIRO_CONTENT_COLOR_ALPHA,
width, height,
&cairo_pdf_surface_paginated_backend);
status = surface->paginated_surface->status;
if (status == CAIRO_STATUS_SUCCESS)
if (status == CAIRO_STATUS_SUCCESS) {
/* paginated keeps the only reference to surface now, drop ours */
cairo_surface_destroy (&surface->base);
return surface->paginated_surface;
}
BAIL1:
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
@ -741,8 +747,12 @@ _cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group)
cairo_pattern_destroy (group->source);
if (group->mask)
cairo_pattern_destroy (group->mask);
if (group->utf8)
free (group->utf8);
if (group->glyphs)
free (group->glyphs);
if (group->clusters)
free (group->clusters);
if (group->scaled_font)
cairo_scaled_font_destroy (group->scaled_font);
free (group);
@ -771,15 +781,23 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
/* Gradients with zero stops do not produce any output */
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
{
cairo_gradient_pattern_t *gradient;
gradient = (cairo_gradient_pattern_t *) pattern;
/* Gradients with zero stops do not produce any output */
if (gradient->n_stops == 0)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
/* Gradients with one stop are the same as solid colors */
if (gradient->n_stops == 1) {
pattern_res->id = 0;
gstate_res->id = 0;
return CAIRO_STATUS_SUCCESS;
}
}
pdf_pattern.pattern = cairo_pattern_reference (pattern);
@ -851,6 +869,8 @@ _cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface,
surface->pdf_stream.self = self;
surface->pdf_stream.length = length;
surface->pdf_stream.compressed = compressed;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\n"
@ -892,6 +912,10 @@ _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
if (! surface->pdf_stream.active)
return CAIRO_STATUS_SUCCESS;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
if (surface->pdf_stream.compressed) {
status = _cairo_output_stream_destroy (surface->output);
surface->output = surface->pdf_stream.old_output;
@ -982,6 +1006,8 @@ _cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface,
assert (surface->group_stream.active == FALSE);
surface->group_stream.active = TRUE;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
surface->group_stream.mem_stream = _cairo_memory_stream_create ();
@ -1033,6 +1059,10 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
assert (surface->pdf_stream.active == FALSE);
assert (surface->group_stream.active == TRUE);
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
if (surface->compress_content) {
status = _cairo_output_stream_destroy (surface->group_stream.stream);
surface->group_stream.stream = NULL;
@ -1116,6 +1146,10 @@ _cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface)
assert (surface->pdf_stream.active == TRUE);
assert (surface->group_stream.active == FALSE);
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output, "Q\n");
status = _cairo_pdf_surface_close_stream (surface);
if (status)
@ -1181,7 +1215,10 @@ _cairo_pdf_surface_finish (void *abstract_surface)
"%%%%EOF\n",
offset);
_cairo_pdf_operators_fini (&surface->pdf_operators);
status2 = _cairo_pdf_operators_fini (&surface->pdf_operators);
/* pdf_operators has already been flushed when the last stream was
* closed so we should never be writing anything here. */
assert(status2 == CAIRO_STATUS_SUCCESS);
/* close any active streams still open due to fatal errors */
status2 = _cairo_pdf_surface_close_stream (surface);
@ -1230,13 +1267,23 @@ _cairo_pdf_surface_finish (void *abstract_surface)
static cairo_int_status_t
_cairo_pdf_surface_start_page (void *abstract_surface)
{
cairo_pdf_surface_t *surface = abstract_surface;
_cairo_pdf_group_resources_clear (&surface->resources);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_pdf_surface_has_fallback_images (void *abstract_surface,
cairo_bool_t has_fallbacks)
{
cairo_status_t status;
cairo_pdf_surface_t *surface = abstract_surface;
surface->has_fallback_images = FALSE;
_cairo_pdf_group_resources_clear (&surface->resources);
status = _cairo_pdf_surface_open_content_stream (surface, TRUE);
surface->has_fallback_images = has_fallbacks;
status = _cairo_pdf_surface_open_content_stream (surface, has_fallbacks);
if (status)
return status;
@ -1496,7 +1543,7 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
cairo_paginated_mode_t old_paginated_mode;
cairo_clip_t *old_clip;
cairo_rectangle_int_t meta_extents;
cairo_status_t status, status2;
cairo_status_t status;
int alpha = 0;
status = _cairo_surface_get_extents (meta_surface, &meta_extents);
@ -1524,7 +1571,7 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
if (status)
goto CLEANUP_GROUP;
return status;
_cairo_output_stream_printf (surface->output,
"q /a%d gs 0 0 0 rg 0 0 %f %f re f Q\n",
@ -1537,18 +1584,18 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
CAIRO_META_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
if (status)
goto CLEANUP_GROUP;
return status;
status = _cairo_surface_set_clip (&surface->base, old_clip);
if (status)
return status;
status = _cairo_pdf_surface_close_content_stream (surface);
CLEANUP_GROUP:
_cairo_pdf_surface_set_size_internal (surface,
old_width,
old_height);
surface->paginated_mode = old_paginated_mode;
status2 = _cairo_surface_set_clip (&surface->base, old_clip);
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
return status;
}
@ -2562,29 +2609,73 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
{
cairo_status_t status;
int alpha;
cairo_bool_t is_solid_color = FALSE;
cairo_color_t *solid_color;
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *) pattern;
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
status = _cairo_pdf_surface_add_alpha (surface, solid_pattern->color.alpha, &alpha);
if (status)
return status;
is_solid_color = TRUE;
solid_color = &solid->color;
}
_cairo_output_stream_printf (surface->output,
"%f %f %f ",
solid_pattern->color.red,
solid_pattern->color.green,
solid_pattern->color.blue);
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
{
cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
if (is_stroke)
_cairo_output_stream_printf (surface->output, "RG ");
else
_cairo_output_stream_printf (surface->output, "rg ");
if (gradient->n_stops == 1) {
is_solid_color = TRUE;
solid_color = &gradient->stops[0].color;
}
}
_cairo_output_stream_printf (surface->output,
"/a%d gs\n",
alpha);
surface->select_pattern_gstate_saved = FALSE;
if (is_solid_color) {
if (surface->current_pattern_is_solid_color == FALSE ||
surface->current_color_red != solid_color->red ||
surface->current_color_green != solid_color->green ||
surface->current_color_blue != solid_color->blue ||
surface->current_color_is_stroke != is_stroke)
{
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"%f %f %f ",
solid_color->red,
solid_color->green,
solid_color->blue);
if (is_stroke)
_cairo_output_stream_printf (surface->output, "RG ");
else
_cairo_output_stream_printf (surface->output, "rg ");
surface->current_color_red = solid_color->red;
surface->current_color_green = solid_color->green;
surface->current_color_blue = solid_color->blue;
surface->current_color_is_stroke = is_stroke;
}
if (surface->current_pattern_is_solid_color == FALSE ||
surface->current_color_alpha != solid_color->alpha)
{
status = _cairo_pdf_surface_add_alpha (surface, solid_color->alpha, &alpha);
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"/a%d gs\n",
alpha);
surface->current_color_alpha = solid_color->alpha;
}
surface->current_pattern_is_solid_color = TRUE;
} else {
status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
if (status)
@ -2594,6 +2685,10 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
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)
@ -2612,17 +2707,28 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
"/a%d gs\n",
alpha);
surface->select_pattern_gstate_saved = TRUE;
surface->current_pattern_is_solid_color = FALSE;
}
return _cairo_output_stream_get_status (surface->output);
}
static void
static cairo_int_status_t
_cairo_pdf_surface_unselect_pattern (cairo_pdf_surface_t *surface)
{
if (surface->select_pattern_gstate_saved)
cairo_int_status_t status;
if (surface->select_pattern_gstate_saved) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output, "Q\n");
_cairo_pdf_operators_reset (&surface->pdf_operators);
}
surface->select_pattern_gstate_saved = FALSE;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
@ -2671,9 +2777,17 @@ _cairo_pdf_surface_intersect_clip_path (void *abstract_surface,
cairo_antialias_t antialias)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_int_status_t status;
if (path == NULL) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output, "Q q\n");
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
return CAIRO_STATUS_SUCCESS;
}
@ -2743,34 +2857,54 @@ _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface)
"endobj\n");
}
static cairo_status_t
_cairo_pdf_surface_emit_unicode_for_glyph (cairo_pdf_surface_t *surface,
const char *utf8)
{
uint16_t *utf16 = NULL;
int utf16_len = 0;
cairo_status_t status;
int i;
if (utf8 && *utf8) {
status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
if (status && status != CAIRO_STATUS_INVALID_STRING)
return status;
}
_cairo_output_stream_printf (surface->output, "<");
if (utf16 == NULL || utf16_len == 0) {
/* According to the "ToUnicode Mapping File Tutorial"
* http://www.adobe.com/devnet/acrobat/pdfs/5411.ToUnicode.pdf
*
* Glyphs that do not map to a Unicode code point must be
* mapped to 0xfffd "REPLACEMENT CHARACTER".
*/
_cairo_output_stream_printf (surface->output,
"fffd");
} else {
for (i = 0; i < utf16_len; i++)
_cairo_output_stream_printf (surface->output,
"%04x", (int) (utf16[i]));
}
_cairo_output_stream_printf (surface->output, ">");
if (utf16)
free (utf16);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
cairo_scaled_font_subset_t *font_subset,
cairo_bool_t is_composite,
cairo_pdf_resource_t *stream)
{
const cairo_scaled_font_backend_t *backend;
unsigned int i, num_bfchar;
cairo_int_status_t status;
stream->id = 0;
if (font_subset->to_unicode == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_truetype_create_glyph_to_unicode_map (font_subset);
if (status) {
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
backend = font_subset->scaled_font->backend;
if (backend->map_glyphs_to_unicode == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = backend->map_glyphs_to_unicode (font_subset->scaled_font,
font_subset);
if (status)
return status;
}
status = _cairo_pdf_surface_open_stream (surface,
NULL,
@ -2804,10 +2938,12 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
"endcodespacerange\n");
num_bfchar = font_subset->num_glyphs - 1;
/* The CMap specification has a limit of 100 characters per beginbfchar operator */
_cairo_output_stream_printf (surface->output,
"%d beginbfchar\n",
num_bfchar > 100 ? 100 : num_bfchar);
for (i = 0; i < num_bfchar; i++) {
if (i != 0 && i % 100 == 0) {
_cairo_output_stream_printf (surface->output,
@ -2817,13 +2953,16 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
}
if (is_composite) {
_cairo_output_stream_printf (surface->output,
"<%04x> <%04lx>\n",
i + 1, font_subset->to_unicode[i + 1]);
"<%04x> ",
i + 1);
} else {
_cairo_output_stream_printf (surface->output,
"<%02x> <%04lx>\n",
i + 1, font_subset->to_unicode[i + 1]);
"<%02x> ",
i + 1);
}
_cairo_pdf_surface_emit_unicode_for_glyph (surface, font_subset->utf8[i + 1]);
_cairo_output_stream_printf (surface->output,
"\n");
}
_cairo_output_stream_printf (surface->output,
"endbfchar\n");
@ -3301,71 +3440,18 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
return status;
}
static cairo_int_status_t
_cairo_pdf_surface_emit_bitmap_glyph (cairo_pdf_surface_t *surface,
cairo_scaled_font_t *scaled_font,
unsigned long glyph_index,
cairo_pdf_resource_t *glyph_ret,
cairo_box_t *bbox,
double *width)
static cairo_status_t
_cairo_pdf_emit_imagemask (cairo_image_surface_t *image,
cairo_output_stream_t *stream)
{
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;
unsigned char *byte, output_byte;
int row, col, num_cols;
status = _cairo_scaled_glyph_lookup (scaled_font,
glyph_index,
CAIRO_SCALED_GLYPH_INFO_METRICS|
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
if (status)
return status;
/* The only image type supported by Type 3 fonts are 1-bit image
* masks */
assert (image->format == CAIRO_FORMAT_A1);
x_advance = scaled_glyph->metrics.x_advance;
y_advance = scaled_glyph->metrics.y_advance;
cairo_matrix_transform_distance (&scaled_font->ctm, &x_advance, &y_advance);
*bbox = scaled_glyph->bbox;
*width = x_advance;
image = scaled_glyph->surface;
if (image->format != CAIRO_FORMAT_A1) {
image = _cairo_image_surface_clone (image, CAIRO_FORMAT_A1);
status = cairo_surface_status (&image->base);
if (status)
return status;
}
status = _cairo_pdf_surface_open_stream (surface,
NULL,
surface->compress_content,
NULL);
if (status) {
if (image != scaled_glyph->surface)
cairo_surface_destroy (&image->base);
return status;
}
*glyph_ret = surface->pdf_stream.self;
_cairo_output_stream_printf (surface->output,
"%f 0 %f %f %f %f d1\n",
x_advance,
_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));
_cairo_output_stream_printf (surface->output,
"%f 0 0 %f %f %f cm\n",
_cairo_fixed_to_double (scaled_glyph->bbox.p2.x) - _cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
_cairo_fixed_to_double (scaled_glyph->bbox.p1.y) - _cairo_fixed_to_double (scaled_glyph->bbox.p2.y),
_cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
_cairo_fixed_to_double (scaled_glyph->bbox.p2.y));
_cairo_output_stream_printf (surface->output,
_cairo_output_stream_printf (stream,
"BI\n"
"/IM true\n"
"/W %d\n"
@ -3375,23 +3461,23 @@ _cairo_pdf_surface_emit_bitmap_glyph (cairo_pdf_surface_t *surface,
image->width,
image->height);
_cairo_output_stream_printf (surface->output,
_cairo_output_stream_printf (stream,
"ID ");
for (row = image->data, rows = image->height; rows; row += image->stride, rows--) {
for (byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) {
unsigned char output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
_cairo_output_stream_write (surface->output, &output_byte, 1);
num_cols = (image->width + 7) / 8;
for (row = 0; row < image->height; row++) {
byte = image->data + row * image->stride;
for (col = 0; col < num_cols; col++) {
output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
_cairo_output_stream_write (stream, &output_byte, 1);
byte++;
}
}
_cairo_output_stream_printf (surface->output,
_cairo_output_stream_printf (stream,
"\nEI\n");
status = _cairo_pdf_surface_close_stream (surface);
if (image != scaled_glyph->surface)
cairo_surface_destroy (&image->base);
return status;
return _cairo_output_stream_get_status (stream);
}
static cairo_status_t
@ -3406,6 +3492,7 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
unsigned int i;
cairo_box_t font_bbox = {{0,0},{0,0}};
cairo_box_t bbox = {{0,0},{0,0}};
cairo_surface_t *type3_surface;
if (font_subset->num_glyphs == 0)
return CAIRO_STATUS_SUCCESS;
@ -3426,13 +3513,29 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
NULL,
_cairo_pdf_emit_imagemask);
for (i = 0; i < font_subset->num_glyphs; i++) {
status = _cairo_pdf_surface_emit_bitmap_glyph (surface,
font_subset->scaled_font,
font_subset->glyphs[i],
&glyphs[i],
&bbox,
&widths[i]);
status = _cairo_pdf_surface_open_stream (surface,
NULL,
surface->compress_content,
NULL);
glyphs[i] = surface->pdf_stream.self;
if (i == 0) {
status = _cairo_type3_glyph_surface_emit_notdef_glyph (type3_surface,
surface->output,
&bbox,
&widths[i]);
} else {
status = _cairo_type3_glyph_surface_emit_glyph (type3_surface,
surface->output,
font_subset->glyphs[i],
&bbox,
&widths[i]);
}
status = _cairo_pdf_surface_close_stream (surface);
if (status)
break;
@ -3452,6 +3555,7 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
font_bbox.p2.y = bbox.p2.y;
}
}
cairo_surface_destroy (type3_surface);
if (status) {
free (glyphs);
free (widths);
@ -3512,20 +3616,16 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
"<< /Type /Font\n"
" /Subtype /Type3\n"
" /FontBBox [%f %f %f %f]\n"
" /FontMatrix [ %f %f %f %f 0 0 ]\n"
" /FontMatrix [ 1 0 0 1 0 0 ]\n"
" /Encoding %d 0 R\n"
" /CharProcs %d 0 R\n"
" /FirstChar 0\n"
" /LastChar %d\n",
subset_resource.id,
_cairo_fixed_to_double (font_bbox.p1.x),
_cairo_fixed_to_double (font_bbox.p1.y),
- _cairo_fixed_to_double (font_bbox.p2.y),
_cairo_fixed_to_double (font_bbox.p2.x),
_cairo_fixed_to_double (font_bbox.p2.y),
matrix.xx,
matrix.yx,
-matrix.xy,
-matrix.yy,
- _cairo_fixed_to_double (font_bbox.p1.y),
encoding.id,
char_procs.id,
font_subset->num_glyphs - 1);
@ -3582,6 +3682,7 @@ _cairo_pdf_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_s
status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
}
ASSERT_NOT_REACHED;
@ -3730,7 +3831,9 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
"0 0 %f %f re f\n",
surface->width, surface->height);
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
status = _cairo_pdf_surface_close_group (surface, &mask_group);
@ -3783,7 +3886,9 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
"0 0 %f %f re f\n",
surface->width, surface->height);
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
status = _cairo_pdf_surface_close_group (surface, NULL);
@ -3872,16 +3977,21 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface,
&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);
status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
group->utf8, group->utf8_len,
group->glyphs, group->num_glyphs,
group->clusters, group->num_clusters,
group->backward,
group->scaled_font);
break;
}
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
status = _cairo_pdf_surface_close_group (surface, NULL);
_cairo_pdf_surface_set_size_internal (surface,
@ -4161,8 +4271,19 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
if (_cairo_surface_is_meta (surface_pattern->surface)) {
if (_cairo_pattern_is_opaque (pattern))
if (_cairo_pattern_is_opaque (pattern)) {
return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
} else {
/* FIXME: The analysis surface does not yet have
* the capability to analyze a non opaque meta
* surface and mark it supported if there is
* nothing underneath. For now meta surfaces of
* type CONTENT_COLOR_ALPHA painted with
* OPERATOR_SOURCE will result in a fallback
* image. */
return CAIRO_INT_STATUS_UNSUPPORTED;
}
} else {
return _cairo_pdf_surface_analyze_surface_pattern_transparency (surface,
surface_pattern);
@ -4202,7 +4323,6 @@ _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
if (status)
return status;
surface->has_fallback_images = TRUE;
_cairo_pdf_group_resources_clear (&surface->resources);
return _cairo_pdf_surface_open_content_stream (surface, TRUE);
}
@ -4257,6 +4377,10 @@ _cairo_pdf_surface_paint (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
gstate_res.id,
@ -4270,7 +4394,9 @@ _cairo_pdf_surface_paint (void *abstract_surface,
"0 0 %f %f re f\n",
surface->width, surface->height);
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
return _cairo_output_stream_get_status (surface->output);
@ -4333,6 +4459,10 @@ _cairo_pdf_surface_mask (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
group->group_res.id,
@ -4401,6 +4531,10 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
gstate_res.id,
@ -4418,7 +4552,9 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
return _cairo_output_stream_get_status (surface->output);
@ -4485,6 +4621,10 @@ _cairo_pdf_surface_fill (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
gstate_res.id,
@ -4500,7 +4640,9 @@ _cairo_pdf_surface_fill (void *abstract_surface,
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
return _cairo_output_stream_get_status (surface->output);
@ -4587,18 +4729,31 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
return _cairo_output_stream_get_status (surface->output);
}
static cairo_bool_t
_cairo_pdf_surface_has_show_text_glyphs (void *abstract_surface)
{
return TRUE;
}
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_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@ -4626,13 +4781,37 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface,
group->operation = PDF_SHOW_GLYPHS;
group->source = cairo_pattern_reference (source);
group->source_res = pattern_res;
group->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (group->glyphs == NULL) {
_cairo_pdf_smask_group_destroy (group);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (utf8_len) {
group->utf8 = malloc(utf8_len);
if (group->utf8) {
_cairo_pdf_smask_group_destroy (group);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
memcpy (group->utf8, utf8, utf8_len);
}
group->utf8_len = utf8_len;
if (num_glyphs) {
group->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (group->glyphs == NULL) {
_cairo_pdf_smask_group_destroy (group);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
memcpy (group->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
}
memcpy (group->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
group->num_glyphs = num_glyphs;
if (num_clusters) {
group->clusters = _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t));
if (group->clusters) {
_cairo_pdf_smask_group_destroy (group);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
memcpy (group->clusters, clusters, sizeof (cairo_text_cluster_t) * num_clusters);
}
group->num_clusters = num_clusters;
group->scaled_font = cairo_scaled_font_reference (scaled_font);
status = _cairo_pdf_surface_add_smask_group (surface, group);
if (status) {
@ -4648,6 +4827,10 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
gstate_res.id,
@ -4657,19 +4840,34 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
glyphs,
num_glyphs,
scaled_font);
/* Each call to show_glyphs() with a transclucent pattern must
* be in a separate text object otherwise overlapping text
* from separate calls to show_glyphs will not composite with
* each other. */
if (! _cairo_pattern_is_opaque (source)) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
}
status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
backward,
scaled_font);
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
return _cairo_output_stream_get_status (surface->output);
}
static void
_cairo_pdf_surface_set_paginated_mode (void *abstract_surface,
cairo_paginated_mode_t paginated_mode)
@ -4709,15 +4907,20 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
_cairo_pdf_surface_mask,
_cairo_pdf_surface_stroke,
_cairo_pdf_surface_fill,
_cairo_pdf_surface_show_glyphs,
NULL, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_compatible */
NULL, /* reset */
_cairo_pdf_surface_fill_stroke,
NULL, /* create_solid_pattern_surface */
_cairo_pdf_surface_has_show_text_glyphs,
_cairo_pdf_surface_show_text_glyphs,
};
static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend = {
_cairo_pdf_surface_start_page,
_cairo_pdf_surface_set_paginated_mode
_cairo_pdf_surface_set_paginated_mode,
NULL, /* set_bounding_box */
_cairo_pdf_surface_has_fallback_images,
};

View File

@ -37,7 +37,7 @@
#ifndef CAIRO_PDF_H
#define CAIRO_PDF_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_PDF_SURFACE

View File

@ -45,15 +45,6 @@ _cairo_pen_compute_slopes (cairo_pen_t *pen);
static void
_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_direction_t dir, cairo_polygon_t *polygon);
void
_cairo_pen_init_empty (cairo_pen_t *pen)
{
pen->radius = 0;
pen->tolerance = 0;
pen->vertices = NULL;
pen->num_vertices = 0;
}
cairo_status_t
_cairo_pen_init (cairo_pen_t *pen,
double radius,
@ -78,10 +69,14 @@ _cairo_pen_init (cairo_pen_t *pen,
radius,
ctm);
pen->vertices = _cairo_malloc_ab (pen->num_vertices,
sizeof (cairo_pen_vertex_t));
if (pen->vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
pen->vertices = _cairo_malloc_ab (pen->num_vertices,
sizeof (cairo_pen_vertex_t));
if (pen->vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else {
pen->vertices = pen->vertices_embedded;
}
/*
* Compute pen coordinates. To generate the right ellipse, compute points around
@ -107,10 +102,11 @@ _cairo_pen_init (cairo_pen_t *pen,
void
_cairo_pen_fini (cairo_pen_t *pen)
{
free (pen->vertices);
pen->vertices = NULL;
if (pen->vertices != pen->vertices_embedded)
free (pen->vertices);
_cairo_pen_init_empty (pen);
pen->vertices = pen->vertices_embedded;
pen->num_vertices = 0;
}
cairo_status_t
@ -118,13 +114,17 @@ _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
{
*pen = *other;
pen->vertices = pen->vertices_embedded;
if (pen->num_vertices) {
pen->vertices = _cairo_malloc_ab (pen->num_vertices,
sizeof (cairo_pen_vertex_t));
if (pen->vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
pen->vertices = _cairo_malloc_ab (pen->num_vertices,
sizeof (cairo_pen_vertex_t));
if (pen->vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
memcpy (pen->vertices, other->vertices, pen->num_vertices * sizeof (cairo_pen_vertex_t));
memcpy (pen->vertices, other->vertices,
pen->num_vertices * sizeof (cairo_pen_vertex_t));
}
return CAIRO_STATUS_SUCCESS;
@ -133,18 +133,35 @@ _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
cairo_status_t
_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
{
cairo_pen_vertex_t *vertices;
cairo_status_t status;
int num_vertices;
int i;
num_vertices = pen->num_vertices + num_points;
vertices = _cairo_realloc_ab (pen->vertices,
num_vertices, sizeof (cairo_pen_vertex_t));
if (vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (num_vertices > ARRAY_LENGTH (pen->vertices_embedded) ||
pen->vertices != pen->vertices_embedded)
{
cairo_pen_vertex_t *vertices;
if (pen->vertices == pen->vertices_embedded) {
vertices = _cairo_malloc_ab (num_vertices,
sizeof (cairo_pen_vertex_t));
if (vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (vertices, pen->vertices,
pen->num_vertices * sizeof (cairo_pen_vertex_t));
} else {
vertices = _cairo_realloc_ab (pen->vertices,
num_vertices,
sizeof (cairo_pen_vertex_t));
if (vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
pen->vertices = vertices;
}
pen->vertices = vertices;
pen->num_vertices = num_vertices;
/* initialize new vertices */

View File

@ -197,6 +197,9 @@ write_png (cairo_surface_t *surface,
case CAIRO_FORMAT_A1:
depth = 1;
png_color_type = PNG_COLOR_TYPE_GRAY;
#ifndef WORDS_BIGENDIAN
png_set_packswap (png);
#endif
break;
default:
status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
@ -274,7 +277,7 @@ stdio_write_func (png_structp png, png_bytep data, png_size_t size)
* Return value: %CAIRO_STATUS_SUCCESS if the PNG file was written
* successfully. Otherwise, %CAIRO_STATUS_NO_MEMORY if memory could not
* be allocated for the operation or
* CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
* %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
* pixel contents, or %CAIRO_STATUS_WRITE_ERROR if an I/O error occurs
* while attempting to write the file.
**/
@ -341,7 +344,7 @@ stream_write_func (png_structp png, png_bytep data, png_size_t size)
* Return value: %CAIRO_STATUS_SUCCESS if the PNG file was written
* successfully. Otherwise, %CAIRO_STATUS_NO_MEMORY is returned if
* memory could not be allocated for the operation,
* CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
* %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
* pixel contents.
**/
cairo_status_t
@ -351,6 +354,12 @@ cairo_surface_write_to_png_stream (cairo_surface_t *surface,
{
struct png_write_closure_t png_closure;
if (surface->status)
return surface->status;
if (surface->finished)
return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
png_closure.write_func = write_func;
png_closure.closure = closure;
@ -498,25 +507,37 @@ read_png (png_rw_ptr read_func,
if (interlace != PNG_INTERLACE_NONE)
png_set_interlace_handling (png);
png_set_filler (png, 0xff, PNG_FILLER_AFTER);
/* recheck header after setting EXPAND options */
png_read_update_info (png, info);
png_get_IHDR (png, info,
&png_width, &png_height, &depth,
&color_type, &interlace, NULL, NULL);
if (depth != 8 || interlace != PNG_INTERLACE_NONE ||
! (color_type == PNG_COLOR_TYPE_RGB ||
color_type == PNG_COLOR_TYPE_RGB_ALPHA))
{
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_READ_ERROR));
goto BAIL;
}
switch (color_type) {
default:
case PNG_COLOR_TYPE_GRAY_ALPHA:
ASSERT_NOT_REACHED;
/* fall-through just in case ;-) */
case PNG_COLOR_TYPE_RGB_ALPHA:
format = CAIRO_FORMAT_ARGB32;
png_set_read_user_transform_fn (png, premultiply_data);
break;
case PNG_COLOR_TYPE_GRAY:
case PNG_COLOR_TYPE_PALETTE:
case PNG_COLOR_TYPE_RGB:
format = CAIRO_FORMAT_RGB24;
png_set_read_user_transform_fn (png, convert_bytes_to_data);
png_set_filler (png, 0xff, PNG_FILLER_AFTER);
break;
}
png_read_update_info (png, info);
stride = cairo_format_stride_for_width (format, png_width);
if (stride < 0) {
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
@ -597,9 +618,9 @@ stdio_read_func (png_structp png, png_bytep data, png_size_t size)
* surface can be checked for with cairo_surface_status(surface) which
* may return one of the following values:
*
* CAIRO_STATUS_NO_MEMORY
* CAIRO_STATUS_FILE_NOT_FOUND
* CAIRO_STATUS_READ_ERROR
* %CAIRO_STATUS_NO_MEMORY
* %CAIRO_STATUS_FILE_NOT_FOUND
* %CAIRO_STATUS_READ_ERROR
**/
cairo_surface_t *
cairo_image_surface_create_from_png (const char *filename)

View File

@ -48,8 +48,8 @@ _cairo_polygon_init (cairo_polygon_t *polygon)
polygon->num_edges = 0;
polygon->edges_size = 0;
polygon->edges = NULL;
polygon->edges = polygon->edges_embedded;
polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded);
polygon->has_current_point = FALSE;
}
@ -79,26 +79,17 @@ _cairo_polygon_grow (cairo_polygon_t *polygon)
{
cairo_edge_t *new_edges;
int old_size = polygon->edges_size;
int embedded_size = ARRAY_LENGTH (polygon->edges_embedded);
int new_size = 2 * MAX (old_size, 16);
/* we have a local buffer at polygon->edges_embedded. try to fulfill the request
* from there. */
if (old_size < embedded_size) {
polygon->edges = polygon->edges_embedded;
polygon->edges_size = embedded_size;
return CAIRO_STATUS_SUCCESS;
}
int new_size = 2 * old_size;
assert (polygon->num_edges <= polygon->edges_size);
if (polygon->edges == polygon->edges_embedded) {
new_edges = _cairo_malloc_ab (new_size, sizeof (cairo_edge_t));
if (new_edges)
if (new_edges != NULL)
memcpy (new_edges, polygon->edges, old_size * sizeof (cairo_edge_t));
} else {
new_edges = _cairo_realloc_ab (polygon->edges,
new_size, sizeof (cairo_edge_t));
new_size, sizeof (cairo_edge_t));
}
if (new_edges == NULL)

View File

@ -49,6 +49,7 @@ struct _cairo {
cairo_gstate_t *gstate;
cairo_gstate_t gstate_tail[1];
cairo_gstate_t *gstate_freelist;
cairo_path_fixed_t path[1];
};

View File

@ -69,6 +69,12 @@ typedef struct cairo_ps_surface {
void *image_extra;
cairo_bool_t use_string_datasource;
cairo_bool_t current_pattern_is_solid_color;
double current_color_red;
double current_color_green;
double current_color_blue;
double current_color_alpha;
int num_pages;
cairo_paginated_mode_t paginated_mode;

View File

@ -49,6 +49,7 @@
#include "cairo-paginated-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-type3-glyph-surface-private.h"
#include <stdio.h>
#include <ctype.h>
@ -172,24 +173,35 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
"/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"
"/pdfmark where { pop globaldict /?pdfmark /exec load put }\n"
" { globaldict begin /?pdfmark /pop load def /pdfmark\n"
" /cleartomark load def end } ifelse\n"
"/BDC { mark 3 1 roll /BDC pdfmark } bind def\n"
"/EMC { mark /EMC pdfmark } bind def\n"
"/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def\n"
"/Tj { show currentpoint cairo_store_point } bind def\n"
"/TJ {\n"
" {\n"
" dup\n"
" type /stringtype eq\n"
" { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse\n"
" } forall\n"
" currentpoint cairo_store_point\n"
"} bind def\n"
"/Td { matrix translate cairo_font_matrix matrix concatmatrix aload\n"
" /cairo_font_matrix exch def 6 2 roll 0 0 6 array astore\n"
" cairo_font exch selectfont moveto } bind def\n"
"/Tm { 6 copy 6 array astore /cairo_font_matrix exch def 6 2 roll 0 0\n"
" 6 array astore cairo_font exch selectfont moveto } bind def\n"
"/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore\n"
" cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def\n"
"/Tf { pop /cairo_font exch def /cairo_font_matrix where\n"
" { cairo_selectfont } if } bind def\n"
"/Td { matrix translate cairo_font_matrix matrix concatmatrix dup\n"
" /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point\n"
" /cairo_font where { cairo_selectfont } if } bind def\n"
"/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def\n"
" cairo_store_point /cairo_font where { cairo_selectfont } if } bind def\n"
"/g { setgray } bind def\n"
"/rg { setrgbcolor } bind def\n");
"/rg { setrgbcolor } bind def\n"
"/d1 { setcachedevice } bind def\n");
_cairo_output_stream_printf (surface->final_stream,
"%%%%EndProlog\n");
@ -369,113 +381,49 @@ _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface,
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,
cairo_box_t *bbox)
static cairo_status_t
_cairo_ps_emit_imagemask (cairo_image_surface_t *image,
cairo_output_stream_t *stream)
{
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;
status = _cairo_scaled_glyph_lookup (scaled_font,
glyph_index,
CAIRO_SCALED_GLYPH_INFO_METRICS|
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
if (status)
return status;
/* The only image type supported by Type 3 fonts are 1-bit image
* masks */
assert (image->format == CAIRO_FORMAT_A1);
*bbox = scaled_glyph->bbox;
x_advance = scaled_glyph->metrics.x_advance;
y_advance = scaled_glyph->metrics.y_advance;
cairo_matrix_transform_distance (&scaled_font->ctm, &x_advance, &y_advance);
image = scaled_glyph->surface;
if (image->format != CAIRO_FORMAT_A1) {
image = _cairo_image_surface_clone (image, CAIRO_FORMAT_A1);
if (cairo_surface_status (&image->base))
return cairo_surface_status (&image->base);
}
_cairo_output_stream_printf (surface->final_stream,
"%f 0 %f %f %f %f setcachedevice\n",
x_advance,
_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));
_cairo_output_stream_printf (surface->final_stream,
_cairo_output_stream_printf (stream,
"<<\n"
" /ImageType 1\n"
" /Width %d\n"
" /Height %d\n"
" /ImageMatrix [%f %f %f %f %f %f]\n"
" /ImageMatrix [%d 0 0 %d 0 %d]\n"
" /Decode [1 0]\n"
" /BitsPerComponent 1\n",
image->width,
image->height,
image->base.device_transform.xx,
image->base.device_transform.yx,
image->base.device_transform.xy,
image->base.device_transform.yy,
image->base.device_transform.x0,
image->base.device_transform.y0);
image->width,
-image->height,
image->height);
_cairo_output_stream_printf (surface->final_stream,
_cairo_output_stream_printf (stream,
" /DataSource {<");
for (row = image->data, rows = image->height; rows; row += image->stride, rows--) {
for (byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) {
unsigned char output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
_cairo_output_stream_printf (surface->final_stream, "%02x ", output_byte);
_cairo_output_stream_printf (stream, "%02x ", output_byte);
}
_cairo_output_stream_printf (surface->final_stream, "\n ");
_cairo_output_stream_printf (stream, "\n ");
}
_cairo_output_stream_printf (surface->final_stream,
_cairo_output_stream_printf (stream,
" >}\n");
_cairo_output_stream_printf (surface->final_stream,
_cairo_output_stream_printf (stream,
">>\n");
_cairo_output_stream_printf (surface->final_stream,
_cairo_output_stream_printf (stream,
"imagemask\n");
if (image != scaled_glyph->surface)
cairo_surface_destroy (&image->base);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_ps_surface_emit_glyph (cairo_ps_surface_t *surface,
cairo_scaled_font_t *scaled_font,
unsigned long scaled_font_glyph_index,
unsigned int subset_glyph_index,
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_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);
return status;
return _cairo_output_stream_get_status (stream);
}
static cairo_status_t
@ -489,6 +437,8 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
unsigned int i;
cairo_box_t font_bbox = {{0,0},{0,0}};
cairo_box_t bbox = {{0,0},{0,0}};
cairo_surface_t *type3_surface;
double width;
#if DEBUG_PS
_cairo_output_stream_printf (surface->final_stream,
@ -499,13 +449,13 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
_cairo_output_stream_printf (surface->final_stream,
"8 dict begin\n"
"/FontType 3 def\n"
"/FontMatrix [%f %f %f %f 0 0] def\n"
"/FontMatrix [1 0 0 1 0 0] def\n"
"/Encoding 256 array def\n"
"0 1 255 { Encoding exch /.notdef put } for\n",
matrix.xx,
matrix.yx,
-matrix.xy,
-matrix.yy);
"0 1 255 { Encoding exch /.notdef put } for\n");
type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
NULL,
_cairo_ps_emit_imagemask);
for (i = 1; i < font_subset->num_glyphs; i++) {
if (font_subset->glyph_names != NULL) {
@ -522,13 +472,25 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
"/Glyphs [\n");
for (i = 0; i < font_subset->num_glyphs; i++) {
status = _cairo_ps_surface_emit_glyph (surface,
font_subset->scaled_font,
font_subset->glyphs[i], i,
&bbox);
_cairo_output_stream_printf (surface->final_stream,
" { %% %d\n", i);
if (i == 0) {
status = _cairo_type3_glyph_surface_emit_notdef_glyph (type3_surface,
surface->final_stream,
&bbox,
&width);
} else {
status = _cairo_type3_glyph_surface_emit_glyph (type3_surface,
surface->final_stream,
font_subset->glyphs[i],
&bbox,
&width);
}
if (status)
return status;
_cairo_output_stream_printf (surface->final_stream,
" }\n");
if (i == 0) {
font_bbox.p1.x = bbox.p1.x;
font_bbox.p1.y = bbox.p1.y;
@ -545,6 +507,7 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
font_bbox.p2.y = bbox.p2.y;
}
}
cairo_surface_destroy (type3_surface);
_cairo_output_stream_printf (surface->final_stream,
"] def\n"
@ -557,9 +520,9 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
"end\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.y),
_cairo_fixed_to_double (font_bbox.p2.x),
_cairo_fixed_to_double (font_bbox.p2.y),
- _cairo_fixed_to_double (font_bbox.p1.y),
font_subset->font_id,
font_subset->subset_id);
@ -728,6 +691,7 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
surface->force_fallbacks = FALSE;
surface->content = CAIRO_CONTENT_COLOR_ALPHA;
surface->use_string_datasource = FALSE;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_init (&surface->pdf_operators,
surface->stream,
@ -747,8 +711,11 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
width, height,
&cairo_ps_surface_paginated_backend);
status = surface->paginated_surface->status;
if (status == CAIRO_STATUS_SUCCESS)
if (status == CAIRO_STATUS_SUCCESS) {
/* paginated keeps the only reference to surface now, drop ours */
cairo_surface_destroy (&surface->base);
return surface->paginated_surface;
}
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
CLEANUP_OUTPUT_STREAM:
@ -1324,19 +1291,30 @@ _cairo_ps_surface_start_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
static void
static cairo_int_status_t
_cairo_ps_surface_end_page (cairo_ps_surface_t *surface)
{
cairo_int_status_t status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->stream,
"Q\n");
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_ps_surface_show_page (void *abstract_surface)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_int_status_t status;
_cairo_ps_surface_end_page (surface);
status = _cairo_ps_surface_end_page (surface);
if (status)
return status;
_cairo_output_stream_printf (surface->stream, "showpage\n");
@ -1718,7 +1696,7 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface,
{
const cairo_color_t *background_color;
cairo_surface_t *opaque;
cairo_pattern_union_t pattern;
cairo_surface_pattern_t pattern;
cairo_status_t status;
if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
@ -1732,7 +1710,7 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface,
if (opaque->status)
return opaque->status;
_cairo_pattern_init_for_surface (&pattern.surface, &image->base);
_cairo_pattern_init_for_surface (&pattern, &image->base);
status = _cairo_surface_fill_rectangle (opaque,
CAIRO_OPERATOR_SOURCE,
@ -2052,6 +2030,8 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
old_clip = _cairo_surface_get_clip (&surface->base);
surface->width = meta_extents.width;
surface->height = meta_extents.height;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
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);
@ -2075,11 +2055,17 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->stream,
" Q\n");
surface->content = old_content;
surface->width = old_width;
surface->height = old_height;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
surface->cairo_to_ps = old_cairo_to_ps;
status = _cairo_surface_set_clip (&surface->base, old_clip);
if (status)
@ -2618,6 +2604,19 @@ _cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface,
if (pattern->base.n_stops == 0)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (pattern->base.n_stops == 1) {
cairo_solid_pattern_t solid;
_cairo_pattern_init_solid (&solid,
&pattern->base.stops[0].color,
CAIRO_CONTENT_COLOR_ALPHA);
_cairo_ps_surface_emit_solid_pattern (surface,
&solid);
_cairo_pattern_fini (&solid.base);
return CAIRO_STATUS_SUCCESS;
}
extend = cairo_pattern_get_extend (&pattern->base.base);
pat_to_ps = pattern->base.base.matrix;
@ -2745,6 +2744,19 @@ _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface,
if (pattern->base.n_stops == 0)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (pattern->base.n_stops == 1) {
cairo_solid_pattern_t solid;
_cairo_pattern_init_solid (&solid,
&pattern->base.stops[0].color,
CAIRO_CONTENT_COLOR_ALPHA);
_cairo_ps_surface_emit_solid_pattern (surface,
&solid);
_cairo_pattern_fini (&solid.base);
return CAIRO_STATUS_SUCCESS;
}
extend = cairo_pattern_get_extend (&pattern->base.base);
pat_to_ps = pattern->base.base.matrix;
@ -2801,13 +2813,41 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
cairo_pattern_t *pattern,
cairo_operator_t op)
{
/* FIXME: We should keep track of what pattern is currently set in
* the postscript file and only emit code if we're setting a
* different pattern. */
cairo_status_t status;
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
if (surface->current_pattern_is_solid_color == FALSE ||
surface->current_color_red != solid->color.red ||
surface->current_color_green != solid->color.green ||
surface->current_color_blue != solid->color.blue ||
surface->current_color_alpha != solid->color.alpha)
{
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
surface->current_pattern_is_solid_color = TRUE;
surface->current_color_red = solid->color.red;
surface->current_color_green = solid->color.green;
surface->current_color_blue = solid->color.blue;
surface->current_color_alpha = solid->color.alpha;
}
return CAIRO_STATUS_SUCCESS;
}
surface->current_pattern_is_solid_color = FALSE;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
_cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
break;
@ -2846,6 +2886,7 @@ _cairo_ps_surface_intersect_clip_path (void *abstract_surface,
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
cairo_status_t status;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
@ -2856,7 +2897,14 @@ _cairo_ps_surface_intersect_clip_path (void *abstract_surface,
#endif
if (path == NULL) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (stream, "Q q\n");
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
return CAIRO_STATUS_SUCCESS;
}
@ -2919,6 +2967,10 @@ _cairo_ps_surface_paint (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
(source->extend == CAIRO_EXTEND_NONE ||
source->extend == CAIRO_EXTEND_PAD))
@ -3011,6 +3063,10 @@ _cairo_ps_surface_fill (void *abstract_surface,
(source->extend == CAIRO_EXTEND_NONE ||
source->extend == CAIRO_EXTEND_PAD))
{
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->stream, "q\n");
status = _cairo_pdf_operators_clip (&surface->pdf_operators,
@ -3026,6 +3082,7 @@ _cairo_ps_surface_fill (void *abstract_surface,
return status;
_cairo_output_stream_printf (surface->stream, "Q\n");
_cairo_pdf_operators_reset (&surface->pdf_operators);
} else {
status = _cairo_ps_surface_emit_pattern (surface, source, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
@ -3048,7 +3105,8 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_status_t status;
@ -3073,10 +3131,12 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
if (status)
return status;
return _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
glyphs,
num_glyphs,
scaled_font);
return _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
NULL, 0,
glyphs, num_glyphs,
NULL, 0,
FALSE,
scaled_font);
}
static void
@ -3150,6 +3210,8 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface,
if (y2 > surface->bbox_y2)
surface->bbox_y2 = y2;
}
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
return _cairo_output_stream_get_status (surface->stream);
}

View File

@ -37,7 +37,7 @@
#ifndef CAIRO_PS_H
#define CAIRO_PS_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_PS_SURFACE

View File

@ -127,9 +127,9 @@ struct _cairo_quartz_font_face {
CGFontRef cgFont;
};
/**
** font face backend
**/
/*
* font face backend
*/
static void
_cairo_quartz_font_face_destroy (void *abstract_face)
@ -165,7 +165,7 @@ _cairo_quartz_font_face_scaled_font_create (void *abstract_face,
status = _cairo_scaled_font_init (&font->base,
&font_face->base, font_matrix, ctm, options,
&cairo_quartz_scaled_font_backend);
&_cairo_quartz_scaled_font_backend);
if (status)
goto FINISH;
@ -188,6 +188,7 @@ _cairo_quartz_font_face_scaled_font_create (void *abstract_face,
quartz_CGFontMetrics *m;
m = CGFontGetHMetricsPtr (font_face->cgFont);
/* On OX 10.4, GetHMetricsPtr sometimes returns NULL for unknown reasons */
if (!m) {
status = _cairo_error(CAIRO_STATUS_NULL_POINTER);
goto FINISH;
@ -260,9 +261,9 @@ cairo_quartz_font_face_create_for_cgfont (CGFontRef font)
return &font_face->base;
}
/**
** scaled font backend
**/
/*
* scaled font backend
*/
static cairo_quartz_font_face_t *
_cairo_quartz_scaled_to_face (void *abstract_font)
@ -740,7 +741,7 @@ _cairo_quartz_ucs4_to_index (void *abstract_font,
return glyph;
}
const cairo_scaled_font_backend_t cairo_quartz_scaled_font_backend = {
const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend = {
CAIRO_FONT_TYPE_QUARTZ,
_cairo_quartz_font_create_toy,
_cairo_quartz_font_fini,

View File

@ -43,6 +43,7 @@
#include "cairo-quartz-private.h"
#define SURFACE_ERROR_NO_MEMORY (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY)))
#define SURFACE_ERROR_TYPE_MISMATCH (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_SURFACE_TYPE_MISMATCH)))
#define SURFACE_ERROR_INVALID_FORMAT (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_FORMAT)))
CGImageRef
@ -300,7 +301,7 @@ cairo_quartz_image_surface_create (cairo_surface_t *surface)
unsigned char *data;
if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_IMAGE)
return SURFACE_ERROR_NO_MEMORY;
return SURFACE_ERROR_TYPE_MISMATCH;
image_surface = (cairo_image_surface_t*) surface;
width = image_surface->width;
@ -337,7 +338,7 @@ cairo_quartz_image_surface_create (cairo_surface_t *surface)
TRUE,
NULL,
DataProviderReleaseCallback,
surface);
image_surface);
if (!image) {
free (qisurf);

View File

@ -36,7 +36,7 @@
#ifndef CAIRO_QUARTZ_IMAGE_H
#define CAIRO_QUARTZ_IMAGE_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_QUARTZ_IMAGE_SURFACE

View File

@ -41,7 +41,7 @@
#include "cairoint.h"
#ifdef CAIRO_HAS_QUARTZ_SURFACE
#include <cairo-quartz.h>
#include "cairo-quartz.h"
typedef struct cairo_quartz_surface {
cairo_surface_t base;

View File

@ -695,6 +695,13 @@ CreateRepeatingGradientFunction (cairo_quartz_surface_t *surface,
/* Obtain a CGImageRef from a #cairo_surface_t * */
static void
DataProviderReleaseCallback (void *info, const void *data, size_t size)
{
cairo_surface_t *surface = (cairo_surface_t *) info;
cairo_surface_destroy (surface);
}
static cairo_status_t
_cairo_surface_to_cgimage (cairo_surface_t *target,
cairo_surface_t *source,
@ -737,17 +744,22 @@ _cairo_surface_to_cgimage (cairo_surface_t *target,
if (isurf->width == 0 || isurf->height == 0) {
*image_out = NULL;
} else {
image = _cairo_quartz_create_cgimage (isurf->format,
isurf->width,
isurf->height,
isurf->stride,
isurf->data,
TRUE,
NULL, NULL, NULL);
cairo_image_surface_t *isurf_snap = NULL;
isurf_snap = _cairo_surface_snapshot (isurf);
if (isurf_snap == NULL)
return CAIRO_STATUS_NO_MEMORY;
/* Create a copy to ensure that the CGImageRef doesn't depend on the image surface's backing store */
*image_out = CGImageCreateCopy (image);
CGImageRelease (image);
image = _cairo_quartz_create_cgimage (isurf_snap->format,
isurf_snap->width,
isurf_snap->height,
isurf_snap->stride,
isurf_snap->data,
TRUE,
NULL,
DataProviderReleaseCallback,
isurf_snap);
*image_out = image;
}
if ((cairo_surface_t*) isurf != source)
@ -1875,7 +1887,8 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs)
{
CGAffineTransform textTransform, ctm;
#define STATIC_BUF_SIZE 64
@ -2154,7 +2167,7 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
cairo_surface_t *gradient_surf = NULL;
cairo_t *gradient_surf_cr = NULL;
cairo_pattern_union_t surface_pattern;
cairo_surface_pattern_t surface_pattern;
cairo_int_status_t status;
/* Render the gradient to a surface */
@ -2171,9 +2184,9 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
if (status)
goto BAIL;
_cairo_pattern_init_for_surface (&surface_pattern.surface, gradient_surf);
_cairo_pattern_init_for_surface (&surface_pattern, gradient_surf);
status = _cairo_quartz_surface_mask_with_surface (surface, op, source, &surface_pattern.surface);
status = _cairo_quartz_surface_mask_with_surface (surface, op, source, &surface_pattern);
_cairo_pattern_fini (&surface_pattern.base);

View File

@ -36,7 +36,7 @@
#ifndef CAIRO_QUARTZ_H
#define CAIRO_QUARTZ_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_QUARTZ_SURFACE

View File

@ -39,6 +39,38 @@
#include "cairoint.h"
cairo_private void
_cairo_box_from_doubles (cairo_box_t *box,
double *x1, double *y1,
double *x2, double *y2)
{
box->p1.x = _cairo_fixed_from_double (*x1);
box->p1.y = _cairo_fixed_from_double (*y1);
box->p2.x = _cairo_fixed_from_double (*x2);
box->p2.y = _cairo_fixed_from_double (*y2);
}
cairo_private void
_cairo_box_to_doubles (const cairo_box_t *box,
double *x1, double *y1,
double *x2, double *y2)
{
*x1 = _cairo_fixed_to_double (box->p1.x);
*y1 = _cairo_fixed_to_double (box->p1.y);
*x2 = _cairo_fixed_to_double (box->p2.x);
*y2 = _cairo_fixed_to_double (box->p2.y);
}
void
_cairo_box_from_rectangle (cairo_box_t *box,
const cairo_rectangle_int_t *rect)
{
box->p1.x = _cairo_fixed_from_int (rect->x);
box->p1.y = _cairo_fixed_from_int (rect->y);
box->p2.x = _cairo_fixed_from_int (rect->x + rect->width);
box->p2.y = _cairo_fixed_from_int (rect->y + rect->height);
}
/* XXX We currently have a confusing mix of boxes and rectangles as
* exemplified by this function. A #cairo_box_t is a rectangular area
* represented by the coordinates of the upper left and lower right
@ -54,7 +86,8 @@
*/
void
_cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_int_t *rectangle)
_cairo_box_round_to_rectangle (const cairo_box_t *box,
cairo_rectangle_int_t *rectangle)
{
rectangle->x = _cairo_fixed_integer_floor (box->p1.x);
rectangle->y = _cairo_fixed_integer_floor (box->p1.y);

View File

@ -44,7 +44,7 @@
/* #cairo_region_t is defined in cairoint.h */
struct _cairo_region {
pixman_region16_t rgn;
pixman_region32_t rgn;
};
cairo_private void

View File

@ -40,14 +40,14 @@
void
_cairo_region_init (cairo_region_t *region)
{
pixman_region_init (&region->rgn);
pixman_region32_init (&region->rgn);
}
void
_cairo_region_init_rect (cairo_region_t *region,
cairo_rectangle_int_t *rect)
{
pixman_region_init_rect (&region->rgn,
pixman_region32_init_rect (&region->rgn,
rect->x, rect->y,
rect->width, rect->height);
}
@ -57,13 +57,13 @@ _cairo_region_init_boxes (cairo_region_t *region,
cairo_box_int_t *boxes,
int count)
{
pixman_box16_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box16_t)];
pixman_box16_t *pboxes = stack_pboxes;
pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
pixman_box32_t *pboxes = stack_pboxes;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
int i;
if (count > ARRAY_LENGTH(stack_pboxes)) {
pboxes = _cairo_malloc_ab (count, sizeof(pixman_box16_t));
pboxes = _cairo_malloc_ab (count, sizeof(pixman_box32_t));
if (pboxes == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@ -75,7 +75,7 @@ _cairo_region_init_boxes (cairo_region_t *region,
pboxes[i].y2 = boxes[i].p2.y;
}
if (!pixman_region_init_rects (&region->rgn, pboxes, count))
if (!pixman_region32_init_rects (&region->rgn, pboxes, count))
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (pboxes != stack_pboxes)
@ -87,13 +87,13 @@ _cairo_region_init_boxes (cairo_region_t *region,
void
_cairo_region_fini (cairo_region_t *region)
{
pixman_region_fini (&region->rgn);
pixman_region32_fini (&region->rgn);
}
cairo_int_status_t
_cairo_region_copy (cairo_region_t *dst, cairo_region_t *src)
{
if (!pixman_region_copy (&dst->rgn, &src->rgn))
if (!pixman_region32_copy (&dst->rgn, &src->rgn))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
@ -102,18 +102,18 @@ _cairo_region_copy (cairo_region_t *dst, cairo_region_t *src)
int
_cairo_region_num_boxes (cairo_region_t *region)
{
return pixman_region_n_rects (&region->rgn);
return pixman_region32_n_rects (&region->rgn);
}
cairo_int_status_t
_cairo_region_get_boxes (cairo_region_t *region, int *num_boxes, cairo_box_int_t **boxes)
{
int nboxes;
pixman_box16_t *pboxes;
pixman_box32_t *pboxes;
cairo_box_int_t *cboxes;
int i;
pboxes = pixman_region_rectangles (&region->rgn, &nboxes);
pboxes = pixman_region32_rectangles (&region->rgn, &nboxes);
if (nboxes == 0) {
*num_boxes = 0;
@ -154,7 +154,7 @@ _cairo_region_boxes_fini (cairo_region_t *region, cairo_box_int_t *boxes)
void
_cairo_region_get_extents (cairo_region_t *region, cairo_rectangle_int_t *extents)
{
pixman_box16_t *pextents = pixman_region_extents (&region->rgn);
pixman_box32_t *pextents = pixman_region32_extents (&region->rgn);
extents->x = pextents->x1;
extents->y = pextents->y1;
@ -165,7 +165,7 @@ _cairo_region_get_extents (cairo_region_t *region, cairo_rectangle_int_t *extent
cairo_int_status_t
_cairo_region_subtract (cairo_region_t *dst, cairo_region_t *a, cairo_region_t *b)
{
if (!pixman_region_subtract (&dst->rgn, &a->rgn, &b->rgn))
if (!pixman_region32_subtract (&dst->rgn, &a->rgn, &b->rgn))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
@ -174,7 +174,7 @@ _cairo_region_subtract (cairo_region_t *dst, cairo_region_t *a, cairo_region_t *
cairo_int_status_t
_cairo_region_intersect (cairo_region_t *dst, cairo_region_t *a, cairo_region_t *b)
{
if (!pixman_region_intersect (&dst->rgn, &a->rgn, &b->rgn))
if (!pixman_region32_intersect (&dst->rgn, &a->rgn, &b->rgn))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
@ -185,7 +185,7 @@ _cairo_region_union_rect (cairo_region_t *dst,
cairo_region_t *src,
cairo_rectangle_int_t *rect)
{
if (!pixman_region_union_rect (&dst->rgn, &src->rgn,
if (!pixman_region32_union_rect (&dst->rgn, &src->rgn,
rect->x, rect->y,
rect->width, rect->height))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@ -196,25 +196,25 @@ _cairo_region_union_rect (cairo_region_t *dst,
cairo_bool_t
_cairo_region_not_empty (cairo_region_t *region)
{
return (cairo_bool_t) pixman_region_not_empty (&region->rgn);
return (cairo_bool_t) pixman_region32_not_empty (&region->rgn);
}
void
_cairo_region_translate (cairo_region_t *region,
int x, int y)
{
pixman_region_translate (&region->rgn, x, y);
pixman_region32_translate (&region->rgn, x, y);
}
pixman_region_overlap_t
_cairo_region_contains_rectangle (cairo_region_t *region, cairo_rectangle_int_t *rect)
{
pixman_box16_t pbox;
pixman_box32_t pbox;
pbox.x1 = rect->x;
pbox.y1 = rect->y;
pbox.x2 = rect->x + rect->width;
pbox.y2 = rect->y + rect->height;
return pixman_region_contains_rectangle (&region->rgn, &pbox);
return pixman_region32_contains_rectangle (&region->rgn, &pbox);
}

View File

@ -81,6 +81,7 @@
#define cairo_glyph_extents _moz_cairo_glyph_extents
#define cairo_glyph_path _moz_cairo_glyph_path
#define cairo_has_current_point _moz_cairo_has_current_point
#define cairo_has_show_text_glyphs _moz_cairo_has_show_text_glyphs
#define cairo_identity_matrix _moz_cairo_identity_matrix
#define cairo_image_surface_create _moz_cairo_image_surface_create
#define cairo_image_surface_create_for_data _moz_cairo_image_surface_create_for_data
@ -193,6 +194,7 @@
#define cairo_scaled_font_get_font_matrix _moz_cairo_scaled_font_get_font_matrix
#define cairo_scaled_font_get_font_options _moz_cairo_scaled_font_get_font_options
#define cairo_scaled_font_get_reference_count _moz_cairo_scaled_font_get_reference_count
#define cairo_scaled_font_get_scale_matrix _moz_cairo_scaled_font_get_scale_matrix
#define cairo_scaled_font_get_type _moz_cairo_scaled_font_get_type
#define cairo_scaled_font_get_user_data _moz_cairo_scaled_font_get_user_data
#define cairo_scaled_font_glyph_extents _moz_cairo_scaled_font_glyph_extents
@ -224,6 +226,7 @@
#define cairo_show_glyphs _moz_cairo_show_glyphs
#define cairo_show_page _moz_cairo_show_page
#define cairo_show_text _moz_cairo_show_text
#define cairo_show_text_glyphs _moz_cairo_show_text_glyphs
#define cairo_status _moz_cairo_status
#define cairo_status_to_string _moz_cairo_status_to_string
#define cairo_stroke _moz_cairo_stroke
@ -237,6 +240,7 @@
#define cairo_surface_flush _moz_cairo_surface_flush
#define cairo_surface_get_content _moz_cairo_surface_get_content
#define cairo_surface_get_device_offset _moz_cairo_surface_get_device_offset
#define cairo_surface_get_fallback_resolution _moz_cairo_surface_get_fallback_resolution
#define cairo_surface_get_font_options _moz_cairo_surface_get_font_options
#define cairo_surface_get_reference_count _moz_cairo_surface_get_reference_count
#define cairo_surface_get_type _moz_cairo_surface_get_type
@ -260,6 +264,15 @@
#define cairo_text_path _moz_cairo_text_path
#define cairo_transform _moz_cairo_transform
#define cairo_translate _moz_cairo_translate
#define cairo_user_font_face_create _moz_cairo_user_font_face_create
#define cairo_user_font_face_get_init_func _moz_cairo_user_font_face_get_init_func
#define cairo_user_font_face_get_render_glyph_func _moz_cairo_user_font_face_get_render_glyph_func
#define cairo_user_font_face_get_text_to_glyphs_func _moz_cairo_user_font_face_get_text_to_glyphs_func
#define cairo_user_font_face_get_unicode_to_glyph_func _moz_cairo_user_font_face_get_unicode_to_glyph_func
#define cairo_user_font_face_set_init_func _moz_cairo_user_font_face_set_init_func
#define cairo_user_font_face_set_render_glyph_func _moz_cairo_user_font_face_set_render_glyph_func
#define cairo_user_font_face_set_text_to_glyphs_func _moz_cairo_user_font_face_set_text_to_glyphs_func
#define cairo_user_font_face_set_unicode_to_glyph_func _moz_cairo_user_font_face_set_unicode_to_glyph_func
#define cairo_user_to_device _moz_cairo_user_to_device
#define cairo_user_to_device_distance _moz_cairo_user_to_device_distance
#define cairo_version _moz_cairo_version
@ -295,10 +308,10 @@
#define cairo_xlib_surface_get_xrender_format _moz_cairo_xlib_surface_get_xrender_format
#define cairo_xlib_surface_set_drawable _moz_cairo_xlib_surface_set_drawable
#define cairo_xlib_surface_set_size _moz_cairo_xlib_surface_set_size
#define pixman_transform_point_3d _moz_pixman_transform_point_3d
#define pixman_region_set_static_pointers _moz_pixman_region_set_static_pointers
#define pixman_region_init _moz_pixman_region_init
#define pixman_region_init_rect _moz_pixman_region_init_rect
#define pixman_region_init_rects _moz_pixman_region_init_rects
#define pixman_region_init_with_extents _moz_pixman_region_init_with_extents
#define pixman_region_fini _moz_pixman_region_fini
#define pixman_region_translate _moz_pixman_region_translate
@ -317,9 +330,34 @@
#define pixman_region_equal _moz_pixman_region_equal
#define pixman_region_selfcheck _moz_pixman_region_selfcheck
#define pixman_region_reset _moz_pixman_region_reset
#define pixman_region_init_rects _moz_pixman_region_init_rects
#define pixman_region32_init _moz_pixman_region32_init
#define pixman_region32_init_rect _moz_pixman_region32_init_rect
#define pixman_region32_init_rects _moz_pixman_region32_init_rects
#define pixman_region32_init_with_extents _moz_pixman_region32_init_with_extents
#define pixman_region32_fini _moz_pixman_region32_fini
#define pixman_region32_translate _moz_pixman_region32_translate
#define pixman_region32_copy _moz_pixman_region32_copy
#define pixman_region32_intersect _moz_pixman_region32_intersect
#define pixman_region32_union _moz_pixman_region32_union
#define pixman_region32_union_rect _moz_pixman_region32_union_rect
#define pixman_region32_subtract _moz_pixman_region32_subtract
#define pixman_region32_inverse _moz_pixman_region32_inverse
#define pixman_region32_contains_point _moz_pixman_region32_contains_point
#define pixman_region32_contains_rectangle _moz_pixman_region32_contains_rectangle
#define pixman_region32_not_empty _moz_pixman_region32_not_empty
#define pixman_region32_extents _moz_pixman_region32_extents
#define pixman_region32_n_rects _moz_pixman_region32_n_rects
#define pixman_region32_rectangles _moz_pixman_region32_rectangles
#define pixman_region32_equal _moz_pixman_region32_equal
#define pixman_region32_selfcheck _moz_pixman_region32_selfcheck
#define pixman_region32_reset _moz_pixman_region32_reset
#define pixman_blt _moz_pixman_blt
#define pixman_fill _moz_pixman_fill
#define pixman_transform_point_3d _moz_pixman_transform_point_3d
#define pixman_version _moz_pixman_version
#define pixman_version_string _moz_pixman_version_string
#define pixman_format_supported_destination _moz_pixman_format_supported_destination
#define pixman_format_supported_source _moz_pixman_format_supported_source
#define pixman_image_create_solid_fill _moz_pixman_image_create_solid_fill
#define pixman_image_create_linear_gradient _moz_pixman_image_create_linear_gradient
#define pixman_image_create_radial_gradient _moz_pixman_image_create_radial_gradient
@ -328,11 +366,12 @@
#define pixman_image_ref _moz_pixman_image_ref
#define pixman_image_unref _moz_pixman_image_unref
#define pixman_image_set_clip_region _moz_pixman_image_set_clip_region
#define pixman_image_set_clip_region32 _moz_pixman_image_set_clip_region32
#define pixman_image_set_has_client_clip _moz_pixman_image_set_has_client_clip
#define pixman_image_set_transform _moz_pixman_image_set_transform
#define pixman_image_set_repeat _moz_pixman_image_set_repeat
#define pixman_image_set_filter _moz_pixman_image_set_filter
#define pixman_image_set_filter_params _moz_pixman_image_set_filter_params
#define pixman_image_set_source_clipping _moz_pixman_image_set_source_clipping
#define pixman_image_set_alpha_map _moz_pixman_image_set_alpha_map
#define pixman_image_set_component_alpha _moz_pixman_image_set_component_alpha
#define pixman_image_set_accessors _moz_pixman_image_set_accessors
@ -354,5 +393,3 @@
#define pixman_add_traps _moz_pixman_add_traps
#define pixman_add_trapezoids _moz_pixman_add_trapezoids
#define pixman_rasterize_trapezoid _moz_pixman_rasterize_trapezoid
#define pixman_transform_point_3d _moz_pixman_transform_point_3d

View File

@ -89,9 +89,14 @@ struct _cairo_scaled_font {
cairo_matrix_t ctm; /* user space => device space */
cairo_font_options_t options;
cairo_bool_t placeholder; /* protected by fontmap mutex */
cairo_bool_t finished;
/* "live" scaled_font members */
cairo_matrix_t scale; /* font space => device space */
cairo_matrix_t scale_inverse; /* device space => font space */
double max_scale; /* maximum x/y expansion of scale */
cairo_font_extents_t extents; /* user space */
/* The mutex protects modification to all subsequent fields. */

View File

@ -46,6 +46,9 @@ typedef struct _cairo_scaled_font_subsets_glyph {
cairo_bool_t is_scaled;
cairo_bool_t is_composite;
double x_advance;
double y_advance;
cairo_bool_t utf8_is_mapped;
uint32_t unicode;
} cairo_scaled_font_subsets_glyph_t;
/**
@ -175,17 +178,25 @@ _cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *font_subsets);
* @is_scaled: If true, the mapped glyph is from a bitmap font, and separate font
* subset is created for each font scale used. If false, the outline of the mapped glyph
* is available. One font subset for each font face is created.
* @x_advance: When @is_scaled is true, @x_advance contains the x_advance for the mapped glyph in device space.
* When @is_scaled is false, @x_advance contains the x_advance for the the mapped glyph from an unhinted 1 point font.
* @x_advance, @y_advance: When @is_scaled is true, @x_advance and @y_advance contain
* the x and y advance for the mapped glyph in device space.
* When @is_scaled is false, @x_advance and @y_advance contain the x and y advance for
* the the mapped glyph from an unhinted 1 point font.
* @utf8_is_mapped: If true the utf8 string provided to _cairo_scaled_font_subsets_map_glyph()
* is (or already was) the utf8 string mapped to this glyph. If false the glyph is already
* mapped to a different utf8 string.
* @unicode: the unicode character mapped to this glyph by the font backend.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero
* value indicating an error. Possible errors include
* CAIRO_STATUS_NO_MEMORY.
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_t *scaled_font,
unsigned long scaled_font_glyph_index,
const char * utf8,
int utf8_len,
cairo_scaled_font_subsets_glyph_t *subset_glyph_ret);
typedef cairo_status_t
@ -220,7 +231,7 @@ typedef cairo_status_t
*
* Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero
* value indicating an error. Possible errors include
* CAIRO_STATUS_NO_MEMORY.
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *font_subsets,
@ -255,7 +266,7 @@ _cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *fon
*
* Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero
* value indicating an error. Possible errors include
* CAIRO_STATUS_NO_MEMORY.
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets,
@ -270,7 +281,7 @@ _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t
* in @font_subsets. The array as store in font_subsets->glyph_names.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font backend does not support
* %CAIRO_INT_STATUS_UNSUPPORTED if the font backend does not support
* mapping the glyph indices to unicode characters. Possible errors
* include %CAIRO_STATUS_NO_MEMORY.
**/
@ -298,7 +309,7 @@ typedef struct _cairo_cff_subset {
* data.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* cff file, or an non-zero value indicating an error. Possible
* errors include %CAIRO_STATUS_NO_MEMORY.
**/
@ -329,7 +340,7 @@ _cairo_cff_subset_fini (cairo_cff_subset_t *cff_subset);
* with information about the subset and the cff data.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* cff file, or an non-zero value indicating an error. Possible
* errors include %CAIRO_STATUS_NO_MEMORY.
**/
@ -372,7 +383,7 @@ typedef struct _cairo_truetype_subset {
* data.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* truetype file, or an non-zero value indicating an error. Possible
* errors include %CAIRO_STATUS_NO_MEMORY.
**/
@ -416,7 +427,7 @@ typedef struct _cairo_type1_subset {
* with information about the subset and the type1 data.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* file, or an non-zero value indicating an error. Possible errors
* include %CAIRO_STATUS_NO_MEMORY.
**/
@ -458,7 +469,7 @@ _cairo_type1_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font);
* part of the font is binary encoded.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* file, or an non-zero value indicating an error. Possible errors
* include %CAIRO_STATUS_NO_MEMORY.
**/
@ -479,7 +490,7 @@ _cairo_type1_fallback_init_binary (cairo_type1_subset_t *type_subset,
* part of the font is hex encoded.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* file, or an non-zero value indicating an error. Possible errors
* include %CAIRO_STATUS_NO_MEMORY.
**/
@ -517,7 +528,7 @@ typedef struct _cairo_type2_charstrings {
* with information about the subset.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type2
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type2
* charstrings, or an non-zero value indicating an error. Possible errors
* include %CAIRO_STATUS_NO_MEMORY.
**/
@ -546,11 +557,33 @@ _cairo_type2_charstrings_fini (cairo_type2_charstrings_t *charstrings);
* fontsubset->to_unicode.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the unicode encoding of
* %CAIRO_INT_STATUS_UNSUPPORTED if the unicode encoding of
* the glyphs is not available. Possible errors include
* CAIRO_STATUS_NO_MEMORY.
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_int_status_t
_cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t *font_subset);
/**
* _cairo_truetype_index_to_ucs4:
* @scaled_font: the #cairo_scaled_font_t
* @index: the glyph index
* @ucs4: return value for the unicode value of the glyph
*
* If possible (depending on the format of the underlying
* #cairo_scaled_font_t and the font backend in use) assign
* the unicode character of the glyph to @ucs4.
*
* If mapping glyph indices to unicode is supported but the unicode
* value of the specified glyph is not available, @ucs4 is set to -1.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* %CAIRO_INT_STATUS_UNSUPPORTED if mapping glyph indices to unicode
* is not supported. Possible errors include %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_int_status_t
_cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font,
unsigned long index,
uint32_t *ucs4);
#endif /* CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H */

View File

@ -43,6 +43,7 @@
#define _BSD_SOURCE /* for snprintf(), strdup() */
#include "cairoint.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-user-font-private.h"
#define MAX_GLYPHS_PER_SIMPLE_FONT 256
#define MAX_GLYPHS_PER_COMPOSITE_FONT 65536
@ -53,18 +54,6 @@ typedef enum {
CAIRO_SUBSETS_COMPOSITE
} cairo_subsets_type_t;
struct _cairo_scaled_font_subsets {
cairo_subsets_type_t type;
int max_glyphs_per_unscaled_subset_used;
cairo_hash_table_t *unscaled_sub_fonts;
int max_glyphs_per_scaled_subset_used;
cairo_hash_table_t *scaled_sub_fonts;
int num_sub_fonts;
};
typedef struct _cairo_sub_font {
cairo_hash_entry_t base;
@ -79,18 +68,42 @@ typedef struct _cairo_sub_font {
int max_glyphs_per_subset;
cairo_hash_table_t *sub_font_glyphs;
struct _cairo_sub_font *next;
} cairo_sub_font_t;
struct _cairo_scaled_font_subsets {
cairo_subsets_type_t type;
int max_glyphs_per_unscaled_subset_used;
cairo_hash_table_t *unscaled_sub_fonts;
cairo_sub_font_t *unscaled_sub_fonts_list;
cairo_sub_font_t *unscaled_sub_fonts_list_end;
int max_glyphs_per_scaled_subset_used;
cairo_hash_table_t *scaled_sub_fonts;
cairo_sub_font_t *scaled_sub_fonts_list;
cairo_sub_font_t *scaled_sub_fonts_list_end;
int num_sub_fonts;
};
typedef struct _cairo_sub_font_glyph {
cairo_hash_entry_t base;
unsigned int subset_id;
unsigned int subset_glyph_index;
double x_advance;
double y_advance;
cairo_bool_t is_mapped;
uint32_t unicode;
char *utf8;
int utf8_len;
} cairo_sub_font_glyph_t;
typedef struct _cairo_sub_font_collection {
unsigned long *glyphs; /* scaled_font_glyph_index */
char **utf8;
unsigned int glyphs_size;
unsigned int max_glyph;
unsigned int num_glyphs;
@ -110,6 +123,8 @@ typedef struct _cairo_string_entry {
static cairo_status_t
_cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
unsigned long scaled_font_glyph_index,
const char * utf8,
int utf8_len,
cairo_scaled_font_subsets_glyph_t *subset_glyph);
static void
@ -132,7 +147,8 @@ static cairo_sub_font_glyph_t *
_cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index,
unsigned int subset_id,
unsigned int subset_glyph_index,
double x_advance)
double x_advance,
double y_advance)
{
cairo_sub_font_glyph_t *sub_font_glyph;
@ -146,6 +162,11 @@ _cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index,
sub_font_glyph->subset_id = subset_id;
sub_font_glyph->subset_glyph_index = subset_glyph_index;
sub_font_glyph->x_advance = x_advance;
sub_font_glyph->y_advance = y_advance;
sub_font_glyph->is_mapped = FALSE;
sub_font_glyph->unicode = -1;
sub_font_glyph->utf8 = NULL;
sub_font_glyph->utf8_len = 0;
return sub_font_glyph;
}
@ -153,6 +174,9 @@ _cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index,
static void
_cairo_sub_font_glyph_destroy (cairo_sub_font_glyph_t *sub_font_glyph)
{
if (sub_font_glyph->utf8 != NULL)
free (sub_font_glyph->utf8);
free (sub_font_glyph);
}
@ -184,6 +208,7 @@ _cairo_sub_font_glyph_collect (void *entry, void *closure)
assert (subset_glyph_index < collection->glyphs_size);
collection->glyphs[subset_glyph_index] = scaled_font_glyph_index;
collection->utf8[subset_glyph_index] = sub_font_glyph->utf8;
if (subset_glyph_index > collection->max_glyph)
collection->max_glyph = subset_glyph_index;
@ -252,9 +277,10 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
free (sub_font);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
sub_font->next = NULL;
/* Reserve first glyph in subset for the .notdef glyph */
status = _cairo_sub_font_map_glyph (sub_font, 0, &subset_glyph);
status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, 0, &subset_glyph);
if (status) {
_cairo_hash_table_destroy (sub_font->sub_font_glyphs);
free (sub_font);
@ -286,9 +312,86 @@ _cairo_sub_font_pluck (void *entry, void *closure)
_cairo_sub_font_destroy (sub_font);
}
static cairo_status_t
_cairo_sub_font_glyph_lookup_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
cairo_scaled_font_t *scaled_font,
unsigned long scaled_font_glyph_index)
{
uint32_t unicode;
char buf[8];
int len;
cairo_status_t status;
/* Do a reverse lookup on the glyph index. unicode is -1 if the
* index could not be mapped to a unicode character. */
status = _cairo_truetype_index_to_ucs4 (scaled_font, scaled_font_glyph_index, &unicode);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
unicode = -1;
if (unicode == (uint32_t)-1 && scaled_font->backend->index_to_ucs4)
status = scaled_font->backend->index_to_ucs4 (scaled_font, scaled_font_glyph_index, &unicode);
sub_font_glyph->unicode = unicode;
sub_font_glyph->utf8 = NULL;
sub_font_glyph->utf8_len = 0;
if (unicode != (uint32_t)-1) {
len = _cairo_ucs4_to_utf8 (unicode, buf);
if (len > 0) {
sub_font_glyph->utf8 = malloc(len + 1);
memcpy (sub_font_glyph->utf8, buf, len);
sub_font_glyph->utf8[len] = 0;
sub_font_glyph->utf8_len = len;
}
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_bool_t
_cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
const char *utf8,
int utf8_len)
{
int add_zero_byte = 0;
if (utf8 != NULL && utf8_len != 0) {
if (sub_font_glyph->utf8 != NULL) {
if (utf8_len == sub_font_glyph->utf8_len &&
memcmp (utf8, sub_font_glyph->utf8, utf8_len) == 0)
{
/* Requested utf8 mapping matches the existing mapping */
return TRUE;
}
else
{
/* Requested utf8 mapping does not match the existing mapping */
return FALSE;
}
} else {
/* No existing mapping. Use the requested mapping */
if (sub_font_glyph->utf8[utf8_len - 1] != 0)
add_zero_byte = 1;
sub_font_glyph->utf8 = malloc (utf8_len + add_zero_byte);
memcpy (sub_font_glyph->utf8, utf8, utf8_len);
if (add_zero_byte)
sub_font_glyph->utf8[utf8_len] = 0;
sub_font_glyph->utf8_len = utf8_len;
return TRUE;
}
}
/* No mapping was requested. */
return FALSE;
}
static cairo_bool_t
_cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
unsigned long scaled_font_glyph_index,
const char * utf8,
int utf8_len,
cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
cairo_sub_font_glyph_t key, *sub_font_glyph;
@ -303,8 +406,11 @@ _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
subset_glyph->is_scaled = sub_font->is_scaled;
subset_glyph->is_composite = sub_font->is_composite;
subset_glyph->x_advance = sub_font_glyph->x_advance;
subset_glyph->y_advance = sub_font_glyph->y_advance;
subset_glyph->utf8_is_mapped = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, utf8, utf8_len);
subset_glyph->unicode = sub_font_glyph->unicode;
return TRUE;
return TRUE;
}
return FALSE;
@ -313,6 +419,8 @@ _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
static cairo_status_t
_cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
unsigned long scaled_font_glyph_index,
const char * utf8,
int utf8_len,
cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
cairo_sub_font_glyph_t key, *sub_font_glyph;
@ -330,7 +438,7 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
sub_font->num_glyphs_in_current_subset = 0;
/* Reserve first glyph in subset for the .notdef glyph */
status = _cairo_sub_font_map_glyph (sub_font, 0, &tmp_subset_glyph);
status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, 0, &tmp_subset_glyph);
if (status)
return status;
}
@ -346,10 +454,15 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
sub_font->current_subset,
sub_font->num_glyphs_in_current_subset,
scaled_glyph->metrics.x_advance);
scaled_glyph->metrics.x_advance,
scaled_glyph->metrics.y_advance);
if (sub_font_glyph == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_sub_font_glyph_lookup_unicode (sub_font_glyph,
sub_font->scaled_font,
scaled_font_glyph_index);
status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
if (status) {
_cairo_sub_font_glyph_destroy (sub_font_glyph);
@ -376,6 +489,8 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
subset_glyph->is_scaled = sub_font->is_scaled;
subset_glyph->is_composite = sub_font->is_composite;
subset_glyph->x_advance = sub_font_glyph->x_advance;
subset_glyph->y_advance = sub_font_glyph->y_advance;
subset_glyph->utf8_is_mapped = FALSE;
return CAIRO_STATUS_SUCCESS;
}
@ -412,6 +527,7 @@ _cairo_sub_font_collect (void *entry, void *closure)
subset.font_id = sub_font->font_id;
subset.subset_id = i;
subset.glyphs = collection->glyphs;
subset.utf8 = collection->utf8;
subset.num_glyphs = collection->num_glyphs;
subset.glyph_names = NULL;
/* No need to check for out of memory here. If to_unicode is NULL, the PDF
@ -461,6 +577,8 @@ _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
free (subsets);
return NULL;
}
subsets->unscaled_sub_fonts_list = NULL;
subsets->unscaled_sub_fonts_list_end = NULL;
subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
if (! subsets->scaled_sub_fonts) {
@ -468,6 +586,8 @@ _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
free (subsets);
return NULL;
}
subsets->scaled_sub_fonts_list = NULL;
subsets->scaled_sub_fonts_list_end = NULL;
return subsets;
}
@ -506,6 +626,8 @@ cairo_status_t
_cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
cairo_scaled_font_t *scaled_font,
unsigned long scaled_font_glyph_index,
const char * utf8,
int utf8_len,
cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
cairo_sub_font_t key, *sub_font;
@ -527,6 +649,7 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
{
if (_cairo_sub_font_lookup_glyph (sub_font,
scaled_font_glyph_index,
utf8, utf8_len,
subset_glyph))
return CAIRO_STATUS_SUCCESS;
}
@ -540,6 +663,7 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
{
if (_cairo_sub_font_lookup_glyph (sub_font,
scaled_font_glyph_index,
utf8, utf8_len,
subset_glyph))
return CAIRO_STATUS_SUCCESS;
}
@ -564,7 +688,8 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
return status;
if (status == CAIRO_STATUS_SUCCESS &&
subsets->type != CAIRO_SUBSETS_SCALED)
subsets->type != CAIRO_SUBSETS_SCALED &&
! _cairo_font_face_is_user (scaled_font->font_face))
{
/* Path available. Add to unscaled subset. */
key.is_scaled = FALSE;
@ -611,11 +736,16 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
&sub_font->base);
if (status) {
_cairo_sub_font_destroy (sub_font);
return status;
}
if (!subsets->unscaled_sub_fonts_list)
subsets->unscaled_sub_fonts_list = sub_font;
else
subsets->unscaled_sub_fonts_list_end->next = sub_font;
subsets->unscaled_sub_fonts_list_end = sub_font;
subsets->num_sub_fonts++;
}
} else {
@ -650,13 +780,18 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
_cairo_sub_font_destroy (sub_font);
return status;
}
if (!subsets->scaled_sub_fonts_list)
subsets->scaled_sub_fonts_list = sub_font;
else
subsets->scaled_sub_fonts_list_end->next = sub_font;
subsets->scaled_sub_fonts_list_end = sub_font;
subsets->num_sub_fonts++;
}
}
return _cairo_sub_font_map_glyph (sub_font,
scaled_font_glyph_index,
utf8, utf8_len,
subset_glyph);
}
@ -667,6 +802,7 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
cairo_bool_t is_scaled)
{
cairo_sub_font_collection_t collection;
cairo_sub_font_t *sub_font;
if (is_scaled)
collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
@ -677,20 +813,30 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
return CAIRO_STATUS_SUCCESS;
collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long));
if (collection.glyphs == NULL)
collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *));
if (collection.glyphs == NULL || collection.utf8 == NULL) {
if (collection.glyphs != NULL)
free (collection.glyphs);
if (collection.utf8 != NULL)
free (collection.utf8);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
collection.font_subset_callback = font_subset_callback;
collection.font_subset_callback_closure = closure;
collection.status = CAIRO_STATUS_SUCCESS;
if (is_scaled)
_cairo_hash_table_foreach (font_subsets->scaled_sub_fonts,
_cairo_sub_font_collect, &collection);
sub_font = font_subsets->scaled_sub_fonts_list;
else
_cairo_hash_table_foreach (font_subsets->unscaled_sub_fonts,
_cairo_sub_font_collect, &collection);
sub_font = font_subsets->unscaled_sub_fonts_list;
while (sub_font) {
_cairo_sub_font_collect (sub_font, &collection);
sub_font = sub_font->next;
}
free (collection.utf8);
free (collection.glyphs);
return collection.status;
@ -757,29 +903,14 @@ create_string_entry (char *s, cairo_string_entry_t **entry)
cairo_int_status_t
_cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset)
{
const cairo_scaled_font_backend_t *backend;
unsigned int i;
cairo_status_t status;
cairo_hash_table_t *names;
cairo_string_entry_t key, *entry;
char buf[30];
if (subset->to_unicode == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_truetype_create_glyph_to_unicode_map (subset);
if (status) {
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
backend = subset->scaled_font->backend;
if (backend->map_glyphs_to_unicode == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = backend->map_glyphs_to_unicode (subset->scaled_font, subset);
if (status)
return status;
}
char *utf8;
uint16_t *utf16;
int utf16_len;
names = _cairo_hash_table_create (_cairo_string_equal);
if (names == NULL)
@ -808,8 +939,17 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset
}
for (i = 1; i < subset->num_glyphs; i++) {
if (subset->to_unicode[i] <= 0xffff) {
snprintf (buf, sizeof(buf), "uni%04X", (unsigned int)(subset->to_unicode[i]));
utf8 = subset->utf8[i];
utf16 = NULL;
utf16_len = 0;
if (utf8 && *utf8) {
status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
if (status && status != CAIRO_STATUS_INVALID_STRING)
return status; // FIXME
}
if (utf16_len == 1) {
snprintf (buf, sizeof(buf), "uni%04X", (int)(utf16[0]));
_cairo_string_init_key (&key, buf);
if (_cairo_hash_table_lookup (names, &key.base,
(cairo_hash_entry_t **) &entry)) {
@ -818,6 +958,8 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset
} else {
snprintf (buf, sizeof(buf), "g%d", i);
}
if (utf16)
free (utf16);
subset->glyph_names[i] = strdup (buf);
if (subset->glyph_names[i] == NULL) {

View File

@ -167,6 +167,8 @@ _cairo_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph)
cairo_surface_destroy (&scaled_glyph->surface->base);
if (scaled_glyph->path != NULL)
_cairo_path_fixed_destroy (scaled_glyph->path);
if (scaled_glyph->meta_surface != NULL)
cairo_surface_destroy (scaled_glyph->meta_surface);
}
static void
@ -190,8 +192,11 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = {
CAIRO_SUBPIXEL_ORDER_DEFAULT,
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_METRICS_DEFAULT} ,
FALSE, /* placeholder */
TRUE, /* finished */
{ 1., 0., 0., 1., 0, 0}, /* scale */
{ 1., 0., 0., 1., 0, 0}, /* scale_inverse */
1., /* max_scale */
{ 0., 0., 0., 0., 0. }, /* extents */
CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */
NULL, /* glyphs */
@ -203,10 +208,10 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = {
/**
* _cairo_scaled_font_set_error:
* @scaled_font: a scaled_font
* @status: a status value indicating an error, (eg. not
* CAIRO_STATUS_SUCCESS)
* @status: a status value indicating an error
*
* Atomically sets scaled_font->status to @status and calls _cairo_error;
* Does nothing if status is %CAIRO_STATUS_SUCCESS.
*
* All assignments of an error status to scaled_font->status should happen
* through _cairo_scaled_font_set_error(). Note that due to the nature of
@ -343,7 +348,6 @@ _cairo_scaled_font_map_unlock (void)
void
_cairo_scaled_font_map_destroy (void)
{
int i;
cairo_scaled_font_map_t *font_map;
cairo_scaled_font_t *scaled_font;
@ -354,15 +358,23 @@ _cairo_scaled_font_map_destroy (void)
goto CLEANUP_MUTEX_LOCK;
}
for (i = 0; i < font_map->num_holdovers; i++) {
scaled_font = font_map->holdovers[i];
/* We should only get here through the reset_static_data path
* and there had better not be any active references at that
* point. */
/* remove scaled_fonts starting from the end so that font_map->holdovers
* is always in a consistent state when we release the mutex. */
while (font_map->num_holdovers) {
scaled_font = font_map->holdovers[font_map->num_holdovers-1];
assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
_cairo_hash_table_remove (font_map->hash_table,
&scaled_font->hash_entry);
font_map->num_holdovers--;
/* release the lock to avoid the possibility of a recursive
* deadlock when the scaled font destroy closure gets called */
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
_cairo_scaled_font_fini (scaled_font);
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
free (scaled_font);
}
@ -375,6 +387,113 @@ _cairo_scaled_font_map_destroy (void)
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
}
/* If a scaled font wants to unlock the font map while still being
* created (needed for user-fonts), we need to take extra care not
* ending up with multiple identical scaled fonts being created.
*
* What we do is, we create a fake identical scaled font, and mark
* it as placeholder, lock its mutex, and insert that in the fontmap
* hash table. This makes other code trying to create an identical
* scaled font to just wait and retry.
*
* The reason we have to create a fake scaled font instead of just using
* scaled_font is for lifecycle management: we need to (or rather,
* other code needs to) reference the scaked_font in the hash.
* We can't do that on the input scaled_font as it may be freed by
* font backend upon error.
*/
void
_cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t *scaled_font)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_scaled_font_t *placeholder_scaled_font;
placeholder_scaled_font = malloc (sizeof (cairo_scaled_font_t));
if (!placeholder_scaled_font) {
status = CAIRO_STATUS_NO_MEMORY;
goto FREE;
}
/* full initialization is wasteful, but who cares... */
status = _cairo_scaled_font_init (placeholder_scaled_font,
scaled_font->font_face,
&scaled_font->font_matrix,
&scaled_font->ctm,
&scaled_font->options,
NULL);
if (status)
goto FINI;
placeholder_scaled_font->placeholder = TRUE;
CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex);
status = _cairo_hash_table_insert (cairo_scaled_font_map->hash_table,
&placeholder_scaled_font->hash_entry);
if (status)
goto UNLOCK_KEY;
goto UNLOCK;
UNLOCK_KEY:
CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
FINI:
_cairo_scaled_font_fini (placeholder_scaled_font);
FREE:
free (placeholder_scaled_font);
status = _cairo_scaled_font_set_error (scaled_font, status);
UNLOCK:
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
}
void
_cairo_scaled_font_unregister_placeholder_and_lock_font_map (cairo_scaled_font_t *scaled_font)
{
cairo_scaled_font_t *placeholder_scaled_font;
cairo_bool_t found;
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
found = _cairo_hash_table_lookup (cairo_scaled_font_map->hash_table,
&scaled_font->hash_entry,
(cairo_hash_entry_t**) &placeholder_scaled_font);
assert (found);
assert (placeholder_scaled_font->placeholder);
_cairo_hash_table_remove (cairo_scaled_font_map->hash_table,
&scaled_font->hash_entry);
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
cairo_scaled_font_destroy (placeholder_scaled_font);
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
}
static void
_cairo_scaled_font_placeholder_wait_for_creation_to_finish (cairo_scaled_font_t *scaled_font)
{
/* reference the place holder so it doesn't go away */
cairo_scaled_font_reference (scaled_font);
/* now unlock the fontmap mutex so creation has a chance to finish */
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
/* wait on placeholder mutex until we are awaken */
CAIRO_MUTEX_LOCK (scaled_font->mutex);
/* ok, creation done. just clean up and back out */
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
cairo_scaled_font_destroy (scaled_font);
}
/* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
*
* Not necessarily better than a lot of other hashes, but should be OK, and
@ -407,6 +526,7 @@ _cairo_scaled_font_init_key (cairo_scaled_font_t *scaled_font,
uint32_t hash = FNV1_32_INIT;
scaled_font->status = CAIRO_STATUS_SUCCESS;
scaled_font->placeholder = FALSE;
scaled_font->font_face = font_face;
scaled_font->font_matrix = *font_matrix;
scaled_font->ctm = *ctm;
@ -477,6 +597,8 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
&scaled_font->font_matrix,
&scaled_font->ctm);
scaled_font->max_scale = MAX (fabs (scaled_font->scale.xx) + fabs (scaled_font->scale.xy),
fabs (scaled_font->scale.yx) + fabs (scaled_font->scale.yy));
scaled_font->scale_inverse = scaled_font->scale;
status = cairo_matrix_invert (&scaled_font->scale_inverse);
if (status) {
@ -485,9 +607,9 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
* producing an error.
*
* FIXME: If the scale is rank 1, we still go into error mode. But then
* again, that's what we doo everywhere in cairo.
* again, that's what we do everywhere in cairo.
*
* Also, the check for == 0. below may bee too harsh...
* Also, the check for == 0. below may be too harsh...
*/
if (scaled_font->scale.xx == 0. && scaled_font->scale.xy == 0. &&
scaled_font->scale.yx == 0. && scaled_font->scale.yy == 0.)
@ -499,6 +621,8 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
return status;
}
scaled_font->finished = FALSE;
scaled_font->glyphs = _cairo_cache_create (_cairo_scaled_glyph_keys_equal,
_cairo_scaled_glyph_destroy,
MAX_GLYPHS_CACHED_PER_FONT);
@ -551,7 +675,7 @@ _cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font,
status = _cairo_matrix_compute_scale_factors (&scaled_font->font_matrix,
&font_scale_x, &font_scale_y,
/* XXX */ 1);
1);
if (status)
return status;
@ -572,6 +696,8 @@ _cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font,
void
_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
{
scaled_font->finished = TRUE;
if (scaled_font->font_face != NULL)
cairo_font_face_destroy (scaled_font->font_face);
@ -584,7 +710,8 @@ _cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
scaled_font->surface_backend->scaled_font_fini != NULL)
scaled_font->surface_backend->scaled_font_fini (scaled_font);
scaled_font->backend->fini (scaled_font);
if (scaled_font->backend != NULL && scaled_font->backend->fini != NULL)
scaled_font->backend->fini (scaled_font);
_cairo_user_data_array_fini (&scaled_font->user_data);
}
@ -637,9 +764,20 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
_cairo_scaled_font_init_key (&key, font_face,
font_matrix, ctm, options);
while (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry,
(cairo_hash_entry_t**) &scaled_font))
{
if (!scaled_font->placeholder)
break;
/* If the scaled font is being created (happens for user-font),
* just wait until it's done, then retry */
_cairo_scaled_font_placeholder_wait_for_creation_to_finish (scaled_font);
}
/* 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))
if (scaled_font)
{
/* If the original reference count is 0, then this font must have
* been found in font_map->holdovers, (which means this caching is
@ -793,26 +931,29 @@ slim_hidden_def (cairo_scaled_font_reference);
void
cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
{
cairo_scaled_font_map_t *font_map;
cairo_scaled_font_t *lru = NULL;
cairo_scaled_font_map_t *font_map;
if (scaled_font == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
return;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
font_map = _cairo_scaled_font_map_lock ();
assert (font_map != NULL);
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
if (_cairo_reference_count_dec_and_test (&scaled_font->ref_count)) {
if (scaled_font->hash_entry.hash != ZOMBIE) {
if (!scaled_font->placeholder && scaled_font->hash_entry.hash != ZOMBIE) {
/* Rather than immediately destroying this object, we put it into
* the font_map->holdovers array in case it will get used again
* soon (and is why we must hold the lock over the atomic op on
* the reference count). To make room for it, we do actually
* destroy the least-recently-used holdover.
*/
if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS)
{
lru = font_map->holdovers[0];
@ -830,8 +971,10 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
font_map->num_holdovers++;
} else
lru = scaled_font;
}
_cairo_scaled_font_map_unlock ();
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
/* If we pulled an item from the holdovers array, (while the font
* map lock was held, of course), then there is no way that anyone
@ -1033,6 +1176,21 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
return;
}
if (num_glyphs == 0)
return;
if (num_glyphs < 0) {
_cairo_error_throw (CAIRO_STATUS_NEGATIVE_COUNT);
/* XXX Can't propagate error */
return;
}
if (glyphs == NULL) {
_cairo_error_throw (CAIRO_STATUS_NULL_POINTER);
/* XXX Can't propagate error */
return;
}
CAIRO_MUTEX_LOCK (scaled_font->mutex);
_cairo_scaled_font_freeze_cache (scaled_font);
@ -1119,20 +1277,26 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
cairo_status_t status;
cairo_scaled_glyph_t *scaled_glyph;
*num_glyphs = 0;
*glyphs = NULL;
status = scaled_font->status;
if (status)
return status;
if (utf8[0] == '\0') {
*num_glyphs = 0;
*glyphs = NULL;
if (utf8[0] == '\0')
return CAIRO_STATUS_SUCCESS;
}
CAIRO_MUTEX_LOCK (scaled_font->mutex);
_cairo_scaled_font_freeze_cache (scaled_font);
if (scaled_font->backend->text_to_glyphs) {
/* validate input so backend does not have to */
status = _cairo_utf8_to_ucs4 (utf8, -1, NULL, NULL);
if (status)
goto DONE;
status = scaled_font->backend->text_to_glyphs (scaled_font,
x, y, utf8,
glyphs, num_glyphs);
@ -1141,7 +1305,7 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
goto DONE;
}
status = _cairo_utf8_to_ucs4 ((unsigned char*)utf8, -1, &ucs4, num_glyphs);
status = _cairo_utf8_to_ucs4 (utf8, -1, &ucs4, num_glyphs);
if (status)
goto DONE;
@ -1212,7 +1376,7 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
if (status)
return _cairo_scaled_font_set_error (scaled_font, status);
/* glyph images are snapped to pixel locations */
/* XXX glyph images are snapped to pixel locations */
x = _cairo_lround (glyphs[i].x);
y = _cairo_lround (glyphs[i].y);
@ -1271,13 +1435,18 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
return CAIRO_STATUS_SUCCESS;
if (scaled_font->backend->show_glyphs != NULL) {
int remaining_glyphs = num_glyphs;
status = scaled_font->backend->show_glyphs (scaled_font,
op, pattern,
surface,
source_x, source_y,
dest_x, dest_y,
width, height,
glyphs, num_glyphs);
glyphs, num_glyphs, &remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
status = CAIRO_STATUS_SUCCESS;
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_scaled_font_set_error (scaled_font, status);
}
@ -1641,7 +1810,7 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
}
/**
* cairo_scaled_glyph_set_metrics:
* _cairo_scaled_glyph_set_metrics:
* @scaled_glyph: a #cairo_scaled_glyph_t
* @scaled_font: a #cairo_scaled_font_t
* @fs_metrics: a #cairo_text_extents_t in font space
@ -1649,7 +1818,7 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
* _cairo_scaled_glyph_set_metrics() stores user space metrics
* for the specified glyph given font space metrics. It is
* called by the font backend when initializing a glyph with
* CAIRO_SCALED_GLYPH_INFO_METRICS.
* %CAIRO_SCALED_GLYPH_INFO_METRICS.
**/
void
_cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph,
@ -1744,6 +1913,16 @@ _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
scaled_glyph->path = path;
}
void
_cairo_scaled_glyph_set_meta_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_surface_t *meta_surface)
{
if (scaled_glyph->meta_surface != NULL)
cairo_surface_destroy (meta_surface);
scaled_glyph->meta_surface = meta_surface;
}
/**
* _cairo_scaled_glyph_lookup:
* @scaled_font: a #cairo_scaled_font_t
@ -1763,7 +1942,7 @@ _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
*
* If the desired info is not available, (for example, when trying to
* get INFO_PATH with a bitmapped font), this function will return
* CAIRO_INT_STATUS_UNSUPPORTED.
* %CAIRO_INT_STATUS_UNSUPPORTED.
*
* Note: This function must be called with scaled_font->mutex held.
**/
@ -1799,10 +1978,11 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
}
_cairo_scaled_glyph_set_index(scaled_glyph, index);
scaled_glyph->cache_entry.size = 1; /* XXX */
scaled_glyph->cache_entry.size = 1; /* We currently don't differentiate on glyph size at all */
scaled_glyph->scaled_font = scaled_font;
scaled_glyph->surface = NULL;
scaled_glyph->path = NULL;
scaled_glyph->meta_surface = NULL;
scaled_glyph->surface_private = NULL;
/* ask backend to initialize metrics and shape fields */
@ -1834,11 +2014,38 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
scaled_glyph->path == NULL))
need_info |= CAIRO_SCALED_GLYPH_INFO_PATH;
if (((info & CAIRO_SCALED_GLYPH_INFO_META_SURFACE) != 0 &&
scaled_glyph->path == NULL))
need_info |= CAIRO_SCALED_GLYPH_INFO_META_SURFACE;
if (need_info) {
status = (*scaled_font->backend->
scaled_glyph_init) (scaled_font, scaled_glyph, need_info);
if (status)
goto CLEANUP;
/* Don't trust the scaled_glyph_init() return value, the font
* backend may not even know about some of the info. For example,
* no backend other than the user-fonts knows about meta-surface
* glyph info. */
if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0 &&
scaled_glyph->surface == NULL) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto CLEANUP;
}
if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0 &&
scaled_glyph->path == NULL) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto CLEANUP;
}
if ((info & CAIRO_SCALED_GLYPH_INFO_META_SURFACE) != 0 &&
scaled_glyph->meta_surface == NULL) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto CLEANUP;
}
}
CLEANUP:
@ -1854,6 +2061,13 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
return status;
}
double
_cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font)
{
return scaled_font->max_scale;
}
/**
* cairo_scaled_font_get_font_face:
* @scaled_font: a #cairo_scaled_font_t
@ -1920,6 +2134,30 @@ cairo_scaled_font_get_ctm (cairo_scaled_font_t *scaled_font,
}
slim_hidden_def (cairo_scaled_font_get_ctm);
/**
* cairo_scaled_font_get_scale_matrix:
* @scaled_font: a #cairo_scaled_font_t
* @scale_matrix: return value for the matrix
*
* Stores the scale matrix of @scaled_font into @matrix.
* The scale matrix is product of the font matrix and the ctm
* associated with the scaled font, and hence is the matrix mapping from
* font space to device space.
*
* Since: 1.8
**/
void
cairo_scaled_font_get_scale_matrix (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *scale_matrix)
{
if (scaled_font->status) {
cairo_matrix_init_identity (scale_matrix);
return;
}
*scale_matrix = scaled_font->scale;
}
/**
* cairo_scaled_font_get_font_options:
* @scaled_font: a #cairo_scaled_font_t

View File

@ -358,7 +358,7 @@ _clip_and_composite (cairo_clip_t *clip,
cairo_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
cairo_pattern_union_t solid_pattern;
cairo_solid_pattern_t solid_pattern;
cairo_status_t status;
if (_cairo_rectangle_empty (extents))
@ -366,7 +366,7 @@ _clip_and_composite (cairo_clip_t *clip,
return CAIRO_STATUS_SUCCESS;
if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE,
_cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
src = &solid_pattern.base;
op = CAIRO_OPERATOR_DEST_OUT;
@ -415,14 +415,14 @@ _composite_trap_region (cairo_clip_t *clip,
cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_pattern_union_t solid_pattern;
cairo_pattern_union_t mask;
cairo_solid_pattern_t solid_pattern;
cairo_surface_pattern_t mask;
int num_rects = _cairo_region_num_boxes (trap_region);
unsigned int clip_serial;
cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
if (clip_surface && op == CAIRO_OPERATOR_CLEAR) {
_cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE,
_cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
src = &solid_pattern.base;
op = CAIRO_OPERATOR_DEST_OUT;
@ -444,7 +444,7 @@ _composite_trap_region (cairo_clip_t *clip,
}
if (clip_surface)
_cairo_pattern_init_for_surface (&mask.surface, clip_surface);
_cairo_pattern_init_for_surface (&mask, clip_surface);
status = _cairo_surface_composite (op,
src,
@ -487,13 +487,13 @@ _composite_traps_draw_func (void *closure,
const cairo_rectangle_int_t *extents)
{
cairo_composite_traps_info_t *info = closure;
cairo_pattern_union_t pattern;
cairo_solid_pattern_t pattern;
cairo_status_t status;
if (dst_x != 0 || dst_y != 0)
_cairo_traps_translate (info->traps, - dst_x, - dst_y);
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
_cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
if (!src)
src = &pattern.base;
@ -929,7 +929,7 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure
const cairo_rectangle_int_t *extents)
{
cairo_show_glyphs_info_t *glyph_info = closure;
cairo_pattern_union_t pattern;
cairo_solid_pattern_t pattern;
cairo_status_t status;
/* Modifying the glyph array is fine because we know that this function
@ -946,7 +946,7 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure
}
}
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
_cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
if (!src)
src = &pattern.base;
@ -1032,7 +1032,7 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
{
cairo_surface_t *snapshot;
cairo_status_t status;
cairo_pattern_union_t pattern;
cairo_surface_pattern_t pattern;
cairo_image_surface_t *image;
void *image_extra;
@ -1050,7 +1050,7 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
return snapshot;
}
_cairo_pattern_init_for_surface (&pattern.surface, &image->base);
_cairo_pattern_init_for_surface (&pattern, &image->base);
status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
&pattern.base,

View File

@ -43,7 +43,7 @@
#define DEFINE_NIL_SURFACE(status, name) \
const cairo_surface_t name = { \
&cairo_image_surface_backend, /* backend */ \
&_cairo_image_surface_backend, /* backend */ \
CAIRO_SURFACE_TYPE_IMAGE, \
CAIRO_CONTENT_COLOR, \
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ \
@ -96,10 +96,11 @@ _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
/**
* _cairo_surface_set_error:
* @surface: a surface
* @status: a status value indicating an error, (eg. not
* CAIRO_STATUS_SUCCESS)
* @status: a status value indicating an error
*
* Atomically sets surface->status to @status and calls _cairo_error;
* Does nothing if status is %CAIRO_STATUS_SUCCESS or any of the internal
* status values.
*
* All assignments of an error status to surface->status should happen
* through _cairo_surface_set_error(). Note that due to the nature of
@ -301,8 +302,7 @@ cairo_surface_create_similar (cairo_surface_t *other,
return _cairo_surface_create_similar_solid (other, content,
width, height,
CAIRO_COLOR_TRANSPARENT,
NULL);
CAIRO_COLOR_TRANSPARENT);
}
slim_hidden_def (cairo_surface_create_similar);
@ -311,34 +311,25 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_content_t content,
int width,
int height,
const cairo_color_t *color,
cairo_pattern_t *pattern)
const cairo_color_t *color)
{
cairo_status_t status;
cairo_surface_t *surface;
cairo_pattern_t *source;
cairo_solid_pattern_t solid_pattern;
surface = _cairo_surface_create_similar_scratch (other, content,
width, height);
if (surface->status)
return surface;
if (pattern == NULL) {
source = _cairo_pattern_create_solid (color, content);
if (source->status) {
cairo_surface_destroy (surface);
return _cairo_surface_create_in_error (source->status);
}
} else
source = pattern;
_cairo_pattern_init_solid (&solid_pattern, color, content);
status = _cairo_surface_paint (surface,
color == CAIRO_COLOR_TRANSPARENT ?
CAIRO_OPERATOR_CLEAR :
CAIRO_OPERATOR_SOURCE, source);
CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
&solid_pattern.base);
if (source != pattern)
cairo_pattern_destroy (source);
_cairo_pattern_fini (&solid_pattern.base);
if (status) {
cairo_surface_destroy (surface);
@ -348,6 +339,43 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other,
return surface;
}
cairo_surface_t *
_cairo_surface_create_solid_pattern_surface (cairo_surface_t *other,
cairo_solid_pattern_t *solid_pattern)
{
cairo_surface_t *surface;
if (other->backend->create_solid_pattern_surface) {
surface = other->backend->create_solid_pattern_surface (other, solid_pattern);
if (surface)
return surface;
}
surface = _cairo_surface_create_similar_solid (other,
solid_pattern->content,
1, 1,
&solid_pattern->color);
return surface;
}
cairo_int_status_t
_cairo_surface_repaint_solid_pattern_surface (cairo_surface_t *other,
cairo_surface_t *solid_surface,
cairo_solid_pattern_t *solid_pattern)
{
if (other->backend->create_solid_pattern_surface)
/* Solid pattern surface for this backend are not trivial to make.
* Skip repainting.
*
* This does not work optimally with things like analysis surface that
* are proxies. But returning UNSUPPORTED is *safe* as it only
* disables some caching.
*/
return CAIRO_INT_STATUS_UNSUPPORTED;
return _cairo_surface_paint (solid_surface, CAIRO_OPERATOR_SOURCE, &solid_pattern->base);
}
cairo_clip_mode_t
_cairo_surface_get_clip_mode (cairo_surface_t *surface)
{
@ -417,7 +445,7 @@ cairo_surface_destroy (cairo_surface_t *surface)
slim_hidden_def(cairo_surface_destroy);
/**
* cairo_surface_reset:
* _cairo_surface_reset:
* @surface: a #cairo_surface_t
*
* Resets the surface back to defaults such that it may be reused in lieu
@ -474,9 +502,10 @@ cairo_surface_get_reference_count (cairo_surface_t *surface)
* external resources. For example, for the Xlib backend it means
* that cairo will no longer access the drawable, which can be freed.
* After calling cairo_surface_finish() the only valid operations on a
* surface are getting and setting user data and referencing and
* destroying it. Further drawing to the surface will not affect the
* surface but will instead trigger a CAIRO_STATUS_SURFACE_FINISHED
* surface are getting and setting user, referencing and
* destroying, and flushing and finishing it.
* Further drawing to the surface will not affect the
* surface but will instead trigger a %CAIRO_STATUS_SURFACE_FINISHED
* error.
*
* When the last call to cairo_surface_destroy() decreases the
@ -495,28 +524,18 @@ cairo_surface_finish (cairo_surface_t *surface)
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
return;
if (surface->finished) {
status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
if (surface->finished)
return;
}
if (surface->backend->finish == NULL) {
surface->finished = TRUE;
return;
}
cairo_surface_flush (surface);
if (!surface->status && surface->backend->flush) {
status = surface->backend->flush (surface);
if (status) {
/* call finish even if in error mode */
if (surface->backend->finish) {
status = surface->backend->finish (surface);
if (status)
status = _cairo_surface_set_error (surface, status);
return;
}
}
status = surface->backend->finish (surface);
if (status)
status = _cairo_surface_set_error (surface, status);
surface->finished = TRUE;
}
slim_hidden_def (cairo_surface_finish);
@ -662,10 +681,8 @@ cairo_surface_flush (cairo_surface_t *surface)
if (surface->status)
return;
if (surface->finished) {
status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
if (surface->finished)
return;
}
if (surface->backend->flush) {
status = surface->backend->flush (surface);
@ -673,6 +690,7 @@ cairo_surface_flush (cairo_surface_t *surface)
status = _cairo_surface_set_error (surface, status);
}
}
slim_hidden_def (cairo_surface_flush);
/**
* cairo_surface_mark_dirty:
@ -763,11 +781,8 @@ slim_hidden_def (cairo_surface_mark_dirty_rectangle);
* different backend space, (differing by the fallback resolution
* scale factors), we need a scale factor correction.
*
* Caution: There is no guarantee that a surface with both a
* device_scale and a device_offset will be treated in consistent
* fashion. So, for now, just don't do that. (And we'll need to
* examine this issue in more detail if we were to ever want to export
* support for device scaling.)
* Caution: Not all places we use device transform correctly handle
* both a translate and a scale. An audit would be nice.
**/
void
_cairo_surface_set_device_scale (cairo_surface_t *surface,
@ -788,9 +803,13 @@ _cairo_surface_set_device_scale (cairo_surface_t *surface,
surface->device_transform.xx = sx;
surface->device_transform.yy = sy;
surface->device_transform.xy = 0.0;
surface->device_transform.yx = 0.0;
surface->device_transform_inverse.xx = 1.0 / sx;
surface->device_transform_inverse.yy = 1.0 / sy;
surface->device_transform_inverse.xy = 0.0;
surface->device_transform_inverse.yx = 0.0;
}
/**
@ -914,6 +933,29 @@ cairo_surface_set_fallback_resolution (cairo_surface_t *surface,
}
slim_hidden_def (cairo_surface_set_fallback_resolution);
/**
* cairo_surface_get_fallback_resolution:
* @surface: a #cairo_surface_t
* @x_pixels_per_inch: horizontal pixels per inch
* @y_pixels_per_inch: vertical pixels per inch
*
* This function returns the previous fallback resolution set by
* cairo_surface_set_fallback_resolution(), or default fallback
* resolution if never set.
*
* Since: 1.8
**/
void
cairo_surface_get_fallback_resolution (cairo_surface_t *surface,
double *x_pixels_per_inch,
double *y_pixels_per_inch)
{
if (x_pixels_per_inch)
*x_pixels_per_inch = surface->x_fallback_resolution;
if (y_pixels_per_inch)
*y_pixels_per_inch = surface->y_fallback_resolution;
}
cairo_bool_t
_cairo_surface_has_device_transform (cairo_surface_t *surface)
{
@ -1142,7 +1184,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
* surface-modifying function on the result of this function.
*
* The caller owns the return value and should call
* cairo_surface_destroy when finished with it. This function will not
* cairo_surface_destroy() when finished with it. This function will not
* return %NULL, but will return a nil surface instead.
*
* Return value: The snapshot surface. Note that the return surface
@ -1774,7 +1816,7 @@ _cairo_surface_get_current_clip_serial (cairo_surface_t *surface)
* this function allocates one from the specified surface. As zero is
* reserved for the special no-clipping case, this function will not
* return that except for an in-error surface, (ie. surface->status !=
* CAIRO_STATUS_SUCCESS).
* %CAIRO_STATUS_SUCCESS).
*/
unsigned int
_cairo_surface_allocate_clip_serial (cairo_surface_t *surface)
@ -2066,47 +2108,80 @@ _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip)
* This behavior would have to be changed is we ever exported a public
* variant of this function.
*/
cairo_status_t
cairo_int_status_t
_cairo_surface_get_extents (cairo_surface_t *surface,
cairo_rectangle_int_t *rectangle)
cairo_rectangle_int_t *extents)
{
cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->status)
return surface->status;
if (surface->finished)
return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
return _cairo_surface_set_error (surface,
surface->backend->get_extents (surface, rectangle));
if (surface->backend->get_extents) {
status = _cairo_surface_set_error (surface,
surface->backend->get_extents (surface, extents));
}
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
extents->x = CAIRO_RECT_INT_MIN;
extents->y = CAIRO_RECT_INT_MIN;
extents->width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
extents->height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
}
return status;
}
cairo_bool_t
_cairo_surface_has_show_text_glyphs (cairo_surface_t *surface)
{
if (surface->backend->has_show_text_glyphs)
return surface->backend->has_show_text_glyphs (surface);
else
return surface->backend->show_text_glyphs != NULL;
}
/* Note: the backends may modify the contents of the glyph array as long as
* they do not return %CAIRO_STATUS_UNSUPPORTED. This makes it possible to
* they do not return %CAIRO_INT_STATUS_UNSUPPORTED. This makes it possible to
* avoid copying the array again and again, and edit it in-place.
* Backends are in fact free to use the array as a generic buffer as they
* see fit.
*
* For show_glyphs backend method, and NOT for show_text_glyphs method,
* when they do return UNSUPPORTED, they may adjust remaining_glyphs to notify
* that they have successfully rendered some of the glyphs (from the beginning
* of the array), but not all. If they don't touch remaining_glyphs, it
* defaults to all glyphs.
*
* See commits 5a9642c5746fd677aed35ce620ce90b1029b1a0c and
* 1781e6018c17909311295a9cc74b70500c6b4d0a for the rationale.
*/
cairo_status_t
_cairo_surface_show_glyphs (cairo_surface_t *surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
_cairo_surface_show_text_glyphs (cairo_surface_t *surface,
cairo_operator_t op,
cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font)
{
cairo_status_t status;
cairo_scaled_font_t *dev_scaled_font = scaled_font;
cairo_pattern_t *dev_source;
cairo_matrix_t font_matrix;
assert (! surface->is_snapshot);
if (surface->status)
return surface->status;
if (!num_glyphs)
if (!num_glyphs && !utf8_len)
return CAIRO_STATUS_SUCCESS;
status = _cairo_surface_copy_pattern_for_destination (source,
@ -2115,24 +2190,20 @@ _cairo_surface_show_glyphs (cairo_surface_t *surface,
if (status)
return _cairo_surface_set_error (surface, status);
cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix);
if (_cairo_surface_has_device_transform (surface) &&
! _cairo_matrix_is_integer_translation (&surface->device_transform, NULL, NULL))
{
cairo_font_options_t *font_options;
cairo_matrix_t dev_ctm;
font_options = cairo_font_options_create ();
cairo_font_options_t font_options;
cairo_matrix_t dev_ctm, font_matrix;
cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix);
cairo_scaled_font_get_ctm (scaled_font, &dev_ctm);
cairo_matrix_multiply (&dev_ctm, &dev_ctm, &surface->device_transform);
cairo_scaled_font_get_font_options (scaled_font, font_options);
cairo_scaled_font_get_font_options (scaled_font, &font_options);
dev_scaled_font = cairo_scaled_font_create (cairo_scaled_font_get_font_face (scaled_font),
&font_matrix,
&dev_ctm,
font_options);
cairo_font_options_destroy (font_options);
&font_options);
}
status = cairo_scaled_font_status (dev_scaled_font);
if (status) {
@ -2144,10 +2215,59 @@ _cairo_surface_show_glyphs (cairo_surface_t *surface,
status = CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->backend->show_glyphs)
status = surface->backend->show_glyphs (surface, op, dev_source,
glyphs, num_glyphs,
dev_scaled_font);
/* The logic here is duplicated in _cairo_analysis_surface show_glyphs and
* show_text_glyphs. Keep in synch. */
if (clusters) {
/* A real show_text_glyphs call. Try show_text_glyphs backend
* method first */
if (surface->backend->show_text_glyphs) {
status = surface->backend->show_text_glyphs (surface, op, dev_source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
backward,
dev_scaled_font);
}
if (status == CAIRO_INT_STATUS_UNSUPPORTED && surface->backend->show_glyphs) {
int remaining_glyphs = num_glyphs;
status = surface->backend->show_glyphs (surface, op, dev_source,
glyphs, num_glyphs,
dev_scaled_font,
&remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0)
status = CAIRO_STATUS_SUCCESS;
}
} else {
/* A mere show_glyphs call. Try show_glyphs backend method first */
if (surface->backend->show_glyphs) {
int remaining_glyphs = num_glyphs;
status = surface->backend->show_glyphs (surface, op, dev_source,
glyphs, num_glyphs,
dev_scaled_font,
&remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0)
status = CAIRO_STATUS_SUCCESS;
} else if (surface->backend->show_text_glyphs) {
/* Intentionally only try show_text_glyphs method for show_glyphs
* calls if backend does not have show_glyphs. If backend has
* both methods implemented, we don't fallback from show_glyphs to
* show_text_glyphs, and hence the backend can assume in its
* show_text_glyphs call that clusters is not NULL (which also
* implies that UTF-8 is not NULL, unless the text is
* zero-length).
*/
status = surface->backend->show_text_glyphs (surface, op, dev_source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
backward,
dev_scaled_font);
}
}
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
status = _cairo_surface_fallback_show_glyphs (surface, op, dev_source,
@ -2165,8 +2285,8 @@ _cairo_surface_show_glyphs (cairo_surface_t *surface,
}
/* XXX: Previously, we had a function named _cairo_surface_show_glyphs
* with not-so-useful semantics. We've now got a new
* _cairo_surface_show_glyphs with the proper semantics, and its
* with not-so-useful semantics. We've now got a
* _cairo_surface_show_text_glyphs with the proper semantics, and its
* fallback still uses this old function (which still needs to be
* cleaned up in terms of both semantics and naming). */
cairo_status_t
@ -2514,6 +2634,11 @@ _cairo_surface_create_in_error (cairo_status_t status)
case CAIRO_STATUS_INVALID_DSC_COMMENT:
case CAIRO_STATUS_INVALID_INDEX:
case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
case CAIRO_STATUS_FONT_TYPE_MISMATCH:
case CAIRO_STATUS_USER_FONT_IMMUTABLE:
case CAIRO_STATUS_USER_FONT_ERROR:
case CAIRO_STATUS_NEGATIVE_COUNT:
case CAIRO_STATUS_INVALID_CLUSTERS:
default:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t *) &_cairo_surface_nil;

View File

@ -384,8 +384,11 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
surface->height,
&cairo_svg_surface_paginated_backend);
status = paginated->status;
if (status == CAIRO_STATUS_SUCCESS)
if (status == CAIRO_STATUS_SUCCESS) {
/* paginated keeps the only reference to surface now, drop ours */
cairo_surface_destroy (&surface->base);
return paginated;
}
/* ignore status as we are on the error path */
CLEANUP:
@ -2139,7 +2142,8 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
cairo_pattern_t *pattern,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs)
{
cairo_svg_surface_t *surface = abstract_surface;
cairo_svg_document_t *document = surface->document;
@ -2173,6 +2177,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
for (i = 0; i < num_glyphs; i++) {
status = _cairo_scaled_font_subsets_map_glyph (document->font_subsets,
scaled_font, glyphs[i].index,
NULL, 0,
&subset_glyph);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
_cairo_output_stream_printf (surface->xml_node, "</g>\n");
@ -2198,7 +2203,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
FALLBACK:
_cairo_path_fixed_init (&path);
_cairo_path_fixed_init (&path);
status = _cairo_scaled_font_glyph_path (scaled_font,(cairo_glyph_t *) glyphs, num_glyphs, &path);

View File

@ -32,7 +32,7 @@
#ifndef CAIRO_SVG_H
#define CAIRO_SVG_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_SVG_SURFACE

View File

@ -557,7 +557,8 @@ _cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
}
cairo_bool_t
_cairo_traps_contain (cairo_traps_t *traps, double x, double y)
_cairo_traps_contain (const cairo_traps_t *traps,
double x, double y)
{
int i;
cairo_point_t point;
@ -574,7 +575,8 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y)
}
void
_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents)
_cairo_traps_extents (const cairo_traps_t *traps,
cairo_box_t *extents)
{
if (traps->num_traps == 0) {
extents->p1.x = extents->p1.y = _cairo_fixed_from_int (0);
@ -598,8 +600,8 @@ _cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents)
* or %CAIRO_STATUS_NO_MEMORY
**/
cairo_int_status_t
_cairo_traps_extract_region (cairo_traps_t *traps,
cairo_region_t *region)
_cairo_traps_extract_region (const cairo_traps_t *traps,
cairo_region_t *region)
{
cairo_box_int_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (cairo_box_int_t)];
cairo_box_int_t *boxes = stack_boxes;
@ -655,3 +657,50 @@ _cairo_traps_extract_region (cairo_traps_t *traps,
return status;
}
/* moves trap points such that they become the actual corners of the trapezoid */
static void
_sanitize_trap (cairo_trapezoid_t *t)
{
cairo_trapezoid_t s = *t;
#define FIX(lr, tb, p) \
if (t->lr.p.y != t->tb) { \
t->lr.p.x = s.lr.p2.x + _cairo_fixed_mul_div (s.lr.p1.x - s.lr.p2.x, s.tb - s.lr.p2.y, s.lr.p1.y - s.lr.p2.y); \
t->lr.p.y = s.tb; \
}
FIX (left, top, p1);
FIX (left, bottom, p2);
FIX (right, top, p1);
FIX (right, bottom, p2);
}
cairo_private cairo_status_t
_cairo_traps_path (const cairo_traps_t *traps,
cairo_path_fixed_t *path)
{
int i;
for (i = 0; i < traps->num_traps; i++) {
cairo_status_t status;
cairo_trapezoid_t trap = traps->traps[i];
if (trap.top == trap.bottom)
continue;
_sanitize_trap (&trap);
status = _cairo_path_fixed_move_to (path, trap.left.p1.x, trap.top);
if (status) return status;
status = _cairo_path_fixed_line_to (path, trap.right.p1.x, trap.top);
if (status) return status;
status = _cairo_path_fixed_line_to (path, trap.right.p2.x, trap.bottom);
if (status) return status;
status = _cairo_path_fixed_line_to (path, trap.left.p2.x, trap.bottom);
if (status) return status;
status = _cairo_path_fixed_close_path (path);
if (status) return status;
}
return CAIRO_STATUS_SUCCESS;
}

View File

@ -1173,25 +1173,27 @@ _cairo_truetype_subset_fini (cairo_truetype_subset_t *subset)
}
static cairo_int_status_t
_cairo_truetype_map_glyphs_to_unicode (cairo_scaled_font_subset_t *font_subset,
unsigned long table_offset)
_cairo_truetype_reverse_cmap (cairo_scaled_font_t *scaled_font,
unsigned long table_offset,
unsigned long index,
uint32_t *ucs4)
{
cairo_status_t status;
const cairo_scaled_font_backend_t *backend;
tt_segment_map_t *map;
char buf[4];
unsigned int num_segments, i, j;
unsigned int num_segments, i;
unsigned long size;
uint16_t *start_code;
uint16_t *end_code;
uint16_t *delta;
uint16_t *range_offset;
uint16_t *glyph_array;
uint16_t g_id, c;
uint16_t c;
backend = font_subset->scaled_font->backend;
backend = scaled_font->backend;
size = 4;
status = backend->load_truetype_table (font_subset->scaled_font,
status = backend->load_truetype_table (scaled_font,
TT_TAG_cmap, table_offset,
(unsigned char *) &buf,
&size);
@ -1208,7 +1210,7 @@ _cairo_truetype_map_glyphs_to_unicode (cairo_scaled_font_subset_t *font_subset,
if (map == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = backend->load_truetype_table (font_subset->scaled_font,
status = backend->load_truetype_table (scaled_font,
TT_TAG_cmap, table_offset,
(unsigned char *) map,
&size);
@ -1222,44 +1224,42 @@ _cairo_truetype_map_glyphs_to_unicode (cairo_scaled_font_subset_t *font_subset,
range_offset = &(delta[num_segments]);
glyph_array = &(range_offset[num_segments]);
i = 0;
while (i < font_subset->num_glyphs) {
g_id = (uint16_t) font_subset->glyphs[i];
/* search for glyph in segments
* with rangeOffset=0 */
for (j = 0; j < num_segments; j++) {
c = g_id - be16_to_cpu (delta[j]);
if (range_offset[j] == 0 &&
c >= be16_to_cpu (start_code[j]) &&
c <= be16_to_cpu (end_code[j]))
{
font_subset->to_unicode[i] = c;
goto next_glyph;
}
}
/* search for glyph in segments with rangeOffset=1 */
for (j = 0; j < num_segments; j++) {
if (range_offset[j] != 0) {
uint16_t *glyph_ids = &range_offset[j] + be16_to_cpu (range_offset[j])/2;
int range_size = be16_to_cpu (end_code[j]) - be16_to_cpu (start_code[j]) + 1;
uint16_t g_id_be = cpu_to_be16 (g_id);
int k;
for (k = 0; k < range_size; k++) {
if (glyph_ids[k] == g_id_be) {
font_subset->to_unicode[i] = be16_to_cpu (start_code[j]) + k;
goto next_glyph;
}
}
}
}
next_glyph:
i++;
/* search for glyph in segments
* with rangeOffset=0 */
for (i = 0; i < num_segments; i++) {
c = index - be16_to_cpu (delta[i]);
if (range_offset[i] == 0 &&
c >= be16_to_cpu (start_code[i]) &&
c <= be16_to_cpu (end_code[i]))
{
*ucs4 = c;
goto found;
}
}
/* search for glyph in segments with rangeOffset=1 */
for (i = 0; i < num_segments; i++) {
if (range_offset[i] != 0) {
uint16_t *glyph_ids = &range_offset[i] + be16_to_cpu (range_offset[i])/2;
int range_size = be16_to_cpu (end_code[i]) - be16_to_cpu (start_code[i]) + 1;
uint16_t g_id_be = cpu_to_be16 (index);
int j;
for (j = 0; j < range_size; j++) {
if (glyph_ids[j] == g_id_be) {
*ucs4 = be16_to_cpu (start_code[i]) + j;
goto found;
}
}
}
}
/* glyph not found */
*ucs4 = -1;
found:
status = CAIRO_STATUS_SUCCESS;
fail:
free (map);
@ -1267,7 +1267,9 @@ fail:
}
cairo_int_status_t
_cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t *font_subset)
_cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font,
unsigned long index,
uint32_t *ucs4)
{
cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
const cairo_scaled_font_backend_t *backend;
@ -1276,12 +1278,12 @@ _cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t *font_su
int num_tables, i;
unsigned long size;
backend = font_subset->scaled_font->backend;
backend = scaled_font->backend;
if (!backend->load_truetype_table)
return CAIRO_INT_STATUS_UNSUPPORTED;
size = 4;
status = backend->load_truetype_table (font_subset->scaled_font,
status = backend->load_truetype_table (scaled_font,
TT_TAG_cmap, 0,
(unsigned char *) &buf,
&size);
@ -1295,7 +1297,7 @@ _cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t *font_su
if (cmap == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = backend->load_truetype_table (font_subset->scaled_font,
status = backend->load_truetype_table (scaled_font,
TT_TAG_cmap, 0,
(unsigned char *) cmap,
&size);
@ -1306,10 +1308,12 @@ _cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t *font_su
for (i = 0; i < num_tables; i++) {
if (be16_to_cpu (cmap->index[i].platform) == 3 &&
be16_to_cpu (cmap->index[i].encoding) == 1) {
status = _cairo_truetype_map_glyphs_to_unicode (font_subset,
be32_to_cpu (cmap->index[i].offset));
status = _cairo_truetype_reverse_cmap (scaled_font,
be32_to_cpu (cmap->index[i].offset),
index,
ucs4);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto cleanup;
break;
}
}

View File

@ -276,6 +276,47 @@ cairo_type1_font_subset_find_segments (cairo_type1_font_subset_t *font)
return CAIRO_STATUS_SUCCESS;
}
/* Search for the definition of key and erase it by overwriting with spaces.
* This function is looks for definitions of the form:
*
* /key1 1234 def
* /key2 [12 34 56] def
*
* ie a key defined as an integer or array of integers.
*
*/
static void
cairo_type1_font_erase_dict_key (cairo_type1_font_subset_t *font,
const char *key)
{
const char *start, *p, *segment_end;
segment_end = font->header_segment + font->header_segment_size;
start = font->header_segment;
do {
start = find_token (start, segment_end, key);
if (start) {
p = start + strlen(key);
/* skip integers or array of integers */
while (p < segment_end &&
(isspace(*p) ||
isdigit(*p) ||
*p == '[' ||
*p == ']'))
{
p++;
}
if (p + 3 < segment_end && memcmp(p, "def", 3) == 0) {
/* erase definition of the key */
memset((char *) start, ' ', p + 3 - start);
}
start += strlen(key);
}
} while (start);
}
static cairo_status_t
cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font,
const char *name)
@ -283,14 +324,57 @@ cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font,
const char *start, *end, *segment_end;
unsigned int i;
/* FIXME:
* This function assumes that /FontName always appears
* before /Encoding. This appears to always be the case with Type1
* fonts.
*
* The more recently added code for removing the UniqueID and XUID
* keys can not make any assumptions about the position of the
* keys in the dictionary so it is implemented by overwriting the
* key definition with spaces before we start copying the font to
* the output.
*
* This code should be rewritten to not make any assumptions about
* the order of dictionary keys. This will allow UniqueID to be
* stripped out instead of leaving a bunch of spaces in the
* output.
*/
cairo_type1_font_erase_dict_key (font, "/UniqueID");
cairo_type1_font_erase_dict_key (font, "/XUID");
segment_end = font->header_segment + font->header_segment_size;
start = find_token (font->header_segment, segment_end, "/FontName");
/* Type 1 fonts created by Fontforge have some PostScript code at
* the start of the font that skips the font if the printer has a
* cached copy of the font with the same unique id. This breaks
* our subsetted font so we disable it by searching for the
* PostScript operator "known" when used to check for the
* "/UniqueID" dictionary key. We append " pop false " after it to
* pop the result of this check off the stack and replace it with
* "false" to make the PostScript code think "/UniqueID" does not
* exist.
*/
end = font->header_segment;
start = find_token (font->header_segment, segment_end, "/UniqueID");
if (start) {
start += 9;
while (start < segment_end && isspace (*start))
start++;
if (start + 5 < segment_end && memcmp(start, "known", 5) == 0) {
_cairo_output_stream_write (font->output, font->header_segment,
start + 5 - font->header_segment);
_cairo_output_stream_printf (font->output, " pop false ");
end = start + 5;
}
}
start = find_token (end, segment_end, "/FontName");
if (start == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
_cairo_output_stream_write (font->output, font->header_segment,
start - font->header_segment);
_cairo_output_stream_write (font->output, end,
start - end);
_cairo_output_stream_printf (font->output, "/FontName /%s def", name);
@ -382,6 +466,7 @@ cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font)
unsigned char *in, *end;
char *out;
int c, p;
int i;
in = (unsigned char *) font->eexec_segment;
end = (unsigned char *) in + font->eexec_segment_size;
@ -407,6 +492,23 @@ cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font)
}
font->cleartext_end = out;
/* Overwrite random bytes with spaces.
*
* The first 4 bytes of the cleartext are the random bytes
* required by the encryption algorithm. When encrypting the
* cleartext, the first ciphertext byte must not be a white space
* character and the first 4 bytes must not be an ASCII Hex
* character. Some fonts do not check that their randomly chosen
* bytes results in ciphertext that complies with this
* restriction. This may cause problems for some PDF consumers. By
* replacing the random bytes with spaces, the first four bytes of
* ciphertext will always be 0xf9, 0x83, 0xef, 0x00 which complies
* with this restriction. Using spaces also means we don't have to
* skip over the random bytes when parsing the cleartext.
*/
for (i = 0; i < 4 && i < font->eexec_segment_size; i++)
font->cleartext[i] = ' ';
return CAIRO_STATUS_SUCCESS;
}

View File

@ -0,0 +1,74 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 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.
*
* 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 Adrian Johnson.
*
* Contributor(s):
* Adrian Johnson <ajohnson@redneon.com>
*/
#ifndef CAIRO_TYPE3_GLYPH_SURFACE_PRIVATE_H
#define CAIRO_TYPE3_GLYPH_SURFACE_PRIVATE_H
#include "cairo-surface-private.h"
#include "cairo-pdf-operators-private.h"
typedef cairo_status_t (*cairo_type3_glyph_surface_emit_image_t) (cairo_image_surface_t *image,
cairo_output_stream_t *stream);
typedef struct cairo_type3_glyph_surface {
cairo_surface_t base;
cairo_scaled_font_t *scaled_font;
cairo_output_stream_t *stream;
cairo_pdf_operators_t pdf_operators;
cairo_matrix_t cairo_to_pdf;
cairo_type3_glyph_surface_emit_image_t emit_image;
} cairo_type3_glyph_surface_t;
cairo_private cairo_surface_t *
_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
cairo_output_stream_t *stream,
cairo_type3_glyph_surface_emit_image_t emit_image);
cairo_private cairo_status_t
_cairo_type3_glyph_surface_emit_notdef_glyph (void *abstract_surface,
cairo_output_stream_t *stream,
cairo_box_t *bbox,
double *width);
cairo_private cairo_status_t
_cairo_type3_glyph_surface_emit_glyph (void *abstract_surface,
cairo_output_stream_t *stream,
unsigned long glyph_index,
cairo_box_t *bbox,
double *width);
#endif /* CAIRO_TYPE3_GLYPH_SURFACE_PRIVATE_H */

View File

@ -0,0 +1,445 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 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.
*
* 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 Adrian Johnson.
*
* Contributor(s):
* Adrian Johnson <ajohnson@redneon.com>
*/
#include "cairoint.h"
#include "cairo-type3-glyph-surface-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-meta-surface-private.h"
static const cairo_surface_backend_t cairo_type3_glyph_surface_backend;
cairo_surface_t *
_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
cairo_output_stream_t *stream,
cairo_type3_glyph_surface_emit_image_t emit_image)
{
cairo_type3_glyph_surface_t *surface;
cairo_matrix_t invert_y_axis;
surface = malloc (sizeof (cairo_type3_glyph_surface_t));
if (surface == NULL)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&surface->base, &cairo_type3_glyph_surface_backend,
CAIRO_CONTENT_COLOR_ALPHA);
surface->scaled_font = scaled_font;
surface->stream = stream;
surface->emit_image = emit_image;
/* Setup the transform from the user-font device space to Type 3
* font space. The Type 3 font space is defined by the FontMatrix
* entry in the Type 3 dictionary. In the PDF backend this is an
* identity matrix. */
surface->cairo_to_pdf = scaled_font->scale_inverse;
cairo_matrix_init_scale (&invert_y_axis, 1, -1);
cairo_matrix_multiply (&surface->cairo_to_pdf, &surface->cairo_to_pdf, &invert_y_axis);
_cairo_pdf_operators_init (&surface->pdf_operators,
surface->stream,
&surface->cairo_to_pdf,
NULL);
return &surface->base;
}
static cairo_status_t
_cairo_type3_glyph_surface_emit_image (cairo_type3_glyph_surface_t *surface,
cairo_image_surface_t *image,
cairo_matrix_t *image_matrix)
{
cairo_status_t status;
cairo_image_surface_t *image_mask;
/* The only image type supported by Type 3 fonts are 1-bit image
* masks */
if (image->format == CAIRO_FORMAT_A1) {
image_mask = image;
} else {
image_mask = _cairo_image_surface_clone (image, CAIRO_FORMAT_A1);
status = cairo_surface_status (&image->base);
if (status)
return status;
}
_cairo_output_stream_printf (surface->stream,
"q %f %f %f %f %f %f cm\n",
image_matrix->xx,
image_matrix->xy,
image_matrix->yx,
image_matrix->yy,
image_matrix->x0,
image_matrix->y0);
status = surface->emit_image (image_mask, surface->stream);
_cairo_output_stream_printf (surface->stream,
"Q\n");
if (image_mask != image)
cairo_surface_destroy (&image_mask->base);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_type3_glyph_surface_emit_image_pattern (cairo_type3_glyph_surface_t *surface,
cairo_image_surface_t *image,
cairo_matrix_t *pattern_matrix)
{
cairo_matrix_t mat, upside_down;
cairo_status_t status;
if (image->width == 0 || image->height == 0)
return CAIRO_STATUS_SUCCESS;
mat = *pattern_matrix;
/* Get the pattern space to user space matrix */
status = cairo_matrix_invert (&mat);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
/* Make this a pattern space to Type 3 font space matrix */
cairo_matrix_multiply (&mat, &mat, &surface->cairo_to_pdf);
/* PDF images are in a 1 unit by 1 unit image space. Turn the 1 by
* 1 image upside down to convert to flip the Y-axis going from
* cairo to PDF. Then scale the image up to the required size. */
cairo_matrix_scale (&mat, image->width, image->height);
cairo_matrix_init (&upside_down, 1, 0, 0, -1, 0, 1);
cairo_matrix_multiply (&mat, &upside_down, &mat);
return _cairo_type3_glyph_surface_emit_image (surface, image, &mat);
}
static cairo_status_t
_cairo_type3_glyph_surface_finish (void *abstract_surface)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
return _cairo_pdf_operators_fini (&surface->pdf_operators);
}
static cairo_int_status_t
_cairo_type3_glyph_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_type3_glyph_surface_t *surface = abstract_surface;
if (path == NULL) {
_cairo_output_stream_printf (surface->stream, "Q q\n");
return CAIRO_STATUS_SUCCESS;
}
return _cairo_pdf_operators_clip (&surface->pdf_operators,
path,
fill_rule);
}
static cairo_int_status_t
_cairo_type3_glyph_surface_paint (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
cairo_surface_pattern_t *pattern;
cairo_image_surface_t *image;
void *image_extra;
cairo_status_t status;
if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
pattern = (cairo_surface_pattern_t *) source;
status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
if (status)
goto fail;
status = _cairo_type3_glyph_surface_emit_image_pattern (surface,
image,
&pattern->base.matrix);
fail:
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
return status;
}
static cairo_int_status_t
_cairo_type3_glyph_surface_mask (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_pattern_t *mask)
{
return _cairo_type3_glyph_surface_paint (abstract_surface, op, mask);
}
static cairo_int_status_t
_cairo_type3_glyph_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_type3_glyph_surface_t *surface = abstract_surface;
return _cairo_pdf_operators_stroke (&surface->pdf_operators,
path,
style,
ctm,
ctm_inverse);
}
static cairo_int_status_t
_cairo_type3_glyph_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_type3_glyph_surface_t *surface = abstract_surface;
cairo_int_status_t status;
status = _cairo_pdf_operators_fill (&surface->pdf_operators,
path,
fill_rule);
return status;
}
static cairo_int_status_t
_cairo_type3_glyph_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,
int *remaining_glyphs)
{
/* XXX: Some refactoring is required before we can add font
* subsets in the middle of emitting all the subsets. */
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
}
static const cairo_surface_backend_t cairo_type3_glyph_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_TYPE3_GLYPH,
NULL, /* _cairo_type3_glyph_surface_create_similar */
_cairo_type3_glyph_surface_finish,
NULL, /* acquire_source_image */
NULL, /* release_source_image */
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* cairo_type3_glyph_surface_copy_page */
NULL, /* _cairo_type3_glyph_surface_show_page */
NULL, /* set_clip_region */
_cairo_type3_glyph_surface_intersect_clip_path,
NULL, /* _cairo_type3_glyph_surface_get_extents */
NULL, /* old_show_glyphs */
NULL, /* _cairo_type3_glyph_surface_get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
_cairo_type3_glyph_surface_paint,
_cairo_type3_glyph_surface_mask,
_cairo_type3_glyph_surface_stroke,
_cairo_type3_glyph_surface_fill,
_cairo_type3_glyph_surface_show_glyphs,
NULL, /* snapshot */
};
static void
_cairo_type3_glyph_surface_set_stream (cairo_type3_glyph_surface_t *surface,
cairo_output_stream_t *stream)
{
surface->stream = stream;
_cairo_pdf_operators_set_stream (&surface->pdf_operators, stream);
}
static cairo_status_t
_cairo_type3_glyph_surface_emit_fallback_image (cairo_type3_glyph_surface_t *surface,
unsigned long glyph_index)
{
cairo_scaled_glyph_t *scaled_glyph;
cairo_status_t status;
cairo_image_surface_t *image;
cairo_matrix_t mat;
double width, height, x, y;
status = _cairo_scaled_glyph_lookup (surface->scaled_font,
glyph_index,
CAIRO_SCALED_GLYPH_INFO_METRICS |
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
if (status)
return status;
image = scaled_glyph->surface;
if (image->width == 0 || image->height == 0)
return CAIRO_STATUS_SUCCESS;
x = _cairo_fixed_to_double (scaled_glyph->bbox.p1.x);
y = _cairo_fixed_to_double (scaled_glyph->bbox.p2.y);
width = _cairo_fixed_to_double (scaled_glyph->bbox.p2.x) -
_cairo_fixed_to_double (scaled_glyph->bbox.p1.x);
height = _cairo_fixed_to_double (scaled_glyph->bbox.p2.y) -
_cairo_fixed_to_double (scaled_glyph->bbox.p1.y);
mat.xx = width;
mat.xy = 0;
mat.yx = 0;
mat.yy = height;
mat.x0 = x;
mat.y0 = y;
cairo_matrix_multiply (&mat, &mat, &surface->scaled_font->scale_inverse);
mat.y0 *= -1;
return _cairo_type3_glyph_surface_emit_image (surface, image, &mat);
}
cairo_status_t
_cairo_type3_glyph_surface_emit_notdef_glyph (void *abstract_surface,
cairo_output_stream_t *stream,
cairo_box_t *bbox,
double *width)
{
bbox->p1.x = 0;
bbox->p1.y = 0;
bbox->p2.x = 0;
bbox->p2.y = 0;
*width = 0.0;
_cairo_output_stream_printf (stream, "0 0 0 0 0 0 d1\n");
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_type3_glyph_surface_emit_glyph (void *abstract_surface,
cairo_output_stream_t *stream,
unsigned long glyph_index,
cairo_box_t *bbox,
double *width)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
cairo_scaled_glyph_t *scaled_glyph;
cairo_status_t status, status2;
double x_advance, y_advance;
cairo_output_stream_t *mem_stream;
cairo_matrix_t font_matrix_inverse;
_cairo_type3_glyph_surface_set_stream (surface, stream);
status = _cairo_scaled_glyph_lookup (surface->scaled_font,
glyph_index,
CAIRO_SCALED_GLYPH_INFO_METRICS |
CAIRO_SCALED_GLYPH_INFO_META_SURFACE,
&scaled_glyph);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
status = _cairo_scaled_glyph_lookup (surface->scaled_font,
glyph_index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
if (status)
return status;
status = CAIRO_INT_STATUS_IMAGE_FALLBACK;
}
x_advance = scaled_glyph->metrics.x_advance;
y_advance = scaled_glyph->metrics.y_advance;
font_matrix_inverse = surface->scaled_font->font_matrix;
status2 = cairo_matrix_invert (&font_matrix_inverse);
/* The invertability of font_matrix is tested in
* pdf_operators_show_glyphs before any glyphs are mappped to the
* subset. */
assert (status2 == CAIRO_STATUS_SUCCESS);
cairo_matrix_transform_distance (&font_matrix_inverse, &x_advance, &y_advance);
*width = x_advance;
*bbox = scaled_glyph->bbox;
_cairo_matrix_transform_bounding_box_fixed (&surface->scaled_font->scale_inverse,
bbox, NULL);
_cairo_output_stream_printf (surface->stream,
"%f 0 %f %f %f %f d1\n",
x_advance,
_cairo_fixed_to_double (bbox->p1.x),
- _cairo_fixed_to_double (bbox->p2.y),
_cairo_fixed_to_double (bbox->p2.x),
- _cairo_fixed_to_double (bbox->p1.y));
if (status == CAIRO_STATUS_SUCCESS) {
mem_stream = _cairo_memory_stream_create ();
_cairo_type3_glyph_surface_set_stream (surface, mem_stream);
_cairo_output_stream_printf (surface->stream, "q\n");
status = _cairo_meta_surface_replay (scaled_glyph->meta_surface,
&surface->base);
_cairo_output_stream_printf (surface->stream, "Q\n");
_cairo_type3_glyph_surface_set_stream (surface, stream);
if (status == CAIRO_STATUS_SUCCESS)
_cairo_memory_stream_copy (mem_stream, stream);
status2 = _cairo_output_stream_destroy (mem_stream);
if (status2)
return status2;
}
if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
status = _cairo_type3_glyph_surface_emit_fallback_image (surface, glyph_index);
return status;
}

View File

@ -130,16 +130,19 @@ typedef enum _cairo_paginated_mode {
} cairo_paginated_mode_t;
/* Sure wish C had a real enum type so that this would be distinct
from cairo_status_t. Oh well, without that, I'll use this bogus 1000
offset */
* from #cairo_status_t. Oh well, without that, I'll use this bogus 100
* offset. We want to keep it fit in int8_t as the compiler may choose
* that for #cairo_status_t */
typedef enum _cairo_int_status {
CAIRO_INT_STATUS_DEGENERATE = 1000,
CAIRO_INT_STATUS_UNSUPPORTED,
CAIRO_INT_STATUS_UNSUPPORTED = 100,
CAIRO_INT_STATUS_DEGENERATE,
CAIRO_INT_STATUS_NOTHING_TO_DO,
CAIRO_INT_STATUS_CACHE_EMPTY,
CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY,
CAIRO_INT_STATUS_IMAGE_FALLBACK,
CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN
CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN,
CAIRO_INT_STATUS_LAST_STATUS
} cairo_int_status_t;
typedef enum _cairo_internal_surface_type {
@ -148,7 +151,9 @@ typedef enum _cairo_internal_surface_type {
CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED
CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TYPE3_GLYPH
} cairo_internal_surface_type_t;
typedef struct _cairo_region cairo_region_t;
@ -207,13 +212,13 @@ struct _cairo_point_int32 {
#if CAIRO_FIXED_BITS == 32 && CAIRO_FIXED_FRAC_BITS >= 16
typedef struct _cairo_rectangle_int16 cairo_rectangle_int_t;
typedef struct _cairo_point_int16 cairo_point_int_t;
#define CAIRO_RECT_INT_MIN INT16_MIN
#define CAIRO_RECT_INT_MAX INT16_MAX
#define CAIRO_RECT_INT_MIN (INT16_MIN >> (CAIRO_FIXED_FRAC_BITS - 16))
#define CAIRO_RECT_INT_MAX (INT16_MAX >> (CAIRO_FIXED_FRAC_BITS - 16))
#elif CAIRO_FIXED_BITS == 32
typedef struct _cairo_rectangle_int32 cairo_rectangle_int_t;
typedef struct _cairo_point_int32 cairo_point_int_t;
#define CAIRO_RECT_INT_MIN INT32_MIN
#define CAIRO_RECT_INT_MAX INT32_MAX
#define CAIRO_RECT_INT_MIN (INT32_MIN >> CAIRO_FIXED_FRAC_BITS)
#define CAIRO_RECT_INT_MAX (INT32_MAX >> CAIRO_FIXED_FRAC_BITS)
#else
#error Not sure how to pick a cairo_rectangle_int_t and cairo_point_int_t for your CAIRO_FIXED_BITS!
#endif
@ -253,7 +258,7 @@ typedef struct _cairo_polygon {
int num_edges;
int edges_size;
cairo_edge_t *edges;
cairo_edge_t edges_embedded[8];
cairo_edge_t edges_embedded[32];
} cairo_polygon_t;
typedef struct _cairo_spline_knots {
@ -268,7 +273,7 @@ typedef struct _cairo_spline {
int num_points;
int points_size;
cairo_point_t *points;
cairo_point_t points_embedded[8];
cairo_point_t points_embedded[64];
} cairo_spline_t;
typedef struct _cairo_pen_vertex {
@ -282,8 +287,9 @@ typedef struct _cairo_pen {
double radius;
double tolerance;
cairo_pen_vertex_t *vertices;
int num_vertices;
cairo_pen_vertex_t *vertices;
cairo_pen_vertex_t vertices_embedded[32];
} cairo_pen_t;
typedef struct _cairo_color cairo_color_t;

View File

@ -1,4 +1,5 @@
/* cairo_unicode.c: Unicode conversion routines
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* The code in this file is derived from GLib's gutf8.c and
* ultimately from libunicode. It is relicensed under the
@ -201,7 +202,7 @@ _utf8_get_char_extended (const unsigned char *p,
* If @len is supplied and the string has an embedded nul
* byte, only the portion before the nul byte is converted.
* @result: location to store a pointer to a newly allocated UTF-32
* string (always native endian). Free with free(). A 0
* string (always native endian), or %NULL. Free with free(). A 0
* word will be written after the last character.
* @items_written: location to store number of 32-bit words
* written. (Not including the trailing 0)
@ -215,20 +216,21 @@ _utf8_get_char_extended (const unsigned char *p,
* an invalid sequence was found.
**/
cairo_status_t
_cairo_utf8_to_ucs4 (const unsigned char *str,
int len,
uint32_t **result,
int *items_written)
_cairo_utf8_to_ucs4 (const char *str,
int len,
uint32_t **result,
int *items_written)
{
uint32_t *str32 = NULL;
int n_chars, i;
const unsigned char *in;
const unsigned char * const ustr = (const unsigned char *) str;
in = str;
in = ustr;
n_chars = 0;
while ((len < 0 || str + len - in > 0) && *in)
while ((len < 0 || ustr + len - in > 0) && *in)
{
uint32_t wc = _utf8_get_char_extended (in, str + len - in);
uint32_t wc = _utf8_get_char_extended (in, ustr + len - in);
if (wc & 0x80000000 || !UNICODE_VALID (wc))
return _cairo_error (CAIRO_STATUS_INVALID_STRING);
@ -239,24 +241,66 @@ _cairo_utf8_to_ucs4 (const unsigned char *str,
in = UTF8_NEXT_CHAR (in);
}
str32 = _cairo_malloc_ab (n_chars + 1, sizeof (uint32_t));
if (!str32)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (result) {
str32 = _cairo_malloc_ab (n_chars + 1, sizeof (uint32_t));
if (!str32)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
in = str;
for (i=0; i < n_chars; i++) {
str32[i] = _utf8_get_char (in);
in = UTF8_NEXT_CHAR (in);
in = ustr;
for (i=0; i < n_chars; i++) {
str32[i] = _utf8_get_char (in);
in = UTF8_NEXT_CHAR (in);
}
str32[i] = 0;
*result = str32;
}
str32[i] = 0;
*result = str32;
if (items_written)
*items_written = n_chars;
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_ucs4_to_utf8:
* @unicode: a UCS-4 character
* @utf8: buffer to write utf8 string into. Must have at least 4 bytes
* space available.
*
* Return value: Number of bytes in the utf8 string or 0 if an invalid
* unicode character
**/
int
_cairo_ucs4_to_utf8 (uint32_t unicode,
char *utf8)
{
int bytes;
char *p;
if (unicode < 0x80) {
*utf8 = unicode;
return 1;
} else if (unicode < 0x800) {
bytes = 2;
} else if (unicode < 0x10000) {
bytes = 3;
} else if (unicode < 0x200000) {
bytes = 4;
} else {
return 0;
}
p = utf8 + bytes;
while (p > utf8) {
*--p = 0x80 | (unicode & 0x3f);
unicode >>= 6;
}
*p |= 0xf0 << (4 - bytes);
return bytes;
}
#if CAIRO_HAS_UTF8_TO_UTF16
/**
* _cairo_utf8_to_utf16:
@ -280,19 +324,20 @@ _cairo_utf8_to_ucs4 (const unsigned char *str,
* an invalid sequence was found.
**/
cairo_status_t
_cairo_utf8_to_utf16 (const unsigned char *str,
int len,
uint16_t **result,
int *items_written)
_cairo_utf8_to_utf16 (const char *str,
int len,
uint16_t **result,
int *items_written)
{
uint16_t *str16 = NULL;
int n16, i;
const unsigned char *in;
const unsigned char * const ustr = (const unsigned char *) str;
in = str;
in = ustr;
n16 = 0;
while ((len < 0 || str + len - in > 0) && *in) {
uint32_t wc = _utf8_get_char_extended (in, str + len - in);
while ((len < 0 || ustr + len - in > 0) && *in) {
uint32_t wc = _utf8_get_char_extended (in, ustr + len - in);
if (wc & 0x80000000 || !UNICODE_VALID (wc))
return _cairo_error (CAIRO_STATUS_INVALID_STRING);
@ -311,7 +356,7 @@ _cairo_utf8_to_utf16 (const unsigned char *str,
if (!str16)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
in = str;
in = ustr;
for (i = 0; i < n16;) {
uint32_t wc = _utf8_get_char (in);

View File

@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2006, 2008 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
@ -30,41 +30,16 @@
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Kristian Høgsberg <krh@redhat.com>
* Behdad Esfahbod <behdad@behdad.org>
*/
#ifndef CAIRO_DEBUG_H
#define CAIRO_DEBUG_H
#ifndef CAIRO_USER_FONT_PRIVATE_H
#define CAIRO_USER_FONT_PRIVATE_H
#include <cairo-features.h>
#include <stdio.h>
#include "cairo.h"
CAIRO_BEGIN_DECLS
cairo_private cairo_bool_t
_cairo_font_face_is_user (cairo_font_face_t *font_face);
struct _cairo_path_fixed;
struct _cairo_traps;
struct _cairo_trapezoid;
struct _cairo_clip;
cairo_public void
cairo_debug_reset_static_data (void);
cairo_public void
cairo_debug_dump_clip (struct _cairo_clip *clip,
FILE *fp);
cairo_public void
cairo_debug_dump_path (struct _cairo_path_fixed *path,
FILE *fp);
cairo_public void
cairo_debug_dump_traps (struct _cairo_traps *traps,
FILE *fp);
cairo_public void
cairo_debug_dump_trapezoid_array (struct _cairo_trapezoid *traps,
int num_traps,
FILE *fp);
CAIRO_END_DECLS
#endif /* CAIRO_H */
#endif /* CAIRO_USER_FONT_PRIVATE_H */

View File

@ -0,0 +1,688 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006, 2008 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 Red Hat, Inc.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Behdad Esfahbod <behdad@behdad.org>
*/
#include "cairoint.h"
#include "cairo-user-font-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-analysis-surface-private.h"
typedef struct _cairo_user_scaled_font_methods {
cairo_user_scaled_font_init_func_t init;
cairo_user_scaled_font_render_glyph_func_t render_glyph;
cairo_user_scaled_font_unicode_to_glyph_func_t unicode_to_glyph;
cairo_user_scaled_font_text_to_glyphs_func_t text_to_glyphs;
} cairo_user_scaled_font_methods_t;
typedef struct _cairo_user_font_face {
cairo_font_face_t base;
/* Set to true after first scaled font is created. At that point,
* the scaled_font_methods cannot change anymore. */
cairo_bool_t immutable;
cairo_user_scaled_font_methods_t scaled_font_methods;
} cairo_user_font_face_t;
typedef struct _cairo_user_scaled_font {
cairo_scaled_font_t base;
cairo_text_extents_t default_glyph_extents;
/* space to compute extents in, and factors to convert back to user space */
cairo_matrix_t extent_scale;
double extent_x_scale;
double extent_y_scale;
/* multiplier for metrics hinting */
double snap_x_scale;
double snap_y_scale;
} cairo_user_scaled_font_t;
/* #cairo_user_scaled_font_t */
static const cairo_scaled_font_backend_t cairo_user_scaled_font_backend;
static cairo_int_status_t
_cairo_user_scaled_glyph_init (void *abstract_font,
cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_glyph_info_t info)
{
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_user_scaled_font_t *scaled_font = abstract_font;
cairo_surface_t *meta_surface = scaled_glyph->meta_surface;
if (!scaled_glyph->meta_surface) {
cairo_user_font_face_t *face =
(cairo_user_font_face_t *) scaled_font->base.font_face;
cairo_text_extents_t extents = scaled_font->default_glyph_extents;
cairo_content_t content = scaled_font->base.options.antialias == CAIRO_ANTIALIAS_SUBPIXEL ?
CAIRO_CONTENT_COLOR_ALPHA :
CAIRO_CONTENT_ALPHA;
cairo_t *cr;
meta_surface = _cairo_meta_surface_create (content, -1, -1);
cr = cairo_create (meta_surface);
cairo_set_matrix (cr, &scaled_font->base.scale);
cairo_set_font_size (cr, 1.0);
cairo_set_font_options (cr, &scaled_font->base.options);
if (face->scaled_font_methods.render_glyph)
status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font,
_cairo_scaled_glyph_index(scaled_glyph),
cr, &extents);
else
status = CAIRO_STATUS_USER_FONT_ERROR;
if (status == CAIRO_STATUS_SUCCESS)
status = cairo_status (cr);
cairo_destroy (cr);
if (status) {
cairo_surface_destroy (meta_surface);
return status;
}
_cairo_scaled_glyph_set_meta_surface (scaled_glyph,
&scaled_font->base,
meta_surface);
/* set metrics */
if (extents.width == 0.) {
/* Compute extents.x/y/width/height from meta_surface, in font space */
cairo_box_t bbox;
double x1, y1, x2, y2;
double x_scale, y_scale;
cairo_surface_t *null_surface = _cairo_null_surface_create (cairo_surface_get_content (meta_surface));
cairo_surface_t *analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1);
cairo_surface_destroy (null_surface);
_cairo_analysis_surface_set_ctm (analysis_surface, &scaled_font->extent_scale);
status = _cairo_meta_surface_replay (meta_surface, analysis_surface);
_cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox);
cairo_surface_destroy (analysis_surface);
_cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2);
x_scale = scaled_font->extent_x_scale;
y_scale = scaled_font->extent_y_scale;
extents.x_bearing = x1 * x_scale;
extents.y_bearing = y1 * y_scale;
extents.width = (x2 - x1) * x_scale;
extents.height = (y2 - y1) * y_scale;
}
if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) {
extents.x_advance = _cairo_lround (extents.x_advance / scaled_font->snap_x_scale) * scaled_font->snap_x_scale;
extents.y_advance = _cairo_lround (extents.y_advance / scaled_font->snap_y_scale) * scaled_font->snap_y_scale;
}
_cairo_scaled_glyph_set_metrics (scaled_glyph,
&scaled_font->base,
&extents);
}
if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) {
cairo_surface_t *surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_format_t format;
int width, height;
/* TODO
* extend the glyph cache to support argb glyphs.
* need to figure out the semantics and interaction with subpixel
* rendering first.
*/
width = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x) -
_cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
height = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y) -
_cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
switch (scaled_font->base.options.antialias) {
default:
case CAIRO_ANTIALIAS_DEFAULT:
case CAIRO_ANTIALIAS_GRAY: format = CAIRO_FORMAT_A8; break;
case CAIRO_ANTIALIAS_NONE: format = CAIRO_FORMAT_A1; break;
case CAIRO_ANTIALIAS_SUBPIXEL: format = CAIRO_FORMAT_ARGB32; break;
}
surface = cairo_image_surface_create (format, width, height);
cairo_surface_set_device_offset (surface,
- _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x),
- _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y));
status = _cairo_meta_surface_replay (meta_surface, surface);
if (status) {
cairo_surface_destroy(surface);
return status;
}
_cairo_scaled_glyph_set_surface (scaled_glyph,
&scaled_font->base,
(cairo_image_surface_t *) surface);
}
if (info & CAIRO_SCALED_GLYPH_INFO_PATH) {
cairo_path_fixed_t *path = _cairo_path_fixed_create ();
if (!path)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_meta_surface_get_path (meta_surface, path);
if (status) {
_cairo_path_fixed_destroy (path);
return status;
}
_cairo_scaled_glyph_set_path (scaled_glyph,
&scaled_font->base,
path);
}
return status;
}
static unsigned long
_cairo_user_ucs4_to_index (void *abstract_font,
uint32_t ucs4)
{
cairo_user_scaled_font_t *scaled_font = abstract_font;
cairo_user_font_face_t *face =
(cairo_user_font_face_t *) scaled_font->base.font_face;
unsigned long glyph = 0;
if (face->scaled_font_methods.unicode_to_glyph) {
cairo_status_t status;
status = face->scaled_font_methods.unicode_to_glyph (&scaled_font->base,
ucs4, &glyph);
if (status != CAIRO_STATUS_SUCCESS) {
status = _cairo_scaled_font_set_error (&scaled_font->base, status);
glyph = 0;
}
} else {
glyph = ucs4;
}
return glyph;
}
static cairo_int_status_t
_cairo_user_text_to_glyphs (void *abstract_font,
double x,
double y,
const char *utf8,
cairo_glyph_t **glyphs,
int *num_glyphs)
{
cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
cairo_user_scaled_font_t *scaled_font = abstract_font;
cairo_user_font_face_t *face =
(cairo_user_font_face_t *) scaled_font->base.font_face;
if (face->scaled_font_methods.text_to_glyphs) {
int i;
*glyphs = NULL;
*num_glyphs = -1;
/* XXX currently user allocs glyphs array but cairo frees it */
status = face->scaled_font_methods.text_to_glyphs (&scaled_font->base,
utf8, glyphs, num_glyphs);
if (status != CAIRO_STATUS_SUCCESS) {
status = _cairo_scaled_font_set_error (&scaled_font->base, status);
if (*glyphs) {
free (*glyphs);
*glyphs = NULL;
}
return status;
}
if (*num_glyphs < 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
/* Convert from font space to user space and add x,y */
for (i = 0; i < *num_glyphs; i++) {
double gx = (*glyphs)[i].x;
double gy = (*glyphs)[i].y;
cairo_matrix_transform_point (&scaled_font->base.font_matrix,
&gx, &gy);
(*glyphs)[i].x = gx + x;
(*glyphs)[i].y = gy + y;
}
}
return status;
}
static const cairo_scaled_font_backend_t cairo_user_scaled_font_backend = {
CAIRO_FONT_TYPE_USER,
NULL, /* create_toy */
NULL, /* scaled_font_fini */
_cairo_user_scaled_glyph_init,
_cairo_user_text_to_glyphs,
_cairo_user_ucs4_to_index,
NULL, /* show_glyphs */
NULL, /* load_truetype_table */
NULL, /* map_glyphs_to_unicode */
};
/* #cairo_user_font_face_t */
static cairo_status_t
_cairo_user_font_face_scaled_font_create (void *abstract_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
cairo_scaled_font_t **scaled_font)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_user_font_face_t *font_face = abstract_face;
cairo_user_scaled_font_t *user_scaled_font = NULL;
cairo_font_extents_t font_extents = {1., 0., 1., 1., 0.};
font_face->immutable = TRUE;
user_scaled_font = malloc (sizeof (cairo_user_scaled_font_t));
if (user_scaled_font == NULL)
return CAIRO_STATUS_NO_MEMORY;
status = _cairo_scaled_font_init (&user_scaled_font->base,
&font_face->base,
font_matrix, ctm, options,
&cairo_user_scaled_font_backend);
if (status) {
free (user_scaled_font);
return status;
}
/* XXX metrics hinting? */
/* compute a normalized version of font scale matrix to compute
* extents in. This is to minimize error caused by the cairo_fixed_t
* representation. */
{
double fixed_scale, x_scale, y_scale;
user_scaled_font->extent_scale = user_scaled_font->base.scale_inverse;
status = _cairo_matrix_compute_scale_factors (&user_scaled_font->extent_scale,
&x_scale, &y_scale,
1);
if (status == CAIRO_STATUS_SUCCESS) {
if (x_scale == 0) x_scale = 1.;
if (y_scale == 0) y_scale = 1.;
user_scaled_font->snap_x_scale = x_scale;
user_scaled_font->snap_y_scale = y_scale;
/* since glyphs are pretty much 1.0x1.0, we can reduce error by
* scaling to a larger square. say, 1024.x1024. */
fixed_scale = 1024.;
x_scale /= fixed_scale;
y_scale /= fixed_scale;
cairo_matrix_scale (&user_scaled_font->extent_scale, 1. / x_scale, 1. / y_scale);
user_scaled_font->extent_x_scale = x_scale;
user_scaled_font->extent_y_scale = y_scale;
}
}
if (status == CAIRO_STATUS_SUCCESS && font_face->scaled_font_methods.init != NULL) {
/* Lock the scaled_font mutex such that user doesn't accidentally try
* to use it just yet. */
CAIRO_MUTEX_LOCK (user_scaled_font->base.mutex);
/* Give away fontmap lock such that user-font can use other fonts */
_cairo_scaled_font_register_placeholder_and_unlock_font_map (&user_scaled_font->base);
status = font_face->scaled_font_methods.init (&user_scaled_font->base,
&font_extents);
_cairo_scaled_font_unregister_placeholder_and_lock_font_map (&user_scaled_font->base);
CAIRO_MUTEX_UNLOCK (user_scaled_font->base.mutex);
}
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_scaled_font_set_metrics (&user_scaled_font->base, &font_extents);
if (status != CAIRO_STATUS_SUCCESS) {
_cairo_scaled_font_fini (&user_scaled_font->base);
free (user_scaled_font);
} else {
user_scaled_font->default_glyph_extents.x_bearing = 0.;
user_scaled_font->default_glyph_extents.y_bearing = -font_extents.ascent;
user_scaled_font->default_glyph_extents.width = 0.;
user_scaled_font->default_glyph_extents.height = font_extents.ascent + font_extents.descent;
user_scaled_font->default_glyph_extents.x_advance = font_extents.max_x_advance;
user_scaled_font->default_glyph_extents.y_advance = 0.;
*scaled_font = &user_scaled_font->base;
}
return status;
}
static const cairo_font_face_backend_t _cairo_user_font_face_backend = {
CAIRO_FONT_TYPE_USER,
NULL, /* destroy */
_cairo_user_font_face_scaled_font_create
};
cairo_bool_t
_cairo_font_face_is_user (cairo_font_face_t *font_face)
{
return font_face->backend == &_cairo_user_font_face_backend;
}
/* Implement the public interface */
/**
* cairo_user_font_face_create:
*
* Creates a new user font-face.
*
* Use the setter functions to associate callbacks with the returned
* user font. The only mandatory callback is render_glyph.
*
* After the font-face is created, the user can attach arbitrary data
* (the actual font data) to it using cairo_font_face_set_user_data()
* and access it from the user-font callbacks by using
* cairo_scaled_font_get_font_face() followed by
* cairo_font_face_get_user_data().
*
* Return value: a newly created #cairo_font_face_t. Free with
* cairo_font_face_destroy() when you are done using it.
*
* Since: 1.8
**/
cairo_font_face_t *
cairo_user_font_face_create (void)
{
cairo_user_font_face_t *font_face;
font_face = malloc (sizeof (cairo_user_font_face_t));
if (!font_face) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_face_t *)&_cairo_font_face_nil;
}
_cairo_font_face_init (&font_face->base, &_cairo_user_font_face_backend);
font_face->immutable = FALSE;
memset (&font_face->scaled_font_methods, 0, sizeof (font_face->scaled_font_methods));
return &font_face->base;
}
/* User-font method setters */
/**
* cairo_user_font_face_set_init_func:
* @font_face: A user font face
* @init_func: The init callback, or %NULL
*
* Sets the scaled-font initialization function of a user-font.
* See #cairo_user_scaled_font_init_func_t for details of how the callback
* works.
*
* The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
* error will occur. A user font-face is immutable as soon as a scaled-font
* is created from it.
*
* Since: 1.8
**/
void
cairo_user_font_face_set_init_func (cairo_font_face_t *font_face,
cairo_user_scaled_font_init_func_t init_func)
{
cairo_user_font_face_t *user_font_face = (cairo_user_font_face_t *) font_face;
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return;
}
if (user_font_face->immutable) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
return;
}
user_font_face->scaled_font_methods.init = init_func;
}
/**
* cairo_user_font_face_set_render_glyph_func:
* @font_face: A user font face
* @render_glyph_func: The render_glyph callback, or %NULL
*
* Sets the glyph rendering function of a user-font.
* See #cairo_user_scaled_font_render_glyph_func_t for details of how the callback
* works.
*
* The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
* error will occur. A user font-face is immutable as soon as a scaled-font
* is created from it.
*
* The render_glyph callback is the only mandatory callback of a user-font.
* If the callback is %NULL and a glyph is tried to be rendered using
* @font_face, a %CAIRO_STATUS_USER_FONT_ERROR will occur.
*
* Since: 1.8
**/
void
cairo_user_font_face_set_render_glyph_func (cairo_font_face_t *font_face,
cairo_user_scaled_font_render_glyph_func_t render_glyph_func)
{
cairo_user_font_face_t *user_font_face = (cairo_user_font_face_t *) font_face;
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return;
}
if (user_font_face->immutable) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
return;
}
user_font_face->scaled_font_methods.render_glyph = render_glyph_func;
}
/**
* cairo_user_font_face_set_text_to_glyphs_func:
* @font_face: A user font face
* @text_to_glyphs_func: The text_to_glyphs callback, or %NULL
*
* Sets th text-to-glyphs conversion function of a user-font.
* See #cairo_user_scaled_font_text_to_glyphs_func_t for details of how the callback
* works.
*
* The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
* error will occur. A user font-face is immutable as soon as a scaled-font
* is created from it.
*
* Since: 1.8
**/
void
cairo_user_font_face_set_text_to_glyphs_func (cairo_font_face_t *font_face,
cairo_user_scaled_font_text_to_glyphs_func_t text_to_glyphs_func)
{
cairo_user_font_face_t *user_font_face = (cairo_user_font_face_t *) font_face;
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return;
}
if (user_font_face->immutable) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
return;
}
user_font_face->scaled_font_methods.text_to_glyphs = text_to_glyphs_func;
}
/**
* cairo_user_font_face_set_unicode_to_glyph_func:
* @font_face: A user font face
* @unicode_to_glyph_func: The unicode_to_glyph callback, or %NULL
*
* Sets the unicode-to-glyph conversion function of a user-font.
* See #cairo_user_scaled_font_unicode_to_glyph_func_t for details of how the callback
* works.
*
* The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
* error will occur. A user font-face is immutable as soon as a scaled-font
* is created from it.
*
* Since: 1.8
**/
void
cairo_user_font_face_set_unicode_to_glyph_func (cairo_font_face_t *font_face,
cairo_user_scaled_font_unicode_to_glyph_func_t unicode_to_glyph_func)
{
cairo_user_font_face_t *user_font_face = (cairo_user_font_face_t *) font_face;
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return;
}
if (user_font_face->immutable) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
return;
}
user_font_face->scaled_font_methods.unicode_to_glyph = unicode_to_glyph_func;
}
/* User-font method getters */
/**
* cairo_user_font_face_get_init_func:
* @font_face: A user font face
*
* Gets the scaled-font initialization function of a user-font.
*
* Return value: The init callback of @font_face
* or %NULL if none set.
*
* Since: 1.8
**/
cairo_user_scaled_font_init_func_t
cairo_user_font_face_get_init_func (cairo_font_face_t *font_face)
{
cairo_user_font_face_t *user_font_face = (cairo_user_font_face_t *) font_face;
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return NULL;
}
return user_font_face->scaled_font_methods.init;
}
/**
* cairo_user_font_face_get_render_glyph_func:
* @font_face: A user font face
*
* Gets the glyph rendering function of a user-font.
*
* Return value: The render_glyph callback of @font_face
* or %NULL if none set.
*
* Since: 1.8
**/
cairo_user_scaled_font_render_glyph_func_t
cairo_user_font_face_get_render_glyph_func (cairo_font_face_t *font_face)
{
cairo_user_font_face_t *user_font_face = (cairo_user_font_face_t *) font_face;
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return NULL;
}
return user_font_face->scaled_font_methods.render_glyph;
}
/**
* cairo_user_font_face_get_text_to_glyphs_func:
* @font_face: A user font face
*
* Gets the text-to-glyphs conversion function of a user-font.
*
* Return value: The text_to_glyphs callback of @font_face
* or %NULL if none set.
*
* Since: 1.8
**/
cairo_user_scaled_font_text_to_glyphs_func_t
cairo_user_font_face_get_text_to_glyphs_func (cairo_font_face_t *font_face)
{
cairo_user_font_face_t *user_font_face = (cairo_user_font_face_t *) font_face;
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return NULL;
}
return user_font_face->scaled_font_methods.text_to_glyphs;
}
/**
* cairo_user_font_face_get_unicode_to_glyph_func:
* @font_face: A user font face
*
* Gets the unicode-to-glyph conversion function of a user-font.
*
* Return value: The unicode_to_glyph callback of @font_face
* or %NULL if none set.
*
* Since: 1.8
**/
cairo_user_scaled_font_unicode_to_glyph_func_t
cairo_user_font_face_get_unicode_to_glyph_func (cairo_font_face_t *font_face)
{
cairo_user_font_face_t *user_font_face = (cairo_user_font_face_t *) font_face;
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return NULL;
}
return user_font_face->scaled_font_methods.unicode_to_glyph;
}

View File

@ -78,6 +78,22 @@
#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.)
#endif
#if HAVE_BYTESWAP_H
# include <byteswap.h>
#endif
#ifndef bswap_16
# define bswap_16(p) \
(((((uint16_t)(p)) & 0x00ff) << 8) | \
(((uint16_t)(p)) >> 8));
#endif
#ifndef bswap_32
# define bswap_32(p) \
(((((uint32_t)(p)) & 0x000000ff) << 24) | \
((((uint32_t)(p)) & 0x0000ff00) << 8) | \
((((uint32_t)(p)) & 0x00ff0000) >> 8) | \
((((uint32_t)(p))) >> 24));
#endif
#if !HAVE_UINT64_T

View File

@ -61,7 +61,7 @@
#define CMAP_TAG 0x70616d63
const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend;
const cairo_scaled_font_backend_t _cairo_win32_scaled_font_backend;
typedef struct {
cairo_scaled_font_t base;
@ -322,7 +322,7 @@ _win32_scaled_font_create (LOGFONTW *logfont,
status = _cairo_scaled_font_init (&f->base, font_face,
font_matrix, ctm, options,
&cairo_win32_scaled_font_backend);
&_cairo_win32_scaled_font_backend);
if (status)
goto FAIL;
@ -934,7 +934,7 @@ _cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_f
extents.x_bearing = 0;
extents.y_bearing = scaled_font->base.ctm.yy * (-font_extents.ascent / scaled_font->y_scale);
extents.width = width / scaled_font->x_scale;
extents.width = width / (WIN32_FONT_LOGICAL_SCALE * scaled_font->x_scale);
extents.height = scaled_font->base.ctm.yy * (font_extents.ascent + font_extents.descent) / scaled_font->y_scale;
extents.x_advance = extents.width;
extents.y_advance = 0;
@ -1320,7 +1320,8 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs)
int num_glyphs,
int *remaining_glyphs)
{
cairo_win32_scaled_font_t *scaled_font = abstract_font;
cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface;
@ -1435,7 +1436,7 @@ _cairo_win32_scaled_font_load_truetype_table (void *abstract_font,
unsigned long *length)
{
HDC hdc;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_status_t status;
cairo_win32_scaled_font_t *scaled_font = abstract_font;
hdc = _get_global_font_dc ();
@ -1443,20 +1444,23 @@ _cairo_win32_scaled_font_load_truetype_table (void *abstract_font,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
tag = (tag&0x000000ff)<<24 | (tag&0x0000ff00)<<8 | (tag&0x00ff0000)>>8 | (tag&0xff000000)>>24;
status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
if (status)
return status;
*length = GetFontData (hdc, tag, offset, buffer, *length);
if (*length == GDI_ERROR)
status = CAIRO_INT_STATUS_UNSUPPORTED;
_cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base);
cairo_win32_scaled_font_done_font (&scaled_font->base);
return status;
}
static cairo_int_status_t
_cairo_win32_scaled_font_map_glyphs_to_unicode (void *abstract_font,
cairo_scaled_font_subset_t *font_subset)
static cairo_status_t
_cairo_win32_scaled_font_index_to_ucs4 (void *abstract_font,
unsigned long index,
uint32_t *ucs4)
{
cairo_win32_scaled_font_t *scaled_font = abstract_font;
GLYPHSET *glyph_set;
@ -1464,7 +1468,7 @@ _cairo_win32_scaled_font_map_glyphs_to_unicode (void *abstract_font,
WORD *glyph_indices = NULL;
HDC hdc = NULL;
int res;
unsigned int i, j, k, count, num_glyphs;
unsigned int i, j, num_glyphs;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
hdc = _get_global_font_dc ();
@ -1478,37 +1482,36 @@ _cairo_win32_scaled_font_map_glyphs_to_unicode (void *abstract_font,
res = GetFontUnicodeRanges(hdc, NULL);
if (res == 0) {
status = _cairo_win32_print_gdi_error (
"_cairo_win32_scaled_font_map_glyphs_to_unicode:GetFontUnicodeRanges");
goto fail1;
"_cairo_win32_scaled_font_index_to_ucs4:GetFontUnicodeRanges");
goto exit1;
}
glyph_set = malloc (res);
if (glyph_set == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1;
goto exit1;
}
res = GetFontUnicodeRanges(hdc, glyph_set);
if (res == 0) {
status = _cairo_win32_print_gdi_error (
"_cairo_win32_scaled_font_map_glyphs_to_unicode:GetFontUnicodeRanges");
goto fail2;
"_cairo_win32_scaled_font_index_to_ucs4:GetFontUnicodeRanges");
goto exit1;
}
count = font_subset->num_glyphs;
for (i = 0; i < glyph_set->cRanges && count > 0; i++) {
for (i = 0; i < glyph_set->cRanges; i++) {
num_glyphs = glyph_set->ranges[i].cGlyphs;
utf16 = _cairo_malloc_ab (num_glyphs + 1, sizeof (uint16_t));
if (utf16 == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
goto exit1;
}
glyph_indices = _cairo_malloc_ab (num_glyphs + 1, sizeof (WORD));
if (glyph_indices == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
goto exit2;
}
for (j = 0; j < num_glyphs; j++)
@ -1517,33 +1520,30 @@ _cairo_win32_scaled_font_map_glyphs_to_unicode (void *abstract_font,
if (GetGlyphIndicesW (hdc, utf16, num_glyphs, glyph_indices, 0) == GDI_ERROR) {
status = _cairo_win32_print_gdi_error (
"_cairo_win32_scaled_font_map_glyphs_to_unicode:GetGlyphIndicesW");
goto fail2;
"_cairo_win32_scaled_font_index_to_ucs4:GetGlyphIndicesW");
goto exit2;
}
for (j = 0; j < num_glyphs; j++) {
for (k = 0; k < font_subset->num_glyphs; k++) {
if (font_subset->glyphs[k] == glyph_indices[j]) {
font_subset->to_unicode[k] = utf16[j];
count--;
break;
}
if (glyph_indices[j] == index) {
*ucs4 = utf16[j];
goto exit2;
}
}
free (glyph_indices);
glyph_indices = NULL;
free (utf16);
utf16= NULL;
utf16 = NULL;
}
fail2:
exit2:
if (glyph_indices)
free (glyph_indices);
if (utf16)
free (utf16);
free (glyph_set);
fail1:
exit1:
cairo_win32_scaled_font_done_font (&scaled_font->base);
return status;
@ -1775,7 +1775,7 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font
return status;
}
const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend = {
const cairo_scaled_font_backend_t _cairo_win32_scaled_font_backend = {
CAIRO_FONT_TYPE_WIN32,
_cairo_win32_scaled_font_create_toy,
_cairo_win32_scaled_font_fini,
@ -1784,7 +1784,7 @@ const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend = {
NULL, /* ucs4_to_index */
_cairo_win32_scaled_font_show_glyphs,
_cairo_win32_scaled_font_load_truetype_table,
_cairo_win32_scaled_font_map_glyphs_to_unicode,
_cairo_win32_scaled_font_index_to_ucs4,
};
/* #cairo_win32_font_face_t */
@ -1939,6 +1939,12 @@ cairo_win32_font_face_create_for_hfont (HFONT font)
return cairo_win32_font_face_create_for_logfontw_hfont (&logfont, font);
}
static cairo_bool_t
_cairo_scaled_font_is_win32 (cairo_scaled_font_t *scaled_font)
{
return scaled_font->backend == &_cairo_win32_scaled_font_backend;
}
/**
* cairo_win32_scaled_font_select_font:
* @scaled_font: A #cairo_scaled_font_t from the Win32 font backend. Such an
@ -1972,6 +1978,10 @@ cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font,
HFONT old_hfont = NULL;
int old_mode;
if (! _cairo_scaled_font_is_win32 (scaled_font)) {
return _cairo_error (CAIRO_STATUS_FONT_TYPE_MISMATCH);
}
if (scaled_font->status)
return scaled_font->status;
@ -2011,6 +2021,9 @@ cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font,
void
cairo_win32_scaled_font_done_font (cairo_scaled_font_t *scaled_font)
{
if (! _cairo_scaled_font_is_win32 (scaled_font)) {
_cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH);
}
}
/**
@ -2028,6 +2041,10 @@ cairo_win32_scaled_font_done_font (cairo_scaled_font_t *scaled_font)
double
cairo_win32_scaled_font_get_metrics_factor (cairo_scaled_font_t *scaled_font)
{
if (! _cairo_scaled_font_is_win32 (scaled_font)) {
_cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH);
return 1.;
}
return 1. / ((cairo_win32_scaled_font_t *)scaled_font)->logical_scale;
}
@ -2046,6 +2063,11 @@ cairo_win32_scaled_font_get_logical_to_device (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *logical_to_device)
{
cairo_win32_scaled_font_t *win_font = (cairo_win32_scaled_font_t *)scaled_font;
if (! _cairo_scaled_font_is_win32 (scaled_font)) {
_cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH);
cairo_matrix_init_identity (logical_to_device);
return;
}
*logical_to_device = win_font->logical_to_device;
}
@ -2064,5 +2086,10 @@ cairo_win32_scaled_font_get_device_to_logical (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *device_to_logical)
{
cairo_win32_scaled_font_t *win_font = (cairo_win32_scaled_font_t *)scaled_font;
if (! _cairo_scaled_font_is_win32 (scaled_font)) {
_cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH);
cairo_matrix_init_identity (device_to_logical);
return;
}
*device_to_logical = win_font->device_to_logical;
}

View File

@ -494,7 +494,6 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
cairo_image_surface_t *image;
void *image_extra;
cairo_surface_t *opaque_surface;
cairo_pattern_union_t opaque_pattern;
cairo_image_surface_t *opaque_image = NULL;
BITMAPINFO bi;
cairo_matrix_t m;
@ -538,6 +537,8 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
}
if (image->format != CAIRO_FORMAT_RGB24) {
cairo_surface_pattern_t opaque_pattern;
opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
image->width,
image->height);
@ -546,7 +547,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
goto FINISH3;
}
_cairo_pattern_init_for_surface (&opaque_pattern.surface, &image->base);
_cairo_pattern_init_for_surface (&opaque_pattern, &image->base);
status = _cairo_surface_fill_rectangle (opaque_surface,
CAIRO_OPERATOR_SOURCE,
@ -1293,7 +1294,8 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
@ -1322,20 +1324,26 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
* non Windows fonts. ie filled outlines for Type 1 fonts and
* fallback images for bitmap fonts.
*/
if (_cairo_win32_scaled_font_is_bitmap (scaled_font))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32) {
if (_cairo_win32_scaled_font_is_bitmap (scaled_font))
return CAIRO_INT_STATUS_UNSUPPORTED;
else
return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
}
if (!(cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32 &&
! _cairo_win32_scaled_font_is_type1 (scaled_font) &&
source->type == CAIRO_PATTERN_TYPE_SOLID)) {
for (i = 0; i < num_glyphs; i++) {
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_PATH,
&scaled_glyph);
if (status)
return status;
}
/* For non win32 fonts we need to check that each glyph has a
* path available. If a path is not available,
* _cairo_scaled_glyph_lookup() will return
* CAIRO_INT_STATUS_UNSUPPORTED and a fallback image will be
* used.
*/
for (i = 0; i < num_glyphs; i++) {
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_PATH,
&scaled_glyph);
if (status)
return status;
}
return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
@ -1372,7 +1380,8 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
}
status = _cairo_win32_surface_show_glyphs (surface, op,
source, glyphs,
num_glyphs, scaled_font);
num_glyphs, scaled_font,
remaining_glyphs);
if (surface->has_ctm)
cairo_scaled_font_destroy (scaled_font);
@ -1493,11 +1502,14 @@ _cairo_win32_printing_surface_set_paginated_mode (void *abstract_surface,
* associated methods must be used for correct output.
*
* Return value: the newly created surface
*
* Since: 1.6
**/
cairo_surface_t *
cairo_win32_printing_surface_create (HDC hdc)
{
cairo_win32_surface_t *surface;
cairo_surface_t *paginated;
RECT rect;
surface = malloc (sizeof (cairo_win32_surface_t));
@ -1533,11 +1545,16 @@ cairo_win32_printing_surface_create (HDC hdc)
_cairo_surface_init (&surface->base, &cairo_win32_printing_surface_backend,
CAIRO_CONTENT_COLOR_ALPHA);
return _cairo_paginated_surface_create (&surface->base,
CAIRO_CONTENT_COLOR_ALPHA,
surface->extents.width,
surface->extents.height,
&cairo_win32_surface_paginated_backend);
paginated = _cairo_paginated_surface_create (&surface->base,
CAIRO_CONTENT_COLOR_ALPHA,
surface->extents.width,
surface->extents.height,
&cairo_win32_surface_paginated_backend);
/* paginated keeps the only reference to surface now, drop ours */
cairo_surface_destroy (&surface->base);
return paginated;
}
cairo_bool_t

View File

@ -36,8 +36,8 @@
#ifndef CAIRO_WIN32_PRIVATE_H
#define CAIRO_WIN32_PRIVATE_H
#include <cairo-win32.h>
#include <cairoint.h>
#include "cairo-win32.h"
#include "cairoint.h"
#ifndef SHADEBLENDCAPS
#define SHADEBLENDCAPS 120
@ -143,7 +143,8 @@ _cairo_win32_surface_show_glyphs (void *surface,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font);
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs);
cairo_surface_t *
_cairo_win32_surface_create_similar (void *abstract_src,

View File

@ -48,6 +48,7 @@
#include "cairoint.h"
#include "cairo-clip-private.h"
#include "cairo-paginated-private.h"
#include "cairo-win32-private.h"
#include <windows.h>
@ -445,7 +446,7 @@ _cairo_win32_surface_clone_similar (void *abstract_surface,
cairo_content_t src_content;
cairo_surface_t *new_surface;
cairo_status_t status;
cairo_pattern_union_t pattern;
cairo_surface_pattern_t pattern;
src_content = cairo_surface_get_content(src);
new_surface =
@ -454,7 +455,7 @@ _cairo_win32_surface_clone_similar (void *abstract_surface,
if (cairo_surface_status(new_surface))
return cairo_surface_status(new_surface);
_cairo_pattern_init_for_surface (&pattern.surface, src);
_cairo_pattern_init_for_surface (&pattern, src);
status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
&pattern.base,
@ -1555,7 +1556,8 @@ _cairo_win32_surface_show_glyphs (void *surface,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs)
{
#if CAIRO_HAS_WIN32_FONT
cairo_win32_surface_t *dst = surface;
@ -1705,7 +1707,6 @@ cairo_win32_surface_create (HDC hdc)
{
cairo_win32_surface_t *surface;
int depth;
cairo_format_t format;
RECT rect;
@ -1873,13 +1874,25 @@ cairo_win32_surface_get_dc (cairo_surface_t *surface)
{
cairo_win32_surface_t *winsurf;
if (!_cairo_surface_is_win32(surface) &&
!_cairo_surface_is_win32_printing(surface))
return NULL;
if (_cairo_surface_is_win32 (surface)){
winsurf = (cairo_win32_surface_t *) surface;
winsurf = (cairo_win32_surface_t *) surface;
return winsurf->dc;
}
return winsurf->dc;
if (_cairo_surface_is_paginated (surface)) {
cairo_surface_t *target;
target = _cairo_paginated_surface_get_target (surface);
if (_cairo_surface_is_win32_printing (target)) {
winsurf = (cairo_win32_surface_t *) target;
return winsurf->dc;
}
}
return NULL;
}
/**

View File

@ -37,7 +37,7 @@
#ifndef _CAIRO_WIN32_H_
#define _CAIRO_WIN32_H_
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_WIN32_SURFACE

View File

@ -1627,7 +1627,8 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
cairo_pattern_t *src_pattern,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font);
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs);
static cairo_bool_t
_cairo_xcb_surface_is_similar (void *surface_a,
@ -1855,7 +1856,7 @@ _cairo_xcb_screen_from_visual (xcb_connection_t *c, xcb_visualtype_t *visual)
* by the provided visual.
*
* Note: If @drawable is a window, then the function
* cairo_xcb_surface_set_size must be called whenever the size of the
* cairo_xcb_surface_set_size() must be called whenever the size of the
* window changes.
*
* Return value: the newly created surface
@ -1917,7 +1918,7 @@ cairo_xcb_surface_create_for_bitmap (xcb_connection_t *c,
* by the provided picture format.
*
* Note: If @drawable is a Window, then the function
* cairo_xcb_surface_set_size must be called whenever the size of the
* cairo_xcb_surface_set_size() must be called whenever the size of the
* window changes.
*
* Return value: the newly created surface.
@ -2310,7 +2311,8 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
cairo_pattern_t *src_pattern,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs)
{
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_xcb_surface_t *dst = abstract_dst;
@ -2330,7 +2332,7 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
cairo_xcb_surface_show_glyphs_func_t show_glyphs_func;
cairo_pattern_union_t solid_pattern;
cairo_solid_pattern_t solid_pattern;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || dst->xrender_format.id == XCB_NONE)
return CAIRO_INT_STATUS_UNSUPPORTED;
@ -2393,7 +2395,7 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
* so PictOpClear was never used with CompositeText before.
*/
if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE,
_cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
src_pattern = &solid_pattern.base;
op = CAIRO_OPERATOR_DEST_OUT;

View File

@ -37,7 +37,7 @@
#ifndef CAIRO_XCB_XRENDER_H
#define CAIRO_XCB_XRENDER_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_XCB_SURFACE

View File

@ -37,7 +37,7 @@
#ifndef CAIRO_XCB_H
#define CAIRO_XCB_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_XCB_SURFACE

View File

@ -289,6 +289,9 @@ _cairo_xlib_display_get (Display *dpy)
display->close_display_hooks = NULL;
display->closed = FALSE;
memset (display->cached_xrender_formats, 0,
sizeof (display->cached_xrender_formats));
display->buggy_repeat = FALSE;
if (strstr (ServerVendor (dpy), "X.Org") != NULL) {
/* When modularized, the X.Org server VendorRelease was
@ -498,3 +501,35 @@ _cairo_xlib_display_notify (cairo_xlib_display_t *display)
}
CAIRO_MUTEX_UNLOCK (display->mutex);
}
XRenderPictFormat *
_cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display,
cairo_format_t format)
{
XRenderPictFormat *xrender_format;
CAIRO_MUTEX_LOCK (display->mutex);
xrender_format = display->cached_xrender_formats[format];
if (xrender_format == NULL) {
int pict_format;
switch (format) {
case CAIRO_FORMAT_A1:
pict_format = PictStandardA1; break;
case CAIRO_FORMAT_A8:
pict_format = PictStandardA8; break;
case CAIRO_FORMAT_RGB24:
pict_format = PictStandardRGB24; break;
default:
ASSERT_NOT_REACHED;
case CAIRO_FORMAT_ARGB32:
pict_format = PictStandardARGB32; break;
}
xrender_format = XRenderFindStandardFormat (display->display,
pict_format);
display->cached_xrender_formats[format] = xrender_format;
}
CAIRO_MUTEX_UNLOCK (display->mutex);
return xrender_format;
}

View File

@ -34,6 +34,7 @@
#define CAIRO_XLIB_PRIVATE_H
#include "cairo-xlib.h"
#include "cairo-xlib-xrender-private.h"
#include "cairo-compiler-private.h"
#include "cairo-freelist-private.h"
@ -61,6 +62,8 @@ struct _cairo_xlib_display {
Display *display;
cairo_xlib_screen_info_t *screens;
XRenderPictFormat *cached_xrender_formats[CAIRO_FORMAT_A1 + 1];
cairo_xlib_job_t *workqueue;
cairo_freelist_t wq_freelist;
@ -70,15 +73,24 @@ struct _cairo_xlib_display {
unsigned int closed :1;
};
/* size of color cube */
#define CUBE_SIZE 6
/* size of gray ramp */
#define RAMP_SIZE 16
typedef struct _cairo_xlib_visual_info {
VisualID visualid;
XColor colors[256];
unsigned long rgb333_to_pseudocolor[512];
struct { uint8_t a, r, g, b; } colors[256];
uint8_t cube_to_pseudocolor[CUBE_SIZE][CUBE_SIZE][CUBE_SIZE];
uint8_t field8_to_cube[256];
int8_t dither8_to_cube[256];
uint8_t gray8_to_pseudocolor[256];
} cairo_xlib_visual_info_t;
struct _cairo_xlib_screen_info {
cairo_xlib_screen_info_t *next;
cairo_reference_count_t ref_count;
cairo_mutex_t mutex;
cairo_xlib_display_t *display;
Screen *screen;
@ -117,6 +129,10 @@ _cairo_xlib_display_queue_resource (cairo_xlib_display_t *display,
cairo_private void
_cairo_xlib_display_notify (cairo_xlib_display_t *display);
cairo_private XRenderPictFormat *
_cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display,
cairo_format_t format);
cairo_private cairo_xlib_screen_info_t *
_cairo_xlib_screen_info_get (Display *display, Screen *screen);

View File

@ -111,8 +111,10 @@ get_integer_default (Display *dpy,
v = XGetDefault (dpy, "Xft", option);
if (v) {
#if CAIRO_HAS_FT_FONT
if (FcNameConstant ((FcChar8 *) v, value))
return TRUE;
#endif
i = strtol (v, &e, 0);
if (e != v)
@ -254,14 +256,23 @@ _cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t *info)
void
_cairo_xlib_screen_info_close_display (cairo_xlib_screen_info_t *info)
{
cairo_xlib_visual_info_t **visuals;
int i;
CAIRO_MUTEX_LOCK (info->mutex);
for (i = 0; i < ARRAY_LENGTH (info->gc); i++) {
if (info->gc[i] != NULL) {
XFreeGC (info->display->display, info->gc[i]);
info->gc[i] = NULL;
}
}
visuals = _cairo_array_index (&info->visuals, 0);
for (i = 0; i < _cairo_array_num_elements (&info->visuals); i++)
_cairo_xlib_visual_info_destroy (info->display->display, visuals[i]);
_cairo_array_truncate (&info->visuals, 0);
CAIRO_MUTEX_UNLOCK (info->mutex);
}
void
@ -269,8 +280,6 @@ _cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info)
{
cairo_xlib_screen_info_t **prev;
cairo_xlib_screen_info_t *list;
cairo_xlib_visual_info_t **visuals;
int i;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&info->ref_count));
@ -284,9 +293,6 @@ _cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info)
break;
}
}
visuals = _cairo_array_index (&info->visuals, 0);
for (i = 0; i < _cairo_array_num_elements (&info->visuals); i++)
_cairo_xlib_visual_info_destroy (info->display->display, visuals[i]);
CAIRO_MUTEX_UNLOCK (info->display->mutex);
_cairo_xlib_screen_info_close_display (info);
@ -295,6 +301,8 @@ _cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info)
_cairo_array_fini (&info->visuals);
CAIRO_MUTEX_FINI (info->mutex);
free (info);
}
@ -335,6 +343,7 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
info = malloc (sizeof (cairo_xlib_screen_info_t));
if (info != NULL) {
CAIRO_REFERENCE_COUNT_INIT (&info->ref_count, 2); /* Add one for display cache */
CAIRO_MUTEX_INIT (info->mutex);
info->display = _cairo_xlib_display_reference (display);
info->screen = screen;
info->has_render = FALSE;
@ -385,16 +394,19 @@ GC
_cairo_xlib_screen_get_gc (cairo_xlib_screen_info_t *info, int depth)
{
GC gc;
cairo_bool_t needs_reset;
depth = depth_to_index (depth);
CAIRO_MUTEX_LOCK (info->mutex);
gc = info->gc[depth];
info->gc[depth] = NULL;
needs_reset = info->gc_needs_clip_reset & (1 << depth);
info->gc_needs_clip_reset &= ~(1 << depth);
CAIRO_MUTEX_UNLOCK (info->mutex);
if (info->gc_needs_clip_reset & (1 << depth)) {
if (needs_reset)
XSetClipMask(info->display->display, gc, None);
info->gc_needs_clip_reset &= ~(1 << depth);
}
return gc;
}
@ -403,21 +415,25 @@ cairo_status_t
_cairo_xlib_screen_put_gc (cairo_xlib_screen_info_t *info, int depth, GC gc, cairo_bool_t reset_clip)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
GC oldgc;
depth = depth_to_index (depth);
if (info->gc[depth] != NULL) {
status = _cairo_xlib_display_queue_work (info->display,
(cairo_xlib_notify_func) XFreeGC,
info->gc[depth],
NULL);
}
CAIRO_MUTEX_LOCK (info->mutex);
oldgc = info->gc[depth];
info->gc[depth] = gc;
if (reset_clip)
info->gc_needs_clip_reset |= 1 << depth;
else
info->gc_needs_clip_reset &= ~(1 << depth);
CAIRO_MUTEX_UNLOCK (info->mutex);
if (oldgc != NULL) {
status = _cairo_xlib_display_queue_work (info->display,
(cairo_xlib_notify_func) XFreeGC,
oldgc,
NULL);
}
return status;
}
@ -427,11 +443,12 @@ _cairo_xlib_screen_get_visual_info (cairo_xlib_screen_info_t *info,
Visual *visual,
cairo_xlib_visual_info_t **out)
{
Display *dpy = info->display->display;
cairo_xlib_visual_info_t **visuals, *ret = NULL;
cairo_status_t status;
int i, n_visuals;
CAIRO_MUTEX_LOCK (info->display->mutex);
CAIRO_MUTEX_LOCK (info->mutex);
visuals = _cairo_array_index (&info->visuals, 0);
n_visuals = _cairo_array_num_elements (&info->visuals);
for (i = 0; i < n_visuals; i++) {
@ -440,28 +457,28 @@ _cairo_xlib_screen_get_visual_info (cairo_xlib_screen_info_t *info,
break;
}
}
CAIRO_MUTEX_UNLOCK (info->display->mutex);
CAIRO_MUTEX_UNLOCK (info->mutex);
if (ret != NULL) {
*out = ret;
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_xlib_visual_info_create (info->display->display,
status = _cairo_xlib_visual_info_create (dpy,
XScreenNumberOfScreen (info->screen),
visual->visualid,
&ret);
if (status)
return status;
CAIRO_MUTEX_LOCK (info->display->mutex);
CAIRO_MUTEX_LOCK (info->mutex);
if (n_visuals != _cairo_array_num_elements (&info->visuals)) {
/* check that another thread has not added our visual */
int new_visuals = _cairo_array_num_elements (&info->visuals);
visuals = _cairo_array_index (&info->visuals, 0);
for (i = n_visuals; i < new_visuals; i++) {
if (visuals[i]->visualid == visual->visualid) {
_cairo_xlib_visual_info_destroy (info->display->display, ret);
_cairo_xlib_visual_info_destroy (dpy, ret);
ret = visuals[i];
break;
}
@ -470,10 +487,10 @@ _cairo_xlib_screen_get_visual_info (cairo_xlib_screen_info_t *info,
status = _cairo_array_append (&info->visuals, &ret);
} else
status = _cairo_array_append (&info->visuals, &ret);
CAIRO_MUTEX_UNLOCK (info->display->mutex);
CAIRO_MUTEX_UNLOCK (info->mutex);
if (status) {
_cairo_xlib_visual_info_destroy (info->display->display, ret);
_cairo_xlib_visual_info_destroy (dpy, ret);
return status;
}

Some files were not shown because too many files have changed in this diff Show More