diff --git a/configure.in b/configure.in index b69b11bcf6f..f86af0da3ff 100644 --- a/configure.in +++ b/configure.in @@ -7248,7 +7248,6 @@ if test "$MOZ_SVG" -o "$MOZ_ENABLE_CANVAS" -o "$MOZ_ENABLE_CAIRO_GFX" ; then fi if test "$MOZ_WIDGET_TOOLKIT" = "mac" -o "$MOZ_WIDGET_TOOLKIT" = "cocoa"; then QUARTZ_SURFACE_FEATURE="#define CAIRO_HAS_QUARTZ_SURFACE 1" - NQUARTZ_SURFACE_FEATURE="#define CAIRO_HAS_NQUARTZ_SURFACE 1" ATSUI_FONT_FEATURE="#define CAIRO_HAS_ATSUI_FONT 1" fi if test "$MOZ_WIDGET_TOOLKIT" = "windows"; then diff --git a/gfx/cairo/README b/gfx/cairo/README index 3e2989ddf3e..df9d443a6c8 100644 --- a/gfx/cairo/README +++ b/gfx/cairo/README @@ -7,10 +7,20 @@ http://www.cairographics.org/. VERSIONS: - cairo (1.3.12 tagged snapshot) + cairo (1.4.2) glitz 0.5.2 (cvs - 2006-01-10) ***** NOTE FOR VISUAL C++ 6.0 ***** VC6 is not supported. Please upgrade to VC8. +==== Patches ==== + +All patches in the cairo tree are surrounded by "MOZILLA_CAIRO_NOT_DEFINED" (which should NOT be defined). + +Some specific things: + +max-font-size.patch: Clamp freetype font size to 1000 to avoid overflow issues + +fbcompose-bandaid.patch: Disable "optimized" code in non-MMX case due to bugs + diff --git a/gfx/cairo/cairo/src/Makefile.in b/gfx/cairo/cairo/src/Makefile.in index 83a56c92962..c128e377a9e 100644 --- a/gfx/cairo/cairo/src/Makefile.in +++ b/gfx/cairo/cairo/src/Makefile.in @@ -129,11 +129,6 @@ endif ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) CSRCS += cairo-quartz-surface.c cairo-atsui-font.c EXPORTS += cairo-quartz.h cairo-atsui.h - -ifdef MOZ_ENABLE_CAIRO_GFX -CSRCS += cairo-nquartz-surface.c -EXPORTS += cairo-nquartz.h -endif endif ifeq ($(MOZ_WIDGET_TOOLKIT),beos) diff --git a/gfx/cairo/cairo/src/cairo-analysis-surface-private.h b/gfx/cairo/cairo/src/cairo-analysis-surface-private.h index 9a66d57527b..9d3410b867f 100644 --- a/gfx/cairo/cairo/src/cairo-analysis-surface-private.h +++ b/gfx/cairo/cairo/src/cairo-analysis-surface-private.h @@ -1,4 +1,4 @@ -/* $Id: cairo-analysis-surface-private.h,v 1.4 2007/04/03 18:59:47 vladimir%pobox.com Exp $ +/* $Id: cairo-analysis-surface-private.h,v 1.5 2007/04/04 01:09:15 vladimir%pobox.com Exp $ * * Copyright © 2005 Keith Packard * diff --git a/gfx/cairo/cairo/src/cairo-atsui-font.c b/gfx/cairo/cairo/src/cairo-atsui-font.c index e8d57105c74..a26e76ffa1c 100644 --- a/gfx/cairo/cairo/src/cairo-atsui-font.c +++ b/gfx/cairo/cairo/src/cairo-atsui-font.c @@ -82,6 +82,9 @@ struct _cairo_atsui_font { ATSUStyle style; ATSUStyle unscaled_style; ATSUFontID fontID; + + Fixed size; + CGAffineTransform font_matrix; }; struct _cairo_atsui_font_face { @@ -146,47 +149,6 @@ cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id) return &font_face->base; } -static CGContextRef -CGBitmapContextCreateWithCairoImageSurface (const cairo_image_surface_t * surface) -{ - CGContextRef contextRef; - CGColorSpaceRef colorSpace; - int bits_per_comp, alpha; - - /* Create a CGBitmapContext for the dest surface for drawing into */ - if (surface->depth == 1) { - colorSpace = CGColorSpaceCreateDeviceGray (); - bits_per_comp = 1; - alpha = kCGImageAlphaNone; - } else if (surface->depth == 8) { - colorSpace = CGColorSpaceCreateDeviceGray (); - bits_per_comp = 8; - alpha = kCGImageAlphaNone; - } else if (surface->depth == 24) { - colorSpace = CGColorSpaceCreateDeviceRGB (); - bits_per_comp = 8; - alpha = kCGImageAlphaNoneSkipFirst | CG_BITMAP_BYTE_ORDER_FLAG; - } else if (surface->depth == 32) { - colorSpace = CGColorSpaceCreateDeviceRGB (); - bits_per_comp = 8; - alpha = kCGImageAlphaPremultipliedFirst | CG_BITMAP_BYTE_ORDER_FLAG; - } else { - /* not reached */ - return NULL; - } - - contextRef = CGBitmapContextCreate (surface->data, - surface->width, - surface->height, - bits_per_comp, - surface->stride, - colorSpace, - alpha); - CGColorSpaceRelease (colorSpace); - - return contextRef; -} - static CGAffineTransform CGAffineTransformMakeWithCairoFontScale(const cairo_matrix_t *scale) { @@ -195,29 +157,19 @@ CGAffineTransformMakeWithCairoFontScale(const cairo_matrix_t *scale) 0, 0); } -static CGAffineTransform -CGAffineTransformMakeWithCairoScaleFactors(const cairo_matrix_t *scale) -{ - double xscale = 1.0; - double yscale = 1.0; - _cairo_matrix_compute_scale_factors(scale, &xscale, &yscale, 1); - return CGAffineTransformMake(xscale, 0, - 0, yscale, - 0, 0); -} - static ATSUStyle -CreateSizedCopyOfStyle(ATSUStyle inStyle, const cairo_matrix_t *scale) +CreateSizedCopyOfStyle(ATSUStyle inStyle, + const Fixed *theSize, + const CGAffineTransform *theTransform) { ATSUStyle style; OSStatus err; - - /* Set the style's size */ - Fixed theSize = FloatToFixed(1.0); - CGAffineTransform theTransform = CGAffineTransformMakeWithCairoScaleFactors(scale); - const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag, kATSUFontMatrixTag }; - const ByteCount theFontStyleSizes[] = { sizeof(Fixed), sizeof(CGAffineTransform) }; - ATSUAttributeValuePtr theFontStyleValues[] = { &theSize, &theTransform }; + const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag, + kATSUFontMatrixTag }; + const ByteCount theFontStyleSizes[] = { sizeof(Fixed), + sizeof(CGAffineTransform) }; + ATSUAttributeValuePtr theFontStyleValues[] = { (Fixed *)theSize, + (CGAffineTransform *)theTransform }; err = ATSUCreateAndCopyStyle(inStyle, &style); @@ -273,6 +225,8 @@ _cairo_atsui_font_create_scaled (cairo_font_face_t *font_face, cairo_atsui_font_t *font = NULL; OSStatus err; cairo_status_t status; + double xscale = 1.0; + double yscale = 1.0; font = malloc(sizeof(cairo_atsui_font_t)); if (font == NULL) @@ -281,7 +235,14 @@ _cairo_atsui_font_create_scaled (cairo_font_face_t *font_face, _cairo_scaled_font_init(&font->base, font_face, font_matrix, ctm, options, &cairo_atsui_scaled_font_backend); - font->style = CreateSizedCopyOfStyle(style, &font->base.scale); + _cairo_matrix_compute_scale_factors (&font->base.scale, + &xscale, &yscale, 1); + font->font_matrix = CGAffineTransformMake (1., 0., + 0., yscale/xscale, + 0., 0.); + font->size = FloatToFixed (xscale); + + font->style = CreateSizedCopyOfStyle (style, &font->size, &font->font_matrix); { Fixed theSize = FloatToFixed(1.0); @@ -480,11 +441,19 @@ OSStatus _close_path_for_metrics(void *callback_data) return noErr; } +static GlyphID +_cairo_atsui_scaled_glyph_index (cairo_scaled_glyph_t *scaled_glyph) { + unsigned long index = _cairo_scaled_glyph_index (scaled_glyph); + if (index > 0xffff) + return kATSDeletedGlyphcode; + return index; +} + static cairo_status_t _cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph) { - cairo_text_extents_t extents; + cairo_text_extents_t extents = {0, 0, 0, 0, 0, 0}; OSStatus err, callback_err; ATSGlyphScreenMetrics metricsH; static ATSCubicMoveToUPP moveProc = NULL; @@ -492,10 +461,17 @@ _cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font, static ATSCubicCurveToUPP curveProc = NULL; static ATSCubicClosePathUPP closePathProc = NULL; CGMutablePathRef path; - GlyphID theGlyph = _cairo_scaled_glyph_index (scaled_glyph); + GlyphID theGlyph = _cairo_atsui_scaled_glyph_index (scaled_glyph); double xscale, yscale; CGRect rect; + if (theGlyph == kATSDeletedGlyphcode) { + _cairo_scaled_glyph_set_metrics (scaled_glyph, + &scaled_font->base, + &extents); + return CAIRO_STATUS_SUCCESS; + } + /* We calculate the advance from the screen metrics. We * could probably take this from the glyph path. */ @@ -503,7 +479,7 @@ _cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font, 1, &theGlyph, 0, false, false, &metricsH); if (err != noErr) - return CAIRO_INT_STATUS_UNSUPPORTED; + return CAIRO_STATUS_NO_MEMORY; /* Scale down to font units.*/ _cairo_matrix_compute_scale_factors (&scaled_font->base.scale, @@ -532,11 +508,8 @@ _cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font, (void *)path, &callback_err); if (err != noErr) { - /* This could potentially happen for bitmap fonts, where - * no paths are available. - */ CGPathRelease (path); - return CAIRO_INT_STATUS_UNSUPPORTED; + return CAIRO_STATUS_NO_MEMORY; } rect = CGPathGetBoundingBox (path); @@ -636,6 +609,7 @@ _cairo_atsui_scaled_font_init_glyph_path (cairo_atsui_font_t *scaled_font, static ATSCubicLineToUPP lineProc = NULL; static ATSCubicCurveToUPP curveProc = NULL; static ATSCubicClosePathUPP closePathProc = NULL; + GlyphID theGlyph = _cairo_atsui_scaled_glyph_index (scaled_glyph); OSStatus err; cairo_atsui_scaled_path_t scaled_path; cairo_matrix_t *font_to_device = &scaled_font->base.scale; @@ -643,6 +617,17 @@ _cairo_atsui_scaled_font_init_glyph_path (cairo_atsui_font_t *scaled_font, double xscale; double yscale; + scaled_path.path = _cairo_path_fixed_create (); + if (!scaled_path.path) + return CAIRO_STATUS_NO_MEMORY; + + if (theGlyph == kATSDeletedGlyphcode) { + _cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base, + scaled_path.path); + + return CAIRO_STATUS_SUCCESS; + } + /* extract the rotation/shear component of the scale matrix. */ _cairo_matrix_compute_scale_factors (font_to_device, &xscale, &yscale, 1); cairo_matrix_init (&unscaled_font_to_device, @@ -653,9 +638,6 @@ _cairo_atsui_scaled_font_init_glyph_path (cairo_atsui_font_t *scaled_font, cairo_matrix_scale (&unscaled_font_to_device, 1.0/xscale, 1.0/yscale); scaled_path.scale = &unscaled_font_to_device; - scaled_path.path = _cairo_path_fixed_create (); - if (!scaled_path.path) - return CAIRO_STATUS_NO_MEMORY; if (moveProc == NULL) { moveProc = NewATSCubicMoveToUPP(_move_to); @@ -665,7 +647,7 @@ _cairo_atsui_scaled_font_init_glyph_path (cairo_atsui_font_t *scaled_font, } err = ATSUGlyphGetCubicPaths(scaled_font->style, - _cairo_scaled_glyph_index (scaled_glyph), + theGlyph, moveProc, lineProc, curveProc, @@ -691,7 +673,7 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font, cairo_scaled_font_t base = scaled_font->base; cairo_font_extents_t extents = base.extents; - GlyphID theGlyph = _cairo_scaled_glyph_index (scaled_glyph); + GlyphID theGlyph = _cairo_atsui_scaled_glyph_index (scaled_glyph); ATSGlyphScreenMetrics metricsH; double left, bottom, width, height; double xscale, yscale; @@ -699,6 +681,16 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font, CGAffineTransform transform; + if (theGlyph == kATSDeletedGlyphcode) { + surface = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2); + if (!surface) + return CAIRO_STATUS_NO_MEMORY; + _cairo_scaled_glyph_set_surface (scaled_glyph, + &base, + surface); + return CAIRO_STATUS_SUCCESS; + } + /* Compute a box to contain the glyph mask. The vertical * sizes come from the font extents; extra pixels are * added to account for fractional sizes. @@ -754,10 +746,23 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font, if (!surface) return CAIRO_STATUS_NO_MEMORY; - drawingContext = CGBitmapContextCreateWithCairoImageSurface (surface); + /* Create a CGBitmapContext for the dest surface for drawing into */ + { + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray (); + + drawingContext = CGBitmapContextCreate (surface->data, + surface->width, + surface->height, + 8, + surface->stride, + colorSpace, + kCGImageAlphaNone); + CGColorSpaceRelease (colorSpace); + } + if (!drawingContext) { cairo_surface_destroy ((cairo_surface_t *)surface); - return CAIRO_INT_STATUS_UNSUPPORTED; + return CAIRO_STATUS_NO_MEMORY; } atsFont = FMGetATSFontRefFromFont (scaled_font->fontID); @@ -839,6 +844,9 @@ _cairo_atsui_font_text_to_glyphs (void *abstract_font, cairo_atsui_font_t *font = abstract_font; ItemCount glyphCount; int i; + CGPoint point; + double xscale, yscale; + CGAffineTransform device_to_user_scale; status = _cairo_utf8_to_utf16 ((unsigned char *)utf8, -1, &utf16, &n16); if (status) @@ -865,9 +873,18 @@ _cairo_atsui_font_text_to_glyphs (void *abstract_font, return CAIRO_STATUS_NO_MEMORY; } + _cairo_matrix_compute_scale_factors (&font->base.ctm, &xscale, &yscale, 1); + device_to_user_scale = + CGAffineTransformInvert (CGAffineTransformMake (xscale, 0, + 0, yscale, + 0, 0)); for (i = 0; i < *num_glyphs; i++) { (*glyphs)[i].index = layoutRecords[i].glyphID; - (*glyphs)[i].x = x + FixedToFloat(layoutRecords[i].realPos); + /* ATSLayoutRecord.realPos is in device units, convert to user units */ + point = CGPointMake (FixedToFloat (layoutRecords[i].realPos), 0); + point = CGPointApplyAffineTransform (point, device_to_user_scale); + + (*glyphs)[i].x = x + point.x; (*glyphs)[i].y = y; } @@ -881,158 +898,6 @@ _cairo_atsui_font_text_to_glyphs (void *abstract_font, return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_atsui_font_old_show_glyphs (void *abstract_font, - cairo_operator_t op, - cairo_pattern_t *pattern, - cairo_surface_t *generic_surface, - int source_x, - int source_y, - int dest_x, - int dest_y, - unsigned int width, - unsigned int height, - cairo_glyph_t *glyphs, - int num_glyphs) -{ - cairo_atsui_font_t *font = abstract_font; - CGContextRef drawingContext; - cairo_image_surface_t *destImageSurface; - int i; - void *extra = NULL; - cairo_bool_t can_draw_directly; - cairo_rectangle_int16_t rect; - cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *)generic_surface; - - ATSFontRef atsFont; - CGFontRef cgFont; - CGAffineTransform textTransform; - - if (!_cairo_surface_is_quartz (generic_surface)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - /* Check if we can draw directly to the destination surface */ - can_draw_directly = _cairo_pattern_is_opaque_solid (pattern) && - op == CAIRO_OPERATOR_OVER; - - if (!can_draw_directly) { - rect.x = dest_x; - rect.y = dest_y; - rect.width = width; - rect.height = height; - - _cairo_surface_acquire_dest_image(generic_surface, - &rect, - &destImageSurface, - &rect, - &extra); - - drawingContext = CGBitmapContextCreateWithCairoImageSurface (destImageSurface); - if (!drawingContext) - return CAIRO_INT_STATUS_UNSUPPORTED; - - CGContextTranslateCTM(drawingContext, 0, destImageSurface->height); - CGContextScaleCTM(drawingContext, 1.0f, -1.0f); - } else { - drawingContext = ((cairo_quartz_surface_t *)generic_surface)->context; - CGContextSaveGState (drawingContext); - } - - atsFont = FMGetATSFontRefFromFont(font->fontID); - cgFont = CGFontCreateWithPlatformFont(&atsFont); - - CGContextSetFont(drawingContext, cgFont); - - if (font->base.options.antialias == CAIRO_ANTIALIAS_NONE) { - CGContextSetShouldAntialias (drawingContext, false); - } - - textTransform = CGAffineTransformMakeWithCairoFontScale(&font->base.scale); - textTransform = CGAffineTransformScale(textTransform, 1.0f, -1.0f); - - CGContextSetFontSize(drawingContext, 1.0); - CGContextSetTextMatrix(drawingContext, textTransform); - - if (pattern->type == CAIRO_PATTERN_TYPE_SOLID && - _cairo_pattern_is_opaque_solid(pattern)) - { - cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *)pattern; - CGContextSetRGBFillColor(drawingContext, - solid->color.red, - solid->color.green, - solid->color.blue, 1.0f); - } else { - CGContextSetRGBFillColor(drawingContext, 0.0f, 0.0f, 0.0f, 0.0f); - } - - if (surface->clip_region) { - pixman_box16_t *boxes = pixman_region_rects (surface->clip_region); - int num_boxes = pixman_region_num_rects (surface->clip_region); - CGRect stack_rects[10]; - CGRect *rects; - int i; - - /* XXX: Return-value of malloc needs to be checked for - * NULL. Can someone fix this who is more familiar with - * the cleanup needed in this function? - */ - if (num_boxes > 10) - rects = malloc (sizeof (CGRect) * num_boxes); - else - rects = stack_rects; - - for (i = 0; i < num_boxes; i++) { - rects[i].origin.x = boxes[i].x1; - rects[i].origin.y = boxes[i].y1; - rects[i].size.width = boxes[i].x2 - boxes[i].x1; - rects[i].size.height = boxes[i].y2 - boxes[i].y1; - } - - CGContextClipToRects (drawingContext, rects, num_boxes); - - if (rects != stack_rects) - free(rects); - } - - /* TODO - bold and italic text - * - * We could draw the text using ATSUI and get bold, italics - * etc. for free, but ATSUI does a lot of text layout work - * that we don't really need... - */ - - for (i = 0; i < num_glyphs; i++) { - CGGlyph theGlyph = glyphs[i].index; - - /* round glyph locations to the nearest pixel */ - /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ - CGContextShowGlyphsAtPoint(drawingContext, - _cairo_lround (glyphs[i].x), - _cairo_lround (glyphs[i].y), - &theGlyph, 1); - } - - if (!can_draw_directly) { - CGContextRelease(drawingContext); - - _cairo_surface_release_dest_image(generic_surface, - &rect, - destImageSurface, - &rect, - extra); - } else { - CGContextRestoreGState (drawingContext); - } - - return CAIRO_STATUS_SUCCESS; -} - -cairo_bool_t -_cairo_scaled_font_is_atsui (cairo_scaled_font_t *sfont) -{ - return (sfont->backend == &cairo_atsui_scaled_font_backend); -} - ATSUStyle _cairo_atsui_scaled_font_get_atsu_style (cairo_scaled_font_t *sfont) { @@ -1049,6 +914,30 @@ _cairo_atsui_scaled_font_get_atsu_font_id (cairo_scaled_font_t *sfont) return afont->fontID; } +static cairo_int_status_t +_cairo_atsui_load_truetype_table (void *abstract_font, + unsigned long tag, + long offset, + unsigned char *buffer, + unsigned long *length) +{ + cairo_atsui_font_t *scaled_font = abstract_font; + ATSFontRef atsFont; + OSStatus err; + + atsFont = FMGetATSFontRefFromFont (scaled_font->fontID); + err = ATSFontGetTable ( atsFont, tag, + (ByteOffset) offset, + (ByteCount) *length, + buffer, + length); + if (err != noErr) { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + return CAIRO_STATUS_SUCCESS; +} + const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend = { CAIRO_FONT_TYPE_ATSUI, _cairo_atsui_font_create_toy, @@ -1056,6 +945,8 @@ const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend = { _cairo_atsui_font_scaled_glyph_init, _cairo_atsui_font_text_to_glyphs, NULL, /* ucs4_to_index */ - _cairo_atsui_font_old_show_glyphs, + NULL, /* show_glyphs */ + _cairo_atsui_load_truetype_table, + NULL, /* map_glyphs_to_unicode */ }; diff --git a/gfx/cairo/cairo/src/cairo-bentley-ottmann.c b/gfx/cairo/cairo/src/cairo-bentley-ottmann.c index 4a72a8d0d88..928b6cd5646 100644 --- a/gfx/cairo/cairo/src/cairo-bentley-ottmann.c +++ b/gfx/cairo/cairo/src/cairo-bentley-ottmann.c @@ -121,7 +121,7 @@ typedef struct _cairo_bo_event { #define SKIP_ELT_TO_EVENT(elt) SKIP_LIST_ELT_TO_DATA (cairo_bo_event_t, (elt)) typedef struct _cairo_bo_event_queue { - skip_list_t intersection_queue; + cairo_skip_list_t intersection_queue; cairo_bo_event_t *startstop_events; cairo_bo_event_t **sorted_startstop_event_ptrs; @@ -129,9 +129,9 @@ typedef struct _cairo_bo_event_queue { unsigned num_startstop_events; } cairo_bo_event_queue_t; -/* This structure extends skip_list_t, which must come first. */ +/* This structure extends cairo_skip_list_t, which must come first. */ typedef struct _cairo_bo_sweep_line { - skip_list_t active_edges; + cairo_skip_list_t active_edges; cairo_bo_edge_t *head; cairo_bo_edge_t *tail; int32_t current_y; @@ -697,7 +697,7 @@ _cairo_bo_event_queue_insert (cairo_bo_event_queue_t *queue, cairo_bo_event_t *event) { /* Don't insert if there's already an equivalent intersection event in the queue. */ - skip_list_insert (&queue->intersection_queue, event, + _cairo_skip_list_insert (&queue->intersection_queue, event, event->type == CAIRO_BO_EVENT_TYPE_INTERSECTION); } @@ -706,7 +706,7 @@ _cairo_bo_event_queue_delete (cairo_bo_event_queue_t *queue, cairo_bo_event_t *event) { if (CAIRO_BO_EVENT_TYPE_INTERSECTION == event->type) - skip_list_delete_given ( &queue->intersection_queue, &event->elt ); + _cairo_skip_list_delete_given ( &queue->intersection_queue, &event->elt ); } static cairo_bo_event_t * @@ -740,7 +740,7 @@ _cairo_bo_event_queue_init (cairo_bo_event_queue_t *event_queue, memset (event_queue, 0, sizeof(*event_queue)); - skip_list_init (&event_queue->intersection_queue, + _cairo_skip_list_init (&event_queue->intersection_queue, cairo_bo_event_compare_abstract, sizeof (cairo_bo_event_t)); if (0 == num_edges) @@ -789,7 +789,7 @@ _cairo_bo_event_queue_init (cairo_bo_event_queue_t *event_queue, static void _cairo_bo_event_queue_fini (cairo_bo_event_queue_t *event_queue) { - skip_list_fini (&event_queue->intersection_queue); + _cairo_skip_list_fini (&event_queue->intersection_queue); if (event_queue->startstop_events) free (event_queue->startstop_events); if (event_queue->sorted_startstop_event_ptrs) @@ -834,7 +834,7 @@ _cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_ static void _cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line) { - skip_list_init (&sweep_line->active_edges, + _cairo_skip_list_init (&sweep_line->active_edges, _sweep_line_elt_compare, sizeof (sweep_line_elt_t)); sweep_line->head = NULL; @@ -845,7 +845,7 @@ _cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line) static void _cairo_bo_sweep_line_fini (cairo_bo_sweep_line_t *sweep_line) { - skip_list_fini (&sweep_line->active_edges); + _cairo_skip_list_fini (&sweep_line->active_edges); } static void @@ -856,7 +856,7 @@ _cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line, sweep_line_elt_t *sweep_line_elt; cairo_bo_edge_t **prev_of_next, **next_of_prev; - sweep_line_elt = skip_list_insert (&sweep_line->active_edges, &edge, + sweep_line_elt = _cairo_skip_list_insert (&sweep_line->active_edges, &edge, 1 /* unique inserts*/); next_elt = sweep_line_elt->elt.next[0]; @@ -884,7 +884,7 @@ _cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line, { cairo_bo_edge_t **left_next, **right_prev; - skip_list_delete_given (&sweep_line->active_edges, &edge->sweep_line_elt->elt); + _cairo_skip_list_delete_given (&sweep_line->active_edges, &edge->sweep_line_elt->elt); left_next = &sweep_line->head; if (edge->prev) @@ -975,7 +975,7 @@ _cairo_bo_event_queue_print (cairo_bo_event_queue_t *event_queue) { skip_elt_t *elt; /* XXX: fixme to print the start/stop array too. */ - skip_list_t *queue = &event_queue->intersection_queue; + cairo_skip_list_t *queue = &event_queue->intersection_queue; cairo_bo_event_t *event; printf ("Event queue:\n"); @@ -1767,7 +1767,7 @@ int main (void) { char random_name[] = "random-XX"; - static cairo_bo_edge_t random_edges[MAX_RANDOM], *edge; + cairo_bo_edge_t random_edges[MAX_RANDOM], *edge; unsigned int i, num_random; test_t *test; diff --git a/gfx/cairo/cairo/src/cairo-cff-subset.c b/gfx/cairo/cairo/src/cairo-cff-subset.c index d26ee870cab..b35498940b8 100644 --- a/gfx/cairo/cairo/src/cairo-cff-subset.c +++ b/gfx/cairo/cairo/src/cairo-cff-subset.c @@ -31,6 +31,7 @@ * * Contributor(s): * Adrian Johnson + * Eugeniy Meshcheryakov */ #include "cairoint.h" @@ -81,6 +82,13 @@ typedef struct _cff_dict_operator { int operand_offset; } cff_dict_operator_t; +typedef struct _cff_charset { + cairo_bool_t is_builtin; + const uint16_t *sids; + const unsigned char *data; + int length; +} cff_charset_t; + typedef struct _cairo_cff_font { cairo_scaled_font_subset_t *scaled_font_subset; @@ -100,11 +108,14 @@ typedef struct _cairo_cff_font { cairo_array_t global_sub_index; cairo_array_t local_sub_index; int num_glyphs; + cff_charset_t charset; + int charset_offset; /* Subsetted Font Data */ char *subset_font_name; cairo_array_t charstrings_subset_index; cairo_array_t strings_subset_index; + cairo_array_t charset_subset; cairo_array_t output; /* Subset Metrics */ @@ -114,34 +125,6 @@ typedef struct _cairo_cff_font { } cairo_cff_font_t; -#ifdef WORDS_BIGENDIAN - -#define cpu_to_be16(v) (v) -#define be16_to_cpu(v) (v) -#define cpu_to_be32(v) (v) - -#else - -static inline uint16_t -cpu_to_be16(uint16_t v) -{ - return (v << 8) | (v >> 8); -} - -static inline uint16_t -be16_to_cpu(uint16_t v) -{ - return cpu_to_be16 (v); -} - -static inline uint32_t -cpu_to_be32(uint32_t v) -{ - return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16); -} - -#endif - /* Encoded integer using maximum sized encoding. This is required for * operands that are later modified after encoding. */ static unsigned char * @@ -505,20 +488,6 @@ fail: return status; } -static void -cff_dict_remove (cairo_hash_table_t *dict, unsigned short operator) -{ - cff_dict_operator_t key, *op; - - _cairo_dict_init_key (&key, operator); - if (_cairo_hash_table_lookup (dict, &key.base, - (cairo_hash_entry_t **) &op)) - { - free (op->operand); - _cairo_hash_table_remove (dict, (cairo_hash_entry_t *) op); - } -} - static unsigned char * cff_dict_get_operands (cairo_hash_table_t *dict, unsigned short operator, @@ -742,12 +711,19 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font) decode_integer (operand, &offset); cairo_cff_font_read_private_dict (font, font->data + offset, size); - cff_dict_remove (font->top_dict, CHARSET_OP); + operand = cff_dict_get_operands (font->top_dict, CHARSET_OP, &size); + if (!operand) + font->charset_offset = 0; + else { + decode_integer (operand, &offset); + font->charset_offset = offset; + } /* Use maximum sized encoding to reserve space for later modification. */ end_buf = encode_integer_max (buf, 0); cff_dict_set_operands (font->top_dict, CHARSTRINGS_OP, buf, end_buf - buf); cff_dict_set_operands (font->top_dict, ENCODING_OP, buf, end_buf - buf); + cff_dict_set_operands (font->top_dict, CHARSET_OP, buf, end_buf - buf); /* Private has two operands - size and offset */ end_buf = encode_integer_max (end_buf, 0); cff_dict_set_operands (font->top_dict, PRIVATE_OP, buf, end_buf - buf); @@ -770,6 +746,138 @@ cairo_cff_font_read_global_subroutines (cairo_cff_font_t *font) return cff_index_read (&font->global_sub_index, &font->current_ptr, font->data_end); } +static cairo_int_status_t +cff_charset_read_data (cff_charset_t *charset, const unsigned char *data, + const unsigned char *data_end, int num_glyphs) +{ + const unsigned char *p = data; + + num_glyphs -= 1; /* do not count .notdef */ + + if (p + 1 > data_end) + return CAIRO_INT_STATUS_UNSUPPORTED; + + switch (*p++) { + case 0: + if (p + num_glyphs*2 > data_end) + return CAIRO_INT_STATUS_UNSUPPORTED; + charset->is_builtin = FALSE; + charset->data = data; + charset->length = num_glyphs * 2 + 1; + break; + case 1: + while (num_glyphs > 0) { + if (p + 3 > data_end) + return CAIRO_INT_STATUS_UNSUPPORTED; + num_glyphs -= p[2] + 1; + p += 3; + } + if (num_glyphs < 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + charset->is_builtin = FALSE; + charset->data = data; + charset->length = p - data; + break; + case 2: + while (num_glyphs > 0) { + if (p + 4 > data_end) + return CAIRO_INT_STATUS_UNSUPPORTED; + num_glyphs -= be16_to_cpu(*(uint16_t *)(p + 2)) + 1; + p += 4; + } + if (num_glyphs < 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + charset->is_builtin = FALSE; + charset->data = data; + charset->length = p - data; + break; + default: + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + return CAIRO_STATUS_SUCCESS; +} + +static const uint16_t ISOAdobe_charset[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 228, +}; + +static const uint16_t Expert_charset[] = { + 1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13, + 14, 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, 247, + 248, 27, 28, 249, 250, 251, 252, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, + 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, + 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 158, 155, 163, + 319, 320, 321, 322, 323, 324, 325, 326, 150, 164, 169, + 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, + 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378, +}; + +static const uint16_t ExpertSubset_charset[] = { + 1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, + 251, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 272, + 300, 301, 302, 305, 314, 315, 158, 155, 163, 320, 321, + 322, 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, + 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, +}; + +static cairo_int_status_t +cairo_cff_font_read_charset (cairo_cff_font_t *font) +{ + switch (font->charset_offset) { + case 0: + /* ISOAdobe charset */ + font->charset.is_builtin = TRUE; + font->charset.sids = ISOAdobe_charset; + font->charset.length = sizeof (ISOAdobe_charset); + return CAIRO_STATUS_SUCCESS; + case 1: + /* Expert charset */ + font->charset.is_builtin = TRUE; + font->charset.sids = Expert_charset; + font->charset.length = sizeof (Expert_charset); + return CAIRO_STATUS_SUCCESS; + case 2: + /* ExpertSubset charset */; + font->charset.is_builtin = TRUE; + font->charset.sids = ExpertSubset_charset; + font->charset.length = sizeof (ExpertSubset_charset); + return CAIRO_STATUS_SUCCESS; + default: + break; + } + return cff_charset_read_data (&font->charset, font->data + (unsigned)font->charset_offset, + font->data_end, font->num_glyphs); +} + typedef cairo_int_status_t (*font_read_t) (cairo_cff_font_t *font); @@ -779,6 +887,8 @@ static const font_read_t font_read_funcs[] = { cairo_cff_font_read_top_dict, cairo_cff_font_read_strings, cairo_cff_font_read_global_subroutines, + /* non-contiguous */ + cairo_cff_font_read_charset, }; static cairo_int_status_t @@ -898,6 +1008,80 @@ cairo_cff_font_subset_charstrings (cairo_cff_font_t *font) return CAIRO_STATUS_SUCCESS; } +static uint16_t +cff_sid_from_gid (const cff_charset_t *charset, int gid) +{ + const uint16_t *sids; + const unsigned char *p; + int prev_glyph; + + if (charset->is_builtin) { + if (gid - 1 < charset->length / 2) + return charset->sids[gid - 1]; + } + else { + /* no need to check sizes here, this was done during reading */ + switch (charset->data[0]) { + case 0: + sids = (const uint16_t *)(charset->data + 1); + return be16_to_cpu(sids[gid - 1]); + case 1: + prev_glyph = 1; + for (p = charset->data + 1; p < charset->data + charset->length; p += 3) { + if (gid <= prev_glyph + p[2]) { + uint16_t sid = be16_to_cpu(*(const uint16_t *)p); + return sid + gid - prev_glyph; + } + prev_glyph += p[2] + 1; + } + break; + case 2: + prev_glyph = 1; + for (p = charset->data + 1; p < charset->data + charset->length; p += 4) { + uint16_t nLeft = be16_to_cpu(*(const uint16_t *)(p + 2)); + if (gid <= prev_glyph + nLeft) { + uint16_t sid = be16_to_cpu(*(const uint16_t *)p); + return sid + gid - prev_glyph; + } + prev_glyph += nLeft + 1; + } + break; + default: + break; + } + } + return 0; +} + +static cairo_status_t +cairo_cff_font_subset_charset (cairo_cff_font_t *font) +{ + unsigned int i; + + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { + int gid = font->scaled_font_subset->glyphs[i]; + uint16_t original_sid = cff_sid_from_gid(&font->charset, gid); + uint16_t new_sid; + cff_index_element_t *element; + cairo_status_t status; + + if (original_sid >= NUM_STD_STRINGS) { + element = _cairo_array_index (&font->strings_index, original_sid - NUM_STD_STRINGS); + new_sid = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index); + status = cff_index_append (&font->strings_subset_index, element->data, element->length); + if (status) + return status; + } + else + new_sid = original_sid; + + status = _cairo_array_append(&font->charset_subset, &new_sid); + if (status) + return status; + } + return CAIRO_STATUS_SUCCESS; +} + static cairo_status_t cairo_cff_font_subset_font (cairo_cff_font_t *font) { @@ -910,6 +1094,10 @@ cairo_cff_font_subset_font (cairo_cff_font_t *font) return status; status = cairo_cff_font_subset_charstrings (font); + if (status) + return status; + + status = cairo_cff_font_subset_charset (font); return status; } @@ -1038,6 +1226,27 @@ cairo_cff_font_write_encoding (cairo_cff_font_t *font) return _cairo_array_append_multiple (&font->output, buf, 4); } +static cairo_status_t +cairo_cff_font_write_charset (cairo_cff_font_t *font) +{ + unsigned char format = 0; + unsigned int i; + cairo_status_t status; + + cairo_cff_font_set_topdict_operator_to_cur_pos (font, CHARSET_OP); + status = _cairo_array_append (&font->output, &format); + if (status) + return status; + + for (i = 0; i < (unsigned)_cairo_array_num_elements(&font->charset_subset); i++) { + uint16_t sid = cpu_to_be16(*(uint16_t *)_cairo_array_index(&font->charset_subset, i)); + status = _cairo_array_append_multiple (&font->output, &sid, sizeof(sid)); + if (status) + return status; + } + return CAIRO_STATUS_SUCCESS; +} + static cairo_status_t cairo_cff_font_write_charstrings (cairo_cff_font_t *font) { @@ -1098,6 +1307,7 @@ static const font_write_t font_write_funcs[] = { cairo_cff_font_write_strings, cairo_cff_font_write_global_subrs, cairo_cff_font_write_encoding, + cairo_cff_font_write_charset, cairo_cff_font_write_charstrings, cairo_cff_font_write_private_dict_and_local_sub, }; @@ -1345,6 +1555,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset, cff_index_init (&font->local_sub_index); cff_index_init (&font->charstrings_subset_index); cff_index_init (&font->strings_subset_index); + _cairo_array_init (&font->charset_subset, sizeof(uint16_t)); free (name); *font_return = font; @@ -1383,6 +1594,7 @@ cairo_cff_font_destroy (cairo_cff_font_t *font) cff_index_fini (&font->local_sub_index); cff_index_fini (&font->charstrings_subset_index); cff_index_fini (&font->strings_subset_index); + _cairo_array_fini (&font->charset_subset); free (font); } diff --git a/gfx/cairo/cairo/src/cairo-clip.c b/gfx/cairo/cairo/src/cairo-clip.c index 605589bb936..efecd89efd2 100644 --- a/gfx/cairo/cairo/src/cairo-clip.c +++ b/gfx/cairo/cairo/src/cairo-clip.c @@ -48,7 +48,10 @@ _cairo_clip_path_destroy (cairo_clip_path_t *clip_path); void _cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target) { - clip->mode = _cairo_surface_get_clip_mode (target); + if (target) + clip->mode = _cairo_surface_get_clip_mode (target); + else + clip->mode = CAIRO_CLIP_MODE_MASK; clip->surface = NULL; clip->surface_rect.x = 0; diff --git a/gfx/cairo/cairo/src/cairo-color.c b/gfx/cairo/cairo/src/cairo-color.c index a3488392661..ad6316e10ef 100644 --- a/gfx/cairo/cairo/src/cairo-color.c +++ b/gfx/cairo/cairo/src/cairo-color.c @@ -95,7 +95,8 @@ _cairo_color_init_rgb (cairo_color_t *color, * then special-casing the result of an input value of 1.0 so that it * maps to 65535 instead of 65536. */ -static inline uint16_t _color_to_short (double d) +uint16_t +_cairo_color_double_to_short (double d) { uint32_t i; i = (uint32_t) (d * 65536); @@ -106,10 +107,10 @@ static inline uint16_t _color_to_short (double d) static void _cairo_color_compute_shorts (cairo_color_t *color) { - color->red_short = _color_to_short (color->red * color->alpha); - color->green_short = _color_to_short (color->green * color->alpha); - color->blue_short = _color_to_short (color->blue * color->alpha); - color->alpha_short = _color_to_short (color->alpha); + color->red_short = _cairo_color_double_to_short (color->red * color->alpha); + color->green_short = _cairo_color_double_to_short (color->green * color->alpha); + color->blue_short = _cairo_color_double_to_short (color->blue * color->alpha); + color->alpha_short = _cairo_color_double_to_short (color->alpha); } void diff --git a/gfx/cairo/cairo/src/cairo-directfb-surface.c b/gfx/cairo/cairo/src/cairo-directfb-surface.c index 46a4c7f6a74..686510d61ed 100644 --- a/gfx/cairo/cairo/src/cairo-directfb-surface.c +++ b/gfx/cairo/cairo/src/cairo-directfb-surface.c @@ -52,9 +52,9 @@ /* - * Rectangle works fine. + * Rectangle causes problems (see bugs 361377, 359553, 359243 in Gnome BTS). */ -#define DFB_RECTANGLES 1 +#define DFB_RECTANGLES 0 /* * Composite works fine. diff --git a/gfx/cairo/cairo/src/cairo-directfb.h b/gfx/cairo/cairo/src/cairo-directfb.h index 845f3de6828..795a0dc167b 100644 --- a/gfx/cairo/cairo/src/cairo-directfb.h +++ b/gfx/cairo/cairo/src/cairo-directfb.h @@ -48,5 +48,8 @@ cairo_directfb_surface_create (IDirectFB *dfb,IDirectFBSurface *surface); CAIRO_END_DECLS +#else /*CAIRO_HAS_DIRECTFB_SURFACE*/ +# error Cairo was not compiled with support for the directfb backend #endif /*CAIRO_HAS_DIRECTFB_SURFACE*/ + #endif /*CAIRO_DIRECTFB_H*/ diff --git a/gfx/cairo/cairo/src/cairo-features.h.in b/gfx/cairo/cairo/src/cairo-features.h.in index 0b5d7dcf5b1..84fb3e5a8ef 100644 --- a/gfx/cairo/cairo/src/cairo-features.h.in +++ b/gfx/cairo/cairo/src/cairo-features.h.in @@ -52,10 +52,10 @@ #endif #define CAIRO_VERSION_MAJOR 1 -#define CAIRO_VERSION_MINOR 3 -#define CAIRO_VERSION_MICRO 12 +#define CAIRO_VERSION_MINOR 4 +#define CAIRO_VERSION_MICRO 2 -#define CAIRO_VERSION_STRING "1.3.12" +#define CAIRO_VERSION_STRING "1.4.2" @PS_SURFACE_FEATURE@ @@ -67,8 +67,6 @@ @QUARTZ_SURFACE_FEATURE@ -@NQUARTZ_SURFACE_FEATURE@ - @XCB_SURFACE_FEATURE@ @WIN32_SURFACE_FEATURE@ diff --git a/gfx/cairo/cairo/src/cairo-font.c b/gfx/cairo/cairo/src/cairo-font.c index 373068673e4..cacc5899da9 100644 --- a/gfx/cairo/cairo/src/cairo-font.c +++ b/gfx/cairo/cairo/src/cairo-font.c @@ -1,3 +1,4 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ /* cairo - a vector graphics library with display and print output * * Copyright © 2002 University of Southern California @@ -65,32 +66,40 @@ _cairo_font_face_init (cairo_font_face_t *font_face, _cairo_user_data_array_init (&font_face->user_data); } +/* This mutex protects both cairo_toy_font_hash_table as well as + reference count manipulations for all cairo_font_face_t. */ +CAIRO_MUTEX_DECLARE (_cairo_font_face_mutex); + /** * cairo_font_face_reference: - * @font_face: a #cairo_font_face_t, (may be NULL in which case this + * @font_face: a #cairo_font_face_t, (may be %NULL in which case this * function does nothing). * * Increases the reference count on @font_face by one. This prevents * @font_face from being destroyed until a matching call to * cairo_font_face_destroy() is made. * + * The number of references to a #cairo_font_face_t can be get using + * cairo_font_face_get_reference_count(). + * * Return value: the referenced #cairo_font_face_t. **/ cairo_font_face_t * cairo_font_face_reference (cairo_font_face_t *font_face) { - if (font_face == NULL) - return NULL; - - if (font_face->ref_count == CAIRO_REF_COUNT_INVALID) + if (font_face == NULL || font_face->ref_count == CAIRO_REF_COUNT_INVALID) return font_face; + CAIRO_MUTEX_LOCK (_cairo_font_face_mutex); + /* We would normally assert (font_face->ref_count >0) here but we * can't get away with that due to the zombie case as documented * in _cairo_ft_font_face_destroy. */ font_face->ref_count++; + CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex); + return font_face; } slim_hidden_def (cairo_font_face_reference); @@ -106,16 +115,19 @@ slim_hidden_def (cairo_font_face_reference); void cairo_font_face_destroy (cairo_font_face_t *font_face) { - if (font_face == NULL) + if (font_face == NULL || font_face->ref_count == CAIRO_REF_COUNT_INVALID) return; - if (font_face->ref_count == CAIRO_REF_COUNT_INVALID) - return; + CAIRO_MUTEX_LOCK (_cairo_font_face_mutex); assert (font_face->ref_count > 0); - if (--(font_face->ref_count) > 0) + if (--(font_face->ref_count) > 0) { + CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex); return; + } + + CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex); font_face->backend->destroy (font_face); @@ -134,7 +146,7 @@ slim_hidden_def (cairo_font_face_destroy); /** * cairo_font_face_get_type: - * @font_face: a #cairo_font_face_t + * @font_face: a font face * * This function returns the type of the backend used to create * a font face. See #cairo_font_type_t for available types. @@ -149,6 +161,26 @@ cairo_font_face_get_type (cairo_font_face_t *font_face) return font_face->backend->type; } +/** + * cairo_font_face_get_reference_count: + * @font_face: a #cairo_font_face_t + * + * Returns the current reference count of @font_face. + * + * Return value: the current reference count of @font_face. If the + * object is a nil object, 0 will be returned. + * + * Since: 1.4 + **/ +unsigned int +cairo_font_face_get_reference_count (cairo_font_face_t *font_face) +{ + if (font_face == NULL || font_face->ref_count == CAIRO_REF_COUNT_INVALID) + return 0; + + return font_face->ref_count; +} + /** * cairo_font_face_status: * @font_face: a #cairo_font_face_t @@ -226,16 +258,16 @@ _cairo_toy_font_face_keys_equal (const void *key_a, * our cache and mapping from cairo_font_face_t => cairo_scaled_font_t * works. Once the corresponding cairo_font_face_t objects fall out of * downstream caches, we don't need them in this hash table anymore. + * + * Modifications to this hash table are protected by + * _cairo_font_face_mutex. */ - static cairo_hash_table_t *cairo_toy_font_face_hash_table = NULL; -CAIRO_MUTEX_DECLARE (cairo_toy_font_face_hash_table_mutex); - static cairo_hash_table_t * _cairo_toy_font_face_hash_table_lock (void) { - CAIRO_MUTEX_LOCK (cairo_toy_font_face_hash_table_mutex); + CAIRO_MUTEX_LOCK (_cairo_font_face_mutex); if (cairo_toy_font_face_hash_table == NULL) { @@ -243,7 +275,7 @@ _cairo_toy_font_face_hash_table_lock (void) _cairo_hash_table_create (_cairo_toy_font_face_keys_equal); if (cairo_toy_font_face_hash_table == NULL) { - CAIRO_MUTEX_UNLOCK (cairo_toy_font_face_hash_table_mutex); + CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex); return NULL; } } @@ -254,7 +286,7 @@ _cairo_toy_font_face_hash_table_lock (void) static void _cairo_toy_font_face_hash_table_unlock (void) { - CAIRO_MUTEX_UNLOCK (cairo_toy_font_face_hash_table_mutex); + CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex); } /** @@ -363,8 +395,11 @@ _cairo_toy_font_face_create (const char *family, &key.base.hash_entry, (cairo_hash_entry_t **) &font_face)) { + /* We increment the reference count here manually to avoid + double-locking. */ + font_face->base.ref_count++; _cairo_toy_font_face_hash_table_unlock (); - return cairo_font_face_reference (&font_face->base); + return &font_face->base; } /* Otherwise create it and insert into hash table. */ @@ -471,8 +506,11 @@ _cairo_font_reset_static_data (void) { _cairo_scaled_font_map_destroy (); - CAIRO_MUTEX_LOCK (cairo_toy_font_face_hash_table_mutex); + /* We manually acquire the lock rather than calling + * cairo_toy_font_face_hash_table_lock simply to avoid + * creating the table only to destroy it again. */ + CAIRO_MUTEX_LOCK (_cairo_font_face_mutex); _cairo_hash_table_destroy (cairo_toy_font_face_hash_table); cairo_toy_font_face_hash_table = NULL; - CAIRO_MUTEX_UNLOCK (cairo_toy_font_face_hash_table_mutex); + CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex); } diff --git a/gfx/cairo/cairo/src/cairo-ft-font.c b/gfx/cairo/cairo/src/cairo-ft-font.c index 660f8531e88..6174d1415c1 100644 --- a/gfx/cairo/cairo/src/cairo-ft-font.c +++ b/gfx/cairo/cairo/src/cairo-ft-font.c @@ -62,9 +62,11 @@ */ #define MAX_OPEN_FACES 10 +#ifndef MOZILLA_CAIRO_NOT_DEFINED /* This is the maximum font size we allow to be passed to FT_Set_Char_Size */ #define MAX_FONT_SIZE 1000 +#endif /* !MOZILLA_CAIRO_NOT_DEFINED */ /* * The simple 2x2 matrix is converted into separate scale and shape @@ -104,7 +106,8 @@ struct _cairo_ft_unscaled_font { cairo_matrix_t current_shape; FT_Matrix Current_Shape; - int lock; /* count of how many times this font has been locked */ + cairo_mutex_t mutex; + int lock_count; cairo_ft_font_face_t *faces; /* Linked list of faces for this font */ }; @@ -153,7 +156,7 @@ typedef struct _cairo_ft_unscaled_font_map { static cairo_ft_unscaled_font_map_t *cairo_ft_unscaled_font_map = NULL; -CAIRO_MUTEX_DECLARE(cairo_ft_unscaled_font_map_mutex); +CAIRO_MUTEX_DECLARE(_cairo_ft_unscaled_font_map_mutex); static void _font_map_release_face_lock_held (cairo_ft_unscaled_font_map_t *font_map, @@ -211,7 +214,7 @@ _cairo_ft_unscaled_font_map_destroy (void) cairo_ft_unscaled_font_t *unscaled; cairo_ft_unscaled_font_map_t *font_map; - CAIRO_MUTEX_LOCK (cairo_ft_unscaled_font_map_mutex); + CAIRO_MUTEX_LOCK (_cairo_ft_unscaled_font_map_mutex); if (cairo_ft_unscaled_font_map) { font_map = cairo_ft_unscaled_font_map; @@ -244,20 +247,20 @@ _cairo_ft_unscaled_font_map_destroy (void) cairo_ft_unscaled_font_map = NULL; } - CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex); + CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex); } static cairo_ft_unscaled_font_map_t * _cairo_ft_unscaled_font_map_lock (void) { - CAIRO_MUTEX_LOCK (cairo_ft_unscaled_font_map_mutex); + CAIRO_MUTEX_LOCK (_cairo_ft_unscaled_font_map_mutex); if (cairo_ft_unscaled_font_map == NULL) { _cairo_ft_unscaled_font_map_create (); if (cairo_ft_unscaled_font_map == NULL) { - CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex); + CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex); return NULL; } } @@ -268,7 +271,7 @@ _cairo_ft_unscaled_font_map_lock (void) static void _cairo_ft_unscaled_font_map_unlock (void) { - CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex); + CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex); } static void @@ -337,7 +340,8 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, } unscaled->have_scale = FALSE; - unscaled->lock = 0; + CAIRO_MUTEX_INIT (&unscaled->mutex); + unscaled->lock_count = 0; unscaled->faces = NULL; @@ -370,6 +374,8 @@ _cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled) free (unscaled->filename); unscaled->filename = NULL; } + + CAIRO_MUTEX_FINI (&unscaled->mutex); } static int @@ -501,7 +507,7 @@ _has_unlocked_face (void *entry) { cairo_ft_unscaled_font_t *unscaled = entry; - return (unscaled->lock == 0 && unscaled->face); + return (unscaled->lock_count == 0 && unscaled->face); } /* Ensures that an unscaled font has a face object. If we exceed @@ -516,44 +522,47 @@ _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled) cairo_ft_unscaled_font_map_t *font_map; FT_Face face = NULL; - if (unscaled->face) { - unscaled->lock++; + CAIRO_MUTEX_LOCK (unscaled->mutex); + unscaled->lock_count++; + + if (unscaled->face) return unscaled->face; - } /* If this unscaled font was created from an FT_Face then we just * returned it above. */ assert (!unscaled->from_face); font_map = _cairo_ft_unscaled_font_map_lock (); - assert (font_map != NULL); - - while (font_map->num_open_faces >= MAX_OPEN_FACES) { - cairo_ft_unscaled_font_t *entry; + assert (font_map != NULL); - entry = _cairo_hash_table_random_entry (font_map->hash_table, - _has_unlocked_face); - if (entry == NULL) - break; + while (font_map->num_open_faces >= MAX_OPEN_FACES) + { + cairo_ft_unscaled_font_t *entry; - _font_map_release_face_lock_held (font_map, entry); + entry = _cairo_hash_table_random_entry (font_map->hash_table, + _has_unlocked_face); + if (entry == NULL) + break; + + _font_map_release_face_lock_held (font_map, entry); + } } + _cairo_ft_unscaled_font_map_unlock (); if (FT_New_Face (font_map->ft_library, unscaled->filename, unscaled->id, &face) != FT_Err_Ok) - goto FAIL; + { + CAIRO_MUTEX_UNLOCK (unscaled->mutex); + return NULL; + } unscaled->face = face; - unscaled->lock++; font_map->num_open_faces++; - FAIL: - _cairo_ft_unscaled_font_map_unlock (); - return face; } slim_hidden_def (cairo_ft_scaled_font_lock_face); @@ -563,9 +572,11 @@ slim_hidden_def (cairo_ft_scaled_font_lock_face); void _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled) { - assert (unscaled->lock > 0); + assert (unscaled->lock_count > 0); - unscaled->lock--; + unscaled->lock_count--; + + CAIRO_MUTEX_UNLOCK (unscaled->mutex); } slim_hidden_def (cairo_ft_scaled_font_unlock_face); @@ -647,6 +658,7 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled, FT_Set_Transform(unscaled->face, &mat, NULL); if ((unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) != 0) { +#ifndef MOZILLA_CAIRO_NOT_DEFINED double x_scale = sf.x_scale; double y_scale = sf.y_scale; if (x_scale > MAX_FONT_SIZE) { @@ -656,10 +668,16 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled, y_scale = MAX_FONT_SIZE; } + error = FT_Set_Char_Size (unscaled->face, + sf.x_scale * 64.0, + sf.y_scale * 64.0, + 0, 0); +#else error = FT_Set_Char_Size (unscaled->face, x_scale * 64.0, y_scale * 64.0, 0, 0); +#endif /* MOZCAIRO */ assert (error == 0); } else { double min_distance = DBL_MAX; @@ -1501,6 +1519,8 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled, _cairo_scaled_font_set_metrics (&scaled_font->base, &fs_metrics); + _cairo_ft_unscaled_font_unlock_face (unscaled); + return &scaled_font->base; } @@ -1780,10 +1800,13 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, cairo_bool_t vertical_layout = FALSE; cairo_status_t status = CAIRO_STATUS_SUCCESS; - face = cairo_ft_scaled_font_lock_face (abstract_font); + face = _cairo_ft_unscaled_font_lock_face (unscaled); if (!face) return CAIRO_STATUS_NO_MEMORY; + _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, + &scaled_font->base.scale); + /* Ignore global advance unconditionally */ load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; @@ -1823,6 +1846,8 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, _cairo_ft_scaled_glyph_vertical_layout_bearing_fix (scaled_font, glyph); if (info & CAIRO_SCALED_GLYPH_INFO_METRICS) { + + cairo_bool_t hint_metrics = scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF; /* * Compute font-space metrics */ @@ -1848,8 +1873,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, * FreeType, then we need to do the metric hinting ourselves. */ - if ((scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) && - (load_flags & FT_LOAD_NO_HINTING)) + if (hint_metrics && (load_flags & FT_LOAD_NO_HINTING)) { FT_Pos x1, x2; FT_Pos y1, y2; @@ -1896,14 +1920,20 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) * x_factor; fs_metrics.y_bearing = DOUBLE_FROM_26_6 (-metrics->horiBearingY) * y_factor; - fs_metrics.x_advance = DOUBLE_FROM_26_6 (metrics->horiAdvance) * x_factor; + if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE) + fs_metrics.x_advance = DOUBLE_FROM_26_6 (metrics->horiAdvance) * x_factor; + else + fs_metrics.x_advance = DOUBLE_FROM_16_16 (glyph->linearHoriAdvance) * x_factor; fs_metrics.y_advance = 0 * y_factor; } else { fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingX) * x_factor; fs_metrics.y_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingY) * y_factor; fs_metrics.x_advance = 0 * x_factor; - fs_metrics.y_advance = DOUBLE_FROM_26_6 (metrics->vertAdvance) * y_factor; + if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE) + fs_metrics.y_advance = DOUBLE_FROM_26_6 (metrics->vertAdvance) * y_factor; + else + fs_metrics.y_advance = DOUBLE_FROM_26_6 (glyph->linearVertAdvance) * y_factor; } } @@ -1946,7 +1976,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, load_flags | FT_LOAD_NO_BITMAP); if (error) { - cairo_ft_scaled_font_unlock_face (abstract_font); + _cairo_ft_unscaled_font_unlock_face (unscaled); return CAIRO_STATUS_NO_MEMORY; } #if HAVE_FT_GLYPHSLOT_EMBOLDEN @@ -1974,7 +2004,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, path); } FAIL: - cairo_ft_scaled_font_unlock_face (abstract_font); + _cairo_ft_unscaled_font_unlock_face (unscaled); return status; } @@ -2026,6 +2056,38 @@ _cairo_ft_load_truetype_table (void *abstract_font, return status; } +static void +_cairo_ft_map_glyphs_to_unicode (void *abstract_font, + cairo_scaled_font_subset_t *font_subset) +{ + cairo_ft_scaled_font_t *scaled_font = abstract_font; + cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; + FT_Face face; + FT_UInt glyph; + unsigned long charcode; + unsigned int i; + int count; + + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return; + + count = font_subset->num_glyphs; + charcode = FT_Get_First_Char( face, &glyph); + while (glyph != 0 && count > 0) + { + for (i = 0; i < font_subset->num_glyphs; i++) { + if (font_subset->glyphs[i] == glyph) { + font_subset->to_unicode[i] = charcode; + count--; + break; + } + } + charcode = FT_Get_Next_Char(face, charcode, &glyph); + } + _cairo_ft_unscaled_font_unlock_face (unscaled); +} + const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = { CAIRO_FONT_TYPE_FT, _cairo_ft_scaled_font_create_toy, @@ -2035,6 +2097,7 @@ const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = { _cairo_ft_ucs4_to_index, NULL, /* show_glyphs */ _cairo_ft_load_truetype_table, + _cairo_ft_map_glyphs_to_unicode, }; /* cairo_ft_font_face_t */ @@ -2392,13 +2455,14 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face, * of times. * * You must be careful when using this function in a library or in a - * threaded application, because other threads may lock faces that - * share the same #FT_Face object. For this reason, you must call - * cairo_ft_lock() before locking any face objects, and - * cairo_ft_unlock() after you are done. (These functions are not yet - * implemented, so this function cannot be currently safely used in a - * threaded application.) - + * threaded application, because freetype's design makes it unsafe to + * call freetype functions simultaneously from multiple threads, (even + * if using distinct FT_Face objects). Because of this, application + * code that acquires an FT_Face object with this call must add it's + * own locking to protect any use of that object, (and which also must + * protect any other calls into cairo as almost any cairo function + * might result in a call into the freetype library). + * * Return value: The #FT_Face object for @font, scaled appropriately, * or %NULL if @scaled_font is in an error state (see * cairo_scaled_font_status()) or there is insufficient memory. @@ -2421,6 +2485,14 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font) _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, &scaled_font->base.scale); + /* NOTE: We deliberately release the unscaled font's mutex here, + * so that we are not holding a lock across two separate calls to + * cairo function, (which would give the application some + * opportunity for creating deadlock. This is obviously unsafe, + * but as documented, the user must add manual locking when using + * this function. */ + CAIRO_MUTEX_UNLOCK (scaled_font->unscaled->mutex); + return face; } @@ -2441,6 +2513,12 @@ cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *abstract_font) if (scaled_font->base.status) return; + /* NOTE: We released the unscaled font's mutex at the end of + * cairo_ft_scaled_font_lock_face, so we have to acquire it again + * as _cairo_ft_unscaled_font_unlock_face expects it to be held + * when we call into it. */ + CAIRO_MUTEX_LOCK (scaled_font->unscaled->mutex); + _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled); } diff --git a/gfx/cairo/cairo/src/cairo-glitz-surface.c b/gfx/cairo/cairo/src/cairo-glitz-surface.c index f492739177c..b9e4f72d2b7 100644 --- a/gfx/cairo/cairo/src/cairo-glitz-surface.c +++ b/gfx/cairo/cairo/src/cairo-glitz-surface.c @@ -594,7 +594,7 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern, unsigned int *pixels; unsigned int i, n_base_params; glitz_buffer_t *buffer; - static glitz_pixel_format_t format = { + static const glitz_pixel_format_t format = { GLITZ_FOURCC_RGB, { 32, @@ -686,12 +686,12 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern, { cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern; - params[0] = grad->gradient.inner.x; - params[1] = grad->gradient.inner.y; - params[2] = grad->gradient.inner.radius; - params[3] = grad->gradient.outer.x; - params[4] = grad->gradient.outer.y; - params[5] = grad->gradient.outer.radius; + params[0] = grad->gradient.c1.x; + params[1] = grad->gradient.c1.y; + params[2] = grad->gradient.c1.radius; + params[3] = grad->gradient.c2.x; + params[4] = grad->gradient.c2.y; + params[5] = grad->gradient.c2.radius; attr->filter = GLITZ_FILTER_RADIAL_GRADIENT; } @@ -976,7 +976,7 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, (glitz_rectangle_t *) rects, n_rects); } break; case CAIRO_OPERATOR_CLEAR: { - static glitz_color_t glitz_color = { 0, 0, 0, 0 }; + static const glitz_color_t glitz_color = { 0, 0, 0, 0 }; glitz_set_rectangles (dst->surface, &glitz_color, (glitz_rectangle_t *) rects, n_rects); @@ -1095,7 +1095,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, if (op == CAIRO_OPERATOR_ADD || n_traps <= 1) { - static glitz_color_t clear_black = { 0, 0, 0, 0 }; + static const glitz_color_t clear_black = { 0, 0, 0, 0 }; glitz_color_t color; glitz_geometry_format_t format; int n_trap_added; @@ -1941,7 +1941,7 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, int i, cached_glyphs = 0; int remaining_glyps = num_glyphs; glitz_float_t x1, y1, x2, y2; - static glitz_vertex_format_t format = { + static const glitz_vertex_format_t format = { GLITZ_PRIMITIVE_QUADS, GLITZ_DATA_TYPE_FLOAT, sizeof (glitz_float_t) * 4, diff --git a/gfx/cairo/cairo/src/cairo-gstate.c b/gfx/cairo/cairo/src/cairo-gstate.c index a740d868cca..b75a90baab7 100644 --- a/gfx/cairo/cairo/src/cairo-gstate.c +++ b/gfx/cairo/cairo/src/cairo-gstate.c @@ -42,16 +42,9 @@ #include "cairo-clip-private.h" #include "cairo-gstate-private.h" -static cairo_status_t -_cairo_gstate_init (cairo_gstate_t *gstate, - cairo_surface_t *target); - static cairo_status_t _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other); -static void -_cairo_gstate_fini (cairo_gstate_t *gstate); - static cairo_status_t _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate); @@ -67,40 +60,7 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate, int num_glyphs, cairo_glyph_t *transformed_glyphs); -/** - * _cairo_gstate_create: - * @target: a #cairo_surface_t, not NULL - * - * Create a new #cairo_gstate_t to draw to target with all graphics - * state parameters set to defaults. gstate->next will be set to NULL - * and may be used by the caller to chain #cairo_gstate_t objects - * together. - * - * Return value: a new #cairo_gstate_t or NULL if there is - * insufficient memory. - **/ -cairo_gstate_t * -_cairo_gstate_create (cairo_surface_t *target) -{ - cairo_status_t status; - cairo_gstate_t *gstate; - - assert (target != NULL); - - gstate = malloc (sizeof (cairo_gstate_t)); - if (gstate == NULL) - return NULL; - - status = _cairo_gstate_init (gstate, target); - if (status) { - free (gstate); - return NULL; - } - - return gstate; -} - -static cairo_status_t +cairo_status_t _cairo_gstate_init (cairo_gstate_t *gstate, cairo_surface_t *target) { @@ -189,7 +149,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) return CAIRO_STATUS_SUCCESS; } -static void +void _cairo_gstate_fini (cairo_gstate_t *gstate) { _cairo_stroke_style_fini (&gstate->stroke_style); @@ -722,8 +682,8 @@ _cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate, cairo_matrix_multiply (&matrix_inverse, &gstate->ctm_inverse, &gstate->target->device_transform_inverse); - cairo_matrix_transform_bounding_box (&matrix_inverse, - x1, y1, x2, y2, is_tight); + _cairo_matrix_transform_bounding_box (&matrix_inverse, + x1, y1, x2, y2, is_tight); } /* XXX: NYI @@ -955,6 +915,11 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate, cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_traps_t traps; + if (gstate->stroke_style.line_width <= 0.0) { + *inside_ret = FALSE; + return CAIRO_STATUS_SUCCESS; + } + _cairo_gstate_user_to_backend (gstate, &x, &y); _cairo_traps_init (&traps); @@ -1073,12 +1038,23 @@ _cairo_gstate_traps_extents_to_user_rectangle (cairo_gstate_t *gstate, if (extents.p1.x >= extents.p2.x || extents.p1.y >= extents.p2.y) { /* no traps, so we actually won't draw anything */ - *x1 = *y1 = *x2 = *y2 = 0; + if (x1) + *x1 = 0.0; + if (y1) + *y1 = 0.0; + if (x2) + *x2 = 0.0; + if (y2) + *y2 = 0.0; } else { - *x1 = _cairo_fixed_to_double (extents.p1.x); - *y1 = _cairo_fixed_to_double (extents.p1.y); - *x2 = _cairo_fixed_to_double (extents.p2.x); - *y2 = _cairo_fixed_to_double (extents.p2.y); + if (x1) + *x1 = _cairo_fixed_to_double (extents.p1.x); + if (y1) + *y1 = _cairo_fixed_to_double (extents.p1.y); + if (x2) + *x2 = _cairo_fixed_to_double (extents.p2.x); + if (y2) + *y2 = _cairo_fixed_to_double (extents.p2.y); _cairo_gstate_backend_to_user_rectangle (gstate, x1, y1, x2, y2, NULL); } @@ -1093,6 +1069,18 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate, cairo_status_t status; cairo_traps_t traps; + if (gstate->stroke_style.line_width <= 0.0) { + if (x1) + *x1 = 0.0; + if (y1) + *y1 = 0.0; + if (x2) + *x2 = 0.0; + if (y2) + *y2 = 0.0; + return CAIRO_STATUS_SUCCESS; + } + _cairo_traps_init (&traps); status = _cairo_path_fixed_stroke_to_traps (path, @@ -1165,11 +1153,15 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate, status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &extents); if (status) return status; - - *x1 = extents.x; - *y1 = extents.y; - *x2 = extents.x + extents.width; - *y2 = extents.y + extents.height; + + if (x1) + *x1 = extents.x; + if (y1) + *y1 = extents.y; + if (x2) + *x2 = extents.x + extents.width; + if (y2) + *y2 = extents.y + extents.height; _cairo_gstate_backend_to_user_rectangle (gstate, x1, y1, x2, y2, NULL); @@ -1271,6 +1263,21 @@ _cairo_gstate_get_font_face (cairo_gstate_t *gstate, return CAIRO_STATUS_SUCCESS; } +cairo_status_t +_cairo_gstate_get_scaled_font (cairo_gstate_t *gstate, + cairo_scaled_font_t **scaled_font) +{ + cairo_status_t status; + + status = _cairo_gstate_ensure_scaled_font (gstate); + if (status) + return status; + + *scaled_font = gstate->scaled_font; + + return CAIRO_STATUS_SUCCESS; +} + /* * Like everything else in this file, fonts involve Too Many Coordinate Spaces; * it is easy to get confused about what's going on. diff --git a/gfx/cairo/cairo/src/cairo-image-surface.c b/gfx/cairo/cairo/src/cairo-image-surface.c index 1b5215f9b8f..627901216b0 100644 --- a/gfx/cairo/cairo/src/cairo-image-surface.c +++ b/gfx/cairo/cairo/src/cairo-image-surface.c @@ -1116,6 +1116,7 @@ _cairo_image_surface_clone (cairo_image_surface_t *surface, cairo_image_surface_create (format, surface->width, surface->height); + /* Use _cairo_surface_composite directly */ cr = cairo_create (&clone->base); cairo_surface_get_device_offset (&surface->base, &x, &y); cairo_set_source_surface (cr, &surface->base, x, y); diff --git a/gfx/cairo/cairo/src/cairo-matrix.c b/gfx/cairo/cairo/src/cairo-matrix.c index 0ad0ddeb9af..b689f2aaff7 100644 --- a/gfx/cairo/cairo/src/cairo-matrix.c +++ b/gfx/cairo/cairo/src/cairo-matrix.c @@ -356,10 +356,10 @@ cairo_matrix_transform_point (const cairo_matrix_t *matrix, double *x, double *y slim_hidden_def(cairo_matrix_transform_point); void -cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix, - double *x1, double *y1, - double *x2, double *y2, - cairo_bool_t *is_tight) +_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix, + double *x1, double *y1, + double *x2, double *y2, + cairo_bool_t *is_tight) { int i; double quad_x[4], quad_y[4]; @@ -417,7 +417,6 @@ cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix, quad_x[2] == quad_x[0] && quad_y[2] == quad_y[3]); } } -slim_hidden_def(cairo_matrix_transform_bounding_box); static void _cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar) diff --git a/gfx/cairo/cairo/src/cairo-nquartz-surface.c b/gfx/cairo/cairo/src/cairo-nquartz-surface.c deleted file mode 100644 index fd41569c6b6..00000000000 --- 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 - */ - -#include - -#ifdef CAIRO_NQUARTZ_SUPPORT_AGL -#include -#include -#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 - -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 -} - diff --git a/gfx/cairo/cairo/src/cairo-nquartz.h b/gfx/cairo/cairo/src/cairo-nquartz.h deleted file mode 100644 index c6c58e75107..00000000000 --- 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 - */ - -#ifndef CAIRO_NQUARTZ_H -#define CAIRO_NQUARTZ_H - -#include - -#if CAIRO_HAS_NQUARTZ_SURFACE - -#include - -#include - -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 */ diff --git a/gfx/cairo/cairo/src/cairo-os2-surface.c b/gfx/cairo/cairo/src/cairo-os2-surface.c index 92bd711c66d..f6ec8f6256c 100644 --- a/gfx/cairo/cairo/src/cairo-os2-surface.c +++ b/gfx/cairo/cairo/src/cairo-os2-surface.c @@ -69,11 +69,11 @@ static int cairo_os2_initialization_count = 0; /* The mutex semaphores Cairo uses all around: */ -HMTX cairo_toy_font_face_hash_table_mutex = 0; -HMTX cairo_scaled_font_map_mutex = 0; +HMTX _cairo_scaled_font_map_mutex = 0; HMTX _global_image_glyph_cache_mutex = 0; +HMTX _cairo_font_face_mutex = 0; #ifdef CAIRO_HAS_FT_FONT -HMTX cairo_ft_unscaled_font_map_mutex = 0; +HMTX _cairo_ft_unscaled_font_map_mutex = 0; #endif static void inline @@ -106,13 +106,13 @@ cairo_os2_init (void) /* Create the mutex semaphores we'll use! */ /* cairo-font.c: */ - DosCreateMutexSem (NULL, &cairo_toy_font_face_hash_table_mutex, 0, FALSE); - DosCreateMutexSem (NULL, &cairo_scaled_font_map_mutex, 0, FALSE); + DosCreateMutexSem (NULL, &_cairo_scaled_font_map_mutex, 0, FALSE); DosCreateMutexSem (NULL, &_global_image_glyph_cache_mutex, 0, FALSE); + DosCreateMutexSem (NULL, &_cairo_font_face_mutex, 0, FALSE); #ifdef CAIRO_HAS_FT_FONT /* cairo-ft-font.c: */ - DosCreateMutexSem (NULL, &cairo_ft_unscaled_font_map_mutex, 0, FALSE); + DosCreateMutexSem (NULL, &_cairo_ft_unscaled_font_map_mutex, 0, FALSE); #endif /* Initialize FontConfig */ @@ -139,24 +139,24 @@ cairo_os2_fini (void) /* Destroy the mutex semaphores we've created! */ /* cairo-font.c: */ - if (cairo_toy_font_face_hash_table_mutex) { - DosCloseMutexSem (cairo_toy_font_face_hash_table_mutex); - cairo_toy_font_face_hash_table_mutex = 0; - } - if (cairo_scaled_font_map_mutex) { - DosCloseMutexSem (cairo_scaled_font_map_mutex); - cairo_scaled_font_map_mutex = 0; + if (_cairo_scaled_font_map_mutex) { + DosCloseMutexSem (_cairo_scaled_font_map_mutex); + _cairo_scaled_font_map_mutex = 0; } if (_global_image_glyph_cache_mutex) { DosCloseMutexSem (_global_image_glyph_cache_mutex); _global_image_glyph_cache_mutex = 0; } + if (_cairo_font_face_mutex) { + DosCloseMutexSem (_cairo_font_face_mutex); + _cairo_font_face_mutex = 0; + } #ifdef CAIRO_HAS_FT_FONT /* cairo-ft-font.c: */ - if (cairo_ft_unscaled_font_map_mutex) { - DosCloseMutexSem (cairo_ft_unscaled_font_map_mutex); - cairo_ft_unscaled_font_map_mutex = 0; + if (_cairo_ft_unscaled_font_map_mutex) { + DosCloseMutexSem (_cairo_ft_unscaled_font_map_mutex); + _cairo_ft_unscaled_font_map_mutex = 0; } #endif diff --git a/gfx/cairo/cairo/src/cairo-os2.h b/gfx/cairo/cairo/src/cairo-os2.h index 3e1b4aad482..6a6c04d5b8b 100644 --- a/gfx/cairo/cairo/src/cairo-os2.h +++ b/gfx/cairo/cairo/src/cairo-os2.h @@ -194,6 +194,8 @@ cairo_os2_surface_set_manual_window_refresh (cairo_surface_t *surface, cairo_public cairo_bool_t cairo_os2_surface_get_manual_window_refresh (cairo_surface_t *surface); +#else /* CAIRO_HAS_OS2_SURFACE */ +# error Cairo was not compiled with support for the OS/2 backend #endif /* CAIRO_HAS_OS2_SURFACE */ CAIRO_END_DECLS diff --git a/gfx/cairo/cairo/src/cairo-output-stream.c b/gfx/cairo/cairo/src/cairo-output-stream.c index f9e527f33c1..df3ae4d4334 100644 --- a/gfx/cairo/cairo/src/cairo-output-stream.c +++ b/gfx/cairo/cairo/src/cairo-output-stream.c @@ -224,6 +224,10 @@ _cairo_dtostr (char *buffer, size_t size, double d) char *p; int decimal_len; + /* Omit the minus sign from negative zero. */ + if (d == 0.0) + d = 0.0; + snprintf (buffer, size, "%f", d); locale_data = localeconv (); diff --git a/gfx/cairo/cairo/src/cairo-paginated-surface.c b/gfx/cairo/cairo/src/cairo-paginated-surface.c index b313ac1f518..c8e46124f99 100644 --- a/gfx/cairo/cairo/src/cairo-paginated-surface.c +++ b/gfx/cairo/cairo/src/cairo-paginated-surface.c @@ -70,6 +70,7 @@ typedef struct _cairo_paginated_surface { * fallbacks. */ cairo_surface_t *meta; + int page_num; cairo_bool_t page_is_blank; } cairo_paginated_surface_t; @@ -122,6 +123,7 @@ _cairo_paginated_surface_create (cairo_surface_t *target, if (cairo_surface_status (surface->meta)) goto FAIL_CLEANUP_SURFACE; + surface->page_num = 1; surface->page_is_blank = TRUE; return &surface->base; @@ -155,12 +157,22 @@ static cairo_status_t _cairo_paginated_surface_finish (void *abstract_surface) { cairo_paginated_surface_t *surface = abstract_surface; + cairo_status_t status = CAIRO_STATUS_SUCCESS; - cairo_surface_destroy (surface->meta); + if (surface->page_is_blank == FALSE || surface->page_num == 1) + status = _cairo_paginated_surface_show_page (abstract_surface); + + if (status == CAIRO_STATUS_SUCCESS) + cairo_surface_finish (surface->target); + + if (status == CAIRO_STATUS_SUCCESS) + cairo_surface_finish (surface->meta); cairo_surface_destroy (surface->target); - return CAIRO_STATUS_SUCCESS; + cairo_surface_destroy (surface->meta); + + return status; } static cairo_surface_t * @@ -288,6 +300,8 @@ _cairo_paginated_surface_copy_page (void *abstract_surface) _paint_page (surface); + surface->page_num++; + /* XXX: It might make sense to add some suport here for calling * _cairo_surface_copy_page on the target surface. It would be an * optimization for the output, (so that PostScript could include @@ -296,9 +310,7 @@ _cairo_paginated_surface_copy_page (void *abstract_surface) * show_page and we implement the copying by simply not destroying * the meta-surface. */ - _cairo_surface_show_page (surface->target); - - return CAIRO_STATUS_SUCCESS; + return _cairo_surface_show_page (surface->target); } static cairo_int_status_t @@ -322,6 +334,7 @@ _cairo_paginated_surface_show_page (void *abstract_surface) if (cairo_surface_status (surface->meta)) return cairo_surface_status (surface->meta); + surface->page_num++; surface->page_is_blank = TRUE; return CAIRO_STATUS_SUCCESS; @@ -442,6 +455,7 @@ _cairo_paginated_surface_show_glyphs (void *abstract_surface, cairo_scaled_font_t *scaled_font) { cairo_paginated_surface_t *surface = abstract_surface; + cairo_int_status_t status; /* Optimize away erasing of nothing. */ if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR) @@ -449,9 +463,23 @@ _cairo_paginated_surface_show_glyphs (void *abstract_surface, surface->page_is_blank = FALSE; - return _cairo_surface_show_glyphs (surface->meta, op, source, - glyphs, num_glyphs, - scaled_font); + /* Since this is a "wrapping" surface, we're calling back into + * _cairo_surface_show_glyphs from within a call to the same. + * Since _cairo_surface_show_glyphs acquires a mutex, we release + * and re-acquire the mutex around this nested call. + * + * Yes, this is ugly, but we consider it pragmatic as compared to + * adding locking code to all 18 surface-backend-specific + * show_glyphs functions, (which would get less testing and likely + * lead to bugs). + */ + CAIRO_MUTEX_UNLOCK (scaled_font->mutex); + status = _cairo_surface_show_glyphs (surface->meta, op, source, + glyphs, num_glyphs, + scaled_font); + CAIRO_MUTEX_LOCK (scaled_font->mutex); + + return status; } static cairo_surface_t * diff --git a/gfx/cairo/cairo/src/cairo-path-fill.c b/gfx/cairo/cairo/src/cairo-path-fill.c index 7377960f8b6..b1b7a120d27 100644 --- a/gfx/cairo/cairo/src/cairo-path-fill.c +++ b/gfx/cairo/cairo/src/cairo-path-fill.c @@ -35,6 +35,7 @@ */ #include "cairoint.h" +#include "cairo-path-fixed-private.h" typedef struct cairo_filler { double tolerance; @@ -169,6 +170,10 @@ _cairo_filler_close_path (void *closure) return CAIRO_STATUS_SUCCESS; } +static cairo_int_status_t +_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path, + cairo_traps_t *traps); + cairo_status_t _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, @@ -178,6 +183,12 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_filler_t filler; + /* Before we do anything else, we use a special-case filler for + * a device-axis aligned rectangle if possible. */ + status = _cairo_path_fixed_fill_rectangle (path, traps); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + _cairo_filler_init (&filler, tolerance, traps); status = _cairo_path_fixed_interpret (path, @@ -205,3 +216,84 @@ BAIL: return status; } + +/* This special-case filler supports only a path that describes a + * device-axis aligned rectangle. It exists to avoid the overhead of + * the general tessellator when drawing very common rectangles. + * + * If the path described anything but a device-axis aligned rectangle, + * this function will return CAIRO_INT_STATUS_UNSUPPORTED. + */ +static cairo_int_status_t +_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path, + cairo_traps_t *traps) +{ + cairo_path_buf_t *buf = path->buf_head; + int final; + + /* Ensure the path has the operators we expect for a rectangular path. + */ + if (buf == NULL || buf->num_ops < 5) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO || + buf->op[1] != CAIRO_PATH_OP_LINE_TO || + buf->op[2] != CAIRO_PATH_OP_LINE_TO || + buf->op[3] != CAIRO_PATH_OP_LINE_TO) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* Now, there are choices. The rectangle might end with a LINE_TO + * (to the original point), but this isn't required. If it + * doesn't, then it must end with a CLOSE_PATH. */ + if (buf->op[4] == CAIRO_PATH_OP_LINE_TO) { + if (buf->points[4].x != buf->points[0].x || + buf->points[4].y != buf->points[0].y) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + } else if (buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH) { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* Finally, a trailing CLOSE_PATH or MOVE_TO after the rectangle + * is fine. But anything more than that means we must return + * unsupported. */ + final = 5; + if (final < buf->num_ops && + buf->op[final] == CAIRO_PATH_OP_CLOSE_PATH) + { + final++; + } + if (final < buf->num_ops && + buf->op[final] == CAIRO_PATH_OP_MOVE_TO) + { + final++; + } + if (final < buf->num_ops) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Now that we've verified the operators, we must ensure that the + * path coordinates are consistent with a rectangle. There are two + * choices here. */ + if (buf->points[0].y == buf->points[1].y && + buf->points[1].x == buf->points[2].x && + buf->points[2].y == buf->points[3].y && + buf->points[3].x == buf->points[0].x) + { + return _cairo_traps_tessellate_convex_quad (traps, + buf->points); + } + + if (buf->points[0].x == buf->points[1].x && + buf->points[1].y == buf->points[2].y && + buf->points[2].x == buf->points[3].x && + buf->points[3].y == buf->points[0].y) + { + return _cairo_traps_tessellate_convex_quad (traps, + buf->points); + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} diff --git a/gfx/cairo/cairo/src/cairo-path-fixed-private.h b/gfx/cairo/cairo/src/cairo-path-fixed-private.h index 12ca6186c3e..65401f34911 100644 --- a/gfx/cairo/cairo/src/cairo-path-fixed-private.h +++ b/gfx/cairo/cairo/src/cairo-path-fixed-private.h @@ -42,34 +42,30 @@ typedef enum cairo_path_op { CAIRO_PATH_OP_CURVE_TO = 2, CAIRO_PATH_OP_CLOSE_PATH = 3 } __attribute__ ((packed)) cairo_path_op_t; /* Don't want 32 bits if we can avoid it. */ +/* XXX Shall we just not use char instead of hoping for __attribute__ working? */ -#define CAIRO_PATH_BUF_SIZE 64 +/* make cairo_path_fixed fit a 512 bytes. about 50 items */ +#define CAIRO_PATH_BUF_SIZE ((512 - 12 * sizeof (void*)) \ + / (sizeof (cairo_point_t) + sizeof (cairo_path_op_t))) -typedef struct _cairo_path_op_buf { +typedef struct _cairo_path_buf { + struct _cairo_path_buf *next, *prev; int num_ops; - cairo_path_op_t op[CAIRO_PATH_BUF_SIZE]; - - struct _cairo_path_op_buf *next, *prev; -} cairo_path_op_buf_t; - -typedef struct _cairo_path_arg_buf { int num_points; + + cairo_path_op_t op[CAIRO_PATH_BUF_SIZE]; cairo_point_t points[CAIRO_PATH_BUF_SIZE]; - struct _cairo_path_arg_buf *next, *prev; -} cairo_path_arg_buf_t; +} cairo_path_buf_t; struct _cairo_path_fixed { - cairo_path_op_buf_t *op_buf_head; - cairo_path_op_buf_t *op_buf_tail; - - cairo_path_arg_buf_t *arg_buf_head; - cairo_path_arg_buf_t *arg_buf_tail; - cairo_point_t last_move_point; cairo_point_t current_point; unsigned int has_current_point : 1; unsigned int has_curve_to : 1; + + cairo_path_buf_t *buf_tail; + cairo_path_buf_t buf_head[1]; }; #endif /* CAIRO_PATH_FIXED_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-path-fixed.c b/gfx/cairo/cairo/src/cairo-path-fixed.c index 3505c668bbb..4845ada2175 100644 --- a/gfx/cairo/cairo/src/cairo-path-fixed.c +++ b/gfx/cairo/cairo/src/cairo-path-fixed.c @@ -48,42 +48,33 @@ _cairo_path_fixed_add (cairo_path_fixed_t *path, int num_points); static void -_cairo_path_fixed_add_op_buf (cairo_path_fixed_t *path, - cairo_path_op_buf_t *op_buf); +_cairo_path_fixed_add_buf (cairo_path_fixed_t *path, + cairo_path_buf_t *buf); + +static cairo_path_buf_t * +_cairo_path_buf_create (void); static void -_cairo_path_fixed_add_arg_buf (cairo_path_fixed_t *path, - cairo_path_arg_buf_t *arg_buf); - -static cairo_path_op_buf_t * -_cairo_path_op_buf_create (void); +_cairo_path_buf_destroy (cairo_path_buf_t *buf); static void -_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op_buf); +_cairo_path_buf_add_op (cairo_path_buf_t *buf, + cairo_path_op_t op); static void -_cairo_path_op_buf_add_op (cairo_path_op_buf_t *op_buf, - cairo_path_op_t op); - -static cairo_path_arg_buf_t * -_cairo_path_arg_buf_create (void); - -static void -_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg_buf); - -static void -_cairo_path_arg_buf_add_points (cairo_path_arg_buf_t *arg_buf, - cairo_point_t *points, - int num_points); +_cairo_path_buf_add_points (cairo_path_buf_t *buf, + cairo_point_t *points, + int num_points); void _cairo_path_fixed_init (cairo_path_fixed_t *path) { - path->op_buf_head = NULL; - path->op_buf_tail = NULL; + path->buf_head->next = NULL; + path->buf_head->prev = NULL; + path->buf_tail = path->buf_head; - path->arg_buf_head = NULL; - path->arg_buf_tail = NULL; + path->buf_head->num_ops = 0; + path->buf_head->num_points = 0; path->current_point.x = 0; path->current_point.y = 0; @@ -96,8 +87,7 @@ cairo_status_t _cairo_path_fixed_init_copy (cairo_path_fixed_t *path, cairo_path_fixed_t *other) { - cairo_path_op_buf_t *op_buf, *other_op_buf; - cairo_path_arg_buf_t *arg_buf, *other_arg_buf; + cairo_path_buf_t *buf, *other_buf; _cairo_path_fixed_init (path); path->current_point = other->current_point; @@ -105,30 +95,23 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path, path->has_curve_to = other->has_curve_to; path->last_move_point = other->last_move_point; - for (other_op_buf = other->op_buf_head; - other_op_buf; - other_op_buf = other_op_buf->next) + path->buf_head->num_ops = other->buf_head->num_ops; + path->buf_head->num_points = other->buf_head->num_points; + memcpy (path->buf_head->op, other->buf_head->op, + other->buf_head->num_ops * sizeof (other->buf_head->op[0])); + memcpy (path->buf_head->points, other->buf_head->points, + other->buf_head->num_points * sizeof (other->buf_head->points[0])); + for (other_buf = other->buf_head->next; + other_buf; + other_buf = other_buf->next) { - op_buf = _cairo_path_op_buf_create (); - if (op_buf == NULL) { + buf = _cairo_path_buf_create (); + if (buf == NULL) { _cairo_path_fixed_fini (path); return CAIRO_STATUS_NO_MEMORY; } - memcpy (op_buf, other_op_buf, sizeof (cairo_path_op_buf_t)); - _cairo_path_fixed_add_op_buf (path, op_buf); - } - - for (other_arg_buf = other->arg_buf_head; - other_arg_buf; - other_arg_buf = other_arg_buf->next) - { - arg_buf = _cairo_path_arg_buf_create (); - if (arg_buf == NULL) { - _cairo_path_fixed_fini (path); - return CAIRO_STATUS_NO_MEMORY; - } - memcpy (arg_buf, other_arg_buf, sizeof (cairo_path_arg_buf_t)); - _cairo_path_fixed_add_arg_buf (path, arg_buf); + memcpy (buf, other_buf, sizeof (cairo_path_buf_t)); + _cairo_path_fixed_add_buf (path, buf); } return CAIRO_STATUS_SUCCESS; @@ -148,22 +131,19 @@ _cairo_path_fixed_create (void) void _cairo_path_fixed_fini (cairo_path_fixed_t *path) { - cairo_path_op_buf_t *op_buf; - cairo_path_arg_buf_t *arg_buf; + cairo_path_buf_t *buf; - while (path->op_buf_head) { - op_buf = path->op_buf_head; - path->op_buf_head = op_buf->next; - _cairo_path_op_buf_destroy (op_buf); + buf = path->buf_head->next; + while (buf) { + cairo_path_buf_t *this = buf; + buf = buf->next; + _cairo_path_buf_destroy (this); } - path->op_buf_tail = NULL; - - while (path->arg_buf_head) { - arg_buf = path->arg_buf_head; - path->arg_buf_head = arg_buf->next; - _cairo_path_arg_buf_destroy (arg_buf); - } - path->arg_buf_tail = NULL; + path->buf_head->next = NULL; + path->buf_head->prev = NULL; + path->buf_tail = path->buf_head; + path->buf_head->num_ops = 0; + path->buf_head->num_points = 0; path->has_current_point = FALSE; path->has_curve_to = FALSE; @@ -189,11 +169,11 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path, /* If the previous op was also a MOVE_TO, then just change its * point rather than adding a new op. */ - if (path->op_buf_tail && path->op_buf_tail->num_ops && - path->op_buf_tail->op[path->op_buf_tail->num_ops - 1] == CAIRO_PATH_OP_MOVE_TO) + if (path->buf_tail && path->buf_tail->num_ops && + path->buf_tail->op[path->buf_tail->num_ops - 1] == CAIRO_PATH_OP_MOVE_TO) { cairo_point_t *last_move_to_point; - last_move_to_point = &path->arg_buf_tail->points[path->arg_buf_tail->num_points - 1]; + last_move_to_point = &path->buf_tail->points[path->buf_tail->num_points - 1]; *last_move_to_point = point; } else { status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1); @@ -376,133 +356,77 @@ _cairo_path_fixed_add (cairo_path_fixed_t *path, cairo_point_t *points, int num_points) { - if (path->op_buf_tail == NULL || - path->op_buf_tail->num_ops + 1 > CAIRO_PATH_BUF_SIZE) + if (path->buf_tail->num_ops + 1 > CAIRO_PATH_BUF_SIZE || + path->buf_tail->num_points + num_points > CAIRO_PATH_BUF_SIZE) { - cairo_path_op_buf_t *op_buf; + cairo_path_buf_t *buf; - op_buf = _cairo_path_op_buf_create (); - if (op_buf == NULL) + buf = _cairo_path_buf_create (); + if (buf == NULL) return CAIRO_STATUS_NO_MEMORY; - _cairo_path_fixed_add_op_buf (path, op_buf); + _cairo_path_fixed_add_buf (path, buf); } - _cairo_path_op_buf_add_op (path->op_buf_tail, op); - - if (path->arg_buf_tail == NULL || - path->arg_buf_tail->num_points + num_points > CAIRO_PATH_BUF_SIZE) - { - cairo_path_arg_buf_t *arg_buf; - - arg_buf = _cairo_path_arg_buf_create (); - - if (arg_buf == NULL) - return CAIRO_STATUS_NO_MEMORY; - - _cairo_path_fixed_add_arg_buf (path, arg_buf); - } - - _cairo_path_arg_buf_add_points (path->arg_buf_tail, points, num_points); + _cairo_path_buf_add_op (path->buf_tail, op); + _cairo_path_buf_add_points (path->buf_tail, points, num_points); return CAIRO_STATUS_SUCCESS; } static void -_cairo_path_fixed_add_op_buf (cairo_path_fixed_t *path, - cairo_path_op_buf_t *op_buf) +_cairo_path_fixed_add_buf (cairo_path_fixed_t *path, + cairo_path_buf_t *buf) { - op_buf->next = NULL; - op_buf->prev = path->op_buf_tail; + buf->next = NULL; + buf->prev = path->buf_tail; - if (path->op_buf_tail) { - path->op_buf_tail->next = op_buf; - } else { - path->op_buf_head = op_buf; + path->buf_tail->next = buf; + path->buf_tail = buf; +} + +static cairo_path_buf_t * +_cairo_path_buf_create (void) +{ + cairo_path_buf_t *buf; + + buf = malloc (sizeof (cairo_path_buf_t)); + + if (buf) { + buf->next = NULL; + buf->prev = NULL; + buf->num_ops = 0; + buf->num_points = 0; } - path->op_buf_tail = op_buf; + return buf; } static void -_cairo_path_fixed_add_arg_buf (cairo_path_fixed_t *path, - cairo_path_arg_buf_t *arg_buf) +_cairo_path_buf_destroy (cairo_path_buf_t *buf) { - arg_buf->next = NULL; - arg_buf->prev = path->arg_buf_tail; - - if (path->arg_buf_tail) { - path->arg_buf_tail->next = arg_buf; - } else { - path->arg_buf_head = arg_buf; - } - - path->arg_buf_tail = arg_buf; -} - -static cairo_path_op_buf_t * -_cairo_path_op_buf_create (void) -{ - cairo_path_op_buf_t *op_buf; - - op_buf = malloc (sizeof (cairo_path_op_buf_t)); - - if (op_buf) { - op_buf->num_ops = 0; - op_buf->next = NULL; - } - - return op_buf; + free (buf); } static void -_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op_buf) +_cairo_path_buf_add_op (cairo_path_buf_t *buf, + cairo_path_op_t op) { - free (op_buf); + buf->op[buf->num_ops++] = op; } static void -_cairo_path_op_buf_add_op (cairo_path_op_buf_t *op_buf, - cairo_path_op_t op) -{ - op_buf->op[op_buf->num_ops++] = op; -} - -static cairo_path_arg_buf_t * -_cairo_path_arg_buf_create (void) -{ - cairo_path_arg_buf_t *arg_buf; - - arg_buf = malloc (sizeof (cairo_path_arg_buf_t)); - - if (arg_buf) { - arg_buf->num_points = 0; - arg_buf->next = NULL; - } - - return arg_buf; -} - -static void -_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg_buf) -{ - free (arg_buf); -} - -static void -_cairo_path_arg_buf_add_points (cairo_path_arg_buf_t *arg_buf, - cairo_point_t *points, - int num_points) +_cairo_path_buf_add_points (cairo_path_buf_t *buf, + cairo_point_t *points, + int num_points) { int i; for (i=0; i < num_points; i++) { - arg_buf->points[arg_buf->num_points++] = points[i]; + buf->points[buf->num_points++] = points[i]; } } -#define CAIRO_PATH_OP_MAX_ARGS 3 - static int const num_args[] = { 1, /* cairo_path_move_to */ @@ -521,61 +445,43 @@ _cairo_path_fixed_interpret (cairo_path_fixed_t *path, void *closure) { cairo_status_t status; - int i, arg; - cairo_path_op_buf_t *op_buf; + cairo_path_buf_t *buf; cairo_path_op_t op; - cairo_path_arg_buf_t *arg_buf = path->arg_buf_head; - int buf_i = 0; - cairo_point_t point[CAIRO_PATH_OP_MAX_ARGS]; cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD); int step = forward ? 1 : -1; - for (op_buf = forward ? path->op_buf_head : path->op_buf_tail; - op_buf; - op_buf = forward ? op_buf->next : op_buf->prev) + for (buf = forward ? path->buf_head : path->buf_tail; + buf; + buf = forward ? buf->next : buf->prev) { - int start, stop; + cairo_point_t *points; + int start, stop, i; if (forward) { start = 0; - stop = op_buf->num_ops; + stop = buf->num_ops; + points = buf->points; } else { - start = op_buf->num_ops - 1; + start = buf->num_ops - 1; stop = -1; + points = buf->points + buf->num_points; } for (i=start; i != stop; i += step) { - op = op_buf->op[i]; + op = buf->op[i]; if (! forward) { - if (buf_i == 0) { - arg_buf = arg_buf->prev; - buf_i = arg_buf->num_points; - } - buf_i -= num_args[op]; - } - - for (arg = 0; arg < num_args[op]; arg++) { - point[arg] = arg_buf->points[buf_i]; - buf_i++; - if (buf_i >= arg_buf->num_points) { - arg_buf = arg_buf->next; - buf_i = 0; - } - } - - if (! forward) { - buf_i -= num_args[op]; + points -= num_args[op]; } switch (op) { case CAIRO_PATH_OP_MOVE_TO: - status = (*move_to) (closure, &point[0]); + status = (*move_to) (closure, &points[0]); break; case CAIRO_PATH_OP_LINE_TO: - status = (*line_to) (closure, &point[0]); + status = (*line_to) (closure, &points[0]); break; case CAIRO_PATH_OP_CURVE_TO: - status = (*curve_to) (closure, &point[0], &point[1], &point[2]); + status = (*curve_to) (closure, &points[0], &points[1], &points[2]); break; case CAIRO_PATH_OP_CLOSE_PATH: default: @@ -584,6 +490,11 @@ _cairo_path_fixed_interpret (cairo_path_fixed_t *path, } if (status) return status; + + if (forward) { + points += num_args[op]; + } + } } @@ -597,31 +508,31 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path, cairo_fixed_t scalex, cairo_fixed_t scaley) { - cairo_path_arg_buf_t *arg_buf = path->arg_buf_head; + cairo_path_buf_t *buf = path->buf_head; int i; cairo_int64_t i64temp; cairo_fixed_t fixedtemp; - while (arg_buf) { - for (i = 0; i < arg_buf->num_points; i++) { + while (buf) { + for (i = 0; i < buf->num_points; i++) { if (scalex == CAIRO_FIXED_ONE) { - arg_buf->points[i].x += offx; + buf->points[i].x += offx; } else { - fixedtemp = arg_buf->points[i].x + offx; + fixedtemp = buf->points[i].x + offx; i64temp = _cairo_int32x32_64_mul (fixedtemp, scalex); - arg_buf->points[i].x = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16)); + buf->points[i].x = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16)); } if (scaley == CAIRO_FIXED_ONE) { - arg_buf->points[i].y += offy; + buf->points[i].y += offy; } else { - fixedtemp = arg_buf->points[i].y + offy; + fixedtemp = buf->points[i].y + offy; i64temp = _cairo_int32x32_64_mul (fixedtemp, scaley); - arg_buf->points[i].y = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16)); + buf->points[i].y = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16)); } } - arg_buf = arg_buf->next; + buf = buf->next; } } diff --git a/gfx/cairo/cairo/src/cairo-path-stroke.c b/gfx/cairo/cairo/src/cairo-path-stroke.c index 519434c40f5..09bafbf8e71 100644 --- a/gfx/cairo/cairo/src/cairo-path-stroke.c +++ b/gfx/cairo/cairo/src/cairo-path-stroke.c @@ -51,7 +51,7 @@ typedef struct cairo_stroker { cairo_point_t current_point; cairo_point_t first_point; - cairo_bool_t has_sub_path; + cairo_bool_t has_initial_sub_path; cairo_bool_t has_current_face; cairo_stroke_face_t current_face; @@ -61,7 +61,8 @@ typedef struct cairo_stroker { cairo_bool_t dashed; unsigned int dash_index; - int dash_on; + cairo_bool_t dash_on; + cairo_bool_t dash_starts_on; double dash_remain; } cairo_stroker_t; @@ -114,7 +115,7 @@ static void _cairo_stroker_start_dash (cairo_stroker_t *stroker) { double offset; - int on = 1; + cairo_bool_t on = TRUE; unsigned int i = 0; offset = stroker->style->dash_offset; @@ -124,13 +125,13 @@ _cairo_stroker_start_dash (cairo_stroker_t *stroker) segment shrinks to zero it will be skipped over. */ while (offset > 0.0 && offset >= stroker->style->dash[i]) { offset -= stroker->style->dash[i]; - on = 1-on; + on = !on; if (++i == stroker->style->num_dashes) i = 0; } stroker->dashed = TRUE; stroker->dash_index = i; - stroker->dash_on = on; + stroker->dash_on = stroker->dash_starts_on = on; stroker->dash_remain = stroker->style->dash[i] - offset; } @@ -142,7 +143,7 @@ _cairo_stroker_step_dash (cairo_stroker_t *stroker, double step) stroker->dash_index++; if (stroker->dash_index == stroker->style->num_dashes) stroker->dash_index = 0; - stroker->dash_on = 1-stroker->dash_on; + stroker->dash_on = !stroker->dash_on; stroker->dash_remain = stroker->style->dash[stroker->dash_index]; } } @@ -167,7 +168,7 @@ _cairo_stroker_init (cairo_stroker_t *stroker, stroker->has_current_face = FALSE; stroker->has_first_face = FALSE; - stroker->has_sub_path = FALSE; + stroker->has_initial_sub_path = FALSE; if (stroker->style->dash) _cairo_stroker_start_dash (stroker); @@ -466,17 +467,25 @@ _cairo_stroker_add_caps (cairo_stroker_t *stroker) { cairo_status_t status; /* check for a degenerative sub_path */ - if (stroker->has_sub_path + if (stroker->has_initial_sub_path && !stroker->has_first_face && !stroker->has_current_face && stroker->style->line_cap == CAIRO_LINE_JOIN_ROUND) { /* pick an arbitrary slope to use */ cairo_slope_t slope = {1, 0}; - _compute_face (&stroker->first_point, &slope, stroker, &stroker->first_face); + cairo_stroke_face_t face; - stroker->has_first_face = stroker->has_current_face = TRUE; - stroker->current_face = stroker->first_face; + /* arbitrarily choose first_point + * first_point and current_point should be the same */ + _compute_face (&stroker->first_point, &slope, stroker, &face); + + status = _cairo_stroker_add_leading_cap (stroker, &face); + if (status) + return status; + status = _cairo_stroker_add_trailing_cap (stroker, &face); + if (status) + return status; } if (stroker->has_first_face) { @@ -594,6 +603,7 @@ _cairo_stroker_move_to (void *closure, cairo_point_t *point) cairo_status_t status; cairo_stroker_t *stroker = closure; + /* Cap the start and end of the previous sub path as needed */ status = _cairo_stroker_add_caps (stroker); if (status) return status; @@ -603,7 +613,7 @@ _cairo_stroker_move_to (void *closure, cairo_point_t *point) stroker->has_first_face = FALSE; stroker->has_current_face = FALSE; - stroker->has_sub_path = FALSE; + stroker->has_initial_sub_path = FALSE; return CAIRO_STATUS_SUCCESS; } @@ -628,7 +638,7 @@ _cairo_stroker_line_to (void *closure, cairo_point_t *point) cairo_point_t *p2 = point; cairo_slope_t slope; - stroker->has_sub_path = TRUE; + stroker->has_initial_sub_path = TRUE; if (p1->x == p2->x && p1->y == p2->y) return CAIRO_STATUS_SUCCESS; @@ -640,14 +650,14 @@ _cairo_stroker_line_to (void *closure, cairo_point_t *point) return status; if (stroker->has_current_face) { + /* Join with final face from previous segment */ status = _cairo_stroker_join (stroker, &stroker->current_face, &start); if (status) return status; - } else { - if (!stroker->has_first_face) { - stroker->first_face = start; - stroker->has_first_face = TRUE; - } + } else if (!stroker->has_first_face) { + /* Save sub path's first face in case needed for closing join */ + stroker->first_face = start; + stroker->has_first_face = TRUE; } stroker->current_face = end; stroker->has_current_face = TRUE; @@ -665,17 +675,16 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_stroker_t *stroker = closure; - double mag, remain, tmp; + double mag, remain, step_length = 0; double dx, dy; double dx2, dy2; cairo_point_t fd1, fd2; - cairo_bool_t first = TRUE; cairo_stroke_face_t sub_start, sub_end; cairo_point_t *p1 = &stroker->current_point; cairo_point_t *p2 = point; cairo_slope_t slope; - stroker->has_sub_path = stroker->dash_on; + stroker->has_initial_sub_path = stroker->dash_starts_on; if (p1->x == p2->x && p1->y == p2->y) return CAIRO_STATUS_SUCCESS; @@ -687,90 +696,75 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point) cairo_matrix_transform_distance (stroker->ctm_inverse, &dx, &dy); - mag = sqrt (dx *dx + dy * dy); + mag = sqrt (dx * dx + dy * dy); remain = mag; fd1 = *p1; while (remain) { - tmp = stroker->dash_remain; - if (tmp > remain) - tmp = remain; - remain -= tmp; - dx2 = dx * (mag - remain)/mag; + step_length = MIN (stroker->dash_remain, remain); + remain -= step_length; + dx2 = dx * (mag - remain)/mag; dy2 = dy * (mag - remain)/mag; cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2); - fd2.x = _cairo_fixed_from_double (dx2); - fd2.y = _cairo_fixed_from_double (dy2); - fd2.x += p1->x; - fd2.y += p1->y; - /* - * XXX simplify this case analysis - */ + fd2.x = _cairo_fixed_from_double (dx2) + p1->x; + fd2.y = _cairo_fixed_from_double (dy2) + p1->y; + if (stroker->dash_on) { status = _cairo_stroker_add_sub_edge (stroker, &fd1, &fd2, &slope, &sub_start, &sub_end); if (status) return status; - if (!first) { - /* - * Not first dash in this segment, cap start - */ + + if (stroker->has_current_face) { + /* Join with final face from previous segment */ + status = _cairo_stroker_join (stroker, &stroker->current_face, &sub_start); + stroker->has_current_face = FALSE; + if (status) + return status; + } else if (!stroker->has_first_face && stroker->dash_starts_on) { + /* Save sub path's first face in case needed for closing join */ + stroker->first_face = sub_start; + stroker->has_first_face = TRUE; + } else { + /* Cap dash start if not connecting to a previous segment */ status = _cairo_stroker_add_leading_cap (stroker, &sub_start); if (status) return status; - } else { - /* - * First in this segment, join to any current_face, else - * if at start of sub-path, mark position, else - * cap - */ - if (stroker->has_current_face) { - status = _cairo_stroker_join (stroker, &stroker->current_face, &sub_start); - if (status) - return status; - } else { - if (!stroker->has_first_face) { - stroker->first_face = sub_start; - stroker->has_first_face = TRUE; - } else { - status = _cairo_stroker_add_leading_cap (stroker, &sub_start); - if (status) - return status; - } - } - stroker->has_sub_path = TRUE; } + if (remain) { - /* - * Cap if not at end of segment - */ + /* Cap dash end if not at end of segment */ status = _cairo_stroker_add_trailing_cap (stroker, &sub_end); if (status) return status; } else { - /* - * Mark previous line face and fix up next time - * through - */ stroker->current_face = sub_end; stroker->has_current_face = TRUE; } } else { - /* - * If starting with off dash, check previous face - * and cap if necessary - */ - if (first) { - if (stroker->has_current_face) { - status = _cairo_stroker_add_trailing_cap (stroker, &stroker->current_face); - if (status) - return status; - } - } - if (!remain) + if (stroker->has_current_face) { + /* Cap final face from previous segment */ + status = _cairo_stroker_add_trailing_cap (stroker, &stroker->current_face); + if (status) + return status; stroker->has_current_face = FALSE; + } } - _cairo_stroker_step_dash (stroker, tmp); + _cairo_stroker_step_dash (stroker, step_length); fd1 = fd2; - first = FALSE; + } + + if (stroker->dash_on && !stroker->has_current_face) { + /* This segment ends on a transition to dash_on, compute a new face + * and add cap for the begining of the next dash_on step. + * + * Note: this will create a degenerate cap if this is not the last line + * in the path. Whether this behaviour is desirable or not is debatable. + * On one side these degnerate caps can not be reproduced with regular path stroking. + * On the other side Acroread 7 also produces the degenerate caps. */ + _compute_face (point, &slope, stroker, &stroker->current_face); + stroker->has_current_face = TRUE; + status = _cairo_stroker_add_leading_cap (stroker, &stroker->current_face); + if (status) + return status; } stroker->current_point = *point; @@ -807,11 +801,9 @@ _cairo_stroker_curve_to (void *closure, status = _cairo_stroker_join (stroker, &stroker->current_face, &start); if (status) return status; - } else { - if (!stroker->has_first_face) { - stroker->first_face = start; - stroker->has_first_face = TRUE; - } + } else if (!stroker->has_first_face) { + stroker->first_face = start; + stroker->has_first_face = TRUE; } stroker->current_face = end; stroker->has_current_face = TRUE; @@ -928,16 +920,18 @@ _cairo_stroker_close_path (void *closure) return status; if (stroker->has_first_face && stroker->has_current_face) { + /* Join first and final faces of sub path */ status = _cairo_stroker_join (stroker, &stroker->current_face, &stroker->first_face); if (status) return status; } else { + /* Cap the start and end of the sub path as needed */ status = _cairo_stroker_add_caps (stroker); if (status) return status; } - stroker->has_sub_path = FALSE; + stroker->has_initial_sub_path = FALSE; stroker->has_first_face = FALSE; stroker->has_current_face = FALSE; @@ -996,6 +990,7 @@ _cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path, if (status) goto BAIL; + /* Cap the start and end of the final sub path as needed */ status = _cairo_stroker_add_caps (&stroker); BAIL: @@ -1287,16 +1282,17 @@ _cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path, NULL, _cairo_rectilinear_stroker_close_path, &rectilinear_stroker); - if (status) { - _cairo_traps_fini (traps); - return status; - } + if (status) + goto BAIL; status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker); - if (status) - return status; + +BAIL: _cairo_rectilinear_stroker_fini (&rectilinear_stroker); - return CAIRO_STATUS_SUCCESS; + if (status) + _cairo_traps_fini (traps); + + return status; } diff --git a/gfx/cairo/cairo/src/cairo-path.c b/gfx/cairo/cairo/src/cairo-path.c index 544abf3fa10..7c2374c2a4f 100644 --- a/gfx/cairo/cairo/src/cairo-path.c +++ b/gfx/cairo/cairo/src/cairo-path.c @@ -465,19 +465,19 @@ _cairo_path_append_to_context (const cairo_path_t *path, p = &path->data[i]; switch (p->header.type) { case CAIRO_PATH_MOVE_TO: - if (p->header.length != 2) + if (p->header.length < 2) return CAIRO_STATUS_INVALID_PATH_DATA; cairo_move_to (cr, p[1].point.x, p[1].point.y); break; case CAIRO_PATH_LINE_TO: - if (p->header.length != 2) + if (p->header.length < 2) return CAIRO_STATUS_INVALID_PATH_DATA; cairo_line_to (cr, p[1].point.x, p[1].point.y); break; case CAIRO_PATH_CURVE_TO: - if (p->header.length != 4) + if (p->header.length < 4) return CAIRO_STATUS_INVALID_PATH_DATA; cairo_curve_to (cr, p[1].point.x, p[1].point.y, @@ -485,7 +485,7 @@ _cairo_path_append_to_context (const cairo_path_t *path, p[3].point.x, p[3].point.y); break; case CAIRO_PATH_CLOSE_PATH: - if (p->header.length != 1) + if (p->header.length < 1) return CAIRO_STATUS_INVALID_PATH_DATA; cairo_close_path (cr); break; diff --git a/gfx/cairo/cairo/src/cairo-pattern.c b/gfx/cairo/cairo/src/cairo-pattern.c index bc12a9d7f07..f076259b525 100644 --- a/gfx/cairo/cairo/src/cairo-pattern.c +++ b/gfx/cairo/cairo/src/cairo-pattern.c @@ -34,6 +34,7 @@ const cairo_solid_pattern_t cairo_pattern_nil = { { CAIRO_PATTERN_TYPE_SOLID, /* type */ CAIRO_REF_COUNT_INVALID, /* ref_count */ CAIRO_STATUS_NO_MEMORY, /* status */ + { 0, 0, 0, NULL }, /* user_data */ { 1., 0., 0., 1., 0., 0., }, /* matrix */ CAIRO_FILTER_DEFAULT, /* filter */ CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */ @@ -43,6 +44,7 @@ static const cairo_solid_pattern_t cairo_pattern_nil_null_pointer = { { CAIRO_PATTERN_TYPE_SOLID, /* type */ CAIRO_REF_COUNT_INVALID, /* ref_count */ CAIRO_STATUS_NULL_POINTER,/* status */ + { 0, 0, 0, NULL }, /* user_data */ { 1., 0., 0., 1., 0., 0., }, /* matrix */ CAIRO_FILTER_DEFAULT, /* filter */ CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */ @@ -84,6 +86,8 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type) pattern->ref_count = 1; pattern->status = CAIRO_STATUS_SUCCESS; + _cairo_user_data_array_init (&pattern->user_data); + if (type == CAIRO_PATTERN_TYPE_SURFACE) pattern->extend = CAIRO_EXTEND_SURFACE_DEFAULT; else @@ -113,11 +117,15 @@ _cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern, *dst = *src; } - if (other->n_stops) + if (other->stops == other->stops_embedded) + pattern->stops = pattern->stops_embedded; + else if (other->stops) { - pattern->stops = malloc (other->n_stops * + pattern->stops = malloc (other->stops_size * sizeof (pixman_gradient_stop_t)); if (pattern->stops == NULL) { + pattern->stops_size = 0; + pattern->n_stops = 0; _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY); return; } @@ -165,6 +173,8 @@ _cairo_pattern_init_copy (cairo_pattern_t *pattern, void _cairo_pattern_fini (cairo_pattern_t *pattern) { + _cairo_user_data_array_fini (&pattern->user_data); + switch (pattern->type) { case CAIRO_PATTERN_TYPE_SOLID: break; @@ -179,7 +189,7 @@ _cairo_pattern_fini (cairo_pattern_t *pattern) cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern; - if (gradient->stops) + if (gradient->stops && gradient->stops != gradient->stops_embedded) free (gradient->stops); } break; } @@ -215,8 +225,9 @@ _cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern, { _cairo_pattern_init (&pattern->base, type); - pattern->stops = NULL; - pattern->n_stops = 0; + pattern->n_stops = 0; + pattern->stops_size = 0; + pattern->stops = NULL; } void @@ -238,12 +249,12 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern, { _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_RADIAL); - pattern->gradient.inner.x = _cairo_fixed_from_double (cx0); - pattern->gradient.inner.y = _cairo_fixed_from_double (cy0); - pattern->gradient.inner.radius = _cairo_fixed_from_double (fabs (radius0)); - pattern->gradient.outer.x = _cairo_fixed_from_double (cx1); - pattern->gradient.outer.y = _cairo_fixed_from_double (cy1); - pattern->gradient.outer.radius = _cairo_fixed_from_double (fabs (radius1)); + pattern->gradient.c1.x = _cairo_fixed_from_double (cx0); + pattern->gradient.c1.y = _cairo_fixed_from_double (cy0); + pattern->gradient.c1.radius = _cairo_fixed_from_double (fabs (radius0)); + pattern->gradient.c2.x = _cairo_fixed_from_double (cx1); + pattern->gradient.c2.y = _cairo_fixed_from_double (cy1); + pattern->gradient.c2.radius = _cairo_fixed_from_double (fabs (radius1)); } cairo_pattern_t * @@ -490,15 +501,15 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0, * @pattern from being destroyed until a matching call to * cairo_pattern_destroy() is made. * + * The number of references to a #cairo_pattern_t can be get using + * cairo_pattern_get_reference_count(). + * * Return value: the referenced #cairo_pattern_t. **/ cairo_pattern_t * cairo_pattern_reference (cairo_pattern_t *pattern) { - if (pattern == NULL) - return NULL; - - if (pattern->ref_count == CAIRO_REF_COUNT_INVALID) + if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID) return pattern; assert (pattern->ref_count > 0); @@ -555,10 +566,7 @@ slim_hidden_def (cairo_pattern_status); void cairo_pattern_destroy (cairo_pattern_t *pattern) { - if (pattern == NULL) - return; - - if (pattern->ref_count == CAIRO_REF_COUNT_INVALID) + if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID) return; assert (pattern->ref_count > 0); @@ -572,6 +580,116 @@ cairo_pattern_destroy (cairo_pattern_t *pattern) } slim_hidden_def (cairo_pattern_destroy); +/** + * cairo_pattern_get_reference_count: + * @pattern: a #cairo_pattern_t + * + * Returns the current reference count of @pattern. + * + * Return value: the current reference count of @pattern. If the + * object is a nil object, 0 will be returned. + * + * Since: 1.4 + **/ +unsigned int +cairo_pattern_get_reference_count (cairo_pattern_t *pattern) +{ + if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID) + return 0; + + return pattern->ref_count; +} + +/** + * cairo_pattern_get_user_data: + * @pattern: a #cairo_pattern_t + * @key: the address of the #cairo_user_data_key_t the user data was + * attached to + * + * Return user data previously attached to @pattern using the + * specified key. If no user data has been attached with the given + * key this function returns %NULL. + * + * Return value: the user data previously attached or %NULL. + * + * Since: 1.4 + **/ +void * +cairo_pattern_get_user_data (cairo_pattern_t *pattern, + const cairo_user_data_key_t *key) +{ + return _cairo_user_data_array_get_data (&pattern->user_data, + key); +} + +/** + * cairo_pattern_set_user_data: + * @pattern: a #cairo_pattern_t + * @key: the address of a #cairo_user_data_key_t to attach the user data to + * @user_data: the user data to attach to the #cairo_pattern_t + * @destroy: a #cairo_destroy_func_t which will be called when the + * #cairo_t is destroyed or when new user data is attached using the + * same key. + * + * Attach user data to @pattern. To remove user data from a surface, + * call this function with the key that was used to set it and %NULL + * for @data. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a + * slot could not be allocated for the user data. + * + * Since: 1.4 + **/ +cairo_status_t +cairo_pattern_set_user_data (cairo_pattern_t *pattern, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy) +{ + if (pattern->ref_count == CAIRO_REF_COUNT_INVALID) + return CAIRO_STATUS_NO_MEMORY; + + return _cairo_user_data_array_set_data (&pattern->user_data, + key, user_data, destroy); +} + +/* make room for at least one more color stop */ +static cairo_status_t +_cairo_pattern_gradient_grow (cairo_gradient_pattern_t *pattern) +{ + pixman_gradient_stop_t *new_stops; + int old_size = pattern->stops_size; + int embedded_size = sizeof (pattern->stops_embedded) / sizeof (pattern->stops_embedded[0]); + int new_size = 2 * MAX (old_size, 4); + + /* we have a local buffer at pattern->stops_embedded. try to fulfill the request + * from there. */ + if (old_size < embedded_size) { + pattern->stops = pattern->stops_embedded; + pattern->stops_size = embedded_size; + return CAIRO_STATUS_SUCCESS; + } + + assert (pattern->n_stops <= pattern->stops_size); + + if (pattern->stops == pattern->stops_embedded) { + new_stops = malloc (new_size * sizeof (pixman_gradient_stop_t)); + if (new_stops) + memcpy (new_stops, pattern->stops, old_size * sizeof (pixman_gradient_stop_t)); + } else { + new_stops = realloc (pattern->stops, new_size * sizeof (pixman_gradient_stop_t)); + } + + if (new_stops == NULL) { + return CAIRO_STATUS_NO_MEMORY; + } + + pattern->stops = new_stops; + pattern->stops_size = new_size; + + return CAIRO_STATUS_SUCCESS; +} + static void _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, double offset, @@ -580,38 +698,38 @@ _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, double blue, double alpha) { - pixman_gradient_stop_t *new_stops; + pixman_gradient_stop_t *stops; cairo_fixed_t x; unsigned int i; - new_stops = realloc (pattern->stops, (pattern->n_stops + 1) * - sizeof (pixman_gradient_stop_t)); - if (new_stops == NULL) - { - _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY); - return; + if (pattern->n_stops >= pattern->stops_size) { + cairo_status_t status = _cairo_pattern_gradient_grow (pattern); + if (status) { + _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY); + return; + } } - pattern->stops = new_stops; + stops = pattern->stops; x = _cairo_fixed_from_double (offset); for (i = 0; i < pattern->n_stops; i++) { - if (x < new_stops[i].x) + if (x < stops[i].x) { - memmove (&new_stops[i + 1], &new_stops[i], + memmove (&stops[i + 1], &stops[i], sizeof (pixman_gradient_stop_t) * (pattern->n_stops - i)); break; } } - new_stops[i].x = x; + stops[i].x = x; - new_stops[i].color.red = red * 65535.0; - new_stops[i].color.green = green * 65535.0; - new_stops[i].color.blue = blue * 65535.0; - new_stops[i].color.alpha = alpha * 65535.0; + stops[i].color.red = _cairo_color_double_to_short (red); + stops[i].color.green = _cairo_color_double_to_short (green); + stops[i].color.blue = _cairo_color_double_to_short (blue); + stops[i].color.alpha = _cairo_color_double_to_short (alpha); pattern->n_stops++; } @@ -767,6 +885,15 @@ cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix) *matrix = pattern->matrix; } +/** + * cairo_pattern_set_filter: + * @pattern: a #cairo_pattern_t + * @filter: a #cairo_filter_t describing the filter to use for resizing + * the pattern + * + * Sets the filter to be used for resizing when using this pattern. + * See #cairo_filter_t for details on each filter. + **/ void cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter) { @@ -776,6 +903,15 @@ cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter) pattern->filter = filter; } +/** + * cairo_pattern_get_filter: + * @pattern: a #cairo_pattern_t + * + * Gets the current filter for a pattern. See #cairo_filter_t + * for details on each filter. + * + * Return value: the current filter used for resizing the pattern. + **/ cairo_filter_t cairo_pattern_get_filter (cairo_pattern_t *pattern) { @@ -1144,6 +1280,63 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern, ty = 0; } + /* XXX: Hack: + * + * The way we currently support CAIRO_EXTEND_REFLECT is to create + * an image twice bigger on each side, and create a pattern of four + * images such that the new image, when repeated, has the same effect + * of reflecting the original pattern. + * + * This is because the reflect support in pixman is broken and we + * pass repeat instead of reflect to pixman. See + * _cairo_image_surface_set_attributes() for that. + */ + if (attr->extend == CAIRO_EXTEND_REFLECT) { + cairo_t *cr; + int w,h; + + cairo_rectangle_int16_t extents; + status = _cairo_surface_get_extents (pattern->surface, &extents); + if (status) + return status; + + attr->extend = CAIRO_EXTEND_REPEAT; + + x = extents.x; + y = extents.y; + w = 2 * extents.width; + h = 2 * extents.height; + + *out = cairo_surface_create_similar (dst, dst->content, w, h); + if (!*out) + return CAIRO_STATUS_NO_MEMORY; + + (*out)->device_transform = pattern->surface->device_transform; + (*out)->device_transform_inverse = pattern->surface->device_transform_inverse; + + cr = cairo_create (*out); + + cairo_set_source_surface (cr, pattern->surface, -x, -y); + cairo_paint (cr); + + cairo_scale (cr, -1, +1); + cairo_set_source_surface (cr, pattern->surface, x-w, -y); + cairo_paint (cr); + + cairo_scale (cr, +1, -1); + cairo_set_source_surface (cr, pattern->surface, x-w, y-h); + cairo_paint (cr); + + cairo_scale (cr, -1, +1); + cairo_set_source_surface (cr, pattern->surface, -x, y-h); + cairo_paint (cr); + + status = cairo_status (cr); + cairo_destroy (cr); + + return status; + } + if (_cairo_surface_is_image (dst)) { cairo_image_surface_t *image; @@ -1159,10 +1352,16 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern, } else { + cairo_rectangle_int16_t extents; + status = _cairo_surface_get_extents (pattern->surface, &extents); + if (status) + return status; + /* If we're repeating, we just play it safe and clone the entire surface. */ - if (attr->extend == CAIRO_EXTEND_REPEAT) { - cairo_rectangle_int16_t extents; - status = _cairo_surface_get_extents (pattern->surface, &extents); + /* If requested width and height are -1, clone the entire surface. + * This is relied on in the svg backend. */ + if (attr->extend == CAIRO_EXTEND_REPEAT || + (width == (unsigned int) -1 && height == (unsigned int) -1)) { x = extents.x; y = extents.y; width = extents.width; @@ -1179,13 +1378,19 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern, double y2 = y + height; cairo_bool_t is_tight; - cairo_matrix_transform_bounding_box (&attr->matrix, - &x1, &y1, &x2, &y2, - &is_tight); - x = floor (x1); - y = floor (y1); - width = ceil (x2) - x; - height = ceil (y2) - y; + _cairo_matrix_transform_bounding_box (&attr->matrix, + &x1, &y1, &x2, &y2, + &is_tight); + + /* The transform_bounding_box call may have resulted + * in a region larger than the surface, but we never + * want to clone more than the surface itself, (we + * know we're not repeating at this point due to the + * above. */ + x = MAX (0, floor (x1)); + y = MAX (0, floor (y1)); + width = MIN (extents.width, ceil (x2)) - x; + height = MIN (extents.height, ceil (y2)) - y; } x += tx; y += ty; @@ -1193,6 +1398,29 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern, status = _cairo_surface_clone_similar (dst, pattern->surface, x, y, width, height, out); + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + + cairo_t *cr; + + *out = cairo_surface_create_similar (dst, dst->content, + width, height); + if (!*out) + return CAIRO_STATUS_NO_MEMORY; + + (*out)->device_transform = pattern->surface->device_transform; + (*out)->device_transform_inverse = pattern->surface->device_transform_inverse; + + /* XXX Use _cairo_surface_composite directly */ + cr = cairo_create (*out); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, pattern->surface, -x, -y); + cairo_paint (cr); + + status = cairo_status (cr); + cairo_destroy (cr); + } } return status; @@ -1256,10 +1484,10 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern, cairo_color_t color; _cairo_color_init_rgba (&color, - src->stops->color.red / 65536.0, - src->stops->color.green / 65536.0, - src->stops->color.blue / 65536.0, - src->stops->color.alpha / 65536.0); + src->stops->color.red / 65535.0, + src->stops->color.green / 65535.0, + src->stops->color.blue / 65535.0, + src->stops->color.alpha / 65535.0); _cairo_pattern_init_solid (&solid, &color); } @@ -1451,6 +1679,7 @@ _cairo_pattern_get_extents (cairo_pattern_t *pattern, imatrix = pattern->matrix; cairo_matrix_invert (&imatrix); + /* XXX Use _cairo_matrix_transform_bounding_box here */ for (sy = 0; sy <= 1; sy++) { for (sx = 0; sx <= 1; sx++) { x = surface_extents.x + sx * surface_extents.width; @@ -1569,6 +1798,7 @@ cairo_pattern_get_surface (cairo_pattern_t *pattern, * cairo_pattern_get_color_stop_rgba * @pattern: a #cairo_pattern_t * @index: index of the stop to return data for + * @offset: return value for the offset of the stop, or %NULL * @red: return value for red component of color, or %NULL * @green: return value for green component of color, or %NULL * @blue: return value for blue component of color, or %NULL @@ -1685,12 +1915,12 @@ cairo_pattern_get_linear_points (cairo_pattern_t *pattern, /** * cairo_pattern_get_radial_circles * @pattern: a #cairo_pattern_t - * @x0: return value for the x coordinate of the center of the first (inner) circle, or %NULL - * @y0: return value for the y coordinate of the center of the first (inner) circle, or %NULL - * @r0: return value for the radius of the first (inner) circle, or %NULL - * @x1: return value for the x coordinate of the center of the second (outer) circle, or %NULL - * @y1: return value for the y coordinate of the center of the second (outer) circle, or %NULL - * @r1: return value for the radius of the second (outer) circle, or %NULL + * @x0: return value for the x coordinate of the center of the first circle, or %NULL + * @y0: return value for the y coordinate of the center of the first circle, or %NULL + * @r0: return value for the radius of the first circle, or %NULL + * @x1: return value for the x coordinate of the center of the second circle, or %NULL + * @y1: return value for the y coordinate of the center of the second circle, or %NULL + * @r1: return value for the radius of the second circle, or %NULL * * Gets the gradient endpoint circles for a radial gradient, each * specified as a center coordinate and a radius. @@ -1712,17 +1942,17 @@ cairo_pattern_get_radial_circles (cairo_pattern_t *pattern, return CAIRO_STATUS_PATTERN_TYPE_MISMATCH; if (x0) - *x0 = _cairo_fixed_to_double (radial->gradient.inner.x); + *x0 = _cairo_fixed_to_double (radial->gradient.c1.x); if (y0) - *y0 = _cairo_fixed_to_double (radial->gradient.inner.y); + *y0 = _cairo_fixed_to_double (radial->gradient.c1.y); if (r0) - *r0 = _cairo_fixed_to_double (radial->gradient.inner.radius); + *r0 = _cairo_fixed_to_double (radial->gradient.c1.radius); if (x1) - *x1 = _cairo_fixed_to_double (radial->gradient.outer.x); + *x1 = _cairo_fixed_to_double (radial->gradient.c2.x); if (y1) - *y1 = _cairo_fixed_to_double (radial->gradient.outer.y); + *y1 = _cairo_fixed_to_double (radial->gradient.c2.y); if (r1) - *r1 = _cairo_fixed_to_double (radial->gradient.outer.radius); + *r1 = _cairo_fixed_to_double (radial->gradient.c2.radius); return CAIRO_STATUS_SUCCESS; } diff --git a/gfx/cairo/cairo/src/cairo-pdf-surface.c b/gfx/cairo/cairo/src/cairo-pdf-surface.c index 9c6c8e8c7de..924b80c03f8 100644 --- a/gfx/cairo/cairo/src/cairo-pdf-surface.c +++ b/gfx/cairo/cairo/src/cairo-pdf-surface.c @@ -277,7 +277,8 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, _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); @@ -379,7 +380,9 @@ cairo_pdf_surface_create (const char *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, @@ -654,7 +657,7 @@ compress_dup (const void *data, unsigned long data_size, * 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) { @@ -725,7 +728,7 @@ emit_smask (cairo_pdf_surface_t *surface, /* 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) { @@ -744,7 +747,7 @@ emit_image (cairo_pdf_surface_t *surface, /* 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); @@ -794,7 +797,7 @@ emit_image (cairo_pdf_surface_t *surface, 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; @@ -838,7 +841,7 @@ emit_image (cairo_pdf_surface_t *surface, } 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; @@ -863,77 +866,80 @@ emit_solid_pattern (cairo_pdf_surface_t *surface, } 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; @@ -980,8 +986,8 @@ emit_surface_pattern (cairo_pdf_surface_t *surface, 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" @@ -1016,7 +1022,9 @@ emit_surface_pattern (cairo_pdf_surface_t *surface, 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; } @@ -1028,7 +1036,7 @@ typedef struct _cairo_pdf_color_stop { } 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) { @@ -1057,7 +1065,7 @@ emit_linear_colorgradient (cairo_pdf_surface_t *surface, } 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[]) { @@ -1066,7 +1074,7 @@ emit_stitched_colorgradient (cairo_pdf_surface_t *surface, /* 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]); } @@ -1119,7 +1127,7 @@ emit_stitched_colorgradient (cairo_pdf_surface_t *surface, #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; @@ -1162,11 +1170,11 @@ emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *patt 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); } @@ -1177,7 +1185,7 @@ emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *patt } 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; @@ -1185,7 +1193,7 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *patte _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; @@ -1240,7 +1248,7 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *patte } 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; @@ -1248,20 +1256,20 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *patte _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 @@ -1316,20 +1324,20 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *patte } 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); } @@ -1630,11 +1638,90 @@ _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface) "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> \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> 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; @@ -1672,6 +1759,8 @@ _cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface, "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" @@ -1710,7 +1799,7 @@ _cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface, " /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++) @@ -1719,7 +1808,14 @@ _cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface, 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"); @@ -1738,7 +1834,7 @@ _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; @@ -1772,6 +1868,8 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface, "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" @@ -1819,7 +1917,14 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface, 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"); @@ -1873,11 +1978,13 @@ _cairo_pdf_surface_emit_type1_fallback_font (cairo_pdf_surface_t *surface, 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; @@ -1914,17 +2021,19 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface, "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" @@ -1932,14 +2041,30 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface, "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" @@ -1949,19 +2074,28 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface, " /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"); + + 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" ">>\r\n" "endobj\r\n"); @@ -2025,13 +2159,16 @@ 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, @@ -2041,6 +2178,12 @@ _cairo_pdf_surface_emit_bitmap_glyph (cairo_pdf_surface_t *surface, 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); @@ -2048,17 +2191,18 @@ _cairo_pdf_surface_emit_bitmap_glyph (cairo_pdf_surface_t *surface, 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), @@ -2097,7 +2241,9 @@ 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; @@ -2109,7 +2255,9 @@ _cairo_pdf_surface_emit_glyph (cairo_pdf_surface_t *surface, 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); @@ -2119,10 +2267,13 @@ 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) { @@ -2130,11 +2281,35 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, 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); @@ -2164,6 +2339,8 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, 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); @@ -2171,13 +2348,17 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, "%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, @@ -2189,9 +2370,15 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, _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" @@ -2206,8 +2393,8 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, } 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; @@ -2229,6 +2416,14 @@ _cairo_pdf_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset, 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) @@ -2240,9 +2435,12 @@ _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; @@ -2252,114 +2450,6 @@ _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface) 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) { @@ -2444,9 +2534,12 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface) 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"); @@ -2478,10 +2571,11 @@ _surface_pattern_supported (cairo_surface_pattern_t *pattern) switch (extend) { case CAIRO_EXTEND_NONE: case CAIRO_EXTEND_REPEAT: - return TRUE; 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 FALSE; + return TRUE; } ASSERT_NOT_REACHED; @@ -2521,7 +2615,7 @@ _cairo_pdf_test_force_fallbacks (void) } 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) { @@ -2540,11 +2634,11 @@ _operation_supported (cairo_pdf_surface_t *surface, } 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; @@ -2559,7 +2653,7 @@ _cairo_pdf_surface_paint (void *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 @@ -2568,10 +2662,10 @@ _cairo_pdf_surface_paint (void *abstract_surface, * possible only because there is nothing between the fallback * images and the paper, nor is anything painted above. */ /* - assert (_operation_supported (op, source)); + assert (__cairo_pdf_surface_operation_supported (op, source)); */ - status = emit_pattern (surface, source); + status = _cairo_pdf_surface_emit_pattern (surface, source); if (status) return status; @@ -2680,11 +2774,11 @@ _cairo_pdf_surface_stroke (void *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); - assert (_operation_supported (surface, op, source)); + assert (__cairo_pdf_surface_operation_supported (surface, op, source)); - status = emit_pattern (surface, source); + status = _cairo_pdf_surface_emit_pattern (surface, source); if (status) return status; @@ -2729,11 +2823,11 @@ _cairo_pdf_surface_fill (void *abstract_surface, pdf_path_info_t info; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _analyze_operation (surface, op, source); + return _cairo_pdf_surface_analyze_operation (surface, op, source); - assert (_operation_supported (surface, op, source)); + assert (__cairo_pdf_surface_operation_supported (surface, op, source)); - status = emit_pattern (surface, source); + status = _cairo_pdf_surface_emit_pattern (surface, source); if (status) return status; @@ -2782,11 +2876,11 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface, int i; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _analyze_operation (surface, op, source); + return _cairo_pdf_surface_analyze_operation (surface, op, source); - assert (_operation_supported (surface, op, source)); + assert (__cairo_pdf_surface_operation_supported (surface, op, source)); - status = emit_pattern (surface, source); + status = _cairo_pdf_surface_emit_pattern (surface, source); if (status) return status; @@ -2826,7 +2920,7 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface, _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); } } diff --git a/gfx/cairo/cairo/src/cairo-polygon.c b/gfx/cairo/cairo/src/cairo-polygon.c index dc9d3805b16..52c72b710d1 100644 --- a/gfx/cairo/cairo/src/cairo-polygon.c +++ b/gfx/cairo/cairo/src/cairo-polygon.c @@ -40,7 +40,7 @@ /* private functions */ static cairo_status_t -_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional); +_cairo_polygon_grow (cairo_polygon_t *polygon); void _cairo_polygon_init (cairo_polygon_t *polygon) @@ -50,42 +50,55 @@ _cairo_polygon_init (cairo_polygon_t *polygon) polygon->edges_size = 0; polygon->edges = NULL; - polygon->has_current_point = 0; + polygon->has_current_point = FALSE; } void _cairo_polygon_fini (cairo_polygon_t *polygon) { - if (polygon->edges_size) { + if (polygon->edges && polygon->edges != polygon->edges_embedded) free (polygon->edges); - polygon->edges = NULL; - polygon->edges_size = 0; - polygon->num_edges = 0; - } - polygon->has_current_point = 0; + polygon->edges = NULL; + polygon->edges_size = 0; + polygon->num_edges = 0; + + polygon->has_current_point = FALSE; } +/* make room for at least one more edge */ static cairo_status_t -_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional) +_cairo_polygon_grow (cairo_polygon_t *polygon) { cairo_edge_t *new_edges; int old_size = polygon->edges_size; - int new_size = polygon->num_edges + additional; + int embedded_size = sizeof (polygon->edges_embedded) / sizeof (polygon->edges_embedded[0]); + int new_size = 2 * MAX (old_size, 16); - if (new_size <= polygon->edges_size) { + /* we have a local buffer at polygon->edges_embedded. try to fulfill the request + * from there. */ + if (old_size < embedded_size) { + polygon->edges = polygon->edges_embedded; + polygon->edges_size = embedded_size; return CAIRO_STATUS_SUCCESS; } - polygon->edges_size = new_size; - new_edges = realloc (polygon->edges, polygon->edges_size * sizeof (cairo_edge_t)); + assert (polygon->num_edges <= polygon->edges_size); + + if (polygon->edges == polygon->edges_embedded) { + new_edges = malloc (new_size * sizeof (cairo_edge_t)); + if (new_edges) + memcpy (new_edges, polygon->edges, old_size * sizeof (cairo_edge_t)); + } else { + new_edges = realloc (polygon->edges, new_size * sizeof (cairo_edge_t)); + } if (new_edges == NULL) { - polygon->edges_size = old_size; return CAIRO_STATUS_NO_MEMORY; } polygon->edges = new_edges; + polygon->edges_size = new_size; return CAIRO_STATUS_SUCCESS; } @@ -102,8 +115,7 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_poin } if (polygon->num_edges >= polygon->edges_size) { - int additional = polygon->edges_size ? polygon->edges_size : 16; - status = _cairo_polygon_grow_by (polygon, additional); + status = _cairo_polygon_grow (polygon); if (status) { return status; } @@ -134,7 +146,7 @@ _cairo_polygon_move_to (cairo_polygon_t *polygon, cairo_point_t *point) if (! polygon->has_current_point) polygon->first_point = *point; polygon->current_point = *point; - polygon->has_current_point = 1; + polygon->has_current_point = TRUE; return CAIRO_STATUS_SUCCESS; } @@ -165,7 +177,7 @@ _cairo_polygon_close (cairo_polygon_t *polygon) if (status) return status; - polygon->has_current_point = 0; + polygon->has_current_point = FALSE; } return CAIRO_STATUS_SUCCESS; diff --git a/gfx/cairo/cairo/src/cairo-private.h b/gfx/cairo/cairo/src/cairo-private.h index 7051f7ebd18..14cc79aea20 100644 --- a/gfx/cairo/cairo/src/cairo-private.h +++ b/gfx/cairo/cairo/src/cairo-private.h @@ -44,9 +44,12 @@ struct _cairo { cairo_status_t status; - cairo_path_fixed_t path; + cairo_user_data_array_t user_data; cairo_gstate_t *gstate; + cairo_gstate_t gstate_tail[1]; + + cairo_path_fixed_t path[1]; }; #endif /* CAIRO_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-ps-surface.c b/gfx/cairo/cairo/src/cairo-ps-surface.c index 45d9fe70b1c..5f43e98c797 100644 --- a/gfx/cairo/cairo/src/cairo-ps-surface.c +++ b/gfx/cairo/cairo/src/cairo-ps-surface.c @@ -484,18 +484,18 @@ _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface, /* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */ - for (i = 1; i < font_subset->num_glyphs; i++) + for (i = 0; i < font_subset->num_glyphs; i++) _cairo_output_stream_printf (surface->final_stream, "Encoding %d /g%d put\n", i, i); _cairo_output_stream_printf (surface->final_stream, "/CharStrings %d dict dup begin\n" "/.notdef 0 def\n", - font_subset->num_glyphs); + font_subset->num_glyphs + 1); - for (i = 1; i < font_subset->num_glyphs; i++) + for (i = 0; i < font_subset->num_glyphs; i++) _cairo_output_stream_printf (surface->final_stream, - "/g%d %d def\n", i, i); + "/g%d %d def\n", i, i + 1); _cairo_output_stream_printf (surface->final_stream, "end readonly def\n"); @@ -709,8 +709,8 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface, static void -_cairo_ps_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset, - void *closure) +_cairo_ps_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset, + void *closure) { cairo_ps_surface_t *surface = closure; cairo_status_t status; @@ -728,6 +728,14 @@ _cairo_ps_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset, status = _cairo_ps_surface_emit_type1_font_fallback (surface, font_subset); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return; +} + +static void +_cairo_ps_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset, + void *closure) +{ + cairo_ps_surface_t *surface = closure; + cairo_status_t status; status = _cairo_ps_surface_emit_type3_font_subset (surface, font_subset); if (status != CAIRO_INT_STATUS_UNSUPPORTED) @@ -742,9 +750,12 @@ _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface) _cairo_output_stream_printf (surface->final_stream, "%% _cairo_ps_surface_emit_font_subsets\n"); - status = _cairo_scaled_font_subsets_foreach (surface->font_subsets, - _cairo_ps_surface_emit_font_subset, - surface); + status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets, + _cairo_ps_surface_emit_unscaled_font_subset, + surface); + status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets, + _cairo_ps_surface_emit_scaled_font_subset, + surface); _cairo_scaled_font_subsets_destroy (surface->font_subsets); surface->font_subsets = NULL; @@ -798,7 +809,8 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream, if (status) goto CLEANUP_TMPFILE; - surface->font_subsets = _cairo_scaled_font_subsets_create (PS_SURFACE_MAX_GLYPHS_PER_FONT); + surface->font_subsets = _cairo_scaled_font_subsets_create (PS_SURFACE_MAX_GLYPHS_PER_FONT, + PS_SURFACE_MAX_GLYPHS_PER_FONT); if (! surface->font_subsets) goto CLEANUP_OUTPUT_STREAM; @@ -868,7 +880,9 @@ cairo_ps_surface_create (const char *filename, status = _cairo_output_stream_get_status (stream); if (status) { _cairo_error (status); - return (cairo_surface_t*) &_cairo_surface_nil; + return (status == CAIRO_STATUS_WRITE_ERROR) ? + (cairo_surface_t*) &_cairo_surface_nil_write_error : + (cairo_surface_t*) &_cairo_surface_nil; } return _cairo_ps_surface_create_for_stream_internal (stream, @@ -1323,9 +1337,37 @@ color_is_gray (cairo_color_t *color) static cairo_bool_t surface_pattern_supported (const cairo_surface_pattern_t *pattern) { - if (pattern->surface->backend->acquire_source_image != NULL) - return TRUE; + cairo_extend_t extend; + if (pattern->surface->backend->acquire_source_image == NULL) + return FALSE; + + /* Does an ALPHA-only source surface even make sense? Maybe, but I + * don't think it's worth the extra code to support it. */ + +/* XXX: Need to write this function here... + content = cairo_surface_get_content (pattern->surface); + if (content == CAIRO_CONTENT_ALPHA) + return FALSE; +*/ + + /* Cast away the const, trusting get_extend not to muck with it. + * And I really wish I had a way to cast away just the const, and + * not potentially coerce this pointer to an incorrect type at the + * same time. :-( + */ + extend = cairo_pattern_get_extend ((cairo_pattern_t*)&pattern->base); + switch (extend) { + case CAIRO_EXTEND_NONE: + case CAIRO_EXTEND_REPEAT: + case CAIRO_EXTEND_REFLECT: + /* There's no point returning FALSE for EXTEND_PAD, as the image + * surface does not currently implement it either */ + case CAIRO_EXTEND_PAD: + return TRUE; + } + + ASSERT_NOT_REACHED; return FALSE; } @@ -1362,7 +1404,7 @@ _cairo_ps_test_force_fallbacks (void) } static cairo_int_status_t -operation_supported (cairo_ps_surface_t *surface, +_cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *pattern) { @@ -1382,11 +1424,11 @@ operation_supported (cairo_ps_surface_t *surface, } static cairo_int_status_t -_analyze_operation (cairo_ps_surface_t *surface, +_cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *pattern) { - if (operation_supported (surface, op, pattern)) + if (_cairo_ps_surface_operation_supported (surface, op, pattern)) return CAIRO_STATUS_SUCCESS; else return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1516,9 +1558,8 @@ _string_array_stream_create (cairo_output_stream_t *output) * surface we can render natively in PS. */ static cairo_status_t -emit_image (cairo_ps_surface_t *surface, +_cairo_ps_surface_emit_image (cairo_ps_surface_t *surface, cairo_image_surface_t *image, - cairo_matrix_t *matrix, const char *name) { cairo_status_t status; @@ -1627,17 +1668,14 @@ emit_image (cairo_ps_surface_t *surface, " /%sDataIndex %sDataIndex 1 add def\n" " %sDataIndex %sData length 1 sub gt { /%sDataIndex 0 def } if\n" " } /ASCII85Decode filter /LZWDecode filter\n" - " /ImageMatrix [ %f %f %f %f %f %f ]\n" + " /ImageMatrix [ 1 0 0 1 0 0 ]\n" " >>\n" " image\n" "} def\n", name, opaque_image->width, opaque_image->height, - name, name, name, name, name, name, name, - matrix->xx, matrix->yx, - matrix->xy, matrix->yy, - 0.0, 0.0); + name, name, name, name, name, name, name); status = CAIRO_STATUS_SUCCESS; @@ -1652,7 +1690,7 @@ emit_image (cairo_ps_surface_t *surface, } static void -emit_solid_pattern (cairo_ps_surface_t *surface, +_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface, cairo_solid_pattern_t *pattern) { if (color_is_gray (&pattern->color)) @@ -1668,12 +1706,13 @@ emit_solid_pattern (cairo_ps_surface_t *surface, } static void -emit_surface_pattern (cairo_ps_surface_t *surface, +_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, cairo_surface_pattern_t *pattern) { double bbox_width, bbox_height; - int xstep, ystep; + double xstep, ystep; cairo_matrix_t inverse = pattern->base.matrix; + cairo_matrix_invert (&inverse); if (_cairo_surface_is_meta (pattern->surface)) { @@ -1694,32 +1733,49 @@ emit_surface_pattern (cairo_ps_surface_t *surface, &image_extra); assert (status == CAIRO_STATUS_SUCCESS); - emit_image (surface, image, &pattern->base.matrix, "MyPattern"); + _cairo_ps_surface_emit_image (surface, image, "MyPattern"); bbox_width = image->width; bbox_height = image->height; - cairo_matrix_transform_distance (&inverse, - &bbox_width, &bbox_height); - /* In PostScript, (as far as I can tell), all patterns are - * repeating. So we support cairo's EXTEND_NONE semantics by - * setting the repeat step size to the larger of the image size - * and the extents of the destination surface. That way we - * guarantee the pattern will not repeat. - */ switch (pattern->base.extend) { + /* We implement EXTEND_PAD like EXTEND_NONE for now */ + case CAIRO_EXTEND_PAD: case CAIRO_EXTEND_NONE: - xstep = MAX (image->width, surface->width); - ystep = MAX (image->height, surface->height); + { + /* In PS/PDF, (as far as I can tell), all patterns are + * repeating. So we support cairo's EXTEND_NONE semantics + * by setting the repeat step size to a size large enough + * to guarantee that no more than a single occurrence will + * be visible. + * + * First, map the surface extents into pattern space (since + * xstep and ystep are in pattern space). Then use an upper + * bound on the length of the diagonal of the pattern image + * and the surface as repeat size. This guarantees to never + * repeat visibly. + */ + double x1 = 0.0, y1 = 0.0; + double x2 = surface->width, y2 = surface->height; + _cairo_matrix_transform_bounding_box (&pattern->base.matrix, + &x1, &y1, &x2, &y2, + NULL); + + /* Rather than computing precise bounds of the union, just + * add the surface extents unconditionally. We only + * required an answer that's large enough, we don't really + * care if it's not as tight as possible.*/ + xstep = ystep = ceil ((x2 - x1) + (y2 - y1) + + image->width + image->height); break; + } case CAIRO_EXTEND_REPEAT: + case CAIRO_EXTEND_REFLECT: xstep = image->width; ystep = image->height; break; - /* All the rest should have been analyzed away, so these cases - * should be unreachable. */ - case CAIRO_EXTEND_REFLECT: - case CAIRO_EXTEND_PAD: + /* All the rest (if any) should have been analyzed away, so these + * cases should be unreachable. */ default: ASSERT_NOT_REACHED; xstep = 0; @@ -1734,37 +1790,39 @@ emit_surface_pattern (cairo_ps_surface_t *surface, " /PaintType 1\n" " /TilingType 1\n"); _cairo_output_stream_printf (surface->stream, - " /BBox [0 0 %d %d]\n", - (int) bbox_width, (int) bbox_height); + " /BBox [0 0 %f %f]\n", + bbox_width, bbox_height); _cairo_output_stream_printf (surface->stream, - " /XStep %d /YStep %d\n", + " /XStep %f /YStep %f\n", xstep, ystep); _cairo_output_stream_printf (surface->stream, " /PaintProc { MyPattern } bind\n" ">>\n"); _cairo_output_stream_printf (surface->stream, - "[ 1 0 0 1 %f %f ]\n", + "[ %f %f %f %f %f %f ]\n", + inverse.xx, inverse.yx, + inverse.xy, inverse.yy, inverse.x0, inverse.y0); _cairo_output_stream_printf (surface->stream, "makepattern setpattern\n"); } static void -emit_linear_pattern (cairo_ps_surface_t *surface, +_cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface, cairo_linear_pattern_t *pattern) { /* XXX: NYI */ } static void -emit_radial_pattern (cairo_ps_surface_t *surface, +_cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface, cairo_radial_pattern_t *pattern) { /* XXX: NYI */ } static void -emit_pattern (cairo_ps_surface_t *surface, cairo_pattern_t *pattern) +_cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, cairo_pattern_t *pattern) { /* FIXME: We should keep track of what pattern is currently set in * the postscript file and only emit code if we're setting a @@ -1772,19 +1830,19 @@ emit_pattern (cairo_ps_surface_t *surface, cairo_pattern_t *pattern) switch (pattern->type) { case CAIRO_PATTERN_TYPE_SOLID: - emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern); + _cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern); break; case CAIRO_PATTERN_TYPE_SURFACE: - emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern); + _cairo_ps_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern); break; case CAIRO_PATTERN_TYPE_LINEAR: - emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern); + _cairo_ps_surface_emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern); break; case CAIRO_PATTERN_TYPE_RADIAL: - emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern); + _cairo_ps_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern); break; } } @@ -1874,7 +1932,7 @@ _cairo_ps_surface_paint (void *abstract_surface, cairo_rectangle_int16_t extents, pattern_extents; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _analyze_operation (surface, op, source); + return _cairo_ps_surface_analyze_operation (surface, op, source); /* XXX: It would be nice to be able to assert this condition * here. But, we actually allow one 'cheat' that is used when @@ -1883,7 +1941,7 @@ _cairo_ps_surface_paint (void *abstract_surface, * possible only because there is nothing between the fallback * images and the paper, nor is anything painted above. */ /* - assert (_operation_supported (op, source)); + assert (__cairo_ps_surface_operation_supported (op, source)); */ _cairo_output_stream_printf (stream, @@ -1893,7 +1951,7 @@ _cairo_ps_surface_paint (void *abstract_surface, _cairo_pattern_get_extents (source, &pattern_extents); _cairo_rectangle_intersect (&extents, &pattern_extents); - emit_pattern (surface, source); + _cairo_ps_surface_emit_pattern (surface, source); _cairo_output_stream_printf (stream, "%d %d M\n", extents.x, extents.y); @@ -1961,9 +2019,9 @@ _cairo_ps_surface_stroke (void *abstract_surface, double dash_offset = style->dash_offset; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _analyze_operation (surface, op, source); + return _cairo_ps_surface_analyze_operation (surface, op, source); - assert (operation_supported (surface, op, source)); + assert (_cairo_ps_surface_operation_supported (surface, op, source)); _cairo_output_stream_printf (stream, @@ -2032,7 +2090,7 @@ _cairo_ps_surface_stroke (void *abstract_surface, } } - emit_pattern (surface, source); + _cairo_ps_surface_emit_pattern (surface, source); _cairo_output_stream_printf (stream, "gsave\n"); @@ -2092,14 +2150,14 @@ _cairo_ps_surface_fill (void *abstract_surface, const char *ps_operator; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _analyze_operation (surface, op, source); + return _cairo_ps_surface_analyze_operation (surface, op, source); - assert (operation_supported (surface, op, source)); + assert (_cairo_ps_surface_operation_supported (surface, op, source)); _cairo_output_stream_printf (stream, "%% _cairo_ps_surface_fill\n"); - emit_pattern (surface, source); + _cairo_ps_surface_emit_pattern (surface, source); /* We're filling not stroking, so we pass CAIRO_LINE_CAP_ROUND. */ status = _cairo_ps_surface_emit_path (surface, stream, path, @@ -2150,9 +2208,9 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface, cairo_output_stream_t *word_wrap; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _analyze_operation (surface, op, source); + return _cairo_ps_surface_analyze_operation (surface, op, source); - assert (operation_supported (surface, op, source)); + assert (_cairo_ps_surface_operation_supported (surface, op, source)); _cairo_output_stream_printf (stream, "%% _cairo_ps_surface_show_glyphs\n"); @@ -2162,7 +2220,7 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface, num_glyphs_unsigned = num_glyphs; - emit_pattern (surface, source); + _cairo_ps_surface_emit_pattern (surface, source); glyph_ids = malloc (num_glyphs_unsigned*sizeof (cairo_ps_glyph_id_t)); if (glyph_ids == NULL) return CAIRO_STATUS_NO_MEMORY; diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h index f9db501c92b..23d7d4be51f 100644 --- a/gfx/cairo/cairo/src/cairo-quartz-private.h +++ b/gfx/cairo/cairo/src/cairo-quartz-private.h @@ -1,6 +1,7 @@ /* cairo - a vector graphics library with display and print output * * Copyright © 2004 Calum Robinson + * Copyright (C) 2006,2007 Mozilla Corporation * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -31,36 +32,43 @@ * * Contributor(s): * Calum Robinson + * Vladimir Vukicevic */ #ifndef CAIRO_QUARTZ_PRIVATE_H #define CAIRO_QUARTZ_PRIVATE_H #include + +#ifdef CAIRO_HAS_QUARTZ_SURFACE #include 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 */ diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c index 151961c5e19..33f3a10ca48 100644 --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c @@ -1,6 +1,7 @@ +/* -*- 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 @@ -27,239 +28,1749 @@ * * 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 + * Vladimir Vukicevic */ +#include + #include "cairoint.h" -#include "cairo-private.h" + #include "cairo-quartz-private.h" -static cairo_status_t -_cairo_quartz_surface_finish(void *abstract_surface) -{ - cairo_quartz_surface_t *surface = abstract_surface; +#undef QUARTZ_DEBUG - if (surface->clip_region) - pixman_region_destroy (surface->clip_region); +#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_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_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; + + 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.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_quartz_surface_finish (void *abstract_surface) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + + ND((stderr, "_cairo_quartz_surface_finish[%p] cgc: %p\n", surface, surface->cgContext)); + + /* Restore our saved gstate that we use to reset clipping */ + CGContextRestoreGState (surface->cgContext); + + CGContextRelease (surface->cgContext); + + surface->cgContext = NULL; + + if (surface->imageData) { + free (surface->imageData); + surface->imageData = NULL; + } return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_quartz_surface_acquire_source_image(void *abstract_surface, - cairo_image_surface_t **image_out, - void **image_extra) +_cairo_quartz_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) { - cairo_quartz_surface_t *surface = abstract_surface; + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; -#if 0 - if (CGBitmapContextGetBitmapInfo (surface->context) != 0) { - /* XXX: We can create an image out of the bitmap here */ - } -#endif + //ND((stderr, "%p _cairo_quartz_surface_acquire_source_image\n", surface)); - return CAIRO_INT_STATUS_UNSUPPORTED; + *image_extra = NULL; + + return _cairo_quartz_get_image (surface, image_out, NULL); } static cairo_status_t -_cairo_quartz_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_quartz_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_quartz_surface_t *surface = abstract_surface; - cairo_surface_t *image_surface; + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_int_status_t status; unsigned char *data; - int x1, y1, x2, y2; - x1 = surface->extents.x; - x2 = surface->extents.x + surface->extents.width; - y1 = surface->extents.y; - y2 = surface->extents.y + surface->extents.height; + ND((stderr, "%p _cairo_quartz_surface_acquire_dest_image\n", surface)); - if (interest_rect->x > x1) - x1 = interest_rect->x; - if (interest_rect->y > y1) - y1 = interest_rect->y; - if (interest_rect->x + interest_rect->width < x2) - x2 = interest_rect->x + interest_rect->width; - if (interest_rect->y + interest_rect->height < y2) - y2 = interest_rect->y + interest_rect->height; + *image_rect = surface->extents; - if (x1 >= x2 || y1 >= y2) { - *image_out = NULL; - *image_extra = NULL; + status = _cairo_quartz_get_image (surface, image_out, &data); + if (status) + return status; + + *image_extra = data; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_quartz_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_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + unsigned char *imageData = (unsigned char *) image_extra; + + //ND((stderr, "%p _cairo_quartz_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 | kCGBitmapByteOrder32Host, + 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_quartz_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + /*cairo_quartz_surface_t *surface = (cairo_quartz_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_quartz_surface_create (format, width, height); +} + +static cairo_status_t +_cairo_quartz_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_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_quartz_surface_t *new_surface = NULL; + cairo_format_t new_format; + + CGImageRef quartz_image = NULL; + + if (cairo_surface_get_type(src) == CAIRO_SURFACE_TYPE_QUARTZ) { + cairo_quartz_surface_t *qsurf = (cairo_quartz_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_quartz_surface_t *) + cairo_quartz_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); + + quartz_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_quartz_surface_get_extents (void *abstract_surface, + cairo_rectangle_int16_t *extents) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + + *extents = surface->extents; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_quartz_surface_paint (void *abstract_surface, + cairo_operator_t op, + cairo_pattern_t *source) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; + cairo_quartz_action_t action; + + ND((stderr, "%p _cairo_quartz_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_quartz_cairo_operator_to_quartz (op)); + + action = _cairo_quartz_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_quartz_teardown_source (surface, source); + + ND((stderr, "-- paint\n")); + return rv; +} + +static cairo_int_status_t +_cairo_quartz_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_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; + cairo_quartz_action_t action; + + ND((stderr, "%p _cairo_quartz_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_quartz_cairo_operator_to_quartz (op)); + + action = _cairo_quartz_setup_source (surface, source); + if (action == DO_UNSUPPORTED) { + CGContextRestoreGState (surface->cgContext); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + CGContextBeginPath (surface->cgContext); + _cairo_quartz_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_quartz_teardown_source (surface, source); + + CGContextRestoreGState (surface->cgContext); + + ND((stderr, "-- fill\n")); + return rv; +} + +static cairo_int_status_t +_cairo_quartz_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_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; + cairo_quartz_action_t action; + + ND((stderr, "%p _cairo_quartz_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_quartz_cairo_line_cap_to_quartz (style->line_cap)); + CGContextSetLineJoin (surface->cgContext, _cairo_quartz_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; + unsigned 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_quartz_cairo_operator_to_quartz (op)); + + action = _cairo_quartz_setup_source (surface, source); + if (action == DO_UNSUPPORTED) { + CGContextRestoreGState (surface->cgContext); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + CGContextBeginPath (surface->cgContext); + _cairo_quartz_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_quartz_teardown_source (surface, source); + + CGContextRestoreGState (surface->cgContext); + + ND((stderr, "-- stroke\n")); + return rv; +} + +#if CAIRO_HAS_ATSUI_FONT +static cairo_int_status_t +_cairo_quartz_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_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; + cairo_quartz_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_get_type (scaled_font) != CAIRO_FONT_TYPE_ATSUI) + return CAIRO_INT_STATUS_UNSUPPORTED; + + CGContextSaveGState (surface->cgContext); + + action = _cairo_quartz_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; + } + + CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_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, ctm; + _cairo_quartz_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); + + ctm = CGAffineTransformMake (scaled_font->ctm.xx, + -scaled_font->ctm.yx, + -scaled_font->ctm.xy, + scaled_font->ctm.yy, + 0., 0.); + textTransform = CGAffineTransformConcat (ctm, 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); + } + + double xprev = glyphs[0].x; + double 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; + cg_advances[i-1].width = glyphs[i].x - xprev; + cg_advances[i-1].height = glyphs[i].y - yprev; + xprev = glyphs[i].x; + yprev = glyphs[i].y; + } + +#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_quartz_teardown_source (surface, source); + + CGContextRestoreGState (surface->cgContext); + + return rv; +} +#endif /* CAIRO_HAS_ATSUI_FONT */ + +static cairo_int_status_t +_cairo_quartz_surface_mask (void *abstract_surface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_pattern_t *mask) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; + + ND((stderr, "%p _cairo_quartz_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; } - image_rect->x = x1; - image_rect->y = y1; - image_rect->width = x2 - x1; - image_rect->height = y2 - y1; + rv = _cairo_quartz_surface_paint (surface, op, source); - data = calloc (image_rect->width * image_rect->height * 4, 1); - image_surface = cairo_image_surface_create_for_data (data, - CAIRO_FORMAT_ARGB32, - image_rect->width, - image_rect->height, - image_rect->width * 4); - - *image_out = (cairo_image_surface_t *)image_surface; - *image_extra = data; - - return CAIRO_STATUS_SUCCESS; - - return CAIRO_INT_STATUS_UNSUPPORTED; -} - -static CGImageRef -create_image_from_surface (cairo_image_surface_t *image_surface, void *data) -{ - CGImageRef image; - CGColorSpaceRef color_space; - CGDataProviderRef data_provider; - int width, height; - - width = cairo_image_surface_get_width ((cairo_surface_t *)image_surface); - height = cairo_image_surface_get_height ((cairo_surface_t *)image_surface); - - color_space = CGColorSpaceCreateDeviceRGB(); - data_provider = CGDataProviderCreateWithData (NULL, data, - width * height * 4, NULL); - image = CGImageCreate (width, height, - 8, 32, - width * 4, - color_space, - kCGImageAlphaPremultipliedFirst, - data_provider, - NULL, - FALSE, kCGRenderingIntentDefault); - - CGColorSpaceRelease (color_space); - CGDataProviderRelease (data_provider); - - return image; -} - -static void -_cairo_quartz_surface_release_dest_image(void *abstract_surface, - cairo_rectangle_int16_t *intersect_rect, - cairo_image_surface_t *image, - cairo_rectangle_int16_t *image_rect, - void *image_extra) -{ - cairo_quartz_surface_t *surface = abstract_surface; - CGImageRef image_ref; - CGRect rect; - - image_ref = create_image_from_surface (image, image_extra); - - rect = CGRectMake (image_rect->x, image_rect->y, image_rect->width, image_rect->height); - - if (surface->y_grows_down) { - CGContextSaveGState (surface->context); - CGContextTranslateCTM (surface->context, 0, image_rect->height + 2 * image_rect->y); - CGContextScaleCTM (surface->context, 1, -1); + if (mask->type == CAIRO_PATTERN_TYPE_SOLID) { + CGContextSetAlpha (surface->cgContext, 1.0); } - CGContextDrawImage(surface->context, rect, image_ref); - CFRelease (image_ref); + ND((stderr, "-- mask\n")); - if (surface->y_grows_down) { - CGContextRestoreGState (surface->context); - } - - cairo_surface_destroy ((cairo_surface_t *)image); - free (image_extra); + return rv; } static cairo_int_status_t -_cairo_quartz_surface_set_clip_region(void *abstract_surface, - pixman_region16_t * region) +_cairo_quartz_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_quartz_surface_t *surface = abstract_surface; + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; - if (surface->clip_region) - pixman_region_destroy (surface->clip_region); + ND((stderr, "%p _cairo_quartz_surface_intersect_clip_path path: %p\n", surface, path)); - if (region) { - surface->clip_region = pixman_region_create (); - pixman_region_copy (surface->clip_region, region); - } else - surface->clip_region = NULL; + 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 quartz 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_quartz_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; } -static cairo_int_status_t -_cairo_quartz_surface_get_extents (void *abstract_surface, - cairo_rectangle_int16_t *rectangle) -{ - cairo_quartz_surface_t *surface = abstract_surface; - - *rectangle = surface->extents; - - return CAIRO_STATUS_SUCCESS; -} +// XXXtodo implement show_page; need to figure out how to handle begin/end static const struct _cairo_surface_backend cairo_quartz_surface_backend = { CAIRO_SURFACE_TYPE_QUARTZ, - NULL, /* create_similar */ + _cairo_quartz_surface_create_similar, _cairo_quartz_surface_finish, _cairo_quartz_surface_acquire_source_image, NULL, /* release_source_image */ _cairo_quartz_surface_acquire_dest_image, _cairo_quartz_surface_release_dest_image, - NULL, /* clone_similar */ + _cairo_quartz_surface_clone_similar, NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ NULL, /* copy_page */ NULL, /* show_page */ - _cairo_quartz_surface_set_clip_region, - NULL, /* intersect_clip_path */ + NULL, /* set_clip_region */ + _cairo_quartz_surface_intersect_clip_path, _cairo_quartz_surface_get_extents, - NULL /* old_show_glyphs */ + NULL, /* old_show_glyphs */ + NULL, /* get_font_options */ + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + NULL, /* scaled_font_fini */ + NULL, /* scaled_glyph_fini */ + + _cairo_quartz_surface_paint, + _cairo_quartz_surface_mask, + _cairo_quartz_surface_stroke, + _cairo_quartz_surface_fill, +#if CAIRO_HAS_ATSUI_FONT + _cairo_quartz_surface_show_glyphs, +#else + NULL, /* surface_show_glyphs */ +#endif /* CAIRO_HAS_ATSUI_FONT */ + + NULL, /* snapshot */ }; -cairo_surface_t *cairo_quartz_surface_create(CGContextRef context, - int width, - int height, - cairo_bool_t y_grows_down) +static cairo_quartz_surface_t * +_cairo_quartz_surface_create_internal (CGContextRef cgContext, + cairo_content_t content, + unsigned int width, + unsigned int height) { cairo_quartz_surface_t *surface; - CGRect clip_box; + /* Init the base surface */ surface = malloc(sizeof(cairo_quartz_surface_t)); if (surface == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); - return (cairo_surface_t*) &_cairo_surface_nil; + return NULL; } - /* XXX: The content value here might be totally wrong. */ + memset(surface, 0, sizeof(cairo_quartz_surface_t)); + _cairo_surface_init(&surface->base, &cairo_quartz_surface_backend, - CAIRO_CONTENT_COLOR_ALPHA); + content); - surface->context = context; - surface->clip_region = NULL; - surface->y_grows_down = y_grows_down; + /* Save our extents */ + surface->extents.x = surface->extents.y = 0; + surface->extents.width = width; + surface->extents.height = height; - clip_box = CGContextGetClipBoundingBox (context); - surface->extents.x = clip_box.origin.x; - surface->extents.y = clip_box.origin.y; - surface->extents.width = clip_box.size.width; - surface->extents.height = clip_box.size.height; + /* 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); - return (cairo_surface_t *) surface; + surface->cgContext = cgContext; + surface->cgContextBaseCTM = CGContextGetCTM (cgContext); + + surface->imageData = NULL; + + return surface; } + +/** + * cairo_quartz_surface_create_for_cg_context + * @cgContext: the existing CGContext for which to create the surface + * @width: width of the surface, in pixels + * @height: height of the surface, in pixels + * + * Creates a Quartz surface that wraps the given CGContext. The + * CGContext is assumed to be in the QuickDraw coordinate space (that + * is, with the origin at the upper left and the Y axis increasing + * downward.) If the CGContext is in the Quartz coordinate space (with + * the origin at the bottom left), then it should be flipped before + * this function is called: + * + * + * GContextTranslateCTM (cgContext, 0.0, height); + * CGContextScaleCTM (cgContext, 1.0, -1.0); + * + * + * A very small number of Cairo operations cannot be translated to + * Quartz operations; those operations will fail on this surface. + * If all Cairo operations are required to succeed, consider rendering + * to a surface created by cairo_quartz_surface_create() and then copying + * the result to the CGContext. + * + * Return value: the newly created Cairo surface. + * + * Since: 1.4 + **/ -int -_cairo_surface_is_quartz (cairo_surface_t *surface) +cairo_surface_t * +cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext, + unsigned int width, + unsigned int height) { - return surface->backend == &cairo_quartz_surface_backend; + cairo_quartz_surface_t *surf; + + CGContextRetain (cgContext); + + surf = _cairo_quartz_surface_create_internal (cgContext, CAIRO_CONTENT_COLOR_ALPHA, + width, height); + if (!surf) { + CGContextRelease (cgContext); + // create_internal will have set an error + return (cairo_surface_t*) &_cairo_surface_nil; + } + + return (cairo_surface_t *) surf; } + +/** + * cairo_quartz_surface_create + * @format: format of pixels in the surface to create + * @width: width of the surface, in pixels + * @height: height of the surface, in pixels + * + * Creates a Quartz surface backed by a CGBitmap. The surface is + * created using the Device RGB (or Device Gray, for A8) color space. + * All Cairo operations, including those that require software + * rendering, will succeed on this surface. + * + * Return value: the newly created surface. + * + * Since: 1.4 + **/ +cairo_surface_t * +cairo_quartz_surface_create (cairo_format_t format, + unsigned int width, + unsigned int height) +{ + cairo_quartz_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; + } + + /* flip the Y axis */ + CGContextTranslateCTM (cgc, 0.0, height); + CGContextScaleCTM (cgc, 1.0, -1.0); + + surf = _cairo_quartz_surface_create_internal (cgc, _cairo_content_from_format (format), + width, height); + 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; +} + +/** + * cairo_quartz_surface_get_cg_context + * @surface: the Cairo Quartz surface + * + * Returns the CGContextRef that the given Quartz surface is backed + * by. + * + * Return value: the CGContextRef for the given surface. + * + * Since: 1.4 + **/ +CGContextRef +cairo_quartz_surface_get_cg_context (cairo_surface_t *surface) +{ + cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t*)surface; + + if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_QUARTZ) + return NULL; + + return quartz->cgContext; +} + + +/* Debug stuff */ + +#ifdef QUARTZ_DEBUG + +#include + +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 +quartz_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 +quartz_surface_to_png (cairo_quartz_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_QUARTZ) { + fprintf (stderr, "** quartz_surface_to_png: surface %p isn't quartz!\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, "quartz surface at %p is not a bitmap context!\n", nq); + return; + } + + ExportCGImageToPNGFile(imgref, dest); + + CGImageRelease(imgref); +#endif +} + diff --git a/gfx/cairo/cairo/src/cairo-quartz.h b/gfx/cairo/cairo/src/cairo-quartz.h index 286efe8b87c..5d78d391393 100644 --- a/gfx/cairo/cairo/src/cairo-quartz.h +++ b/gfx/cairo/cairo/src/cairo-quartz.h @@ -1,6 +1,6 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright 2006, 2007 Mozilla Corporation * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -27,11 +27,10 @@ * * The Original Code is the cairo graphics library. * - * The Initial Developer of the Original Code is University of Southern - * California. + * The Initial Developer of the Original Code is Mozilla Corporation. * * Contributor(s): - * Carl D. Worth + * Vladimir Vukicevic */ #ifndef CAIRO_QUARTZ_H @@ -46,10 +45,17 @@ CAIRO_BEGIN_DECLS cairo_public cairo_surface_t * -cairo_quartz_surface_create (CGContextRef context, - int width, - int height, - cairo_bool_t y_grows_down); +cairo_quartz_surface_create (cairo_format_t format, + unsigned int width, + unsigned int height); + +cairo_public cairo_surface_t * +cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext, + unsigned int width, + unsigned int height); + +cairo_public CGContextRef +cairo_quartz_surface_get_cg_context (cairo_surface_t *surface); CAIRO_END_DECLS diff --git a/gfx/cairo/cairo/src/cairo-rename.h b/gfx/cairo/cairo/src/cairo-rename.h index 245659432d1..935f22df6d2 100644 --- a/gfx/cairo/cairo/src/cairo-rename.h +++ b/gfx/cairo/cairo/src/cairo-rename.h @@ -35,6 +35,7 @@ #define cairo_fill_preserve _moz_cairo_fill_preserve #define cairo_font_extents _moz_cairo_font_extents #define cairo_font_face_destroy _moz_cairo_font_face_destroy +#define cairo_font_face_get_reference_count _moz_cairo_font_face_get_reference_count #define cairo_font_face_get_type _moz_cairo_font_face_get_type #define cairo_font_face_get_user_data _moz_cairo_font_face_get_user_data #define cairo_font_face_reference _moz_cairo_font_face_reference @@ -75,9 +76,12 @@ #define cairo_get_matrix _moz_cairo_get_matrix #define cairo_get_miter_limit _moz_cairo_get_miter_limit #define cairo_get_operator _moz_cairo_get_operator +#define cairo_get_reference_count _moz_cairo_get_reference_count +#define cairo_get_scaled_font _moz_cairo_get_scaled_font #define cairo_get_source _moz_cairo_get_source #define cairo_get_target _moz_cairo_get_target #define cairo_get_tolerance _moz_cairo_get_tolerance +#define cairo_get_user_data _moz_cairo_get_user_data #define cairo_glitz_surface_create _moz_cairo_glitz_surface_create #define cairo_glyph_extents _moz_cairo_glyph_extents #define cairo_glyph_path _moz_cairo_glyph_path @@ -105,17 +109,12 @@ #define cairo_matrix_multiply _moz_cairo_matrix_multiply #define cairo_matrix_rotate _moz_cairo_matrix_rotate #define cairo_matrix_scale _moz_cairo_matrix_scale -#define cairo_matrix_transform_bounding_box _moz_cairo_matrix_transform_bounding_box #define cairo_matrix_transform_distance _moz_cairo_matrix_transform_distance #define cairo_matrix_transform_point _moz_cairo_matrix_transform_point #define cairo_matrix_translate _moz_cairo_matrix_translate #define cairo_move_to _moz_cairo_move_to #define cairo_new_path _moz_cairo_new_path #define cairo_new_sub_path _moz_cairo_new_sub_path -#define cairo_nquartz_surface_create _moz_cairo_nquartz_surface_create -#define cairo_nquartz_surface_create_for_agl_context _moz_cairo_nquartz_surface_create_for_agl_context -#define cairo_nquartz_surface_create_for_cg_context _moz_cairo_nquartz_surface_create_for_cg_context -#define cairo_nquartz_surface_get_cg_context _moz_cairo_nquartz_surface_get_cg_context #define cairo_os2_fini _moz_cairo_os2_fini #define cairo_os2_init _moz_cairo_os2_init #define cairo_os2_surface_create _moz_cairo_os2_surface_create @@ -142,13 +141,16 @@ #define cairo_pattern_get_linear_points _moz_cairo_pattern_get_linear_points #define cairo_pattern_get_matrix _moz_cairo_pattern_get_matrix #define cairo_pattern_get_radial_circles _moz_cairo_pattern_get_radial_circles +#define cairo_pattern_get_reference_count _moz_cairo_pattern_get_reference_count #define cairo_pattern_get_rgba _moz_cairo_pattern_get_rgba #define cairo_pattern_get_surface _moz_cairo_pattern_get_surface #define cairo_pattern_get_type _moz_cairo_pattern_get_type +#define cairo_pattern_get_user_data _moz_cairo_pattern_get_user_data #define cairo_pattern_reference _moz_cairo_pattern_reference #define cairo_pattern_set_extend _moz_cairo_pattern_set_extend #define cairo_pattern_set_filter _moz_cairo_pattern_set_filter #define cairo_pattern_set_matrix _moz_cairo_pattern_set_matrix +#define cairo_pattern_set_user_data _moz_cairo_pattern_set_user_data #define cairo_pattern_status _moz_cairo_pattern_status #define cairo_pdf_surface_create _moz_cairo_pdf_surface_create #define cairo_pdf_surface_create_for_stream _moz_cairo_pdf_surface_create_for_stream @@ -164,6 +166,8 @@ #define cairo_push_group _moz_cairo_push_group #define cairo_push_group_with_content _moz_cairo_push_group_with_content #define cairo_quartz_surface_create _moz_cairo_quartz_surface_create +#define cairo_quartz_surface_create_for_cg_context _moz_cairo_quartz_surface_create_for_cg_context +#define cairo_quartz_surface_get_cg_context _moz_cairo_quartz_surface_get_cg_context #define cairo_rectangle _moz_cairo_rectangle #define cairo_rectangle_list_destroy _moz_cairo_rectangle_list_destroy #define cairo_reference _moz_cairo_reference @@ -182,9 +186,12 @@ #define cairo_scaled_font_get_font_face _moz_cairo_scaled_font_get_font_face #define cairo_scaled_font_get_font_matrix _moz_cairo_scaled_font_get_font_matrix #define cairo_scaled_font_get_font_options _moz_cairo_scaled_font_get_font_options +#define cairo_scaled_font_get_reference_count _moz_cairo_scaled_font_get_reference_count #define cairo_scaled_font_get_type _moz_cairo_scaled_font_get_type +#define cairo_scaled_font_get_user_data _moz_cairo_scaled_font_get_user_data #define cairo_scaled_font_glyph_extents _moz_cairo_scaled_font_glyph_extents #define cairo_scaled_font_reference _moz_cairo_scaled_font_reference +#define cairo_scaled_font_set_user_data _moz_cairo_scaled_font_set_user_data #define cairo_scaled_font_status _moz_cairo_scaled_font_status #define cairo_scaled_font_text_extents _moz_cairo_scaled_font_text_extents #define cairo_select_font_face _moz_cairo_select_font_face @@ -207,6 +214,7 @@ #define cairo_set_source_rgba _moz_cairo_set_source_rgba #define cairo_set_source_surface _moz_cairo_set_source_surface #define cairo_set_tolerance _moz_cairo_set_tolerance +#define cairo_set_user_data _moz_cairo_set_user_data #define cairo_show_glyphs _moz_cairo_show_glyphs #define cairo_show_page _moz_cairo_show_page #define cairo_show_text _moz_cairo_show_text @@ -226,7 +234,6 @@ #define cairo_surface_get_reference_count _moz_cairo_surface_get_reference_count #define cairo_surface_get_type _moz_cairo_surface_get_type #define cairo_surface_get_user_data _moz_cairo_surface_get_user_data -#define cairo_surface_is_nquartz _moz_cairo_surface_is_nquartz #define cairo_surface_mark_dirty _moz_cairo_surface_mark_dirty #define cairo_surface_mark_dirty_rectangle _moz_cairo_surface_mark_dirty_rectangle #define cairo_surface_reference _moz_cairo_surface_reference diff --git a/gfx/cairo/cairo/src/cairo-scaled-font-subsets-private.h b/gfx/cairo/cairo/src/cairo-scaled-font-subsets-private.h index 2c81fdc63fe..510434049ba 100644 --- a/gfx/cairo/cairo/src/cairo-scaled-font-subsets-private.h +++ b/gfx/cairo/cairo/src/cairo-scaled-font-subsets-private.h @@ -41,23 +41,17 @@ typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t; -typedef struct _cairo_scaled_font_subset { - cairo_scaled_font_t *scaled_font; - unsigned int font_id; - unsigned int subset_id; - - /* Index of glyphs array is subset_glyph_index. - * Value of glyphs array is scaled_font_glyph_index. - */ - unsigned long *glyphs; - unsigned int num_glyphs; -} cairo_scaled_font_subset_t; - /** * _cairo_scaled_font_subsets_create: - * @max_glyphs_per_subset: the maximum number of glyphs that should - * appear in any subset. A value of 0 indicates that there is no limit - * to the number of glyphs per subset. + * + * @max_glyphs_per_unscaled_subset: the maximum number of glyphs that + * should appear in any unscaled subset. A value of 0 indicates that + * no unscaled subset will be created. All glyphs will mapped to + * scaled subsets. + * + * @max_glyphs_per_scaled_subset: the maximum number of glyphs that + * should appear in any scaled subset. A value of 0 indicates that + * no scaled subset will be created. * * Create a new #cairo_scaled_font_subsets_t object which can be used * to create subsets of any number of cairo_scaled_font_t @@ -66,12 +60,16 @@ typedef struct _cairo_scaled_font_subset { * subsets with glyph indices packed into the range * [0 .. max_glyphs_per_subset). * + * @max_glyphs_per_unscaled_subset and @max_glyphs_per_scaled_subset + * cannot both be 0. + * * Return value: a pointer to the newly creates font subsets. The * caller owns this object and should call * _cairo_scaled_font_subsets_destroy() when done with it. **/ cairo_private cairo_scaled_font_subsets_t * -_cairo_scaled_font_subsets_create (int max_glyphs_per_subset); +_cairo_scaled_font_subsets_create (int max_glyphs_unscaled_per_subset, + int max_glyphs_scaled_per_subset); /** * _cairo_scaled_font_subsets_destroy: @@ -150,7 +148,7 @@ typedef void * @font_subset_callback: a function to be called for each font subset * @closure: closure data for the callback function * - * Iterate over each unique font subset as created by calls to + * Iterate over each unique scaled font subset as created by calls to * _cairo_scaled_font_subsets_map_glyph(). A subset is determined by * unique pairs of (font_id, subset_id) as returned by * _cairo_scaled_font_subsets_map_glyph(). @@ -175,9 +173,44 @@ typedef void * CAIRO_STATUS_NO_MEMORY. **/ cairo_private cairo_status_t -_cairo_scaled_font_subsets_foreach (cairo_scaled_font_subsets_t *font_subsets, - cairo_scaled_font_subset_callback_func_t font_subset_callback, - void *closure); +_cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *font_subsets, + cairo_scaled_font_subset_callback_func_t font_subset_callback, + void *closure); + +/** + * _cairo_scaled_font_subsets_foreach_unscaled: + * @font_subsets: a #cairo_scaled_font_subsets_t + * @font_subset_callback: a function to be called for each font subset + * @closure: closure data for the callback function + * + * Iterate over each unique unscaled font subset as created by calls to + * _cairo_scaled_font_subsets_map_glyph(). A subset is determined by + * unique pairs of (font_id, subset_id) as returned by + * _cairo_scaled_font_subsets_map_glyph(). + * + * For each subset, @font_subset_callback will be called and will be + * provided with both a #cairo_scaled_font_subset_t object containing + * all the glyphs in the subset as well as the value of @closure. + * + * The #cairo_scaled_font_subset_t object contains the scaled_font, + * the font_id, and the subset_id corresponding to all glyphs + * belonging to the subset. In addition, it contains an array providing + * a mapping between subset glyph indices and the original scaled font + * glyph indices. + * + * The index of the array corresponds to subset_glyph_index values + * returned by _cairo_scaled_font_subsets_map_glyph() while the + * values of the array correspond to the scaled_font_glyph_index + * values passed as input to the same function. + * + * Return value: CAIRO_STATUS_SUCCESS if successful, or a non-zero + * value indicating an error. Possible errors include + * CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets, + cairo_scaled_font_subset_callback_func_t font_subset_callback, + void *closure); typedef struct _cairo_cff_subset { char *base_font; @@ -222,9 +255,9 @@ _cairo_cff_subset_fini (cairo_cff_subset_t *cff_subset); typedef struct _cairo_truetype_subset { char *base_font; - int *widths; - long x_min, y_min, x_max, y_max; - long ascent, descent; + double *widths; + double x_min, y_min, x_max, y_max; + double ascent, descent; char *data; unsigned long data_length; unsigned long *string_offsets; @@ -361,4 +394,21 @@ _cairo_type1_fallback_init_hex (cairo_type1_subset_t *type_subset, cairo_private void _cairo_type1_fallback_fini (cairo_type1_subset_t *subset); +/** + * _cairo_truetype_create_glyph_to_unicode_map: + * @font_subset: the #cairo_scaled_font_subset_t to initialize from + * + * If possible (depending on the format of the underlying + * cairo_scaled_font_t and the font backend in use) assign + * the unicode character of each glyph in font_subset to + * fontsubset->to_unicode. + * + * Return value: CAIRO_STATUS_SUCCESS if successful, + * CAIRO_INT_STATUS_UNSUPPORTED if the unicode encoding of + * the glyphs is not available. Possible errors include + * CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_int_status_t +_cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t *font_subset); + #endif /* CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-scaled-font-subsets.c b/gfx/cairo/cairo/src/cairo-scaled-font-subsets.c index 0c428e7c3af..d98cba2f862 100644 --- a/gfx/cairo/cairo/src/cairo-scaled-font-subsets.c +++ b/gfx/cairo/cairo/src/cairo-scaled-font-subsets.c @@ -43,16 +43,21 @@ #include "cairo-scaled-font-subsets-private.h" struct _cairo_scaled_font_subsets { - int max_glyphs_per_subset_limit; - int max_glyphs_per_subset_used; - int num_sub_fonts; + int max_glyphs_per_unscaled_subset_limit; + int max_glyphs_per_unscaled_subset_used; + cairo_hash_table_t *unscaled_sub_fonts; - cairo_hash_table_t *sub_fonts; + int max_glyphs_per_scaled_subset_limit; + int max_glyphs_per_scaled_subset_used; + cairo_hash_table_t *scaled_sub_fonts; + + int num_sub_fonts; }; typedef struct _cairo_sub_font { cairo_hash_entry_t base; + cairo_bool_t is_scaled; cairo_scaled_font_subsets_t *parent; cairo_scaled_font_t *scaled_font; unsigned int font_id; @@ -163,22 +168,34 @@ _cairo_sub_fonts_equal (const void *key_a, const void *key_b) const cairo_sub_font_t *sub_font_a = key_a; const cairo_sub_font_t *sub_font_b = key_b; - return sub_font_a->scaled_font == sub_font_b->scaled_font; + if (sub_font_a->is_scaled) + return sub_font_a->scaled_font == sub_font_b->scaled_font; + else + return sub_font_a->scaled_font->font_face == sub_font_b->scaled_font->font_face; } static void _cairo_sub_font_init_key (cairo_sub_font_t *sub_font, cairo_scaled_font_t *scaled_font) { - sub_font->base.hash = (unsigned long) scaled_font; - sub_font->scaled_font = scaled_font; + if (sub_font->is_scaled) + { + sub_font->base.hash = (unsigned long) scaled_font; + sub_font->scaled_font = scaled_font; + } + else + { + sub_font->base.hash = (unsigned long) scaled_font->font_face; + sub_font->scaled_font = scaled_font; + } } static cairo_sub_font_t * _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent, cairo_scaled_font_t *scaled_font, unsigned int font_id, - int max_glyphs_per_subset) + int max_glyphs_per_subset, + cairo_bool_t is_scaled) { cairo_sub_font_t *sub_font; @@ -186,6 +203,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent, if (sub_font == NULL) return NULL; + sub_font->is_scaled = is_scaled; _cairo_sub_font_init_key (sub_font, scaled_font); sub_font->parent = parent; @@ -226,6 +244,27 @@ _cairo_sub_font_pluck (void *entry, void *closure) _cairo_sub_font_destroy (sub_font); } +static cairo_status_t +_cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font, + unsigned long scaled_font_glyph_index, + unsigned int *subset_id, + unsigned int *subset_glyph_index) +{ + cairo_sub_font_glyph_t key, *sub_font_glyph; + + _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); + if (_cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base, + (cairo_hash_entry_t **) &sub_font_glyph)) + { + *subset_id = sub_font_glyph->subset_id; + *subset_glyph_index = sub_font_glyph->subset_glyph_index; + + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_STATUS_NULL_POINTER; +} + static cairo_status_t _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, unsigned long scaled_font_glyph_index, @@ -239,8 +278,7 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, if (! _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base, (cairo_hash_entry_t **) &sub_font_glyph)) { - if (sub_font->max_glyphs_per_subset && - sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset) + if (sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset) { sub_font->current_subset++; sub_font->num_glyphs_in_current_subset = 0; @@ -252,8 +290,16 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, if (sub_font_glyph == NULL) return CAIRO_STATUS_NO_MEMORY; - if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_subset_used) - sub_font->parent->max_glyphs_per_subset_used = sub_font->num_glyphs_in_current_subset; + if (sub_font->is_scaled) + { + if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_scaled_subset_used) + sub_font->parent->max_glyphs_per_scaled_subset_used = sub_font->num_glyphs_in_current_subset; + } + else + { + if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_unscaled_subset_used) + sub_font->parent->max_glyphs_per_unscaled_subset_used = sub_font->num_glyphs_in_current_subset; + } status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base); if (status) @@ -273,6 +319,7 @@ _cairo_sub_font_collect (void *entry, void *closure) cairo_sub_font_collection_t *collection = closure; cairo_scaled_font_subset_t subset; int i; + unsigned int j; for (i = 0; i <= sub_font->current_subset; i++) { collection->subset_id = i; @@ -291,14 +338,26 @@ _cairo_sub_font_collect (void *entry, void *closure) subset.subset_id = i; subset.glyphs = collection->glyphs; subset.num_glyphs = collection->num_glyphs; - - (collection->font_subset_callback) (&subset, + /* No need to check for out of memory here. If to_unicode is NULL, the PDF + * surface does not emit an ToUnicode stream */ + subset.to_unicode = malloc (collection->num_glyphs*sizeof(unsigned long)); + if (subset.to_unicode) { + for (j = 0; j < collection->num_glyphs; j++) { + /* default unicode character required when mapping fails */ + subset.to_unicode[j] = 0xfffd; + } + } + (collection->font_subset_callback) (&subset, collection->font_subset_callback_closure); + + if (subset.to_unicode != NULL) + free (subset.to_unicode); } } cairo_scaled_font_subsets_t * -_cairo_scaled_font_subsets_create (int max_glyphs_per_subset) +_cairo_scaled_font_subsets_create (int max_glyphs_per_unscaled_subset, + int max_glyphs_per_scaled_subset) { cairo_scaled_font_subsets_t *subsets; @@ -306,12 +365,23 @@ _cairo_scaled_font_subsets_create (int max_glyphs_per_subset) if (subsets == NULL) return NULL; - subsets->max_glyphs_per_subset_limit = max_glyphs_per_subset; - subsets->max_glyphs_per_subset_used = 0; + subsets->max_glyphs_per_unscaled_subset_limit = max_glyphs_per_unscaled_subset; + subsets->max_glyphs_per_unscaled_subset_used = 0; + + subsets->max_glyphs_per_scaled_subset_limit = max_glyphs_per_scaled_subset; + subsets->max_glyphs_per_scaled_subset_used = 0; + subsets->num_sub_fonts = 0; - subsets->sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal); - if (! subsets->sub_fonts) { + subsets->unscaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal); + if (! subsets->unscaled_sub_fonts) { + free (subsets); + return NULL; + } + + subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal); + if (! subsets->scaled_sub_fonts) { + free (subsets->unscaled_sub_fonts); free (subsets); return NULL; } @@ -322,8 +392,11 @@ _cairo_scaled_font_subsets_create (int max_glyphs_per_subset) void _cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets) { - _cairo_hash_table_foreach (subsets->sub_fonts, _cairo_sub_font_pluck, subsets->sub_fonts); - _cairo_hash_table_destroy (subsets->sub_fonts); + _cairo_hash_table_foreach (subsets->scaled_sub_fonts, _cairo_sub_font_pluck, subsets->scaled_sub_fonts); + _cairo_hash_table_destroy (subsets->scaled_sub_fonts); + + _cairo_hash_table_foreach (subsets->unscaled_sub_fonts, _cairo_sub_font_pluck, subsets->unscaled_sub_fonts); + _cairo_hash_table_destroy (subsets->unscaled_sub_fonts); free (subsets); } @@ -336,38 +409,106 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, unsigned int *subset_glyph_index) { cairo_sub_font_t key, *sub_font; + cairo_scaled_glyph_t *scaled_glyph; cairo_status_t status; - _cairo_sub_font_init_key (&key, scaled_font); - if (! _cairo_hash_table_lookup (subsets->sub_fonts, &key.base, - (cairo_hash_entry_t **) &sub_font)) - { - sub_font = _cairo_sub_font_create (subsets, scaled_font, - subsets->num_sub_fonts++, - subsets->max_glyphs_per_subset_limit); - if (sub_font == NULL) - return CAIRO_STATUS_NO_MEMORY; - - status = _cairo_hash_table_insert (subsets->sub_fonts, - &sub_font->base); - if (status) - return status; + /* Lookup glyph in unscaled subsets */ + if (subsets->max_glyphs_per_unscaled_subset_limit > 0) { + key.is_scaled = FALSE; + _cairo_sub_font_init_key (&key, scaled_font); + if (_cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base, + (cairo_hash_entry_t **) &sub_font)) + { + status = _cairo_sub_font_lookup_glyph (sub_font, scaled_font_glyph_index, + subset_id, subset_glyph_index); + if (status == CAIRO_STATUS_SUCCESS) { + *font_id = sub_font->font_id; + return CAIRO_STATUS_SUCCESS; + } + } } + /* Lookup glyph in scaled subsets */ + if (subsets->max_glyphs_per_scaled_subset_limit > 0) { + key.is_scaled = TRUE; + _cairo_sub_font_init_key (&key, scaled_font); + if (_cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base, + (cairo_hash_entry_t **) &sub_font)) + { + status = _cairo_sub_font_lookup_glyph (sub_font, scaled_font_glyph_index, + subset_id, subset_glyph_index); + if (status == CAIRO_STATUS_SUCCESS) { + *font_id = sub_font->font_id; + return CAIRO_STATUS_SUCCESS; + } + } + } + + /* Glyph not found. Determine whether the glyph is outline or + * bitmap and add to the appropriate subset */ + status = _cairo_scaled_glyph_lookup (scaled_font, + scaled_font_glyph_index, + CAIRO_SCALED_GLYPH_INFO_PATH, + &scaled_glyph); + if (status == 0 && subsets->max_glyphs_per_unscaled_subset_limit > 0) { + /* Path available. Add to unscaled subset. */ + key.is_scaled = FALSE; + _cairo_sub_font_init_key (&key, scaled_font); + if (! _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base, + (cairo_hash_entry_t **) &sub_font)) + { + sub_font = _cairo_sub_font_create (subsets, scaled_font, + subsets->num_sub_fonts++, + subsets->max_glyphs_per_unscaled_subset_limit, + FALSE); + if (sub_font == NULL) + return CAIRO_STATUS_NO_MEMORY; + + status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts, + &sub_font->base); + if (status) + return status; + } + } else if (subsets->max_glyphs_per_scaled_subset_limit > 0) { + /* No path available. Add to scaled subset. */ + key.is_scaled = TRUE; + _cairo_sub_font_init_key (&key, scaled_font); + if (! _cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base, + (cairo_hash_entry_t **) &sub_font)) + { + sub_font = _cairo_sub_font_create (subsets, scaled_font, + subsets->num_sub_fonts++, + subsets->max_glyphs_per_scaled_subset_limit, + TRUE); + if (sub_font == NULL) + return CAIRO_STATUS_NO_MEMORY; + + status = _cairo_hash_table_insert (subsets->scaled_sub_fonts, + &sub_font->base); + if (status) + return status; + } + } else { + return CAIRO_INT_STATUS_UNSUPPORTED; + } *font_id = sub_font->font_id; return _cairo_sub_font_map_glyph (sub_font, scaled_font_glyph_index, - subset_id, subset_glyph_index); + subset_id, subset_glyph_index); } -cairo_private cairo_status_t -_cairo_scaled_font_subsets_foreach (cairo_scaled_font_subsets_t *font_subsets, - cairo_scaled_font_subset_callback_func_t font_subset_callback, - void *closure) +static cairo_status_t +_cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t *font_subsets, + cairo_scaled_font_subset_callback_func_t font_subset_callback, + void *closure, + cairo_bool_t is_scaled) { cairo_sub_font_collection_t collection; - collection.glyphs_size = font_subsets->max_glyphs_per_subset_used; + if (is_scaled) + collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used; + else + collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used; collection.glyphs = malloc (collection.glyphs_size * sizeof(unsigned long)); if (collection.glyphs == NULL) return CAIRO_STATUS_NO_MEMORY; @@ -375,10 +516,36 @@ _cairo_scaled_font_subsets_foreach (cairo_scaled_font_subsets_t *font_subsets, collection.font_subset_callback = font_subset_callback; collection.font_subset_callback_closure = closure; - _cairo_hash_table_foreach (font_subsets->sub_fonts, - _cairo_sub_font_collect, &collection); + if (is_scaled) + _cairo_hash_table_foreach (font_subsets->scaled_sub_fonts, + _cairo_sub_font_collect, &collection); + else + _cairo_hash_table_foreach (font_subsets->unscaled_sub_fonts, + _cairo_sub_font_collect, &collection); free (collection.glyphs); return CAIRO_STATUS_SUCCESS; } + +cairo_private cairo_status_t +_cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *font_subsets, + cairo_scaled_font_subset_callback_func_t font_subset_callback, + void *closure) +{ + return _cairo_scaled_font_subsets_foreach_internal (font_subsets, + font_subset_callback, + closure, + TRUE); +} + +cairo_private cairo_status_t +_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets, + cairo_scaled_font_subset_callback_func_t font_subset_callback, + void *closure) +{ + return _cairo_scaled_font_subsets_foreach_internal (font_subsets, + font_subset_callback, + closure, + FALSE); +} diff --git a/gfx/cairo/cairo/src/cairo-scaled-font.c b/gfx/cairo/cairo/src/cairo-scaled-font.c index 6da6106a32a..6efde8002e6 100644 --- a/gfx/cairo/cairo/src/cairo-scaled-font.c +++ b/gfx/cairo/cairo/src/cairo-scaled-font.c @@ -1,5 +1,5 @@ -/* $Id: cairo-scaled-font.c,v 1.15 2007/04/03 19:21:53 vladimir%pobox.com Exp $ - * +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* * Copyright © 2005 Keith Packard * * This library is free software; you can redistribute it and/or @@ -71,10 +71,11 @@ _cairo_scaled_glyph_destroy (void *abstract_glyph) free (scaled_glyph); } -static const cairo_scaled_font_t _cairo_scaled_font_nil = { +const cairo_scaled_font_t _cairo_scaled_font_nil = { { 0 }, /* hash_entry */ CAIRO_STATUS_NO_MEMORY, /* status */ CAIRO_REF_COUNT_INVALID, /* ref_count */ + { 0, 0, 0, NULL }, /* user_data */ NULL, /* font_face */ { 1., 0., 0., 1., 0, 0}, /* font_matrix */ { 1., 0., 0., 1., 0, 0}, /* ctm */ @@ -84,6 +85,7 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = { CAIRO_HINT_METRICS_DEFAULT} , { 1., 0., 0., 1., 0, 0}, /* scale */ { 0., 0., 0., 0., 0. }, /* extents */ + CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */ NULL, /* glyphs */ NULL, /* surface_backend */ NULL, /* surface_private */ @@ -183,7 +185,7 @@ typedef struct _cairo_scaled_font_map { static cairo_scaled_font_map_t *cairo_scaled_font_map = NULL; -CAIRO_MUTEX_DECLARE (cairo_scaled_font_map_mutex); +CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex); static int _cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_key_b); @@ -191,7 +193,7 @@ _cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_ static cairo_scaled_font_map_t * _cairo_scaled_font_map_lock (void) { - CAIRO_MUTEX_LOCK (cairo_scaled_font_map_mutex); + CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex); if (cairo_scaled_font_map == NULL) { cairo_scaled_font_map = malloc (sizeof (cairo_scaled_font_map_t)); @@ -212,14 +214,14 @@ _cairo_scaled_font_map_lock (void) CLEANUP_SCALED_FONT_MAP: free (cairo_scaled_font_map); CLEANUP_MUTEX_LOCK: - CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex); + CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); return NULL; } static void _cairo_scaled_font_map_unlock (void) { - CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex); + CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); } void @@ -229,7 +231,7 @@ _cairo_scaled_font_map_destroy (void) cairo_scaled_font_map_t *font_map; cairo_scaled_font_t *scaled_font; - CAIRO_MUTEX_LOCK (cairo_scaled_font_map_mutex); + CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex); font_map = cairo_scaled_font_map; if (font_map == NULL) { @@ -254,7 +256,7 @@ _cairo_scaled_font_map_destroy (void) cairo_scaled_font_map = NULL; CLEANUP_MUTEX_LOCK: - CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex); + CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); } /* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/) @@ -352,6 +354,8 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, { scaled_font->ref_count = 1; + _cairo_user_data_array_init (&scaled_font->user_data); + _cairo_scaled_font_init_key (scaled_font, font_face, font_matrix, ctm, options); @@ -361,6 +365,7 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, &scaled_font->font_matrix, &scaled_font->ctm); + CAIRO_MUTEX_INIT (&scaled_font->mutex); scaled_font->glyphs = _cairo_cache_create (_cairo_scaled_glyph_keys_equal, _cairo_scaled_glyph_destroy, max_glyphs_cached_per_font); @@ -385,6 +390,15 @@ _cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font) _cairo_cache_thaw (scaled_font->glyphs); } +void +_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font) +{ + _cairo_cache_destroy (scaled_font->glyphs); + scaled_font->glyphs = _cairo_cache_create (_cairo_scaled_glyph_keys_equal, + _cairo_scaled_glyph_destroy, + max_glyphs_cached_per_font); +} + void _cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font, cairo_font_extents_t *fs_metrics) @@ -416,12 +430,15 @@ _cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font) if (scaled_font->glyphs != NULL) _cairo_cache_destroy (scaled_font->glyphs); + CAIRO_MUTEX_FINI (&scaled_font->mutex); + if (scaled_font->surface_backend != NULL && scaled_font->surface_backend->scaled_font_fini != NULL) scaled_font->surface_backend->scaled_font_fini (scaled_font); scaled_font->backend->fini (scaled_font); + _cairo_user_data_array_fini (&scaled_font->user_data); } /** @@ -459,7 +476,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, font_map = _cairo_scaled_font_map_lock (); if (font_map == NULL) - goto UNWIND; + return NULL; _cairo_scaled_font_init_key (&key, font_face, font_matrix, ctm, options); @@ -467,70 +484,6 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, /* Return existing scaled_font if it exists in the hash table. */ if (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry, (cairo_hash_entry_t**) &scaled_font)) - { - _cairo_scaled_font_map_unlock (); - return cairo_scaled_font_reference (scaled_font); - } - - /* Otherwise create it and insert it into the hash table. */ - status = font_face->backend->scaled_font_create (font_face, font_matrix, - ctm, options, &scaled_font); - if (status) - goto UNWIND_FONT_MAP_LOCK; - - status = _cairo_hash_table_insert (font_map->hash_table, - &scaled_font->hash_entry); - if (status) - goto UNWIND_SCALED_FONT_CREATE; - - _cairo_scaled_font_map_unlock (); - - return scaled_font; - -UNWIND_SCALED_FONT_CREATE: - /* We can't call _cairo_scaled_font_destroy here since it expects - * that the font has already been successfully inserted into the - * hash table. */ - _cairo_scaled_font_fini (scaled_font); - free (scaled_font); -UNWIND_FONT_MAP_LOCK: - _cairo_scaled_font_map_unlock (); -UNWIND: - return NULL; -} -slim_hidden_def (cairo_scaled_font_create); - -/** - * cairo_scaled_font_reference: - * @scaled_font: a #cairo_scaled_font_t, (may be NULL in which case - * this function does nothing) - * - * Increases the reference count on @scaled_font by one. This prevents - * @scaled_font from being destroyed until a matching call to - * cairo_scaled_font_destroy() is made. - * - * Returns: the referenced #cairo_scaled_font_t - **/ -cairo_scaled_font_t * -cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font) -{ - cairo_scaled_font_map_t *font_map; - - if (scaled_font == NULL) - return NULL; - - if (scaled_font->ref_count == CAIRO_REF_COUNT_INVALID) - return scaled_font; - - /* We would normally assert (scaled_font->ref_count > 0) here, but - * we are using ref_count == 0 as a legitimate case for the - * holdovers array. See below. */ - - /* cairo_scaled_font_t objects are cached and shared between - * threads. This works because these objects are immutable. Except - * that the reference count is mutable, so we have to do locking - * around any modification of the reference count. */ - font_map = _cairo_scaled_font_map_lock (); { /* If the original reference count is 0, then this font must have * been found in font_map->holdovers, (which means this caching is @@ -550,8 +503,64 @@ cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font) (font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*)); } + /* We increment the reference count manually here, (rather + * than calling into cairo_scaled_font_reference), since we + * must modify the reference count while our lock is still + * held. */ scaled_font->ref_count++; + _cairo_scaled_font_map_unlock (); + } else { + /* Otherwise create it and insert it into the hash table. */ + status = font_face->backend->scaled_font_create (font_face, font_matrix, + ctm, options, &scaled_font); + if (status) { + _cairo_scaled_font_map_unlock (); + return NULL; + } + status = _cairo_hash_table_insert (font_map->hash_table, + &scaled_font->hash_entry); + _cairo_scaled_font_map_unlock (); + + if (status) { + /* We can't call _cairo_scaled_font_destroy here since it expects + * that the font has already been successfully inserted into the + * hash table. */ + _cairo_scaled_font_fini (scaled_font); + free (scaled_font); + return NULL; + } + } + + return scaled_font; +} +slim_hidden_def (cairo_scaled_font_create); + +/** + * cairo_scaled_font_reference: + * @scaled_font: a #cairo_scaled_font_t, (may be NULL in which case + * this function does nothing) + * + * Increases the reference count on @scaled_font by one. This prevents + * @scaled_font from being destroyed until a matching call to + * cairo_scaled_font_destroy() is made. + * + * The number of references to a #cairo_scaled_font_t can be get using + * cairo_scaled_font_get_reference_count(). + * + * Returns: the referenced #cairo_scaled_font_t + **/ +cairo_scaled_font_t * +cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font) +{ + if (scaled_font == NULL || scaled_font->ref_count == CAIRO_REF_COUNT_INVALID) + return scaled_font; + + _cairo_scaled_font_map_lock (); + { + assert (scaled_font->ref_count > 0); + + scaled_font->ref_count++; } _cairo_scaled_font_map_unlock (); @@ -571,17 +580,11 @@ void cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font) { cairo_scaled_font_map_t *font_map; + cairo_scaled_font_t *lru = NULL; - if (scaled_font == NULL) + if (scaled_font == NULL || scaled_font->ref_count == CAIRO_REF_COUNT_INVALID) return; - if (scaled_font->ref_count == CAIRO_REF_COUNT_INVALID) - return; - - /* cairo_scaled_font_t objects are cached and shared between - * threads. This works because these objects are immutable. Except - * that the reference count is mutable, so we have to do locking - * around any modification of the reference count. */ font_map = _cairo_scaled_font_map_lock (); { assert (font_map != NULL); @@ -595,17 +598,13 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font) * soon. To make room for it, we do actually destroy the * least-recently-used holdover. */ - if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS) { - cairo_scaled_font_t *lru; - + if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS) + { lru = font_map->holdovers[0]; assert (lru->ref_count == 0); _cairo_hash_table_remove (font_map->hash_table, &lru->hash_entry); - _cairo_scaled_font_fini (lru); - free (lru); - font_map->num_holdovers--; memmove (&font_map->holdovers[0], &font_map->holdovers[1], @@ -617,9 +616,93 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font) } } _cairo_scaled_font_map_unlock (); + + /* If we pulled an item from the holdovers array, (while the font + * map lock was held, of course), then there is no way that anyone + * else could have acquired a reference to it. So we can now + * safely call fini on it without any lock held. This is desirable + * as we never want to call into any backend function with a lock + * held. */ + if (lru) { + _cairo_scaled_font_fini (lru); + free (lru); + } } slim_hidden_def (cairo_scaled_font_destroy); +/** + * cairo_scaled_font_get_reference_count: + * @scaled_font: a #cairo_scaled_font_t + * + * Returns the current reference count of @scaled_font. + * + * Return value: the current reference count of @scaled_font. If the + * object is a nil object, 0 will be returned. + * + * Since: 1.4 + **/ +unsigned int +cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font) +{ + if (scaled_font == NULL || scaled_font->ref_count == CAIRO_REF_COUNT_INVALID) + return 0; + + return scaled_font->ref_count; +} + +/** + * cairo_scaled_font_get_user_data: + * @scaled_font: a #cairo_scaled_font_t + * @key: the address of the #cairo_user_data_key_t the user data was + * attached to + * + * Return user data previously attached to @scaled_font using the + * specified key. If no user data has been attached with the given + * key this function returns %NULL. + * + * Return value: the user data previously attached or %NULL. + * + * Since: 1.4 + **/ +void * +cairo_scaled_font_get_user_data (cairo_scaled_font_t *scaled_font, + const cairo_user_data_key_t *key) +{ + return _cairo_user_data_array_get_data (&scaled_font->user_data, + key); +} + +/** + * cairo_scaled_font_set_user_data: + * @scaled_font: a #cairo_scaled_font_t + * @key: the address of a #cairo_user_data_key_t to attach the user data to + * @user_data: the user data to attach to the #cairo_scaled_font_t + * @destroy: a #cairo_destroy_func_t which will be called when the + * #cairo_t is destroyed or when new user data is attached using the + * same key. + * + * Attach user data to @scaled_font. To remove user data from a surface, + * call this function with the key that was used to set it and %NULL + * for @data. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a + * slot could not be allocated for the user data. + * + * Since: 1.4 + **/ +cairo_status_t +cairo_scaled_font_set_user_data (cairo_scaled_font_t *scaled_font, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy) +{ + if (scaled_font->ref_count == CAIRO_REF_COUNT_INVALID) + return CAIRO_STATUS_NO_MEMORY; + + return _cairo_user_data_array_set_data (&scaled_font->user_data, + key, user_data, destroy); +} + /* Public font API follows. */ /** @@ -711,6 +794,8 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font, if (scaled_font->status) return; + CAIRO_MUTEX_LOCK (scaled_font->mutex); + for (i = 0; i < num_glyphs; i++) { double left, top, right, bottom; @@ -720,7 +805,7 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font, &scaled_glyph); if (status) { _cairo_scaled_font_set_error (scaled_font, status); - return; + goto UNLOCK; } /* "Ink" extents should skip "invisible" glyphs */ @@ -774,6 +859,9 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font, extents->x_advance = 0.0; extents->y_advance = 0.0; } + + UNLOCK: + CAIRO_MUTEX_UNLOCK (scaled_font->mutex); } slim_hidden_def (cairo_scaled_font_glyph_extents); @@ -796,24 +884,26 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, return CAIRO_STATUS_SUCCESS; } + CAIRO_MUTEX_LOCK (scaled_font->mutex); + if (scaled_font->backend->text_to_glyphs) { status = scaled_font->backend->text_to_glyphs (scaled_font, x, y, utf8, glyphs, num_glyphs); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + goto DONE; } status = _cairo_utf8_to_ucs4 ((unsigned char*)utf8, -1, &ucs4, num_glyphs); if (status) - return status; + goto DONE; *glyphs = (cairo_glyph_t *) malloc ((*num_glyphs) * (sizeof (cairo_glyph_t))); if (*glyphs == NULL) { status = CAIRO_STATUS_NO_MEMORY; - goto FAIL; + goto DONE; } for (i = 0; i < *num_glyphs; i++) { @@ -829,15 +919,18 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, if (status) { free (*glyphs); *glyphs = NULL; - goto FAIL; + goto DONE; } x += scaled_glyph->metrics.x_advance; y += scaled_glyph->metrics.y_advance; } - FAIL: - free (ucs4); + DONE: + CAIRO_MUTEX_UNLOCK (scaled_font->mutex); + + if (ucs4) + free (ucs4); return status; } @@ -1338,6 +1431,8 @@ _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph, * If the desired info is not available, (for example, when trying to * get INFO_PATH with a bitmapped font), this function will return * CAIRO_INT_STATUS_UNSUPPORTED. + * + * NOTE: This function must be called with scaled_font->mutex held. **/ cairo_int_status_t _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, @@ -1353,8 +1448,6 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, if (scaled_font->status) return scaled_font->status; - CAIRO_MUTEX_LOCK (cairo_scaled_font_map_mutex); - key.hash = index; /* * Check cache for glyph @@ -1425,8 +1518,6 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, *scaled_glyph_ret = scaled_glyph; } - CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex); - return status; } diff --git a/gfx/cairo/cairo/src/cairo-skiplist-private.h b/gfx/cairo/cairo/src/cairo-skiplist-private.h index d776ad642d9..b152f4b15de 100644 --- a/gfx/cairo/cairo/src/cairo-skiplist-private.h +++ b/gfx/cairo/cairo/src/cairo-skiplist-private.h @@ -34,7 +34,7 @@ * a skip_elt_t, (which will be allocated with variable size). * * The caller must also pass the size of the structure to - * skip_list_init. + * _cairo_skip_list_init. */ typedef struct _skip_elt { int prev_index; @@ -45,16 +45,16 @@ typedef struct _skip_elt { #define SKIP_LIST_ELT_TO_DATA(type, elt) ((type *) ((char *) (elt) - (sizeof (type) - sizeof (skip_elt_t)))) typedef int -(*skip_list_compare_t) (void *list, void *a, void *b); +(*cairo_skip_list_compare_t) (void *list, void *a, void *b); typedef struct _skip_list { - skip_list_compare_t compare; + cairo_skip_list_compare_t compare; size_t elt_size; size_t data_size; skip_elt_t *chains[MAX_LEVEL]; skip_elt_t *freelists[MAX_LEVEL]; int max_level; -} skip_list_t; +} cairo_skip_list_t; /* Initialize a new skip list. The compare function accepts a pointer * to the list as well as pointers to two elements. The function must @@ -65,8 +65,8 @@ typedef struct _skip_list { * list elements must have as its final member a skip_elt_t */ cairo_private void -skip_list_init (skip_list_t *list, - skip_list_compare_t compare, +_cairo_skip_list_init (cairo_skip_list_t *list, + cairo_skip_list_compare_t compare, size_t elt_size); @@ -74,7 +74,7 @@ skip_list_init (skip_list_t *list, * in it. (XXX: currently this simply deletes all elements.) */ cairo_private void -skip_list_fini (skip_list_t *list); +_cairo_skip_list_fini (cairo_skip_list_t *list); /* Insert a new element into the list at the correct sort order as * determined by compare. If unique is true, then duplicate elements @@ -82,18 +82,18 @@ skip_list_fini (skip_list_t *list); * Otherwise data will be copied (elt_size bytes from via * memcpy) and the new element is returned. */ cairo_private void * -skip_list_insert (skip_list_t *list, void *data, int unique); +_cairo_skip_list_insert (cairo_skip_list_t *list, void *data, int unique); /* Find an element which compare considers equal to */ cairo_private void * -skip_list_find (skip_list_t *list, void *data); +_cairo_skip_list_find (cairo_skip_list_t *list, void *data); /* Delete an element which compare considers equal to */ cairo_private void -skip_list_delete (skip_list_t *list, void *data); +_cairo_skip_list_delete (cairo_skip_list_t *list, void *data); /* Delete the given element from the list. */ cairo_private void -skip_list_delete_given (skip_list_t *list, skip_elt_t *given); +_cairo_skip_list_delete_given (cairo_skip_list_t *list, skip_elt_t *given); #endif diff --git a/gfx/cairo/cairo/src/cairo-skiplist.c b/gfx/cairo/cairo/src/cairo-skiplist.c index 6dc4e3c20a5..451ecb06df0 100644 --- a/gfx/cairo/cairo/src/cairo-skiplist.c +++ b/gfx/cairo/cairo/src/cairo-skiplist.c @@ -34,7 +34,7 @@ /* Four 256 element lookup tables back to back implementing a linear * feedback shift register of degree 32. */ -static unsigned const lfsr_lut[1024] = { +static unsigned const _cairo_lfsr_random_lut[1024] = { 0x00000000, 0x9a795537, 0xae8bff59, 0x34f2aa6e, 0xc76eab85, 0x5d17feb2, 0x69e554dc, 0xf39c01eb, 0x14a4023d, 0x8edd570a, 0xba2ffd64, 0x2056a853, 0xd3caa9b8, 0x49b3fc8f, 0x7d4156e1, 0xe73803d6, 0x2948047a, 0xb331514d, @@ -207,24 +207,25 @@ static unsigned const lfsr_lut[1024] = { 0xeaa6b0df, 0x6a98c0b4, 0x184c1316, 0x9872637d, 0x8249a6f7, 0x0277d69c, 0xb63e2de3, 0x36005d88, 0x2c3b9802, 0xac05e869}; +static unsigned _cairo_lfsr_random_state = 0x12345678; + static unsigned lfsr_random(void) { - static unsigned state = 0x12345678; unsigned next; - next = lfsr_lut[((state>> 0) & 0xFF) + 0*256]; - next ^= lfsr_lut[((state>> 8) & 0xFF) + 1*256]; - next ^= lfsr_lut[((state>>16) & 0xFF) + 2*256]; - next ^= lfsr_lut[((state>>24) & 0xFF) + 3*256]; - return state = next; + next = _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>> 0) & 0xFF) + 0*256]; + next ^= _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>> 8) & 0xFF) + 1*256]; + next ^= _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>>16) & 0xFF) + 2*256]; + next ^= _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>>24) & 0xFF) + 3*256]; + return _cairo_lfsr_random_state = next; } /* * Initialize an empty skip list */ void -skip_list_init (skip_list_t *list, - skip_list_compare_t compare, +_cairo_skip_list_init (cairo_skip_list_t *list, + cairo_skip_list_compare_t compare, size_t elt_size) { int i; @@ -242,13 +243,13 @@ skip_list_init (skip_list_t *list, } void -skip_list_fini (skip_list_t *list) +_cairo_skip_list_fini (cairo_skip_list_t *list) { skip_elt_t *elt; int i; while ((elt = list->chains[0])) { - skip_list_delete_given (list, elt); + _cairo_skip_list_delete_given (list, elt); } for (i=0; ifreelists[i]; @@ -283,7 +284,7 @@ random_level (void) } static void * -alloc_node_for_level (skip_list_t *list, unsigned level) +alloc_node_for_level (cairo_skip_list_t *list, unsigned level) { if (list->freelists[level-1]) { skip_elt_t *elt = list->freelists[level-1]; @@ -294,7 +295,7 @@ alloc_node_for_level (skip_list_t *list, unsigned level) } static void -free_elt (skip_list_t *list, skip_elt_t *elt) +free_elt (cairo_skip_list_t *list, skip_elt_t *elt) { elt->prev = list->freelists[elt->prev_index]; list->freelists[elt->prev_index] = elt; @@ -304,7 +305,7 @@ free_elt (skip_list_t *list, skip_elt_t *elt) * Insert 'data' into the list */ void * -skip_list_insert (skip_list_t *list, void *data, int unique) +_cairo_skip_list_insert (cairo_skip_list_t *list, void *data, int unique) { skip_elt_t **update[MAX_LEVEL]; skip_elt_t *prev[MAX_LEVEL]; @@ -369,7 +370,7 @@ skip_list_insert (skip_list_t *list, void *data, int unique) } void * -skip_list_find (skip_list_t *list, void *data) +_cairo_skip_list_find (cairo_skip_list_t *list, void *data) { int i; skip_elt_t **next = list->chains; @@ -394,7 +395,7 @@ skip_list_find (skip_list_t *list, void *data) } void -skip_list_delete (skip_list_t *list, void *data) +_cairo_skip_list_delete (cairo_skip_list_t *list, void *data) { skip_elt_t **update[MAX_LEVEL], *prev[MAX_LEVEL]; skip_elt_t *elt, **next; @@ -430,7 +431,7 @@ skip_list_delete (skip_list_t *list, void *data) } void -skip_list_delete_given (skip_list_t *list, skip_elt_t *given) +_cairo_skip_list_delete_given (cairo_skip_list_t *list, skip_elt_t *given) { skip_elt_t **update[MAX_LEVEL], *prev[MAX_LEVEL]; skip_elt_t *elt, **next; diff --git a/gfx/cairo/cairo/src/cairo-slope.c b/gfx/cairo/cairo/src/cairo-slope.c index 2c888e404d4..78664c5386f 100644 --- a/gfx/cairo/cairo/src/cairo-slope.c +++ b/gfx/cairo/cairo/src/cairo-slope.c @@ -51,7 +51,7 @@ _cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b) difference between a and b is less than PI. < 0 => a less positive than b - == 0 => a equal to be + == 0 => a equal to b > 0 => a more positive than b */ int @@ -67,6 +67,12 @@ _cairo_slope_compare (cairo_slope_t *a, cairo_slope_t *b) if (diff < 0) return -1; + /* special-case zero vectors. the intended logic here is: + * zero vectors all compare equal, and more positive than any + * non-zero vector. + */ + if (a->dx == 0 && a->dy == 0 && b->dx == 0 && b->dy ==0) + return 0; if (a->dx == 0 && a->dy == 0) return 1; if (b->dx == 0 && b->dy ==0) diff --git a/gfx/cairo/cairo/src/cairo-spline.c b/gfx/cairo/cairo/src/cairo-spline.c index 900d3ca0b55..3624bfc348c 100644 --- a/gfx/cairo/cairo/src/cairo-spline.c +++ b/gfx/cairo/cairo/src/cairo-spline.c @@ -37,7 +37,7 @@ #include "cairoint.h" static cairo_status_t -_cairo_spline_grow_by (cairo_spline_t *spline, int additional); +_cairo_spline_grow (cairo_spline_t *spline); static cairo_status_t _cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point); @@ -90,31 +90,47 @@ _cairo_spline_init (cairo_spline_t *spline, void _cairo_spline_fini (cairo_spline_t *spline) { - spline->num_points = 0; - spline->points_size = 0; - free (spline->points); + if (spline->points && spline->points != spline->points_embedded) + free (spline->points); + spline->points = NULL; + spline->points_size = 0; + spline->num_points = 0; } +/* make room for at least one more point */ static cairo_status_t -_cairo_spline_grow_by (cairo_spline_t *spline, int additional) +_cairo_spline_grow (cairo_spline_t *spline) { cairo_point_t *new_points; int old_size = spline->points_size; - int new_size = spline->num_points + additional; + int embedded_size = sizeof (spline->points_embedded) / sizeof (spline->points_embedded[0]); + int new_size = 2 * MAX (old_size, 16); - if (new_size <= spline->points_size) + /* we have a local buffer at spline->points_embedded. try to fulfill the request + * from there. */ + if (old_size < embedded_size) { + spline->points = spline->points_embedded; + spline->points_size = embedded_size; return CAIRO_STATUS_SUCCESS; + } - spline->points_size = new_size; - new_points = realloc (spline->points, spline->points_size * sizeof (cairo_point_t)); + assert (spline->num_points <= spline->points_size); + + if (spline->points == spline->points_embedded) { + new_points = malloc (new_size * sizeof (cairo_point_t)); + if (new_points) + memcpy (new_points, spline->points, old_size * sizeof (cairo_point_t)); + } else { + new_points = realloc (spline->points, new_size * sizeof (cairo_point_t)); + } if (new_points == NULL) { - spline->points_size = old_size; return CAIRO_STATUS_NO_MEMORY; } spline->points = new_points; + spline->points_size = new_size; return CAIRO_STATUS_SUCCESS; } @@ -132,8 +148,7 @@ _cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point) } if (spline->num_points >= spline->points_size) { - int additional = spline->points_size ? spline->points_size : 32; - status = _cairo_spline_grow_by (spline, additional); + status = _cairo_spline_grow (spline); if (status) return status; } diff --git a/gfx/cairo/cairo/src/cairo-surface.c b/gfx/cairo/cairo/src/cairo-surface.c index ca7a937c318..92efa00571b 100644 --- a/gfx/cairo/cairo/src/cairo-surface.c +++ b/gfx/cairo/cairo/src/cairo-surface.c @@ -41,107 +41,45 @@ #include "cairo-surface-fallback-private.h" #include "cairo-clip-private.h" -const cairo_surface_t _cairo_surface_nil = { - &cairo_image_surface_backend, /* backend */ - CAIRO_SURFACE_TYPE_IMAGE, - CAIRO_CONTENT_COLOR, - CAIRO_REF_COUNT_INVALID, /* ref_count */ - CAIRO_STATUS_NO_MEMORY, /* status */ - FALSE, /* finished */ - { 0, /* size */ - 0, /* num_elements */ - 0, /* element_size */ - NULL, /* elements */ - }, /* user_data */ - { 1.0, 0.0, - 0.0, 1.0, - 0.0, 0.0 - }, /* device_transform */ - { 1.0, 0.0, - 0.0, 1.0, - 0.0, 0.0 - }, /* device_transform_inverse */ - 0.0, /* x_fallback_resolution */ - 0.0, /* y_fallback_resolution */ - NULL, /* clip */ - 0, /* next_clip_serial */ - 0, /* current_clip_serial */ - FALSE, /* is_snapshot */ - FALSE, /* has_font_options */ - { CAIRO_ANTIALIAS_DEFAULT, - CAIRO_SUBPIXEL_ORDER_DEFAULT, - CAIRO_HINT_STYLE_DEFAULT, - CAIRO_HINT_METRICS_DEFAULT - } /* font_options */ -}; +#define DEFINE_NIL_SURFACE(status, name) \ +const cairo_surface_t name = { \ + &cairo_image_surface_backend, /* backend */ \ + CAIRO_SURFACE_TYPE_IMAGE, \ + CAIRO_CONTENT_COLOR, \ + CAIRO_REF_COUNT_INVALID, /* ref_count */ \ + status, /* status */ \ + FALSE, /* finished */ \ + { 0, /* size */ \ + 0, /* num_elements */ \ + 0, /* element_size */ \ + NULL, /* elements */ \ + }, /* user_data */ \ + { 1.0, 0.0, \ + 0.0, 1.0, \ + 0.0, 0.0 \ + }, /* device_transform */ \ + { 1.0, 0.0, \ + 0.0, 1.0, \ + 0.0, 0.0 \ + }, /* device_transform_inverse */ \ + 0.0, /* x_fallback_resolution */ \ + 0.0, /* y_fallback_resolution */ \ + NULL, /* clip */ \ + 0, /* next_clip_serial */ \ + 0, /* current_clip_serial */ \ + FALSE, /* is_snapshot */ \ + FALSE, /* has_font_options */ \ + { CAIRO_ANTIALIAS_DEFAULT, \ + CAIRO_SUBPIXEL_ORDER_DEFAULT, \ + CAIRO_HINT_STYLE_DEFAULT, \ + CAIRO_HINT_METRICS_DEFAULT \ + } /* font_options */ \ +} -const cairo_surface_t _cairo_surface_nil_file_not_found = { - &cairo_image_surface_backend, /* backend */ - CAIRO_SURFACE_TYPE_IMAGE, - CAIRO_CONTENT_COLOR, - CAIRO_REF_COUNT_INVALID, /* ref_count */ - CAIRO_STATUS_FILE_NOT_FOUND, /* status */ - FALSE, /* finished */ - { 0, /* size */ - 0, /* num_elements */ - 0, /* element_size */ - NULL, /* elements */ - }, /* user_data */ - { 1.0, 0.0, - 0.0, 1.0, - 0.0, 0.0 - }, /* device_transform */ - { 1.0, 0.0, - 0.0, 1.0, - 0.0, 0.0 - }, /* device_transform_inverse */ - 0.0, /* x_fallback_resolution */ - 0.0, /* y_fallback_resolution */ - NULL, /* clip */ - 0, /* next_clip_serial */ - 0, /* current_clip_serial */ - FALSE, /* is_snapshot */ - FALSE, /* has_font_options */ - { CAIRO_ANTIALIAS_DEFAULT, - CAIRO_SUBPIXEL_ORDER_DEFAULT, - CAIRO_HINT_STYLE_DEFAULT, - CAIRO_HINT_METRICS_DEFAULT - } /* font_options */ -}; - -const cairo_surface_t _cairo_surface_nil_read_error = { - &cairo_image_surface_backend, /* backend */ - CAIRO_SURFACE_TYPE_IMAGE, - CAIRO_CONTENT_COLOR, - CAIRO_REF_COUNT_INVALID, /* ref_count */ - CAIRO_STATUS_READ_ERROR, /* status */ - FALSE, /* finished */ - { 0, /* size */ - 0, /* num_elements */ - 0, /* element_size */ - NULL, /* elements */ - }, /* user_data */ - { 1.0, 0.0, - 0.0, 1.0, - 0.0, 0.0 - }, /* device_transform */ - { 1.0, 0.0, - 0.0, 1.0, - 0.0, 0.0 - }, /* device_transform_inverse */ - 0.0, /* x_fallback_resolution */ - 0.0, /* y_fallback_resolution */ - NULL, /* clip */ - 0, /* next_clip_serial */ - 0, /* current_clip_serial */ - FALSE, /* is_snapshot */ - FALSE, /* has_font_options */ - { CAIRO_ANTIALIAS_DEFAULT, - CAIRO_SUBPIXEL_ORDER_DEFAULT, - CAIRO_HINT_STYLE_DEFAULT, - CAIRO_HINT_METRICS_DEFAULT - } /* font_options */ -}; +DEFINE_NIL_SURFACE(CAIRO_STATUS_NO_MEMORY, _cairo_surface_nil); +DEFINE_NIL_SURFACE(CAIRO_STATUS_FILE_NOT_FOUND, _cairo_surface_nil_file_not_found); +DEFINE_NIL_SURFACE(CAIRO_STATUS_READ_ERROR, _cairo_surface_nil_read_error); +DEFINE_NIL_SURFACE(CAIRO_STATUS_WRITE_ERROR, _cairo_surface_nil_write_error); static void _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern, @@ -203,10 +141,12 @@ slim_hidden_def (cairo_surface_get_type); * cairo_surface_get_content: * @surface: a #cairo_surface_t * - * Return value: The content type of @surface which indicates whether - * the surface contains color and/or alpha information. See + * This function returns the content type of @surface which indicates + * whether the surface contains color and/or alpha information. See * #cairo_content_t. * + * Return value: The content type of @surface. + * * Since: 1.2 **/ cairo_content_t @@ -281,12 +221,23 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other, if (other->status) return (cairo_surface_t*) &_cairo_surface_nil; - if (other->backend->create_similar) + if (other->backend->create_similar) { surface = other->backend->create_similar (other, content, width, height); + /* It's not an error if the backend didn't create a valid + * surface---it may just not be supported. */ + if (surface && surface->status) { + cairo_surface_destroy (surface); + surface = NULL; + } + } - if (!surface) + if (surface == NULL) surface = cairo_image_surface_create (format, width, height); + /* If any error occurred, then return the nil surface we received. */ + if (surface->status) + return surface; + cairo_surface_get_font_options (other, &options); _cairo_surface_set_font_options (surface, &options); @@ -402,15 +353,15 @@ _cairo_surface_get_clip_mode (cairo_surface_t *surface) * @surface from being destroyed until a matching call to * cairo_surface_destroy() is made. * + * The number of references to a #cairo_surface_t can be get using + * cairo_surface_get_reference_count(). + * * Return value: the referenced #cairo_surface_t. **/ cairo_surface_t * cairo_surface_reference (cairo_surface_t *surface) { - if (surface == NULL) - return NULL; - - if (surface->ref_count == CAIRO_REF_COUNT_INVALID) + if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID) return surface; assert (surface->ref_count > 0); @@ -432,10 +383,7 @@ slim_hidden_def (cairo_surface_reference); void cairo_surface_destroy (cairo_surface_t *surface) { - if (surface == NULL) - return; - - if (surface->ref_count == CAIRO_REF_COUNT_INVALID) + if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID) return; assert (surface->ref_count > 0); @@ -444,7 +392,8 @@ cairo_surface_destroy (cairo_surface_t *surface) if (surface->ref_count) return; - cairo_surface_finish (surface); + if (! surface->finished) + cairo_surface_finish (surface); _cairo_user_data_array_fini (&surface->user_data); @@ -452,6 +401,26 @@ cairo_surface_destroy (cairo_surface_t *surface) } slim_hidden_def(cairo_surface_destroy); +/** + * cairo_surface_get_reference_count: + * @surface: a #cairo_surface_t + * + * Returns the current reference count of @surface. + * + * Return value: the current reference count of @surface. If the + * object is a nil object, 0 will be returned. + * + * Since: 1.4 + **/ +unsigned int +cairo_surface_get_reference_count (cairo_surface_t *surface) +{ + if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID) + return 0; + + return surface->ref_count; +} + /** * cairo_surface_finish: * @surface: the #cairo_surface_t to finish @@ -475,6 +444,12 @@ cairo_surface_finish (cairo_surface_t *surface) { cairo_status_t status; + if (surface == NULL) + return; + + if (surface->ref_count == CAIRO_REF_COUNT_INVALID) + return; + if (surface->finished) { _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); return; @@ -815,8 +790,10 @@ cairo_surface_get_device_offset (cairo_surface_t *surface, double *x_offset, double *y_offset) { - *x_offset = surface->device_transform.x0; - *y_offset = surface->device_transform.y0; + if (x_offset) + *x_offset = surface->device_transform.x0; + if (y_offset) + *y_offset = surface->device_transform.y0; } slim_hidden_def (cairo_surface_get_device_offset); @@ -1024,7 +1001,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, status = surface->backend->clone_similar (surface, src, src_x, src_y, width, height, clone_out); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_STATUS_SUCCESS && *clone_out != src) (*clone_out)->device_transform = src->device_transform; if (status != CAIRO_INT_STATUS_UNSUPPORTED) @@ -1036,8 +1013,10 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, status = surface->backend->clone_similar (surface, &image->base, src_x, src_y, width, height, clone_out); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_STATUS_SUCCESS && *clone_out != src) { (*clone_out)->device_transform = src->device_transform; + (*clone_out)->device_transform_inverse = src->device_transform_inverse; + } /* If the above failed point, we could implement a full fallback * using acquire_dest_image, but that's going to be very @@ -1276,12 +1255,6 @@ _cairo_surface_paint (cairo_surface_t *surface, assert (! surface->is_snapshot); - if (source->type == CAIRO_PATTERN_TYPE_SURFACE && - (source->extend == CAIRO_EXTEND_REFLECT || source->extend == CAIRO_EXTEND_PAD)) - { - return CAIRO_STATUS_NO_MEMORY; - } - _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); if (surface->backend->paint) { @@ -1310,12 +1283,6 @@ _cairo_surface_mask (cairo_surface_t *surface, assert (! surface->is_snapshot); - if (source->type == CAIRO_PATTERN_TYPE_SURFACE && - (source->extend == CAIRO_EXTEND_REFLECT || source->extend == CAIRO_EXTEND_PAD)) - { - return CAIRO_STATUS_NO_MEMORY; - } - _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); _cairo_surface_copy_pattern_for_destination (mask, surface, &dev_mask.base); @@ -1354,12 +1321,6 @@ _cairo_surface_stroke (cairo_surface_t *surface, assert (! surface->is_snapshot); - if (source->type == CAIRO_PATTERN_TYPE_SURFACE && - (source->extend == CAIRO_EXTEND_REFLECT || source->extend == CAIRO_EXTEND_PAD)) - { - return CAIRO_STATUS_NO_MEMORY; - } - _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); if (surface->backend->stroke) { @@ -1399,12 +1360,6 @@ _cairo_surface_fill (cairo_surface_t *surface, assert (! surface->is_snapshot); - if (source->type == CAIRO_PATTERN_TYPE_SURFACE && - (source->extend == CAIRO_EXTEND_REFLECT || source->extend == CAIRO_EXTEND_PAD)) - { - return CAIRO_STATUS_NO_MEMORY; - } - _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); if (surface->backend->fill) { @@ -1806,12 +1761,6 @@ _cairo_surface_show_glyphs (cairo_surface_t *surface, assert (! surface->is_snapshot); - if (source->type == CAIRO_PATTERN_TYPE_SURFACE && - (source->extend == CAIRO_EXTEND_REFLECT || source->extend == CAIRO_EXTEND_PAD)) - { - return CAIRO_STATUS_NO_MEMORY; - } - if (!num_glyphs) return CAIRO_STATUS_SUCCESS; @@ -1839,19 +1788,22 @@ _cairo_surface_show_glyphs (cairo_surface_t *surface, cairo_font_options_destroy (font_options); } - if (surface->backend->show_glyphs) { + CAIRO_MUTEX_LOCK (dev_scaled_font->mutex); + + status = CAIRO_INT_STATUS_UNSUPPORTED; + + if (surface->backend->show_glyphs) status = surface->backend->show_glyphs (surface, op, &dev_source.base, glyphs, num_glyphs, dev_scaled_font); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - goto FINISH; - } - status = _cairo_surface_fallback_show_glyphs (surface, op, &dev_source.base, - glyphs, num_glyphs, - dev_scaled_font); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + status = _cairo_surface_fallback_show_glyphs (surface, op, &dev_source.base, + glyphs, num_glyphs, + dev_scaled_font); + + CAIRO_MUTEX_UNLOCK (dev_scaled_font->mutex); -FINISH: if (dev_scaled_font != scaled_font) cairo_scaled_font_destroy (dev_scaled_font); @@ -2137,17 +2089,5 @@ _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern, } } -/** - * cairo_surface_get_reference_count - * @surface: the #cairo_surface_t to fetch the reference count for - * - * Returns the number of references to this surface that are held. - */ -unsigned int -cairo_surface_get_reference_count (cairo_surface_t *surface) -{ - return surface->ref_count; -} - /* LocalWords: rasterized */ diff --git a/gfx/cairo/cairo/src/cairo-svg-surface.c b/gfx/cairo/cairo/src/cairo-svg-surface.c index 534ba01f967..5cb9ce0b97f 100644 --- a/gfx/cairo/cairo/src/cairo-svg-surface.c +++ b/gfx/cairo/cairo/src/cairo-svg-surface.c @@ -240,7 +240,9 @@ cairo_svg_surface_create (const char *filename, status = _cairo_output_stream_get_status (stream); if (status) { _cairo_error (status); - return (cairo_surface_t *) &_cairo_surface_nil; + return (status == CAIRO_STATUS_WRITE_ERROR) ? + (cairo_surface_t *) &_cairo_surface_nil_write_error : + (cairo_surface_t *) &_cairo_surface_nil; } return _cairo_svg_surface_create_for_stream_internal (stream, width, height, CAIRO_SVG_VERSION_1_1); @@ -475,7 +477,7 @@ _cairo_svg_surface_show_page (void *abstract_surface) } static void -emit_transform (cairo_output_stream_t *output, +_cairo_svg_surface_emit_transform (cairo_output_stream_t *output, char const *attribute_str, char const *trailer, cairo_matrix_t *matrix) @@ -563,7 +565,7 @@ _cairo_svg_path_close_path (void *closure) } static cairo_status_t -emit_path (cairo_output_stream_t *output, +_cairo_svg_surface_emit_path (cairo_output_stream_t *output, cairo_path_fixed_t *path, cairo_matrix_t *ctm_inverse) { @@ -606,7 +608,7 @@ _cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t *document, _cairo_output_stream_printf (document->xml_node_glyphs, "xml_node_glyphs, scaled_glyph->path, NULL); + status = _cairo_svg_surface_emit_path (document->xml_node_glyphs, scaled_glyph->path, NULL); _cairo_output_stream_printf (document->xml_node_glyphs, "/>\n"); @@ -642,7 +644,7 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document, } _cairo_output_stream_printf (document->xml_node_glyphs, "xml_node_glyphs, " transform", ">/n", &image->base.device_transform); + _cairo_svg_surface_emit_transform (document->xml_node_glyphs, " transform", ">/n", &image->base.device_transform); for (y = 0, row = image->data, rows = image->height; rows; row += image->stride, rows--, y++) { for (x = 0, byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) { @@ -674,7 +676,7 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t *document, cairo_status_t status; _cairo_output_stream_printf (document->xml_node_glyphs, - "\n", + "\n", font_id, subset_glyph_index); @@ -707,9 +709,9 @@ _cairo_svg_document_emit_font_subset (cairo_scaled_font_subset_t *font_subset, static void _cairo_svg_document_emit_font_subsets (cairo_svg_document_t *document) { - _cairo_scaled_font_subsets_foreach (document->font_subsets, - _cairo_svg_document_emit_font_subset, - document); + _cairo_scaled_font_subsets_foreach_scaled (document->font_subsets, + _cairo_svg_document_emit_font_subset, + document); _cairo_scaled_font_subsets_destroy (document->font_subsets); document->font_subsets = NULL; } @@ -735,7 +737,7 @@ _cairo_svg_test_force_fallbacks (void) } static cairo_int_status_t -_operation_supported (cairo_svg_surface_t *surface, +__cairo_svg_surface_operation_supported (cairo_svg_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *pattern) { @@ -752,11 +754,11 @@ _operation_supported (cairo_svg_surface_t *surface, } static cairo_int_status_t -_analyze_operation (cairo_svg_surface_t *surface, +_cairo_svg_surface_analyze_operation (cairo_svg_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *pattern) { - if (_operation_supported (surface, op, pattern)) + if (__cairo_svg_surface_operation_supported (surface, op, pattern)) return CAIRO_STATUS_SUCCESS; else return CAIRO_INT_STATUS_UNSUPPORTED; @@ -799,7 +801,7 @@ _cairo_svg_surface_finish (void *abstract_surface) } static void -emit_alpha_filter (cairo_svg_document_t *document) +_cairo_svg_surface_emit_alpha_filter (cairo_svg_document_t *document) { if (document->alpha_filter) return; @@ -914,19 +916,27 @@ _cairo_surface_base64_encode (cairo_surface_t *surface, } static cairo_status_t -emit_composite_image_pattern (cairo_output_stream_t *output, +_cairo_svg_surface_emit_composite_image_pattern (cairo_output_stream_t *output, cairo_svg_surface_t *svg_surface, cairo_surface_pattern_t *pattern, int pattern_id, const char *extra_attributes) { - cairo_image_surface_t *image; + cairo_surface_t *surface; + cairo_surface_attributes_t surface_attr; + cairo_rectangle_int16_t extents; cairo_status_t status; cairo_matrix_t p2u; - void *image_extra; - status = _cairo_surface_acquire_source_image (pattern->surface, - &image, &image_extra); + status = _cairo_pattern_acquire_surface ((cairo_pattern_t *)pattern, + (cairo_surface_t *)svg_surface, + 0, 0, (unsigned int)-1, (unsigned int)-1, + &surface, &surface_attr); + if (status) + return status; + + status = _cairo_surface_get_extents (surface, &extents); + if (status) return status; @@ -939,36 +949,37 @@ emit_composite_image_pattern (cairo_output_stream_t *output, "patternUnits=\"userSpaceOnUse\" " "width=\"%d\" height=\"%d\"", pattern_id, - image->width, image->height); - emit_transform (output, " patternTransform", ">\n", &p2u); + extents.width, extents.height); + _cairo_svg_surface_emit_transform (output, " patternTransform", ">\n", &p2u); } _cairo_output_stream_printf (output, " width, image->height); + extents.width, extents.height); if (pattern_id == invalid_pattern_id) - emit_transform (output, " transform", "", &p2u); + _cairo_svg_surface_emit_transform (output, " transform", "", &p2u); if (extra_attributes) _cairo_output_stream_printf (output, " %s", extra_attributes); _cairo_output_stream_printf (output, " xlink:href=\""); - status = _cairo_surface_base64_encode (pattern->surface, output); + status = _cairo_surface_base64_encode (surface, output); _cairo_output_stream_printf (output, "\"/>\n"); if (pattern_id != invalid_pattern_id) _cairo_output_stream_printf (output, "\n"); - _cairo_surface_release_source_image (pattern->surface, image, image_extra); + _cairo_pattern_release_surface ((cairo_pattern_t *)pattern, + surface, &surface_attr); return status; } static int -emit_meta_surface (cairo_svg_document_t *document, +_cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, cairo_meta_surface_t *surface) { cairo_surface_t *paginated_surface; @@ -1010,7 +1021,7 @@ emit_meta_surface (cairo_svg_document_t *document, _cairo_array_append (&document->meta_snapshots, &new_snapshot); if (meta->content == CAIRO_CONTENT_ALPHA) { - emit_alpha_filter (document); + _cairo_svg_surface_emit_alpha_filter (document); _cairo_output_stream_printf (document->xml_node_defs, "surface; - id = emit_meta_surface (document, meta_surface); + id = _cairo_svg_surface_emit_meta_surface (document, meta_surface); p2u = pattern->base.matrix; cairo_matrix_invert (&p2u); @@ -1081,7 +1092,7 @@ emit_composite_meta_pattern (cairo_output_stream_t *output, pattern_id, meta_surface->width_pixels, meta_surface->height_pixels); - emit_transform (output, " patternTransform", ">\n", &p2u); + _cairo_svg_surface_emit_transform (output, " patternTransform", ">\n", &p2u); } _cairo_output_stream_printf (output, @@ -1089,7 +1100,7 @@ emit_composite_meta_pattern (cairo_output_stream_t *output, id); if (pattern_id == invalid_pattern_id) - emit_transform (output, " transform", "", &p2u); + _cairo_svg_surface_emit_transform (output, " transform", "", &p2u); if (extra_attributes) _cairo_output_stream_printf (output, " %s", extra_attributes); @@ -1103,7 +1114,7 @@ emit_composite_meta_pattern (cairo_output_stream_t *output, } static cairo_status_t -emit_composite_pattern (cairo_output_stream_t *output, +_cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_surface_pattern_t *pattern, int pattern_id, @@ -1111,16 +1122,16 @@ emit_composite_pattern (cairo_output_stream_t *output, { if (_cairo_surface_is_meta (pattern->surface)) { - return emit_composite_meta_pattern (output, surface, pattern, + return _cairo_svg_surface_emit_composite_meta_pattern (output, surface, pattern, pattern_id, extra_attributes); } - return emit_composite_image_pattern (output, surface, pattern, + return _cairo_svg_surface_emit_composite_image_pattern (output, surface, pattern, pattern_id, extra_attributes); } static void -emit_operator (cairo_output_stream_t *output, +_cairo_svg_surface_emit_operator (cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_operator_t op) { @@ -1142,7 +1153,7 @@ emit_operator (cairo_output_stream_t *output, } static void -emit_solid_pattern (cairo_svg_surface_t *surface, +_cairo_svg_surface_emit_solid_pattern (cairo_svg_surface_t *surface, cairo_solid_pattern_t *pattern, cairo_output_stream_t *style, cairo_bool_t is_stroke) @@ -1158,7 +1169,7 @@ emit_solid_pattern (cairo_svg_surface_t *surface, } static void -emit_surface_pattern (cairo_svg_surface_t *surface, +_cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t *surface, cairo_surface_pattern_t *pattern, cairo_output_stream_t *style, cairo_bool_t is_stroke) @@ -1167,7 +1178,7 @@ emit_surface_pattern (cairo_svg_surface_t *surface, int pattern_id; pattern_id = document->pattern_id++; - emit_composite_pattern (document->xml_node_defs, surface, pattern, + _cairo_svg_surface_emit_composite_pattern (document->xml_node_defs, surface, pattern, pattern_id, NULL); _cairo_output_stream_printf (style, @@ -1177,30 +1188,169 @@ emit_surface_pattern (cairo_svg_surface_t *surface, } static void -emit_pattern_stops (cairo_output_stream_t *output, +_cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output, cairo_gradient_pattern_t const *pattern, - double start_offset) + double start_offset, + cairo_bool_t reverse_stops, + cairo_bool_t emulate_reflect) { + pixman_gradient_stop_t *stops; double offset; + unsigned int n_stops; unsigned int i; - for (i = 0; i < pattern->n_stops; i++) { - offset = start_offset + (1 - start_offset ) * - _cairo_fixed_to_double (pattern->stops[i].x); + if (pattern->n_stops < 1) + return; + + if (pattern->n_stops == 1) { + _cairo_output_stream_printf (output, + "\n", + _cairo_fixed_to_double (pattern->stops[0].x), + pattern->stops[0].color.red / 655.35, + pattern->stops[0].color.green / 655.35, + pattern->stops[0].color.blue / 655.35, + pattern->stops[0].color.alpha / 65535.0); + return; + } + + if (emulate_reflect || reverse_stops) { + n_stops = emulate_reflect ? pattern->n_stops * 2 - 2: pattern->n_stops; + stops = malloc (sizeof (pixman_gradient_stop_t) * n_stops); + + for (i = 0; i < pattern->n_stops; i++) { + if (reverse_stops) { + stops[i] = pattern->stops[pattern->n_stops - i - 1]; + stops[i].x = _cairo_fixed_from_double (1.0 - _cairo_fixed_to_double (stops[i].x)); + } else + stops[i] = pattern->stops[i]; + if (emulate_reflect) { + stops[i].x /= 2; + if (i > 0 && i < (pattern->n_stops - 1)) { + if (reverse_stops) { + stops[i + pattern->n_stops - 1] = pattern->stops[i]; + stops[i + pattern->n_stops - 1].x = + _cairo_fixed_from_double (0.5 + 0.5 + * _cairo_fixed_to_double (stops[i + pattern->n_stops - 1].x)); + } else { + stops[i + pattern->n_stops - 1] = pattern->stops[pattern->n_stops - i - 1]; + stops[i + pattern->n_stops - 1].x = + _cairo_fixed_from_double (1 - 0.5 + * _cairo_fixed_to_double (stops [i + pattern->n_stops - 1].x)); + } + } + } + } + } else { + n_stops = pattern->n_stops; + stops = pattern->stops; + } + + if (start_offset >= 0.0) + for (i = 0; i < n_stops; i++) { + offset = start_offset + (1 - start_offset ) * + _cairo_fixed_to_double (stops[i].x); + _cairo_output_stream_printf (output, + "\n", + offset, + stops[i].color.red / 655.35, + stops[i].color.green / 655.35, + stops[i].color.blue / 655.35, + stops[i].color.alpha / 65535.0); + } + else { + cairo_bool_t found = FALSE; + unsigned int offset_index; + pixman_color_t offset_color_start, offset_color_stop; + + for (i = 0; i < n_stops; i++) { + if (_cairo_fixed_to_double (stops[i].x) >= -start_offset) { + if (i > 0) { + if (stops[i].x != stops[i-1].x) { + double x0, x1; + pixman_color_t *color0, *color1; + + x0 = _cairo_fixed_to_double (stops[i-1].x); + x1 = _cairo_fixed_to_double (stops[i].x); + color0 = &stops[i-1].color; + color1 = &stops[i].color; + offset_color_start.red = color0->red + (color1->red - color0->red) + * (-start_offset - x0) / (x1 - x0); + offset_color_start.green = color0->green + (color1->green - color0->green) + * (-start_offset - x0) / (x1 - x0); + offset_color_start.blue = color0->blue + (color1->blue - color0->blue) + * (-start_offset - x0) / (x1 - x0); + offset_color_start.alpha = color0->alpha + (color1->alpha - color0->alpha) + * (-start_offset - x0) / (x1 - x0); + offset_color_stop = offset_color_start; + } else { + offset_color_stop = stops[i-1].color; + offset_color_start = stops[i].color; + } + } else + offset_color_stop = offset_color_start = stops[i].color; + offset_index = i; + found = TRUE; + break; + } + } + + if (!found) { + offset_index = n_stops - 1; + offset_color_stop = offset_color_start = stops[offset_index].color; + } + _cairo_output_stream_printf (output, - "\n", - offset, - pattern->stops[i].color.red / 655.35, - pattern->stops[i].color.green / 655.35, - pattern->stops[i].color.blue / 655.35, - pattern->stops[i].color.alpha / 65535.0); + offset_color_start.red / 655.35, + offset_color_start.green / 655.35, + offset_color_start.blue / 655.35, + offset_color_start.alpha / 65535.0); + for (i = offset_index; i < n_stops; i++) { + _cairo_output_stream_printf (output, + "\n", + _cairo_fixed_to_double (stops[i].x) + start_offset, + stops[i].color.red / 655.35, + stops[i].color.green / 655.35, + stops[i].color.blue / 655.35, + stops[i].color.alpha / 65535.0); + } + for (i = 0; i < offset_index; i++) { + _cairo_output_stream_printf (output, + "\n", + 1.0 + _cairo_fixed_to_double (stops[i].x) + start_offset, + stops[i].color.red / 655.35, + stops[i].color.green / 655.35, + stops[i].color.blue / 655.35, + stops[i].color.alpha / 65535.0); + } + + _cairo_output_stream_printf (output, + "\n", + offset_color_stop.red / 655.35, + offset_color_stop.green / 655.35, + offset_color_stop.blue / 655.35, + offset_color_stop.alpha / 65535.0); + } + + if (reverse_stops || emulate_reflect) + free (stops); } static void -emit_pattern_extend (cairo_output_stream_t *output, +_cairo_svg_surface_emit_pattern_extend (cairo_output_stream_t *output, cairo_pattern_t *pattern) { switch (pattern->extend) { @@ -1211,15 +1361,13 @@ emit_pattern_extend (cairo_output_stream_t *output, _cairo_output_stream_printf (output, "spreadMethod=\"reflect\" "); break; case CAIRO_EXTEND_NONE: - break; case CAIRO_EXTEND_PAD: - /* FIXME not implemented */ break; } } static void -emit_linear_pattern (cairo_svg_surface_t *surface, +_cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface, cairo_linear_pattern_t *pattern, cairo_output_stream_t *style, cairo_bool_t is_stroke) @@ -1240,12 +1388,12 @@ emit_linear_pattern (cairo_svg_surface_t *surface, document->linear_pattern_id, x0, y0, x1, y1); - emit_pattern_extend (document->xml_node_defs, &pattern->base.base), + _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base), p2u = pattern->base.base.matrix; cairo_matrix_invert (&p2u); - emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u); + _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u); - emit_pattern_stops (document->xml_node_defs ,&pattern->base, 0.0); + _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs ,&pattern->base, 0.0, FALSE, FALSE); _cairo_output_stream_printf (document->xml_node_defs, "\n"); @@ -1259,46 +1407,160 @@ emit_linear_pattern (cairo_svg_surface_t *surface, } static void -emit_radial_pattern (cairo_svg_surface_t *surface, +_cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface, cairo_radial_pattern_t *pattern, cairo_output_stream_t *style, cairo_bool_t is_stroke) { cairo_svg_document_t *document = surface->document; cairo_matrix_t p2u; + cairo_extend_t extend; double x0, y0, x1, y1, r0, r1; double fx, fy; + cairo_bool_t reverse_stops; + pixman_circle_t *c0, *c1; - x0 = _cairo_fixed_to_double (pattern->gradient.inner.x); - y0 = _cairo_fixed_to_double (pattern->gradient.inner.y); - r0 = _cairo_fixed_to_double (pattern->gradient.inner.radius); - x1 = _cairo_fixed_to_double (pattern->gradient.outer.x); - y1 = _cairo_fixed_to_double (pattern->gradient.outer.y); - r1 = _cairo_fixed_to_double (pattern->gradient.outer.radius); + extend = pattern->base.base.extend; - /* SVG doesn't have a start radius, so computing now SVG focal coordinates - * and emulating start radius by translating color stops. - * FIXME: We also need to emulate cairo behaviour inside start circle when - * extend != CAIRO_EXTEND_NONE. - * FIXME: Handle radius1 <= radius0 */ - fx = (r1 * x0 - r0 * x1) / (r1 - r0); - fy = (r1 * y0 - r0 * y1) / (r1 - r0); + if (pattern->gradient.c1.radius < pattern->gradient.c2.radius) { + c0 = &pattern->gradient.c1; + c1 = &pattern->gradient.c2; + reverse_stops = FALSE; + } else { + c0 = &pattern->gradient.c2; + c1 = &pattern->gradient.c1; + reverse_stops = TRUE; + } - _cairo_output_stream_printf (document->xml_node_defs, - "radial_pattern_id, - x1, y1, - fx, fy, r1); + x0 = _cairo_fixed_to_double (c0->x); + y0 = _cairo_fixed_to_double (c0->y); + r0 = _cairo_fixed_to_double (c0->radius); + x1 = _cairo_fixed_to_double (c1->x); + y1 = _cairo_fixed_to_double (c1->y); + r1 = _cairo_fixed_to_double (c1->radius); - emit_pattern_extend (document->xml_node_defs, &pattern->base.base), p2u = pattern->base.base.matrix; cairo_matrix_invert (&p2u); - emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u); - emit_pattern_stops (document->xml_node_defs, &pattern->base, r0 / r1); + if (pattern->gradient.c1.radius == pattern->gradient.c2.radius) { + _cairo_output_stream_printf (document->xml_node_defs, + "radial_pattern_id, + x1, y1, + x1, y1, r1); + + _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u); + + if (extend == CAIRO_EXTEND_NONE || + pattern->base.n_stops < 1) + _cairo_output_stream_printf (document->xml_node_defs, + "\n"); + else { + _cairo_output_stream_printf (document->xml_node_defs, + "\n", + pattern->base.stops[0].color.red / 655.35, + pattern->base.stops[0].color.green / 655.35, + pattern->base.stops[0].color.blue / 655.35, + pattern->base.stops[0].color.alpha / 65535.0); + if (pattern->base.n_stops > 1) + _cairo_output_stream_printf (document->xml_node_defs, + "\n", + pattern->base.stops[1].color.red / 655.35, + pattern->base.stops[1].color.green / 655.35, + pattern->base.stops[1].color.blue / 655.35, + pattern->base.stops[1].color.alpha / 65535.0); + } + + } else { + double offset, r, x, y; + cairo_bool_t emulate_reflect = FALSE; + + fx = (r1 * x0 - r0 * x1) / (r1 - r0); + fy = (r1 * y0 - r0 * y1) / (r1 - r0); + + /* SVG doesn't support the inner circle and use instead a gradient focal. + * That means we need to emulate the cairo behaviour by processing the + * cairo gradient stops. + * The CAIRO_EXTENT_NONE and CAIRO_EXTENT_PAD modes are quite easy to handle, + * it's just a matter of stop position translation and calculation of + * the corresponding SVG radial gradient focal. + * The CAIRO_EXTENT_REFLECT and CAIRO_EXTEND_REPEAT modes require to compute a new + * radial gradient, with an new outer circle, equal to r1 - r0 in the CAIRO_EXTEND_REPEAT + * case, and 2 * (r1 - r0) in the CAIRO_EXTENT_REFLECT case, and a new gradient stop + * list that maps to the original cairo stop list. + */ + if ((extend == CAIRO_EXTEND_REFLECT + || extend == CAIRO_EXTEND_REPEAT) + && r0 > 0.0) { + double r_org = r1; + + if (extend == CAIRO_EXTEND_REFLECT) { + r1 = 2 * r1 - r0; + emulate_reflect = TRUE; + } + + offset = fmod (r1, r1 - r0) / (r1 - r0) - 1.0; + r = r1 - r0; + + /* New position of outer circle. */ + x = r * (x1 - fx) / r_org + fx; + y = r * (y1 - fy) / r_org + fy; + + x1 = x; + y1 = y; + r1 = r; + r0 = 0.0; + } else { + offset = r0 / r1; + } + + _cairo_output_stream_printf (document->xml_node_defs, + "radial_pattern_id, + x1, y1, + fx, fy, r1); + + if (emulate_reflect) + _cairo_output_stream_printf (document->xml_node_defs, "spreadMethod=\"repeat\" "); + else + _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base); + _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u); + + /* To support cairo's EXTEND_NONE, (for which SVG has no similar + * notion), we add transparent color stops on either end of the + * user-provided stops. */ + if (extend == CAIRO_EXTEND_NONE) { + _cairo_output_stream_printf (document->xml_node_defs, + "\n"); + if (r0 != 0.0) + _cairo_output_stream_printf (document->xml_node_defs, + "\n", + r0 / r1); + } + _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs, &pattern->base, offset, + reverse_stops, emulate_reflect); + if (pattern->base.base.extend == CAIRO_EXTEND_NONE) + _cairo_output_stream_printf (document->xml_node_defs, + "\n"); + } _cairo_output_stream_printf (document->xml_node_defs, "\n"); @@ -1312,24 +1574,24 @@ emit_radial_pattern (cairo_svg_surface_t *surface, } static void -emit_pattern (cairo_svg_surface_t *surface, cairo_pattern_t *pattern, +_cairo_svg_surface_emit_pattern (cairo_svg_surface_t *surface, cairo_pattern_t *pattern, cairo_output_stream_t *output, cairo_bool_t is_stroke) { switch (pattern->type) { case CAIRO_PATTERN_TYPE_SOLID: - emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern, output, is_stroke); + _cairo_svg_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern, output, is_stroke); break; case CAIRO_PATTERN_TYPE_SURFACE: - emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, output, is_stroke); + _cairo_svg_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, output, is_stroke); break; case CAIRO_PATTERN_TYPE_LINEAR: - emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern, output, is_stroke); + _cairo_svg_surface_emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern, output, is_stroke); break; case CAIRO_PATTERN_TYPE_RADIAL: - emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, output, is_stroke); + _cairo_svg_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, output, is_stroke); break; } } @@ -1347,20 +1609,20 @@ _cairo_svg_surface_fill (void *abstract_surface, cairo_status_t status; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _analyze_operation (surface, op, source); + return _cairo_svg_surface_analyze_operation (surface, op, source); - assert (_operation_supported (surface, op, source)); + assert (__cairo_svg_surface_operation_supported (surface, op, source)); _cairo_output_stream_printf (surface->xml_node, "xml_node, surface, op); - emit_pattern (surface, source, surface->xml_node, FALSE); + _cairo_svg_surface_emit_operator (surface->xml_node, surface, op); + _cairo_svg_surface_emit_pattern (surface, source, surface->xml_node, FALSE); _cairo_output_stream_printf (surface->xml_node, "\" "); - status = emit_path (surface->xml_node, path, NULL); + status = _cairo_svg_surface_emit_path (surface->xml_node, path, NULL); _cairo_output_stream_printf (surface->xml_node, "/>\n"); @@ -1387,7 +1649,7 @@ _cairo_svg_surface_get_extents (void *abstract_surface, } static cairo_status_t -emit_paint (cairo_output_stream_t *output, +_cairo_svg_surface_emit_paint (cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_operator_t op, cairo_pattern_t *source, @@ -1395,7 +1657,7 @@ emit_paint (cairo_output_stream_t *output, { if (source->type == CAIRO_PATTERN_TYPE_SURFACE && source->extend == CAIRO_EXTEND_NONE) - return emit_composite_pattern (output, + return _cairo_svg_surface_emit_composite_pattern (output, surface, (cairo_surface_pattern_t *) source, invalid_pattern_id, @@ -1406,8 +1668,8 @@ emit_paint (cairo_output_stream_t *output, "width=\"%f\" height=\"%f\" " "style=\"", surface->width, surface->height); - emit_operator (output, surface, op); - emit_pattern (surface, source, output, FALSE); + _cairo_svg_surface_emit_operator (output, surface, op); + _cairo_svg_surface_emit_pattern (surface, source, output, FALSE); _cairo_output_stream_printf (output, " stroke: none;\""); if (extra_attributes) @@ -1427,7 +1689,7 @@ _cairo_svg_surface_paint (void *abstract_surface, cairo_svg_surface_t *surface = abstract_surface; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _analyze_operation (surface, op, source); + return _cairo_svg_surface_analyze_operation (surface, op, source); /* XXX: It would be nice to be able to assert this condition * here. But, we actually allow one 'cheat' that is used when @@ -1436,7 +1698,7 @@ _cairo_svg_surface_paint (void *abstract_surface, * possible only because there is nothing between the fallback * images and the paper, nor is anything painted above. */ /* - assert (_operation_supported (surface, op, source)); + assert (__cairo_svg_surface_operation_supported (surface, op, source)); */ /* Emulation of clear and source operators, when no clipping region @@ -1467,7 +1729,7 @@ _cairo_svg_surface_paint (void *abstract_surface, } } - emit_paint (surface->xml_node, surface, op, source, NULL); + _cairo_svg_surface_emit_paint (surface->xml_node, surface, op, source, NULL); return CAIRO_STATUS_SUCCESS; } @@ -1484,13 +1746,13 @@ _cairo_svg_surface_mask (void *abstract_surface, char buffer[64]; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _analyze_operation (surface, op, source); + return _cairo_svg_surface_analyze_operation (surface, op, source); - assert (_operation_supported (surface, op, source)); + assert (__cairo_svg_surface_operation_supported (surface, op, source)); - emit_alpha_filter (document); + _cairo_svg_surface_emit_alpha_filter (document); - /* emit_paint() will output a pattern definition to + /* _cairo_svg_surface_emit_paint() will output a pattern definition to * document->xml_node_defs so we need to write the mask element to * a temporary stream and then copy that to xml_node_defs. */ mask_stream = _cairo_memory_stream_create (); @@ -1498,7 +1760,7 @@ _cairo_svg_surface_mask (void *abstract_surface, "\n" " \n", document->mask_id); - emit_paint (mask_stream, surface, op, mask, NULL); + _cairo_svg_surface_emit_paint (mask_stream, surface, op, mask, NULL); _cairo_output_stream_printf (mask_stream, " \n" "\n"); @@ -1507,7 +1769,7 @@ _cairo_svg_surface_mask (void *abstract_surface, snprintf (buffer, sizeof buffer, "mask=\"url(#mask%d);\"", document->mask_id); - emit_paint (surface->xml_node, surface, op, source, buffer); + _cairo_svg_surface_emit_paint (surface->xml_node, surface, op, source, buffer); document->mask_id++; @@ -1531,9 +1793,9 @@ _cairo_svg_surface_stroke (void *abstract_dst, unsigned int i; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _analyze_operation (surface, op, source); + return _cairo_svg_surface_analyze_operation (surface, op, source); - assert (_operation_supported (surface, op, source)); + assert (__cairo_svg_surface_operation_supported (surface, op, source)); switch (stroke_style->line_cap) { case CAIRO_LINE_CAP_BUTT: @@ -1572,8 +1834,8 @@ _cairo_svg_surface_stroke (void *abstract_dst, line_cap, line_join); - emit_pattern (surface, source, surface->xml_node, TRUE); - emit_operator (surface->xml_node, surface, op); + _cairo_svg_surface_emit_pattern (surface, source, surface->xml_node, TRUE); + _cairo_svg_surface_emit_operator (surface->xml_node, surface, op); if (stroke_style->num_dashes > 0) { _cairo_output_stream_printf (surface->xml_node, "stroke-dasharray: "); @@ -1596,9 +1858,9 @@ _cairo_svg_surface_stroke (void *abstract_dst, "stroke-miterlimit: %f;\" ", stroke_style->miter_limit); - status = emit_path (surface->xml_node, path, ctm_inverse); + status = _cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse); - emit_transform (surface->xml_node, " transform", "/>\n", ctm); + _cairo_svg_surface_emit_transform (surface->xml_node, " transform", "/>\n", ctm); return status; } @@ -1619,9 +1881,9 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, int i; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _analyze_operation (surface, op, pattern); + return _cairo_svg_surface_analyze_operation (surface, op, pattern); - assert (_operation_supported (surface, op, pattern)); + assert (__cairo_svg_surface_operation_supported (surface, op, pattern)); if (num_glyphs <= 0) return CAIRO_STATUS_SUCCESS; @@ -1633,7 +1895,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, goto FALLBACK; _cairo_output_stream_printf (surface->xml_node, "xml_node, FALSE); + _cairo_svg_surface_emit_pattern (surface, pattern, surface->xml_node, FALSE); _cairo_output_stream_printf (surface->xml_node, "\">\n"); for (i = 0; i < num_glyphs; i++) { @@ -1698,7 +1960,7 @@ _cairo_svg_surface_intersect_clip_path (void *dst, "\n" " clip_id); - status = emit_path (document->xml_node_defs, path, NULL); + status = _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL); _cairo_output_stream_printf (document->xml_node_defs, "/>\n" "\n"); @@ -1772,7 +2034,7 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream, } /* The use of defs for font glyphs imposes no per-subset limit. */ - document->font_subsets = _cairo_scaled_font_subsets_create (0); + document->font_subsets = _cairo_scaled_font_subsets_create (0, INT_MAX); if (document->font_subsets == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); free (document); diff --git a/gfx/cairo/cairo/src/cairo-traps.c b/gfx/cairo/cairo/src/cairo-traps.c index 9b3931fce16..dd5837bf5de 100644 --- a/gfx/cairo/cairo/src/cairo-traps.c +++ b/gfx/cairo/cairo/src/cairo-traps.c @@ -1,5 +1,6 @@ /* * Copyright © 2002 Keith Packard + * Copyright © 2007 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -40,7 +41,7 @@ /* private functions */ static cairo_status_t -_cairo_traps_grow_by (cairo_traps_t *traps, int additional); +_cairo_traps_grow (cairo_traps_t *traps); static cairo_status_t _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom, @@ -49,18 +50,6 @@ _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bo static int _compare_point_fixed_by_y (const void *av, const void *bv); -static int -_compare_cairo_edge_by_top (const void *av, const void *bv); - -static int -_compare_cairo_edge_by_slope (const void *av, const void *bv); - -static cairo_fixed_16_16_t -_compute_x (cairo_line_t *line, cairo_fixed_t y); - -static int -_line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret); - void _cairo_traps_init (cairo_traps_t *traps) { @@ -70,19 +59,19 @@ _cairo_traps_init (cairo_traps_t *traps) traps->traps_size = 0; traps->traps = NULL; - traps->extents.p1.x = traps->extents.p1.y = INT16_MAX << 16; - traps->extents.p2.x = traps->extents.p2.y = INT16_MIN << 16; + traps->extents.p1.x = traps->extents.p1.y = INT32_MAX; + traps->extents.p2.x = traps->extents.p2.y = INT32_MIN; } void _cairo_traps_fini (cairo_traps_t *traps) { - if (traps->traps_size) { + if (traps->traps && traps->traps != traps->traps_embedded) free (traps->traps); - traps->traps = NULL; - traps->traps_size = 0; - traps->num_traps = 0; - } + + traps->traps = NULL; + traps->traps_size = 0; + traps->num_traps = 0; } /** @@ -100,7 +89,7 @@ _cairo_traps_init_box (cairo_traps_t *traps, { _cairo_traps_init (traps); - traps->status = _cairo_traps_grow_by (traps, 1); + traps->status = _cairo_traps_grow (traps); if (traps->status) return traps->status; @@ -134,8 +123,7 @@ _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bo } if (traps->num_traps >= traps->traps_size) { - int inc = traps->traps_size ? traps->traps_size : 32; - traps->status = _cairo_traps_grow_by (traps, inc); + traps->status = _cairo_traps_grow (traps); if (traps->status) return traps->status; } @@ -193,29 +181,43 @@ _cairo_traps_add_trap_from_points (cairo_traps_t *traps, cairo_fixed_t top, cair return _cairo_traps_add_trap (traps, top, bottom, &left, &right); } +/* make room for at least one more trap */ static cairo_status_t -_cairo_traps_grow_by (cairo_traps_t *traps, int additional) +_cairo_traps_grow (cairo_traps_t *traps) { cairo_trapezoid_t *new_traps; int old_size = traps->traps_size; - int new_size = traps->num_traps + additional; + int embedded_size = sizeof (traps->traps_embedded) / sizeof (traps->traps_embedded[0]); + int new_size = 2 * MAX (old_size, 16); + + /* we have a local buffer at traps->traps_embedded. try to fulfill the request + * from there. */ + if (old_size < embedded_size) { + traps->traps = traps->traps_embedded; + traps->traps_size = embedded_size; + return traps->status; + } + + assert (traps->num_traps <= traps->traps_size); if (traps->status) return traps->status; - if (new_size <= traps->traps_size) - return traps->status; - - traps->traps_size = new_size; - new_traps = realloc (traps->traps, traps->traps_size * sizeof (cairo_trapezoid_t)); + if (traps->traps == traps->traps_embedded) { + new_traps = malloc (new_size * sizeof (cairo_trapezoid_t)); + if (new_traps) + memcpy (new_traps, traps->traps, old_size * sizeof (cairo_trapezoid_t)); + } else { + new_traps = realloc (traps->traps, new_size * sizeof (cairo_trapezoid_t)); + } if (new_traps == NULL) { - traps->traps_size = old_size; traps->status = CAIRO_STATUS_NO_MEMORY; return traps->status; } traps->traps = new_traps; + traps->traps_size = new_size; return traps->status; } @@ -309,57 +311,20 @@ _cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps, } } +/* A triangle is simply a degenerate case of a convex + * quadrilateral. We would not benefit from having any distinct + * implementation of triangle vs. quadrilateral tessellation here. */ cairo_status_t _cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3]) { - cairo_line_t line; - cairo_fixed_16_16_t intersect; - cairo_point_t tsort[3]; + cairo_point_t quad[4]; - memcpy (tsort, t, 3 * sizeof (cairo_point_t)); - qsort (tsort, 3, sizeof (cairo_point_t), _compare_point_fixed_by_y); + quad[0] = t[0]; + quad[1] = t[0]; + quad[2] = t[1]; + quad[3] = t[2]; - /* horizontal top edge requires special handling */ - if (tsort[0].y == tsort[1].y) { - if (tsort[0].x < tsort[1].x) - _cairo_traps_add_trap_from_points (traps, - tsort[1].y, tsort[2].y, - tsort[0], tsort[2], - tsort[1], tsort[2]); - else - _cairo_traps_add_trap_from_points (traps, - tsort[1].y, tsort[2].y, - tsort[1], tsort[2], - tsort[0], tsort[2]); - return traps->status; - } - - line.p1 = tsort[0]; - line.p2 = tsort[1]; - - intersect = _compute_x (&line, tsort[2].y); - - if (intersect < tsort[2].x) { - _cairo_traps_add_trap_from_points (traps, - tsort[0].y, tsort[1].y, - tsort[0], tsort[1], - tsort[0], tsort[2]); - _cairo_traps_add_trap_from_points (traps, - tsort[1].y, tsort[2].y, - tsort[1], tsort[2], - tsort[0], tsort[2]); - } else { - _cairo_traps_add_trap_from_points (traps, - tsort[0].y, tsort[1].y, - tsort[0], tsort[2], - tsort[0], tsort[1]); - _cairo_traps_add_trap_from_points (traps, - tsort[1].y, tsort[2].y, - tsort[0], tsort[2], - tsort[1], tsort[2]); - } - - return traps->status; + return _cairo_traps_tessellate_convex_quad (traps, quad); } cairo_status_t @@ -367,6 +332,8 @@ _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, cairo_point_t q[4]) { int a, b, c, d; int i; + cairo_slope_t ab, ad; + cairo_bool_t b_left_of_d; /* Choose a as a point with minimal y */ a = 0; @@ -386,24 +353,50 @@ _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, cairo_point_t q[4]) } /* Without freedom left to choose anything else, we have four - * cases to tessellate which we can distinguish by comparing c.y - * to d.y and then by comparing b.x to d.x. And then for any of - * these cases there is a trivial way to emit three - * trapezoids. The 4 cases and their trapezoids are described and - * implemented below: - */ - if (q[c].y < q[d].y) { - if (q[b].x < q[d].x) { - /* c.y < d.y && b.x < d.x + * cases to tessellate. + * + * First, we have to determine the Y-axis sort of the four + * vertices, (either abcd or abdc). After that we need to detemine + * which edges will be "left" and which will be "right" in the + * resulting trapezoids. This can be determined by computing a + * slope comparison of ab and ad to determine if b is left of d or + * not. + * + * Note that "left of" here is in the sense of which edges should + * be the left vs. right edges of the trapezoid. In particular, b + * left of d does *not* mean that b.x is less than d.x. + * + * This should hopefully be made clear in the lame ASCII art + * below. Since the same slope comparison is used in all cases, we + * compute it before testing for the Y-value sort. */ + + /* Note: If a == b then the ab slope doesn't give us any + * information. In that case, we can replace it with the ac (or + * equivalenly the bc) slope which gives us exactly the same + * information we need. At worst the names of the identifiers ab + * and b_left_of_d are inaccurate in this case, (would be ac, and + * c_left_of_d). */ + if (q[a].x == q[b].x && q[a].y == q[b].y) + _cairo_slope_init (&ab, &q[a], &q[c]); + else + _cairo_slope_init (&ab, &q[a], &q[b]); + + _cairo_slope_init (&ad, &q[a], &q[d]); + + b_left_of_d = (_cairo_slope_compare (&ab, &ad) > 0); + + if (q[c].y <= q[d].y) { + if (b_left_of_d) { + /* Y-sort is abcd and b is left of d, (slope(ab) > slope (ad)) * - * top bot left right - * a - * / | a.y b.y ab ad - * b | - * | | b.y c.y bc ad - * c | - * \ | c.y d.y cd ad - * d + * top bot left right + * _a a a + * / / /| |\ a.y b.y ab ad + * b / b | b \ + * / / | | \ \ b.y c.y bc ad + * c / c | c \ + * | / \| \ \ c.y d.y cd ad + * d d d */ _cairo_traps_add_trap_from_points (traps, q[a].y, q[b].y, @@ -415,15 +408,15 @@ _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, cairo_point_t q[4]) q[c].y, q[d].y, q[c], q[d], q[a], q[d]); } else { - /* c.y < d.y && b.x >= d.x + /* Y-sort is abcd and b is right of d, (slope(ab) <= slope (ad)) * - * a - * | \ a.y b.y ad ab - * | b - * | | b.y c.y ad bc - * | c - * | / c.y d.y ad cd - * d + * a a a_ + * /| |\ \ \ a.y b.y ad ab + * / b | b \ b + * / / | | \ \ b.y c.y ad bc + * / c | c \ c + * / / |/ \ | c.y d.y ad cd + * d d d */ _cairo_traps_add_trap_from_points (traps, q[a].y, q[b].y, @@ -436,16 +429,16 @@ _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, cairo_point_t q[4]) q[a], q[d], q[c], q[d]); } } else { - if (q[b].x < q[d].x) { - /* c.y >= d.y && b.x < d.x + if (b_left_of_d) { + /* Y-sort is abdc and b is left of d, (slope (ab) > slope (ad)) * - * a - * / \ a.y b.y ab ad - * b \ - * \ \ b.y d.y bc ad - * \ d - * \ / d.y c.y bc dc - * c + * a a a + * // / \ |\ a.y b.y ab ad + * /b/ b \ b \ + * / / \ \ \ \ b.y d.y bc ad + * /d/ \ d \ d + * // \ / \| d.y c.y bc dc + * c c c */ _cairo_traps_add_trap_from_points (traps, q[a].y, q[b].y, @@ -457,15 +450,15 @@ _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, cairo_point_t q[4]) q[d].y, q[c].y, q[b], q[c], q[d], q[c]); } else { - /* c.y >= d.y && b.x >= d.x + /* Y-sort is abdc and b is right of d, (slope (ab) <= slope (ad)) * - * a - * / \ a.y b.y ad ab - * / b - * / / b.y d.y ad bc - * d / - * \ / d.y c.y dc bc - * c + * a a a + * /| / \ \\ a.y b.y ad ab + * / b / b \b\ + * / / / / \ \ b.y d.y ad bc + * d / d / \d\ + * |/ \ / \\ d.y c.y dc bc + * c c c */ _cairo_traps_add_trap_from_points (traps, q[a].y, q[b].y, @@ -482,400 +475,6 @@ _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, cairo_point_t q[4]) return traps->status; } -static int -_compare_cairo_edge_by_top (const void *av, const void *bv) -{ - const cairo_edge_t *a = av, *b = bv; - - return a->edge.p1.y - b->edge.p1.y; -} - -/* Return value is: - > 0 if a is "clockwise" from b, (in a mathematical, not a graphical sense) - == 0 if slope (a) == slope (b) - < 0 if a is "counter-clockwise" from b -*/ -static int -_compare_cairo_edge_by_slope (const void *av, const void *bv) -{ - const cairo_edge_t *a = av, *b = bv; - cairo_fixed_32_32_t d; - - cairo_fixed_48_16_t a_dx = a->edge.p2.x - a->edge.p1.x; - cairo_fixed_48_16_t a_dy = a->edge.p2.y - a->edge.p1.y; - cairo_fixed_48_16_t b_dx = b->edge.p2.x - b->edge.p1.x; - cairo_fixed_48_16_t b_dy = b->edge.p2.y - b->edge.p1.y; - - d = b_dy * a_dx - a_dy * b_dx; - - if (d > 0) - return 1; - else if (d == 0) - return 0; - else - return -1; -} - -static int -_compare_cairo_edge_by_current_x_slope (const void *av, const void *bv) -{ - const cairo_edge_t *a = av, *b = bv; - int ret; - - ret = a->current_x - b->current_x; - if (ret == 0) - ret = _compare_cairo_edge_by_slope (a, b); - return ret; -} - -/* XXX: Both _compute_x and _compute_inverse_slope will divide by zero - for horizontal lines. Now, we "know" that when we are tessellating - polygons that the polygon data structure discards all horizontal - edges, but there's nothing here to guarantee that. I suggest the - following: - - A) Move all of the polygon tessellation code out of xrtraps.c and - into xrpoly.c, (in order to be in the same module as the code - discarding horizontal lines). - - OR - - B) Re-implement the line intersection in a way that avoids all - division by zero. Here's one approach. The only disadvantage - might be that that there are not meaningful names for all of the - sub-computations -- just a bunch of determinants. I haven't - looked at complexity, (both are probably similar and it probably - doesn't matter much anyway). - */ - -/* XXX: Keith's new intersection code is much cleaner, and uses - * sufficient precision for correctly sorting intersections according - * to the analysis in Hobby's paper. - * - * But, when we enable this code, some things are failing, (eg. the - * stars in test/fill_rule get filled wrong). This could indicate a - * bug in one of tree places: - * - * 1) The new intersection code in this file - * - * 2) cairo_wideint.c (which is only exercised here) - * - * 3) In the current tessellator, (where the old intersection - * code, with its mystic increments could be masking the bug). - * - * It will likely be easier to revisit this when the new tessellation - * code is in place. So, for now, we'll simply disable the new - * intersection code. - */ - -#define CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE 0 - -#if CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE -static const cairo_fixed_32_32_t -_det16_32 (cairo_fixed_16_16_t a, - cairo_fixed_16_16_t b, - cairo_fixed_16_16_t c, - cairo_fixed_16_16_t d) -{ - return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d), - _cairo_int32x32_64_mul (b, c)); -} - -static const cairo_fixed_64_64_t -_det32_64 (cairo_fixed_32_32_t a, - cairo_fixed_32_32_t b, - cairo_fixed_32_32_t c, - cairo_fixed_32_32_t d) -{ - return _cairo_int128_sub (_cairo_int64x64_128_mul (a, d), - _cairo_int64x64_128_mul (b, c)); -} - -static const cairo_fixed_32_32_t -_fixed_16_16_to_fixed_32_32 (cairo_fixed_16_16_t a) -{ - return _cairo_int64_lsl (_cairo_int32_to_int64 (a), 16); -} - -static int -_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection) -{ - cairo_fixed_16_16_t dx1, dx2, dy1, dy2; - cairo_fixed_32_32_t den_det; - cairo_fixed_32_32_t l1_det, l2_det; - cairo_fixed_64_64_t num_det; - cairo_fixed_32_32_t intersect_32_32; - cairo_fixed_48_16_t intersect_48_16; - cairo_fixed_16_16_t intersect_16_16; - cairo_quorem128_t qr; - - dx1 = l1->p1.x - l1->p2.x; - dy1 = l1->p1.y - l1->p2.y; - dx2 = l2->p1.x - l2->p2.x; - dy2 = l2->p1.y - l2->p2.y; - den_det = _det16_32 (dx1, dy1, - dx2, dy2); - - if (_cairo_int64_eq (den_det, _cairo_int32_to_int64(0))) - return 0; - - l1_det = _det16_32 (l1->p1.x, l1->p1.y, - l1->p2.x, l1->p2.y); - l2_det = _det16_32 (l2->p1.x, l2->p1.y, - l2->p2.x, l2->p2.y); - - num_det = _det32_64 (l1_det, _fixed_16_16_to_fixed_32_32 (dy1), - l2_det, _fixed_16_16_to_fixed_32_32 (dy2)); - - /* - * Ok, this one is a bit tricky in fixed point, the denominator - * needs to be left with 32-bits of fraction so that the - * result of the divide ends up with 32-bits of fraction (64 - 32 = 32) - */ - qr = _cairo_int128_divrem (num_det, _cairo_int64_to_int128 (den_det)); - - intersect_32_32 = _cairo_int128_to_int64 (qr.quo); - - /* - * Find the ceiling of the quotient -- divrem returns - * the quotient truncated towards zero, so if the - * quotient should be positive (num_den and den_det have same sign) - * bump the quotient up by one. - */ - - if (_cairo_int128_ne (qr.rem, _cairo_int32_to_int128 (0)) && - (_cairo_int128_ge (num_det, _cairo_int32_to_int128 (0)) == - _cairo_int64_ge (den_det, _cairo_int32_to_int64 (0)))) - { - intersect_32_32 = _cairo_int64_add (intersect_32_32, - _cairo_int32_to_int64 (1)); - } - - /* - * Now convert from 32.32 to 48.16 and take the ceiling; - * this requires adding in 15 1 bits and shifting the result - */ - - intersect_32_32 = _cairo_int64_add (intersect_32_32, - _cairo_int32_to_int64 ((1 << 16) - 1)); - intersect_48_16 = _cairo_int64_rsa (intersect_32_32, 16); - - /* - * And drop the top bits - */ - intersect_16_16 = _cairo_int64_to_int32 (intersect_48_16); - - *y_intersection = intersect_16_16; - - return 1; -} -#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */ - -static cairo_fixed_16_16_t -_compute_x (cairo_line_t *line, cairo_fixed_t y) -{ - cairo_fixed_16_16_t dx = line->p2.x - line->p1.x; - cairo_fixed_32_32_t ex = (cairo_fixed_48_16_t) (y - line->p1.y) * (cairo_fixed_48_16_t) dx; - cairo_fixed_16_16_t dy = line->p2.y - line->p1.y; - - return line->p1.x + (ex / dy); -} - -#if ! CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE -static double -_compute_inverse_slope (cairo_line_t *l) -{ - return (_cairo_fixed_to_double (l->p2.x - l->p1.x) / - _cairo_fixed_to_double (l->p2.y - l->p1.y)); -} - -static double -_compute_x_intercept (cairo_line_t *l, double inverse_slope) -{ - return _cairo_fixed_to_double (l->p1.x) - inverse_slope * _cairo_fixed_to_double (l->p1.y); -} - -static int -_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_ret) -{ - /* - * x = m1y + b1 - * x = m2y + b2 - * m1y + b1 = m2y + b2 - * y * (m1 - m2) = b2 - b1 - * y = (b2 - b1) / (m1 - m2) - */ - cairo_fixed_16_16_t y_intersect; - double m1 = _compute_inverse_slope (l1); - double b1 = _compute_x_intercept (l1, m1); - double m2 = _compute_inverse_slope (l2); - double b2 = _compute_x_intercept (l2, m2); - - if (m1 == m2) - return 0; - - y_intersect = _cairo_fixed_from_double ((b2 - b1) / (m1 - m2)); - - if (m1 < m2) { - cairo_line_t *t; - t = l1; - l1 = l2; - l2 = t; - } - - /* Assuming 56 bits of floating point precision, the intersection - is accurate within one sub-pixel coordinate. We must ensure - that we return a value that is at or after the intersection. At - most, we must increment once. */ - if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect)) - y_intersect++; - /* XXX: Hmm... Keith's error calculations said we'd at most be off - by one sub-pixel. But, I found that the paint-fill-BE-01.svg - test from the W3C SVG conformance suite definitely requires two - increments. - - It could be that we need one to overcome the error, and another - to round up. - - It would be nice to be sure this code is correct, (but we can't - do the while loop as it will work for way to long on - exceedingly distant intersections with large errors that we - really don't care about anyway as they will be ignored by the - calling function. - */ - if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect)) - y_intersect++; - /* XXX: hmm... now I found "intersection_killer" inside xrspline.c - that requires 3 increments. Clearly, we haven't characterized - this completely yet. */ - if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect)) - y_intersect++; - /* I think I've found the answer to our problems. The insight is - that everytime we round we are changing the slopes of the - relevant lines, so we may be introducing new intersections that - we miss, so everything breaks apart. John Hobby wrote a paper - on how to fix this: - - [Hobby93c] John D. Hobby, Practical Segment Intersection with - Finite Precision Output, Computation Geometry Theory and - Applications, 13(4), 1999. - - Available online (2003-08017): - - http://cm.bell-labs.com/cm/cs/doc/93/2-27.ps.gz - - Now we just need to go off and implement that. - */ - - *y_ret = y_intersect; - - return 1; -} -#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */ - -/* The algorithm here is pretty simple: - - inactive = [edges] - y = min_p1_y (inactive) - - while (num_active || num_inactive) { - active = all edges containing y - - next_y = min ( min_p2_y (active), min_p1_y (inactive), min_intersection (active) ) - - fill_traps (active, y, next_y, fill_rule) - - y = next_y - } - - The invariants that hold during fill_traps are: - - All edges in active contain both y and next_y - No edges in active intersect within y and next_y - - These invariants mean that fill_traps is as simple as sorting the - active edges, forming a trapezoid between each adjacent pair. Then, - either the even-odd or winding rule is used to determine whether to - emit each of these trapezoids. - - Warning: This function obliterates the edges of the polygon provided. -*/ -cairo_status_t -_cairo_traps_tessellate_polygon (cairo_traps_t *traps, - cairo_polygon_t *poly, - cairo_fill_rule_t fill_rule) -{ - int i, active, inactive; - cairo_fixed_t y, y_next, intersect; - int in_out, num_edges = poly->num_edges; - cairo_edge_t *edges = poly->edges; - - if (num_edges == 0) - return CAIRO_STATUS_SUCCESS; - - qsort (edges, num_edges, sizeof (cairo_edge_t), _compare_cairo_edge_by_top); - - y = edges[0].edge.p1.y; - active = 0; - inactive = 0; - while (active < num_edges) { - while (inactive < num_edges && edges[inactive].edge.p1.y <= y) - inactive++; - - for (i = active; i < inactive; i++) - edges[i].current_x = _compute_x (&edges[i].edge, y); - - qsort (&edges[active], inactive - active, - sizeof (cairo_edge_t), _compare_cairo_edge_by_current_x_slope); - - /* find next inflection point */ - y_next = edges[active].edge.p2.y; - - for (i = active; i < inactive; i++) { - if (edges[i].edge.p2.y < y_next) - y_next = edges[i].edge.p2.y; - /* check intersect */ - if (i != inactive - 1 && edges[i].current_x != edges[i+1].current_x) - if (_line_segs_intersect_ceil (&edges[i].edge, &edges[i+1].edge, - &intersect)) - if (intersect > y && intersect < y_next) - y_next = intersect; - } - /* check next inactive point */ - if (inactive < num_edges && edges[inactive].edge.p1.y < y_next) - y_next = edges[inactive].edge.p1.y; - - /* walk the active edges generating trapezoids */ - in_out = 0; - for (i = active; i < inactive - 1; i++) { - if (fill_rule == CAIRO_FILL_RULE_WINDING) { - if (edges[i].clockWise) - in_out++; - else - in_out--; - if (in_out == 0) - continue; - } else { - in_out++; - if ((in_out & 1) == 0) - continue; - } - _cairo_traps_add_trap (traps, y, y_next, &edges[i].edge, &edges[i+1].edge); - } - - /* delete inactive edges */ - for (i = active; i < inactive; i++) { - if (edges[i].edge.p2.y <= y_next) { - memmove (&edges[active+1], &edges[active], (i - active) * sizeof (cairo_edge_t)); - active++; - } - } - - y = y_next; - } - return traps->status; -} - static cairo_bool_t _cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt) { diff --git a/gfx/cairo/cairo/src/cairo-truetype-subset-private.h b/gfx/cairo/cairo/src/cairo-truetype-subset-private.h index e9b2c47e47c..e4be77ce182 100644 --- a/gfx/cairo/cairo/src/cairo-truetype-subset-private.h +++ b/gfx/cairo/cairo/src/cairo-truetype-subset-private.h @@ -62,9 +62,33 @@ #define TT_TAG_loca MAKE_TT_TAG('l','o','c','a') #define TT_TAG_maxp MAKE_TT_TAG('m','a','x','p') #define TT_TAG_name MAKE_TT_TAG('n','a','m','e') +#define TT_TAG_post MAKE_TT_TAG('p','o','s','t') #define TT_TAG_prep MAKE_TT_TAG('p','r','e','p') /* All tt_* structs are big-endian */ +typedef struct _tt_cmap_index { + uint16_t platform; + uint16_t encoding; + uint32_t offset; +} tt_cmap_index_t; + +typedef struct _tt_cmap { + uint16_t version; + uint16_t num_tables; + tt_cmap_index_t index[1]; +} tt_cmap_t; + +typedef struct _segment_map { + uint16_t format; + uint16_t length; + uint16_t version; + uint16_t segCountX2; + uint16_t searchRange; + uint16_t entrySelector; + uint16_t rangeShift; + uint16_t endCount[1]; +} tt_segment_map_t; + typedef struct _tt_head { int16_t version_1; int16_t version_2; diff --git a/gfx/cairo/cairo/src/cairo-truetype-subset.c b/gfx/cairo/cairo/src/cairo-truetype-subset.c index 86509dfb19a..7e77bb8aaae 100644 --- a/gfx/cairo/cairo/src/cairo-truetype-subset.c +++ b/gfx/cairo/cairo/src/cairo-truetype-subset.c @@ -56,6 +56,7 @@ typedef struct _cairo_truetype_font { int *widths; long x_min, y_min, x_max, y_max; long ascent, descent; + int units_per_em; } base; subset_glyph_t *glyphs; @@ -79,41 +80,6 @@ cairo_truetype_font_use_glyph (cairo_truetype_font_t *font, int glyph); #define SFNT_VERSION 0x00010000 #define SFNT_STRING_MAX_LENGTH 65535 -#ifdef WORDS_BIGENDIAN - -#define cpu_to_be16(v) (v) -#define be16_to_cpu(v) (v) -#define cpu_to_be32(v) (v) -#define be32_to_cpu(v) (v) - -#else - -static inline uint16_t -cpu_to_be16(uint16_t v) -{ - return (v << 8) | (v >> 8); -} - -static inline uint16_t -be16_to_cpu(uint16_t v) -{ - return cpu_to_be16 (v); -} - -static inline uint32_t -cpu_to_be32(uint32_t v) -{ - return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16); -} - -static inline uint32_t -be32_to_cpu(uint32_t v) -{ - return cpu_to_be32 (v); -} - -#endif - static cairo_status_t _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, cairo_truetype_font_t **font_return) @@ -200,6 +166,9 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, font->base.y_max = (int16_t) be16_to_cpu (head.y_max); font->base.ascent = (int16_t) be16_to_cpu (hhea.ascender); font->base.descent = (int16_t) be16_to_cpu (hhea.descender); + font->base.units_per_em = (int16_t) be16_to_cpu (head.units_per_em); + if (font->base.units_per_em == 0) + font->base.units_per_em = 2048; /* Extract the font name from the name table. At present this * just looks for the Mac platform/Roman encoded font name. It @@ -371,22 +340,45 @@ cairo_truetype_font_write_cmap_table (cairo_truetype_font_t *font, { unsigned int i; - cairo_truetype_font_write_be16 (font, 0); - cairo_truetype_font_write_be16 (font, 1); + cairo_truetype_font_write_be16 (font, 0); /* Table version */ + cairo_truetype_font_write_be16 (font, 2); /* Num tables */ - cairo_truetype_font_write_be16 (font, 1); - cairo_truetype_font_write_be16 (font, 0); - cairo_truetype_font_write_be32 (font, 12); + cairo_truetype_font_write_be16 (font, 3); /* Platform */ + cairo_truetype_font_write_be16 (font, 0); /* Encoding */ + cairo_truetype_font_write_be32 (font, 20); /* Offset to start of table */ + + cairo_truetype_font_write_be16 (font, 1); /* Platform */ + cairo_truetype_font_write_be16 (font, 0); /* Encoding */ + cairo_truetype_font_write_be32 (font, 52); /* Offset to start of table */ + + /* Output a format 4 encoding table. */ + + cairo_truetype_font_write_be16 (font, 4); /* Format */ + cairo_truetype_font_write_be16 (font, 32); /* Length */ + cairo_truetype_font_write_be16 (font, 0); /* Version */ + cairo_truetype_font_write_be16 (font, 4); /* 2*segcount */ + cairo_truetype_font_write_be16 (font, 4); /* searchrange */ + cairo_truetype_font_write_be16 (font, 1); /* entry selector */ + cairo_truetype_font_write_be16 (font, 0); /* rangeshift */ + cairo_truetype_font_write_be16 (font, 0xf000 + font->base.num_glyphs - 2); /* end count[0] */ + cairo_truetype_font_write_be16 (font, 0xffff); /* end count[1] */ + cairo_truetype_font_write_be16 (font, 0); /* reserved */ + cairo_truetype_font_write_be16 (font, 0xf000); /* startCode[0] */ + cairo_truetype_font_write_be16 (font, 0xffff); /* startCode[1] */ + cairo_truetype_font_write_be16 (font, 0x1001); /* delta[0] */ + cairo_truetype_font_write_be16 (font, 1); /* delta[1] */ + cairo_truetype_font_write_be16 (font, 0); /* rangeOffset[0] */ + cairo_truetype_font_write_be16 (font, 0); /* rangeOffset[1] */ /* Output a format 6 encoding table. */ cairo_truetype_font_write_be16 (font, 6); cairo_truetype_font_write_be16 (font, 10 + 2 * (font->base.num_glyphs - 1)); cairo_truetype_font_write_be16 (font, 0); - cairo_truetype_font_write_be16 (font, 1); /* First glyph */ - cairo_truetype_font_write_be16 (font, font->base.num_glyphs - 1); - for (i = 1; i < font->base.num_glyphs; i++) - cairo_truetype_font_write_be16 (font, i); + cairo_truetype_font_write_be16 (font, 0); /* First character */ + cairo_truetype_font_write_be16 (font, font->base.num_glyphs); + for (i = 0; i < font->base.num_glyphs; i++) + cairo_truetype_font_write_be16 (font, i + 1); return font->status; } @@ -532,6 +524,9 @@ cairo_truetype_font_write_head_table (cairo_truetype_font_t *font, font->status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer); font->backend->load_truetype_table( font->scaled_font_subset->scaled_font, tag, 0, buffer, &size); + /* set checkSumAdjustment to 0 for table checksum calcualtion */ + *(uint32_t *)(buffer + 8) = 0; + return font->status; } @@ -640,28 +635,65 @@ cairo_truetype_font_write_maxp_table (cairo_truetype_font_t *font, return font->status; } +static int +cairo_truetype_font_write_post_table (cairo_truetype_font_t *font, + unsigned long tag) +{ + char buf[10]; + int n; + unsigned i; + + cairo_truetype_font_write_be32 (font, 0x00020000); + cairo_truetype_font_write_be32 (font, 0); + cairo_truetype_font_write_be16 (font, 0); + cairo_truetype_font_write_be16 (font, 1); + cairo_truetype_font_write_be32 (font, 0); + cairo_truetype_font_write_be32 (font, 0); + cairo_truetype_font_write_be32 (font, 0); + cairo_truetype_font_write_be32 (font, 0); + cairo_truetype_font_write_be32 (font, 0); + cairo_truetype_font_write_be16 (font, font->base.num_glyphs); + cairo_truetype_font_write_be16 (font, 0); + for (i = 1; i < font->base.num_glyphs; i++) + cairo_truetype_font_write_be16 (font, i + 257); + + for (i = 1; i < font->base.num_glyphs; i++) { + n = snprintf(buf + 1, 9, "g%d", i - 1); + buf[0] = n; + cairo_truetype_font_write (font, buf, n + 1); + } + + return font->status; +} + typedef struct table table_t; struct table { unsigned long tag; int (*write) (cairo_truetype_font_t *font, unsigned long tag); + int pos; /* position in the font directory */ }; static const table_t truetype_tables[] = { /* As we write out the glyf table we remap composite glyphs. * Remapping composite glyphs will reference the sub glyphs the * composite glyph is made up of. That needs to be done first so - * we have all the glyphs in the subset before going further. */ - { TT_TAG_glyf, cairo_truetype_font_write_glyf_table }, - { TT_TAG_cmap, cairo_truetype_font_write_cmap_table }, - { TT_TAG_cvt, cairo_truetype_font_write_generic_table }, - { TT_TAG_fpgm, cairo_truetype_font_write_generic_table }, - { TT_TAG_head, cairo_truetype_font_write_head_table }, - { TT_TAG_hhea, cairo_truetype_font_write_hhea_table }, - { TT_TAG_hmtx, cairo_truetype_font_write_hmtx_table }, - { TT_TAG_loca, cairo_truetype_font_write_loca_table }, - { TT_TAG_maxp, cairo_truetype_font_write_maxp_table }, - { TT_TAG_name, cairo_truetype_font_write_generic_table }, - { TT_TAG_prep, cairo_truetype_font_write_generic_table }, + * we have all the glyphs in the subset before going further. + * + * The third column in this table is the order in which the + * directory entries will appear in the table directory. + * The table directory must be sorted in tag order. */ + { TT_TAG_glyf, cairo_truetype_font_write_glyf_table, 3 }, + { TT_TAG_cmap, cairo_truetype_font_write_cmap_table, 0 }, + { TT_TAG_cvt, cairo_truetype_font_write_generic_table, 1 }, + { TT_TAG_fpgm, cairo_truetype_font_write_generic_table, 2 }, + { TT_TAG_head, cairo_truetype_font_write_head_table, 4 }, + { TT_TAG_hhea, cairo_truetype_font_write_hhea_table, 5 }, + { TT_TAG_hmtx, cairo_truetype_font_write_hmtx_table, 6 }, + { TT_TAG_loca, cairo_truetype_font_write_loca_table, 7 }, + { TT_TAG_maxp, cairo_truetype_font_write_maxp_table, 8 }, + { TT_TAG_name, cairo_truetype_font_write_generic_table, 9 }, + { TT_TAG_post, cairo_truetype_font_write_post_table, 10 }, + { TT_TAG_prep, cairo_truetype_font_write_generic_table, 11 }, }; static cairo_status_t @@ -716,7 +748,7 @@ cairo_truetype_font_calculate_checksum (cairo_truetype_font_t *font, p = (uint32_t *) (data + start); padded_end = (uint32_t *) (data + ((end + 3) & ~3)); while (p < padded_end) - checksum += *p++; + checksum += be32_to_cpu(*p++); return checksum; } @@ -761,7 +793,7 @@ cairo_truetype_font_generate (cairo_truetype_font_t *font, end = _cairo_array_num_elements (&font->output); next = cairo_truetype_font_align_output (font); - cairo_truetype_font_update_entry (font, i, truetype_tables[i].tag, + cairo_truetype_font_update_entry (font, truetype_tables[i].pos, truetype_tables[i].tag, start, end); cairo_truetype_font_check_boundary (font, next); start = next; @@ -813,6 +845,10 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset, if (status) return status; + /* Add the notdef glyph. This is required at glyph index 0 + * in the subsetted font. */ + cairo_truetype_font_use_glyph (font, 0); + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { parent_glyph = font->scaled_font_subset->glyphs[i]; cairo_truetype_font_use_glyph (font, parent_glyph); @@ -827,18 +863,23 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset, if (truetype_subset->base_font == NULL) goto fail1; - truetype_subset->widths = calloc (sizeof (int), font->base.num_glyphs); + /* The widths array returned must contain only widths for + * the glyphs in font_subset. The notdef glyph at index 0 + * and any subglyphs appended after font_subset->num_glyphs + * are omitted. */ + truetype_subset->widths = calloc (sizeof (double), + font->scaled_font_subset->num_glyphs); if (truetype_subset->widths == NULL) goto fail2; - for (i = 0; i < font->base.num_glyphs; i++) - truetype_subset->widths[i] = font->base.widths[i]; + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) + truetype_subset->widths[i] = (double)font->base.widths[i + 1]/font->base.units_per_em; - truetype_subset->x_min = font->base.x_min; - truetype_subset->y_min = font->base.y_min; - truetype_subset->x_max = font->base.x_max; - truetype_subset->y_max = font->base.y_max; - truetype_subset->ascent = font->base.ascent; - truetype_subset->descent = font->base.descent; + truetype_subset->x_min = (double)font->base.x_min/font->base.units_per_em; + truetype_subset->y_min = (double)font->base.y_min/font->base.units_per_em; + truetype_subset->x_max = (double)font->base.x_max/font->base.units_per_em; + truetype_subset->y_max = (double)font->base.y_max/font->base.units_per_em; + truetype_subset->ascent = (double)font->base.ascent/font->base.units_per_em; + truetype_subset->descent = (double)font->base.descent/font->base.units_per_em; truetype_subset->data = malloc (length); if (truetype_subset->data == NULL) @@ -880,3 +921,145 @@ _cairo_truetype_subset_fini (cairo_truetype_subset_t *subset) free (subset->string_offsets); } +static cairo_int_status_t +_cairo_truetype_map_glyphs_to_unicode (cairo_scaled_font_subset_t *font_subset, + unsigned long table_offset) +{ + cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + const cairo_scaled_font_backend_t *backend; + tt_segment_map_t *map; + char buf[4]; + unsigned int num_segments, i, j; + unsigned long size; + uint16_t *start_code; + uint16_t *end_code; + uint16_t *delta; + uint16_t *range_offset; + uint16_t *glyph_array; + uint16_t g_id, c; + + backend = font_subset->scaled_font->backend; + size = 4; + if (backend->load_truetype_table (font_subset->scaled_font, + TT_TAG_cmap, table_offset, + (unsigned char *) &buf, + &size) != CAIRO_STATUS_SUCCESS) { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* All table formats have the same first two words */ + map = (tt_segment_map_t *) buf; + if (be16_to_cpu (map->format) != 4) + return CAIRO_INT_STATUS_UNSUPPORTED; + + size = be16_to_cpu (map->length); + map = malloc (size); + if (map == NULL) + return CAIRO_STATUS_NO_MEMORY; + if (backend->load_truetype_table (font_subset->scaled_font, + TT_TAG_cmap, table_offset, + (unsigned char *) map, + &size) != CAIRO_STATUS_SUCCESS) { + goto fail; + } + + num_segments = be16_to_cpu (map->segCountX2)/2; + end_code = map->endCount; + start_code = &(end_code[num_segments + 1]); + delta = &(start_code[num_segments]); + range_offset = &(delta[num_segments]); + glyph_array = &(range_offset[num_segments]); + + i = 0; + while (i < font_subset->num_glyphs) { + g_id = (uint16_t) font_subset->glyphs[i]; + + /* search for glyph in segments + * with rangeOffset=0 */ + for (j = 0; j < num_segments; j++) { + c = g_id - be16_to_cpu (delta[j]); + if (range_offset[j] == 0 && + c >= be16_to_cpu (start_code[j]) && + c <= be16_to_cpu (end_code[j])) + { + font_subset->to_unicode[i] = c; + goto next_glyph; + } + } + + /* search for glyph in segments with rangeOffset=1 */ + for (j = 0; j < num_segments; j++) { + if (range_offset[j] != 0) { + uint16_t *glyph_ids = &range_offset[j] + be16_to_cpu (range_offset[j])/2; + int range_size = be16_to_cpu (end_code[j]) - be16_to_cpu (start_code[j]) + 1; + uint16_t g_id_be = cpu_to_be16 (g_id); + int k; + + for (k = 0; k < range_size; k++) { + if (glyph_ids[k] == g_id_be) { + font_subset->to_unicode[i] = be16_to_cpu (start_code[j]) + k; + goto next_glyph; + } + } + } + } + + next_glyph: + i++; + } + status = CAIRO_STATUS_SUCCESS; +fail: + free (map); + + return status; +} + +cairo_int_status_t +_cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t *font_subset) +{ + cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + const cairo_scaled_font_backend_t *backend; + tt_cmap_t *cmap; + char buf[4]; + int num_tables, i; + unsigned long size; + + backend = font_subset->scaled_font->backend; + if (!backend->load_truetype_table) + return CAIRO_INT_STATUS_UNSUPPORTED; + + size = 4; + if (backend->load_truetype_table (font_subset->scaled_font, + TT_TAG_cmap, 0, (unsigned char *) &buf, + &size) != CAIRO_STATUS_SUCCESS) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cmap = (tt_cmap_t *) buf; + num_tables = be16_to_cpu (cmap->num_tables); + size = 4 + num_tables*sizeof(tt_cmap_index_t); + cmap = malloc (size); + if (cmap == NULL) + return CAIRO_STATUS_NO_MEMORY; + if (backend->load_truetype_table (font_subset->scaled_font, + TT_TAG_cmap, 0, (unsigned char *) cmap, + &size) != CAIRO_STATUS_SUCCESS) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto cleanup; + } + + /* Find a table with Unicode mapping */ + for (i = 0; i < num_tables; i++) { + if (be16_to_cpu (cmap->index[i].platform) == 3 && + be16_to_cpu (cmap->index[i].encoding) == 1) { + status = _cairo_truetype_map_glyphs_to_unicode (font_subset, + be32_to_cpu (cmap->index[i].offset)); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + goto cleanup; + } + } + +cleanup: + free (cmap); + + return status; +} diff --git a/gfx/cairo/cairo/src/cairo-type1-fallback.c b/gfx/cairo/cairo/src/cairo-type1-fallback.c index 4776faf6d67..a183b28b497 100644 --- a/gfx/cairo/cairo/src/cairo-type1-fallback.c +++ b/gfx/cairo/cairo/src/cairo-type1-fallback.c @@ -34,6 +34,7 @@ */ #include "cairoint.h" +#include "cairo-type1-private.h" #include "cairo-scaled-font-subsets-private.h" #include "cairo-path-fixed-private.h" #include "cairo-output-stream-private.h" @@ -116,11 +117,6 @@ fail: return CAIRO_STATUS_NO_MEMORY; } -/* Magic constants for the type1 eexec encryption */ -static const unsigned short encrypt_c1 = 52845, encrypt_c2 = 22719; -static const unsigned short private_dict_key = 55665; -static const unsigned short charstring_key = 4330; - /* Charstring commands. If the high byte is 0 the command is encoded * with a single byte. */ #define CHARSTRING_sbw 0x0c07 @@ -301,13 +297,13 @@ charstring_encrypt (cairo_array_t *data) unsigned char *d, *end; uint16_t c, p, r; - r = charstring_key; + r = CAIRO_TYPE1_CHARSTRING_KEY; d = (unsigned char *) _cairo_array_index (data, 0); end = d + _cairo_array_num_elements (data); while (d < end) { p = *d; c = p ^ (r >> 8); - r = (c + r) * encrypt_c1 + encrypt_c2; + r = (c + r) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2; *d++ = c; } } @@ -534,7 +530,7 @@ cairo_type1_write_stream_encrypted (void *closure, while (in < end) { p = *in++; c = p ^ (font->eexec_key >> 8); - font->eexec_key = (c + font->eexec_key) * encrypt_c1 + encrypt_c2; + font->eexec_key = (c + font->eexec_key) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2; if (font->hex_encode) { digits[0] = hex_digits[c >> 4]; @@ -564,7 +560,7 @@ cairo_type1_font_write_private_dict (cairo_type1_font_t *font, cairo_int_status_t status; cairo_output_stream_t *encrypted_output; - font->eexec_key = private_dict_key; + font->eexec_key = CAIRO_TYPE1_PRIVATE_DICT_KEY; font->hex_column = 0; encrypted_output = _cairo_output_stream_create ( cairo_type1_write_stream_encrypted, @@ -680,8 +676,9 @@ static void cairo_type1_font_destroy (cairo_type1_font_t *font) { free (font->widths); - _cairo_array_fini (&font->contents); cairo_scaled_font_destroy (font->type1_scaled_font); + _cairo_array_fini (&font->contents); + _cairo_output_stream_destroy (font->output); free (font); } diff --git a/gfx/cairo/cairo/src/cairo-type1-subset.c b/gfx/cairo/cairo/src/cairo-type1-subset.c index 4455ca59fa6..e4f5015dd7b 100644 --- a/gfx/cairo/cairo/src/cairo-type1-subset.c +++ b/gfx/cairo/cairo/src/cairo-type1-subset.c @@ -34,6 +34,7 @@ */ #include "cairoint.h" +#include "cairo-type1-private.h" #include "cairo-scaled-font-subsets-private.h" #include "cairo-output-stream-private.h" @@ -107,6 +108,7 @@ _cairo_type1_font_subset_create (cairo_unscaled_font_t *unscaled_font, cairo_bool_t hex_encode) { cairo_ft_unscaled_font_t *ft_unscaled_font; + cairo_status_t status; FT_Face face; PS_FontInfoRec font_info; cairo_type1_font_subset_t *font; @@ -116,12 +118,16 @@ _cairo_type1_font_subset_create (cairo_unscaled_font_t *unscaled_font, face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font); - if (FT_Get_PS_Font_Info(face, &font_info) != 0) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (FT_Get_PS_Font_Info(face, &font_info) != 0) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto fail1; + } font = calloc (sizeof (cairo_type1_font_subset_t), 1); - if (font == NULL) - return CAIRO_STATUS_NO_MEMORY; + if (font == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail1; + } font->base.unscaled_font = _cairo_unscaled_font_reference (unscaled_font); font->base.num_glyphs = face->num_glyphs; @@ -132,8 +138,10 @@ _cairo_type1_font_subset_create (cairo_unscaled_font_t *unscaled_font, font->base.ascent = face->ascender; font->base.descent = face->descender; font->base.base_font = strdup (face->family_name); - if (font->base.base_font == NULL) - goto fail1; + if (font->base.base_font == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail2; + } for (i = 0, j = 0; font->base.base_font[j]; j++) { if (font->base.base_font[j] == ' ') @@ -143,8 +151,10 @@ _cairo_type1_font_subset_create (cairo_unscaled_font_t *unscaled_font, font->base.base_font[i] = '\0'; font->glyphs = calloc (face->num_glyphs, sizeof font->glyphs[0]); - if (font->glyphs == NULL) - goto fail2; + if (font->glyphs == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail3; + } font->hex_encode = hex_encode; font->num_glyphs = 0; @@ -159,12 +169,15 @@ _cairo_type1_font_subset_create (cairo_unscaled_font_t *unscaled_font, return CAIRO_STATUS_SUCCESS; - fail2: + fail3: free (font->base.base_font); - fail1: + fail2: + _cairo_unscaled_font_destroy (unscaled_font); free (font); + fail1: + _cairo_ft_unscaled_font_unlock_face (ft_unscaled_font); - return CAIRO_STATUS_NO_MEMORY; + return status; } static int @@ -179,11 +192,6 @@ cairo_type1_font_subset_use_glyph (cairo_type1_font_subset_t *font, int glyph) return font->glyphs[glyph].subset_index; } -/* Magic constants for the type1 eexec encryption */ -static const unsigned short c1 = 52845, c2 = 22719; -static const unsigned short private_dict_key = 55665; -static const unsigned short charstring_key = 4330; - static cairo_bool_t is_ps_delimiter(int c) { @@ -325,7 +333,7 @@ cairo_type1_font_subset_write_encrypted (cairo_type1_font_subset_t *font, while (in < end) { p = *in++; c = p ^ (font->eexec_key >> 8); - font->eexec_key = (c + font->eexec_key) * c1 + c2; + font->eexec_key = (c + font->eexec_key) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2; if (font->hex_encode) { digits[0] = hex_digits[c >> 4]; @@ -349,7 +357,7 @@ cairo_type1_font_subset_write_encrypted (cairo_type1_font_subset_t *font, static cairo_status_t cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font) { - unsigned short r = private_dict_key; + unsigned short r = CAIRO_TYPE1_PRIVATE_DICT_KEY; unsigned char *in, *end; char *out; int c, p; @@ -372,7 +380,7 @@ cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font) c = *in++; } p = c ^ (r >> 8); - r = (c + r) * c1 + c2; + r = (c + r) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2; *out++ = p; } @@ -452,13 +460,13 @@ cairo_type1_font_subset_get_glyph_names_and_widths (cairo_type1_font_subset_t *f static void cairo_type1_font_subset_decrypt_charstring (const unsigned char *in, int size, unsigned char *out) { - unsigned short r = charstring_key; + unsigned short r = CAIRO_TYPE1_CHARSTRING_KEY; int c, p, i; for (i = 0; i < size; i++) { c = *in++; p = c ^ (r >> 8); - r = (c + r) * c1 + c2; + r = (c + r) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2; *out++ = p; } } @@ -1004,7 +1012,7 @@ cairo_type1_font_subset_write (cairo_type1_font_subset_t *font, return font->status = CAIRO_INT_STATUS_UNSUPPORTED; } - font->eexec_key = private_dict_key; + font->eexec_key = CAIRO_TYPE1_PRIVATE_DICT_KEY; font->hex_column = 0; cairo_type1_font_subset_write_private_dict (font, name); diff --git a/gfx/cairo/cairo/src/cairo-win32-font.c b/gfx/cairo/cairo/src/cairo-win32-font.c index 139a73b34df..de81c0a262e 100644 --- a/gfx/cairo/cairo/src/cairo-win32-font.c +++ b/gfx/cairo/cairo/src/cairo-win32-font.c @@ -693,7 +693,7 @@ _cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font) if (!hdc) return CAIRO_STATUS_NO_MEMORY; - if (scaled_font->preserve_axes) { + if (scaled_font->preserve_axes || scaled_font->base.options.hint_metrics == CAIRO_HINT_METRICS_OFF) { /* For 90-degree rotations (including 0), we get the metrics * from the GDI in logical space, then convert back to font space */ @@ -723,7 +723,7 @@ _cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font) _cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base); extents.ascent = (double)metrics.tmAscent / scaled_font->em_square; - extents.descent = metrics.tmDescent * scaled_font->em_square; + extents.descent = (double)metrics.tmDescent / scaled_font->em_square; extents.height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / scaled_font->em_square; extents.max_x_advance = (double)(metrics.tmMaxCharWidth) / scaled_font->em_square; extents.max_y_advance = 0; @@ -1281,6 +1281,20 @@ _cairo_win32_scaled_font_load_truetype_table (void *abstract_font, return status; } +static void +_cairo_win32_scaled_font_map_glyphs_to_unicode (void *abstract_font, + cairo_scaled_font_subset_t *font_subset) +{ + cairo_win32_scaled_font_t *scaled_font = abstract_font; + unsigned int i; + + if (scaled_font->glyph_indexing) + return; + + for (i = 0; i < font_subset->num_glyphs; i++) + font_subset->to_unicode[i] = font_subset->glyphs[i]; +} + static void _cairo_win32_transform_FIXED_to_fixed (cairo_matrix_t *matrix, FIXED Fx, FIXED Fy, @@ -1467,6 +1481,7 @@ const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend = { NULL, /* ucs4_to_index */ _cairo_win32_scaled_font_show_glyphs, _cairo_win32_scaled_font_load_truetype_table, + _cairo_win32_scaled_font_map_glyphs_to_unicode, }; /* cairo_win32_font_face_t */ @@ -1649,7 +1664,7 @@ cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font, /** * cairo_win32_scaled_font_done_font: - * @scaled_font: A #cairo_scaled_font_t from the Win32 font backend. + * @scaled_font: A scaled font from the Win32 font backend. * * Releases any resources allocated by cairo_win32_scaled_font_select_font() **/ @@ -1660,7 +1675,7 @@ cairo_win32_scaled_font_done_font (cairo_scaled_font_t *scaled_font) /** * cairo_win32_scaled_font_get_metrics_factor: - * @scaled_font: a #cairo_scaled_font_t from the Win32 font backend + * @scaled_font: a scaled font from the Win32 font backend * * Gets a scale factor between logical coordinates in the coordinate * space used by cairo_win32_scaled_font_select_font() (that is, the @@ -1676,6 +1691,16 @@ cairo_win32_scaled_font_get_metrics_factor (cairo_scaled_font_t *scaled_font) return 1. / ((cairo_win32_scaled_font_t *)scaled_font)->logical_scale; } +/** + * cairo_win32_scaled_font_get_logical_to_device: + * @scaled_font: a scaled font from the Win32 font backend + * @logical_to_device: matrix to return + * + * Gets the transformation mapping the logical space used by @scaled_font + * to device space. + * + * Since: 1.4 + **/ void cairo_win32_scaled_font_get_logical_to_device (cairo_scaled_font_t *scaled_font, cairo_matrix_t *logical_to_device) @@ -1684,6 +1709,16 @@ cairo_win32_scaled_font_get_logical_to_device (cairo_scaled_font_t *scaled_font, *logical_to_device = win_font->logical_to_device; } +/** + * cairo_win32_scaled_font_get_device_to_logical: + * @scaled_font: a scaled font from the Win32 font backend + * @device_to_logical: matrix to return + * + * Gets the transformation mapping device space to the logical space + * used by @scaled_font. + * + * Since: 1.4 + **/ void cairo_win32_scaled_font_get_device_to_logical (cairo_scaled_font_t *scaled_font, cairo_matrix_t *device_to_logical) diff --git a/gfx/cairo/cairo/src/cairo-win32-private.h b/gfx/cairo/cairo/src/cairo-win32-private.h index ce574dc3d13..8256b20964f 100644 --- a/gfx/cairo/cairo/src/cairo-win32-private.h +++ b/gfx/cairo/cairo/src/cairo-win32-private.h @@ -46,7 +46,11 @@ #define SB_NONE 0 #endif +#if MOZILLA_CAIRO_NOT_DEFINED +#define WIN32_FONT_LOGICAL_SCALE 32 +#else #define WIN32_FONT_LOGICAL_SCALE 1 +#endif typedef struct _cairo_win32_surface { cairo_surface_t base; diff --git a/gfx/cairo/cairo/src/cairo-win32-surface.c b/gfx/cairo/cairo/src/cairo-win32-surface.c index 4025b94eca4..9123b82a0e0 100644 --- a/gfx/cairo/cairo/src/cairo-win32-surface.c +++ b/gfx/cairo/cairo/src/cairo-win32-surface.c @@ -1487,6 +1487,7 @@ _cairo_win32_surface_show_glyphs (void *surface, int num_glyphs, cairo_scaled_font_t *scaled_font) { +#if CAIRO_HAS_WIN32_FONT cairo_win32_surface_t *dst = surface; WORD glyph_buf_stack[STACK_GLYPH_SIZE]; @@ -1580,8 +1581,8 @@ _cairo_win32_surface_show_glyphs (void *surface, next_logical_x = _cairo_lround (next_user_x); next_logical_y = _cairo_lround (next_user_y); - dxy_buf[j] = _cairo_lround ((next_logical_x - logical_x) * WIN32_FONT_LOGICAL_SCALE); - dxy_buf[j+1] = _cairo_lround ((next_logical_y - logical_y) * WIN32_FONT_LOGICAL_SCALE); + dxy_buf[j] = _cairo_lround (next_logical_x - logical_x); + dxy_buf[j+1] = _cairo_lround (next_logical_y - logical_y); logical_x = next_logical_x; logical_y = next_logical_y; @@ -1607,6 +1608,9 @@ _cairo_win32_surface_show_glyphs (void *surface, free(dxy_buf); } return (win_result) ? CAIRO_STATUS_SUCCESS : CAIRO_INT_STATUS_UNSUPPORTED; +#else + return CAIRO_INT_STATUS_UNSUPPORTED; +#endif } #undef STACK_GLYPH_SIZE @@ -1728,6 +1732,7 @@ cairo_win32_surface_create_with_dib (cairo_format_t format, /** * cairo_win32_surface_create_with_ddb: + * @hdc: the DC to create a surface for * @format: format of pixels in the surface to create * @width: width of the surface, in pixels * @height: height of the surface, in pixels @@ -1890,9 +1895,11 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = { */ #if !defined(HAVE_PTHREAD_H) -CRITICAL_SECTION cairo_toy_font_face_hash_table_mutex; -CRITICAL_SECTION cairo_scaled_font_map_mutex; -CRITICAL_SECTION cairo_ft_unscaled_font_map_mutex; +CRITICAL_SECTION _cairo_scaled_font_map_mutex; +#ifdef CAIRO_HAS_FT_FONT +CRITICAL_SECTION _cairo_ft_unscaled_font_map_mutex; +#endif +CRITICAL_SECTION _cairo_font_face_mutex; static int _cairo_win32_initialized = 0; @@ -1902,9 +1909,11 @@ _cairo_win32_initialize (void) { return; /* every 'mutex' from CAIRO_MUTEX_DECALRE needs to be initialized here */ - InitializeCriticalSection (&cairo_toy_font_face_hash_table_mutex); - InitializeCriticalSection (&cairo_scaled_font_map_mutex); - InitializeCriticalSection (&cairo_ft_unscaled_font_map_mutex); + InitializeCriticalSection (&_cairo_scaled_font_map_mutex); +#ifdef CAIRO_HAS_FT_FONT + InitializeCriticalSection (&_cairo_ft_unscaled_font_map_mutex); +#endif + InitializeCriticalSection (&_cairo_font_face_mutex); _cairo_win32_initialized = 1; } @@ -1921,9 +1930,11 @@ DllMain (HINSTANCE hinstDLL, _cairo_win32_initialize(); break; case DLL_PROCESS_DETACH: - DeleteCriticalSection (&cairo_toy_font_face_hash_table_mutex); - DeleteCriticalSection (&cairo_scaled_font_map_mutex); - DeleteCriticalSection (&cairo_ft_unscaled_font_map_mutex); + DeleteCriticalSection (&_cairo_scaled_font_map_mutex); +#ifdef CAIRO_HAS_FT_FONT + DeleteCriticalSection (&_cairo_ft_unscaled_font_map_mutex); +#endif + DeleteCriticalSection (&_cairo_font_face_mutex); break; } return TRUE; diff --git a/gfx/cairo/cairo/src/cairo-xcb-surface.c b/gfx/cairo/cairo/src/cairo-xcb-surface.c index 2fdf8a1d53b..08979611909 100644 --- a/gfx/cairo/cairo/src/cairo-xcb-surface.c +++ b/gfx/cairo/cairo/src/cairo-xcb-surface.c @@ -1289,10 +1289,9 @@ _create_a8_picture (cairo_xcb_surface_t *surface, = _CAIRO_FORMAT_TO_XRENDER_FORMAT (surface->dpy, CAIRO_FORMAT_A8); xcb_rectangle_t rect = { 0, 0, width, height }; - xcb_create_pixmap (surface->dpy, pixmap, surface->drawable, - width <= 0 ? 1 : width, - height <= 0 ? 1 : height, - 8); + xcb_create_pixmap (surface->dpy, 8, pixmap, surface->drawable, + width <= 0 ? 1 : width, + height <= 0 ? 1 : height); xcb_render_create_picture (surface->dpy, picture, pixmap, format->id, mask, values); xcb_render_fill_rectangles (surface->dpy, XCB_RENDER_PICT_OP_SRC, picture, *color, 1, &rect); xcb_free_pixmap (surface->dpy, pixmap); diff --git a/gfx/cairo/cairo/src/cairo-xlib-private.h b/gfx/cairo/cairo/src/cairo-xlib-private.h index ed9bc34ed09..5dd91b0ac97 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-private.h +++ b/gfx/cairo/cairo/src/cairo-xlib-private.h @@ -37,6 +37,14 @@ #include "cairo-xlib.h" typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t; +typedef struct _cairo_xlib_hook cairo_xlib_hook_t; + +struct _cairo_xlib_hook { + cairo_xlib_hook_t *next; + void (*func) (Display *display, void *data); + void *data; + void *key; +}; struct _cairo_xlib_screen_info { cairo_xlib_screen_info_t *next; @@ -46,18 +54,24 @@ struct _cairo_xlib_screen_info { cairo_bool_t has_render; cairo_font_options_t font_options; + + cairo_xlib_hook_t *close_display_hooks; }; cairo_private cairo_xlib_screen_info_t * _cairo_xlib_screen_info_get (Display *display, Screen *screen); +cairo_private cairo_bool_t +_cairo_xlib_add_close_display_hook (Display *display, void (*func) (Display *, void *), void *data, void *key); +cairo_private void +_cairo_xlib_remove_close_display_hook (Display *display, void *key); + #if CAIRO_HAS_XLIB_XRENDER_SURFACE #include "cairo-xlib-xrender.h" -#if 0 +#ifdef MOZILLA_CAIRO_NOT_DEFINED slim_hidden_proto (cairo_xlib_surface_create_with_xrender_format); #endif - #endif #endif /* CAIRO_XLIB_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-xlib-screen.c b/gfx/cairo/cairo/src/cairo-xlib-screen.c index cbdb540d392..4c34608a2e0 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-screen.c +++ b/gfx/cairo/cairo/src/cairo-xlib-screen.c @@ -247,31 +247,36 @@ CAIRO_MUTEX_DECLARE(_xlib_screen_mutex); static cairo_xlib_screen_info_t *_cairo_xlib_screen_list = NULL; -/* XXX: From this function we should also run through and cleanup - * anything else that still has a pointer to this Display*. For - * example, we should clean up any Xlib-specific glyph caches. */ static int _cairo_xlib_close_display (Display *dpy, XExtCodes *codes) { - cairo_xlib_screen_info_t *info, *prev; + cairo_xlib_screen_info_t *info, **prev, *next; /* * Unhook from the global list */ CAIRO_MUTEX_LOCK (_xlib_screen_mutex); - prev = NULL; - for (info = _cairo_xlib_screen_list; info; info = info->next) { + prev = &_cairo_xlib_screen_list; + for (info = _cairo_xlib_screen_list; info; info = next) { + next = info->next; if (info->display == dpy) { - if (prev) - prev->next = info->next; - else - _cairo_xlib_screen_list = info->next; + *prev = next; + /* call all registered shutdown routines */ + while (info->close_display_hooks) { + cairo_xlib_hook_t *hook = info->close_display_hooks; + info->close_display_hooks = hook->next; + + hook->func (dpy, hook->data); + + free (hook); + } free (info); - break; + } else { + prev = &info->next; } - prev = info; } + *prev = NULL; CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); /* Return value in accordance with requirements of @@ -291,6 +296,11 @@ _cairo_xlib_screen_info_reset (void) for (info = _cairo_xlib_screen_list; info; info = next) { next = info->next; + while (info->close_display_hooks) { + cairo_xlib_hook_t *hook = info->close_display_hooks; + info->close_display_hooks = hook->next; + free (hook); + } free (info); } @@ -300,8 +310,8 @@ _cairo_xlib_screen_info_reset (void) } -cairo_xlib_screen_info_t * -_cairo_xlib_screen_info_get (Display *dpy, Screen *screen) +static cairo_xlib_screen_info_t * +_cairo_xlib_screen_info_get_unlocked (Display *dpy, Screen *screen) { cairo_xlib_screen_info_t *info; cairo_xlib_screen_info_t **prev; @@ -309,26 +319,15 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen) XExtCodes *codes; cairo_bool_t seen_display = FALSE; - /* There is an apparent deadlock between this mutex and the - * mutex for the display, but it's actually safe. For the - * app to call XCloseDisplay() while any other thread is - * inside this function would be an error in the logic - * app, and the CloseDisplay hook is the only other place we - * acquire this mutex. - */ - CAIRO_MUTEX_LOCK (_xlib_screen_mutex); - for (prev = &_cairo_xlib_screen_list; (info = *prev); prev = &(*prev)->next) { if (info->display == dpy) { seen_display = TRUE; - if (info->screen == screen) - { + if (info->screen == screen || screen == NULL) { /* * MRU the list */ - if (prev != &_cairo_xlib_screen_list) - { + if (prev != &_cairo_xlib_screen_list) { *prev = info->next; info->next = _cairo_xlib_screen_list; _cairo_xlib_screen_list = info; @@ -339,18 +338,17 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen) } if (info) - goto out; + return info; info = malloc (sizeof (cairo_xlib_screen_info_t)); if (!info) - goto out; + return NULL; if (!seen_display) { codes = XAddExtension (dpy); if (!codes) { free (info); - info = NULL; - goto out; + return NULL; } XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display); @@ -361,24 +359,110 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen) info->has_render = (XRenderQueryExtension (dpy, &event_base, &error_base) && (XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0)); + info->close_display_hooks = NULL; + _cairo_xlib_init_screen_font_options (info); info->next = _cairo_xlib_screen_list; _cairo_xlib_screen_list = info; - out: + return info; +} +cairo_xlib_screen_info_t * +_cairo_xlib_screen_info_get (Display *dpy, Screen *screen) +{ + cairo_xlib_screen_info_t *info; + + /* There is an apparent deadlock between this mutex and the + * mutex for the display, but it's actually safe. For the + * app to call XCloseDisplay() while any other thread is + * inside this function would be an error in the logic + * app, and the CloseDisplay hook is the only other place we + * acquire this mutex. + */ + CAIRO_MUTEX_LOCK (_xlib_screen_mutex); + + info = _cairo_xlib_screen_info_get_unlocked (dpy, screen); + CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); return info; } +cairo_bool_t +_cairo_xlib_add_close_display_hook (Display *dpy, void (*func) (Display *, void *), void *data, void *key) +{ + cairo_xlib_screen_info_t *info; + cairo_xlib_hook_t *hook; + cairo_xlib_hook_t **prev; + cairo_bool_t success = FALSE; + + CAIRO_MUTEX_LOCK (_xlib_screen_mutex); + + info = _cairo_xlib_screen_info_get_unlocked (dpy, NULL); + if (!info) + goto unlock; + + for (prev = &info->close_display_hooks; (hook = *prev); prev = &hook->next) + { + if (hook->key == key) { + /* + * MRU the list + */ + if (prev != &info->close_display_hooks) { + *prev = hook->next; + hook->next = info->close_display_hooks; + info->close_display_hooks = hook; + } + break; + } + } + + if (!hook) { + hook = malloc (sizeof (cairo_xlib_hook_t)); + if (!hook) + goto unlock; + hook->func = func; + hook->data = data; + hook->key = key; + hook->next = info->close_display_hooks; + info->close_display_hooks = hook; + } + + success = TRUE; + unlock: + CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); + return success; +} + +void +_cairo_xlib_remove_close_display_hook (Display *dpy, void *key) +{ + cairo_xlib_screen_info_t *info; + cairo_xlib_hook_t *hook; + cairo_xlib_hook_t **prev; + + CAIRO_MUTEX_LOCK (_xlib_screen_mutex); + + info = _cairo_xlib_screen_info_get_unlocked (dpy, NULL); + if (!info) + goto unlock; + + for (prev = &info->close_display_hooks; (hook = *prev); prev = &hook->next) + { + if (hook->key == key) { + *prev = hook->next; + free (hook); + break; + } + } + +unlock: + CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); +} + void _cairo_xlib_screen_reset_static_data (void) { _cairo_xlib_screen_info_reset (); - -#if HAVE_XRMFINALIZE - XrmFinalize (); -#endif - } diff --git a/gfx/cairo/cairo/src/cairo-xlib-surface.c b/gfx/cairo/cairo/src/cairo-xlib-surface.c index d076d9c18cd..be285cd46a9 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-surface.c +++ b/gfx/cairo/cairo/src/cairo-xlib-surface.c @@ -610,24 +610,27 @@ _get_image_surface (cairo_xlib_surface_t *surface, _swap_ximage_to_native (ximage); /* - * Compute the pixel format masks from either a visual or a - * XRenderFormat, failing we assume the drawable is an - * alpha-only pixmap as it could only have been created - * that way through the cairo_xlib_surface_create_for_bitmap - * function. + * Compute the pixel format masks from either a XrenderFormat or + * else from a visual; failing that we assume the drawable is an + * alpha-only pixmap as it could only have been created that way + * through the cairo_xlib_surface_create_for_bitmap function. */ - if (surface->visual) { + if (surface->xrender_format) { + masks.bpp = ximage->bits_per_pixel; + masks.red_mask = (unsigned long) surface->xrender_format->direct.redMask + << surface->xrender_format->direct.red; + masks.green_mask = (unsigned long) surface->xrender_format->direct.greenMask + << surface->xrender_format->direct.green; + masks.blue_mask = (unsigned long) surface->xrender_format->direct.blueMask + << surface->xrender_format->direct.blue; + masks.alpha_mask = (unsigned long) surface->xrender_format->direct.alphaMask + << surface->xrender_format->direct.alpha; + } else if (surface->visual) { masks.bpp = ximage->bits_per_pixel; masks.alpha_mask = 0; masks.red_mask = surface->visual->red_mask; masks.green_mask = surface->visual->green_mask; masks.blue_mask = surface->visual->blue_mask; - } else if (surface->xrender_format) { - masks.bpp = ximage->bits_per_pixel; - masks.red_mask = (unsigned long)surface->xrender_format->direct.redMask << surface->xrender_format->direct.red; - masks.green_mask = (unsigned long)surface->xrender_format->direct.greenMask << surface->xrender_format->direct.green; - masks.blue_mask = (unsigned long)surface->xrender_format->direct.blueMask << surface->xrender_format->direct.blue; - masks.alpha_mask = (unsigned long)surface->xrender_format->direct.alphaMask << surface->xrender_format->direct.alpha; } else { masks.bpp = ximage->bits_per_pixel; masks.red_mask = 0; @@ -2019,7 +2022,7 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy, return _cairo_xlib_surface_create_internal (dpy, drawable, screen, NULL, format, width, height, 0); } -#if 0 +#ifdef MOZILLA_CAIRO_NOT_DEFINED slim_hidden_def (cairo_xlib_surface_create_with_xrender_format); #endif @@ -2270,6 +2273,24 @@ typedef struct _cairo_xlib_surface_font_private { XRenderPictFormat *xrender_format; } cairo_xlib_surface_font_private_t; +static void +_cairo_xlib_surface_remove_scaled_font (Display *dpy, + void *data) +{ + cairo_scaled_font_t *scaled_font = data; + cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; + + _cairo_scaled_font_reset_cache (scaled_font); + + /* separate function to avoid deadlock if we tried to remove the + * close display hook ala _cairo_xlib_surface_scaled_font_fini() */ + if (font_private) { + XRenderFreeGlyphSet (font_private->dpy, font_private->glyphset); + free (font_private); + scaled_font->surface_private = NULL; + } +} + static cairo_status_t _cairo_xlib_surface_font_init (Display *dpy, cairo_scaled_font_t *scaled_font, @@ -2277,6 +2298,11 @@ _cairo_xlib_surface_font_init (Display *dpy, { cairo_xlib_surface_font_private_t *font_private; + if (!_cairo_xlib_add_close_display_hook (dpy, + _cairo_xlib_surface_remove_scaled_font, + scaled_font, scaled_font)) + return CAIRO_STATUS_NO_MEMORY; + font_private = malloc (sizeof (cairo_xlib_surface_font_private_t)); if (!font_private) return CAIRO_STATUS_NO_MEMORY; @@ -2287,6 +2313,7 @@ _cairo_xlib_surface_font_init (Display *dpy, font_private->glyphset = XRenderCreateGlyphSet (dpy, font_private->xrender_format); scaled_font->surface_private = font_private; scaled_font->surface_backend = &cairo_xlib_surface_backend; + return CAIRO_STATUS_SUCCESS; } @@ -2296,6 +2323,7 @@ _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font) cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; if (font_private) { + _cairo_xlib_remove_close_display_hook (font_private->dpy, scaled_font); XRenderFreeGlyphSet (font_private->dpy, font_private->glyphset); free (font_private); } diff --git a/gfx/cairo/cairo/src/cairo.c b/gfx/cairo/cairo/src/cairo.c index 2e522a63be2..21303debd05 100644 --- a/gfx/cairo/cairo/src/cairo.c +++ b/gfx/cairo/cairo/src/cairo.c @@ -47,15 +47,18 @@ static const cairo_t cairo_nil = { CAIRO_REF_COUNT_INVALID, /* ref_count */ CAIRO_STATUS_NO_MEMORY, /* status */ - { /* path */ - NULL, NULL, /* op_buf_head, op_buf_tail */ - NULL, NULL, /* arg_buf_head, arg_buf_tail */ + { 0, 0, 0, NULL }, /* user_data */ + NULL, /* gstate */ + {{ /* gstate_tail */ + 0 + }}, + {{ /* path */ { 0, 0 }, /* last_move_point */ { 0, 0 }, /* current point */ FALSE, /* has_current_point */ - FALSE /* has_curve_to */ - }, - NULL /* gstate */ + FALSE, /* has_curve_to */ + NULL, {{0}} /* buf_tail, buf_head */ + }} }; #include @@ -195,18 +198,17 @@ cairo_create (cairo_surface_t *target) cr->status = CAIRO_STATUS_SUCCESS; - _cairo_path_fixed_init (&cr->path); + _cairo_user_data_array_init (&cr->user_data); + + cr->gstate = cr->gstate_tail; + _cairo_gstate_init (cr->gstate, target); + + _cairo_path_fixed_init (cr->path); if (target == NULL) { - cr->gstate = NULL; _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); - return cr; } - cr->gstate = _cairo_gstate_create (target); - if (cr->gstate == NULL) - _cairo_set_error (cr, CAIRO_STATUS_NO_MEMORY); - return cr; } slim_hidden_def (cairo_create); @@ -219,15 +221,15 @@ slim_hidden_def (cairo_create); * @cr from being destroyed until a matching call to cairo_destroy() * is made. * + * The number of references to a #cairo_t can be get using + * cairo_get_reference_count(). + * * Return value: the referenced #cairo_t. **/ cairo_t * cairo_reference (cairo_t *cr) { - if (cr == NULL) - return NULL; - - if (cr->ref_count == CAIRO_REF_COUNT_INVALID) + if (cr == NULL || cr->ref_count == CAIRO_REF_COUNT_INVALID) return cr; assert (cr->ref_count > 0); @@ -248,10 +250,7 @@ cairo_reference (cairo_t *cr) void cairo_destroy (cairo_t *cr) { - if (cr == NULL) - return; - - if (cr->ref_count == CAIRO_REF_COUNT_INVALID) + if (cr == NULL || cr->ref_count == CAIRO_REF_COUNT_INVALID) return; assert (cr->ref_count > 0); @@ -260,19 +259,96 @@ cairo_destroy (cairo_t *cr) if (cr->ref_count) return; - while (cr->gstate) { + while (cr->gstate != cr->gstate_tail) { cairo_gstate_t *tmp = cr->gstate; cr->gstate = tmp->next; _cairo_gstate_destroy (tmp); } - _cairo_path_fixed_fini (&cr->path); + _cairo_gstate_fini (cr->gstate); + + _cairo_path_fixed_fini (cr->path); + + _cairo_user_data_array_fini (&cr->user_data); free (cr); } slim_hidden_def (cairo_destroy); +/** + * cairo_get_user_data: + * @cr: a #cairo_t + * @key: the address of the #cairo_user_data_key_t the user data was + * attached to + * + * Return user data previously attached to @cr using the specified + * key. If no user data has been attached with the given key this + * function returns %NULL. + * + * Return value: the user data previously attached or %NULL. + * + * Since: 1.4 + **/ +void * +cairo_get_user_data (cairo_t *cr, + const cairo_user_data_key_t *key) +{ + return _cairo_user_data_array_get_data (&cr->user_data, + key); +} + +/** + * cairo_set_user_data: + * @cr: a #cairo_t + * @key: the address of a #cairo_user_data_key_t to attach the user data to + * @user_data: the user data to attach to the #cairo_t + * @destroy: a #cairo_destroy_func_t which will be called when the + * #cairo_t is destroyed or when new user data is attached using the + * same key. + * + * Attach user data to @cr. To remove user data from a surface, + * call this function with the key that was used to set it and %NULL + * for @data. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a + * slot could not be allocated for the user data. + * + * Since: 1.4 + **/ +cairo_status_t +cairo_set_user_data (cairo_t *cr, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy) +{ + if (cr->ref_count == CAIRO_REF_COUNT_INVALID) + return CAIRO_STATUS_NO_MEMORY; + + return _cairo_user_data_array_set_data (&cr->user_data, + key, user_data, destroy); +} + +/** + * cairo_get_reference_count: + * @cr: a #cairo_t + * + * Returns the current reference count of @cr. + * + * Return value: the current reference count of @cr. If the + * object is a nil object, 0 will be returned. + * + * Since: 1.4 + **/ +unsigned int +cairo_get_reference_count (cairo_t *cr) +{ + if (cr == NULL || cr->ref_count == CAIRO_REF_COUNT_INVALID) + return 0; + + return cr->ref_count; +} + /** * cairo_save: * @cr: a #cairo_t @@ -325,13 +401,15 @@ cairo_restore (cairo_t *cr) if (cr->status) return; + if (cr->gstate == cr->gstate_tail) { + _cairo_set_error (cr, CAIRO_STATUS_INVALID_RESTORE); + return; + } + top = cr->gstate; cr->gstate = top->next; _cairo_gstate_destroy (top); - - if (cr->gstate == NULL) - _cairo_set_error (cr, CAIRO_STATUS_INVALID_RESTORE); } slim_hidden_def(cairo_restore); @@ -855,8 +933,8 @@ cairo_set_line_width (cairo_t *cr, double width) /** * cairo_set_line_cap: - * @cr: a cairo context, as a #cairo_t - * @line_cap: a line cap style, as a #cairo_line_cap_t + * @cr: a cairo context + * @line_cap: a line cap style * * Sets the current line cap style within the cairo context. See * #cairo_line_cap_t for details about how the available line cap @@ -880,8 +958,8 @@ cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap) /** * cairo_set_line_join: - * @cr: a cairo context, as a #cairo_t - * @line_join: a line joint style, as a #cairo_line_join_t + * @cr: a cairo context + * @line_join: a line joint style * * Sets the current line join style within the cairo context. See * #cairo_line_join_t for details about how the available line join @@ -954,11 +1032,13 @@ cairo_set_dash (cairo_t *cr, * cairo_get_dash_count: * @cr: a #cairo_t * - * Returns the length of the dash array in @cr (0 if dashing is not - * currently in effect). + * This function returns the length of the dash array in @cr (0 if dashing + * is not currently in effect). * * See also cairo_set_dash() and cairo_get_dash(). * + * Return value: the length of the dash array, or 0 if no dash array set. + * * Since: 1.4 */ int @@ -993,6 +1073,25 @@ cairo_get_dash (cairo_t *cr, *offset = cr->gstate->stroke_style.dash_offset; } +/** + * cairo_set_miter_limit: + * @cr: a cairo context + * @limit: miter limit to set + * + * Sets the current miter limit within the cairo context. + * + * If the current line join style is set to %CAIRO_LINE_JOIN_MITER + * (see cairo_set_line_join()), the miter limit is used to determine + * whether the lines should be joined with a bevel instead of a miter. + * Cairo divides the length of the miter by the line width. + * If the result is greater than the miter limit, the style is + * converted to a bevel. + * + * As with the other stroke parameters, the current line miter limit is + * examined by cairo_stroke(), cairo_stroke_extents(), and + * cairo_stroke_to_path(), but does not have any effect during path + * construction. + **/ void cairo_set_miter_limit (cairo_t *cr, double limit) { @@ -1048,6 +1147,7 @@ cairo_scale (cairo_t *cr, double sx, double sy) if (cr->status) _cairo_set_error (cr, cr->status); } +slim_hidden_def (cairo_scale); /** * cairo_rotate: @@ -1232,7 +1332,7 @@ cairo_new_path (cairo_t *cr) if (cr->status) return; - _cairo_path_fixed_fini (&cr->path); + _cairo_path_fixed_fini (cr->path); } slim_hidden_def(cairo_new_path); @@ -1257,7 +1357,7 @@ cairo_move_to (cairo_t *cr, double x, double y) x_fixed = _cairo_fixed_from_double (x); y_fixed = _cairo_fixed_from_double (y); - cr->status = _cairo_path_fixed_move_to (&cr->path, x_fixed, y_fixed); + cr->status = _cairo_path_fixed_move_to (cr->path, x_fixed, y_fixed); if (cr->status) _cairo_set_error (cr, cr->status); } @@ -1287,7 +1387,7 @@ cairo_new_sub_path (cairo_t *cr) if (cr->status) return; - _cairo_path_fixed_new_sub_path (&cr->path); + _cairo_path_fixed_new_sub_path (cr->path); } /** @@ -1315,7 +1415,7 @@ cairo_line_to (cairo_t *cr, double x, double y) x_fixed = _cairo_fixed_from_double (x); y_fixed = _cairo_fixed_from_double (y); - cr->status = _cairo_path_fixed_line_to (&cr->path, x_fixed, y_fixed); + cr->status = _cairo_path_fixed_line_to (cr->path, x_fixed, y_fixed); if (cr->status) _cairo_set_error (cr, cr->status); } @@ -1366,7 +1466,7 @@ cairo_curve_to (cairo_t *cr, x3_fixed = _cairo_fixed_from_double (x3); y3_fixed = _cairo_fixed_from_double (y3); - cr->status = _cairo_path_fixed_curve_to (&cr->path, + cr->status = _cairo_path_fixed_curve_to (cr->path, x1_fixed, y1_fixed, x2_fixed, y2_fixed, x3_fixed, y3_fixed); @@ -1532,7 +1632,7 @@ cairo_rel_move_to (cairo_t *cr, double dx, double dy) dx_fixed = _cairo_fixed_from_double (dx); dy_fixed = _cairo_fixed_from_double (dy); - cr->status = _cairo_path_fixed_rel_move_to (&cr->path, dx_fixed, dy_fixed); + cr->status = _cairo_path_fixed_rel_move_to (cr->path, dx_fixed, dy_fixed); if (cr->status) _cairo_set_error (cr, cr->status); } @@ -1567,7 +1667,7 @@ cairo_rel_line_to (cairo_t *cr, double dx, double dy) dx_fixed = _cairo_fixed_from_double (dx); dy_fixed = _cairo_fixed_from_double (dy); - cr->status = _cairo_path_fixed_rel_line_to (&cr->path, dx_fixed, dy_fixed); + cr->status = _cairo_path_fixed_rel_line_to (cr->path, dx_fixed, dy_fixed); if (cr->status) _cairo_set_error (cr, cr->status); } @@ -1625,7 +1725,7 @@ cairo_rel_curve_to (cairo_t *cr, dx3_fixed = _cairo_fixed_from_double (dx3); dy3_fixed = _cairo_fixed_from_double (dy3); - cr->status = _cairo_path_fixed_rel_curve_to (&cr->path, + cr->status = _cairo_path_fixed_rel_curve_to (cr->path, dx1_fixed, dy1_fixed, dx2_fixed, dy2_fixed, dx3_fixed, dy3_fixed); @@ -1713,7 +1813,7 @@ cairo_close_path (cairo_t *cr) if (cr->status) return; - cr->status = _cairo_path_fixed_close_path (&cr->path); + cr->status = _cairo_path_fixed_close_path (cr->path); if (cr->status) _cairo_set_error (cr, cr->status); } @@ -1903,7 +2003,7 @@ cairo_stroke_preserve (cairo_t *cr) if (cr->status) return; - cr->status = _cairo_gstate_stroke (cr->gstate, &cr->path); + cr->status = _cairo_gstate_stroke (cr->gstate, cr->path); if (cr->status) _cairo_set_error (cr, cr->status); } @@ -1944,7 +2044,7 @@ cairo_fill_preserve (cairo_t *cr) if (cr->status) return; - cr->status = _cairo_gstate_fill (cr->gstate, &cr->path); + cr->status = _cairo_gstate_fill (cr->gstate, cr->path); if (cr->status) _cairo_set_error (cr, cr->status); } @@ -2014,7 +2114,7 @@ cairo_in_stroke (cairo_t *cr, double x, double y) return 0; cr->status = _cairo_gstate_in_stroke (cr->gstate, - &cr->path, + cr->path, x, y, &inside); if (cr->status) return 0; @@ -2046,7 +2146,7 @@ cairo_in_fill (cairo_t *cr, double x, double y) return 0; cr->status = _cairo_gstate_in_fill (cr->gstate, - &cr->path, + cr->path, x, y, &inside); if (cr->status) { _cairo_set_error (cr, cr->status); @@ -2082,7 +2182,7 @@ cairo_stroke_extents (cairo_t *cr, return; cr->status = _cairo_gstate_stroke_extents (cr->gstate, - &cr->path, + cr->path, x1, y1, x2, y2); if (cr->status) _cairo_set_error (cr, cr->status); @@ -2112,7 +2212,7 @@ cairo_fill_extents (cairo_t *cr, return; cr->status = _cairo_gstate_fill_extents (cr->gstate, - &cr->path, + cr->path, x1, y1, x2, y2); if (cr->status) _cairo_set_error (cr, cr->status); @@ -2176,7 +2276,7 @@ cairo_clip_preserve (cairo_t *cr) if (cr->status) return; - cr->status = _cairo_gstate_clip (cr->gstate, &cr->path); + cr->status = _cairo_gstate_clip (cr->gstate, cr->path); if (cr->status) _cairo_set_error (cr, cr->status); } @@ -2251,8 +2351,9 @@ _cairo_rectangle_list_create_in_error (cairo_status_t status) /** * cairo_copy_clip_rectangle_list: + * @cr: a cairo context * - * Returns the current clip region as a list of rectangles in user coordinates. + * Gets the current clip region as a list of rectangles in user coordinates. * Never returns %NULL. * * The status in the list may be CAIRO_STATUS_CLIP_NOT_REPRESENTABLE to @@ -2263,6 +2364,8 @@ _cairo_rectangle_list_create_in_error (cairo_status_t status) * The caller must always call cairo_rectangle_list_destroy on the result of * this function. * + * Returns: the current clip region as a list of rectangles in user coordinates. + * * Since: 1.4 **/ cairo_rectangle_list_t * @@ -2303,34 +2406,6 @@ cairo_select_font_face (cairo_t *cr, _cairo_set_error (cr, cr->status); } -/** - * cairo_get_font_face: - * @cr: a #cairo_t - * - * Gets the current font face for a #cairo_t. - * - * Return value: the current font object. Can return %NULL - * on out-of-memory or if the context is already in - * an error state. This object is owned by cairo. To keep - * a reference to it, you must call cairo_font_face_reference(). - **/ -cairo_font_face_t * -cairo_get_font_face (cairo_t *cr) -{ - cairo_font_face_t *font_face; - - if (cr->status) - return (cairo_font_face_t*) &_cairo_font_face_nil; - - cr->status = _cairo_gstate_get_font_face (cr->gstate, &font_face); - if (cr->status) { - _cairo_set_error (cr, cr->status); - return (cairo_font_face_t*) &_cairo_font_face_nil; - } - - return font_face; -} - /** * cairo_font_extents: * @cr: a #cairo_t @@ -2372,6 +2447,41 @@ cairo_set_font_face (cairo_t *cr, _cairo_set_error (cr, cr->status); } +/** + * cairo_get_font_face: + * @cr: a #cairo_t + * + * Gets the current font face for a #cairo_t. + * + * Return value: the current font face. This object is owned by + * cairo. To keep a reference to it, you must call + * cairo_font_face_reference. + * + * This function never returns %NULL. If memory cannot be allocated, a + * special "nil" #cairo_font_face_t object will be returned on which + * cairo_font_face_status() returns %CAIRO_STATUS_NO_MEMORY. Using + * this nil object will cause its error state to propagate to other + * objects it is passed to, (for example, calling + * cairo_set_font_face() with a nil font will trigger an error that + * will shutdown the cairo_t object). + **/ +cairo_font_face_t * +cairo_get_font_face (cairo_t *cr) +{ + cairo_font_face_t *font_face; + + if (cr->status) + return (cairo_font_face_t*) &_cairo_font_face_nil; + + cr->status = _cairo_gstate_get_font_face (cr->gstate, &font_face); + if (cr->status) { + _cairo_set_error (cr, cr->status); + return (cairo_font_face_t*) &_cairo_font_face_nil; + } + + return font_face; +} + /** * cairo_set_font_size: * @cr: a #cairo_t @@ -2516,6 +2626,43 @@ BAIL: _cairo_set_error (cr, cr->status); } +/** + * cairo_get_scaled_font: + * @cr: a #cairo_t + * + * Gets the current scaled font for a #cairo_t. + * + * Return value: the current scaled font. This object is owned by + * cairo. To keep a reference to it, you must call + * cairo_scaled_font_reference(). + * + * This function never returns %NULL. If memory cannot be allocated, a + * special "nil" #cairo_scaled_font_t object will be returned on which + * cairo_scaled_font_status() returns %CAIRO_STATUS_NO_MEMORY. Using + * this nil object will cause its error state to propagate to other + * objects it is passed to, (for example, calling + * cairo_set_scaled_font() with a nil font will trigger an error that + * will shutdown the cairo_t object). + * + * Since: 1.4 + **/ +cairo_scaled_font_t * +cairo_get_scaled_font (cairo_t *cr) +{ + cairo_scaled_font_t *scaled_font; + + if (cr->status) + return (cairo_scaled_font_t *)&_cairo_scaled_font_nil; + + cr->status = _cairo_gstate_get_scaled_font (cr->gstate, &scaled_font); + if (cr->status) { + _cairo_set_error (cr, cr->status); + return (cairo_scaled_font_t *)&_cairo_scaled_font_nil; + } + + return scaled_font; +} + /** * cairo_text_extents: * @cr: a #cairo_t @@ -2635,9 +2782,9 @@ cairo_glyph_extents (cairo_t *cr, * * NOTE: The cairo_show_text() function call is part of what the cairo * designers call the "toy" text API. It is convenient for short demos - * and simple programs, but it is not expected to be adequate for the - * most serious of text-using applications. See cairo_show_glyphs() - * for the "real" text display API in cairo. + * and simple programs, but it is not expected to be adequate for + * serious text-using applications. See cairo_show_glyphs() for the + * "real" text display API in cairo. **/ void cairo_show_text (cairo_t *cr, const char *utf8) @@ -2687,6 +2834,16 @@ cairo_show_text (cairo_t *cr, const char *utf8) _cairo_set_error (cr, cr->status); } +/** + * cairo_show_glyphs: + * @cr: a cairo context + * @glyphs: array of glyphs to show + * @num_glyphs: number of glyphs to show + * + * A drawing operator that generates the shape from an array of glyphs, + * rendered according to the current font_face, font_size + * (font_matrix), and font_options. + **/ void cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs) { @@ -2701,10 +2858,35 @@ cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs) _cairo_set_error (cr, cr->status); } +/** + * cairo_text_path: + * @cr: a cairo context + * @utf8: a string of text encoded in UTF-8 + * + * Adds closed paths for text to the current path. The generated + * path if filled, achieves an effect similar to that of + * cairo_show_text(). + * + * Text conversion and positioning is done similar to cairo_show_text(). + * + * Like cairo_show_text(), After this call the current point is + * moved to the origin of where the next glyph would be placed in + * this same progression. That is, the current point will be at + * the origin of the final glyph offset by its advance values. + * This allows for chaining multiple calls to to cairo_text_path() + * without having to set current point in between. + * + * NOTE: The cairo_text_path() function call is part of what the cairo + * designers call the "toy" text API. It is convenient for short demos + * and simple programs, but it is not expected to be adequate for + * serious text-using applications. See cairo_glyph_path() for the + * "real" text path API in cairo. + **/ void cairo_text_path (cairo_t *cr, const char *utf8) { - cairo_glyph_t *glyphs = NULL; + cairo_text_extents_t extents; + cairo_glyph_t *glyphs = NULL, *last_glyph; int num_glyphs; double x, y; @@ -2717,16 +2899,32 @@ cairo_text_path (cairo_t *cr, const char *utf8) x, y, &glyphs, &num_glyphs); - if (cr->status) { - if (glyphs) - free (glyphs); - _cairo_set_error (cr, cr->status); + if (cr->status) + goto BAIL; + + if (num_glyphs == 0) return; - } cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, num_glyphs, - &cr->path); + cr->path); + + if (cr->status) + goto BAIL; + + last_glyph = &glyphs[num_glyphs - 1]; + cr->status = _cairo_gstate_glyph_extents (cr->gstate, + last_glyph, 1, + &extents); + + if (cr->status) + goto BAIL; + + x = last_glyph->x + extents.x_advance; + y = last_glyph->y + extents.y_advance; + cairo_move_to (cr, x, y); + + BAIL: if (glyphs) free (glyphs); @@ -2734,6 +2932,16 @@ cairo_text_path (cairo_t *cr, const char *utf8) _cairo_set_error (cr, cr->status); } +/** + * cairo_glyph_path: + * @cr: a cairo context + * @glyphs: array of glyphs to show + * @num_glyphs: number of glyphs to show + * + * Adds closed paths for the glyphs to the current path. The generated + * path if filled, achieves an effect similar to that of + * cairo_show_glyphs(). + **/ void cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs) { @@ -2742,7 +2950,7 @@ cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs) cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, num_glyphs, - &cr->path); + cr->path); if (cr->status) _cairo_set_error (cr, cr->status); } @@ -2818,7 +3026,7 @@ cairo_get_current_point (cairo_t *cr, double *x_ret, double *y_ret) cairo_fixed_t x_fixed, y_fixed; double x, y; - status = _cairo_path_fixed_get_current_point (&cr->path, &x_fixed, &y_fixed); + status = _cairo_path_fixed_get_current_point (cr->path, &x_fixed, &y_fixed); if (status == CAIRO_STATUS_NO_CURRENT_POINT) { x = 0.0; y = 0.0; @@ -2853,10 +3061,12 @@ cairo_get_fill_rule (cairo_t *cr) * cairo_get_line_width: * @cr: a cairo context * - * Return value: the current line width value exactly as set by + * This function returns the current line width value exactly as set by * cairo_set_line_width(). Note that the value is unchanged even if * the CTM has changed between the calls to cairo_set_line_width() and * cairo_get_line_width(). + * + * Return value: the current line width. **/ double cairo_get_line_width (cairo_t *cr) @@ -3008,7 +3218,7 @@ cairo_copy_path (cairo_t *cr) if (cr->status) return _cairo_path_create_in_error (cr->status); - return _cairo_path_create (&cr->path, cr->gstate); + return _cairo_path_create (cr->path, cr->gstate); } /** @@ -3050,7 +3260,7 @@ cairo_copy_path_flat (cairo_t *cr) if (cr->status) return _cairo_path_create_in_error (cr->status); - return _cairo_path_create_flat (&cr->path, cr->gstate); + return _cairo_path_create_flat (cr->path, cr->gstate); } /** diff --git a/gfx/cairo/cairo/src/cairo.h b/gfx/cairo/cairo/src/cairo.h index 779da17e5ee..a80efde210e 100644 --- a/gfx/cairo/cairo/src/cairo.h +++ b/gfx/cairo/cairo/src/cairo.h @@ -72,7 +72,7 @@ cairo_version_string (void); * /* do something */ * } * - */ + **/ typedef int cairo_bool_t; /** @@ -80,6 +80,13 @@ typedef int cairo_bool_t; * * A #cairo_t contains the current state of the rendering device, * including coordinates of yet to be drawn shapes. + * + * Cairo contexts, as #cairo_t objects are named, are central to + * cairo and all drawing with cairo is always done to a #cairo_t + * object. + * + * Memory management of #cairo_t is done with + * cairo_reference() and cairo_destroy(). **/ typedef struct _cairo cairo_t; @@ -88,13 +95,17 @@ typedef struct _cairo cairo_t; * * A #cairo_surface_t represents an image, either as the destination * of a drawing operation or as source when drawing onto another - * surface. There are different subtypes of cairo_surface_t for + * surface. To draw to a #cairo_surface_t, create a cairo context + * with the surface as the target, using cairo_create(). + * + * There are different subtypes of #cairo_surface_t for * different drawing backends; for example, cairo_image_surface_create() * creates a bitmap image in memory. + * The type of a surface can be queried with cairo_surface_get_type(). * * Memory management of #cairo_surface_t is done with * cairo_surface_reference() and cairo_surface_destroy(). - */ + **/ typedef struct _cairo_surface cairo_surface_t; /** @@ -120,6 +131,25 @@ typedef struct _cairo_matrix { double x0; double y0; } cairo_matrix_t; +/** + * cairo_pattern_t: + * + * A #cairo_pattern_t represents a source when drawing onto a + * surface. There are different subtypes of #cairo_pattern_t, + * for different types of sources; for example, + * cairo_pattern_create_rgb() creates a pattern for a solid + * opaque color. + * + * Other than various cairo_pattern_create_type + * functions, some of the pattern types can be implicitly created + * using vairous cairo_set_source_type functions; + * for example cairo_set_source_rgb(). + * + * The type of a pattern can be queried with cairo_pattern_get_type(). + * + * Memory management of #cairo_pattern_t is done with + * cairo_pattern_reference() and cairo_pattern_destroy(). + **/ typedef struct _cairo_pattern cairo_pattern_t; /** @@ -129,7 +159,7 @@ typedef struct _cairo_pattern cairo_pattern_t; * #cairo_destroy_func_t the type of function which is called when a * data element is destroyed. It is passed the pointer to the data * element and should free any memory and resources allocated for it. - */ + **/ typedef void (*cairo_destroy_func_t) (void *data); /** @@ -141,7 +171,7 @@ typedef void (*cairo_destroy_func_t) (void *data); * and there is no need to initialize the object; only the unique * address of a #cairo_data_key_t object is used. Typically, you * would just use the address of a static #cairo_data_key_t object. - */ + **/ typedef struct _cairo_user_data_key { int unused; } cairo_user_data_key_t; @@ -219,7 +249,7 @@ typedef enum _cairo_status { * Note: The large values here are designed to keep cairo_content_t * values distinct from cairo_format_t values so that the * implementation can detect the error if users confuse the two types. - */ + **/ typedef enum _cairo_content { CAIRO_CONTENT_COLOR = 0x1000, CAIRO_CONTENT_ALPHA = 0x2000, @@ -241,7 +271,7 @@ typedef enum _cairo_content { * CAIRO_STATUS_WRITE_ERROR otherwise. * * Returns: the status code of the write operation - */ + **/ typedef cairo_status_t (*cairo_write_func_t) (void *closure, const unsigned char *data, unsigned int length); @@ -261,7 +291,7 @@ typedef cairo_status_t (*cairo_write_func_t) (void *closure, * CAIRO_STATUS_READ_ERROR otherwise. * * Returns: the status code of the read operation - */ + **/ typedef cairo_status_t (*cairo_read_func_t) (void *closure, unsigned char *data, unsigned int length); @@ -276,6 +306,19 @@ cairo_reference (cairo_t *cr); cairo_public void cairo_destroy (cairo_t *cr); +cairo_public unsigned int +cairo_get_reference_count (cairo_t *cr); + +cairo_public void * +cairo_get_user_data (cairo_t *cr, + const cairo_user_data_key_t *key); + +cairo_public cairo_status_t +cairo_set_user_data (cairo_t *cr, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy); + cairo_public void cairo_save (cairo_t *cr); @@ -402,7 +445,7 @@ cairo_set_line_width (cairo_t *cr, double width); * @CAIRO_LINE_CAP_ROUND: use a round ending, the center of the circle is the end point * @CAIRO_LINE_CAP_SQUARE: use squared ending, the center of the square is the end point * - * enumeration for style of line-endings + * Specifies how to render the endpoint of a line when stroking. **/ typedef enum _cairo_line_cap { CAIRO_LINE_CAP_BUTT, @@ -413,6 +456,17 @@ typedef enum _cairo_line_cap { cairo_public void cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap); +/** + * cairo_line_join_t + * @CAIRO_LINE_JOIN_MITER: use a sharp (angled) corner, see + * cairo_set_miter_limit() + * @CAIRO_LINE_JOIN_ROUND: use a rounded join, the center of the circle is the + * joint point + * @CAIRO_LINE_JOIN_BEVEL: use a cut-off join, the join is cut off at half + * the line width from the joint point + * + * Specifies how to render the junction of two lines when stroking. + **/ typedef enum _cairo_line_join { CAIRO_LINE_JOIN_MITER, CAIRO_LINE_JOIN_ROUND, @@ -598,23 +652,30 @@ cairo_clip_extents (cairo_t *cr, /** * cairo_rectangle_t: - * + * @x: X coordinate of the left side of the rectangle + * @y: Y coordinate of the the top side of the rectangle + * @width: width of the rectangle + * @height: height of the rectangle + * * A data structure for holding a rectangle. * * Since: 1.4 - */ + **/ typedef struct _cairo_rectangle { double x, y, width, height; } cairo_rectangle_t; /** * cairo_rectangle_list_t: + * @status: Error status of the rectangle list + * @rectangles: Array containing the rectangles + * @num_rectangles: Number of rectangles in this list * * A data structure for holding a dynamically allocated * array of rectangles. * * Since: 1.4 - */ + **/ typedef struct _cairo_rectangle_list { cairo_status_t status; cairo_rectangle_t *rectangles; @@ -636,7 +697,14 @@ cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list); * resolution. A cairo_scaled_font_t is most useful for low-level font * usage where a library or application wants to cache a reference * to a scaled font to speed up the computation of metrics. - */ + * + * There are various types of scaled fonts, depending on the + * font backend they use. The type of a + * scaled font can be queried using cairo_scaled_font_get_type(). + * + * Memory management of #cairo_scaled_font_t is done with + * cairo_scaled_font_reference() and cairo_scaled_font_destroy(). + **/ typedef struct _cairo_scaled_font cairo_scaled_font_t; /** @@ -648,7 +716,14 @@ typedef struct _cairo_scaled_font cairo_scaled_font_t; * directions) . A font face can be set on a #cairo_t by using * cairo_set_font_face(); the size and font matrix are set with * cairo_set_font_size() and cairo_set_font_matrix(). - */ + * + * There are various types of font faces, depending on the + * font backend they use. The type of a + * font face can be queried using cairo_font_face_get_type(). + * + * Memory management of #cairo_font_face_t is done with + * cairo_font_face_reference() and cairo_font_face_destroy(). + **/ typedef struct _cairo_font_face cairo_font_face_t; /** @@ -707,7 +782,7 @@ typedef struct { * doubled. They will change slightly due to hinting (so you can't * assume that metrics are independent of the transformation matrix), * but otherwise will remain unchanged. - */ + **/ typedef struct { double x_bearing; double y_bearing; @@ -757,7 +832,7 @@ typedef struct { * not be doubled. They will change slightly due to hinting (so you * can't assume that metrics are independent of the transformation * matrix), but otherwise will remain unchanged. - */ + **/ typedef struct { double ascent; double descent; @@ -766,12 +841,27 @@ typedef struct { double max_y_advance; } cairo_font_extents_t; +/** + * cairo_font_slant_t: + * @CAIRO_FONT_SLANT_NORMAL: Upright font style + * @CAIRO_FONT_SLANT_ITALIC: Italic font style + * @CAIRO_FONT_SLANT_OBLIQUE: Oblique font style + * + * Specifies variants of a font face based on their slant. + **/ typedef enum _cairo_font_slant { CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_SLANT_ITALIC, CAIRO_FONT_SLANT_OBLIQUE } cairo_font_slant_t; +/** + * cairo_font_weight_t: + * @CAIRO_FONT_WEIGHT_NORMAL: Normal font weight + * @CAIRO_FONT_WEIGHT_BOLD: Bold font weight + * + * Specifies variants of a font face based on their weight. + **/ typedef enum _cairo_font_weight { CAIRO_FONT_WEIGHT_NORMAL, CAIRO_FONT_WEIGHT_BOLD @@ -823,7 +913,7 @@ typedef enum _cairo_subpixel_order { * styles are supported by all font backends. * * New entries may be added in future versions. - */ + **/ typedef enum _cairo_hint_style { CAIRO_HINT_STYLE_DEFAULT, CAIRO_HINT_STYLE_NONE, @@ -844,13 +934,33 @@ typedef enum _cairo_hint_style { * device space. Doing this improves the consistency of * letter and line spacing, however it also means that text * will be laid out differently at different zoom factors. - */ + **/ typedef enum _cairo_hint_metrics { CAIRO_HINT_METRICS_DEFAULT, CAIRO_HINT_METRICS_OFF, CAIRO_HINT_METRICS_ON } cairo_hint_metrics_t; +/** + * cairo_font_options_t: + * + * An opaque structure holding all options that are used when + * rendering fonts. + * + * Individual features of a #cairo_font_options_t can be set or + * accessed using functions named + * cairo_font_options_set_feature_name and + * cairo_font_options_get_feature_name, like + * cairo_font_options_set_antialias() and + * cairo_font_options_get_antialias(). + * + * New features may be added to a #cairo_font_options_t in the + * future. For this reason, cairo_font_options_copy(), + * cairo_font_options_equal(), cairo_font_options_merge(), and + * cairo_font_options_hash() should be used to copy, check + * for equality, merge, or compute a hash value of + * #cairo_font_options_t objects. + **/ typedef struct _cairo_font_options cairo_font_options_t; cairo_public cairo_font_options_t * @@ -927,25 +1037,30 @@ cairo_public void cairo_get_font_options (cairo_t *cr, cairo_font_options_t *options); +cairo_public void +cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face); + +cairo_public cairo_font_face_t * +cairo_get_font_face (cairo_t *cr); + cairo_public void cairo_set_scaled_font (cairo_t *cr, const cairo_scaled_font_t *scaled_font); +cairo_public cairo_scaled_font_t * +cairo_get_scaled_font (cairo_t *cr); + cairo_public void cairo_show_text (cairo_t *cr, const char *utf8); cairo_public void cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs); -cairo_public cairo_font_face_t * -cairo_get_font_face (cairo_t *cr); +cairo_public void +cairo_text_path (cairo_t *cr, const char *utf8); cairo_public void -cairo_font_extents (cairo_t *cr, - cairo_font_extents_t *extents); - -cairo_public void -cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face); +cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs); cairo_public void cairo_text_extents (cairo_t *cr, @@ -959,10 +1074,8 @@ cairo_glyph_extents (cairo_t *cr, cairo_text_extents_t *extents); cairo_public void -cairo_text_path (cairo_t *cr, const char *utf8); - -cairo_public void -cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs); +cairo_font_extents (cairo_t *cr, + cairo_font_extents_t *extents); /* Generic identifier for a font style */ @@ -972,6 +1085,9 @@ cairo_font_face_reference (cairo_font_face_t *font_face); cairo_public void cairo_font_face_destroy (cairo_font_face_t *font_face); +cairo_public unsigned int +cairo_font_face_get_reference_count (cairo_font_face_t *font_face); + cairo_public cairo_status_t cairo_font_face_status (cairo_font_face_t *font_face); @@ -1010,7 +1126,7 @@ cairo_font_face_status (cairo_font_face_t *font_face); * New entries may be added in future versions. * * Since: 1.2 - */ + **/ typedef enum _cairo_font_type { CAIRO_FONT_TYPE_TOY, CAIRO_FONT_TYPE_FT, @@ -1045,12 +1161,25 @@ cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font); cairo_public void cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font); +cairo_public unsigned int +cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font); + cairo_public cairo_status_t cairo_scaled_font_status (cairo_scaled_font_t *scaled_font); cairo_public cairo_font_type_t cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font); +cairo_public void * +cairo_scaled_font_get_user_data (cairo_scaled_font_t *scaled_font, + const cairo_user_data_key_t *key); + +cairo_public cairo_status_t +cairo_scaled_font_set_user_data (cairo_scaled_font_t *scaled_font, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy); + cairo_public void cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font, cairo_font_extents_t *extents); @@ -1128,6 +1257,17 @@ cairo_get_target (cairo_t *cr); cairo_public cairo_surface_t * cairo_get_group_target (cairo_t *cr); +/** + * cairo_path_data_type_t: + * @CAIRO_PATH_MOVE_TO: A move-to operation + * @CAIRO_PATH_LINE_TO: A line-to operation + * @CAIRO_PATH_CURVE_TO: A curve-to operation + * @CAIRO_PATH_CLOSE_PATH: A close-path operation + * + * #cairo_path_data_t is used to describe the type of one portion + * of a path when represented as a #cairo_path_t. + * See #cairo_path_data_t for details. + **/ typedef enum _cairo_path_data_type { CAIRO_PATH_MOVE_TO, CAIRO_PATH_LINE_TO, @@ -1149,8 +1289,7 @@ typedef enum _cairo_path_data_type { * the array, (one header followed by 0 or more points). The length * value of the header is the number of array elements for the current * portion including the header, (ie. length == 1 + # of points), and - * where the number of points for each element type must be as - * follows: + * where the number of points for each element type is as follows: * * * %CAIRO_PATH_MOVE_TO: 1 point @@ -1193,6 +1332,14 @@ typedef enum _cairo_path_data_type { * } * cairo_path_destroy (path); * + * + * As of cairo 1.4, cairo does not mind if there are more elements in + * a portion of the path than needed. Such elements can be used by + * users of the cairo API to hold extra values in the path data + * structure. For this reason, it is recommended that applications + * always use data->header.length to + * iterate over the path data, instead of hardcoding the number of + * elements for each element type. **/ typedef union _cairo_path_data_t cairo_path_data_t; union _cairo_path_data_t { @@ -1268,12 +1415,12 @@ cairo_surface_finish (cairo_surface_t *surface); cairo_public void cairo_surface_destroy (cairo_surface_t *surface); -cairo_public cairo_status_t -cairo_surface_status (cairo_surface_t *surface); - cairo_public unsigned int cairo_surface_get_reference_count (cairo_surface_t *surface); +cairo_public cairo_status_t +cairo_surface_status (cairo_surface_t *surface); + /** * cairo_surface_type_t * @CAIRO_SURFACE_TYPE_IMAGE: The surface is of type image @@ -1311,7 +1458,7 @@ cairo_surface_get_reference_count (cairo_surface_t *surface); * New entries may be added in future versions. * * Since: 1.2 - */ + **/ typedef enum _cairo_surface_type { CAIRO_SURFACE_TYPE_IMAGE, CAIRO_SURFACE_TYPE_PDF, @@ -1324,7 +1471,6 @@ typedef enum _cairo_surface_type { CAIRO_SURFACE_TYPE_BEOS, CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_SURFACE_TYPE_SVG, - CAIRO_SURFACE_TYPE_NQUARTZ, CAIRO_SURFACE_TYPE_OS2 } cairo_surface_type_t; @@ -1417,7 +1563,7 @@ cairo_surface_set_fallback_resolution (cairo_surface_t *surface, * image data. * * New entries may be added in future versions. - */ + **/ typedef enum _cairo_format { CAIRO_FORMAT_ARGB32, CAIRO_FORMAT_RGB24, @@ -1493,9 +1639,22 @@ cairo_pattern_reference (cairo_pattern_t *pattern); cairo_public void cairo_pattern_destroy (cairo_pattern_t *pattern); +cairo_public unsigned int +cairo_pattern_get_reference_count (cairo_pattern_t *pattern); + cairo_public cairo_status_t cairo_pattern_status (cairo_pattern_t *pattern); +cairo_public void * +cairo_pattern_get_user_data (cairo_pattern_t *pattern, + const cairo_user_data_key_t *key); + +cairo_public cairo_status_t +cairo_pattern_set_user_data (cairo_pattern_t *pattern, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy); + /** * cairo_pattern_type_t * @CAIRO_PATTERN_TYPE_SOLID: The pattern is a solid (uniform) @@ -1525,7 +1684,7 @@ cairo_pattern_status (cairo_pattern_t *pattern); * New entries may be added in future versions. * * Since: 1.2 - */ + **/ typedef enum _cairo_pattern_type { CAIRO_PATTERN_TYPE_SOLID, CAIRO_PATTERN_TYPE_SURFACE, @@ -1570,7 +1729,7 @@ cairo_pattern_get_matrix (cairo_pattern_t *pattern, * of a pattern will be drawn. * * New entries may be added in future versions. - */ + **/ typedef enum _cairo_extend { CAIRO_EXTEND_NONE, CAIRO_EXTEND_REPEAT, @@ -1677,12 +1836,6 @@ cairo_public void cairo_matrix_transform_point (const cairo_matrix_t *matrix, double *x, double *y); -cairo_public void -cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix, - double *x1, double *y1, - double *x2, double *y2, - cairo_bool_t *is_tight); - /* Functions to be used while debugging (not intended for use in production code) */ cairo_public void cairo_debug_reset_static_data (void); diff --git a/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h index 28c39b31eb8..d50a7892e72 100644 --- a/gfx/cairo/cairo/src/cairoint.h +++ b/gfx/cairo/cairo/src/cairoint.h @@ -73,7 +73,7 @@ CAIRO_BEGIN_DECLS -#if __GNUC__ >= 3 && defined(__ELF__) +#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun) # define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) # define slim_hidden_def(name) slim_hidden_def1(name, slim_hidden_int_name(name)) # define slim_hidden_int_name(name) INT_##name @@ -102,7 +102,7 @@ CAIRO_BEGIN_DECLS #endif /* slim_internal.h */ -#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) +#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun) #define cairo_private __attribute__((__visibility__("hidden"))) #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) #define cairo_private __hidden @@ -134,13 +134,20 @@ CAIRO_BEGIN_DECLS #define __attribute__(x) #endif -#if 0 +#if MOZILLA_CAIRO_NOT_DEFINED #if HAVE_PTHREAD_H # include # define CAIRO_MUTEX_DECLARE(name) static pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER -#define CAIRO_MUTEX_DECLARE_GLOBAL(name) pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER +# define CAIRO_MUTEX_DECLARE_GLOBAL(name) pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER # define CAIRO_MUTEX_LOCK(name) pthread_mutex_lock (&name) # define CAIRO_MUTEX_UNLOCK(name) pthread_mutex_unlock (&name) +typedef pthread_mutex_t cairo_mutex_t; +#define CAIRO_MUTEX_INIT(mutex) do { \ + pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER; \ + memcpy (mutex, &tmp_mutex, sizeof (tmp_mutex)); \ +} while (0) +# define CAIRO_MUTEX_FINI(mutex) pthread_mutex_destroy (mutex) +# define CAIRO_MUTEX_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER #endif #if !defined(CAIRO_MUTEX_DECLARE) && defined CAIRO_HAS_WIN32_SURFACE @@ -160,6 +167,10 @@ CAIRO_BEGIN_DECLS # define CAIRO_MUTEX_DECLARE_GLOBAL(name) extern LPCRITICAL_SECTION name; # define CAIRO_MUTEX_LOCK(name) EnterCriticalSection (&name) # define CAIRO_MUTEX_UNLOCK(name) LeaveCriticalSection (&name) +typedef CRITICAL_SECTION cairo_mutex_t; +# define CAIRO_MUTEX_INIT(mutex) InitializeCriticalSection (mutex) +# define CAIRO_MUTEX_FINI(mutex) DeleteCriticalSection (mutex) +# define CAIRO_MUTEX_NIL_INITIALIZER { 0 } #endif #if defined(__OS2__) && !defined(CAIRO_MUTEX_DECLARE) @@ -171,6 +182,10 @@ CAIRO_BEGIN_DECLS # define CAIRO_MUTEX_DECLARE_GLOBAL(name) extern HMTX name # define CAIRO_MUTEX_LOCK(name) DosRequestMutexSem(name, SEM_INDEFINITE_WAIT) # define CAIRO_MUTEX_UNLOCK(name) DosReleaseMutexSem(name) +typedef HMTX cairo_mutex_t; +# define CAIRO_MUTEX_INIT(mutex) DosCreateMutexSem (NULL, mutex, 0L, FALSE) +# define CAIRO_MUTEX_FINI(mutex) DosCloseMutexSem (*(mutex)) +# define CAIRO_MUTEX_NIL_INITIALIZER 0 #endif #if !defined(CAIRO_MUTEX_DECLARE) && defined CAIRO_HAS_BEOS_SURFACE @@ -181,14 +196,29 @@ cairo_private void _cairo_beos_unlock(void*); # define CAIRO_MUTEX_DECLARE_GLOBAL(name) extern void* name; # define CAIRO_MUTEX_LOCK(name) _cairo_beos_lock (&name) # define CAIRO_MUTEX_UNLOCK(name) _cairo_beos_unlock (&name) +# error "XXX: Someone who understands BeOS needs to add definitions for" \ + " cairo_mutex_t, CAIRO_MUTEX_INIT, and CAIRO_MUTEX_FINI," \ + " to cairoint.h" +typedef ??? cairo_mutex_t; +# define CAIRO_MUTEX_INIT(mutex) ??? +# define CAIRO_MUTEX_FINI(mutex) ??? +# define CAIRO_MUTEX_NIL_INITIALIZER {} #endif -#endif +#endif /* MOZILLA_CAIRO_NOT_REACHED */ #ifndef CAIRO_MUTEX_DECLARE +#if MOZILLA_CAIRO_NOT_DEFINED +# error "No mutex declarations. Cairo will not work with multiple threads." \ + "(Remove this #error directive to acknowledge & accept this limitation)." +#endif +typedef void *cairo_mutex_t; # define CAIRO_MUTEX_DECLARE(name) # define CAIRO_MUTEX_DECLARE_GLOBAL(name) # define CAIRO_MUTEX_LOCK(name) # define CAIRO_MUTEX_UNLOCK(name) +#define CAIRO_MUTEX_INIT(mutex) (*(mutex) = 0) +#define CAIRO_MUTEX_FINI(mutex) +#define CAIRO_MUTEX_NIL_INITIALIZER 0 #endif #undef MIN @@ -209,6 +239,18 @@ cairo_private void _cairo_beos_unlock(void*); #define M_PI 3.14159265358979323846 #endif +#ifndef MOZILLA_CAIRO_NOT_DEFINED +#ifndef INT32_MAX +# ifdef INT_MAX +# define INT32_MAX INT_MAX +# define INT32_MIN INT_MIN +# else +# define INT32_MAX 2147483647 +# define INT32_MIN (-2147483647 - 1) +# endif +#endif +#endif + /* Size in bytes of buffer to use off the stack per functions. * Mostly used by text functions. For larger allocations, they'll * malloc(). */ @@ -250,6 +292,41 @@ typedef cairo_fixed_16_16_t cairo_fixed_t; #define CAIRO_BITSWAP8_IF_LITTLE_ENDIAN(c) CAIRO_BITSWAP8(c) #endif +#ifdef WORDS_BIGENDIAN + +#define cpu_to_be16(v) (v) +#define be16_to_cpu(v) (v) +#define cpu_to_be32(v) (v) +#define be32_to_cpu(v) (v) + +#else + +static inline uint16_t +cpu_to_be16(uint16_t v) +{ + return (v << 8) | (v >> 8); +} + +static inline uint16_t +be16_to_cpu(uint16_t v) +{ + return cpu_to_be16 (v); +} + +static inline uint32_t +cpu_to_be32(uint32_t v) +{ + return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16); +} + +static inline uint32_t +be32_to_cpu(uint32_t v) +{ + return cpu_to_be32 (v); +} + +#endif + #include "cairo-hash-private.h" #include "cairo-cache-private.h" @@ -364,15 +441,14 @@ typedef struct _cairo_edge { } cairo_edge_t; typedef struct _cairo_polygon { + cairo_point_t first_point; + cairo_point_t current_point; + cairo_bool_t has_current_point; + int num_edges; int edges_size; cairo_edge_t *edges; - - cairo_point_t first_point; - cairo_point_t current_point; - int has_current_point; - - int closed; + cairo_edge_t edges_embedded[8]; } cairo_polygon_t; typedef struct _cairo_spline { @@ -384,6 +460,7 @@ typedef struct _cairo_spline { int num_points; int points_size; cairo_point_t *points; + cairo_point_t points_embedded[8]; } cairo_spline_t; typedef struct _cairo_pen_vertex { @@ -523,12 +600,43 @@ typedef struct _cairo_scaled_glyph { #define _cairo_scaled_glyph_set_index(g,i) ((g)->cache_entry.hash = (i)) struct _cairo_scaled_font { + /* For most cairo objects, the rule for multiple threads is that + * the user is responsible for any locking if the same object is + * manipulated from multiple threads simultaneously. + * + * However, with the caching that cairo does for scaled fonts, a + * user can easily end up with the same cairo_scaled_font object + * being manipulated from multiple threads without the user ever + * being aware of this, (and in fact, unable to control it). + * + * So, as a special exception, the cairo implementation takes care + * of all locking needed for cairo_scaled_font_t. Most of what is + * in the scaled font is immutable, (which is what allows for the + * sharing in the first place). The things that are modified and + * the locks protecting them are as follows: + * + * 1. The reference count (scaled_font->ref_count) + * + * Modifications to the reference count are protected by the + * _cairo_scaled_font_map_mutex. This is because the reference + * count of a scaled font is intimately related with the font + * map itself, (and the magic holdovers array). + * + * 2. The cache of glyphs (scaled_font->glyphs) + * 3. The backend private data (scaled_font->surface_backend, + * scaled_font->surface_private) + * + * Modifications to these fields are protected with locks on + * scaled_font->mutex in the generic scaled_font code. + */ + /* must be first to be stored in a hash table */ cairo_hash_entry_t hash_entry; /* useful bits for _cairo_scaled_font_nil */ cairo_status_t status; unsigned int ref_count; + cairo_user_data_array_t user_data; /* hash key members */ cairo_font_face_t *font_face; /* may be NULL */ @@ -539,6 +647,10 @@ struct _cairo_scaled_font { /* "live" scaled_font members */ cairo_matrix_t scale; /* font space => device space */ cairo_font_extents_t extents; /* user space */ + + /* The mutex protects modification to all subsequent fields. */ + cairo_mutex_t mutex; + cairo_cache_t *glyphs; /* glyph index -> cairo_scaled_glyph_t */ /* @@ -598,6 +710,19 @@ typedef enum _cairo_scaled_glyph_info { CAIRO_SCALED_GLYPH_INFO_PATH = (1 << 2) } cairo_scaled_glyph_info_t; +typedef struct _cairo_scaled_font_subset { + cairo_scaled_font_t *scaled_font; + unsigned int font_id; + unsigned int subset_id; + + /* Index of glyphs array is subset_glyph_index. + * Value of glyphs array is scaled_font_glyph_index. + */ + unsigned long *glyphs; + unsigned long *to_unicode; + unsigned int num_glyphs; +} cairo_scaled_font_subset_t; + struct _cairo_scaled_font_backend { cairo_font_type_t type; @@ -651,6 +776,11 @@ struct _cairo_scaled_font_backend { long offset, unsigned char *buffer, unsigned long *length); + + void + (*map_glyphs_to_unicode)(void *scaled_font, + cairo_scaled_font_subset_t *font_subset); + }; struct _cairo_font_face_backend { @@ -1042,12 +1172,14 @@ typedef enum { #define CAIRO_FILTER_DEFAULT CAIRO_FILTER_BEST struct _cairo_pattern { - cairo_pattern_type_t type; - unsigned int ref_count; - cairo_status_t status; - cairo_matrix_t matrix; - cairo_filter_t filter; - cairo_extend_t extend; + cairo_pattern_type_t type; + unsigned int ref_count; + cairo_status_t status; + cairo_user_data_array_t user_data; + + cairo_matrix_t matrix; + cairo_filter_t filter; + cairo_extend_t extend; }; typedef struct _cairo_solid_pattern { @@ -1066,8 +1198,10 @@ typedef struct _cairo_surface_pattern { typedef struct _cairo_gradient_pattern { cairo_pattern_t base; + unsigned int n_stops; + unsigned int stops_size; pixman_gradient_stop_t *stops; - unsigned int n_stops; + pixman_gradient_stop_t stops_embedded[2]; } cairo_gradient_pattern_t; typedef struct _cairo_linear_pattern { @@ -1110,10 +1244,12 @@ typedef struct _cairo_surface_attributes { typedef struct _cairo_traps { cairo_status_t status; - cairo_trapezoid_t *traps; + cairo_box_t extents; + int num_traps; int traps_size; - cairo_box_t extents; + cairo_trapezoid_t *traps; + cairo_trapezoid_t traps_embedded[1]; } cairo_traps_t; #define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL @@ -1196,15 +1332,19 @@ cairo_private int _cairo_fixed_integer_ceil (cairo_fixed_t f); /* cairo_gstate.c */ -cairo_private cairo_gstate_t * -_cairo_gstate_create (cairo_surface_t *target); +cairo_private cairo_status_t +_cairo_gstate_init (cairo_gstate_t *gstate, + cairo_surface_t *target); cairo_private void -_cairo_gstate_destroy (cairo_gstate_t *gstate); +_cairo_gstate_fini (cairo_gstate_t *gstate); cairo_private cairo_gstate_t * _cairo_gstate_clone (cairo_gstate_t *gstate); +cairo_private void +_cairo_gstate_destroy (cairo_gstate_t *gstate); + cairo_private cairo_bool_t _cairo_gstate_is_redirected (cairo_gstate_t *gstate); @@ -1420,6 +1560,10 @@ cairo_private cairo_status_t _cairo_gstate_get_font_face (cairo_gstate_t *gstate, cairo_font_face_t **font_face); +cairo_private cairo_status_t +_cairo_gstate_get_scaled_font (cairo_gstate_t *gstate, + cairo_scaled_font_t **scaled_font); + cairo_private cairo_status_t _cairo_gstate_get_font_extents (cairo_gstate_t *gstate, cairo_font_extents_t *extents); @@ -1467,6 +1611,9 @@ _cairo_stock_color (cairo_stock_t stock); #define CAIRO_COLOR_BLACK _cairo_stock_color (CAIRO_STOCK_BLACK) #define CAIRO_COLOR_TRANSPARENT _cairo_stock_color (CAIRO_STOCK_TRANSPARENT) +cairo_private uint16_t +_cairo_color_double_to_short (double d); + cairo_private void _cairo_color_init (cairo_color_t *color); @@ -1505,11 +1652,15 @@ _cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font); cairo_private void _cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font); +cairo_private void +_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font); + cairo_private void _cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font, cairo_status_t status); extern const cairo_private cairo_font_face_t _cairo_font_face_nil; +extern const cairo_private cairo_scaled_font_t _cairo_scaled_font_nil; cairo_private void _cairo_font_face_init (cairo_font_face_t *font_face, @@ -1760,6 +1911,7 @@ _cairo_stroke_style_fini (cairo_stroke_style_t *style); extern const cairo_private cairo_surface_t _cairo_surface_nil; extern const cairo_private cairo_surface_t _cairo_surface_nil_read_error; +extern const cairo_private cairo_surface_t _cairo_surface_nil_write_error; extern const cairo_private cairo_surface_t _cairo_surface_nil_file_not_found; cairo_private void @@ -2185,6 +2337,12 @@ _cairo_matrix_get_affine (const cairo_matrix_t *matrix, double *xy, double *yy, double *x0, double *y0); +cairo_private void +_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix, + double *x1, double *y1, + double *x2, double *y2, + cairo_bool_t *is_tight); + cairo_private void _cairo_matrix_compute_determinant (const cairo_matrix_t *matrix, double *det); @@ -2420,7 +2578,6 @@ slim_hidden_proto (cairo_matrix_multiply); slim_hidden_proto (cairo_matrix_scale); slim_hidden_proto (cairo_matrix_transform_distance); slim_hidden_proto (cairo_matrix_transform_point); -slim_hidden_proto (cairo_matrix_transform_bounding_box); slim_hidden_proto (cairo_matrix_translate); slim_hidden_proto (cairo_move_to); slim_hidden_proto (cairo_new_path); @@ -2441,6 +2598,7 @@ slim_hidden_proto (cairo_push_group_with_content); slim_hidden_proto (cairo_rel_line_to); slim_hidden_proto (cairo_restore); slim_hidden_proto (cairo_save); +slim_hidden_proto (cairo_scale); slim_hidden_proto (cairo_scaled_font_create); slim_hidden_proto (cairo_scaled_font_destroy); slim_hidden_proto (cairo_scaled_font_extents); @@ -2467,9 +2625,14 @@ slim_hidden_proto (cairo_surface_reference); slim_hidden_proto (cairo_surface_set_device_offset); slim_hidden_proto (cairo_surface_set_fallback_resolution); slim_hidden_proto (cairo_surface_status); -slim_hidden_proto (cairo_surface_write_to_png_stream); slim_hidden_proto (cairo_version_string); +#if CAIRO_HAS_PNG_FUNCTIONS + +slim_hidden_proto (cairo_surface_write_to_png_stream); + +#endif + CAIRO_END_DECLS #endif diff --git a/gfx/cairo/cairo/src/test-fallback-surface.c b/gfx/cairo/cairo/src/test-fallback-surface.c index 479c8ef62e5..21ee19077fb 100644 --- a/gfx/cairo/cairo/src/test-fallback-surface.c +++ b/gfx/cairo/cairo/src/test-fallback-surface.c @@ -64,10 +64,10 @@ typedef struct _test_fallback_surface { const cairo_private cairo_surface_backend_t test_fallback_surface_backend; -slim_hidden_proto (_test_fallback_surface_create); +slim_hidden_proto (_cairo_test_fallback_surface_create); cairo_surface_t * -_test_fallback_surface_create (cairo_content_t content, +_cairo_test_fallback_surface_create (cairo_content_t content, int width, int height) { @@ -91,7 +91,7 @@ _test_fallback_surface_create (cairo_content_t content, return &surface->base; } -slim_hidden_def (_test_fallback_surface_create); +slim_hidden_def (_cairo_test_fallback_surface_create); static cairo_surface_t * _test_fallback_surface_create_similar (void *abstract_surface, @@ -101,7 +101,7 @@ _test_fallback_surface_create_similar (void *abstract_surface, { assert (CAIRO_CONTENT_VALID (content)); - return _test_fallback_surface_create (content, + return _cairo_test_fallback_surface_create (content, width, height); } diff --git a/gfx/cairo/cairo/src/test-fallback-surface.h b/gfx/cairo/cairo/src/test-fallback-surface.h index 25603072e90..744b303a1e0 100644 --- a/gfx/cairo/cairo/src/test-fallback-surface.h +++ b/gfx/cairo/cairo/src/test-fallback-surface.h @@ -41,7 +41,7 @@ CAIRO_BEGIN_DECLS cairo_surface_t * -_test_fallback_surface_create (cairo_content_t content, +_cairo_test_fallback_surface_create (cairo_content_t content, int width, int height); diff --git a/gfx/cairo/cairo/src/test-meta-surface.c b/gfx/cairo/cairo/src/test-meta-surface.c index 7939b6e93fc..6c5877971ed 100644 --- a/gfx/cairo/cairo/src/test-meta-surface.c +++ b/gfx/cairo/cairo/src/test-meta-surface.c @@ -68,7 +68,7 @@ static cairo_int_status_t _test_meta_surface_show_page (void *abstract_surface); cairo_surface_t * -_test_meta_surface_create (cairo_content_t content, +_cairo_test_meta_surface_create (cairo_content_t content, int width, int height) { @@ -252,12 +252,27 @@ _test_meta_surface_show_glyphs (void *abstract_surface, cairo_scaled_font_t *scaled_font) { test_meta_surface_t *surface = abstract_surface; + cairo_int_status_t status; surface->image_reflects_meta = FALSE; - return _cairo_surface_show_glyphs (surface->meta, op, source, - glyphs, num_glyphs, - scaled_font); + /* Since this is a "wrapping" surface, we're calling back into + * _cairo_surface_show_glyphs from within a call to the same. + * Since _cairo_surface_show_glyphs acquires a mutex, we release + * and re-acquire the mutex around this nested call. + * + * Yes, this is ugly, but we consider it pragmatic as compared to + * adding locking code to all 18 surface-backend-specific + * show_glyphs functions, (which would get less testing and likely + * lead to bugs). + */ + CAIRO_MUTEX_UNLOCK (scaled_font->mutex); + status = _cairo_surface_show_glyphs (surface->meta, op, source, + glyphs, num_glyphs, + scaled_font); + CAIRO_MUTEX_LOCK (scaled_font->mutex); + + return status; } static cairo_surface_t * diff --git a/gfx/cairo/cairo/src/test-meta-surface.h b/gfx/cairo/cairo/src/test-meta-surface.h index 4022ab7ffee..c036bb9c89c 100644 --- a/gfx/cairo/cairo/src/test-meta-surface.h +++ b/gfx/cairo/cairo/src/test-meta-surface.h @@ -41,7 +41,7 @@ CAIRO_BEGIN_DECLS cairo_surface_t * -_test_meta_surface_create (cairo_content_t content, +_cairo_test_meta_surface_create (cairo_content_t content, int width, int height); diff --git a/gfx/cairo/cairo/src/test-paginated-surface.c b/gfx/cairo/cairo/src/test-paginated-surface.c index 544efcf5a91..d82749f69d9 100644 --- a/gfx/cairo/cairo/src/test-paginated-surface.c +++ b/gfx/cairo/cairo/src/test-paginated-surface.c @@ -61,7 +61,7 @@ static const cairo_surface_backend_t test_paginated_surface_backend; static const cairo_paginated_surface_backend_t test_paginated_surface_paginated_backend; cairo_surface_t * -_test_paginated_surface_create_for_data (unsigned char *data, +_cairo_test_paginated_surface_create_for_data (unsigned char *data, cairo_content_t content, int width, int height, @@ -233,12 +233,27 @@ _test_paginated_surface_show_glyphs (void *abstract_surface, cairo_scaled_font_t *scaled_font) { test_paginated_surface_t *surface = abstract_surface; + cairo_int_status_t status; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return CAIRO_STATUS_SUCCESS; - return _cairo_surface_show_glyphs (surface->target, op, source, - glyphs, num_glyphs, scaled_font); + /* Since this is a "wrapping" surface, we're calling back into + * _cairo_surface_show_glyphs from within a call to the same. + * Since _cairo_surface_show_glyphs acquires a mutex, we release + * and re-acquire the mutex around this nested call. + * + * Yes, this is ugly, but we consider it pragmatic as compared to + * adding locking code to all 18 surface-backend-specific + * show_glyphs functions, (which would get less testing and likely + * lead to bugs). + */ + CAIRO_MUTEX_UNLOCK (scaled_font->mutex); + status = _cairo_surface_show_glyphs (surface->target, op, source, + glyphs, num_glyphs, scaled_font); + CAIRO_MUTEX_LOCK (scaled_font->mutex); + + return status; } static void diff --git a/gfx/cairo/cairo/src/test-paginated-surface.h b/gfx/cairo/cairo/src/test-paginated-surface.h index df5500290b4..4879cfcd100 100644 --- a/gfx/cairo/cairo/src/test-paginated-surface.h +++ b/gfx/cairo/cairo/src/test-paginated-surface.h @@ -41,7 +41,7 @@ CAIRO_BEGIN_DECLS cairo_surface_t * -_test_paginated_surface_create_for_data (unsigned char *data, +_cairo_test_paginated_surface_create_for_data (unsigned char *data, cairo_content_t content, int width, int height, diff --git a/gfx/cairo/libpixman/src/fbcompose.c b/gfx/cairo/libpixman/src/fbcompose.c index 3ec25830d7e..ef0be03567f 100644 --- a/gfx/cairo/libpixman/src/fbcompose.c +++ b/gfx/cairo/libpixman/src/fbcompose.c @@ -28,7 +28,9 @@ #endif #include "pixman-xserver-compat.h" #include "fbpict.h" +#ifndef MOZILLA_CAIRO_NOT_DEFINED #include "fbmmx.h" +#endif /* MOZCAIRO */ #ifdef RENDER @@ -38,6 +40,7 @@ #define _USE_MATH_DEFINES #endif +#include #include #ifndef M_PI @@ -2740,12 +2743,13 @@ typedef struct CARD32 right_rb; int32_t left_x; int32_t right_x; - int32_t width_x; int32_t stepper; pixman_gradient_stop_t *stops; int num_stops; unsigned int spread; + + int need_reset; } GradientWalker; static void @@ -2757,13 +2761,14 @@ _gradient_walker_init (GradientWalker *walker, walker->stops = pGradient->gradient.stops; walker->left_x = 0; walker->right_x = 0x10000; - walker->width_x = 0; /* will force a reset */ walker->stepper = 0; walker->left_ag = 0; walker->left_rb = 0; walker->right_ag = 0; walker->right_rb = 0; walker->spread = spread; + + walker->need_reset = TRUE; } static void @@ -2853,13 +2858,15 @@ _gradient_walker_reset (GradientWalker *walker, pixman_color_t *tmp_c; int32_t tmp_x; - tmp_x = 0x20000 - right_x; - right_x = 0x20000 - left_x; + tmp_x = 0x10000 - right_x; + right_x = 0x10000 - left_x; left_x = tmp_x; tmp_c = right_c; right_c = left_c; left_c = tmp_c; + + x = 0x10000 - x; } left_x += (pos - x); right_x += (pos - x); @@ -2893,27 +2900,28 @@ _gradient_walker_reset (GradientWalker *walker, walker->left_x = left_x; walker->right_x = right_x; - walker->width_x = right_x - left_x; walker->left_ag = ((left_c->alpha >> 8) << 16) | (left_c->green >> 8); walker->left_rb = ((left_c->red & 0xff00) << 8) | (left_c->blue >> 8); walker->right_ag = ((right_c->alpha >> 8) << 16) | (right_c->green >> 8); walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8); - if ( walker->width_x == 0 || + if ( walker->left_x == walker->right_x || ( walker->left_ag == walker->right_ag && walker->left_rb == walker->right_rb ) ) { - walker->width_x = 1; walker->stepper = 0; } else { - walker->stepper = ((1 << 24) + walker->width_x/2)/walker->width_x; + int32_t width = right_x - left_x; + walker->stepper = ((1 << 24) + width/2)/width; } + + walker->need_reset = FALSE; } #define GRADIENT_WALKER_NEED_RESET(w,x) \ - ( (x) < (w)->left_x || (x) - (w)->left_x >= (w)->width_x ) + ( (w)->need_reset || (x) < (w)->left_x || (x) >= (w)->right_x) /* the following assumes that GRADIENT_WALKER_NEED_RESET(w,x) is FALSE */ static CARD32 @@ -2948,8 +2956,6 @@ _gradient_walker_pixel (GradientWalker *walker, return (color | (t1 & 0xff00ff) | (t2 & 0xff00)); } - - static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *buffer, CARD32 *mask, CARD32 maskBits) { SourcePictPtr pGradient = pict->pSourcePict; @@ -3081,13 +3087,128 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 * } } } else { + +/* + * In the radial gradient problem we are given two circles (c₁,r₁) and + * (c₂,r₂) that define the gradient itself. Then, for any point p, we + * must compute the value(s) of t within [0.0, 1.0] representing the + * circle(s) that would color the point. + * + * There are potentially two values of t since the point p can be + * colored by both sides of the circle, (which happens whenever one + * circle is not entirely contained within the other). + * + * If we solve for a value of t that is outside of [0.0, 1.0] then we + * use the extend mode (NONE, REPEAT, REFLECT, or PAD) to map to a + * value within [0.0, 1.0]. + * + * Here is an illustration of the problem: + * + * p₂ + * p • + * • ╲ + * · ╲r₂ + * p₁ · ╲ + * • θ╲ + * ╲ ╌╌• + * ╲r₁ · c₂ + * θ╲ · + * ╌╌• + * c₁ + * + * Given (c₁,r₁), (c₂,r₂) and p, we must find an angle θ such that two + * points p₁ and p₂ on the two circles are collinear with p. Then, the + * desired value of t is the ratio of the length of p₁p to the length + * of p₁p₂. + * + * So, we have six unknown values: (p₁x, p₁y), (p₂x, p₂y), θ and t. + * We can also write six equations that constrain the problem: + * + * Point p₁ is a distance r₁ from c₁ at an angle of θ: + * + * 1. p₁x = c₁x + r₁·cos θ + * 2. p₁y = c₁y + r₁·sin θ + * + * Point p₂ is a distance r₂ from c₂ at an angle of θ: + * + * 3. p₂x = c₂x + r2·cos θ + * 4. p₂y = c₂y + r2·sin θ + * + * Point p lies at a fraction t along the line segment p₁p₂: + * + * 5. px = t·p₂x + (1-t)·p₁x + * 6. py = t·p₂y + (1-t)·p₁y + * + * To solve, first subtitute 1-4 into 5 and 6: + * + * px = t·(c₂x + r₂·cos θ) + (1-t)·(c₁x + r₁·cos θ) + * py = t·(c₂y + r₂·sin θ) + (1-t)·(c₁y + r₁·sin θ) + * + * Then solve each for cos θ and sin θ expressed as a function of t: + * + * cos θ = (-(c₂x - c₁x)·t + (px - c₁x)) / ((r₂-r₁)·t + r₁) + * sin θ = (-(c₂y - c₁y)·t + (py - c₁y)) / ((r₂-r₁)·t + r₁) + * + * To simplify this a bit, we define new variables for several of the + * common terms as shown below: + * + * p₂ + * p • + * • ╲ + * · ┆ ╲r₂ + * p₁ · ┆ ╲ + * • pdy┆ ╲ + * ╲ ┆ •c₂ + * ╲r₁ ┆ · ┆ + * ╲ ·┆ ┆cdy + * •╌╌╌╌┴╌╌╌╌╌╌╌┘ + * c₁ pdx cdx + * + * cdx = (c₂x - c₁x) + * cdy = (c₂y - c₁y) + * dr = r₂-r₁ + * pdx = px - c₁x + * pdy = py - c₁y + * + * Note that cdx, cdy, and dr do not depend on point p at all, so can + * be pre-computed for the entire gradient. The simplifed equations + * are now: + * + * cos θ = (-cdx·t + pdx) / (dr·t + r₁) + * sin θ = (-cdy·t + pdy) / (dr·t + r₁) + * + * Finally, to get a single function of t and eliminate the last + * unknown θ, we use the identity sin²θ + cos²θ = 1. First, square + * each equation, (we knew a quadratic was coming since it must be + * possible to obtain two solutions in some cases): + * + * cos²θ = (cdx²t² - 2·cdx·pdx·t + pdx²) / (dr²·t² + 2·r₁·dr·t + r₁²) + * sin²θ = (cdy²t² - 2·cdy·pdy·t + pdy²) / (dr²·t² + 2·r₁·dr·t + r₁²) + * + * Then add both together, set the result equal to 1, and express as a + * standard quadratic equation in t of the form At² + Bt + C = 0 + * + * (cdx² + cdy² - dr²)·t² - 2·(cdx·pdx + cdy·pdy + r₁·dr)·t + (pdx² + pdy² - r₁²) = 0 + * + * In other words: + * + * A = cdx² + cdy² - dr² + * B = -2·(pdx·cdx + pdy·cdy + r₁·dr) + * C = pdx² + pdy² - r₁² + * + * And again, notice that A does not depend on p, so can be + * precomputed. From here we just use the quadratic formula to solve + * for t: + * + * t = (-2·B ± ⎷(B² - 4·A·C)) / 2·A + */ /* radial or conical */ Bool projective = FALSE; double cx = 1.; double cy = 0.; double cz = 0.; - double rx = x; - double ry = y; + double rx = x + 0.5; + double ry = y + 0.5; double rz = 1.; if (pict->transform) { @@ -3109,23 +3230,36 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 * } if (pGradient->type == SourcePictTypeRadial) { + pixman_radial_gradient_image_t *radial; + radial = &pGradient->radial; if (!projective) { - rx -= pGradient->radial.fx; - ry -= pGradient->radial.fy; - while (buffer < end) { - double b, c, det, s; - if (!mask || *mask++ & maskBits) { - xFixed_48_16 t; + double pdx, pdy; + double B, C; + double det; + double c1x = xFixedToDouble (radial->c1.x); + double c1y = xFixedToDouble (radial->c1.y); + double r1 = xFixedToDouble (radial->c1.radius); + xFixed_48_16 t; - b = 2*(rx*pGradient->radial.dx + ry*pGradient->radial.dy); - c = -(rx*rx + ry*ry); - det = (b * b) - (4 * pGradient->radial.a * c); - s = (-b + sqrt(det))/(2. * pGradient->radial.a); + pdx = rx - c1x; + pdy = ry - c1y; - t = (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536); + B = -2 * ( pdx * radial->cdx + + pdy * radial->cdy + + r1 * radial->dr); + C = (pdx * pdx + pdy * pdy - r1 * r1); + + det = (B * B) - (4 * radial->A * C); + if (det < 0.0) + det = 0.0; + + if (radial->A < 0) + t = (xFixed_48_16) ((- B - sqrt(det)) / (2.0 * radial->A) * 65536); + else + t = (xFixed_48_16) ((- B + sqrt(det)) / (2.0 * radial->A) * 65536); *buffer = _gradient_walker_pixel (&walker, t); } @@ -3134,35 +3268,12 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 * ry += cy; } } else { - while (buffer < end) { - double x, y; - double b, c, det, s; - - if (!mask || *mask++ & maskBits) - { - xFixed_48_16 t; - - if (rz != 0) { - x = rx/rz; - y = ry/rz; - } else { - x = y = 0.; - } - x -= pGradient->radial.fx; - y -= pGradient->radial.fy; - b = 2*(x*pGradient->radial.dx + y*pGradient->radial.dy); - c = -(x*x + y*y); - det = (b * b) - (4 * pGradient->radial.a * c); - s = (-b + sqrt(det))/(2. * pGradient->radial.a); - t = (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536); - - *buffer = _gradient_walker_pixel (&walker, t); - } - ++buffer; - rx += cx; - ry += cy; - rz += cz; - } + /* In cairo, we don't have projective transformed + * radial gradients---so I'm not going to bother + * implementing something untested and broken + * here. Instead, someone trying to get this code into + * shape for use in the X server can fix this here. */ + assert (0); } } else /* SourcePictTypeConical */ { double a = pGradient->conical.angle/(180.*65536); @@ -3927,6 +4038,7 @@ fbCompositeRect (const FbComposeData *data, CARD32 *scanline_buffer) if (!compose) return; +#ifndef MOZILLA_CAIRO_NOT_DEFINED /* XXX: The non-MMX version of some of the fbCompose functions * overwrite the source or mask data (ones that use * fbCombineMaskC, fbCombineMaskAlphaC, or fbCombineMaskValueC @@ -3944,6 +4056,7 @@ fbCompositeRect (const FbComposeData *data, CARD32 *scanline_buffer) srcClass = SourcePictClassUnknown; maskClass = SourcePictClassUnknown; } +#endif /* MOZCAIRO */ for (i = 0; i < data->height; ++i) { /* fill first half of scanline with source */ diff --git a/gfx/cairo/libpixman/src/fbmmx.c b/gfx/cairo/libpixman/src/fbmmx.c index 0751e3cf928..387d4b46e68 100644 --- a/gfx/cairo/libpixman/src/fbmmx.c +++ b/gfx/cairo/libpixman/src/fbmmx.c @@ -157,6 +157,11 @@ static const MMXData c = #define MC(x) c.mmx_##x #endif +/* cast to void* in the middle to shut gcc up warning about + * "dereferencing type-punned pointers". + */ +#define M64(x) (*(__m64*)(void*)(&x)) + static __inline__ __m64 shift (__m64 v, int s) { @@ -1467,8 +1472,6 @@ fbCompositeSrc_8888x0565mmx (pixman_operator_t op, fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); - assert (pSrc->pDrawable == pMask->pDrawable); - while (height--) { dst = dstLine; @@ -1497,46 +1500,22 @@ fbCompositeSrc_8888x0565mmx (pixman_operator_t op, while (w >= 4) { - CARD32 s0, s1, s2, s3; - unsigned char a0, a1, a2, a3; __m64 vsrc0, vsrc1, vsrc2, vsrc3; + __m64 vdest; - s0 = *src; - s1 = *(src + 1); - s2 = *(src + 2); - s3 = *(src + 3); + vsrc0 = load8888(*(src + 0)); + vsrc1 = load8888(*(src + 1)); + vsrc2 = load8888(*(src + 2)); + vsrc3 = load8888(*(src + 3)); - a0 = (s0 >> 24); - a1 = (s1 >> 24); - a2 = (s2 >> 24); - a3 = (s3 >> 24); - - vsrc0 = load8888(s0); - vsrc1 = load8888(s1); - vsrc2 = load8888(s2); - vsrc3 = load8888(s3); - - if ((a0 & a1 & a2 & a3) == 0xFF) - { - __m64 vdest; - vdest = pack565(vsrc0, _mm_setzero_si64(), 0); - vdest = pack565(vsrc1, vdest, 1); - vdest = pack565(vsrc2, vdest, 2); - vdest = pack565(vsrc3, vdest, 3); - - *(__m64 *)dst = vdest; - } - else if (a0 | a1 | a2 | a3) - { - __m64 vdest = *(__m64 *)dst; - - vdest = pack565(over(vsrc0, expand_alpha(vsrc0), expand565(vdest, 0)), vdest, 0); - vdest = pack565(over(vsrc1, expand_alpha(vsrc1), expand565(vdest, 1)), vdest, 1); - vdest = pack565(over(vsrc2, expand_alpha(vsrc2), expand565(vdest, 2)), vdest, 2); - vdest = pack565(over(vsrc3, expand_alpha(vsrc3), expand565(vdest, 3)), vdest, 3); - - *(__m64 *)dst = vdest; - } + vdest = *(__m64 *)dst; + + vdest = pack565(over(vsrc0, expand_alpha(vsrc0), expand565(vdest, 0)), vdest, 0); + vdest = pack565(over(vsrc1, expand_alpha(vsrc1), expand565(vdest, 1)), vdest, 1); + vdest = pack565(over(vsrc2, expand_alpha(vsrc2), expand565(vdest, 2)), vdest, 2); + vdest = pack565(over(vsrc3, expand_alpha(vsrc3), expand565(vdest, 3)), vdest, 3); + + *(__m64 *)dst = vdest; w -= 4; dst += 4; @@ -1617,7 +1596,7 @@ fbCompositeSolidMask_nx8x8888mmx (pixman_operator_t op, if (m) { - __m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev (*(__m64*)(&m)), load8888(*dst)); + __m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev (M64(m)), load8888(*dst)); *dst = store8888(vdest); } @@ -1645,8 +1624,8 @@ fbCompositeSolidMask_nx8x8888mmx (pixman_operator_t op, vdest = *(__m64 *)dst; - dest0 = in_over(vsrc, vsrca, expand_alpha_rev (*(__m64*)(&m0)), expand8888(vdest, 0)); - dest1 = in_over(vsrc, vsrca, expand_alpha_rev (*(__m64*)(&m1)), expand8888(vdest, 1)); + dest0 = in_over(vsrc, vsrca, expand_alpha_rev (M64(m0)), expand8888(vdest, 0)); + dest1 = in_over(vsrc, vsrca, expand_alpha_rev (M64(m1)), expand8888(vdest, 1)); *(__m64 *)dst = pack8888(dest0, dest1); } @@ -1665,7 +1644,7 @@ fbCompositeSolidMask_nx8x8888mmx (pixman_operator_t op, if (m) { __m64 vdest = load8888(*dst); - vdest = in_over(vsrc, vsrca, expand_alpha_rev (*(__m64*)(&m)), vdest); + vdest = in_over(vsrc, vsrca, expand_alpha_rev (M64(m)), vdest); *dst = store8888(vdest); } @@ -1735,7 +1714,7 @@ fbCompositeSolidMaskSrc_nx8x8888mmx (pixman_operator_t op, if (m) { - __m64 vdest = in(vsrc, expand_alpha_rev (*(__m64*)(&m))); + __m64 vdest = in(vsrc, expand_alpha_rev (M64(m))); *dst = store8888(vdest); } else @@ -1767,8 +1746,8 @@ fbCompositeSolidMaskSrc_nx8x8888mmx (pixman_operator_t op, vdest = *(__m64 *)dst; - dest0 = in(vsrc, expand_alpha_rev (*(__m64*)(&m0))); - dest1 = in(vsrc, expand_alpha_rev (*(__m64*)(&m1))); + dest0 = in(vsrc, expand_alpha_rev (M64(m0))); + dest1 = in(vsrc, expand_alpha_rev (M64(m1))); *(__m64 *)dst = pack8888(dest0, dest1); } @@ -1791,7 +1770,7 @@ fbCompositeSolidMaskSrc_nx8x8888mmx (pixman_operator_t op, if (m) { __m64 vdest = load8888(*dst); - vdest = in(vsrc, expand_alpha_rev (*(__m64*)(&m))); + vdest = in(vsrc, expand_alpha_rev (M64(m))); *dst = store8888(vdest); } else @@ -1846,7 +1825,7 @@ fbCompositeSolidMask_nx8x0565mmx (pixman_operator_t op, vsrca = expand_alpha (vsrc); vsrc16 = pack565(vsrc, _mm_setzero_si64(), 0); - src16 = *(ullong*)(&vsrc16); + src16 = *(ullong*)(void*)(&vsrc16); srcsrcsrcsrc = (ullong)src16 << 48 | (ullong)src16 << 32 | (ullong)src16 << 16 | (ullong)src16; @@ -1868,7 +1847,7 @@ fbCompositeSolidMask_nx8x0565mmx (pixman_operator_t op, if (m) { __m64 vd = _mm_cvtsi32_si64 (*dst); - __m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev (*(__m64*)(&m)), expand565(vd, 0)); + __m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev (M64(m)), expand565(vd, 0)); *dst = _mm_cvtsi64_si32 (pack565(vdest, _mm_setzero_si64(), 0)); } @@ -1898,13 +1877,13 @@ fbCompositeSolidMask_nx8x0565mmx (pixman_operator_t op, vdest = *(__m64 *)dst; - vm0 = *(__m64*)(&m0); + vm0 = M64(m0); vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm0), expand565(vdest, 0)), vdest, 0); - vm1 = *(__m64*)(&m1); + vm1 = M64(m1); vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm1), expand565(vdest, 1)), vdest, 1); - vm2 = *(__m64*)(&m2); + vm2 = M64(m2); vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm2), expand565(vdest, 2)), vdest, 2); - vm3 = *(__m64*)(&m3); + vm3 = M64(m3); vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm3), expand565(vdest, 3)), vdest, 3); *(__m64 *)dst = vdest; @@ -1924,7 +1903,7 @@ fbCompositeSolidMask_nx8x0565mmx (pixman_operator_t op, if (m) { __m64 vd = _mm_cvtsi32_si64 (*dst); - __m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev (*(__m64*)(&m)), expand565(vd, 0)); + __m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev (M64(m)), expand565(vd, 0)); *dst = _mm_cvtsi64_si32 (pack565(vdest, _mm_setzero_si64(), 0)); } @@ -2655,7 +2634,7 @@ fbSolidFillmmx (FbPixels *pDraw, } fill = ((ullong)xor << 32) | xor; - vfill = *(__m64*)&fill; + vfill = M64(fill); while (height--) { diff --git a/gfx/cairo/libpixman/src/fbpict.c b/gfx/cairo/libpixman/src/fbpict.c index 63b1cbcf050..0bd989fe08d 100644 --- a/gfx/cairo/libpixman/src/fbpict.c +++ b/gfx/cairo/libpixman/src/fbpict.c @@ -2123,7 +2123,9 @@ static unsigned int detectCPUFeatures(void) { features |= SSE; if (result & (1 << 26)) features |= SSE2; - if ((result & MMX) && !(result & SSE) && (strcmp(vendor, "AuthenticAMD") == 0)) { + if ((features & MMX) && !(features & SSE) && + (strcmp(vendor, "AuthenticAMD") == 0 || + strcmp(vendor, "Geode by NSC") == 0)) { /* check for AMD MMX extensions */ #ifdef __GNUC__ diff --git a/gfx/cairo/libpixman/src/fbtrap.c b/gfx/cairo/libpixman/src/fbtrap.c index c7a250dd1f4..b3287511a5b 100644 --- a/gfx/cairo/libpixman/src/fbtrap.c +++ b/gfx/cairo/libpixman/src/fbtrap.c @@ -1,5 +1,5 @@ /* - * $Id: fbtrap.c,v 1.14 2007/04/03 18:59:49 vladimir%pobox.com Exp $ + * $Id: fbtrap.c,v 1.15 2007/04/04 01:09:16 vladimir%pobox.com Exp $ * * Copyright © 2004 Keith Packard * diff --git a/gfx/cairo/libpixman/src/icimage.c b/gfx/cairo/libpixman/src/icimage.c index 44c4c8b34bc..4d957a0fc37 100644 --- a/gfx/cairo/libpixman/src/icimage.c +++ b/gfx/cairo/libpixman/src/icimage.c @@ -247,7 +247,6 @@ pixman_image_create_radial_gradient (const pixman_radial_gradient_t *gradient, { pixman_radial_gradient_image_t *radial; pixman_image_t *image; - double x; if (n_stops < 2) return NULL; @@ -270,19 +269,14 @@ pixman_image_create_radial_gradient (const pixman_radial_gradient_t *gradient, memcpy (radial->stops, stops, sizeof (pixman_gradient_stop_t) * n_stops); radial->type = SourcePictTypeRadial; - x = (double) gradient->inner.radius / (double) gradient->outer.radius; - radial->dx = (gradient->outer.x - gradient->inner.x); - radial->dy = (gradient->outer.y - gradient->inner.y); - radial->fx = (gradient->inner.x) - x * radial->dx; - radial->fy = (gradient->inner.y) - x * radial->dy; - radial->m = 1. / (1 + x); - radial->b = -x * radial->m; - radial->dx /= 65536.; - radial->dy /= 65536.; - radial->fx /= 65536.; - radial->fy /= 65536.; - x = gradient->outer.radius / 65536.; - radial->a = x * x - radial->dx * radial->dx - radial->dy * radial->dy; + radial->c1 = gradient->c1; + radial->c2 = gradient->c2; + radial->cdx = xFixedToDouble (gradient->c2.x - gradient->c1.x); + radial->cdy = xFixedToDouble (gradient->c2.y - gradient->c1.y); + radial->dr = xFixedToDouble (gradient->c2.radius - gradient->c1.radius); + radial->A = ( radial->cdx * radial->cdx + + radial->cdy * radial->cdy + - radial->dr * radial->dr); image->pSourcePict = (pixman_source_image_t *) radial; diff --git a/gfx/cairo/libpixman/src/icimage.h b/gfx/cairo/libpixman/src/icimage.h index 82202a71e56..bbf41b99c02 100644 --- a/gfx/cairo/libpixman/src/icimage.h +++ b/gfx/cairo/libpixman/src/icimage.h @@ -101,13 +101,12 @@ typedef struct _pixman_radial_gradient_image { int stopRange; uint32_t *colorTable; int colorTableSize; - double fx; - double fy; - double dx; - double dy; - double a; - double m; - double b; + pixman_circle_t c1; + pixman_circle_t c2; + double cdx; + double cdy; + double dr; + double A; } pixman_radial_gradient_image_t; typedef struct _pixman_conical_gradient_image { diff --git a/gfx/cairo/libpixman/src/icint.h b/gfx/cairo/libpixman/src/icint.h index 93795b056f9..47a2220059b 100644 --- a/gfx/cairo/libpixman/src/icint.h +++ b/gfx/cairo/libpixman/src/icint.h @@ -1026,6 +1026,7 @@ typedef xFixed_16_16 xFixed; #define IntToxFixed(i) ((xFixed) (i) << XFIXED_BITS) #define xFixedE ((xFixed) 1) #define xFixed1 (IntToxFixed(1)) +#define xFixedToDouble(f) (double) ((f) / (double) xFixed1) #define xFixed1MinusE (xFixed1 - xFixedE) #define xFixedFrac(f) ((f) & xFixed1MinusE) #define xFixedFloor(f) ((f) & ~xFixed1MinusE) diff --git a/gfx/cairo/libpixman/src/pixman-remap.h b/gfx/cairo/libpixman/src/pixman-remap.h index 9426ab80986..290df328123 100644 --- a/gfx/cairo/libpixman/src/pixman-remap.h +++ b/gfx/cairo/libpixman/src/pixman-remap.h @@ -1,80 +1,80 @@ -#define pixman_add_trapezoids _moz_cairo_pixman_add_trapezoids -#define pixman_color_to_pixel _moz_cairo_pixman_color_to_pixel -#define composeFunctions _moz_cairo_pixman_compose_functions -#define fbComposeSetupMMX _moz_cairo_pixman_compose_setup_mmx -#define pixman_composite _moz_cairo_pixman_composite -#define fbCompositeCopyAreammx _moz_cairo_pixman_composite_copy_area_mmx -#define fbCompositeSolidMask_nx8888x0565Cmmx _moz_cairo_pixman_composite_solid_mask_nx8888x0565Cmmx -#define fbCompositeSolidMask_nx8888x8888Cmmx _moz_cairo_pixman_composite_solid_mask_nx8888x8888Cmmx -#define fbCompositeSolidMask_nx8x0565mmx _moz_cairo_pixman_composite_solid_mask_nx8x0565mmx -#define fbCompositeSolidMask_nx8x8888mmx _moz_cairo_pixman_composite_solid_mask_nx8x8888mmx -#define fbCompositeSolidMaskSrc_nx8x8888mmx _moz_cairo_pixman_composite_solid_mask_src_nx8x8888mmx -#define fbCompositeSolid_nx0565mmx _moz_cairo_pixman_composite_solid_nx0565mmx -#define fbCompositeSolid_nx8888mmx _moz_cairo_pixman_composite_solid_nx8888mmx -#define fbCompositeSrc_8888RevNPx0565mmx _moz_cairo_pixman_composite_src_8888RevNPx0565mmx -#define fbCompositeSrc_8888RevNPx8888mmx _moz_cairo_pixman_composite_src_8888RevNPx8888_mmx -#define fbCompositeSrc_8888x0565mmx _moz_cairo_pixman_composite_src_8888x0565mmx -#define fbCompositeSrc_8888x8888mmx _moz_cairo_pixman_composite_src_8888x8888mmx -#define fbCompositeSrc_8888x8x8888mmx _moz_cairo_pixman_composite_src_8888x8x8888mmx -#define fbCompositeSrcAdd_8000x8000mmx _moz_cairo_pixman_composite_src_add_8000x8000mmx -#define fbCompositeSrcAdd_8888x8888mmx _moz_cairo_pixman_composite_src_add_8888x8888mmx -#define fbCompositeSrc_x888x8x8888mmx _moz_cairo_pixman_composite_src_x888x8x8888mmx -#define pixman_composite_trapezoids _moz_cairo_pixman_composite_trapezoids -#define pixman_composite_tri_fan _moz_cairo_pixman_composite_tri_fan -#define pixman_composite_tri_strip _moz_cairo_pixman_composite_tri_strip -#define pixman_composite_triangles _moz_cairo_pixman_composite_triangles -#define fbCopyAreammx _moz_cairo_pixman_copy_area_mmx -#define pixman_fill_rectangle _moz_cairo_pixman_fill_rectangle -#define pixman_fill_rectangles _moz_cairo_pixman_fill_rectangles -#define pixman_format_create _moz_cairo_pixman_format_create -#define pixman_format_create_masks _moz_cairo_pixman_format_create_masks -#define pixman_format_destroy _moz_cairo_pixman_format_destroy -#define pixman_format_get_masks _moz_cairo_pixman_format_get_masks -#define pixman_format_init _moz_cairo_pixman_format_init +#define pixman_add_trapezoids _cairo_pixman_add_trapezoids +#define pixman_color_to_pixel _cairo_pixman_color_to_pixel +#define composeFunctions _cairo_pixman_compose_functions +#define fbComposeSetupMMX _cairo_pixman_compose_setup_mmx +#define pixman_composite _cairo_pixman_composite +#define fbCompositeCopyAreammx _cairo_pixman_composite_copy_area_mmx +#define fbCompositeSolidMask_nx8888x0565Cmmx _cairo_pixman_composite_solid_mask_nx8888x0565Cmmx +#define fbCompositeSolidMask_nx8888x8888Cmmx _cairo_pixman_composite_solid_mask_nx8888x8888Cmmx +#define fbCompositeSolidMask_nx8x0565mmx _cairo_pixman_composite_solid_mask_nx8x0565mmx +#define fbCompositeSolidMask_nx8x8888mmx _cairo_pixman_composite_solid_mask_nx8x8888mmx +#define fbCompositeSolidMaskSrc_nx8x8888mmx _cairo_pixman_composite_solid_mask_src_nx8x8888mmx +#define fbCompositeSolid_nx0565mmx _cairo_pixman_composite_solid_nx0565mmx +#define fbCompositeSolid_nx8888mmx _cairo_pixman_composite_solid_nx8888mmx +#define fbCompositeSrc_8888RevNPx0565mmx _cairo_pixman_composite_src_8888RevNPx0565mmx +#define fbCompositeSrc_8888RevNPx8888mmx _cairo_pixman_composite_src_8888RevNPx8888_mmx +#define fbCompositeSrc_8888x0565mmx _cairo_pixman_composite_src_8888x0565mmx +#define fbCompositeSrc_8888x8888mmx _cairo_pixman_composite_src_8888x8888mmx +#define fbCompositeSrc_8888x8x8888mmx _cairo_pixman_composite_src_8888x8x8888mmx +#define fbCompositeSrcAdd_8000x8000mmx _cairo_pixman_composite_src_add_8000x8000mmx +#define fbCompositeSrcAdd_8888x8888mmx _cairo_pixman_composite_src_add_8888x8888mmx +#define fbCompositeSrc_x888x8x8888mmx _cairo_pixman_composite_src_x888x8x8888mmx +#define pixman_composite_trapezoids _cairo_pixman_composite_trapezoids +#define pixman_composite_tri_fan _cairo_pixman_composite_tri_fan +#define pixman_composite_tri_strip _cairo_pixman_composite_tri_strip +#define pixman_composite_triangles _cairo_pixman_composite_triangles +#define fbCopyAreammx _cairo_pixman_copy_area_mmx +#define pixman_fill_rectangle _cairo_pixman_fill_rectangle +#define pixman_fill_rectangles _cairo_pixman_fill_rectangles +#define pixman_format_create _cairo_pixman_format_create +#define pixman_format_create_masks _cairo_pixman_format_create_masks +#define pixman_format_destroy _cairo_pixman_format_destroy +#define pixman_format_get_masks _cairo_pixman_format_get_masks +#define pixman_format_init _cairo_pixman_format_init #if defined(USE_MMX) && !defined(__amd64__) && !defined(__x86_64__) -#define fbHaveMMX _moz_cairo_pixman_have_mmx +#define fbHaveMMX _cairo_pixman_have_mmx #endif -#define pixman_image_create _moz_cairo_pixman_image_create -#define pixman_image_create_for_data _moz_cairo_pixman_image_create_for_data -#define pixman_image_destroy _moz_cairo_pixman_image_destroy -#define pixman_image_get_data _moz_cairo_pixman_image_get_data -#define pixman_image_get_depth _moz_cairo_pixman_image_get_depth -#define pixman_image_get_format _moz_cairo_pixman_image_get_format -#define pixman_image_get_height _moz_cairo_pixman_image_get_height -#define pixman_image_get_stride _moz_cairo_pixman_image_get_stride -#define pixman_image_get_width _moz_cairo_pixman_image_get_width -#define pixman_image_set_clip_region _moz_cairo_pixman_image_set_clip_region -#define pixman_image_set_component_alpha _moz_cairo_pixman_image_set_component_alpha -#define pixman_image_set_filter _moz_cairo_pixman_image_set_filter -#define pixman_image_set_repeat _moz_cairo_pixman_image_set_repeat -#define pixman_image_set_transform _moz_cairo_pixman_image_set_transform -#define pixman_image_create_linear_gradient _moz_cairo_pixman_image_create_linear_gradient -#define pixman_image_create_radial_gradient _moz_cairo_pixman_image_create_radial_gradient -#define miIsSolidAlpha _moz_cairo_pixman_is_solid_alpha -#define pixman_pixel_to_color _moz_cairo_pixman_pixel_to_color -#define pixman_region_append _moz_cairo_pixman_region_append -#define pixman_region_contains_point _moz_cairo_pixman_region_contains_point -#define pixman_region_contains_rectangle _moz_cairo_pixman_region_contains_rectangle -#define pixman_region_copy _moz_cairo_pixman_region_copy -#define pixman_region_create _moz_cairo_pixman_region_create -#define pixman_region_create_simple _moz_cairo_pixman_region_create_simple -#define pixman_region_destroy _moz_cairo_pixman_region_destroy -#define pixman_region_empty _moz_cairo_pixman_region_empty -#define pixman_region_extents _moz_cairo_pixman_region_extents -#define pixman_region_intersect _moz_cairo_pixman_region_intersect -#define pixman_region_inverse _moz_cairo_pixman_region_inverse -#define pixman_region_not_empty _moz_cairo_pixman_region_not_empty -#define pixman_region_num_rects _moz_cairo_pixman_region_num_rects -#define pixman_region_rects _moz_cairo_pixman_region_rects -#define pixman_region_reset _moz_cairo_pixman_region_reset -#define pixman_region_subtract _moz_cairo_pixman_region_subtract -#define pixman_region_translate _moz_cairo_pixman_region_translate -#define pixman_region_union _moz_cairo_pixman_region_union -#define pixman_region_union_rect _moz_cairo_pixman_region_union_rect -#define pixman_region_validate _moz_cairo_pixman_region_validate -#define RenderEdgeInit _moz_cairo_pixman_render_edge_init -#define RenderEdgeStep _moz_cairo_pixman_render_edge_step -#define RenderLineFixedEdgeInit _moz_cairo_pixman_render_line_fixed_edge_init -#define RenderSampleCeilY _moz_cairo_pixman_render_sample_ceil_y -#define RenderSampleFloorY _moz_cairo_pixman_render_sample_floor_y -#define fbSolidFillmmx _moz_cairo_pixman_solid_fill_mmx +#define pixman_image_create _cairo_pixman_image_create +#define pixman_image_create_for_data _cairo_pixman_image_create_for_data +#define pixman_image_destroy _cairo_pixman_image_destroy +#define pixman_image_get_data _cairo_pixman_image_get_data +#define pixman_image_get_depth _cairo_pixman_image_get_depth +#define pixman_image_get_format _cairo_pixman_image_get_format +#define pixman_image_get_height _cairo_pixman_image_get_height +#define pixman_image_get_stride _cairo_pixman_image_get_stride +#define pixman_image_get_width _cairo_pixman_image_get_width +#define pixman_image_set_clip_region _cairo_pixman_image_set_clip_region +#define pixman_image_set_component_alpha _cairo_pixman_image_set_component_alpha +#define pixman_image_set_filter _cairo_pixman_image_set_filter +#define pixman_image_set_repeat _cairo_pixman_image_set_repeat +#define pixman_image_set_transform _cairo_pixman_image_set_transform +#define pixman_image_create_linear_gradient _cairo_pixman_image_create_linear_gradient +#define pixman_image_create_radial_gradient _cairo_pixman_image_create_radial_gradient +#define miIsSolidAlpha _cairo_pixman_is_solid_alpha +#define pixman_pixel_to_color _cairo_pixman_pixel_to_color +#define pixman_region_append _cairo_pixman_region_append +#define pixman_region_contains_point _cairo_pixman_region_contains_point +#define pixman_region_contains_rectangle _cairo_pixman_region_contains_rectangle +#define pixman_region_copy _cairo_pixman_region_copy +#define pixman_region_create _cairo_pixman_region_create +#define pixman_region_create_simple _cairo_pixman_region_create_simple +#define pixman_region_destroy _cairo_pixman_region_destroy +#define pixman_region_empty _cairo_pixman_region_empty +#define pixman_region_extents _cairo_pixman_region_extents +#define pixman_region_intersect _cairo_pixman_region_intersect +#define pixman_region_inverse _cairo_pixman_region_inverse +#define pixman_region_not_empty _cairo_pixman_region_not_empty +#define pixman_region_num_rects _cairo_pixman_region_num_rects +#define pixman_region_rects _cairo_pixman_region_rects +#define pixman_region_reset _cairo_pixman_region_reset +#define pixman_region_subtract _cairo_pixman_region_subtract +#define pixman_region_translate _cairo_pixman_region_translate +#define pixman_region_union _cairo_pixman_region_union +#define pixman_region_union_rect _cairo_pixman_region_union_rect +#define pixman_region_validate _cairo_pixman_region_validate +#define RenderEdgeInit _cairo_pixman_render_edge_init +#define RenderEdgeStep _cairo_pixman_render_edge_step +#define RenderLineFixedEdgeInit _cairo_pixman_render_line_fixed_edge_init +#define RenderSampleCeilY _cairo_pixman_render_sample_ceil_y +#define RenderSampleFloorY _cairo_pixman_render_sample_floor_y +#define fbSolidFillmmx _cairo_pixman_solid_fill_mmx diff --git a/gfx/cairo/libpixman/src/pixman.h b/gfx/cairo/libpixman/src/pixman.h index 309e5e655b8..9120eb6ed1e 100644 --- a/gfx/cairo/libpixman/src/pixman.h +++ b/gfx/cairo/libpixman/src/pixman.h @@ -99,7 +99,7 @@ SOFTWARE. #include "pixman-remap.h" -#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) +#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun__) #define pixman_private __attribute__((__visibility__("hidden"))) #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) #define pixman_private __hidden @@ -364,8 +364,8 @@ typedef struct pixman_linear_gradient { } pixman_linear_gradient_t; typedef struct pixman_radial_gradient { - pixman_circle_t inner; - pixman_circle_t outer; + pixman_circle_t c1; + pixman_circle_t c2; } pixman_radial_gradient_t; typedef enum { diff --git a/gfx/cairo/libpixman/src/slim_internal.h b/gfx/cairo/libpixman/src/slim_internal.h deleted file mode 100644 index 4cf74961ef1..00000000000 --- a/gfx/cairo/libpixman/src/slim_internal.h +++ /dev/null @@ -1,106 +0,0 @@ -/* slim - Shared Library Interface Macros - * - * Copyright © 2003 Richard Henderson - * - * Permission to use, copy, modify, distribute, and sell this software - * and its documentation for any purpose is hereby granted without - * fee, provided that the above copyright notice appear in all copies - * and that both that copyright notice and this permission notice - * appear in supporting documentation, and that the name of Richard Henderson - * not be used in advertising or publicity pertaining to distribution - * of the software without specific, written prior permission. - * Richard Henderson makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without express - * or implied warranty. - * - * RICHARD HENDERSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN - * NO EVENT SHALL RICHARD HENDERSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Author: Richard Henderson - */ - -#ifndef _SLIM_INTERNAL_H_ -#define _SLIM_INTERNAL_H_ 1 - -/* XXX THIS DOCUMENTATION IS BLOODY WRONG. SOMEONE DID NOT ACTUALLY - CONSULT WITH THE COMPILERS THEY CLAIMED TO SUPPORT */ -/* This macro marks a symbol as STV_HIDDEN, which prevents it from being - added to the dynamic symbol table of the shared library. This prevents - users of the library from knowingly or unknowingly accessing library - internals that may change in future releases. It also allows the - compiler to generate slightly more efficient code in some cases. - - The macro should be placed either immediately before the return type in - a function declaration: - - pixman_private int - somefunction(void); - - or after a data name, - XXX THIS IS WRONG. YOU CAN NOT DO THIS WITH THE COMPILERS THAT - THIS PACKAGE CLAIMS TO SUPPORT. - extern int somedata pixman_private; - - The ELF visibility attribute did not exist before gcc 3.3. */ -/* ??? Not marked with "slim" because that makes it look too much - like the function name instead of just an attribute. */ - -#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) -#define pixman_private __attribute__((__visibility__("hidden"))) -#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) -#define pixman_private __hidden -#else /* not gcc >= 3.3 and not Sun Studio >= 8 */ -#define pixman_private -#endif - -/* The following macros are used for PLT bypassing. First of all, - you need to have the function prototyped somewhere, say in foo.h: - - int foo (int __bar); - - If calls to foo within libfoo.so should always go to foo defined - in libfoo.so, then in fooint.h you add: - - slim_hidden_proto (foo) - - and after the foo function definition: - - int foo (int __bar) - { - return __bar; - } - slim_hidden_def (foo); - - This works by arranging for the C symbol "foo" to be renamed to - "INT_foo" at the assembly level, which is marked pixman_private. - We then create another symbol at the same address (an alias) with - the C symbol "EXT_foo", which is renamed to "foo" at the assembly - level. */ - -#if __GNUC__ >= 3 && defined(__ELF__) -# define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) -# define slim_hidden_def(name) slim_hidden_def1(name, slim_hidden_int_name(name)) -# define slim_hidden_int_name(name) INT_##name -# define slim_hidden_proto1(name, internal) \ - extern __typeof (name) name \ - __asm__ (slim_hidden_asmname (internal)) \ - pixman_private; -# define slim_hidden_def1(name, internal) \ - extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name)) \ - __attribute__((__alias__(slim_hidden_asmname(internal)))) -# define slim_hidden_ulp slim_hidden_ulp1(__USER_LABEL_PREFIX__) -# define slim_hidden_ulp1(x) slim_hidden_ulp2(x) -# define slim_hidden_ulp2(x) #x -# define slim_hidden_asmname(name) slim_hidden_asmname1(name) -# define slim_hidden_asmname1(name) slim_hidden_ulp #name -#else -# define slim_hidden_proto(name) -# define slim_hidden_def(name) -#endif - -#endif /* _SLIM_INTERNAL_H_ */ diff --git a/gfx/src/thebes/nsThebesDeviceContext.cpp b/gfx/src/thebes/nsThebesDeviceContext.cpp index ce3d643c472..d0918377225 100644 --- a/gfx/src/thebes/nsThebesDeviceContext.cpp +++ b/gfx/src/thebes/nsThebesDeviceContext.cpp @@ -150,7 +150,7 @@ nsThebesDeviceContext::SetDPI() if (mPrintingSurface && (mPrintingSurface->GetType() == gfxASurface::SurfaceTypePDF || mPrintingSurface->GetType() == gfxASurface::SurfaceTypePS || - mPrintingSurface->GetType() == gfxASurface::SurfaceTypeQuartz2)) { + mPrintingSurface->GetType() == gfxASurface::SurfaceTypeQuartz)) { dpi = 72; dotsArePixels = PR_FALSE; } else { @@ -700,7 +700,7 @@ nsThebesDeviceContext::CalcPrintingSize() #endif #ifdef XP_MACOSX - case gfxASurface::SurfaceTypeQuartz2: + case gfxASurface::SurfaceTypeQuartz: inPoints = PR_TRUE; // this is really only true when we're printing size = reinterpret_cast(mPrintingSurface.get())->GetSize(); break; diff --git a/gfx/thebes/public/gfxASurface.h b/gfx/thebes/public/gfxASurface.h index 83664df1c8e..c20a5a279a4 100644 --- a/gfx/thebes/public/gfxASurface.h +++ b/gfx/thebes/public/gfxASurface.h @@ -81,7 +81,6 @@ public: SurfaceTypeBeOS, SurfaceTypeDirectFB, SurfaceTypeSVG, - SurfaceTypeQuartz2, SurfaceTypeOS2 } gfxSurfaceType; diff --git a/gfx/thebes/public/gfxQuartzSurface.h b/gfx/thebes/public/gfxQuartzSurface.h index 7610acd941b..2d909d55a1e 100644 --- a/gfx/thebes/public/gfxQuartzSurface.h +++ b/gfx/thebes/public/gfxQuartzSurface.h @@ -46,7 +46,7 @@ class THEBES_API gfxQuartzSurface : public gfxASurface { public: gfxQuartzSurface(const gfxSize& size, gfxImageFormat format); - gfxQuartzSurface(CGContextRef context, PRBool y_grows_down, const gfxSize& size); + gfxQuartzSurface(CGContextRef context, const gfxSize& size); gfxQuartzSurface(cairo_surface_t *csurf); virtual ~gfxQuartzSurface(); diff --git a/gfx/thebes/src/gfxASurface.cpp b/gfx/thebes/src/gfxASurface.cpp index 2cb8bec8b8f..0547ee5012d 100644 --- a/gfx/thebes/src/gfxASurface.cpp +++ b/gfx/thebes/src/gfxASurface.cpp @@ -50,7 +50,7 @@ #include "gfxXlibSurface.h" #endif -#ifdef CAIRO_HAS_NQUARTZ_SURFACE +#ifdef CAIRO_HAS_QUARTZ_SURFACE #include "gfxQuartzSurface.h" #endif @@ -139,8 +139,8 @@ gfxASurface::Wrap (cairo_surface_t *csurf) result = new gfxXlibSurface(csurf); } #endif -#ifdef CAIRO_HAS_NQUARTZ_SURFACE - else if (stype == CAIRO_SURFACE_TYPE_NQUARTZ) { +#ifdef CAIRO_HAS_QUARTZ_SURFACE + else if (stype == CAIRO_SURFACE_TYPE_QUARTZ) { result = new gfxQuartzSurface(csurf); } #endif diff --git a/gfx/thebes/src/gfxMatrix.cpp b/gfx/thebes/src/gfxMatrix.cpp index 3ec31a9580a..602aa18e0f5 100644 --- a/gfx/thebes/src/gfxMatrix.cpp +++ b/gfx/thebes/src/gfxMatrix.cpp @@ -108,12 +108,60 @@ gfxMatrix::Transform(const gfxRect& rect) const gfxRect gfxMatrix::TransformBounds(const gfxRect& rect) const { - double x0 = rect.pos.x; - double y0 = rect.pos.y; - double x1 = rect.pos.x + rect.size.width; - double y1 = rect.pos.y + rect.size.height; + /* Code taken from cairo-matrix.c, _cairo_matrix_transform_bounding_box isn't public */ + int i; + double quad_x[4], quad_y[4]; + double min_x, max_x; + double min_y, max_y; - cairo_matrix_transform_bounding_box(CONST_CAIRO_MATRIX(this), &x0, &y0, &x1, &y1, NULL); + quad_x[0] = rect.pos.x; + quad_y[0] = rect.pos.y; + cairo_matrix_transform_point (CONST_CAIRO_MATRIX(this), &quad_x[0], &quad_y[0]); - return gfxRect(x0, y0, x1 - x0, y1 - y0); + quad_x[1] = rect.pos.x + rect.size.width; + quad_y[1] = rect.pos.y; + cairo_matrix_transform_point (CONST_CAIRO_MATRIX(this), &quad_x[1], &quad_y[1]); + + quad_x[2] = rect.pos.x; + quad_y[2] = rect.pos.y + rect.size.height; + cairo_matrix_transform_point (CONST_CAIRO_MATRIX(this), &quad_x[2], &quad_y[2]); + + quad_x[3] = rect.pos.x + rect.size.width; + quad_y[3] = rect.pos.y + rect.size.height; + cairo_matrix_transform_point (CONST_CAIRO_MATRIX(this), &quad_x[3], &quad_y[3]); + + min_x = max_x = quad_x[0]; + min_y = max_y = quad_y[0]; + + for (i = 1; i < 4; i++) { + if (quad_x[i] < min_x) + min_x = quad_x[i]; + if (quad_x[i] > max_x) + max_x = quad_x[i]; + + if (quad_y[i] < min_y) + min_y = quad_y[i]; + if (quad_y[i] > max_y) + max_y = quad_y[i]; + } + + // we don't compute this now +#if 0 + if (is_tight) { + /* it's tight if and only if the four corner points form an axis-aligned + rectangle. + And that's true if and only if we can derive corners 0 and 3 from + corners 1 and 2 in one of two straightforward ways... + We could use a tolerance here but for now we'll fall back to FALSE in the case + of floating point error. + */ + *is_tight = + (quad_x[1] == quad_x[0] && quad_y[1] == quad_y[3] && + quad_x[2] == quad_x[3] && quad_y[2] == quad_y[0]) || + (quad_x[1] == quad_x[3] && quad_y[1] == quad_y[0] && + quad_x[2] == quad_x[0] && quad_y[2] == quad_y[3]); + } +#endif + + return gfxRect(min_x, min_y, max_x - min_x, max_y - min_y); } diff --git a/gfx/thebes/src/gfxQuartzPDFSurface.cpp b/gfx/thebes/src/gfxQuartzPDFSurface.cpp index 8fe5c0d2c7a..e2ffaca6138 100644 --- a/gfx/thebes/src/gfxQuartzPDFSurface.cpp +++ b/gfx/thebes/src/gfxQuartzPDFSurface.cpp @@ -37,7 +37,7 @@ #include "gfxQuartzPDFSurface.h" -#include "cairo-nquartz.h" +#include "cairo-quartz.h" gfxQuartzPDFSurface::gfxQuartzPDFSurface(const char *filename, gfxSize aSizeInPoints) { @@ -50,7 +50,7 @@ gfxQuartzPDFSurface::gfxQuartzPDFSurface(const char *filename, gfxSize aSizeInPo CFRelease(file); CFRelease(fileURL); - Init(cairo_nquartz_surface_create_for_cg_context(mCGContext, aSizeInPoints.width, aSizeInPoints.height, PR_FALSE)); + Init(cairo_quartz_surface_create_for_cg_context(mCGContext, aSizeInPoints.width, aSizeInPoints.height)); } gfxQuartzPDFSurface::~gfxQuartzPDFSurface() diff --git a/gfx/thebes/src/gfxQuartzSurface.cpp b/gfx/thebes/src/gfxQuartzSurface.cpp index a0f124272ad..f145c7716f3 100644 --- a/gfx/thebes/src/gfxQuartzSurface.cpp +++ b/gfx/thebes/src/gfxQuartzSurface.cpp @@ -37,15 +37,15 @@ #include "gfxQuartzSurface.h" -#include "cairo-nquartz.h" +#include "cairo-quartz.h" gfxQuartzSurface::gfxQuartzSurface(const gfxSize& size, gfxImageFormat format) : mSize(size) { - cairo_surface_t *surf = cairo_nquartz_surface_create + cairo_surface_t *surf = cairo_quartz_surface_create ((cairo_format_t) format, floor(size.width), floor(size.height)); - mCGContext = cairo_nquartz_surface_get_cg_context (surf); + mCGContext = cairo_quartz_surface_get_cg_context (surf); CGContextRetain(mCGContext); @@ -53,15 +53,13 @@ gfxQuartzSurface::gfxQuartzSurface(const gfxSize& size, gfxImageFormat format) } gfxQuartzSurface::gfxQuartzSurface(CGContextRef context, - PRBool y_grows_down, const gfxSize& size) : mCGContext(context), mSize(size) { cairo_surface_t *surf = - cairo_nquartz_surface_create_for_cg_context(context, - floor(size.width), - floor(size.height), - y_grows_down); + cairo_quartz_surface_create_for_cg_context(context, + floor(size.width), + floor(size.height)); CGContextRetain(mCGContext); @@ -71,7 +69,7 @@ gfxQuartzSurface::gfxQuartzSurface(CGContextRef context, gfxQuartzSurface::gfxQuartzSurface(cairo_surface_t *csurf) : mSize(-1.0, -1.0) { - mCGContext = cairo_nquartz_surface_get_cg_context (csurf); + mCGContext = cairo_quartz_surface_get_cg_context (csurf); CGContextRetain (mCGContext); Init(csurf, PR_TRUE); diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm index 714c1e5497a..12c7a2c4ce2 100644 --- a/widget/src/cocoa/nsChildView.mm +++ b/widget/src/cocoa/nsChildView.mm @@ -2154,7 +2154,7 @@ NSEvent* globalDragEvent = nil; NSRect bounds = [self bounds]; nsRefPtr targetSurface = - new gfxQuartzSurface(cgContext, PR_TRUE, gfxSize(bounds.size.width, bounds.size.height)); + new gfxQuartzSurface(cgContext, gfxSize(bounds.size.width, bounds.size.height)); #ifdef DEBUG_UPDATE fprintf (stderr, "---- Update[%p][%p] [%f %f %f %f] cgc: %p\n gecko bounds: [%d %d %d %d]\n", diff --git a/widget/src/cocoa/nsDeviceContextSpecX.mm b/widget/src/cocoa/nsDeviceContextSpecX.mm index ee84b99d3d3..0506e0aabbc 100644 --- a/widget/src/cocoa/nsDeviceContextSpecX.mm +++ b/widget/src/cocoa/nsDeviceContextSpecX.mm @@ -268,10 +268,13 @@ NS_IMETHODIMP nsDeviceContextSpecX::GetSurfaceForPrinter(gfxASurface **surface) nsRefPtr newSurface; - if (context) - newSurface = new gfxQuartzSurface(context, PR_FALSE, gfxSize(width, height)); - else + if (context) { + CGContextTranslateCTM(context, 0.0, height); + CGContextScaleCTM(context, 1.0, -1.0); + newSurface = new gfxQuartzSurface(context, gfxSize(width, height)); + } else { newSurface = new gfxQuartzSurface(gfxSize((PRInt32)width, (PRInt32)height), gfxASurface::ImageFormatARGB32); + } if (!newSurface) return NS_ERROR_FAILURE; diff --git a/widget/src/cocoa/nsNativeThemeCocoa.mm b/widget/src/cocoa/nsNativeThemeCocoa.mm index e1fcc21818d..8d4c24509ea 100644 --- a/widget/src/cocoa/nsNativeThemeCocoa.mm +++ b/widget/src/cocoa/nsNativeThemeCocoa.mm @@ -322,8 +322,8 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsIRenderingContext* aContext, nsIFrame double offsetX = 0.0, offsetY = 0.0; nsRefPtr thebesSurface = thebesCtx->CurrentSurface(&offsetX, &offsetY); - if (thebesSurface->GetType() != gfxASurface::SurfaceTypeQuartz2) { - fprintf(stderr, "Expected surface of type Quartz2, got %d\n", + if (thebesSurface->GetType() != gfxASurface::SurfaceTypeQuartz) { + fprintf(stderr, "Expected surface of type Quartz, got %d\n", thebesSurface->GetType()); return NS_ERROR_FAILURE; }