--- a/configure.in
+++ b/configure.in
@@ -7243,17 +7243,16 @@ if test "$MOZ_SVG" -o "$MOZ_ENABLE_CANVA
PS_SURFACE_FEATURE="#define CAIRO_HAS_PS_SURFACE 1"
PDF_SURFACE_FEATURE="#define CAIRO_HAS_PDF_SURFACE 1"
FT_FONT_FEATURE="#define CAIRO_HAS_FT_FONT 1"
MOZ_ENABLE_CAIRO_FT=1
CAIRO_FT_CFLAGS="$FT2_CFLAGS"
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
WIN32_SURFACE_FEATURE="#define CAIRO_HAS_WIN32_SURFACE 1"
WIN32_FONT_FEATURE="#define CAIRO_HAS_WIN32_FONT 1"
PDF_SURFACE_FEATURE="#define CAIRO_HAS_PDF_SURFACE 1"
fi
if test "$MOZ_WIDGET_TOOLKIT" = "os2"; then
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -2,15 +2,25 @@ Snapshots of cairo and glitz for mozilla
We only include the relevant parts of each release (generally, src/*.[ch]),
as we have Makefile.in's that integrate into the Mozilla build system. For
documentation and similar, please see the official tarballs at
http://www.cairographics.org/.
VERSIONS:
- cairo (1.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
+
--- a/gfx/cairo/cairo/src/Makefile.in
+++ b/gfx/cairo/cairo/src/Makefile.in
@@ -124,21 +124,16 @@ endif
ifeq ($(MOZ_WIDGET_TOOLKIT),os2)
CSRCS += cairo-os2-surface.c
EXPORTS += cairo-os2.h cairo-os2-private.h
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)
CPPSRCS += cairo-beos-surface.cpp
EXPORTS += cairo-beos.h
endif
ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
--- a/gfx/cairo/cairo/src/cairo-analysis-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-analysis-surface-private.h
@@ -1,9 +1,9 @@
-/* $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
*
* 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
--- a/gfx/cairo/cairo/src/cairo-atsui-font.c
+++ b/gfx/cairo/cairo/src/cairo-atsui-font.c
@@ -77,16 +77,19 @@ static cairo_status_t _cairo_atsui_font_
cairo_scaled_font_t **font_out);
struct _cairo_atsui_font {
cairo_scaled_font_t base;
ATSUStyle style;
ATSUStyle unscaled_style;
ATSUFontID fontID;
+
+ Fixed size;
+ CGAffineTransform font_matrix;
};
struct _cairo_atsui_font_face {
cairo_font_face_t base;
ATSUFontID font_id;
};
struct _cairo_atsui_scaled_path {
@@ -141,88 +144,37 @@ cairo_atsui_font_face_create_for_atsu_fo
font_face->font_id = font_id;
_cairo_font_face_init (&font_face->base, &_cairo_atsui_font_face_backend);
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)
{
return CGAffineTransformMake(scale->xx, scale->yx,
scale->xy, scale->yy,
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);
err = ATSUSetAttributes(style,
sizeof(theFontStyleTags) /
sizeof(ATSUAttributeTag), theFontStyleTags,
theFontStyleSizes, theFontStyleValues);
@@ -268,25 +220,34 @@ static cairo_status_t
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
cairo_scaled_font_t **font_out)
{
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)
return CAIRO_STATUS_NO_MEMORY;
_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);
const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag };
const ByteCount theFontStyleSizes[] = { sizeof(Fixed) };
ATSUAttributeValuePtr theFontStyleValues[] = { &theSize };
err = ATSUSetAttributes(style,
@@ -475,40 +436,55 @@ static
OSStatus _close_path_for_metrics(void *callback_data)
{
CGMutablePathRef path = callback_data;
CGPathCloseSubpath (path);
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;
static ATSCubicLineToUPP lineProc = NULL;
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.
*/
err = ATSUGlyphGetScreenMetrics (scaled_font->style,
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,
&xscale, &yscale, 1);
xscale = 1.0/xscale;
yscale = 1.0/yscale;
extents.x_advance = metricsH.deviceAdvance.x * xscale;
@@ -527,21 +503,18 @@ static cairo_status_t
* Its only meaningful if err != noErr, and we don't currently
* use it for anything.
*/
err = ATSUGlyphGetCubicPaths (scaled_font->style, theGlyph,
moveProc, lineProc, curveProc, closePathProc,
(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);
extents.x_bearing = rect.origin.x * xscale;
extents.y_bearing = rect.origin.y * yscale;
extents.width = rect.size.width * xscale;
extents.height = rect.size.height * yscale;
@@ -631,46 +604,55 @@ static OSStatus
static cairo_status_t
_cairo_atsui_scaled_font_init_glyph_path (cairo_atsui_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph)
{
static ATSCubicMoveToUPP moveProc = NULL;
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;
cairo_matrix_t unscaled_font_to_device;
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,
font_to_device->xx,
font_to_device->yx,
font_to_device->xy,
font_to_device->yy, 0., 0.);
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);
lineProc = NewATSCubicLineToUPP(_line_to);
curveProc = NewATSCubicCurveToUPP(_curve_to);
closePathProc = NewATSCubicClosePathUPP(_close_path);
}
err = ATSUGlyphGetCubicPaths(scaled_font->style,
- _cairo_scaled_glyph_index (scaled_glyph),
+ theGlyph,
moveProc,
lineProc,
curveProc,
closePathProc, (void *)&scaled_path, &err);
_cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base,
scaled_path.path);
@@ -686,24 +668,34 @@ static cairo_status_t
cairo_image_surface_t *surface;
cairo_format_t format;
ATSFontRef atsFont;
CGFontRef cgFont;
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;
CGRect bbox;
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.
*/
height = extents.ascent + extents.descent + 2.0;
bottom = -extents.descent - 1.0;
/* Horizontal sizes come from the glyph typographic metrics.
@@ -749,20 +741,33 @@ static cairo_status_t
/* XXX should we select format based on antialiasing flags, as ft does? */
format = CAIRO_FORMAT_A8;
/* create the glyph mask surface */
surface = (cairo_image_surface_t *)cairo_image_surface_create (format, bbox.size.width, bbox.size.height);
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);
cgFont = CGFontCreateWithPlatformFont (&atsFont);
CGContextSetFont (drawingContext, cgFont);
if (base.options.antialias == CAIRO_ANTIALIAS_NONE) {
@@ -834,16 +839,19 @@ static cairo_int_status_t
uint16_t *utf16;
int n16;
OSStatus err;
ATSUTextLayout textLayout;
ATSLayoutRecord *layoutRecords;
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)
return status;
err = ATSUCreateTextLayout(&textLayout);
err = ATSUSetTextPointerLocation(textLayout, utf16, 0, n16, n16);
@@ -860,202 +868,85 @@ static cairo_int_status_t
*num_glyphs = glyphCount - 1;
*glyphs =
(cairo_glyph_t *) malloc(*num_glyphs * (sizeof (cairo_glyph_t)));
if (*glyphs == NULL) {
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;
}
free (utf16);
ATSUDirectReleaseLayoutDataArrayPtr(NULL,
kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
(void *) &layoutRecords);
ATSUDisposeTextLayout(textLayout);
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)
{
cairo_atsui_font_t *afont = (cairo_atsui_font_t *) sfont;
return afont->style;
}
ATSUFontID
_cairo_atsui_scaled_font_get_atsu_font_id (cairo_scaled_font_t *sfont)
{
cairo_atsui_font_t *afont = (cairo_atsui_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,
_cairo_atsui_font_fini,
_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 */
};
--- a/gfx/cairo/cairo/src/cairo-bentley-ottmann.c
+++ b/gfx/cairo/cairo/src/cairo-bentley-ottmann.c
@@ -116,27 +116,27 @@ typedef struct _cairo_bo_event {
cairo_bo_edge_t *e2;
cairo_bo_point32_t point;
skip_elt_t elt;
} cairo_bo_event_t;
#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;
unsigned next_startstop_event_index;
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;
} cairo_bo_sweep_line_t;
static inline int
_cairo_bo_point32_compare (cairo_bo_point32_t const *a,
cairo_bo_point32_t const *b)
@@ -692,26 +692,26 @@ static void
event->point = point;
}
static void
_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);
}
static void
_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 *
_cairo_bo_event_dequeue (cairo_bo_event_queue_t *event_queue)
{
skip_elt_t *elt = event_queue->intersection_queue.chains[0];
cairo_bo_event_t *intersection = elt ? SKIP_ELT_TO_EVENT (elt) : NULL;
cairo_bo_event_t *startstop;
@@ -735,17 +735,17 @@ static cairo_status_t
int num_edges)
{
int i;
cairo_bo_event_t *events, **sorted_event_ptrs;
unsigned num_events = 2*num_edges;
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)
return CAIRO_STATUS_SUCCESS;
/* The skip_elt_t field of a cairo_bo_event_t isn't used for start
* or stop events, so this allocation is safe. XXX: make the
* event type a union so it doesn't always contain the skip
@@ -784,17 +784,17 @@ static cairo_status_t
sizeof(cairo_bo_event_t *),
cairo_bo_event_compare_pointers);
return CAIRO_STATUS_SUCCESS;
}
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)
free (event_queue->sorted_startstop_event_ptrs);
}
static void
_cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_t *event_queue,
@@ -829,39 +829,39 @@ static void
intersection);
_cairo_bo_event_queue_insert (event_queue, &event);
}
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;
sweep_line->tail = NULL;
sweep_line->current_y = 0;
}
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
_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge)
{
skip_elt_t *next_elt;
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];
if (next_elt)
prev_of_next = & (SKIP_ELT_TO_EDGE (next_elt)->prev);
else
prev_of_next = &sweep_line->tail;
@@ -879,17 +879,17 @@ static void
}
static void
_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge)
{
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)
left_next = &edge->prev->next;
right_prev = &sweep_line->tail;
if (edge->next)
right_prev = &edge->next->prev;
@@ -970,17 +970,17 @@ static void
printf ("\n");
}
static void
_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");
for (elt = queue->chains[0];
elt;
elt = elt->next[0])
{
@@ -1762,17 +1762,17 @@ run_test (const char *test_name,
}
#define MAX_RANDOM 300
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;
for (i = 0; i < sizeof (tests) / sizeof (tests[0]); i++) {
test = &tests[i];
run_test (test->name, test->edges, test->num_edges);
}
--- a/gfx/cairo/cairo/src/cairo-cff-subset.c
+++ b/gfx/cairo/cairo/src/cairo-cff-subset.c
@@ -26,16 +26,17 @@
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Adrian Johnson.
*
* Contributor(s):
* Adrian Johnson <ajohnson@redneon.com>
+ * Eugeniy Meshcheryakov <eugen@debian.org>
*/
#include "cairoint.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-truetype-subset-private.h"
/* CFF Dict Operators. If the high byte is 0 the command is encoded
* with a single byte. */
@@ -76,16 +77,23 @@ typedef struct _cff_dict_operator {
cairo_hash_entry_t base;
unsigned short operator;
unsigned char *operand;
int operand_length;
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;
const cairo_scaled_font_backend_t *backend;
/* Font Data */
unsigned char *data;
unsigned long data_length;
@@ -95,58 +103,33 @@ typedef struct _cairo_cff_font {
char *font_name;
cairo_hash_table_t *top_dict;
cairo_hash_table_t *private_dict;
cairo_array_t strings_index;
cairo_array_t charstrings_index;
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 */
int *widths;
int x_min, y_min, x_max, y_max;
int ascent, descent;
} 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 *
encode_integer_max (unsigned char *p, int i)
{
*p++ = 29;
*p++ = i >> 24;
*p++ = (i >> 16) & 0xff;
@@ -500,30 +483,16 @@ cff_dict_read (cairo_hash_table_t *dict,
}
fail:
_cairo_array_fini (&operands);
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,
int *size)
{
cff_dict_operator_t key, *op;
_cairo_dict_init_key (&key, operator);
@@ -737,22 +706,29 @@ cairo_cff_font_read_top_dict (cairo_cff_
goto fail;
font->num_glyphs = _cairo_array_num_elements (&font->charstrings_index);
operand = cff_dict_get_operands (font->top_dict, PRIVATE_OP, &size);
operand = decode_integer (operand, &size);
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);
fail:
cff_index_fini (&index);
return status;
@@ -765,25 +741,159 @@ cairo_cff_font_read_strings (cairo_cff_f
}
static cairo_int_status_t
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);
static const font_read_t font_read_funcs[] = {
cairo_cff_font_read_header,
cairo_cff_font_read_name,
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
cairo_cff_font_read_font (cairo_cff_font_t *font)
{
cairo_int_status_t status;
unsigned int i;
@@ -893,28 +1003,106 @@ cairo_cff_font_subset_charstrings (cairo
element->length);
if (status)
return status;
}
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)
{
cairo_status_t status;
/* TODO: subset subroutines */
status = cairo_cff_font_subset_strings (font);
if (status)
return status;
status = cairo_cff_font_subset_charstrings (font);
+ if (status)
+ return status;
+
+ status = cairo_cff_font_subset_charset (font);
return status;
}
/* Set the operand of the specified operator in the (already written)
* top dict to point to the current position in the output
* array. Operands updated with this function must have previously
* been encoded with the 5-byte (max) integer encoding. */
@@ -1034,16 +1222,37 @@ cairo_cff_font_write_encoding (cairo_cff
buf[2] = 0; /* First code in range */
/* Codes left in range excluding first */
buf[3] = font->scaled_font_subset->num_glyphs - 1;
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)
{
cairo_cff_font_set_topdict_operator_to_cur_pos (font, CHARSTRINGS_OP);
return cff_index_write (&font->charstrings_subset_index, &font->output);
}
static cairo_status_t
@@ -1093,16 +1302,17 @@ typedef cairo_status_t
static const font_write_t font_write_funcs[] = {
cairo_cff_font_write_header,
cairo_cff_font_write_name,
cairo_cff_font_write_top_dict,
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,
};
static cairo_status_t
cairo_cff_font_write_subset (cairo_cff_font_t *font)
{
cairo_int_status_t status;
@@ -1340,16 +1550,17 @@ static cairo_int_status_t
cff_dict_init (&font->top_dict);
cff_dict_init (&font->private_dict);
cff_index_init (&font->strings_index);
cff_index_init (&font->charstrings_index);
cff_index_init (&font->global_sub_index);
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;
return CAIRO_STATUS_SUCCESS;
fail7:
free (font->data);
@@ -1378,16 +1589,17 @@ cairo_cff_font_destroy (cairo_cff_font_t
cff_dict_fini (font->top_dict);
cff_dict_fini (font->private_dict);
cff_index_fini (&font->strings_index);
cff_index_fini (&font->charstrings_index);
cff_index_fini (&font->global_sub_index);
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);
}
cairo_status_t
_cairo_cff_subset_init (cairo_cff_subset_t *cff_subset,
const char *subset_name,
cairo_scaled_font_subset_t *font_subset)
{
--- a/gfx/cairo/cairo/src/cairo-clip.c
+++ b/gfx/cairo/cairo/src/cairo-clip.c
@@ -43,17 +43,20 @@ static cairo_clip_path_t *
_cairo_clip_path_reference (cairo_clip_path_t *clip_path);
static void
_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;
clip->surface_rect.y = 0;
clip->surface_rect.width = 0;
clip->surface_rect.height = 0;
clip->serial = 0;
--- a/gfx/cairo/cairo/src/cairo-color.c
+++ b/gfx/cairo/cairo/src/cairo-color.c
@@ -90,31 +90,32 @@ void
}
/* Convert a double in [0.0, 1.0] to an integer in [0, 65535]
* The conversion is designed to divide the input range into 65536
* equally-sized regions. This is achieved by multiplying by 65536 and
* 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);
i -= (i >> 16);
return i;
}
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
_cairo_color_init_rgba (cairo_color_t *color,
double red, double green, double blue,
double alpha)
{
color->red = red;
--- a/gfx/cairo/cairo/src/cairo-directfb-surface.c
+++ b/gfx/cairo/cairo/src/cairo-directfb-surface.c
@@ -47,19 +47,19 @@
#include <direct/memcpy.h>
#include <direct/util.h>
#include "cairo-directfb.h"
#include "cairoint.h"
/*
- * 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.
*/
#define DFB_COMPOSITE 1
/*
* CompositeTrapezoids works (without antialiasing).
--- a/gfx/cairo/cairo/src/cairo-directfb.h
+++ b/gfx/cairo/cairo/src/cairo-directfb.h
@@ -43,10 +43,13 @@
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
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*/
--- a/gfx/cairo/cairo/src/cairo-features.h.in
+++ b/gfx/cairo/cairo/src/cairo-features.h.in
@@ -47,33 +47,31 @@
# define CAIRO_END_DECLS
#endif
#ifndef cairo_public
# define cairo_public
#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@
@PDF_SURFACE_FEATURE@
@SVG_SURFACE_FEATURE@
@XLIB_SURFACE_FEATURE@
@QUARTZ_SURFACE_FEATURE@
-@NQUARTZ_SURFACE_FEATURE@
-
@XCB_SURFACE_FEATURE@
@WIN32_SURFACE_FEATURE@
@OS2_SURFACE_FEATURE@
@BEOS_SURFACE_FEATURE@
--- a/gfx/cairo/cairo/src/cairo-font.c
+++ b/gfx/cairo/cairo/src/cairo-font.c
@@ -1,8 +1,9 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
@@ -60,67 +61,78 @@ void
{
font_face->status = CAIRO_STATUS_SUCCESS;
font_face->ref_count = 1;
font_face->backend = backend;
_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 == NULL || font_face->ref_count == CAIRO_REF_COUNT_INVALID)
+ return font_face;
- if (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);
/**
* cairo_font_face_destroy:
* @font_face: a #cairo_font_face_t
*
* Decreases the reference count on @font_face by one. If the result
* is zero, then @font_face and all associated resources are freed.
* See 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);
/* We allow resurrection to deal with some memory management for the
* FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t
* need to effectively mutually reference each other
*/
if (font_face->ref_count > 0)
@@ -129,32 +141,52 @@ cairo_font_face_destroy (cairo_font_face
_cairo_user_data_array_fini (&font_face->user_data);
free (font_face);
}
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.
*
* Return value: The type of @font_face.
*
* Since: 1.2
**/
cairo_font_type_t
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
*
* Checks whether an error has previously occurred for this
* font face
*
* Return value: %CAIRO_STATUS_SUCCESS or another error such as
* %CAIRO_STATUS_NO_MEMORY.
@@ -221,45 +253,45 @@ static int
const void *key_b);
/* We maintain a hash table from family/weight/slant =>
* cairo_font_face_t for cairo_toy_font_t. The primary purpose of
* this mapping is to provide unique cairo_font_face_t values so that
* 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)
{
cairo_toy_font_face_hash_table =
_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;
}
}
return cairo_toy_font_face_hash_table;
}
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);
}
/**
* _cairo_toy_font_face_init_key:
*
* Initialize those portions of cairo_toy_font_face_t needed to use
* it as a hash table key, including the hash code buried away in
* font_face->base.hash_entry. No memory allocation is performed here
@@ -358,18 +390,21 @@ cairo_font_face_t *
_cairo_toy_font_face_init_key (&key, family, slant, weight);
/* Return existing font_face if it exists in the hash table. */
if (_cairo_hash_table_lookup (hash_table,
&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. */
font_face = malloc (sizeof (cairo_toy_font_face_t));
if (font_face == NULL)
goto UNWIND_HASH_TABLE_LOCK;
status = _cairo_toy_font_face_init (font_face, family, slant, weight);
@@ -466,13 +501,16 @@ void
free (unscaled_font);
}
void
_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);
}
--- a/gfx/cairo/cairo/src/cairo-ft-font.c
+++ b/gfx/cairo/cairo/src/cairo-ft-font.c
@@ -57,19 +57,21 @@
#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0)
#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0))
#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0)
/* This is the max number of FT_face objects we keep open at once
*/
#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
* factors so that hinting works right
*/
typedef struct _cairo_ft_font_transform {
double x_scale, y_scale;
@@ -99,17 +101,18 @@ struct _cairo_ft_unscaled_font {
cairo_bool_t have_scale;
cairo_matrix_t current_scale;
double x_scale; /* Extracted X scale factor */
double y_scale; /* Extracted Y scale factor */
cairo_bool_t have_shape; /* true if the current scale has a non-scale component*/
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 */
};
static int
_cairo_ft_unscaled_font_keys_equal (const void *key_a,
const void *key_b);
@@ -148,17 +151,17 @@ static const cairo_unscaled_font_backend
typedef struct _cairo_ft_unscaled_font_map {
cairo_hash_table_t *hash_table;
FT_Library ft_library;
int num_open_faces;
} cairo_ft_unscaled_font_map_t;
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,
cairo_ft_unscaled_font_t *unscaled)
{
if (unscaled->face) {
FT_Done_Face (unscaled->face);
unscaled->face = NULL;
@@ -206,17 +209,17 @@ FAIL:
}
static void
_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;
/* This is rather inefficient, but destroying the hash table
* is something we only do during debugging, (during
* cairo_debug_reset_static_data), when efficiency is not
* relevant. */
@@ -239,41 +242,41 @@ static void
_cairo_hash_table_destroy (font_map->hash_table);
free (font_map);
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;
}
}
return cairo_ft_unscaled_font_map;
}
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
_cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key,
char *filename,
int id)
{
unsigned long hash;
@@ -332,17 +335,18 @@ static cairo_status_t
filename_copy = strdup (filename);
if (filename_copy == NULL)
return CAIRO_STATUS_NO_MEMORY;
_cairo_ft_unscaled_font_init_key (unscaled, filename_copy, id);
}
unscaled->have_scale = FALSE;
- unscaled->lock = 0;
+ CAIRO_MUTEX_INIT (&unscaled->mutex);
+ unscaled->lock_count = 0;
unscaled->faces = NULL;
return CAIRO_STATUS_SUCCESS;
}
cairo_bool_t
_cairo_unscaled_font_is_ft (cairo_unscaled_font_t *unscaled_font)
@@ -365,16 +369,18 @@ static void
_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled)
{
assert (unscaled->face == NULL);
if (unscaled->filename) {
free (unscaled->filename);
unscaled->filename = NULL;
}
+
+ CAIRO_MUTEX_FINI (&unscaled->mutex);
}
static int
_cairo_ft_unscaled_font_keys_equal (const void *key_a,
const void *key_b)
{
const cairo_ft_unscaled_font_t *unscaled_a = key_a;
const cairo_ft_unscaled_font_t *unscaled_b = key_b;
@@ -496,81 +502,86 @@ static void
}
}
static cairo_bool_t
_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
* MAX_OPEN_FACES, try to close some.
*
* This differs from _cairo_ft_scaled_font_lock_face in that it doesn't
* set the scale on the face, but just returns it at the last scale.
*/
FT_Face
_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);
+ {
+ assert (font_map != NULL);
- while (font_map->num_open_faces >= MAX_OPEN_FACES)
- {
- cairo_ft_unscaled_font_t *entry;
+ while (font_map->num_open_faces >= MAX_OPEN_FACES)
+ {
+ cairo_ft_unscaled_font_t *entry;
- entry = _cairo_hash_table_random_entry (font_map->hash_table,
- _has_unlocked_face);
- if (entry == NULL)
- break;
+ 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);
+ _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);
/* Unlock unscaled font locked with _cairo_ft_unscaled_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);
static void
_compute_transform (cairo_ft_font_transform_t *sf,
cairo_matrix_t *scale)
{
cairo_matrix_t normalized = *scale;
@@ -642,29 +653,36 @@ static void
cairo_matrix_init (&unscaled->current_shape,
sf.shape[0][0], sf.shape[0][1],
sf.shape[1][0], sf.shape[1][1],
0.0, 0.0);
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) {
x_scale = MAX_FONT_SIZE;
}
if (y_scale > MAX_FONT_SIZE) {
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;
int i;
int best_i = 0;
for (i = 0; i < unscaled->face->num_fixed_sizes; i++) {
#if HAVE_FT_BITMAP_SIZE_Y_PPEM
@@ -1496,16 +1514,18 @@ static cairo_scaled_font_t *
} else {
fs_metrics.max_x_advance = 0;
fs_metrics.max_y_advance = face->max_advance_height / scale;
}
}
_cairo_scaled_font_set_metrics (&scaled_font->base, &fs_metrics);
+ _cairo_ft_unscaled_font_unlock_face (unscaled);
+
return &scaled_font->base;
}
cairo_bool_t
_cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font)
{
return scaled_font->backend == &cairo_ft_scaled_font_backend;
}
@@ -1775,20 +1795,23 @@ static cairo_int_status_t
FT_Face face;
FT_Error error;
int load_flags = scaled_font->ft_options.load_flags;
FT_Glyph_Metrics *metrics;
double x_factor, y_factor;
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;
if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0 &&
(info & CAIRO_SCALED_GLYPH_INFO_SURFACE) == 0)
load_flags |= FT_LOAD_NO_BITMAP;
/*
@@ -1818,16 +1841,18 @@ static cairo_int_status_t
if (scaled_font->ft_options.extra_flags & CAIRO_FT_OPTIONS_EMBOLDEN)
FT_GlyphSlot_Embolden (glyph);
#endif
if (vertical_layout)
_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
*/
metrics = &glyph->metrics;
if (unscaled->x_scale == 0)
x_factor = 0;
else
@@ -1843,18 +1868,17 @@ static cairo_int_status_t
*
* Scale metrics back to glyph space from the scaled glyph space returned
* by FreeType
*
* If we want hinted metrics but aren't asking for hinted glyphs from
* 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;
FT_Pos advance;
if (!vertical_layout) {
x1 = (metrics->horiBearingX) & -64;
x2 = (metrics->horiBearingX + metrics->width + 63) & -64;
@@ -1891,24 +1915,30 @@ static cairo_int_status_t
} else {
fs_metrics.width = DOUBLE_FROM_26_6 (metrics->width) * x_factor;
fs_metrics.height = DOUBLE_FROM_26_6 (metrics->height) * y_factor;
if (!vertical_layout) {
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;
}
}
_cairo_scaled_glyph_set_metrics (scaled_glyph,
&scaled_font->base,
&fs_metrics);
}
@@ -1941,17 +1971,17 @@ static cairo_int_status_t
* so reload it. This will probably never occur though
*/
if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0) {
error = FT_Load_Glyph (face,
_cairo_scaled_glyph_index(scaled_glyph),
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
/*
* embolden glyphs if requested
*/
if (scaled_font->ft_options.extra_flags & CAIRO_FT_OPTIONS_EMBOLDEN)
FT_GlyphSlot_Embolden (glyph);
@@ -1969,17 +1999,17 @@ static cairo_int_status_t
if (status)
goto FAIL;
_cairo_scaled_glyph_set_path (scaled_glyph,
&scaled_font->base,
path);
}
FAIL:
- cairo_ft_scaled_font_unlock_face (abstract_font);
+ _cairo_ft_unscaled_font_unlock_face (unscaled);
return status;
}
static unsigned long
_cairo_ft_ucs4_to_index (void *abstract_font,
uint32_t ucs4)
{
@@ -2021,25 +2051,58 @@ static cairo_int_status_t
status = CAIRO_STATUS_SUCCESS;
_cairo_ft_unscaled_font_unlock_face (unscaled);
#endif
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,
_cairo_ft_scaled_font_fini,
_cairo_ft_scaled_glyph_init,
NULL, /* text_to_glyphs */
_cairo_ft_ucs4_to_index,
NULL, /* show_glyphs */
_cairo_ft_load_truetype_table,
+ _cairo_ft_map_glyphs_to_unicode,
};
/* cairo_ft_font_face_t */
static void
_cairo_ft_font_face_destroy (void *abstract_face)
{
cairo_ft_font_face_t *font_face = abstract_face;
@@ -2387,23 +2450,24 @@ cairo_ft_font_face_create_for_ft_face (F
* when you are done using it. Since the #FT_Face object can be
* shared between multiple #cairo_scaled_font_t objects, you must not
* lock any other font objects until you unlock this one. A count is
* kept of the number of times cairo_ft_font_lock_face() is
* called. cairo_ft_font_unlock_face() must be called the same number
* 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.
**/
FT_Face
cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font)
{
cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
@@ -2416,16 +2480,24 @@ cairo_ft_scaled_font_lock_face (cairo_sc
if (face == NULL) {
_cairo_scaled_font_set_error (&scaled_font->base, CAIRO_STATUS_NO_MEMORY);
return NULL;
}
_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;
}
/**
* cairo_ft_scaled_font_unlock_face:
* @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an
* object can be created by calling cairo_scaled_font_create() on a
* FreeType backend font face (see cairo_ft_font_face_create_for_pattern(),
@@ -2436,16 +2508,22 @@ cairo_ft_scaled_font_lock_face (cairo_sc
void
cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *abstract_font)
{
cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
if (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);
}
/* We expose our unscaled font implementation internally for the the
* PDF backend, which needs to keep track of the the different
* fonts-on-disk used by a document, so it can embed them.
*/
cairo_unscaled_font_t *
--- a/gfx/cairo/cairo/src/cairo-glitz-surface.c
+++ b/gfx/cairo/cairo/src/cairo-glitz-surface.c
@@ -589,17 +589,17 @@ static cairo_int_status_t
cairo_gradient_pattern_t *gradient =
(cairo_gradient_pattern_t *) pattern;
char *data;
glitz_fixed16_16_t *params;
int n_params;
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,
0xff000000,
0x00ff0000,
0x0000ff00,
0x000000ff
},
@@ -681,22 +681,22 @@ static cairo_int_status_t
params[2] = grad->gradient.p2.x;
params[3] = grad->gradient.p2.y;
attr->filter = GLITZ_FILTER_LINEAR_GRADIENT;
}
else
{
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;
}
switch (pattern->extend) {
case CAIRO_EXTEND_NONE:
attr->fill = GLITZ_FILL_TRANSPARENT;
break;
case CAIRO_EXTEND_REPEAT:
@@ -971,17 +971,17 @@ static cairo_int_status_t
glitz_color.green = color->green_short;
glitz_color.blue = color->blue_short;
glitz_color.alpha = color->alpha_short;
glitz_set_rectangles (dst->surface, &glitz_color,
(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);
} break;
case CAIRO_OPERATOR_SATURATE:
return CAIRO_INT_STATUS_UNSUPPORTED;
case CAIRO_OPERATOR_OVER:
case CAIRO_OPERATOR_IN:
@@ -1090,17 +1090,17 @@ static cairo_int_status_t
}
alpha = 0xffff;
if (status)
return status;
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;
int offset = 0;
int data_size = 0;
int size = 30 * n_traps; /* just a guess */
format.vertex.primitive = GLITZ_PRIMITIVE_QUADS;
@@ -1936,17 +1936,17 @@ static cairo_int_status_t
glitz_float_t stack_vertices[N_STACK_BUF * 16];
glitz_float_t *vertices;
glitz_buffer_t *buffer;
cairo_int_status_t status;
int x_offset, y_offset;
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,
GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK,
{ 0 },
{
GLITZ_DATA_TYPE_FLOAT,
GLITZ_COORDINATE_SIZE_XY,
--- a/gfx/cairo/cairo/src/cairo-gstate.c
+++ b/gfx/cairo/cairo/src/cairo-gstate.c
@@ -38,74 +38,34 @@
#include <stdlib.h>
#include "cairoint.h"
#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);
static cairo_status_t
_cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate);
static void
_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate);
static void
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_glyph_t *transformed_glyphs);
-/**
- * _cairo_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)
{
gstate->op = CAIRO_GSTATE_OPERATOR_DEFAULT;
gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
gstate->antialias = CAIRO_ANTIALIAS_DEFAULT;
@@ -184,17 +144,17 @@ static cairo_status_t
gstate->source = cairo_pattern_reference (other->source);
gstate->next = NULL;
return CAIRO_STATUS_SUCCESS;
}
-static void
+void
_cairo_gstate_fini (cairo_gstate_t *gstate)
{
_cairo_stroke_style_fini (&gstate->stroke_style);
cairo_font_face_destroy (gstate->font_face);
gstate->font_face = NULL;
cairo_scaled_font_destroy (gstate->scaled_font);
@@ -717,18 +677,18 @@ void
double *x1, double *y1,
double *x2, double *y2,
cairo_bool_t *is_tight)
{
cairo_matrix_t matrix_inverse;
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
cairo_status_t
_cairo_gstate_stroke_to_path (cairo_gstate_t *gstate)
{
cairo_status_t status;
@@ -950,16 +910,21 @@ cairo_status_t
cairo_path_fixed_t *path,
double x,
double y,
cairo_bool_t *inside_ret)
{
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);
status = _cairo_path_fixed_stroke_to_traps (path,
&gstate->stroke_style,
&gstate->ctm,
&gstate->ctm_inverse,
@@ -1068,36 +1033,59 @@ static void
double *x2, double *y2)
{
cairo_box_t extents;
_cairo_traps_extents (traps, &extents);
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);
}
}
cairo_status_t
_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
{
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,
&gstate->stroke_style,
&gstate->ctm,
&gstate->ctm_inverse,
gstate->tolerance,
&traps);
@@ -1160,21 +1148,25 @@ cairo_status_t
status = _cairo_surface_get_extents (gstate->target, &extents);
if (status)
return status;
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);
return CAIRO_STATUS_SUCCESS;
}
cairo_rectangle_list_t*
_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate)
@@ -1266,16 +1258,31 @@ cairo_status_t
if (status)
return status;
*font_face = gstate->font_face;
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.
*
* The user's view
* ---------------
*
* Users ask for things in user space. When cairo starts, a user space unit
--- a/gfx/cairo/cairo/src/cairo-image-surface.c
+++ b/gfx/cairo/cairo/src/cairo-image-surface.c
@@ -1111,16 +1111,17 @@ cairo_image_surface_t *
cairo_image_surface_t *clone;
cairo_t *cr;
double x, y;
clone = (cairo_image_surface_t *)
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);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
cairo_destroy (cr);
cairo_surface_set_device_offset (&clone->base, x, y);
--- a/gfx/cairo/cairo/src/cairo-matrix.c
+++ b/gfx/cairo/cairo/src/cairo-matrix.c
@@ -351,20 +351,20 @@ cairo_matrix_transform_point (const cair
cairo_matrix_transform_distance (matrix, x, y);
*x += matrix->x0;
*y += matrix->y0;
}
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];
double min_x, max_x;
double min_y, max_y;
quad_x[0] = *x1;
quad_y[0] = *y1;
@@ -412,17 +412,16 @@ cairo_matrix_transform_bounding_box (con
*/
*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]);
}
}
-slim_hidden_def(cairo_matrix_transform_bounding_box);
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
{
matrix->xx *= scalar;
matrix->yx *= scalar;
matrix->xy *= scalar;
deleted file mode 100644
--- a/gfx/cairo/cairo/src/cairo-nquartz-surface.c
+++ /dev/null
@@ -1,1866 +0,0 @@
-/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2006 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>
- */
-
-#include <Carbon/Carbon.h>
-
-#ifdef CAIRO_NQUARTZ_SUPPORT_AGL
-#include <AGL/agl.h>
-#include <OpenGL/gl.h>
-#endif
-
-#include "cairoint.h"
-#include "cairo-private.h"
-#include "cairo-nquartz.h"
-
-#include "cairo-quartz-private.h"
-
-#undef NQUARTZ_DEBUG
-
-#ifdef NQUARTZ_DEBUG
-#define ND(_x) fprintf _x
-#else
-#define ND(_x) do {} while(0)
-#endif
-
-/* This method is private, but it exists. Its params are are exposed
- * as args to the NS* method, but not as CG.
- */
-enum PrivateCGCompositeMode {
- kPrivateCGCompositeClear = 0,
- kPrivateCGCompositeCopy = 1,
- kPrivateCGCompositeSourceOver = 2,
- kPrivateCGCompositeSourceIn = 3,
- kPrivateCGCompositeSourceOut = 4,
- kPrivateCGCompositeSourceAtop = 5,
- kPrivateCGCompositeDestinationOver = 6,
- kPrivateCGCompositeDestinationIn = 7,
- kPrivateCGCompositeDestinationOut = 8,
- kPrivateCGCompositeDestinationAtop = 9,
- kPrivateCGCompositeXOR = 10,
- kPrivateCGCompositePlusDarker = 11, // (max (0, (1-d) + (1-s)))
- kPrivateCGCompositePlusLighter = 12, // (min (1, s + d))
-};
-typedef enum PrivateCGCompositeMode PrivateCGCompositeMode;
-CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode);
-CG_EXTERN void CGContextResetCTM (CGContextRef);
-CG_EXTERN void CGContextSetCTM (CGContextRef, CGAffineTransform);
-CG_EXTERN void CGContextResetClip (CGContextRef);
-CG_EXTERN CGSize CGContextGetPatternPhase (CGContextRef);
-
-/* We need to work with the 10.3 SDK as well (and 10.3 machines; luckily, 10.3.9
- * has all the stuff we care about, just some of it isn't exported in the SDK.
- */
-#ifndef kCGBitmapByteOrder32Host
-#define USE_10_3_WORKAROUNDS
-#define kCGBitmapAlphaInfoMask 0x1F
-#define kCGBitmapByteOrderMask 0x7000
-#define kCGBitmapByteOrder32Host 0
-
-typedef uint32_t CGBitmapInfo;
-
-/* public in 10.4, present in 10.3.9 */
-CG_EXTERN void CGContextReplacePathWithStrokedPath (CGContextRef);
-CG_EXTERN CGImageRef CGBitmapContextCreateImage (CGContextRef);
-#endif
-
-
-typedef struct cairo_nquartz_surface {
- cairo_surface_t base;
-
- void *imageData;
-
- CGContextRef cgContext;
- CGAffineTransform cgContextBaseCTM;
-
- cairo_rectangle_int16_t extents;
-
- /* These are stored while drawing operations are in place, set up
- * by nquartz_setup_source() and nquartz_finish_source()
- */
- CGAffineTransform imageTransform;
- CGImageRef sourceImage;
- CGShadingRef sourceShading;
- CGPatternRef sourcePattern;
-#ifdef CAIRO_NQUARTZ_SUPPORT_AGL
- AGLContext aglContext;
-#else
- void *_unused;
-#endif
-} cairo_nquartz_surface_t;
-
-/**
- ** Utility functions
- **/
-
-void nquartz_surface_to_png (cairo_nquartz_surface_t *nq, char *dest);
-void nquartz_image_to_png (CGImageRef, char *dest);
-
-/*
- * Cairo path -> Quartz path conversion helpers
- */
-
-/* cairo path -> mutable path */
-static cairo_status_t
-_cairo_path_to_quartz_path_move_to (void *closure, cairo_point_t *point)
-{
- CGPathMoveToPoint ((CGMutablePathRef) closure, NULL,
- _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y));
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_to_quartz_path_line_to (void *closure, cairo_point_t *point)
-{
- CGPathAddLineToPoint ((CGMutablePathRef) closure, NULL,
- _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y));
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_to_quartz_path_curve_to (void *closure, cairo_point_t *p0, cairo_point_t *p1, cairo_point_t *p2)
-{
- CGPathAddCurveToPoint ((CGMutablePathRef) closure, NULL,
- _cairo_fixed_to_double(p0->x), _cairo_fixed_to_double(p0->y),
- _cairo_fixed_to_double(p1->x), _cairo_fixed_to_double(p1->y),
- _cairo_fixed_to_double(p2->x), _cairo_fixed_to_double(p2->y));
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_to_quartz_path_close_path (void *closure)
-{
- CGPathCloseSubpath ((CGMutablePathRef) closure);
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* cairo path -> execute in context */
-static cairo_status_t
-_cairo_path_to_quartz_context_move_to (void *closure, cairo_point_t *point)
-{
- //ND((stderr, "moveto: %f %f\n", _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y)));
- CGContextMoveToPoint ((CGContextRef) closure,
- _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y));
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_to_quartz_context_line_to (void *closure, cairo_point_t *point)
-{
- //ND((stderr, "lineto: %f %f\n", _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y)));
- if (CGContextIsPathEmpty ((CGContextRef) closure))
- CGContextMoveToPoint ((CGContextRef) closure,
- _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y));
- else
- CGContextAddLineToPoint ((CGContextRef) closure,
- _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y));
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_to_quartz_context_curve_to (void *closure, cairo_point_t *p0, cairo_point_t *p1, cairo_point_t *p2)
-{
- //ND( (stderr, "curveto: %f,%f %f,%f %f,%f\n",
- // _cairo_fixed_to_double(p0->x), _cairo_fixed_to_double(p0->y),
- // _cairo_fixed_to_double(p1->x), _cairo_fixed_to_double(p1->y),
- // _cairo_fixed_to_double(p2->x), _cairo_fixed_to_double(p2->y)));
-
- CGContextAddCurveToPoint ((CGContextRef) closure,
- _cairo_fixed_to_double(p0->x), _cairo_fixed_to_double(p0->y),
- _cairo_fixed_to_double(p1->x), _cairo_fixed_to_double(p1->y),
- _cairo_fixed_to_double(p2->x), _cairo_fixed_to_double(p2->y));
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_to_quartz_context_close_path (void *closure)
-{
- //ND((stderr, "closepath\n"));
- CGContextClosePath ((CGContextRef) closure);
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_nquartz_cairo_path_to_quartz_path (cairo_path_fixed_t *path,
- CGMutablePathRef cgPath)
-{
- return _cairo_path_fixed_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_path_to_quartz_path_move_to,
- _cairo_path_to_quartz_path_line_to,
- _cairo_path_to_quartz_path_curve_to,
- _cairo_path_to_quartz_path_close_path,
- cgPath);
-}
-
-static cairo_status_t
-_cairo_nquartz_cairo_path_to_quartz_context (cairo_path_fixed_t *path,
- CGContextRef cgc)
-{
- return _cairo_path_fixed_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_path_to_quartz_context_move_to,
- _cairo_path_to_quartz_context_line_to,
- _cairo_path_to_quartz_context_curve_to,
- _cairo_path_to_quartz_context_close_path,
- cgc);
-}
-
-/*
- * Misc helpers/callbacks
- */
-
-static PrivateCGCompositeMode
-_cairo_nquartz_cairo_operator_to_quartz (cairo_operator_t op)
-{
- switch (op) {
- case CAIRO_OPERATOR_CLEAR:
- return kPrivateCGCompositeClear;
- case CAIRO_OPERATOR_SOURCE:
- return kPrivateCGCompositeCopy;
- case CAIRO_OPERATOR_OVER:
- return kPrivateCGCompositeSourceOver;
- case CAIRO_OPERATOR_IN:
- /* XXX This doesn't match image output */
- return kPrivateCGCompositeSourceIn;
- case CAIRO_OPERATOR_OUT:
- /* XXX This doesn't match image output */
- return kPrivateCGCompositeSourceOut;
- case CAIRO_OPERATOR_ATOP:
- return kPrivateCGCompositeSourceAtop;
-
- case CAIRO_OPERATOR_DEST:
- /* XXX this is handled specially (noop)! */
- return kPrivateCGCompositeCopy;
- case CAIRO_OPERATOR_DEST_OVER:
- return kPrivateCGCompositeDestinationOver;
- case CAIRO_OPERATOR_DEST_IN:
- /* XXX This doesn't match image output */
- return kPrivateCGCompositeDestinationIn;
- case CAIRO_OPERATOR_DEST_OUT:
- return kPrivateCGCompositeDestinationOut;
- case CAIRO_OPERATOR_DEST_ATOP:
- /* XXX This doesn't match image output */
- return kPrivateCGCompositeDestinationAtop;
-
- case CAIRO_OPERATOR_XOR:
- return kPrivateCGCompositeXOR; /* This will generate strange results */
- case CAIRO_OPERATOR_ADD:
- return kPrivateCGCompositePlusLighter;
- case CAIRO_OPERATOR_SATURATE:
- /* XXX This doesn't match image output for SATURATE; there's no equivalent */
- return kPrivateCGCompositePlusDarker; /* ??? */
- }
-
-
- return kPrivateCGCompositeCopy;
-}
-
-static CGLineCap
-_cairo_nquartz_cairo_line_cap_to_quartz (cairo_line_cap_t ccap)
-{
- switch (ccap) {
- case CAIRO_LINE_CAP_BUTT: return kCGLineCapButt; break;
- case CAIRO_LINE_CAP_ROUND: return kCGLineCapRound; break;
- case CAIRO_LINE_CAP_SQUARE: return kCGLineCapSquare; break;
- }
-
- return kCGLineCapButt;
-}
-
-static CGLineJoin
-_cairo_nquartz_cairo_line_join_to_quartz (cairo_line_join_t cjoin)
-{
- switch (cjoin) {
- case CAIRO_LINE_JOIN_MITER: return kCGLineJoinMiter; break;
- case CAIRO_LINE_JOIN_ROUND: return kCGLineJoinRound; break;
- case CAIRO_LINE_JOIN_BEVEL: return kCGLineJoinBevel; break;
- }
-
- return kCGLineJoinMiter;
-}
-
-static void
-_cairo_nquartz_cairo_matrix_to_quartz (const cairo_matrix_t *src,
- CGAffineTransform *dst)
-{
- dst->a = src->xx;
- dst->b = src->xy;
- dst->c = src->yx;
- dst->d = src->yy;
- dst->tx = src->x0;
- dst->ty = src->y0;
-}
-
-/**
- ** Source -> Quartz setup and finish functions
- **/
-
-static void
-ComputeGradientValue (void *info, const float *in, float *out)
-{
- float fdist = *in; /* 0.0 .. 1.0 */
- cairo_fixed_16_16_t fdist_fix = _cairo_fixed_from_double(*in);
- cairo_gradient_pattern_t *grad = (cairo_gradient_pattern_t*) info;
- int i;
-
- for (i = 0; i < grad->n_stops; i++) {
- if (grad->stops[i].x > fdist_fix)
- break;
- }
-
- if (i == 0 || i == grad->n_stops) {
- if (i == grad->n_stops)
- --i;
- out[0] = grad->stops[i].color.red / 65535.;
- out[1] = grad->stops[i].color.green / 65535.;
- out[2] = grad->stops[i].color.blue / 65535.;
- out[3] = grad->stops[i].color.alpha / 65535.;
- } else {
- float ax = _cairo_fixed_to_double(grad->stops[i-1].x);
- float bx = _cairo_fixed_to_double(grad->stops[i].x) - ax;
- float bp = (fdist - ax)/bx;
- float ap = 1.0 - bp;
-
- out[0] =
- (grad->stops[i-1].color.red / 65535.) * ap +
- (grad->stops[i].color.red / 65535.) * bp;
- out[1] =
- (grad->stops[i-1].color.green / 65535.) * ap +
- (grad->stops[i].color.green / 65535.) * bp;
- out[2] =
- (grad->stops[i-1].color.blue / 65535.) * ap +
- (grad->stops[i].color.blue / 65535.) * bp;
- out[3] =
- (grad->stops[i-1].color.alpha / 65535.) * ap +
- (grad->stops[i].color.alpha / 65535.) * bp;
- }
-}
-
-static CGFunctionRef
-CreateGradientFunction (cairo_gradient_pattern_t *gpat)
-{
- static const float input_value_range[2] = { 0.f, 1.f };
- static const float output_value_ranges[8] = { 0.f, 1.f, 0.f, 1.f, 0.f, 1.f, 0.f, 1.f };
- static const CGFunctionCallbacks callbacks = {
- 0, ComputeGradientValue, (CGFunctionReleaseInfoCallback) cairo_pattern_destroy
- };
-
- return CGFunctionCreate (gpat,
- 1,
- input_value_range,
- 4,
- output_value_ranges,
- &callbacks);
-}
-
-static CGShadingRef
-_cairo_nquartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat)
-{
- cairo_matrix_t mat;
- double x0, y0;
-
- if (abspat->type != CAIRO_PATTERN_TYPE_LINEAR &&
- abspat->type != CAIRO_PATTERN_TYPE_RADIAL)
- return NULL;
-
- /* We can only do this if we have an identity pattern matrix;
- * otherwise fall back through to the generic pattern case.
- * XXXperf we could optimize this by creating a pattern with the shading;
- * but we'd need to know the extents to do that.
- * ... but we don't care; we can use the surface extents for it
- * XXXtodo - implement gradients with non-identity pattern matrices
- */
- cairo_pattern_get_matrix (abspat, &mat);
- if (mat.xx != 1.0 || mat.yy != 1.0 || mat.xy != 0.0 || mat.yx != 0.0)
- return NULL;
-
- x0 = mat.x0;
- y0 = mat.y0;
-
- if (abspat->type == CAIRO_PATTERN_TYPE_LINEAR) {
- cairo_linear_pattern_t *lpat = (cairo_linear_pattern_t*) abspat;
- CGShadingRef shading;
- CGPoint start, end;
- CGFunctionRef gradFunc;
- CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
-
- start = CGPointMake (_cairo_fixed_to_double (lpat->gradient.p1.x) - x0,
- _cairo_fixed_to_double (lpat->gradient.p1.y) - y0);
- end = CGPointMake (_cairo_fixed_to_double (lpat->gradient.p2.x) - x0,
- _cairo_fixed_to_double (lpat->gradient.p2.y) - y0);
-
- cairo_pattern_reference (abspat);
- gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) lpat);
- shading = CGShadingCreateAxial (rgb,
- start, end,
- gradFunc,
- true, true);
- CGColorSpaceRelease(rgb);
- CGFunctionRelease(gradFunc);
-
- return shading;
- }
-
- if (abspat->type == CAIRO_PATTERN_TYPE_RADIAL) {
- cairo_radial_pattern_t *rpat = (cairo_radial_pattern_t*) abspat;
- CGShadingRef shading;
- CGPoint start, end;
- CGFunctionRef gradFunc;
- CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
-
- start = CGPointMake (_cairo_fixed_to_double (rpat->gradient.inner.x) - x0,
- _cairo_fixed_to_double (rpat->gradient.inner.y) - y0);
- end = CGPointMake (_cairo_fixed_to_double (rpat->gradient.outer.x) - x0,
- _cairo_fixed_to_double (rpat->gradient.outer.y) - y0);
-
- cairo_pattern_reference (abspat);
- gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) rpat);
- shading = CGShadingCreateRadial (rgb,
- start,
- _cairo_fixed_to_double (rpat->gradient.inner.radius),
- end,
- _cairo_fixed_to_double (rpat->gradient.outer.radius),
- gradFunc,
- true, true);
- CGColorSpaceRelease(rgb);
- CGFunctionRelease(gradFunc);
-
- return shading;
- }
-
- /* Shouldn't be reached */
- ASSERT_NOT_REACHED;
- return NULL;
-}
-
-
-/* Generic cairo_pattern -> CGPattern function */
-static void
-SurfacePatternDrawFunc (void *info, CGContextRef context)
-{
- cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) info;
- cairo_surface_t *pat_surf = spat->surface;
- cairo_rectangle_int16_t extents;
- cairo_status_t status;
-
- cairo_nquartz_surface_t *quartz_surf = NULL;
-
- cairo_bool_t flip = FALSE;
-
- CGImageRef img;
-
- if (!cairo_surface_is_nquartz (pat_surf)) {
- ND((stderr, "-- source is not nquartz surface\n"));
- /* This sucks; we should really store a dummy nquartz surface
- * for passing in here
- * XXXtodo store a dummy nquartz surface somewhere for handing off to clone_similar
- * XXXtodo/perf don't use clone if the source surface is an image surface! Instead,
- * just create the CGImage directly!
- */
-
- cairo_surface_t *dummy = cairo_nquartz_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
-
- cairo_rectangle_int16_t rect;
- _cairo_surface_get_extents (pat_surf, &rect);
-
- cairo_surface_t *new_surf = NULL;
-
- _cairo_surface_clone_similar (dummy, pat_surf, rect.x, rect.y,
- rect.width, rect.height, &new_surf);
-
- cairo_surface_destroy(dummy);
-
- quartz_surf = (cairo_nquartz_surface_t *) new_surf;
- } else {
- ND((stderr, "-- source is nquartz surface\n"));
- /* If it's a nquartz surface, we can try to see if it's a CGBitmapContext;
- * we do this when we call CGBitmapContextCreateImage below.
- */
- cairo_surface_reference (pat_surf);
- quartz_surf = (cairo_nquartz_surface_t*) pat_surf;
-
- /* XXXtodo WHY does this need to be flipped? Writing this stuff
- * to disk shows that in both this path and the path above the source image
- * has an identical orientation, and the destination context at all times has a Y
- * flip. So why do we need to flip in this case?
- */
- flip = TRUE;
- }
-
- /* this is a 10.4 API, present in 10.3.9 */
- CGContextFlush (quartz_surf->cgContext);
- img = CGBitmapContextCreateImage (quartz_surf->cgContext);
-
- if (!img) {
- // ... give up.
- ND((stderr, "CGBitmapContextCreateImage failed\n"));
- cairo_surface_destroy ((cairo_surface_t*)quartz_surf);
- return;
- }
-
- if (flip) {
- CGContextTranslateCTM (context, 0, CGImageGetHeight(img));
- CGContextScaleCTM (context, 1, -1);
- }
-
- CGRect imageBounds;
- imageBounds.size = CGSizeMake (CGImageGetWidth(img), CGImageGetHeight(img));
- imageBounds.origin.x = 0;
- imageBounds.origin.y = 0;
-
- CGContextDrawImage (context, imageBounds, img);
-
- CGImageRelease (img);
-
- cairo_surface_destroy ((cairo_surface_t*) quartz_surf);
-}
-
-/* Borrowed from cairo-meta-surface */
-static cairo_status_t
-_init_pattern_with_snapshot (cairo_pattern_t *pattern,
- const cairo_pattern_t *other)
-{
- _cairo_pattern_init_copy (pattern, other);
-
- if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
- cairo_surface_pattern_t *surface_pattern =
- (cairo_surface_pattern_t *) pattern;
- cairo_surface_t *surface = surface_pattern->surface;
-
- surface_pattern->surface = _cairo_surface_snapshot (surface);
-
- cairo_surface_destroy (surface);
-
- if (surface_pattern->surface->status)
- return surface_pattern->surface->status;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static CGPatternRef
-_cairo_nquartz_cairo_repeating_surface_pattern_to_quartz (cairo_nquartz_surface_t *dest,
- cairo_pattern_t *abspat)
-{
- cairo_surface_pattern_t *spat;
- cairo_surface_t *pat_surf;
- cairo_rectangle_int16_t extents;
-
- CGRect pbounds;
- CGAffineTransform ptransform, stransform;
- CGPatternCallbacks cb = { 0,
- SurfacePatternDrawFunc,
- (CGFunctionReleaseInfoCallback) cairo_pattern_destroy };
- CGPatternRef cgpat;
- float rw, rh;
-
- cairo_pattern_union_t *snap_pattern = NULL;
- cairo_pattern_t *target_pattern = abspat;
-
- /* SURFACE is the only type we'll handle here */
- if (abspat->type != CAIRO_PATTERN_TYPE_SURFACE)
- return NULL;
-
- spat = (cairo_surface_pattern_t *) abspat;
- pat_surf = spat->surface;
-
- _cairo_surface_get_extents (pat_surf, &extents);
- pbounds.origin.x = 0;
- pbounds.origin.y = 0;
- pbounds.size.width = extents.width;
- pbounds.size.height = extents.height;
-
- cairo_matrix_t m = spat->base.matrix;
- cairo_matrix_invert(&m);
- _cairo_nquartz_cairo_matrix_to_quartz (&m, &stransform);
-
- /* The pattern matrix is relative to the bottom left, again; the
- * incoming cairo pattern matrix is relative to the upper left.
- * So we take the pattern matrix and the original context matrix,
- * which gives us the correct base translation/y flip.
- */
- ptransform = CGAffineTransformConcat(stransform, dest->cgContextBaseCTM);
-
-#ifdef NQUARTZ_DEBUG
- ND((stderr, " pbounds: %f %f %f %f\n", pbounds.origin.x, pbounds.origin.y, pbounds.size.width, pbounds.size.height));
- ND((stderr, " pattern xform: t: %f %f xx: %f xy: %f yx: %f yy: %f\n", ptransform.tx, ptransform.ty, ptransform.a, ptransform.b, ptransform.c, ptransform.d));
- CGAffineTransform xform = CGContextGetCTM(dest->cgContext);
- ND((stderr, " context xform: t: %f %f xx: %f xy: %f yx: %f yy: %f\n", xform.tx, xform.ty, xform.a, xform.b, xform.c, xform.d));
-#endif
-
- // kjs seems to indicate this should work (setting to 0,0 to avoid
- // tiling); however, the pattern CTM scaling ends up being NaN in
- // the pattern draw function if either rw or rh are 0.
- // XXXtodo get pattern drawing working with extend options
- // XXXtodo/perf optimize CAIRO_EXTEND_NONE to a single DrawImage instead of a pattern
-#if 0
- if (spat->base.extend == CAIRO_EXTEND_NONE) {
- /* XXX wasteful; this will keep drawing the pattern in the
- * original location. We need to set up the clip region
- * instead to do this right.
- */
- rw = 0;
- rh = 0;
- } else if (spat->base.extend == CAIRO_EXTEND_REPEAT) {
- rw = extents.width;
- rh = extents.height;
- } else if (spat->base.extend == CAIRO_EXTEND_REFLECT) {
- /* XXX broken; need to emulate by reflecting the image into 4 quadrants
- * and then tiling that
- */
- rw = extents.width;
- rh = extents.height;
- } else {
- /* CAIRO_EXTEND_PAD */
- /* XXX broken. */
- rw = 0;
- rh = 0;
- }
-#else
- rw = extents.width;
- rh = extents.height;
-#endif
-
- /* XXX fixme: only do snapshots if the context is for printing, or get rid of the
- other block if it doesn't fafect performance */
- if (1 /* context is for printing */) {
- snap_pattern = (cairo_pattern_union_t*) malloc(sizeof(cairo_pattern_union_t));
- target_pattern = (cairo_pattern_t*) snap_pattern;
- _init_pattern_with_snapshot (snap_pattern, abspat);
- } else {
- cairo_pattern_reference (abspat);
- target_pattern = abspat;
- }
-
- cgpat = CGPatternCreate (target_pattern,
- pbounds,
- ptransform,
- rw, rh,
- kCGPatternTilingConstantSpacing, /* kCGPatternTilingNoDistortion, */
- TRUE,
- &cb);
- return cgpat;
-}
-
-typedef enum {
- DO_SOLID,
- DO_SHADING,
- DO_PATTERN,
- DO_UNSUPPORTED
-} cairo_nquartz_action_t;
-
-static cairo_nquartz_action_t
-_cairo_nquartz_setup_source (cairo_nquartz_surface_t *surface,
- cairo_pattern_t *source)
-{
- assert (!(surface->sourceImage || surface->sourceShading || surface->sourcePattern));
-
- if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
- cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
-
- CGContextSetRGBStrokeColor (surface->cgContext,
- solid->color.red,
- solid->color.green,
- solid->color.blue,
- solid->color.alpha);
- CGContextSetRGBFillColor (surface->cgContext,
- solid->color.red,
- solid->color.green,
- solid->color.blue,
- solid->color.alpha);
-
- return DO_SOLID;
- } else if (source->type == CAIRO_PATTERN_TYPE_LINEAR ||
- source->type == CAIRO_PATTERN_TYPE_RADIAL)
- {
- CGShadingRef shading = _cairo_nquartz_cairo_gradient_pattern_to_quartz (source);
- if (!shading)
- return DO_UNSUPPORTED;
-
- surface->sourceShading = shading;
-
- return DO_SHADING;
- } else if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
- CGPatternRef pattern = _cairo_nquartz_cairo_repeating_surface_pattern_to_quartz (surface, source);
- if (!pattern)
- return DO_UNSUPPORTED;
-
- float patternAlpha = 1.0f;
-
- // Save before we change the pattern, colorspace, etc. so that
- // we can restore and make sure that quartz releases our
- // pattern (which may be stack allocated)
- CGContextSaveGState(surface->cgContext);
-
- CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
- CGContextSetFillColorSpace (surface->cgContext, patternSpace);
- CGContextSetFillPattern (surface->cgContext, pattern, &patternAlpha);
- CGContextSetStrokeColorSpace (surface->cgContext, patternSpace);
- CGContextSetStrokePattern (surface->cgContext, pattern, &patternAlpha);
- CGColorSpaceRelease (patternSpace);
-
- /* Quartz likes to munge the pattern phase (as yet unexplained
- * why); force it to 0,0 as we've already baked in the correct
- * pattern translation into the pattern matrix
- */
- CGContextSetPatternPhase (surface->cgContext, CGSizeMake(0,0));
-
- surface->sourcePattern = pattern;
-
- return DO_PATTERN;
- } else {
- return DO_UNSUPPORTED;
- }
-
- ASSERT_NOT_REACHED;
-}
-
-static void
-_cairo_nquartz_teardown_source (cairo_nquartz_surface_t *surface,
- cairo_pattern_t *source)
-{
- if (surface->sourceImage) {
- // nothing to do; we don't use sourceImage yet
- }
-
- if (surface->sourceShading) {
- CGShadingRelease(surface->sourceShading);
- surface->sourceShading = NULL;
- }
-
- if (surface->sourcePattern) {
- CGPatternRelease(surface->sourcePattern);
- // To tear down the pattern and colorspace
- CGContextRestoreGState(surface->cgContext);
-
- surface->sourcePattern = NULL;
- }
-}
-
-/**
- ** get source/dest image implementation
- **/
-
-static void
-ImageDataReleaseFunc(void *info, const void *data, size_t size)
-{
- if (data != NULL) {
- free((void *) data);
- }
-}
-
-/* Read the image from the surface's front buffer */
-static cairo_int_status_t
-_cairo_nquartz_get_image (cairo_nquartz_surface_t *surface,
- cairo_image_surface_t **image_out,
- unsigned char **data_out)
-{
- unsigned char *imageData;
- cairo_image_surface_t *isurf;
-
- /* If we weren't constructed with an AGL Context
- * or a CCGBitmapContext, then we have no way
- * of doing this
- */
-#ifdef CAIRO_NQUARTZ_SUPPORT_AGL
- if (surface->aglContext) {
- AGLContext oldContext;
- cairo_format_masks_t masks = { 32, 0xff << 24, 0xff << 16, 0xff << 8, 0xff << 0 };
- unsigned int i;
-
- oldContext = aglGetCurrentContext();
- if (oldContext != surface->aglContext)
- aglSetCurrentContext(surface->aglContext);
-
- imageData = (unsigned char *) malloc (surface->extents.width * surface->extents.height * 4);
- if (!imageData)
- return CAIRO_STATUS_NO_MEMORY;
-
- glReadBuffer (GL_FRONT);
- glReadPixels (0, 0, surface->extents.width, surface->extents.height,
- GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
- imageData);
-
- /* swap lines */
- /* XXX find some fast code to do this */
- unsigned int lineSize = surface->extents.width * 4;
- unsigned char *tmpLine = malloc(lineSize);
- for (i = 0; i < surface->extents.height / 2; i++) {
- unsigned char *l0 = imageData + lineSize * i;
- unsigned char *l1 = imageData + (lineSize * (surface->extents.height - i - 1));
- memcpy (tmpLine, l0, lineSize);
- memcpy (l0, l1, lineSize);
- memcpy (l1, tmpLine, lineSize);
- }
- free (tmpLine);
-
- if (oldContext && oldContext != surface->aglContext)
- aglSetCurrentContext(oldContext);
-
- isurf = (cairo_image_surface_t *)_cairo_image_surface_create_with_masks
- (imageData,
- &masks,
- surface->extents.width,
- surface->extents.height,
- surface->extents.width * 4);
-
- if (data_out)
- *data_out = imageData;
- else
- _cairo_image_surface_assume_ownership_of_data (isurf);
-#else
- /* no AGL */
- if (0) {
-#endif
- } else if (CGBitmapContextGetBitsPerPixel(surface->cgContext) != 0) {
- unsigned int stride;
- unsigned int bitinfo;
- unsigned int bpc, bpp;
- CGColorSpaceRef colorspace;
- unsigned int color_comps;
-
- imageData = (unsigned char *) CGBitmapContextGetData(surface->cgContext);
-#ifdef USE_10_3_WORKAROUNDS
- bitinfo = CGBitmapContextGetAlphaInfo (surface->cgContext);
-#else
- bitinfo = CGBitmapContextGetBitmapInfo (surface->cgContext);
-#endif
- stride = CGBitmapContextGetBytesPerRow (surface->cgContext);
- bpp = CGBitmapContextGetBitsPerPixel (surface->cgContext);
- bpc = CGBitmapContextGetBitsPerComponent (surface->cgContext);
-
- // let's hope they don't add YUV under us
- colorspace = CGBitmapContextGetColorSpace (surface->cgContext);
- color_comps = CGColorSpaceGetNumberOfComponents(colorspace);
-
- // XXX TODO: We can handle all of these by converting to
- // pixman masks, including non-native-endian masks
- if (bpc != 8)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (bpp != 32 && bpp != 8)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (color_comps != 3 && color_comps != 1)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (bpp == 32 && color_comps == 3 &&
- (bitinfo & kCGBitmapAlphaInfoMask) == kCGImageAlphaPremultipliedFirst &&
- (bitinfo & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Host)
- {
- isurf = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (imageData,
- CAIRO_FORMAT_ARGB32,
- surface->extents.width,
- surface->extents.height,
- stride);
- } else if (bpp == 32 && color_comps == 3 &&
- (bitinfo & kCGBitmapAlphaInfoMask) == kCGImageAlphaNoneSkipFirst &&
- (bitinfo & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Host)
- {
- isurf = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (imageData,
- CAIRO_FORMAT_RGB24,
- surface->extents.width,
- surface->extents.height,
- stride);
- } else if (bpp == 8 && color_comps == 1)
- {
- isurf = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (imageData,
- CAIRO_FORMAT_A8,
- surface->extents.width,
- surface->extents.height,
- stride);
- } else {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
- } else {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- *image_out = isurf;
- return CAIRO_STATUS_SUCCESS;
-}
-
-/**
- ** Cairo surface backend implementations
- **/
-
-static cairo_status_t
-_cairo_nquartz_surface_finish (void *abstract_surface)
-{
- cairo_nquartz_surface_t *surface = (cairo_nquartz_surface_t *) abstract_surface;
-
- ND((stderr, "_cairo_nquartz_surface_finish[%p] cgc: %p\n", surface, surface->cgContext));
-
-#ifdef CAIRO_NQUARTZ_SUPPORT_AGL
- if (surface->aglContext)
- aglSetCurrentContext(surface->aglContext);
-#endif
-
- CGContextFlush (surface->cgContext);
-
- /* Restore our saved gstate that we use to reset clipping */
- CGContextRestoreGState (surface->cgContext);
-
- CGContextRelease (surface->cgContext);
-
- surface->cgContext = NULL;
-
-#ifdef CAIRO_NQUARTZ_SUPPORT_AGL
- if (surface->aglContext)
- glFlush();
-
- surface->aglContext = NULL;
-#endif
-
- if (surface->imageData) {
- free (surface->imageData);
- surface->imageData = NULL;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_nquartz_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_nquartz_surface_t *surface = (cairo_nquartz_surface_t *) abstract_surface;
-
- //ND((stderr, "%p _cairo_nquartz_surface_acquire_source_image\n", surface));
-
- *image_extra = NULL;
-
- return _cairo_nquartz_get_image (surface, image_out, NULL);
-}
-
-static cairo_status_t
-_cairo_nquartz_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int16_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int16_t *image_rect,
- void **image_extra)
-{
- cairo_nquartz_surface_t *surface = (cairo_nquartz_surface_t *) abstract_surface;
- cairo_int_status_t status;
- unsigned char *data;
-
- ND((stderr, "%p _cairo_nquartz_surface_acquire_dest_image\n", surface));
-
- *image_rect = surface->extents;
-
- status = _cairo_nquartz_get_image (surface, image_out, &data);
- if (status)
- return status;
-
- *image_extra = data;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_nquartz_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int16_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int16_t *image_rect,
- void *image_extra)
-{
- cairo_nquartz_surface_t *surface = (cairo_nquartz_surface_t *) abstract_surface;
- unsigned char *imageData = (unsigned char *) image_extra;
-
- //ND((stderr, "%p _cairo_nquartz_surface_release_dest_image\n", surface));
-
- if (!CGBitmapContextGetData (surface->cgContext)) {
- CGDataProviderRef dataProvider;
- CGImageRef img;
-
- dataProvider = CGDataProviderCreateWithData (NULL, imageData,
- surface->extents.width * surface->extents.height * 4,
- ImageDataReleaseFunc);
-
- img = CGImageCreate (surface->extents.width, surface->extents.height,
- 8, 32,
- surface->extents.width * 4,
- CGColorSpaceCreateDeviceRGB(),
- kCGImageAlphaPremultipliedFirst,
- dataProvider,
- NULL,
- false,
- kCGRenderingIntentDefault);
-
- CGContextSetCompositeOperation (surface->cgContext, kPrivateCGCompositeCopy);
-
- CGContextDrawImage (surface->cgContext,
- CGRectMake (0, 0, surface->extents.width, surface->extents.height),
- img);
-
- CGImageRelease (img);
- CGDataProviderRelease (dataProvider);
-
- ND((stderr, "Image for surface %p was recovered from a bitmap\n", surface));
- }
-
- cairo_surface_destroy ((cairo_surface_t *) image);
-}
-
-static cairo_surface_t *
-_cairo_nquartz_surface_create_similar (void *abstract_surface,
- cairo_content_t content,
- int width,
- int height)
-{
- cairo_nquartz_surface_t *surface = (cairo_nquartz_surface_t *) abstract_surface;
-
- cairo_format_t format;
-
- if (content == CAIRO_CONTENT_COLOR_ALPHA)
- format = CAIRO_FORMAT_ARGB32;
- else if (content == CAIRO_CONTENT_COLOR)
- format = CAIRO_FORMAT_RGB24;
- else if (content == CAIRO_CONTENT_ALPHA)
- format = CAIRO_FORMAT_A8;
- else
- return NULL;
-
- return cairo_nquartz_surface_create (format, width, height);
-}
-
-static cairo_status_t
-_cairo_nquartz_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- cairo_surface_t **clone_out)
-{
- cairo_nquartz_surface_t *surface = (cairo_nquartz_surface_t *) abstract_surface;
- cairo_nquartz_surface_t *new_surface = NULL;
- cairo_format_t new_format;
-
- CGImageRef quartz_image = NULL;
- cairo_surface_t *surface_to_release = NULL;
-
- if (cairo_surface_is_nquartz (src)) {
- cairo_nquartz_surface_t *qsurf = (cairo_nquartz_surface_t *) src;
- quartz_image = CGBitmapContextCreateImage (qsurf->cgContext);
- new_format = CAIRO_FORMAT_ARGB32; /* XXX bogus; recover a real format from the image */
- } else if (_cairo_surface_is_image (src)) {
- cairo_image_surface_t *isurf = (cairo_image_surface_t *) src;
- CGDataProviderRef dataProvider;
- CGColorSpaceRef cgColorspace;
- CGBitmapInfo bitinfo;
- int bitsPerComponent, bitsPerPixel;
-
- if (isurf->format == CAIRO_FORMAT_ARGB32) {
- cgColorspace = CGColorSpaceCreateDeviceRGB();
- bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
- bitsPerComponent = 8;
- bitsPerPixel = 32;
- } else if (isurf->format == CAIRO_FORMAT_RGB24) {
- cgColorspace = CGColorSpaceCreateDeviceRGB();
- bitinfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
- bitsPerComponent = 8;
- bitsPerPixel = 32;
- } else if (isurf->format == CAIRO_FORMAT_A8) {
- cgColorspace = CGColorSpaceCreateDeviceGray();
- bitinfo = kCGImageAlphaNone;
- bitsPerComponent = 8;
- bitsPerPixel = 8;
- } else {
- /* SUPPORT A1, maybe */
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- new_format = isurf->format;
-
- dataProvider = CGDataProviderCreateWithData (NULL,
- isurf->data,
- isurf->height * isurf->stride,
- NULL);
-
- quartz_image = CGImageCreate (isurf->width, isurf->height,
- bitsPerComponent,
- bitsPerPixel,
- isurf->stride,
- cgColorspace,
- bitinfo,
- dataProvider,
- NULL,
- false,
- kCGRenderingIntentDefault);
- CGDataProviderRelease (dataProvider);
- CGColorSpaceRelease (cgColorspace);
- } else {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- if (!quartz_image)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- new_surface = (cairo_nquartz_surface_t *)
- cairo_nquartz_surface_create (new_format,
- CGImageGetWidth (quartz_image),
- CGImageGetHeight (quartz_image));
- if (!new_surface || new_surface->base.status)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- CGContextSetCompositeOperation (new_surface->cgContext,
- kPrivateCGCompositeCopy);
-
- nquartz_image_to_png (quartz_image, NULL);
-
- CGContextDrawImage (new_surface->cgContext,
- CGRectMake (src_x, src_y, width, height),
- quartz_image);
- CGImageRelease (quartz_image);
-
- *clone_out = (cairo_surface_t*) new_surface;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_nquartz_surface_get_extents (void *abstract_surface,
- cairo_rectangle_int16_t *extents)
-{
- cairo_nquartz_surface_t *surface = (cairo_nquartz_surface_t *) abstract_surface;
-
- *extents = surface->extents;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_nquartz_surface_paint (void *abstract_surface,
- cairo_operator_t op,
- cairo_pattern_t *source)
-{
- cairo_nquartz_surface_t *surface = (cairo_nquartz_surface_t *) abstract_surface;
- cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
- cairo_nquartz_action_t action;
-
- ND((stderr, "%p _cairo_nquartz_surface_paint op %d source->type %d\n", surface, op, source->type));
-
- if (op == CAIRO_OPERATOR_DEST)
- return CAIRO_STATUS_SUCCESS;
-
- CGContextSetCompositeOperation (surface->cgContext, _cairo_nquartz_cairo_operator_to_quartz (op));
-
- CGRect bounds = CGContextGetClipBoundingBox (surface->cgContext);
-
- action = _cairo_nquartz_setup_source (surface, source);
-
- if (action == DO_SOLID || action == DO_PATTERN) {
- CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x,
- surface->extents.y,
- surface->extents.width,
- surface->extents.height));
- } else if (action == DO_SHADING) {
- CGContextDrawShading (surface->cgContext, surface->sourceShading);
- } else {
- rv = CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- _cairo_nquartz_teardown_source (surface, source);
-
- ND((stderr, "-- paint\n"));
- return rv;
-}
-
-static cairo_int_status_t
-_cairo_nquartz_surface_fill (void *abstract_surface,
- cairo_operator_t op,
- cairo_pattern_t *source,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_nquartz_surface_t *surface = (cairo_nquartz_surface_t *) abstract_surface;
- cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
- cairo_nquartz_action_t action;
-
- ND((stderr, "%p _cairo_nquartz_surface_fill op %d source->type %d\n", surface, op, source->type));
-
- if (op == CAIRO_OPERATOR_DEST)
- return CAIRO_STATUS_SUCCESS;
-
- CGContextSaveGState (surface->cgContext);
-
- CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
- CGContextSetCompositeOperation (surface->cgContext, _cairo_nquartz_cairo_operator_to_quartz (op));
-
- action = _cairo_nquartz_setup_source (surface, source);
- if (action == DO_UNSUPPORTED) {
- CGContextRestoreGState (surface->cgContext);
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- CGContextBeginPath (surface->cgContext);
- _cairo_nquartz_cairo_path_to_quartz_context (path, surface->cgContext);
-
- if (action == DO_SOLID || action == DO_PATTERN) {
- if (fill_rule == CAIRO_FILL_RULE_WINDING)
- CGContextFillPath (surface->cgContext);
- else
- CGContextEOFillPath (surface->cgContext);
- } else if (action == DO_SHADING) {
-
- // we have to clip and then paint the shading; we can't fill
- // with the shading
- if (fill_rule == CAIRO_FILL_RULE_WINDING)
- CGContextClip (surface->cgContext);
- else
- CGContextEOClip (surface->cgContext);
-
- CGContextDrawShading (surface->cgContext, surface->sourceShading);
- } else {
- rv = CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- _cairo_nquartz_teardown_source (surface, source);
-
- CGContextRestoreGState (surface->cgContext);
-
- ND((stderr, "-- fill\n"));
- return rv;
-}
-
-static cairo_int_status_t
-_cairo_nquartz_surface_stroke (void *abstract_surface,
- cairo_operator_t op,
- cairo_pattern_t *source,
- cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_nquartz_surface_t *surface = (cairo_nquartz_surface_t *) abstract_surface;
- cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
- cairo_nquartz_action_t action;
-
- ND((stderr, "%p _cairo_nquartz_surface_stroke op %d source->type %d\n", surface, op, source->type));
-
- if (op == CAIRO_OPERATOR_DEST)
- return CAIRO_STATUS_SUCCESS;
-
- CGContextSaveGState (surface->cgContext);
-
- // Turning antialiasing off causes misrendering with
- // single-pixel lines (e.g. 20,10.5 -> 21,10.5 end up being rendered as 2 pixels)
- //CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
- CGContextSetLineWidth (surface->cgContext, style->line_width);
- CGContextSetLineCap (surface->cgContext, _cairo_nquartz_cairo_line_cap_to_quartz (style->line_cap));
- CGContextSetLineJoin (surface->cgContext, _cairo_nquartz_cairo_line_join_to_quartz (style->line_join));
- CGContextSetMiterLimit (surface->cgContext, style->miter_limit);
-
- if (style->dash && style->num_dashes) {
-#define STATIC_DASH 32
- float sdash[STATIC_DASH];
- float *fdash = sdash;
- int k;
- if (style->num_dashes > STATIC_DASH)
- fdash = malloc (sizeof(float)*style->num_dashes);
-
- for (k = 0; k < style->num_dashes; k++)
- fdash[k] = (float) style->dash[k];
-
- CGContextSetLineDash (surface->cgContext, style->dash_offset, fdash, style->num_dashes);
-
- if (fdash != sdash)
- free (fdash);
- }
-
- CGContextSetCompositeOperation (surface->cgContext, _cairo_nquartz_cairo_operator_to_quartz (op));
-
- action = _cairo_nquartz_setup_source (surface, source);
- if (action == DO_UNSUPPORTED) {
- CGContextRestoreGState (surface->cgContext);
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- CGContextBeginPath (surface->cgContext);
- _cairo_nquartz_cairo_path_to_quartz_context (path, surface->cgContext);
-
- if (action == DO_SOLID || action == DO_PATTERN) {
- CGContextStrokePath (surface->cgContext);
- } else if (action == DO_SHADING) {
- // we have to clip and then paint the shading; first we have to convert
- // the stroke to a path that we can fill
- CGContextReplacePathWithStrokedPath (surface->cgContext);
- CGContextClip (surface->cgContext);
-
- CGContextDrawShading (surface->cgContext, surface->sourceShading);
- } else {
- rv = CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- _cairo_nquartz_teardown_source (surface, source);
-
- CGContextRestoreGState (surface->cgContext);
-
- ND((stderr, "-- stroke\n"));
- return rv;
-}
-
-static cairo_int_status_t
-_cairo_nquartz_surface_show_glyphs (void *abstract_surface,
- cairo_operator_t op,
- cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_nquartz_surface_t *surface = (cairo_nquartz_surface_t *) abstract_surface;
- cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
- cairo_nquartz_action_t action;
- int i;
-
- if (num_glyphs <= 0)
- return CAIRO_STATUS_SUCCESS;
-
- if (op == CAIRO_OPERATOR_DEST)
- return CAIRO_STATUS_SUCCESS;
-
- if (!_cairo_scaled_font_is_atsui (scaled_font))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- CGContextSaveGState (surface->cgContext);
-
- action = _cairo_nquartz_setup_source (surface, source);
- if (action == DO_SOLID || action == DO_PATTERN) {
- CGContextSetTextDrawingMode (surface->cgContext, kCGTextFill);
- } else if (action == DO_SHADING) {
- CGContextSetTextDrawingMode (surface->cgContext, kCGTextClip);
- } else {
- /* Unsupported */
- CGContextRestoreGState (surface->cgContext);
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- double y_height = surface->extents.height;
-
- CGContextSetCompositeOperation (surface->cgContext, _cairo_nquartz_cairo_operator_to_quartz (op));
-
- ATSUFontID fid = _cairo_atsui_scaled_font_get_atsu_font_id (scaled_font);
- ATSFontRef atsfref = FMGetATSFontRefFromFont (fid);
- CGFontRef cgfref = CGFontCreateWithPlatformFont (&atsfref);
-
- CGContextSetFont (surface->cgContext, cgfref);
- CGFontRelease (cgfref);
-
- /* So this should include the size; I don't know if I need to extract the
- * size from this and call CGContextSetFontSize.. will I get crappy hinting
- * with this 1.0 size business? Or will CG just multiply that size into the
- * text matrix?
- */
- //ND((stderr, "show_glyphs: glyph 0 at: %f, %f\n", glyphs[0].x, glyphs[0].y));
- CGAffineTransform cairoTextTransform, textTransform;
- _cairo_nquartz_cairo_matrix_to_quartz (&scaled_font->font_matrix, &cairoTextTransform);
-
- textTransform = CGAffineTransformMakeTranslation (glyphs[0].x, glyphs[0].y);
- textTransform = CGAffineTransformScale (textTransform, 1.0, -1.0);
- textTransform = CGAffineTransformConcat (cairoTextTransform, textTransform);
-
- CGContextSetTextMatrix (surface->cgContext, textTransform);
- CGContextSetFontSize (surface->cgContext, 1.0);
-
- // XXXtodo/perf: stack storage for glyphs/sizes
-#define STATIC_BUF_SIZE 64
- CGGlyph glyphs_static[STATIC_BUF_SIZE];
- CGSize cg_advances_static[STATIC_BUF_SIZE];
- CGGlyph *cg_glyphs = &glyphs_static[0];
- CGSize *cg_advances = &cg_advances_static[0];
-
- if (num_glyphs > STATIC_BUF_SIZE) {
- cg_glyphs = (CGGlyph*) malloc(sizeof(CGGlyph) * num_glyphs);
- cg_advances = (CGSize*) malloc(sizeof(CGSize) * num_glyphs);
- }
-
- float xprev = glyphs[0].x;
- float yprev = glyphs[0].y;
-
- cg_glyphs[0] = glyphs[0].index;
- cg_advances[0].width = 0;
- cg_advances[0].height = 0;
-
- for (i = 1; i < num_glyphs; i++) {
- cg_glyphs[i] = glyphs[i].index;
- float xf = glyphs[i].x;
- float yf = glyphs[i].y;
- cg_advances[i-1].width = xf - xprev;
- cg_advances[i-1].height = yf - yprev;
- xprev = xf;
- yprev = yf;
- }
-
-#if 0
- for (i = 0; i < num_glyphs; i++) {
- ND((stderr, "[%d: %d %f,%f]\n", i, cg_glyphs[i], cg_advances[i].width, cg_advances[i].height));
- }
-#endif
-
- CGContextShowGlyphsWithAdvances (surface->cgContext,
- cg_glyphs,
- cg_advances,
- num_glyphs);
-
- if (cg_glyphs != &glyphs_static[0]) {
- free (cg_glyphs);
- free (cg_advances);
- }
-
- if (action == DO_SHADING)
- CGContextDrawShading (surface->cgContext, surface->sourceShading);
-
- _cairo_nquartz_teardown_source (surface, source);
-
- CGContextRestoreGState (surface->cgContext);
-
- return rv;
-}
-
-static cairo_int_status_t
-_cairo_nquartz_surface_mask (void *abstract_surface,
- cairo_operator_t op,
- cairo_pattern_t *source,
- cairo_pattern_t *mask)
-{
- cairo_nquartz_surface_t *surface = (cairo_nquartz_surface_t *) abstract_surface;
- cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
-
- ND((stderr, "%p _cairo_nquartz_surface_mask op %d source->type %d mask->type %d\n", surface, op, source->type, mask->type));
-
- if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
- /* This is easy; we just need to paint with the alpha. */
- cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask;
-
- CGContextSetAlpha (surface->cgContext, solid_mask->color.alpha);
- } else {
- /* So, CGContextClipToMask is not present in 10.3.9, so we're
- * doomed; if we have imageData, we can do fallback, otherwise
- * just pretend success.
- */
- if (surface->imageData)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- rv = _cairo_nquartz_surface_paint (surface, op, source);
-
- if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
- CGContextSetAlpha (surface->cgContext, 1.0);
- }
-
- ND((stderr, "-- mask\n"));
-
- return rv;
-}
-
-static cairo_int_status_t
-_cairo_nquartz_surface_intersect_clip_path (void *abstract_surface,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_nquartz_surface_t *surface = (cairo_nquartz_surface_t *) abstract_surface;
-
- ND((stderr, "%p _cairo_nquartz_surface_intersect_clip_path path: %p\n", surface, path));
-
- if (path == NULL) {
- /* If we're being asked to reset the clip, we can only do it
- * by restoring the gstate to our previous saved one, and
- * saving it again.
- *
- * Note that this assumes that ALL nquartz surface creation
- * functions will do a SaveGState first; we do this in create_internal.
- */
- CGContextRestoreGState (surface->cgContext);
- CGContextSaveGState (surface->cgContext);
- } else {
- CGContextBeginPath (surface->cgContext);
- _cairo_nquartz_cairo_path_to_quartz_context (path, surface->cgContext);
- if (fill_rule == CAIRO_FILL_RULE_WINDING)
- CGContextClip (surface->cgContext);
- else
- CGContextEOClip (surface->cgContext);
- }
-
- ND((stderr, "-- intersect_clip_path\n"));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-// XXXtodo implement show_page; need to figure out how to handle begin/end
-
-static const struct _cairo_surface_backend cairo_nquartz_surface_backend = {
- CAIRO_SURFACE_TYPE_NQUARTZ,
- _cairo_nquartz_surface_create_similar,
- _cairo_nquartz_surface_finish,
- _cairo_nquartz_surface_acquire_source_image,
- NULL, /* release_source_image */
- _cairo_nquartz_surface_acquire_dest_image,
- _cairo_nquartz_surface_release_dest_image,
- _cairo_nquartz_surface_clone_similar,
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* copy_page */
- NULL, /* show_page */
- NULL, /* set_clip_region */
- _cairo_nquartz_surface_intersect_clip_path,
- _cairo_nquartz_surface_get_extents,
- NULL, /* old_show_glyphs */
- NULL, /* get_font_options */
- NULL, /* flush */
- NULL, /* mark_dirty_rectangle */
- NULL, /* scaled_font_fini */
- NULL, /* scaled_glyph_fini */
-
- _cairo_nquartz_surface_paint,
- _cairo_nquartz_surface_mask,
- _cairo_nquartz_surface_stroke,
- _cairo_nquartz_surface_fill,
- _cairo_nquartz_surface_show_glyphs,
-
- NULL, /* snapshot */
-};
-
-cairo_bool_t
-cairo_surface_is_nquartz (cairo_surface_t *surf)
-{
- return (surf->backend == &cairo_nquartz_surface_backend);
-}
-
-static cairo_nquartz_surface_t *
-_cairo_nquartz_surface_create_internal (CGContextRef cgContext,
-#ifdef CAIRO_NQUARTZ_SUPPORT_AGL
- AGLContext aglContext,
-#else
- void * unused,
-#endif
- cairo_content_t content,
- unsigned int width,
- unsigned int height,
- cairo_bool_t y_grows_down)
-{
- cairo_nquartz_surface_t *surface;
-
- /* Init the base surface */
- surface = malloc(sizeof(cairo_nquartz_surface_t));
- if (surface == NULL) {
- _cairo_error (CAIRO_STATUS_NO_MEMORY);
- return NULL;
- }
-
- memset(surface, 0, sizeof(cairo_nquartz_surface_t));
-
- _cairo_surface_init(&surface->base, &cairo_nquartz_surface_backend,
- content);
-
- /* Save our extents */
- surface->extents.x = surface->extents.y = 0;
- surface->extents.width = width;
- surface->extents.height = height;
-
- if (!y_grows_down) {
- /* Then make the CGContext sane */
- CGContextTranslateCTM (cgContext, 0.0, surface->extents.height);
- CGContextScaleCTM (cgContext, 1.0, -1.0);
- }
-
- /* Save so we can always get back to a known-good CGContext -- this is
- * required for proper behaviour of intersect_clip_path(NULL)
- */
- CGContextSaveGState (cgContext);
-
-#ifdef CAIRO_NQUARTZ_SUPPORT_AGL
- surface->aglContext = aglContext;
-#endif
- surface->cgContext = cgContext;
- surface->cgContextBaseCTM = CGContextGetCTM (cgContext);
-
- surface->imageData = NULL;
-
- return surface;
-}
-
-#ifdef CAIRO_NQUARTZ_SUPPORT_AGL
-cairo_surface_t *
-cairo_nquartz_surface_create_for_agl_context (AGLContext aglContext,
- unsigned int width,
- unsigned int height,
- cairo_bool_t y_grows_down)
-{
- cairo_nquartz_surface_t *surf;
- CGSize sz;
-
- /* Make our CGContext from the AGL context */
- sz.width = width;
- sz.height = height;
-
- CGContextRef cgc = CGGLContextCreate (aglContext, sz, NULL /* device RGB colorspace */);
-
- surf = _cairo_nquartz_surface_create_internal (cgc, aglContext, CAIRO_CONTENT_COLOR_ALPHA,
- width, height, y_grows_down);
- if (!surf) {
- CGContextRelease (cgc);
- // create_internal will have set an error
- return (cairo_surface_t*) &_cairo_surface_nil;
- }
-
- return (cairo_surface_t *) surf;
-}
-#endif
-
-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_nquartz_surface_t *surf;
-
- CGContextRetain (cgContext);
-
- surf = _cairo_nquartz_surface_create_internal (cgContext, NULL, CAIRO_CONTENT_COLOR_ALPHA,
- width, height, y_grows_down);
- if (!surf) {
- CGContextRelease (cgContext);
- // create_internal will have set an error
- return (cairo_surface_t*) &_cairo_surface_nil;
- }
-
- return (cairo_surface_t *) surf;
-}
-
-cairo_surface_t *
-cairo_nquartz_surface_create (cairo_format_t format,
- unsigned int width,
- unsigned int height)
-{
- cairo_nquartz_surface_t *surf;
- CGContextRef cgc;
- CGColorSpaceRef cgColorspace;
- CGBitmapInfo bitinfo;
- void *imageData;
- int stride;
- int bitsPerComponent;
-
- if (format == CAIRO_FORMAT_ARGB32) {
- cgColorspace = CGColorSpaceCreateDeviceRGB();
- stride = width * 4;
- bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
- bitsPerComponent = 8;
- } else if (format == CAIRO_FORMAT_RGB24) {
- cgColorspace = CGColorSpaceCreateDeviceRGB();
- stride = width * 4;
- bitinfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
- bitsPerComponent = 8;
- } else if (format == CAIRO_FORMAT_A8) {
- cgColorspace = CGColorSpaceCreateDeviceGray();
- if (width % 4 == 0)
- stride = width;
- else
- stride = (width & ~3) + 4;
- bitinfo = kCGImageAlphaNone;
- bitsPerComponent = 8;
- } else if (format == CAIRO_FORMAT_A1) {
- /* I don't think we can usefully support this, as defined by
- * cairo_format_t -- these are 1-bit pixels stored in 32-bit
- * quantities.
- */
- _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
- return (cairo_surface_t*) &_cairo_surface_nil;
- } else {
- _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
- return (cairo_surface_t*) &_cairo_surface_nil;
- }
-
- imageData = malloc (height * stride);
- if (!imageData) {
- CGColorSpaceRelease (cgColorspace);
- _cairo_error (CAIRO_STATUS_NO_MEMORY);
- return (cairo_surface_t*) &_cairo_surface_nil;
- }
-
- cgc = CGBitmapContextCreate (imageData,
- width,
- height,
- bitsPerComponent,
- stride,
- cgColorspace,
- bitinfo);
- CGColorSpaceRelease (cgColorspace);
-
- if (!cgc) {
- _cairo_error (CAIRO_STATUS_NO_MEMORY);
- return (cairo_surface_t*) &_cairo_surface_nil;
- }
-
- surf = _cairo_nquartz_surface_create_internal (cgc, NULL, _cairo_content_from_format (format),
- width, height, FALSE);
- if (!surf) {
- CGContextRelease (cgc);
- // create_internal will have set an error
- return (cairo_surface_t*) &_cairo_surface_nil;
- }
-
- surf->imageData = imageData;
-
- return (cairo_surface_t *) surf;
-}
-
-CGContextRef
-cairo_nquartz_surface_get_cg_context (cairo_surface_t *surf)
-{
- cairo_nquartz_surface_t *nquartz = (cairo_nquartz_surface_t*)surf;
-
- if (!cairo_surface_is_nquartz(surf))
- return NULL;
-
- return nquartz->cgContext;
-}
-
-
-/* Debug stuff */
-
-#ifdef NQUARTZ_DEBUG
-
-#include <Movies.h>
-
-void ExportCGImageToPNGFile(CGImageRef inImageRef, char* dest)
-{
- Handle dataRef = NULL;
- OSType dataRefType;
- CFStringRef inPath = CFStringCreateWithCString(NULL, dest, kCFStringEncodingASCII);
-
- GraphicsExportComponent grex = 0;
- unsigned long sizeWritten;
-
- ComponentResult result;
-
- // create the data reference
- result = QTNewDataReferenceFromFullPathCFString(inPath, kQTNativeDefaultPathStyle,
- 0, &dataRef, &dataRefType);
-
- if (NULL != dataRef && noErr == result) {
- // get the PNG exporter
- result = OpenADefaultComponent(GraphicsExporterComponentType, kQTFileTypePNG,
- &grex);
-
- if (grex) {
- // tell the exporter where to find its source image
- result = GraphicsExportSetInputCGImage(grex, inImageRef);
-
- if (noErr == result) {
- // tell the exporter where to save the exporter image
- result = GraphicsExportSetOutputDataReference(grex, dataRef,
- dataRefType);
-
- if (noErr == result) {
- // write the PNG file
- result = GraphicsExportDoExport(grex, &sizeWritten);
- }
- }
-
- // remember to close the component
- CloseComponent(grex);
- }
-
- // remember to dispose of the data reference handle
- DisposeHandle(dataRef);
- }
-}
-#endif
-
-void
-nquartz_image_to_png (CGImageRef imgref, char *dest)
-{
-#if 0
- static int sctr = 0;
- char sptr[] = "/Users/vladimir/Desktop/barXXXXX.png";
-
- if (dest == NULL) {
- fprintf (stderr, "** Writing %p to bar%d\n", imgref, sctr);
- sprintf (sptr, "/Users/vladimir/Desktop/bar%d.png", sctr);
- sctr++;
- dest = sptr;
- }
-
- ExportCGImageToPNGFile(imgref, dest);
-#endif
-}
-
-void
-nquartz_surface_to_png (cairo_nquartz_surface_t *nq, char *dest)
-{
-#if 0
- static int sctr = 0;
- char sptr[] = "/Users/vladimir/Desktop/fooXXXXX.png";
-
- if (nq->base.type != CAIRO_SURFACE_TYPE_NQUARTZ) {
- fprintf (stderr, "** nquartz_surface_to_png: surface %p isn't nquartz!\n", nq);
- return;
- }
-
- if (dest == NULL) {
- fprintf (stderr, "** Writing %p to foo%d\n", nq, sctr);
- sprintf (sptr, "/Users/vladimir/Desktop/foo%d.png", sctr);
- sctr++;
- dest = sptr;
- }
-
- CGImageRef imgref = CGBitmapContextCreateImage (nq->cgContext);
- if (imgref == NULL) {
- fprintf (stderr, "nquartz surface at %p is not a bitmap context!\n", nq);
- return;
- }
-
- ExportCGImageToPNGFile(imgref, dest);
-
- CGImageRelease(imgref);
-#endif
-}
-
deleted file mode 100644
--- a/gfx/cairo/cairo/src/cairo-nquartz.h
+++ /dev/null
@@ -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 */
--- a/gfx/cairo/cairo/src/cairo-os2-surface.c
+++ b/gfx/cairo/cairo/src/cairo-os2-surface.c
@@ -64,21 +64,21 @@
* and termination, if the code is built to be a DLL.
* (if BUILD_CAIRO_DLL is defined)
*/
/* Initialization counter: */
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
DisableFPUException (void)
{
unsigned short usCW;
/* Some OS/2 PM API calls modify the FPU Control Word,
@@ -101,23 +101,23 @@ cairo_os2_init (void)
cairo_os2_initialization_count++;
if (cairo_os2_initialization_count > 1) return;
DisableFPUException ();
/* 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 */
FcInit ();
}
cairo_public void
cairo_os2_fini (void)
@@ -134,34 +134,34 @@ cairo_os2_fini (void)
/* (Check cairo_debug_reset_static_date () for an example of this!) */
_cairo_font_reset_static_data ();
#ifdef CAIRO_HAS_FT_FONT
_cairo_ft_font_reset_static_data ();
#endif
/* 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
/* Uninitialize FontConfig */
FcFini ();
#ifdef __WATCOMC__
/* It can happen that the libraries we use have memory leaks,
--- a/gfx/cairo/cairo/src/cairo-os2.h
+++ b/gfx/cairo/cairo/src/cairo-os2.h
@@ -189,13 +189,15 @@ cairo_os2_surface_set_manual_window_refr
/* cairo_os2_surface_get_manual_window_refresh () : */
/* */
/* This API can return the current mode of the surface. It is */
/* TRUE by default. */
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
#endif /* _CAIRO_OS2_H_ */
--- a/gfx/cairo/cairo/src/cairo-output-stream.c
+++ b/gfx/cairo/cairo/src/cairo-output-stream.c
@@ -219,16 +219,20 @@ int
_cairo_dtostr (char *buffer, size_t size, double d)
{
struct lconv *locale_data;
const char *decimal_point;
int decimal_point_len;
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 ();
decimal_point = locale_data->decimal_point;
decimal_point_len = strlen (decimal_point);
assert (decimal_point_len != 0);
p = buffer;
--- a/gfx/cairo/cairo/src/cairo-paginated-surface.c
+++ b/gfx/cairo/cairo/src/cairo-paginated-surface.c
@@ -65,16 +65,17 @@ typedef struct _cairo_paginated_surface
/* Paginated-surface specific functions for the target */
const cairo_paginated_surface_backend_t *backend;
/* A cairo_meta_surface to record all operations. To be replayed
* against target, and also against image surface as necessary for
* fallbacks. */
cairo_surface_t *meta;
+ int page_num;
cairo_bool_t page_is_blank;
} cairo_paginated_surface_t;
const cairo_private cairo_surface_backend_t cairo_paginated_surface_backend;
static cairo_int_status_t
_cairo_paginated_surface_show_page (void *abstract_surface);
@@ -117,16 +118,17 @@ cairo_surface_t *
surface->height = height;
surface->backend = backend;
surface->meta = _cairo_meta_surface_create (content, width, height);
if (cairo_surface_status (surface->meta))
goto FAIL_CLEANUP_SURFACE;
+ surface->page_num = 1;
surface->page_is_blank = TRUE;
return &surface->base;
FAIL_CLEANUP_SURFACE:
free (surface);
FAIL:
_cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -150,22 +152,32 @@ cairo_surface_t *
return paginated_surface->target;
}
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;
+
+ 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);
cairo_surface_destroy (surface->meta);
- cairo_surface_destroy (surface->target);
-
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
static cairo_surface_t *
_cairo_paginated_surface_create_image_surface (void *abstract_surface,
int width,
int height)
{
cairo_paginated_surface_t *surface = abstract_surface;
@@ -283,27 +295,27 @@ static cairo_int_status_t
cairo_paginated_surface_t *surface = abstract_surface;
status = _start_page (surface);
if (status)
return status;
_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
* copypage, for example), but the interaction with image
* fallbacks gets tricky. For now, we just let the target see a
* 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
_cairo_paginated_surface_show_page (void *abstract_surface)
{
cairo_status_t status;
cairo_paginated_surface_t *surface = abstract_surface;
@@ -317,16 +329,17 @@ static cairo_int_status_t
cairo_surface_destroy (surface->meta);
surface->meta = _cairo_meta_surface_create (surface->content,
surface->width, surface->height);
if (cairo_surface_status (surface->meta))
return cairo_surface_status (surface->meta);
+ surface->page_num++;
surface->page_is_blank = TRUE;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_paginated_surface_intersect_clip_path (void *abstract_surface,
cairo_path_fixed_t *path,
@@ -437,26 +450,41 @@ static cairo_int_status_t
_cairo_paginated_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
{
cairo_paginated_surface_t *surface = abstract_surface;
+ cairo_int_status_t status;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
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 *
_cairo_paginated_surface_snapshot (void *abstract_other)
{
cairo_paginated_surface_t *other = abstract_other;
/* XXX: Just making a snapshot of other->meta is what we really
--- a/gfx/cairo/cairo/src/cairo-path-fill.c
+++ b/gfx/cairo/cairo/src/cairo-path-fill.c
@@ -30,16 +30,17 @@
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
+#include "cairo-path-fixed-private.h"
typedef struct cairo_filler {
double tolerance;
cairo_traps_t *traps;
cairo_point_t current_point;
cairo_polygon_t polygon;
@@ -164,25 +165,35 @@ static cairo_status_t
status = _cairo_polygon_close (polygon);
if (status)
return status;
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,
double tolerance,
cairo_traps_t *traps)
{
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,
CAIRO_DIRECTION_FORWARD,
_cairo_filler_move_to,
_cairo_filler_line_to,
_cairo_filler_curve_to,
_cairo_filler_close_path,
@@ -200,8 +211,89 @@ cairo_status_t
if (status)
goto BAIL;
BAIL:
_cairo_filler_fini (&filler);
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;
+}
--- a/gfx/cairo/cairo/src/cairo-path-fixed-private.h
+++ b/gfx/cairo/cairo/src/cairo-path-fixed-private.h
@@ -37,39 +37,35 @@
#define CAIRO_PATH_FIXED_PRIVATE_H
typedef enum cairo_path_op {
CAIRO_PATH_OP_MOVE_TO = 0,
CAIRO_PATH_OP_LINE_TO = 1,
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;
+ int num_points;
+
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_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 */
--- a/gfx/cairo/cairo/src/cairo-path-fixed.c
+++ b/gfx/cairo/cairo/src/cairo-path-fixed.c
@@ -43,97 +43,80 @@
/* private functions */
static cairo_status_t
_cairo_path_fixed_add (cairo_path_fixed_t *path,
cairo_path_op_t op,
cairo_point_t *points,
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 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);
-
-static void
-_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op_buf);
+static cairo_path_buf_t *
+_cairo_path_buf_create (void);
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);
+_cairo_path_buf_destroy (cairo_path_buf_t *buf);
static void
-_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg_buf);
+_cairo_path_buf_add_op (cairo_path_buf_t *buf,
+ cairo_path_op_t op);
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;
path->has_current_point = FALSE;
path->has_curve_to = FALSE;
path->last_move_point = path->current_point;
}
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;
path->has_current_point = other->has_current_point;
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;
}
cairo_path_fixed_t *
_cairo_path_fixed_create (void)
{
@@ -143,32 +126,29 @@ cairo_path_fixed_t *
return NULL;
_cairo_path_fixed_init (path);
return path;
}
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;
}
void
_cairo_path_fixed_destroy (cairo_path_fixed_t *path)
{
@@ -184,21 +164,21 @@ cairo_status_t
cairo_status_t status;
cairo_point_t point;
point.x = x;
point.y = y;
/* 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);
if (status)
return status;
}
path->current_point = point;
@@ -371,143 +351,87 @@ cairo_status_t
}
static cairo_status_t
_cairo_path_fixed_add (cairo_path_fixed_t *path,
cairo_path_op_t op,
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;
+
+ path->buf_tail->next = buf;
+ path->buf_tail = buf;
+}
- if (path->op_buf_tail) {
- path->op_buf_tail->next = op_buf;
- } else {
- path->op_buf_head = op_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 */
1, /* cairo_path_op_line_to */
3, /* cairo_path_op_curve_to */
0, /* cairo_path_op_close_path */
};
@@ -516,117 +440,104 @@ cairo_status_t
cairo_direction_t dir,
cairo_path_fixed_move_to_func_t *move_to,
cairo_path_fixed_line_to_func_t *line_to,
cairo_path_fixed_curve_to_func_t *curve_to,
cairo_path_fixed_close_path_func_t *close_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:
status = (*close_path) (closure);
break;
}
if (status)
return status;
+
+ if (forward) {
+ points += num_args[op];
+ }
+
}
}
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
cairo_fixed_t offx,
cairo_fixed_t offy,
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;
}
}
/**
* _cairo_path_fixed_device_transform:
* @path: a #cairo_path_fixed_t to be transformed
* @device_transform: a matrix with only scaling/translation (no rotation or shear)
--- a/gfx/cairo/cairo/src/cairo-path-stroke.c
+++ b/gfx/cairo/cairo/src/cairo-path-stroke.c
@@ -46,27 +46,28 @@ typedef struct cairo_stroker {
cairo_traps_t *traps;
cairo_pen_t pen;
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;
cairo_bool_t has_first_face;
cairo_stroke_face_t first_face;
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;
/* private functions */
static void
_cairo_stroker_init (cairo_stroker_t *stroker,
cairo_stroke_style_t *stroke_style,
cairo_matrix_t *ctm,
@@ -109,45 +110,45 @@ static int
static cairo_status_t
_cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_stroke_face_t *out);
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;
/* We stop searching for a starting point as soon as the
offset reaches zero. Otherwise when an initial dash
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;
}
static void
_cairo_stroker_step_dash (cairo_stroker_t *stroker, double step)
{
stroker->dash_remain -= step;
if (stroker->dash_remain <= 0) {
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];
}
}
static void
_cairo_stroker_init (cairo_stroker_t *stroker,
cairo_stroke_style_t *stroke_style,
cairo_matrix_t *ctm,
@@ -162,17 +163,17 @@ static void
stroker->traps = traps;
_cairo_pen_init (&stroker->pen,
stroke_style->line_width / 2.0,
tolerance, ctm);
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);
else
stroker->dashed = FALSE;
}
static void
@@ -461,27 +462,35 @@ static cairo_status_t
static void
_compute_face (cairo_point_t *point, cairo_slope_t *slope, cairo_stroker_t *stroker, cairo_stroke_face_t *face);
static cairo_status_t
_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;
+
+ /* arbitrarily choose first_point
+ * first_point and current_point should be the same */
+ _compute_face (&stroker->first_point, &slope, stroker, &face);
- stroker->has_first_face = stroker->has_current_face = TRUE;
- stroker->current_face = stroker->first_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) {
status = _cairo_stroker_add_leading_cap (stroker, &stroker->first_face);
if (status)
return status;
}
@@ -589,26 +598,27 @@ static cairo_status_t
}
static cairo_status_t
_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;
stroker->first_point = *point;
stroker->current_point = *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;
}
static cairo_status_t
_cairo_stroker_move_to_dashed (void *closure, cairo_point_t *point)
{
/* reset the dash pattern for new sub paths */
@@ -623,36 +633,36 @@ static cairo_status_t
{
cairo_status_t status;
cairo_stroker_t *stroker = closure;
cairo_stroke_face_t start, end;
cairo_point_t *p1 = &stroker->current_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;
_cairo_slope_init (&slope, p1, p2);
status = _cairo_stroker_add_sub_edge (stroker, p1, p2, &slope, &start, &end);
if (status)
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;
stroker->current_point = *point;
return CAIRO_STATUS_SUCCESS;
}
@@ -660,122 +670,106 @@ static cairo_status_t
/*
* Dashed lines. Cap each dash end, join around turns when on
*/
static cairo_status_t
_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;
_cairo_slope_init (&slope, p1, p2);
dx = _cairo_fixed_to_double (p2->x - p1->x);
dy = _cairo_fixed_to_double (p2->y - p1->y);
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 (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;
}
- if (!remain)
- 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;
return status;
}
static cairo_status_t
@@ -802,21 +796,19 @@ static cairo_status_t
_compute_face (a, &spline.initial_slope, stroker, &start);
_compute_face (d, &spline.final_slope, stroker, &end);
if (stroker->has_current_face) {
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;
extra_points[0] = start.cw;
extra_points[0].x -= start.point.x;
extra_points[0].y -= start.point.y;
extra_points[1] = start.ccw;
@@ -923,26 +915,28 @@ static cairo_status_t
if (stroker->dashed)
status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point);
else
status = _cairo_stroker_line_to (stroker, &stroker->first_point);
if (status)
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;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path,
@@ -991,16 +985,17 @@ cairo_status_t
_cairo_stroker_move_to,
_cairo_stroker_line_to,
_cairo_stroker_curve_to,
_cairo_stroker_close_path,
&stroker);
if (status)
goto BAIL;
+ /* Cap the start and end of the final sub path as needed */
status = _cairo_stroker_add_caps (&stroker);
BAIL:
_cairo_stroker_fini (&stroker);
return status;
}
@@ -1282,21 +1277,22 @@ static cairo_int_status_t
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_rectilinear_stroker_move_to,
_cairo_rectilinear_stroker_line_to,
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;
}
--- a/gfx/cairo/cairo/src/cairo-path.c
+++ b/gfx/cairo/cairo/src/cairo-path.c
@@ -460,37 +460,37 @@ cairo_status_t
{
int i;
cairo_path_data_t *p;
for (i=0; i < path->num_data; i += path->data[i].header.length) {
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,
p[2].point.x, p[2].point.y,
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;
default:
return CAIRO_STATUS_INVALID_PATH_DATA;
}
}
--- a/gfx/cairo/cairo/src/cairo-pattern.c
+++ b/gfx/cairo/cairo/src/cairo-pattern.c
@@ -29,25 +29,27 @@
*/
#include "cairoint.h"
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 */
};
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 */
};
/**
* _cairo_pattern_set_error:
* @pattern: a pattern
@@ -79,16 +81,18 @@ static void
static void
_cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
{
pattern->type = 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
pattern->extend = CAIRO_EXTEND_GRADIENT_DEFAULT;
pattern->filter = CAIRO_FILTER_DEFAULT;
cairo_matrix_init_identity (&pattern->matrix);
@@ -108,21 +112,25 @@ static void
else
{
cairo_radial_pattern_t *dst = (cairo_radial_pattern_t *) pattern;
cairo_radial_pattern_t *src = (cairo_radial_pattern_t *) other;
*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;
}
memcpy (pattern->stops, other->stops,
other->n_stops * sizeof (pixman_gradient_stop_t));
}
}
@@ -160,31 +168,33 @@ void
}
pattern->ref_count = 1;
}
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;
case CAIRO_PATTERN_TYPE_SURFACE: {
cairo_surface_pattern_t *surface_pattern =
(cairo_surface_pattern_t *) pattern;
cairo_surface_destroy (surface_pattern->surface);
} break;
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL: {
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;
}
}
void
_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
const cairo_color_t *color)
@@ -210,18 +220,19 @@ void
}
static void
_cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern,
cairo_pattern_type_t type)
{
_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
_cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
double x0, double y0, double x1, double y1)
{
_cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_LINEAR);
@@ -233,22 +244,22 @@ void
void
_cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
double cx0, double cy0, double radius0,
double cx1, double cy1, double radius1)
{
_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 *
_cairo_pattern_create_solid (const cairo_color_t *color)
{
cairo_solid_pattern_t *pattern;
pattern = malloc (sizeof (cairo_solid_pattern_t));
@@ -485,25 +496,25 @@ cairo_pattern_create_radial (double cx0,
/**
* cairo_pattern_reference:
* @pattern: a #cairo_pattern_t
*
* Increases the reference count on @pattern by one. This prevents
* @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);
pattern->ref_count++;
return pattern;
}
@@ -550,73 +561,180 @@ slim_hidden_def (cairo_pattern_status);
*
* Decreases the reference count on @pattern by one. If the result is
* zero, then @pattern and all associated resources are freed. See
* cairo_pattern_reference().
**/
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);
pattern->ref_count--;
if (pattern->ref_count)
return;
_cairo_pattern_fini (pattern);
free (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,
double red,
double green,
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++;
}
/**
* cairo_pattern_add_color_stop_rgb:
* @pattern: a #cairo_pattern_t
* @offset: an offset in the range [0.0 .. 1.0]
@@ -762,25 +880,43 @@ slim_hidden_def (cairo_pattern_set_matri
* Stores the pattern's transformation matrix into @matrix.
**/
void
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)
{
if (pattern->status)
return;
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)
{
return pattern->filter;
}
/**
* cairo_pattern_set_extend:
@@ -1139,65 +1275,157 @@ static cairo_int_status_t
else
{
attr->matrix = pattern->base.matrix;
attr->x_offset = attr->y_offset = 0;
tx = 0;
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;
status = _cairo_surface_acquire_source_image (pattern->surface,
&image,
&attr->extra);
if (status)
return status;
*out = &image->base;
attr->acquired = TRUE;
}
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;
height = extents.height;
} else {
/* Otherwise, we first transform the rectangle to the
* coordinate space of the source surface so that we can
* clone only that portion of the surface that will be
* read. */
if (! _cairo_matrix_is_identity (&attr->matrix)) {
double x1 = x;
double y1 = y;
double x2 = x + width;
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;
}
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;
}
/**
* _cairo_pattern_acquire_surface:
* @pattern: a #cairo_pattern_t
@@ -1251,20 +1479,20 @@ cairo_int_status_t
{
cairo_solid_pattern_t solid;
if (src->n_stops)
{
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);
}
else
{
const cairo_color_t *color;
color = _cairo_stock_color (CAIRO_STOCK_TRANSPARENT);
@@ -1446,16 +1674,17 @@ cairo_status_t
status = _cairo_surface_get_extents (surface, &surface_extents);
if (status)
return status;
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;
y = surface_extents.y + sy * surface_extents.height;
cairo_matrix_transform_point (&imatrix, &x, &y);
if (x < 0) x = 0;
if (x > INT16_MAX) x = INT16_MAX;
if (y < 0) y = 0;
@@ -1564,16 +1793,17 @@ cairo_pattern_get_surface (cairo_pattern
return CAIRO_STATUS_SUCCESS;
}
/**
* 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
* @alpha: return value for alpha component of color, or %NULL
*
* Gets the color and offset information at the given @index for a
* gradient pattern. Values of @index are 0 to 1 less than the number
* returned by cairo_pattern_get_color_stop_count().
@@ -1680,22 +1910,22 @@ cairo_pattern_get_linear_points (cairo_p
*y1 = _cairo_fixed_to_double (linear->gradient.p2.y);
return CAIRO_STATUS_SUCCESS;
}
/**
* 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.
*
* Return value: %CAIRO_STATUS_SUCCESS, or
* %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a radial
* gradient pattern.
*
@@ -1707,22 +1937,22 @@ cairo_pattern_get_radial_circles (cairo_
double *x1, double *y1, double *r1)
{
cairo_radial_pattern_t *radial = (cairo_radial_pattern_t*) pattern;
if (pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
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;
}
--- a/gfx/cairo/cairo/src/cairo-pdf-surface.c
+++ b/gfx/cairo/cairo/src/cairo-pdf-surface.c
@@ -272,17 +272,18 @@ static cairo_surface_t *
_cairo_array_init (&surface->objects, sizeof (cairo_pdf_object_t));
_cairo_array_init (&surface->pages, sizeof (cairo_pdf_resource_t));
_cairo_array_init (&surface->patterns, sizeof (cairo_pdf_resource_t));
_cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t));
_cairo_array_init (&surface->streams, sizeof (cairo_pdf_resource_t));
_cairo_array_init (&surface->alphas, sizeof (double));
- surface->font_subsets = _cairo_scaled_font_subsets_create (PDF_SURFACE_MAX_GLYPHS_PER_FONT);
+ surface->font_subsets = _cairo_scaled_font_subsets_create (PDF_SURFACE_MAX_GLYPHS_PER_FONT,
+ PDF_SURFACE_MAX_GLYPHS_PER_FONT);
if (! surface->font_subsets) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
free (surface);
return (cairo_surface_t*) &_cairo_surface_nil;
}
_cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
@@ -374,17 +375,19 @@ cairo_pdf_surface_create (const char *f
{
cairo_status_t status;
cairo_output_stream_t *output;
output = _cairo_output_stream_create_for_filename (filename);
status = _cairo_output_stream_get_status (output);
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_pdf_surface_create_for_stream_internal (output,
width_in_points,
height_in_points);
}
static cairo_bool_t
@@ -649,17 +652,17 @@ compress_dup (const void *data, unsigned
/* Emit alpha channel from the image into the given data, providing
* an id that can be used to reference the resulting SMask object.
*
* In the case that the alpha channel happens to be all opaque, then
* no SMask object will be emitted and *id_ret will be set to 0.
*/
static cairo_status_t
-emit_smask (cairo_pdf_surface_t *surface,
+_cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface,
cairo_image_surface_t *image,
cairo_pdf_resource_t *stream_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
char *alpha, *alpha_compressed;
unsigned long alpha_size, alpha_compressed_size;
pixman_bits_t *pixel;
int i, x, y;
@@ -720,17 +723,17 @@ emit_smask (cairo_pdf_surface_t *surfac
free (alpha);
CLEANUP:
return status;
}
/* Emit image data into the given surface, providing a resource that
* can be used to reference the data in image_ret. */
static cairo_status_t
-emit_image (cairo_pdf_surface_t *surface,
+_cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
cairo_image_surface_t *image,
cairo_pdf_resource_t *image_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
char *rgb, *compressed;
unsigned long rgb_size, compressed_size;
pixman_bits_t *pixel;
int i, x, y;
@@ -739,17 +742,17 @@ emit_image (cairo_pdf_surface_t *surfac
/* XXX: Need to rewrite this as a pdf_surface function with
* pause/resume of content_stream, (currently the only caller does
* the pause/resume already, but that is expected to change in the
* future). */
/* These are the only image formats we currently support, (which
* makes things a lot simpler here). This is enforced through
- * _analyze_operation which only accept source surfaces of
+ * _cairo_pdf_surface_analyze_operation which only accept source surfaces of
* CONTENT_COLOR or CONTENT_COLOR_ALPHA.
*/
assert (image->format == CAIRO_FORMAT_RGB24 || image->format == CAIRO_FORMAT_ARGB32);
rgb_size = image->height * image->width * 3;
rgb = malloc (rgb_size);
if (rgb == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
@@ -789,17 +792,17 @@ emit_image (cairo_pdf_surface_t *surfac
compressed = compress_dup (rgb, rgb_size, &compressed_size);
if (compressed == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto CLEANUP_RGB;
}
need_smask = FALSE;
if (image->format == CAIRO_FORMAT_ARGB32) {
- status = emit_smask (surface, image, &smask);
+ status = _cairo_pdf_surface_emit_smask (surface, image, &smask);
if (status)
goto CLEANUP_COMPRESSED;
if (smask.id)
need_smask = TRUE;
}
#define IMAGE_DICTIONARY " /Type /XObject\r\n" \
@@ -833,17 +836,17 @@ emit_image (cairo_pdf_surface_t *surfac
free (compressed);
CLEANUP_RGB:
free (rgb);
CLEANUP:
return status;
}
static cairo_status_t
-emit_solid_pattern (cairo_pdf_surface_t *surface,
+_cairo_pdf_surface_emit_solid_pattern (cairo_pdf_surface_t *surface,
cairo_solid_pattern_t *pattern)
{
cairo_pdf_resource_t alpha;
alpha = _cairo_pdf_surface_add_alpha (surface, pattern->color.alpha);
/* With some work, we could separate the stroking
* or non-stroking color here as actually needed. */
@@ -858,87 +861,90 @@ emit_solid_pattern (cairo_pdf_surface_t
pattern->color.green,
pattern->color.blue,
alpha.id);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-emit_surface_pattern (cairo_pdf_surface_t *surface,
+_cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
cairo_surface_pattern_t *pattern)
{
cairo_pdf_resource_t stream;
+ cairo_surface_t *pat_surface;
+ cairo_surface_attributes_t pat_attr;
cairo_image_surface_t *image;
void *image_extra;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_pdf_resource_t alpha, image_resource = {0}; /* squelch bogus compiler warning */
cairo_matrix_t cairo_p2d, pdf_p2d;
cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base);
- int xstep, ystep;
+ double xstep, ystep;
cairo_rectangle_int16_t surface_extents;
/* XXX: Should do something clever here for PDF source surfaces ? */
_cairo_pdf_surface_pause_content_stream (surface);
- status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
+ status = _cairo_pattern_acquire_surface ((cairo_pattern_t *)pattern,
+ (cairo_surface_t *)surface,
+ 0, 0, -1, -1,
+ &pat_surface, &pat_attr);
if (status)
return status;
- status = emit_image (surface, image, &image_resource);
+ status = _cairo_surface_acquire_source_image (pat_surface, &image, &image_extra);
+ if (status)
+ goto BAIL2;
+
+ status = _cairo_pdf_surface_emit_image (surface, image, &image_resource);
if (status)
goto BAIL;
_cairo_surface_get_extents (&surface->base, &surface_extents);
switch (extend) {
+ /* We implement EXTEND_PAD like EXTEND_NONE for now */
+ case CAIRO_EXTEND_PAD:
case CAIRO_EXTEND_NONE:
{
- /* In PDF, (as far as I can tell), all patterns are
+ /* 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 pattern's extents through the inverse
- * pattern matrix to compute the device-space bounds of
- * the desired single occurrence. Then consider the bounds
- * of (the union of this rectangle with the target surface
- * extents). If the repeat size is larger than the
- * diagonal of the bounds of the union, then it is
- * guaranteed to never repeat visibly.
+ * 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 = image->width, y2 = image->height;
- cairo_matrix_t surface_to_device = pattern->base.matrix;
- cairo_matrix_invert (&surface_to_device);
- cairo_matrix_transform_bounding_box (&surface_to_device,
- &x1, &y1, &x2, &y2,
- NULL);
+ 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. */
- x1 = MAX (fabs(x1), fabs(x2)) + surface_extents.width;
- y1 = MAX (fabs(y1), fabs(y2)) + surface_extents.height;
- /* Similarly, don't bother computing the square root to
- * determine the length of the final diagonal. */
- xstep = _cairo_lround (ceil (x1 * y1));
- ystep = _cairo_lround (ceil (x1 * y1));
+ * 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 this case
- * should be unreachable. */
- case CAIRO_EXTEND_REFLECT:
- case CAIRO_EXTEND_PAD:
+ /* All the rest (if any) should have been analyzed away, so this
+ * case should be unreachable. */
default:
ASSERT_NOT_REACHED;
xstep = 0;
ystep = 0;
}
/* At this point, (that is, within the surface backend interface),
* the pattern's matrix maps from cairo's device space to cairo's
@@ -975,18 +981,18 @@ emit_surface_pattern (cairo_pdf_surface_
cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d);
cairo_matrix_translate (&pdf_p2d, 0.0, image->height);
cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
stream = _cairo_pdf_surface_open_stream (surface,
FALSE,
" /BBox [0 0 %d %d]\r\n"
- " /XStep %d\r\n"
- " /YStep %d\r\n"
+ " /XStep %f\r\n"
+ " /YStep %f\r\n"
" /PatternType 1\r\n"
" /TilingType 1\r\n"
" /PaintType 1\r\n"
" /Matrix [ %f %f %f %f %f %f ]\r\n"
" /Resources << /XObject << /res%d %d 0 R >> >>\r\n",
image->width, image->height,
xstep, ystep,
pdf_p2d.xx, pdf_p2d.yx,
@@ -1011,29 +1017,31 @@ emit_surface_pattern (cairo_pdf_surface_
* or non-stroking pattern here as actually needed. */
_cairo_output_stream_printf (surface->output,
"/Pattern CS /res%d SCN "
"/Pattern cs /res%d scn "
"/a%d gs\r\n",
stream.id, stream.id, alpha.id);
BAIL:
- _cairo_surface_release_source_image (pattern->surface, image, image_extra);
+ _cairo_surface_release_source_image (pat_surface, image, image_extra);
+ BAIL2:
+ _cairo_pattern_release_surface ((cairo_pattern_t *)pattern, pat_surface, &pat_attr);
return status;
}
typedef struct _cairo_pdf_color_stop {
double offset;
cairo_pdf_resource_t gradient;
unsigned char color_char[4];
} cairo_pdf_color_stop_t;
static cairo_pdf_resource_t
-emit_linear_colorgradient (cairo_pdf_surface_t *surface,
+_cairo_pdf_surface_emit_linear_colorgradient (cairo_pdf_surface_t *surface,
cairo_pdf_color_stop_t *stop1,
cairo_pdf_color_stop_t *stop2)
{
cairo_pdf_resource_t function = _cairo_pdf_surface_new_object (surface);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\r\n"
"<< /FunctionType 0\r\n"
@@ -1052,26 +1060,26 @@ emit_linear_colorgradient (cairo_pdf_sur
"\r\n"
"endstream\r\n"
"endobj\r\n");
return function;
}
static cairo_pdf_resource_t
-emit_stitched_colorgradient (cairo_pdf_surface_t *surface,
+_cairo_pdf_surface_emit_stitched_colorgradient (cairo_pdf_surface_t *surface,
unsigned int n_stops,
cairo_pdf_color_stop_t stops[])
{
cairo_pdf_resource_t function;
unsigned int i;
/* emit linear gradients between pairs of subsequent stops... */
for (i = 0; i < n_stops-1; i++) {
- stops[i].gradient = emit_linear_colorgradient (surface,
+ stops[i].gradient = _cairo_pdf_surface_emit_linear_colorgradient (surface,
&stops[i],
&stops[i+1]);
}
/* ... and stitch them together */
function = _cairo_pdf_surface_new_object (surface);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\r\n"
@@ -1114,17 +1122,17 @@ emit_stitched_colorgradient (cairo_pdf_s
"endobj\r\n");
return function;
}
#define COLOR_STOP_EPSILON 1e-6
static cairo_pdf_resource_t
-emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern)
+_cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern)
{
cairo_pdf_resource_t function;
cairo_pdf_color_stop_t *allstops, *stops;
unsigned int i, n_stops;
function = _cairo_pdf_surface_new_object (surface);
allstops = malloc ((pattern->n_stops + 2) * sizeof (cairo_pdf_color_stop_t));
@@ -1157,40 +1165,40 @@ emit_pattern_stops (cairo_pdf_surface_t
&stops[n_stops - 1],
sizeof (cairo_pdf_color_stop_t));
stops[n_stops].offset = 1.0;
n_stops++;
}
if (n_stops == 2) {
/* no need for stitched function */
- function = emit_linear_colorgradient (surface, &stops[0], &stops[1]);
+ function = _cairo_pdf_surface_emit_linear_colorgradient (surface, &stops[0], &stops[1]);
} else {
/* multiple stops: stitch. XXX possible optimization: regulary spaced
* stops do not require stitching. XXX */
- function = emit_stitched_colorgradient (surface,
+ function = _cairo_pdf_surface_emit_stitched_colorgradient (surface,
n_stops,
stops);
}
free (allstops);
return function;
}
static cairo_status_t
-emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern)
+_cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern)
{
cairo_pdf_resource_t function, pattern_resource, alpha;
double x0, y0, x1, y1;
cairo_matrix_t p2u;
_cairo_pdf_surface_pause_content_stream (surface);
- function = emit_pattern_stops (surface, &pattern->base);
+ function = _cairo_pdf_surface_emit_pattern_stops (surface, &pattern->base);
if (function.id == 0)
return CAIRO_STATUS_NO_MEMORY;
p2u = pattern->base.base.matrix;
cairo_matrix_invert (&p2u);
x0 = _cairo_fixed_to_double (pattern->gradient.p1.x);
y0 = _cairo_fixed_to_double (pattern->gradient.p1.y);
@@ -1235,38 +1243,38 @@ emit_linear_pattern (cairo_pdf_surface_t
alpha.id);
_cairo_pdf_surface_resume_content_stream (surface);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern)
+_cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern)
{
cairo_pdf_resource_t function, pattern_resource, alpha;
double x0, y0, x1, y1, r0, r1;
cairo_matrix_t p2u;
_cairo_pdf_surface_pause_content_stream (surface);
- function = emit_pattern_stops (surface, &pattern->base);
+ function = _cairo_pdf_surface_emit_pattern_stops (surface, &pattern->base);
if (function.id == 0)
return CAIRO_STATUS_NO_MEMORY;
p2u = pattern->base.base.matrix;
cairo_matrix_invert (&p2u);
- 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);
+ x0 = _cairo_fixed_to_double (pattern->gradient.c1.x);
+ y0 = _cairo_fixed_to_double (pattern->gradient.c1.y);
+ r0 = _cairo_fixed_to_double (pattern->gradient.c1.radius);
cairo_matrix_transform_point (&p2u, &x0, &y0);
- 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);
+ x1 = _cairo_fixed_to_double (pattern->gradient.c2.x);
+ y1 = _cairo_fixed_to_double (pattern->gradient.c2.y);
+ r1 = _cairo_fixed_to_double (pattern->gradient.c2.radius);
cairo_matrix_transform_point (&p2u, &x1, &y1);
/* FIXME: This is surely crack, but how should you scale a radius
* in a non-orthogonal coordinate system? */
cairo_matrix_transform_distance (&p2u, &r0, &r1);
/* FIXME: There is a difference between the cairo gradient extend
* semantics and PDF extend semantics. PDFs extend=false means
@@ -1311,30 +1319,30 @@ emit_radial_pattern (cairo_pdf_surface_t
alpha.id);
_cairo_pdf_surface_resume_content_stream (surface);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-emit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+_cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
{
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
- return emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
+ return _cairo_pdf_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
case CAIRO_PATTERN_TYPE_SURFACE:
- return emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern);
+ return _cairo_pdf_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern);
case CAIRO_PATTERN_TYPE_LINEAR:
- return emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
+ return _cairo_pdf_surface_emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
case CAIRO_PATTERN_TYPE_RADIAL:
- return emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern);
+ return _cairo_pdf_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern);
}
ASSERT_NOT_REACHED;
return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
}
static cairo_int_status_t
@@ -1625,21 +1633,100 @@ static void
/* TODO: Figure out wich other defaults to be inherited by /Page
* objects. */
_cairo_output_stream_printf (surface->output,
">>\r\n"
"endobj\r\n");
}
+static cairo_pdf_resource_t
+_cairo_pdf_surface_emit_toUnicode_stream (cairo_pdf_surface_t *surface,
+ cairo_scaled_font_subset_t *font_subset)
+{
+ const cairo_scaled_font_backend_t *backend;
+ cairo_pdf_resource_t stream;
+ unsigned int i;
+
+ if (font_subset->to_unicode == NULL) {
+ stream.id = 0;
+ return stream;
+ }
+
+ if (_cairo_truetype_create_glyph_to_unicode_map (font_subset) != CAIRO_STATUS_SUCCESS) {
+ backend = font_subset->scaled_font->backend;
+ if (backend->map_glyphs_to_unicode == NULL) {
+ stream.id = 0;
+ return stream;
+ }
+ backend->map_glyphs_to_unicode (font_subset->scaled_font, font_subset);
+ }
+
+ stream = _cairo_pdf_surface_open_stream (surface, FALSE, NULL);
+ _cairo_output_stream_printf (surface->output,
+ "/CIDInit /ProcSet findresource begin\r\n"
+ "12 dict begin\r\n"
+ "begincmap\r\n"
+ "/CIDSystemInfo\r\n"
+ "<< /Registry (Cairo)\r\n"
+ " /Ordering (ToUnicode-%d-%d)\r\n"
+ " /Supplement 0\r\n"
+ ">> def\r\n"
+ "/CMapName /Cairo-ToUnicode-%d-%d def\r\n"
+ "/CMapType 2 def\r\n"
+ "1 begincodespacerange\r\n"
+ "<00> <ff>\r\n"
+ "endcodespacerange\r\n",
+ font_subset->font_id,
+ font_subset->subset_id,
+ font_subset->font_id,
+ font_subset->subset_id);
+
+ /* The CMap specification has a limit of 100 characters per beginbfchar operator */
+ _cairo_output_stream_printf (surface->output,
+ "%d beginbfchar\r\n",
+ font_subset->num_glyphs > 100 ? 100 : font_subset->num_glyphs);
+ for (i = 0; i < font_subset->num_glyphs; i++) {
+ if (i != 0 && i % 100 == 0) {
+ _cairo_output_stream_printf (surface->output,
+ "endbfchar\r\n"
+ "%d beginbfchar\r\n",
+ font_subset->num_glyphs - i > 100 ? 100 : font_subset->num_glyphs - i);
+ }
+ _cairo_output_stream_printf (surface->output,
+ "<%02x> <%04x>\r\n",
+ i, font_subset->to_unicode[i]);
+ }
+ _cairo_output_stream_printf (surface->output,
+ "endbfchar\r\n");
+
+ if (font_subset->num_glyphs < 256) {
+ _cairo_output_stream_printf (surface->output,
+ "1 beginnotdefrange\r\n"
+ "<%02x> <ff> 0\r\n"
+ "endnotdefrange\r\n",
+ font_subset->num_glyphs);
+ }
+
+ _cairo_output_stream_printf (surface->output,
+ "endcmap\r\n"
+ "CMapName currentdict /CMap defineresource pop\r\n"
+ "end\r\n"
+ "end\r\n");
+
+ _cairo_pdf_surface_close_stream (surface);
+
+ return stream;
+}
+
static cairo_status_t
_cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface,
cairo_scaled_font_subset_t *font_subset)
{
- cairo_pdf_resource_t stream, descriptor, subset_resource;
+ cairo_pdf_resource_t stream, descriptor, subset_resource, to_unicode_stream;
cairo_status_t status;
cairo_pdf_font_t font;
cairo_cff_subset_t subset;
unsigned long compressed_length;
char *compressed;
unsigned int i;
char name[64];
@@ -1667,16 +1754,18 @@ static cairo_status_t
compressed_length);
_cairo_output_stream_write (surface->output, compressed, compressed_length);
_cairo_output_stream_printf (surface->output,
"\r\n"
"endstream\r\n"
"endobj\r\n");
free (compressed);
+ to_unicode_stream = _cairo_pdf_surface_emit_toUnicode_stream (surface, font_subset);
+
descriptor = _cairo_pdf_surface_new_object (surface);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\r\n"
"<< /Type /FontDescriptor\r\n"
" /FontName /%s\r\n"
" /Flags 4\r\n"
" /FontBBox [ %ld %ld %ld %ld ]\r\n"
" /ItalicAngle 0\r\n"
@@ -1705,26 +1794,33 @@ static cairo_status_t
" /Subtype /Type1\r\n"
" /BaseFont /%s\r\n"
" /FirstChar 0\r\n"
" /LastChar %d\r\n"
" /FontDescriptor %d 0 R\r\n"
" /Widths [",
subset_resource.id,
subset.base_font,
- font_subset->num_glyphs,
+ font_subset->num_glyphs - 1,
descriptor.id);
for (i = 0; i < font_subset->num_glyphs; i++)
_cairo_output_stream_printf (surface->output,
" %d",
subset.widths[i]);
_cairo_output_stream_printf (surface->output,
- " ]\r\n"
+ " ]\r\n");
+
+ if (to_unicode_stream.id != 0)
+ _cairo_output_stream_printf (surface->output,
+ " /ToUnicode %d 0 R\r\n",
+ to_unicode_stream.id);
+
+ _cairo_output_stream_printf (surface->output,
">>\r\n"
"endobj\r\n");
font.font_id = font_subset->font_id;
font.subset_id = font_subset->subset_id;
font.subset_resource = subset_resource;
_cairo_array_append (&surface->fonts, &font);
@@ -1733,17 +1829,17 @@ static cairo_status_t
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface,
cairo_scaled_font_subset_t *font_subset,
cairo_type1_subset_t *subset)
{
- cairo_pdf_resource_t stream, descriptor, subset_resource;
+ cairo_pdf_resource_t stream, descriptor, subset_resource, to_unicode_stream;
cairo_pdf_font_t font;
unsigned long length, compressed_length;
char *compressed;
unsigned int i;
/* We ignore the zero-trailer and set Length3 to 0. */
length = subset->header_length + subset->data_length;
@@ -1767,16 +1863,18 @@ static cairo_status_t
subset->data_length);
_cairo_output_stream_write (surface->output, compressed, compressed_length);
_cairo_output_stream_printf (surface->output,
"\r\n"
"endstream\r\n"
"endobj\r\n");
free (compressed);
+ to_unicode_stream = _cairo_pdf_surface_emit_toUnicode_stream (surface, font_subset);
+
descriptor = _cairo_pdf_surface_new_object (surface);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\r\n"
"<< /Type /FontDescriptor\r\n"
" /FontName /%s\r\n"
" /Flags 4\r\n"
" /FontBBox [ %ld %ld %ld %ld ]\r\n"
" /ItalicAngle 0\r\n"
@@ -1814,17 +1912,24 @@ static cairo_status_t
descriptor.id);
for (i = 0; i < font_subset->num_glyphs; i++)
_cairo_output_stream_printf (surface->output,
" %d",
subset->widths[i]);
_cairo_output_stream_printf (surface->output,
- " ]\r\n"
+ " ]\r\n");
+
+ if (to_unicode_stream.id != 0)
+ _cairo_output_stream_printf (surface->output,
+ " /ToUnicode %d 0 R\r\n",
+ to_unicode_stream.id);
+
+ _cairo_output_stream_printf (surface->output,
">>\r\n"
"endobj\r\n");
font.font_id = font_subset->font_id;
font.subset_id = font_subset->subset_id;
font.subset_resource = subset_resource;
_cairo_array_append (&surface->fonts, &font);
@@ -1868,21 +1973,23 @@ static cairo_status_t
return status;
status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset);
_cairo_type1_fallback_fini (&subset);
return status;
}
+#define PDF_UNITS_PER_EM 1000
+
static cairo_status_t
_cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
cairo_scaled_font_subset_t *font_subset)
{
- cairo_pdf_resource_t stream, descriptor, subset_resource;
+ cairo_pdf_resource_t stream, descriptor, encoding, subset_resource, to_unicode_stream;
cairo_status_t status;
cairo_pdf_font_t font;
cairo_truetype_subset_t subset;
unsigned long compressed_length;
char *compressed;
unsigned int i;
status = _cairo_truetype_subset_init (&subset, font_subset);
@@ -1909,64 +2016,91 @@ static cairo_status_t
subset.data_length);
_cairo_output_stream_write (surface->output, compressed, compressed_length);
_cairo_output_stream_printf (surface->output,
"\r\n"
"endstream\r\n"
"endobj\r\n");
free (compressed);
+ to_unicode_stream = _cairo_pdf_surface_emit_toUnicode_stream (surface, font_subset);
+
descriptor = _cairo_pdf_surface_new_object (surface);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\r\n"
"<< /Type /FontDescriptor\r\n"
- " /FontName /7%s\r\n"
+ " /FontName /%s\r\n"
" /Flags 4\r\n"
" /FontBBox [ %ld %ld %ld %ld ]\r\n"
" /ItalicAngle 0\r\n"
" /Ascent %ld\r\n"
" /Descent %ld\r\n"
- " /CapHeight 500\r\n"
+ " /CapHeight %ld\r\n"
" /StemV 80\r\n"
" /StemH 80\r\n"
" /FontFile2 %u 0 R\r\n"
">>\r\n"
"endobj\r\n",
descriptor.id,
subset.base_font,
- subset.x_min,
- subset.y_min,
- subset.x_max,
- subset.y_max,
- subset.ascent,
- subset.descent,
+ (long)(subset.x_min*PDF_UNITS_PER_EM),
+ (long)(subset.y_min*PDF_UNITS_PER_EM),
+ (long)(subset.x_max*PDF_UNITS_PER_EM),
+ (long)(subset.y_max*PDF_UNITS_PER_EM),
+ (long)(subset.ascent*PDF_UNITS_PER_EM),
+ (long)(subset.descent*PDF_UNITS_PER_EM),
+ (long)(subset.y_max*PDF_UNITS_PER_EM),
stream.id);
+ encoding = _cairo_pdf_surface_new_object (surface);
+ _cairo_output_stream_printf (surface->output,
+ "%d 0 obj\r\n"
+ "<< /Type /Encoding\r\n"
+ " /Differences [0 ",
+ encoding.id);
+
+ for (i = 0; i < font_subset->num_glyphs; i++)
+ _cairo_output_stream_printf (surface->output, "/g%d ", i);
+
+ _cairo_output_stream_printf (surface->output,
+ " ]\r\n"
+ ">>\r\n"
+ "endobj\r\n");
+
subset_resource = _cairo_pdf_surface_new_object (surface);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\r\n"
"<< /Type /Font\r\n"
" /Subtype /TrueType\r\n"
" /BaseFont /%s\r\n"
" /FirstChar 0\r\n"
" /LastChar %d\r\n"
" /FontDescriptor %d 0 R\r\n"
+ " /Encoding %d 0 R\r\n"
" /Widths [",
subset_resource.id,
subset.base_font,
font_subset->num_glyphs - 1,
- descriptor.id);
+ descriptor.id,
+ encoding.id);
for (i = 0; i < font_subset->num_glyphs; i++)
_cairo_output_stream_printf (surface->output,
- " %d",
- subset.widths[i]);
+ " %ld",
+ (long)(subset.widths[i]*PDF_UNITS_PER_EM));
_cairo_output_stream_printf (surface->output,
- " ]\r\n"
+ " ]\r\n");
+
+ if (to_unicode_stream.id != 0)
+ _cairo_output_stream_printf (surface->output,
+ " /ToUnicode %d 0 R\r\n",
+ to_unicode_stream.id);
+
+ _cairo_output_stream_printf (surface->output,
">>\r\n"
"endobj\r\n");
font.font_id = font_subset->font_id;
font.subset_id = font_subset->subset_id;
font.subset_resource = subset_resource;
_cairo_array_append (&surface->fonts, &font);
@@ -2020,50 +2154,60 @@ static cairo_int_status_t
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_pdf_surface_emit_bitmap_glyph (cairo_pdf_surface_t *surface,
cairo_scaled_font_t *scaled_font,
unsigned long glyph_index,
- cairo_pdf_resource_t *glyph_ret)
+ cairo_pdf_resource_t *glyph_ret,
+ cairo_box_t *bbox,
+ double *width)
{
cairo_scaled_glyph_t *scaled_glyph;
cairo_status_t status;
cairo_image_surface_t *image;
unsigned char *row, *byte;
int rows, cols;
+ double x_advance, y_advance;
status = _cairo_scaled_glyph_lookup (scaled_font,
glyph_index,
CAIRO_SCALED_GLYPH_INFO_METRICS|
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
if (status)
return status;
+ x_advance = scaled_glyph->metrics.x_advance;
+ y_advance = scaled_glyph->metrics.y_advance;
+ cairo_matrix_transform_distance (&scaled_font->ctm, &x_advance, &y_advance);
+ *bbox = scaled_glyph->bbox;
+ *width = x_advance;
+
image = scaled_glyph->surface;
if (image->format != CAIRO_FORMAT_A1) {
image = _cairo_image_surface_clone (image, CAIRO_FORMAT_A1);
if (cairo_surface_status (&image->base))
return cairo_surface_status (&image->base);
}
- *glyph_ret = _cairo_pdf_surface_open_stream (surface, FALSE, NULL);
+ *glyph_ret = _cairo_pdf_surface_open_stream (surface, TRUE, NULL);
_cairo_output_stream_printf (surface->output,
- "0 0 %f %f %f %f d1\r\n",
+ "%f 0 %f %f %f %f d1\r\n",
+ x_advance,
_cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
- - _cairo_fixed_to_double (scaled_glyph->bbox.p2.y),
+ _cairo_fixed_to_double (scaled_glyph->bbox.p2.y),
_cairo_fixed_to_double (scaled_glyph->bbox.p2.x),
- - _cairo_fixed_to_double (scaled_glyph->bbox.p1.y));
+ _cairo_fixed_to_double (scaled_glyph->bbox.p1.y));
_cairo_output_stream_printf (surface->output,
- "%f 0.0 0.0 %f %f %f cm\r\n",
+ "%f 0 0 %f %f %f cm\r\n",
_cairo_fixed_to_double (scaled_glyph->bbox.p2.x) - _cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
_cairo_fixed_to_double (scaled_glyph->bbox.p1.y) - _cairo_fixed_to_double (scaled_glyph->bbox.p2.y),
_cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
_cairo_fixed_to_double (scaled_glyph->bbox.p2.y));
_cairo_output_stream_printf (surface->output,
"BI\r\n"
"/IM true\r\n"
@@ -2092,54 +2236,85 @@ static cairo_int_status_t
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_pdf_surface_emit_glyph (cairo_pdf_surface_t *surface,
cairo_scaled_font_t *scaled_font,
unsigned long glyph_index,
- cairo_pdf_resource_t *glyph_ret)
+ cairo_pdf_resource_t *glyph_ret,
+ cairo_box_t *bbox,
+ double *width)
{
cairo_status_t status;
status = _cairo_pdf_surface_emit_outline_glyph (surface,
scaled_font,
glyph_index,
glyph_ret);
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
status = _cairo_pdf_surface_emit_bitmap_glyph (surface,
scaled_font,
glyph_index,
- glyph_ret);
+ glyph_ret,
+ bbox,
+ width);
if (status)
_cairo_surface_set_error (&surface->base, status);
}
static cairo_status_t
_cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
cairo_scaled_font_subset_t *font_subset)
{
- cairo_pdf_resource_t *glyphs, encoding, char_procs, subset_resource;
+ cairo_pdf_resource_t *glyphs, encoding, char_procs, subset_resource, to_unicode_stream;
cairo_pdf_font_t font;
cairo_matrix_t matrix;
+ double *widths;
unsigned int i;
+ cairo_box_t font_bbox = {{0,0},{0,0}};
+ cairo_box_t bbox = {{0,0},{0,0}};
glyphs = malloc (font_subset->num_glyphs * sizeof (cairo_pdf_resource_t));
if (glyphs == NULL) {
_cairo_surface_set_error (&surface->base, CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
}
+ widths = malloc (font_subset->num_glyphs * sizeof (double));
+ if (widths == NULL) {
+ free (glyphs);
+ _cairo_surface_set_error (&surface->base, CAIRO_STATUS_NO_MEMORY);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
for (i = 0; i < font_subset->num_glyphs; i++) {
_cairo_pdf_surface_emit_glyph (surface,
font_subset->scaled_font,
font_subset->glyphs[i],
- &glyphs[i]);
+ &glyphs[i],
+ &bbox,
+ &widths[i]);
+ if (i == 0) {
+ font_bbox.p1.x = bbox.p1.x;
+ font_bbox.p1.y = bbox.p1.y;
+ font_bbox.p2.x = bbox.p2.x;
+ font_bbox.p2.y = bbox.p2.y;
+ } else {
+ if (bbox.p1.x < font_bbox.p1.x)
+ font_bbox.p1.x = bbox.p1.x;
+ if (bbox.p1.y < font_bbox.p1.y)
+ font_bbox.p1.y = bbox.p1.y;
+ if (bbox.p2.x > font_bbox.p2.x)
+ font_bbox.p2.x = bbox.p2.x;
+ if (bbox.p2.y > font_bbox.p2.y)
+ font_bbox.p2.y = bbox.p2.y;
+ }
}
encoding = _cairo_pdf_surface_new_object (surface);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\r\n"
"<< /Type /Encoding\r\n"
" /Differences [0", encoding.id);
for (i = 0; i < font_subset->num_glyphs; i++)
@@ -2159,60 +2334,72 @@ static cairo_status_t
" /%d %d 0 R\r\n",
i, glyphs[i].id);
_cairo_output_stream_printf (surface->output,
">>\r\n"
"endobj\r\n");
free (glyphs);
+ to_unicode_stream = _cairo_pdf_surface_emit_toUnicode_stream (surface, font_subset);
+
subset_resource = _cairo_pdf_surface_new_object (surface);
matrix = font_subset->scaled_font->scale;
cairo_matrix_invert (&matrix);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\r\n"
"<< /Type /Font\r\n"
" /Subtype /Type3\r\n"
- " /FontBBox [0 0 0 0]\r\n"
+ " /FontBBox [%f %f %f %f]\r\n"
" /FontMatrix [ %f %f %f %f 0 0 ]\r\n"
" /Encoding %d 0 R\r\n"
" /CharProcs %d 0 R\r\n"
" /FirstChar 0\r\n"
" /LastChar %d\r\n",
subset_resource.id,
+ _cairo_fixed_to_double (font_bbox.p1.x),
+ _cairo_fixed_to_double (font_bbox.p1.y),
+ _cairo_fixed_to_double (font_bbox.p2.x),
+ _cairo_fixed_to_double (font_bbox.p2.y),
matrix.xx,
matrix.yx,
-matrix.xy,
-matrix.yy,
encoding.id,
char_procs.id,
font_subset->num_glyphs - 1);
_cairo_output_stream_printf (surface->output,
" /Widths [");
for (i = 0; i < font_subset->num_glyphs; i++)
- _cairo_output_stream_printf (surface->output, " 0");
+ _cairo_output_stream_printf (surface->output, " %f", widths[i]);
_cairo_output_stream_printf (surface->output,
"]\r\n");
+ free (widths);
+
+ if (to_unicode_stream.id != 0)
+ _cairo_output_stream_printf (surface->output,
+ " /ToUnicode %d 0 R\r\n",
+ to_unicode_stream.id);
_cairo_output_stream_printf (surface->output,
">>\r\n"
"endobj\r\n");
font.font_id = font_subset->font_id;
font.subset_id = font_subset->subset_id;
font.subset_resource = subset_resource;
_cairo_array_append (&surface->fonts, &font);
return CAIRO_STATUS_SUCCESS;
}
static void
-_cairo_pdf_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
- void *closure)
+_cairo_pdf_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset,
+ void *closure)
{
cairo_pdf_surface_t *surface = closure;
cairo_status_t status;
status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return;
@@ -2224,147 +2411,50 @@ static void
status = _cairo_pdf_surface_emit_truetype_font_subset (surface, font_subset);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return;
status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return;
+}
+
+static void
+_cairo_pdf_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset,
+ void *closure)
+{
+ cairo_pdf_surface_t *surface = closure;
+ cairo_status_t status;
status = _cairo_pdf_surface_emit_type3_font_subset (surface, font_subset);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return;
}
static cairo_status_t
_cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface)
{
cairo_status_t status;
- status = _cairo_scaled_font_subsets_foreach (surface->font_subsets,
- _cairo_pdf_surface_emit_font_subset,
- surface);
+ status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
+ _cairo_pdf_surface_emit_unscaled_font_subset,
+ surface);
+ status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
+ _cairo_pdf_surface_emit_scaled_font_subset,
+ surface);
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
surface->font_subsets = NULL;
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
}
-#if 0
-static cairo_status_t
-_cairo_pdf_surface_write_fonts (cairo_pdf_surface_t *surface)
-{
- cairo_font_subset_t *font;
- cairo_pdf_resource_t font_resource;
- int num_fonts, i, j;
- const char *data;
- char *compressed;
- unsigned long data_size, compressed_size;
- cairo_pdf_resource_t stream, descriptor;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- num_fonts = _cairo_array_num_elements (&surface->fonts);
- for (i = 0; i < num_fonts; i++) {
- _cairo_array_copy_element (&surface->fonts, i, &font);
-
- status = _cairo_font_subset_generate (font, &data, &data_size);
- if (status)
- goto fail;
-
- compressed = compress_dup (data, data_size, &compressed_size);
- if (compressed == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto fail;
- }
-
- stream = _cairo_pdf_surface_new_object (surface);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\r\n"
- "<< /Filter /FlateDecode\r\n"
- " /Length %lu\r\n"
- " /Length1 %lu\r\n"
- ">>\r\n"
- "stream\r\n",
- stream.id,
- compressed_size,
- data_size);
- _cairo_output_stream_write (surface->output, compressed, compressed_size);
- _cairo_output_stream_printf (surface->output,
- "\r\n"
- "endstream\r\n"
- "endobj\r\n");
- free (compressed);
-
- descriptor = _cairo_pdf_surface_new_object (surface);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\r\n"
- "<< /Type /FontDescriptor\r\n"
- " /FontName /7%s\r\n"
- " /Flags 4\r\n"
- " /FontBBox [ %ld %ld %ld %ld ]\r\n"
- " /ItalicAngle 0\r\n"
- " /Ascent %ld\r\n"
- " /Descent %ld\r\n"
- " /CapHeight 500\r\n"
- " /StemV 80\r\n"
- " /StemH 80\r\n"
- " /FontFile2 %u 0 R\r\n"
- ">>\r\n"
- "endobj\r\n",
- descriptor.id,
- font->base_font,
- font->x_min,
- font->y_min,
- font->x_max,
- font->y_max,
- font->ascent,
- font->descent,
- stream.id);
-
- font_resource.id = font->font_id;
- _cairo_pdf_surface_update_object (surface, font_resource);
- _cairo_output_stream_printf (surface->output,
- "%d 0 obj\r\n"
- "<< /Type /Font\r\n"
- " /Subtype /TrueType\r\n"
- " /BaseFont /%s\r\n"
- " /FirstChar 0\r\n"
- " /LastChar %d\r\n"
- " /FontDescriptor %d 0 R\r\n"
- " /Widths ",
- font->font_id,
- font->base_font,
- font->num_glyphs,
- descriptor.id);
-
- _cairo_output_stream_printf (surface->output,
- "[");
-
- for (j = 0; j < font->num_glyphs; j++)
- _cairo_output_stream_printf (surface->output,
- " %d",
- font->widths[j]);
-
- _cairo_output_stream_printf (surface->output,
- " ]\r\n"
- ">>\r\n"
- "endobj\r\n");
-
- fail:
- _cairo_font_subset_destroy (font);
- }
-
- return status;
-}
-#endif
-
static cairo_pdf_resource_t
_cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface)
{
cairo_pdf_resource_t catalog;
catalog = _cairo_pdf_surface_new_object (surface);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\r\n"
@@ -2439,19 +2529,22 @@ static cairo_status_t
num_streams = _cairo_array_num_elements (&surface->streams);
for (i = 0; i < num_streams; i++) {
_cairo_array_copy_element (&surface->streams, i, &stream);
_cairo_output_stream_printf (surface->output,
" %d 0 R",
stream.id);
}
_cairo_output_stream_printf (surface->output,
- " ]\r\n");
-
- _cairo_output_stream_printf (surface->output,
+ " ]\r\n"
+ " /Group <<\r\n"
+ " /Type /Group\r\n"
+ " /S /Transparency\r\n"
+ " /CS /DeviceRGB\r\n"
+ " >>\r\n"
">>\r\n"
"endobj\r\n");
status = _cairo_array_append (&surface->pages, &page);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
@@ -2473,20 +2566,21 @@ static cairo_bool_t
if (content == CAIRO_CONTENT_ALPHA)
return FALSE;
*/
extend = cairo_pattern_get_extend (&pattern->base);
switch (extend) {
case CAIRO_EXTEND_NONE:
case CAIRO_EXTEND_REPEAT:
+ case CAIRO_EXTEND_REFLECT:
+ /* 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;
- case CAIRO_EXTEND_REFLECT:
- case CAIRO_EXTEND_PAD:
- return FALSE;
}
ASSERT_NOT_REACHED;
return FALSE;
}
static cairo_bool_t
_pattern_supported (cairo_pattern_t *pattern)
@@ -2516,17 +2610,17 @@ static cairo_bool_t cairo_pdf_force_fall
**/
void
_cairo_pdf_test_force_fallbacks (void)
{
cairo_pdf_force_fallbacks = TRUE;
}
static cairo_int_status_t
-_operation_supported (cairo_pdf_surface_t *surface,
+__cairo_pdf_surface_operation_supported (cairo_pdf_surface_t *surface,
cairo_operator_t op,
cairo_pattern_t *pattern)
{
if (cairo_pdf_force_fallbacks)
return FALSE;
if (! _pattern_supported (pattern))
return FALSE;
@@ -2535,48 +2629,48 @@ static cairo_int_status_t
* but this should cover many common cases at least. */
if (op == CAIRO_OPERATOR_OVER)
return TRUE;
return FALSE;
}
static cairo_int_status_t
-_analyze_operation (cairo_pdf_surface_t *surface,
+_cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
cairo_operator_t op,
cairo_pattern_t *pattern)
{
- if (_operation_supported (surface, op, pattern))
+ if (__cairo_pdf_surface_operation_supported (surface, op, pattern))
return CAIRO_STATUS_SUCCESS;
else
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_pdf_surface_paint (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _analyze_operation (surface, op, source);
+ return _cairo_pdf_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
* painting the final image-based fallbacks. The final fallbacks
* do have alpha which we support by blending with white. This is
* 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_pdf_surface_operation_supported (op, source));
*/
- status = emit_pattern (surface, source);
+ status = _cairo_pdf_surface_emit_pattern (surface, source);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"0 0 %f %f re f\r\n",
surface->width, surface->height);
return _cairo_output_stream_get_status (surface->output);
@@ -2675,21 +2769,21 @@ static cairo_int_status_t
double tolerance,
cairo_antialias_t antialias)
{
cairo_pdf_surface_t *surface = abstract_surface;
pdf_path_info_t info;
cairo_status_t status;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _analyze_operation (surface, op, source);
-
- assert (_operation_supported (surface, op, source));
-
- status = emit_pattern (surface, source);
+ return _cairo_pdf_surface_analyze_operation (surface, op, source);
+
+ assert (__cairo_pdf_surface_operation_supported (surface, op, source));
+
+ status = _cairo_pdf_surface_emit_pattern (surface, source);
if (status)
return status;
status = _cairo_pdf_surface_emit_stroke_style (surface,
style);
if (status)
return status;
@@ -2724,21 +2818,21 @@ static cairo_int_status_t
cairo_antialias_t antialias)
{
cairo_pdf_surface_t *surface = abstract_surface;
const char *pdf_operator;
cairo_status_t status;
pdf_path_info_t info;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _analyze_operation (surface, op, source);
-
- assert (_operation_supported (surface, op, source));
-
- status = emit_pattern (surface, source);
+ return _cairo_pdf_surface_analyze_operation (surface, op, source);
+
+ assert (__cairo_pdf_surface_operation_supported (surface, op, source));
+
+ status = _cairo_pdf_surface_emit_pattern (surface, source);
if (status)
return status;
info.output = surface->output;
info.ctm_inverse = NULL;
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
@@ -2777,21 +2871,21 @@ static cairo_int_status_t
cairo_pdf_surface_t *surface = abstract_surface;
unsigned int current_subset_id = (unsigned int)-1;
unsigned int font_id, subset_id, subset_glyph_index;
cairo_bool_t diagonal;
cairo_status_t status;
int i;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _analyze_operation (surface, op, source);
-
- assert (_operation_supported (surface, op, source));
-
- status = emit_pattern (surface, source);
+ return _cairo_pdf_surface_analyze_operation (surface, op, source);
+
+ assert (__cairo_pdf_surface_operation_supported (surface, op, source));
+
+ status = _cairo_pdf_surface_emit_pattern (surface, source);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"BT\r\n");
if (scaled_font->scale.xy == 0.0 &&
scaled_font->scale.yx == 0.0)
@@ -2821,17 +2915,17 @@ static cairo_int_status_t
glyphs[i].x,
glyphs[i].y,
subset_glyph_index);
current_subset_id = subset_id;
} else {
_cairo_output_stream_printf (surface->output,
"%f %f Td <%02x> Tj\r\n",
(glyphs[i].x - glyphs[i-1].x)/scaled_font->scale.xx,
- (glyphs[i].y - glyphs[i-1].y)/scaled_font->scale.yy,
+ (glyphs[i].y - glyphs[i-1].y)/-scaled_font->scale.yy,
subset_glyph_index);
}
}
_cairo_output_stream_printf (surface->output,
"ET\r\n");
return _cairo_output_stream_get_status (surface->output);
--- a/gfx/cairo/cairo/src/cairo-polygon.c
+++ b/gfx/cairo/cairo/src/cairo-polygon.c
@@ -35,80 +35,92 @@
*/
#include <stdlib.h>
#include "cairoint.h"
/* 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)
{
polygon->num_edges = 0;
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;
}
cairo_status_t
_cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_point_t *p2)
{
cairo_status_t status;
cairo_edge_t *edge;
/* drop horizontal edges */
if (p1->y == p2->y) {
goto DONE;
}
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;
}
}
edge = &polygon->edges[polygon->num_edges];
if (p1->y < p2->y) {
edge->edge.p1 = *p1;
@@ -129,17 +141,17 @@ cairo_status_t
}
cairo_status_t
_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;
}
cairo_status_t
_cairo_polygon_line_to (cairo_polygon_t *polygon, cairo_point_t *point)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
@@ -160,13 +172,13 @@ cairo_status_t
if (polygon->has_current_point) {
status = _cairo_polygon_add_edge (polygon,
&polygon->current_point,
&polygon->first_point);
if (status)
return status;
- polygon->has_current_point = 0;
+ polygon->has_current_point = FALSE;
}
return CAIRO_STATUS_SUCCESS;
}
--- a/gfx/cairo/cairo/src/cairo-private.h
+++ b/gfx/cairo/cairo/src/cairo-private.h
@@ -39,14 +39,17 @@
#include "cairo-gstate-private.h"
#include "cairo-path-fixed-private.h"
struct _cairo {
unsigned int ref_count;
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 */
--- a/gfx/cairo/cairo/src/cairo-ps-surface.c
+++ b/gfx/cairo/cairo/src/cairo-ps-surface.c
@@ -479,28 +479,28 @@ static cairo_status_t
"/FontBBox [ 0 0 0 0 ] def\n"
"/Encoding 256 array def\n"
"0 1 255 { Encoding exch /.notdef put } for\n",
font_subset->font_id,
font_subset->subset_id);
/* 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");
_cairo_output_stream_printf (surface->final_stream,
"/sfnts [\n");
begin = 0;
end = 0;
@@ -704,18 +704,18 @@ static cairo_status_t
"\t}\n"
">> definefont pop\n");
return CAIRO_STATUS_SUCCESS;
}
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;
#if CAIRO_HAS_FT_FONT
status = _cairo_ps_surface_emit_type1_font_subset (surface, font_subset);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return;
@@ -723,33 +723,44 @@ static void
status = _cairo_ps_surface_emit_truetype_font_subset (surface, font_subset);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return;
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)
return;
}
static cairo_status_t
_cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface)
{
cairo_status_t status;
_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;
return status;
}
static void
_cairo_ps_surface_emit_body (cairo_ps_surface_t *surface)
@@ -793,17 +804,18 @@ static cairo_surface_t *
if (surface->tmpfile == NULL)
goto CLEANUP_SURFACE;
surface->stream = _cairo_output_stream_create_for_file (surface->tmpfile);
status = _cairo_output_stream_get_status (surface->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;
surface->width = width;
surface->height = height;
surface->max_width = width;
surface->max_height = height;
surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
@@ -863,17 +875,19 @@ cairo_ps_surface_create (const char *fi
{
cairo_status_t status;
cairo_output_stream_t *stream;
stream = _cairo_output_stream_create_for_filename (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,
width_in_points,
height_in_points);
}
/**
@@ -1318,19 +1332,47 @@ color_is_gray (cairo_color_t *color)
return (fabs (color->red - color->green) < epsilon &&
fabs (color->red - color->blue) < epsilon);
}
static cairo_bool_t
surface_pattern_supported (const cairo_surface_pattern_t *pattern)
{
- if (pattern->surface->backend->acquire_source_image != NULL)
+ 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;
}
static cairo_bool_t
pattern_supported (const cairo_pattern_t *pattern)
{
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
return TRUE;
@@ -1357,17 +1399,17 @@ static cairo_bool_t cairo_ps_force_fallb
**/
void
_cairo_ps_test_force_fallbacks (void)
{
cairo_ps_force_fallbacks = TRUE;
}
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)
{
if (cairo_ps_force_fallbacks)
return FALSE;
if (! pattern_supported (pattern))
return FALSE;
@@ -1377,21 +1419,21 @@ operation_supported (cairo_ps_surface_t
if (_cairo_operator_always_translucent (op))
return FALSE;
return _cairo_pattern_is_opaque (pattern);
}
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;
}
/* The "standard" implementation limit for PostScript string sizes is
* 65535 characters (see PostScript Language Reference, Appendix
* B). We go one short of that because we sometimes need two
@@ -1511,19 +1553,18 @@ static cairo_output_stream_t *
return &stream->base;
}
/* PS Output - this section handles output of the parts of the meta
* surface we can render natively in PS. */
static cairo_status_t
-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;
unsigned char *rgb, *compressed;
unsigned long rgb_size, compressed_size;
cairo_surface_t *opaque;
cairo_image_surface_t *opaque_image;
cairo_pattern_union_t pattern;
@@ -1622,63 +1663,61 @@ emit_image (cairo_ps_surface_t *surfa
" /Height %d\n"
" /BitsPerComponent 8\n"
" /Decode [ 0 1 0 1 0 1 ]\n"
" /DataSource {\n"
" %sData %sDataIndex get\n"
" /%sDataIndex %sDataIndex 1 add def\n"
" %sDataIndex %sData length 1 sub gt { /%sDataIndex 0 def } if\n"
" } /ASCII85Decode filter /LZWDecode filter\n"
- " /ImageMatrix [ %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;
free (compressed);
bail2:
free (rgb);
bail1:
if (opaque_image != image)
cairo_surface_destroy (opaque);
bail0:
return status;
}
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))
_cairo_output_stream_printf (surface->stream,
"%f G\n",
pattern->color.red);
else
_cairo_output_stream_printf (surface->stream,
"%f %f %f R\n",
pattern->color.red,
pattern->color.green,
pattern->color.blue);
}
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)) {
_cairo_output_stream_printf (surface->stream, "/MyPattern {\n");
_cairo_meta_surface_replay (pattern->surface, &surface->base);
bbox_width = surface->width;
bbox_height = surface->height;
xstep = surface->width;
@@ -1689,107 +1728,126 @@ emit_surface_pattern (cairo_ps_surface_t
void *image_extra;
cairo_status_t status;
status = _cairo_surface_acquire_source_image (pattern->surface,
&image,
&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;
ystep = 0;
}
_cairo_surface_release_source_image (pattern->surface, image,
image_extra);
}
_cairo_output_stream_printf (surface->stream,
"<< /PatternType 1\n"
" /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
* different 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;
}
}
static cairo_int_status_t
_cairo_ps_surface_intersect_clip_path (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
@@ -1869,36 +1927,36 @@ static cairo_int_status_t
cairo_operator_t op,
cairo_pattern_t *source)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
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
* painting the final image-based fallbacks. The final fallbacks
* do have alpha which we support by blending with white. This is
* 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,
"%% _cairo_ps_surface_paint\n");
_cairo_surface_get_extents (&surface->base, &extents);
_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);
_cairo_output_stream_printf (stream, "%d %d L\n",
extents.x + extents.width,
extents.y);
_cairo_output_stream_printf (stream, "%d %d L\n",
extents.x + extents.width,
@@ -1956,19 +2014,19 @@ static cairo_int_status_t
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
cairo_int_status_t status;
double *dash = style->dash;
int num_dashes = style->num_dashes;
double dash_offset = style->dash_offset;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _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_stroke\n");
/* PostScript has "special needs" when it comes to zero-length
* dash segments with butt caps. It apparently (at least
* according to ghostscript) draws hairlines for this
@@ -2027,17 +2085,17 @@ static cairo_int_status_t
* we rotated a 0.0 value to the front of the list.
* Set i to -2 so it will get incremented to 0. */
if (i == 2)
i = -2;
}
}
}
- emit_pattern (surface, source);
+ _cairo_ps_surface_emit_pattern (surface, source);
_cairo_output_stream_printf (stream,
"gsave\n");
status = _cairo_ps_surface_emit_path (surface, stream, path,
style->line_cap);
/*
* Switch to user space to set line parameters
@@ -2087,24 +2145,24 @@ static cairo_int_status_t
cairo_antialias_t antialias)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
cairo_int_status_t status;
const char *ps_operator;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _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,
CAIRO_LINE_CAP_ROUND);
switch (fill_rule) {
case CAIRO_FILL_RULE_WINDING:
ps_operator = "F";
@@ -2145,29 +2203,29 @@ static cairo_int_status_t
unsigned int font_id;
cairo_ps_glyph_id_t *glyph_ids;
cairo_status_t status;
unsigned int num_glyphs_unsigned, i, j, last, end;
cairo_bool_t vertical, horizontal;
cairo_output_stream_t *word_wrap;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _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");
if (num_glyphs <= 0)
return CAIRO_STATUS_SUCCESS;
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;
for (i = 0; i < num_glyphs_unsigned; i++) {
status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
scaled_font, glyphs[i].index,
&font_id,
--- a/gfx/cairo/cairo/src/cairo-quartz-private.h
+++ b/gfx/cairo/cairo/src/cairo-quartz-private.h
@@ -1,11 +1,12 @@
/* 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
* 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.
@@ -26,41 +27,48 @@
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Calum Robinson
*
* 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 */
--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
+++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
@@ -1,11 +1,12 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2004 Calum Robinson
+ * 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
* 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.
@@ -22,244 +23,1754 @@
* 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 Calum Robinson
+ * The Initial Developer of the Original Code is Mozilla Corporation.
*
* Contributor(s):
- * Calum Robinson <calumr@mac.com>
+ * Vladimir Vukicevic <vladimir@mozilla.com>
*/
+#include <Carbon/Carbon.h>
+
#include "cairoint.h"
-#include "cairo-private.h"
+
#include "cairo-quartz-private.h"
+#undef QUARTZ_DEBUG
+
+#ifdef QUARTZ_DEBUG
+#define ND(_x) fprintf _x
+#else
+#define ND(_x) do {} while(0)
+#endif
+
+/* This method is private, but it exists. Its params are are exposed
+ * as args to the NS* method, but not as CG.
+ */
+enum PrivateCGCompositeMode {
+ kPrivateCGCompositeClear = 0,
+ kPrivateCGCompositeCopy = 1,
+ kPrivateCGCompositeSourceOver = 2,
+ kPrivateCGCompositeSourceIn = 3,
+ kPrivateCGCompositeSourceOut = 4,
+ kPrivateCGCompositeSourceAtop = 5,
+ kPrivateCGCompositeDestinationOver = 6,
+ kPrivateCGCompositeDestinationIn = 7,
+ kPrivateCGCompositeDestinationOut = 8,
+ kPrivateCGCompositeDestinationAtop = 9,
+ kPrivateCGCompositeXOR = 10,
+ kPrivateCGCompositePlusDarker = 11, // (max (0, (1-d) + (1-s)))
+ kPrivateCGCompositePlusLighter = 12, // (min (1, s + d))
+};
+typedef enum PrivateCGCompositeMode PrivateCGCompositeMode;
+CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode);
+CG_EXTERN void CGContextResetCTM (CGContextRef);
+CG_EXTERN void CGContextSetCTM (CGContextRef, CGAffineTransform);
+CG_EXTERN void CGContextResetClip (CGContextRef);
+CG_EXTERN CGSize CGContextGetPatternPhase (CGContextRef);
+
+/* We need to work with the 10.3 SDK as well (and 10.3 machines; luckily, 10.3.9
+ * has all the stuff we care about, just some of it isn't exported in the SDK.
+ */
+#ifndef kCGBitmapByteOrder32Host
+#define USE_10_3_WORKAROUNDS
+#define kCGBitmapAlphaInfoMask 0x1F
+#define kCGBitmapByteOrderMask 0x7000
+#define kCGBitmapByteOrder32Host 0
+
+typedef uint32_t CGBitmapInfo;
+
+/* public in 10.4, present in 10.3.9 */
+CG_EXTERN void CGContextReplacePathWithStrokedPath (CGContextRef);
+CG_EXTERN CGImageRef CGBitmapContextCreateImage (CGContextRef);
+#endif
+
+
+/*
+ * Utility functions
+ */
+
+static void quartz_surface_to_png (cairo_quartz_surface_t *nq, char *dest);
+static void quartz_image_to_png (CGImageRef, char *dest);
+
+/*
+ * Cairo path -> Quartz path conversion helpers
+ */
+
+/* cairo path -> mutable path */
+static cairo_status_t
+_cairo_path_to_quartz_path_move_to (void *closure, cairo_point_t *point)
+{
+ CGPathMoveToPoint ((CGMutablePathRef) closure, NULL,
+ _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y));
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_path_to_quartz_path_line_to (void *closure, cairo_point_t *point)
+{
+ CGPathAddLineToPoint ((CGMutablePathRef) closure, NULL,
+ _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y));
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_path_to_quartz_path_curve_to (void *closure, cairo_point_t *p0, cairo_point_t *p1, cairo_point_t *p2)
+{
+ CGPathAddCurveToPoint ((CGMutablePathRef) closure, NULL,
+ _cairo_fixed_to_double(p0->x), _cairo_fixed_to_double(p0->y),
+ _cairo_fixed_to_double(p1->x), _cairo_fixed_to_double(p1->y),
+ _cairo_fixed_to_double(p2->x), _cairo_fixed_to_double(p2->y));
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_path_to_quartz_path_close_path (void *closure)
+{
+ CGPathCloseSubpath ((CGMutablePathRef) closure);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* cairo path -> execute in context */
+static cairo_status_t
+_cairo_path_to_quartz_context_move_to (void *closure, cairo_point_t *point)
+{
+ //ND((stderr, "moveto: %f %f\n", _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y)));
+ CGContextMoveToPoint ((CGContextRef) closure,
+ _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y));
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_path_to_quartz_context_line_to (void *closure, cairo_point_t *point)
+{
+ //ND((stderr, "lineto: %f %f\n", _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y)));
+ if (CGContextIsPathEmpty ((CGContextRef) closure))
+ CGContextMoveToPoint ((CGContextRef) closure,
+ _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y));
+ else
+ CGContextAddLineToPoint ((CGContextRef) closure,
+ _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y));
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_path_to_quartz_context_curve_to (void *closure, cairo_point_t *p0, cairo_point_t *p1, cairo_point_t *p2)
+{
+ //ND( (stderr, "curveto: %f,%f %f,%f %f,%f\n",
+ // _cairo_fixed_to_double(p0->x), _cairo_fixed_to_double(p0->y),
+ // _cairo_fixed_to_double(p1->x), _cairo_fixed_to_double(p1->y),
+ // _cairo_fixed_to_double(p2->x), _cairo_fixed_to_double(p2->y)));
+
+ CGContextAddCurveToPoint ((CGContextRef) closure,
+ _cairo_fixed_to_double(p0->x), _cairo_fixed_to_double(p0->y),
+ _cairo_fixed_to_double(p1->x), _cairo_fixed_to_double(p1->y),
+ _cairo_fixed_to_double(p2->x), _cairo_fixed_to_double(p2->y));
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_path_to_quartz_context_close_path (void *closure)
+{
+ //ND((stderr, "closepath\n"));
+ CGContextClosePath ((CGContextRef) closure);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_quartz_cairo_path_to_quartz_path (cairo_path_fixed_t *path,
+ CGMutablePathRef cgPath)
+{
+ return _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_path_to_quartz_path_move_to,
+ _cairo_path_to_quartz_path_line_to,
+ _cairo_path_to_quartz_path_curve_to,
+ _cairo_path_to_quartz_path_close_path,
+ cgPath);
+}
+
static cairo_status_t
-_cairo_quartz_surface_finish(void *abstract_surface)
+_cairo_quartz_cairo_path_to_quartz_context (cairo_path_fixed_t *path,
+ CGContextRef cgc)
+{
+ return _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_path_to_quartz_context_move_to,
+ _cairo_path_to_quartz_context_line_to,
+ _cairo_path_to_quartz_context_curve_to,
+ _cairo_path_to_quartz_context_close_path,
+ cgc);
+}
+
+/*
+ * Misc helpers/callbacks
+ */
+
+static PrivateCGCompositeMode
+_cairo_quartz_cairo_operator_to_quartz (cairo_operator_t op)
+{
+ switch (op) {
+ case CAIRO_OPERATOR_CLEAR:
+ return kPrivateCGCompositeClear;
+ case CAIRO_OPERATOR_SOURCE:
+ return kPrivateCGCompositeCopy;
+ case CAIRO_OPERATOR_OVER:
+ return kPrivateCGCompositeSourceOver;
+ case CAIRO_OPERATOR_IN:
+ /* XXX This doesn't match image output */
+ return kPrivateCGCompositeSourceIn;
+ case CAIRO_OPERATOR_OUT:
+ /* XXX This doesn't match image output */
+ return kPrivateCGCompositeSourceOut;
+ case CAIRO_OPERATOR_ATOP:
+ return kPrivateCGCompositeSourceAtop;
+
+ case CAIRO_OPERATOR_DEST:
+ /* XXX this is handled specially (noop)! */
+ return kPrivateCGCompositeCopy;
+ case CAIRO_OPERATOR_DEST_OVER:
+ return kPrivateCGCompositeDestinationOver;
+ case CAIRO_OPERATOR_DEST_IN:
+ /* XXX This doesn't match image output */
+ return kPrivateCGCompositeDestinationIn;
+ case CAIRO_OPERATOR_DEST_OUT:
+ return kPrivateCGCompositeDestinationOut;
+ case CAIRO_OPERATOR_DEST_ATOP:
+ /* XXX This doesn't match image output */
+ return kPrivateCGCompositeDestinationAtop;
+
+ case CAIRO_OPERATOR_XOR:
+ return kPrivateCGCompositeXOR; /* This will generate strange results */
+ case CAIRO_OPERATOR_ADD:
+ return kPrivateCGCompositePlusLighter;
+ case CAIRO_OPERATOR_SATURATE:
+ /* XXX This doesn't match image output for SATURATE; there's no equivalent */
+ return kPrivateCGCompositePlusDarker; /* ??? */
+ }
+
+
+ return kPrivateCGCompositeCopy;
+}
+
+static CGLineCap
+_cairo_quartz_cairo_line_cap_to_quartz (cairo_line_cap_t ccap)
+{
+ switch (ccap) {
+ case CAIRO_LINE_CAP_BUTT: return kCGLineCapButt; break;
+ case CAIRO_LINE_CAP_ROUND: return kCGLineCapRound; break;
+ case CAIRO_LINE_CAP_SQUARE: return kCGLineCapSquare; break;
+ }
+
+ return kCGLineCapButt;
+}
+
+static CGLineJoin
+_cairo_quartz_cairo_line_join_to_quartz (cairo_line_join_t cjoin)
+{
+ switch (cjoin) {
+ case CAIRO_LINE_JOIN_MITER: return kCGLineJoinMiter; break;
+ case CAIRO_LINE_JOIN_ROUND: return kCGLineJoinRound; break;
+ case CAIRO_LINE_JOIN_BEVEL: return kCGLineJoinBevel; break;
+ }
+
+ return kCGLineJoinMiter;
+}
+
+static void
+_cairo_quartz_cairo_matrix_to_quartz (const cairo_matrix_t *src,
+ CGAffineTransform *dst)
+{
+ dst->a = src->xx;
+ dst->b = src->xy;
+ dst->c = src->yx;
+ dst->d = src->yy;
+ dst->tx = src->x0;
+ dst->ty = src->y0;
+}
+
+/*
+ * Source -> Quartz setup and finish functions
+ */
+
+static void
+ComputeGradientValue (void *info, const float *in, float *out)
+{
+ float fdist = *in; /* 0.0 .. 1.0 */
+ cairo_fixed_16_16_t fdist_fix = _cairo_fixed_from_double(*in);
+ cairo_gradient_pattern_t *grad = (cairo_gradient_pattern_t*) info;
+ unsigned int i;
+
+ for (i = 0; i < grad->n_stops; i++) {
+ if (grad->stops[i].x > fdist_fix)
+ break;
+ }
+
+ if (i == 0 || i == grad->n_stops) {
+ if (i == grad->n_stops)
+ --i;
+ out[0] = grad->stops[i].color.red / 65535.;
+ out[1] = grad->stops[i].color.green / 65535.;
+ out[2] = grad->stops[i].color.blue / 65535.;
+ out[3] = grad->stops[i].color.alpha / 65535.;
+ } else {
+ float ax = _cairo_fixed_to_double(grad->stops[i-1].x);
+ float bx = _cairo_fixed_to_double(grad->stops[i].x) - ax;
+ float bp = (fdist - ax)/bx;
+ float ap = 1.0 - bp;
+
+ out[0] =
+ (grad->stops[i-1].color.red / 65535.) * ap +
+ (grad->stops[i].color.red / 65535.) * bp;
+ out[1] =
+ (grad->stops[i-1].color.green / 65535.) * ap +
+ (grad->stops[i].color.green / 65535.) * bp;
+ out[2] =
+ (grad->stops[i-1].color.blue / 65535.) * ap +
+ (grad->stops[i].color.blue / 65535.) * bp;
+ out[3] =
+ (grad->stops[i-1].color.alpha / 65535.) * ap +
+ (grad->stops[i].color.alpha / 65535.) * bp;
+ }
+}
+
+static CGFunctionRef
+CreateGradientFunction (cairo_gradient_pattern_t *gpat)
+{
+ static const float input_value_range[2] = { 0.f, 1.f };
+ static const float output_value_ranges[8] = { 0.f, 1.f, 0.f, 1.f, 0.f, 1.f, 0.f, 1.f };
+ static const CGFunctionCallbacks callbacks = {
+ 0, ComputeGradientValue, (CGFunctionReleaseInfoCallback) cairo_pattern_destroy
+ };
+
+ return CGFunctionCreate (gpat,
+ 1,
+ input_value_range,
+ 4,
+ output_value_ranges,
+ &callbacks);
+}
+
+static CGShadingRef
+_cairo_quartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat)
+{
+ cairo_matrix_t mat;
+ double x0, y0;
+
+ if (abspat->type != CAIRO_PATTERN_TYPE_LINEAR &&
+ abspat->type != CAIRO_PATTERN_TYPE_RADIAL)
+ return NULL;
+
+ /* We can only do this if we have an identity pattern matrix;
+ * otherwise fall back through to the generic pattern case.
+ * XXXperf we could optimize this by creating a pattern with the shading;
+ * but we'd need to know the extents to do that.
+ * ... but we don't care; we can use the surface extents for it
+ * XXXtodo - implement gradients with non-identity pattern matrices
+ */
+ cairo_pattern_get_matrix (abspat, &mat);
+ if (mat.xx != 1.0 || mat.yy != 1.0 || mat.xy != 0.0 || mat.yx != 0.0)
+ return NULL;
+
+ x0 = mat.x0;
+ y0 = mat.y0;
+
+ if (abspat->type == CAIRO_PATTERN_TYPE_LINEAR) {
+ cairo_linear_pattern_t *lpat = (cairo_linear_pattern_t*) abspat;
+ CGShadingRef shading;
+ CGPoint start, end;
+ CGFunctionRef gradFunc;
+ CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
+
+ start = CGPointMake (_cairo_fixed_to_double (lpat->gradient.p1.x) - x0,
+ _cairo_fixed_to_double (lpat->gradient.p1.y) - y0);
+ end = CGPointMake (_cairo_fixed_to_double (lpat->gradient.p2.x) - x0,
+ _cairo_fixed_to_double (lpat->gradient.p2.y) - y0);
+
+ cairo_pattern_reference (abspat);
+ gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) lpat);
+ shading = CGShadingCreateAxial (rgb,
+ start, end,
+ gradFunc,
+ true, true);
+ CGColorSpaceRelease(rgb);
+ CGFunctionRelease(gradFunc);
+
+ return shading;
+ }
+
+ if (abspat->type == CAIRO_PATTERN_TYPE_RADIAL) {
+ cairo_radial_pattern_t *rpat = (cairo_radial_pattern_t*) abspat;
+ CGShadingRef shading;
+ CGPoint start, end;
+ CGFunctionRef gradFunc;
+ CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
+
+ start = CGPointMake (_cairo_fixed_to_double (rpat->gradient.c1.x) - x0,
+ _cairo_fixed_to_double (rpat->gradient.c1.y) - y0);
+ end = CGPointMake (_cairo_fixed_to_double (rpat->gradient.c2.x) - x0,
+ _cairo_fixed_to_double (rpat->gradient.c2.y) - y0);
+
+ cairo_pattern_reference (abspat);
+ gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) rpat);
+ shading = CGShadingCreateRadial (rgb,
+ start,
+ _cairo_fixed_to_double (rpat->gradient.c1.radius),
+ end,
+ _cairo_fixed_to_double (rpat->gradient.c2.radius),
+ gradFunc,
+ true, true);
+ CGColorSpaceRelease(rgb);
+ CGFunctionRelease(gradFunc);
+
+ return shading;
+ }
+
+ /* Shouldn't be reached */
+ ASSERT_NOT_REACHED;
+ return NULL;
+}
+
+
+/* Generic cairo_pattern -> CGPattern function */
+static void
+SurfacePatternDrawFunc (void *info, CGContextRef context)
+{
+ cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) info;
+ cairo_surface_t *pat_surf = spat->surface;
+
+ cairo_quartz_surface_t *quartz_surf = NULL;
+
+ cairo_bool_t flip = FALSE;
+
+ CGImageRef img;
+
+ if (cairo_surface_get_type(pat_surf) != CAIRO_SURFACE_TYPE_QUARTZ) {
+ /* This sucks; we should really store a dummy quartz surface
+ * for passing in here
+ * XXXtodo store a dummy quartz surface somewhere for handing off to clone_similar
+ * XXXtodo/perf don't use clone if the source surface is an image surface! Instead,
+ * just create the CGImage directly!
+ */
+
+ cairo_surface_t *dummy = cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+ cairo_surface_t *new_surf = NULL;
+ cairo_rectangle_int16_t rect;
+
+ _cairo_surface_get_extents (pat_surf, &rect);
+
+ _cairo_surface_clone_similar (dummy, pat_surf, rect.x, rect.y,
+ rect.width, rect.height, &new_surf);
+
+ cairo_surface_destroy(dummy);
+
+ quartz_surf = (cairo_quartz_surface_t *) new_surf;
+ } else {
+ /* If it's a quartz surface, we can try to see if it's a CGBitmapContext;
+ * we do this when we call CGBitmapContextCreateImage below.
+ */
+ cairo_surface_reference (pat_surf);
+ quartz_surf = (cairo_quartz_surface_t*) pat_surf;
+
+ /* XXXtodo WHY does this need to be flipped? Writing this stuff
+ * to disk shows that in both this path and the path above the source image
+ * has an identical orientation, and the destination context at all times has a Y
+ * flip. So why do we need to flip in this case?
+ */
+ flip = TRUE;
+ }
+
+ img = CGBitmapContextCreateImage (quartz_surf->cgContext);
+
+ if (!img) {
+ // ... give up.
+ ND((stderr, "CGBitmapContextCreateImage failed\n"));
+ cairo_surface_destroy ((cairo_surface_t*)quartz_surf);
+ return;
+ }
+
+ if (flip) {
+ CGContextTranslateCTM (context, 0, CGImageGetHeight(img));
+ CGContextScaleCTM (context, 1, -1);
+ }
+
+ CGRect imageBounds;
+ imageBounds.size = CGSizeMake (CGImageGetWidth(img), CGImageGetHeight(img));
+ imageBounds.origin.x = 0;
+ imageBounds.origin.y = 0;
+
+ CGContextDrawImage (context, imageBounds, img);
+
+ CGImageRelease (img);
+
+ cairo_surface_destroy ((cairo_surface_t*) quartz_surf);
+}
+
+/* Borrowed from cairo-meta-surface */
+static cairo_status_t
+_init_pattern_with_snapshot (cairo_pattern_t *pattern,
+ const cairo_pattern_t *other)
{
- cairo_quartz_surface_t *surface = abstract_surface;
+ _cairo_pattern_init_copy (pattern, other);
+
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern =
+ (cairo_surface_pattern_t *) pattern;
+ cairo_surface_t *surface = surface_pattern->surface;
+
+ surface_pattern->surface = _cairo_surface_snapshot (surface);
+
+ cairo_surface_destroy (surface);
+
+ if (surface_pattern->surface->status)
+ return surface_pattern->surface->status;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static CGPatternRef
+_cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t *dest,
+ cairo_pattern_t *abspat)
+{
+ cairo_surface_pattern_t *spat;
+ cairo_surface_t *pat_surf;
+ cairo_rectangle_int16_t extents;
+
+ CGRect pbounds;
+ CGAffineTransform ptransform, stransform;
+ CGPatternCallbacks cb = { 0,
+ SurfacePatternDrawFunc,
+ (CGFunctionReleaseInfoCallback) cairo_pattern_destroy };
+ CGPatternRef cgpat;
+ float rw, rh;
+
+ cairo_pattern_union_t *snap_pattern = NULL;
+ cairo_pattern_t *target_pattern = abspat;
+
+ cairo_matrix_t m;
+ /* SURFACE is the only type we'll handle here */
+ if (abspat->type != CAIRO_PATTERN_TYPE_SURFACE)
+ return NULL;
+
+ spat = (cairo_surface_pattern_t *) abspat;
+ pat_surf = spat->surface;
+
+ _cairo_surface_get_extents (pat_surf, &extents);
+ pbounds.origin.x = 0;
+ pbounds.origin.y = 0;
+ pbounds.size.width = extents.width;
+ pbounds.size.height = extents.height;
+
+ m = spat->base.matrix;
+ cairo_matrix_invert(&m);
+ _cairo_quartz_cairo_matrix_to_quartz (&m, &stransform);
+
+ /* The pattern matrix is relative to the bottom left, again; the
+ * incoming cairo pattern matrix is relative to the upper left.
+ * So we take the pattern matrix and the original context matrix,
+ * which gives us the correct base translation/y flip.
+ */
+ ptransform = CGAffineTransformConcat(stransform, dest->cgContextBaseCTM);
+
+#ifdef QUARTZ_DEBUG
+ ND((stderr, " pbounds: %f %f %f %f\n", pbounds.origin.x, pbounds.origin.y, pbounds.size.width, pbounds.size.height));
+ ND((stderr, " pattern xform: t: %f %f xx: %f xy: %f yx: %f yy: %f\n", ptransform.tx, ptransform.ty, ptransform.a, ptransform.b, ptransform.c, ptransform.d));
+ CGAffineTransform xform = CGContextGetCTM(dest->cgContext);
+ ND((stderr, " context xform: t: %f %f xx: %f xy: %f yx: %f yy: %f\n", xform.tx, xform.ty, xform.a, xform.b, xform.c, xform.d));
+#endif
+
+ // kjs seems to indicate this should work (setting to 0,0 to avoid
+ // tiling); however, the pattern CTM scaling ends up being NaN in
+ // the pattern draw function if either rw or rh are 0.
+ // XXXtodo get pattern drawing working with extend options
+ // XXXtodo/perf optimize CAIRO_EXTEND_NONE to a single DrawImage instead of a pattern
+#if 0
+ if (spat->base.extend == CAIRO_EXTEND_NONE) {
+ /* XXX wasteful; this will keep drawing the pattern in the
+ * original location. We need to set up the clip region
+ * instead to do this right.
+ */
+ rw = 0;
+ rh = 0;
+ } else if (spat->base.extend == CAIRO_EXTEND_REPEAT) {
+ rw = extents.width;
+ rh = extents.height;
+ } else if (spat->base.extend == CAIRO_EXTEND_REFLECT) {
+ /* XXX broken; need to emulate by reflecting the image into 4 quadrants
+ * and then tiling that
+ */
+ rw = extents.width;
+ rh = extents.height;
+ } else {
+ /* CAIRO_EXTEND_PAD */
+ /* XXX broken. */
+ rw = 0;
+ rh = 0;
+ }
+#else
+ rw = extents.width;
+ rh = extents.height;
+#endif
+
+ /* XXX fixme: only do snapshots if the context is for printing, or get rid of the
+ other block if it doesn't fafect performance */
+ if (1 /* context is for printing */) {
+ snap_pattern = (cairo_pattern_union_t*) malloc(sizeof(cairo_pattern_union_t));
+ target_pattern = (cairo_pattern_t*) snap_pattern;
+ _init_pattern_with_snapshot (target_pattern, abspat);
+ } else {
+ cairo_pattern_reference (abspat);
+ target_pattern = abspat;
+ }
+
+ cgpat = CGPatternCreate (target_pattern,
+ pbounds,
+ ptransform,
+ rw, rh,
+ kCGPatternTilingConstantSpacing, /* kCGPatternTilingNoDistortion, */
+ TRUE,
+ &cb);
+ return cgpat;
+}
+
+typedef enum {
+ DO_SOLID,
+ DO_SHADING,
+ DO_PATTERN,
+ DO_UNSUPPORTED
+} cairo_quartz_action_t;
+
+static cairo_quartz_action_t
+_cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
+ cairo_pattern_t *source)
+{
+ assert (!(surface->sourceImage || surface->sourceShading || surface->sourcePattern));
+
+ if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
+ cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
+
+ CGContextSetRGBStrokeColor (surface->cgContext,
+ solid->color.red,
+ solid->color.green,
+ solid->color.blue,
+ solid->color.alpha);
+ CGContextSetRGBFillColor (surface->cgContext,
+ solid->color.red,
+ solid->color.green,
+ solid->color.blue,
+ solid->color.alpha);
+
+ return DO_SOLID;
+ } else if (source->type == CAIRO_PATTERN_TYPE_LINEAR ||
+ source->type == CAIRO_PATTERN_TYPE_RADIAL)
+ {
+ CGShadingRef shading = _cairo_quartz_cairo_gradient_pattern_to_quartz (source);
+ if (!shading)
+ return DO_UNSUPPORTED;
+
+ surface->sourceShading = shading;
+
+ return DO_SHADING;
+ } else if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ CGPatternRef pattern = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source);
+ if (!pattern)
+ return DO_UNSUPPORTED;
- if (surface->clip_region)
- pixman_region_destroy (surface->clip_region);
+ float patternAlpha = 1.0f;
+
+ // Save before we change the pattern, colorspace, etc. so that
+ // we can restore and make sure that quartz releases our
+ // pattern (which may be stack allocated)
+ CGContextSaveGState(surface->cgContext);
+
+ CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
+ CGContextSetFillColorSpace (surface->cgContext, patternSpace);
+ CGContextSetFillPattern (surface->cgContext, pattern, &patternAlpha);
+ CGContextSetStrokeColorSpace (surface->cgContext, patternSpace);
+ CGContextSetStrokePattern (surface->cgContext, pattern, &patternAlpha);
+ CGColorSpaceRelease (patternSpace);
+
+ /* Quartz likes to munge the pattern phase (as yet unexplained
+ * why); force it to 0,0 as we've already baked in the correct
+ * pattern translation into the pattern matrix
+ */
+ CGContextSetPatternPhase (surface->cgContext, CGSizeMake(0,0));
+
+ surface->sourcePattern = pattern;
+
+ return DO_PATTERN;
+ } else {
+ return DO_UNSUPPORTED;
+ }
+
+ ASSERT_NOT_REACHED;
+}
+
+static void
+_cairo_quartz_teardown_source (cairo_quartz_surface_t *surface,
+ cairo_pattern_t *source)
+{
+ if (surface->sourceImage) {
+ // nothing to do; we don't use sourceImage yet
+ }
+
+ if (surface->sourceShading) {
+ CGShadingRelease(surface->sourceShading);
+ surface->sourceShading = NULL;
+ }
+
+ if (surface->sourcePattern) {
+ CGPatternRelease(surface->sourcePattern);
+ // To tear down the pattern and colorspace
+ CGContextRestoreGState(surface->cgContext);
+
+ surface->sourcePattern = NULL;
+ }
+}
+
+/*
+ * get source/dest image implementation
+ */
+
+static void
+ImageDataReleaseFunc(void *info, const void *data, size_t size)
+{
+ if (data != NULL) {
+ free((void *) data);
+ }
+}
+
+/* Read the image from the surface's front buffer */
+static cairo_int_status_t
+_cairo_quartz_get_image (cairo_quartz_surface_t *surface,
+ cairo_image_surface_t **image_out,
+ unsigned char **data_out)
+{
+ unsigned char *imageData;
+ cairo_image_surface_t *isurf;
+
+ if (CGBitmapContextGetBitsPerPixel(surface->cgContext) != 0) {
+ unsigned int stride;
+ unsigned int bitinfo;
+ unsigned int bpc, bpp;
+ CGColorSpaceRef colorspace;
+ unsigned int color_comps;
+
+ imageData = (unsigned char *) CGBitmapContextGetData(surface->cgContext);
+#ifdef USE_10_3_WORKAROUNDS
+ bitinfo = CGBitmapContextGetAlphaInfo (surface->cgContext);
+#else
+ bitinfo = CGBitmapContextGetBitmapInfo (surface->cgContext);
+#endif
+ stride = CGBitmapContextGetBytesPerRow (surface->cgContext);
+ bpp = CGBitmapContextGetBitsPerPixel (surface->cgContext);
+ bpc = CGBitmapContextGetBitsPerComponent (surface->cgContext);
+
+ // let's hope they don't add YUV under us
+ colorspace = CGBitmapContextGetColorSpace (surface->cgContext);
+ color_comps = CGColorSpaceGetNumberOfComponents(colorspace);
+
+ // XXX TODO: We can handle all of these by converting to
+ // pixman masks, including non-native-endian masks
+ if (bpc != 8)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (bpp != 32 && bpp != 8)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (color_comps != 3 && color_comps != 1)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (bpp == 32 && color_comps == 3 &&
+ (bitinfo & kCGBitmapAlphaInfoMask) == kCGImageAlphaPremultipliedFirst &&
+ (bitinfo & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Host)
+ {
+ isurf = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data (imageData,
+ CAIRO_FORMAT_ARGB32,
+ surface->extents.width,
+ surface->extents.height,
+ stride);
+ } else if (bpp == 32 && color_comps == 3 &&
+ (bitinfo & kCGBitmapAlphaInfoMask) == kCGImageAlphaNoneSkipFirst &&
+ (bitinfo & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Host)
+ {
+ isurf = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data (imageData,
+ CAIRO_FORMAT_RGB24,
+ surface->extents.width,
+ surface->extents.he