b=374462, update cairo to 1.4.2, r=stuart

This commit is contained in:
vladimir@pobox.com 2007-04-03 18:09:15 -07:00
Родитель 7a656c0720
Коммит 724852819d
88 изменённых файлов: 6319 добавлений и 4968 удалений

Просмотреть файл

@ -7248,7 +7248,6 @@ if test "$MOZ_SVG" -o "$MOZ_ENABLE_CANVAS" -o "$MOZ_ENABLE_CAIRO_GFX" ; then
fi
if test "$MOZ_WIDGET_TOOLKIT" = "mac" -o "$MOZ_WIDGET_TOOLKIT" = "cocoa"; then
QUARTZ_SURFACE_FEATURE="#define CAIRO_HAS_QUARTZ_SURFACE 1"
NQUARTZ_SURFACE_FEATURE="#define CAIRO_HAS_NQUARTZ_SURFACE 1"
ATSUI_FONT_FEATURE="#define CAIRO_HAS_ATSUI_FONT 1"
fi
if test "$MOZ_WIDGET_TOOLKIT" = "windows"; then

Просмотреть файл

@ -7,10 +7,20 @@ http://www.cairographics.org/.
VERSIONS:
cairo (1.3.12 tagged snapshot)
cairo (1.4.2)
glitz 0.5.2 (cvs - 2006-01-10)
***** NOTE FOR VISUAL C++ 6.0 *****
VC6 is not supported. Please upgrade to VC8.
==== Patches ====
All patches in the cairo tree are surrounded by "MOZILLA_CAIRO_NOT_DEFINED" (which should NOT be defined).
Some specific things:
max-font-size.patch: Clamp freetype font size to 1000 to avoid overflow issues
fbcompose-bandaid.patch: Disable "optimized" code in non-MMX case due to bugs

Просмотреть файл

@ -129,11 +129,6 @@ endif
ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
CSRCS += cairo-quartz-surface.c cairo-atsui-font.c
EXPORTS += cairo-quartz.h cairo-atsui.h
ifdef MOZ_ENABLE_CAIRO_GFX
CSRCS += cairo-nquartz-surface.c
EXPORTS += cairo-nquartz.h
endif
endif
ifeq ($(MOZ_WIDGET_TOOLKIT),beos)

Просмотреть файл

@ -1,4 +1,4 @@
/* $Id: cairo-analysis-surface-private.h,v 1.4 2007/04/03 18:59:47 vladimir%pobox.com Exp $
/* $Id: cairo-analysis-surface-private.h,v 1.5 2007/04/04 01:09:15 vladimir%pobox.com Exp $
*
* Copyright © 2005 Keith Packard
*

Просмотреть файл

@ -82,6 +82,9 @@ struct _cairo_atsui_font {
ATSUStyle style;
ATSUStyle unscaled_style;
ATSUFontID fontID;
Fixed size;
CGAffineTransform font_matrix;
};
struct _cairo_atsui_font_face {
@ -146,47 +149,6 @@ cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id)
return &font_face->base;
}
static CGContextRef
CGBitmapContextCreateWithCairoImageSurface (const cairo_image_surface_t * surface)
{
CGContextRef contextRef;
CGColorSpaceRef colorSpace;
int bits_per_comp, alpha;
/* Create a CGBitmapContext for the dest surface for drawing into */
if (surface->depth == 1) {
colorSpace = CGColorSpaceCreateDeviceGray ();
bits_per_comp = 1;
alpha = kCGImageAlphaNone;
} else if (surface->depth == 8) {
colorSpace = CGColorSpaceCreateDeviceGray ();
bits_per_comp = 8;
alpha = kCGImageAlphaNone;
} else if (surface->depth == 24) {
colorSpace = CGColorSpaceCreateDeviceRGB ();
bits_per_comp = 8;
alpha = kCGImageAlphaNoneSkipFirst | CG_BITMAP_BYTE_ORDER_FLAG;
} else if (surface->depth == 32) {
colorSpace = CGColorSpaceCreateDeviceRGB ();
bits_per_comp = 8;
alpha = kCGImageAlphaPremultipliedFirst | CG_BITMAP_BYTE_ORDER_FLAG;
} else {
/* not reached */
return NULL;
}
contextRef = CGBitmapContextCreate (surface->data,
surface->width,
surface->height,
bits_per_comp,
surface->stride,
colorSpace,
alpha);
CGColorSpaceRelease (colorSpace);
return contextRef;
}
static CGAffineTransform
CGAffineTransformMakeWithCairoFontScale(const cairo_matrix_t *scale)
{
@ -195,29 +157,19 @@ CGAffineTransformMakeWithCairoFontScale(const cairo_matrix_t *scale)
0, 0);
}
static CGAffineTransform
CGAffineTransformMakeWithCairoScaleFactors(const cairo_matrix_t *scale)
{
double xscale = 1.0;
double yscale = 1.0;
_cairo_matrix_compute_scale_factors(scale, &xscale, &yscale, 1);
return CGAffineTransformMake(xscale, 0,
0, yscale,
0, 0);
}
static ATSUStyle
CreateSizedCopyOfStyle(ATSUStyle inStyle, const cairo_matrix_t *scale)
CreateSizedCopyOfStyle(ATSUStyle inStyle,
const Fixed *theSize,
const CGAffineTransform *theTransform)
{
ATSUStyle style;
OSStatus err;
/* Set the style's size */
Fixed theSize = FloatToFixed(1.0);
CGAffineTransform theTransform = CGAffineTransformMakeWithCairoScaleFactors(scale);
const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag, kATSUFontMatrixTag };
const ByteCount theFontStyleSizes[] = { sizeof(Fixed), sizeof(CGAffineTransform) };
ATSUAttributeValuePtr theFontStyleValues[] = { &theSize, &theTransform };
const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag,
kATSUFontMatrixTag };
const ByteCount theFontStyleSizes[] = { sizeof(Fixed),
sizeof(CGAffineTransform) };
ATSUAttributeValuePtr theFontStyleValues[] = { (Fixed *)theSize,
(CGAffineTransform *)theTransform };
err = ATSUCreateAndCopyStyle(inStyle, &style);
@ -273,6 +225,8 @@ _cairo_atsui_font_create_scaled (cairo_font_face_t *font_face,
cairo_atsui_font_t *font = NULL;
OSStatus err;
cairo_status_t status;
double xscale = 1.0;
double yscale = 1.0;
font = malloc(sizeof(cairo_atsui_font_t));
if (font == NULL)
@ -281,7 +235,14 @@ _cairo_atsui_font_create_scaled (cairo_font_face_t *font_face,
_cairo_scaled_font_init(&font->base, font_face, font_matrix, ctm, options,
&cairo_atsui_scaled_font_backend);
font->style = CreateSizedCopyOfStyle(style, &font->base.scale);
_cairo_matrix_compute_scale_factors (&font->base.scale,
&xscale, &yscale, 1);
font->font_matrix = CGAffineTransformMake (1., 0.,
0., yscale/xscale,
0., 0.);
font->size = FloatToFixed (xscale);
font->style = CreateSizedCopyOfStyle (style, &font->size, &font->font_matrix);
{
Fixed theSize = FloatToFixed(1.0);
@ -480,11 +441,19 @@ OSStatus _close_path_for_metrics(void *callback_data)
return noErr;
}
static GlyphID
_cairo_atsui_scaled_glyph_index (cairo_scaled_glyph_t *scaled_glyph) {
unsigned long index = _cairo_scaled_glyph_index (scaled_glyph);
if (index > 0xffff)
return kATSDeletedGlyphcode;
return index;
}
static cairo_status_t
_cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph)
{
cairo_text_extents_t extents;
cairo_text_extents_t extents = {0, 0, 0, 0, 0, 0};
OSStatus err, callback_err;
ATSGlyphScreenMetrics metricsH;
static ATSCubicMoveToUPP moveProc = NULL;
@ -492,10 +461,17 @@ _cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font,
static ATSCubicCurveToUPP curveProc = NULL;
static ATSCubicClosePathUPP closePathProc = NULL;
CGMutablePathRef path;
GlyphID theGlyph = _cairo_scaled_glyph_index (scaled_glyph);
GlyphID theGlyph = _cairo_atsui_scaled_glyph_index (scaled_glyph);
double xscale, yscale;
CGRect rect;
if (theGlyph == kATSDeletedGlyphcode) {
_cairo_scaled_glyph_set_metrics (scaled_glyph,
&scaled_font->base,
&extents);
return CAIRO_STATUS_SUCCESS;
}
/* We calculate the advance from the screen metrics. We
* could probably take this from the glyph path.
*/
@ -503,7 +479,7 @@ _cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font,
1, &theGlyph, 0, false,
false, &metricsH);
if (err != noErr)
return CAIRO_INT_STATUS_UNSUPPORTED;
return CAIRO_STATUS_NO_MEMORY;
/* Scale down to font units.*/
_cairo_matrix_compute_scale_factors (&scaled_font->base.scale,
@ -532,11 +508,8 @@ _cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font,
(void *)path, &callback_err);
if (err != noErr) {
/* This could potentially happen for bitmap fonts, where
* no paths are available.
*/
CGPathRelease (path);
return CAIRO_INT_STATUS_UNSUPPORTED;
return CAIRO_STATUS_NO_MEMORY;
}
rect = CGPathGetBoundingBox (path);
@ -636,6 +609,7 @@ _cairo_atsui_scaled_font_init_glyph_path (cairo_atsui_font_t *scaled_font,
static ATSCubicLineToUPP lineProc = NULL;
static ATSCubicCurveToUPP curveProc = NULL;
static ATSCubicClosePathUPP closePathProc = NULL;
GlyphID theGlyph = _cairo_atsui_scaled_glyph_index (scaled_glyph);
OSStatus err;
cairo_atsui_scaled_path_t scaled_path;
cairo_matrix_t *font_to_device = &scaled_font->base.scale;
@ -643,6 +617,17 @@ _cairo_atsui_scaled_font_init_glyph_path (cairo_atsui_font_t *scaled_font,
double xscale;
double yscale;
scaled_path.path = _cairo_path_fixed_create ();
if (!scaled_path.path)
return CAIRO_STATUS_NO_MEMORY;
if (theGlyph == kATSDeletedGlyphcode) {
_cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base,
scaled_path.path);
return CAIRO_STATUS_SUCCESS;
}
/* extract the rotation/shear component of the scale matrix. */
_cairo_matrix_compute_scale_factors (font_to_device, &xscale, &yscale, 1);
cairo_matrix_init (&unscaled_font_to_device,
@ -653,9 +638,6 @@ _cairo_atsui_scaled_font_init_glyph_path (cairo_atsui_font_t *scaled_font,
cairo_matrix_scale (&unscaled_font_to_device, 1.0/xscale, 1.0/yscale);
scaled_path.scale = &unscaled_font_to_device;
scaled_path.path = _cairo_path_fixed_create ();
if (!scaled_path.path)
return CAIRO_STATUS_NO_MEMORY;
if (moveProc == NULL) {
moveProc = NewATSCubicMoveToUPP(_move_to);
@ -665,7 +647,7 @@ _cairo_atsui_scaled_font_init_glyph_path (cairo_atsui_font_t *scaled_font,
}
err = ATSUGlyphGetCubicPaths(scaled_font->style,
_cairo_scaled_glyph_index (scaled_glyph),
theGlyph,
moveProc,
lineProc,
curveProc,
@ -691,7 +673,7 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font,
cairo_scaled_font_t base = scaled_font->base;
cairo_font_extents_t extents = base.extents;
GlyphID theGlyph = _cairo_scaled_glyph_index (scaled_glyph);
GlyphID theGlyph = _cairo_atsui_scaled_glyph_index (scaled_glyph);
ATSGlyphScreenMetrics metricsH;
double left, bottom, width, height;
double xscale, yscale;
@ -699,6 +681,16 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font,
CGAffineTransform transform;
if (theGlyph == kATSDeletedGlyphcode) {
surface = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2);
if (!surface)
return CAIRO_STATUS_NO_MEMORY;
_cairo_scaled_glyph_set_surface (scaled_glyph,
&base,
surface);
return CAIRO_STATUS_SUCCESS;
}
/* Compute a box to contain the glyph mask. The vertical
* sizes come from the font extents; extra pixels are
* added to account for fractional sizes.
@ -754,10 +746,23 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font,
if (!surface)
return CAIRO_STATUS_NO_MEMORY;
drawingContext = CGBitmapContextCreateWithCairoImageSurface (surface);
/* Create a CGBitmapContext for the dest surface for drawing into */
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray ();
drawingContext = CGBitmapContextCreate (surface->data,
surface->width,
surface->height,
8,
surface->stride,
colorSpace,
kCGImageAlphaNone);
CGColorSpaceRelease (colorSpace);
}
if (!drawingContext) {
cairo_surface_destroy ((cairo_surface_t *)surface);
return CAIRO_INT_STATUS_UNSUPPORTED;
return CAIRO_STATUS_NO_MEMORY;
}
atsFont = FMGetATSFontRefFromFont (scaled_font->fontID);
@ -839,6 +844,9 @@ _cairo_atsui_font_text_to_glyphs (void *abstract_font,
cairo_atsui_font_t *font = abstract_font;
ItemCount glyphCount;
int i;
CGPoint point;
double xscale, yscale;
CGAffineTransform device_to_user_scale;
status = _cairo_utf8_to_utf16 ((unsigned char *)utf8, -1, &utf16, &n16);
if (status)
@ -865,9 +873,18 @@ _cairo_atsui_font_text_to_glyphs (void *abstract_font,
return CAIRO_STATUS_NO_MEMORY;
}
_cairo_matrix_compute_scale_factors (&font->base.ctm, &xscale, &yscale, 1);
device_to_user_scale =
CGAffineTransformInvert (CGAffineTransformMake (xscale, 0,
0, yscale,
0, 0));
for (i = 0; i < *num_glyphs; i++) {
(*glyphs)[i].index = layoutRecords[i].glyphID;
(*glyphs)[i].x = x + FixedToFloat(layoutRecords[i].realPos);
/* ATSLayoutRecord.realPos is in device units, convert to user units */
point = CGPointMake (FixedToFloat (layoutRecords[i].realPos), 0);
point = CGPointApplyAffineTransform (point, device_to_user_scale);
(*glyphs)[i].x = x + point.x;
(*glyphs)[i].y = y;
}
@ -881,158 +898,6 @@ _cairo_atsui_font_text_to_glyphs (void *abstract_font,
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_atsui_font_old_show_glyphs (void *abstract_font,
cairo_operator_t op,
cairo_pattern_t *pattern,
cairo_surface_t *generic_surface,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs)
{
cairo_atsui_font_t *font = abstract_font;
CGContextRef drawingContext;
cairo_image_surface_t *destImageSurface;
int i;
void *extra = NULL;
cairo_bool_t can_draw_directly;
cairo_rectangle_int16_t rect;
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *)generic_surface;
ATSFontRef atsFont;
CGFontRef cgFont;
CGAffineTransform textTransform;
if (!_cairo_surface_is_quartz (generic_surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
/* Check if we can draw directly to the destination surface */
can_draw_directly = _cairo_pattern_is_opaque_solid (pattern) &&
op == CAIRO_OPERATOR_OVER;
if (!can_draw_directly) {
rect.x = dest_x;
rect.y = dest_y;
rect.width = width;
rect.height = height;
_cairo_surface_acquire_dest_image(generic_surface,
&rect,
&destImageSurface,
&rect,
&extra);
drawingContext = CGBitmapContextCreateWithCairoImageSurface (destImageSurface);
if (!drawingContext)
return CAIRO_INT_STATUS_UNSUPPORTED;
CGContextTranslateCTM(drawingContext, 0, destImageSurface->height);
CGContextScaleCTM(drawingContext, 1.0f, -1.0f);
} else {
drawingContext = ((cairo_quartz_surface_t *)generic_surface)->context;
CGContextSaveGState (drawingContext);
}
atsFont = FMGetATSFontRefFromFont(font->fontID);
cgFont = CGFontCreateWithPlatformFont(&atsFont);
CGContextSetFont(drawingContext, cgFont);
if (font->base.options.antialias == CAIRO_ANTIALIAS_NONE) {
CGContextSetShouldAntialias (drawingContext, false);
}
textTransform = CGAffineTransformMakeWithCairoFontScale(&font->base.scale);
textTransform = CGAffineTransformScale(textTransform, 1.0f, -1.0f);
CGContextSetFontSize(drawingContext, 1.0);
CGContextSetTextMatrix(drawingContext, textTransform);
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID &&
_cairo_pattern_is_opaque_solid(pattern))
{
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *)pattern;
CGContextSetRGBFillColor(drawingContext,
solid->color.red,
solid->color.green,
solid->color.blue, 1.0f);
} else {
CGContextSetRGBFillColor(drawingContext, 0.0f, 0.0f, 0.0f, 0.0f);
}
if (surface->clip_region) {
pixman_box16_t *boxes = pixman_region_rects (surface->clip_region);
int num_boxes = pixman_region_num_rects (surface->clip_region);
CGRect stack_rects[10];
CGRect *rects;
int i;
/* XXX: Return-value of malloc needs to be checked for
* NULL. Can someone fix this who is more familiar with
* the cleanup needed in this function?
*/
if (num_boxes > 10)
rects = malloc (sizeof (CGRect) * num_boxes);
else
rects = stack_rects;
for (i = 0; i < num_boxes; i++) {
rects[i].origin.x = boxes[i].x1;
rects[i].origin.y = boxes[i].y1;
rects[i].size.width = boxes[i].x2 - boxes[i].x1;
rects[i].size.height = boxes[i].y2 - boxes[i].y1;
}
CGContextClipToRects (drawingContext, rects, num_boxes);
if (rects != stack_rects)
free(rects);
}
/* TODO - bold and italic text
*
* We could draw the text using ATSUI and get bold, italics
* etc. for free, but ATSUI does a lot of text layout work
* that we don't really need...
*/
for (i = 0; i < num_glyphs; i++) {
CGGlyph theGlyph = glyphs[i].index;
/* round glyph locations to the nearest pixel */
/* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
CGContextShowGlyphsAtPoint(drawingContext,
_cairo_lround (glyphs[i].x),
_cairo_lround (glyphs[i].y),
&theGlyph, 1);
}
if (!can_draw_directly) {
CGContextRelease(drawingContext);
_cairo_surface_release_dest_image(generic_surface,
&rect,
destImageSurface,
&rect,
extra);
} else {
CGContextRestoreGState (drawingContext);
}
return CAIRO_STATUS_SUCCESS;
}
cairo_bool_t
_cairo_scaled_font_is_atsui (cairo_scaled_font_t *sfont)
{
return (sfont->backend == &cairo_atsui_scaled_font_backend);
}
ATSUStyle
_cairo_atsui_scaled_font_get_atsu_style (cairo_scaled_font_t *sfont)
{
@ -1049,6 +914,30 @@ _cairo_atsui_scaled_font_get_atsu_font_id (cairo_scaled_font_t *sfont)
return afont->fontID;
}
static cairo_int_status_t
_cairo_atsui_load_truetype_table (void *abstract_font,
unsigned long tag,
long offset,
unsigned char *buffer,
unsigned long *length)
{
cairo_atsui_font_t *scaled_font = abstract_font;
ATSFontRef atsFont;
OSStatus err;
atsFont = FMGetATSFontRefFromFont (scaled_font->fontID);
err = ATSFontGetTable ( atsFont, tag,
(ByteOffset) offset,
(ByteCount) *length,
buffer,
length);
if (err != noErr) {
return CAIRO_INT_STATUS_UNSUPPORTED;
}
return CAIRO_STATUS_SUCCESS;
}
const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend = {
CAIRO_FONT_TYPE_ATSUI,
_cairo_atsui_font_create_toy,
@ -1056,6 +945,8 @@ const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend = {
_cairo_atsui_font_scaled_glyph_init,
_cairo_atsui_font_text_to_glyphs,
NULL, /* ucs4_to_index */
_cairo_atsui_font_old_show_glyphs,
NULL, /* show_glyphs */
_cairo_atsui_load_truetype_table,
NULL, /* map_glyphs_to_unicode */
};

Просмотреть файл

@ -121,7 +121,7 @@ typedef struct _cairo_bo_event {
#define SKIP_ELT_TO_EVENT(elt) SKIP_LIST_ELT_TO_DATA (cairo_bo_event_t, (elt))
typedef struct _cairo_bo_event_queue {
skip_list_t intersection_queue;
cairo_skip_list_t intersection_queue;
cairo_bo_event_t *startstop_events;
cairo_bo_event_t **sorted_startstop_event_ptrs;
@ -129,9 +129,9 @@ typedef struct _cairo_bo_event_queue {
unsigned num_startstop_events;
} cairo_bo_event_queue_t;
/* This structure extends skip_list_t, which must come first. */
/* This structure extends cairo_skip_list_t, which must come first. */
typedef struct _cairo_bo_sweep_line {
skip_list_t active_edges;
cairo_skip_list_t active_edges;
cairo_bo_edge_t *head;
cairo_bo_edge_t *tail;
int32_t current_y;
@ -697,7 +697,7 @@ _cairo_bo_event_queue_insert (cairo_bo_event_queue_t *queue,
cairo_bo_event_t *event)
{
/* Don't insert if there's already an equivalent intersection event in the queue. */
skip_list_insert (&queue->intersection_queue, event,
_cairo_skip_list_insert (&queue->intersection_queue, event,
event->type == CAIRO_BO_EVENT_TYPE_INTERSECTION);
}
@ -706,7 +706,7 @@ _cairo_bo_event_queue_delete (cairo_bo_event_queue_t *queue,
cairo_bo_event_t *event)
{
if (CAIRO_BO_EVENT_TYPE_INTERSECTION == event->type)
skip_list_delete_given ( &queue->intersection_queue, &event->elt );
_cairo_skip_list_delete_given ( &queue->intersection_queue, &event->elt );
}
static cairo_bo_event_t *
@ -740,7 +740,7 @@ _cairo_bo_event_queue_init (cairo_bo_event_queue_t *event_queue,
memset (event_queue, 0, sizeof(*event_queue));
skip_list_init (&event_queue->intersection_queue,
_cairo_skip_list_init (&event_queue->intersection_queue,
cairo_bo_event_compare_abstract,
sizeof (cairo_bo_event_t));
if (0 == num_edges)
@ -789,7 +789,7 @@ _cairo_bo_event_queue_init (cairo_bo_event_queue_t *event_queue,
static void
_cairo_bo_event_queue_fini (cairo_bo_event_queue_t *event_queue)
{
skip_list_fini (&event_queue->intersection_queue);
_cairo_skip_list_fini (&event_queue->intersection_queue);
if (event_queue->startstop_events)
free (event_queue->startstop_events);
if (event_queue->sorted_startstop_event_ptrs)
@ -834,7 +834,7 @@ _cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_
static void
_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line)
{
skip_list_init (&sweep_line->active_edges,
_cairo_skip_list_init (&sweep_line->active_edges,
_sweep_line_elt_compare,
sizeof (sweep_line_elt_t));
sweep_line->head = NULL;
@ -845,7 +845,7 @@ _cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line)
static void
_cairo_bo_sweep_line_fini (cairo_bo_sweep_line_t *sweep_line)
{
skip_list_fini (&sweep_line->active_edges);
_cairo_skip_list_fini (&sweep_line->active_edges);
}
static void
@ -856,7 +856,7 @@ _cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line,
sweep_line_elt_t *sweep_line_elt;
cairo_bo_edge_t **prev_of_next, **next_of_prev;
sweep_line_elt = skip_list_insert (&sweep_line->active_edges, &edge,
sweep_line_elt = _cairo_skip_list_insert (&sweep_line->active_edges, &edge,
1 /* unique inserts*/);
next_elt = sweep_line_elt->elt.next[0];
@ -884,7 +884,7 @@ _cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line,
{
cairo_bo_edge_t **left_next, **right_prev;
skip_list_delete_given (&sweep_line->active_edges, &edge->sweep_line_elt->elt);
_cairo_skip_list_delete_given (&sweep_line->active_edges, &edge->sweep_line_elt->elt);
left_next = &sweep_line->head;
if (edge->prev)
@ -975,7 +975,7 @@ _cairo_bo_event_queue_print (cairo_bo_event_queue_t *event_queue)
{
skip_elt_t *elt;
/* XXX: fixme to print the start/stop array too. */
skip_list_t *queue = &event_queue->intersection_queue;
cairo_skip_list_t *queue = &event_queue->intersection_queue;
cairo_bo_event_t *event;
printf ("Event queue:\n");
@ -1767,7 +1767,7 @@ int
main (void)
{
char random_name[] = "random-XX";
static cairo_bo_edge_t random_edges[MAX_RANDOM], *edge;
cairo_bo_edge_t random_edges[MAX_RANDOM], *edge;
unsigned int i, num_random;
test_t *test;

Просмотреть файл

@ -31,6 +31,7 @@
*
* Contributor(s):
* Adrian Johnson <ajohnson@redneon.com>
* Eugeniy Meshcheryakov <eugen@debian.org>
*/
#include "cairoint.h"
@ -81,6 +82,13 @@ typedef struct _cff_dict_operator {
int operand_offset;
} cff_dict_operator_t;
typedef struct _cff_charset {
cairo_bool_t is_builtin;
const uint16_t *sids;
const unsigned char *data;
int length;
} cff_charset_t;
typedef struct _cairo_cff_font {
cairo_scaled_font_subset_t *scaled_font_subset;
@ -100,11 +108,14 @@ typedef struct _cairo_cff_font {
cairo_array_t global_sub_index;
cairo_array_t local_sub_index;
int num_glyphs;
cff_charset_t charset;
int charset_offset;
/* Subsetted Font Data */
char *subset_font_name;
cairo_array_t charstrings_subset_index;
cairo_array_t strings_subset_index;
cairo_array_t charset_subset;
cairo_array_t output;
/* Subset Metrics */
@ -114,34 +125,6 @@ typedef struct _cairo_cff_font {
} cairo_cff_font_t;
#ifdef WORDS_BIGENDIAN
#define cpu_to_be16(v) (v)
#define be16_to_cpu(v) (v)
#define cpu_to_be32(v) (v)
#else
static inline uint16_t
cpu_to_be16(uint16_t v)
{
return (v << 8) | (v >> 8);
}
static inline uint16_t
be16_to_cpu(uint16_t v)
{
return cpu_to_be16 (v);
}
static inline uint32_t
cpu_to_be32(uint32_t v)
{
return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16);
}
#endif
/* Encoded integer using maximum sized encoding. This is required for
* operands that are later modified after encoding. */
static unsigned char *
@ -505,20 +488,6 @@ fail:
return status;
}
static void
cff_dict_remove (cairo_hash_table_t *dict, unsigned short operator)
{
cff_dict_operator_t key, *op;
_cairo_dict_init_key (&key, operator);
if (_cairo_hash_table_lookup (dict, &key.base,
(cairo_hash_entry_t **) &op))
{
free (op->operand);
_cairo_hash_table_remove (dict, (cairo_hash_entry_t *) op);
}
}
static unsigned char *
cff_dict_get_operands (cairo_hash_table_t *dict,
unsigned short operator,
@ -742,12 +711,19 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
decode_integer (operand, &offset);
cairo_cff_font_read_private_dict (font, font->data + offset, size);
cff_dict_remove (font->top_dict, CHARSET_OP);
operand = cff_dict_get_operands (font->top_dict, CHARSET_OP, &size);
if (!operand)
font->charset_offset = 0;
else {
decode_integer (operand, &offset);
font->charset_offset = offset;
}
/* Use maximum sized encoding to reserve space for later modification. */
end_buf = encode_integer_max (buf, 0);
cff_dict_set_operands (font->top_dict, CHARSTRINGS_OP, buf, end_buf - buf);
cff_dict_set_operands (font->top_dict, ENCODING_OP, buf, end_buf - buf);
cff_dict_set_operands (font->top_dict, CHARSET_OP, buf, end_buf - buf);
/* Private has two operands - size and offset */
end_buf = encode_integer_max (end_buf, 0);
cff_dict_set_operands (font->top_dict, PRIVATE_OP, buf, end_buf - buf);
@ -770,6 +746,138 @@ cairo_cff_font_read_global_subroutines (cairo_cff_font_t *font)
return cff_index_read (&font->global_sub_index, &font->current_ptr, font->data_end);
}
static cairo_int_status_t
cff_charset_read_data (cff_charset_t *charset, const unsigned char *data,
const unsigned char *data_end, int num_glyphs)
{
const unsigned char *p = data;
num_glyphs -= 1; /* do not count .notdef */
if (p + 1 > data_end)
return CAIRO_INT_STATUS_UNSUPPORTED;
switch (*p++) {
case 0:
if (p + num_glyphs*2 > data_end)
return CAIRO_INT_STATUS_UNSUPPORTED;
charset->is_builtin = FALSE;
charset->data = data;
charset->length = num_glyphs * 2 + 1;
break;
case 1:
while (num_glyphs > 0) {
if (p + 3 > data_end)
return CAIRO_INT_STATUS_UNSUPPORTED;
num_glyphs -= p[2] + 1;
p += 3;
}
if (num_glyphs < 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
charset->is_builtin = FALSE;
charset->data = data;
charset->length = p - data;
break;
case 2:
while (num_glyphs > 0) {
if (p + 4 > data_end)
return CAIRO_INT_STATUS_UNSUPPORTED;
num_glyphs -= be16_to_cpu(*(uint16_t *)(p + 2)) + 1;
p += 4;
}
if (num_glyphs < 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
charset->is_builtin = FALSE;
charset->data = data;
charset->length = p - data;
break;
default:
return CAIRO_INT_STATUS_UNSUPPORTED;
}
return CAIRO_STATUS_SUCCESS;
}
static const uint16_t ISOAdobe_charset[] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
222, 223, 224, 225, 226, 227, 228,
};
static const uint16_t Expert_charset[] = {
1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13,
14, 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, 247,
248, 27, 28, 249, 250, 251, 252, 253, 254, 255, 256, 257,
258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110,
267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277,
278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288,
289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299,
300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310,
311, 312, 313, 314, 315, 316, 317, 318, 158, 155, 163,
319, 320, 321, 322, 323, 324, 325, 326, 150, 164, 169,
327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337,
338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348,
349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359,
360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370,
371, 372, 373, 374, 375, 376, 377, 378,
};
static const uint16_t ExpertSubset_charset[] = {
1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240,
241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250,
251, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262,
263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 272,
300, 301, 302, 305, 314, 315, 158, 155, 163, 320, 321,
322, 323, 324, 325, 326, 150, 164, 169, 327, 328, 329,
330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340,
341, 342, 343, 344, 345, 346,
};
static cairo_int_status_t
cairo_cff_font_read_charset (cairo_cff_font_t *font)
{
switch (font->charset_offset) {
case 0:
/* ISOAdobe charset */
font->charset.is_builtin = TRUE;
font->charset.sids = ISOAdobe_charset;
font->charset.length = sizeof (ISOAdobe_charset);
return CAIRO_STATUS_SUCCESS;
case 1:
/* Expert charset */
font->charset.is_builtin = TRUE;
font->charset.sids = Expert_charset;
font->charset.length = sizeof (Expert_charset);
return CAIRO_STATUS_SUCCESS;
case 2:
/* ExpertSubset charset */;
font->charset.is_builtin = TRUE;
font->charset.sids = ExpertSubset_charset;
font->charset.length = sizeof (ExpertSubset_charset);
return CAIRO_STATUS_SUCCESS;
default:
break;
}
return cff_charset_read_data (&font->charset, font->data + (unsigned)font->charset_offset,
font->data_end, font->num_glyphs);
}
typedef cairo_int_status_t
(*font_read_t) (cairo_cff_font_t *font);
@ -779,6 +887,8 @@ static const font_read_t font_read_funcs[] = {
cairo_cff_font_read_top_dict,
cairo_cff_font_read_strings,
cairo_cff_font_read_global_subroutines,
/* non-contiguous */
cairo_cff_font_read_charset,
};
static cairo_int_status_t
@ -898,6 +1008,80 @@ cairo_cff_font_subset_charstrings (cairo_cff_font_t *font)
return CAIRO_STATUS_SUCCESS;
}
static uint16_t
cff_sid_from_gid (const cff_charset_t *charset, int gid)
{
const uint16_t *sids;
const unsigned char *p;
int prev_glyph;
if (charset->is_builtin) {
if (gid - 1 < charset->length / 2)
return charset->sids[gid - 1];
}
else {
/* no need to check sizes here, this was done during reading */
switch (charset->data[0]) {
case 0:
sids = (const uint16_t *)(charset->data + 1);
return be16_to_cpu(sids[gid - 1]);
case 1:
prev_glyph = 1;
for (p = charset->data + 1; p < charset->data + charset->length; p += 3) {
if (gid <= prev_glyph + p[2]) {
uint16_t sid = be16_to_cpu(*(const uint16_t *)p);
return sid + gid - prev_glyph;
}
prev_glyph += p[2] + 1;
}
break;
case 2:
prev_glyph = 1;
for (p = charset->data + 1; p < charset->data + charset->length; p += 4) {
uint16_t nLeft = be16_to_cpu(*(const uint16_t *)(p + 2));
if (gid <= prev_glyph + nLeft) {
uint16_t sid = be16_to_cpu(*(const uint16_t *)p);
return sid + gid - prev_glyph;
}
prev_glyph += nLeft + 1;
}
break;
default:
break;
}
}
return 0;
}
static cairo_status_t
cairo_cff_font_subset_charset (cairo_cff_font_t *font)
{
unsigned int i;
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
int gid = font->scaled_font_subset->glyphs[i];
uint16_t original_sid = cff_sid_from_gid(&font->charset, gid);
uint16_t new_sid;
cff_index_element_t *element;
cairo_status_t status;
if (original_sid >= NUM_STD_STRINGS) {
element = _cairo_array_index (&font->strings_index, original_sid - NUM_STD_STRINGS);
new_sid = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
status = cff_index_append (&font->strings_subset_index, element->data, element->length);
if (status)
return status;
}
else
new_sid = original_sid;
status = _cairo_array_append(&font->charset_subset, &new_sid);
if (status)
return status;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
cairo_cff_font_subset_font (cairo_cff_font_t *font)
{
@ -910,6 +1094,10 @@ cairo_cff_font_subset_font (cairo_cff_font_t *font)
return status;
status = cairo_cff_font_subset_charstrings (font);
if (status)
return status;
status = cairo_cff_font_subset_charset (font);
return status;
}
@ -1038,6 +1226,27 @@ cairo_cff_font_write_encoding (cairo_cff_font_t *font)
return _cairo_array_append_multiple (&font->output, buf, 4);
}
static cairo_status_t
cairo_cff_font_write_charset (cairo_cff_font_t *font)
{
unsigned char format = 0;
unsigned int i;
cairo_status_t status;
cairo_cff_font_set_topdict_operator_to_cur_pos (font, CHARSET_OP);
status = _cairo_array_append (&font->output, &format);
if (status)
return status;
for (i = 0; i < (unsigned)_cairo_array_num_elements(&font->charset_subset); i++) {
uint16_t sid = cpu_to_be16(*(uint16_t *)_cairo_array_index(&font->charset_subset, i));
status = _cairo_array_append_multiple (&font->output, &sid, sizeof(sid));
if (status)
return status;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
cairo_cff_font_write_charstrings (cairo_cff_font_t *font)
{
@ -1098,6 +1307,7 @@ static const font_write_t font_write_funcs[] = {
cairo_cff_font_write_strings,
cairo_cff_font_write_global_subrs,
cairo_cff_font_write_encoding,
cairo_cff_font_write_charset,
cairo_cff_font_write_charstrings,
cairo_cff_font_write_private_dict_and_local_sub,
};
@ -1345,6 +1555,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
cff_index_init (&font->local_sub_index);
cff_index_init (&font->charstrings_subset_index);
cff_index_init (&font->strings_subset_index);
_cairo_array_init (&font->charset_subset, sizeof(uint16_t));
free (name);
*font_return = font;
@ -1383,6 +1594,7 @@ cairo_cff_font_destroy (cairo_cff_font_t *font)
cff_index_fini (&font->local_sub_index);
cff_index_fini (&font->charstrings_subset_index);
cff_index_fini (&font->strings_subset_index);
_cairo_array_fini (&font->charset_subset);
free (font);
}

Просмотреть файл

@ -48,7 +48,10 @@ _cairo_clip_path_destroy (cairo_clip_path_t *clip_path);
void
_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target)
{
clip->mode = _cairo_surface_get_clip_mode (target);
if (target)
clip->mode = _cairo_surface_get_clip_mode (target);
else
clip->mode = CAIRO_CLIP_MODE_MASK;
clip->surface = NULL;
clip->surface_rect.x = 0;

Просмотреть файл

@ -95,7 +95,8 @@ _cairo_color_init_rgb (cairo_color_t *color,
* then special-casing the result of an input value of 1.0 so that it
* maps to 65535 instead of 65536.
*/
static inline uint16_t _color_to_short (double d)
uint16_t
_cairo_color_double_to_short (double d)
{
uint32_t i;
i = (uint32_t) (d * 65536);
@ -106,10 +107,10 @@ static inline uint16_t _color_to_short (double d)
static void
_cairo_color_compute_shorts (cairo_color_t *color)
{
color->red_short = _color_to_short (color->red * color->alpha);
color->green_short = _color_to_short (color->green * color->alpha);
color->blue_short = _color_to_short (color->blue * color->alpha);
color->alpha_short = _color_to_short (color->alpha);
color->red_short = _cairo_color_double_to_short (color->red * color->alpha);
color->green_short = _cairo_color_double_to_short (color->green * color->alpha);
color->blue_short = _cairo_color_double_to_short (color->blue * color->alpha);
color->alpha_short = _cairo_color_double_to_short (color->alpha);
}
void

Просмотреть файл

@ -52,9 +52,9 @@
/*
* Rectangle works fine.
* Rectangle causes problems (see bugs 361377, 359553, 359243 in Gnome BTS).
*/
#define DFB_RECTANGLES 1
#define DFB_RECTANGLES 0
/*
* Composite works fine.

Просмотреть файл

@ -48,5 +48,8 @@ cairo_directfb_surface_create (IDirectFB *dfb,IDirectFBSurface *surface);
CAIRO_END_DECLS
#else /*CAIRO_HAS_DIRECTFB_SURFACE*/
# error Cairo was not compiled with support for the directfb backend
#endif /*CAIRO_HAS_DIRECTFB_SURFACE*/
#endif /*CAIRO_DIRECTFB_H*/

Просмотреть файл

@ -52,10 +52,10 @@
#endif
#define CAIRO_VERSION_MAJOR 1
#define CAIRO_VERSION_MINOR 3
#define CAIRO_VERSION_MICRO 12
#define CAIRO_VERSION_MINOR 4
#define CAIRO_VERSION_MICRO 2
#define CAIRO_VERSION_STRING "1.3.12"
#define CAIRO_VERSION_STRING "1.4.2"
@PS_SURFACE_FEATURE@
@ -67,8 +67,6 @@
@QUARTZ_SURFACE_FEATURE@
@NQUARTZ_SURFACE_FEATURE@
@XCB_SURFACE_FEATURE@
@WIN32_SURFACE_FEATURE@

Просмотреть файл

@ -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 © 2002 University of Southern California
@ -65,32 +66,40 @@ _cairo_font_face_init (cairo_font_face_t *font_face,
_cairo_user_data_array_init (&font_face->user_data);
}
/* This mutex protects both cairo_toy_font_hash_table as well as
reference count manipulations for all cairo_font_face_t. */
CAIRO_MUTEX_DECLARE (_cairo_font_face_mutex);
/**
* cairo_font_face_reference:
* @font_face: a #cairo_font_face_t, (may be NULL in which case this
* @font_face: a #cairo_font_face_t, (may be %NULL in which case this
* function does nothing).
*
* Increases the reference count on @font_face by one. This prevents
* @font_face from being destroyed until a matching call to
* cairo_font_face_destroy() is made.
*
* The number of references to a #cairo_font_face_t can be get using
* cairo_font_face_get_reference_count().
*
* Return value: the referenced #cairo_font_face_t.
**/
cairo_font_face_t *
cairo_font_face_reference (cairo_font_face_t *font_face)
{
if (font_face == NULL)
return NULL;
if (font_face->ref_count == CAIRO_REF_COUNT_INVALID)
if (font_face == NULL || font_face->ref_count == CAIRO_REF_COUNT_INVALID)
return font_face;
CAIRO_MUTEX_LOCK (_cairo_font_face_mutex);
/* We would normally assert (font_face->ref_count >0) here but we
* can't get away with that due to the zombie case as documented
* in _cairo_ft_font_face_destroy. */
font_face->ref_count++;
CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
return font_face;
}
slim_hidden_def (cairo_font_face_reference);
@ -106,16 +115,19 @@ slim_hidden_def (cairo_font_face_reference);
void
cairo_font_face_destroy (cairo_font_face_t *font_face)
{
if (font_face == NULL)
if (font_face == NULL || font_face->ref_count == CAIRO_REF_COUNT_INVALID)
return;
if (font_face->ref_count == CAIRO_REF_COUNT_INVALID)
return;
CAIRO_MUTEX_LOCK (_cairo_font_face_mutex);
assert (font_face->ref_count > 0);
if (--(font_face->ref_count) > 0)
if (--(font_face->ref_count) > 0) {
CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
return;
}
CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
font_face->backend->destroy (font_face);
@ -134,7 +146,7 @@ slim_hidden_def (cairo_font_face_destroy);
/**
* cairo_font_face_get_type:
* @font_face: a #cairo_font_face_t
* @font_face: a font face
*
* This function returns the type of the backend used to create
* a font face. See #cairo_font_type_t for available types.
@ -149,6 +161,26 @@ cairo_font_face_get_type (cairo_font_face_t *font_face)
return font_face->backend->type;
}
/**
* cairo_font_face_get_reference_count:
* @font_face: a #cairo_font_face_t
*
* Returns the current reference count of @font_face.
*
* Return value: the current reference count of @font_face. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.4
**/
unsigned int
cairo_font_face_get_reference_count (cairo_font_face_t *font_face)
{
if (font_face == NULL || font_face->ref_count == CAIRO_REF_COUNT_INVALID)
return 0;
return font_face->ref_count;
}
/**
* cairo_font_face_status:
* @font_face: a #cairo_font_face_t
@ -226,16 +258,16 @@ _cairo_toy_font_face_keys_equal (const void *key_a,
* our cache and mapping from cairo_font_face_t => cairo_scaled_font_t
* works. Once the corresponding cairo_font_face_t objects fall out of
* downstream caches, we don't need them in this hash table anymore.
*
* Modifications to this hash table are protected by
* _cairo_font_face_mutex.
*/
static cairo_hash_table_t *cairo_toy_font_face_hash_table = NULL;
CAIRO_MUTEX_DECLARE (cairo_toy_font_face_hash_table_mutex);
static cairo_hash_table_t *
_cairo_toy_font_face_hash_table_lock (void)
{
CAIRO_MUTEX_LOCK (cairo_toy_font_face_hash_table_mutex);
CAIRO_MUTEX_LOCK (_cairo_font_face_mutex);
if (cairo_toy_font_face_hash_table == NULL)
{
@ -243,7 +275,7 @@ _cairo_toy_font_face_hash_table_lock (void)
_cairo_hash_table_create (_cairo_toy_font_face_keys_equal);
if (cairo_toy_font_face_hash_table == NULL) {
CAIRO_MUTEX_UNLOCK (cairo_toy_font_face_hash_table_mutex);
CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
return NULL;
}
}
@ -254,7 +286,7 @@ _cairo_toy_font_face_hash_table_lock (void)
static void
_cairo_toy_font_face_hash_table_unlock (void)
{
CAIRO_MUTEX_UNLOCK (cairo_toy_font_face_hash_table_mutex);
CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
}
/**
@ -363,8 +395,11 @@ _cairo_toy_font_face_create (const char *family,
&key.base.hash_entry,
(cairo_hash_entry_t **) &font_face))
{
/* We increment the reference count here manually to avoid
double-locking. */
font_face->base.ref_count++;
_cairo_toy_font_face_hash_table_unlock ();
return cairo_font_face_reference (&font_face->base);
return &font_face->base;
}
/* Otherwise create it and insert into hash table. */
@ -471,8 +506,11 @@ _cairo_font_reset_static_data (void)
{
_cairo_scaled_font_map_destroy ();
CAIRO_MUTEX_LOCK (cairo_toy_font_face_hash_table_mutex);
/* We manually acquire the lock rather than calling
* cairo_toy_font_face_hash_table_lock simply to avoid
* creating the table only to destroy it again. */
CAIRO_MUTEX_LOCK (_cairo_font_face_mutex);
_cairo_hash_table_destroy (cairo_toy_font_face_hash_table);
cairo_toy_font_face_hash_table = NULL;
CAIRO_MUTEX_UNLOCK (cairo_toy_font_face_hash_table_mutex);
CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
}

Просмотреть файл

@ -62,9 +62,11 @@
*/
#define MAX_OPEN_FACES 10
#ifndef MOZILLA_CAIRO_NOT_DEFINED
/* This is the maximum font size we allow to be passed to FT_Set_Char_Size
*/
#define MAX_FONT_SIZE 1000
#endif /* !MOZILLA_CAIRO_NOT_DEFINED */
/*
* The simple 2x2 matrix is converted into separate scale and shape
@ -104,7 +106,8 @@ struct _cairo_ft_unscaled_font {
cairo_matrix_t current_shape;
FT_Matrix Current_Shape;
int lock; /* count of how many times this font has been locked */
cairo_mutex_t mutex;
int lock_count;
cairo_ft_font_face_t *faces; /* Linked list of faces for this font */
};
@ -153,7 +156,7 @@ typedef struct _cairo_ft_unscaled_font_map {
static cairo_ft_unscaled_font_map_t *cairo_ft_unscaled_font_map = NULL;
CAIRO_MUTEX_DECLARE(cairo_ft_unscaled_font_map_mutex);
CAIRO_MUTEX_DECLARE(_cairo_ft_unscaled_font_map_mutex);
static void
_font_map_release_face_lock_held (cairo_ft_unscaled_font_map_t *font_map,
@ -211,7 +214,7 @@ _cairo_ft_unscaled_font_map_destroy (void)
cairo_ft_unscaled_font_t *unscaled;
cairo_ft_unscaled_font_map_t *font_map;
CAIRO_MUTEX_LOCK (cairo_ft_unscaled_font_map_mutex);
CAIRO_MUTEX_LOCK (_cairo_ft_unscaled_font_map_mutex);
if (cairo_ft_unscaled_font_map) {
font_map = cairo_ft_unscaled_font_map;
@ -244,20 +247,20 @@ _cairo_ft_unscaled_font_map_destroy (void)
cairo_ft_unscaled_font_map = NULL;
}
CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex);
CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex);
}
static cairo_ft_unscaled_font_map_t *
_cairo_ft_unscaled_font_map_lock (void)
{
CAIRO_MUTEX_LOCK (cairo_ft_unscaled_font_map_mutex);
CAIRO_MUTEX_LOCK (_cairo_ft_unscaled_font_map_mutex);
if (cairo_ft_unscaled_font_map == NULL)
{
_cairo_ft_unscaled_font_map_create ();
if (cairo_ft_unscaled_font_map == NULL) {
CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex);
CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex);
return NULL;
}
}
@ -268,7 +271,7 @@ _cairo_ft_unscaled_font_map_lock (void)
static void
_cairo_ft_unscaled_font_map_unlock (void)
{
CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex);
CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex);
}
static void
@ -337,7 +340,8 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
}
unscaled->have_scale = FALSE;
unscaled->lock = 0;
CAIRO_MUTEX_INIT (&unscaled->mutex);
unscaled->lock_count = 0;
unscaled->faces = NULL;
@ -370,6 +374,8 @@ _cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled)
free (unscaled->filename);
unscaled->filename = NULL;
}
CAIRO_MUTEX_FINI (&unscaled->mutex);
}
static int
@ -501,7 +507,7 @@ _has_unlocked_face (void *entry)
{
cairo_ft_unscaled_font_t *unscaled = entry;
return (unscaled->lock == 0 && unscaled->face);
return (unscaled->lock_count == 0 && unscaled->face);
}
/* Ensures that an unscaled font has a face object. If we exceed
@ -516,44 +522,47 @@ _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled)
cairo_ft_unscaled_font_map_t *font_map;
FT_Face face = NULL;
if (unscaled->face) {
unscaled->lock++;
CAIRO_MUTEX_LOCK (unscaled->mutex);
unscaled->lock_count++;
if (unscaled->face)
return unscaled->face;
}
/* If this unscaled font was created from an FT_Face then we just
* returned it above. */
assert (!unscaled->from_face);
font_map = _cairo_ft_unscaled_font_map_lock ();
assert (font_map != NULL);
while (font_map->num_open_faces >= MAX_OPEN_FACES)
{
cairo_ft_unscaled_font_t *entry;
assert (font_map != NULL);
entry = _cairo_hash_table_random_entry (font_map->hash_table,
_has_unlocked_face);
if (entry == NULL)
break;
while (font_map->num_open_faces >= MAX_OPEN_FACES)
{
cairo_ft_unscaled_font_t *entry;
_font_map_release_face_lock_held (font_map, entry);
entry = _cairo_hash_table_random_entry (font_map->hash_table,
_has_unlocked_face);
if (entry == NULL)
break;
_font_map_release_face_lock_held (font_map, entry);
}
}
_cairo_ft_unscaled_font_map_unlock ();
if (FT_New_Face (font_map->ft_library,
unscaled->filename,
unscaled->id,
&face) != FT_Err_Ok)
goto FAIL;
{
CAIRO_MUTEX_UNLOCK (unscaled->mutex);
return NULL;
}
unscaled->face = face;
unscaled->lock++;
font_map->num_open_faces++;
FAIL:
_cairo_ft_unscaled_font_map_unlock ();
return face;
}
slim_hidden_def (cairo_ft_scaled_font_lock_face);
@ -563,9 +572,11 @@ slim_hidden_def (cairo_ft_scaled_font_lock_face);
void
_cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled)
{
assert (unscaled->lock > 0);
assert (unscaled->lock_count > 0);
unscaled->lock--;
unscaled->lock_count--;
CAIRO_MUTEX_UNLOCK (unscaled->mutex);
}
slim_hidden_def (cairo_ft_scaled_font_unlock_face);
@ -647,6 +658,7 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled,
FT_Set_Transform(unscaled->face, &mat, NULL);
if ((unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) != 0) {
#ifndef MOZILLA_CAIRO_NOT_DEFINED
double x_scale = sf.x_scale;
double y_scale = sf.y_scale;
if (x_scale > MAX_FONT_SIZE) {
@ -656,10 +668,16 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled,
y_scale = MAX_FONT_SIZE;
}
error = FT_Set_Char_Size (unscaled->face,
sf.x_scale * 64.0,
sf.y_scale * 64.0,
0, 0);
#else
error = FT_Set_Char_Size (unscaled->face,
x_scale * 64.0,
y_scale * 64.0,
0, 0);
#endif /* MOZCAIRO */
assert (error == 0);
} else {
double min_distance = DBL_MAX;
@ -1501,6 +1519,8 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled,
_cairo_scaled_font_set_metrics (&scaled_font->base, &fs_metrics);
_cairo_ft_unscaled_font_unlock_face (unscaled);
return &scaled_font->base;
}
@ -1780,10 +1800,13 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
cairo_bool_t vertical_layout = FALSE;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
face = cairo_ft_scaled_font_lock_face (abstract_font);
face = _cairo_ft_unscaled_font_lock_face (unscaled);
if (!face)
return CAIRO_STATUS_NO_MEMORY;
_cairo_ft_unscaled_font_set_scale (scaled_font->unscaled,
&scaled_font->base.scale);
/* Ignore global advance unconditionally */
load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
@ -1823,6 +1846,8 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
_cairo_ft_scaled_glyph_vertical_layout_bearing_fix (scaled_font, glyph);
if (info & CAIRO_SCALED_GLYPH_INFO_METRICS) {
cairo_bool_t hint_metrics = scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF;
/*
* Compute font-space metrics
*/
@ -1848,8 +1873,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
* FreeType, then we need to do the metric hinting ourselves.
*/
if ((scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) &&
(load_flags & FT_LOAD_NO_HINTING))
if (hint_metrics && (load_flags & FT_LOAD_NO_HINTING))
{
FT_Pos x1, x2;
FT_Pos y1, y2;
@ -1896,14 +1920,20 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) * x_factor;
fs_metrics.y_bearing = DOUBLE_FROM_26_6 (-metrics->horiBearingY) * y_factor;
fs_metrics.x_advance = DOUBLE_FROM_26_6 (metrics->horiAdvance) * x_factor;
if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE)
fs_metrics.x_advance = DOUBLE_FROM_26_6 (metrics->horiAdvance) * x_factor;
else
fs_metrics.x_advance = DOUBLE_FROM_16_16 (glyph->linearHoriAdvance) * x_factor;
fs_metrics.y_advance = 0 * y_factor;
} else {
fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingX) * x_factor;
fs_metrics.y_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingY) * y_factor;
fs_metrics.x_advance = 0 * x_factor;
fs_metrics.y_advance = DOUBLE_FROM_26_6 (metrics->vertAdvance) * y_factor;
if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE)
fs_metrics.y_advance = DOUBLE_FROM_26_6 (metrics->vertAdvance) * y_factor;
else
fs_metrics.y_advance = DOUBLE_FROM_26_6 (glyph->linearVertAdvance) * y_factor;
}
}
@ -1946,7 +1976,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
load_flags | FT_LOAD_NO_BITMAP);
if (error) {
cairo_ft_scaled_font_unlock_face (abstract_font);
_cairo_ft_unscaled_font_unlock_face (unscaled);
return CAIRO_STATUS_NO_MEMORY;
}
#if HAVE_FT_GLYPHSLOT_EMBOLDEN
@ -1974,7 +2004,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
path);
}
FAIL:
cairo_ft_scaled_font_unlock_face (abstract_font);
_cairo_ft_unscaled_font_unlock_face (unscaled);
return status;
}
@ -2026,6 +2056,38 @@ _cairo_ft_load_truetype_table (void *abstract_font,
return status;
}
static void
_cairo_ft_map_glyphs_to_unicode (void *abstract_font,
cairo_scaled_font_subset_t *font_subset)
{
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;
face = _cairo_ft_unscaled_font_lock_face (unscaled);
if (!face)
return;
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);
}
_cairo_ft_unscaled_font_unlock_face (unscaled);
}
const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = {
CAIRO_FONT_TYPE_FT,
_cairo_ft_scaled_font_create_toy,
@ -2035,6 +2097,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_font_face_t */
@ -2392,13 +2455,14 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face,
* of times.
*
* You must be careful when using this function in a library or in a
* threaded application, because other threads may lock faces that
* share the same #FT_Face object. For this reason, you must call
* cairo_ft_lock() before locking any face objects, and
* cairo_ft_unlock() after you are done. (These functions are not yet
* implemented, so this function cannot be currently safely used in a
* threaded application.)
* threaded application, because freetype's design makes it unsafe to
* call freetype functions simultaneously from multiple threads, (even
* if using distinct FT_Face objects). Because of this, application
* code that acquires an FT_Face object with this call must add it's
* own locking to protect any use of that object, (and which also must
* protect any other calls into cairo as almost any cairo function
* might result in a call into the freetype library).
*
* Return value: The #FT_Face object for @font, scaled appropriately,
* or %NULL if @scaled_font is in an error state (see
* cairo_scaled_font_status()) or there is insufficient memory.
@ -2421,6 +2485,14 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font)
_cairo_ft_unscaled_font_set_scale (scaled_font->unscaled,
&scaled_font->base.scale);
/* NOTE: We deliberately release the unscaled font's mutex here,
* so that we are not holding a lock across two separate calls to
* cairo function, (which would give the application some
* opportunity for creating deadlock. This is obviously unsafe,
* but as documented, the user must add manual locking when using
* this function. */
CAIRO_MUTEX_UNLOCK (scaled_font->unscaled->mutex);
return face;
}
@ -2441,6 +2513,12 @@ cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *abstract_font)
if (scaled_font->base.status)
return;
/* NOTE: We released the unscaled font's mutex at the end of
* cairo_ft_scaled_font_lock_face, so we have to acquire it again
* as _cairo_ft_unscaled_font_unlock_face expects it to be held
* when we call into it. */
CAIRO_MUTEX_LOCK (scaled_font->unscaled->mutex);
_cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled);
}

Просмотреть файл

@ -594,7 +594,7 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern,
unsigned int *pixels;
unsigned int i, n_base_params;
glitz_buffer_t *buffer;
static glitz_pixel_format_t format = {
static const glitz_pixel_format_t format = {
GLITZ_FOURCC_RGB,
{
32,
@ -686,12 +686,12 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern,
{
cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
params[0] = grad->gradient.inner.x;
params[1] = grad->gradient.inner.y;
params[2] = grad->gradient.inner.radius;
params[3] = grad->gradient.outer.x;
params[4] = grad->gradient.outer.y;
params[5] = grad->gradient.outer.radius;
params[0] = grad->gradient.c1.x;
params[1] = grad->gradient.c1.y;
params[2] = grad->gradient.c1.radius;
params[3] = grad->gradient.c2.x;
params[4] = grad->gradient.c2.y;
params[5] = grad->gradient.c2.radius;
attr->filter = GLITZ_FILTER_RADIAL_GRADIENT;
}
@ -976,7 +976,7 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
(glitz_rectangle_t *) rects, n_rects);
} break;
case CAIRO_OPERATOR_CLEAR: {
static glitz_color_t glitz_color = { 0, 0, 0, 0 };
static const glitz_color_t glitz_color = { 0, 0, 0, 0 };
glitz_set_rectangles (dst->surface, &glitz_color,
(glitz_rectangle_t *) rects, n_rects);
@ -1095,7 +1095,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
if (op == CAIRO_OPERATOR_ADD || n_traps <= 1)
{
static glitz_color_t clear_black = { 0, 0, 0, 0 };
static const glitz_color_t clear_black = { 0, 0, 0, 0 };
glitz_color_t color;
glitz_geometry_format_t format;
int n_trap_added;
@ -1941,7 +1941,7 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
int i, cached_glyphs = 0;
int remaining_glyps = num_glyphs;
glitz_float_t x1, y1, x2, y2;
static glitz_vertex_format_t format = {
static const glitz_vertex_format_t format = {
GLITZ_PRIMITIVE_QUADS,
GLITZ_DATA_TYPE_FLOAT,
sizeof (glitz_float_t) * 4,

Просмотреть файл

@ -42,16 +42,9 @@
#include "cairo-clip-private.h"
#include "cairo-gstate-private.h"
static cairo_status_t
_cairo_gstate_init (cairo_gstate_t *gstate,
cairo_surface_t *target);
static cairo_status_t
_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other);
static void
_cairo_gstate_fini (cairo_gstate_t *gstate);
static cairo_status_t
_cairo_gstate_ensure_font_face (cairo_gstate_t *gstate);
@ -67,40 +60,7 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
int num_glyphs,
cairo_glyph_t *transformed_glyphs);
/**
* _cairo_gstate_create:
* @target: a #cairo_surface_t, not NULL
*
* Create a new #cairo_gstate_t to draw to target with all graphics
* state parameters set to defaults. 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.
**/
cairo_gstate_t *
_cairo_gstate_create (cairo_surface_t *target)
{
cairo_status_t status;
cairo_gstate_t *gstate;
assert (target != NULL);
gstate = malloc (sizeof (cairo_gstate_t));
if (gstate == NULL)
return NULL;
status = _cairo_gstate_init (gstate, target);
if (status) {
free (gstate);
return NULL;
}
return gstate;
}
static cairo_status_t
cairo_status_t
_cairo_gstate_init (cairo_gstate_t *gstate,
cairo_surface_t *target)
{
@ -189,7 +149,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
return CAIRO_STATUS_SUCCESS;
}
static void
void
_cairo_gstate_fini (cairo_gstate_t *gstate)
{
_cairo_stroke_style_fini (&gstate->stroke_style);
@ -722,8 +682,8 @@ _cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
cairo_matrix_multiply (&matrix_inverse, &gstate->ctm_inverse,
&gstate->target->device_transform_inverse);
cairo_matrix_transform_bounding_box (&matrix_inverse,
x1, y1, x2, y2, is_tight);
_cairo_matrix_transform_bounding_box (&matrix_inverse,
x1, y1, x2, y2, is_tight);
}
/* XXX: NYI
@ -955,6 +915,11 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate,
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_traps_t traps;
if (gstate->stroke_style.line_width <= 0.0) {
*inside_ret = FALSE;
return CAIRO_STATUS_SUCCESS;
}
_cairo_gstate_user_to_backend (gstate, &x, &y);
_cairo_traps_init (&traps);
@ -1073,12 +1038,23 @@ _cairo_gstate_traps_extents_to_user_rectangle (cairo_gstate_t *gstate,
if (extents.p1.x >= extents.p2.x || extents.p1.y >= extents.p2.y) {
/* no traps, so we actually won't draw anything */
*x1 = *y1 = *x2 = *y2 = 0;
if (x1)
*x1 = 0.0;
if (y1)
*y1 = 0.0;
if (x2)
*x2 = 0.0;
if (y2)
*y2 = 0.0;
} else {
*x1 = _cairo_fixed_to_double (extents.p1.x);
*y1 = _cairo_fixed_to_double (extents.p1.y);
*x2 = _cairo_fixed_to_double (extents.p2.x);
*y2 = _cairo_fixed_to_double (extents.p2.y);
if (x1)
*x1 = _cairo_fixed_to_double (extents.p1.x);
if (y1)
*y1 = _cairo_fixed_to_double (extents.p1.y);
if (x2)
*x2 = _cairo_fixed_to_double (extents.p2.x);
if (y2)
*y2 = _cairo_fixed_to_double (extents.p2.y);
_cairo_gstate_backend_to_user_rectangle (gstate, x1, y1, x2, y2, NULL);
}
@ -1093,6 +1069,18 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
cairo_status_t status;
cairo_traps_t traps;
if (gstate->stroke_style.line_width <= 0.0) {
if (x1)
*x1 = 0.0;
if (y1)
*y1 = 0.0;
if (x2)
*x2 = 0.0;
if (y2)
*y2 = 0.0;
return CAIRO_STATUS_SUCCESS;
}
_cairo_traps_init (&traps);
status = _cairo_path_fixed_stroke_to_traps (path,
@ -1165,11 +1153,15 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate,
status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &extents);
if (status)
return status;
*x1 = extents.x;
*y1 = extents.y;
*x2 = extents.x + extents.width;
*y2 = extents.y + extents.height;
if (x1)
*x1 = extents.x;
if (y1)
*y1 = extents.y;
if (x2)
*x2 = extents.x + extents.width;
if (y2)
*y2 = extents.y + extents.height;
_cairo_gstate_backend_to_user_rectangle (gstate, x1, y1, x2, y2, NULL);
@ -1271,6 +1263,21 @@ _cairo_gstate_get_font_face (cairo_gstate_t *gstate,
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_gstate_get_scaled_font (cairo_gstate_t *gstate,
cairo_scaled_font_t **scaled_font)
{
cairo_status_t status;
status = _cairo_gstate_ensure_scaled_font (gstate);
if (status)
return status;
*scaled_font = gstate->scaled_font;
return CAIRO_STATUS_SUCCESS;
}
/*
* Like everything else in this file, fonts involve Too Many Coordinate Spaces;
* it is easy to get confused about what's going on.

Просмотреть файл

@ -1116,6 +1116,7 @@ _cairo_image_surface_clone (cairo_image_surface_t *surface,
cairo_image_surface_create (format,
surface->width, surface->height);
/* Use _cairo_surface_composite directly */
cr = cairo_create (&clone->base);
cairo_surface_get_device_offset (&surface->base, &x, &y);
cairo_set_source_surface (cr, &surface->base, x, y);

Просмотреть файл

@ -356,10 +356,10 @@ cairo_matrix_transform_point (const cairo_matrix_t *matrix, double *x, double *y
slim_hidden_def(cairo_matrix_transform_point);
void
cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double *x1, double *y1,
double *x2, double *y2,
cairo_bool_t *is_tight)
_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double *x1, double *y1,
double *x2, double *y2,
cairo_bool_t *is_tight)
{
int i;
double quad_x[4], quad_y[4];
@ -417,7 +417,6 @@ cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
quad_x[2] == quad_x[0] && quad_y[2] == quad_y[3]);
}
}
slim_hidden_def(cairo_matrix_transform_bounding_box);
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,80 +0,0 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006 Mozilla Corporation
*
* 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 Mozilla Corporation.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@mozilla.com>
*/
#ifndef CAIRO_NQUARTZ_H
#define CAIRO_NQUARTZ_H
#include <cairo.h>
#if CAIRO_HAS_NQUARTZ_SURFACE
#include <Carbon/Carbon.h>
#include <AGL/agl.h>
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_nquartz_surface_create (cairo_format_t format,
unsigned int width,
unsigned int height);
#ifdef CAIRO_NQUARTZ_SUPPORT_AGL
cairo_public cairo_surface_t *
cairo_nquartz_surface_create_for_agl_context (AGLContext aglContext,
unsigned int width,
unsigned int height,
cairo_bool_t y_grows_down);
#endif
cairo_public cairo_surface_t *
cairo_nquartz_surface_create_for_cg_context (CGContextRef cgContext,
unsigned int width,
unsigned int height,
cairo_bool_t y_grows_down);
cairo_public cairo_bool_t
cairo_surface_is_nquartz (cairo_surface_t *surf);
cairo_public CGContextRef
cairo_nquartz_surface_get_cg_context (cairo_surface_t *surf);
CAIRO_END_DECLS
#else /* CAIRO_HAS_NQUARTZ_SURFACE */
# error Cairo was not compiled with support for the nquartz backend
#endif /* CAIRO_HAS_NQUARTZ_SURFACE */
#endif /* CAIRO_NQUARTZ_H */

Просмотреть файл

@ -69,11 +69,11 @@
static int cairo_os2_initialization_count = 0;
/* The mutex semaphores Cairo uses all around: */
HMTX cairo_toy_font_face_hash_table_mutex = 0;
HMTX cairo_scaled_font_map_mutex = 0;
HMTX _cairo_scaled_font_map_mutex = 0;
HMTX _global_image_glyph_cache_mutex = 0;
HMTX _cairo_font_face_mutex = 0;
#ifdef CAIRO_HAS_FT_FONT
HMTX cairo_ft_unscaled_font_map_mutex = 0;
HMTX _cairo_ft_unscaled_font_map_mutex = 0;
#endif
static void inline
@ -106,13 +106,13 @@ cairo_os2_init (void)
/* Create the mutex semaphores we'll use! */
/* cairo-font.c: */
DosCreateMutexSem (NULL, &cairo_toy_font_face_hash_table_mutex, 0, FALSE);
DosCreateMutexSem (NULL, &cairo_scaled_font_map_mutex, 0, FALSE);
DosCreateMutexSem (NULL, &_cairo_scaled_font_map_mutex, 0, FALSE);
DosCreateMutexSem (NULL, &_global_image_glyph_cache_mutex, 0, FALSE);
DosCreateMutexSem (NULL, &_cairo_font_face_mutex, 0, FALSE);
#ifdef CAIRO_HAS_FT_FONT
/* cairo-ft-font.c: */
DosCreateMutexSem (NULL, &cairo_ft_unscaled_font_map_mutex, 0, FALSE);
DosCreateMutexSem (NULL, &_cairo_ft_unscaled_font_map_mutex, 0, FALSE);
#endif
/* Initialize FontConfig */
@ -139,24 +139,24 @@ cairo_os2_fini (void)
/* Destroy the mutex semaphores we've created! */
/* cairo-font.c: */
if (cairo_toy_font_face_hash_table_mutex) {
DosCloseMutexSem (cairo_toy_font_face_hash_table_mutex);
cairo_toy_font_face_hash_table_mutex = 0;
}
if (cairo_scaled_font_map_mutex) {
DosCloseMutexSem (cairo_scaled_font_map_mutex);
cairo_scaled_font_map_mutex = 0;
if (_cairo_scaled_font_map_mutex) {
DosCloseMutexSem (_cairo_scaled_font_map_mutex);
_cairo_scaled_font_map_mutex = 0;
}
if (_global_image_glyph_cache_mutex) {
DosCloseMutexSem (_global_image_glyph_cache_mutex);
_global_image_glyph_cache_mutex = 0;
}
if (_cairo_font_face_mutex) {
DosCloseMutexSem (_cairo_font_face_mutex);
_cairo_font_face_mutex = 0;
}
#ifdef CAIRO_HAS_FT_FONT
/* cairo-ft-font.c: */
if (cairo_ft_unscaled_font_map_mutex) {
DosCloseMutexSem (cairo_ft_unscaled_font_map_mutex);
cairo_ft_unscaled_font_map_mutex = 0;
if (_cairo_ft_unscaled_font_map_mutex) {
DosCloseMutexSem (_cairo_ft_unscaled_font_map_mutex);
_cairo_ft_unscaled_font_map_mutex = 0;
}
#endif

Просмотреть файл

@ -194,6 +194,8 @@ cairo_os2_surface_set_manual_window_refresh (cairo_surface_t *surface,
cairo_public cairo_bool_t
cairo_os2_surface_get_manual_window_refresh (cairo_surface_t *surface);
#else /* CAIRO_HAS_OS2_SURFACE */
# error Cairo was not compiled with support for the OS/2 backend
#endif /* CAIRO_HAS_OS2_SURFACE */
CAIRO_END_DECLS

Просмотреть файл

@ -224,6 +224,10 @@ _cairo_dtostr (char *buffer, size_t size, double d)
char *p;
int decimal_len;
/* Omit the minus sign from negative zero. */
if (d == 0.0)
d = 0.0;
snprintf (buffer, size, "%f", d);
locale_data = localeconv ();

Просмотреть файл

@ -70,6 +70,7 @@ typedef struct _cairo_paginated_surface {
* fallbacks. */
cairo_surface_t *meta;
int page_num;
cairo_bool_t page_is_blank;
} cairo_paginated_surface_t;
@ -122,6 +123,7 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
if (cairo_surface_status (surface->meta))
goto FAIL_CLEANUP_SURFACE;
surface->page_num = 1;
surface->page_is_blank = TRUE;
return &surface->base;
@ -155,12 +157,22 @@ static cairo_status_t
_cairo_paginated_surface_finish (void *abstract_surface)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_surface_destroy (surface->meta);
if (surface->page_is_blank == FALSE || surface->page_num == 1)
status = _cairo_paginated_surface_show_page (abstract_surface);
if (status == CAIRO_STATUS_SUCCESS)
cairo_surface_finish (surface->target);
if (status == CAIRO_STATUS_SUCCESS)
cairo_surface_finish (surface->meta);
cairo_surface_destroy (surface->target);
return CAIRO_STATUS_SUCCESS;
cairo_surface_destroy (surface->meta);
return status;
}
static cairo_surface_t *
@ -288,6 +300,8 @@ _cairo_paginated_surface_copy_page (void *abstract_surface)
_paint_page (surface);
surface->page_num++;
/* XXX: It might make sense to add some suport here for calling
* _cairo_surface_copy_page on the target surface. It would be an
* optimization for the output, (so that PostScript could include
@ -296,9 +310,7 @@ _cairo_paginated_surface_copy_page (void *abstract_surface)
* show_page and we implement the copying by simply not destroying
* the meta-surface. */
_cairo_surface_show_page (surface->target);
return CAIRO_STATUS_SUCCESS;
return _cairo_surface_show_page (surface->target);
}
static cairo_int_status_t
@ -322,6 +334,7 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
if (cairo_surface_status (surface->meta))
return cairo_surface_status (surface->meta);
surface->page_num++;
surface->page_is_blank = TRUE;
return CAIRO_STATUS_SUCCESS;
@ -442,6 +455,7 @@ _cairo_paginated_surface_show_glyphs (void *abstract_surface,
cairo_scaled_font_t *scaled_font)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_int_status_t status;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
@ -449,9 +463,23 @@ _cairo_paginated_surface_show_glyphs (void *abstract_surface,
surface->page_is_blank = FALSE;
return _cairo_surface_show_glyphs (surface->meta, op, source,
glyphs, num_glyphs,
scaled_font);
/* 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
* and re-acquire the mutex around this nested call.
*
* Yes, this is ugly, but we consider it pragmatic as compared to
* adding locking code to all 18 surface-backend-specific
* show_glyphs functions, (which would get less testing and likely
* lead to bugs).
*/
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
status = _cairo_surface_show_glyphs (surface->meta, op, source,
glyphs, num_glyphs,
scaled_font);
CAIRO_MUTEX_LOCK (scaled_font->mutex);
return status;
}
static cairo_surface_t *

Просмотреть файл

@ -35,6 +35,7 @@
*/
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
typedef struct cairo_filler {
double tolerance;
@ -169,6 +170,10 @@ _cairo_filler_close_path (void *closure)
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
cairo_traps_t *traps);
cairo_status_t
_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
@ -178,6 +183,12 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler_t filler;
/* Before we do anything else, we use a special-case filler for
* a device-axis aligned rectangle if possible. */
status = _cairo_path_fixed_fill_rectangle (path, traps);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
_cairo_filler_init (&filler, tolerance, traps);
status = _cairo_path_fixed_interpret (path,
@ -205,3 +216,84 @@ BAIL:
return status;
}
/* This special-case filler supports only a path that describes a
* device-axis aligned rectangle. It exists to avoid the overhead of
* the general tessellator when drawing very common rectangles.
*
* If the path described anything but a device-axis aligned rectangle,
* this function will return CAIRO_INT_STATUS_UNSUPPORTED.
*/
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
cairo_traps_t *traps)
{
cairo_path_buf_t *buf = path->buf_head;
int final;
/* Ensure the path has the operators we expect for a rectangular path.
*/
if (buf == NULL || buf->num_ops < 5)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO ||
buf->op[1] != CAIRO_PATH_OP_LINE_TO ||
buf->op[2] != CAIRO_PATH_OP_LINE_TO ||
buf->op[3] != CAIRO_PATH_OP_LINE_TO)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
/* Now, there are choices. The rectangle might end with a LINE_TO
* (to the original point), but this isn't required. If it
* doesn't, then it must end with a CLOSE_PATH. */
if (buf->op[4] == CAIRO_PATH_OP_LINE_TO) {
if (buf->points[4].x != buf->points[0].x ||
buf->points[4].y != buf->points[0].y)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
} else if (buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH) {
return CAIRO_INT_STATUS_UNSUPPORTED;
}
/* Finally, a trailing CLOSE_PATH or MOVE_TO after the rectangle
* is fine. But anything more than that means we must return
* unsupported. */
final = 5;
if (final < buf->num_ops &&
buf->op[final] == CAIRO_PATH_OP_CLOSE_PATH)
{
final++;
}
if (final < buf->num_ops &&
buf->op[final] == CAIRO_PATH_OP_MOVE_TO)
{
final++;
}
if (final < buf->num_ops)
return CAIRO_INT_STATUS_UNSUPPORTED;
/* Now that we've verified the operators, we must ensure that the
* path coordinates are consistent with a rectangle. There are two
* choices here. */
if (buf->points[0].y == buf->points[1].y &&
buf->points[1].x == buf->points[2].x &&
buf->points[2].y == buf->points[3].y &&
buf->points[3].x == buf->points[0].x)
{
return _cairo_traps_tessellate_convex_quad (traps,
buf->points);
}
if (buf->points[0].x == buf->points[1].x &&
buf->points[1].y == buf->points[2].y &&
buf->points[2].x == buf->points[3].x &&
buf->points[3].y == buf->points[0].y)
{
return _cairo_traps_tessellate_convex_quad (traps,
buf->points);
}
return CAIRO_INT_STATUS_UNSUPPORTED;
}

Просмотреть файл

@ -42,34 +42,30 @@ typedef enum cairo_path_op {
CAIRO_PATH_OP_CURVE_TO = 2,
CAIRO_PATH_OP_CLOSE_PATH = 3
} __attribute__ ((packed)) cairo_path_op_t; /* Don't want 32 bits if we can avoid it. */
/* XXX Shall we just not use char instead of hoping for __attribute__ working? */
#define CAIRO_PATH_BUF_SIZE 64
/* make cairo_path_fixed fit a 512 bytes. about 50 items */
#define CAIRO_PATH_BUF_SIZE ((512 - 12 * sizeof (void*)) \
/ (sizeof (cairo_point_t) + sizeof (cairo_path_op_t)))
typedef struct _cairo_path_op_buf {
typedef struct _cairo_path_buf {
struct _cairo_path_buf *next, *prev;
int num_ops;
cairo_path_op_t op[CAIRO_PATH_BUF_SIZE];
struct _cairo_path_op_buf *next, *prev;
} cairo_path_op_buf_t;
typedef struct _cairo_path_arg_buf {
int num_points;
cairo_path_op_t op[CAIRO_PATH_BUF_SIZE];
cairo_point_t points[CAIRO_PATH_BUF_SIZE];
struct _cairo_path_arg_buf *next, *prev;
} cairo_path_arg_buf_t;
} cairo_path_buf_t;
struct _cairo_path_fixed {
cairo_path_op_buf_t *op_buf_head;
cairo_path_op_buf_t *op_buf_tail;
cairo_path_arg_buf_t *arg_buf_head;
cairo_path_arg_buf_t *arg_buf_tail;
cairo_point_t last_move_point;
cairo_point_t current_point;
unsigned int has_current_point : 1;
unsigned int has_curve_to : 1;
cairo_path_buf_t *buf_tail;
cairo_path_buf_t buf_head[1];
};
#endif /* CAIRO_PATH_FIXED_PRIVATE_H */

Просмотреть файл

@ -48,42 +48,33 @@ _cairo_path_fixed_add (cairo_path_fixed_t *path,
int num_points);
static void
_cairo_path_fixed_add_op_buf (cairo_path_fixed_t *path,
cairo_path_op_buf_t *op_buf);
_cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
cairo_path_buf_t *buf);
static cairo_path_buf_t *
_cairo_path_buf_create (void);
static void
_cairo_path_fixed_add_arg_buf (cairo_path_fixed_t *path,
cairo_path_arg_buf_t *arg_buf);
static cairo_path_op_buf_t *
_cairo_path_op_buf_create (void);
_cairo_path_buf_destroy (cairo_path_buf_t *buf);
static void
_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op_buf);
_cairo_path_buf_add_op (cairo_path_buf_t *buf,
cairo_path_op_t op);
static void
_cairo_path_op_buf_add_op (cairo_path_op_buf_t *op_buf,
cairo_path_op_t op);
static cairo_path_arg_buf_t *
_cairo_path_arg_buf_create (void);
static void
_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg_buf);
static void
_cairo_path_arg_buf_add_points (cairo_path_arg_buf_t *arg_buf,
cairo_point_t *points,
int num_points);
_cairo_path_buf_add_points (cairo_path_buf_t *buf,
cairo_point_t *points,
int num_points);
void
_cairo_path_fixed_init (cairo_path_fixed_t *path)
{
path->op_buf_head = NULL;
path->op_buf_tail = NULL;
path->buf_head->next = NULL;
path->buf_head->prev = NULL;
path->buf_tail = path->buf_head;
path->arg_buf_head = NULL;
path->arg_buf_tail = NULL;
path->buf_head->num_ops = 0;
path->buf_head->num_points = 0;
path->current_point.x = 0;
path->current_point.y = 0;
@ -96,8 +87,7 @@ cairo_status_t
_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
cairo_path_fixed_t *other)
{
cairo_path_op_buf_t *op_buf, *other_op_buf;
cairo_path_arg_buf_t *arg_buf, *other_arg_buf;
cairo_path_buf_t *buf, *other_buf;
_cairo_path_fixed_init (path);
path->current_point = other->current_point;
@ -105,30 +95,23 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
path->has_curve_to = other->has_curve_to;
path->last_move_point = other->last_move_point;
for (other_op_buf = other->op_buf_head;
other_op_buf;
other_op_buf = other_op_buf->next)
path->buf_head->num_ops = other->buf_head->num_ops;
path->buf_head->num_points = other->buf_head->num_points;
memcpy (path->buf_head->op, other->buf_head->op,
other->buf_head->num_ops * sizeof (other->buf_head->op[0]));
memcpy (path->buf_head->points, other->buf_head->points,
other->buf_head->num_points * sizeof (other->buf_head->points[0]));
for (other_buf = other->buf_head->next;
other_buf;
other_buf = other_buf->next)
{
op_buf = _cairo_path_op_buf_create ();
if (op_buf == NULL) {
buf = _cairo_path_buf_create ();
if (buf == NULL) {
_cairo_path_fixed_fini (path);
return CAIRO_STATUS_NO_MEMORY;
}
memcpy (op_buf, other_op_buf, sizeof (cairo_path_op_buf_t));
_cairo_path_fixed_add_op_buf (path, op_buf);
}
for (other_arg_buf = other->arg_buf_head;
other_arg_buf;
other_arg_buf = other_arg_buf->next)
{
arg_buf = _cairo_path_arg_buf_create ();
if (arg_buf == NULL) {
_cairo_path_fixed_fini (path);
return CAIRO_STATUS_NO_MEMORY;
}
memcpy (arg_buf, other_arg_buf, sizeof (cairo_path_arg_buf_t));
_cairo_path_fixed_add_arg_buf (path, arg_buf);
memcpy (buf, other_buf, sizeof (cairo_path_buf_t));
_cairo_path_fixed_add_buf (path, buf);
}
return CAIRO_STATUS_SUCCESS;
@ -148,22 +131,19 @@ _cairo_path_fixed_create (void)
void
_cairo_path_fixed_fini (cairo_path_fixed_t *path)
{
cairo_path_op_buf_t *op_buf;
cairo_path_arg_buf_t *arg_buf;
cairo_path_buf_t *buf;
while (path->op_buf_head) {
op_buf = path->op_buf_head;
path->op_buf_head = op_buf->next;
_cairo_path_op_buf_destroy (op_buf);
buf = path->buf_head->next;
while (buf) {
cairo_path_buf_t *this = buf;
buf = buf->next;
_cairo_path_buf_destroy (this);
}
path->op_buf_tail = NULL;
while (path->arg_buf_head) {
arg_buf = path->arg_buf_head;
path->arg_buf_head = arg_buf->next;
_cairo_path_arg_buf_destroy (arg_buf);
}
path->arg_buf_tail = NULL;
path->buf_head->next = NULL;
path->buf_head->prev = NULL;
path->buf_tail = path->buf_head;
path->buf_head->num_ops = 0;
path->buf_head->num_points = 0;
path->has_current_point = FALSE;
path->has_curve_to = FALSE;
@ -189,11 +169,11 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path,
/* If the previous op was also a MOVE_TO, then just change its
* point rather than adding a new op. */
if (path->op_buf_tail && path->op_buf_tail->num_ops &&
path->op_buf_tail->op[path->op_buf_tail->num_ops - 1] == CAIRO_PATH_OP_MOVE_TO)
if (path->buf_tail && path->buf_tail->num_ops &&
path->buf_tail->op[path->buf_tail->num_ops - 1] == CAIRO_PATH_OP_MOVE_TO)
{
cairo_point_t *last_move_to_point;
last_move_to_point = &path->arg_buf_tail->points[path->arg_buf_tail->num_points - 1];
last_move_to_point = &path->buf_tail->points[path->buf_tail->num_points - 1];
*last_move_to_point = point;
} else {
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
@ -376,133 +356,77 @@ _cairo_path_fixed_add (cairo_path_fixed_t *path,
cairo_point_t *points,
int num_points)
{
if (path->op_buf_tail == NULL ||
path->op_buf_tail->num_ops + 1 > CAIRO_PATH_BUF_SIZE)
if (path->buf_tail->num_ops + 1 > CAIRO_PATH_BUF_SIZE ||
path->buf_tail->num_points + num_points > CAIRO_PATH_BUF_SIZE)
{
cairo_path_op_buf_t *op_buf;
cairo_path_buf_t *buf;
op_buf = _cairo_path_op_buf_create ();
if (op_buf == NULL)
buf = _cairo_path_buf_create ();
if (buf == NULL)
return CAIRO_STATUS_NO_MEMORY;
_cairo_path_fixed_add_op_buf (path, op_buf);
_cairo_path_fixed_add_buf (path, buf);
}
_cairo_path_op_buf_add_op (path->op_buf_tail, op);
if (path->arg_buf_tail == NULL ||
path->arg_buf_tail->num_points + num_points > CAIRO_PATH_BUF_SIZE)
{
cairo_path_arg_buf_t *arg_buf;
arg_buf = _cairo_path_arg_buf_create ();
if (arg_buf == NULL)
return CAIRO_STATUS_NO_MEMORY;
_cairo_path_fixed_add_arg_buf (path, arg_buf);
}
_cairo_path_arg_buf_add_points (path->arg_buf_tail, points, num_points);
_cairo_path_buf_add_op (path->buf_tail, op);
_cairo_path_buf_add_points (path->buf_tail, points, num_points);
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_path_fixed_add_op_buf (cairo_path_fixed_t *path,
cairo_path_op_buf_t *op_buf)
_cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
cairo_path_buf_t *buf)
{
op_buf->next = NULL;
op_buf->prev = path->op_buf_tail;
buf->next = NULL;
buf->prev = path->buf_tail;
if (path->op_buf_tail) {
path->op_buf_tail->next = op_buf;
} else {
path->op_buf_head = op_buf;
path->buf_tail->next = buf;
path->buf_tail = buf;
}
static cairo_path_buf_t *
_cairo_path_buf_create (void)
{
cairo_path_buf_t *buf;
buf = malloc (sizeof (cairo_path_buf_t));
if (buf) {
buf->next = NULL;
buf->prev = NULL;
buf->num_ops = 0;
buf->num_points = 0;
}
path->op_buf_tail = op_buf;
return buf;
}
static void
_cairo_path_fixed_add_arg_buf (cairo_path_fixed_t *path,
cairo_path_arg_buf_t *arg_buf)
_cairo_path_buf_destroy (cairo_path_buf_t *buf)
{
arg_buf->next = NULL;
arg_buf->prev = path->arg_buf_tail;
if (path->arg_buf_tail) {
path->arg_buf_tail->next = arg_buf;
} else {
path->arg_buf_head = arg_buf;
}
path->arg_buf_tail = arg_buf;
}
static cairo_path_op_buf_t *
_cairo_path_op_buf_create (void)
{
cairo_path_op_buf_t *op_buf;
op_buf = malloc (sizeof (cairo_path_op_buf_t));
if (op_buf) {
op_buf->num_ops = 0;
op_buf->next = NULL;
}
return op_buf;
free (buf);
}
static void
_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op_buf)
_cairo_path_buf_add_op (cairo_path_buf_t *buf,
cairo_path_op_t op)
{
free (op_buf);
buf->op[buf->num_ops++] = op;
}
static void
_cairo_path_op_buf_add_op (cairo_path_op_buf_t *op_buf,
cairo_path_op_t op)
{
op_buf->op[op_buf->num_ops++] = op;
}
static cairo_path_arg_buf_t *
_cairo_path_arg_buf_create (void)
{
cairo_path_arg_buf_t *arg_buf;
arg_buf = malloc (sizeof (cairo_path_arg_buf_t));
if (arg_buf) {
arg_buf->num_points = 0;
arg_buf->next = NULL;
}
return arg_buf;
}
static void
_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg_buf)
{
free (arg_buf);
}
static void
_cairo_path_arg_buf_add_points (cairo_path_arg_buf_t *arg_buf,
cairo_point_t *points,
int num_points)
_cairo_path_buf_add_points (cairo_path_buf_t *buf,
cairo_point_t *points,
int num_points)
{
int i;
for (i=0; i < num_points; i++) {
arg_buf->points[arg_buf->num_points++] = points[i];
buf->points[buf->num_points++] = points[i];
}
}
#define CAIRO_PATH_OP_MAX_ARGS 3
static int const num_args[] =
{
1, /* cairo_path_move_to */
@ -521,61 +445,43 @@ _cairo_path_fixed_interpret (cairo_path_fixed_t *path,
void *closure)
{
cairo_status_t status;
int i, arg;
cairo_path_op_buf_t *op_buf;
cairo_path_buf_t *buf;
cairo_path_op_t op;
cairo_path_arg_buf_t *arg_buf = path->arg_buf_head;
int buf_i = 0;
cairo_point_t point[CAIRO_PATH_OP_MAX_ARGS];
cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD);
int step = forward ? 1 : -1;
for (op_buf = forward ? path->op_buf_head : path->op_buf_tail;
op_buf;
op_buf = forward ? op_buf->next : op_buf->prev)
for (buf = forward ? path->buf_head : path->buf_tail;
buf;
buf = forward ? buf->next : buf->prev)
{
int start, stop;
cairo_point_t *points;
int start, stop, i;
if (forward) {
start = 0;
stop = op_buf->num_ops;
stop = buf->num_ops;
points = buf->points;
} else {
start = op_buf->num_ops - 1;
start = buf->num_ops - 1;
stop = -1;
points = buf->points + buf->num_points;
}
for (i=start; i != stop; i += step) {
op = op_buf->op[i];
op = buf->op[i];
if (! forward) {
if (buf_i == 0) {
arg_buf = arg_buf->prev;
buf_i = arg_buf->num_points;
}
buf_i -= num_args[op];
}
for (arg = 0; arg < num_args[op]; arg++) {
point[arg] = arg_buf->points[buf_i];
buf_i++;
if (buf_i >= arg_buf->num_points) {
arg_buf = arg_buf->next;
buf_i = 0;
}
}
if (! forward) {
buf_i -= num_args[op];
points -= num_args[op];
}
switch (op) {
case CAIRO_PATH_OP_MOVE_TO:
status = (*move_to) (closure, &point[0]);
status = (*move_to) (closure, &points[0]);
break;
case CAIRO_PATH_OP_LINE_TO:
status = (*line_to) (closure, &point[0]);
status = (*line_to) (closure, &points[0]);
break;
case CAIRO_PATH_OP_CURVE_TO:
status = (*curve_to) (closure, &point[0], &point[1], &point[2]);
status = (*curve_to) (closure, &points[0], &points[1], &points[2]);
break;
case CAIRO_PATH_OP_CLOSE_PATH:
default:
@ -584,6 +490,11 @@ _cairo_path_fixed_interpret (cairo_path_fixed_t *path,
}
if (status)
return status;
if (forward) {
points += num_args[op];
}
}
}
@ -597,31 +508,31 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
cairo_fixed_t scalex,
cairo_fixed_t scaley)
{
cairo_path_arg_buf_t *arg_buf = path->arg_buf_head;
cairo_path_buf_t *buf = path->buf_head;
int i;
cairo_int64_t i64temp;
cairo_fixed_t fixedtemp;
while (arg_buf) {
for (i = 0; i < arg_buf->num_points; i++) {
while (buf) {
for (i = 0; i < buf->num_points; i++) {
if (scalex == CAIRO_FIXED_ONE) {
arg_buf->points[i].x += offx;
buf->points[i].x += offx;
} else {
fixedtemp = arg_buf->points[i].x + offx;
fixedtemp = buf->points[i].x + offx;
i64temp = _cairo_int32x32_64_mul (fixedtemp, scalex);
arg_buf->points[i].x = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
buf->points[i].x = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
}
if (scaley == CAIRO_FIXED_ONE) {
arg_buf->points[i].y += offy;
buf->points[i].y += offy;
} else {
fixedtemp = arg_buf->points[i].y + offy;
fixedtemp = buf->points[i].y + offy;
i64temp = _cairo_int32x32_64_mul (fixedtemp, scaley);
arg_buf->points[i].y = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
buf->points[i].y = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
}
}
arg_buf = arg_buf->next;
buf = buf->next;
}
}

Просмотреть файл

@ -51,7 +51,7 @@ typedef struct cairo_stroker {
cairo_point_t current_point;
cairo_point_t first_point;
cairo_bool_t has_sub_path;
cairo_bool_t has_initial_sub_path;
cairo_bool_t has_current_face;
cairo_stroke_face_t current_face;
@ -61,7 +61,8 @@ typedef struct cairo_stroker {
cairo_bool_t dashed;
unsigned int dash_index;
int dash_on;
cairo_bool_t dash_on;
cairo_bool_t dash_starts_on;
double dash_remain;
} cairo_stroker_t;
@ -114,7 +115,7 @@ static void
_cairo_stroker_start_dash (cairo_stroker_t *stroker)
{
double offset;
int on = 1;
cairo_bool_t on = TRUE;
unsigned int i = 0;
offset = stroker->style->dash_offset;
@ -124,13 +125,13 @@ _cairo_stroker_start_dash (cairo_stroker_t *stroker)
segment shrinks to zero it will be skipped over. */
while (offset > 0.0 && offset >= stroker->style->dash[i]) {
offset -= stroker->style->dash[i];
on = 1-on;
on = !on;
if (++i == stroker->style->num_dashes)
i = 0;
}
stroker->dashed = TRUE;
stroker->dash_index = i;
stroker->dash_on = on;
stroker->dash_on = stroker->dash_starts_on = on;
stroker->dash_remain = stroker->style->dash[i] - offset;
}
@ -142,7 +143,7 @@ _cairo_stroker_step_dash (cairo_stroker_t *stroker, double step)
stroker->dash_index++;
if (stroker->dash_index == stroker->style->num_dashes)
stroker->dash_index = 0;
stroker->dash_on = 1-stroker->dash_on;
stroker->dash_on = !stroker->dash_on;
stroker->dash_remain = stroker->style->dash[stroker->dash_index];
}
}
@ -167,7 +168,7 @@ _cairo_stroker_init (cairo_stroker_t *stroker,
stroker->has_current_face = FALSE;
stroker->has_first_face = FALSE;
stroker->has_sub_path = FALSE;
stroker->has_initial_sub_path = FALSE;
if (stroker->style->dash)
_cairo_stroker_start_dash (stroker);
@ -466,17 +467,25 @@ _cairo_stroker_add_caps (cairo_stroker_t *stroker)
{
cairo_status_t status;
/* check for a degenerative sub_path */
if (stroker->has_sub_path
if (stroker->has_initial_sub_path
&& !stroker->has_first_face
&& !stroker->has_current_face
&& stroker->style->line_cap == CAIRO_LINE_JOIN_ROUND)
{
/* pick an arbitrary slope to use */
cairo_slope_t slope = {1, 0};
_compute_face (&stroker->first_point, &slope, stroker, &stroker->first_face);
cairo_stroke_face_t face;
stroker->has_first_face = stroker->has_current_face = TRUE;
stroker->current_face = stroker->first_face;
/* arbitrarily choose first_point
* first_point and current_point should be the same */
_compute_face (&stroker->first_point, &slope, stroker, &face);
status = _cairo_stroker_add_leading_cap (stroker, &face);
if (status)
return status;
status = _cairo_stroker_add_trailing_cap (stroker, &face);
if (status)
return status;
}
if (stroker->has_first_face) {
@ -594,6 +603,7 @@ _cairo_stroker_move_to (void *closure, cairo_point_t *point)
cairo_status_t status;
cairo_stroker_t *stroker = closure;
/* Cap the start and end of the previous sub path as needed */
status = _cairo_stroker_add_caps (stroker);
if (status)
return status;
@ -603,7 +613,7 @@ _cairo_stroker_move_to (void *closure, cairo_point_t *point)
stroker->has_first_face = FALSE;
stroker->has_current_face = FALSE;
stroker->has_sub_path = FALSE;
stroker->has_initial_sub_path = FALSE;
return CAIRO_STATUS_SUCCESS;
}
@ -628,7 +638,7 @@ _cairo_stroker_line_to (void *closure, cairo_point_t *point)
cairo_point_t *p2 = point;
cairo_slope_t slope;
stroker->has_sub_path = TRUE;
stroker->has_initial_sub_path = TRUE;
if (p1->x == p2->x && p1->y == p2->y)
return CAIRO_STATUS_SUCCESS;
@ -640,14 +650,14 @@ _cairo_stroker_line_to (void *closure, cairo_point_t *point)
return status;
if (stroker->has_current_face) {
/* Join with final face from previous segment */
status = _cairo_stroker_join (stroker, &stroker->current_face, &start);
if (status)
return status;
} else {
if (!stroker->has_first_face) {
stroker->first_face = start;
stroker->has_first_face = TRUE;
}
} else if (!stroker->has_first_face) {
/* Save sub path's first face in case needed for closing join */
stroker->first_face = start;
stroker->has_first_face = TRUE;
}
stroker->current_face = end;
stroker->has_current_face = TRUE;
@ -665,17 +675,16 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker_t *stroker = closure;
double mag, remain, tmp;
double mag, remain, step_length = 0;
double dx, dy;
double dx2, dy2;
cairo_point_t fd1, fd2;
cairo_bool_t first = TRUE;
cairo_stroke_face_t sub_start, sub_end;
cairo_point_t *p1 = &stroker->current_point;
cairo_point_t *p2 = point;
cairo_slope_t slope;
stroker->has_sub_path = stroker->dash_on;
stroker->has_initial_sub_path = stroker->dash_starts_on;
if (p1->x == p2->x && p1->y == p2->y)
return CAIRO_STATUS_SUCCESS;
@ -687,90 +696,75 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point)
cairo_matrix_transform_distance (stroker->ctm_inverse, &dx, &dy);
mag = sqrt (dx *dx + dy * dy);
mag = sqrt (dx * dx + dy * dy);
remain = mag;
fd1 = *p1;
while (remain) {
tmp = stroker->dash_remain;
if (tmp > remain)
tmp = remain;
remain -= tmp;
dx2 = dx * (mag - remain)/mag;
step_length = MIN (stroker->dash_remain, remain);
remain -= step_length;
dx2 = dx * (mag - remain)/mag;
dy2 = dy * (mag - remain)/mag;
cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
fd2.x = _cairo_fixed_from_double (dx2);
fd2.y = _cairo_fixed_from_double (dy2);
fd2.x += p1->x;
fd2.y += p1->y;
/*
* XXX simplify this case analysis
*/
fd2.x = _cairo_fixed_from_double (dx2) + p1->x;
fd2.y = _cairo_fixed_from_double (dy2) + p1->y;
if (stroker->dash_on) {
status = _cairo_stroker_add_sub_edge (stroker, &fd1, &fd2, &slope, &sub_start, &sub_end);
if (status)
return status;
if (!first) {
/*
* Not first dash in this segment, cap start
*/
if (stroker->has_current_face) {
/* Join with final face from previous segment */
status = _cairo_stroker_join (stroker, &stroker->current_face, &sub_start);
stroker->has_current_face = FALSE;
if (status)
return status;
} else if (!stroker->has_first_face && stroker->dash_starts_on) {
/* Save sub path's first face in case needed for closing join */
stroker->first_face = sub_start;
stroker->has_first_face = TRUE;
} else {
/* Cap dash start if not connecting to a previous segment */
status = _cairo_stroker_add_leading_cap (stroker, &sub_start);
if (status)
return status;
} else {
/*
* First in this segment, join to any current_face, else
* if at start of sub-path, mark position, else
* cap
*/
if (stroker->has_current_face) {
status = _cairo_stroker_join (stroker, &stroker->current_face, &sub_start);
if (status)
return status;
} else {
if (!stroker->has_first_face) {
stroker->first_face = sub_start;
stroker->has_first_face = TRUE;
} else {
status = _cairo_stroker_add_leading_cap (stroker, &sub_start);
if (status)
return status;
}
}
stroker->has_sub_path = TRUE;
}
if (remain) {
/*
* Cap if not at end of segment
*/
/* Cap dash end if not at end of segment */
status = _cairo_stroker_add_trailing_cap (stroker, &sub_end);
if (status)
return status;
} else {
/*
* Mark previous line face and fix up next time
* through
*/
stroker->current_face = sub_end;
stroker->has_current_face = TRUE;
}
} else {
/*
* If starting with off dash, check previous face
* and cap if necessary
*/
if (first) {
if (stroker->has_current_face) {
status = _cairo_stroker_add_trailing_cap (stroker, &stroker->current_face);
if (status)
return status;
}
}
if (!remain)
if (stroker->has_current_face) {
/* Cap final face from previous segment */
status = _cairo_stroker_add_trailing_cap (stroker, &stroker->current_face);
if (status)
return status;
stroker->has_current_face = FALSE;
}
}
_cairo_stroker_step_dash (stroker, tmp);
_cairo_stroker_step_dash (stroker, step_length);
fd1 = fd2;
first = FALSE;
}
if (stroker->dash_on && !stroker->has_current_face) {
/* This segment ends on a transition to dash_on, compute a new face
* and add cap for the begining of the next dash_on step.
*
* Note: this will create a degenerate cap if this is not the last line
* in the path. Whether this behaviour is desirable or not is debatable.
* On one side these degnerate caps can not be reproduced with regular path stroking.
* On the other side Acroread 7 also produces the degenerate caps. */
_compute_face (point, &slope, stroker, &stroker->current_face);
stroker->has_current_face = TRUE;
status = _cairo_stroker_add_leading_cap (stroker, &stroker->current_face);
if (status)
return status;
}
stroker->current_point = *point;
@ -807,11 +801,9 @@ _cairo_stroker_curve_to (void *closure,
status = _cairo_stroker_join (stroker, &stroker->current_face, &start);
if (status)
return status;
} else {
if (!stroker->has_first_face) {
stroker->first_face = start;
stroker->has_first_face = TRUE;
}
} else if (!stroker->has_first_face) {
stroker->first_face = start;
stroker->has_first_face = TRUE;
}
stroker->current_face = end;
stroker->has_current_face = TRUE;
@ -928,16 +920,18 @@ _cairo_stroker_close_path (void *closure)
return status;
if (stroker->has_first_face && stroker->has_current_face) {
/* Join first and final faces of sub path */
status = _cairo_stroker_join (stroker, &stroker->current_face, &stroker->first_face);
if (status)
return status;
} else {
/* Cap the start and end of the sub path as needed */
status = _cairo_stroker_add_caps (stroker);
if (status)
return status;
}
stroker->has_sub_path = FALSE;
stroker->has_initial_sub_path = FALSE;
stroker->has_first_face = FALSE;
stroker->has_current_face = FALSE;
@ -996,6 +990,7 @@ _cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path,
if (status)
goto BAIL;
/* Cap the start and end of the final sub path as needed */
status = _cairo_stroker_add_caps (&stroker);
BAIL:
@ -1287,16 +1282,17 @@ _cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path,
NULL,
_cairo_rectilinear_stroker_close_path,
&rectilinear_stroker);
if (status) {
_cairo_traps_fini (traps);
return status;
}
if (status)
goto BAIL;
status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker);
if (status)
return status;
BAIL:
_cairo_rectilinear_stroker_fini (&rectilinear_stroker);
return CAIRO_STATUS_SUCCESS;
if (status)
_cairo_traps_fini (traps);
return status;
}

Просмотреть файл

@ -465,19 +465,19 @@ _cairo_path_append_to_context (const cairo_path_t *path,
p = &path->data[i];
switch (p->header.type) {
case CAIRO_PATH_MOVE_TO:
if (p->header.length != 2)
if (p->header.length < 2)
return CAIRO_STATUS_INVALID_PATH_DATA;
cairo_move_to (cr,
p[1].point.x, p[1].point.y);
break;
case CAIRO_PATH_LINE_TO:
if (p->header.length != 2)
if (p->header.length < 2)
return CAIRO_STATUS_INVALID_PATH_DATA;
cairo_line_to (cr,
p[1].point.x, p[1].point.y);
break;
case CAIRO_PATH_CURVE_TO:
if (p->header.length != 4)
if (p->header.length < 4)
return CAIRO_STATUS_INVALID_PATH_DATA;
cairo_curve_to (cr,
p[1].point.x, p[1].point.y,
@ -485,7 +485,7 @@ _cairo_path_append_to_context (const cairo_path_t *path,
p[3].point.x, p[3].point.y);
break;
case CAIRO_PATH_CLOSE_PATH:
if (p->header.length != 1)
if (p->header.length < 1)
return CAIRO_STATUS_INVALID_PATH_DATA;
cairo_close_path (cr);
break;

Просмотреть файл

@ -34,6 +34,7 @@ const cairo_solid_pattern_t cairo_pattern_nil = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_REF_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
{ 0, 0, 0, NULL }, /* user_data */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */
@ -43,6 +44,7 @@ static const cairo_solid_pattern_t cairo_pattern_nil_null_pointer = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_REF_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NULL_POINTER,/* status */
{ 0, 0, 0, NULL }, /* user_data */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */
@ -84,6 +86,8 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
pattern->ref_count = 1;
pattern->status = CAIRO_STATUS_SUCCESS;
_cairo_user_data_array_init (&pattern->user_data);
if (type == CAIRO_PATTERN_TYPE_SURFACE)
pattern->extend = CAIRO_EXTEND_SURFACE_DEFAULT;
else
@ -113,11 +117,15 @@ _cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern,
*dst = *src;
}
if (other->n_stops)
if (other->stops == other->stops_embedded)
pattern->stops = pattern->stops_embedded;
else if (other->stops)
{
pattern->stops = malloc (other->n_stops *
pattern->stops = malloc (other->stops_size *
sizeof (pixman_gradient_stop_t));
if (pattern->stops == NULL) {
pattern->stops_size = 0;
pattern->n_stops = 0;
_cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY);
return;
}
@ -165,6 +173,8 @@ _cairo_pattern_init_copy (cairo_pattern_t *pattern,
void
_cairo_pattern_fini (cairo_pattern_t *pattern)
{
_cairo_user_data_array_fini (&pattern->user_data);
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
break;
@ -179,7 +189,7 @@ _cairo_pattern_fini (cairo_pattern_t *pattern)
cairo_gradient_pattern_t *gradient =
(cairo_gradient_pattern_t *) pattern;
if (gradient->stops)
if (gradient->stops && gradient->stops != gradient->stops_embedded)
free (gradient->stops);
} break;
}
@ -215,8 +225,9 @@ _cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern,
{
_cairo_pattern_init (&pattern->base, type);
pattern->stops = NULL;
pattern->n_stops = 0;
pattern->n_stops = 0;
pattern->stops_size = 0;
pattern->stops = NULL;
}
void
@ -238,12 +249,12 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
{
_cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_RADIAL);
pattern->gradient.inner.x = _cairo_fixed_from_double (cx0);
pattern->gradient.inner.y = _cairo_fixed_from_double (cy0);
pattern->gradient.inner.radius = _cairo_fixed_from_double (fabs (radius0));
pattern->gradient.outer.x = _cairo_fixed_from_double (cx1);
pattern->gradient.outer.y = _cairo_fixed_from_double (cy1);
pattern->gradient.outer.radius = _cairo_fixed_from_double (fabs (radius1));
pattern->gradient.c1.x = _cairo_fixed_from_double (cx0);
pattern->gradient.c1.y = _cairo_fixed_from_double (cy0);
pattern->gradient.c1.radius = _cairo_fixed_from_double (fabs (radius0));
pattern->gradient.c2.x = _cairo_fixed_from_double (cx1);
pattern->gradient.c2.y = _cairo_fixed_from_double (cy1);
pattern->gradient.c2.radius = _cairo_fixed_from_double (fabs (radius1));
}
cairo_pattern_t *
@ -490,15 +501,15 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0,
* @pattern from being destroyed until a matching call to
* cairo_pattern_destroy() is made.
*
* The number of references to a #cairo_pattern_t can be get using
* cairo_pattern_get_reference_count().
*
* Return value: the referenced #cairo_pattern_t.
**/
cairo_pattern_t *
cairo_pattern_reference (cairo_pattern_t *pattern)
{
if (pattern == NULL)
return NULL;
if (pattern->ref_count == CAIRO_REF_COUNT_INVALID)
if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID)
return pattern;
assert (pattern->ref_count > 0);
@ -555,10 +566,7 @@ slim_hidden_def (cairo_pattern_status);
void
cairo_pattern_destroy (cairo_pattern_t *pattern)
{
if (pattern == NULL)
return;
if (pattern->ref_count == CAIRO_REF_COUNT_INVALID)
if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID)
return;
assert (pattern->ref_count > 0);
@ -572,6 +580,116 @@ cairo_pattern_destroy (cairo_pattern_t *pattern)
}
slim_hidden_def (cairo_pattern_destroy);
/**
* cairo_pattern_get_reference_count:
* @pattern: a #cairo_pattern_t
*
* Returns the current reference count of @pattern.
*
* Return value: the current reference count of @pattern. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.4
**/
unsigned int
cairo_pattern_get_reference_count (cairo_pattern_t *pattern)
{
if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID)
return 0;
return pattern->ref_count;
}
/**
* cairo_pattern_get_user_data:
* @pattern: a #cairo_pattern_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Return user data previously attached to @pattern using the
* specified key. If no user data has been attached with the given
* key this function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
*
* Since: 1.4
**/
void *
cairo_pattern_get_user_data (cairo_pattern_t *pattern,
const cairo_user_data_key_t *key)
{
return _cairo_user_data_array_get_data (&pattern->user_data,
key);
}
/**
* cairo_pattern_set_user_data:
* @pattern: a #cairo_pattern_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach to the #cairo_pattern_t
* @destroy: a #cairo_destroy_func_t which will be called when the
* #cairo_t is destroyed or when new user data is attached using the
* same key.
*
* Attach user data to @pattern. To remove user data from a surface,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
*
* Since: 1.4
**/
cairo_status_t
cairo_pattern_set_user_data (cairo_pattern_t *pattern,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
if (pattern->ref_count == CAIRO_REF_COUNT_INVALID)
return CAIRO_STATUS_NO_MEMORY;
return _cairo_user_data_array_set_data (&pattern->user_data,
key, user_data, destroy);
}
/* make room for at least one more color stop */
static cairo_status_t
_cairo_pattern_gradient_grow (cairo_gradient_pattern_t *pattern)
{
pixman_gradient_stop_t *new_stops;
int old_size = pattern->stops_size;
int embedded_size = sizeof (pattern->stops_embedded) / sizeof (pattern->stops_embedded[0]);
int new_size = 2 * MAX (old_size, 4);
/* we have a local buffer at pattern->stops_embedded. try to fulfill the request
* from there. */
if (old_size < embedded_size) {
pattern->stops = pattern->stops_embedded;
pattern->stops_size = embedded_size;
return CAIRO_STATUS_SUCCESS;
}
assert (pattern->n_stops <= pattern->stops_size);
if (pattern->stops == pattern->stops_embedded) {
new_stops = malloc (new_size * sizeof (pixman_gradient_stop_t));
if (new_stops)
memcpy (new_stops, pattern->stops, old_size * sizeof (pixman_gradient_stop_t));
} else {
new_stops = realloc (pattern->stops, new_size * sizeof (pixman_gradient_stop_t));
}
if (new_stops == NULL) {
return CAIRO_STATUS_NO_MEMORY;
}
pattern->stops = new_stops;
pattern->stops_size = new_size;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
double offset,
@ -580,38 +698,38 @@ _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
double blue,
double alpha)
{
pixman_gradient_stop_t *new_stops;
pixman_gradient_stop_t *stops;
cairo_fixed_t x;
unsigned int i;
new_stops = realloc (pattern->stops, (pattern->n_stops + 1) *
sizeof (pixman_gradient_stop_t));
if (new_stops == NULL)
{
_cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY);
return;
if (pattern->n_stops >= pattern->stops_size) {
cairo_status_t status = _cairo_pattern_gradient_grow (pattern);
if (status) {
_cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY);
return;
}
}
pattern->stops = new_stops;
stops = pattern->stops;
x = _cairo_fixed_from_double (offset);
for (i = 0; i < pattern->n_stops; i++)
{
if (x < new_stops[i].x)
if (x < stops[i].x)
{
memmove (&new_stops[i + 1], &new_stops[i],
memmove (&stops[i + 1], &stops[i],
sizeof (pixman_gradient_stop_t) * (pattern->n_stops - i));
break;
}
}
new_stops[i].x = x;
stops[i].x = x;
new_stops[i].color.red = red * 65535.0;
new_stops[i].color.green = green * 65535.0;
new_stops[i].color.blue = blue * 65535.0;
new_stops[i].color.alpha = alpha * 65535.0;
stops[i].color.red = _cairo_color_double_to_short (red);
stops[i].color.green = _cairo_color_double_to_short (green);
stops[i].color.blue = _cairo_color_double_to_short (blue);
stops[i].color.alpha = _cairo_color_double_to_short (alpha);
pattern->n_stops++;
}
@ -767,6 +885,15 @@ cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
*matrix = pattern->matrix;
}
/**
* cairo_pattern_set_filter:
* @pattern: a #cairo_pattern_t
* @filter: a #cairo_filter_t describing the filter to use for resizing
* the pattern
*
* Sets the filter to be used for resizing when using this pattern.
* See #cairo_filter_t for details on each filter.
**/
void
cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
{
@ -776,6 +903,15 @@ cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
pattern->filter = filter;
}
/**
* cairo_pattern_get_filter:
* @pattern: a #cairo_pattern_t
*
* Gets the current filter for a pattern. See #cairo_filter_t
* for details on each filter.
*
* Return value: the current filter used for resizing the pattern.
**/
cairo_filter_t
cairo_pattern_get_filter (cairo_pattern_t *pattern)
{
@ -1144,6 +1280,63 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
ty = 0;
}
/* XXX: Hack:
*
* The way we currently support CAIRO_EXTEND_REFLECT is to create
* an image twice bigger on each side, and create a pattern of four
* images such that the new image, when repeated, has the same effect
* of reflecting the original pattern.
*
* This is because the reflect support in pixman is broken and we
* pass repeat instead of reflect to pixman. See
* _cairo_image_surface_set_attributes() for that.
*/
if (attr->extend == CAIRO_EXTEND_REFLECT) {
cairo_t *cr;
int w,h;
cairo_rectangle_int16_t extents;
status = _cairo_surface_get_extents (pattern->surface, &extents);
if (status)
return status;
attr->extend = CAIRO_EXTEND_REPEAT;
x = extents.x;
y = extents.y;
w = 2 * extents.width;
h = 2 * extents.height;
*out = cairo_surface_create_similar (dst, dst->content, w, h);
if (!*out)
return CAIRO_STATUS_NO_MEMORY;
(*out)->device_transform = pattern->surface->device_transform;
(*out)->device_transform_inverse = pattern->surface->device_transform_inverse;
cr = cairo_create (*out);
cairo_set_source_surface (cr, pattern->surface, -x, -y);
cairo_paint (cr);
cairo_scale (cr, -1, +1);
cairo_set_source_surface (cr, pattern->surface, x-w, -y);
cairo_paint (cr);
cairo_scale (cr, +1, -1);
cairo_set_source_surface (cr, pattern->surface, x-w, y-h);
cairo_paint (cr);
cairo_scale (cr, -1, +1);
cairo_set_source_surface (cr, pattern->surface, -x, y-h);
cairo_paint (cr);
status = cairo_status (cr);
cairo_destroy (cr);
return status;
}
if (_cairo_surface_is_image (dst))
{
cairo_image_surface_t *image;
@ -1159,10 +1352,16 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
}
else
{
cairo_rectangle_int16_t extents;
status = _cairo_surface_get_extents (pattern->surface, &extents);
if (status)
return status;
/* If we're repeating, we just play it safe and clone the entire surface. */
if (attr->extend == CAIRO_EXTEND_REPEAT) {
cairo_rectangle_int16_t extents;
status = _cairo_surface_get_extents (pattern->surface, &extents);
/* If requested width and height are -1, clone the entire surface.
* This is relied on in the svg backend. */
if (attr->extend == CAIRO_EXTEND_REPEAT ||
(width == (unsigned int) -1 && height == (unsigned int) -1)) {
x = extents.x;
y = extents.y;
width = extents.width;
@ -1179,13 +1378,19 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
double y2 = y + height;
cairo_bool_t is_tight;
cairo_matrix_transform_bounding_box (&attr->matrix,
&x1, &y1, &x2, &y2,
&is_tight);
x = floor (x1);
y = floor (y1);
width = ceil (x2) - x;
height = ceil (y2) - y;
_cairo_matrix_transform_bounding_box (&attr->matrix,
&x1, &y1, &x2, &y2,
&is_tight);
/* The transform_bounding_box call may have resulted
* in a region larger than the surface, but we never
* want to clone more than the surface itself, (we
* know we're not repeating at this point due to the
* above. */
x = MAX (0, floor (x1));
y = MAX (0, floor (y1));
width = MIN (extents.width, ceil (x2)) - x;
height = MIN (extents.height, ceil (y2)) - y;
}
x += tx;
y += ty;
@ -1193,6 +1398,29 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
status = _cairo_surface_clone_similar (dst, pattern->surface,
x, y, width, height, out);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
cairo_t *cr;
*out = cairo_surface_create_similar (dst, dst->content,
width, height);
if (!*out)
return CAIRO_STATUS_NO_MEMORY;
(*out)->device_transform = pattern->surface->device_transform;
(*out)->device_transform_inverse = pattern->surface->device_transform_inverse;
/* XXX Use _cairo_surface_composite directly */
cr = cairo_create (*out);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_surface (cr, pattern->surface, -x, -y);
cairo_paint (cr);
status = cairo_status (cr);
cairo_destroy (cr);
}
}
return status;
@ -1256,10 +1484,10 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
cairo_color_t color;
_cairo_color_init_rgba (&color,
src->stops->color.red / 65536.0,
src->stops->color.green / 65536.0,
src->stops->color.blue / 65536.0,
src->stops->color.alpha / 65536.0);
src->stops->color.red / 65535.0,
src->stops->color.green / 65535.0,
src->stops->color.blue / 65535.0,
src->stops->color.alpha / 65535.0);
_cairo_pattern_init_solid (&solid, &color);
}
@ -1451,6 +1679,7 @@ _cairo_pattern_get_extents (cairo_pattern_t *pattern,
imatrix = pattern->matrix;
cairo_matrix_invert (&imatrix);
/* XXX Use _cairo_matrix_transform_bounding_box here */
for (sy = 0; sy <= 1; sy++) {
for (sx = 0; sx <= 1; sx++) {
x = surface_extents.x + sx * surface_extents.width;
@ -1569,6 +1798,7 @@ cairo_pattern_get_surface (cairo_pattern_t *pattern,
* cairo_pattern_get_color_stop_rgba
* @pattern: a #cairo_pattern_t
* @index: index of the stop to return data for
* @offset: return value for the offset of the stop, or %NULL
* @red: return value for red component of color, or %NULL
* @green: return value for green component of color, or %NULL
* @blue: return value for blue component of color, or %NULL
@ -1685,12 +1915,12 @@ cairo_pattern_get_linear_points (cairo_pattern_t *pattern,
/**
* cairo_pattern_get_radial_circles
* @pattern: a #cairo_pattern_t
* @x0: return value for the x coordinate of the center of the first (inner) circle, or %NULL
* @y0: return value for the y coordinate of the center of the first (inner) circle, or %NULL
* @r0: return value for the radius of the first (inner) circle, or %NULL
* @x1: return value for the x coordinate of the center of the second (outer) circle, or %NULL
* @y1: return value for the y coordinate of the center of the second (outer) circle, or %NULL
* @r1: return value for the radius of the second (outer) circle, or %NULL
* @x0: return value for the x coordinate of the center of the first circle, or %NULL
* @y0: return value for the y coordinate of the center of the first circle, or %NULL
* @r0: return value for the radius of the first circle, or %NULL
* @x1: return value for the x coordinate of the center of the second circle, or %NULL
* @y1: return value for the y coordinate of the center of the second circle, or %NULL
* @r1: return value for the radius of the second circle, or %NULL
*
* Gets the gradient endpoint circles for a radial gradient, each
* specified as a center coordinate and a radius.
@ -1712,17 +1942,17 @@ cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
if (x0)
*x0 = _cairo_fixed_to_double (radial->gradient.inner.x);
*x0 = _cairo_fixed_to_double (radial->gradient.c1.x);
if (y0)
*y0 = _cairo_fixed_to_double (radial->gradient.inner.y);
*y0 = _cairo_fixed_to_double (radial->gradient.c1.y);
if (r0)
*r0 = _cairo_fixed_to_double (radial->gradient.inner.radius);
*r0 = _cairo_fixed_to_double (radial->gradient.c1.radius);
if (x1)
*x1 = _cairo_fixed_to_double (radial->gradient.outer.x);
*x1 = _cairo_fixed_to_double (radial->gradient.c2.x);
if (y1)
*y1 = _cairo_fixed_to_double (radial->gradient.outer.y);
*y1 = _cairo_fixed_to_double (radial->gradient.c2.y);
if (r1)
*r1 = _cairo_fixed_to_double (radial->gradient.outer.radius);
*r1 = _cairo_fixed_to_double (radial->gradient.c2.radius);
return CAIRO_STATUS_SUCCESS;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -40,7 +40,7 @@
/* private functions */
static cairo_status_t
_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional);
_cairo_polygon_grow (cairo_polygon_t *polygon);
void
_cairo_polygon_init (cairo_polygon_t *polygon)
@ -50,42 +50,55 @@ _cairo_polygon_init (cairo_polygon_t *polygon)
polygon->edges_size = 0;
polygon->edges = NULL;
polygon->has_current_point = 0;
polygon->has_current_point = FALSE;
}
void
_cairo_polygon_fini (cairo_polygon_t *polygon)
{
if (polygon->edges_size) {
if (polygon->edges && polygon->edges != polygon->edges_embedded)
free (polygon->edges);
polygon->edges = NULL;
polygon->edges_size = 0;
polygon->num_edges = 0;
}
polygon->has_current_point = 0;
polygon->edges = NULL;
polygon->edges_size = 0;
polygon->num_edges = 0;
polygon->has_current_point = FALSE;
}
/* make room for at least one more edge */
static cairo_status_t
_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional)
_cairo_polygon_grow (cairo_polygon_t *polygon)
{
cairo_edge_t *new_edges;
int old_size = polygon->edges_size;
int new_size = polygon->num_edges + additional;
int embedded_size = sizeof (polygon->edges_embedded) / sizeof (polygon->edges_embedded[0]);
int new_size = 2 * MAX (old_size, 16);
if (new_size <= polygon->edges_size) {
/* 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;
}
polygon->edges_size = new_size;
new_edges = realloc (polygon->edges, polygon->edges_size * sizeof (cairo_edge_t));
assert (polygon->num_edges <= polygon->edges_size);
if (polygon->edges == polygon->edges_embedded) {
new_edges = malloc (new_size * sizeof (cairo_edge_t));
if (new_edges)
memcpy (new_edges, polygon->edges, old_size * sizeof (cairo_edge_t));
} else {
new_edges = realloc (polygon->edges, new_size * sizeof (cairo_edge_t));
}
if (new_edges == NULL) {
polygon->edges_size = old_size;
return CAIRO_STATUS_NO_MEMORY;
}
polygon->edges = new_edges;
polygon->edges_size = new_size;
return CAIRO_STATUS_SUCCESS;
}
@ -102,8 +115,7 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_poin
}
if (polygon->num_edges >= polygon->edges_size) {
int additional = polygon->edges_size ? polygon->edges_size : 16;
status = _cairo_polygon_grow_by (polygon, additional);
status = _cairo_polygon_grow (polygon);
if (status) {
return status;
}
@ -134,7 +146,7 @@ _cairo_polygon_move_to (cairo_polygon_t *polygon, cairo_point_t *point)
if (! polygon->has_current_point)
polygon->first_point = *point;
polygon->current_point = *point;
polygon->has_current_point = 1;
polygon->has_current_point = TRUE;
return CAIRO_STATUS_SUCCESS;
}
@ -165,7 +177,7 @@ _cairo_polygon_close (cairo_polygon_t *polygon)
if (status)
return status;
polygon->has_current_point = 0;
polygon->has_current_point = FALSE;
}
return CAIRO_STATUS_SUCCESS;

Просмотреть файл

@ -44,9 +44,12 @@ struct _cairo {
cairo_status_t status;
cairo_path_fixed_t path;
cairo_user_data_array_t user_data;
cairo_gstate_t *gstate;
cairo_gstate_t gstate_tail[1];
cairo_path_fixed_t path[1];
};
#endif /* CAIRO_PRIVATE_H */

Просмотреть файл

@ -484,18 +484,18 @@ _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface,
/* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */
for (i = 1; i < font_subset->num_glyphs; i++)
for (i = 0; i < font_subset->num_glyphs; i++)
_cairo_output_stream_printf (surface->final_stream,
"Encoding %d /g%d put\n", i, i);
_cairo_output_stream_printf (surface->final_stream,
"/CharStrings %d dict dup begin\n"
"/.notdef 0 def\n",
font_subset->num_glyphs);
font_subset->num_glyphs + 1);
for (i = 1; i < font_subset->num_glyphs; i++)
for (i = 0; i < font_subset->num_glyphs; i++)
_cairo_output_stream_printf (surface->final_stream,
"/g%d %d def\n", i, i);
"/g%d %d def\n", i, i + 1);
_cairo_output_stream_printf (surface->final_stream,
"end readonly def\n");
@ -709,8 +709,8 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
static void
_cairo_ps_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
void *closure)
_cairo_ps_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset,
void *closure)
{
cairo_ps_surface_t *surface = closure;
cairo_status_t status;
@ -728,6 +728,14 @@ _cairo_ps_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
status = _cairo_ps_surface_emit_type1_font_fallback (surface, font_subset);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return;
}
static void
_cairo_ps_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset,
void *closure)
{
cairo_ps_surface_t *surface = closure;
cairo_status_t status;
status = _cairo_ps_surface_emit_type3_font_subset (surface, font_subset);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
@ -742,9 +750,12 @@ _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface)
_cairo_output_stream_printf (surface->final_stream,
"%% _cairo_ps_surface_emit_font_subsets\n");
status = _cairo_scaled_font_subsets_foreach (surface->font_subsets,
_cairo_ps_surface_emit_font_subset,
surface);
status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
_cairo_ps_surface_emit_unscaled_font_subset,
surface);
status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
_cairo_ps_surface_emit_scaled_font_subset,
surface);
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
surface->font_subsets = NULL;
@ -798,7 +809,8 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
if (status)
goto CLEANUP_TMPFILE;
surface->font_subsets = _cairo_scaled_font_subsets_create (PS_SURFACE_MAX_GLYPHS_PER_FONT);
surface->font_subsets = _cairo_scaled_font_subsets_create (PS_SURFACE_MAX_GLYPHS_PER_FONT,
PS_SURFACE_MAX_GLYPHS_PER_FONT);
if (! surface->font_subsets)
goto CLEANUP_OUTPUT_STREAM;
@ -868,7 +880,9 @@ cairo_ps_surface_create (const char *filename,
status = _cairo_output_stream_get_status (stream);
if (status) {
_cairo_error (status);
return (cairo_surface_t*) &_cairo_surface_nil;
return (status == CAIRO_STATUS_WRITE_ERROR) ?
(cairo_surface_t*) &_cairo_surface_nil_write_error :
(cairo_surface_t*) &_cairo_surface_nil;
}
return _cairo_ps_surface_create_for_stream_internal (stream,
@ -1323,9 +1337,37 @@ color_is_gray (cairo_color_t *color)
static cairo_bool_t
surface_pattern_supported (const cairo_surface_pattern_t *pattern)
{
if (pattern->surface->backend->acquire_source_image != NULL)
return TRUE;
cairo_extend_t extend;
if (pattern->surface->backend->acquire_source_image == NULL)
return FALSE;
/* Does an ALPHA-only source surface even make sense? Maybe, but I
* don't think it's worth the extra code to support it. */
/* XXX: Need to write this function here...
content = cairo_surface_get_content (pattern->surface);
if (content == CAIRO_CONTENT_ALPHA)
return FALSE;
*/
/* Cast away the const, trusting get_extend not to muck with it.
* And I really wish I had a way to cast away just the const, and
* not potentially coerce this pointer to an incorrect type at the
* same time. :-(
*/
extend = cairo_pattern_get_extend ((cairo_pattern_t*)&pattern->base);
switch (extend) {
case CAIRO_EXTEND_NONE:
case CAIRO_EXTEND_REPEAT:
case CAIRO_EXTEND_REFLECT:
/* There's no point returning FALSE for EXTEND_PAD, as the image
* surface does not currently implement it either */
case CAIRO_EXTEND_PAD:
return TRUE;
}
ASSERT_NOT_REACHED;
return FALSE;
}
@ -1362,7 +1404,7 @@ _cairo_ps_test_force_fallbacks (void)
}
static cairo_int_status_t
operation_supported (cairo_ps_surface_t *surface,
_cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *pattern)
{
@ -1382,11 +1424,11 @@ operation_supported (cairo_ps_surface_t *surface,
}
static cairo_int_status_t
_analyze_operation (cairo_ps_surface_t *surface,
_cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *pattern)
{
if (operation_supported (surface, op, pattern))
if (_cairo_ps_surface_operation_supported (surface, op, pattern))
return CAIRO_STATUS_SUCCESS;
else
return CAIRO_INT_STATUS_UNSUPPORTED;
@ -1516,9 +1558,8 @@ _string_array_stream_create (cairo_output_stream_t *output)
* surface we can render natively in PS. */
static cairo_status_t
emit_image (cairo_ps_surface_t *surface,
_cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
cairo_image_surface_t *image,
cairo_matrix_t *matrix,
const char *name)
{
cairo_status_t status;
@ -1627,17 +1668,14 @@ emit_image (cairo_ps_surface_t *surface,
" /%sDataIndex %sDataIndex 1 add def\n"
" %sDataIndex %sData length 1 sub gt { /%sDataIndex 0 def } if\n"
" } /ASCII85Decode filter /LZWDecode filter\n"
" /ImageMatrix [ %f %f %f %f %f %f ]\n"
" /ImageMatrix [ 1 0 0 1 0 0 ]\n"
" >>\n"
" image\n"
"} def\n",
name,
opaque_image->width,
opaque_image->height,
name, name, name, name, name, name, name,
matrix->xx, matrix->yx,
matrix->xy, matrix->yy,
0.0, 0.0);
name, name, name, name, name, name, name);
status = CAIRO_STATUS_SUCCESS;
@ -1652,7 +1690,7 @@ emit_image (cairo_ps_surface_t *surface,
}
static void
emit_solid_pattern (cairo_ps_surface_t *surface,
_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
cairo_solid_pattern_t *pattern)
{
if (color_is_gray (&pattern->color))
@ -1668,12 +1706,13 @@ emit_solid_pattern (cairo_ps_surface_t *surface,
}
static void
emit_surface_pattern (cairo_ps_surface_t *surface,
_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
cairo_surface_pattern_t *pattern)
{
double bbox_width, bbox_height;
int xstep, ystep;
double xstep, ystep;
cairo_matrix_t inverse = pattern->base.matrix;
cairo_matrix_invert (&inverse);
if (_cairo_surface_is_meta (pattern->surface)) {
@ -1694,32 +1733,49 @@ emit_surface_pattern (cairo_ps_surface_t *surface,
&image_extra);
assert (status == CAIRO_STATUS_SUCCESS);
emit_image (surface, image, &pattern->base.matrix, "MyPattern");
_cairo_ps_surface_emit_image (surface, image, "MyPattern");
bbox_width = image->width;
bbox_height = image->height;
cairo_matrix_transform_distance (&inverse,
&bbox_width, &bbox_height);
/* In PostScript, (as far as I can tell), all patterns are
* repeating. So we support cairo's EXTEND_NONE semantics by
* setting the repeat step size to the larger of the image size
* and the extents of the destination surface. That way we
* guarantee the pattern will not repeat.
*/
switch (pattern->base.extend) {
/* We implement EXTEND_PAD like EXTEND_NONE for now */
case CAIRO_EXTEND_PAD:
case CAIRO_EXTEND_NONE:
xstep = MAX (image->width, surface->width);
ystep = MAX (image->height, surface->height);
{
/* In PS/PDF, (as far as I can tell), all patterns are
* repeating. So we support cairo's EXTEND_NONE semantics
* by setting the repeat step size to a size large enough
* to guarantee that no more than a single occurrence will
* be visible.
*
* First, map the surface extents into pattern space (since
* xstep and ystep are in pattern space). Then use an upper
* bound on the length of the diagonal of the pattern image
* and the surface as repeat size. This guarantees to never
* repeat visibly.
*/
double x1 = 0.0, y1 = 0.0;
double x2 = surface->width, y2 = surface->height;
_cairo_matrix_transform_bounding_box (&pattern->base.matrix,
&x1, &y1, &x2, &y2,
NULL);
/* Rather than computing precise bounds of the union, just
* add the surface extents unconditionally. We only
* required an answer that's large enough, we don't really
* care if it's not as tight as possible.*/
xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
image->width + image->height);
break;
}
case CAIRO_EXTEND_REPEAT:
case CAIRO_EXTEND_REFLECT:
xstep = image->width;
ystep = image->height;
break;
/* All the rest should have been analyzed away, so these cases
* should be unreachable. */
case CAIRO_EXTEND_REFLECT:
case CAIRO_EXTEND_PAD:
/* All the rest (if any) should have been analyzed away, so these
* cases should be unreachable. */
default:
ASSERT_NOT_REACHED;
xstep = 0;
@ -1734,37 +1790,39 @@ emit_surface_pattern (cairo_ps_surface_t *surface,
" /PaintType 1\n"
" /TilingType 1\n");
_cairo_output_stream_printf (surface->stream,
" /BBox [0 0 %d %d]\n",
(int) bbox_width, (int) bbox_height);
" /BBox [0 0 %f %f]\n",
bbox_width, bbox_height);
_cairo_output_stream_printf (surface->stream,
" /XStep %d /YStep %d\n",
" /XStep %f /YStep %f\n",
xstep, ystep);
_cairo_output_stream_printf (surface->stream,
" /PaintProc { MyPattern } bind\n"
">>\n");
_cairo_output_stream_printf (surface->stream,
"[ 1 0 0 1 %f %f ]\n",
"[ %f %f %f %f %f %f ]\n",
inverse.xx, inverse.yx,
inverse.xy, inverse.yy,
inverse.x0, inverse.y0);
_cairo_output_stream_printf (surface->stream,
"makepattern setpattern\n");
}
static void
emit_linear_pattern (cairo_ps_surface_t *surface,
_cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface,
cairo_linear_pattern_t *pattern)
{
/* XXX: NYI */
}
static void
emit_radial_pattern (cairo_ps_surface_t *surface,
_cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface,
cairo_radial_pattern_t *pattern)
{
/* XXX: NYI */
}
static void
emit_pattern (cairo_ps_surface_t *surface, cairo_pattern_t *pattern)
_cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, cairo_pattern_t *pattern)
{
/* FIXME: We should keep track of what pattern is currently set in
* the postscript file and only emit code if we're setting a
@ -1772,19 +1830,19 @@ emit_pattern (cairo_ps_surface_t *surface, cairo_pattern_t *pattern)
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
_cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
break;
case CAIRO_PATTERN_TYPE_SURFACE:
emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern);
_cairo_ps_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern);
break;
case CAIRO_PATTERN_TYPE_LINEAR:
emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
_cairo_ps_surface_emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
break;
case CAIRO_PATTERN_TYPE_RADIAL:
emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern);
_cairo_ps_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern);
break;
}
}
@ -1874,7 +1932,7 @@ _cairo_ps_surface_paint (void *abstract_surface,
cairo_rectangle_int16_t extents, pattern_extents;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, source);
return _cairo_ps_surface_analyze_operation (surface, op, source);
/* XXX: It would be nice to be able to assert this condition
* here. But, we actually allow one 'cheat' that is used when
@ -1883,7 +1941,7 @@ _cairo_ps_surface_paint (void *abstract_surface,
* possible only because there is nothing between the fallback
* images and the paper, nor is anything painted above. */
/*
assert (_operation_supported (op, source));
assert (__cairo_ps_surface_operation_supported (op, source));
*/
_cairo_output_stream_printf (stream,
@ -1893,7 +1951,7 @@ _cairo_ps_surface_paint (void *abstract_surface,
_cairo_pattern_get_extents (source, &pattern_extents);
_cairo_rectangle_intersect (&extents, &pattern_extents);
emit_pattern (surface, source);
_cairo_ps_surface_emit_pattern (surface, source);
_cairo_output_stream_printf (stream, "%d %d M\n",
extents.x, extents.y);
@ -1961,9 +2019,9 @@ _cairo_ps_surface_stroke (void *abstract_surface,
double dash_offset = style->dash_offset;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, source);
return _cairo_ps_surface_analyze_operation (surface, op, source);
assert (operation_supported (surface, op, source));
assert (_cairo_ps_surface_operation_supported (surface, op, source));
_cairo_output_stream_printf (stream,
@ -2032,7 +2090,7 @@ _cairo_ps_surface_stroke (void *abstract_surface,
}
}
emit_pattern (surface, source);
_cairo_ps_surface_emit_pattern (surface, source);
_cairo_output_stream_printf (stream,
"gsave\n");
@ -2092,14 +2150,14 @@ _cairo_ps_surface_fill (void *abstract_surface,
const char *ps_operator;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, source);
return _cairo_ps_surface_analyze_operation (surface, op, source);
assert (operation_supported (surface, op, source));
assert (_cairo_ps_surface_operation_supported (surface, op, source));
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_fill\n");
emit_pattern (surface, source);
_cairo_ps_surface_emit_pattern (surface, source);
/* We're filling not stroking, so we pass CAIRO_LINE_CAP_ROUND. */
status = _cairo_ps_surface_emit_path (surface, stream, path,
@ -2150,9 +2208,9 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
cairo_output_stream_t *word_wrap;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, source);
return _cairo_ps_surface_analyze_operation (surface, op, source);
assert (operation_supported (surface, op, source));
assert (_cairo_ps_surface_operation_supported (surface, op, source));
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_show_glyphs\n");
@ -2162,7 +2220,7 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
num_glyphs_unsigned = num_glyphs;
emit_pattern (surface, source);
_cairo_ps_surface_emit_pattern (surface, source);
glyph_ids = malloc (num_glyphs_unsigned*sizeof (cairo_ps_glyph_id_t));
if (glyph_ids == NULL)
return CAIRO_STATUS_NO_MEMORY;

Просмотреть файл

@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Calum Robinson
* Copyright (C) 2006,2007 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@ -31,36 +32,43 @@
*
* Contributor(s):
* Calum Robinson <calumr@mac.com>
* Vladimir Vukicevic <vladimir@mozilla.com>
*/
#ifndef CAIRO_QUARTZ_PRIVATE_H
#define CAIRO_QUARTZ_PRIVATE_H
#include <cairoint.h>
#ifdef CAIRO_HAS_QUARTZ_SURFACE
#include <cairo-quartz.h>
typedef struct cairo_quartz_surface {
cairo_surface_t base;
CGContextRef context;
void *imageData;
cairo_bool_t y_grows_down;
CGContextRef cgContext;
CGAffineTransform cgContextBaseCTM;
cairo_rectangle_int16_t extents;
pixman_region16_t *clip_region;
/* These are stored while drawing operations are in place, set up
* by quartz_setup_source() and quartz_finish_source()
*/
CGAffineTransform imageTransform;
CGImageRef sourceImage;
CGShadingRef sourceShading;
CGPatternRef sourcePattern;
} cairo_quartz_surface_t;
#endif /* CAIRO_HAS_QUARTZ_SURFACE */
cairo_bool_t
_cairo_surface_is_quartz (cairo_surface_t *surface);
cairo_bool_t
_cairo_scaled_font_is_atsui (cairo_scaled_font_t *sfont);
#if CAIRO_HAS_ATSUI_FONT
ATSUStyle
_cairo_atsui_scaled_font_get_atsu_style (cairo_scaled_font_t *sfont);
ATSUFontID
_cairo_atsui_scaled_font_get_atsu_font_id (cairo_scaled_font_t *sfont);
#endif /* CAIRO_HAS_ATSUI_FONT */
#endif /* CAIRO_QUARTZ_PRIVATE_H */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2006, 2007 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@ -27,11 +27,10 @@
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
* The Initial Developer of the Original Code is Mozilla Corporation.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Vladimir Vukicevic <vladimir@mozilla.com>
*/
#ifndef CAIRO_QUARTZ_H
@ -46,10 +45,17 @@
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_quartz_surface_create (CGContextRef context,
int width,
int height,
cairo_bool_t y_grows_down);
cairo_quartz_surface_create (cairo_format_t format,
unsigned int width,
unsigned int height);
cairo_public cairo_surface_t *
cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
unsigned int width,
unsigned int height);
cairo_public CGContextRef
cairo_quartz_surface_get_cg_context (cairo_surface_t *surface);
CAIRO_END_DECLS

Просмотреть файл

@ -35,6 +35,7 @@
#define cairo_fill_preserve _moz_cairo_fill_preserve
#define cairo_font_extents _moz_cairo_font_extents
#define cairo_font_face_destroy _moz_cairo_font_face_destroy
#define cairo_font_face_get_reference_count _moz_cairo_font_face_get_reference_count
#define cairo_font_face_get_type _moz_cairo_font_face_get_type
#define cairo_font_face_get_user_data _moz_cairo_font_face_get_user_data
#define cairo_font_face_reference _moz_cairo_font_face_reference
@ -75,9 +76,12 @@
#define cairo_get_matrix _moz_cairo_get_matrix
#define cairo_get_miter_limit _moz_cairo_get_miter_limit
#define cairo_get_operator _moz_cairo_get_operator
#define cairo_get_reference_count _moz_cairo_get_reference_count
#define cairo_get_scaled_font _moz_cairo_get_scaled_font
#define cairo_get_source _moz_cairo_get_source
#define cairo_get_target _moz_cairo_get_target
#define cairo_get_tolerance _moz_cairo_get_tolerance
#define cairo_get_user_data _moz_cairo_get_user_data
#define cairo_glitz_surface_create _moz_cairo_glitz_surface_create
#define cairo_glyph_extents _moz_cairo_glyph_extents
#define cairo_glyph_path _moz_cairo_glyph_path
@ -105,17 +109,12 @@
#define cairo_matrix_multiply _moz_cairo_matrix_multiply
#define cairo_matrix_rotate _moz_cairo_matrix_rotate
#define cairo_matrix_scale _moz_cairo_matrix_scale
#define cairo_matrix_transform_bounding_box _moz_cairo_matrix_transform_bounding_box
#define cairo_matrix_transform_distance _moz_cairo_matrix_transform_distance
#define cairo_matrix_transform_point _moz_cairo_matrix_transform_point
#define cairo_matrix_translate _moz_cairo_matrix_translate
#define cairo_move_to _moz_cairo_move_to
#define cairo_new_path _moz_cairo_new_path
#define cairo_new_sub_path _moz_cairo_new_sub_path
#define cairo_nquartz_surface_create _moz_cairo_nquartz_surface_create
#define cairo_nquartz_surface_create_for_agl_context _moz_cairo_nquartz_surface_create_for_agl_context
#define cairo_nquartz_surface_create_for_cg_context _moz_cairo_nquartz_surface_create_for_cg_context
#define cairo_nquartz_surface_get_cg_context _moz_cairo_nquartz_surface_get_cg_context
#define cairo_os2_fini _moz_cairo_os2_fini
#define cairo_os2_init _moz_cairo_os2_init
#define cairo_os2_surface_create _moz_cairo_os2_surface_create
@ -142,13 +141,16 @@
#define cairo_pattern_get_linear_points _moz_cairo_pattern_get_linear_points
#define cairo_pattern_get_matrix _moz_cairo_pattern_get_matrix
#define cairo_pattern_get_radial_circles _moz_cairo_pattern_get_radial_circles
#define cairo_pattern_get_reference_count _moz_cairo_pattern_get_reference_count
#define cairo_pattern_get_rgba _moz_cairo_pattern_get_rgba
#define cairo_pattern_get_surface _moz_cairo_pattern_get_surface
#define cairo_pattern_get_type _moz_cairo_pattern_get_type
#define cairo_pattern_get_user_data _moz_cairo_pattern_get_user_data
#define cairo_pattern_reference _moz_cairo_pattern_reference
#define cairo_pattern_set_extend _moz_cairo_pattern_set_extend
#define cairo_pattern_set_filter _moz_cairo_pattern_set_filter
#define cairo_pattern_set_matrix _moz_cairo_pattern_set_matrix
#define cairo_pattern_set_user_data _moz_cairo_pattern_set_user_data
#define cairo_pattern_status _moz_cairo_pattern_status
#define cairo_pdf_surface_create _moz_cairo_pdf_surface_create
#define cairo_pdf_surface_create_for_stream _moz_cairo_pdf_surface_create_for_stream
@ -164,6 +166,8 @@
#define cairo_push_group _moz_cairo_push_group
#define cairo_push_group_with_content _moz_cairo_push_group_with_content
#define cairo_quartz_surface_create _moz_cairo_quartz_surface_create
#define cairo_quartz_surface_create_for_cg_context _moz_cairo_quartz_surface_create_for_cg_context
#define cairo_quartz_surface_get_cg_context _moz_cairo_quartz_surface_get_cg_context
#define cairo_rectangle _moz_cairo_rectangle
#define cairo_rectangle_list_destroy _moz_cairo_rectangle_list_destroy
#define cairo_reference _moz_cairo_reference
@ -182,9 +186,12 @@
#define cairo_scaled_font_get_font_face _moz_cairo_scaled_font_get_font_face
#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_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
#define cairo_scaled_font_reference _moz_cairo_scaled_font_reference
#define cairo_scaled_font_set_user_data _moz_cairo_scaled_font_set_user_data
#define cairo_scaled_font_status _moz_cairo_scaled_font_status
#define cairo_scaled_font_text_extents _moz_cairo_scaled_font_text_extents
#define cairo_select_font_face _moz_cairo_select_font_face
@ -207,6 +214,7 @@
#define cairo_set_source_rgba _moz_cairo_set_source_rgba
#define cairo_set_source_surface _moz_cairo_set_source_surface
#define cairo_set_tolerance _moz_cairo_set_tolerance
#define cairo_set_user_data _moz_cairo_set_user_data
#define cairo_show_glyphs _moz_cairo_show_glyphs
#define cairo_show_page _moz_cairo_show_page
#define cairo_show_text _moz_cairo_show_text
@ -226,7 +234,6 @@
#define cairo_surface_get_reference_count _moz_cairo_surface_get_reference_count
#define cairo_surface_get_type _moz_cairo_surface_get_type
#define cairo_surface_get_user_data _moz_cairo_surface_get_user_data
#define cairo_surface_is_nquartz _moz_cairo_surface_is_nquartz
#define cairo_surface_mark_dirty _moz_cairo_surface_mark_dirty
#define cairo_surface_mark_dirty_rectangle _moz_cairo_surface_mark_dirty_rectangle
#define cairo_surface_reference _moz_cairo_surface_reference

Просмотреть файл

@ -41,23 +41,17 @@
typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t;
typedef struct _cairo_scaled_font_subset {
cairo_scaled_font_t *scaled_font;
unsigned int font_id;
unsigned int subset_id;
/* Index of glyphs array is subset_glyph_index.
* Value of glyphs array is scaled_font_glyph_index.
*/
unsigned long *glyphs;
unsigned int num_glyphs;
} cairo_scaled_font_subset_t;
/**
* _cairo_scaled_font_subsets_create:
* @max_glyphs_per_subset: the maximum number of glyphs that should
* appear in any subset. A value of 0 indicates that there is no limit
* to the number of glyphs per subset.
*
* @max_glyphs_per_unscaled_subset: the maximum number of glyphs that
* should appear in any unscaled subset. A value of 0 indicates that
* no unscaled subset will be created. All glyphs will mapped to
* scaled subsets.
*
* @max_glyphs_per_scaled_subset: the maximum number of glyphs that
* should appear in any scaled subset. A value of 0 indicates that
* no scaled subset will be created.
*
* Create a new #cairo_scaled_font_subsets_t object which can be used
* to create subsets of any number of cairo_scaled_font_t
@ -66,12 +60,16 @@ typedef struct _cairo_scaled_font_subset {
* subsets with glyph indices packed into the range
* [0 .. max_glyphs_per_subset).
*
* @max_glyphs_per_unscaled_subset and @max_glyphs_per_scaled_subset
* cannot both be 0.
*
* Return value: a pointer to the newly creates font subsets. The
* caller owns this object and should call
* _cairo_scaled_font_subsets_destroy() when done with it.
**/
cairo_private cairo_scaled_font_subsets_t *
_cairo_scaled_font_subsets_create (int max_glyphs_per_subset);
_cairo_scaled_font_subsets_create (int max_glyphs_unscaled_per_subset,
int max_glyphs_scaled_per_subset);
/**
* _cairo_scaled_font_subsets_destroy:
@ -150,7 +148,7 @@ typedef void
* @font_subset_callback: a function to be called for each font subset
* @closure: closure data for the callback function
*
* Iterate over each unique font subset as created by calls to
* Iterate over each unique scaled font subset as created by calls to
* _cairo_scaled_font_subsets_map_glyph(). A subset is determined by
* unique pairs of (font_id, subset_id) as returned by
* _cairo_scaled_font_subsets_map_glyph().
@ -175,9 +173,44 @@ typedef void
* CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_scaled_font_subsets_foreach (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_subset_callback_func_t font_subset_callback,
void *closure);
_cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_subset_callback_func_t font_subset_callback,
void *closure);
/**
* _cairo_scaled_font_subsets_foreach_unscaled:
* @font_subsets: a #cairo_scaled_font_subsets_t
* @font_subset_callback: a function to be called for each font subset
* @closure: closure data for the callback function
*
* Iterate over each unique unscaled font subset as created by calls to
* _cairo_scaled_font_subsets_map_glyph(). A subset is determined by
* unique pairs of (font_id, subset_id) as returned by
* _cairo_scaled_font_subsets_map_glyph().
*
* For each subset, @font_subset_callback will be called and will be
* provided with both a #cairo_scaled_font_subset_t object containing
* all the glyphs in the subset as well as the value of @closure.
*
* The #cairo_scaled_font_subset_t object contains the scaled_font,
* the font_id, and the subset_id corresponding to all glyphs
* belonging to the subset. In addition, it contains an array providing
* a mapping between subset glyph indices and the original scaled font
* glyph indices.
*
* The index of the array corresponds to subset_glyph_index values
* returned by _cairo_scaled_font_subsets_map_glyph() while the
* values of the array correspond to the scaled_font_glyph_index
* values passed as input to the same function.
*
* Return value: CAIRO_STATUS_SUCCESS if successful, or a non-zero
* value indicating an error. Possible errors include
* CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_subset_callback_func_t font_subset_callback,
void *closure);
typedef struct _cairo_cff_subset {
char *base_font;
@ -222,9 +255,9 @@ _cairo_cff_subset_fini (cairo_cff_subset_t *cff_subset);
typedef struct _cairo_truetype_subset {
char *base_font;
int *widths;
long x_min, y_min, x_max, y_max;
long ascent, descent;
double *widths;
double x_min, y_min, x_max, y_max;
double ascent, descent;
char *data;
unsigned long data_length;
unsigned long *string_offsets;
@ -361,4 +394,21 @@ _cairo_type1_fallback_init_hex (cairo_type1_subset_t *type_subset,
cairo_private void
_cairo_type1_fallback_fini (cairo_type1_subset_t *subset);
/**
* _cairo_truetype_create_glyph_to_unicode_map:
* @font_subset: the #cairo_scaled_font_subset_t to initialize from
*
* If possible (depending on the format of the underlying
* cairo_scaled_font_t and the font backend in use) assign
* the unicode character of each glyph in font_subset to
* fontsubset->to_unicode.
*
* Return value: CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the unicode encoding of
* the glyphs is not available. Possible errors include
* CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_int_status_t
_cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t *font_subset);
#endif /* CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H */

Просмотреть файл

@ -43,16 +43,21 @@
#include "cairo-scaled-font-subsets-private.h"
struct _cairo_scaled_font_subsets {
int max_glyphs_per_subset_limit;
int max_glyphs_per_subset_used;
int num_sub_fonts;
int max_glyphs_per_unscaled_subset_limit;
int max_glyphs_per_unscaled_subset_used;
cairo_hash_table_t *unscaled_sub_fonts;
cairo_hash_table_t *sub_fonts;
int max_glyphs_per_scaled_subset_limit;
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;
cairo_bool_t is_scaled;
cairo_scaled_font_subsets_t *parent;
cairo_scaled_font_t *scaled_font;
unsigned int font_id;
@ -163,22 +168,34 @@ _cairo_sub_fonts_equal (const void *key_a, const void *key_b)
const cairo_sub_font_t *sub_font_a = key_a;
const cairo_sub_font_t *sub_font_b = key_b;
return sub_font_a->scaled_font == sub_font_b->scaled_font;
if (sub_font_a->is_scaled)
return sub_font_a->scaled_font == sub_font_b->scaled_font;
else
return sub_font_a->scaled_font->font_face == sub_font_b->scaled_font->font_face;
}
static void
_cairo_sub_font_init_key (cairo_sub_font_t *sub_font,
cairo_scaled_font_t *scaled_font)
{
sub_font->base.hash = (unsigned long) scaled_font;
sub_font->scaled_font = scaled_font;
if (sub_font->is_scaled)
{
sub_font->base.hash = (unsigned long) scaled_font;
sub_font->scaled_font = scaled_font;
}
else
{
sub_font->base.hash = (unsigned long) scaled_font->font_face;
sub_font->scaled_font = scaled_font;
}
}
static cairo_sub_font_t *
_cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
cairo_scaled_font_t *scaled_font,
unsigned int font_id,
int max_glyphs_per_subset)
int max_glyphs_per_subset,
cairo_bool_t is_scaled)
{
cairo_sub_font_t *sub_font;
@ -186,6 +203,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
if (sub_font == NULL)
return NULL;
sub_font->is_scaled = is_scaled;
_cairo_sub_font_init_key (sub_font, scaled_font);
sub_font->parent = parent;
@ -226,6 +244,27 @@ _cairo_sub_font_pluck (void *entry, void *closure)
_cairo_sub_font_destroy (sub_font);
}
static cairo_status_t
_cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
unsigned long scaled_font_glyph_index,
unsigned int *subset_id,
unsigned int *subset_glyph_index)
{
cairo_sub_font_glyph_t key, *sub_font_glyph;
_cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
if (_cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base,
(cairo_hash_entry_t **) &sub_font_glyph))
{
*subset_id = sub_font_glyph->subset_id;
*subset_glyph_index = sub_font_glyph->subset_glyph_index;
return CAIRO_STATUS_SUCCESS;
}
return CAIRO_STATUS_NULL_POINTER;
}
static cairo_status_t
_cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
unsigned long scaled_font_glyph_index,
@ -239,8 +278,7 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
if (! _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base,
(cairo_hash_entry_t **) &sub_font_glyph))
{
if (sub_font->max_glyphs_per_subset &&
sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset)
if (sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset)
{
sub_font->current_subset++;
sub_font->num_glyphs_in_current_subset = 0;
@ -252,8 +290,16 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
if (sub_font_glyph == NULL)
return CAIRO_STATUS_NO_MEMORY;
if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_subset_used)
sub_font->parent->max_glyphs_per_subset_used = sub_font->num_glyphs_in_current_subset;
if (sub_font->is_scaled)
{
if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_scaled_subset_used)
sub_font->parent->max_glyphs_per_scaled_subset_used = sub_font->num_glyphs_in_current_subset;
}
else
{
if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_unscaled_subset_used)
sub_font->parent->max_glyphs_per_unscaled_subset_used = sub_font->num_glyphs_in_current_subset;
}
status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
if (status)
@ -273,6 +319,7 @@ _cairo_sub_font_collect (void *entry, void *closure)
cairo_sub_font_collection_t *collection = closure;
cairo_scaled_font_subset_t subset;
int i;
unsigned int j;
for (i = 0; i <= sub_font->current_subset; i++) {
collection->subset_id = i;
@ -291,14 +338,26 @@ _cairo_sub_font_collect (void *entry, void *closure)
subset.subset_id = i;
subset.glyphs = collection->glyphs;
subset.num_glyphs = collection->num_glyphs;
(collection->font_subset_callback) (&subset,
/* No need to check for out of memory here. If to_unicode is NULL, the PDF
* surface does not emit an ToUnicode stream */
subset.to_unicode = malloc (collection->num_glyphs*sizeof(unsigned long));
if (subset.to_unicode) {
for (j = 0; j < collection->num_glyphs; j++) {
/* default unicode character required when mapping fails */
subset.to_unicode[j] = 0xfffd;
}
}
(collection->font_subset_callback) (&subset,
collection->font_subset_callback_closure);
if (subset.to_unicode != NULL)
free (subset.to_unicode);
}
}
cairo_scaled_font_subsets_t *
_cairo_scaled_font_subsets_create (int max_glyphs_per_subset)
_cairo_scaled_font_subsets_create (int max_glyphs_per_unscaled_subset,
int max_glyphs_per_scaled_subset)
{
cairo_scaled_font_subsets_t *subsets;
@ -306,12 +365,23 @@ _cairo_scaled_font_subsets_create (int max_glyphs_per_subset)
if (subsets == NULL)
return NULL;
subsets->max_glyphs_per_subset_limit = max_glyphs_per_subset;
subsets->max_glyphs_per_subset_used = 0;
subsets->max_glyphs_per_unscaled_subset_limit = max_glyphs_per_unscaled_subset;
subsets->max_glyphs_per_unscaled_subset_used = 0;
subsets->max_glyphs_per_scaled_subset_limit = max_glyphs_per_scaled_subset;
subsets->max_glyphs_per_scaled_subset_used = 0;
subsets->num_sub_fonts = 0;
subsets->sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
if (! subsets->sub_fonts) {
subsets->unscaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
if (! subsets->unscaled_sub_fonts) {
free (subsets);
return NULL;
}
subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
if (! subsets->scaled_sub_fonts) {
free (subsets->unscaled_sub_fonts);
free (subsets);
return NULL;
}
@ -322,8 +392,11 @@ _cairo_scaled_font_subsets_create (int max_glyphs_per_subset)
void
_cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets)
{
_cairo_hash_table_foreach (subsets->sub_fonts, _cairo_sub_font_pluck, subsets->sub_fonts);
_cairo_hash_table_destroy (subsets->sub_fonts);
_cairo_hash_table_foreach (subsets->scaled_sub_fonts, _cairo_sub_font_pluck, subsets->scaled_sub_fonts);
_cairo_hash_table_destroy (subsets->scaled_sub_fonts);
_cairo_hash_table_foreach (subsets->unscaled_sub_fonts, _cairo_sub_font_pluck, subsets->unscaled_sub_fonts);
_cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
free (subsets);
}
@ -336,38 +409,106 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
unsigned int *subset_glyph_index)
{
cairo_sub_font_t key, *sub_font;
cairo_scaled_glyph_t *scaled_glyph;
cairo_status_t status;
_cairo_sub_font_init_key (&key, scaled_font);
if (! _cairo_hash_table_lookup (subsets->sub_fonts, &key.base,
(cairo_hash_entry_t **) &sub_font))
{
sub_font = _cairo_sub_font_create (subsets, scaled_font,
subsets->num_sub_fonts++,
subsets->max_glyphs_per_subset_limit);
if (sub_font == NULL)
return CAIRO_STATUS_NO_MEMORY;
status = _cairo_hash_table_insert (subsets->sub_fonts,
&sub_font->base);
if (status)
return status;
/* Lookup glyph in unscaled subsets */
if (subsets->max_glyphs_per_unscaled_subset_limit > 0) {
key.is_scaled = FALSE;
_cairo_sub_font_init_key (&key, scaled_font);
if (_cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base,
(cairo_hash_entry_t **) &sub_font))
{
status = _cairo_sub_font_lookup_glyph (sub_font, scaled_font_glyph_index,
subset_id, subset_glyph_index);
if (status == CAIRO_STATUS_SUCCESS) {
*font_id = sub_font->font_id;
return CAIRO_STATUS_SUCCESS;
}
}
}
/* Lookup glyph in scaled subsets */
if (subsets->max_glyphs_per_scaled_subset_limit > 0) {
key.is_scaled = TRUE;
_cairo_sub_font_init_key (&key, scaled_font);
if (_cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base,
(cairo_hash_entry_t **) &sub_font))
{
status = _cairo_sub_font_lookup_glyph (sub_font, scaled_font_glyph_index,
subset_id, subset_glyph_index);
if (status == CAIRO_STATUS_SUCCESS) {
*font_id = sub_font->font_id;
return CAIRO_STATUS_SUCCESS;
}
}
}
/* Glyph not found. Determine whether the glyph is outline or
* bitmap and add to the appropriate subset */
status = _cairo_scaled_glyph_lookup (scaled_font,
scaled_font_glyph_index,
CAIRO_SCALED_GLYPH_INFO_PATH,
&scaled_glyph);
if (status == 0 && subsets->max_glyphs_per_unscaled_subset_limit > 0) {
/* Path available. Add to unscaled subset. */
key.is_scaled = FALSE;
_cairo_sub_font_init_key (&key, scaled_font);
if (! _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base,
(cairo_hash_entry_t **) &sub_font))
{
sub_font = _cairo_sub_font_create (subsets, scaled_font,
subsets->num_sub_fonts++,
subsets->max_glyphs_per_unscaled_subset_limit,
FALSE);
if (sub_font == NULL)
return CAIRO_STATUS_NO_MEMORY;
status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
&sub_font->base);
if (status)
return status;
}
} else if (subsets->max_glyphs_per_scaled_subset_limit > 0) {
/* No path available. Add to scaled subset. */
key.is_scaled = TRUE;
_cairo_sub_font_init_key (&key, scaled_font);
if (! _cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base,
(cairo_hash_entry_t **) &sub_font))
{
sub_font = _cairo_sub_font_create (subsets, scaled_font,
subsets->num_sub_fonts++,
subsets->max_glyphs_per_scaled_subset_limit,
TRUE);
if (sub_font == NULL)
return CAIRO_STATUS_NO_MEMORY;
status = _cairo_hash_table_insert (subsets->scaled_sub_fonts,
&sub_font->base);
if (status)
return status;
}
} else {
return CAIRO_INT_STATUS_UNSUPPORTED;
}
*font_id = sub_font->font_id;
return _cairo_sub_font_map_glyph (sub_font, scaled_font_glyph_index,
subset_id, subset_glyph_index);
subset_id, subset_glyph_index);
}
cairo_private cairo_status_t
_cairo_scaled_font_subsets_foreach (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_subset_callback_func_t font_subset_callback,
void *closure)
static cairo_status_t
_cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_subset_callback_func_t font_subset_callback,
void *closure,
cairo_bool_t is_scaled)
{
cairo_sub_font_collection_t collection;
collection.glyphs_size = font_subsets->max_glyphs_per_subset_used;
if (is_scaled)
collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
else
collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used;
collection.glyphs = malloc (collection.glyphs_size * sizeof(unsigned long));
if (collection.glyphs == NULL)
return CAIRO_STATUS_NO_MEMORY;
@ -375,10 +516,36 @@ _cairo_scaled_font_subsets_foreach (cairo_scaled_font_subsets_t *font_subsets,
collection.font_subset_callback = font_subset_callback;
collection.font_subset_callback_closure = closure;
_cairo_hash_table_foreach (font_subsets->sub_fonts,
_cairo_sub_font_collect, &collection);
if (is_scaled)
_cairo_hash_table_foreach (font_subsets->scaled_sub_fonts,
_cairo_sub_font_collect, &collection);
else
_cairo_hash_table_foreach (font_subsets->unscaled_sub_fonts,
_cairo_sub_font_collect, &collection);
free (collection.glyphs);
return CAIRO_STATUS_SUCCESS;
}
cairo_private cairo_status_t
_cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_subset_callback_func_t font_subset_callback,
void *closure)
{
return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
font_subset_callback,
closure,
TRUE);
}
cairo_private cairo_status_t
_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_subset_callback_func_t font_subset_callback,
void *closure)
{
return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
font_subset_callback,
closure,
FALSE);
}

Просмотреть файл

@ -1,5 +1,5 @@
/* $Id: cairo-scaled-font.c,v 1.15 2007/04/03 19:21:53 vladimir%pobox.com Exp $
*
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/*
* Copyright © 2005 Keith Packard
*
* This library is free software; you can redistribute it and/or
@ -71,10 +71,11 @@ _cairo_scaled_glyph_destroy (void *abstract_glyph)
free (scaled_glyph);
}
static const cairo_scaled_font_t _cairo_scaled_font_nil = {
const cairo_scaled_font_t _cairo_scaled_font_nil = {
{ 0 }, /* hash_entry */
CAIRO_STATUS_NO_MEMORY, /* status */
CAIRO_REF_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */
NULL, /* font_face */
{ 1., 0., 0., 1., 0, 0}, /* font_matrix */
{ 1., 0., 0., 1., 0, 0}, /* ctm */
@ -84,6 +85,7 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = {
CAIRO_HINT_METRICS_DEFAULT} ,
{ 1., 0., 0., 1., 0, 0}, /* scale */
{ 0., 0., 0., 0., 0. }, /* extents */
CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */
NULL, /* glyphs */
NULL, /* surface_backend */
NULL, /* surface_private */
@ -183,7 +185,7 @@ typedef struct _cairo_scaled_font_map {
static cairo_scaled_font_map_t *cairo_scaled_font_map = NULL;
CAIRO_MUTEX_DECLARE (cairo_scaled_font_map_mutex);
CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex);
static int
_cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_key_b);
@ -191,7 +193,7 @@ _cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_
static cairo_scaled_font_map_t *
_cairo_scaled_font_map_lock (void)
{
CAIRO_MUTEX_LOCK (cairo_scaled_font_map_mutex);
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
if (cairo_scaled_font_map == NULL) {
cairo_scaled_font_map = malloc (sizeof (cairo_scaled_font_map_t));
@ -212,14 +214,14 @@ _cairo_scaled_font_map_lock (void)
CLEANUP_SCALED_FONT_MAP:
free (cairo_scaled_font_map);
CLEANUP_MUTEX_LOCK:
CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex);
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
return NULL;
}
static void
_cairo_scaled_font_map_unlock (void)
{
CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex);
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
}
void
@ -229,7 +231,7 @@ _cairo_scaled_font_map_destroy (void)
cairo_scaled_font_map_t *font_map;
cairo_scaled_font_t *scaled_font;
CAIRO_MUTEX_LOCK (cairo_scaled_font_map_mutex);
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
font_map = cairo_scaled_font_map;
if (font_map == NULL) {
@ -254,7 +256,7 @@ _cairo_scaled_font_map_destroy (void)
cairo_scaled_font_map = NULL;
CLEANUP_MUTEX_LOCK:
CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex);
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
}
/* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
@ -352,6 +354,8 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
{
scaled_font->ref_count = 1;
_cairo_user_data_array_init (&scaled_font->user_data);
_cairo_scaled_font_init_key (scaled_font, font_face,
font_matrix, ctm, options);
@ -361,6 +365,7 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
&scaled_font->font_matrix,
&scaled_font->ctm);
CAIRO_MUTEX_INIT (&scaled_font->mutex);
scaled_font->glyphs = _cairo_cache_create (_cairo_scaled_glyph_keys_equal,
_cairo_scaled_glyph_destroy,
max_glyphs_cached_per_font);
@ -385,6 +390,15 @@ _cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font)
_cairo_cache_thaw (scaled_font->glyphs);
}
void
_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font)
{
_cairo_cache_destroy (scaled_font->glyphs);
scaled_font->glyphs = _cairo_cache_create (_cairo_scaled_glyph_keys_equal,
_cairo_scaled_glyph_destroy,
max_glyphs_cached_per_font);
}
void
_cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font,
cairo_font_extents_t *fs_metrics)
@ -416,12 +430,15 @@ _cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
if (scaled_font->glyphs != NULL)
_cairo_cache_destroy (scaled_font->glyphs);
CAIRO_MUTEX_FINI (&scaled_font->mutex);
if (scaled_font->surface_backend != NULL &&
scaled_font->surface_backend->scaled_font_fini != NULL)
scaled_font->surface_backend->scaled_font_fini (scaled_font);
scaled_font->backend->fini (scaled_font);
_cairo_user_data_array_fini (&scaled_font->user_data);
}
/**
@ -459,7 +476,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
font_map = _cairo_scaled_font_map_lock ();
if (font_map == NULL)
goto UNWIND;
return NULL;
_cairo_scaled_font_init_key (&key, font_face,
font_matrix, ctm, options);
@ -467,70 +484,6 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
/* 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))
{
_cairo_scaled_font_map_unlock ();
return cairo_scaled_font_reference (scaled_font);
}
/* Otherwise create it and insert it into the hash table. */
status = font_face->backend->scaled_font_create (font_face, font_matrix,
ctm, options, &scaled_font);
if (status)
goto UNWIND_FONT_MAP_LOCK;
status = _cairo_hash_table_insert (font_map->hash_table,
&scaled_font->hash_entry);
if (status)
goto UNWIND_SCALED_FONT_CREATE;
_cairo_scaled_font_map_unlock ();
return scaled_font;
UNWIND_SCALED_FONT_CREATE:
/* We can't call _cairo_scaled_font_destroy here since it expects
* that the font has already been successfully inserted into the
* hash table. */
_cairo_scaled_font_fini (scaled_font);
free (scaled_font);
UNWIND_FONT_MAP_LOCK:
_cairo_scaled_font_map_unlock ();
UNWIND:
return NULL;
}
slim_hidden_def (cairo_scaled_font_create);
/**
* cairo_scaled_font_reference:
* @scaled_font: a #cairo_scaled_font_t, (may be NULL in which case
* this function does nothing)
*
* Increases the reference count on @scaled_font by one. This prevents
* @scaled_font from being destroyed until a matching call to
* cairo_scaled_font_destroy() is made.
*
* Returns: the referenced #cairo_scaled_font_t
**/
cairo_scaled_font_t *
cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
{
cairo_scaled_font_map_t *font_map;
if (scaled_font == NULL)
return NULL;
if (scaled_font->ref_count == CAIRO_REF_COUNT_INVALID)
return scaled_font;
/* We would normally assert (scaled_font->ref_count > 0) here, but
* we are using ref_count == 0 as a legitimate case for the
* holdovers array. See below. */
/* cairo_scaled_font_t objects are cached and shared between
* threads. This works because these objects are immutable. Except
* that the reference count is mutable, so we have to do locking
* around any modification of the reference count. */
font_map = _cairo_scaled_font_map_lock ();
{
/* If the original reference count is 0, then this font must have
* been found in font_map->holdovers, (which means this caching is
@ -550,8 +503,64 @@ cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
(font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*));
}
/* We increment the reference count manually here, (rather
* than calling into cairo_scaled_font_reference), since we
* must modify the reference count while our lock is still
* held. */
scaled_font->ref_count++;
_cairo_scaled_font_map_unlock ();
} else {
/* Otherwise create it and insert it into the hash table. */
status = font_face->backend->scaled_font_create (font_face, font_matrix,
ctm, options, &scaled_font);
if (status) {
_cairo_scaled_font_map_unlock ();
return NULL;
}
status = _cairo_hash_table_insert (font_map->hash_table,
&scaled_font->hash_entry);
_cairo_scaled_font_map_unlock ();
if (status) {
/* We can't call _cairo_scaled_font_destroy here since it expects
* that the font has already been successfully inserted into the
* hash table. */
_cairo_scaled_font_fini (scaled_font);
free (scaled_font);
return NULL;
}
}
return scaled_font;
}
slim_hidden_def (cairo_scaled_font_create);
/**
* cairo_scaled_font_reference:
* @scaled_font: a #cairo_scaled_font_t, (may be NULL in which case
* this function does nothing)
*
* Increases the reference count on @scaled_font by one. This prevents
* @scaled_font from being destroyed until a matching call to
* cairo_scaled_font_destroy() is made.
*
* The number of references to a #cairo_scaled_font_t can be get using
* cairo_scaled_font_get_reference_count().
*
* Returns: the referenced #cairo_scaled_font_t
**/
cairo_scaled_font_t *
cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
{
if (scaled_font == NULL || scaled_font->ref_count == CAIRO_REF_COUNT_INVALID)
return scaled_font;
_cairo_scaled_font_map_lock ();
{
assert (scaled_font->ref_count > 0);
scaled_font->ref_count++;
}
_cairo_scaled_font_map_unlock ();
@ -571,17 +580,11 @@ void
cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
{
cairo_scaled_font_map_t *font_map;
cairo_scaled_font_t *lru = NULL;
if (scaled_font == NULL)
if (scaled_font == NULL || scaled_font->ref_count == CAIRO_REF_COUNT_INVALID)
return;
if (scaled_font->ref_count == CAIRO_REF_COUNT_INVALID)
return;
/* cairo_scaled_font_t objects are cached and shared between
* threads. This works because these objects are immutable. Except
* that the reference count is mutable, so we have to do locking
* around any modification of the reference count. */
font_map = _cairo_scaled_font_map_lock ();
{
assert (font_map != NULL);
@ -595,17 +598,13 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
* soon. To make room for it, we do actually destroy the
* least-recently-used holdover.
*/
if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS) {
cairo_scaled_font_t *lru;
if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS)
{
lru = font_map->holdovers[0];
assert (lru->ref_count == 0);
_cairo_hash_table_remove (font_map->hash_table, &lru->hash_entry);
_cairo_scaled_font_fini (lru);
free (lru);
font_map->num_holdovers--;
memmove (&font_map->holdovers[0],
&font_map->holdovers[1],
@ -617,9 +616,93 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
}
}
_cairo_scaled_font_map_unlock ();
/* 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
* else could have acquired a reference to it. So we can now
* safely call fini on it without any lock held. This is desirable
* as we never want to call into any backend function with a lock
* held. */
if (lru) {
_cairo_scaled_font_fini (lru);
free (lru);
}
}
slim_hidden_def (cairo_scaled_font_destroy);
/**
* cairo_scaled_font_get_reference_count:
* @scaled_font: a #cairo_scaled_font_t
*
* Returns the current reference count of @scaled_font.
*
* Return value: the current reference count of @scaled_font. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.4
**/
unsigned int
cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font)
{
if (scaled_font == NULL || scaled_font->ref_count == CAIRO_REF_COUNT_INVALID)
return 0;
return scaled_font->ref_count;
}
/**
* cairo_scaled_font_get_user_data:
* @scaled_font: a #cairo_scaled_font_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Return user data previously attached to @scaled_font using the
* specified key. If no user data has been attached with the given
* key this function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
*
* Since: 1.4
**/
void *
cairo_scaled_font_get_user_data (cairo_scaled_font_t *scaled_font,
const cairo_user_data_key_t *key)
{
return _cairo_user_data_array_get_data (&scaled_font->user_data,
key);
}
/**
* cairo_scaled_font_set_user_data:
* @scaled_font: a #cairo_scaled_font_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach to the #cairo_scaled_font_t
* @destroy: a #cairo_destroy_func_t which will be called when the
* #cairo_t is destroyed or when new user data is attached using the
* same key.
*
* Attach user data to @scaled_font. To remove user data from a surface,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
*
* Since: 1.4
**/
cairo_status_t
cairo_scaled_font_set_user_data (cairo_scaled_font_t *scaled_font,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
if (scaled_font->ref_count == CAIRO_REF_COUNT_INVALID)
return CAIRO_STATUS_NO_MEMORY;
return _cairo_user_data_array_set_data (&scaled_font->user_data,
key, user_data, destroy);
}
/* Public font API follows. */
/**
@ -711,6 +794,8 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
if (scaled_font->status)
return;
CAIRO_MUTEX_LOCK (scaled_font->mutex);
for (i = 0; i < num_glyphs; i++) {
double left, top, right, bottom;
@ -720,7 +805,7 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
&scaled_glyph);
if (status) {
_cairo_scaled_font_set_error (scaled_font, status);
return;
goto UNLOCK;
}
/* "Ink" extents should skip "invisible" glyphs */
@ -774,6 +859,9 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
extents->x_advance = 0.0;
extents->y_advance = 0.0;
}
UNLOCK:
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
}
slim_hidden_def (cairo_scaled_font_glyph_extents);
@ -796,24 +884,26 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
return CAIRO_STATUS_SUCCESS;
}
CAIRO_MUTEX_LOCK (scaled_font->mutex);
if (scaled_font->backend->text_to_glyphs) {
status = scaled_font->backend->text_to_glyphs (scaled_font,
x, y, utf8,
glyphs, num_glyphs);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
goto DONE;
}
status = _cairo_utf8_to_ucs4 ((unsigned char*)utf8, -1, &ucs4, num_glyphs);
if (status)
return status;
goto DONE;
*glyphs = (cairo_glyph_t *) malloc ((*num_glyphs) * (sizeof (cairo_glyph_t)));
if (*glyphs == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto FAIL;
goto DONE;
}
for (i = 0; i < *num_glyphs; i++) {
@ -829,15 +919,18 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
if (status) {
free (*glyphs);
*glyphs = NULL;
goto FAIL;
goto DONE;
}
x += scaled_glyph->metrics.x_advance;
y += scaled_glyph->metrics.y_advance;
}
FAIL:
free (ucs4);
DONE:
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
if (ucs4)
free (ucs4);
return status;
}
@ -1338,6 +1431,8 @@ _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.
*
* NOTE: This function must be called with scaled_font->mutex held.
**/
cairo_int_status_t
_cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
@ -1353,8 +1448,6 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
if (scaled_font->status)
return scaled_font->status;
CAIRO_MUTEX_LOCK (cairo_scaled_font_map_mutex);
key.hash = index;
/*
* Check cache for glyph
@ -1425,8 +1518,6 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
*scaled_glyph_ret = scaled_glyph;
}
CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex);
return status;
}

Просмотреть файл

@ -34,7 +34,7 @@
* a skip_elt_t, (which will be allocated with variable size).
*
* The caller must also pass the size of the structure to
* skip_list_init.
* _cairo_skip_list_init.
*/
typedef struct _skip_elt {
int prev_index;
@ -45,16 +45,16 @@ typedef struct _skip_elt {
#define SKIP_LIST_ELT_TO_DATA(type, elt) ((type *) ((char *) (elt) - (sizeof (type) - sizeof (skip_elt_t))))
typedef int
(*skip_list_compare_t) (void *list, void *a, void *b);
(*cairo_skip_list_compare_t) (void *list, void *a, void *b);
typedef struct _skip_list {
skip_list_compare_t compare;
cairo_skip_list_compare_t compare;
size_t elt_size;
size_t data_size;
skip_elt_t *chains[MAX_LEVEL];
skip_elt_t *freelists[MAX_LEVEL];
int max_level;
} skip_list_t;
} cairo_skip_list_t;
/* Initialize a new skip list. The compare function accepts a pointer
* to the list as well as pointers to two elements. The function must
@ -65,8 +65,8 @@ typedef struct _skip_list {
* list elements must have as its final member a skip_elt_t
*/
cairo_private void
skip_list_init (skip_list_t *list,
skip_list_compare_t compare,
_cairo_skip_list_init (cairo_skip_list_t *list,
cairo_skip_list_compare_t compare,
size_t elt_size);
@ -74,7 +74,7 @@ skip_list_init (skip_list_t *list,
* in it. (XXX: currently this simply deletes all elements.)
*/
cairo_private void
skip_list_fini (skip_list_t *list);
_cairo_skip_list_fini (cairo_skip_list_t *list);
/* Insert a new element into the list at the correct sort order as
* determined by compare. If unique is true, then duplicate elements
@ -82,18 +82,18 @@ skip_list_fini (skip_list_t *list);
* Otherwise data will be copied (elt_size bytes from <data> via
* memcpy) and the new element is returned. */
cairo_private void *
skip_list_insert (skip_list_t *list, void *data, int unique);
_cairo_skip_list_insert (cairo_skip_list_t *list, void *data, int unique);
/* Find an element which compare considers equal to <data> */
cairo_private void *
skip_list_find (skip_list_t *list, void *data);
_cairo_skip_list_find (cairo_skip_list_t *list, void *data);
/* Delete an element which compare considers equal to <data> */
cairo_private void
skip_list_delete (skip_list_t *list, void *data);
_cairo_skip_list_delete (cairo_skip_list_t *list, void *data);
/* Delete the given element from the list. */
cairo_private void
skip_list_delete_given (skip_list_t *list, skip_elt_t *given);
_cairo_skip_list_delete_given (cairo_skip_list_t *list, skip_elt_t *given);
#endif

Просмотреть файл

@ -34,7 +34,7 @@
/* Four 256 element lookup tables back to back implementing a linear
* feedback shift register of degree 32. */
static unsigned const lfsr_lut[1024] = {
static unsigned const _cairo_lfsr_random_lut[1024] = {
0x00000000, 0x9a795537, 0xae8bff59, 0x34f2aa6e, 0xc76eab85, 0x5d17feb2,
0x69e554dc, 0xf39c01eb, 0x14a4023d, 0x8edd570a, 0xba2ffd64, 0x2056a853,
0xd3caa9b8, 0x49b3fc8f, 0x7d4156e1, 0xe73803d6, 0x2948047a, 0xb331514d,
@ -207,24 +207,25 @@ static unsigned const lfsr_lut[1024] = {
0xeaa6b0df, 0x6a98c0b4, 0x184c1316, 0x9872637d, 0x8249a6f7, 0x0277d69c,
0xb63e2de3, 0x36005d88, 0x2c3b9802, 0xac05e869};
static unsigned _cairo_lfsr_random_state = 0x12345678;
static unsigned
lfsr_random(void)
{
static unsigned state = 0x12345678;
unsigned next;
next = lfsr_lut[((state>> 0) & 0xFF) + 0*256];
next ^= lfsr_lut[((state>> 8) & 0xFF) + 1*256];
next ^= lfsr_lut[((state>>16) & 0xFF) + 2*256];
next ^= lfsr_lut[((state>>24) & 0xFF) + 3*256];
return state = next;
next = _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>> 0) & 0xFF) + 0*256];
next ^= _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>> 8) & 0xFF) + 1*256];
next ^= _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>>16) & 0xFF) + 2*256];
next ^= _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>>24) & 0xFF) + 3*256];
return _cairo_lfsr_random_state = next;
}
/*
* Initialize an empty skip list
*/
void
skip_list_init (skip_list_t *list,
skip_list_compare_t compare,
_cairo_skip_list_init (cairo_skip_list_t *list,
cairo_skip_list_compare_t compare,
size_t elt_size)
{
int i;
@ -242,13 +243,13 @@ skip_list_init (skip_list_t *list,
}
void
skip_list_fini (skip_list_t *list)
_cairo_skip_list_fini (cairo_skip_list_t *list)
{
skip_elt_t *elt;
int i;
while ((elt = list->chains[0])) {
skip_list_delete_given (list, elt);
_cairo_skip_list_delete_given (list, elt);
}
for (i=0; i<MAX_LEVEL; i++) {
elt = list->freelists[i];
@ -283,7 +284,7 @@ random_level (void)
}
static void *
alloc_node_for_level (skip_list_t *list, unsigned level)
alloc_node_for_level (cairo_skip_list_t *list, unsigned level)
{
if (list->freelists[level-1]) {
skip_elt_t *elt = list->freelists[level-1];
@ -294,7 +295,7 @@ alloc_node_for_level (skip_list_t *list, unsigned level)
}
static void
free_elt (skip_list_t *list, skip_elt_t *elt)
free_elt (cairo_skip_list_t *list, skip_elt_t *elt)
{
elt->prev = list->freelists[elt->prev_index];
list->freelists[elt->prev_index] = elt;
@ -304,7 +305,7 @@ free_elt (skip_list_t *list, skip_elt_t *elt)
* Insert 'data' into the list
*/
void *
skip_list_insert (skip_list_t *list, void *data, int unique)
_cairo_skip_list_insert (cairo_skip_list_t *list, void *data, int unique)
{
skip_elt_t **update[MAX_LEVEL];
skip_elt_t *prev[MAX_LEVEL];
@ -369,7 +370,7 @@ skip_list_insert (skip_list_t *list, void *data, int unique)
}
void *
skip_list_find (skip_list_t *list, void *data)
_cairo_skip_list_find (cairo_skip_list_t *list, void *data)
{
int i;
skip_elt_t **next = list->chains;
@ -394,7 +395,7 @@ skip_list_find (skip_list_t *list, void *data)
}
void
skip_list_delete (skip_list_t *list, void *data)
_cairo_skip_list_delete (cairo_skip_list_t *list, void *data)
{
skip_elt_t **update[MAX_LEVEL], *prev[MAX_LEVEL];
skip_elt_t *elt, **next;
@ -430,7 +431,7 @@ skip_list_delete (skip_list_t *list, void *data)
}
void
skip_list_delete_given (skip_list_t *list, skip_elt_t *given)
_cairo_skip_list_delete_given (cairo_skip_list_t *list, skip_elt_t *given)
{
skip_elt_t **update[MAX_LEVEL], *prev[MAX_LEVEL];
skip_elt_t *elt, **next;

Просмотреть файл

@ -51,7 +51,7 @@ _cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b)
difference between a and b is less than PI.
< 0 => a less positive than b
== 0 => a equal to be
== 0 => a equal to b
> 0 => a more positive than b
*/
int
@ -67,6 +67,12 @@ _cairo_slope_compare (cairo_slope_t *a, cairo_slope_t *b)
if (diff < 0)
return -1;
/* special-case zero vectors. the intended logic here is:
* zero vectors all compare equal, and more positive than any
* non-zero vector.
*/
if (a->dx == 0 && a->dy == 0 && b->dx == 0 && b->dy ==0)
return 0;
if (a->dx == 0 && a->dy == 0)
return 1;
if (b->dx == 0 && b->dy ==0)

Просмотреть файл

@ -37,7 +37,7 @@
#include "cairoint.h"
static cairo_status_t
_cairo_spline_grow_by (cairo_spline_t *spline, int additional);
_cairo_spline_grow (cairo_spline_t *spline);
static cairo_status_t
_cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point);
@ -90,31 +90,47 @@ _cairo_spline_init (cairo_spline_t *spline,
void
_cairo_spline_fini (cairo_spline_t *spline)
{
spline->num_points = 0;
spline->points_size = 0;
free (spline->points);
if (spline->points && spline->points != spline->points_embedded)
free (spline->points);
spline->points = NULL;
spline->points_size = 0;
spline->num_points = 0;
}
/* make room for at least one more point */
static cairo_status_t
_cairo_spline_grow_by (cairo_spline_t *spline, int additional)
_cairo_spline_grow (cairo_spline_t *spline)
{
cairo_point_t *new_points;
int old_size = spline->points_size;
int new_size = spline->num_points + additional;
int embedded_size = sizeof (spline->points_embedded) / sizeof (spline->points_embedded[0]);
int new_size = 2 * MAX (old_size, 16);
if (new_size <= spline->points_size)
/* we have a local buffer at spline->points_embedded. try to fulfill the request
* from there. */
if (old_size < embedded_size) {
spline->points = spline->points_embedded;
spline->points_size = embedded_size;
return CAIRO_STATUS_SUCCESS;
}
spline->points_size = new_size;
new_points = realloc (spline->points, spline->points_size * sizeof (cairo_point_t));
assert (spline->num_points <= spline->points_size);
if (spline->points == spline->points_embedded) {
new_points = malloc (new_size * sizeof (cairo_point_t));
if (new_points)
memcpy (new_points, spline->points, old_size * sizeof (cairo_point_t));
} else {
new_points = realloc (spline->points, new_size * sizeof (cairo_point_t));
}
if (new_points == NULL) {
spline->points_size = old_size;
return CAIRO_STATUS_NO_MEMORY;
}
spline->points = new_points;
spline->points_size = new_size;
return CAIRO_STATUS_SUCCESS;
}
@ -132,8 +148,7 @@ _cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point)
}
if (spline->num_points >= spline->points_size) {
int additional = spline->points_size ? spline->points_size : 32;
status = _cairo_spline_grow_by (spline, additional);
status = _cairo_spline_grow (spline);
if (status)
return status;
}

Просмотреть файл

@ -41,107 +41,45 @@
#include "cairo-surface-fallback-private.h"
#include "cairo-clip-private.h"
const cairo_surface_t _cairo_surface_nil = {
&cairo_image_surface_backend, /* backend */
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR,
CAIRO_REF_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
FALSE, /* finished */
{ 0, /* size */
0, /* num_elements */
0, /* element_size */
NULL, /* elements */
}, /* user_data */
{ 1.0, 0.0,
0.0, 1.0,
0.0, 0.0
}, /* device_transform */
{ 1.0, 0.0,
0.0, 1.0,
0.0, 0.0
}, /* device_transform_inverse */
0.0, /* x_fallback_resolution */
0.0, /* y_fallback_resolution */
NULL, /* clip */
0, /* next_clip_serial */
0, /* current_clip_serial */
FALSE, /* is_snapshot */
FALSE, /* has_font_options */
{ CAIRO_ANTIALIAS_DEFAULT,
CAIRO_SUBPIXEL_ORDER_DEFAULT,
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_METRICS_DEFAULT
} /* font_options */
};
#define DEFINE_NIL_SURFACE(status, name) \
const cairo_surface_t name = { \
&cairo_image_surface_backend, /* backend */ \
CAIRO_SURFACE_TYPE_IMAGE, \
CAIRO_CONTENT_COLOR, \
CAIRO_REF_COUNT_INVALID, /* ref_count */ \
status, /* status */ \
FALSE, /* finished */ \
{ 0, /* size */ \
0, /* num_elements */ \
0, /* element_size */ \
NULL, /* elements */ \
}, /* user_data */ \
{ 1.0, 0.0, \
0.0, 1.0, \
0.0, 0.0 \
}, /* device_transform */ \
{ 1.0, 0.0, \
0.0, 1.0, \
0.0, 0.0 \
}, /* device_transform_inverse */ \
0.0, /* x_fallback_resolution */ \
0.0, /* y_fallback_resolution */ \
NULL, /* clip */ \
0, /* next_clip_serial */ \
0, /* current_clip_serial */ \
FALSE, /* is_snapshot */ \
FALSE, /* has_font_options */ \
{ CAIRO_ANTIALIAS_DEFAULT, \
CAIRO_SUBPIXEL_ORDER_DEFAULT, \
CAIRO_HINT_STYLE_DEFAULT, \
CAIRO_HINT_METRICS_DEFAULT \
} /* font_options */ \
}
const cairo_surface_t _cairo_surface_nil_file_not_found = {
&cairo_image_surface_backend, /* backend */
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR,
CAIRO_REF_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_FILE_NOT_FOUND, /* status */
FALSE, /* finished */
{ 0, /* size */
0, /* num_elements */
0, /* element_size */
NULL, /* elements */
}, /* user_data */
{ 1.0, 0.0,
0.0, 1.0,
0.0, 0.0
}, /* device_transform */
{ 1.0, 0.0,
0.0, 1.0,
0.0, 0.0
}, /* device_transform_inverse */
0.0, /* x_fallback_resolution */
0.0, /* y_fallback_resolution */
NULL, /* clip */
0, /* next_clip_serial */
0, /* current_clip_serial */
FALSE, /* is_snapshot */
FALSE, /* has_font_options */
{ CAIRO_ANTIALIAS_DEFAULT,
CAIRO_SUBPIXEL_ORDER_DEFAULT,
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_METRICS_DEFAULT
} /* font_options */
};
const cairo_surface_t _cairo_surface_nil_read_error = {
&cairo_image_surface_backend, /* backend */
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR,
CAIRO_REF_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_READ_ERROR, /* status */
FALSE, /* finished */
{ 0, /* size */
0, /* num_elements */
0, /* element_size */
NULL, /* elements */
}, /* user_data */
{ 1.0, 0.0,
0.0, 1.0,
0.0, 0.0
}, /* device_transform */
{ 1.0, 0.0,
0.0, 1.0,
0.0, 0.0
}, /* device_transform_inverse */
0.0, /* x_fallback_resolution */
0.0, /* y_fallback_resolution */
NULL, /* clip */
0, /* next_clip_serial */
0, /* current_clip_serial */
FALSE, /* is_snapshot */
FALSE, /* has_font_options */
{ CAIRO_ANTIALIAS_DEFAULT,
CAIRO_SUBPIXEL_ORDER_DEFAULT,
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_METRICS_DEFAULT
} /* font_options */
};
DEFINE_NIL_SURFACE(CAIRO_STATUS_NO_MEMORY, _cairo_surface_nil);
DEFINE_NIL_SURFACE(CAIRO_STATUS_FILE_NOT_FOUND, _cairo_surface_nil_file_not_found);
DEFINE_NIL_SURFACE(CAIRO_STATUS_READ_ERROR, _cairo_surface_nil_read_error);
DEFINE_NIL_SURFACE(CAIRO_STATUS_WRITE_ERROR, _cairo_surface_nil_write_error);
static void
_cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
@ -203,10 +141,12 @@ slim_hidden_def (cairo_surface_get_type);
* cairo_surface_get_content:
* @surface: a #cairo_surface_t
*
* Return value: The content type of @surface which indicates whether
* the surface contains color and/or alpha information. See
* This function returns the content type of @surface which indicates
* whether the surface contains color and/or alpha information. See
* #cairo_content_t.
*
* Return value: The content type of @surface.
*
* Since: 1.2
**/
cairo_content_t
@ -281,12 +221,23 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other,
if (other->status)
return (cairo_surface_t*) &_cairo_surface_nil;
if (other->backend->create_similar)
if (other->backend->create_similar) {
surface = other->backend->create_similar (other, content, width, height);
/* It's not an error if the backend didn't create a valid
* surface---it may just not be supported. */
if (surface && surface->status) {
cairo_surface_destroy (surface);
surface = NULL;
}
}
if (!surface)
if (surface == NULL)
surface = cairo_image_surface_create (format, width, height);
/* If any error occurred, then return the nil surface we received. */
if (surface->status)
return surface;
cairo_surface_get_font_options (other, &options);
_cairo_surface_set_font_options (surface, &options);
@ -402,15 +353,15 @@ _cairo_surface_get_clip_mode (cairo_surface_t *surface)
* @surface from being destroyed until a matching call to
* cairo_surface_destroy() is made.
*
* The number of references to a #cairo_surface_t can be get using
* cairo_surface_get_reference_count().
*
* Return value: the referenced #cairo_surface_t.
**/
cairo_surface_t *
cairo_surface_reference (cairo_surface_t *surface)
{
if (surface == NULL)
return NULL;
if (surface->ref_count == CAIRO_REF_COUNT_INVALID)
if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID)
return surface;
assert (surface->ref_count > 0);
@ -432,10 +383,7 @@ slim_hidden_def (cairo_surface_reference);
void
cairo_surface_destroy (cairo_surface_t *surface)
{
if (surface == NULL)
return;
if (surface->ref_count == CAIRO_REF_COUNT_INVALID)
if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID)
return;
assert (surface->ref_count > 0);
@ -444,7 +392,8 @@ cairo_surface_destroy (cairo_surface_t *surface)
if (surface->ref_count)
return;
cairo_surface_finish (surface);
if (! surface->finished)
cairo_surface_finish (surface);
_cairo_user_data_array_fini (&surface->user_data);
@ -452,6 +401,26 @@ cairo_surface_destroy (cairo_surface_t *surface)
}
slim_hidden_def(cairo_surface_destroy);
/**
* cairo_surface_get_reference_count:
* @surface: a #cairo_surface_t
*
* Returns the current reference count of @surface.
*
* Return value: the current reference count of @surface. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.4
**/
unsigned int
cairo_surface_get_reference_count (cairo_surface_t *surface)
{
if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID)
return 0;
return surface->ref_count;
}
/**
* cairo_surface_finish:
* @surface: the #cairo_surface_t to finish
@ -475,6 +444,12 @@ cairo_surface_finish (cairo_surface_t *surface)
{
cairo_status_t status;
if (surface == NULL)
return;
if (surface->ref_count == CAIRO_REF_COUNT_INVALID)
return;
if (surface->finished) {
_cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
return;
@ -815,8 +790,10 @@ cairo_surface_get_device_offset (cairo_surface_t *surface,
double *x_offset,
double *y_offset)
{
*x_offset = surface->device_transform.x0;
*y_offset = surface->device_transform.y0;
if (x_offset)
*x_offset = surface->device_transform.x0;
if (y_offset)
*y_offset = surface->device_transform.y0;
}
slim_hidden_def (cairo_surface_get_device_offset);
@ -1024,7 +1001,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
status = surface->backend->clone_similar (surface, src, src_x, src_y,
width, height, clone_out);
if (status == CAIRO_STATUS_SUCCESS)
if (status == CAIRO_STATUS_SUCCESS && *clone_out != src)
(*clone_out)->device_transform = src->device_transform;
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
@ -1036,8 +1013,10 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
status = surface->backend->clone_similar (surface, &image->base, src_x,
src_y, width, height, clone_out);
if (status == CAIRO_STATUS_SUCCESS)
if (status == CAIRO_STATUS_SUCCESS && *clone_out != src) {
(*clone_out)->device_transform = src->device_transform;
(*clone_out)->device_transform_inverse = src->device_transform_inverse;
}
/* If the above failed point, we could implement a full fallback
* using acquire_dest_image, but that's going to be very
@ -1276,12 +1255,6 @@ _cairo_surface_paint (cairo_surface_t *surface,
assert (! surface->is_snapshot);
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
(source->extend == CAIRO_EXTEND_REFLECT || source->extend == CAIRO_EXTEND_PAD))
{
return CAIRO_STATUS_NO_MEMORY;
}
_cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
if (surface->backend->paint) {
@ -1310,12 +1283,6 @@ _cairo_surface_mask (cairo_surface_t *surface,
assert (! surface->is_snapshot);
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
(source->extend == CAIRO_EXTEND_REFLECT || source->extend == CAIRO_EXTEND_PAD))
{
return CAIRO_STATUS_NO_MEMORY;
}
_cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
_cairo_surface_copy_pattern_for_destination (mask, surface, &dev_mask.base);
@ -1354,12 +1321,6 @@ _cairo_surface_stroke (cairo_surface_t *surface,
assert (! surface->is_snapshot);
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
(source->extend == CAIRO_EXTEND_REFLECT || source->extend == CAIRO_EXTEND_PAD))
{
return CAIRO_STATUS_NO_MEMORY;
}
_cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
if (surface->backend->stroke) {
@ -1399,12 +1360,6 @@ _cairo_surface_fill (cairo_surface_t *surface,
assert (! surface->is_snapshot);
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
(source->extend == CAIRO_EXTEND_REFLECT || source->extend == CAIRO_EXTEND_PAD))
{
return CAIRO_STATUS_NO_MEMORY;
}
_cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
if (surface->backend->fill) {
@ -1806,12 +1761,6 @@ _cairo_surface_show_glyphs (cairo_surface_t *surface,
assert (! surface->is_snapshot);
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
(source->extend == CAIRO_EXTEND_REFLECT || source->extend == CAIRO_EXTEND_PAD))
{
return CAIRO_STATUS_NO_MEMORY;
}
if (!num_glyphs)
return CAIRO_STATUS_SUCCESS;
@ -1839,19 +1788,22 @@ _cairo_surface_show_glyphs (cairo_surface_t *surface,
cairo_font_options_destroy (font_options);
}
if (surface->backend->show_glyphs) {
CAIRO_MUTEX_LOCK (dev_scaled_font->mutex);
status = CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->backend->show_glyphs)
status = surface->backend->show_glyphs (surface, op, &dev_source.base,
glyphs, num_glyphs,
dev_scaled_font);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
}
status = _cairo_surface_fallback_show_glyphs (surface, op, &dev_source.base,
glyphs, num_glyphs,
dev_scaled_font);
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
status = _cairo_surface_fallback_show_glyphs (surface, op, &dev_source.base,
glyphs, num_glyphs,
dev_scaled_font);
CAIRO_MUTEX_UNLOCK (dev_scaled_font->mutex);
FINISH:
if (dev_scaled_font != scaled_font)
cairo_scaled_font_destroy (dev_scaled_font);
@ -2137,17 +2089,5 @@ _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
}
}
/**
* cairo_surface_get_reference_count
* @surface: the #cairo_surface_t to fetch the reference count for
*
* Returns the number of references to this surface that are held.
*/
unsigned int
cairo_surface_get_reference_count (cairo_surface_t *surface)
{
return surface->ref_count;
}
/* LocalWords: rasterized
*/

Просмотреть файл

@ -240,7 +240,9 @@ cairo_svg_surface_create (const char *filename,
status = _cairo_output_stream_get_status (stream);
if (status) {
_cairo_error (status);
return (cairo_surface_t *) &_cairo_surface_nil;
return (status == CAIRO_STATUS_WRITE_ERROR) ?
(cairo_surface_t *) &_cairo_surface_nil_write_error :
(cairo_surface_t *) &_cairo_surface_nil;
}
return _cairo_svg_surface_create_for_stream_internal (stream, width, height, CAIRO_SVG_VERSION_1_1);
@ -475,7 +477,7 @@ _cairo_svg_surface_show_page (void *abstract_surface)
}
static void
emit_transform (cairo_output_stream_t *output,
_cairo_svg_surface_emit_transform (cairo_output_stream_t *output,
char const *attribute_str,
char const *trailer,
cairo_matrix_t *matrix)
@ -563,7 +565,7 @@ _cairo_svg_path_close_path (void *closure)
}
static cairo_status_t
emit_path (cairo_output_stream_t *output,
_cairo_svg_surface_emit_path (cairo_output_stream_t *output,
cairo_path_fixed_t *path,
cairo_matrix_t *ctm_inverse)
{
@ -606,7 +608,7 @@ _cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t *document,
_cairo_output_stream_printf (document->xml_node_glyphs,
"<path style=\"stroke: none;\" ");
status = emit_path (document->xml_node_glyphs, scaled_glyph->path, NULL);
status = _cairo_svg_surface_emit_path (document->xml_node_glyphs, scaled_glyph->path, NULL);
_cairo_output_stream_printf (document->xml_node_glyphs,
"/>\n");
@ -642,7 +644,7 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
}
_cairo_output_stream_printf (document->xml_node_glyphs, "<g");
emit_transform (document->xml_node_glyphs, " transform", ">/n", &image->base.device_transform);
_cairo_svg_surface_emit_transform (document->xml_node_glyphs, " transform", ">/n", &image->base.device_transform);
for (y = 0, row = image->data, rows = image->height; rows; row += image->stride, rows--, y++) {
for (x = 0, byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) {
@ -674,7 +676,7 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t *document,
cairo_status_t status;
_cairo_output_stream_printf (document->xml_node_glyphs,
"<symbol id=\"glyph%d-%d\">\n",
"<symbol overflow=\"visible\" id=\"glyph%d-%d\">\n",
font_id,
subset_glyph_index);
@ -707,9 +709,9 @@ _cairo_svg_document_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
static void
_cairo_svg_document_emit_font_subsets (cairo_svg_document_t *document)
{
_cairo_scaled_font_subsets_foreach (document->font_subsets,
_cairo_svg_document_emit_font_subset,
document);
_cairo_scaled_font_subsets_foreach_scaled (document->font_subsets,
_cairo_svg_document_emit_font_subset,
document);
_cairo_scaled_font_subsets_destroy (document->font_subsets);
document->font_subsets = NULL;
}
@ -735,7 +737,7 @@ _cairo_svg_test_force_fallbacks (void)
}
static cairo_int_status_t
_operation_supported (cairo_svg_surface_t *surface,
__cairo_svg_surface_operation_supported (cairo_svg_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *pattern)
{
@ -752,11 +754,11 @@ _operation_supported (cairo_svg_surface_t *surface,
}
static cairo_int_status_t
_analyze_operation (cairo_svg_surface_t *surface,
_cairo_svg_surface_analyze_operation (cairo_svg_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *pattern)
{
if (_operation_supported (surface, op, pattern))
if (__cairo_svg_surface_operation_supported (surface, op, pattern))
return CAIRO_STATUS_SUCCESS;
else
return CAIRO_INT_STATUS_UNSUPPORTED;
@ -799,7 +801,7 @@ _cairo_svg_surface_finish (void *abstract_surface)
}
static void
emit_alpha_filter (cairo_svg_document_t *document)
_cairo_svg_surface_emit_alpha_filter (cairo_svg_document_t *document)
{
if (document->alpha_filter)
return;
@ -914,19 +916,27 @@ _cairo_surface_base64_encode (cairo_surface_t *surface,
}
static cairo_status_t
emit_composite_image_pattern (cairo_output_stream_t *output,
_cairo_svg_surface_emit_composite_image_pattern (cairo_output_stream_t *output,
cairo_svg_surface_t *svg_surface,
cairo_surface_pattern_t *pattern,
int pattern_id,
const char *extra_attributes)
{
cairo_image_surface_t *image;
cairo_surface_t *surface;
cairo_surface_attributes_t surface_attr;
cairo_rectangle_int16_t extents;
cairo_status_t status;
cairo_matrix_t p2u;
void *image_extra;
status = _cairo_surface_acquire_source_image (pattern->surface,
&image, &image_extra);
status = _cairo_pattern_acquire_surface ((cairo_pattern_t *)pattern,
(cairo_surface_t *)svg_surface,
0, 0, (unsigned int)-1, (unsigned int)-1,
&surface, &surface_attr);
if (status)
return status;
status = _cairo_surface_get_extents (surface, &extents);
if (status)
return status;
@ -939,36 +949,37 @@ emit_composite_image_pattern (cairo_output_stream_t *output,
"patternUnits=\"userSpaceOnUse\" "
"width=\"%d\" height=\"%d\"",
pattern_id,
image->width, image->height);
emit_transform (output, " patternTransform", ">\n", &p2u);
extents.width, extents.height);
_cairo_svg_surface_emit_transform (output, " patternTransform", ">\n", &p2u);
}
_cairo_output_stream_printf (output,
" <image width=\"%d\" height=\"%d\"",
image->width, image->height);
extents.width, extents.height);
if (pattern_id == invalid_pattern_id)
emit_transform (output, " transform", "", &p2u);
_cairo_svg_surface_emit_transform (output, " transform", "", &p2u);
if (extra_attributes)
_cairo_output_stream_printf (output, " %s", extra_attributes);
_cairo_output_stream_printf (output, " xlink:href=\"");
status = _cairo_surface_base64_encode (pattern->surface, output);
status = _cairo_surface_base64_encode (surface, output);
_cairo_output_stream_printf (output, "\"/>\n");
if (pattern_id != invalid_pattern_id)
_cairo_output_stream_printf (output, "</pattern>\n");
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
_cairo_pattern_release_surface ((cairo_pattern_t *)pattern,
surface, &surface_attr);
return status;
}
static int
emit_meta_surface (cairo_svg_document_t *document,
_cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document,
cairo_meta_surface_t *surface)
{
cairo_surface_t *paginated_surface;
@ -1010,7 +1021,7 @@ emit_meta_surface (cairo_svg_document_t *document,
_cairo_array_append (&document->meta_snapshots, &new_snapshot);
if (meta->content == CAIRO_CONTENT_ALPHA) {
emit_alpha_filter (document);
_cairo_svg_surface_emit_alpha_filter (document);
_cairo_output_stream_printf (document->xml_node_defs,
"<g id=\"surface%d\" "
"clip-path=\"url(#clip%d)\" "
@ -1055,7 +1066,7 @@ emit_meta_surface (cairo_svg_document_t *document,
}
static cairo_status_t
emit_composite_meta_pattern (cairo_output_stream_t *output,
_cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output,
cairo_svg_surface_t *surface,
cairo_surface_pattern_t *pattern,
int pattern_id,
@ -1068,7 +1079,7 @@ emit_composite_meta_pattern (cairo_output_stream_t *output,
meta_surface = (cairo_meta_surface_t *) pattern->surface;
id = emit_meta_surface (document, meta_surface);
id = _cairo_svg_surface_emit_meta_surface (document, meta_surface);
p2u = pattern->base.matrix;
cairo_matrix_invert (&p2u);
@ -1081,7 +1092,7 @@ emit_composite_meta_pattern (cairo_output_stream_t *output,
pattern_id,
meta_surface->width_pixels,
meta_surface->height_pixels);
emit_transform (output, " patternTransform", ">\n", &p2u);
_cairo_svg_surface_emit_transform (output, " patternTransform", ">\n", &p2u);
}
_cairo_output_stream_printf (output,
@ -1089,7 +1100,7 @@ emit_composite_meta_pattern (cairo_output_stream_t *output,
id);
if (pattern_id == invalid_pattern_id)
emit_transform (output, " transform", "", &p2u);
_cairo_svg_surface_emit_transform (output, " transform", "", &p2u);
if (extra_attributes)
_cairo_output_stream_printf (output, " %s", extra_attributes);
@ -1103,7 +1114,7 @@ emit_composite_meta_pattern (cairo_output_stream_t *output,
}
static cairo_status_t
emit_composite_pattern (cairo_output_stream_t *output,
_cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t *output,
cairo_svg_surface_t *surface,
cairo_surface_pattern_t *pattern,
int pattern_id,
@ -1111,16 +1122,16 @@ emit_composite_pattern (cairo_output_stream_t *output,
{
if (_cairo_surface_is_meta (pattern->surface)) {
return emit_composite_meta_pattern (output, surface, pattern,
return _cairo_svg_surface_emit_composite_meta_pattern (output, surface, pattern,
pattern_id, extra_attributes);
}
return emit_composite_image_pattern (output, surface, pattern,
return _cairo_svg_surface_emit_composite_image_pattern (output, surface, pattern,
pattern_id, extra_attributes);
}
static void
emit_operator (cairo_output_stream_t *output,
_cairo_svg_surface_emit_operator (cairo_output_stream_t *output,
cairo_svg_surface_t *surface,
cairo_operator_t op)
{
@ -1142,7 +1153,7 @@ emit_operator (cairo_output_stream_t *output,
}
static void
emit_solid_pattern (cairo_svg_surface_t *surface,
_cairo_svg_surface_emit_solid_pattern (cairo_svg_surface_t *surface,
cairo_solid_pattern_t *pattern,
cairo_output_stream_t *style,
cairo_bool_t is_stroke)
@ -1158,7 +1169,7 @@ emit_solid_pattern (cairo_svg_surface_t *surface,
}
static void
emit_surface_pattern (cairo_svg_surface_t *surface,
_cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t *surface,
cairo_surface_pattern_t *pattern,
cairo_output_stream_t *style,
cairo_bool_t is_stroke)
@ -1167,7 +1178,7 @@ emit_surface_pattern (cairo_svg_surface_t *surface,
int pattern_id;
pattern_id = document->pattern_id++;
emit_composite_pattern (document->xml_node_defs, surface, pattern,
_cairo_svg_surface_emit_composite_pattern (document->xml_node_defs, surface, pattern,
pattern_id, NULL);
_cairo_output_stream_printf (style,
@ -1177,30 +1188,169 @@ emit_surface_pattern (cairo_svg_surface_t *surface,
}
static void
emit_pattern_stops (cairo_output_stream_t *output,
_cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output,
cairo_gradient_pattern_t const *pattern,
double start_offset)
double start_offset,
cairo_bool_t reverse_stops,
cairo_bool_t emulate_reflect)
{
pixman_gradient_stop_t *stops;
double offset;
unsigned int n_stops;
unsigned int i;
for (i = 0; i < pattern->n_stops; i++) {
offset = start_offset + (1 - start_offset ) *
_cairo_fixed_to_double (pattern->stops[i].x);
if (pattern->n_stops < 1)
return;
if (pattern->n_stops == 1) {
_cairo_output_stream_printf (output,
"<stop offset=\"%f\" style=\""
"stop-color: rgb(%f%%,%f%%,%f%%); "
"stop-opacity: %f;\"/>\n",
_cairo_fixed_to_double (pattern->stops[0].x),
pattern->stops[0].color.red / 655.35,
pattern->stops[0].color.green / 655.35,
pattern->stops[0].color.blue / 655.35,
pattern->stops[0].color.alpha / 65535.0);
return;
}
if (emulate_reflect || reverse_stops) {
n_stops = emulate_reflect ? pattern->n_stops * 2 - 2: pattern->n_stops;
stops = malloc (sizeof (pixman_gradient_stop_t) * n_stops);
for (i = 0; i < pattern->n_stops; i++) {
if (reverse_stops) {
stops[i] = pattern->stops[pattern->n_stops - i - 1];
stops[i].x = _cairo_fixed_from_double (1.0 - _cairo_fixed_to_double (stops[i].x));
} else
stops[i] = pattern->stops[i];
if (emulate_reflect) {
stops[i].x /= 2;
if (i > 0 && i < (pattern->n_stops - 1)) {
if (reverse_stops) {
stops[i + pattern->n_stops - 1] = pattern->stops[i];
stops[i + pattern->n_stops - 1].x =
_cairo_fixed_from_double (0.5 + 0.5
* _cairo_fixed_to_double (stops[i + pattern->n_stops - 1].x));
} else {
stops[i + pattern->n_stops - 1] = pattern->stops[pattern->n_stops - i - 1];
stops[i + pattern->n_stops - 1].x =
_cairo_fixed_from_double (1 - 0.5
* _cairo_fixed_to_double (stops [i + pattern->n_stops - 1].x));
}
}
}
}
} else {
n_stops = pattern->n_stops;
stops = pattern->stops;
}
if (start_offset >= 0.0)
for (i = 0; i < n_stops; i++) {
offset = start_offset + (1 - start_offset ) *
_cairo_fixed_to_double (stops[i].x);
_cairo_output_stream_printf (output,
"<stop offset=\"%f\" style=\""
"stop-color: rgb(%f%%,%f%%,%f%%); "
"stop-opacity: %f;\"/>\n",
offset,
stops[i].color.red / 655.35,
stops[i].color.green / 655.35,
stops[i].color.blue / 655.35,
stops[i].color.alpha / 65535.0);
}
else {
cairo_bool_t found = FALSE;
unsigned int offset_index;
pixman_color_t offset_color_start, offset_color_stop;
for (i = 0; i < n_stops; i++) {
if (_cairo_fixed_to_double (stops[i].x) >= -start_offset) {
if (i > 0) {
if (stops[i].x != stops[i-1].x) {
double x0, x1;
pixman_color_t *color0, *color1;
x0 = _cairo_fixed_to_double (stops[i-1].x);
x1 = _cairo_fixed_to_double (stops[i].x);
color0 = &stops[i-1].color;
color1 = &stops[i].color;
offset_color_start.red = color0->red + (color1->red - color0->red)
* (-start_offset - x0) / (x1 - x0);
offset_color_start.green = color0->green + (color1->green - color0->green)
* (-start_offset - x0) / (x1 - x0);
offset_color_start.blue = color0->blue + (color1->blue - color0->blue)
* (-start_offset - x0) / (x1 - x0);
offset_color_start.alpha = color0->alpha + (color1->alpha - color0->alpha)
* (-start_offset - x0) / (x1 - x0);
offset_color_stop = offset_color_start;
} else {
offset_color_stop = stops[i-1].color;
offset_color_start = stops[i].color;
}
} else
offset_color_stop = offset_color_start = stops[i].color;
offset_index = i;
found = TRUE;
break;
}
}
if (!found) {
offset_index = n_stops - 1;
offset_color_stop = offset_color_start = stops[offset_index].color;
}
_cairo_output_stream_printf (output,
"<stop offset=\"%f\" style=\""
"<stop offset=\"0\" style=\""
"stop-color: rgb(%f%%,%f%%,%f%%); "
"stop-opacity: %f;\"/>\n",
offset,
pattern->stops[i].color.red / 655.35,
pattern->stops[i].color.green / 655.35,
pattern->stops[i].color.blue / 655.35,
pattern->stops[i].color.alpha / 65535.0);
offset_color_start.red / 655.35,
offset_color_start.green / 655.35,
offset_color_start.blue / 655.35,
offset_color_start.alpha / 65535.0);
for (i = offset_index; i < n_stops; i++) {
_cairo_output_stream_printf (output,
"<stop offset=\"%f\" style=\""
"stop-color: rgb(%f%%,%f%%,%f%%); "
"stop-opacity: %f;\"/>\n",
_cairo_fixed_to_double (stops[i].x) + start_offset,
stops[i].color.red / 655.35,
stops[i].color.green / 655.35,
stops[i].color.blue / 655.35,
stops[i].color.alpha / 65535.0);
}
for (i = 0; i < offset_index; i++) {
_cairo_output_stream_printf (output,
"<stop offset=\"%f\" style=\""
"stop-color: rgb(%f%%,%f%%,%f%%); "
"stop-opacity: %f;\"/>\n",
1.0 + _cairo_fixed_to_double (stops[i].x) + start_offset,
stops[i].color.red / 655.35,
stops[i].color.green / 655.35,
stops[i].color.blue / 655.35,
stops[i].color.alpha / 65535.0);
}
_cairo_output_stream_printf (output,
"<stop offset=\"1\" style=\""
"stop-color: rgb(%f%%,%f%%,%f%%); "
"stop-opacity: %f;\"/>\n",
offset_color_stop.red / 655.35,
offset_color_stop.green / 655.35,
offset_color_stop.blue / 655.35,
offset_color_stop.alpha / 65535.0);
}
if (reverse_stops || emulate_reflect)
free (stops);
}
static void
emit_pattern_extend (cairo_output_stream_t *output,
_cairo_svg_surface_emit_pattern_extend (cairo_output_stream_t *output,
cairo_pattern_t *pattern)
{
switch (pattern->extend) {
@ -1211,15 +1361,13 @@ emit_pattern_extend (cairo_output_stream_t *output,
_cairo_output_stream_printf (output, "spreadMethod=\"reflect\" ");
break;
case CAIRO_EXTEND_NONE:
break;
case CAIRO_EXTEND_PAD:
/* FIXME not implemented */
break;
}
}
static void
emit_linear_pattern (cairo_svg_surface_t *surface,
_cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface,
cairo_linear_pattern_t *pattern,
cairo_output_stream_t *style,
cairo_bool_t is_stroke)
@ -1240,12 +1388,12 @@ emit_linear_pattern (cairo_svg_surface_t *surface,
document->linear_pattern_id,
x0, y0, x1, y1);
emit_pattern_extend (document->xml_node_defs, &pattern->base.base),
_cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base),
p2u = pattern->base.base.matrix;
cairo_matrix_invert (&p2u);
emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u);
_cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u);
emit_pattern_stops (document->xml_node_defs ,&pattern->base, 0.0);
_cairo_svg_surface_emit_pattern_stops (document->xml_node_defs ,&pattern->base, 0.0, FALSE, FALSE);
_cairo_output_stream_printf (document->xml_node_defs,
"</linearGradient>\n");
@ -1259,46 +1407,160 @@ emit_linear_pattern (cairo_svg_surface_t *surface,
}
static void
emit_radial_pattern (cairo_svg_surface_t *surface,
_cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface,
cairo_radial_pattern_t *pattern,
cairo_output_stream_t *style,
cairo_bool_t is_stroke)
{
cairo_svg_document_t *document = surface->document;
cairo_matrix_t p2u;
cairo_extend_t extend;
double x0, y0, x1, y1, r0, r1;
double fx, fy;
cairo_bool_t reverse_stops;
pixman_circle_t *c0, *c1;
x0 = _cairo_fixed_to_double (pattern->gradient.inner.x);
y0 = _cairo_fixed_to_double (pattern->gradient.inner.y);
r0 = _cairo_fixed_to_double (pattern->gradient.inner.radius);
x1 = _cairo_fixed_to_double (pattern->gradient.outer.x);
y1 = _cairo_fixed_to_double (pattern->gradient.outer.y);
r1 = _cairo_fixed_to_double (pattern->gradient.outer.radius);
extend = pattern->base.base.extend;
/* SVG doesn't have a start radius, so computing now SVG focal coordinates
* and emulating start radius by translating color stops.
* FIXME: We also need to emulate cairo behaviour inside start circle when
* extend != CAIRO_EXTEND_NONE.
* FIXME: Handle radius1 <= radius0 */
fx = (r1 * x0 - r0 * x1) / (r1 - r0);
fy = (r1 * y0 - r0 * y1) / (r1 - r0);
if (pattern->gradient.c1.radius < pattern->gradient.c2.radius) {
c0 = &pattern->gradient.c1;
c1 = &pattern->gradient.c2;
reverse_stops = FALSE;
} else {
c0 = &pattern->gradient.c2;
c1 = &pattern->gradient.c1;
reverse_stops = TRUE;
}
_cairo_output_stream_printf (document->xml_node_defs,
"<radialGradient id=\"radial%d\" "
"gradientUnits=\"userSpaceOnUse\" "
"cx=\"%f\" cy=\"%f\" "
"fx=\"%f\" fy=\"%f\" r=\"%f\" ",
document->radial_pattern_id,
x1, y1,
fx, fy, r1);
x0 = _cairo_fixed_to_double (c0->x);
y0 = _cairo_fixed_to_double (c0->y);
r0 = _cairo_fixed_to_double (c0->radius);
x1 = _cairo_fixed_to_double (c1->x);
y1 = _cairo_fixed_to_double (c1->y);
r1 = _cairo_fixed_to_double (c1->radius);
emit_pattern_extend (document->xml_node_defs, &pattern->base.base),
p2u = pattern->base.base.matrix;
cairo_matrix_invert (&p2u);
emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u);
emit_pattern_stops (document->xml_node_defs, &pattern->base, r0 / r1);
if (pattern->gradient.c1.radius == pattern->gradient.c2.radius) {
_cairo_output_stream_printf (document->xml_node_defs,
"<radialGradient id=\"radial%d\" "
"gradientUnits=\"userSpaceOnUse\" "
"cx=\"%f\" cy=\"%f\" "
"fx=\"%f\" fy=\"%f\" r=\"%f\" ",
document->radial_pattern_id,
x1, y1,
x1, y1, r1);
_cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u);
if (extend == CAIRO_EXTEND_NONE ||
pattern->base.n_stops < 1)
_cairo_output_stream_printf (document->xml_node_defs,
"<stop offset=\"0\" style=\""
"stop-color: rgb(0%%,0%%,0%%); "
"stop-opacity: 0;\"/>\n");
else {
_cairo_output_stream_printf (document->xml_node_defs,
"<stop offset=\"0\" style=\""
"stop-color: rgb(%f%%,%f%%,%f%%); "
"stop-opacity: %f;\"/>\n",
pattern->base.stops[0].color.red / 655.35,
pattern->base.stops[0].color.green / 655.35,
pattern->base.stops[0].color.blue / 655.35,
pattern->base.stops[0].color.alpha / 65535.0);
if (pattern->base.n_stops > 1)
_cairo_output_stream_printf (document->xml_node_defs,
"<stop offset=\"0\" style=\""
"stop-color: rgb(%f%%,%f%%,%f%%); "
"stop-opacity: %f;\"/>\n",
pattern->base.stops[1].color.red / 655.35,
pattern->base.stops[1].color.green / 655.35,
pattern->base.stops[1].color.blue / 655.35,
pattern->base.stops[1].color.alpha / 65535.0);
}
} else {
double offset, r, x, y;
cairo_bool_t emulate_reflect = FALSE;
fx = (r1 * x0 - r0 * x1) / (r1 - r0);
fy = (r1 * y0 - r0 * y1) / (r1 - r0);
/* SVG doesn't support the inner circle and use instead a gradient focal.
* That means we need to emulate the cairo behaviour by processing the
* cairo gradient stops.
* The CAIRO_EXTENT_NONE and CAIRO_EXTENT_PAD modes are quite easy to handle,
* it's just a matter of stop position translation and calculation of
* the corresponding SVG radial gradient focal.
* The CAIRO_EXTENT_REFLECT and CAIRO_EXTEND_REPEAT modes require to compute a new
* radial gradient, with an new outer circle, equal to r1 - r0 in the CAIRO_EXTEND_REPEAT
* case, and 2 * (r1 - r0) in the CAIRO_EXTENT_REFLECT case, and a new gradient stop
* list that maps to the original cairo stop list.
*/
if ((extend == CAIRO_EXTEND_REFLECT
|| extend == CAIRO_EXTEND_REPEAT)
&& r0 > 0.0) {
double r_org = r1;
if (extend == CAIRO_EXTEND_REFLECT) {
r1 = 2 * r1 - r0;
emulate_reflect = TRUE;
}
offset = fmod (r1, r1 - r0) / (r1 - r0) - 1.0;
r = r1 - r0;
/* New position of outer circle. */
x = r * (x1 - fx) / r_org + fx;
y = r * (y1 - fy) / r_org + fy;
x1 = x;
y1 = y;
r1 = r;
r0 = 0.0;
} else {
offset = r0 / r1;
}
_cairo_output_stream_printf (document->xml_node_defs,
"<radialGradient id=\"radial%d\" "
"gradientUnits=\"userSpaceOnUse\" "
"cx=\"%f\" cy=\"%f\" "
"fx=\"%f\" fy=\"%f\" r=\"%f\" ",
document->radial_pattern_id,
x1, y1,
fx, fy, r1);
if (emulate_reflect)
_cairo_output_stream_printf (document->xml_node_defs, "spreadMethod=\"repeat\" ");
else
_cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base);
_cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u);
/* To support cairo's EXTEND_NONE, (for which SVG has no similar
* notion), we add transparent color stops on either end of the
* user-provided stops. */
if (extend == CAIRO_EXTEND_NONE) {
_cairo_output_stream_printf (document->xml_node_defs,
"<stop offset=\"0\" style=\""
"stop-color: rgb(0%%,0%%,0%%); "
"stop-opacity: 0;\"/>\n");
if (r0 != 0.0)
_cairo_output_stream_printf (document->xml_node_defs,
"<stop offset=\"%f\" style=\""
"stop-color: rgb(0%%,0%%,0%%); "
"stop-opacity: 0;\"/>\n",
r0 / r1);
}
_cairo_svg_surface_emit_pattern_stops (document->xml_node_defs, &pattern->base, offset,
reverse_stops, emulate_reflect);
if (pattern->base.base.extend == CAIRO_EXTEND_NONE)
_cairo_output_stream_printf (document->xml_node_defs,
"<stop offset=\"1.0\" style=\""
"stop-color: rgb(0%%,0%%,0%%); "
"stop-opacity: 0;\"/>\n");
}
_cairo_output_stream_printf (document->xml_node_defs,
"</radialGradient>\n");
@ -1312,24 +1574,24 @@ emit_radial_pattern (cairo_svg_surface_t *surface,
}
static void
emit_pattern (cairo_svg_surface_t *surface, cairo_pattern_t *pattern,
_cairo_svg_surface_emit_pattern (cairo_svg_surface_t *surface, cairo_pattern_t *pattern,
cairo_output_stream_t *output, cairo_bool_t is_stroke)
{
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern, output, is_stroke);
_cairo_svg_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern, output, is_stroke);
break;
case CAIRO_PATTERN_TYPE_SURFACE:
emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, output, is_stroke);
_cairo_svg_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, output, is_stroke);
break;
case CAIRO_PATTERN_TYPE_LINEAR:
emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern, output, is_stroke);
_cairo_svg_surface_emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern, output, is_stroke);
break;
case CAIRO_PATTERN_TYPE_RADIAL:
emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, output, is_stroke);
_cairo_svg_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, output, is_stroke);
break;
}
}
@ -1347,20 +1609,20 @@ _cairo_svg_surface_fill (void *abstract_surface,
cairo_status_t status;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, source);
return _cairo_svg_surface_analyze_operation (surface, op, source);
assert (_operation_supported (surface, op, source));
assert (__cairo_svg_surface_operation_supported (surface, op, source));
_cairo_output_stream_printf (surface->xml_node,
"<path style=\"stroke: none; "
"fill-rule: %s; ",
fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
"evenodd" : "nonzero");
emit_operator (surface->xml_node, surface, op);
emit_pattern (surface, source, surface->xml_node, FALSE);
_cairo_svg_surface_emit_operator (surface->xml_node, surface, op);
_cairo_svg_surface_emit_pattern (surface, source, surface->xml_node, FALSE);
_cairo_output_stream_printf (surface->xml_node, "\" ");
status = emit_path (surface->xml_node, path, NULL);
status = _cairo_svg_surface_emit_path (surface->xml_node, path, NULL);
_cairo_output_stream_printf (surface->xml_node, "/>\n");
@ -1387,7 +1649,7 @@ _cairo_svg_surface_get_extents (void *abstract_surface,
}
static cairo_status_t
emit_paint (cairo_output_stream_t *output,
_cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
cairo_svg_surface_t *surface,
cairo_operator_t op,
cairo_pattern_t *source,
@ -1395,7 +1657,7 @@ emit_paint (cairo_output_stream_t *output,
{
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
source->extend == CAIRO_EXTEND_NONE)
return emit_composite_pattern (output,
return _cairo_svg_surface_emit_composite_pattern (output,
surface,
(cairo_surface_pattern_t *) source,
invalid_pattern_id,
@ -1406,8 +1668,8 @@ emit_paint (cairo_output_stream_t *output,
"width=\"%f\" height=\"%f\" "
"style=\"",
surface->width, surface->height);
emit_operator (output, surface, op);
emit_pattern (surface, source, output, FALSE);
_cairo_svg_surface_emit_operator (output, surface, op);
_cairo_svg_surface_emit_pattern (surface, source, output, FALSE);
_cairo_output_stream_printf (output, " stroke: none;\"");
if (extra_attributes)
@ -1427,7 +1689,7 @@ _cairo_svg_surface_paint (void *abstract_surface,
cairo_svg_surface_t *surface = abstract_surface;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, source);
return _cairo_svg_surface_analyze_operation (surface, op, source);
/* XXX: It would be nice to be able to assert this condition
* here. But, we actually allow one 'cheat' that is used when
@ -1436,7 +1698,7 @@ _cairo_svg_surface_paint (void *abstract_surface,
* possible only because there is nothing between the fallback
* images and the paper, nor is anything painted above. */
/*
assert (_operation_supported (surface, op, source));
assert (__cairo_svg_surface_operation_supported (surface, op, source));
*/
/* Emulation of clear and source operators, when no clipping region
@ -1467,7 +1729,7 @@ _cairo_svg_surface_paint (void *abstract_surface,
}
}
emit_paint (surface->xml_node, surface, op, source, NULL);
_cairo_svg_surface_emit_paint (surface->xml_node, surface, op, source, NULL);
return CAIRO_STATUS_SUCCESS;
}
@ -1484,13 +1746,13 @@ _cairo_svg_surface_mask (void *abstract_surface,
char buffer[64];
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, source);
return _cairo_svg_surface_analyze_operation (surface, op, source);
assert (_operation_supported (surface, op, source));
assert (__cairo_svg_surface_operation_supported (surface, op, source));
emit_alpha_filter (document);
_cairo_svg_surface_emit_alpha_filter (document);
/* emit_paint() will output a pattern definition to
/* _cairo_svg_surface_emit_paint() will output a pattern definition to
* document->xml_node_defs so we need to write the mask element to
* a temporary stream and then copy that to xml_node_defs. */
mask_stream = _cairo_memory_stream_create ();
@ -1498,7 +1760,7 @@ _cairo_svg_surface_mask (void *abstract_surface,
"<mask id=\"mask%d\">\n"
" <g filter=\"url(#alpha)\">\n",
document->mask_id);
emit_paint (mask_stream, surface, op, mask, NULL);
_cairo_svg_surface_emit_paint (mask_stream, surface, op, mask, NULL);
_cairo_output_stream_printf (mask_stream,
" </g>\n"
"</mask>\n");
@ -1507,7 +1769,7 @@ _cairo_svg_surface_mask (void *abstract_surface,
snprintf (buffer, sizeof buffer, "mask=\"url(#mask%d);\"",
document->mask_id);
emit_paint (surface->xml_node, surface, op, source, buffer);
_cairo_svg_surface_emit_paint (surface->xml_node, surface, op, source, buffer);
document->mask_id++;
@ -1531,9 +1793,9 @@ _cairo_svg_surface_stroke (void *abstract_dst,
unsigned int i;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, source);
return _cairo_svg_surface_analyze_operation (surface, op, source);
assert (_operation_supported (surface, op, source));
assert (__cairo_svg_surface_operation_supported (surface, op, source));
switch (stroke_style->line_cap) {
case CAIRO_LINE_CAP_BUTT:
@ -1572,8 +1834,8 @@ _cairo_svg_surface_stroke (void *abstract_dst,
line_cap,
line_join);
emit_pattern (surface, source, surface->xml_node, TRUE);
emit_operator (surface->xml_node, surface, op);
_cairo_svg_surface_emit_pattern (surface, source, surface->xml_node, TRUE);
_cairo_svg_surface_emit_operator (surface->xml_node, surface, op);
if (stroke_style->num_dashes > 0) {
_cairo_output_stream_printf (surface->xml_node, "stroke-dasharray: ");
@ -1596,9 +1858,9 @@ _cairo_svg_surface_stroke (void *abstract_dst,
"stroke-miterlimit: %f;\" ",
stroke_style->miter_limit);
status = emit_path (surface->xml_node, path, ctm_inverse);
status = _cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse);
emit_transform (surface->xml_node, " transform", "/>\n", ctm);
_cairo_svg_surface_emit_transform (surface->xml_node, " transform", "/>\n", ctm);
return status;
}
@ -1619,9 +1881,9 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
int i;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, pattern);
return _cairo_svg_surface_analyze_operation (surface, op, pattern);
assert (_operation_supported (surface, op, pattern));
assert (__cairo_svg_surface_operation_supported (surface, op, pattern));
if (num_glyphs <= 0)
return CAIRO_STATUS_SUCCESS;
@ -1633,7 +1895,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
goto FALLBACK;
_cairo_output_stream_printf (surface->xml_node, "<g style=\"");
emit_pattern (surface, pattern, surface->xml_node, FALSE);
_cairo_svg_surface_emit_pattern (surface, pattern, surface->xml_node, FALSE);
_cairo_output_stream_printf (surface->xml_node, "\">\n");
for (i = 0; i < num_glyphs; i++) {
@ -1698,7 +1960,7 @@ _cairo_svg_surface_intersect_clip_path (void *dst,
"<clipPath id=\"clip%d\">\n"
" <path ",
document->clip_id);
status = emit_path (document->xml_node_defs, path, NULL);
status = _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
_cairo_output_stream_printf (document->xml_node_defs,
"/>\n"
"</clipPath>\n");
@ -1772,7 +2034,7 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
}
/* The use of defs for font glyphs imposes no per-subset limit. */
document->font_subsets = _cairo_scaled_font_subsets_create (0);
document->font_subsets = _cairo_scaled_font_subsets_create (0, INT_MAX);
if (document->font_subsets == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
free (document);

Просмотреть файл

@ -1,5 +1,6 @@
/*
* Copyright © 2002 Keith Packard
* Copyright © 2007 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
@ -40,7 +41,7 @@
/* private functions */
static cairo_status_t
_cairo_traps_grow_by (cairo_traps_t *traps, int additional);
_cairo_traps_grow (cairo_traps_t *traps);
static cairo_status_t
_cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom,
@ -49,18 +50,6 @@ _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bo
static int
_compare_point_fixed_by_y (const void *av, const void *bv);
static int
_compare_cairo_edge_by_top (const void *av, const void *bv);
static int
_compare_cairo_edge_by_slope (const void *av, const void *bv);
static cairo_fixed_16_16_t
_compute_x (cairo_line_t *line, cairo_fixed_t y);
static int
_line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret);
void
_cairo_traps_init (cairo_traps_t *traps)
{
@ -70,19 +59,19 @@ _cairo_traps_init (cairo_traps_t *traps)
traps->traps_size = 0;
traps->traps = NULL;
traps->extents.p1.x = traps->extents.p1.y = INT16_MAX << 16;
traps->extents.p2.x = traps->extents.p2.y = INT16_MIN << 16;
traps->extents.p1.x = traps->extents.p1.y = INT32_MAX;
traps->extents.p2.x = traps->extents.p2.y = INT32_MIN;
}
void
_cairo_traps_fini (cairo_traps_t *traps)
{
if (traps->traps_size) {
if (traps->traps && traps->traps != traps->traps_embedded)
free (traps->traps);
traps->traps = NULL;
traps->traps_size = 0;
traps->num_traps = 0;
}
traps->traps = NULL;
traps->traps_size = 0;
traps->num_traps = 0;
}
/**
@ -100,7 +89,7 @@ _cairo_traps_init_box (cairo_traps_t *traps,
{
_cairo_traps_init (traps);
traps->status = _cairo_traps_grow_by (traps, 1);
traps->status = _cairo_traps_grow (traps);
if (traps->status)
return traps->status;
@ -134,8 +123,7 @@ _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bo
}
if (traps->num_traps >= traps->traps_size) {
int inc = traps->traps_size ? traps->traps_size : 32;
traps->status = _cairo_traps_grow_by (traps, inc);
traps->status = _cairo_traps_grow (traps);
if (traps->status)
return traps->status;
}
@ -193,29 +181,43 @@ _cairo_traps_add_trap_from_points (cairo_traps_t *traps, cairo_fixed_t top, cair
return _cairo_traps_add_trap (traps, top, bottom, &left, &right);
}
/* make room for at least one more trap */
static cairo_status_t
_cairo_traps_grow_by (cairo_traps_t *traps, int additional)
_cairo_traps_grow (cairo_traps_t *traps)
{
cairo_trapezoid_t *new_traps;
int old_size = traps->traps_size;
int new_size = traps->num_traps + additional;
int embedded_size = sizeof (traps->traps_embedded) / sizeof (traps->traps_embedded[0]);
int new_size = 2 * MAX (old_size, 16);
/* we have a local buffer at traps->traps_embedded. try to fulfill the request
* from there. */
if (old_size < embedded_size) {
traps->traps = traps->traps_embedded;
traps->traps_size = embedded_size;
return traps->status;
}
assert (traps->num_traps <= traps->traps_size);
if (traps->status)
return traps->status;
if (new_size <= traps->traps_size)
return traps->status;
traps->traps_size = new_size;
new_traps = realloc (traps->traps, traps->traps_size * sizeof (cairo_trapezoid_t));
if (traps->traps == traps->traps_embedded) {
new_traps = malloc (new_size * sizeof (cairo_trapezoid_t));
if (new_traps)
memcpy (new_traps, traps->traps, old_size * sizeof (cairo_trapezoid_t));
} else {
new_traps = realloc (traps->traps, new_size * sizeof (cairo_trapezoid_t));
}
if (new_traps == NULL) {
traps->traps_size = old_size;
traps->status = CAIRO_STATUS_NO_MEMORY;
return traps->status;
}
traps->traps = new_traps;
traps->traps_size = new_size;
return traps->status;
}
@ -309,57 +311,20 @@ _cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
}
}
/* A triangle is simply a degenerate case of a convex
* quadrilateral. We would not benefit from having any distinct
* implementation of triangle vs. quadrilateral tessellation here. */
cairo_status_t
_cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3])
{
cairo_line_t line;
cairo_fixed_16_16_t intersect;
cairo_point_t tsort[3];
cairo_point_t quad[4];
memcpy (tsort, t, 3 * sizeof (cairo_point_t));
qsort (tsort, 3, sizeof (cairo_point_t), _compare_point_fixed_by_y);
quad[0] = t[0];
quad[1] = t[0];
quad[2] = t[1];
quad[3] = t[2];
/* horizontal top edge requires special handling */
if (tsort[0].y == tsort[1].y) {
if (tsort[0].x < tsort[1].x)
_cairo_traps_add_trap_from_points (traps,
tsort[1].y, tsort[2].y,
tsort[0], tsort[2],
tsort[1], tsort[2]);
else
_cairo_traps_add_trap_from_points (traps,
tsort[1].y, tsort[2].y,
tsort[1], tsort[2],
tsort[0], tsort[2]);
return traps->status;
}
line.p1 = tsort[0];
line.p2 = tsort[1];
intersect = _compute_x (&line, tsort[2].y);
if (intersect < tsort[2].x) {
_cairo_traps_add_trap_from_points (traps,
tsort[0].y, tsort[1].y,
tsort[0], tsort[1],
tsort[0], tsort[2]);
_cairo_traps_add_trap_from_points (traps,
tsort[1].y, tsort[2].y,
tsort[1], tsort[2],
tsort[0], tsort[2]);
} else {
_cairo_traps_add_trap_from_points (traps,
tsort[0].y, tsort[1].y,
tsort[0], tsort[2],
tsort[0], tsort[1]);
_cairo_traps_add_trap_from_points (traps,
tsort[1].y, tsort[2].y,
tsort[0], tsort[2],
tsort[1], tsort[2]);
}
return traps->status;
return _cairo_traps_tessellate_convex_quad (traps, quad);
}
cairo_status_t
@ -367,6 +332,8 @@ _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, cairo_point_t q[4])
{
int a, b, c, d;
int i;
cairo_slope_t ab, ad;
cairo_bool_t b_left_of_d;
/* Choose a as a point with minimal y */
a = 0;
@ -386,24 +353,50 @@ _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, cairo_point_t q[4])
}
/* Without freedom left to choose anything else, we have four
* cases to tessellate which we can distinguish by comparing c.y
* to d.y and then by comparing b.x to d.x. And then for any of
* these cases there is a trivial way to emit three
* trapezoids. The 4 cases and their trapezoids are described and
* implemented below:
*/
if (q[c].y < q[d].y) {
if (q[b].x < q[d].x) {
/* c.y < d.y && b.x < d.x
* cases to tessellate.
*
* First, we have to determine the Y-axis sort of the four
* vertices, (either abcd or abdc). After that we need to detemine
* which edges will be "left" and which will be "right" in the
* resulting trapezoids. This can be determined by computing a
* slope comparison of ab and ad to determine if b is left of d or
* not.
*
* Note that "left of" here is in the sense of which edges should
* be the left vs. right edges of the trapezoid. In particular, b
* left of d does *not* mean that b.x is less than d.x.
*
* This should hopefully be made clear in the lame ASCII art
* below. Since the same slope comparison is used in all cases, we
* compute it before testing for the Y-value sort. */
/* Note: If a == b then the ab slope doesn't give us any
* information. In that case, we can replace it with the ac (or
* equivalenly the bc) slope which gives us exactly the same
* information we need. At worst the names of the identifiers ab
* and b_left_of_d are inaccurate in this case, (would be ac, and
* c_left_of_d). */
if (q[a].x == q[b].x && q[a].y == q[b].y)
_cairo_slope_init (&ab, &q[a], &q[c]);
else
_cairo_slope_init (&ab, &q[a], &q[b]);
_cairo_slope_init (&ad, &q[a], &q[d]);
b_left_of_d = (_cairo_slope_compare (&ab, &ad) > 0);
if (q[c].y <= q[d].y) {
if (b_left_of_d) {
/* Y-sort is abcd and b is left of d, (slope(ab) > slope (ad))
*
* top bot left right
* a
* / | a.y b.y ab ad
* b |
* | | b.y c.y bc ad
* c |
* \ | c.y d.y cd ad
* d
* top bot left right
* _a a a
* / / /| |\ a.y b.y ab ad
* b / b | b \
* / / | | \ \ b.y c.y bc ad
* c / c | c \
* | / \| \ \ c.y d.y cd ad
* d d d
*/
_cairo_traps_add_trap_from_points (traps,
q[a].y, q[b].y,
@ -415,15 +408,15 @@ _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, cairo_point_t q[4])
q[c].y, q[d].y,
q[c], q[d], q[a], q[d]);
} else {
/* c.y < d.y && b.x >= d.x
/* Y-sort is abcd and b is right of d, (slope(ab) <= slope (ad))
*
* a
* | \ a.y b.y ad ab
* | b
* | | b.y c.y ad bc
* | c
* | / c.y d.y ad cd
* d
* a a a_
* /| |\ \ \ a.y b.y ad ab
* / b | b \ b
* / / | | \ \ b.y c.y ad bc
* / c | c \ c
* / / |/ \ | c.y d.y ad cd
* d d d
*/
_cairo_traps_add_trap_from_points (traps,
q[a].y, q[b].y,
@ -436,16 +429,16 @@ _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, cairo_point_t q[4])
q[a], q[d], q[c], q[d]);
}
} else {
if (q[b].x < q[d].x) {
/* c.y >= d.y && b.x < d.x
if (b_left_of_d) {
/* Y-sort is abdc and b is left of d, (slope (ab) > slope (ad))
*
* a
* / \ a.y b.y ab ad
* b \
* \ \ b.y d.y bc ad
* \ d
* \ / d.y c.y bc dc
* c
* a a a
* // / \ |\ a.y b.y ab ad
* /b/ b \ b \
* / / \ \ \ \ b.y d.y bc ad
* /d/ \ d \ d
* // \ / \| d.y c.y bc dc
* c c c
*/
_cairo_traps_add_trap_from_points (traps,
q[a].y, q[b].y,
@ -457,15 +450,15 @@ _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, cairo_point_t q[4])
q[d].y, q[c].y,
q[b], q[c], q[d], q[c]);
} else {
/* c.y >= d.y && b.x >= d.x
/* Y-sort is abdc and b is right of d, (slope (ab) <= slope (ad))
*
* a
* / \ a.y b.y ad ab
* / b
* / / b.y d.y ad bc
* d /
* \ / d.y c.y dc bc
* c
* a a a
* /| / \ \\ a.y b.y ad ab
* / b / b \b\
* / / / / \ \ b.y d.y ad bc
* d / d / \d\
* |/ \ / \\ d.y c.y dc bc
* c c c
*/
_cairo_traps_add_trap_from_points (traps,
q[a].y, q[b].y,
@ -482,400 +475,6 @@ _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, cairo_point_t q[4])
return traps->status;
}
static int
_compare_cairo_edge_by_top (const void *av, const void *bv)
{
const cairo_edge_t *a = av, *b = bv;
return a->edge.p1.y - b->edge.p1.y;
}
/* Return value is:
> 0 if a is "clockwise" from b, (in a mathematical, not a graphical sense)
== 0 if slope (a) == slope (b)
< 0 if a is "counter-clockwise" from b
*/
static int
_compare_cairo_edge_by_slope (const void *av, const void *bv)
{
const cairo_edge_t *a = av, *b = bv;
cairo_fixed_32_32_t d;
cairo_fixed_48_16_t a_dx = a->edge.p2.x - a->edge.p1.x;
cairo_fixed_48_16_t a_dy = a->edge.p2.y - a->edge.p1.y;
cairo_fixed_48_16_t b_dx = b->edge.p2.x - b->edge.p1.x;
cairo_fixed_48_16_t b_dy = b->edge.p2.y - b->edge.p1.y;
d = b_dy * a_dx - a_dy * b_dx;
if (d > 0)
return 1;
else if (d == 0)
return 0;
else
return -1;
}
static int
_compare_cairo_edge_by_current_x_slope (const void *av, const void *bv)
{
const cairo_edge_t *a = av, *b = bv;
int ret;
ret = a->current_x - b->current_x;
if (ret == 0)
ret = _compare_cairo_edge_by_slope (a, b);
return ret;
}
/* XXX: Both _compute_x and _compute_inverse_slope will divide by zero
for horizontal lines. Now, we "know" that when we are tessellating
polygons that the polygon data structure discards all horizontal
edges, but there's nothing here to guarantee that. I suggest the
following:
A) Move all of the polygon tessellation code out of xrtraps.c and
into xrpoly.c, (in order to be in the same module as the code
discarding horizontal lines).
OR
B) Re-implement the line intersection in a way that avoids all
division by zero. Here's one approach. The only disadvantage
might be that that there are not meaningful names for all of the
sub-computations -- just a bunch of determinants. I haven't
looked at complexity, (both are probably similar and it probably
doesn't matter much anyway).
*/
/* XXX: Keith's new intersection code is much cleaner, and uses
* sufficient precision for correctly sorting intersections according
* to the analysis in Hobby's paper.
*
* But, when we enable this code, some things are failing, (eg. the
* stars in test/fill_rule get filled wrong). This could indicate a
* bug in one of tree places:
*
* 1) The new intersection code in this file
*
* 2) cairo_wideint.c (which is only exercised here)
*
* 3) In the current tessellator, (where the old intersection
* code, with its mystic increments could be masking the bug).
*
* It will likely be easier to revisit this when the new tessellation
* code is in place. So, for now, we'll simply disable the new
* intersection code.
*/
#define CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE 0
#if CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE
static const cairo_fixed_32_32_t
_det16_32 (cairo_fixed_16_16_t a,
cairo_fixed_16_16_t b,
cairo_fixed_16_16_t c,
cairo_fixed_16_16_t d)
{
return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d),
_cairo_int32x32_64_mul (b, c));
}
static const cairo_fixed_64_64_t
_det32_64 (cairo_fixed_32_32_t a,
cairo_fixed_32_32_t b,
cairo_fixed_32_32_t c,
cairo_fixed_32_32_t d)
{
return _cairo_int128_sub (_cairo_int64x64_128_mul (a, d),
_cairo_int64x64_128_mul (b, c));
}
static const cairo_fixed_32_32_t
_fixed_16_16_to_fixed_32_32 (cairo_fixed_16_16_t a)
{
return _cairo_int64_lsl (_cairo_int32_to_int64 (a), 16);
}
static int
_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection)
{
cairo_fixed_16_16_t dx1, dx2, dy1, dy2;
cairo_fixed_32_32_t den_det;
cairo_fixed_32_32_t l1_det, l2_det;
cairo_fixed_64_64_t num_det;
cairo_fixed_32_32_t intersect_32_32;
cairo_fixed_48_16_t intersect_48_16;
cairo_fixed_16_16_t intersect_16_16;
cairo_quorem128_t qr;
dx1 = l1->p1.x - l1->p2.x;
dy1 = l1->p1.y - l1->p2.y;
dx2 = l2->p1.x - l2->p2.x;
dy2 = l2->p1.y - l2->p2.y;
den_det = _det16_32 (dx1, dy1,
dx2, dy2);
if (_cairo_int64_eq (den_det, _cairo_int32_to_int64(0)))
return 0;
l1_det = _det16_32 (l1->p1.x, l1->p1.y,
l1->p2.x, l1->p2.y);
l2_det = _det16_32 (l2->p1.x, l2->p1.y,
l2->p2.x, l2->p2.y);
num_det = _det32_64 (l1_det, _fixed_16_16_to_fixed_32_32 (dy1),
l2_det, _fixed_16_16_to_fixed_32_32 (dy2));
/*
* Ok, this one is a bit tricky in fixed point, the denominator
* needs to be left with 32-bits of fraction so that the
* result of the divide ends up with 32-bits of fraction (64 - 32 = 32)
*/
qr = _cairo_int128_divrem (num_det, _cairo_int64_to_int128 (den_det));
intersect_32_32 = _cairo_int128_to_int64 (qr.quo);
/*
* Find the ceiling of the quotient -- divrem returns
* the quotient truncated towards zero, so if the
* quotient should be positive (num_den and den_det have same sign)
* bump the quotient up by one.
*/
if (_cairo_int128_ne (qr.rem, _cairo_int32_to_int128 (0)) &&
(_cairo_int128_ge (num_det, _cairo_int32_to_int128 (0)) ==
_cairo_int64_ge (den_det, _cairo_int32_to_int64 (0))))
{
intersect_32_32 = _cairo_int64_add (intersect_32_32,
_cairo_int32_to_int64 (1));
}
/*
* Now convert from 32.32 to 48.16 and take the ceiling;
* this requires adding in 15 1 bits and shifting the result
*/
intersect_32_32 = _cairo_int64_add (intersect_32_32,
_cairo_int32_to_int64 ((1 << 16) - 1));
intersect_48_16 = _cairo_int64_rsa (intersect_32_32, 16);
/*
* And drop the top bits
*/
intersect_16_16 = _cairo_int64_to_int32 (intersect_48_16);
*y_intersection = intersect_16_16;
return 1;
}
#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */
static cairo_fixed_16_16_t
_compute_x (cairo_line_t *line, cairo_fixed_t y)
{
cairo_fixed_16_16_t dx = line->p2.x - line->p1.x;
cairo_fixed_32_32_t ex = (cairo_fixed_48_16_t) (y - line->p1.y) * (cairo_fixed_48_16_t) dx;
cairo_fixed_16_16_t dy = line->p2.y - line->p1.y;
return line->p1.x + (ex / dy);
}
#if ! CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE
static double
_compute_inverse_slope (cairo_line_t *l)
{
return (_cairo_fixed_to_double (l->p2.x - l->p1.x) /
_cairo_fixed_to_double (l->p2.y - l->p1.y));
}
static double
_compute_x_intercept (cairo_line_t *l, double inverse_slope)
{
return _cairo_fixed_to_double (l->p1.x) - inverse_slope * _cairo_fixed_to_double (l->p1.y);
}
static int
_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_ret)
{
/*
* x = m1y + b1
* x = m2y + b2
* m1y + b1 = m2y + b2
* y * (m1 - m2) = b2 - b1
* y = (b2 - b1) / (m1 - m2)
*/
cairo_fixed_16_16_t y_intersect;
double m1 = _compute_inverse_slope (l1);
double b1 = _compute_x_intercept (l1, m1);
double m2 = _compute_inverse_slope (l2);
double b2 = _compute_x_intercept (l2, m2);
if (m1 == m2)
return 0;
y_intersect = _cairo_fixed_from_double ((b2 - b1) / (m1 - m2));
if (m1 < m2) {
cairo_line_t *t;
t = l1;
l1 = l2;
l2 = t;
}
/* Assuming 56 bits of floating point precision, the intersection
is accurate within one sub-pixel coordinate. We must ensure
that we return a value that is at or after the intersection. At
most, we must increment once. */
if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
y_intersect++;
/* XXX: Hmm... Keith's error calculations said we'd at most be off
by one sub-pixel. But, I found that the paint-fill-BE-01.svg
test from the W3C SVG conformance suite definitely requires two
increments.
It could be that we need one to overcome the error, and another
to round up.
It would be nice to be sure this code is correct, (but we can't
do the while loop as it will work for way to long on
exceedingly distant intersections with large errors that we
really don't care about anyway as they will be ignored by the
calling function.
*/
if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
y_intersect++;
/* XXX: hmm... now I found "intersection_killer" inside xrspline.c
that requires 3 increments. Clearly, we haven't characterized
this completely yet. */
if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
y_intersect++;
/* I think I've found the answer to our problems. The insight is
that everytime we round we are changing the slopes of the
relevant lines, so we may be introducing new intersections that
we miss, so everything breaks apart. John Hobby wrote a paper
on how to fix this:
[Hobby93c] John D. Hobby, Practical Segment Intersection with
Finite Precision Output, Computation Geometry Theory and
Applications, 13(4), 1999.
Available online (2003-08017):
http://cm.bell-labs.com/cm/cs/doc/93/2-27.ps.gz
Now we just need to go off and implement that.
*/
*y_ret = y_intersect;
return 1;
}
#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */
/* The algorithm here is pretty simple:
inactive = [edges]
y = min_p1_y (inactive)
while (num_active || num_inactive) {
active = all edges containing y
next_y = min ( min_p2_y (active), min_p1_y (inactive), min_intersection (active) )
fill_traps (active, y, next_y, fill_rule)
y = next_y
}
The invariants that hold during fill_traps are:
All edges in active contain both y and next_y
No edges in active intersect within y and next_y
These invariants mean that fill_traps is as simple as sorting the
active edges, forming a trapezoid between each adjacent pair. Then,
either the even-odd or winding rule is used to determine whether to
emit each of these trapezoids.
Warning: This function obliterates the edges of the polygon provided.
*/
cairo_status_t
_cairo_traps_tessellate_polygon (cairo_traps_t *traps,
cairo_polygon_t *poly,
cairo_fill_rule_t fill_rule)
{
int i, active, inactive;
cairo_fixed_t y, y_next, intersect;
int in_out, num_edges = poly->num_edges;
cairo_edge_t *edges = poly->edges;
if (num_edges == 0)
return CAIRO_STATUS_SUCCESS;
qsort (edges, num_edges, sizeof (cairo_edge_t), _compare_cairo_edge_by_top);
y = edges[0].edge.p1.y;
active = 0;
inactive = 0;
while (active < num_edges) {
while (inactive < num_edges && edges[inactive].edge.p1.y <= y)
inactive++;
for (i = active; i < inactive; i++)
edges[i].current_x = _compute_x (&edges[i].edge, y);
qsort (&edges[active], inactive - active,
sizeof (cairo_edge_t), _compare_cairo_edge_by_current_x_slope);
/* find next inflection point */
y_next = edges[active].edge.p2.y;
for (i = active; i < inactive; i++) {
if (edges[i].edge.p2.y < y_next)
y_next = edges[i].edge.p2.y;
/* check intersect */
if (i != inactive - 1 && edges[i].current_x != edges[i+1].current_x)
if (_line_segs_intersect_ceil (&edges[i].edge, &edges[i+1].edge,
&intersect))
if (intersect > y && intersect < y_next)
y_next = intersect;
}
/* check next inactive point */
if (inactive < num_edges && edges[inactive].edge.p1.y < y_next)
y_next = edges[inactive].edge.p1.y;
/* walk the active edges generating trapezoids */
in_out = 0;
for (i = active; i < inactive - 1; i++) {
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
if (edges[i].clockWise)
in_out++;
else
in_out--;
if (in_out == 0)
continue;
} else {
in_out++;
if ((in_out & 1) == 0)
continue;
}
_cairo_traps_add_trap (traps, y, y_next, &edges[i].edge, &edges[i+1].edge);
}
/* delete inactive edges */
for (i = active; i < inactive; i++) {
if (edges[i].edge.p2.y <= y_next) {
memmove (&edges[active+1], &edges[active], (i - active) * sizeof (cairo_edge_t));
active++;
}
}
y = y_next;
}
return traps->status;
}
static cairo_bool_t
_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
{

Просмотреть файл

@ -62,9 +62,33 @@
#define TT_TAG_loca MAKE_TT_TAG('l','o','c','a')
#define TT_TAG_maxp MAKE_TT_TAG('m','a','x','p')
#define TT_TAG_name MAKE_TT_TAG('n','a','m','e')
#define TT_TAG_post MAKE_TT_TAG('p','o','s','t')
#define TT_TAG_prep MAKE_TT_TAG('p','r','e','p')
/* All tt_* structs are big-endian */
typedef struct _tt_cmap_index {
uint16_t platform;
uint16_t encoding;
uint32_t offset;
} tt_cmap_index_t;
typedef struct _tt_cmap {
uint16_t version;
uint16_t num_tables;
tt_cmap_index_t index[1];
} tt_cmap_t;
typedef struct _segment_map {
uint16_t format;
uint16_t length;
uint16_t version;
uint16_t segCountX2;
uint16_t searchRange;
uint16_t entrySelector;
uint16_t rangeShift;
uint16_t endCount[1];
} tt_segment_map_t;
typedef struct _tt_head {
int16_t version_1;
int16_t version_2;

Просмотреть файл

@ -56,6 +56,7 @@ typedef struct _cairo_truetype_font {
int *widths;
long x_min, y_min, x_max, y_max;
long ascent, descent;
int units_per_em;
} base;
subset_glyph_t *glyphs;
@ -79,41 +80,6 @@ cairo_truetype_font_use_glyph (cairo_truetype_font_t *font, int glyph);
#define SFNT_VERSION 0x00010000
#define SFNT_STRING_MAX_LENGTH 65535
#ifdef WORDS_BIGENDIAN
#define cpu_to_be16(v) (v)
#define be16_to_cpu(v) (v)
#define cpu_to_be32(v) (v)
#define be32_to_cpu(v) (v)
#else
static inline uint16_t
cpu_to_be16(uint16_t v)
{
return (v << 8) | (v >> 8);
}
static inline uint16_t
be16_to_cpu(uint16_t v)
{
return cpu_to_be16 (v);
}
static inline uint32_t
cpu_to_be32(uint32_t v)
{
return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16);
}
static inline uint32_t
be32_to_cpu(uint32_t v)
{
return cpu_to_be32 (v);
}
#endif
static cairo_status_t
_cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
cairo_truetype_font_t **font_return)
@ -200,6 +166,9 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
font->base.y_max = (int16_t) be16_to_cpu (head.y_max);
font->base.ascent = (int16_t) be16_to_cpu (hhea.ascender);
font->base.descent = (int16_t) be16_to_cpu (hhea.descender);
font->base.units_per_em = (int16_t) be16_to_cpu (head.units_per_em);
if (font->base.units_per_em == 0)
font->base.units_per_em = 2048;
/* Extract the font name from the name table. At present this
* just looks for the Mac platform/Roman encoded font name. It
@ -371,22 +340,45 @@ cairo_truetype_font_write_cmap_table (cairo_truetype_font_t *font,
{
unsigned int i;
cairo_truetype_font_write_be16 (font, 0);
cairo_truetype_font_write_be16 (font, 1);
cairo_truetype_font_write_be16 (font, 0); /* Table version */
cairo_truetype_font_write_be16 (font, 2); /* Num tables */
cairo_truetype_font_write_be16 (font, 1);
cairo_truetype_font_write_be16 (font, 0);
cairo_truetype_font_write_be32 (font, 12);
cairo_truetype_font_write_be16 (font, 3); /* Platform */
cairo_truetype_font_write_be16 (font, 0); /* Encoding */
cairo_truetype_font_write_be32 (font, 20); /* Offset to start of table */
cairo_truetype_font_write_be16 (font, 1); /* Platform */
cairo_truetype_font_write_be16 (font, 0); /* Encoding */
cairo_truetype_font_write_be32 (font, 52); /* Offset to start of table */
/* Output a format 4 encoding table. */
cairo_truetype_font_write_be16 (font, 4); /* Format */
cairo_truetype_font_write_be16 (font, 32); /* Length */
cairo_truetype_font_write_be16 (font, 0); /* Version */
cairo_truetype_font_write_be16 (font, 4); /* 2*segcount */
cairo_truetype_font_write_be16 (font, 4); /* searchrange */
cairo_truetype_font_write_be16 (font, 1); /* entry selector */
cairo_truetype_font_write_be16 (font, 0); /* rangeshift */
cairo_truetype_font_write_be16 (font, 0xf000 + font->base.num_glyphs - 2); /* end count[0] */
cairo_truetype_font_write_be16 (font, 0xffff); /* end count[1] */
cairo_truetype_font_write_be16 (font, 0); /* reserved */
cairo_truetype_font_write_be16 (font, 0xf000); /* startCode[0] */
cairo_truetype_font_write_be16 (font, 0xffff); /* startCode[1] */
cairo_truetype_font_write_be16 (font, 0x1001); /* delta[0] */
cairo_truetype_font_write_be16 (font, 1); /* delta[1] */
cairo_truetype_font_write_be16 (font, 0); /* rangeOffset[0] */
cairo_truetype_font_write_be16 (font, 0); /* rangeOffset[1] */
/* Output a format 6 encoding table. */
cairo_truetype_font_write_be16 (font, 6);
cairo_truetype_font_write_be16 (font, 10 + 2 * (font->base.num_glyphs - 1));
cairo_truetype_font_write_be16 (font, 0);
cairo_truetype_font_write_be16 (font, 1); /* First glyph */
cairo_truetype_font_write_be16 (font, font->base.num_glyphs - 1);
for (i = 1; i < font->base.num_glyphs; i++)
cairo_truetype_font_write_be16 (font, i);
cairo_truetype_font_write_be16 (font, 0); /* First character */
cairo_truetype_font_write_be16 (font, font->base.num_glyphs);
for (i = 0; i < font->base.num_glyphs; i++)
cairo_truetype_font_write_be16 (font, i + 1);
return font->status;
}
@ -532,6 +524,9 @@ cairo_truetype_font_write_head_table (cairo_truetype_font_t *font,
font->status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
font->backend->load_truetype_table( font->scaled_font_subset->scaled_font,
tag, 0, buffer, &size);
/* set checkSumAdjustment to 0 for table checksum calcualtion */
*(uint32_t *)(buffer + 8) = 0;
return font->status;
}
@ -640,28 +635,65 @@ cairo_truetype_font_write_maxp_table (cairo_truetype_font_t *font,
return font->status;
}
static int
cairo_truetype_font_write_post_table (cairo_truetype_font_t *font,
unsigned long tag)
{
char buf[10];
int n;
unsigned i;
cairo_truetype_font_write_be32 (font, 0x00020000);
cairo_truetype_font_write_be32 (font, 0);
cairo_truetype_font_write_be16 (font, 0);
cairo_truetype_font_write_be16 (font, 1);
cairo_truetype_font_write_be32 (font, 0);
cairo_truetype_font_write_be32 (font, 0);
cairo_truetype_font_write_be32 (font, 0);
cairo_truetype_font_write_be32 (font, 0);
cairo_truetype_font_write_be32 (font, 0);
cairo_truetype_font_write_be16 (font, font->base.num_glyphs);
cairo_truetype_font_write_be16 (font, 0);
for (i = 1; i < font->base.num_glyphs; i++)
cairo_truetype_font_write_be16 (font, i + 257);
for (i = 1; i < font->base.num_glyphs; i++) {
n = snprintf(buf + 1, 9, "g%d", i - 1);
buf[0] = n;
cairo_truetype_font_write (font, buf, n + 1);
}
return font->status;
}
typedef struct table table_t;
struct table {
unsigned long tag;
int (*write) (cairo_truetype_font_t *font, unsigned long tag);
int pos; /* position in the font directory */
};
static const table_t truetype_tables[] = {
/* As we write out the glyf table we remap composite glyphs.
* Remapping composite glyphs will reference the sub glyphs the
* composite glyph is made up of. That needs to be done first so
* we have all the glyphs in the subset before going further. */
{ TT_TAG_glyf, cairo_truetype_font_write_glyf_table },
{ TT_TAG_cmap, cairo_truetype_font_write_cmap_table },
{ TT_TAG_cvt, cairo_truetype_font_write_generic_table },
{ TT_TAG_fpgm, cairo_truetype_font_write_generic_table },
{ TT_TAG_head, cairo_truetype_font_write_head_table },
{ TT_TAG_hhea, cairo_truetype_font_write_hhea_table },
{ TT_TAG_hmtx, cairo_truetype_font_write_hmtx_table },
{ TT_TAG_loca, cairo_truetype_font_write_loca_table },
{ TT_TAG_maxp, cairo_truetype_font_write_maxp_table },
{ TT_TAG_name, cairo_truetype_font_write_generic_table },
{ TT_TAG_prep, cairo_truetype_font_write_generic_table },
* we have all the glyphs in the subset before going further.
*
* The third column in this table is the order in which the
* directory entries will appear in the table directory.
* The table directory must be sorted in tag order. */
{ TT_TAG_glyf, cairo_truetype_font_write_glyf_table, 3 },
{ TT_TAG_cmap, cairo_truetype_font_write_cmap_table, 0 },
{ TT_TAG_cvt, cairo_truetype_font_write_generic_table, 1 },
{ TT_TAG_fpgm, cairo_truetype_font_write_generic_table, 2 },
{ TT_TAG_head, cairo_truetype_font_write_head_table, 4 },
{ TT_TAG_hhea, cairo_truetype_font_write_hhea_table, 5 },
{ TT_TAG_hmtx, cairo_truetype_font_write_hmtx_table, 6 },
{ TT_TAG_loca, cairo_truetype_font_write_loca_table, 7 },
{ TT_TAG_maxp, cairo_truetype_font_write_maxp_table, 8 },
{ TT_TAG_name, cairo_truetype_font_write_generic_table, 9 },
{ TT_TAG_post, cairo_truetype_font_write_post_table, 10 },
{ TT_TAG_prep, cairo_truetype_font_write_generic_table, 11 },
};
static cairo_status_t
@ -716,7 +748,7 @@ cairo_truetype_font_calculate_checksum (cairo_truetype_font_t *font,
p = (uint32_t *) (data + start);
padded_end = (uint32_t *) (data + ((end + 3) & ~3));
while (p < padded_end)
checksum += *p++;
checksum += be32_to_cpu(*p++);
return checksum;
}
@ -761,7 +793,7 @@ cairo_truetype_font_generate (cairo_truetype_font_t *font,
end = _cairo_array_num_elements (&font->output);
next = cairo_truetype_font_align_output (font);
cairo_truetype_font_update_entry (font, i, truetype_tables[i].tag,
cairo_truetype_font_update_entry (font, truetype_tables[i].pos, truetype_tables[i].tag,
start, end);
cairo_truetype_font_check_boundary (font, next);
start = next;
@ -813,6 +845,10 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
if (status)
return status;
/* Add the notdef glyph. This is required at glyph index 0
* in the subsetted font. */
cairo_truetype_font_use_glyph (font, 0);
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
parent_glyph = font->scaled_font_subset->glyphs[i];
cairo_truetype_font_use_glyph (font, parent_glyph);
@ -827,18 +863,23 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
if (truetype_subset->base_font == NULL)
goto fail1;
truetype_subset->widths = calloc (sizeof (int), font->base.num_glyphs);
/* The widths array returned must contain only widths for
* the glyphs in font_subset. The notdef glyph at index 0
* and any subglyphs appended after font_subset->num_glyphs
* are omitted. */
truetype_subset->widths = calloc (sizeof (double),
font->scaled_font_subset->num_glyphs);
if (truetype_subset->widths == NULL)
goto fail2;
for (i = 0; i < font->base.num_glyphs; i++)
truetype_subset->widths[i] = font->base.widths[i];
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
truetype_subset->widths[i] = (double)font->base.widths[i + 1]/font->base.units_per_em;
truetype_subset->x_min = font->base.x_min;
truetype_subset->y_min = font->base.y_min;
truetype_subset->x_max = font->base.x_max;
truetype_subset->y_max = font->base.y_max;
truetype_subset->ascent = font->base.ascent;
truetype_subset->descent = font->base.descent;
truetype_subset->x_min = (double)font->base.x_min/font->base.units_per_em;
truetype_subset->y_min = (double)font->base.y_min/font->base.units_per_em;
truetype_subset->x_max = (double)font->base.x_max/font->base.units_per_em;
truetype_subset->y_max = (double)font->base.y_max/font->base.units_per_em;
truetype_subset->ascent = (double)font->base.ascent/font->base.units_per_em;
truetype_subset->descent = (double)font->base.descent/font->base.units_per_em;
truetype_subset->data = malloc (length);
if (truetype_subset->data == NULL)
@ -880,3 +921,145 @@ _cairo_truetype_subset_fini (cairo_truetype_subset_t *subset)
free (subset->string_offsets);
}
static cairo_int_status_t
_cairo_truetype_map_glyphs_to_unicode (cairo_scaled_font_subset_t *font_subset,
unsigned long table_offset)
{
cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
const cairo_scaled_font_backend_t *backend;
tt_segment_map_t *map;
char buf[4];
unsigned int num_segments, i, j;
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;
backend = font_subset->scaled_font->backend;
size = 4;
if (backend->load_truetype_table (font_subset->scaled_font,
TT_TAG_cmap, table_offset,
(unsigned char *) &buf,
&size) != CAIRO_STATUS_SUCCESS) {
return CAIRO_INT_STATUS_UNSUPPORTED;
}
/* All table formats have the same first two words */
map = (tt_segment_map_t *) buf;
if (be16_to_cpu (map->format) != 4)
return CAIRO_INT_STATUS_UNSUPPORTED;
size = be16_to_cpu (map->length);
map = malloc (size);
if (map == NULL)
return CAIRO_STATUS_NO_MEMORY;
if (backend->load_truetype_table (font_subset->scaled_font,
TT_TAG_cmap, table_offset,
(unsigned char *) map,
&size) != CAIRO_STATUS_SUCCESS) {
goto fail;
}
num_segments = be16_to_cpu (map->segCountX2)/2;
end_code = map->endCount;
start_code = &(end_code[num_segments + 1]);
delta = &(start_code[num_segments]);
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++;
}
status = CAIRO_STATUS_SUCCESS;
fail:
free (map);
return status;
}
cairo_int_status_t
_cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t *font_subset)
{
cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
const cairo_scaled_font_backend_t *backend;
tt_cmap_t *cmap;
char buf[4];
int num_tables, i;
unsigned long size;
backend = font_subset->scaled_font->backend;
if (!backend->load_truetype_table)
return CAIRO_INT_STATUS_UNSUPPORTED;
size = 4;
if (backend->load_truetype_table (font_subset->scaled_font,
TT_TAG_cmap, 0, (unsigned char *) &buf,
&size) != CAIRO_STATUS_SUCCESS)
return CAIRO_INT_STATUS_UNSUPPORTED;
cmap = (tt_cmap_t *) buf;
num_tables = be16_to_cpu (cmap->num_tables);
size = 4 + num_tables*sizeof(tt_cmap_index_t);
cmap = malloc (size);
if (cmap == NULL)
return CAIRO_STATUS_NO_MEMORY;
if (backend->load_truetype_table (font_subset->scaled_font,
TT_TAG_cmap, 0, (unsigned char *) cmap,
&size) != CAIRO_STATUS_SUCCESS) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto cleanup;
}
/* Find a table with Unicode mapping */
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));
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto cleanup;
}
}
cleanup:
free (cmap);
return status;
}

Просмотреть файл

@ -34,6 +34,7 @@
*/
#include "cairoint.h"
#include "cairo-type1-private.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-output-stream-private.h"
@ -116,11 +117,6 @@ fail:
return CAIRO_STATUS_NO_MEMORY;
}
/* Magic constants for the type1 eexec encryption */
static const unsigned short encrypt_c1 = 52845, encrypt_c2 = 22719;
static const unsigned short private_dict_key = 55665;
static const unsigned short charstring_key = 4330;
/* Charstring commands. If the high byte is 0 the command is encoded
* with a single byte. */
#define CHARSTRING_sbw 0x0c07
@ -301,13 +297,13 @@ charstring_encrypt (cairo_array_t *data)
unsigned char *d, *end;
uint16_t c, p, r;
r = charstring_key;
r = CAIRO_TYPE1_CHARSTRING_KEY;
d = (unsigned char *) _cairo_array_index (data, 0);
end = d + _cairo_array_num_elements (data);
while (d < end) {
p = *d;
c = p ^ (r >> 8);
r = (c + r) * encrypt_c1 + encrypt_c2;
r = (c + r) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2;
*d++ = c;
}
}
@ -534,7 +530,7 @@ cairo_type1_write_stream_encrypted (void *closure,
while (in < end) {
p = *in++;
c = p ^ (font->eexec_key >> 8);
font->eexec_key = (c + font->eexec_key) * encrypt_c1 + encrypt_c2;
font->eexec_key = (c + font->eexec_key) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2;
if (font->hex_encode) {
digits[0] = hex_digits[c >> 4];
@ -564,7 +560,7 @@ cairo_type1_font_write_private_dict (cairo_type1_font_t *font,
cairo_int_status_t status;
cairo_output_stream_t *encrypted_output;
font->eexec_key = private_dict_key;
font->eexec_key = CAIRO_TYPE1_PRIVATE_DICT_KEY;
font->hex_column = 0;
encrypted_output = _cairo_output_stream_create (
cairo_type1_write_stream_encrypted,
@ -680,8 +676,9 @@ static void
cairo_type1_font_destroy (cairo_type1_font_t *font)
{
free (font->widths);
_cairo_array_fini (&font->contents);
cairo_scaled_font_destroy (font->type1_scaled_font);
_cairo_array_fini (&font->contents);
_cairo_output_stream_destroy (font->output);
free (font);
}

Просмотреть файл

@ -34,6 +34,7 @@
*/
#include "cairoint.h"
#include "cairo-type1-private.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-output-stream-private.h"
@ -107,6 +108,7 @@ _cairo_type1_font_subset_create (cairo_unscaled_font_t *unscaled_font,
cairo_bool_t hex_encode)
{
cairo_ft_unscaled_font_t *ft_unscaled_font;
cairo_status_t status;
FT_Face face;
PS_FontInfoRec font_info;
cairo_type1_font_subset_t *font;
@ -116,12 +118,16 @@ _cairo_type1_font_subset_create (cairo_unscaled_font_t *unscaled_font,
face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font);
if (FT_Get_PS_Font_Info(face, &font_info) != 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (FT_Get_PS_Font_Info(face, &font_info) != 0) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto fail1;
}
font = calloc (sizeof (cairo_type1_font_subset_t), 1);
if (font == NULL)
return CAIRO_STATUS_NO_MEMORY;
if (font == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto fail1;
}
font->base.unscaled_font = _cairo_unscaled_font_reference (unscaled_font);
font->base.num_glyphs = face->num_glyphs;
@ -132,8 +138,10 @@ _cairo_type1_font_subset_create (cairo_unscaled_font_t *unscaled_font,
font->base.ascent = face->ascender;
font->base.descent = face->descender;
font->base.base_font = strdup (face->family_name);
if (font->base.base_font == NULL)
goto fail1;
if (font->base.base_font == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto fail2;
}
for (i = 0, j = 0; font->base.base_font[j]; j++) {
if (font->base.base_font[j] == ' ')
@ -143,8 +151,10 @@ _cairo_type1_font_subset_create (cairo_unscaled_font_t *unscaled_font,
font->base.base_font[i] = '\0';
font->glyphs = calloc (face->num_glyphs, sizeof font->glyphs[0]);
if (font->glyphs == NULL)
goto fail2;
if (font->glyphs == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto fail3;
}
font->hex_encode = hex_encode;
font->num_glyphs = 0;
@ -159,12 +169,15 @@ _cairo_type1_font_subset_create (cairo_unscaled_font_t *unscaled_font,
return CAIRO_STATUS_SUCCESS;
fail2:
fail3:
free (font->base.base_font);
fail1:
fail2:
_cairo_unscaled_font_destroy (unscaled_font);
free (font);
fail1:
_cairo_ft_unscaled_font_unlock_face (ft_unscaled_font);
return CAIRO_STATUS_NO_MEMORY;
return status;
}
static int
@ -179,11 +192,6 @@ cairo_type1_font_subset_use_glyph (cairo_type1_font_subset_t *font, int glyph)
return font->glyphs[glyph].subset_index;
}
/* Magic constants for the type1 eexec encryption */
static const unsigned short c1 = 52845, c2 = 22719;
static const unsigned short private_dict_key = 55665;
static const unsigned short charstring_key = 4330;
static cairo_bool_t
is_ps_delimiter(int c)
{
@ -325,7 +333,7 @@ cairo_type1_font_subset_write_encrypted (cairo_type1_font_subset_t *font,
while (in < end) {
p = *in++;
c = p ^ (font->eexec_key >> 8);
font->eexec_key = (c + font->eexec_key) * c1 + c2;
font->eexec_key = (c + font->eexec_key) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2;
if (font->hex_encode) {
digits[0] = hex_digits[c >> 4];
@ -349,7 +357,7 @@ cairo_type1_font_subset_write_encrypted (cairo_type1_font_subset_t *font,
static cairo_status_t
cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font)
{
unsigned short r = private_dict_key;
unsigned short r = CAIRO_TYPE1_PRIVATE_DICT_KEY;
unsigned char *in, *end;
char *out;
int c, p;
@ -372,7 +380,7 @@ cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font)
c = *in++;
}
p = c ^ (r >> 8);
r = (c + r) * c1 + c2;
r = (c + r) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2;
*out++ = p;
}
@ -452,13 +460,13 @@ cairo_type1_font_subset_get_glyph_names_and_widths (cairo_type1_font_subset_t *f
static void
cairo_type1_font_subset_decrypt_charstring (const unsigned char *in, int size, unsigned char *out)
{
unsigned short r = charstring_key;
unsigned short r = CAIRO_TYPE1_CHARSTRING_KEY;
int c, p, i;
for (i = 0; i < size; i++) {
c = *in++;
p = c ^ (r >> 8);
r = (c + r) * c1 + c2;
r = (c + r) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2;
*out++ = p;
}
}
@ -1004,7 +1012,7 @@ cairo_type1_font_subset_write (cairo_type1_font_subset_t *font,
return font->status = CAIRO_INT_STATUS_UNSUPPORTED;
}
font->eexec_key = private_dict_key;
font->eexec_key = CAIRO_TYPE1_PRIVATE_DICT_KEY;
font->hex_column = 0;
cairo_type1_font_subset_write_private_dict (font, name);

Просмотреть файл

@ -693,7 +693,7 @@ _cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font)
if (!hdc)
return CAIRO_STATUS_NO_MEMORY;
if (scaled_font->preserve_axes) {
if (scaled_font->preserve_axes || scaled_font->base.options.hint_metrics == CAIRO_HINT_METRICS_OFF) {
/* For 90-degree rotations (including 0), we get the metrics
* from the GDI in logical space, then convert back to font space
*/
@ -723,7 +723,7 @@ _cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font)
_cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base);
extents.ascent = (double)metrics.tmAscent / scaled_font->em_square;
extents.descent = metrics.tmDescent * scaled_font->em_square;
extents.descent = (double)metrics.tmDescent / scaled_font->em_square;
extents.height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / scaled_font->em_square;
extents.max_x_advance = (double)(metrics.tmMaxCharWidth) / scaled_font->em_square;
extents.max_y_advance = 0;
@ -1281,6 +1281,20 @@ _cairo_win32_scaled_font_load_truetype_table (void *abstract_font,
return status;
}
static void
_cairo_win32_scaled_font_map_glyphs_to_unicode (void *abstract_font,
cairo_scaled_font_subset_t *font_subset)
{
cairo_win32_scaled_font_t *scaled_font = abstract_font;
unsigned int i;
if (scaled_font->glyph_indexing)
return;
for (i = 0; i < font_subset->num_glyphs; i++)
font_subset->to_unicode[i] = font_subset->glyphs[i];
}
static void
_cairo_win32_transform_FIXED_to_fixed (cairo_matrix_t *matrix,
FIXED Fx, FIXED Fy,
@ -1467,6 +1481,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_font_face_t */
@ -1649,7 +1664,7 @@ cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font,
/**
* cairo_win32_scaled_font_done_font:
* @scaled_font: A #cairo_scaled_font_t from the Win32 font backend.
* @scaled_font: A scaled font from the Win32 font backend.
*
* Releases any resources allocated by cairo_win32_scaled_font_select_font()
**/
@ -1660,7 +1675,7 @@ cairo_win32_scaled_font_done_font (cairo_scaled_font_t *scaled_font)
/**
* cairo_win32_scaled_font_get_metrics_factor:
* @scaled_font: a #cairo_scaled_font_t from the Win32 font backend
* @scaled_font: a scaled font from the Win32 font backend
*
* Gets a scale factor between logical coordinates in the coordinate
* space used by cairo_win32_scaled_font_select_font() (that is, the
@ -1676,6 +1691,16 @@ cairo_win32_scaled_font_get_metrics_factor (cairo_scaled_font_t *scaled_font)
return 1. / ((cairo_win32_scaled_font_t *)scaled_font)->logical_scale;
}
/**
* cairo_win32_scaled_font_get_logical_to_device:
* @scaled_font: a scaled font from the Win32 font backend
* @logical_to_device: matrix to return
*
* Gets the transformation mapping the logical space used by @scaled_font
* to device space.
*
* Since: 1.4
**/
void
cairo_win32_scaled_font_get_logical_to_device (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *logical_to_device)
@ -1684,6 +1709,16 @@ cairo_win32_scaled_font_get_logical_to_device (cairo_scaled_font_t *scaled_font,
*logical_to_device = win_font->logical_to_device;
}
/**
* cairo_win32_scaled_font_get_device_to_logical:
* @scaled_font: a scaled font from the Win32 font backend
* @device_to_logical: matrix to return
*
* Gets the transformation mapping device space to the logical space
* used by @scaled_font.
*
* Since: 1.4
**/
void
cairo_win32_scaled_font_get_device_to_logical (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *device_to_logical)

Просмотреть файл

@ -46,7 +46,11 @@
#define SB_NONE 0
#endif
#if MOZILLA_CAIRO_NOT_DEFINED
#define WIN32_FONT_LOGICAL_SCALE 32
#else
#define WIN32_FONT_LOGICAL_SCALE 1
#endif
typedef struct _cairo_win32_surface {
cairo_surface_t base;

Просмотреть файл

@ -1487,6 +1487,7 @@ _cairo_win32_surface_show_glyphs (void *surface,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
{
#if CAIRO_HAS_WIN32_FONT
cairo_win32_surface_t *dst = surface;
WORD glyph_buf_stack[STACK_GLYPH_SIZE];
@ -1580,8 +1581,8 @@ _cairo_win32_surface_show_glyphs (void *surface,
next_logical_x = _cairo_lround (next_user_x);
next_logical_y = _cairo_lround (next_user_y);
dxy_buf[j] = _cairo_lround ((next_logical_x - logical_x) * WIN32_FONT_LOGICAL_SCALE);
dxy_buf[j+1] = _cairo_lround ((next_logical_y - logical_y) * WIN32_FONT_LOGICAL_SCALE);
dxy_buf[j] = _cairo_lround (next_logical_x - logical_x);
dxy_buf[j+1] = _cairo_lround (next_logical_y - logical_y);
logical_x = next_logical_x;
logical_y = next_logical_y;
@ -1607,6 +1608,9 @@ _cairo_win32_surface_show_glyphs (void *surface,
free(dxy_buf);
}
return (win_result) ? CAIRO_STATUS_SUCCESS : CAIRO_INT_STATUS_UNSUPPORTED;
#else
return CAIRO_INT_STATUS_UNSUPPORTED;
#endif
}
#undef STACK_GLYPH_SIZE
@ -1728,6 +1732,7 @@ cairo_win32_surface_create_with_dib (cairo_format_t format,
/**
* cairo_win32_surface_create_with_ddb:
* @hdc: the DC to create a surface for
* @format: format of pixels in the surface to create
* @width: width of the surface, in pixels
* @height: height of the surface, in pixels
@ -1890,9 +1895,11 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = {
*/
#if !defined(HAVE_PTHREAD_H)
CRITICAL_SECTION cairo_toy_font_face_hash_table_mutex;
CRITICAL_SECTION cairo_scaled_font_map_mutex;
CRITICAL_SECTION cairo_ft_unscaled_font_map_mutex;
CRITICAL_SECTION _cairo_scaled_font_map_mutex;
#ifdef CAIRO_HAS_FT_FONT
CRITICAL_SECTION _cairo_ft_unscaled_font_map_mutex;
#endif
CRITICAL_SECTION _cairo_font_face_mutex;
static int _cairo_win32_initialized = 0;
@ -1902,9 +1909,11 @@ _cairo_win32_initialize (void) {
return;
/* every 'mutex' from CAIRO_MUTEX_DECALRE needs to be initialized here */
InitializeCriticalSection (&cairo_toy_font_face_hash_table_mutex);
InitializeCriticalSection (&cairo_scaled_font_map_mutex);
InitializeCriticalSection (&cairo_ft_unscaled_font_map_mutex);
InitializeCriticalSection (&_cairo_scaled_font_map_mutex);
#ifdef CAIRO_HAS_FT_FONT
InitializeCriticalSection (&_cairo_ft_unscaled_font_map_mutex);
#endif
InitializeCriticalSection (&_cairo_font_face_mutex);
_cairo_win32_initialized = 1;
}
@ -1921,9 +1930,11 @@ DllMain (HINSTANCE hinstDLL,
_cairo_win32_initialize();
break;
case DLL_PROCESS_DETACH:
DeleteCriticalSection (&cairo_toy_font_face_hash_table_mutex);
DeleteCriticalSection (&cairo_scaled_font_map_mutex);
DeleteCriticalSection (&cairo_ft_unscaled_font_map_mutex);
DeleteCriticalSection (&_cairo_scaled_font_map_mutex);
#ifdef CAIRO_HAS_FT_FONT
DeleteCriticalSection (&_cairo_ft_unscaled_font_map_mutex);
#endif
DeleteCriticalSection (&_cairo_font_face_mutex);
break;
}
return TRUE;

Просмотреть файл

@ -1289,10 +1289,9 @@ _create_a8_picture (cairo_xcb_surface_t *surface,
= _CAIRO_FORMAT_TO_XRENDER_FORMAT (surface->dpy, CAIRO_FORMAT_A8);
xcb_rectangle_t rect = { 0, 0, width, height };
xcb_create_pixmap (surface->dpy, pixmap, surface->drawable,
width <= 0 ? 1 : width,
height <= 0 ? 1 : height,
8);
xcb_create_pixmap (surface->dpy, 8, pixmap, surface->drawable,
width <= 0 ? 1 : width,
height <= 0 ? 1 : height);
xcb_render_create_picture (surface->dpy, picture, pixmap, format->id, mask, values);
xcb_render_fill_rectangles (surface->dpy, XCB_RENDER_PICT_OP_SRC, picture, *color, 1, &rect);
xcb_free_pixmap (surface->dpy, pixmap);

Просмотреть файл

@ -37,6 +37,14 @@
#include "cairo-xlib.h"
typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t;
typedef struct _cairo_xlib_hook cairo_xlib_hook_t;
struct _cairo_xlib_hook {
cairo_xlib_hook_t *next;
void (*func) (Display *display, void *data);
void *data;
void *key;
};
struct _cairo_xlib_screen_info {
cairo_xlib_screen_info_t *next;
@ -46,18 +54,24 @@ struct _cairo_xlib_screen_info {
cairo_bool_t has_render;
cairo_font_options_t font_options;
cairo_xlib_hook_t *close_display_hooks;
};
cairo_private cairo_xlib_screen_info_t *
_cairo_xlib_screen_info_get (Display *display, Screen *screen);
cairo_private cairo_bool_t
_cairo_xlib_add_close_display_hook (Display *display, void (*func) (Display *, void *), void *data, void *key);
cairo_private void
_cairo_xlib_remove_close_display_hook (Display *display, void *key);
#if CAIRO_HAS_XLIB_XRENDER_SURFACE
#include "cairo-xlib-xrender.h"
#if 0
#ifdef MOZILLA_CAIRO_NOT_DEFINED
slim_hidden_proto (cairo_xlib_surface_create_with_xrender_format);
#endif
#endif
#endif /* CAIRO_XLIB_PRIVATE_H */

Просмотреть файл

@ -247,31 +247,36 @@ CAIRO_MUTEX_DECLARE(_xlib_screen_mutex);
static cairo_xlib_screen_info_t *_cairo_xlib_screen_list = NULL;
/* XXX: From this function we should also run through and cleanup
* anything else that still has a pointer to this Display*. For
* example, we should clean up any Xlib-specific glyph caches. */
static int
_cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
{
cairo_xlib_screen_info_t *info, *prev;
cairo_xlib_screen_info_t *info, **prev, *next;
/*
* Unhook from the global list
*/
CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
prev = NULL;
for (info = _cairo_xlib_screen_list; info; info = info->next) {
prev = &_cairo_xlib_screen_list;
for (info = _cairo_xlib_screen_list; info; info = next) {
next = info->next;
if (info->display == dpy) {
if (prev)
prev->next = info->next;
else
_cairo_xlib_screen_list = info->next;
*prev = next;
/* call all registered shutdown routines */
while (info->close_display_hooks) {
cairo_xlib_hook_t *hook = info->close_display_hooks;
info->close_display_hooks = hook->next;
hook->func (dpy, hook->data);
free (hook);
}
free (info);
break;
} else {
prev = &info->next;
}
prev = info;
}
*prev = NULL;
CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
/* Return value in accordance with requirements of
@ -291,6 +296,11 @@ _cairo_xlib_screen_info_reset (void)
for (info = _cairo_xlib_screen_list; info; info = next) {
next = info->next;
while (info->close_display_hooks) {
cairo_xlib_hook_t *hook = info->close_display_hooks;
info->close_display_hooks = hook->next;
free (hook);
}
free (info);
}
@ -300,8 +310,8 @@ _cairo_xlib_screen_info_reset (void)
}
cairo_xlib_screen_info_t *
_cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
static cairo_xlib_screen_info_t *
_cairo_xlib_screen_info_get_unlocked (Display *dpy, Screen *screen)
{
cairo_xlib_screen_info_t *info;
cairo_xlib_screen_info_t **prev;
@ -309,26 +319,15 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
XExtCodes *codes;
cairo_bool_t seen_display = FALSE;
/* There is an apparent deadlock between this mutex and the
* mutex for the display, but it's actually safe. For the
* app to call XCloseDisplay() while any other thread is
* inside this function would be an error in the logic
* app, and the CloseDisplay hook is the only other place we
* acquire this mutex.
*/
CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
for (prev = &_cairo_xlib_screen_list; (info = *prev); prev = &(*prev)->next)
{
if (info->display == dpy) {
seen_display = TRUE;
if (info->screen == screen)
{
if (info->screen == screen || screen == NULL) {
/*
* MRU the list
*/
if (prev != &_cairo_xlib_screen_list)
{
if (prev != &_cairo_xlib_screen_list) {
*prev = info->next;
info->next = _cairo_xlib_screen_list;
_cairo_xlib_screen_list = info;
@ -339,18 +338,17 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
}
if (info)
goto out;
return info;
info = malloc (sizeof (cairo_xlib_screen_info_t));
if (!info)
goto out;
return NULL;
if (!seen_display) {
codes = XAddExtension (dpy);
if (!codes) {
free (info);
info = NULL;
goto out;
return NULL;
}
XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
@ -361,24 +359,110 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
info->has_render = (XRenderQueryExtension (dpy, &event_base, &error_base) &&
(XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0));
info->close_display_hooks = NULL;
_cairo_xlib_init_screen_font_options (info);
info->next = _cairo_xlib_screen_list;
_cairo_xlib_screen_list = info;
out:
return info;
}
cairo_xlib_screen_info_t *
_cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
{
cairo_xlib_screen_info_t *info;
/* There is an apparent deadlock between this mutex and the
* mutex for the display, but it's actually safe. For the
* app to call XCloseDisplay() while any other thread is
* inside this function would be an error in the logic
* app, and the CloseDisplay hook is the only other place we
* acquire this mutex.
*/
CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
info = _cairo_xlib_screen_info_get_unlocked (dpy, screen);
CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
return info;
}
cairo_bool_t
_cairo_xlib_add_close_display_hook (Display *dpy, void (*func) (Display *, void *), void *data, void *key)
{
cairo_xlib_screen_info_t *info;
cairo_xlib_hook_t *hook;
cairo_xlib_hook_t **prev;
cairo_bool_t success = FALSE;
CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
info = _cairo_xlib_screen_info_get_unlocked (dpy, NULL);
if (!info)
goto unlock;
for (prev = &info->close_display_hooks; (hook = *prev); prev = &hook->next)
{
if (hook->key == key) {
/*
* MRU the list
*/
if (prev != &info->close_display_hooks) {
*prev = hook->next;
hook->next = info->close_display_hooks;
info->close_display_hooks = hook;
}
break;
}
}
if (!hook) {
hook = malloc (sizeof (cairo_xlib_hook_t));
if (!hook)
goto unlock;
hook->func = func;
hook->data = data;
hook->key = key;
hook->next = info->close_display_hooks;
info->close_display_hooks = hook;
}
success = TRUE;
unlock:
CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
return success;
}
void
_cairo_xlib_remove_close_display_hook (Display *dpy, void *key)
{
cairo_xlib_screen_info_t *info;
cairo_xlib_hook_t *hook;
cairo_xlib_hook_t **prev;
CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
info = _cairo_xlib_screen_info_get_unlocked (dpy, NULL);
if (!info)
goto unlock;
for (prev = &info->close_display_hooks; (hook = *prev); prev = &hook->next)
{
if (hook->key == key) {
*prev = hook->next;
free (hook);
break;
}
}
unlock:
CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
}
void
_cairo_xlib_screen_reset_static_data (void)
{
_cairo_xlib_screen_info_reset ();
#if HAVE_XRMFINALIZE
XrmFinalize ();
#endif
}

Просмотреть файл

@ -610,24 +610,27 @@ _get_image_surface (cairo_xlib_surface_t *surface,
_swap_ximage_to_native (ximage);
/*
* Compute the pixel format masks from either a visual or a
* XRenderFormat, failing we assume the drawable is an
* alpha-only pixmap as it could only have been created
* that way through the cairo_xlib_surface_create_for_bitmap
* function.
* Compute the pixel format masks from either a XrenderFormat or
* else from a visual; failing that we assume the drawable is an
* alpha-only pixmap as it could only have been created that way
* through the cairo_xlib_surface_create_for_bitmap function.
*/
if (surface->visual) {
if (surface->xrender_format) {
masks.bpp = ximage->bits_per_pixel;
masks.red_mask = (unsigned long) surface->xrender_format->direct.redMask
<< surface->xrender_format->direct.red;
masks.green_mask = (unsigned long) surface->xrender_format->direct.greenMask
<< surface->xrender_format->direct.green;
masks.blue_mask = (unsigned long) surface->xrender_format->direct.blueMask
<< surface->xrender_format->direct.blue;
masks.alpha_mask = (unsigned long) surface->xrender_format->direct.alphaMask
<< surface->xrender_format->direct.alpha;
} else if (surface->visual) {
masks.bpp = ximage->bits_per_pixel;
masks.alpha_mask = 0;
masks.red_mask = surface->visual->red_mask;
masks.green_mask = surface->visual->green_mask;
masks.blue_mask = surface->visual->blue_mask;
} else if (surface->xrender_format) {
masks.bpp = ximage->bits_per_pixel;
masks.red_mask = (unsigned long)surface->xrender_format->direct.redMask << surface->xrender_format->direct.red;
masks.green_mask = (unsigned long)surface->xrender_format->direct.greenMask << surface->xrender_format->direct.green;
masks.blue_mask = (unsigned long)surface->xrender_format->direct.blueMask << surface->xrender_format->direct.blue;
masks.alpha_mask = (unsigned long)surface->xrender_format->direct.alphaMask << surface->xrender_format->direct.alpha;
} else {
masks.bpp = ximage->bits_per_pixel;
masks.red_mask = 0;
@ -2019,7 +2022,7 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy,
return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
NULL, format, width, height, 0);
}
#if 0
#ifdef MOZILLA_CAIRO_NOT_DEFINED
slim_hidden_def (cairo_xlib_surface_create_with_xrender_format);
#endif
@ -2270,6 +2273,24 @@ typedef struct _cairo_xlib_surface_font_private {
XRenderPictFormat *xrender_format;
} cairo_xlib_surface_font_private_t;
static void
_cairo_xlib_surface_remove_scaled_font (Display *dpy,
void *data)
{
cairo_scaled_font_t *scaled_font = data;
cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
_cairo_scaled_font_reset_cache (scaled_font);
/* separate function to avoid deadlock if we tried to remove the
* close display hook ala _cairo_xlib_surface_scaled_font_fini() */
if (font_private) {
XRenderFreeGlyphSet (font_private->dpy, font_private->glyphset);
free (font_private);
scaled_font->surface_private = NULL;
}
}
static cairo_status_t
_cairo_xlib_surface_font_init (Display *dpy,
cairo_scaled_font_t *scaled_font,
@ -2277,6 +2298,11 @@ _cairo_xlib_surface_font_init (Display *dpy,
{
cairo_xlib_surface_font_private_t *font_private;
if (!_cairo_xlib_add_close_display_hook (dpy,
_cairo_xlib_surface_remove_scaled_font,
scaled_font, scaled_font))
return CAIRO_STATUS_NO_MEMORY;
font_private = malloc (sizeof (cairo_xlib_surface_font_private_t));
if (!font_private)
return CAIRO_STATUS_NO_MEMORY;
@ -2287,6 +2313,7 @@ _cairo_xlib_surface_font_init (Display *dpy,
font_private->glyphset = XRenderCreateGlyphSet (dpy, font_private->xrender_format);
scaled_font->surface_private = font_private;
scaled_font->surface_backend = &cairo_xlib_surface_backend;
return CAIRO_STATUS_SUCCESS;
}
@ -2296,6 +2323,7 @@ _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
if (font_private) {
_cairo_xlib_remove_close_display_hook (font_private->dpy, scaled_font);
XRenderFreeGlyphSet (font_private->dpy, font_private->glyphset);
free (font_private);
}

Просмотреть файл

@ -47,15 +47,18 @@
static const cairo_t cairo_nil = {
CAIRO_REF_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
{ /* path */
NULL, NULL, /* op_buf_head, op_buf_tail */
NULL, NULL, /* arg_buf_head, arg_buf_tail */
{ 0, 0, 0, NULL }, /* user_data */
NULL, /* gstate */
{{ /* gstate_tail */
0
}},
{{ /* path */
{ 0, 0 }, /* last_move_point */
{ 0, 0 }, /* current point */
FALSE, /* has_current_point */
FALSE /* has_curve_to */
},
NULL /* gstate */
FALSE, /* has_curve_to */
NULL, {{0}} /* buf_tail, buf_head */
}}
};
#include <assert.h>
@ -195,18 +198,17 @@ cairo_create (cairo_surface_t *target)
cr->status = CAIRO_STATUS_SUCCESS;
_cairo_path_fixed_init (&cr->path);
_cairo_user_data_array_init (&cr->user_data);
cr->gstate = cr->gstate_tail;
_cairo_gstate_init (cr->gstate, target);
_cairo_path_fixed_init (cr->path);
if (target == NULL) {
cr->gstate = NULL;
_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
return cr;
}
cr->gstate = _cairo_gstate_create (target);
if (cr->gstate == NULL)
_cairo_set_error (cr, CAIRO_STATUS_NO_MEMORY);
return cr;
}
slim_hidden_def (cairo_create);
@ -219,15 +221,15 @@ slim_hidden_def (cairo_create);
* @cr from being destroyed until a matching call to cairo_destroy()
* is made.
*
* The number of references to a #cairo_t can be get using
* cairo_get_reference_count().
*
* Return value: the referenced #cairo_t.
**/
cairo_t *
cairo_reference (cairo_t *cr)
{
if (cr == NULL)
return NULL;
if (cr->ref_count == CAIRO_REF_COUNT_INVALID)
if (cr == NULL || cr->ref_count == CAIRO_REF_COUNT_INVALID)
return cr;
assert (cr->ref_count > 0);
@ -248,10 +250,7 @@ cairo_reference (cairo_t *cr)
void
cairo_destroy (cairo_t *cr)
{
if (cr == NULL)
return;
if (cr->ref_count == CAIRO_REF_COUNT_INVALID)
if (cr == NULL || cr->ref_count == CAIRO_REF_COUNT_INVALID)
return;
assert (cr->ref_count > 0);
@ -260,19 +259,96 @@ cairo_destroy (cairo_t *cr)
if (cr->ref_count)
return;
while (cr->gstate) {
while (cr->gstate != cr->gstate_tail) {
cairo_gstate_t *tmp = cr->gstate;
cr->gstate = tmp->next;
_cairo_gstate_destroy (tmp);
}
_cairo_path_fixed_fini (&cr->path);
_cairo_gstate_fini (cr->gstate);
_cairo_path_fixed_fini (cr->path);
_cairo_user_data_array_fini (&cr->user_data);
free (cr);
}
slim_hidden_def (cairo_destroy);
/**
* cairo_get_user_data:
* @cr: a #cairo_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Return user data previously attached to @cr using the specified
* key. If no user data has been attached with the given key this
* function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
*
* Since: 1.4
**/
void *
cairo_get_user_data (cairo_t *cr,
const cairo_user_data_key_t *key)
{
return _cairo_user_data_array_get_data (&cr->user_data,
key);
}
/**
* cairo_set_user_data:
* @cr: a #cairo_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach to the #cairo_t
* @destroy: a #cairo_destroy_func_t which will be called when the
* #cairo_t is destroyed or when new user data is attached using the
* same key.
*
* Attach user data to @cr. To remove user data from a surface,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
*
* Since: 1.4
**/
cairo_status_t
cairo_set_user_data (cairo_t *cr,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
if (cr->ref_count == CAIRO_REF_COUNT_INVALID)
return CAIRO_STATUS_NO_MEMORY;
return _cairo_user_data_array_set_data (&cr->user_data,
key, user_data, destroy);
}
/**
* cairo_get_reference_count:
* @cr: a #cairo_t
*
* Returns the current reference count of @cr.
*
* Return value: the current reference count of @cr. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.4
**/
unsigned int
cairo_get_reference_count (cairo_t *cr)
{
if (cr == NULL || cr->ref_count == CAIRO_REF_COUNT_INVALID)
return 0;
return cr->ref_count;
}
/**
* cairo_save:
* @cr: a #cairo_t
@ -325,13 +401,15 @@ cairo_restore (cairo_t *cr)
if (cr->status)
return;
if (cr->gstate == cr->gstate_tail) {
_cairo_set_error (cr, CAIRO_STATUS_INVALID_RESTORE);
return;
}
top = cr->gstate;
cr->gstate = top->next;
_cairo_gstate_destroy (top);
if (cr->gstate == NULL)
_cairo_set_error (cr, CAIRO_STATUS_INVALID_RESTORE);
}
slim_hidden_def(cairo_restore);
@ -855,8 +933,8 @@ cairo_set_line_width (cairo_t *cr, double width)
/**
* cairo_set_line_cap:
* @cr: a cairo context, as a #cairo_t
* @line_cap: a line cap style, as a #cairo_line_cap_t
* @cr: a cairo context
* @line_cap: a line cap style
*
* Sets the current line cap style within the cairo context. See
* #cairo_line_cap_t for details about how the available line cap
@ -880,8 +958,8 @@ cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap)
/**
* cairo_set_line_join:
* @cr: a cairo context, as a #cairo_t
* @line_join: a line joint style, as a #cairo_line_join_t
* @cr: a cairo context
* @line_join: a line joint style
*
* Sets the current line join style within the cairo context. See
* #cairo_line_join_t for details about how the available line join
@ -954,11 +1032,13 @@ cairo_set_dash (cairo_t *cr,
* cairo_get_dash_count:
* @cr: a #cairo_t
*
* Returns the length of the dash array in @cr (0 if dashing is not
* currently in effect).
* This function returns the length of the dash array in @cr (0 if dashing
* is not currently in effect).
*
* See also cairo_set_dash() and cairo_get_dash().
*
* Return value: the length of the dash array, or 0 if no dash array set.
*
* Since: 1.4
*/
int
@ -993,6 +1073,25 @@ cairo_get_dash (cairo_t *cr,
*offset = cr->gstate->stroke_style.dash_offset;
}
/**
* cairo_set_miter_limit:
* @cr: a cairo context
* @limit: miter limit to set
*
* Sets the current miter limit within the cairo context.
*
* If the current line join style is set to %CAIRO_LINE_JOIN_MITER
* (see cairo_set_line_join()), the miter limit is used to determine
* whether the lines should be joined with a bevel instead of a miter.
* Cairo divides the length of the miter by the line width.
* If the result is greater than the miter limit, the style is
* converted to a bevel.
*
* As with the other stroke parameters, the current line miter limit is
* examined by cairo_stroke(), cairo_stroke_extents(), and
* cairo_stroke_to_path(), but does not have any effect during path
* construction.
**/
void
cairo_set_miter_limit (cairo_t *cr, double limit)
{
@ -1048,6 +1147,7 @@ cairo_scale (cairo_t *cr, double sx, double sy)
if (cr->status)
_cairo_set_error (cr, cr->status);
}
slim_hidden_def (cairo_scale);
/**
* cairo_rotate:
@ -1232,7 +1332,7 @@ cairo_new_path (cairo_t *cr)
if (cr->status)
return;
_cairo_path_fixed_fini (&cr->path);
_cairo_path_fixed_fini (cr->path);
}
slim_hidden_def(cairo_new_path);
@ -1257,7 +1357,7 @@ cairo_move_to (cairo_t *cr, double x, double y)
x_fixed = _cairo_fixed_from_double (x);
y_fixed = _cairo_fixed_from_double (y);
cr->status = _cairo_path_fixed_move_to (&cr->path, x_fixed, y_fixed);
cr->status = _cairo_path_fixed_move_to (cr->path, x_fixed, y_fixed);
if (cr->status)
_cairo_set_error (cr, cr->status);
}
@ -1287,7 +1387,7 @@ cairo_new_sub_path (cairo_t *cr)
if (cr->status)
return;
_cairo_path_fixed_new_sub_path (&cr->path);
_cairo_path_fixed_new_sub_path (cr->path);
}
/**
@ -1315,7 +1415,7 @@ cairo_line_to (cairo_t *cr, double x, double y)
x_fixed = _cairo_fixed_from_double (x);
y_fixed = _cairo_fixed_from_double (y);
cr->status = _cairo_path_fixed_line_to (&cr->path, x_fixed, y_fixed);
cr->status = _cairo_path_fixed_line_to (cr->path, x_fixed, y_fixed);
if (cr->status)
_cairo_set_error (cr, cr->status);
}
@ -1366,7 +1466,7 @@ cairo_curve_to (cairo_t *cr,
x3_fixed = _cairo_fixed_from_double (x3);
y3_fixed = _cairo_fixed_from_double (y3);
cr->status = _cairo_path_fixed_curve_to (&cr->path,
cr->status = _cairo_path_fixed_curve_to (cr->path,
x1_fixed, y1_fixed,
x2_fixed, y2_fixed,
x3_fixed, y3_fixed);
@ -1532,7 +1632,7 @@ cairo_rel_move_to (cairo_t *cr, double dx, double dy)
dx_fixed = _cairo_fixed_from_double (dx);
dy_fixed = _cairo_fixed_from_double (dy);
cr->status = _cairo_path_fixed_rel_move_to (&cr->path, dx_fixed, dy_fixed);
cr->status = _cairo_path_fixed_rel_move_to (cr->path, dx_fixed, dy_fixed);
if (cr->status)
_cairo_set_error (cr, cr->status);
}
@ -1567,7 +1667,7 @@ cairo_rel_line_to (cairo_t *cr, double dx, double dy)
dx_fixed = _cairo_fixed_from_double (dx);
dy_fixed = _cairo_fixed_from_double (dy);
cr->status = _cairo_path_fixed_rel_line_to (&cr->path, dx_fixed, dy_fixed);
cr->status = _cairo_path_fixed_rel_line_to (cr->path, dx_fixed, dy_fixed);
if (cr->status)
_cairo_set_error (cr, cr->status);
}
@ -1625,7 +1725,7 @@ cairo_rel_curve_to (cairo_t *cr,
dx3_fixed = _cairo_fixed_from_double (dx3);
dy3_fixed = _cairo_fixed_from_double (dy3);
cr->status = _cairo_path_fixed_rel_curve_to (&cr->path,
cr->status = _cairo_path_fixed_rel_curve_to (cr->path,
dx1_fixed, dy1_fixed,
dx2_fixed, dy2_fixed,
dx3_fixed, dy3_fixed);
@ -1713,7 +1813,7 @@ cairo_close_path (cairo_t *cr)
if (cr->status)
return;
cr->status = _cairo_path_fixed_close_path (&cr->path);
cr->status = _cairo_path_fixed_close_path (cr->path);
if (cr->status)
_cairo_set_error (cr, cr->status);
}
@ -1903,7 +2003,7 @@ cairo_stroke_preserve (cairo_t *cr)
if (cr->status)
return;
cr->status = _cairo_gstate_stroke (cr->gstate, &cr->path);
cr->status = _cairo_gstate_stroke (cr->gstate, cr->path);
if (cr->status)
_cairo_set_error (cr, cr->status);
}
@ -1944,7 +2044,7 @@ cairo_fill_preserve (cairo_t *cr)
if (cr->status)
return;
cr->status = _cairo_gstate_fill (cr->gstate, &cr->path);
cr->status = _cairo_gstate_fill (cr->gstate, cr->path);
if (cr->status)
_cairo_set_error (cr, cr->status);
}
@ -2014,7 +2114,7 @@ cairo_in_stroke (cairo_t *cr, double x, double y)
return 0;
cr->status = _cairo_gstate_in_stroke (cr->gstate,
&cr->path,
cr->path,
x, y, &inside);
if (cr->status)
return 0;
@ -2046,7 +2146,7 @@ cairo_in_fill (cairo_t *cr, double x, double y)
return 0;
cr->status = _cairo_gstate_in_fill (cr->gstate,
&cr->path,
cr->path,
x, y, &inside);
if (cr->status) {
_cairo_set_error (cr, cr->status);
@ -2082,7 +2182,7 @@ cairo_stroke_extents (cairo_t *cr,
return;
cr->status = _cairo_gstate_stroke_extents (cr->gstate,
&cr->path,
cr->path,
x1, y1, x2, y2);
if (cr->status)
_cairo_set_error (cr, cr->status);
@ -2112,7 +2212,7 @@ cairo_fill_extents (cairo_t *cr,
return;
cr->status = _cairo_gstate_fill_extents (cr->gstate,
&cr->path,
cr->path,
x1, y1, x2, y2);
if (cr->status)
_cairo_set_error (cr, cr->status);
@ -2176,7 +2276,7 @@ cairo_clip_preserve (cairo_t *cr)
if (cr->status)
return;
cr->status = _cairo_gstate_clip (cr->gstate, &cr->path);
cr->status = _cairo_gstate_clip (cr->gstate, cr->path);
if (cr->status)
_cairo_set_error (cr, cr->status);
}
@ -2251,8 +2351,9 @@ _cairo_rectangle_list_create_in_error (cairo_status_t status)
/**
* cairo_copy_clip_rectangle_list:
* @cr: a cairo context
*
* Returns the current clip region as a list of rectangles in user coordinates.
* Gets the current clip region as a list of rectangles in user coordinates.
* Never returns %NULL.
*
* The status in the list may be CAIRO_STATUS_CLIP_NOT_REPRESENTABLE to
@ -2263,6 +2364,8 @@ _cairo_rectangle_list_create_in_error (cairo_status_t status)
* The caller must always call cairo_rectangle_list_destroy on the result of
* this function.
*
* Returns: the current clip region as a list of rectangles in user coordinates.
*
* Since: 1.4
**/
cairo_rectangle_list_t *
@ -2303,34 +2406,6 @@ cairo_select_font_face (cairo_t *cr,
_cairo_set_error (cr, cr->status);
}
/**
* cairo_get_font_face:
* @cr: a #cairo_t
*
* Gets the current font face for a #cairo_t.
*
* Return value: the current font object. Can return %NULL
* on out-of-memory or if the context is already in
* an error state. This object is owned by cairo. To keep
* a reference to it, you must call cairo_font_face_reference().
**/
cairo_font_face_t *
cairo_get_font_face (cairo_t *cr)
{
cairo_font_face_t *font_face;
if (cr->status)
return (cairo_font_face_t*) &_cairo_font_face_nil;
cr->status = _cairo_gstate_get_font_face (cr->gstate, &font_face);
if (cr->status) {
_cairo_set_error (cr, cr->status);
return (cairo_font_face_t*) &_cairo_font_face_nil;
}
return font_face;
}
/**
* cairo_font_extents:
* @cr: a #cairo_t
@ -2372,6 +2447,41 @@ cairo_set_font_face (cairo_t *cr,
_cairo_set_error (cr, cr->status);
}
/**
* cairo_get_font_face:
* @cr: a #cairo_t
*
* Gets the current font face for a #cairo_t.
*
* Return value: the current font face. This object is owned by
* cairo. To keep a reference to it, you must call
* cairo_font_face_reference.
*
* This function never returns %NULL. If memory cannot be allocated, a
* special "nil" #cairo_font_face_t object will be returned on which
* cairo_font_face_status() returns %CAIRO_STATUS_NO_MEMORY. Using
* this nil object will cause its error state to propagate to other
* objects it is passed to, (for example, calling
* cairo_set_font_face() with a nil font will trigger an error that
* will shutdown the cairo_t object).
**/
cairo_font_face_t *
cairo_get_font_face (cairo_t *cr)
{
cairo_font_face_t *font_face;
if (cr->status)
return (cairo_font_face_t*) &_cairo_font_face_nil;
cr->status = _cairo_gstate_get_font_face (cr->gstate, &font_face);
if (cr->status) {
_cairo_set_error (cr, cr->status);
return (cairo_font_face_t*) &_cairo_font_face_nil;
}
return font_face;
}
/**
* cairo_set_font_size:
* @cr: a #cairo_t
@ -2516,6 +2626,43 @@ BAIL:
_cairo_set_error (cr, cr->status);
}
/**
* cairo_get_scaled_font:
* @cr: a #cairo_t
*
* Gets the current scaled font for a #cairo_t.
*
* Return value: the current scaled font. This object is owned by
* cairo. To keep a reference to it, you must call
* cairo_scaled_font_reference().
*
* This function never returns %NULL. If memory cannot be allocated, a
* special "nil" #cairo_scaled_font_t object will be returned on which
* cairo_scaled_font_status() returns %CAIRO_STATUS_NO_MEMORY. Using
* this nil object will cause its error state to propagate to other
* objects it is passed to, (for example, calling
* cairo_set_scaled_font() with a nil font will trigger an error that
* will shutdown the cairo_t object).
*
* Since: 1.4
**/
cairo_scaled_font_t *
cairo_get_scaled_font (cairo_t *cr)
{
cairo_scaled_font_t *scaled_font;
if (cr->status)
return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
cr->status = _cairo_gstate_get_scaled_font (cr->gstate, &scaled_font);
if (cr->status) {
_cairo_set_error (cr, cr->status);
return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
}
return scaled_font;
}
/**
* cairo_text_extents:
* @cr: a #cairo_t
@ -2635,9 +2782,9 @@ cairo_glyph_extents (cairo_t *cr,
*
* NOTE: The cairo_show_text() function call is part of what the cairo
* designers call the "toy" text API. It is convenient for short demos
* and simple programs, but it is not expected to be adequate for the
* most serious of text-using applications. See cairo_show_glyphs()
* for the "real" text display API in cairo.
* and simple programs, but it is not expected to be adequate for
* serious text-using applications. See cairo_show_glyphs() for the
* "real" text display API in cairo.
**/
void
cairo_show_text (cairo_t *cr, const char *utf8)
@ -2687,6 +2834,16 @@ cairo_show_text (cairo_t *cr, const char *utf8)
_cairo_set_error (cr, cr->status);
}
/**
* cairo_show_glyphs:
* @cr: a cairo context
* @glyphs: array of glyphs to show
* @num_glyphs: number of glyphs to show
*
* A drawing operator that generates the shape from an array of glyphs,
* rendered according to the current font_face, font_size
* (font_matrix), and font_options.
**/
void
cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
{
@ -2701,10 +2858,35 @@ cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
_cairo_set_error (cr, cr->status);
}
/**
* cairo_text_path:
* @cr: a cairo context
* @utf8: a string of text encoded in UTF-8
*
* Adds closed paths for text to the current path. The generated
* path if filled, achieves an effect similar to that of
* cairo_show_text().
*
* Text conversion and positioning is done similar to cairo_show_text().
*
* Like cairo_show_text(), After this call the current point is
* moved to the origin of where the next glyph would be placed in
* this same progression. That is, the current point will be at
* the origin of the final glyph offset by its advance values.
* This allows for chaining multiple calls to to cairo_text_path()
* without having to set current point in between.
*
* NOTE: The cairo_text_path() function call is part of what the cairo
* designers call the "toy" text API. It is convenient for short demos
* and simple programs, but it is not expected to be adequate for
* serious text-using applications. See cairo_glyph_path() for the
* "real" text path API in cairo.
**/
void
cairo_text_path (cairo_t *cr, const char *utf8)
{
cairo_glyph_t *glyphs = NULL;
cairo_text_extents_t extents;
cairo_glyph_t *glyphs = NULL, *last_glyph;
int num_glyphs;
double x, y;
@ -2717,16 +2899,32 @@ cairo_text_path (cairo_t *cr, const char *utf8)
x, y,
&glyphs, &num_glyphs);
if (cr->status) {
if (glyphs)
free (glyphs);
_cairo_set_error (cr, cr->status);
if (cr->status)
goto BAIL;
if (num_glyphs == 0)
return;
}
cr->status = _cairo_gstate_glyph_path (cr->gstate,
glyphs, num_glyphs,
&cr->path);
cr->path);
if (cr->status)
goto BAIL;
last_glyph = &glyphs[num_glyphs - 1];
cr->status = _cairo_gstate_glyph_extents (cr->gstate,
last_glyph, 1,
&extents);
if (cr->status)
goto BAIL;
x = last_glyph->x + extents.x_advance;
y = last_glyph->y + extents.y_advance;
cairo_move_to (cr, x, y);
BAIL:
if (glyphs)
free (glyphs);
@ -2734,6 +2932,16 @@ cairo_text_path (cairo_t *cr, const char *utf8)
_cairo_set_error (cr, cr->status);
}
/**
* cairo_glyph_path:
* @cr: a cairo context
* @glyphs: array of glyphs to show
* @num_glyphs: number of glyphs to show
*
* Adds closed paths for the glyphs to the current path. The generated
* path if filled, achieves an effect similar to that of
* cairo_show_glyphs().
**/
void
cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
{
@ -2742,7 +2950,7 @@ cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
cr->status = _cairo_gstate_glyph_path (cr->gstate,
glyphs, num_glyphs,
&cr->path);
cr->path);
if (cr->status)
_cairo_set_error (cr, cr->status);
}
@ -2818,7 +3026,7 @@ cairo_get_current_point (cairo_t *cr, double *x_ret, double *y_ret)
cairo_fixed_t x_fixed, y_fixed;
double x, y;
status = _cairo_path_fixed_get_current_point (&cr->path, &x_fixed, &y_fixed);
status = _cairo_path_fixed_get_current_point (cr->path, &x_fixed, &y_fixed);
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
x = 0.0;
y = 0.0;
@ -2853,10 +3061,12 @@ cairo_get_fill_rule (cairo_t *cr)
* cairo_get_line_width:
* @cr: a cairo context
*
* Return value: the current line width value exactly as set by
* This function returns the current line width value exactly as set by
* cairo_set_line_width(). Note that the value is unchanged even if
* the CTM has changed between the calls to cairo_set_line_width() and
* cairo_get_line_width().
*
* Return value: the current line width.
**/
double
cairo_get_line_width (cairo_t *cr)
@ -3008,7 +3218,7 @@ cairo_copy_path (cairo_t *cr)
if (cr->status)
return _cairo_path_create_in_error (cr->status);
return _cairo_path_create (&cr->path, cr->gstate);
return _cairo_path_create (cr->path, cr->gstate);
}
/**
@ -3050,7 +3260,7 @@ cairo_copy_path_flat (cairo_t *cr)
if (cr->status)
return _cairo_path_create_in_error (cr->status);
return _cairo_path_create_flat (&cr->path, cr->gstate);
return _cairo_path_create_flat (cr->path, cr->gstate);
}
/**

Просмотреть файл

@ -72,7 +72,7 @@ cairo_version_string (void);
* /<!-- -->* do something *<!-- -->/
* }
* </programlisting></informalexample>
*/
**/
typedef int cairo_bool_t;
/**
@ -80,6 +80,13 @@ typedef int cairo_bool_t;
*
* A #cairo_t contains the current state of the rendering device,
* including coordinates of yet to be drawn shapes.
*
* Cairo contexts, as #cairo_t objects are named, are central to
* cairo and all drawing with cairo is always done to a #cairo_t
* object.
*
* Memory management of #cairo_t is done with
* cairo_reference() and cairo_destroy().
**/
typedef struct _cairo cairo_t;
@ -88,13 +95,17 @@ typedef struct _cairo cairo_t;
*
* A #cairo_surface_t represents an image, either as the destination
* of a drawing operation or as source when drawing onto another
* surface. There are different subtypes of cairo_surface_t for
* surface. To draw to a #cairo_surface_t, create a cairo context
* with the surface as the target, using cairo_create().
*
* There are different subtypes of #cairo_surface_t for
* different drawing backends; for example, cairo_image_surface_create()
* creates a bitmap image in memory.
* The type of a surface can be queried with cairo_surface_get_type().
*
* Memory management of #cairo_surface_t is done with
* cairo_surface_reference() and cairo_surface_destroy().
*/
**/
typedef struct _cairo_surface cairo_surface_t;
/**
@ -120,6 +131,25 @@ typedef struct _cairo_matrix {
double x0; double y0;
} cairo_matrix_t;
/**
* cairo_pattern_t:
*
* A #cairo_pattern_t represents a source when drawing onto a
* surface. There are different subtypes of #cairo_pattern_t,
* for different types of sources; for example,
* cairo_pattern_create_rgb() creates a pattern for a solid
* opaque color.
*
* Other than various cairo_pattern_create_<emphasis>type</emphasis>
* functions, some of the pattern types can be implicitly created
* using vairous cairo_set_source_<emphasis>type</emphasis> functions;
* for example cairo_set_source_rgb().
*
* The type of a pattern can be queried with cairo_pattern_get_type().
*
* Memory management of #cairo_pattern_t is done with
* cairo_pattern_reference() and cairo_pattern_destroy().
**/
typedef struct _cairo_pattern cairo_pattern_t;
/**
@ -129,7 +159,7 @@ typedef struct _cairo_pattern cairo_pattern_t;
* #cairo_destroy_func_t the type of function which is called when a
* data element is destroyed. It is passed the pointer to the data
* element and should free any memory and resources allocated for it.
*/
**/
typedef void (*cairo_destroy_func_t) (void *data);
/**
@ -141,7 +171,7 @@ typedef void (*cairo_destroy_func_t) (void *data);
* and there is no need to initialize the object; only the unique
* address of a #cairo_data_key_t object is used. Typically, you
* would just use the address of a static #cairo_data_key_t object.
*/
**/
typedef struct _cairo_user_data_key {
int unused;
} cairo_user_data_key_t;
@ -219,7 +249,7 @@ typedef enum _cairo_status {
* Note: The large values here are designed to keep cairo_content_t
* values distinct from cairo_format_t values so that the
* implementation can detect the error if users confuse the two types.
*/
**/
typedef enum _cairo_content {
CAIRO_CONTENT_COLOR = 0x1000,
CAIRO_CONTENT_ALPHA = 0x2000,
@ -241,7 +271,7 @@ typedef enum _cairo_content {
* CAIRO_STATUS_WRITE_ERROR otherwise.
*
* Returns: the status code of the write operation
*/
**/
typedef cairo_status_t (*cairo_write_func_t) (void *closure,
const unsigned char *data,
unsigned int length);
@ -261,7 +291,7 @@ typedef cairo_status_t (*cairo_write_func_t) (void *closure,
* CAIRO_STATUS_READ_ERROR otherwise.
*
* Returns: the status code of the read operation
*/
**/
typedef cairo_status_t (*cairo_read_func_t) (void *closure,
unsigned char *data,
unsigned int length);
@ -276,6 +306,19 @@ cairo_reference (cairo_t *cr);
cairo_public void
cairo_destroy (cairo_t *cr);
cairo_public unsigned int
cairo_get_reference_count (cairo_t *cr);
cairo_public void *
cairo_get_user_data (cairo_t *cr,
const cairo_user_data_key_t *key);
cairo_public cairo_status_t
cairo_set_user_data (cairo_t *cr,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy);
cairo_public void
cairo_save (cairo_t *cr);
@ -402,7 +445,7 @@ cairo_set_line_width (cairo_t *cr, double width);
* @CAIRO_LINE_CAP_ROUND: use a round ending, the center of the circle is the end point
* @CAIRO_LINE_CAP_SQUARE: use squared ending, the center of the square is the end point
*
* enumeration for style of line-endings
* Specifies how to render the endpoint of a line when stroking.
**/
typedef enum _cairo_line_cap {
CAIRO_LINE_CAP_BUTT,
@ -413,6 +456,17 @@ typedef enum _cairo_line_cap {
cairo_public void
cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap);
/**
* cairo_line_join_t
* @CAIRO_LINE_JOIN_MITER: use a sharp (angled) corner, see
* cairo_set_miter_limit()
* @CAIRO_LINE_JOIN_ROUND: use a rounded join, the center of the circle is the
* joint point
* @CAIRO_LINE_JOIN_BEVEL: use a cut-off join, the join is cut off at half
* the line width from the joint point
*
* Specifies how to render the junction of two lines when stroking.
**/
typedef enum _cairo_line_join {
CAIRO_LINE_JOIN_MITER,
CAIRO_LINE_JOIN_ROUND,
@ -598,23 +652,30 @@ cairo_clip_extents (cairo_t *cr,
/**
* cairo_rectangle_t:
*
* @x: X coordinate of the left side of the rectangle
* @y: Y coordinate of the the top side of the rectangle
* @width: width of the rectangle
* @height: height of the rectangle
*
* A data structure for holding a rectangle.
*
* Since: 1.4
*/
**/
typedef struct _cairo_rectangle {
double x, y, width, height;
} cairo_rectangle_t;
/**
* cairo_rectangle_list_t:
* @status: Error status of the rectangle list
* @rectangles: Array containing the rectangles
* @num_rectangles: Number of rectangles in this list
*
* A data structure for holding a dynamically allocated
* array of rectangles.
*
* Since: 1.4
*/
**/
typedef struct _cairo_rectangle_list {
cairo_status_t status;
cairo_rectangle_t *rectangles;
@ -636,7 +697,14 @@ cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list);
* resolution. A cairo_scaled_font_t is most useful for low-level font
* usage where a library or application wants to cache a reference
* to a scaled font to speed up the computation of metrics.
*/
*
* There are various types of scaled fonts, depending on the
* <firstterm>font backend</firstterm> they use. The type of a
* scaled font can be queried using cairo_scaled_font_get_type().
*
* Memory management of #cairo_scaled_font_t is done with
* cairo_scaled_font_reference() and cairo_scaled_font_destroy().
**/
typedef struct _cairo_scaled_font cairo_scaled_font_t;
/**
@ -648,7 +716,14 @@ typedef struct _cairo_scaled_font cairo_scaled_font_t;
* directions) . A font face can be set on a #cairo_t by using
* cairo_set_font_face(); the size and font matrix are set with
* cairo_set_font_size() and cairo_set_font_matrix().
*/
*
* There are various types of font faces, depending on the
* <firstterm>font backend</firstterm> they use. The type of a
* font face can be queried using cairo_font_face_get_type().
*
* Memory management of #cairo_font_face_t is done with
* cairo_font_face_reference() and cairo_font_face_destroy().
**/
typedef struct _cairo_font_face cairo_font_face_t;
/**
@ -707,7 +782,7 @@ typedef struct {
* doubled. They will change slightly due to hinting (so you can't
* assume that metrics are independent of the transformation matrix),
* but otherwise will remain unchanged.
*/
**/
typedef struct {
double x_bearing;
double y_bearing;
@ -757,7 +832,7 @@ typedef struct {
* not be doubled. They will change slightly due to hinting (so you
* can't assume that metrics are independent of the transformation
* matrix), but otherwise will remain unchanged.
*/
**/
typedef struct {
double ascent;
double descent;
@ -766,12 +841,27 @@ typedef struct {
double max_y_advance;
} cairo_font_extents_t;
/**
* cairo_font_slant_t:
* @CAIRO_FONT_SLANT_NORMAL: Upright font style
* @CAIRO_FONT_SLANT_ITALIC: Italic font style
* @CAIRO_FONT_SLANT_OBLIQUE: Oblique font style
*
* Specifies variants of a font face based on their slant.
**/
typedef enum _cairo_font_slant {
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_SLANT_ITALIC,
CAIRO_FONT_SLANT_OBLIQUE
} cairo_font_slant_t;
/**
* cairo_font_weight_t:
* @CAIRO_FONT_WEIGHT_NORMAL: Normal font weight
* @CAIRO_FONT_WEIGHT_BOLD: Bold font weight
*
* Specifies variants of a font face based on their weight.
**/
typedef enum _cairo_font_weight {
CAIRO_FONT_WEIGHT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD
@ -823,7 +913,7 @@ typedef enum _cairo_subpixel_order {
* styles are supported by all font backends.
*
* New entries may be added in future versions.
*/
**/
typedef enum _cairo_hint_style {
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_STYLE_NONE,
@ -844,13 +934,33 @@ typedef enum _cairo_hint_style {
* device space. Doing this improves the consistency of
* letter and line spacing, however it also means that text
* will be laid out differently at different zoom factors.
*/
**/
typedef enum _cairo_hint_metrics {
CAIRO_HINT_METRICS_DEFAULT,
CAIRO_HINT_METRICS_OFF,
CAIRO_HINT_METRICS_ON
} cairo_hint_metrics_t;
/**
* cairo_font_options_t:
*
* An opaque structure holding all options that are used when
* rendering fonts.
*
* Individual features of a #cairo_font_options_t can be set or
* accessed using functions named
* cairo_font_options_set_<emphasis>feature_name</emphasis> and
* cairo_font_options_get_<emphasis>feature_name</emphasis>, like
* cairo_font_options_set_antialias() and
* cairo_font_options_get_antialias().
*
* New features may be added to a #cairo_font_options_t in the
* future. For this reason, cairo_font_options_copy(),
* cairo_font_options_equal(), cairo_font_options_merge(), and
* cairo_font_options_hash() should be used to copy, check
* for equality, merge, or compute a hash value of
* #cairo_font_options_t objects.
**/
typedef struct _cairo_font_options cairo_font_options_t;
cairo_public cairo_font_options_t *
@ -927,25 +1037,30 @@ cairo_public void
cairo_get_font_options (cairo_t *cr,
cairo_font_options_t *options);
cairo_public void
cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face);
cairo_public cairo_font_face_t *
cairo_get_font_face (cairo_t *cr);
cairo_public void
cairo_set_scaled_font (cairo_t *cr,
const cairo_scaled_font_t *scaled_font);
cairo_public cairo_scaled_font_t *
cairo_get_scaled_font (cairo_t *cr);
cairo_public void
cairo_show_text (cairo_t *cr, const char *utf8);
cairo_public void
cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs);
cairo_public cairo_font_face_t *
cairo_get_font_face (cairo_t *cr);
cairo_public void
cairo_text_path (cairo_t *cr, const char *utf8);
cairo_public void
cairo_font_extents (cairo_t *cr,
cairo_font_extents_t *extents);
cairo_public void
cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face);
cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs);
cairo_public void
cairo_text_extents (cairo_t *cr,
@ -959,10 +1074,8 @@ cairo_glyph_extents (cairo_t *cr,
cairo_text_extents_t *extents);
cairo_public void
cairo_text_path (cairo_t *cr, const char *utf8);
cairo_public void
cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs);
cairo_font_extents (cairo_t *cr,
cairo_font_extents_t *extents);
/* Generic identifier for a font style */
@ -972,6 +1085,9 @@ cairo_font_face_reference (cairo_font_face_t *font_face);
cairo_public void
cairo_font_face_destroy (cairo_font_face_t *font_face);
cairo_public unsigned int
cairo_font_face_get_reference_count (cairo_font_face_t *font_face);
cairo_public cairo_status_t
cairo_font_face_status (cairo_font_face_t *font_face);
@ -1010,7 +1126,7 @@ cairo_font_face_status (cairo_font_face_t *font_face);
* New entries may be added in future versions.
*
* Since: 1.2
*/
**/
typedef enum _cairo_font_type {
CAIRO_FONT_TYPE_TOY,
CAIRO_FONT_TYPE_FT,
@ -1045,12 +1161,25 @@ cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font);
cairo_public void
cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font);
cairo_public unsigned int
cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font);
cairo_public cairo_status_t
cairo_scaled_font_status (cairo_scaled_font_t *scaled_font);
cairo_public cairo_font_type_t
cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font);
cairo_public void *
cairo_scaled_font_get_user_data (cairo_scaled_font_t *scaled_font,
const cairo_user_data_key_t *key);
cairo_public cairo_status_t
cairo_scaled_font_set_user_data (cairo_scaled_font_t *scaled_font,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy);
cairo_public void
cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font,
cairo_font_extents_t *extents);
@ -1128,6 +1257,17 @@ cairo_get_target (cairo_t *cr);
cairo_public cairo_surface_t *
cairo_get_group_target (cairo_t *cr);
/**
* cairo_path_data_type_t:
* @CAIRO_PATH_MOVE_TO: A move-to operation
* @CAIRO_PATH_LINE_TO: A line-to operation
* @CAIRO_PATH_CURVE_TO: A curve-to operation
* @CAIRO_PATH_CLOSE_PATH: A close-path operation
*
* #cairo_path_data_t is used to describe the type of one portion
* of a path when represented as a #cairo_path_t.
* See #cairo_path_data_t for details.
**/
typedef enum _cairo_path_data_type {
CAIRO_PATH_MOVE_TO,
CAIRO_PATH_LINE_TO,
@ -1149,8 +1289,7 @@ typedef enum _cairo_path_data_type {
* the array, (one header followed by 0 or more points). The length
* value of the header is the number of array elements for the current
* portion including the header, (ie. length == 1 + # of points), and
* where the number of points for each element type must be as
* follows:
* where the number of points for each element type is as follows:
*
* <programlisting>
* %CAIRO_PATH_MOVE_TO: 1 point
@ -1193,6 +1332,14 @@ typedef enum _cairo_path_data_type {
* }
* cairo_path_destroy (path);
* </programlisting></informalexample>
*
* As of cairo 1.4, cairo does not mind if there are more elements in
* a portion of the path than needed. Such elements can be used by
* users of the cairo API to hold extra values in the path data
* structure. For this reason, it is recommended that applications
* always use <literal>data->header.length</literal> to
* iterate over the path data, instead of hardcoding the number of
* elements for each element type.
**/
typedef union _cairo_path_data_t cairo_path_data_t;
union _cairo_path_data_t {
@ -1268,12 +1415,12 @@ cairo_surface_finish (cairo_surface_t *surface);
cairo_public void
cairo_surface_destroy (cairo_surface_t *surface);
cairo_public cairo_status_t
cairo_surface_status (cairo_surface_t *surface);
cairo_public unsigned int
cairo_surface_get_reference_count (cairo_surface_t *surface);
cairo_public cairo_status_t
cairo_surface_status (cairo_surface_t *surface);
/**
* cairo_surface_type_t
* @CAIRO_SURFACE_TYPE_IMAGE: The surface is of type image
@ -1311,7 +1458,7 @@ cairo_surface_get_reference_count (cairo_surface_t *surface);
* New entries may be added in future versions.
*
* Since: 1.2
*/
**/
typedef enum _cairo_surface_type {
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_SURFACE_TYPE_PDF,
@ -1324,7 +1471,6 @@ typedef enum _cairo_surface_type {
CAIRO_SURFACE_TYPE_BEOS,
CAIRO_SURFACE_TYPE_DIRECTFB,
CAIRO_SURFACE_TYPE_SVG,
CAIRO_SURFACE_TYPE_NQUARTZ,
CAIRO_SURFACE_TYPE_OS2
} cairo_surface_type_t;
@ -1417,7 +1563,7 @@ cairo_surface_set_fallback_resolution (cairo_surface_t *surface,
* image data.
*
* New entries may be added in future versions.
*/
**/
typedef enum _cairo_format {
CAIRO_FORMAT_ARGB32,
CAIRO_FORMAT_RGB24,
@ -1493,9 +1639,22 @@ cairo_pattern_reference (cairo_pattern_t *pattern);
cairo_public void
cairo_pattern_destroy (cairo_pattern_t *pattern);
cairo_public unsigned int
cairo_pattern_get_reference_count (cairo_pattern_t *pattern);
cairo_public cairo_status_t
cairo_pattern_status (cairo_pattern_t *pattern);
cairo_public void *
cairo_pattern_get_user_data (cairo_pattern_t *pattern,
const cairo_user_data_key_t *key);
cairo_public cairo_status_t
cairo_pattern_set_user_data (cairo_pattern_t *pattern,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy);
/**
* cairo_pattern_type_t
* @CAIRO_PATTERN_TYPE_SOLID: The pattern is a solid (uniform)
@ -1525,7 +1684,7 @@ cairo_pattern_status (cairo_pattern_t *pattern);
* New entries may be added in future versions.
*
* Since: 1.2
*/
**/
typedef enum _cairo_pattern_type {
CAIRO_PATTERN_TYPE_SOLID,
CAIRO_PATTERN_TYPE_SURFACE,
@ -1570,7 +1729,7 @@ cairo_pattern_get_matrix (cairo_pattern_t *pattern,
* of a pattern will be drawn.
*
* New entries may be added in future versions.
*/
**/
typedef enum _cairo_extend {
CAIRO_EXTEND_NONE,
CAIRO_EXTEND_REPEAT,
@ -1677,12 +1836,6 @@ cairo_public void
cairo_matrix_transform_point (const cairo_matrix_t *matrix,
double *x, double *y);
cairo_public void
cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double *x1, double *y1,
double *x2, double *y2,
cairo_bool_t *is_tight);
/* Functions to be used while debugging (not intended for use in production code) */
cairo_public void
cairo_debug_reset_static_data (void);

Просмотреть файл

@ -73,7 +73,7 @@
CAIRO_BEGIN_DECLS
#if __GNUC__ >= 3 && defined(__ELF__)
#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun)
# define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name))
# define slim_hidden_def(name) slim_hidden_def1(name, slim_hidden_int_name(name))
# define slim_hidden_int_name(name) INT_##name
@ -102,7 +102,7 @@ CAIRO_BEGIN_DECLS
#endif
/* slim_internal.h */
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__)
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun)
#define cairo_private __attribute__((__visibility__("hidden")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
#define cairo_private __hidden
@ -134,13 +134,20 @@ CAIRO_BEGIN_DECLS
#define __attribute__(x)
#endif
#if 0
#if MOZILLA_CAIRO_NOT_DEFINED
#if HAVE_PTHREAD_H
# include <pthread.h>
# define CAIRO_MUTEX_DECLARE(name) static pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER
#define CAIRO_MUTEX_DECLARE_GLOBAL(name) pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER
# define CAIRO_MUTEX_DECLARE_GLOBAL(name) pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER
# define CAIRO_MUTEX_LOCK(name) pthread_mutex_lock (&name)
# define CAIRO_MUTEX_UNLOCK(name) pthread_mutex_unlock (&name)
typedef pthread_mutex_t cairo_mutex_t;
#define CAIRO_MUTEX_INIT(mutex) do { \
pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER; \
memcpy (mutex, &tmp_mutex, sizeof (tmp_mutex)); \
} while (0)
# define CAIRO_MUTEX_FINI(mutex) pthread_mutex_destroy (mutex)
# define CAIRO_MUTEX_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#endif
#if !defined(CAIRO_MUTEX_DECLARE) && defined CAIRO_HAS_WIN32_SURFACE
@ -160,6 +167,10 @@ CAIRO_BEGIN_DECLS
# define CAIRO_MUTEX_DECLARE_GLOBAL(name) extern LPCRITICAL_SECTION name;
# define CAIRO_MUTEX_LOCK(name) EnterCriticalSection (&name)
# define CAIRO_MUTEX_UNLOCK(name) LeaveCriticalSection (&name)
typedef CRITICAL_SECTION cairo_mutex_t;
# define CAIRO_MUTEX_INIT(mutex) InitializeCriticalSection (mutex)
# define CAIRO_MUTEX_FINI(mutex) DeleteCriticalSection (mutex)
# define CAIRO_MUTEX_NIL_INITIALIZER { 0 }
#endif
#if defined(__OS2__) && !defined(CAIRO_MUTEX_DECLARE)
@ -171,6 +182,10 @@ CAIRO_BEGIN_DECLS
# define CAIRO_MUTEX_DECLARE_GLOBAL(name) extern HMTX name
# define CAIRO_MUTEX_LOCK(name) DosRequestMutexSem(name, SEM_INDEFINITE_WAIT)
# define CAIRO_MUTEX_UNLOCK(name) DosReleaseMutexSem(name)
typedef HMTX cairo_mutex_t;
# define CAIRO_MUTEX_INIT(mutex) DosCreateMutexSem (NULL, mutex, 0L, FALSE)
# define CAIRO_MUTEX_FINI(mutex) DosCloseMutexSem (*(mutex))
# define CAIRO_MUTEX_NIL_INITIALIZER 0
#endif
#if !defined(CAIRO_MUTEX_DECLARE) && defined CAIRO_HAS_BEOS_SURFACE
@ -181,14 +196,29 @@ cairo_private void _cairo_beos_unlock(void*);
# define CAIRO_MUTEX_DECLARE_GLOBAL(name) extern void* name;
# define CAIRO_MUTEX_LOCK(name) _cairo_beos_lock (&name)
# define CAIRO_MUTEX_UNLOCK(name) _cairo_beos_unlock (&name)
# error "XXX: Someone who understands BeOS needs to add definitions for" \
" cairo_mutex_t, CAIRO_MUTEX_INIT, and CAIRO_MUTEX_FINI," \
" to cairoint.h"
typedef ??? cairo_mutex_t;
# define CAIRO_MUTEX_INIT(mutex) ???
# define CAIRO_MUTEX_FINI(mutex) ???
# define CAIRO_MUTEX_NIL_INITIALIZER {}
#endif
#endif
#endif /* MOZILLA_CAIRO_NOT_REACHED */
#ifndef CAIRO_MUTEX_DECLARE
#if MOZILLA_CAIRO_NOT_DEFINED
# error "No mutex declarations. Cairo will not work with multiple threads." \
"(Remove this #error directive to acknowledge & accept this limitation)."
#endif
typedef void *cairo_mutex_t;
# define CAIRO_MUTEX_DECLARE(name)
# define CAIRO_MUTEX_DECLARE_GLOBAL(name)
# define CAIRO_MUTEX_LOCK(name)
# define CAIRO_MUTEX_UNLOCK(name)
#define CAIRO_MUTEX_INIT(mutex) (*(mutex) = 0)
#define CAIRO_MUTEX_FINI(mutex)
#define CAIRO_MUTEX_NIL_INITIALIZER 0
#endif
#undef MIN
@ -209,6 +239,18 @@ cairo_private void _cairo_beos_unlock(void*);
#define M_PI 3.14159265358979323846
#endif
#ifndef MOZILLA_CAIRO_NOT_DEFINED
#ifndef INT32_MAX
# ifdef INT_MAX
# define INT32_MAX INT_MAX
# define INT32_MIN INT_MIN
# else
# define INT32_MAX 2147483647
# define INT32_MIN (-2147483647 - 1)
# endif
#endif
#endif
/* Size in bytes of buffer to use off the stack per functions.
* Mostly used by text functions. For larger allocations, they'll
* malloc(). */
@ -250,6 +292,41 @@ typedef cairo_fixed_16_16_t cairo_fixed_t;
#define CAIRO_BITSWAP8_IF_LITTLE_ENDIAN(c) CAIRO_BITSWAP8(c)
#endif
#ifdef WORDS_BIGENDIAN
#define cpu_to_be16(v) (v)
#define be16_to_cpu(v) (v)
#define cpu_to_be32(v) (v)
#define be32_to_cpu(v) (v)
#else
static inline uint16_t
cpu_to_be16(uint16_t v)
{
return (v << 8) | (v >> 8);
}
static inline uint16_t
be16_to_cpu(uint16_t v)
{
return cpu_to_be16 (v);
}
static inline uint32_t
cpu_to_be32(uint32_t v)
{
return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16);
}
static inline uint32_t
be32_to_cpu(uint32_t v)
{
return cpu_to_be32 (v);
}
#endif
#include "cairo-hash-private.h"
#include "cairo-cache-private.h"
@ -364,15 +441,14 @@ typedef struct _cairo_edge {
} cairo_edge_t;
typedef struct _cairo_polygon {
cairo_point_t first_point;
cairo_point_t current_point;
cairo_bool_t has_current_point;
int num_edges;
int edges_size;
cairo_edge_t *edges;
cairo_point_t first_point;
cairo_point_t current_point;
int has_current_point;
int closed;
cairo_edge_t edges_embedded[8];
} cairo_polygon_t;
typedef struct _cairo_spline {
@ -384,6 +460,7 @@ typedef struct _cairo_spline {
int num_points;
int points_size;
cairo_point_t *points;
cairo_point_t points_embedded[8];
} cairo_spline_t;
typedef struct _cairo_pen_vertex {
@ -523,12 +600,43 @@ typedef struct _cairo_scaled_glyph {
#define _cairo_scaled_glyph_set_index(g,i) ((g)->cache_entry.hash = (i))
struct _cairo_scaled_font {
/* For most cairo objects, the rule for multiple threads is that
* the user is responsible for any locking if the same object is
* manipulated from multiple threads simultaneously.
*
* However, with the caching that cairo does for scaled fonts, a
* user can easily end up with the same cairo_scaled_font object
* being manipulated from multiple threads without the user ever
* being aware of this, (and in fact, unable to control it).
*
* So, as a special exception, the cairo implementation takes care
* of all locking needed for cairo_scaled_font_t. Most of what is
* in the scaled font is immutable, (which is what allows for the
* sharing in the first place). The things that are modified and
* the locks protecting them are as follows:
*
* 1. The reference count (scaled_font->ref_count)
*
* Modifications to the reference count are protected by the
* _cairo_scaled_font_map_mutex. This is because the reference
* count of a scaled font is intimately related with the font
* map itself, (and the magic holdovers array).
*
* 2. The cache of glyphs (scaled_font->glyphs)
* 3. The backend private data (scaled_font->surface_backend,
* scaled_font->surface_private)
*
* Modifications to these fields are protected with locks on
* scaled_font->mutex in the generic scaled_font code.
*/
/* must be first to be stored in a hash table */
cairo_hash_entry_t hash_entry;
/* useful bits for _cairo_scaled_font_nil */
cairo_status_t status;
unsigned int ref_count;
cairo_user_data_array_t user_data;
/* hash key members */
cairo_font_face_t *font_face; /* may be NULL */
@ -539,6 +647,10 @@ struct _cairo_scaled_font {
/* "live" scaled_font members */
cairo_matrix_t scale; /* font space => device space */
cairo_font_extents_t extents; /* user space */
/* The mutex protects modification to all subsequent fields. */
cairo_mutex_t mutex;
cairo_cache_t *glyphs; /* glyph index -> cairo_scaled_glyph_t */
/*
@ -598,6 +710,19 @@ typedef enum _cairo_scaled_glyph_info {
CAIRO_SCALED_GLYPH_INFO_PATH = (1 << 2)
} cairo_scaled_glyph_info_t;
typedef struct _cairo_scaled_font_subset {
cairo_scaled_font_t *scaled_font;
unsigned int font_id;
unsigned int subset_id;
/* Index of glyphs array is subset_glyph_index.
* Value of glyphs array is scaled_font_glyph_index.
*/
unsigned long *glyphs;
unsigned long *to_unicode;
unsigned int num_glyphs;
} cairo_scaled_font_subset_t;
struct _cairo_scaled_font_backend {
cairo_font_type_t type;
@ -651,6 +776,11 @@ struct _cairo_scaled_font_backend {
long offset,
unsigned char *buffer,
unsigned long *length);
void
(*map_glyphs_to_unicode)(void *scaled_font,
cairo_scaled_font_subset_t *font_subset);
};
struct _cairo_font_face_backend {
@ -1042,12 +1172,14 @@ typedef enum {
#define CAIRO_FILTER_DEFAULT CAIRO_FILTER_BEST
struct _cairo_pattern {
cairo_pattern_type_t type;
unsigned int ref_count;
cairo_status_t status;
cairo_matrix_t matrix;
cairo_filter_t filter;
cairo_extend_t extend;
cairo_pattern_type_t type;
unsigned int ref_count;
cairo_status_t status;
cairo_user_data_array_t user_data;
cairo_matrix_t matrix;
cairo_filter_t filter;
cairo_extend_t extend;
};
typedef struct _cairo_solid_pattern {
@ -1066,8 +1198,10 @@ typedef struct _cairo_surface_pattern {
typedef struct _cairo_gradient_pattern {
cairo_pattern_t base;
unsigned int n_stops;
unsigned int stops_size;
pixman_gradient_stop_t *stops;
unsigned int n_stops;
pixman_gradient_stop_t stops_embedded[2];
} cairo_gradient_pattern_t;
typedef struct _cairo_linear_pattern {
@ -1110,10 +1244,12 @@ typedef struct _cairo_surface_attributes {
typedef struct _cairo_traps {
cairo_status_t status;
cairo_trapezoid_t *traps;
cairo_box_t extents;
int num_traps;
int traps_size;
cairo_box_t extents;
cairo_trapezoid_t *traps;
cairo_trapezoid_t traps_embedded[1];
} cairo_traps_t;
#define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL
@ -1196,15 +1332,19 @@ cairo_private int
_cairo_fixed_integer_ceil (cairo_fixed_t f);
/* cairo_gstate.c */
cairo_private cairo_gstate_t *
_cairo_gstate_create (cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_gstate_init (cairo_gstate_t *gstate,
cairo_surface_t *target);
cairo_private void
_cairo_gstate_destroy (cairo_gstate_t *gstate);
_cairo_gstate_fini (cairo_gstate_t *gstate);
cairo_private cairo_gstate_t *
_cairo_gstate_clone (cairo_gstate_t *gstate);
cairo_private void
_cairo_gstate_destroy (cairo_gstate_t *gstate);
cairo_private cairo_bool_t
_cairo_gstate_is_redirected (cairo_gstate_t *gstate);
@ -1420,6 +1560,10 @@ cairo_private cairo_status_t
_cairo_gstate_get_font_face (cairo_gstate_t *gstate,
cairo_font_face_t **font_face);
cairo_private cairo_status_t
_cairo_gstate_get_scaled_font (cairo_gstate_t *gstate,
cairo_scaled_font_t **scaled_font);
cairo_private cairo_status_t
_cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
cairo_font_extents_t *extents);
@ -1467,6 +1611,9 @@ _cairo_stock_color (cairo_stock_t stock);
#define CAIRO_COLOR_BLACK _cairo_stock_color (CAIRO_STOCK_BLACK)
#define CAIRO_COLOR_TRANSPARENT _cairo_stock_color (CAIRO_STOCK_TRANSPARENT)
cairo_private uint16_t
_cairo_color_double_to_short (double d);
cairo_private void
_cairo_color_init (cairo_color_t *color);
@ -1505,11 +1652,15 @@ _cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font);
cairo_private void
_cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font);
cairo_private void
_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font);
cairo_private void
_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
cairo_status_t status);
extern const cairo_private cairo_font_face_t _cairo_font_face_nil;
extern const cairo_private cairo_scaled_font_t _cairo_scaled_font_nil;
cairo_private void
_cairo_font_face_init (cairo_font_face_t *font_face,
@ -1760,6 +1911,7 @@ _cairo_stroke_style_fini (cairo_stroke_style_t *style);
extern const cairo_private cairo_surface_t _cairo_surface_nil;
extern const cairo_private cairo_surface_t _cairo_surface_nil_read_error;
extern const cairo_private cairo_surface_t _cairo_surface_nil_write_error;
extern const cairo_private cairo_surface_t _cairo_surface_nil_file_not_found;
cairo_private void
@ -2185,6 +2337,12 @@ _cairo_matrix_get_affine (const cairo_matrix_t *matrix,
double *xy, double *yy,
double *x0, double *y0);
cairo_private void
_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double *x1, double *y1,
double *x2, double *y2,
cairo_bool_t *is_tight);
cairo_private void
_cairo_matrix_compute_determinant (const cairo_matrix_t *matrix, double *det);
@ -2420,7 +2578,6 @@ slim_hidden_proto (cairo_matrix_multiply);
slim_hidden_proto (cairo_matrix_scale);
slim_hidden_proto (cairo_matrix_transform_distance);
slim_hidden_proto (cairo_matrix_transform_point);
slim_hidden_proto (cairo_matrix_transform_bounding_box);
slim_hidden_proto (cairo_matrix_translate);
slim_hidden_proto (cairo_move_to);
slim_hidden_proto (cairo_new_path);
@ -2441,6 +2598,7 @@ slim_hidden_proto (cairo_push_group_with_content);
slim_hidden_proto (cairo_rel_line_to);
slim_hidden_proto (cairo_restore);
slim_hidden_proto (cairo_save);
slim_hidden_proto (cairo_scale);
slim_hidden_proto (cairo_scaled_font_create);
slim_hidden_proto (cairo_scaled_font_destroy);
slim_hidden_proto (cairo_scaled_font_extents);
@ -2467,9 +2625,14 @@ slim_hidden_proto (cairo_surface_reference);
slim_hidden_proto (cairo_surface_set_device_offset);
slim_hidden_proto (cairo_surface_set_fallback_resolution);
slim_hidden_proto (cairo_surface_status);
slim_hidden_proto (cairo_surface_write_to_png_stream);
slim_hidden_proto (cairo_version_string);
#if CAIRO_HAS_PNG_FUNCTIONS
slim_hidden_proto (cairo_surface_write_to_png_stream);
#endif
CAIRO_END_DECLS
#endif

Просмотреть файл

@ -64,10 +64,10 @@ typedef struct _test_fallback_surface {
const cairo_private cairo_surface_backend_t test_fallback_surface_backend;
slim_hidden_proto (_test_fallback_surface_create);
slim_hidden_proto (_cairo_test_fallback_surface_create);
cairo_surface_t *
_test_fallback_surface_create (cairo_content_t content,
_cairo_test_fallback_surface_create (cairo_content_t content,
int width,
int height)
{
@ -91,7 +91,7 @@ _test_fallback_surface_create (cairo_content_t content,
return &surface->base;
}
slim_hidden_def (_test_fallback_surface_create);
slim_hidden_def (_cairo_test_fallback_surface_create);
static cairo_surface_t *
_test_fallback_surface_create_similar (void *abstract_surface,
@ -101,7 +101,7 @@ _test_fallback_surface_create_similar (void *abstract_surface,
{
assert (CAIRO_CONTENT_VALID (content));
return _test_fallback_surface_create (content,
return _cairo_test_fallback_surface_create (content,
width, height);
}

Просмотреть файл

@ -41,7 +41,7 @@
CAIRO_BEGIN_DECLS
cairo_surface_t *
_test_fallback_surface_create (cairo_content_t content,
_cairo_test_fallback_surface_create (cairo_content_t content,
int width,
int height);

Просмотреть файл

@ -68,7 +68,7 @@ static cairo_int_status_t
_test_meta_surface_show_page (void *abstract_surface);
cairo_surface_t *
_test_meta_surface_create (cairo_content_t content,
_cairo_test_meta_surface_create (cairo_content_t content,
int width,
int height)
{
@ -252,12 +252,27 @@ _test_meta_surface_show_glyphs (void *abstract_surface,
cairo_scaled_font_t *scaled_font)
{
test_meta_surface_t *surface = abstract_surface;
cairo_int_status_t status;
surface->image_reflects_meta = FALSE;
return _cairo_surface_show_glyphs (surface->meta, op, source,
glyphs, num_glyphs,
scaled_font);
/* 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
* and re-acquire the mutex around this nested call.
*
* Yes, this is ugly, but we consider it pragmatic as compared to
* adding locking code to all 18 surface-backend-specific
* show_glyphs functions, (which would get less testing and likely
* lead to bugs).
*/
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
status = _cairo_surface_show_glyphs (surface->meta, op, source,
glyphs, num_glyphs,
scaled_font);
CAIRO_MUTEX_LOCK (scaled_font->mutex);
return status;
}
static cairo_surface_t *

Просмотреть файл

@ -41,7 +41,7 @@
CAIRO_BEGIN_DECLS
cairo_surface_t *
_test_meta_surface_create (cairo_content_t content,
_cairo_test_meta_surface_create (cairo_content_t content,
int width,
int height);

Просмотреть файл

@ -61,7 +61,7 @@ static const cairo_surface_backend_t test_paginated_surface_backend;
static const cairo_paginated_surface_backend_t test_paginated_surface_paginated_backend;
cairo_surface_t *
_test_paginated_surface_create_for_data (unsigned char *data,
_cairo_test_paginated_surface_create_for_data (unsigned char *data,
cairo_content_t content,
int width,
int height,
@ -233,12 +233,27 @@ _test_paginated_surface_show_glyphs (void *abstract_surface,
cairo_scaled_font_t *scaled_font)
{
test_paginated_surface_t *surface = abstract_surface;
cairo_int_status_t status;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
return _cairo_surface_show_glyphs (surface->target, op, source,
glyphs, num_glyphs, scaled_font);
/* 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
* and re-acquire the mutex around this nested call.
*
* Yes, this is ugly, but we consider it pragmatic as compared to
* adding locking code to all 18 surface-backend-specific
* show_glyphs functions, (which would get less testing and likely
* lead to bugs).
*/
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
status = _cairo_surface_show_glyphs (surface->target, op, source,
glyphs, num_glyphs, scaled_font);
CAIRO_MUTEX_LOCK (scaled_font->mutex);
return status;
}
static void

Просмотреть файл

@ -41,7 +41,7 @@
CAIRO_BEGIN_DECLS
cairo_surface_t *
_test_paginated_surface_create_for_data (unsigned char *data,
_cairo_test_paginated_surface_create_for_data (unsigned char *data,
cairo_content_t content,
int width,
int height,

Просмотреть файл

@ -28,7 +28,9 @@
#endif
#include "pixman-xserver-compat.h"
#include "fbpict.h"
#ifndef MOZILLA_CAIRO_NOT_DEFINED
#include "fbmmx.h"
#endif /* MOZCAIRO */
#ifdef RENDER
@ -38,6 +40,7 @@
#define _USE_MATH_DEFINES
#endif
#include <assert.h>
#include <math.h>
#ifndef M_PI
@ -2740,12 +2743,13 @@ typedef struct
CARD32 right_rb;
int32_t left_x;
int32_t right_x;
int32_t width_x;
int32_t stepper;
pixman_gradient_stop_t *stops;
int num_stops;
unsigned int spread;
int need_reset;
} GradientWalker;
static void
@ -2757,13 +2761,14 @@ _gradient_walker_init (GradientWalker *walker,
walker->stops = pGradient->gradient.stops;
walker->left_x = 0;
walker->right_x = 0x10000;
walker->width_x = 0; /* will force a reset */
walker->stepper = 0;
walker->left_ag = 0;
walker->left_rb = 0;
walker->right_ag = 0;
walker->right_rb = 0;
walker->spread = spread;
walker->need_reset = TRUE;
}
static void
@ -2853,13 +2858,15 @@ _gradient_walker_reset (GradientWalker *walker,
pixman_color_t *tmp_c;
int32_t tmp_x;
tmp_x = 0x20000 - right_x;
right_x = 0x20000 - left_x;
tmp_x = 0x10000 - right_x;
right_x = 0x10000 - left_x;
left_x = tmp_x;
tmp_c = right_c;
right_c = left_c;
left_c = tmp_c;
x = 0x10000 - x;
}
left_x += (pos - x);
right_x += (pos - x);
@ -2893,27 +2900,28 @@ _gradient_walker_reset (GradientWalker *walker,
walker->left_x = left_x;
walker->right_x = right_x;
walker->width_x = right_x - left_x;
walker->left_ag = ((left_c->alpha >> 8) << 16) | (left_c->green >> 8);
walker->left_rb = ((left_c->red & 0xff00) << 8) | (left_c->blue >> 8);
walker->right_ag = ((right_c->alpha >> 8) << 16) | (right_c->green >> 8);
walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8);
if ( walker->width_x == 0 ||
if ( walker->left_x == walker->right_x ||
( walker->left_ag == walker->right_ag &&
walker->left_rb == walker->right_rb ) )
{
walker->width_x = 1;
walker->stepper = 0;
}
else
{
walker->stepper = ((1 << 24) + walker->width_x/2)/walker->width_x;
int32_t width = right_x - left_x;
walker->stepper = ((1 << 24) + width/2)/width;
}
walker->need_reset = FALSE;
}
#define GRADIENT_WALKER_NEED_RESET(w,x) \
( (x) < (w)->left_x || (x) - (w)->left_x >= (w)->width_x )
( (w)->need_reset || (x) < (w)->left_x || (x) >= (w)->right_x)
/* the following assumes that GRADIENT_WALKER_NEED_RESET(w,x) is FALSE */
static CARD32
@ -2948,8 +2956,6 @@ _gradient_walker_pixel (GradientWalker *walker,
return (color | (t1 & 0xff00ff) | (t2 & 0xff00));
}
static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *buffer, CARD32 *mask, CARD32 maskBits)
{
SourcePictPtr pGradient = pict->pSourcePict;
@ -3081,13 +3087,128 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *
}
}
} else {
/*
* In the radial gradient problem we are given two circles (c,r) and
* (c,r) that define the gradient itself. Then, for any point p, we
* must compute the value(s) of t within [0.0, 1.0] representing the
* circle(s) that would color the point.
*
* There are potentially two values of t since the point p can be
* colored by both sides of the circle, (which happens whenever one
* circle is not entirely contained within the other).
*
* If we solve for a value of t that is outside of [0.0, 1.0] then we
* use the extend mode (NONE, REPEAT, REFLECT, or PAD) to map to a
* value within [0.0, 1.0].
*
* Here is an illustration of the problem:
*
* p
* p
*
* · r
* p ·
* θ
*
* r · c
* θ ·
*
* c
*
* Given (c,r), (c,r) and p, we must find an angle θ such that two
* points p and p on the two circles are collinear with p. Then, the
* desired value of t is the ratio of the length of pp to the length
* of pp.
*
* So, we have six unknown values: (px, py), (px, py), θ and t.
* We can also write six equations that constrain the problem:
*
* Point p is a distance r from c at an angle of θ:
*
* 1. px = cx + r·cos θ
* 2. py = cy + r·sin θ
*
* Point p is a distance r from c at an angle of θ:
*
* 3. px = cx + r2·cos θ
* 4. py = cy + r2·sin θ
*
* Point p lies at a fraction t along the line segment pp:
*
* 5. px = t·px + (1-t)·px
* 6. py = t·py + (1-t)·py
*
* To solve, first subtitute 1-4 into 5 and 6:
*
* px = t·(cx + r·cos θ) + (1-t)·(cx + r·cos θ)
* py = t·(cy + r·sin θ) + (1-t)·(cy + r·sin θ)
*
* Then solve each for cos θ and sin θ expressed as a function of t:
*
* cos θ = (-(cx - cx)·t + (px - cx)) / ((r-r)·t + r)
* sin θ = (-(cy - cy)·t + (py - cy)) / ((r-r)·t + r)
*
* To simplify this a bit, we define new variables for several of the
* common terms as shown below:
*
* p
* p
*
* · r
* p ·
* pdy
* c
* r ·
* · cdy
*
* c pdx cdx
*
* cdx = (cx - cx)
* cdy = (cy - cy)
* dr = r-r
* pdx = px - cx
* pdy = py - cy
*
* Note that cdx, cdy, and dr do not depend on point p at all, so can
* be pre-computed for the entire gradient. The simplifed equations
* are now:
*
* cos θ = (-cdx·t + pdx) / (dr·t + r)
* sin θ = (-cdy·t + pdy) / (dr·t + r)
*
* Finally, to get a single function of t and eliminate the last
* unknown θ, we use the identity sin²θ + cos²θ = 1. First, square
* each equation, (we knew a quadratic was coming since it must be
* possible to obtain two solutions in some cases):
*
* cos²θ = (cdx²t² - 2·cdx·pdx·t + pdx²) / (dr²·t² + 2·r·dr·t + r²)
* sin²θ = (cdy²t² - 2·cdy·pdy·t + pdy²) / (dr²·t² + 2·r·dr·t + r²)
*
* Then add both together, set the result equal to 1, and express as a
* standard quadratic equation in t of the form At² + Bt + C = 0
*
* (cdx² + cdy² - dr²)·t² - 2·(cdx·pdx + cdy·pdy + r·dr)·t + (pdx² + pdy² - r²) = 0
*
* In other words:
*
* A = cdx² + cdy² - dr²
* B = -2·(pdx·cdx + pdy·cdy + r·dr)
* C = pdx² + pdy² - r²
*
* And again, notice that A does not depend on p, so can be
* precomputed. From here we just use the quadratic formula to solve
* for t:
*
* t = (-2·B ± (B² - 4·A·C)) / 2·A
*/
/* radial or conical */
Bool projective = FALSE;
double cx = 1.;
double cy = 0.;
double cz = 0.;
double rx = x;
double ry = y;
double rx = x + 0.5;
double ry = y + 0.5;
double rz = 1.;
if (pict->transform) {
@ -3109,23 +3230,36 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *
}
if (pGradient->type == SourcePictTypeRadial) {
pixman_radial_gradient_image_t *radial;
radial = &pGradient->radial;
if (!projective) {
rx -= pGradient->radial.fx;
ry -= pGradient->radial.fy;
while (buffer < end) {
double b, c, det, s;
if (!mask || *mask++ & maskBits)
{
xFixed_48_16 t;
double pdx, pdy;
double B, C;
double det;
double c1x = xFixedToDouble (radial->c1.x);
double c1y = xFixedToDouble (radial->c1.y);
double r1 = xFixedToDouble (radial->c1.radius);
xFixed_48_16 t;
b = 2*(rx*pGradient->radial.dx + ry*pGradient->radial.dy);
c = -(rx*rx + ry*ry);
det = (b * b) - (4 * pGradient->radial.a * c);
s = (-b + sqrt(det))/(2. * pGradient->radial.a);
pdx = rx - c1x;
pdy = ry - c1y;
t = (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536);
B = -2 * ( pdx * radial->cdx
+ pdy * radial->cdy
+ r1 * radial->dr);
C = (pdx * pdx + pdy * pdy - r1 * r1);
det = (B * B) - (4 * radial->A * C);
if (det < 0.0)
det = 0.0;
if (radial->A < 0)
t = (xFixed_48_16) ((- B - sqrt(det)) / (2.0 * radial->A) * 65536);
else
t = (xFixed_48_16) ((- B + sqrt(det)) / (2.0 * radial->A) * 65536);
*buffer = _gradient_walker_pixel (&walker, t);
}
@ -3134,35 +3268,12 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *
ry += cy;
}
} else {
while (buffer < end) {
double x, y;
double b, c, det, s;
if (!mask || *mask++ & maskBits)
{
xFixed_48_16 t;
if (rz != 0) {
x = rx/rz;
y = ry/rz;
} else {
x = y = 0.;
}
x -= pGradient->radial.fx;
y -= pGradient->radial.fy;
b = 2*(x*pGradient->radial.dx + y*pGradient->radial.dy);
c = -(x*x + y*y);
det = (b * b) - (4 * pGradient->radial.a * c);
s = (-b + sqrt(det))/(2. * pGradient->radial.a);
t = (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536);
*buffer = _gradient_walker_pixel (&walker, t);
}
++buffer;
rx += cx;
ry += cy;
rz += cz;
}
/* In cairo, we don't have projective transformed
* radial gradients---so I'm not going to bother
* implementing something untested and broken
* here. Instead, someone trying to get this code into
* shape for use in the X server can fix this here. */
assert (0);
}
} else /* SourcePictTypeConical */ {
double a = pGradient->conical.angle/(180.*65536);
@ -3927,6 +4038,7 @@ fbCompositeRect (const FbComposeData *data, CARD32 *scanline_buffer)
if (!compose)
return;
#ifndef MOZILLA_CAIRO_NOT_DEFINED
/* XXX: The non-MMX version of some of the fbCompose functions
* overwrite the source or mask data (ones that use
* fbCombineMaskC, fbCombineMaskAlphaC, or fbCombineMaskValueC
@ -3944,6 +4056,7 @@ fbCompositeRect (const FbComposeData *data, CARD32 *scanline_buffer)
srcClass = SourcePictClassUnknown;
maskClass = SourcePictClassUnknown;
}
#endif /* MOZCAIRO */
for (i = 0; i < data->height; ++i) {
/* fill first half of scanline with source */

Просмотреть файл

@ -157,6 +157,11 @@ static const MMXData c =
#define MC(x) c.mmx_##x
#endif
/* cast to void* in the middle to shut gcc up warning about
* "dereferencing type-punned pointers".
*/
#define M64(x) (*(__m64*)(void*)(&x))
static __inline__ __m64
shift (__m64 v, int s)
{
@ -1467,8 +1472,6 @@ fbCompositeSrc_8888x0565mmx (pixman_operator_t op,
fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1);
fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1);
assert (pSrc->pDrawable == pMask->pDrawable);
while (height--)
{
dst = dstLine;
@ -1497,46 +1500,22 @@ fbCompositeSrc_8888x0565mmx (pixman_operator_t op,
while (w >= 4)
{
CARD32 s0, s1, s2, s3;
unsigned char a0, a1, a2, a3;
__m64 vsrc0, vsrc1, vsrc2, vsrc3;
__m64 vdest;
s0 = *src;
s1 = *(src + 1);
s2 = *(src + 2);
s3 = *(src + 3);
vsrc0 = load8888(*(src + 0));
vsrc1 = load8888(*(src + 1));
vsrc2 = load8888(*(src + 2));
vsrc3 = load8888(*(src + 3));
a0 = (s0 >> 24);
a1 = (s1 >> 24);
a2 = (s2 >> 24);
a3 = (s3 >> 24);
vsrc0 = load8888(s0);
vsrc1 = load8888(s1);
vsrc2 = load8888(s2);
vsrc3 = load8888(s3);
if ((a0 & a1 & a2 & a3) == 0xFF)
{
__m64 vdest;
vdest = pack565(vsrc0, _mm_setzero_si64(), 0);
vdest = pack565(vsrc1, vdest, 1);
vdest = pack565(vsrc2, vdest, 2);
vdest = pack565(vsrc3, vdest, 3);
*(__m64 *)dst = vdest;
}
else if (a0 | a1 | a2 | a3)
{
__m64 vdest = *(__m64 *)dst;
vdest = pack565(over(vsrc0, expand_alpha(vsrc0), expand565(vdest, 0)), vdest, 0);
vdest = pack565(over(vsrc1, expand_alpha(vsrc1), expand565(vdest, 1)), vdest, 1);
vdest = pack565(over(vsrc2, expand_alpha(vsrc2), expand565(vdest, 2)), vdest, 2);
vdest = pack565(over(vsrc3, expand_alpha(vsrc3), expand565(vdest, 3)), vdest, 3);
*(__m64 *)dst = vdest;
}
vdest = *(__m64 *)dst;
vdest = pack565(over(vsrc0, expand_alpha(vsrc0), expand565(vdest, 0)), vdest, 0);
vdest = pack565(over(vsrc1, expand_alpha(vsrc1), expand565(vdest, 1)), vdest, 1);
vdest = pack565(over(vsrc2, expand_alpha(vsrc2), expand565(vdest, 2)), vdest, 2);
vdest = pack565(over(vsrc3, expand_alpha(vsrc3), expand565(vdest, 3)), vdest, 3);
*(__m64 *)dst = vdest;
w -= 4;
dst += 4;
@ -1617,7 +1596,7 @@ fbCompositeSolidMask_nx8x8888mmx (pixman_operator_t op,
if (m)
{
__m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev (*(__m64*)(&m)), load8888(*dst));
__m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev (M64(m)), load8888(*dst));
*dst = store8888(vdest);
}
@ -1645,8 +1624,8 @@ fbCompositeSolidMask_nx8x8888mmx (pixman_operator_t op,
vdest = *(__m64 *)dst;
dest0 = in_over(vsrc, vsrca, expand_alpha_rev (*(__m64*)(&m0)), expand8888(vdest, 0));
dest1 = in_over(vsrc, vsrca, expand_alpha_rev (*(__m64*)(&m1)), expand8888(vdest, 1));
dest0 = in_over(vsrc, vsrca, expand_alpha_rev (M64(m0)), expand8888(vdest, 0));
dest1 = in_over(vsrc, vsrca, expand_alpha_rev (M64(m1)), expand8888(vdest, 1));
*(__m64 *)dst = pack8888(dest0, dest1);
}
@ -1665,7 +1644,7 @@ fbCompositeSolidMask_nx8x8888mmx (pixman_operator_t op,
if (m)
{
__m64 vdest = load8888(*dst);
vdest = in_over(vsrc, vsrca, expand_alpha_rev (*(__m64*)(&m)), vdest);
vdest = in_over(vsrc, vsrca, expand_alpha_rev (M64(m)), vdest);
*dst = store8888(vdest);
}
@ -1735,7 +1714,7 @@ fbCompositeSolidMaskSrc_nx8x8888mmx (pixman_operator_t op,
if (m)
{
__m64 vdest = in(vsrc, expand_alpha_rev (*(__m64*)(&m)));
__m64 vdest = in(vsrc, expand_alpha_rev (M64(m)));
*dst = store8888(vdest);
}
else
@ -1767,8 +1746,8 @@ fbCompositeSolidMaskSrc_nx8x8888mmx (pixman_operator_t op,
vdest = *(__m64 *)dst;
dest0 = in(vsrc, expand_alpha_rev (*(__m64*)(&m0)));
dest1 = in(vsrc, expand_alpha_rev (*(__m64*)(&m1)));
dest0 = in(vsrc, expand_alpha_rev (M64(m0)));
dest1 = in(vsrc, expand_alpha_rev (M64(m1)));
*(__m64 *)dst = pack8888(dest0, dest1);
}
@ -1791,7 +1770,7 @@ fbCompositeSolidMaskSrc_nx8x8888mmx (pixman_operator_t op,
if (m)
{
__m64 vdest = load8888(*dst);
vdest = in(vsrc, expand_alpha_rev (*(__m64*)(&m)));
vdest = in(vsrc, expand_alpha_rev (M64(m)));
*dst = store8888(vdest);
}
else
@ -1846,7 +1825,7 @@ fbCompositeSolidMask_nx8x0565mmx (pixman_operator_t op,
vsrca = expand_alpha (vsrc);
vsrc16 = pack565(vsrc, _mm_setzero_si64(), 0);
src16 = *(ullong*)(&vsrc16);
src16 = *(ullong*)(void*)(&vsrc16);
srcsrcsrcsrc = (ullong)src16 << 48 | (ullong)src16 << 32 |
(ullong)src16 << 16 | (ullong)src16;
@ -1868,7 +1847,7 @@ fbCompositeSolidMask_nx8x0565mmx (pixman_operator_t op,
if (m)
{
__m64 vd = _mm_cvtsi32_si64 (*dst);
__m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev (*(__m64*)(&m)), expand565(vd, 0));
__m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev (M64(m)), expand565(vd, 0));
*dst = _mm_cvtsi64_si32 (pack565(vdest, _mm_setzero_si64(), 0));
}
@ -1898,13 +1877,13 @@ fbCompositeSolidMask_nx8x0565mmx (pixman_operator_t op,
vdest = *(__m64 *)dst;
vm0 = *(__m64*)(&m0);
vm0 = M64(m0);
vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm0), expand565(vdest, 0)), vdest, 0);
vm1 = *(__m64*)(&m1);
vm1 = M64(m1);
vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm1), expand565(vdest, 1)), vdest, 1);
vm2 = *(__m64*)(&m2);
vm2 = M64(m2);
vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm2), expand565(vdest, 2)), vdest, 2);
vm3 = *(__m64*)(&m3);
vm3 = M64(m3);
vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm3), expand565(vdest, 3)), vdest, 3);
*(__m64 *)dst = vdest;
@ -1924,7 +1903,7 @@ fbCompositeSolidMask_nx8x0565mmx (pixman_operator_t op,
if (m)
{
__m64 vd = _mm_cvtsi32_si64 (*dst);
__m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev (*(__m64*)(&m)), expand565(vd, 0));
__m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev (M64(m)), expand565(vd, 0));
*dst = _mm_cvtsi64_si32 (pack565(vdest, _mm_setzero_si64(), 0));
}
@ -2655,7 +2634,7 @@ fbSolidFillmmx (FbPixels *pDraw,
}
fill = ((ullong)xor << 32) | xor;
vfill = *(__m64*)&fill;
vfill = M64(fill);
while (height--)
{

Просмотреть файл

@ -2123,7 +2123,9 @@ static unsigned int detectCPUFeatures(void) {
features |= SSE;
if (result & (1 << 26))
features |= SSE2;
if ((result & MMX) && !(result & SSE) && (strcmp(vendor, "AuthenticAMD") == 0)) {
if ((features & MMX) && !(features & SSE) &&
(strcmp(vendor, "AuthenticAMD") == 0 ||
strcmp(vendor, "Geode by NSC") == 0)) {
/* check for AMD MMX extensions */
#ifdef __GNUC__

Просмотреть файл

@ -1,5 +1,5 @@
/*
* $Id: fbtrap.c,v 1.14 2007/04/03 18:59:49 vladimir%pobox.com Exp $
* $Id: fbtrap.c,v 1.15 2007/04/04 01:09:16 vladimir%pobox.com Exp $
*
* Copyright © 2004 Keith Packard
*

Просмотреть файл

@ -247,7 +247,6 @@ pixman_image_create_radial_gradient (const pixman_radial_gradient_t *gradient,
{
pixman_radial_gradient_image_t *radial;
pixman_image_t *image;
double x;
if (n_stops < 2)
return NULL;
@ -270,19 +269,14 @@ pixman_image_create_radial_gradient (const pixman_radial_gradient_t *gradient,
memcpy (radial->stops, stops, sizeof (pixman_gradient_stop_t) * n_stops);
radial->type = SourcePictTypeRadial;
x = (double) gradient->inner.radius / (double) gradient->outer.radius;
radial->dx = (gradient->outer.x - gradient->inner.x);
radial->dy = (gradient->outer.y - gradient->inner.y);
radial->fx = (gradient->inner.x) - x * radial->dx;
radial->fy = (gradient->inner.y) - x * radial->dy;
radial->m = 1. / (1 + x);
radial->b = -x * radial->m;
radial->dx /= 65536.;
radial->dy /= 65536.;
radial->fx /= 65536.;
radial->fy /= 65536.;
x = gradient->outer.radius / 65536.;
radial->a = x * x - radial->dx * radial->dx - radial->dy * radial->dy;
radial->c1 = gradient->c1;
radial->c2 = gradient->c2;
radial->cdx = xFixedToDouble (gradient->c2.x - gradient->c1.x);
radial->cdy = xFixedToDouble (gradient->c2.y - gradient->c1.y);
radial->dr = xFixedToDouble (gradient->c2.radius - gradient->c1.radius);
radial->A = ( radial->cdx * radial->cdx
+ radial->cdy * radial->cdy
- radial->dr * radial->dr);
image->pSourcePict = (pixman_source_image_t *) radial;

Просмотреть файл

@ -101,13 +101,12 @@ typedef struct _pixman_radial_gradient_image {
int stopRange;
uint32_t *colorTable;
int colorTableSize;
double fx;
double fy;
double dx;
double dy;
double a;
double m;
double b;
pixman_circle_t c1;
pixman_circle_t c2;
double cdx;
double cdy;
double dr;
double A;
} pixman_radial_gradient_image_t;
typedef struct _pixman_conical_gradient_image {

Просмотреть файл

@ -1026,6 +1026,7 @@ typedef xFixed_16_16 xFixed;
#define IntToxFixed(i) ((xFixed) (i) << XFIXED_BITS)
#define xFixedE ((xFixed) 1)
#define xFixed1 (IntToxFixed(1))
#define xFixedToDouble(f) (double) ((f) / (double) xFixed1)
#define xFixed1MinusE (xFixed1 - xFixedE)
#define xFixedFrac(f) ((f) & xFixed1MinusE)
#define xFixedFloor(f) ((f) & ~xFixed1MinusE)

Просмотреть файл

@ -1,80 +1,80 @@
#define pixman_add_trapezoids _moz_cairo_pixman_add_trapezoids
#define pixman_color_to_pixel _moz_cairo_pixman_color_to_pixel
#define composeFunctions _moz_cairo_pixman_compose_functions
#define fbComposeSetupMMX _moz_cairo_pixman_compose_setup_mmx
#define pixman_composite _moz_cairo_pixman_composite
#define fbCompositeCopyAreammx _moz_cairo_pixman_composite_copy_area_mmx
#define fbCompositeSolidMask_nx8888x0565Cmmx _moz_cairo_pixman_composite_solid_mask_nx8888x0565Cmmx
#define fbCompositeSolidMask_nx8888x8888Cmmx _moz_cairo_pixman_composite_solid_mask_nx8888x8888Cmmx
#define fbCompositeSolidMask_nx8x0565mmx _moz_cairo_pixman_composite_solid_mask_nx8x0565mmx
#define fbCompositeSolidMask_nx8x8888mmx _moz_cairo_pixman_composite_solid_mask_nx8x8888mmx
#define fbCompositeSolidMaskSrc_nx8x8888mmx _moz_cairo_pixman_composite_solid_mask_src_nx8x8888mmx
#define fbCompositeSolid_nx0565mmx _moz_cairo_pixman_composite_solid_nx0565mmx
#define fbCompositeSolid_nx8888mmx _moz_cairo_pixman_composite_solid_nx8888mmx
#define fbCompositeSrc_8888RevNPx0565mmx _moz_cairo_pixman_composite_src_8888RevNPx0565mmx
#define fbCompositeSrc_8888RevNPx8888mmx _moz_cairo_pixman_composite_src_8888RevNPx8888_mmx
#define fbCompositeSrc_8888x0565mmx _moz_cairo_pixman_composite_src_8888x0565mmx
#define fbCompositeSrc_8888x8888mmx _moz_cairo_pixman_composite_src_8888x8888mmx
#define fbCompositeSrc_8888x8x8888mmx _moz_cairo_pixman_composite_src_8888x8x8888mmx
#define fbCompositeSrcAdd_8000x8000mmx _moz_cairo_pixman_composite_src_add_8000x8000mmx
#define fbCompositeSrcAdd_8888x8888mmx _moz_cairo_pixman_composite_src_add_8888x8888mmx
#define fbCompositeSrc_x888x8x8888mmx _moz_cairo_pixman_composite_src_x888x8x8888mmx
#define pixman_composite_trapezoids _moz_cairo_pixman_composite_trapezoids
#define pixman_composite_tri_fan _moz_cairo_pixman_composite_tri_fan
#define pixman_composite_tri_strip _moz_cairo_pixman_composite_tri_strip
#define pixman_composite_triangles _moz_cairo_pixman_composite_triangles
#define fbCopyAreammx _moz_cairo_pixman_copy_area_mmx
#define pixman_fill_rectangle _moz_cairo_pixman_fill_rectangle
#define pixman_fill_rectangles _moz_cairo_pixman_fill_rectangles
#define pixman_format_create _moz_cairo_pixman_format_create
#define pixman_format_create_masks _moz_cairo_pixman_format_create_masks
#define pixman_format_destroy _moz_cairo_pixman_format_destroy
#define pixman_format_get_masks _moz_cairo_pixman_format_get_masks
#define pixman_format_init _moz_cairo_pixman_format_init
#define pixman_add_trapezoids _cairo_pixman_add_trapezoids
#define pixman_color_to_pixel _cairo_pixman_color_to_pixel
#define composeFunctions _cairo_pixman_compose_functions
#define fbComposeSetupMMX _cairo_pixman_compose_setup_mmx
#define pixman_composite _cairo_pixman_composite
#define fbCompositeCopyAreammx _cairo_pixman_composite_copy_area_mmx
#define fbCompositeSolidMask_nx8888x0565Cmmx _cairo_pixman_composite_solid_mask_nx8888x0565Cmmx
#define fbCompositeSolidMask_nx8888x8888Cmmx _cairo_pixman_composite_solid_mask_nx8888x8888Cmmx
#define fbCompositeSolidMask_nx8x0565mmx _cairo_pixman_composite_solid_mask_nx8x0565mmx
#define fbCompositeSolidMask_nx8x8888mmx _cairo_pixman_composite_solid_mask_nx8x8888mmx
#define fbCompositeSolidMaskSrc_nx8x8888mmx _cairo_pixman_composite_solid_mask_src_nx8x8888mmx
#define fbCompositeSolid_nx0565mmx _cairo_pixman_composite_solid_nx0565mmx
#define fbCompositeSolid_nx8888mmx _cairo_pixman_composite_solid_nx8888mmx
#define fbCompositeSrc_8888RevNPx0565mmx _cairo_pixman_composite_src_8888RevNPx0565mmx
#define fbCompositeSrc_8888RevNPx8888mmx _cairo_pixman_composite_src_8888RevNPx8888_mmx
#define fbCompositeSrc_8888x0565mmx _cairo_pixman_composite_src_8888x0565mmx
#define fbCompositeSrc_8888x8888mmx _cairo_pixman_composite_src_8888x8888mmx
#define fbCompositeSrc_8888x8x8888mmx _cairo_pixman_composite_src_8888x8x8888mmx
#define fbCompositeSrcAdd_8000x8000mmx _cairo_pixman_composite_src_add_8000x8000mmx
#define fbCompositeSrcAdd_8888x8888mmx _cairo_pixman_composite_src_add_8888x8888mmx
#define fbCompositeSrc_x888x8x8888mmx _cairo_pixman_composite_src_x888x8x8888mmx
#define pixman_composite_trapezoids _cairo_pixman_composite_trapezoids
#define pixman_composite_tri_fan _cairo_pixman_composite_tri_fan
#define pixman_composite_tri_strip _cairo_pixman_composite_tri_strip
#define pixman_composite_triangles _cairo_pixman_composite_triangles
#define fbCopyAreammx _cairo_pixman_copy_area_mmx
#define pixman_fill_rectangle _cairo_pixman_fill_rectangle
#define pixman_fill_rectangles _cairo_pixman_fill_rectangles
#define pixman_format_create _cairo_pixman_format_create
#define pixman_format_create_masks _cairo_pixman_format_create_masks
#define pixman_format_destroy _cairo_pixman_format_destroy
#define pixman_format_get_masks _cairo_pixman_format_get_masks
#define pixman_format_init _cairo_pixman_format_init
#if defined(USE_MMX) && !defined(__amd64__) && !defined(__x86_64__)
#define fbHaveMMX _moz_cairo_pixman_have_mmx
#define fbHaveMMX _cairo_pixman_have_mmx
#endif
#define pixman_image_create _moz_cairo_pixman_image_create
#define pixman_image_create_for_data _moz_cairo_pixman_image_create_for_data
#define pixman_image_destroy _moz_cairo_pixman_image_destroy
#define pixman_image_get_data _moz_cairo_pixman_image_get_data
#define pixman_image_get_depth _moz_cairo_pixman_image_get_depth
#define pixman_image_get_format _moz_cairo_pixman_image_get_format
#define pixman_image_get_height _moz_cairo_pixman_image_get_height
#define pixman_image_get_stride _moz_cairo_pixman_image_get_stride
#define pixman_image_get_width _moz_cairo_pixman_image_get_width
#define pixman_image_set_clip_region _moz_cairo_pixman_image_set_clip_region
#define pixman_image_set_component_alpha _moz_cairo_pixman_image_set_component_alpha
#define pixman_image_set_filter _moz_cairo_pixman_image_set_filter
#define pixman_image_set_repeat _moz_cairo_pixman_image_set_repeat
#define pixman_image_set_transform _moz_cairo_pixman_image_set_transform
#define pixman_image_create_linear_gradient _moz_cairo_pixman_image_create_linear_gradient
#define pixman_image_create_radial_gradient _moz_cairo_pixman_image_create_radial_gradient
#define miIsSolidAlpha _moz_cairo_pixman_is_solid_alpha
#define pixman_pixel_to_color _moz_cairo_pixman_pixel_to_color
#define pixman_region_append _moz_cairo_pixman_region_append
#define pixman_region_contains_point _moz_cairo_pixman_region_contains_point
#define pixman_region_contains_rectangle _moz_cairo_pixman_region_contains_rectangle
#define pixman_region_copy _moz_cairo_pixman_region_copy
#define pixman_region_create _moz_cairo_pixman_region_create
#define pixman_region_create_simple _moz_cairo_pixman_region_create_simple
#define pixman_region_destroy _moz_cairo_pixman_region_destroy
#define pixman_region_empty _moz_cairo_pixman_region_empty
#define pixman_region_extents _moz_cairo_pixman_region_extents
#define pixman_region_intersect _moz_cairo_pixman_region_intersect
#define pixman_region_inverse _moz_cairo_pixman_region_inverse
#define pixman_region_not_empty _moz_cairo_pixman_region_not_empty
#define pixman_region_num_rects _moz_cairo_pixman_region_num_rects
#define pixman_region_rects _moz_cairo_pixman_region_rects
#define pixman_region_reset _moz_cairo_pixman_region_reset
#define pixman_region_subtract _moz_cairo_pixman_region_subtract
#define pixman_region_translate _moz_cairo_pixman_region_translate
#define pixman_region_union _moz_cairo_pixman_region_union
#define pixman_region_union_rect _moz_cairo_pixman_region_union_rect
#define pixman_region_validate _moz_cairo_pixman_region_validate
#define RenderEdgeInit _moz_cairo_pixman_render_edge_init
#define RenderEdgeStep _moz_cairo_pixman_render_edge_step
#define RenderLineFixedEdgeInit _moz_cairo_pixman_render_line_fixed_edge_init
#define RenderSampleCeilY _moz_cairo_pixman_render_sample_ceil_y
#define RenderSampleFloorY _moz_cairo_pixman_render_sample_floor_y
#define fbSolidFillmmx _moz_cairo_pixman_solid_fill_mmx
#define pixman_image_create _cairo_pixman_image_create
#define pixman_image_create_for_data _cairo_pixman_image_create_for_data
#define pixman_image_destroy _cairo_pixman_image_destroy
#define pixman_image_get_data _cairo_pixman_image_get_data
#define pixman_image_get_depth _cairo_pixman_image_get_depth
#define pixman_image_get_format _cairo_pixman_image_get_format
#define pixman_image_get_height _cairo_pixman_image_get_height
#define pixman_image_get_stride _cairo_pixman_image_get_stride
#define pixman_image_get_width _cairo_pixman_image_get_width
#define pixman_image_set_clip_region _cairo_pixman_image_set_clip_region
#define pixman_image_set_component_alpha _cairo_pixman_image_set_component_alpha
#define pixman_image_set_filter _cairo_pixman_image_set_filter
#define pixman_image_set_repeat _cairo_pixman_image_set_repeat
#define pixman_image_set_transform _cairo_pixman_image_set_transform
#define pixman_image_create_linear_gradient _cairo_pixman_image_create_linear_gradient
#define pixman_image_create_radial_gradient _cairo_pixman_image_create_radial_gradient
#define miIsSolidAlpha _cairo_pixman_is_solid_alpha
#define pixman_pixel_to_color _cairo_pixman_pixel_to_color
#define pixman_region_append _cairo_pixman_region_append
#define pixman_region_contains_point _cairo_pixman_region_contains_point
#define pixman_region_contains_rectangle _cairo_pixman_region_contains_rectangle
#define pixman_region_copy _cairo_pixman_region_copy
#define pixman_region_create _cairo_pixman_region_create
#define pixman_region_create_simple _cairo_pixman_region_create_simple
#define pixman_region_destroy _cairo_pixman_region_destroy
#define pixman_region_empty _cairo_pixman_region_empty
#define pixman_region_extents _cairo_pixman_region_extents
#define pixman_region_intersect _cairo_pixman_region_intersect
#define pixman_region_inverse _cairo_pixman_region_inverse
#define pixman_region_not_empty _cairo_pixman_region_not_empty
#define pixman_region_num_rects _cairo_pixman_region_num_rects
#define pixman_region_rects _cairo_pixman_region_rects
#define pixman_region_reset _cairo_pixman_region_reset
#define pixman_region_subtract _cairo_pixman_region_subtract
#define pixman_region_translate _cairo_pixman_region_translate
#define pixman_region_union _cairo_pixman_region_union
#define pixman_region_union_rect _cairo_pixman_region_union_rect
#define pixman_region_validate _cairo_pixman_region_validate
#define RenderEdgeInit _cairo_pixman_render_edge_init
#define RenderEdgeStep _cairo_pixman_render_edge_step
#define RenderLineFixedEdgeInit _cairo_pixman_render_line_fixed_edge_init
#define RenderSampleCeilY _cairo_pixman_render_sample_ceil_y
#define RenderSampleFloorY _cairo_pixman_render_sample_floor_y
#define fbSolidFillmmx _cairo_pixman_solid_fill_mmx

Просмотреть файл

@ -99,7 +99,7 @@ SOFTWARE.
#include "pixman-remap.h"
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__)
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun__)
#define pixman_private __attribute__((__visibility__("hidden")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
#define pixman_private __hidden
@ -364,8 +364,8 @@ typedef struct pixman_linear_gradient {
} pixman_linear_gradient_t;
typedef struct pixman_radial_gradient {
pixman_circle_t inner;
pixman_circle_t outer;
pixman_circle_t c1;
pixman_circle_t c2;
} pixman_radial_gradient_t;
typedef enum {

Просмотреть файл

@ -1,106 +0,0 @@
/* slim - Shared Library Interface Macros
*
* Copyright © 2003 Richard Henderson
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Richard Henderson
* not be used in advertising or publicity pertaining to distribution
* of the software without specific, written prior permission.
* Richard Henderson makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* RICHARD HENDERSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL RICHARD HENDERSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Richard Henderson <rth@twiddle.net>
*/
#ifndef _SLIM_INTERNAL_H_
#define _SLIM_INTERNAL_H_ 1
/* XXX THIS DOCUMENTATION IS BLOODY WRONG. SOMEONE DID NOT ACTUALLY
CONSULT WITH THE COMPILERS THEY CLAIMED TO SUPPORT */
/* This macro marks a symbol as STV_HIDDEN, which prevents it from being
added to the dynamic symbol table of the shared library. This prevents
users of the library from knowingly or unknowingly accessing library
internals that may change in future releases. It also allows the
compiler to generate slightly more efficient code in some cases.
The macro should be placed either immediately before the return type in
a function declaration:
pixman_private int
somefunction(void);
or after a data name,
XXX THIS IS WRONG. YOU CAN NOT DO THIS WITH THE COMPILERS THAT
THIS PACKAGE CLAIMS TO SUPPORT.
extern int somedata pixman_private;
The ELF visibility attribute did not exist before gcc 3.3. */
/* ??? Not marked with "slim" because that makes it look too much
like the function name instead of just an attribute. */
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__)
#define pixman_private __attribute__((__visibility__("hidden")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
#define pixman_private __hidden
#else /* not gcc >= 3.3 and not Sun Studio >= 8 */
#define pixman_private
#endif
/* The following macros are used for PLT bypassing. First of all,
you need to have the function prototyped somewhere, say in foo.h:
int foo (int __bar);
If calls to foo within libfoo.so should always go to foo defined
in libfoo.so, then in fooint.h you add:
slim_hidden_proto (foo)
and after the foo function definition:
int foo (int __bar)
{
return __bar;
}
slim_hidden_def (foo);
This works by arranging for the C symbol "foo" to be renamed to
"INT_foo" at the assembly level, which is marked pixman_private.
We then create another symbol at the same address (an alias) with
the C symbol "EXT_foo", which is renamed to "foo" at the assembly
level. */
#if __GNUC__ >= 3 && defined(__ELF__)
# define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name))
# define slim_hidden_def(name) slim_hidden_def1(name, slim_hidden_int_name(name))
# define slim_hidden_int_name(name) INT_##name
# define slim_hidden_proto1(name, internal) \
extern __typeof (name) name \
__asm__ (slim_hidden_asmname (internal)) \
pixman_private;
# define slim_hidden_def1(name, internal) \
extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name)) \
__attribute__((__alias__(slim_hidden_asmname(internal))))
# define slim_hidden_ulp slim_hidden_ulp1(__USER_LABEL_PREFIX__)
# define slim_hidden_ulp1(x) slim_hidden_ulp2(x)
# define slim_hidden_ulp2(x) #x
# define slim_hidden_asmname(name) slim_hidden_asmname1(name)
# define slim_hidden_asmname1(name) slim_hidden_ulp #name
#else
# define slim_hidden_proto(name)
# define slim_hidden_def(name)
#endif
#endif /* _SLIM_INTERNAL_H_ */

Просмотреть файл

@ -150,7 +150,7 @@ nsThebesDeviceContext::SetDPI()
if (mPrintingSurface &&
(mPrintingSurface->GetType() == gfxASurface::SurfaceTypePDF ||
mPrintingSurface->GetType() == gfxASurface::SurfaceTypePS ||
mPrintingSurface->GetType() == gfxASurface::SurfaceTypeQuartz2)) {
mPrintingSurface->GetType() == gfxASurface::SurfaceTypeQuartz)) {
dpi = 72;
dotsArePixels = PR_FALSE;
} else {
@ -700,7 +700,7 @@ nsThebesDeviceContext::CalcPrintingSize()
#endif
#ifdef XP_MACOSX
case gfxASurface::SurfaceTypeQuartz2:
case gfxASurface::SurfaceTypeQuartz:
inPoints = PR_TRUE; // this is really only true when we're printing
size = reinterpret_cast<gfxQuartzSurface*>(mPrintingSurface.get())->GetSize();
break;

Просмотреть файл

@ -81,7 +81,6 @@ public:
SurfaceTypeBeOS,
SurfaceTypeDirectFB,
SurfaceTypeSVG,
SurfaceTypeQuartz2,
SurfaceTypeOS2
} gfxSurfaceType;

Просмотреть файл

@ -46,7 +46,7 @@
class THEBES_API gfxQuartzSurface : public gfxASurface {
public:
gfxQuartzSurface(const gfxSize& size, gfxImageFormat format);
gfxQuartzSurface(CGContextRef context, PRBool y_grows_down, const gfxSize& size);
gfxQuartzSurface(CGContextRef context, const gfxSize& size);
gfxQuartzSurface(cairo_surface_t *csurf);
virtual ~gfxQuartzSurface();

Просмотреть файл

@ -50,7 +50,7 @@
#include "gfxXlibSurface.h"
#endif
#ifdef CAIRO_HAS_NQUARTZ_SURFACE
#ifdef CAIRO_HAS_QUARTZ_SURFACE
#include "gfxQuartzSurface.h"
#endif
@ -139,8 +139,8 @@ gfxASurface::Wrap (cairo_surface_t *csurf)
result = new gfxXlibSurface(csurf);
}
#endif
#ifdef CAIRO_HAS_NQUARTZ_SURFACE
else if (stype == CAIRO_SURFACE_TYPE_NQUARTZ) {
#ifdef CAIRO_HAS_QUARTZ_SURFACE
else if (stype == CAIRO_SURFACE_TYPE_QUARTZ) {
result = new gfxQuartzSurface(csurf);
}
#endif

Просмотреть файл

@ -108,12 +108,60 @@ gfxMatrix::Transform(const gfxRect& rect) const
gfxRect
gfxMatrix::TransformBounds(const gfxRect& rect) const
{
double x0 = rect.pos.x;
double y0 = rect.pos.y;
double x1 = rect.pos.x + rect.size.width;
double y1 = rect.pos.y + rect.size.height;
/* Code taken from cairo-matrix.c, _cairo_matrix_transform_bounding_box isn't public */
int i;
double quad_x[4], quad_y[4];
double min_x, max_x;
double min_y, max_y;
cairo_matrix_transform_bounding_box(CONST_CAIRO_MATRIX(this), &x0, &y0, &x1, &y1, NULL);
quad_x[0] = rect.pos.x;
quad_y[0] = rect.pos.y;
cairo_matrix_transform_point (CONST_CAIRO_MATRIX(this), &quad_x[0], &quad_y[0]);
return gfxRect(x0, y0, x1 - x0, y1 - y0);
quad_x[1] = rect.pos.x + rect.size.width;
quad_y[1] = rect.pos.y;
cairo_matrix_transform_point (CONST_CAIRO_MATRIX(this), &quad_x[1], &quad_y[1]);
quad_x[2] = rect.pos.x;
quad_y[2] = rect.pos.y + rect.size.height;
cairo_matrix_transform_point (CONST_CAIRO_MATRIX(this), &quad_x[2], &quad_y[2]);
quad_x[3] = rect.pos.x + rect.size.width;
quad_y[3] = rect.pos.y + rect.size.height;
cairo_matrix_transform_point (CONST_CAIRO_MATRIX(this), &quad_x[3], &quad_y[3]);
min_x = max_x = quad_x[0];
min_y = max_y = quad_y[0];
for (i = 1; i < 4; i++) {
if (quad_x[i] < min_x)
min_x = quad_x[i];
if (quad_x[i] > max_x)
max_x = quad_x[i];
if (quad_y[i] < min_y)
min_y = quad_y[i];
if (quad_y[i] > max_y)
max_y = quad_y[i];
}
// we don't compute this now
#if 0
if (is_tight) {
/* it's tight if and only if the four corner points form an axis-aligned
rectangle.
And that's true if and only if we can derive corners 0 and 3 from
corners 1 and 2 in one of two straightforward ways...
We could use a tolerance here but for now we'll fall back to FALSE in the case
of floating point error.
*/
*is_tight =
(quad_x[1] == quad_x[0] && quad_y[1] == quad_y[3] &&
quad_x[2] == quad_x[3] && quad_y[2] == quad_y[0]) ||
(quad_x[1] == quad_x[3] && quad_y[1] == quad_y[0] &&
quad_x[2] == quad_x[0] && quad_y[2] == quad_y[3]);
}
#endif
return gfxRect(min_x, min_y, max_x - min_x, max_y - min_y);
}

Просмотреть файл

@ -37,7 +37,7 @@
#include "gfxQuartzPDFSurface.h"
#include "cairo-nquartz.h"
#include "cairo-quartz.h"
gfxQuartzPDFSurface::gfxQuartzPDFSurface(const char *filename, gfxSize aSizeInPoints)
{
@ -50,7 +50,7 @@ gfxQuartzPDFSurface::gfxQuartzPDFSurface(const char *filename, gfxSize aSizeInPo
CFRelease(file);
CFRelease(fileURL);
Init(cairo_nquartz_surface_create_for_cg_context(mCGContext, aSizeInPoints.width, aSizeInPoints.height, PR_FALSE));
Init(cairo_quartz_surface_create_for_cg_context(mCGContext, aSizeInPoints.width, aSizeInPoints.height));
}
gfxQuartzPDFSurface::~gfxQuartzPDFSurface()

Просмотреть файл

@ -37,15 +37,15 @@
#include "gfxQuartzSurface.h"
#include "cairo-nquartz.h"
#include "cairo-quartz.h"
gfxQuartzSurface::gfxQuartzSurface(const gfxSize& size, gfxImageFormat format)
: mSize(size)
{
cairo_surface_t *surf = cairo_nquartz_surface_create
cairo_surface_t *surf = cairo_quartz_surface_create
((cairo_format_t) format, floor(size.width), floor(size.height));
mCGContext = cairo_nquartz_surface_get_cg_context (surf);
mCGContext = cairo_quartz_surface_get_cg_context (surf);
CGContextRetain(mCGContext);
@ -53,15 +53,13 @@ gfxQuartzSurface::gfxQuartzSurface(const gfxSize& size, gfxImageFormat format)
}
gfxQuartzSurface::gfxQuartzSurface(CGContextRef context,
PRBool y_grows_down,
const gfxSize& size)
: mCGContext(context), mSize(size)
{
cairo_surface_t *surf =
cairo_nquartz_surface_create_for_cg_context(context,
floor(size.width),
floor(size.height),
y_grows_down);
cairo_quartz_surface_create_for_cg_context(context,
floor(size.width),
floor(size.height));
CGContextRetain(mCGContext);
@ -71,7 +69,7 @@ gfxQuartzSurface::gfxQuartzSurface(CGContextRef context,
gfxQuartzSurface::gfxQuartzSurface(cairo_surface_t *csurf) :
mSize(-1.0, -1.0)
{
mCGContext = cairo_nquartz_surface_get_cg_context (csurf);
mCGContext = cairo_quartz_surface_get_cg_context (csurf);
CGContextRetain (mCGContext);
Init(csurf, PR_TRUE);

Просмотреть файл

@ -2154,7 +2154,7 @@ NSEvent* globalDragEvent = nil;
NSRect bounds = [self bounds];
nsRefPtr<gfxQuartzSurface> targetSurface =
new gfxQuartzSurface(cgContext, PR_TRUE, gfxSize(bounds.size.width, bounds.size.height));
new gfxQuartzSurface(cgContext, gfxSize(bounds.size.width, bounds.size.height));
#ifdef DEBUG_UPDATE
fprintf (stderr, "---- Update[%p][%p] [%f %f %f %f] cgc: %p\n gecko bounds: [%d %d %d %d]\n",

Просмотреть файл

@ -268,10 +268,13 @@ NS_IMETHODIMP nsDeviceContextSpecX::GetSurfaceForPrinter(gfxASurface **surface)
nsRefPtr<gfxASurface> newSurface;
if (context)
newSurface = new gfxQuartzSurface(context, PR_FALSE, gfxSize(width, height));
else
if (context) {
CGContextTranslateCTM(context, 0.0, height);
CGContextScaleCTM(context, 1.0, -1.0);
newSurface = new gfxQuartzSurface(context, gfxSize(width, height));
} else {
newSurface = new gfxQuartzSurface(gfxSize((PRInt32)width, (PRInt32)height), gfxASurface::ImageFormatARGB32);
}
if (!newSurface)
return NS_ERROR_FAILURE;

Просмотреть файл

@ -322,8 +322,8 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsIRenderingContext* aContext, nsIFrame
double offsetX = 0.0, offsetY = 0.0;
nsRefPtr<gfxASurface> thebesSurface = thebesCtx->CurrentSurface(&offsetX, &offsetY);
if (thebesSurface->GetType() != gfxASurface::SurfaceTypeQuartz2) {
fprintf(stderr, "Expected surface of type Quartz2, got %d\n",
if (thebesSurface->GetType() != gfxASurface::SurfaceTypeQuartz) {
fprintf(stderr, "Expected surface of type Quartz, got %d\n",
thebesSurface->GetType());
return NS_ERROR_FAILURE;
}