diff --git a/gfx/cairo/cairo/src/Makefile.in b/gfx/cairo/cairo/src/Makefile.in index c128e377a9e1..16009c03725d 100644 --- a/gfx/cairo/cairo/src/Makefile.in +++ b/gfx/cairo/cairo/src/Makefile.in @@ -71,6 +71,7 @@ CSRCS = \ cairo-deflate-stream.c \ cairo-fixed.c \ cairo-font.c \ + cairo-font-face.c \ cairo-font-options.c \ cairo-freelist.c \ cairo-gstate.c \ @@ -80,6 +81,7 @@ CSRCS = \ cairo-lzw.c \ cairo-matrix.c \ cairo-meta-surface.c \ + cairo-mutex.c \ cairo-operator.c \ cairo-output-stream.c \ cairo-paginated-surface.c \ @@ -154,7 +156,8 @@ endif ifdef MOZ_X11 CSRCS += cairo-xlib-surface.c \ - cairo-xlib-screen.c + cairo-xlib-screen.c \ + cairo-xlib-display.c EXPORTS += cairo-xlib.h cairo-xlib-xrender.h endif diff --git a/gfx/cairo/cairo/src/cairo-analysis-surface-private.h b/gfx/cairo/cairo/src/cairo-analysis-surface-private.h index 9d3410b867f7..c67fa115adfb 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.5 2007/04/04 01:09:15 vladimir%pobox.com Exp $ +/* $Id: cairo-analysis-surface-private.h,v 1.6 2007/06/11 00:01:29 vladimir%pobox.com Exp $ * * Copyright © 2005 Keith Packard * diff --git a/gfx/cairo/cairo/src/cairo-analysis-surface.c b/gfx/cairo/cairo/src/cairo-analysis-surface.c index a89636efae84..26a373fa6c37 100644 --- a/gfx/cairo/cairo/src/cairo-analysis-surface.c +++ b/gfx/cairo/cairo/src/cairo-analysis-surface.c @@ -35,7 +35,7 @@ #include "cairoint.h" #include "cairo-analysis-surface-private.h" -#include "cairo-paginated-surface-private.h" +#include "cairo-paginated-private.h" typedef struct { cairo_surface_t base; diff --git a/gfx/cairo/cairo/src/cairo-arc.c b/gfx/cairo/cairo/src/cairo-arc.c index 2bf6c89f0b12..89e6ce1a655d 100644 --- a/gfx/cairo/cairo/src/cairo-arc.c +++ b/gfx/cairo/cairo/src/cairo-arc.c @@ -34,6 +34,8 @@ * Carl D. Worth */ +#include "cairoint.h" + #include "cairo-arc-private.h" /* Spline deviation from the circle in radius would be given by: @@ -85,7 +87,7 @@ _arc_max_angle_for_tolerance_normalized (double tolerance) { M_PI / 10.0, 1.73863223499021216974e-08 }, { M_PI / 11.0, 9.81410988043554039085e-09 }, }; - int table_size = (sizeof (table) / sizeof (table[0])); + int table_size = ARRAY_LENGTH (table); for (i = 0; i < table_size; i++) if (table[i].error < tolerance) diff --git a/gfx/cairo/cairo/src/cairo-atsui-font.c b/gfx/cairo/cairo/src/cairo-atsui-font.c index a26e76ffa1c9..34560d2886f3 100644 --- a/gfx/cairo/cairo/src/cairo-atsui-font.c +++ b/gfx/cairo/cairo/src/cairo-atsui-font.c @@ -34,11 +34,10 @@ * Calum Robinson */ -#include -#include -#include "cairo-atsui.h" #include "cairoint.h" + #include "cairo.h" +#include "cairo-atsui.h" #include "cairo-quartz-private.h" /* @@ -117,8 +116,7 @@ _cairo_atsui_font_face_scaled_font_create (void *abstract_face, ATSUStyle style; err = ATSUCreateStyle (&style); - err = ATSUSetAttributes(style, - sizeof(styleTags) / sizeof(styleTags[0]), + err = ATSUSetAttributes(style, ARRAY_LENGTH (styleTags), styleTags, styleSizes, styleValues); return _cairo_atsui_font_create_scaled (&font_face->base, font_face->font_id, style, @@ -149,14 +147,6 @@ cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id) return &font_face->base; } -static CGAffineTransform -CGAffineTransformMakeWithCairoFontScale(const cairo_matrix_t *scale) -{ - return CGAffineTransformMake(scale->xx, scale->yx, - scale->xy, scale->yy, - 0, 0); -} - static ATSUStyle CreateSizedCopyOfStyle(ATSUStyle inStyle, const Fixed *theSize, @@ -232,8 +222,13 @@ _cairo_atsui_font_create_scaled (cairo_font_face_t *font_face, if (font == NULL) return CAIRO_STATUS_NO_MEMORY; - _cairo_scaled_font_init(&font->base, font_face, font_matrix, ctm, options, - &cairo_atsui_scaled_font_backend); + status = _cairo_scaled_font_init (&font->base, + font_face, font_matrix, ctm, options, + &cairo_atsui_scaled_font_backend); + if (status) { + free (font); + return status; + } _cairo_matrix_compute_scale_factors (&font->base.scale, &xscale, &yscale, 1); @@ -374,8 +369,7 @@ _cairo_atsui_font_create_toy(cairo_toy_font_face_t *toy_face, ByteCount styleSizes[] = { sizeof(Boolean), sizeof(Boolean), sizeof(ATSUFontID) }; - err = ATSUSetAttributes(style, - sizeof(styleTags) / sizeof(styleTags[0]), + err = ATSUSetAttributes(style, ARRAY_LENGTH (styleTags), styleTags, styleSizes, styleValues); } @@ -397,50 +391,6 @@ _cairo_atsui_font_fini(void *abstract_font) ATSUDisposeStyle(font->unscaled_style); } -static -OSStatus _move_to_for_metrics (const Float32Point *point, void *callback_data) -{ - CGMutablePathRef path = callback_data; - - CGPathMoveToPoint (path, &CGAffineTransformIdentity, - point->x, point->y); - return noErr; -} - -static -OSStatus _line_to_for_metrics(const Float32Point *point, void *callback_data) -{ - CGMutablePathRef path = callback_data; - - CGPathAddLineToPoint (path, &CGAffineTransformIdentity, - point->x, point->y); - return noErr; -} - -static -OSStatus _curve_to_for_metrics (const Float32Point *point1, - const Float32Point *point2, - const Float32Point *point3, - void *callback_data) -{ - CGMutablePathRef path = callback_data; - - CGPathAddCurveToPoint (path, &CGAffineTransformIdentity, - point1->x, point1->y, - point2->x, point2->y, - point3->x, point3->y); - return noErr; -} - -static -OSStatus _close_path_for_metrics(void *callback_data) -{ - CGMutablePathRef path = callback_data; - - CGPathCloseSubpath (path); - return noErr; -} - static GlyphID _cairo_atsui_scaled_glyph_index (cairo_scaled_glyph_t *scaled_glyph) { unsigned long index = _cairo_scaled_glyph_index (scaled_glyph); @@ -454,16 +404,10 @@ _cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph) { cairo_text_extents_t extents = {0, 0, 0, 0, 0, 0}; - OSStatus err, callback_err; + OSStatus err; ATSGlyphScreenMetrics metricsH; - static ATSCubicMoveToUPP moveProc = NULL; - static ATSCubicLineToUPP lineProc = NULL; - static ATSCubicCurveToUPP curveProc = NULL; - static ATSCubicClosePathUPP closePathProc = NULL; - CGMutablePathRef path; GlyphID theGlyph = _cairo_atsui_scaled_glyph_index (scaled_glyph); double xscale, yscale; - CGRect rect; if (theGlyph == kATSDeletedGlyphcode) { _cairo_scaled_glyph_set_metrics (scaled_glyph, @@ -489,41 +433,15 @@ _cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font, extents.x_advance = metricsH.deviceAdvance.x * xscale; extents.y_advance = 0; - - if (moveProc == NULL) { - moveProc = NewATSCubicMoveToUPP (_move_to_for_metrics); - lineProc = NewATSCubicLineToUPP (_line_to_for_metrics); - curveProc = NewATSCubicCurveToUPP (_curve_to_for_metrics); - closePathProc = NewATSCubicClosePathUPP (_close_path_for_metrics); - } - - path = CGPathCreateMutable (); - - /* The callback error contains any error our functions returned. - * Its only meaningful if err != noErr, and we don't currently - * use it for anything. - */ - err = ATSUGlyphGetCubicPaths (scaled_font->style, theGlyph, - moveProc, lineProc, curveProc, closePathProc, - (void *)path, &callback_err); - - if (err != noErr) { - CGPathRelease (path); - return CAIRO_STATUS_NO_MEMORY; - } - - rect = CGPathGetBoundingBox (path); - - extents.x_bearing = rect.origin.x * xscale; - extents.y_bearing = rect.origin.y * yscale; - extents.width = rect.size.width * xscale; - extents.height = rect.size.height * yscale; + + extents.x_bearing = metricsH.topLeft.x * xscale; + extents.y_bearing = -metricsH.topLeft.y * yscale; + extents.width = metricsH.width * xscale; + extents.height = metricsH.height * yscale; _cairo_scaled_glyph_set_metrics (scaled_glyph, &scaled_font->base, &extents); - CGPathRelease (path); - return CAIRO_STATUS_SUCCESS; } @@ -667,6 +585,7 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font, CGContextRef drawingContext; cairo_image_surface_t *surface; cairo_format_t format; + cairo_status_t status; ATSFontRef atsFont; CGFontRef cgFont; @@ -683,8 +602,10 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font, if (theGlyph == kATSDeletedGlyphcode) { surface = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2); - if (!surface) - return CAIRO_STATUS_NO_MEMORY; + status = cairo_surface_status ((cairo_surface_t *)surface); + if (status) + return status; + _cairo_scaled_glyph_set_surface (scaled_glyph, &base, surface); @@ -692,19 +613,25 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font, } /* Compute a box to contain the glyph mask. The vertical - * sizes come from the font extents; extra pixels are + * sizes come from the font extents; extra pixels are * added to account for fractional sizes. */ height = extents.ascent + extents.descent + 2.0; bottom = -extents.descent - 1.0; + _cairo_matrix_compute_scale_factors (&base.scale, + &xscale, &yscale, 1); + bbox = CGRectApplyAffineTransform (CGRectMake (1.0, bottom, 1.0, height), CGAffineTransformMakeScale(xscale, yscale)); + bottom = CGRectGetMinY (bbox); + height = bbox.size.height; + /* Horizontal sizes come from the glyph typographic metrics. * It is possible that this might result in clipped text * in fonts where the typographic bounds don't cover the ink. * The width is recalculated, since metricsH.width is rounded. */ err = ATSUGlyphGetScreenMetrics (scaled_font->style, - 1, &theGlyph, 0, false, + 1, &theGlyph, 0, false, false, &metricsH); left = metricsH.sideBearing.x - 1.0; width = metricsH.deviceAdvance.x @@ -743,8 +670,9 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font, /* create the glyph mask surface */ surface = (cairo_image_surface_t *)cairo_image_surface_create (format, bbox.size.width, bbox.size.height); - if (!surface) - return CAIRO_STATUS_NO_MEMORY; + status = cairo_surface_status ((cairo_surface_t *)surface); + if (status) + return status; /* Create a CGBitmapContext for the dest surface for drawing into */ { diff --git a/gfx/cairo/cairo/src/cairo-base85-stream.c b/gfx/cairo/cairo/src/cairo-base85-stream.c index 7163d0092693..08ae8a74aa70 100644 --- a/gfx/cairo/cairo/src/cairo-base85-stream.c +++ b/gfx/cairo/cairo/src/cairo-base85-stream.c @@ -115,7 +115,7 @@ _cairo_base85_stream_create (cairo_output_stream_t *output) stream = malloc (sizeof (cairo_base85_stream_t)); if (stream == NULL) - return (cairo_output_stream_t *) &cairo_output_stream_nil; + return (cairo_output_stream_t *) &_cairo_output_stream_nil; _cairo_output_stream_init (&stream->base, _cairo_base85_stream_write, diff --git a/gfx/cairo/cairo/src/cairo-bentley-ottmann.c b/gfx/cairo/cairo/src/cairo-bentley-ottmann.c index 928b6cd56464..b8d97fa2634e 100644 --- a/gfx/cairo/cairo/src/cairo-bentley-ottmann.c +++ b/gfx/cairo/cairo/src/cairo-bentley-ottmann.c @@ -137,6 +137,7 @@ typedef struct _cairo_bo_sweep_line { int32_t current_y; } cairo_bo_sweep_line_t; + static inline int _cairo_bo_point32_compare (cairo_bo_point32_t const *a, cairo_bo_point32_t const *b) @@ -692,13 +693,16 @@ _cairo_bo_event_init (cairo_bo_event_t *event, event->point = point; } -static void +static cairo_status_t _cairo_bo_event_queue_insert (cairo_bo_event_queue_t *queue, cairo_bo_event_t *event) { + cairo_status_t status = CAIRO_STATUS_SUCCESS; /* Don't insert if there's already an equivalent intersection event in the queue. */ - _cairo_skip_list_insert (&queue->intersection_queue, event, - event->type == CAIRO_BO_EVENT_TYPE_INTERSECTION); + if (_cairo_skip_list_insert (&queue->intersection_queue, event, + event->type == CAIRO_BO_EVENT_TYPE_INTERSECTION) == NULL) + status = CAIRO_STATUS_NO_MEMORY; + return status; } static void @@ -750,16 +754,14 @@ _cairo_bo_event_queue_init (cairo_bo_event_queue_t *event_queue, * or stop events, so this allocation is safe. XXX: make the * event type a union so it doesn't always contain the skip * elt? */ - events = malloc (num_events * sizeof(cairo_bo_event_t)); - sorted_event_ptrs = malloc (num_events * sizeof(cairo_bo_event_t*)); - if (!events || !sorted_event_ptrs) { - if (events) free(events); - if (sorted_event_ptrs) free(sorted_event_ptrs); + events = malloc (num_events * (sizeof (cairo_bo_event_t) + sizeof(cairo_bo_event_t*))); + if (events == NULL) return CAIRO_STATUS_NO_MEMORY; - } + + sorted_event_ptrs = (cairo_bo_event_t **) (events + num_events); event_queue->startstop_events = events; event_queue->sorted_startstop_event_ptrs = sorted_event_ptrs; - event_queue->num_startstop_events = (unsigned)(num_events); + event_queue->num_startstop_events = num_events; event_queue->next_startstop_event_index = 0; for (i = 0; i < num_edges; i++) { @@ -792,11 +794,9 @@ _cairo_bo_event_queue_fini (cairo_bo_event_queue_t *event_queue) _cairo_skip_list_fini (&event_queue->intersection_queue); if (event_queue->startstop_events) free (event_queue->startstop_events); - if (event_queue->sorted_startstop_event_ptrs) - free (event_queue->sorted_startstop_event_ptrs); } -static void +static cairo_status_t _cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_t *event_queue, cairo_bo_edge_t *left, cairo_bo_edge_t *right) @@ -806,7 +806,7 @@ _cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_ cairo_bo_event_t event; if (left == NULL || right == NULL) - return; + return CAIRO_STATUS_SUCCESS; /* The names "left" and "right" here are correct descriptions of * the order of the two edges within the active edge list. So if a @@ -814,13 +814,13 @@ _cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_ * that the intersection of these two segments has oalready * occurred before the current sweep line position. */ if (_slope_compare (left, right) < 0) - return; + return CAIRO_STATUS_SUCCESS; status = _cairo_bo_edge_intersect (left, right, &intersection); if (status == CAIRO_BO_STATUS_PARALLEL || status == CAIRO_BO_STATUS_NO_INTERSECTION) { - return; + return CAIRO_STATUS_SUCCESS; } _cairo_bo_event_init (&event, @@ -828,7 +828,7 @@ _cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_ left, right, intersection); - _cairo_bo_event_queue_insert (event_queue, &event); + return _cairo_bo_event_queue_insert (event_queue, &event); } static void @@ -848,7 +848,7 @@ _cairo_bo_sweep_line_fini (cairo_bo_sweep_line_t *sweep_line) _cairo_skip_list_fini (&sweep_line->active_edges); } -static void +static cairo_status_t _cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line, cairo_bo_edge_t *edge) { @@ -858,6 +858,8 @@ _cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line, sweep_line_elt = _cairo_skip_list_insert (&sweep_line->active_edges, &edge, 1 /* unique inserts*/); + if (sweep_line_elt == NULL) + return CAIRO_STATUS_NO_MEMORY; next_elt = sweep_line_elt->elt.next[0]; if (next_elt) @@ -876,6 +878,8 @@ _cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line, *next_of_prev = edge; edge->sweep_line_elt = sweep_line_elt; + + return CAIRO_STATUS_SUCCESS; } static void @@ -1057,7 +1061,6 @@ _cairo_bo_edge_end_trap (cairo_bo_edge_t *left, cairo_bo_traps_t *bo_traps) { cairo_fixed_t fixed_top, fixed_bot; - cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_bo_trap_t *trap = left->deferred_trap; cairo_bo_edge_t *right; @@ -1099,11 +1102,11 @@ _cairo_bo_edge_end_trap (cairo_bo_edge_t *left, left_bot.x != right_bot.x || left_bot.y != right_bot.y) { - status = _cairo_traps_add_trap_from_points (bo_traps->traps, - fixed_top, - fixed_bot, - left_top, left_bot, - right_top, right_bot); + _cairo_traps_add_trap_from_points (bo_traps->traps, + fixed_top, + fixed_bot, + left_top, left_bot, + right_top, right_bot); #if DEBUG_PRINT_STATE printf ("Deferred trap: left=(%08x, %08x)-(%08x,%08x) " @@ -1117,7 +1120,8 @@ _cairo_bo_edge_end_trap (cairo_bo_edge_t *left, _cairo_freelist_free (&bo_traps->freelist, trap); left->deferred_trap = NULL; - return status; + + return _cairo_traps_status (bo_traps->traps); } /* Start a new trapezoid at the given top y coordinate, whose edges @@ -1254,7 +1258,7 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_edge_t *edges, cairo_fixed_t ymax, int *num_intersections) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_status_t status; int intersection_count = 0; cairo_bo_event_queue_t event_queue; cairo_bo_sweep_line_t sweep_line; @@ -1264,7 +1268,10 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_edge_t *edges, cairo_bo_edge_t *left, *right; cairo_bo_edge_t *edge1, *edge2; - _cairo_bo_event_queue_init (&event_queue, edges, num_edges); + status = _cairo_bo_event_queue_init (&event_queue, edges, num_edges); + if (status) + return status; + _cairo_bo_sweep_line_init (&sweep_line); _cairo_bo_traps_init (&bo_traps, traps, xmin, ymin, xmax, ymax); @@ -1296,7 +1303,9 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_edge_t *edges, case CAIRO_BO_EVENT_TYPE_START: edge = event->e1; - _cairo_bo_sweep_line_insert (&sweep_line, edge); + status = _cairo_bo_sweep_line_insert (&sweep_line, edge); + if (status) + goto unwind; /* Cache the insert position for use in pass 2. event->e2 = Sortlist::prev (sweep_line, edge); */ @@ -1304,9 +1313,13 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_edge_t *edges, left = edge->prev; right = edge->next; - _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, edge); + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, edge); + if (status) + goto unwind; - _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, edge, right); + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, edge, right); + if (status) + goto unwind; #if DEBUG_PRINT_STATE print_state ("After processing start", &event_queue, &sweep_line); @@ -1326,7 +1339,9 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_edge_t *edges, if (status) goto unwind; - _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, right); + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, right); + if (status) + goto unwind; #if DEBUG_PRINT_STATE print_state ("After processing stop", &event_queue, &sweep_line); @@ -1354,11 +1369,15 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_edge_t *edges, /* after the swap e2 is left of e1 */ - _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, edge2); + if (status) + goto unwind; - _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, edge1, right); + if (status) + goto unwind; #if DEBUG_PRINT_STATE print_state ("After processing intersection", &event_queue, &sweep_line); @@ -1402,6 +1421,7 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps, { int intersections; cairo_status_t status; + cairo_bo_edge_t stack_edges[CAIRO_STACK_BUFFER_SIZE / sizeof (cairo_bo_edge_t)]; cairo_bo_edge_t *edges; cairo_fixed_t xmin = 0x7FFFFFFF; cairo_fixed_t ymin = 0x7FFFFFFF; @@ -1413,9 +1433,13 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps, if (0 == polygon->num_edges) return CAIRO_STATUS_SUCCESS; - edges = malloc (polygon->num_edges * sizeof (cairo_bo_edge_t)); - if (edges == NULL) - return CAIRO_STATUS_NO_MEMORY; + if (polygon->num_edges < ARRAY_LENGTH (stack_edges)) { + edges = stack_edges; + } else { + edges = malloc (polygon->num_edges * sizeof (cairo_bo_edge_t)); + if (edges == NULL) + return CAIRO_STATUS_NO_MEMORY; + } /* Figure out the bounding box of the input coordinates and * validate that we're not given invalid polygon edges. */ @@ -1495,7 +1519,8 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps, xmin, ymin, xmax, ymax, &intersections); - free (edges); + if (edges != stack_edges) + free (edges); return status; } @@ -1771,7 +1796,7 @@ main (void) unsigned int i, num_random; test_t *test; - for (i = 0; i < sizeof (tests) / sizeof (tests[0]); i++) { + for (i = 0; i < ARRAY_LENGTH (tests); i++) { test = &tests[i]; run_test (test->name, test->edges, test->num_edges); } diff --git a/gfx/cairo/cairo/src/cairo-cache-private.h b/gfx/cairo/cairo/src/cairo-cache-private.h index 566dbe22d395..7ab14e26cd17 100644 --- a/gfx/cairo/cairo/src/cairo-cache-private.h +++ b/gfx/cairo/cairo/src/cairo-cache-private.h @@ -39,7 +39,7 @@ #ifndef CAIRO_CACHE_PRIVATE_H #define CAIRO_CACHE_PRIVATE_H -typedef struct _cairo_cache cairo_cache_t; +#include "cairo-types-private.h" /** * cairo_cache_entry_t: diff --git a/gfx/cairo/cairo/src/cairo-cache.c b/gfx/cairo/cairo/src/cairo-cache.c index fa1f003a659c..18c3d8cca38c 100644 --- a/gfx/cairo/cairo/src/cairo-cache.c +++ b/gfx/cairo/cairo/src/cairo-cache.c @@ -38,17 +38,6 @@ #include "cairoint.h" -struct _cairo_cache { - cairo_hash_table_t *hash_table; - - cairo_destroy_func_t entry_destroy; - - unsigned long max_size; - unsigned long size; - - int freeze_count; -}; - static void _cairo_cache_remove (cairo_cache_t *cache, cairo_cache_entry_t *entry); diff --git a/gfx/cairo/cairo/src/cairo-cff-subset.c b/gfx/cairo/cairo/src/cairo-cff-subset.c index b35498940b82..2adc709c0bde 100644 --- a/gfx/cairo/cairo/src/cairo-cff-subset.c +++ b/gfx/cairo/cairo/src/cairo-cff-subset.c @@ -37,15 +37,20 @@ #include "cairoint.h" #include "cairo-scaled-font-subsets-private.h" #include "cairo-truetype-subset-private.h" +#include /* CFF Dict Operators. If the high byte is 0 the command is encoded * with a single byte. */ #define BASEFONTNAME_OP 0x0c16 +#define CIDCOUNT_OP 0x0c22 #define CHARSET_OP 0x000f #define CHARSTRINGS_OP 0x0011 #define COPYRIGHT_OP 0x0c00 #define ENCODING_OP 0x0010 #define FAMILYNAME_OP 0x0003 +#define FDARRAY_OP 0x0c24 +#define FDSELECT_OP 0x0c25 +#define FONTBBOX_OP 0x0005 #define FONTNAME_OP 0x0c26 #define FULLNAME_OP 0x0002 #define LOCAL_SUB_OP 0x0013 @@ -53,13 +58,13 @@ #define POSTSCRIPT_OP 0x0c15 #define PRIVATE_OP 0x0012 #define ROS_OP 0x0c1e +#define UNIQUEID_OP 0x000d #define VERSION_OP 0x0000 #define WEIGHT_OP 0x0004 +#define XUID_OP 0x000e #define NUM_STD_STRINGS 391 -#define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) ) - typedef struct _cff_header { uint8_t major; uint8_t minor; @@ -82,13 +87,6 @@ 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; @@ -108,14 +106,23 @@ 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; + cairo_bool_t is_cid; + + /* CID Font Data */ + int *fdselect; + unsigned int num_fontdicts; + cairo_hash_table_t **fd_dict; + cairo_hash_table_t **fd_private_dict; + cairo_array_t *fd_local_sub_index; /* Subsetted Font Data */ char *subset_font_name; cairo_array_t charstrings_subset_index; cairo_array_t strings_subset_index; - cairo_array_t charset_subset; + int *fdselect_subset; + unsigned int num_subset_fontdicts; + int *fd_subset_map; + int *private_dict_offset; cairo_array_t output; /* Subset Metrics */ @@ -347,7 +354,6 @@ cff_index_write (cairo_array_t *index, cairo_array_t *output) status = _cairo_array_append_multiple (output, buf, offset_size); if (status) return status; - } for (i = 0; i < num_elem; i++) { @@ -374,7 +380,9 @@ cff_index_append (cairo_array_t *index, unsigned char *object , int length) } static cairo_status_t -cff_index_append_copy (cairo_array_t *index, unsigned char *object , int length) +cff_index_append_copy (cairo_array_t *index, + const unsigned char *object, + unsigned int length) { cff_index_element_t element; @@ -488,6 +496,21 @@ 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); + free (op); + } +} + static unsigned char * cff_dict_get_operands (cairo_hash_table_t *dict, unsigned short operator, @@ -563,19 +586,12 @@ typedef struct _dict_write_info { } dict_write_info_t; static void -_cairo_dict_collect (void *entry, void *closure) +cairo_dict_write_operator (cff_dict_operator_t *op, dict_write_info_t *write_info) { - dict_write_info_t *write_info = closure; - cff_dict_operator_t *op = entry; unsigned char data; - if (write_info->status) - return; - op->operand_offset = _cairo_array_num_elements (write_info->output); - write_info->status = _cairo_array_append_multiple (write_info->output, - op->operand, - op->operand_length); + write_info->status = _cairo_array_append_multiple (write_info->output, op->operand, op->operand_length); if (write_info->status) return; @@ -589,13 +605,36 @@ _cairo_dict_collect (void *entry, void *closure) write_info->status = _cairo_array_append (write_info->output, &data); } +static void +_cairo_dict_collect (void *entry, void *closure) +{ + dict_write_info_t *write_info = closure; + cff_dict_operator_t *op = entry; + + if (write_info->status) + return; + + /* The ROS operator is handled separately in cff_dict_write() */ + if (op->operator != ROS_OP) + cairo_dict_write_operator (op, write_info); +} + static cairo_status_t cff_dict_write (cairo_hash_table_t *dict, cairo_array_t *output) { dict_write_info_t write_info; + cff_dict_operator_t key, *op; write_info.output = output; write_info.status = CAIRO_STATUS_SUCCESS; + + /* The CFF specification requires that the Top Dict of CID fonts + * begin with the ROS operator. */ + _cairo_dict_init_key (&key, ROS_OP); + if (_cairo_hash_table_lookup (dict, &key.base, + (cairo_hash_entry_t **) &op)) + cairo_dict_write_operator (op, &write_info); + _cairo_hash_table_foreach (dict, _cairo_dict_collect, &write_info); return write_info.status; @@ -646,6 +685,8 @@ cairo_cff_font_read_name (cairo_cff_font_t *font) static cairo_int_status_t cairo_cff_font_read_private_dict (cairo_cff_font_t *font, + cairo_hash_table_t *private_dict, + cairo_array_t *local_sub_index, unsigned char *ptr, int size) { @@ -656,21 +697,140 @@ cairo_cff_font_read_private_dict (cairo_cff_font_t *font, unsigned char *operand; unsigned char *p; - cff_dict_read (font->private_dict, ptr, size); - operand = cff_dict_get_operands (font->private_dict, LOCAL_SUB_OP, &i); + cff_dict_read (private_dict, ptr, size); + operand = cff_dict_get_operands (private_dict, LOCAL_SUB_OP, &i); if (operand) { decode_integer (operand, &offset); p = ptr + offset; - cff_index_read (&font->local_sub_index, &p, font->data_end); + cff_index_read (local_sub_index, &p, font->data_end); /* Use maximum sized encoding to reserve space for later modification. */ end_buf = encode_integer_max (buf, 0); - cff_dict_set_operands (font->private_dict, LOCAL_SUB_OP, buf, end_buf - buf); + cff_dict_set_operands (private_dict, LOCAL_SUB_OP, buf, end_buf - buf); } return CAIRO_STATUS_SUCCESS; } +static cairo_int_status_t +cairo_cff_font_read_fdselect (cairo_cff_font_t *font, unsigned char *p) +{ + int type, num_ranges, first, last, fd, i, j; + + font->fdselect = calloc (font->num_glyphs, sizeof (int)); + if (font->fdselect == NULL) + return CAIRO_STATUS_NO_MEMORY; + + type = *p++; + if (type == 0) + { + for (i = 0; i < font->num_glyphs; i++) + font->fdselect[i] = *p++; + } else if (type == 3) { + num_ranges = be16_to_cpu( *((uint16_t *)p) ); + p += 2; + for (i = 0; i < num_ranges; i++) + { + first = be16_to_cpu( *((uint16_t *)p) ); + p += 2; + fd = *p++; + last = be16_to_cpu( *((uint16_t *)p) ); + for (j = first; j < last; j++) + font->fdselect[j] = fd; + } + } else { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr) +{ + cairo_array_t index; + cff_index_element_t *element; + unsigned int i; + int size; + unsigned char *operand; + int offset; + cairo_int_status_t status; + unsigned char buf[100]; + unsigned char *end_buf; + + cff_index_init (&index); + status = cff_index_read (&index, &ptr, font->data_end); + if (status) + goto fail; + + font->num_fontdicts = _cairo_array_num_elements (&index); + + font->fd_dict = calloc (sizeof (cairo_hash_table_t *), font->num_fontdicts); + if (font->fd_dict == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail; + } + + font->fd_private_dict = calloc (sizeof (cairo_hash_table_t *), font->num_fontdicts); + if (font->fd_private_dict == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail; + } + + font->fd_local_sub_index = calloc (sizeof (cairo_array_t), font->num_fontdicts); + if (font->fd_local_sub_index == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail; + } + + for (i = 0; i < font->num_fontdicts; i++) { + cff_dict_init (&font->fd_dict[i]); + if (font->fd_dict[i] == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail; + } + element = _cairo_array_index (&index, i); + status = cff_dict_read (font->fd_dict[i], element->data, element->length); + if (status) + goto fail; + + operand = cff_dict_get_operands (font->fd_dict[i], PRIVATE_OP, &size); + if (operand == NULL) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto fail; + } + operand = decode_integer (operand, &size); + decode_integer (operand, &offset); + cff_dict_init (&font->fd_private_dict[i]); + if (font->fd_private_dict[i] == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail; + } + cff_index_init (&font->fd_local_sub_index[i]); + status = cairo_cff_font_read_private_dict (font, + font->fd_private_dict[i], + &font->fd_local_sub_index[i], + font->data + offset, + size); + if (status) + goto fail; + /* Set integer operand to max value to use max size encoding to reserve + * space for any value later */ + end_buf = encode_integer_max (buf, 0); + end_buf = encode_integer_max (end_buf, 0); + status = cff_dict_set_operands (font->fd_dict[i], PRIVATE_OP, buf, end_buf - buf); + if (status) + goto fail; + } + + return CAIRO_STATUS_SUCCESS; + +fail: + cff_index_fini (&index); + + return status; +} + static cairo_int_status_t cairo_cff_font_read_top_dict (cairo_cff_font_t *font) { @@ -690,13 +850,14 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font) goto fail; element = _cairo_array_index (&index, 0); - cff_dict_read (font->top_dict, element->data, element->length); - - /* CID fonts are NYI */ - if (cff_dict_get_operands (font->top_dict, ROS_OP, &size) != NULL) { - status = CAIRO_INT_STATUS_UNSUPPORTED; + status = cff_dict_read (font->top_dict, element->data, element->length); + if (status) goto fail; - } + + if (cff_dict_get_operands (font->top_dict, ROS_OP, &size) != NULL) + font->is_cid = TRUE; + else + font->is_cid = FALSE; operand = cff_dict_get_operands (font->top_dict, CHARSTRINGS_OP, &size); decode_integer (operand, &offset); @@ -706,27 +867,39 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font) goto fail; font->num_glyphs = _cairo_array_num_elements (&font->charstrings_index); - operand = cff_dict_get_operands (font->top_dict, PRIVATE_OP, &size); - operand = decode_integer (operand, &size); - decode_integer (operand, &offset); - cairo_cff_font_read_private_dict (font, font->data + offset, size); + if (font->is_cid) { + operand = cff_dict_get_operands (font->top_dict, FDSELECT_OP, &size); + decode_integer (operand, &offset); + cairo_cff_font_read_fdselect (font, font->data + offset); - 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; + operand = cff_dict_get_operands (font->top_dict, FDARRAY_OP, &size); + decode_integer (operand, &offset); + cairo_cff_font_read_cid_fontdict (font, font->data + offset); + } else { + operand = cff_dict_get_operands (font->top_dict, PRIVATE_OP, &size); + operand = decode_integer (operand, &size); + decode_integer (operand, &offset); + cairo_cff_font_read_private_dict (font, + font->private_dict, + &font->local_sub_index, + font->data + offset, + size); } /* 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, FDSELECT_OP, buf, end_buf - buf); + cff_dict_set_operands (font->top_dict, FDARRAY_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); + + cff_dict_remove (font->top_dict, ENCODING_OP); + cff_dict_remove (font->top_dict, PRIVATE_OP); + + /* Remove the unique identifier operators as the subsetted font is + * not the same is the original font. */ + cff_dict_remove (font->top_dict, UNIQUEID_OP); + cff_dict_remove (font->top_dict, XUID_OP); fail: cff_index_fini (&index); @@ -746,138 +919,6 @@ 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); @@ -887,8 +928,6 @@ 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 @@ -906,6 +945,34 @@ cairo_cff_font_read_font (cairo_cff_font_t *font) return CAIRO_STATUS_SUCCESS; } +static void +cairo_cff_font_set_ros_strings (cairo_cff_font_t *font) +{ + unsigned char buf[30]; + unsigned char *p; + int sid1, sid2; + const char *registry = "Adobe"; + const char *ordering = "Identity"; + + sid1 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index); + cff_index_append_copy (&font->strings_subset_index, + (unsigned char *)registry, + strlen(registry)); + + sid2 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index); + cff_index_append_copy (&font->strings_subset_index, + (unsigned char *)ordering, + strlen(ordering)); + + p = encode_integer (buf, sid1); + p = encode_integer (p, sid2); + p = encode_integer (p, 0); + cff_dict_set_operands (font->top_dict, ROS_OP, buf, p - buf); + + p = encode_integer (buf, font->scaled_font_subset->num_glyphs); + cff_dict_set_operands (font->top_dict, CIDCOUNT_OP, buf, p - buf); +} + static cairo_status_t cairo_cff_font_subset_dict_string(cairo_cff_font_t *font, cairo_hash_table_t *dict, @@ -966,20 +1033,6 @@ cairo_cff_font_subset_dict_strings (cairo_cff_font_t *font, return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -cairo_cff_font_subset_strings (cairo_cff_font_t *font) -{ - cairo_status_t status; - - status = cairo_cff_font_subset_dict_strings (font, font->top_dict); - if (status) - return status; - - status = cairo_cff_font_subset_dict_strings (font, font->private_dict); - - return status; -} - static cairo_status_t cairo_cff_font_subset_charstrings (cairo_cff_font_t *font) { @@ -987,14 +1040,6 @@ cairo_cff_font_subset_charstrings (cairo_cff_font_t *font) unsigned int i; cairo_status_t status; - /* add .notdef */ - element = _cairo_array_index (&font->charstrings_index, 0); - status = cff_index_append (&font->charstrings_subset_index, - element->data, - element->length); - if (status) - return status; - for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { element = _cairo_array_index (&font->charstrings_index, font->scaled_font_subset->glyphs[i]); @@ -1008,78 +1053,105 @@ 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) +static cairo_status_t +cairo_cff_font_subset_fontdict (cairo_cff_font_t *font) { - const uint16_t *sids; - const unsigned char *p; - int prev_glyph; + unsigned int i; + int fd; + int *reverse_map; - if (charset->is_builtin) { - if (gid - 1 < charset->length / 2) - return charset->sids[gid - 1]; + font->fdselect_subset = calloc (font->scaled_font_subset->num_glyphs, + sizeof (int)); + if (font->fdselect_subset == NULL) + return CAIRO_STATUS_NO_MEMORY; + + font->fd_subset_map = calloc (font->num_fontdicts, sizeof (int)); + if (font->fd_subset_map == NULL) + return CAIRO_STATUS_NO_MEMORY; + + font->private_dict_offset = calloc (font->num_fontdicts, sizeof (int)); + if (font->private_dict_offset == NULL) + return CAIRO_STATUS_NO_MEMORY; + + reverse_map = calloc (font->num_fontdicts, sizeof (int)); + if (reverse_map == NULL) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < font->num_fontdicts; i++) + reverse_map[i] = -1; + + font->num_subset_fontdicts = 0; + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { + fd = font->fdselect[font->scaled_font_subset->glyphs[i]]; + if (reverse_map[fd] < 0) { + font->fd_subset_map[font->num_subset_fontdicts] = fd; + reverse_map[fd] = font->num_subset_fontdicts++; + } + font->fdselect_subset[i] = reverse_map[fd]; } - 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; + + free (reverse_map); + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -cairo_cff_font_subset_charset (cairo_cff_font_t *font) +cairo_cff_font_create_cid_fontdict (cairo_cff_font_t *font) { + unsigned char buf[100]; + unsigned char *end_buf; + + font->num_fontdicts = 1; + font->fd_dict = malloc (sizeof (cairo_hash_table_t *)); + if (font->fd_dict == NULL) + return CAIRO_STATUS_NO_MEMORY; + + cff_dict_init (&font->fd_dict[0]); + + font->fd_subset_map = malloc (sizeof (int)); + if (font->fd_subset_map == NULL) + return CAIRO_STATUS_NO_MEMORY; + + font->private_dict_offset = malloc (sizeof (int)); + if (font->private_dict_offset == NULL) + return CAIRO_STATUS_NO_MEMORY; + + font->fd_subset_map[0] = 0; + font->num_subset_fontdicts = 1; + + /* Set integer operand to max value to use max size encoding to reserve + * space for any value later */ + end_buf = encode_integer_max (buf, 0); + end_buf = encode_integer_max (end_buf, 0); + cff_dict_set_operands (font->fd_dict[0], PRIVATE_OP, buf, end_buf - buf); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_cff_font_subset_strings (cairo_cff_font_t *font) +{ + cairo_status_t status; 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; + status = cairo_cff_font_subset_dict_strings (font, font->top_dict); + if (status) + return status; + if (font->is_cid) { + for (i = 0; i < font->num_subset_fontdicts; i++) { + status = cairo_cff_font_subset_dict_strings (font, font->fd_dict[font->fd_subset_map[i]]); + if (status) + return 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; + status = cairo_cff_font_subset_dict_strings (font, font->fd_private_dict[font->fd_subset_map[i]]); + if (status) + return status; + } + } else { + status = cairo_cff_font_subset_dict_strings (font, font->private_dict); } - return CAIRO_STATUS_SUCCESS; + + return status; } static cairo_status_t @@ -1087,18 +1159,21 @@ cairo_cff_font_subset_font (cairo_cff_font_t *font) { cairo_status_t status; - /* TODO: subset subroutines */ + cairo_cff_font_set_ros_strings (font); + + status = cairo_cff_font_subset_charstrings (font); + if (status) + return status; + + if (font->is_cid) + cairo_cff_font_subset_fontdict (font); + else + cairo_cff_font_create_cid_fontdict (font); status = cairo_cff_font_subset_strings (font); if (status) return status; - status = cairo_cff_font_subset_charstrings (font); - if (status) - return status; - - status = cairo_cff_font_subset_charset (font); - return status; } @@ -1212,38 +1287,82 @@ cairo_cff_font_write_global_subrs (cairo_cff_font_t *font) } static cairo_status_t -cairo_cff_font_write_encoding (cairo_cff_font_t *font) +cairo_cff_font_write_fdselect (cairo_cff_font_t *font) { - unsigned char buf[10]; + unsigned char data; + unsigned int i; + cairo_int_status_t status; - cairo_cff_font_set_topdict_operator_to_cur_pos (font, ENCODING_OP); - buf[0] = 1; /* Format 1 */ - buf[1] = 1; /* Number of ranges */ - buf[2] = 0; /* First code in range */ - /* Codes left in range excluding first */ - buf[3] = font->scaled_font_subset->num_glyphs - 1; + cairo_cff_font_set_topdict_operator_to_cur_pos (font, FDSELECT_OP); - return _cairo_array_append_multiple (&font->output, buf, 4); + if (font->is_cid) { + data = 0; + status = _cairo_array_append (&font->output, &data); + if (status) + return status; + + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { + data = font->fdselect_subset[i]; + status = _cairo_array_append (&font->output, &data); + if (status) + return status; + } + } else { + unsigned char byte; + uint16_t word; + + status = _cairo_array_grow_by (&font->output, 9); + if (status) + return status; + + byte = 3; + status = _cairo_array_append (&font->output, &byte); + assert (status == CAIRO_STATUS_SUCCESS); + + word = cpu_to_be16 (1); + status = _cairo_array_append_multiple (&font->output, &word, 2); + assert (status == CAIRO_STATUS_SUCCESS); + + word = cpu_to_be16 (0); + status = _cairo_array_append_multiple (&font->output, &word, 2); + assert (status == CAIRO_STATUS_SUCCESS); + + byte = 0; + status = _cairo_array_append (&font->output, &byte); + assert (status == CAIRO_STATUS_SUCCESS); + + word = cpu_to_be16 (font->scaled_font_subset->num_glyphs); + status = _cairo_array_append_multiple (&font->output, &word, 2); + assert (status == CAIRO_STATUS_SUCCESS); + } + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t cairo_cff_font_write_charset (cairo_cff_font_t *font) { - unsigned char format = 0; - unsigned int i; + unsigned char byte; + uint16_t word; cairo_status_t status; cairo_cff_font_set_topdict_operator_to_cur_pos (font, CHARSET_OP); - status = _cairo_array_append (&font->output, &format); + status = _cairo_array_grow_by (&font->output, 5); if (status) - return status; + return status; + + byte = 2; + status = _cairo_array_append (&font->output, &byte); + assert (status == CAIRO_STATUS_SUCCESS); + + word = cpu_to_be16 (1); + status = _cairo_array_append_multiple (&font->output, &word, 2); + assert (status == CAIRO_STATUS_SUCCESS); + + word = cpu_to_be16 (font->scaled_font_subset->num_glyphs - 2); + status = _cairo_array_append_multiple (&font->output, &word, 2); + assert (status == CAIRO_STATUS_SUCCESS); - 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; } @@ -1256,9 +1375,48 @@ cairo_cff_font_write_charstrings (cairo_cff_font_t *font) } static cairo_status_t -cairo_cff_font_write_private_dict_and_local_sub (cairo_cff_font_t *font) +cairo_cff_font_write_cid_fontdict (cairo_cff_font_t *font) { - int offset, private_dict_offset; + unsigned int i; + cairo_int_status_t status; + uint32_t *offset_array; + int offset_base; + uint16_t count; + uint8_t offset_size = 4; + + cairo_cff_font_set_topdict_operator_to_cur_pos (font, FDARRAY_OP); + count = cpu_to_be16 (font->num_subset_fontdicts); + status = _cairo_array_append_multiple (&font->output, &count, sizeof (uint16_t)); + if (status) + return status; + status = _cairo_array_append (&font->output, &offset_size); + if (status) + return status; + status = _cairo_array_allocate (&font->output, + (font->num_subset_fontdicts + 1)*offset_size, + (void **) &offset_array); + if (status) + return status; + offset_base = _cairo_array_num_elements (&font->output) - 1; + *offset_array++ = cpu_to_be32(1); + for (i = 0; i < font->num_subset_fontdicts; i++) { + status = cff_dict_write (font->fd_dict[font->fd_subset_map[i]], + &font->output); + if (status) + return status; + *offset_array++ = cpu_to_be32(_cairo_array_num_elements (&font->output) - offset_base); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_cff_font_write_private_dict (cairo_cff_font_t *font, + int dict_num, + cairo_hash_table_t *parent_dict, + cairo_hash_table_t *private_dict) +{ + int offset; int size; unsigned char buf[10]; unsigned char *buf_end; @@ -1266,30 +1424,46 @@ cairo_cff_font_write_private_dict_and_local_sub (cairo_cff_font_t *font) cairo_status_t status; /* Write private dict and update offset and size in top dict */ - private_dict_offset = _cairo_array_num_elements (&font->output); - status = cff_dict_write (font->private_dict, &font->output); + font->private_dict_offset[dict_num] = _cairo_array_num_elements (&font->output); + status = cff_dict_write (private_dict, &font->output); if (status) return status; - size = _cairo_array_num_elements (&font->output) - private_dict_offset; + size = _cairo_array_num_elements (&font->output) - font->private_dict_offset[dict_num]; /* private entry has two operands - size and offset */ buf_end = encode_integer_max (buf, size); - buf_end = encode_integer_max (buf_end, private_dict_offset); - offset = cff_dict_get_location (font->top_dict, PRIVATE_OP, &size); + buf_end = encode_integer_max (buf_end, font->private_dict_offset[dict_num]); + offset = cff_dict_get_location (parent_dict, PRIVATE_OP, &size); assert (offset > 0); p = _cairo_array_index (&font->output, offset); memcpy (p, buf, buf_end - buf); - if (_cairo_array_num_elements (&font->local_sub_index) > 0) { + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_cff_font_write_local_sub (cairo_cff_font_t *font, + int dict_num, + cairo_hash_table_t *private_dict, + cairo_array_t *local_sub_index) +{ + int offset; + int size; + unsigned char buf[10]; + unsigned char *buf_end; + unsigned char *p; + cairo_status_t status; + + if (_cairo_array_num_elements (local_sub_index) > 0) { /* Write local subroutines and update offset in private * dict. Local subroutines offset is relative to start of * private dict */ - offset = _cairo_array_num_elements (&font->output) - private_dict_offset; + offset = _cairo_array_num_elements (&font->output) - font->private_dict_offset[dict_num]; buf_end = encode_integer_max (buf, offset); - offset = cff_dict_get_location (font->private_dict, LOCAL_SUB_OP, &size); + offset = cff_dict_get_location (private_dict, LOCAL_SUB_OP, &size); assert (offset > 0); p = _cairo_array_index (&font->output, offset); memcpy (p, buf, buf_end - buf); - status = cff_index_write (&font->local_sub_index, &font->output); + status = cff_index_write (local_sub_index, &font->output); if (status) return status; } @@ -1297,6 +1471,47 @@ cairo_cff_font_write_private_dict_and_local_sub (cairo_cff_font_t *font) return CAIRO_STATUS_SUCCESS; } + +static cairo_status_t +cairo_cff_font_write_cid_private_dict_and_local_sub (cairo_cff_font_t *font) +{ + unsigned int i; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + if (font->is_cid) { + for (i = 0; i < font->num_subset_fontdicts; i++) { + status = cairo_cff_font_write_private_dict ( + font, + i, + font->fd_dict[font->fd_subset_map[i]], + font->fd_private_dict[font->fd_subset_map[i]]); + if (status) + return status; + } + + for (i = 0; i < font->num_subset_fontdicts; i++) { + status = cairo_cff_font_write_local_sub ( + font, + i, + font->fd_private_dict[font->fd_subset_map[i]], + &font->fd_local_sub_index[font->fd_subset_map[i]]); + if (status) + return status; + } + } else { + status = cairo_cff_font_write_private_dict (font, + 0, + font->fd_dict[0], + font->private_dict); + status = cairo_cff_font_write_local_sub (font, + 0, + font->private_dict, + &font->local_sub_index); + } + + return status; +} + typedef cairo_status_t (*font_write_t) (cairo_cff_font_t *font); @@ -1306,10 +1521,11 @@ static const font_write_t font_write_funcs[] = { cairo_cff_font_write_top_dict, cairo_cff_font_write_strings, cairo_cff_font_write_global_subrs, - cairo_cff_font_write_encoding, + cairo_cff_font_write_fdselect, cairo_cff_font_write_charset, cairo_cff_font_write_charstrings, - cairo_cff_font_write_private_dict_and_local_sub, + cairo_cff_font_write_cid_fontdict, + cairo_cff_font_write_cid_private_dict_and_local_sub, }; static cairo_status_t @@ -1373,7 +1589,7 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font) return status; num_hmetrics = be16_to_cpu (hhea.num_hmetrics); - for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { + for (i = 1; i < font->scaled_font_subset->num_glyphs; i++) { glyph_index = font->scaled_font_subset->glyphs[i]; long_entry_size = 2 * sizeof (int16_t); short_entry_size = sizeof (int16_t); @@ -1555,7 +1771,13 @@ _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)); + font->fdselect = NULL; + font->fd_dict = NULL; + font->fd_private_dict = NULL; + font->fd_local_sub_index = NULL; + font->fdselect_subset = NULL; + font->fd_subset_map = NULL; + font->private_dict_offset = NULL; free (name); *font_return = font; @@ -1582,6 +1804,8 @@ fail1: static void cairo_cff_font_destroy (cairo_cff_font_t *font) { + unsigned int i; + free (font->widths); free (font->font_name); free (font->subset_font_name); @@ -1594,7 +1818,43 @@ 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); + + /* If we bailed out early as a result of an error some of the + * following cairo_cff_font_t members may still be NULL */ + if (font->fd_dict) { + for (i = 0; i < font->num_fontdicts; i++) { + if (font->fd_dict[i]) + cff_dict_fini (font->fd_dict[i]); + } + free (font->fd_dict); + } + if (font->fd_subset_map) + free (font->fd_subset_map); + if (font->private_dict_offset) + free (font->private_dict_offset); + + if (font->is_cid) { + if (font->fdselect) + free (font->fdselect); + if (font->fdselect_subset) + free (font->fdselect_subset); + if (font->fd_private_dict) { + for (i = 0; i < font->num_fontdicts; i++) { + if (font->fd_private_dict[i]) + cff_dict_fini (font->fd_private_dict[i]); + } + free (font->fd_private_dict); + } + if (font->fd_local_sub_index) { + for (i = 0; i < font->num_fontdicts; i++) + cff_index_fini (&font->fd_local_sub_index[i]); + free (font->fd_local_sub_index); + } + } + + if (font->data) + free (font->data); + free (font); } @@ -1662,3 +1922,215 @@ _cairo_cff_subset_fini (cairo_cff_subset_t *subset) free (subset->widths); free (subset->data); } + +static cairo_int_status_t +_cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset, + cairo_cff_font_t **font_return, + const char *subset_name) +{ + cairo_status_t status; + cairo_cff_font_t *font; + + font = malloc (sizeof (cairo_cff_font_t)); + if (font == NULL) + return CAIRO_STATUS_NO_MEMORY; + + font->backend = NULL; + font->scaled_font_subset = scaled_font_subset; + + _cairo_array_init (&font->output, sizeof (char)); + status = _cairo_array_grow_by (&font->output, 4096); + if (status) + goto fail1; + + font->subset_font_name = strdup (subset_name); + if (font->subset_font_name == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail2; + } + + font->font_name = strdup (subset_name); + if (font->subset_font_name == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail3; + } + + font->x_min = 0; + font->y_min = 0; + font->x_max = 0; + font->y_max = 0; + font->ascent = 0; + font->descent = 0; + + font->widths = calloc (font->scaled_font_subset->num_glyphs, sizeof (int)); + if (font->widths == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail4; + } + + font->data_length = 0; + font->data = NULL; + font->data_end = 0; + + cff_dict_init (&font->top_dict); + cff_dict_init (&font->private_dict); + cff_index_init (&font->strings_index); + cff_index_init (&font->charstrings_index); + cff_index_init (&font->global_sub_index); + cff_index_init (&font->local_sub_index); + cff_index_init (&font->charstrings_subset_index); + cff_index_init (&font->strings_subset_index); + font->fdselect = NULL; + font->fd_dict = NULL; + font->fd_private_dict = NULL; + font->fd_local_sub_index = NULL; + font->fdselect_subset = NULL; + font->fd_subset_map = NULL; + font->private_dict_offset = NULL; + + *font_return = font; + + return CAIRO_STATUS_SUCCESS; + +fail4: + free (font->font_name); +fail3: + free (font->subset_font_name); +fail2: + _cairo_array_fini (&font->output); +fail1: + free (font); + return status; +} + +static cairo_int_status_t +cairo_cff_font_fallback_generate (cairo_cff_font_t *font, + cairo_type2_charstrings_t *type2_subset, + const char **data, + unsigned long *length) +{ + cairo_int_status_t status; + cff_header_t header; + cairo_array_t *charstring; + unsigned char buf[40]; + unsigned char *end_buf; + unsigned int i; + + /* Create header */ + header.major = 1; + header.minor = 0; + header.header_size = 4; + header.offset_size = 4; + font->header = &header; + + /* Create Top Dict */ + font->is_cid = FALSE; + end_buf = encode_integer (buf, type2_subset->x_min); + end_buf = encode_integer (end_buf, type2_subset->y_min); + end_buf = encode_integer (end_buf, type2_subset->x_max); + end_buf = encode_integer (end_buf, type2_subset->y_max); + cff_dict_set_operands (font->top_dict, FONTBBOX_OP, buf, end_buf - buf); + 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, FDSELECT_OP, buf, end_buf - buf); + cff_dict_set_operands (font->top_dict, FDARRAY_OP, buf, end_buf - buf); + cff_dict_set_operands (font->top_dict, CHARSET_OP, buf, end_buf - buf); + cairo_cff_font_set_ros_strings (font); + + /* Create CID FD dictionary */ + cairo_cff_font_create_cid_fontdict (font); + + /* Create charstrings */ + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { + charstring = _cairo_array_index(&type2_subset->charstrings, i); + + status = cff_index_append (&font->charstrings_subset_index, + _cairo_array_index (charstring, 0), + _cairo_array_num_elements (charstring)); + + if (status) + return status; + } + + status = cairo_cff_font_write_subset (font); + if (status) + return status; + + *data = _cairo_array_index (&font->output, 0); + *length = _cairo_array_num_elements (&font->output); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset, + const char *subset_name, + cairo_scaled_font_subset_t *font_subset) +{ + cairo_cff_font_t *font = NULL; /* squelch bogus compiler warning */ + cairo_status_t status; + const char *data = NULL; /* squelch bogus compiler warning */ + unsigned long length = 0; /* squelch bogus compiler warning */ + unsigned int i; + cairo_type2_charstrings_t type2_subset; + + status = _cairo_cff_font_fallback_create (font_subset, &font, subset_name); + if (status) + return status; + + status = _cairo_type2_charstrings_init (&type2_subset, font_subset); + if (status) + goto fail1; + + status = cairo_cff_font_fallback_generate (font, &type2_subset, &data, &length); + if (status) + goto fail1; + + cff_subset->base_font = strdup (font->font_name); + if (cff_subset->base_font == NULL) + goto fail1; + + cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs); + if (cff_subset->widths == NULL) + goto fail2; + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) + cff_subset->widths[i] = type2_subset.widths[i]; + + cff_subset->x_min = type2_subset.x_min; + cff_subset->y_min = type2_subset.y_min; + cff_subset->x_max = type2_subset.x_max; + cff_subset->y_max = type2_subset.y_max; + cff_subset->ascent = type2_subset.y_max; + cff_subset->descent = type2_subset.y_min; + + _cairo_type2_charstrings_fini (&type2_subset); + + cff_subset->data = malloc (length); + if (cff_subset->data == NULL) + goto fail3; + + memcpy (cff_subset->data, data, length); + cff_subset->data_length = length; + cff_subset->data_length = length; + + cairo_cff_font_destroy (font); + + return CAIRO_STATUS_SUCCESS; + + fail3: + free (cff_subset->widths); + fail2: + free (cff_subset->base_font); + fail1: + cairo_cff_font_destroy (font); + + return status; +} + +void +_cairo_cff_fallback_fini (cairo_cff_subset_t *subset) +{ + free (subset->base_font); + free (subset->widths); + free (subset->data); +} diff --git a/gfx/cairo/cairo/src/cairo-clip-private.h b/gfx/cairo/cairo/src/cairo-clip-private.h index 3c4ff0d4233d..e7190cf1d563 100644 --- a/gfx/cairo/cairo/src/cairo-clip-private.h +++ b/gfx/cairo/cairo/src/cairo-clip-private.h @@ -38,7 +38,7 @@ #include "cairo-path-fixed-private.h" -extern cairo_private const cairo_rectangle_list_t _cairo_rectangles_nil; +extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil; struct _cairo_clip_path { unsigned int ref_count; @@ -72,7 +72,8 @@ struct _cairo_clip { /* * A clip region that can be placed in the surface */ - pixman_region16_t *region; + pixman_region16_t region; + cairo_bool_t has_region; /* * If the surface supports path clipping, we store the list of * clipping paths that has been set here as a linked list. @@ -83,18 +84,15 @@ struct _cairo_clip { cairo_private void _cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target); -cairo_private void -_cairo_clip_fini (cairo_clip_t *clip); - -cairo_private void +cairo_private cairo_status_t _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other); -cairo_private void +cairo_private cairo_status_t _cairo_clip_init_deep_copy (cairo_clip_t *clip, cairo_clip_t *other, cairo_surface_t *target); -cairo_private cairo_status_t +cairo_private void _cairo_clip_reset (cairo_clip_t *clip); cairo_private cairo_status_t diff --git a/gfx/cairo/cairo/src/cairo-clip.c b/gfx/cairo/cairo/src/cairo-clip.c index efecd89efd2f..60f2418ffe43 100644 --- a/gfx/cairo/cairo/src/cairo-clip.c +++ b/gfx/cairo/cairo/src/cairo-clip.c @@ -61,28 +61,13 @@ _cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target) clip->serial = 0; - clip->region = NULL; + pixman_region_init (&clip->region); + clip->has_region = FALSE; clip->path = NULL; } -void -_cairo_clip_fini (cairo_clip_t *clip) -{ - cairo_surface_destroy (clip->surface); - clip->surface = NULL; - - clip->serial = 0; - - if (clip->region) - pixman_region_destroy (clip->region); - clip->region = NULL; - - _cairo_clip_path_destroy (clip->path); - clip->path = NULL; -} - -void +cairo_status_t _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other) { clip->mode = other->mode; @@ -92,17 +77,26 @@ _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other) clip->serial = other->serial; - if (other->region == NULL) { - clip->region = other->region; + pixman_region_init (&clip->region); + + if (other->has_region) { + if (pixman_region_copy (&clip->region, &other->region) != + PIXMAN_REGION_STATUS_SUCCESS) { + pixman_region_fini (&clip->region); + cairo_surface_destroy (clip->surface); + return CAIRO_STATUS_NO_MEMORY; + } + clip->has_region = TRUE; } else { - clip->region = pixman_region_create (); - pixman_region_copy (clip->region, other->region); + clip->has_region = FALSE; } clip->path = _cairo_clip_path_reference (other->path); + + return CAIRO_STATUS_SUCCESS; } -cairo_status_t +void _cairo_clip_reset (cairo_clip_t *clip) { /* destroy any existing clip-region artifacts */ @@ -111,14 +105,18 @@ _cairo_clip_reset (cairo_clip_t *clip) clip->serial = 0; - if (clip->region) - pixman_region_destroy (clip->region); - clip->region = NULL; + if (clip->has_region) { + /* pixman_region_fini just releases the resources used but + * doesn't bother with leaving the region in a valid state. + * So pixman_region_init has to be called afterwards. */ + pixman_region_fini (&clip->region); + pixman_region_init (&clip->region); + + clip->has_region = FALSE; + } _cairo_clip_path_destroy (clip->path); clip->path = NULL; - - return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -170,27 +168,26 @@ _cairo_clip_intersect_to_rectangle (cairo_clip_t *clip, return status; } - if (clip->region) { - pixman_region16_t *intersection; + if (clip->has_region) { cairo_status_t status = CAIRO_STATUS_SUCCESS; - pixman_region_status_t pixman_status; + pixman_region16_t intersection; - intersection = _cairo_region_create_from_rectangle (rectangle); - if (intersection == NULL) - return CAIRO_STATUS_NO_MEMORY; + pixman_region_init_rect (&intersection, + rectangle->x, rectangle->y, + rectangle->width, rectangle->height); - pixman_status = pixman_region_intersect (intersection, - clip->region, - intersection); - if (pixman_status == PIXMAN_REGION_STATUS_SUCCESS) - _cairo_region_extents_rectangle (intersection, rectangle); - else + if (PIXMAN_REGION_STATUS_SUCCESS != + pixman_region_intersect (&intersection, &clip->region, + &intersection)) { status = CAIRO_STATUS_NO_MEMORY; + } else { + _cairo_region_extents_rectangle (&intersection, rectangle); + } - pixman_region_destroy (intersection); + pixman_region_fini (&intersection); - if (status) - return status; + if (status) + return status; } if (clip->surface) @@ -203,6 +200,8 @@ cairo_status_t _cairo_clip_intersect_to_region (cairo_clip_t *clip, pixman_region16_t *region) { + pixman_region_status_t pixman_status; + if (!clip) return CAIRO_STATUS_SUCCESS; @@ -210,28 +209,28 @@ _cairo_clip_intersect_to_region (cairo_clip_t *clip, /* Intersect clip path into region. */ } - if (clip->region) - pixman_region_intersect (region, clip->region, region); + if (clip->has_region) { + pixman_status = pixman_region_intersect (region, &clip->region, region); + if (pixman_status != PIXMAN_REGION_STATUS_SUCCESS) + return CAIRO_STATUS_NO_MEMORY; + } if (clip->surface) { - pixman_region16_t *clip_rect; - pixman_region_status_t pixman_status; cairo_status_t status = CAIRO_STATUS_SUCCESS; + pixman_region16_t clip_rect; - clip_rect = _cairo_region_create_from_rectangle (&clip->surface_rect); - if (clip_rect == NULL) - return CAIRO_STATUS_NO_MEMORY; + pixman_region_init_rect (&clip_rect, + clip->surface_rect.x, clip->surface_rect.y, + clip->surface_rect.width, clip->surface_rect.height); - pixman_status = pixman_region_intersect (region, - clip_rect, - region); - if (pixman_status != PIXMAN_REGION_STATUS_SUCCESS) + if (PIXMAN_REGION_STATUS_SUCCESS != + pixman_region_intersect (region, &clip_rect, region)) status = CAIRO_STATUS_NO_MEMORY; - pixman_region_destroy (clip_rect); + pixman_region_fini (&clip_rect); - if (status) - return status; + if (status) + return status; } return CAIRO_STATUS_SUCCESS; @@ -329,42 +328,47 @@ _cairo_clip_path_destroy (cairo_clip_path_t *clip_path) free (clip_path); } -static cairo_status_t +static cairo_int_status_t _cairo_clip_intersect_region (cairo_clip_t *clip, cairo_traps_t *traps, cairo_surface_t *target) { - pixman_region16_t *region; - cairo_status_t status; + pixman_region16_t region; + cairo_int_status_t status; if (clip->mode != CAIRO_CLIP_MODE_REGION) return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_traps_extract_region (traps, ®ion); + if (status) return status; - if (region == NULL) - return CAIRO_INT_STATUS_UNSUPPORTED; - status = CAIRO_STATUS_SUCCESS; - if (clip->region == NULL) { - clip->region = region; - } else { - pixman_region16_t *intersection = pixman_region_create(); - if (pixman_region_intersect (intersection, - clip->region, region) - == PIXMAN_REGION_STATUS_SUCCESS) { - pixman_region_destroy (clip->region); - clip->region = intersection; - } else { + if (!clip->has_region) { + if (pixman_region_copy (&clip->region, ®ion) == + PIXMAN_REGION_STATUS_SUCCESS) + clip->has_region = TRUE; + else status = CAIRO_STATUS_NO_MEMORY; - } - pixman_region_destroy (region); + } else { + pixman_region16_t intersection; + pixman_region_init (&intersection); + + if (PIXMAN_REGION_STATUS_SUCCESS != + pixman_region_intersect (&intersection, + &clip->region, + ®ion) || + PIXMAN_REGION_STATUS_SUCCESS != + pixman_region_copy (&clip->region, &intersection)) + status = CAIRO_STATUS_NO_MEMORY; + + pixman_region_fini (&intersection); } clip->serial = _cairo_surface_allocate_clip_serial (target); + pixman_region_fini (®ion); return status; } @@ -402,14 +406,16 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip, CAIRO_CONTENT_ALPHA, surface_rect.width, surface_rect.height, - CAIRO_COLOR_WHITE); + CAIRO_COLOR_WHITE, + NULL); if (surface->status) return CAIRO_STATUS_NO_MEMORY; /* Render the new clipping path into the new mask surface. */ _cairo_traps_translate (traps, -surface_rect.x, -surface_rect.y); - _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); + _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE, + CAIRO_CONTENT_COLOR); status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN, &pattern.base, @@ -509,8 +515,8 @@ _cairo_clip_translate (cairo_clip_t *clip, cairo_fixed_t tx, cairo_fixed_t ty) { - if (clip->region) { - pixman_region_translate (clip->region, + if (clip->has_region) { + pixman_region_translate (&clip->region, _cairo_fixed_integer_part (tx), _cairo_fixed_integer_part (ty)); } @@ -549,7 +555,7 @@ _cairo_clip_path_reapply_clip_path (cairo_clip_t *clip, clip_path->antialias); } -void +cairo_status_t _cairo_clip_init_deep_copy (cairo_clip_t *clip, cairo_clip_t *other, cairo_surface_t *target) @@ -560,18 +566,22 @@ _cairo_clip_init_deep_copy (cairo_clip_t *clip, /* We should reapply the original clip path in this case, and let * whatever the right handling is happen */ } else { - if (other->region) { - clip->region = pixman_region_create (); - pixman_region_copy (clip->region, other->region); + if (other->has_region) { + if (pixman_region_copy (&clip->region, &other->region) != + PIXMAN_REGION_STATUS_SUCCESS) + goto BAIL; + clip->has_region = TRUE; } if (other->surface) { - _cairo_surface_clone_similar (target, other->surface, + if (_cairo_surface_clone_similar (target, other->surface, other->surface_rect.x, other->surface_rect.y, other->surface_rect.width, other->surface_rect.height, - &clip->surface); + &clip->surface) != + CAIRO_STATUS_SUCCESS) + goto BAIL; clip->surface_rect = other->surface_rect; } @@ -579,6 +589,16 @@ _cairo_clip_init_deep_copy (cairo_clip_t *clip, _cairo_clip_path_reapply_clip_path (clip, other->path); } } + + return CAIRO_STATUS_SUCCESS; + +BAIL: + if (clip->has_region) + pixman_region_fini (&clip->region); + if (clip->surface) + cairo_surface_destroy (clip->surface); + + return CAIRO_STATUS_NO_MEMORY; } const cairo_rectangle_list_t _cairo_rectangles_nil = @@ -613,16 +633,16 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate) if (clip->path || clip->surface) return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable; - n_boxes = clip->region ? pixman_region_num_rects (clip->region) : 1; + n_boxes = clip->has_region ? pixman_region_num_rects (&clip->region) : 1; rectangles = malloc (sizeof (cairo_rectangle_t)*n_boxes); if (rectangles == NULL) return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; - if (clip->region) { + if (clip->has_region) { pixman_box16_t *boxes; int i; - boxes = pixman_region_rects (clip->region); + boxes = pixman_region_rects (&clip->region); for (i = 0; i < n_boxes; ++i) { if (!_cairo_clip_rect_to_user(gstate, boxes[i].x1, boxes[i].y1, boxes[i].x2 - boxes[i].x1, @@ -635,10 +655,14 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate) } } else { cairo_rectangle_int16_t extents; - _cairo_surface_get_extents (_cairo_gstate_get_target (gstate), &extents); - if (!_cairo_clip_rect_to_user(gstate, extents.x, extents.y, - extents.width, extents.height, - rectangles)) { + if (_cairo_surface_get_extents (_cairo_gstate_get_target (gstate), + &extents) != CAIRO_STATUS_SUCCESS) { + free (rectangles); + return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; + } + if (! _cairo_clip_rect_to_user(gstate, extents.x, extents.y, + extents.width, extents.height, + rectangles)) { free (rectangles); return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable; diff --git a/gfx/cairo/cairo/src/cairo-color.c b/gfx/cairo/cairo/src/cairo-color.c index ad6316e10efe..50a9a1c26d3d 100644 --- a/gfx/cairo/cairo/src/cairo-color.c +++ b/gfx/cairo/cairo/src/cairo-color.c @@ -160,3 +160,13 @@ _cairo_color_get_rgba_premultiplied (cairo_color_t *color, *blue = color->blue * color->alpha; *alpha = color->alpha; } + +cairo_bool_t +_cairo_color_equal (const cairo_color_t *color_a, + const cairo_color_t *color_b) +{ + return color_a->red_short == color_b->red_short && + color_a->green_short == color_b->green_short && + color_a->blue_short == color_b->blue_short && + color_a->alpha_short == color_b->alpha_short; +} diff --git a/gfx/cairo/cairo/src/cairo-debug.c b/gfx/cairo/cairo/src/cairo-debug.c index 7c299325f250..6a50353ca327 100644 --- a/gfx/cairo/cairo/src/cairo-debug.c +++ b/gfx/cairo/cairo/src/cairo-debug.c @@ -59,13 +59,11 @@ void cairo_debug_reset_static_data (void) { -#if CAIRO_HAS_XLIB_SURFACE - _cairo_xlib_screen_reset_static_data (); -#endif - _cairo_font_reset_static_data (); #if CAIRO_HAS_FT_FONT _cairo_ft_font_reset_static_data (); #endif + + _cairo_pattern_reset_static_data (); } diff --git a/gfx/cairo/cairo/src/cairo-deflate-stream.c b/gfx/cairo/cairo/src/cairo-deflate-stream.c index 816f5c57c758..38ce63961b9b 100644 --- a/gfx/cairo/cairo/src/cairo-deflate-stream.c +++ b/gfx/cairo/cairo/src/cairo-deflate-stream.c @@ -119,7 +119,7 @@ _cairo_deflate_stream_create (cairo_output_stream_t *output) stream = malloc (sizeof (cairo_deflate_stream_t)); if (stream == NULL) - return (cairo_output_stream_t *) &cairo_output_stream_nil; + return (cairo_output_stream_t *) &_cairo_output_stream_nil; _cairo_output_stream_init (&stream->base, _cairo_deflate_stream_write, @@ -130,8 +130,10 @@ _cairo_deflate_stream_create (cairo_output_stream_t *output) stream->zlib_stream.zfree = Z_NULL; stream->zlib_stream.opaque = Z_NULL; - if (deflateInit (&stream->zlib_stream, Z_DEFAULT_COMPRESSION) != Z_OK) - return (cairo_output_stream_t *) &cairo_output_stream_nil; + if (deflateInit (&stream->zlib_stream, Z_DEFAULT_COMPRESSION) != Z_OK) { + free (stream); + return (cairo_output_stream_t *) &_cairo_output_stream_nil; + } stream->zlib_stream.next_in = stream->input_buf; stream->zlib_stream.avail_in = 0; diff --git a/gfx/cairo/cairo/src/cairo-directfb-surface.c b/gfx/cairo/cairo/src/cairo-directfb-surface.c index 686510d61ed0..3dc386382faf 100644 --- a/gfx/cairo/cairo/src/cairo-directfb-surface.c +++ b/gfx/cairo/cairo/src/cairo-directfb-surface.c @@ -35,10 +35,9 @@ * Claudio Ciccani */ -#include -#include -#include -#include +#include "cairoint.h" + +#include "cairo-directfb.h" #include @@ -47,9 +46,6 @@ #include #include -#include "cairo-directfb.h" -#include "cairoint.h" - /* * Rectangle causes problems (see bugs 361377, 359553, 359243 in Gnome BTS). @@ -337,7 +333,7 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface, cairo_format_t cairo_format; cairo_format = surface->format; - if (surface->format == -1) { + if (surface->format == (cairo_format_t) -1) { if( intrest_rec ) { source_rect.x = intrest_rec->x; source_rect.y = intrest_rec->y; @@ -1515,6 +1511,17 @@ _cairo_directfb_surface_show_glyphs ( void *abstract_dst, #endif /* DFB_SHOW_GLYPHS */ +static cairo_bool_t +_cairo_directfb_surface_is_similar (void *surface_a, + void *surface_b, + cairo_content_t content) +{ + cairo_directfb_surface_t *a = (cairo_directfb_surface_t *) surface_a; + cairo_directfb_surface_t *b = (cairo_directfb_surface_t *) surface_b; + + return a->dfb == b->dfb; +} + static cairo_surface_backend_t cairo_directfb_surface_backend = { CAIRO_SURFACE_TYPE_DIRECTFB, /*type*/ _cairo_directfb_surface_create_similar,/*create_similar*/ @@ -1564,7 +1571,9 @@ static cairo_surface_backend_t cairo_directfb_surface_backend = { #else NULL, /* show_glyphs */ #endif - NULL /* snapshot */ + NULL, /* snapshot */ + _cairo_directfb_is_similar, + NULL /* reset */ }; diff --git a/gfx/cairo/cairo/src/cairo-directfb.h b/gfx/cairo/cairo/src/cairo-directfb.h index 795a0dc167bc..5b35a443d58d 100644 --- a/gfx/cairo/cairo/src/cairo-directfb.h +++ b/gfx/cairo/cairo/src/cairo-directfb.h @@ -41,6 +41,8 @@ #ifdef CAIRO_HAS_DIRECTFB_SURFACE +#include + CAIRO_BEGIN_DECLS cairo_public cairo_surface_t * diff --git a/gfx/cairo/cairo/src/cairo-font-face.c b/gfx/cairo/cairo/src/cairo-font-face.c new file mode 100644 index 000000000000..3b6dab3b6a53 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-font-face.c @@ -0,0 +1,519 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Graydon Hoare + * Owen Taylor + */ + +#include "cairoint.h" + +/* Forward declare so we can use it as an arbitrary backend for + * _cairo_font_face_nil. + */ +static const cairo_font_face_backend_t _cairo_toy_font_face_backend; + +/* cairo_font_face_t */ + +const cairo_font_face_t _cairo_font_face_nil = { + { 0 }, /* hash_entry */ + CAIRO_STATUS_NO_MEMORY, /* status */ + CAIRO_REF_COUNT_INVALID, /* ref_count */ + { 0, 0, 0, NULL }, /* user_data */ + &_cairo_toy_font_face_backend +}; + +void +_cairo_font_face_init (cairo_font_face_t *font_face, + const cairo_font_face_backend_t *backend) +{ + CAIRO_MUTEX_INITIALIZE (); + + font_face->status = CAIRO_STATUS_SUCCESS; + font_face->ref_count = 1; + font_face->backend = backend; + + _cairo_user_data_array_init (&font_face->user_data); +} + +/** + * cairo_font_face_reference: + * @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 || font_face->ref_count == CAIRO_REF_COUNT_INVALID) + return font_face; + + CAIRO_MUTEX_LOCK (_cairo_font_face_mutex); + + /* We would normally assert (font_face->ref_count >0) here but we + * can't get away with that due to the zombie case as documented + * in _cairo_ft_font_face_destroy. */ + + font_face->ref_count++; + + CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex); + + return font_face; +} +slim_hidden_def (cairo_font_face_reference); + +/** + * cairo_font_face_destroy: + * @font_face: a #cairo_font_face_t + * + * Decreases the reference count on @font_face by one. If the result + * is zero, then @font_face and all associated resources are freed. + * See cairo_font_face_reference(). + **/ +void +cairo_font_face_destroy (cairo_font_face_t *font_face) +{ + if (font_face == NULL || 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) { + CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex); + return; + } + + CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex); + + font_face->backend->destroy (font_face); + + /* We allow resurrection to deal with some memory management for the + * FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t + * need to effectively mutually reference each other + */ + if (font_face->ref_count > 0) + return; + + _cairo_user_data_array_fini (&font_face->user_data); + + free (font_face); +} +slim_hidden_def (cairo_font_face_destroy); + +/** + * cairo_font_face_get_type: + * @font_face: a font face + * + * This function returns the type of the backend used to create + * a font face. See #cairo_font_type_t for available types. + * + * Return value: The type of @font_face. + * + * Since: 1.2 + **/ +cairo_font_type_t +cairo_font_face_get_type (cairo_font_face_t *font_face) +{ + return font_face->backend->type; +} + +/** + * cairo_font_face_get_reference_count: + * @font_face: a #cairo_font_face_t + * + * Returns the current reference count of @font_face. + * + * Return value: the current reference count of @font_face. If the + * object is a nil object, 0 will be returned. + * + * Since: 1.4 + **/ +unsigned int +cairo_font_face_get_reference_count (cairo_font_face_t *font_face) +{ + if (font_face == NULL || font_face->ref_count == CAIRO_REF_COUNT_INVALID) + return 0; + + return font_face->ref_count; +} + +/** + * cairo_font_face_status: + * @font_face: a #cairo_font_face_t + * + * Checks whether an error has previously occurred for this + * font face + * + * Return value: %CAIRO_STATUS_SUCCESS or another error such as + * %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_status_t +cairo_font_face_status (cairo_font_face_t *font_face) +{ + return font_face->status; +} + +/** + * cairo_font_face_get_user_data: + * @font_face: a #cairo_font_face_t + * @key: the address of the #cairo_user_data_key_t the user data was + * attached to + * + * Return user data previously attached to @font_face 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. + **/ +void * +cairo_font_face_get_user_data (cairo_font_face_t *font_face, + const cairo_user_data_key_t *key) +{ + return _cairo_user_data_array_get_data (&font_face->user_data, + key); +} + +/** + * cairo_font_face_set_user_data: + * @font_face: a #cairo_font_face_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 font face + * @destroy: a #cairo_destroy_func_t which will be called when the + * font face is destroyed or when new user data is attached using the + * same key. + * + * Attach user data to @font_face. To remove user data from a font face, + * 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. + **/ +cairo_status_t +cairo_font_face_set_user_data (cairo_font_face_t *font_face, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy) +{ + if (font_face->ref_count == CAIRO_REF_COUNT_INVALID) + return CAIRO_STATUS_NO_MEMORY; + + return _cairo_user_data_array_set_data (&font_face->user_data, + key, user_data, destroy); +} + +static const cairo_font_face_backend_t _cairo_toy_font_face_backend; + +static int +_cairo_toy_font_face_keys_equal (const void *key_a, + const void *key_b); + +/* We maintain a hash table from family/weight/slant => + * cairo_font_face_t for cairo_toy_font_t. The primary purpose of + * this mapping is to provide unique cairo_font_face_t values so that + * our cache and mapping from cairo_font_face_t => cairo_scaled_font_t + * works. Once the corresponding cairo_font_face_t objects fall out of + * downstream caches, we don't need them in this hash table anymore. + * + * Modifications to this hash table are protected by + * _cairo_font_face_mutex. + */ +static cairo_hash_table_t *cairo_toy_font_face_hash_table = NULL; + +static cairo_hash_table_t * +_cairo_toy_font_face_hash_table_lock (void) +{ + CAIRO_MUTEX_LOCK (_cairo_font_face_mutex); + + if (cairo_toy_font_face_hash_table == NULL) + { + cairo_toy_font_face_hash_table = + _cairo_hash_table_create (_cairo_toy_font_face_keys_equal); + + if (cairo_toy_font_face_hash_table == NULL) { + CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex); + return NULL; + } + } + + return cairo_toy_font_face_hash_table; +} + +static void +_cairo_toy_font_face_hash_table_unlock (void) +{ + CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex); +} + +/** + * _cairo_toy_font_face_init_key: + * + * Initialize those portions of cairo_toy_font_face_t needed to use + * it as a hash table key, including the hash code buried away in + * font_face->base.hash_entry. No memory allocation is performed here + * so that no fini call is needed. We do this to make it easier to use + * an automatic cairo_toy_font_face_t variable as a key. + **/ +static void +_cairo_toy_font_face_init_key (cairo_toy_font_face_t *key, + const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight) +{ + unsigned long hash; + + key->family = family; + key->owns_family = FALSE; + + key->slant = slant; + key->weight = weight; + + /* 1607 and 1451 are just a couple of arbitrary primes. */ + hash = _cairo_hash_string (family); + hash += ((unsigned long) slant) * 1607; + hash += ((unsigned long) weight) * 1451; + + key->base.hash_entry.hash = hash; +} + +static cairo_status_t +_cairo_toy_font_face_init (cairo_toy_font_face_t *font_face, + const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight) +{ + char *family_copy; + + family_copy = strdup (family); + if (family_copy == NULL) + return CAIRO_STATUS_NO_MEMORY; + + _cairo_toy_font_face_init_key (font_face, family_copy, + slant, weight); + font_face->owns_family = TRUE; + + _cairo_font_face_init (&font_face->base, &_cairo_toy_font_face_backend); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_toy_font_face_fini (cairo_toy_font_face_t *font_face) +{ + /* We assert here that we own font_face->family before casting + * away the const qualifer. */ + assert (font_face->owns_family); + free ((char*) font_face->family); +} + +static int +_cairo_toy_font_face_keys_equal (const void *key_a, + const void *key_b) +{ + const cairo_toy_font_face_t *face_a = key_a; + const cairo_toy_font_face_t *face_b = key_b; + + return (strcmp (face_a->family, face_b->family) == 0 && + face_a->slant == face_b->slant && + face_a->weight == face_b->weight); +} + +/** + * _cairo_toy_font_face_create: + * @family: a font family name, encoded in UTF-8 + * @slant: the slant for the font + * @weight: the weight for the font + * + * Creates a font face from a triplet of family, slant, and weight. + * These font faces are used in implementation of the the #cairo_t "toy" + * font API. + * + * Return value: a newly created #cairo_font_face_t, destroy with + * cairo_font_face_destroy() + **/ +cairo_font_face_t * +_cairo_toy_font_face_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight) +{ + cairo_status_t status; + cairo_toy_font_face_t key, *font_face; + cairo_hash_table_t *hash_table; + + hash_table = _cairo_toy_font_face_hash_table_lock (); + if (hash_table == NULL) + goto UNWIND; + + _cairo_toy_font_face_init_key (&key, family, slant, weight); + + /* Return existing font_face if it exists in the hash table. */ + if (_cairo_hash_table_lookup (hash_table, + &key.base.hash_entry, + (cairo_hash_entry_t **) &font_face)) + { + /* We increment the reference count here manually to avoid + double-locking. */ + font_face->base.ref_count++; + _cairo_toy_font_face_hash_table_unlock (); + return &font_face->base; + } + + /* Otherwise create it and insert into hash table. */ + font_face = malloc (sizeof (cairo_toy_font_face_t)); + if (font_face == NULL) + goto UNWIND_HASH_TABLE_LOCK; + + status = _cairo_toy_font_face_init (font_face, family, slant, weight); + if (status) + goto UNWIND_FONT_FACE_MALLOC; + + status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry); + if (status) + goto UNWIND_FONT_FACE_INIT; + + _cairo_toy_font_face_hash_table_unlock (); + + return &font_face->base; + + UNWIND_FONT_FACE_INIT: + UNWIND_FONT_FACE_MALLOC: + free (font_face); + UNWIND_HASH_TABLE_LOCK: + _cairo_toy_font_face_hash_table_unlock (); + UNWIND: + return (cairo_font_face_t*) &_cairo_font_face_nil; +} + +static void +_cairo_toy_font_face_destroy (void *abstract_face) +{ + cairo_toy_font_face_t *font_face = abstract_face; + cairo_hash_table_t *hash_table; + + if (font_face == NULL) + return; + + hash_table = _cairo_toy_font_face_hash_table_lock (); + /* All created objects must have been mapped in the hash table. */ + assert (hash_table != NULL); + + _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry); + + _cairo_toy_font_face_hash_table_unlock (); + + _cairo_toy_font_face_fini (font_face); +} + +static cairo_status_t +_cairo_toy_font_face_scaled_font_create (void *abstract_font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font) +{ + cairo_toy_font_face_t *font_face = abstract_font_face; + const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT; + cairo_status_t status; + + status = cairo_font_options_status ((cairo_font_options_t *) options); + if (status) + return status; + + return backend->create_toy (font_face, + font_matrix, ctm, options, scaled_font); +} + +static const cairo_font_face_backend_t _cairo_toy_font_face_backend = { + CAIRO_FONT_TYPE_TOY, + _cairo_toy_font_face_destroy, + _cairo_toy_font_face_scaled_font_create +}; + +void +_cairo_unscaled_font_init (cairo_unscaled_font_t *unscaled_font, + const cairo_unscaled_font_backend_t *backend) +{ + unscaled_font->ref_count = 1; + unscaled_font->backend = backend; +} + +cairo_unscaled_font_t * +_cairo_unscaled_font_reference (cairo_unscaled_font_t *unscaled_font) +{ + if (unscaled_font == NULL) + return NULL; + + unscaled_font->ref_count++; + + return unscaled_font; +} + +void +_cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font) +{ + if (unscaled_font == NULL) + return; + + if (--(unscaled_font->ref_count) > 0) + return; + + unscaled_font->backend->destroy (unscaled_font); + + free (unscaled_font); +} + +void +_cairo_font_reset_static_data (void) +{ + _cairo_scaled_font_map_destroy (); + + /* 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_font_face_mutex); +} diff --git a/gfx/cairo/cairo/src/cairo-font-options.c b/gfx/cairo/cairo/src/cairo-font-options.c index 316299b0574f..33b021da1126 100644 --- a/gfx/cairo/cairo/src/cairo-font-options.c +++ b/gfx/cairo/cairo/src/cairo-font-options.c @@ -36,7 +36,7 @@ #include "cairoint.h" -static const cairo_font_options_t cairo_font_options_nil = { +static const cairo_font_options_t _cairo_font_options_nil = { CAIRO_ANTIALIAS_DEFAULT, CAIRO_SUBPIXEL_ORDER_DEFAULT, CAIRO_HINT_STYLE_DEFAULT, @@ -52,7 +52,7 @@ static const cairo_font_options_t cairo_font_options_nil = { void _cairo_font_options_init_default (cairo_font_options_t *options) { - if (options == (cairo_font_options_t *)&cairo_font_options_nil) + if (options == (cairo_font_options_t *)&_cairo_font_options_nil) return; options->antialias = CAIRO_ANTIALIAS_DEFAULT; @@ -89,7 +89,7 @@ cairo_font_options_create (void) cairo_font_options_t *options = malloc (sizeof (cairo_font_options_t)); if (!options) - return (cairo_font_options_t *)&cairo_font_options_nil; + return (cairo_font_options_t *)&_cairo_font_options_nil; _cairo_font_options_init_default (options); @@ -113,10 +113,14 @@ slim_hidden_def (cairo_font_options_create); cairo_font_options_t * cairo_font_options_copy (const cairo_font_options_t *original) { - cairo_font_options_t *options = malloc (sizeof (cairo_font_options_t)); + cairo_font_options_t *options; + if (original == &_cairo_font_options_nil) + return (cairo_font_options_t *)&_cairo_font_options_nil; + + options = malloc (sizeof (cairo_font_options_t)); if (!options) - return (cairo_font_options_t *)&cairo_font_options_nil; + return (cairo_font_options_t *)&_cairo_font_options_nil; _cairo_font_options_init_copy (options, original); @@ -133,7 +137,7 @@ cairo_font_options_copy (const cairo_font_options_t *original) void cairo_font_options_destroy (cairo_font_options_t *options) { - if (options == (cairo_font_options_t *)&cairo_font_options_nil) + if (options == (cairo_font_options_t *)&_cairo_font_options_nil) return; free (options); @@ -152,11 +156,12 @@ slim_hidden_def (cairo_font_options_destroy); cairo_status_t cairo_font_options_status (cairo_font_options_t *options) { - if (options == (cairo_font_options_t *)&cairo_font_options_nil) + if (options == (cairo_font_options_t *)&_cairo_font_options_nil) return CAIRO_STATUS_NO_MEMORY; else return CAIRO_STATUS_SUCCESS; } +slim_hidden_def (cairo_font_options_status); /** * cairo_font_options_merge: @@ -172,7 +177,7 @@ void cairo_font_options_merge (cairo_font_options_t *options, const cairo_font_options_t *other) { - if (options == (cairo_font_options_t *)&cairo_font_options_nil) + if (options == (cairo_font_options_t *)&_cairo_font_options_nil) return; if (other->antialias != CAIRO_ANTIALIAS_DEFAULT) @@ -240,7 +245,7 @@ void cairo_font_options_set_antialias (cairo_font_options_t *options, cairo_antialias_t antialias) { - if (options == (cairo_font_options_t *)&cairo_font_options_nil) + if (options == (cairo_font_options_t *)&_cairo_font_options_nil) return; options->antialias = antialias; @@ -276,7 +281,7 @@ void cairo_font_options_set_subpixel_order (cairo_font_options_t *options, cairo_subpixel_order_t subpixel_order) { - if (options == (cairo_font_options_t *)&cairo_font_options_nil) + if (options == (cairo_font_options_t *)&_cairo_font_options_nil) return; options->subpixel_order = subpixel_order; @@ -312,7 +317,7 @@ void cairo_font_options_set_hint_style (cairo_font_options_t *options, cairo_hint_style_t hint_style) { - if (options == (cairo_font_options_t *)&cairo_font_options_nil) + if (options == (cairo_font_options_t *)&_cairo_font_options_nil) return; options->hint_style = hint_style; @@ -348,7 +353,7 @@ void cairo_font_options_set_hint_metrics (cairo_font_options_t *options, cairo_hint_metrics_t hint_metrics) { - if (options == (cairo_font_options_t *)&cairo_font_options_nil) + if (options == (cairo_font_options_t *)&_cairo_font_options_nil) return; options->hint_metrics = hint_metrics; diff --git a/gfx/cairo/cairo/src/cairo-freelist-private.h b/gfx/cairo/cairo/src/cairo-freelist-private.h index 41855f7ebc10..7e2036c23b02 100644 --- a/gfx/cairo/cairo/src/cairo-freelist-private.h +++ b/gfx/cairo/cairo/src/cairo-freelist-private.h @@ -26,8 +26,6 @@ #include /* Opaque implementation types. */ -struct _cairo_freelist; -struct _cairo_freelist_node; typedef struct _cairo_freelist cairo_freelist_t; typedef struct _cairo_freelist_node cairo_freelist_node_t; diff --git a/gfx/cairo/cairo/src/cairo-freelist.c b/gfx/cairo/cairo/src/cairo-freelist.c index eed1934cfbb3..3887f4b5f0ea 100644 --- a/gfx/cairo/cairo/src/cairo-freelist.c +++ b/gfx/cairo/cairo/src/cairo-freelist.c @@ -19,8 +19,9 @@ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ -#include -#include + +#include "cairoint.h" + #include "cairo-freelist-private.h" void diff --git a/gfx/cairo/cairo/src/cairo-ft-font.c b/gfx/cairo/cairo/src/cairo-ft-font.c index 6174d1415c16..89bb12a44a64 100644 --- a/gfx/cairo/cairo/src/cairo-ft-font.c +++ b/gfx/cairo/cairo/src/cairo-ft-font.c @@ -37,10 +37,12 @@ * Carl Worth */ -#include +#include "cairoint.h" #include "cairo-ft-private.h" +#include + #include #include @@ -62,12 +64,6 @@ */ #define MAX_OPEN_FACES 10 -#ifndef MOZILLA_CAIRO_NOT_DEFINED -/* This is the maximum font size we allow to be passed to FT_Set_Char_Size - */ -#define MAX_FONT_SIZE 1000 -#endif /* !MOZILLA_CAIRO_NOT_DEFINED */ - /* * The simple 2x2 matrix is converted into separate scale and shape * factors so that hinting works right @@ -156,8 +152,6 @@ 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); - static void _font_map_release_face_lock_held (cairo_ft_unscaled_font_map_t *font_map, cairo_ft_unscaled_font_t *unscaled) @@ -261,6 +255,7 @@ _cairo_ft_unscaled_font_map_lock (void) if (cairo_ft_unscaled_font_map == NULL) { CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex); + _cairo_error (CAIRO_STATUS_NO_MEMORY); return NULL; } } @@ -333,14 +328,16 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, unscaled->face = NULL; filename_copy = strdup (filename); - if (filename_copy == NULL) + if (filename_copy == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_NO_MEMORY; + } _cairo_ft_unscaled_font_init_key (unscaled, filename_copy, id); } unscaled->have_scale = FALSE; - CAIRO_MUTEX_INIT (&unscaled->mutex); + CAIRO_MUTEX_INIT (unscaled->mutex); unscaled->lock_count = 0; unscaled->faces = NULL; @@ -375,7 +372,7 @@ _cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled) unscaled->filename = NULL; } - CAIRO_MUTEX_FINI (&unscaled->mutex); + CAIRO_MUTEX_FINI (unscaled->mutex); } static int @@ -419,8 +416,8 @@ _cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern) if (_cairo_hash_table_lookup (font_map->hash_table, &key.base.hash_entry, (cairo_hash_entry_t **) &unscaled)) { - _cairo_ft_unscaled_font_map_unlock (); _cairo_unscaled_font_reference (&unscaled->base); + _cairo_ft_unscaled_font_map_unlock (); return unscaled; } @@ -556,6 +553,7 @@ _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled) &face) != FT_Err_Ok) { CAIRO_MUTEX_UNLOCK (unscaled->mutex); + _cairo_error (CAIRO_STATUS_NO_MEMORY); return NULL; } @@ -614,7 +612,7 @@ _compute_transform (cairo_ft_font_transform_t *sf, /* Temporarily scales an unscaled font to the give scale. We catch * scaling to the same size, since changing a FT_Face is expensive. */ -static void +static cairo_status_t _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled, cairo_matrix_t *scale) { @@ -629,7 +627,7 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled, scale->yx == unscaled->current_scale.yx && scale->xy == unscaled->current_scale.xy && scale->yy == unscaled->current_scale.yy) - return; + return CAIRO_STATUS_SUCCESS; unscaled->have_scale = TRUE; unscaled->current_scale = *scale; @@ -658,27 +656,14 @@ _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) { - x_scale = MAX_FONT_SIZE; - } - if (y_scale > MAX_FONT_SIZE) { - y_scale = MAX_FONT_SIZE; - } - error = FT_Set_Char_Size (unscaled->face, sf.x_scale * 64.0, sf.y_scale * 64.0, 0, 0); -#else - error = FT_Set_Char_Size (unscaled->face, - x_scale * 64.0, - y_scale * 64.0, - 0, 0); -#endif /* MOZCAIRO */ - assert (error == 0); + if (error) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } } else { double min_distance = DBL_MAX; int i; @@ -707,8 +692,13 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled, error = FT_Set_Pixel_Sizes (unscaled->face, unscaled->face->available_sizes[best_i].width, unscaled->face->available_sizes[best_i].height); - assert (error == 0); + if (error) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } } + + return CAIRO_STATUS_SUCCESS; } /* Empirically-derived subpixel filtering values thanks to Keith @@ -753,8 +743,10 @@ _get_bitmap_surface (FT_Bitmap *bitmap, assert (stride == bitmap->pitch); } else { data = malloc (stride * height); - if (!data) + if (!data) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_NO_MEMORY; + } if (stride == bitmap->pitch) { memcpy (data, bitmap->buffer, stride * height); @@ -801,8 +793,10 @@ _get_bitmap_surface (FT_Bitmap *bitmap, data = bitmap->buffer; } else { data = malloc (stride * height); - if (!data) + if (!data) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_NO_MEMORY; + } memcpy (data, bitmap->buffer, stride * height); } format = CAIRO_FORMAT_A8; @@ -841,6 +835,12 @@ _get_bitmap_surface (FT_Bitmap *bitmap, stride = bitmap->pitch; stride_rgba = (width_rgba * 4 + 3) & ~3; data_rgba = calloc (1, stride_rgba * height); + if (data_rgba == NULL) { + if (own_buffer) + free (bitmap->buffer); + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } os = 1; switch (font_options->subpixel_order) { @@ -905,6 +905,9 @@ _get_bitmap_surface (FT_Bitmap *bitmap, case FT_PIXEL_MODE_GRAY4: /* These could be triggered by very rare types of TrueType fonts */ default: + if (own_buffer) + free (bitmap->buffer); + _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_NO_MEMORY; } @@ -1035,6 +1038,7 @@ _render_glyph_outline (FT_Face face, bitmap.buffer = calloc (1, stride * bitmap.rows); if (bitmap.buffer == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_NO_MEMORY; } @@ -1042,6 +1046,7 @@ _render_glyph_outline (FT_Face face, if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) { free (bitmap.buffer); + _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_NO_MEMORY; } @@ -1079,8 +1084,10 @@ _render_glyph_bitmap (FT_Face face, * we avoid the FT_LOAD_NO_RECURSE flag. */ error = FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL); - if (error) + if (error) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_NO_MEMORY; + } status = _get_bitmap_surface (&glyphslot->bitmap, FALSE, font_options, surface); if (status) @@ -1178,24 +1185,33 @@ _transform_glyph_bitmap (cairo_matrix_t * shape, /* Initialize it to empty */ - _cairo_surface_fill_rectangle (image, CAIRO_OPERATOR_CLEAR, - CAIRO_COLOR_TRANSPARENT, - 0, 0, - width, height); + status = _cairo_surface_fill_rectangle (image, CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + 0, 0, + width, height); + if (status) { + cairo_surface_destroy (image); + return status; + } /* Draw the original bitmap transformed into the new bitmap */ _cairo_pattern_init_for_surface (&pattern, &(*surface)->base); cairo_pattern_set_matrix (&pattern.base, &transformed_to_original); - _cairo_surface_composite (CAIRO_OPERATOR_OVER, - &pattern.base, NULL, image, - 0, 0, 0, 0, 0, 0, - width, - height); + status = _cairo_surface_composite (CAIRO_OPERATOR_OVER, + &pattern.base, NULL, image, + 0, 0, 0, 0, 0, 0, + width, + height); _cairo_pattern_fini (&pattern.base); + if (status) { + cairo_surface_destroy (image); + return status; + } + /* Now update the cache entry for the new bitmap, recomputing * the origin based on the final transform. */ @@ -1445,6 +1461,7 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled, FT_Face face; FT_Size_Metrics *metrics; cairo_font_extents_t fs_metrics; + cairo_status_t status; face = _cairo_ft_unscaled_font_lock_face (unscaled); if (!face) @@ -1453,6 +1470,7 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled, scaled_font = malloc (sizeof(cairo_ft_scaled_font_t)); if (scaled_font == NULL) { _cairo_ft_unscaled_font_unlock_face (unscaled); + _cairo_error (CAIRO_STATUS_NO_MEMORY); return NULL; } @@ -1465,13 +1483,26 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled, _cairo_font_options_init_copy (&scaled_font->ft_options.base, options); _cairo_ft_options_merge (&scaled_font->ft_options, &ft_options); - _cairo_scaled_font_init (&scaled_font->base, - font_face, - font_matrix, ctm, options, - &cairo_ft_scaled_font_backend); + status = _cairo_scaled_font_init (&scaled_font->base, + font_face, + font_matrix, ctm, options, + &cairo_ft_scaled_font_backend); + if (status) { + free (scaled_font); + _cairo_unscaled_font_destroy (&unscaled->base); + _cairo_ft_unscaled_font_unlock_face (unscaled); + return NULL; + } + + status = _cairo_ft_unscaled_font_set_scale (unscaled, + &scaled_font->base.scale); + if (status) { + free (scaled_font); + _cairo_unscaled_font_destroy (&unscaled->base); + _cairo_ft_unscaled_font_unlock_face (unscaled); + return NULL; + } - _cairo_ft_unscaled_font_set_scale (unscaled, - &scaled_font->base.scale); metrics = &face->size->metrics; @@ -1549,8 +1580,10 @@ _cairo_ft_scaled_font_create_toy (cairo_toy_font_face_t *toy_face, unsigned char *family = (unsigned char*) toy_face->family; pattern = FcPatternCreate (); - if (!pattern) + if (!pattern) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_NO_MEMORY; + } switch (toy_face->weight) { @@ -1620,6 +1653,7 @@ _cairo_ft_scaled_font_create_toy (cairo_toy_font_face_t *toy_face, *font = new_font; return CAIRO_STATUS_SUCCESS; } else { + _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_NO_MEMORY; } } @@ -1644,8 +1678,10 @@ _move_to (FT_Vector *to, void *closure) x = _cairo_fixed_from_26_6 (to->x); y = _cairo_fixed_from_26_6 (to->y); - _cairo_path_fixed_close_path (path); - _cairo_path_fixed_move_to (path, x, y); + if (_cairo_path_fixed_close_path (path) != CAIRO_STATUS_SUCCESS) + return 1; + if (_cairo_path_fixed_move_to (path, x, y) != CAIRO_STATUS_SUCCESS) + return 1; return 0; } @@ -1659,7 +1695,8 @@ _line_to (FT_Vector *to, void *closure) x = _cairo_fixed_from_26_6 (to->x); y = _cairo_fixed_from_26_6 (to->y); - _cairo_path_fixed_line_to (path, x, y); + if (_cairo_path_fixed_line_to (path, x, y) != CAIRO_STATUS_SUCCESS) + return 1; return 0; } @@ -1675,7 +1712,9 @@ _conic_to (FT_Vector *control, FT_Vector *to, void *closure) cairo_fixed_t x3, y3; cairo_point_t conic; - _cairo_path_fixed_get_current_point (path, &x0, &y0); + if (_cairo_path_fixed_get_current_point (path, &x0, &y0) != + CAIRO_STATUS_SUCCESS) + return 1; conic.x = _cairo_fixed_from_26_6 (control->x); conic.y = _cairo_fixed_from_26_6 (control->y); @@ -1689,10 +1728,11 @@ _conic_to (FT_Vector *control, FT_Vector *to, void *closure) x2 = x3 + 2.0/3.0 * (conic.x - x3); y2 = y3 + 2.0/3.0 * (conic.y - y3); - _cairo_path_fixed_curve_to (path, - x1, y1, - x2, y2, - x3, y3); + if (_cairo_path_fixed_curve_to (path, + x1, y1, + x2, y2, + x3, y3) != CAIRO_STATUS_SUCCESS) + return 1; return 0; } @@ -1715,10 +1755,11 @@ _cubic_to (FT_Vector *control1, FT_Vector *control2, x2 = _cairo_fixed_from_26_6 (to->x); y2 = _cairo_fixed_from_26_6 (to->y); - _cairo_path_fixed_curve_to (path, - x0, y0, - x1, y1, - x2, y2); + if (_cairo_path_fixed_curve_to (path, + x0, y0, + x1, y1, + x2, y2) != CAIRO_STATUS_SUCCESS) + return 1; return 0; } @@ -1743,6 +1784,7 @@ _decompose_glyph_outline (FT_Face face, FT_GlyphSlot glyph; cairo_path_fixed_t *path; + cairo_status_t status; path = _cairo_path_fixed_create (); if (!path) @@ -1752,9 +1794,17 @@ _decompose_glyph_outline (FT_Face face, /* Font glyphs have an inverted Y axis compared to cairo. */ FT_Outline_Transform (&glyph->outline, &invert_y); - FT_Outline_Decompose (&glyph->outline, &outline_funcs, path); + if (FT_Outline_Decompose (&glyph->outline, &outline_funcs, path)) { + _cairo_path_fixed_destroy (path); + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } - _cairo_path_fixed_close_path (path); + status = _cairo_path_fixed_close_path (path); + if (status) { + _cairo_path_fixed_destroy (path); + return status; + } *pathp = path; @@ -1798,14 +1848,16 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, FT_Glyph_Metrics *metrics; double x_factor, y_factor; cairo_bool_t vertical_layout = FALSE; - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_status_t status; 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); + status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, + &scaled_font->base.scale); + if (status) + goto FAIL; /* Ignore global advance unconditionally */ load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; @@ -1951,9 +2003,12 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, } else { status = _render_glyph_bitmap (face, &scaled_font->ft_options.base, &surface); - if (status == CAIRO_STATUS_SUCCESS && unscaled->have_shape) + if (status == CAIRO_STATUS_SUCCESS && unscaled->have_shape) { status = _transform_glyph_bitmap (&unscaled->current_shape, &surface); + if (status) + cairo_surface_destroy (&surface->base); + } } if (status) goto FAIL; @@ -1977,6 +2032,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, if (error) { _cairo_ft_unscaled_font_unlock_face (unscaled); + _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_NO_MEMORY; } #if HAVE_FT_GLYPHSLOT_EMBOLDEN @@ -2186,10 +2242,12 @@ _cairo_ft_font_face_scaled_font_create (void *abstract_face, &font_face->base, font_matrix, ctm, options, ft_options); - if (*scaled_font) + if (*scaled_font) { return CAIRO_STATUS_SUCCESS; - else + } else { + _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_NO_MEMORY; + } } static const cairo_font_face_backend_t _cairo_ft_font_face_backend = { @@ -2202,23 +2260,32 @@ static cairo_font_face_t * _cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled, cairo_ft_options_t *ft_options) { - cairo_ft_font_face_t *font_face; + cairo_ft_font_face_t *font_face, **prev_font_face; /* Looked for an existing matching font face */ - for (font_face = unscaled->faces; + for (font_face = unscaled->faces, prev_font_face = &unscaled->faces; font_face; - font_face = font_face->next) + prev_font_face = &font_face->next, font_face = font_face->next) { if (font_face->ft_options.load_flags == ft_options->load_flags && font_face->ft_options.extra_flags == ft_options->extra_flags && cairo_font_options_equal (&font_face->ft_options.base, &ft_options->base)) - return cairo_font_face_reference (&font_face->base); + { + if (! font_face->base.status) + return cairo_font_face_reference (&font_face->base); + + /* The font_face has been left in an error state, abandon it. */ + *prev_font_face = font_face->next; + break; + } } /* No match found, create a new one */ font_face = malloc (sizeof (cairo_ft_font_face_t)); - if (!font_face) + if (!font_face) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); return NULL; + } font_face->unscaled = unscaled; _cairo_unscaled_font_reference (&unscaled->base); @@ -2376,10 +2443,8 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern) if (font_face) return font_face; - else { - _cairo_error (CAIRO_STATUS_NO_MEMORY); + else return (cairo_font_face_t *)&_cairo_font_face_nil; - } } /** @@ -2429,12 +2494,10 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face, font_face = _cairo_ft_font_face_create (unscaled, &ft_options); _cairo_unscaled_font_destroy (&unscaled->base); - if (font_face) { + if (font_face) return font_face; - } else { - _cairo_error (CAIRO_STATUS_NO_MEMORY); + else return (cairo_font_face_t *)&_cairo_font_face_nil; - } } /** @@ -2472,6 +2535,7 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font) { cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font; FT_Face face; + cairo_status_t status; if (scaled_font->base.status) return NULL; @@ -2482,8 +2546,13 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font) return NULL; } - _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, - &scaled_font->base.scale); + status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, + &scaled_font->base.scale); + if (status) { + _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled); + _cairo_scaled_font_set_error (&scaled_font->base, status); + return NULL; + } /* NOTE: We deliberately release the unscaled font's mutex here, * so that we are not holding a lock across two separate calls to diff --git a/gfx/cairo/cairo/src/cairo-ft-font.c.orig b/gfx/cairo/cairo/src/cairo-ft-font.c.orig new file mode 100644 index 000000000000..89bb12a44a64 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-ft-font.c.orig @@ -0,0 +1,2624 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2000 Keith Packard + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Graydon Hoare + * Owen Taylor + * Keith Packard + * Carl Worth + */ + +#include "cairoint.h" + +#include "cairo-ft-private.h" + +#include + +#include +#include + +#include +#include FT_FREETYPE_H +#include FT_OUTLINE_H +#include FT_IMAGE_H +#include FT_TRUETYPE_TABLES_H +#if HAVE_FT_GLYPHSLOT_EMBOLDEN +#include FT_SYNTHESIS_H +#endif + +#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0)) +#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0) +#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) +#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) + +/* This is the max number of FT_face objects we keep open at once + */ +#define MAX_OPEN_FACES 10 + +/* + * The simple 2x2 matrix is converted into separate scale and shape + * factors so that hinting works right + */ + +typedef struct _cairo_ft_font_transform { + double x_scale, y_scale; + double shape[2][2]; +} cairo_ft_font_transform_t; + +/* + * We create an object that corresponds to a single font on the disk; + * (identified by a filename/id pair) these are shared between all + * fonts using that file. For cairo_ft_font_face_create_for_ft_face(), we + * just create a one-off version with a permanent face value. + */ + +typedef struct _cairo_ft_font_face cairo_ft_font_face_t; + +struct _cairo_ft_unscaled_font { + cairo_unscaled_font_t base; + + cairo_bool_t from_face; /* from cairo_ft_font_face_create_for_ft_face()? */ + FT_Face face; /* provided or cached face */ + + /* only set if from_face is false */ + char *filename; + int id; + + /* We temporarily scale the unscaled font as needed */ + cairo_bool_t have_scale; + cairo_matrix_t current_scale; + double x_scale; /* Extracted X scale factor */ + double y_scale; /* Extracted Y scale factor */ + cairo_bool_t have_shape; /* true if the current scale has a non-scale component*/ + cairo_matrix_t current_shape; + FT_Matrix Current_Shape; + + cairo_mutex_t mutex; + int lock_count; + + cairo_ft_font_face_t *faces; /* Linked list of faces for this font */ +}; + +static int +_cairo_ft_unscaled_font_keys_equal (const void *key_a, + const void *key_b); + +static void +_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled); + +typedef enum _cairo_ft_extra_flags { + CAIRO_FT_OPTIONS_HINT_METRICS = (1 << 0), + CAIRO_FT_OPTIONS_EMBOLDEN = (1 << 1) +} cairo_ft_extra_flags_t; + +typedef struct _cairo_ft_options { + cairo_font_options_t base; + int load_flags; /* flags for FT_Load_Glyph */ + cairo_ft_extra_flags_t extra_flags; /* other flags that affect results */ +} cairo_ft_options_t; + +struct _cairo_ft_font_face { + cairo_font_face_t base; + cairo_ft_unscaled_font_t *unscaled; + cairo_ft_options_t ft_options; + cairo_ft_font_face_t *next; +}; + +static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend; + +/* + * We maintain a hash table to map file/id => cairo_ft_unscaled_font_t. + * The hash table itself isn't limited in size. However, we limit the + * number of FT_Face objects we keep around; when we've exceeded that + * limit and need to create a new FT_Face, we dump the FT_Face from a + * random cairo_ft_unscaled_font_t which has an unlocked FT_Face, (if + * there are any). + */ + +typedef struct _cairo_ft_unscaled_font_map { + cairo_hash_table_t *hash_table; + FT_Library ft_library; + int num_open_faces; +} cairo_ft_unscaled_font_map_t; + +static cairo_ft_unscaled_font_map_t *cairo_ft_unscaled_font_map = NULL; + +static void +_font_map_release_face_lock_held (cairo_ft_unscaled_font_map_t *font_map, + cairo_ft_unscaled_font_t *unscaled) +{ + if (unscaled->face) { + FT_Done_Face (unscaled->face); + unscaled->face = NULL; + unscaled->have_scale = FALSE; + + font_map->num_open_faces--; + } +} + +static void +_cairo_ft_unscaled_font_map_create (void) +{ + cairo_ft_unscaled_font_map_t *font_map; + + /* This function is only intended to be called from + * _cairo_ft_unscaled_font_map_lock. So we'll crash if we can + * detect some other call path. */ + assert (cairo_ft_unscaled_font_map == NULL); + + font_map = malloc (sizeof (cairo_ft_unscaled_font_map_t)); + if (font_map == NULL) + goto FAIL; + + font_map->hash_table = + _cairo_hash_table_create (_cairo_ft_unscaled_font_keys_equal); + + if (font_map->hash_table == NULL) + goto FAIL; + + if (FT_Init_FreeType (&font_map->ft_library)) + goto FAIL; + + font_map->num_open_faces = 0; + + cairo_ft_unscaled_font_map = font_map; + return; + +FAIL: + if (font_map) { + if (font_map->hash_table) + _cairo_hash_table_destroy (font_map->hash_table); + free (font_map); + } + cairo_ft_unscaled_font_map = NULL; +} + +static void +_cairo_ft_unscaled_font_map_destroy (void) +{ + cairo_ft_unscaled_font_t *unscaled; + cairo_ft_unscaled_font_map_t *font_map; + + CAIRO_MUTEX_LOCK (_cairo_ft_unscaled_font_map_mutex); + + if (cairo_ft_unscaled_font_map) { + font_map = cairo_ft_unscaled_font_map; + + /* This is rather inefficient, but destroying the hash table + * is something we only do during debugging, (during + * cairo_debug_reset_static_data), when efficiency is not + * relevant. */ + while (1) { + unscaled = _cairo_hash_table_random_entry (font_map->hash_table, + NULL); + if (unscaled == NULL) + break; + _cairo_hash_table_remove (font_map->hash_table, + &unscaled->base.hash_entry); + + _font_map_release_face_lock_held (font_map, unscaled); + _cairo_ft_unscaled_font_fini (unscaled); + free (unscaled); + } + + assert (font_map->num_open_faces == 0); + + FT_Done_FreeType (font_map->ft_library); + + _cairo_hash_table_destroy (font_map->hash_table); + + free (font_map); + + cairo_ft_unscaled_font_map = NULL; + } + + CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex); +} + +static cairo_ft_unscaled_font_map_t * +_cairo_ft_unscaled_font_map_lock (void) +{ + 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_error (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + } + + return cairo_ft_unscaled_font_map; +} + +static void +_cairo_ft_unscaled_font_map_unlock (void) +{ + CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex); +} + +static void +_cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key, + char *filename, + int id) +{ + unsigned long hash; + + key->filename = filename; + key->id = id; + + /* 1607 is just an arbitrary prime. */ + hash = _cairo_hash_string (filename); + hash += ((unsigned long) id) * 1607; + + key->base.hash_entry.hash = hash; +} + +/** + * _cairo_ft_unscaled_font_init: + * + * Initialize a cairo_ft_unscaled_font_t. + * + * There are two basic flavors of cairo_ft_unscaled_font_t, one + * created from an FT_Face and the other created from a filename/id + * pair. These two flavors are identified as from_face and !from_face. + * + * To initialize a from_face font, pass filename==NULL, id=0 and the + * desired face. + * + * To initialize a !from_face font, pass the filename/id as desired + * and face==NULL. + * + * Note that the code handles these two flavors in very distinct + * ways. For example there is a hash_table mapping + * filename/id->cairo_unscaled_font_t in the !from_face case, but no + * parallel in the from_face case, (where the calling code would have + * to do its own mapping to ensure similar sharing). + **/ +static cairo_status_t +_cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, + const char *filename, + int id, + FT_Face face) +{ + _cairo_unscaled_font_init (&unscaled->base, + &cairo_ft_unscaled_font_backend); + + if (face) { + unscaled->from_face = TRUE; + unscaled->face = face; + unscaled->filename = NULL; + unscaled->id = 0; + } else { + char *filename_copy; + + unscaled->from_face = FALSE; + unscaled->face = NULL; + + filename_copy = strdup (filename); + if (filename_copy == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + + _cairo_ft_unscaled_font_init_key (unscaled, filename_copy, id); + } + + unscaled->have_scale = FALSE; + CAIRO_MUTEX_INIT (unscaled->mutex); + unscaled->lock_count = 0; + + unscaled->faces = NULL; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_bool_t +_cairo_unscaled_font_is_ft (cairo_unscaled_font_t *unscaled_font) +{ + return unscaled_font->backend == &cairo_ft_unscaled_font_backend; +} + +/** + * _cairo_ft_unscaled_font_fini: + * + * Free all data associated with a cairo_ft_unscaled_font_t. + * + * CAUTION: The unscaled->face field must be NULL before calling this + * function. This is because the cairo_ft_unscaled_font_map keeps a + * count of these faces (font_map->num_open_faces) so it maintains the + * unscaled->face field while it has its lock held. See + * _font_map_release_face_lock_held(). + **/ +static void +_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled) +{ + assert (unscaled->face == NULL); + + if (unscaled->filename) { + free (unscaled->filename); + unscaled->filename = NULL; + } + + CAIRO_MUTEX_FINI (unscaled->mutex); +} + +static int +_cairo_ft_unscaled_font_keys_equal (const void *key_a, + const void *key_b) +{ + const cairo_ft_unscaled_font_t *unscaled_a = key_a; + const cairo_ft_unscaled_font_t *unscaled_b = key_b; + + return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0 && + unscaled_a->id == unscaled_b->id); +} + +/* Finds or creates a cairo_ft_unscaled_font for the filename/id from + * pattern. Returns a new reference to the unscaled font. + */ +static cairo_ft_unscaled_font_t * +_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern) +{ + cairo_ft_unscaled_font_t key, *unscaled; + cairo_ft_unscaled_font_map_t *font_map; + cairo_status_t status; + FcChar8 *fc_filename; + char *filename; + int id; + + if (FcPatternGetString (pattern, FC_FILE, 0, &fc_filename) != FcResultMatch) + goto UNWIND; + filename = (char *) fc_filename; + + if (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch) + goto UNWIND; + + font_map = _cairo_ft_unscaled_font_map_lock (); + if (font_map == NULL) + goto UNWIND; + + _cairo_ft_unscaled_font_init_key (&key, filename, id); + + /* Return existing unscaled font if it exists in the hash table. */ + if (_cairo_hash_table_lookup (font_map->hash_table, &key.base.hash_entry, + (cairo_hash_entry_t **) &unscaled)) + { + _cairo_unscaled_font_reference (&unscaled->base); + _cairo_ft_unscaled_font_map_unlock (); + return unscaled; + } + + /* Otherwise create it and insert into hash table. */ + unscaled = malloc (sizeof (cairo_ft_unscaled_font_t)); + if (unscaled == NULL) + goto UNWIND_FONT_MAP_LOCK; + + status = _cairo_ft_unscaled_font_init (unscaled, filename, id, NULL); + if (status) + goto UNWIND_UNSCALED_MALLOC; + + status = _cairo_hash_table_insert (font_map->hash_table, + &unscaled->base.hash_entry); + if (status) + goto UNWIND_UNSCALED_FONT_INIT; + + _cairo_ft_unscaled_font_map_unlock (); + + return unscaled; + +UNWIND_UNSCALED_FONT_INIT: + _cairo_ft_unscaled_font_fini (unscaled); +UNWIND_UNSCALED_MALLOC: + free (unscaled); +UNWIND_FONT_MAP_LOCK: + _cairo_ft_unscaled_font_map_unlock (); +UNWIND: + return NULL; +} + +static cairo_ft_unscaled_font_t * +_cairo_ft_unscaled_font_create_from_face (FT_Face face) +{ + cairo_status_t status; + cairo_ft_unscaled_font_t *unscaled; + + unscaled = malloc (sizeof (cairo_ft_unscaled_font_t)); + if (unscaled == NULL) + return NULL; + + status = _cairo_ft_unscaled_font_init (unscaled, NULL, 0, face); + if (status) { + free (unscaled); + return NULL; + } + + return unscaled; +} + +static void +_cairo_ft_unscaled_font_destroy (void *abstract_font) +{ + cairo_ft_unscaled_font_t *unscaled = abstract_font; + + if (unscaled == NULL) + return; + + if (unscaled->from_face) { + /* See comments in _ft_font_face_destroy about the "zombie" state + * for a _ft_font_face. + */ + if (unscaled->faces && !unscaled->faces->unscaled) + cairo_font_face_destroy (&unscaled->faces->base); + } else { + cairo_ft_unscaled_font_map_t *font_map; + + font_map = _cairo_ft_unscaled_font_map_lock (); + /* All created objects must have been mapped in the font map. */ + assert (font_map != NULL); + + _cairo_hash_table_remove (font_map->hash_table, + &unscaled->base.hash_entry); + + _font_map_release_face_lock_held (font_map, unscaled); + _cairo_ft_unscaled_font_fini (unscaled); + + _cairo_ft_unscaled_font_map_unlock (); + } +} + +static cairo_bool_t +_has_unlocked_face (void *entry) +{ + cairo_ft_unscaled_font_t *unscaled = entry; + + return (unscaled->lock_count == 0 && unscaled->face); +} + +/* Ensures that an unscaled font has a face object. If we exceed + * MAX_OPEN_FACES, try to close some. + * + * This differs from _cairo_ft_scaled_font_lock_face in that it doesn't + * set the scale on the face, but just returns it at the last scale. + */ +FT_Face +_cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled) +{ + cairo_ft_unscaled_font_map_t *font_map; + FT_Face face = NULL; + + 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; + + 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) + { + CAIRO_MUTEX_UNLOCK (unscaled->mutex); + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + unscaled->face = face; + + font_map->num_open_faces++; + + return face; +} +slim_hidden_def (cairo_ft_scaled_font_lock_face); + +/* Unlock unscaled font locked with _cairo_ft_unscaled_font_lock_face + */ +void +_cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled) +{ + assert (unscaled->lock_count > 0); + + unscaled->lock_count--; + + CAIRO_MUTEX_UNLOCK (unscaled->mutex); +} +slim_hidden_def (cairo_ft_scaled_font_unlock_face); + +static void +_compute_transform (cairo_ft_font_transform_t *sf, + cairo_matrix_t *scale) +{ + cairo_matrix_t normalized = *scale; + double tx, ty; + + /* The font matrix has x and y "scale" components which we extract and + * use as character scale values. These influence the way freetype + * chooses hints, as well as selecting different bitmaps in + * hand-rendered fonts. We also copy the normalized matrix to + * freetype's transformation. + */ + + _cairo_matrix_compute_scale_factors (&normalized, + &sf->x_scale, &sf->y_scale, + /* XXX */ 1); + + if (sf->x_scale != 0 && sf->y_scale != 0) { + cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale); + + _cairo_matrix_get_affine (&normalized, + &sf->shape[0][0], &sf->shape[0][1], + &sf->shape[1][0], &sf->shape[1][1], + &tx, &ty); + } else { + sf->shape[0][0] = sf->shape[1][1] = 1.0; + sf->shape[0][1] = sf->shape[1][0] = 0.0; + } +} + +/* Temporarily scales an unscaled font to the give scale. We catch + * scaling to the same size, since changing a FT_Face is expensive. + */ +static cairo_status_t +_cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled, + cairo_matrix_t *scale) +{ + cairo_ft_font_transform_t sf; + FT_Matrix mat; + FT_Error error; + + assert (unscaled->face != NULL); + + if (unscaled->have_scale && + scale->xx == unscaled->current_scale.xx && + scale->yx == unscaled->current_scale.yx && + scale->xy == unscaled->current_scale.xy && + scale->yy == unscaled->current_scale.yy) + return CAIRO_STATUS_SUCCESS; + + unscaled->have_scale = TRUE; + unscaled->current_scale = *scale; + + _compute_transform (&sf, scale); + + unscaled->x_scale = sf.x_scale; + unscaled->y_scale = sf.y_scale; + + mat.xx = DOUBLE_TO_16_16(sf.shape[0][0]); + mat.yx = - DOUBLE_TO_16_16(sf.shape[0][1]); + mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0]); + mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]); + + unscaled->have_shape = (mat.xx != 0x10000 || + mat.yx != 0x00000 || + mat.xy != 0x00000 || + mat.yy != 0x10000); + + unscaled->Current_Shape = mat; + cairo_matrix_init (&unscaled->current_shape, + sf.shape[0][0], sf.shape[0][1], + sf.shape[1][0], sf.shape[1][1], + 0.0, 0.0); + + FT_Set_Transform(unscaled->face, &mat, NULL); + + if ((unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) != 0) { + error = FT_Set_Char_Size (unscaled->face, + sf.x_scale * 64.0, + sf.y_scale * 64.0, + 0, 0); + if (error) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + } else { + double min_distance = DBL_MAX; + int i; + int best_i = 0; + + for (i = 0; i < unscaled->face->num_fixed_sizes; i++) { +#if HAVE_FT_BITMAP_SIZE_Y_PPEM + double size = unscaled->face->available_sizes[i].y_ppem / 64.; +#else + double size = unscaled->face->available_sizes[i].height; +#endif + double distance = fabs (size - sf.y_scale); + + if (distance <= min_distance) { + min_distance = distance; + best_i = i; + } + } +#if HAVE_FT_BITMAP_SIZE_Y_PPEM + error = FT_Set_Char_Size (unscaled->face, + unscaled->face->available_sizes[best_i].x_ppem, + unscaled->face->available_sizes[best_i].y_ppem, + 0, 0); + if (error) +#endif + error = FT_Set_Pixel_Sizes (unscaled->face, + unscaled->face->available_sizes[best_i].width, + unscaled->face->available_sizes[best_i].height); + if (error) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +/* Empirically-derived subpixel filtering values thanks to Keith + * Packard and libXft. */ +static const int filters[3][3] = { + /* red */ +#if 0 + { 65538*4/7,65538*2/7,65538*1/7 }, + /* green */ + { 65536*1/4, 65536*2/4, 65537*1/4 }, + /* blue */ + { 65538*1/7,65538*2/7,65538*4/7 }, +#endif + { 65538*9/13,65538*3/13,65538*1/13 }, + /* green */ + { 65538*1/6, 65538*4/6, 65538*1/6 }, + /* blue */ + { 65538*1/13,65538*3/13,65538*9/13 }, +}; + +/* Fills in val->image with an image surface created from @bitmap + */ +static cairo_status_t +_get_bitmap_surface (FT_Bitmap *bitmap, + cairo_bool_t own_buffer, + cairo_font_options_t *font_options, + cairo_image_surface_t **surface) +{ + int width, height, stride; + unsigned char *data; + int format = CAIRO_FORMAT_A8; + cairo_bool_t subpixel = FALSE; + + width = bitmap->width; + height = bitmap->rows; + + switch (bitmap->pixel_mode) { + case FT_PIXEL_MODE_MONO: + stride = (((width + 31) & ~31) >> 3); + if (own_buffer) { + data = bitmap->buffer; + assert (stride == bitmap->pitch); + } else { + data = malloc (stride * height); + if (!data) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + + if (stride == bitmap->pitch) { + memcpy (data, bitmap->buffer, stride * height); + } else { + int i; + unsigned char *source, *dest; + + source = bitmap->buffer; + dest = data; + for (i = height; i; i--) { + memcpy (dest, source, bitmap->pitch); + memset (dest + bitmap->pitch, '\0', stride - bitmap->pitch); + + source += bitmap->pitch; + dest += stride; + } + } + } + +#ifndef WORDS_BIGENDIAN + { + unsigned char *d = data; + int count = stride * height; + + while (count--) { + *d = CAIRO_BITSWAP8 (*d); + d++; + } + } +#endif + format = CAIRO_FORMAT_A1; + break; + + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + case FT_PIXEL_MODE_GRAY: + switch (font_options->antialias) { + case CAIRO_ANTIALIAS_DEFAULT: + case CAIRO_ANTIALIAS_GRAY: + case CAIRO_ANTIALIAS_NONE: + default: + stride = bitmap->pitch; + if (own_buffer) { + data = bitmap->buffer; + } else { + data = malloc (stride * height); + if (!data) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + memcpy (data, bitmap->buffer, stride * height); + } + format = CAIRO_FORMAT_A8; + break; + case CAIRO_ANTIALIAS_SUBPIXEL: { + int x, y; + unsigned char *in_line, *out_line, *in; + unsigned int *out; + unsigned int red, green, blue; + int rf, gf, bf; + int s; + int o, os; + unsigned char *data_rgba; + unsigned int width_rgba, stride_rgba; + int vmul = 1; + int hmul = 1; + + switch (font_options->subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + case CAIRO_SUBPIXEL_ORDER_BGR: + default: + width /= 3; + hmul = 3; + break; + case CAIRO_SUBPIXEL_ORDER_VRGB: + case CAIRO_SUBPIXEL_ORDER_VBGR: + vmul = 3; + height /= 3; + break; + } + /* + * Filter the glyph to soften the color fringes + */ + width_rgba = width; + stride = bitmap->pitch; + stride_rgba = (width_rgba * 4 + 3) & ~3; + data_rgba = calloc (1, stride_rgba * height); + if (data_rgba == NULL) { + if (own_buffer) + free (bitmap->buffer); + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + + os = 1; + switch (font_options->subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_VRGB: + os = stride; + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + default: + rf = 0; + gf = 1; + bf = 2; + break; + case CAIRO_SUBPIXEL_ORDER_VBGR: + os = stride; + case CAIRO_SUBPIXEL_ORDER_BGR: + bf = 0; + gf = 1; + rf = 2; + break; + } + in_line = bitmap->buffer; + out_line = data_rgba; + for (y = 0; y < height; y++) + { + in = in_line; + out = (unsigned int *) out_line; + in_line += stride * vmul; + out_line += stride_rgba; + for (x = 0; x < width * hmul; x += hmul) + { + red = green = blue = 0; + o = 0; + for (s = 0; s < 3; s++) + { + red += filters[rf][s]*in[x+o]; + green += filters[gf][s]*in[x+o]; + blue += filters[bf][s]*in[x+o]; + o += os; + } + red = red / 65536; + green = green / 65536; + blue = blue / 65536; + *out++ = (green << 24) | (red << 16) | (green << 8) | blue; + } + } + + /* Images here are stored in native format. The + * backend must convert to its own format as needed + */ + + if (own_buffer) + free (bitmap->buffer); + data = data_rgba; + stride = stride_rgba; + format = CAIRO_FORMAT_ARGB32; + subpixel = TRUE; + break; + } + } + break; + case FT_PIXEL_MODE_GRAY2: + case FT_PIXEL_MODE_GRAY4: + /* These could be triggered by very rare types of TrueType fonts */ + default: + if (own_buffer) + free (bitmap->buffer); + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + + *surface = (cairo_image_surface_t *) + cairo_image_surface_create_for_data (data, + format, + width, height, stride); + if ((*surface)->base.status) { + free (data); + return CAIRO_STATUS_NO_MEMORY; + } + + if (subpixel) + pixman_image_set_component_alpha ((*surface)->pixman_image, TRUE); + + _cairo_image_surface_assume_ownership_of_data ((*surface)); + + return CAIRO_STATUS_SUCCESS; +} + +/* Converts an outline FT_GlyphSlot into an image + * + * This could go through _render_glyph_bitmap as well, letting + * FreeType convert the outline to a bitmap, but doing it ourselves + * has two minor advantages: first, we save a copy of the bitmap + * buffer: we can directly use the buffer that FreeType renders + * into. + * + * Second, it may help when we add support for subpixel + * rendering: the Xft code does it this way. (Keith thinks that + * it may also be possible to get the subpixel rendering with + * FT_Render_Glyph: something worth looking into in more detail + * when we add subpixel support. If so, we may want to eliminate + * this version of the code path entirely. + */ +static cairo_status_t +_render_glyph_outline (FT_Face face, + cairo_font_options_t *font_options, + cairo_image_surface_t **surface) +{ + FT_GlyphSlot glyphslot = face->glyph; + FT_Outline *outline = &glyphslot->outline; + FT_Bitmap bitmap; + FT_BBox cbox; + FT_Matrix matrix; + int hmul = 1; + int vmul = 1; + unsigned int width, height, stride; + cairo_bool_t subpixel = FALSE; + cairo_status_t status; + + FT_Outline_Get_CBox (outline, &cbox); + + cbox.xMin &= -64; + cbox.yMin &= -64; + cbox.xMax = (cbox.xMax + 63) & -64; + cbox.yMax = (cbox.yMax + 63) & -64; + + width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6); + height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6); + stride = (width * hmul + 3) & ~3; + + if (width * height == 0) { + cairo_format_t format; + /* Looks like fb handles zero-sized images just fine */ + switch (font_options->antialias) { + case CAIRO_ANTIALIAS_NONE: + format = CAIRO_FORMAT_A1; + break; + case CAIRO_ANTIALIAS_SUBPIXEL: + format= CAIRO_FORMAT_ARGB32; + break; + case CAIRO_ANTIALIAS_DEFAULT: + case CAIRO_ANTIALIAS_GRAY: + default: + format = CAIRO_FORMAT_A8; + break; + } + + (*surface) = (cairo_image_surface_t *) + cairo_image_surface_create_for_data (NULL, format, 0, 0, 0); + if ((*surface)->base.status) + return CAIRO_STATUS_NO_MEMORY; + } else { + + matrix.xx = matrix.yy = 0x10000L; + matrix.xy = matrix.yx = 0; + + switch (font_options->antialias) { + case CAIRO_ANTIALIAS_NONE: + bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + bitmap.num_grays = 1; + stride = ((width + 31) & -32) >> 3; + break; + case CAIRO_ANTIALIAS_DEFAULT: + case CAIRO_ANTIALIAS_GRAY: + bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap.num_grays = 256; + stride = (width + 3) & -4; + break; + case CAIRO_ANTIALIAS_SUBPIXEL: + switch (font_options->subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_RGB: + case CAIRO_SUBPIXEL_ORDER_BGR: + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + default: + matrix.xx *= 3; + hmul = 3; + subpixel = TRUE; + break; + case CAIRO_SUBPIXEL_ORDER_VRGB: + case CAIRO_SUBPIXEL_ORDER_VBGR: + matrix.yy *= 3; + vmul = 3; + subpixel = TRUE; + break; + } + FT_Outline_Transform (outline, &matrix); + + bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap.num_grays = 256; + stride = (width * hmul + 3) & -4; + } + + bitmap.pitch = stride; + bitmap.width = width * hmul; + bitmap.rows = height * vmul; + bitmap.buffer = calloc (1, stride * bitmap.rows); + + if (bitmap.buffer == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + + FT_Outline_Translate (outline, -cbox.xMin*hmul, -cbox.yMin*vmul); + + if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) { + free (bitmap.buffer); + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + + status = _get_bitmap_surface (&bitmap, TRUE, font_options, surface); + if (status) + return status; + } + + /* + * Note: the font's coordinate system is upside down from ours, so the + * Y coordinate of the control box needs to be negated. + */ + cairo_surface_set_device_offset (&(*surface)->base, + floor ((double) cbox.xMin / 64.0), + floor (-(double) cbox.yMax / 64.0)); + + return CAIRO_STATUS_SUCCESS; +} + +/* Converts a bitmap (or other) FT_GlyphSlot into an image */ +static cairo_status_t +_render_glyph_bitmap (FT_Face face, + cairo_font_options_t *font_options, + cairo_image_surface_t **surface) +{ + FT_GlyphSlot glyphslot = face->glyph; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + FT_Error error; + + /* According to the FreeType docs, glyphslot->format could be + * something other than FT_GLYPH_FORMAT_OUTLINE or + * FT_GLYPH_FORMAT_BITMAP. Calling FT_Render_Glyph gives FreeType + * the opportunity to convert such to + * bitmap. FT_GLYPH_FORMAT_COMPOSITE will not be encountered since + * we avoid the FT_LOAD_NO_RECURSE flag. + */ + error = FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL); + if (error) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + + status = _get_bitmap_surface (&glyphslot->bitmap, FALSE, font_options, surface); + if (status) + return status; + + /* + * Note: the font's coordinate system is upside down from ours, so the + * Y coordinate of the control box needs to be negated. + */ + cairo_surface_set_device_offset (&(*surface)->base, + glyphslot->bitmap_left, + -glyphslot->bitmap_top); + + return status; +} + +static cairo_status_t +_transform_glyph_bitmap (cairo_matrix_t * shape, + cairo_image_surface_t ** surface) +{ + cairo_matrix_t original_to_transformed; + cairo_matrix_t transformed_to_original; + cairo_image_surface_t *old_image; + cairo_surface_t *image; + double x[4], y[4]; + double origin_x, origin_y; + int origin_width, origin_height; + int i; + int x_min, y_min, x_max, y_max; + int width, height; + cairo_status_t status; + cairo_surface_pattern_t pattern; + + /* We want to compute a transform that takes the origin + * (device_x_offset, device_y_offset) to 0,0, then applies + * the "shape" portion of the font transform + */ + original_to_transformed = *shape; + + cairo_surface_get_device_offset (&(*surface)->base, &origin_x, &origin_y); + origin_width = cairo_image_surface_get_width (&(*surface)->base); + origin_height = cairo_image_surface_get_height (&(*surface)->base); + + cairo_matrix_translate (&original_to_transformed, + origin_x, origin_y); + + /* Find the bounding box of the original bitmap under that + * transform + */ + x[0] = 0; y[0] = 0; + x[1] = origin_width; y[1] = 0; + x[2] = origin_width; y[2] = origin_height; + x[3] = 0; y[3] = origin_height; + + for (i = 0; i < 4; i++) + cairo_matrix_transform_point (&original_to_transformed, + &x[i], &y[i]); + + x_min = floor (x[0]); y_min = floor (y[0]); + x_max = ceil (x[0]); y_max = ceil (y[0]); + + for (i = 1; i < 4; i++) { + if (x[i] < x_min) + x_min = floor (x[i]); + if (x[i] > x_max) + x_max = ceil (x[i]); + if (y[i] < y_min) + y_min = floor (y[i]); + if (y[i] > y_max) + y_max = ceil (y[i]); + } + + /* Adjust the transform so that the bounding box starts at 0,0 ... + * this gives our final transform from original bitmap to transformed + * bitmap. + */ + original_to_transformed.x0 -= x_min; + original_to_transformed.y0 -= y_min; + + /* Create the transformed bitmap + */ + width = x_max - x_min; + height = y_max - y_min; + + transformed_to_original = original_to_transformed; + status = cairo_matrix_invert (&transformed_to_original); + if (status) + return status; + + /* We need to pad out the width to 32-bit intervals for cairo-xlib-surface.c */ + width = (width + 3) & ~3; + image = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); + if (image->status) + return CAIRO_STATUS_NO_MEMORY; + + /* Initialize it to empty + */ + status = _cairo_surface_fill_rectangle (image, CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + 0, 0, + width, height); + if (status) { + cairo_surface_destroy (image); + return status; + } + + /* Draw the original bitmap transformed into the new bitmap + */ + _cairo_pattern_init_for_surface (&pattern, &(*surface)->base); + cairo_pattern_set_matrix (&pattern.base, &transformed_to_original); + + status = _cairo_surface_composite (CAIRO_OPERATOR_OVER, + &pattern.base, NULL, image, + 0, 0, 0, 0, 0, 0, + width, + height); + + _cairo_pattern_fini (&pattern.base); + + if (status) { + cairo_surface_destroy (image); + return status; + } + + /* Now update the cache entry for the new bitmap, recomputing + * the origin based on the final transform. + */ + origin_x = - origin_x; + origin_y = - origin_y; + cairo_matrix_transform_point (&original_to_transformed, + &origin_x, &origin_y); + + old_image = (*surface); + (*surface) = (cairo_image_surface_t *)image; + cairo_surface_destroy (&old_image->base); + + cairo_surface_set_device_offset (&(*surface)->base, + - _cairo_lround (origin_x), + - _cairo_lround (origin_y)); + return status; +} + +static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend = { + _cairo_ft_unscaled_font_destroy, +#if 0 + _cairo_ft_unscaled_font_create_glyph +#endif +}; + +/* cairo_ft_scaled_font_t */ + +typedef struct _cairo_ft_scaled_font { + cairo_scaled_font_t base; + cairo_ft_unscaled_font_t *unscaled; + cairo_ft_options_t ft_options; +} cairo_ft_scaled_font_t; + +const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend; + +/* The load flags passed to FT_Load_Glyph control aspects like hinting and + * antialiasing. Here we compute them from the fields of a FcPattern. + */ +static void +_get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret) +{ + FcBool antialias, vertical_layout, hinting, autohint, bitmap, embolden; + cairo_ft_options_t ft_options; + int rgba; +#ifdef FC_HINT_STYLE + int hintstyle; +#endif + + _cairo_font_options_init_default (&ft_options.base); + ft_options.load_flags = FT_LOAD_DEFAULT; + ft_options.extra_flags = 0; + +#ifndef FC_EMBEDDED_BITMAP +#define FC_EMBEDDED_BITMAP "embeddedbitmap" +#endif + + /* Check whether to force use of embedded bitmaps */ + if (FcPatternGetBool (pattern, + FC_EMBEDDED_BITMAP, 0, &bitmap) != FcResultMatch) + bitmap = FcFalse; + + /* disable antialiasing if requested */ + if (FcPatternGetBool (pattern, + FC_ANTIALIAS, 0, &antialias) != FcResultMatch) + antialias = FcTrue; + + if (antialias) { + cairo_subpixel_order_t subpixel_order; + + if (!bitmap) + ft_options.load_flags |= FT_LOAD_NO_BITMAP; + + /* disable hinting if requested */ + if (FcPatternGetBool (pattern, + FC_HINTING, 0, &hinting) != FcResultMatch) + hinting = FcTrue; + + if (FcPatternGetInteger (pattern, + FC_RGBA, 0, &rgba) != FcResultMatch) + rgba = FC_RGBA_UNKNOWN; + + switch (rgba) { + case FC_RGBA_RGB: + subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; + break; + case FC_RGBA_BGR: + subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; + break; + case FC_RGBA_VRGB: + subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; + break; + case FC_RGBA_VBGR: + subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; + break; + case FC_RGBA_UNKNOWN: + case FC_RGBA_NONE: + default: + subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; + break; + } + + if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) { + ft_options.base.subpixel_order = subpixel_order; + ft_options.base.antialias = CAIRO_ANTIALIAS_SUBPIXEL; + } + +#ifdef FC_HINT_STYLE + if (FcPatternGetInteger (pattern, + FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) + hintstyle = FC_HINT_FULL; + + if (!hinting) + hintstyle = FC_HINT_NONE; + + switch (hintstyle) { + case FC_HINT_NONE: + ft_options.base.hint_style = CAIRO_HINT_STYLE_NONE; + break; + case FC_HINT_SLIGHT: + ft_options.base.hint_style = CAIRO_HINT_STYLE_SLIGHT; + break; + case FC_HINT_MEDIUM: + default: + ft_options.base.hint_style = CAIRO_HINT_STYLE_MEDIUM; + break; + case FC_HINT_FULL: + ft_options.base.hint_style = CAIRO_HINT_STYLE_FULL; + break; + } +#else /* !FC_HINT_STYLE */ + if (!hinting) { + ft_options.base.hint_style = CAIRO_HINT_STYLE_NONE; + } +#endif /* FC_FHINT_STYLE */ + } else { + ft_options.base.antialias = CAIRO_ANTIALIAS_NONE; + } + + /* force autohinting if requested */ + if (FcPatternGetBool (pattern, + FC_AUTOHINT, 0, &autohint) != FcResultMatch) + autohint = FcFalse; + + if (autohint) + ft_options.load_flags |= FT_LOAD_FORCE_AUTOHINT; + + if (FcPatternGetBool (pattern, + FC_VERTICAL_LAYOUT, 0, &vertical_layout) != FcResultMatch) + vertical_layout = FcFalse; + + if (vertical_layout) + ft_options.load_flags |= FT_LOAD_VERTICAL_LAYOUT; + +#ifndef FC_EMBOLDEN +#define FC_EMBOLDEN "embolden" +#endif + if (FcPatternGetBool (pattern, + FC_EMBOLDEN, 0, &embolden) != FcResultMatch) + embolden = FcFalse; + + if (embolden) + ft_options.extra_flags |= CAIRO_FT_OPTIONS_EMBOLDEN; + + *ret = ft_options; +} + +static void +_cairo_ft_options_merge (cairo_ft_options_t *options, + cairo_ft_options_t *other) +{ + int load_flags = other->load_flags; + int load_target = FT_LOAD_TARGET_NORMAL; + + /* clear load target mode */ + load_flags &= ~(FT_LOAD_TARGET_(FT_LOAD_TARGET_MODE(other->load_flags))); + + if (load_flags & FT_LOAD_NO_HINTING) + other->base.hint_style = CAIRO_HINT_STYLE_NONE; + + if (other->base.antialias == CAIRO_ANTIALIAS_NONE || + options->base.antialias == CAIRO_ANTIALIAS_NONE) { + options->base.antialias = CAIRO_ANTIALIAS_NONE; + options->base.subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; + } + + if (other->base.antialias == CAIRO_ANTIALIAS_SUBPIXEL && + (options->base.antialias == CAIRO_ANTIALIAS_DEFAULT || + options->base.antialias == CAIRO_ANTIALIAS_GRAY)) { + options->base.antialias = CAIRO_ANTIALIAS_SUBPIXEL; + options->base.subpixel_order = other->base.subpixel_order; + } + + if (options->base.hint_style == CAIRO_HINT_STYLE_DEFAULT) + options->base.hint_style = other->base.hint_style; + + if (other->base.hint_style == CAIRO_HINT_STYLE_NONE) + options->base.hint_style = CAIRO_HINT_STYLE_NONE; + + if (options->base.antialias == CAIRO_ANTIALIAS_NONE) { + if (options->base.hint_style == CAIRO_HINT_STYLE_NONE) + load_flags |= FT_LOAD_NO_HINTING; + else + load_target = FT_LOAD_TARGET_MONO; + load_flags |= FT_LOAD_MONOCHROME; + } else { + switch (options->base.hint_style) { + case CAIRO_HINT_STYLE_NONE: + load_flags |= FT_LOAD_NO_HINTING; + break; + case CAIRO_HINT_STYLE_SLIGHT: + load_target = FT_LOAD_TARGET_LIGHT; + break; + case CAIRO_HINT_STYLE_MEDIUM: + break; + case CAIRO_HINT_STYLE_FULL: + case CAIRO_HINT_STYLE_DEFAULT: + if (options->base.antialias == CAIRO_ANTIALIAS_SUBPIXEL) { + switch (options->base.subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + case CAIRO_SUBPIXEL_ORDER_BGR: + load_target |= FT_LOAD_TARGET_LCD; + break; + case CAIRO_SUBPIXEL_ORDER_VRGB: + case CAIRO_SUBPIXEL_ORDER_VBGR: + load_target |= FT_LOAD_TARGET_LCD_V; + break; + } + } + break; + } + } + + options->load_flags = load_flags | load_target; + options->extra_flags = other->extra_flags; +} + +static cairo_scaled_font_t * +_cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled, + cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_ft_options_t ft_options) +{ + cairo_ft_scaled_font_t *scaled_font = NULL; + FT_Face face; + FT_Size_Metrics *metrics; + cairo_font_extents_t fs_metrics; + cairo_status_t status; + + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return NULL; + + scaled_font = malloc (sizeof(cairo_ft_scaled_font_t)); + if (scaled_font == NULL) { + _cairo_ft_unscaled_font_unlock_face (unscaled); + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + _cairo_unscaled_font_reference (&unscaled->base); + scaled_font->unscaled = unscaled; + + if (options->hint_metrics != CAIRO_HINT_METRICS_OFF) + ft_options.extra_flags |= CAIRO_FT_OPTIONS_HINT_METRICS; + + _cairo_font_options_init_copy (&scaled_font->ft_options.base, options); + _cairo_ft_options_merge (&scaled_font->ft_options, &ft_options); + + status = _cairo_scaled_font_init (&scaled_font->base, + font_face, + font_matrix, ctm, options, + &cairo_ft_scaled_font_backend); + if (status) { + free (scaled_font); + _cairo_unscaled_font_destroy (&unscaled->base); + _cairo_ft_unscaled_font_unlock_face (unscaled); + return NULL; + } + + status = _cairo_ft_unscaled_font_set_scale (unscaled, + &scaled_font->base.scale); + if (status) { + free (scaled_font); + _cairo_unscaled_font_destroy (&unscaled->base); + _cairo_ft_unscaled_font_unlock_face (unscaled); + return NULL; + } + + + metrics = &face->size->metrics; + + /* + * Get to unscaled metrics so that the upper level can get back to + * user space + */ + if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) { + double x_factor, y_factor; + + if (unscaled->x_scale == 0) + x_factor = 0; + else + x_factor = 1 / unscaled->x_scale; + + if (unscaled->y_scale == 0) + y_factor = 0; + else + y_factor = 1 / unscaled->y_scale; + + fs_metrics.ascent = DOUBLE_FROM_26_6(metrics->ascender) * y_factor; + fs_metrics.descent = DOUBLE_FROM_26_6(- metrics->descender) * y_factor; + fs_metrics.height = DOUBLE_FROM_26_6(metrics->height) * y_factor; + if (!_cairo_ft_scaled_font_is_vertical (&scaled_font->base)) { + fs_metrics.max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) * x_factor; + fs_metrics.max_y_advance = 0; + } else { + fs_metrics.max_x_advance = 0; + fs_metrics.max_y_advance = DOUBLE_FROM_26_6(metrics->max_advance) * y_factor; + } + } else { + double scale = face->units_per_EM; + + fs_metrics.ascent = face->ascender / scale; + fs_metrics.descent = - face->descender / scale; + fs_metrics.height = face->height / scale; + if (!_cairo_ft_scaled_font_is_vertical (&scaled_font->base)) { + fs_metrics.max_x_advance = face->max_advance_width / scale; + fs_metrics.max_y_advance = 0; + } else { + fs_metrics.max_x_advance = 0; + fs_metrics.max_y_advance = face->max_advance_height / scale; + } + } + + _cairo_scaled_font_set_metrics (&scaled_font->base, &fs_metrics); + + _cairo_ft_unscaled_font_unlock_face (unscaled); + + return &scaled_font->base; +} + +cairo_bool_t +_cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font) +{ + return scaled_font->backend == &cairo_ft_scaled_font_backend; +} + +static cairo_status_t +_cairo_ft_scaled_font_create_toy (cairo_toy_font_face_t *toy_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *font_options, + cairo_scaled_font_t **font) +{ + FcPattern *pattern, *resolved; + cairo_ft_unscaled_font_t *unscaled; + cairo_scaled_font_t *new_font = NULL; + FcResult result; + int fcslant; + int fcweight; + cairo_matrix_t scale; + cairo_ft_font_transform_t sf; + cairo_ft_options_t ft_options; + unsigned char *family = (unsigned char*) toy_face->family; + + pattern = FcPatternCreate (); + if (!pattern) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + + switch (toy_face->weight) + { + case CAIRO_FONT_WEIGHT_BOLD: + fcweight = FC_WEIGHT_BOLD; + break; + case CAIRO_FONT_WEIGHT_NORMAL: + default: + fcweight = FC_WEIGHT_MEDIUM; + break; + } + + switch (toy_face->slant) + { + case CAIRO_FONT_SLANT_ITALIC: + fcslant = FC_SLANT_ITALIC; + break; + case CAIRO_FONT_SLANT_OBLIQUE: + fcslant = FC_SLANT_OBLIQUE; + break; + case CAIRO_FONT_SLANT_NORMAL: + default: + fcslant = FC_SLANT_ROMAN; + break; + } + + if (!FcPatternAddString (pattern, FC_FAMILY, family)) + goto FREE_PATTERN; + if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant)) + goto FREE_PATTERN; + if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight)) + goto FREE_PATTERN; + + cairo_matrix_multiply (&scale, font_matrix, ctm); + _compute_transform (&sf, &scale); + + FcPatternAddInteger (pattern, FC_PIXEL_SIZE, sf.y_scale); + + FcConfigSubstitute (NULL, pattern, FcMatchPattern); + cairo_ft_font_options_substitute (font_options, pattern); + FcDefaultSubstitute (pattern); + + resolved = FcFontMatch (NULL, pattern, &result); + if (!resolved) + goto FREE_PATTERN; + + unscaled = _cairo_ft_unscaled_font_create_for_pattern (resolved); + if (!unscaled) + goto FREE_RESOLVED; + + _get_pattern_ft_options (resolved, &ft_options); + + new_font = _cairo_ft_scaled_font_create (unscaled, + &toy_face->base, + font_matrix, ctm, + font_options, ft_options); + + _cairo_unscaled_font_destroy (&unscaled->base); + + FREE_RESOLVED: + FcPatternDestroy (resolved); + + FREE_PATTERN: + FcPatternDestroy (pattern); + + if (new_font) { + *font = new_font; + return CAIRO_STATUS_SUCCESS; + } else { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } +} + +static void +_cairo_ft_scaled_font_fini (void *abstract_font) +{ + cairo_ft_scaled_font_t *scaled_font = abstract_font; + + if (scaled_font == NULL) + return; + + _cairo_unscaled_font_destroy (&scaled_font->unscaled->base); +} + +static int +_move_to (FT_Vector *to, void *closure) +{ + cairo_path_fixed_t *path = closure; + cairo_fixed_t x, y; + + x = _cairo_fixed_from_26_6 (to->x); + y = _cairo_fixed_from_26_6 (to->y); + + if (_cairo_path_fixed_close_path (path) != CAIRO_STATUS_SUCCESS) + return 1; + if (_cairo_path_fixed_move_to (path, x, y) != CAIRO_STATUS_SUCCESS) + return 1; + + return 0; +} + +static int +_line_to (FT_Vector *to, void *closure) +{ + cairo_path_fixed_t *path = closure; + cairo_fixed_t x, y; + + x = _cairo_fixed_from_26_6 (to->x); + y = _cairo_fixed_from_26_6 (to->y); + + if (_cairo_path_fixed_line_to (path, x, y) != CAIRO_STATUS_SUCCESS) + return 1; + + return 0; +} + +static int +_conic_to (FT_Vector *control, FT_Vector *to, void *closure) +{ + cairo_path_fixed_t *path = closure; + + cairo_fixed_t x0, y0; + cairo_fixed_t x1, y1; + cairo_fixed_t x2, y2; + cairo_fixed_t x3, y3; + cairo_point_t conic; + + if (_cairo_path_fixed_get_current_point (path, &x0, &y0) != + CAIRO_STATUS_SUCCESS) + return 1; + + conic.x = _cairo_fixed_from_26_6 (control->x); + conic.y = _cairo_fixed_from_26_6 (control->y); + + x3 = _cairo_fixed_from_26_6 (to->x); + y3 = _cairo_fixed_from_26_6 (to->y); + + x1 = x0 + 2.0/3.0 * (conic.x - x0); + y1 = y0 + 2.0/3.0 * (conic.y - y0); + + x2 = x3 + 2.0/3.0 * (conic.x - x3); + y2 = y3 + 2.0/3.0 * (conic.y - y3); + + if (_cairo_path_fixed_curve_to (path, + x1, y1, + x2, y2, + x3, y3) != CAIRO_STATUS_SUCCESS) + return 1; + + return 0; +} + +static int +_cubic_to (FT_Vector *control1, FT_Vector *control2, + FT_Vector *to, void *closure) +{ + cairo_path_fixed_t *path = closure; + cairo_fixed_t x0, y0; + cairo_fixed_t x1, y1; + cairo_fixed_t x2, y2; + + x0 = _cairo_fixed_from_26_6 (control1->x); + y0 = _cairo_fixed_from_26_6 (control1->y); + + x1 = _cairo_fixed_from_26_6 (control2->x); + y1 = _cairo_fixed_from_26_6 (control2->y); + + x2 = _cairo_fixed_from_26_6 (to->x); + y2 = _cairo_fixed_from_26_6 (to->y); + + if (_cairo_path_fixed_curve_to (path, + x0, y0, + x1, y1, + x2, y2) != CAIRO_STATUS_SUCCESS) + return 1; + + return 0; +} + +static cairo_status_t +_decompose_glyph_outline (FT_Face face, + cairo_font_options_t *options, + cairo_path_fixed_t **pathp) +{ + static const FT_Outline_Funcs outline_funcs = { + (FT_Outline_MoveToFunc)_move_to, + (FT_Outline_LineToFunc)_line_to, + (FT_Outline_ConicToFunc)_conic_to, + (FT_Outline_CubicToFunc)_cubic_to, + 0, /* shift */ + 0, /* delta */ + }; + static const FT_Matrix invert_y = { + DOUBLE_TO_16_16 (1.0), 0, + 0, DOUBLE_TO_16_16 (-1.0), + }; + + FT_GlyphSlot glyph; + cairo_path_fixed_t *path; + cairo_status_t status; + + path = _cairo_path_fixed_create (); + if (!path) + return CAIRO_STATUS_NO_MEMORY; + + glyph = face->glyph; + + /* Font glyphs have an inverted Y axis compared to cairo. */ + FT_Outline_Transform (&glyph->outline, &invert_y); + if (FT_Outline_Decompose (&glyph->outline, &outline_funcs, path)) { + _cairo_path_fixed_destroy (path); + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + + status = _cairo_path_fixed_close_path (path); + if (status) { + _cairo_path_fixed_destroy (path); + return status; + } + + *pathp = path; + + return CAIRO_STATUS_SUCCESS; +} + +/* + * Translate glyph to match its metrics. + */ +static void +_cairo_ft_scaled_glyph_vertical_layout_bearing_fix (void *abstract_font, + FT_GlyphSlot glyph) +{ + cairo_ft_scaled_font_t *scaled_font = abstract_font; + FT_Vector vector; + + vector.x = glyph->metrics.vertBearingX - glyph->metrics.horiBearingX; + vector.y = -glyph->metrics.vertBearingY - glyph->metrics.horiBearingY; + + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + FT_Vector_Transform (&vector, &scaled_font->unscaled->Current_Shape); + FT_Outline_Translate(&glyph->outline, vector.x, vector.y); + } else if (glyph->format == FT_GLYPH_FORMAT_BITMAP) { + glyph->bitmap_left += vector.x / 64; + glyph->bitmap_top += vector.y / 64; + } +} + +static cairo_int_status_t +_cairo_ft_scaled_glyph_init (void *abstract_font, + cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_info_t info) +{ + cairo_text_extents_t fs_metrics; + cairo_ft_scaled_font_t *scaled_font = abstract_font; + cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; + FT_GlyphSlot glyph; + FT_Face face; + FT_Error error; + int load_flags = scaled_font->ft_options.load_flags; + FT_Glyph_Metrics *metrics; + double x_factor, y_factor; + cairo_bool_t vertical_layout = FALSE; + cairo_status_t status; + + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return CAIRO_STATUS_NO_MEMORY; + + status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, + &scaled_font->base.scale); + if (status) + goto FAIL; + + /* Ignore global advance unconditionally */ + load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; + + if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0 && + (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) == 0) + load_flags |= FT_LOAD_NO_BITMAP; + + /* + * Don't pass FT_LOAD_VERTICAL_LAYOUT to FT_Load_Glyph here as + * suggested by freetype people. + */ + if (load_flags & FT_LOAD_VERTICAL_LAYOUT) { + load_flags &= ~FT_LOAD_VERTICAL_LAYOUT; + vertical_layout = TRUE; + } + + error = FT_Load_Glyph (scaled_font->unscaled->face, + _cairo_scaled_glyph_index(scaled_glyph), + load_flags); + + if (error) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } + + glyph = face->glyph; + +#if HAVE_FT_GLYPHSLOT_EMBOLDEN + /* + * embolden glyphs if requested + */ + if (scaled_font->ft_options.extra_flags & CAIRO_FT_OPTIONS_EMBOLDEN) + FT_GlyphSlot_Embolden (glyph); +#endif + + if (vertical_layout) + _cairo_ft_scaled_glyph_vertical_layout_bearing_fix (scaled_font, glyph); + + if (info & CAIRO_SCALED_GLYPH_INFO_METRICS) { + + cairo_bool_t hint_metrics = scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF; + /* + * Compute font-space metrics + */ + metrics = &glyph->metrics; + + if (unscaled->x_scale == 0) + x_factor = 0; + else + x_factor = 1 / unscaled->x_scale; + + if (unscaled->y_scale == 0) + y_factor = 0; + else + y_factor = 1 / unscaled->y_scale; + + /* + * Note: Y coordinates of the horizontal bearing need to be negated. + * + * Scale metrics back to glyph space from the scaled glyph space returned + * by FreeType + * + * If we want hinted metrics but aren't asking for hinted glyphs from + * FreeType, then we need to do the metric hinting ourselves. + */ + + if (hint_metrics && (load_flags & FT_LOAD_NO_HINTING)) + { + FT_Pos x1, x2; + FT_Pos y1, y2; + FT_Pos advance; + + if (!vertical_layout) { + x1 = (metrics->horiBearingX) & -64; + x2 = (metrics->horiBearingX + metrics->width + 63) & -64; + y1 = (-metrics->horiBearingY) & -64; + y2 = (-metrics->horiBearingY + metrics->height + 63) & -64; + + advance = ((metrics->horiAdvance + 32) & -64); + + fs_metrics.x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor; + fs_metrics.y_bearing = DOUBLE_FROM_26_6 (y1) * y_factor; + + fs_metrics.width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor; + fs_metrics.height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor; + + fs_metrics.x_advance = DOUBLE_FROM_26_6 (advance) * x_factor; + fs_metrics.y_advance = 0; + } else { + x1 = (metrics->vertBearingX) & -64; + x2 = (metrics->vertBearingX + metrics->width + 63) & -64; + y1 = (metrics->vertBearingY) & -64; + y2 = (metrics->vertBearingY + metrics->height + 63) & -64; + + advance = ((metrics->vertAdvance + 32) & -64); + + fs_metrics.x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor; + fs_metrics.y_bearing = DOUBLE_FROM_26_6 (y1) * y_factor; + + fs_metrics.width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor; + fs_metrics.height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor; + + fs_metrics.x_advance = 0; + fs_metrics.y_advance = DOUBLE_FROM_26_6 (advance) * y_factor; + } + } else { + fs_metrics.width = DOUBLE_FROM_26_6 (metrics->width) * x_factor; + fs_metrics.height = DOUBLE_FROM_26_6 (metrics->height) * y_factor; + + if (!vertical_layout) { + fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) * x_factor; + fs_metrics.y_bearing = DOUBLE_FROM_26_6 (-metrics->horiBearingY) * y_factor; + + 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; + if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE) + fs_metrics.y_advance = DOUBLE_FROM_26_6 (metrics->vertAdvance) * y_factor; + else + fs_metrics.y_advance = DOUBLE_FROM_26_6 (glyph->linearVertAdvance) * y_factor; + } + } + + _cairo_scaled_glyph_set_metrics (scaled_glyph, + &scaled_font->base, + &fs_metrics); + } + + if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0) { + cairo_image_surface_t *surface; + + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + status = _render_glyph_outline (face, &scaled_font->ft_options.base, + &surface); + } else { + status = _render_glyph_bitmap (face, &scaled_font->ft_options.base, + &surface); + if (status == CAIRO_STATUS_SUCCESS && unscaled->have_shape) { + status = _transform_glyph_bitmap (&unscaled->current_shape, + &surface); + if (status) + cairo_surface_destroy (&surface->base); + } + } + if (status) + goto FAIL; + + _cairo_scaled_glyph_set_surface (scaled_glyph, + &scaled_font->base, + surface); + } + + if (info & CAIRO_SCALED_GLYPH_INFO_PATH) { + cairo_path_fixed_t *path; + + /* + * A kludge -- the above code will trash the outline, + * so reload it. This will probably never occur though + */ + if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0) { + error = FT_Load_Glyph (face, + _cairo_scaled_glyph_index(scaled_glyph), + load_flags | FT_LOAD_NO_BITMAP); + + if (error) { + _cairo_ft_unscaled_font_unlock_face (unscaled); + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } +#if HAVE_FT_GLYPHSLOT_EMBOLDEN + /* + * embolden glyphs if requested + */ + if (scaled_font->ft_options.extra_flags & CAIRO_FT_OPTIONS_EMBOLDEN) + FT_GlyphSlot_Embolden (glyph); +#endif + if (vertical_layout) + _cairo_ft_scaled_glyph_vertical_layout_bearing_fix (scaled_font, glyph); + + } + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) + status = _decompose_glyph_outline (face, &scaled_font->ft_options.base, + &path); + else + status = CAIRO_INT_STATUS_UNSUPPORTED; + + if (status) + goto FAIL; + + _cairo_scaled_glyph_set_path (scaled_glyph, + &scaled_font->base, + path); + } + FAIL: + _cairo_ft_unscaled_font_unlock_face (unscaled); + + return status; +} + +static unsigned long +_cairo_ft_ucs4_to_index (void *abstract_font, + uint32_t ucs4) +{ + cairo_ft_scaled_font_t *scaled_font = abstract_font; + cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; + FT_Face face; + FT_UInt index; + + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return 0; + index = FT_Get_Char_Index (face, ucs4); + _cairo_ft_unscaled_font_unlock_face (unscaled); + return index; +} + +static cairo_int_status_t +_cairo_ft_load_truetype_table (void *abstract_font, + unsigned long tag, + long offset, + unsigned char *buffer, + unsigned long *length) +{ + cairo_ft_scaled_font_t *scaled_font = abstract_font; + cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; + FT_Face face; + cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + + if (_cairo_ft_scaled_font_is_vertical (&scaled_font->base)) + return CAIRO_INT_STATUS_UNSUPPORTED; + +#if HAVE_FT_LOAD_SFNT_TABLE + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return CAIRO_STATUS_NO_MEMORY; + + if (FT_IS_SFNT (face) && + FT_Load_Sfnt_Table (face, tag, offset, buffer, length) == 0) + status = CAIRO_STATUS_SUCCESS; + + _cairo_ft_unscaled_font_unlock_face (unscaled); +#endif + + return status; +} + +static void +_cairo_ft_map_glyphs_to_unicode (void *abstract_font, + cairo_scaled_font_subset_t *font_subset) +{ + cairo_ft_scaled_font_t *scaled_font = abstract_font; + cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; + FT_Face face; + FT_UInt glyph; + unsigned long charcode; + unsigned int i; + int count; + + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return; + + count = font_subset->num_glyphs; + charcode = FT_Get_First_Char( face, &glyph); + while (glyph != 0 && count > 0) + { + for (i = 0; i < font_subset->num_glyphs; i++) { + if (font_subset->glyphs[i] == glyph) { + font_subset->to_unicode[i] = charcode; + count--; + break; + } + } + charcode = FT_Get_Next_Char(face, charcode, &glyph); + } + _cairo_ft_unscaled_font_unlock_face (unscaled); +} + +const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = { + CAIRO_FONT_TYPE_FT, + _cairo_ft_scaled_font_create_toy, + _cairo_ft_scaled_font_fini, + _cairo_ft_scaled_glyph_init, + NULL, /* text_to_glyphs */ + _cairo_ft_ucs4_to_index, + NULL, /* show_glyphs */ + _cairo_ft_load_truetype_table, + _cairo_ft_map_glyphs_to_unicode, +}; + +/* cairo_ft_font_face_t */ + +static void +_cairo_ft_font_face_destroy (void *abstract_face) +{ + cairo_ft_font_face_t *font_face = abstract_face; + + cairo_ft_font_face_t *tmp_face = NULL; + cairo_ft_font_face_t *last_face = NULL; + + if (font_face == NULL) + return; + + /* When destroying the face created by cairo_ft_font_face_create_for_ft_face, + * we have a special "zombie" state for the face when the unscaled font + * is still alive but there are no public references to the font face. + * + * We go from: + * + * font_face ------> unscaled + * <-....weak....../ + * + * To: + * + * font_face <------- unscaled + */ + + if (font_face->unscaled && + font_face->unscaled->from_face && + font_face->unscaled->base.ref_count > 1) + { + cairo_font_face_reference (&font_face->base); + + _cairo_unscaled_font_destroy (&font_face->unscaled->base); + font_face->unscaled = NULL; + + return; + } + + if (font_face->unscaled) { + /* Remove face from linked list */ + for (tmp_face = font_face->unscaled->faces; + tmp_face; + tmp_face = tmp_face->next) + { + if (tmp_face == font_face) { + if (last_face) + last_face->next = tmp_face->next; + else + font_face->unscaled->faces = tmp_face->next; + } + + last_face = tmp_face; + } + + _cairo_unscaled_font_destroy (&font_face->unscaled->base); + font_face->unscaled = NULL; + } +} + +static cairo_status_t +_cairo_ft_font_face_scaled_font_create (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font) +{ + cairo_ft_font_face_t *font_face = abstract_face; + cairo_ft_options_t ft_options; + + /* The handling of font options is different depending on how the + * font face was created. When the user creates a font face with + * cairo_ft_font_face_create_for_ft_face(), then the load flags + * passed in augment the load flags for the options. But for + * cairo_ft_font_face_create_for_pattern(), the load flags are + * derived from a pattern where the user has called + * cairo_ft_font_options_substitute(), so *just* use those load + * flags and ignore the options. + */ + + ft_options = font_face->ft_options; + + *scaled_font = _cairo_ft_scaled_font_create (font_face->unscaled, + &font_face->base, + font_matrix, ctm, + options, ft_options); + if (*scaled_font) { + return CAIRO_STATUS_SUCCESS; + } else { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } +} + +static const cairo_font_face_backend_t _cairo_ft_font_face_backend = { + CAIRO_FONT_TYPE_FT, + _cairo_ft_font_face_destroy, + _cairo_ft_font_face_scaled_font_create +}; + +static cairo_font_face_t * +_cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled, + cairo_ft_options_t *ft_options) +{ + cairo_ft_font_face_t *font_face, **prev_font_face; + + /* Looked for an existing matching font face */ + for (font_face = unscaled->faces, prev_font_face = &unscaled->faces; + font_face; + prev_font_face = &font_face->next, font_face = font_face->next) + { + if (font_face->ft_options.load_flags == ft_options->load_flags && + font_face->ft_options.extra_flags == ft_options->extra_flags && + cairo_font_options_equal (&font_face->ft_options.base, &ft_options->base)) + { + if (! font_face->base.status) + return cairo_font_face_reference (&font_face->base); + + /* The font_face has been left in an error state, abandon it. */ + *prev_font_face = font_face->next; + break; + } + } + + /* No match found, create a new one */ + font_face = malloc (sizeof (cairo_ft_font_face_t)); + if (!font_face) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + font_face->unscaled = unscaled; + _cairo_unscaled_font_reference (&unscaled->base); + + font_face->ft_options = *ft_options; + + font_face->next = unscaled->faces; + unscaled->faces = font_face; + + _cairo_font_face_init (&font_face->base, &_cairo_ft_font_face_backend); + + return &font_face->base; +} + +/* implement the platform-specific interface */ + +/** + * cairo_ft_font_options_substitute: + * @options: a #cairo_font_options_t object + * @pattern: an existing #FcPattern + * + * Add options to a #FcPattern based on a #cairo_font_options_t font + * options object. Options that are already in the pattern, are not overridden, + * so you should call this function after calling FcConfigSubstitute() (the + * user's settings should override options based on the surface type), but + * before calling FcDefaultSubstitute(). + **/ +void +cairo_ft_font_options_substitute (const cairo_font_options_t *options, + FcPattern *pattern) +{ + FcValue v; + + if (options->antialias != CAIRO_ANTIALIAS_DEFAULT) + { + if (FcPatternGet (pattern, FC_ANTIALIAS, 0, &v) == FcResultNoMatch) + { + FcPatternAddBool (pattern, FC_ANTIALIAS, options->antialias != CAIRO_ANTIALIAS_NONE); + if (options->antialias != CAIRO_ANTIALIAS_SUBPIXEL) { + FcPatternDel (pattern, FC_RGBA); + FcPatternAddInteger (pattern, FC_RGBA, FC_RGBA_NONE); + } + } + } + + if (options->antialias != CAIRO_ANTIALIAS_DEFAULT) + { + if (FcPatternGet (pattern, FC_RGBA, 0, &v) == FcResultNoMatch) + { + int rgba; + + if (options->antialias == CAIRO_ANTIALIAS_SUBPIXEL) { + switch (options->subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + default: + rgba = FC_RGBA_RGB; + break; + case CAIRO_SUBPIXEL_ORDER_BGR: + rgba = FC_RGBA_BGR; + break; + case CAIRO_SUBPIXEL_ORDER_VRGB: + rgba = FC_RGBA_VRGB; + break; + case CAIRO_SUBPIXEL_ORDER_VBGR: + rgba = FC_RGBA_VBGR; + break; + } + } else { + rgba = FC_RGBA_NONE; + } + + FcPatternAddInteger (pattern, FC_RGBA, rgba); + } + } + + if (options->hint_style != CAIRO_HINT_STYLE_DEFAULT) + { + if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch) + { + FcPatternAddBool (pattern, FC_HINTING, options->hint_style != CAIRO_HINT_STYLE_NONE); + } + +#ifdef FC_HINT_STYLE + if (FcPatternGet (pattern, FC_HINT_STYLE, 0, &v) == FcResultNoMatch) + { + int hint_style; + + switch (options->hint_style) { + case CAIRO_HINT_STYLE_NONE: + hint_style = FC_HINT_NONE; + break; + case CAIRO_HINT_STYLE_SLIGHT: + hint_style = FC_HINT_SLIGHT; + break; + case CAIRO_HINT_STYLE_MEDIUM: + hint_style = FC_HINT_MEDIUM; + break; + case CAIRO_HINT_STYLE_FULL: + case CAIRO_HINT_STYLE_DEFAULT: + default: + hint_style = FC_HINT_FULL; + break; + } + + FcPatternAddInteger (pattern, FC_HINT_STYLE, hint_style); + } +#endif + } +} +slim_hidden_def (cairo_ft_font_options_substitute); + +/** + * cairo_ft_font_face_create_for_pattern: + * @pattern: A fully resolved fontconfig + * pattern. A pattern can be resolved, by, among other things, calling + * FcConfigSubstitute(), FcDefaultSubstitute(), then + * FcFontMatch(). Cairo will call FcPatternReference() on this + * pattern, so you should not further modify the pattern, but you can + * release your reference to the pattern with FcPatternDestroy() if + * you no longer need to access it. + * + * Creates a new font face for the FreeType font backend based on a + * fontconfig pattern. This font can then be used with + * cairo_set_font_face() or cairo_scaled_font_create(). The + * #cairo_scaled_font_t returned from cairo_scaled_font_create() is + * also for the FreeType backend and can be used with functions such + * as cairo_ft_font_lock_face(). + * + * Font rendering options are represented both here and when you + * call cairo_scaled_font_create(). Font options that have a representation + * in a #FcPattern must be passed in here; to modify #FcPattern + * appropriately to reflect the options in a #cairo_font_options_t, call + * cairo_ft_font_options_substitute(). + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + **/ +cairo_font_face_t * +cairo_ft_font_face_create_for_pattern (FcPattern *pattern) +{ + cairo_ft_unscaled_font_t *unscaled; + cairo_font_face_t *font_face; + cairo_ft_options_t ft_options; + + unscaled = _cairo_ft_unscaled_font_create_for_pattern (pattern); + if (unscaled == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; + } + + _get_pattern_ft_options (pattern, &ft_options); + font_face = _cairo_ft_font_face_create (unscaled, &ft_options); + _cairo_unscaled_font_destroy (&unscaled->base); + + if (font_face) + return font_face; + else + return (cairo_font_face_t *)&_cairo_font_face_nil; +} + +/** + * cairo_ft_font_face_create_for_ft_face: + * @face: A FreeType face object, already opened. This must + * be kept around until the face's ref_count drops to + * zero and it is freed. Since the face may be referenced + * internally to Cairo, the best way to determine when it + * is safe to free the face is to pass a + * #cairo_destroy_func_t to cairo_font_face_set_user_data() + * @load_flags: flags to pass to FT_Load_Glyph when loading + * glyphs from the font. These flags are OR'ed together with + * the flags derived from the #cairo_font_options_t passed + * to cairo_scaled_font_create(), so only a few values such + * as %FT_LOAD_VERTICAL_LAYOUT, and %FT_LOAD_FORCE_AUTOHINT + * are useful. You should not pass any of the flags affecting + * the load target, such as %FT_LOAD_TARGET_LIGHT. + * + * Creates a new font face for the FreeType font backend from a + * pre-opened FreeType face. This font can then be used with + * cairo_set_font_face() or cairo_scaled_font_create(). The + * #cairo_scaled_font_t returned from cairo_scaled_font_create() is + * also for the FreeType backend and can be used with functions such + * as cairo_ft_font_lock_face(). + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + **/ +cairo_font_face_t * +cairo_ft_font_face_create_for_ft_face (FT_Face face, + int load_flags) +{ + cairo_ft_unscaled_font_t *unscaled; + cairo_font_face_t *font_face; + cairo_ft_options_t ft_options; + + unscaled = _cairo_ft_unscaled_font_create_from_face (face); + if (unscaled == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; + } + + ft_options.load_flags = load_flags; + ft_options.extra_flags = 0; + _cairo_font_options_init_default (&ft_options.base); + + font_face = _cairo_ft_font_face_create (unscaled, &ft_options); + _cairo_unscaled_font_destroy (&unscaled->base); + + if (font_face) + return font_face; + else + return (cairo_font_face_t *)&_cairo_font_face_nil; +} + +/** + * cairo_ft_scaled_font_lock_face: + * @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an + * object can be created by calling cairo_scaled_font_create() on a + * FreeType backend font face (see cairo_ft_font_face_create_for_pattern(), + * cairo_ft_font_face_create_for_face()). + * + * cairo_ft_font_lock_face() gets the #FT_Face object from a FreeType + * backend font and scales it appropriately for the font. You must + * release the face with cairo_ft_font_unlock_face() + * when you are done using it. Since the #FT_Face object can be + * shared between multiple #cairo_scaled_font_t objects, you must not + * lock any other font objects until you unlock this one. A count is + * kept of the number of times cairo_ft_font_lock_face() is + * called. cairo_ft_font_unlock_face() must be called the same number + * of times. + * + * You must be careful when using this function in a library or in a + * threaded application, because freetype's design makes it unsafe to + * call freetype functions simultaneously from multiple threads, (even + * if using distinct FT_Face objects). Because of this, application + * code that acquires an FT_Face object with this call must add it's + * own locking to protect any use of that object, (and which also must + * protect any other calls into cairo as almost any cairo function + * might result in a call into the freetype library). + * + * Return value: The #FT_Face object for @font, scaled appropriately, + * or %NULL if @scaled_font is in an error state (see + * cairo_scaled_font_status()) or there is insufficient memory. + **/ +FT_Face +cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font) +{ + cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font; + FT_Face face; + cairo_status_t status; + + if (scaled_font->base.status) + return NULL; + + face = _cairo_ft_unscaled_font_lock_face (scaled_font->unscaled); + if (face == NULL) { + _cairo_scaled_font_set_error (&scaled_font->base, CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, + &scaled_font->base.scale); + if (status) { + _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled); + _cairo_scaled_font_set_error (&scaled_font->base, status); + return NULL; + } + + /* NOTE: We deliberately release the unscaled font's mutex here, + * so that we are not holding a lock across two separate calls to + * cairo function, (which would give the application some + * opportunity for creating deadlock. This is obviously unsafe, + * but as documented, the user must add manual locking when using + * this function. */ + CAIRO_MUTEX_UNLOCK (scaled_font->unscaled->mutex); + + return face; +} + +/** + * cairo_ft_scaled_font_unlock_face: + * @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an + * object can be created by calling cairo_scaled_font_create() on a + * FreeType backend font face (see cairo_ft_font_face_create_for_pattern(), + * cairo_ft_font_face_create_for_ft_face()). + * + * Releases a face obtained with cairo_ft_scaled_font_lock_face(). + **/ +void +cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *abstract_font) +{ + cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font; + + if (scaled_font->base.status) + return; + + /* NOTE: We released the unscaled font's mutex at the end of + * cairo_ft_scaled_font_lock_face, so we have to acquire it again + * as _cairo_ft_unscaled_font_unlock_face expects it to be held + * when we call into it. */ + CAIRO_MUTEX_LOCK (scaled_font->unscaled->mutex); + + _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled); +} + +/* We expose our unscaled font implementation internally for the the + * PDF backend, which needs to keep track of the the different + * fonts-on-disk used by a document, so it can embed them. + */ +cairo_unscaled_font_t * +_cairo_ft_scaled_font_get_unscaled_font (cairo_scaled_font_t *abstract_font) +{ + cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font; + + return &scaled_font->unscaled->base; +} + +cairo_bool_t +_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font) +{ + cairo_ft_scaled_font_t *ft_scaled_font; + + if (!_cairo_scaled_font_is_ft (scaled_font)) + return FALSE; + + ft_scaled_font = (cairo_ft_scaled_font_t *) scaled_font; + if (ft_scaled_font->ft_options.load_flags & FT_LOAD_VERTICAL_LAYOUT) + return TRUE; + return FALSE; +} + +void +_cairo_ft_font_reset_static_data (void) +{ + _cairo_ft_unscaled_font_map_destroy (); +} diff --git a/gfx/cairo/cairo/src/cairo-glitz-surface.c b/gfx/cairo/cairo/src/cairo-glitz-surface.c index b9e4f72d2b7c..ab15404291e5 100644 --- a/gfx/cairo/cairo/src/cairo-glitz-surface.c +++ b/gfx/cairo/cairo/src/cairo-glitz-surface.c @@ -33,7 +33,8 @@ typedef struct _cairo_glitz_surface { glitz_surface_t *surface; glitz_format_t *format; - pixman_region16_t *clip; + cairo_bool_t has_clip; + pixman_region16_t clip; } cairo_glitz_surface_t; static const cairo_surface_backend_t * @@ -44,10 +45,9 @@ _cairo_glitz_surface_finish (void *abstract_surface) { cairo_glitz_surface_t *surface = abstract_surface; - if (surface->clip) - { - glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); - pixman_region_destroy (surface->clip); + if (surface->has_clip) { + glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); + pixman_region_fini (&surface->clip); } glitz_surface_destroy (surface->surface); @@ -208,7 +208,7 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, } /* clear out the glitz clip; the clip affects glitz_get_pixels */ - if (surface->clip) + if (surface->has_clip) glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); @@ -221,12 +221,12 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, glitz_buffer_destroy (buffer); /* restore the clip, if any */ - if (surface->clip) { + if (surface->has_clip) { glitz_box_t *box; int n; - box = (glitz_box_t *) pixman_region_rects (surface->clip); - n = pixman_region_num_rects (surface->clip); + box = (glitz_box_t *) pixman_region_rects (&surface->clip); + n = pixman_region_num_rects (&surface->clip); glitz_surface_set_clip_region (surface->surface, 0, 0, box, n); } @@ -668,7 +668,7 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern, } glitz_set_pixels (src->surface, 0, 0, gradient->n_stops, 1, - &format, buffer); + (glitz_pixel_format_t *)&format, buffer); glitz_buffer_destroy (buffer); @@ -822,11 +822,16 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src, combined = src_solid->color; _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha); - _cairo_pattern_init_solid (&tmp.solid, &combined); + _cairo_pattern_init_solid (&tmp.solid, &combined, + CAIRO_COLOR_IS_OPAQUE (&combined) ? + CAIRO_CONTENT_COLOR : + CAIRO_CONTENT_COLOR_ALPHA); mask = NULL; } else { - _cairo_pattern_init_copy (&tmp.base, src); + status = _cairo_pattern_init_copy (&tmp.base, src); + if (status) + return status; } status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst, @@ -841,7 +846,9 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src, if (mask) { - _cairo_pattern_init_copy (&tmp.base, mask); + status = _cairo_pattern_init_copy (&tmp.base, mask); + if (status) + return status; status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst, mask_x, mask_y, @@ -1002,7 +1009,8 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, _cairo_surface_create_similar_solid (&dst->base, CAIRO_CONTENT_COLOR_ALPHA, 1, 1, - (cairo_color_t *) color); + (cairo_color_t *) color, + NULL); if (src->base.status) return CAIRO_STATUS_NO_MEMORY; @@ -1071,7 +1079,9 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { - _cairo_pattern_init_copy (&tmp_src_pattern.base, pattern); + status = _cairo_pattern_init_copy (&tmp_src_pattern.base, pattern); + if (status) + return status; status = _cairo_glitz_pattern_acquire_surface (&tmp_src_pattern.base, dst, @@ -1283,26 +1293,32 @@ _cairo_glitz_surface_set_clip_region (void *abstract_surface, glitz_box_t *box; int n; - if (!surface->clip) - { - surface->clip = pixman_region_create (); - if (!surface->clip) - return CAIRO_STATUS_NO_MEMORY; - } - pixman_region_copy (surface->clip, region); + if (!surface->has_clip) { + pixman_region_init (&surface->clip); + surface->has_clip = TRUE; + } + + if (pixman_region_copy (&surface->clip, region) != + PIXMAN_REGION_STATUS_SUCCESS) + { + pixman_region_fini (&surface->clip); + surface->has_clip = FALSE; + return CAIRO_STATUS_NO_MEMORY; + } + + box = (glitz_box_t *) pixman_region_rects (&surface->clip); + n = pixman_region_num_rects (&surface->clip); - box = (glitz_box_t *) pixman_region_rects (surface->clip); - n = pixman_region_num_rects (surface->clip); glitz_surface_set_clip_region (surface->surface, 0, 0, box, n); } else { glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); - if (surface->clip) - pixman_region_destroy (surface->clip); - - surface->clip = NULL; + if (surface->has_clip) { + pixman_region_fini (&surface->clip); + surface->has_clip = FALSE; + } } return CAIRO_STATUS_SUCCESS; @@ -2172,6 +2188,33 @@ _cairo_glitz_surface_flush (void *abstract_surface) return CAIRO_STATUS_SUCCESS; } +static cairo_bool_t +_cairo_glitz_surface_is_similar (void *surface_a, + void *surface_b, + cairo_content_t content) +{ + cairo_glitz_surface_t *a = (cairo_glitz_surface_t *) surface_a; + cairo_glitz_surface_t *b = (cairo_glitz_surface_t *) surface_b; + + glitz_drawable_t *drawable_a = glitz_surface_get_drawable (a->surface); + glitz_drawable_t *drawable_b = glitz_surface_get_drawable (b->surface); + + return drawable_a == drawable_b; +} + +static cairo_status_t +_cairo_glitz_surface_reset (void *abstract_surface) +{ + cairo_glitz_surface_t *surface = abstract_surface; + cairo_status_t status; + + status = _cairo_glitz_surface_set_clip_region (surface, NULL); + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} + static const cairo_surface_backend_t cairo_glitz_surface_backend = { CAIRO_SURFACE_TYPE_GLITZ, _cairo_glitz_surface_create_similar, @@ -2194,7 +2237,18 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = { _cairo_glitz_surface_flush, NULL, /* mark_dirty_rectangle */ _cairo_glitz_surface_scaled_font_fini, - _cairo_glitz_surface_scaled_glyph_fini + _cairo_glitz_surface_scaled_glyph_fini, + + NULL, /* paint */ + NULL, /* mask */ + NULL, /* stroke */ + NULL, /* fill */ + NULL, /* show_glyphs */ + + NULL, /* snapshot */ + _cairo_glitz_surface_is_similar, + + _cairo_glitz_surface_reset }; static const cairo_surface_backend_t * @@ -2240,9 +2294,9 @@ cairo_glitz_surface_create (glitz_surface_t *surface) glitz_surface_reference (surface); - crsurface->surface = surface; - crsurface->format = format; - crsurface->clip = NULL; + crsurface->surface = surface; + crsurface->format = format; + crsurface->has_clip = FALSE; return (cairo_surface_t *) crsurface; } diff --git a/gfx/cairo/cairo/src/cairo-gstate.c b/gfx/cairo/cairo/src/cairo-gstate.c index b75a90baab7e..fc8c5456902a 100644 --- a/gfx/cairo/cairo/src/cairo-gstate.c +++ b/gfx/cairo/cairo/src/cairo-gstate.c @@ -35,8 +35,6 @@ * Carl D. Worth */ -#include - #include "cairoint.h" #include "cairo-clip-private.h" @@ -64,6 +62,8 @@ cairo_status_t _cairo_gstate_init (cairo_gstate_t *gstate, cairo_surface_t *target) { + gstate->next = NULL; + gstate->op = CAIRO_GSTATE_OPERATOR_DEFAULT; gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT; @@ -91,13 +91,12 @@ _cairo_gstate_init (cairo_gstate_t *gstate, _cairo_gstate_identity_matrix (gstate); gstate->source_ctm_inverse = gstate->ctm_inverse; - gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK); + gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK, + CAIRO_CONTENT_COLOR); if (gstate->source->status) return CAIRO_STATUS_NO_MEMORY; - gstate->next = NULL; - - return CAIRO_STATUS_SUCCESS; + return target ? target->status : CAIRO_STATUS_NULL_POINTER; } /** @@ -131,7 +130,9 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) _cairo_font_options_init_copy (&gstate->font_options , &other->font_options); - _cairo_clip_init_copy (&gstate->clip, &other->clip); + status = _cairo_clip_init_copy (&gstate->clip, &other->clip); + if (status) + return status; gstate->target = cairo_surface_reference (other->target); /* parent_target is always set to NULL; it's only ever set by redirect_target */ @@ -160,7 +161,7 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) cairo_scaled_font_destroy (gstate->scaled_font); gstate->scaled_font = NULL; - _cairo_clip_fini (&gstate->clip); + _cairo_clip_reset (&gstate->clip); cairo_surface_destroy (gstate->target); gstate->target = NULL; @@ -175,7 +176,7 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) gstate->source = NULL; } -void +static void _cairo_gstate_destroy (cairo_gstate_t *gstate) { if (gstate == NULL) @@ -197,7 +198,7 @@ _cairo_gstate_destroy (cairo_gstate_t *gstate) * Return value: a new cairo_gstate_t or NULL if there is insufficient * memory. **/ -cairo_gstate_t* +static cairo_gstate_t* _cairo_gstate_clone (cairo_gstate_t *other) { cairo_status_t status; @@ -218,6 +219,55 @@ _cairo_gstate_clone (cairo_gstate_t *other) return gstate; } +/** + * _cairo_gstate_save: + * @gstate: input/output gstate pointer + * + * Makes a copy of the current state of @gstate and saves it + * to @gstate->next, then put the address of the newly allcated + * copy into @gstate. _cairo_gstate_restore() reverses this. + **/ +cairo_status_t +_cairo_gstate_save (cairo_gstate_t **gstate) +{ + cairo_gstate_t *top; + + top = _cairo_gstate_clone (*gstate); + + if (top == NULL) { + return CAIRO_STATUS_NO_MEMORY; + } + + top->next = *gstate; + *gstate = top; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_gstate_restore: + * @gstate: input/output gstate pointer + * + * Reverses the effects of one _cairo_gstate_save() call. + **/ +cairo_status_t +_cairo_gstate_restore (cairo_gstate_t **gstate) +{ + cairo_gstate_t *top; + + top = *gstate; + + if (top->next == NULL) { + return CAIRO_STATUS_INVALID_RESTORE; + } + + *gstate = top->next; + + _cairo_gstate_destroy (top); + + return CAIRO_STATUS_SUCCESS; +} + static cairo_status_t _cairo_gstate_recursive_apply_clip_path (cairo_gstate_t *gstate, cairo_clip_path_t *cpath) @@ -252,9 +302,11 @@ _cairo_gstate_recursive_apply_clip_path (cairo_gstate_t *gstate, * original #cairo_t target, the clip will be INVALID after this call, * and the caller should either recreate or reset the clip. **/ -void +cairo_status_t _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child) { + cairo_status_t status; + /* If this gstate is already redirected, this is an error; we need a * new gstate to be able to redirect */ assert (gstate->parent_target == NULL); @@ -269,14 +321,18 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child) * since its ref is now owned by gstate->parent_target */ gstate->target = cairo_surface_reference (child); - _cairo_clip_fini (&gstate->clip); - _cairo_clip_init_deep_copy (&gstate->clip, &gstate->next->clip, child); + _cairo_clip_reset (&gstate->clip); + status = _cairo_clip_init_deep_copy (&gstate->clip, &gstate->next->clip, child); + if (status) + return status; /* The clip is in surface backend coordinates for the previous target; * translate it into the child's backend coordinates. */ _cairo_clip_translate (&gstate->clip, _cairo_fixed_from_double (child->device_transform.x0 - gstate->parent_target->device_transform.x0), _cairo_fixed_from_double (child->device_transform.y0 - gstate->parent_target->device_transform.y0)); + + return CAIRO_STATUS_SUCCESS; } /** @@ -356,7 +412,7 @@ _cairo_gstate_set_source (cairo_gstate_t *gstate, if (source->status) return source->status; - cairo_pattern_reference (source); + source = cairo_pattern_reference (source); cairo_pattern_destroy (gstate->source); gstate->source = source; gstate->source_ctm_inverse = gstate->ctm_inverse; @@ -507,6 +563,24 @@ _cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dash return CAIRO_STATUS_SUCCESS; } +void +_cairo_gstate_get_dash (cairo_gstate_t *gstate, + double *dashes, + int *num_dashes, + double *offset) +{ + if (dashes) + memcpy (dashes, + gstate->stroke_style.dash, + sizeof (double) * gstate->stroke_style.num_dashes); + + if (num_dashes) + *num_dashes = gstate->stroke_style.num_dashes; + + if (offset) + *offset = gstate->stroke_style.dash_offset; +} + cairo_status_t _cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit) { @@ -583,13 +657,16 @@ _cairo_gstate_transform (cairo_gstate_t *gstate, const cairo_matrix_t *matrix) { cairo_matrix_t tmp; + cairo_status_t status; _cairo_gstate_unset_scaled_font (gstate); tmp = *matrix; cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); - cairo_matrix_invert (&tmp); + status = cairo_matrix_invert (&tmp); + if (status) + return status; cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); return CAIRO_STATUS_SUCCESS; @@ -613,49 +690,39 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate, return CAIRO_STATUS_SUCCESS; } -cairo_status_t +void _cairo_gstate_identity_matrix (cairo_gstate_t *gstate) { _cairo_gstate_unset_scaled_font (gstate); cairo_matrix_init_identity (&gstate->ctm); cairo_matrix_init_identity (&gstate->ctm_inverse); - - return CAIRO_STATUS_SUCCESS; } -cairo_status_t +void _cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y) { cairo_matrix_transform_point (&gstate->ctm, x, y); - - return CAIRO_STATUS_SUCCESS; } -cairo_status_t +void _cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate, double *dx, double *dy) { cairo_matrix_transform_distance (&gstate->ctm, dx, dy); - - return CAIRO_STATUS_SUCCESS; } -cairo_status_t +void _cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y) { cairo_matrix_transform_point (&gstate->ctm_inverse, x, y); - - return CAIRO_STATUS_SUCCESS; } -cairo_status_t +void _cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate, double *dx, double *dy) { cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy); - - return CAIRO_STATUS_SUCCESS; } void @@ -697,7 +764,7 @@ _cairo_gstate_stroke_to_path (cairo_gstate_t *gstate) } */ -static void +static cairo_status_t _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern, cairo_pattern_t *original, @@ -705,8 +772,12 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate, { cairo_surface_pattern_t *surface_pattern; cairo_surface_t *surface; + cairo_status_t status; + + status = _cairo_pattern_init_copy (pattern, original); + if (status) + return status; - _cairo_pattern_init_copy (pattern, original); _cairo_pattern_transform (pattern, ctm_inverse); if (cairo_pattern_get_type (original) == CAIRO_PATTERN_TYPE_SURFACE) { @@ -716,25 +787,26 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate, _cairo_pattern_transform (pattern, &surface->device_transform); } + return CAIRO_STATUS_SUCCESS; } -static void +static cairo_status_t _cairo_gstate_copy_transformed_source (cairo_gstate_t *gstate, cairo_pattern_t *pattern) { - _cairo_gstate_copy_transformed_pattern (gstate, pattern, - gstate->source, - &gstate->source_ctm_inverse); + return _cairo_gstate_copy_transformed_pattern (gstate, pattern, + gstate->source, + &gstate->source_ctm_inverse); } -static void +static cairo_status_t _cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate, cairo_pattern_t *pattern, cairo_pattern_t *mask) { - _cairo_gstate_copy_transformed_pattern (gstate, pattern, - mask, - &gstate->ctm_inverse); + return _cairo_gstate_copy_transformed_pattern (gstate, pattern, + mask, + &gstate->ctm_inverse); } cairo_status_t @@ -750,7 +822,9 @@ _cairo_gstate_paint (cairo_gstate_t *gstate) if (status) return status; - _cairo_gstate_copy_transformed_source (gstate, &pattern.base); + status = _cairo_gstate_copy_transformed_source (gstate, &pattern.base); + if (status) + return status; status = _cairo_surface_paint (gstate->target, gstate->op, @@ -857,16 +931,22 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, if (status) return status; - _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); - _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask); + status = _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + if (status) + return status; + + status = _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask); + if (status) + goto CLEANUP_SOURCE; status = _cairo_surface_mask (gstate->target, gstate->op, &source_pattern.base, &mask_pattern.base); - _cairo_pattern_fini (&source_pattern.base); _cairo_pattern_fini (&mask_pattern.base); +CLEANUP_SOURCE: + _cairo_pattern_fini (&source_pattern.base); return status; } @@ -887,7 +967,10 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) if (status) return status; - _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + status = _cairo_gstate_copy_transformed_source (gstate, + &source_pattern.base); + if (status) + return status; status = _cairo_surface_stroke (gstate->target, gstate->op, @@ -954,7 +1037,9 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) if (status) return status; - _cairo_gstate_copy_transformed_source (gstate, &pattern.base); + status = _cairo_gstate_copy_transformed_source (gstate, &pattern.base); + if (status) + return status; status = _cairo_surface_fill (gstate->target, gstate->op, @@ -1001,29 +1086,13 @@ BAIL: cairo_status_t _cairo_gstate_copy_page (cairo_gstate_t *gstate) { - cairo_int_status_t status; - - status = _cairo_surface_copy_page (gstate->target); - - /* It's fine if some surfaces just don't support this. */ - if (status == CAIRO_INT_STATUS_UNSUPPORTED) - return CAIRO_STATUS_SUCCESS; - - return status; + return _cairo_surface_copy_page (gstate->target); } cairo_status_t _cairo_gstate_show_page (cairo_gstate_t *gstate) { - cairo_int_status_t status; - - status = _cairo_surface_show_page (gstate->target); - - /* It's fine if some surfaces just don't support this. */ - if (status == CAIRO_INT_STATUS_UNSUPPORTED) - return CAIRO_STATUS_SUCCESS; - - return status; + return _cairo_surface_show_page (gstate->target); } static void @@ -1125,7 +1194,9 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate, cairo_status_t _cairo_gstate_reset_clip (cairo_gstate_t *gstate) { - return _cairo_clip_reset (&gstate->clip); + _cairo_clip_reset (&gstate->clip); + + return CAIRO_STATUS_SUCCESS; } cairo_status_t @@ -1190,12 +1261,15 @@ _cairo_gstate_select_font_face (cairo_gstate_t *gstate, cairo_font_weight_t weight) { cairo_font_face_t *font_face; + cairo_status_t status; font_face = _cairo_toy_font_face_create (family, slant, weight); if (font_face->status) return font_face->status; - _cairo_gstate_set_font_face (gstate, font_face); + status = _cairo_gstate_set_font_face (gstate, font_face); + if (status) + return status; cairo_font_face_destroy (font_face); return CAIRO_STATUS_SUCCESS; @@ -1230,15 +1304,13 @@ _cairo_gstate_get_font_matrix (cairo_gstate_t *gstate, *matrix = gstate->font_matrix; } -cairo_status_t +void _cairo_gstate_set_font_options (cairo_gstate_t *gstate, const cairo_font_options_t *options) { _cairo_gstate_unset_scaled_font (gstate); gstate->font_options = *options; - - return CAIRO_STATUS_SUCCESS; } void @@ -1357,17 +1429,19 @@ _cairo_gstate_get_scaled_font (cairo_gstate_t *gstate, static cairo_status_t _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate) { - if (!gstate->font_face) { - cairo_font_face_t *font_face; + cairo_font_face_t *font_face; - font_face = _cairo_toy_font_face_create (CAIRO_FONT_FAMILY_DEFAULT, - CAIRO_FONT_SLANT_DEFAULT, - CAIRO_FONT_WEIGHT_DEFAULT); - if (font_face->status) - return font_face->status; - else - gstate->font_face = font_face; - } + if (gstate->font_face != NULL) + return gstate->font_face->status; + + + font_face = _cairo_toy_font_face_create (CAIRO_FONT_FAMILY_DEFAULT, + CAIRO_FONT_SLANT_DEFAULT, + CAIRO_FONT_WEIGHT_DEFAULT); + if (font_face->status) + return font_face->status; + + gstate->font_face = font_face; return CAIRO_STATUS_SUCCESS; } @@ -1377,9 +1451,10 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate) { cairo_status_t status; cairo_font_options_t options; + cairo_scaled_font_t *scaled_font; - if (gstate->scaled_font) - return CAIRO_STATUS_SUCCESS; + if (gstate->scaled_font != NULL) + return gstate->scaled_font->status; status = _cairo_gstate_ensure_font_face (gstate); if (status) @@ -1388,13 +1463,16 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate) cairo_surface_get_font_options (gstate->target, &options); cairo_font_options_merge (&options, &gstate->font_options); - gstate->scaled_font = cairo_scaled_font_create (gstate->font_face, - &gstate->font_matrix, - &gstate->ctm, - &options); + scaled_font = cairo_scaled_font_create (gstate->font_face, + &gstate->font_matrix, + &gstate->ctm, + &options); - if (!gstate->scaled_font) - return CAIRO_STATUS_NO_MEMORY; + status = cairo_scaled_font_status (scaled_font); + if (status) + return status; + + gstate->scaled_font = scaled_font; return CAIRO_STATUS_SUCCESS; } @@ -1409,7 +1487,7 @@ _cairo_gstate_get_font_extents (cairo_gstate_t *gstate, cairo_scaled_font_extents (gstate->scaled_font, extents); - return CAIRO_STATUS_SUCCESS; + return cairo_scaled_font_status (gstate->scaled_font); } cairo_status_t @@ -1426,13 +1504,8 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, if (status) return status; - status = _cairo_scaled_font_text_to_glyphs (gstate->scaled_font, x, y, - utf8, glyphs, num_glyphs); - - if (status || !glyphs || !num_glyphs || !(*glyphs) || !(num_glyphs)) - return status; - - return CAIRO_STATUS_SUCCESS; + return _cairo_scaled_font_text_to_glyphs (gstate->scaled_font, x, y, + utf8, glyphs, num_glyphs); } cairo_status_t @@ -1468,7 +1541,7 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate, glyphs, num_glyphs, extents); - return CAIRO_STATUS_SUCCESS; + return cairo_scaled_font_status (gstate->scaled_font); } #define STACK_GLYPHS_LEN ((int) (CAIRO_STACK_BUFFER_SIZE / sizeof (cairo_glyph_t))) @@ -1505,7 +1578,9 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, _cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs, transformed_glyphs); - _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + status = _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + if (status) + goto CLEANUP_GLYPHS; status = _cairo_surface_show_glyphs (gstate->target, gstate->op, @@ -1516,6 +1591,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, _cairo_pattern_fini (&source_pattern.base); +CLEANUP_GLYPHS: if (transformed_glyphs != stack_transformed_glyphs) free (transformed_glyphs); diff --git a/gfx/cairo/cairo/src/cairo-hash-private.h b/gfx/cairo/cairo/src/cairo-hash-private.h index 617b8410dbdd..8ed3ba83aa3c 100644 --- a/gfx/cairo/cairo/src/cairo-hash-private.h +++ b/gfx/cairo/cairo/src/cairo-hash-private.h @@ -39,51 +39,13 @@ #ifndef CAIRO_HASH_PRIVATE_H #define CAIRO_HASH_PRIVATE_H +#include "cairo-types-private.h" + /* XXX: I'd like this file to be self-contained in terms of * includeability, but that's not really possible with the current * monolithic cairoint.h. So, for now, just include cairoint.h instead * if you want to include this file. */ -typedef struct _cairo_hash_table cairo_hash_table_t; - -/** - * cairo_hash_entry_t: - * - * A #cairo_hash_entry_t contains both a key and a value for - * cairo_hash_table_t. User-derived types for cairo_hash_entry_t must - * be type-compatible with this structure (eg. they must have an - * unsigned long as the first parameter. The easiest way to get this - * is to use: - * - * typedef _my_entry { - * cairo_hash_entry_t base; - * ... Remainder of key and value fields here .. - * } my_entry_t; - * - * which then allows a pointer to my_entry_t to be passed to any of - * the cairo_hash_table functions as follows without requiring a cast: - * - * _cairo_hash_table_insert (hash_table, &my_entry->base); - * - * IMPORTANT: The caller is reponsible for initializing - * my_entry->base.hash with a hash code derived from the key. The - * essential property of the hash code is that keys_equal must never - * return TRUE for two keys that have different hashes. The best hash - * code will reduce the frequency of two keys with the same code for - * which keys_equal returns FALSE. - * - * Which parts of the entry make up the "key" and which part make up - * the value are entirely up to the caller, (as determined by the - * computation going into base.hash as well as the keys_equal - * function). A few of the cairo_hash_table functions accept an entry - * which will be used exclusively as a "key", (indicated by a - * parameter name of key). In these cases, the value-related fields of - * the entry need not be initialized if so desired. - **/ -typedef struct _cairo_hash_entry { - unsigned long hash; -} cairo_hash_entry_t; - typedef cairo_bool_t (*cairo_hash_keys_equal_func_t) (const void *key_a, const void *key_b); diff --git a/gfx/cairo/cairo/src/cairo-hash.c b/gfx/cairo/cairo/src/cairo-hash.c index 948cd232f898..99343754f3f3 100644 --- a/gfx/cairo/cairo/src/cairo-hash.c +++ b/gfx/cairo/cairo/src/cairo-hash.c @@ -115,7 +115,7 @@ static const cairo_hash_table_arrangement_t hash_table_arrangements [] = { { 268435456, 590559793, 590559791 } }; -#define NUM_HASH_TABLE_ARRANGEMENTS ((int)(sizeof(hash_table_arrangements)/sizeof(hash_table_arrangements[0]))) +#define NUM_HASH_TABLE_ARRANGEMENTS ARRAY_LENGTH (hash_table_arrangements) struct _cairo_hash_table { cairo_hash_keys_equal_func_t keys_equal; @@ -481,8 +481,12 @@ _cairo_hash_table_insert (cairo_hash_table_t *hash_table, hash_table->live_entries++; status = _cairo_hash_table_resize (hash_table); - if (status) + if (status) { + /* abort the insert... */ + *entry = DEAD_ENTRY; + hash_table->live_entries--; return status; + } return CAIRO_STATUS_SUCCESS; } @@ -561,6 +565,9 @@ _cairo_hash_table_foreach (cairo_hash_table_t *hash_table, * the table may need resizing. Just do this every time * as the check is inexpensive. */ - if (--hash_table->iterating == 0) + if (--hash_table->iterating == 0) { + /* Should we fail to shrink the hash table, it is left unaltered, + * and we don't need to propagate the error status. */ _cairo_hash_table_resize (hash_table); + } } diff --git a/gfx/cairo/cairo/src/cairo-image-surface.c b/gfx/cairo/cairo/src/cairo-image-surface.c index 627901216b0b..ad41a4cba97b 100644 --- a/gfx/cairo/cairo/src/cairo-image-surface.c +++ b/gfx/cairo/cairo/src/cairo-image-surface.c @@ -36,7 +36,7 @@ #include "cairoint.h" -const cairo_image_surface_t _cairo_image_surface_nil_invalid_format = { +static const cairo_image_surface_t _cairo_image_surface_nil_invalid_format = { { &cairo_image_surface_backend, /* backend */ CAIRO_SURFACE_TYPE_IMAGE, @@ -131,7 +131,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, /* Try to recover a cairo_format_t from a pixman_format * by looking at the bpp and masks values. */ -static cairo_format_t +static cairo_internal_format_t _cairo_format_from_pixman_format (pixman_format_t *pixman_format) { unsigned int bpp, am, rm, gm, bm; @@ -167,7 +167,7 @@ _cairo_format_from_pixman_format (pixman_format_t *pixman_format) rm == 0xf800 && gm == 0x07e0 && bm == 0x001f) - return CAIRO_FORMAT_RGB16_565; + return CAIRO_INTERNAL_FORMAT_RGB16_565; break; case 8: if (am == 0xff && @@ -212,28 +212,23 @@ _cairo_image_surface_create_with_masks (unsigned char *data, int stride) { cairo_surface_t *surface; - pixman_format_t *pixman_format; - pixman_image_t *pixman_image; - cairo_format_t cairo_format; + pixman_format_t pixman_format; + pixman_image_t *pixman_image; + cairo_format_t cairo_format; - pixman_format = pixman_format_create_masks (format->bpp, - format->alpha_mask, - format->red_mask, - format->green_mask, - format->blue_mask); + pixman_format_init_masks (&pixman_format, + format->bpp, + format->alpha_mask, + format->red_mask, + format->green_mask, + format->blue_mask); - if (pixman_format == NULL) { - _cairo_error (CAIRO_STATUS_NO_MEMORY); - return (cairo_surface_t*) &_cairo_surface_nil; - } + cairo_format = _cairo_format_from_pixman_format (&pixman_format); - cairo_format = _cairo_format_from_pixman_format (pixman_format); - - pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format, + pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, + &pixman_format, width, height, format->bpp, stride); - pixman_format_destroy (pixman_format); - if (pixman_image == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_surface_t*) &_cairo_surface_nil; @@ -241,28 +236,33 @@ _cairo_image_surface_create_with_masks (unsigned char *data, surface = _cairo_image_surface_create_for_pixman_image (pixman_image, cairo_format); + if (cairo_surface_status (surface)) { + pixman_image_destroy (pixman_image); + } return surface; } -static pixman_format_t * -_create_pixman_format (cairo_format_t format) +static void +_init_pixman_format (pixman_format_t *pixman_format, cairo_format_t format) { + int ret; switch (format) { case CAIRO_FORMAT_A1: - return pixman_format_create (PIXMAN_FORMAT_NAME_A1); + ret = pixman_format_init (pixman_format, PIXMAN_FORMAT_NAME_A1); break; case CAIRO_FORMAT_A8: - return pixman_format_create (PIXMAN_FORMAT_NAME_A8); + ret = pixman_format_init (pixman_format, PIXMAN_FORMAT_NAME_A8); break; case CAIRO_FORMAT_RGB24: - return pixman_format_create (PIXMAN_FORMAT_NAME_RGB24); + ret = pixman_format_init (pixman_format, PIXMAN_FORMAT_NAME_RGB24); break; case CAIRO_FORMAT_ARGB32: default: - return pixman_format_create (PIXMAN_FORMAT_NAME_ARGB32); + ret = pixman_format_init (pixman_format, PIXMAN_FORMAT_NAME_ARGB32); break; } + assert (ret); } /** @@ -290,31 +290,27 @@ cairo_image_surface_create (cairo_format_t format, int width, int height) { - cairo_surface_t *surface; - pixman_format_t *pixman_format; - pixman_image_t *pixman_image; + cairo_surface_t *surface; + pixman_format_t pixman_format; + pixman_image_t *pixman_image; if (! CAIRO_FORMAT_VALID (format)) { _cairo_error (CAIRO_STATUS_INVALID_FORMAT); return (cairo_surface_t*) &_cairo_image_surface_nil_invalid_format; } - pixman_format = _create_pixman_format (format); - if (pixman_format == NULL) { - _cairo_error (CAIRO_STATUS_NO_MEMORY); - return (cairo_surface_t*) &_cairo_surface_nil; - } - - pixman_image = pixman_image_create (pixman_format, width, height); - - pixman_format_destroy (pixman_format); + _init_pixman_format (&pixman_format, format); + pixman_image = pixman_image_create (&pixman_format, width, height); if (pixman_image == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_surface_t*) &_cairo_surface_nil; } surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format); + if (cairo_surface_status (surface)) { + pixman_image_destroy (pixman_image); + } return surface; } @@ -369,32 +365,29 @@ cairo_image_surface_create_for_data (unsigned char *data, int height, int stride) { - cairo_surface_t *surface; - pixman_format_t *pixman_format; - pixman_image_t *pixman_image; + cairo_surface_t *surface; + pixman_format_t pixman_format; + pixman_image_t *pixman_image; if (! CAIRO_FORMAT_VALID (format)) return (cairo_surface_t*) &_cairo_surface_nil; - pixman_format = _create_pixman_format (format); - if (pixman_format == NULL) { - _cairo_error (CAIRO_STATUS_NO_MEMORY); - return (cairo_surface_t*) &_cairo_surface_nil; - } + _init_pixman_format (&pixman_format, format); - pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format, + pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, + &pixman_format, width, height, _cairo_format_bpp (format), stride); - - pixman_format_destroy (pixman_format); - if (pixman_image == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_surface_t*) &_cairo_surface_nil; } surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format); + if (cairo_surface_status (surface)) { + pixman_image_destroy (pixman_image); + } return surface; } @@ -567,7 +560,7 @@ _cairo_content_from_format (cairo_format_t format) case CAIRO_INTERNAL_FORMAT_ABGR32: return CAIRO_CONTENT_COLOR_ALPHA; case CAIRO_FORMAT_RGB24: - case CAIRO_FORMAT_RGB16_565: + case CAIRO_INTERNAL_FORMAT_RGB16_565: case CAIRO_INTERNAL_FORMAT_BGR24: return CAIRO_CONTENT_COLOR; case CAIRO_FORMAT_A8: @@ -690,7 +683,8 @@ _cairo_image_surface_set_matrix (cairo_image_surface_t *surface, _cairo_matrix_to_pixman_matrix (matrix, &pixman_transform); - pixman_image_set_transform (surface->pixman_image, &pixman_transform); + if (pixman_image_set_transform (surface->pixman_image, &pixman_transform)) + return CAIRO_STATUS_NO_MEMORY; return CAIRO_STATUS_SUCCESS; } @@ -907,8 +901,10 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, pixman_color.alpha = color->alpha_short; /* XXX: The pixman_rectangle_t cast is evil... it needs to go away somehow. */ - pixman_fill_rectangles (_pixman_operator(op), surface->pixman_image, - &pixman_color, (pixman_rectangle_t *) rects, num_rects); + if (pixman_fill_rectangles (_pixman_operator(op), surface->pixman_image, + &pixman_color, + (pixman_rectangle_t *) rects, num_rects)) + return CAIRO_STATUS_NO_MEMORY; return CAIRO_STATUS_SUCCESS; } @@ -932,10 +928,11 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, cairo_image_surface_t *src; cairo_int_status_t status; pixman_image_t *mask; - pixman_format_t *format; + pixman_format_t format; pixman_bits_t *mask_data; - int mask_stride; - int mask_bpp; + int mask_stride; + int mask_bpp; + int ret; /* Special case adding trapezoids onto a mask surface; we want to avoid * creating an intermediate temporary mask unecessarily. @@ -974,7 +971,8 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, switch (antialias) { case CAIRO_ANTIALIAS_NONE: - format = pixman_format_create (PIXMAN_FORMAT_NAME_A1); + ret = pixman_format_init (&format, PIXMAN_FORMAT_NAME_A1); + assert (ret); mask_stride = (width + 31)/8; mask_bpp = 1; break; @@ -982,28 +980,23 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, case CAIRO_ANTIALIAS_SUBPIXEL: case CAIRO_ANTIALIAS_DEFAULT: default: - format = pixman_format_create (PIXMAN_FORMAT_NAME_A8); + ret = pixman_format_init (&format, PIXMAN_FORMAT_NAME_A8); + assert (ret); mask_stride = (width + 3) & ~3; mask_bpp = 8; break; } - if (!format) { - status = CAIRO_STATUS_NO_MEMORY; - goto CLEANUP_SOURCE; - } /* The image must be initially transparent */ mask_data = calloc (1, mask_stride * height); - if (!mask_data) { + if (mask_data == NULL) { status = CAIRO_STATUS_NO_MEMORY; - pixman_format_destroy (format); goto CLEANUP_SOURCE; } - mask = pixman_image_create_for_data (mask_data, format, width, height, + mask = pixman_image_create_for_data (mask_data, &format, width, height, mask_bpp, mask_stride); - pixman_format_destroy (format); - if (!mask) { + if (mask == NULL) { status = CAIRO_STATUS_NO_MEMORY; goto CLEANUP_IMAGE_DATA; } @@ -1047,7 +1040,8 @@ _cairo_image_surface_set_clip_region (void *abstract_surface, { cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface; - pixman_image_set_clip_region (surface->pixman_image, region); + if (pixman_image_set_clip_region (surface->pixman_image, region)) + return CAIRO_STATUS_NO_MEMORY; surface->has_clip = region != NULL; @@ -1068,6 +1062,28 @@ _cairo_image_surface_get_extents (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } +static void +_cairo_image_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + _cairo_font_options_init_default (options); + + cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON); +} + +static cairo_status_t +_cairo_image_surface_reset (void *abstract_surface) +{ + cairo_image_surface_t *surface = abstract_surface; + cairo_status_t status; + + status = _cairo_image_surface_set_clip_region (surface, NULL); + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} + /** * _cairo_surface_is_image: * @surface: a #cairo_surface_t @@ -1099,7 +1115,22 @@ const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_set_clip_region, NULL, /* intersect_clip_path */ _cairo_image_surface_get_extents, - NULL /* old_show_glyphs */ + NULL, /* old_show_glyphs */ + _cairo_image_surface_get_font_options, + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + NULL, //* font_fini */ + NULL, //* glyph_fini */ + + NULL, /* paint */ + NULL, /* mask */ + NULL, /* stroke */ + NULL, /* fill */ + NULL, /* show_glyphs */ + NULL, /* snapshot */ + NULL, /* is_similar */ + + _cairo_image_surface_reset }; /* A convenience function for when one needs to coerce an image diff --git a/gfx/cairo/cairo/src/cairo-matrix.c b/gfx/cairo/cairo/src/cairo-matrix.c index b689f2aaff76..c85b02768acc 100644 --- a/gfx/cairo/cairo/src/cairo-matrix.c +++ b/gfx/cairo/cairo/src/cairo-matrix.c @@ -35,7 +35,6 @@ */ #define _GNU_SOURCE -#include #include "cairoint.h" @@ -198,7 +197,7 @@ slim_hidden_def(cairo_matrix_init_scale); * @sx: scale factor in the X direction * @sy: scale factor in the Y direction * - * Applies scaling by @tx, @ty to the transformation in @matrix. The + * Applies scaling by @sx, @sy to the transformation in @matrix. The * effect of the new transformation is to first scale the coordinates * by @sx and @sy, then apply the original transformation to the coordinates. **/ @@ -496,7 +495,7 @@ _cairo_matrix_compute_determinant (const cairo_matrix_t *matrix, } /* Compute the amount that each basis vector is scaled by. */ -cairo_status_t +void _cairo_matrix_compute_scale_factors (const cairo_matrix_t *matrix, double *sx, double *sy, int x_major) { @@ -536,8 +535,6 @@ _cairo_matrix_compute_scale_factors (const cairo_matrix_t *matrix, *sy = major; } } - - return CAIRO_STATUS_SUCCESS; } cairo_bool_t diff --git a/gfx/cairo/cairo/src/cairo-meta-surface.c b/gfx/cairo/cairo/src/cairo-meta-surface.c index e196df29cf3a..8dbd6084167a 100644 --- a/gfx/cairo/cairo/src/cairo-meta-surface.c +++ b/gfx/cairo/cairo/src/cairo-meta-surface.c @@ -212,7 +212,11 @@ static cairo_status_t _init_pattern_with_snapshot (cairo_pattern_t *pattern, const cairo_pattern_t *other) { - _cairo_pattern_init_copy (pattern, other); + cairo_status_t status; + + status = _cairo_pattern_init_copy (pattern, other); + if (status) + return status; if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *surface_pattern = @@ -648,6 +652,9 @@ _cairo_meta_surface_replay (cairo_surface_t *surface, cairo_matrix_t *device_transform = &target->device_transform; cairo_path_fixed_t path_copy, *dev_path; + if (surface->status) + return surface->status; + meta = (cairo_meta_surface_t *) surface; status = CAIRO_STATUS_SUCCESS; @@ -668,7 +675,9 @@ _cairo_meta_surface_replay (cairo_surface_t *surface, dev_path = _cairo_command_get_path (command); if (dev_path && has_device_transform) { - _cairo_path_fixed_init_copy (&path_copy, dev_path); + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); + if (status) + break; _cairo_path_fixed_device_transform (&path_copy, device_transform); dev_path = &path_copy; } @@ -754,7 +763,7 @@ _cairo_meta_surface_replay (cairo_surface_t *surface, /* XXX Meta surface clipping is broken and requires some * cairo-gstate.c rewriting. Work around it for now. */ if (dev_path == NULL) - status = _cairo_clip_reset (&clip); + _cairo_clip_reset (&clip); else status = _cairo_clip_clip (&clip, dev_path, command->intersect_clip_path.fill_rule, @@ -773,7 +782,7 @@ _cairo_meta_surface_replay (cairo_surface_t *surface, break; } - _cairo_clip_fini (&clip); + _cairo_clip_reset (&clip); return status; } diff --git a/gfx/cairo/cairo/src/cairo-mutex-list-private.h b/gfx/cairo/cairo/src/cairo-mutex-list-private.h new file mode 100644 index 000000000000..abb4a9a3db3e --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-mutex-list-private.h @@ -0,0 +1,51 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Mathias Hasselmann + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * Contributor(s): + * Mathias Hasselmann + */ + + +CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_pattern_cache_lock); +CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock); + +CAIRO_MUTEX_DECLARE (_cairo_font_face_mutex); +CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex); + +#if CAIRO_HAS_FT_FONT +CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex); +#endif + +#if CAIRO_HAS_XLIB_SURFACE +CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex); +#endif + + +/* Undefine, to err on unintended inclusion */ +#undef CAIRO_MUTEX_DECLARE diff --git a/gfx/cairo/cairo/src/cairo-mutex-private.h b/gfx/cairo/cairo/src/cairo-mutex-private.h new file mode 100644 index 000000000000..88e88bb0f5ce --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-mutex-private.h @@ -0,0 +1,175 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005,2007 Red Hat, Inc. + * Copyright © 2007 Mathias Hasselmann + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Mathias Hasselmann + * Behdad Esfahbod + */ + +#ifndef CAIRO_MUTEX_PRIVATE_H +#define CAIRO_MUTEX_PRIVATE_H + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "cairo-mutex-type-private.h" + +/* Only the following three are mandatory at this point */ +#ifndef CAIRO_MUTEX_LOCK +# error "CAIRO_MUTEX_LOCK not defined. Check cairo-mutex-type-private.h." +#endif +#ifndef CAIRO_MUTEX_UNLOCK +# error "CAIRO_MUTEX_UNLOCK not defined. Check cairo-mutex-type-private.h." +#endif +#ifndef CAIRO_MUTEX_NIL_INITIALIZER +# error "CAIRO_MUTEX_NIL_INITIALIZER not defined. Check cairo-mutex-type-private.h." +#endif + +CAIRO_BEGIN_DECLS + + +#define CAIRO_MUTEX_DECLARE(mutex) extern cairo_mutex_t mutex +#include "cairo-mutex-list-private.h" +#undef CAIRO_MUTEX_DECLARE + + +/* make sure implementations don't fool us: we decide these ourself */ +#undef _CAIRO_MUTEX_USE_STATIC_INITIALIZER +#undef _CAIRO_MUTEX_USE_STATIC_FINALIZER + + +#ifdef CAIRO_MUTEX_INIT + +/* If CAIRO_MUTEX_INIT is defined, we may need to initialize all + * static mutex'es. */ +# ifndef CAIRO_MUTEX_INITIALIZE +# define CAIRO_MUTEX_INITIALIZE() do { \ + if (!_cairo_mutex_initialized) \ + _cairo_mutex_initialize (); \ + } while(0) + + cairo_private void _cairo_mutex_initialize (void); + + /* and make sure we implement the above */ +# define _CAIRO_MUTEX_USE_STATIC_INITIALIZER 1 +# endif /* CAIRO_MUTEX_INITIALIZE */ + +#else /* no CAIRO_MUTEX_INIT */ + +/* Otherwise we probably don't need to initialize static mutex'es, */ +# ifndef CAIRO_MUTEX_INITIALIZE +# define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP +# endif /* CAIRO_MUTEX_INITIALIZE */ + +/* and dynamic ones can be initialized using the static initializer. */ +# define CAIRO_MUTEX_INIT(mutex) do { \ + cairo_mutex_t _tmp_mutex = CAIRO_MUTEX_NIL_INITIALIZER; \ + memcpy (&(mutex), &_tmp_mutex, sizeof (_tmp_mutex)); \ + } while (0) + +#endif /* CAIRO_MUTEX_INIT */ + + +#ifdef CAIRO_MUTEX_FINI + +/* If CAIRO_MUTEX_FINI is defined, we may need to finalize all + * static mutex'es. */ +# ifndef CAIRO_MUTEX_FINALIZE +# define CAIRO_MUTEX_FINALIZE() do { \ + if (_cairo_mutex_initialized) \ + _cairo_mutex_finalize (); \ + } while(0) + + cairo_private void _cairo_mutex_finalize (void); + + /* and make sure we implement the above */ +# define _CAIRO_MUTEX_USE_STATIC_FINALIZER 1 +# endif /* CAIRO_MUTEX_FINALIZE */ + +#else /* no CAIRO_MUTEX_FINI */ + +/* Otherwise we probably don't need to finalize static mutex'es, */ +# ifndef CAIRO_MUTEX_FINALIZE +# define CAIRO_MUTEX_FINALIZE() CAIRO_MUTEX_NOOP +# endif /* CAIRO_MUTEX_FINALIZE */ + +/* neither do the dynamic ones. */ +# define CAIRO_MUTEX_FINI(mutex) CAIRO_MUTEX_NOOP1(mutex) + +#endif /* CAIRO_MUTEX_FINI */ + + +#ifndef _CAIRO_MUTEX_USE_STATIC_INITIALIZER +#define _CAIRO_MUTEX_USE_STATIC_INITIALIZER 0 +#endif +#ifndef _CAIRO_MUTEX_USE_STATIC_FINALIZER +#define _CAIRO_MUTEX_USE_STATIC_FINALIZER 0 +#endif + +/* only if using static initializer and/or finalizer define the boolean */ +#if _CAIRO_MUTEX_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_USE_STATIC_FINALIZER + cairo_private extern cairo_bool_t _cairo_mutex_initialized; +#endif + + +CAIRO_END_DECLS + +/* Make sure everything we want is defined */ +#ifndef CAIRO_MUTEX_INITIALIZE +# error "CAIRO_MUTEX_INITIALIZE not defined" +#endif +#ifndef CAIRO_MUTEX_FINALIZE +# error "CAIRO_MUTEX_FINALIZE not defined" +#endif +#ifndef CAIRO_MUTEX_LOCK +# error "CAIRO_MUTEX_LOCK not defined" +#endif +#ifndef CAIRO_MUTEX_UNLOCK +# error "CAIRO_MUTEX_UNLOCK not defined" +#endif +#ifndef CAIRO_MUTEX_INIT +# error "CAIRO_MUTEX_INIT not defined" +#endif +#ifndef CAIRO_MUTEX_FINI +# error "CAIRO_MUTEX_FINI not defined" +#endif +#ifndef CAIRO_MUTEX_NIL_INITIALIZER +# error "CAIRO_MUTEX_NIL_INITIALIZER not defined" +#endif + +#endif diff --git a/gfx/cairo/cairo/src/cairo-mutex-type-private.h b/gfx/cairo/cairo/src/cairo-mutex-type-private.h new file mode 100644 index 000000000000..59d581afadda --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-mutex-type-private.h @@ -0,0 +1,210 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005,2007 Red Hat, Inc. + * Copyright © 2007 Mathias Hasselmann + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Mathias Hasselmann + * Behdad Esfahbod + */ + +#ifndef CAIRO_MUTEX_TYPE_PRIVATE_H +#define CAIRO_MUTEX_TYPE_PRIVATE_H + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +CAIRO_BEGIN_DECLS + + +/* A fully qualified no-operation statement */ +#define CAIRO_MUTEX_NOOP do {/*no-op*/} while (0) +/* And one that evaluates it's argument once */ +#define CAIRO_MUTEX_NOOP1(expr) do { if (expr) ; } while (0) + + +/* Cairo mutex implementation: + * + * Any new mutex implementation needs to do the following: + * + * - Condition on the right header or feature. Headers are + * preferred as eg. you still can use win32 mutex implementation + * on a win32 system even if you do not compile the win32 + * surface/backend. + * + * - typedef cairo_mutex_t to the proper mutex type on your target + * system. Note that you may or may not need to use a pointer, + * depending on what kinds of initialization your mutex + * implementation supports. No trailing semicolon needed. + * You should be able to compile the following snippet (don't try + * running it): + * + * cairo_mutex_t _cairo_some_mutex; + * + * - #define CAIRO_MUTEX_LOCK(mutex) and CAIRO_MUTEX_UNLOCK(mutex) to + * proper statement to lock/unlock the mutex object passed in. + * You can (and should) assume that the mutex is already + * initialized, and is-not-already-locked/is-locked, + * respectively. Use the "do { ... } while (0)" idiom if necessary. + * No trailing semicolons are needed (in any macro you define here). + * You should be able to compile the following snippet: + * + * cairo_mutex_t _cairo_some_mutex; + * + * if (1) + * CAIRO_MUTEX_LOCK (_cairo_some_mutex); + * else + * CAIRO_MUTEX_UNLOCK (_cairo_some_mutex); + * + * - #define CAIRO_MUTEX_NIL_INITIALIZER to something that can + * initialize the cairo_mutex_t type you defined. Most of the + * time one of 0, NULL, or {} works. At this point + * you should be able to compile the following snippet: + * + * cairo_mutex_t _cairo_some_mutex = CAIRO_MUTEX_NIL_INITIALIZER; + * + * if (1) + * CAIRO_MUTEX_LOCK (_cairo_some_mutex); + * else + * CAIRO_MUTEX_UNLOCK (_cairo_some_mutex); + * + * - If the above code is not enough to initialize a mutex on + * your platform, #define CAIRO_MUTEX_INIT(mutex) to statement + * to initialize the mutex (allocate resources, etc). Such that + * you should be able to compile AND RUN the following snippet: + * + * cairo_mutex_t _cairo_some_mutex = CAIRO_MUTEX_NIL_INITIALIZER; + * + * CAIRO_MUTEX_INIT (_cairo_some_mutex); + * + * if (1) + * CAIRO_MUTEX_LOCK (_cairo_some_mutex); + * else + * CAIRO_MUTEX_UNLOCK (_cairo_some_mutex); + * + * - If you define CAIRO_MUTEX_INIT(mutex), cairo will use it to + * initialize all static mutex'es. If for any reason that should + * not happen (eg. CAIRO_MUTEX_INIT is just a faster way than + * what cairo does using CAIRO_MUTEX_NIL_INITIALIZER), then + * #define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP + * + * - If your system supports freeing a mutex object (deallocating + * resources, etc), then #define CAIRO_MUTEX_FINI(mutex) to do + * that. + * + * - If you define CAIRO_MUTEX_FINI(mutex), cairo will use it to + * define a finalizer function to finalize all static mutex'es. + * However, it's up to you to call CAIRO_MUTEX_FINALIZE() at + * proper places, eg. when the system is unloading the cairo library. + * So, if for any reason finalizing static mutex'es is not needed + * (eg. you never call CAIRO_MUTEX_FINALIZE), then + * #define CAIRO_MUTEX_FINALIZE() CAIRO_MUTEX_NOOP + * + * - That is all. If for any reason you think the above API is + * not enough to implement cairo_mutex_t on your system, please + * stop and write to the cairo mailing list about it. DO NOT + * poke around cairo-mutex-private.h for possible solutions. + */ + +#if CAIRO_NO_MUTEX + +/* A poor man's mutex */ + + typedef int cairo_mutex_t; + +# define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP +# define CAIRO_MUTEX_LOCK(mutex) do { while (mutex) ; (mutex) = 1; } while (0) +# define CAIRO_MUTEX_UNLOCK(mutex) (mutex) = 0 +# define CAIRO_MUTEX_NIL_INITIALIZER 0 + +#elif HAVE_PTHREAD_H /*******************************************************/ + +# include + + typedef pthread_mutex_t cairo_mutex_t; + +# define CAIRO_MUTEX_LOCK(mutex) pthread_mutex_lock (&(mutex)) +# define CAIRO_MUTEX_UNLOCK(mutex) pthread_mutex_unlock (&(mutex)) +# define CAIRO_MUTEX_FINI(mutex) pthread_mutex_destroy (&(mutex)) +# define CAIRO_MUTEX_FINALIZE() CAIRO_MUTEX_NOOP +# define CAIRO_MUTEX_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER + +#elif HAVE_WINDOWS_H /*******************************************************/ + +# include + + typedef CRITICAL_SECTION cairo_mutex_t; + +# define CAIRO_MUTEX_LOCK(mutex) EnterCriticalSection (&(mutex)) +# define CAIRO_MUTEX_UNLOCK(mutex) LeaveCriticalSection (&(mutex)) +# define CAIRO_MUTEX_INIT(mutex) InitializeCriticalSection (&(mutex)) +# define CAIRO_MUTEX_FINI(mutex) DeleteCriticalSection (&(mutex)) +# define CAIRO_MUTEX_NIL_INITIALIZER { NULL, 0, 0, NULL, NULL, 0 } + +#elif defined __OS2__ /******************************************************/ + +# define INCL_BASE +# define INCL_PM +# include + + typedef HMTX cairo_mutex_t; + +# define CAIRO_MUTEX_LOCK(mutex) DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT) +# define CAIRO_MUTEX_UNLOCK(mutex) DosReleaseMutexSem(mutex) +# define CAIRO_MUTEX_INIT(mutex) DosCreateMutexSem (NULL, &(mutex), 0L, FALSE) +# define CAIRO_MUTEX_FINI(mutex) DosCloseMutexSem (mutex) +# define CAIRO_MUTEX_NIL_INITIALIZER 0 + +#elif CAIRO_HAS_BEOS_SURFACE /***********************************************/ + + typedef BLocker* cairo_mutex_t; + +# define CAIRO_MUTEX_LOCK(mutex) (mutex)->Lock() +# define CAIRO_MUTEX_UNLOCK(mutex) (mutex)->Unlock() +# define CAIRO_MUTEX_INIT(mutex) (mutex) = new BLocker() +# define CAIRO_MUTEX_FINI(mutex) delete (mutex) +# define CAIRO_MUTEX_NIL_INITIALIZER NULL + +#else /**********************************************************************/ + +# error "XXX: No mutex implementation found. Cairo will not work with multiple threads. Define CAIRO_NO_MUTEX to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support." + + +#endif + +CAIRO_END_DECLS + +#endif diff --git a/gfx/cairo/cairo/src/cairo-mutex.c b/gfx/cairo/cairo/src/cairo-mutex.c new file mode 100644 index 000000000000..88aaf0d0290b --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-mutex.c @@ -0,0 +1,80 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Mathias Hasselmann + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * Contributor(s): + * Mathias Hasselmann + */ + +#include "cairoint.h" + +#define CAIRO_MUTEX_DECLARE(mutex) cairo_mutex_t mutex = CAIRO_MUTEX_NIL_INITIALIZER +#include "cairo-mutex-list-private.h" +#undef CAIRO_MUTEX_DECLARE + +#if _CAIRO_MUTEX_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_USE_STATIC_FINALIZER + +# if _CAIRO_MUTEX_USE_STATIC_INITIALIZER +# define _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE FALSE +# else +# define _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE TRUE +# endif + +cairo_bool_t _cairo_mutex_initialized = _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE; + +# undef _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE + +#endif + +#if _CAIRO_MUTEX_USE_STATIC_INITIALIZER +void _cairo_mutex_initialize (void) +{ + if (_cairo_mutex_initialized) + return; + + _cairo_mutex_initialized = TRUE; + +#define CAIRO_MUTEX_DECLARE(mutex) CAIRO_MUTEX_INIT (mutex) +#include "cairo-mutex-list-private.h" +#undef CAIRO_MUTEX_DECLARE +} +#endif + +#if _CAIRO_MUTEX_USE_STATIC_FINALIZER +void _cairo_mutex_finalize (void) +{ + if (!_cairo_mutex_initialized) + return; + + _cairo_mutex_initialized = FALSE; + +#define CAIRO_MUTEX_DECLARE(mutex) CAIRO_MUTEX_FINI (mutex) +#include "cairo-mutex-list-private.h" +#undef CAIRO_MUTEX_DECLARE +} +#endif diff --git a/gfx/cairo/cairo/src/cairo-os2-surface.c b/gfx/cairo/cairo/src/cairo-os2-surface.c index f6ec8f6256c5..319a7aba2fb9 100644 --- a/gfx/cairo/cairo/src/cairo-os2-surface.c +++ b/gfx/cairo/cairo/src/cairo-os2-surface.c @@ -35,8 +35,12 @@ * Peter Weilbacher */ -#include -#include +#include "cairoint.h" + +#include "cairo-os2-private.h" + +#include + #include #ifdef BUILD_CAIRO_DLL # define INCL_WIN @@ -49,9 +53,6 @@ # include # endif #endif -#include "cairoint.h" -#include "cairo-os2-private.h" -#include "fontconfig/fontconfig.h" /* * Here comes the extra API for the OS/2 platform. Currently it consists @@ -68,14 +69,6 @@ /* Initialization counter: */ static int cairo_os2_initialization_count = 0; -/* The mutex semaphores Cairo uses all around: */ -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; -#endif - static void inline DisableFPUException (void) { @@ -103,20 +96,10 @@ cairo_os2_init (void) DisableFPUException (); - /* Create the mutex semaphores we'll use! */ - - /* cairo-font.c: */ - 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); -#endif - /* Initialize FontConfig */ FcInit (); + + CAIRO_MUTEX_INITIALIZE (); } cairo_public void @@ -137,28 +120,7 @@ cairo_os2_fini (void) _cairo_ft_font_reset_static_data (); #endif - /* Destroy the mutex semaphores we've created! */ - /* cairo-font.c: */ - 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; - } -#endif + CAIRO_MUTEX_FINALIZE (); /* Uninitialize FontConfig */ FcFini (); diff --git a/gfx/cairo/cairo/src/cairo-output-stream-private.h b/gfx/cairo/cairo/src/cairo-output-stream-private.h index d68fbb4802e1..0600431eac6c 100644 --- a/gfx/cairo/cairo/src/cairo-output-stream-private.h +++ b/gfx/cairo/cairo/src/cairo-output-stream-private.h @@ -37,7 +37,7 @@ #ifndef CAIRO_OUTPUT_STREAM_PRIVATE_H #define CAIRO_OUTPUT_STREAM_PRIVATE_H -typedef struct _cairo_output_stream cairo_output_stream_t; +#include "cairo-types-private.h" typedef cairo_status_t (*cairo_output_stream_write_func_t) (cairo_output_stream_t *output_stream, const unsigned char *data, @@ -53,7 +53,7 @@ struct _cairo_output_stream { cairo_bool_t closed; }; -extern const cairo_private cairo_output_stream_t cairo_output_stream_nil; +extern const cairo_private cairo_output_stream_t _cairo_output_stream_nil; cairo_private void _cairo_output_stream_init (cairo_output_stream_t *stream, @@ -107,7 +107,7 @@ _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream, const char *data, size_t length); -cairo_private int +cairo_private void _cairo_dtostr (char *buffer, size_t size, double d); cairo_private void diff --git a/gfx/cairo/cairo/src/cairo-output-stream.c b/gfx/cairo/cairo/src/cairo-output-stream.c index df3ae4d4334c..b9f0d383aaf5 100644 --- a/gfx/cairo/cairo/src/cairo-output-stream.c +++ b/gfx/cairo/cairo/src/cairo-output-stream.c @@ -34,11 +34,12 @@ * Kristian Høgsberg */ -#include +#include "cairoint.h" + +#include "cairo-output-stream-private.h" + #include #include -#include "cairoint.h" -#include "cairo-output-stream-private.h" #ifdef _MSC_VER #define snprintf _snprintf @@ -63,7 +64,7 @@ _cairo_output_stream_fini (cairo_output_stream_t *stream) return _cairo_output_stream_close (stream); } -const cairo_output_stream_t cairo_output_stream_nil = { +const cairo_output_stream_t _cairo_output_stream_nil = { NULL, /* write_func */ NULL, /* close_func */ 0, /* position */ @@ -71,7 +72,7 @@ const cairo_output_stream_t cairo_output_stream_nil = { FALSE /* closed */ }; -static const cairo_output_stream_t cairo_output_stream_nil_write_error = { +static const cairo_output_stream_t _cairo_output_stream_nil_write_error = { NULL, /* write_func */ NULL, /* close_func */ 0, /* position */ @@ -119,7 +120,7 @@ _cairo_output_stream_create (cairo_write_func_t write_func, stream = malloc (sizeof (cairo_output_stream_with_closure_t)); if (stream == NULL) - return (cairo_output_stream_t *) &cairo_output_stream_nil; + return (cairo_output_stream_t *) &_cairo_output_stream_nil; _cairo_output_stream_init (&stream->base, closure_write, closure_close); stream->write_func = write_func; @@ -137,8 +138,8 @@ _cairo_output_stream_close (cairo_output_stream_t *stream) if (stream->closed) return stream->status; - if (stream == &cairo_output_stream_nil || - stream == &cairo_output_stream_nil_write_error) + if (stream == &_cairo_output_stream_nil || + stream == &_cairo_output_stream_nil_write_error) { return stream->status; } @@ -214,52 +215,49 @@ _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream, * has been relicensed under the LGPL/MPL dual license for inclusion * into cairo (see COPYING). -- Kristian Høgsberg */ - -int +void _cairo_dtostr (char *buffer, size_t size, double d) { - struct lconv *locale_data; - const char *decimal_point; - int decimal_point_len; - char *p; - int decimal_len; + struct lconv *locale_data; + const char *decimal_point; + int decimal_point_len; + char *p; + int decimal_len; - /* Omit the minus sign from negative zero. */ - if (d == 0.0) - d = 0.0; + /* Omit the minus sign from negative zero. */ + if (d == 0.0) + d = 0.0; - snprintf (buffer, size, "%f", d); + snprintf (buffer, size, "%f", d); - locale_data = localeconv (); - decimal_point = locale_data->decimal_point; - decimal_point_len = strlen (decimal_point); + locale_data = localeconv (); + decimal_point = locale_data->decimal_point; + decimal_point_len = strlen (decimal_point); - assert (decimal_point_len != 0); - p = buffer; + assert (decimal_point_len != 0); + p = buffer; - if (*p == '+' || *p == '-') - p++; + if (*p == '+' || *p == '-') + p++; - while (isdigit (*p)) - p++; + while (isdigit (*p)) + p++; - if (strncmp (p, decimal_point, decimal_point_len) == 0) { - *p = '.'; - decimal_len = strlen (p + decimal_point_len); - memmove (p + 1, p + decimal_point_len, decimal_len); - p[1 + decimal_len] = 0; + if (strncmp (p, decimal_point, decimal_point_len) == 0) { + *p = '.'; + decimal_len = strlen (p + decimal_point_len); + memmove (p + 1, p + decimal_point_len, decimal_len); + p[1 + decimal_len] = 0; - /* Remove trailing zeros and decimal point if possible. */ - for (p = p + decimal_len; *p == '0'; p--) - *p = 0; + /* Remove trailing zeros and decimal point if possible. */ + for (p = p + decimal_len; *p == '0'; p--) + *p = 0; - if (*p == '.') { - *p = 0; - p--; - } - } - - return p + 1 - buffer; + if (*p == '.') { + *p = 0; + p--; + } + } } enum { @@ -278,10 +276,13 @@ void _cairo_output_stream_vprintf (cairo_output_stream_t *stream, const char *fmt, va_list ap) { - char buffer[512], single_fmt[32]; - char *p, *end; +#define SINGLE_FMT_BUFFER_SIZE 32 + char buffer[512], single_fmt[SINGLE_FMT_BUFFER_SIZE]; + int single_fmt_length; + char *p; const char *f, *start; - int length_modifier; + int length_modifier, width; + cairo_bool_t var_width; if (stream->status) return; @@ -305,10 +306,14 @@ _cairo_output_stream_vprintf (cairo_output_stream_t *stream, if (*f == '0') f++; - if (isdigit (*f)) { - strtol (f, &end, 10); - f = end; - } + var_width = FALSE; + if (*f == '*') { + var_width = TRUE; + f++; + } + + while (isdigit (*f)) + f++; length_modifier = 0; if (*f == 'l') { @@ -316,9 +321,15 @@ _cairo_output_stream_vprintf (cairo_output_stream_t *stream, f++; } + /* The only format strings exist in the cairo implementation + * itself. So there's an internal consistency problem if any + * of them is larger than our format buffer size. */ + single_fmt_length = f - start + 1; + assert (single_fmt_length + 1 <= SINGLE_FMT_BUFFER_SIZE); + /* Reuse the format string for this conversion. */ - memcpy (single_fmt, start, f + 1 - start); - single_fmt[f + 1 - start] = '\0'; + memcpy (single_fmt, start, single_fmt_length); + single_fmt[single_fmt_length] = '\0'; /* Flush contents of buffer before snprintf()'ing into it. */ _cairo_output_stream_write (stream, buffer, p - buffer); @@ -337,15 +348,27 @@ _cairo_output_stream_vprintf (cairo_output_stream_t *stream, case 'o': case 'x': case 'X': - snprintf (buffer, sizeof buffer, single_fmt, va_arg (ap, int)); + if (var_width) { + width = va_arg (ap, int); + snprintf (buffer, sizeof buffer, + single_fmt, width, va_arg (ap, int)); + } else { + snprintf (buffer, sizeof buffer, single_fmt, va_arg (ap, int)); + } break; case 'd' | LENGTH_MODIFIER_LONG: case 'u' | LENGTH_MODIFIER_LONG: case 'o' | LENGTH_MODIFIER_LONG: case 'x' | LENGTH_MODIFIER_LONG: case 'X' | LENGTH_MODIFIER_LONG: - snprintf (buffer, sizeof buffer, - single_fmt, va_arg (ap, long int)); + if (var_width) { + width = va_arg (ap, int); + snprintf (buffer, sizeof buffer, + single_fmt, width, va_arg (ap, long int)); + } else { + snprintf (buffer, sizeof buffer, + single_fmt, va_arg (ap, long int)); + } break; case 's': snprintf (buffer, sizeof buffer, @@ -446,11 +469,11 @@ _cairo_output_stream_create_for_file (FILE *file) stdio_stream_t *stream; if (file == NULL) - return (cairo_output_stream_t *) &cairo_output_stream_nil_write_error; + return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error; stream = malloc (sizeof *stream); if (stream == NULL) - return (cairo_output_stream_t *) &cairo_output_stream_nil; + return (cairo_output_stream_t *) &_cairo_output_stream_nil; _cairo_output_stream_init (&stream->base, stdio_write, stdio_flush); stream->file = file; @@ -466,12 +489,12 @@ _cairo_output_stream_create_for_filename (const char *filename) file = fopen (filename, "wb"); if (file == NULL) - return (cairo_output_stream_t *) &cairo_output_stream_nil_write_error; + return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error; stream = malloc (sizeof *stream); if (stream == NULL) { fclose (file); - return (cairo_output_stream_t *) &cairo_output_stream_nil; + return (cairo_output_stream_t *) &_cairo_output_stream_nil; } _cairo_output_stream_init (&stream->base, stdio_write, stdio_close); @@ -512,7 +535,7 @@ _cairo_memory_stream_create (void) stream = malloc (sizeof *stream); if (stream == NULL) - return (cairo_output_stream_t *) &cairo_output_stream_nil; + return (cairo_output_stream_t *) &_cairo_output_stream_nil; _cairo_output_stream_init (&stream->base, memory_write, memory_close); _cairo_array_init (&stream->array, 1); diff --git a/gfx/cairo/cairo/src/cairo-paginated-private.h b/gfx/cairo/cairo/src/cairo-paginated-private.h new file mode 100644 index 000000000000..42d100b4bcfb --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-paginated-private.h @@ -0,0 +1,136 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl Worth + */ + +#ifndef CAIRO_PAGINATED_H +#define CAIRO_PAGINATED_H + +#include "cairoint.h" + +struct _cairo_paginated_surface_backend { + /* Optional. Will be called once for each page. + * + * NOTE: With respect to the order of drawing operations as seen + * by the target, this call will occur before any drawing + * operations for the relevant page. However, with respect to the + * function calls as made by the user, this call will be *after* + * any drawing operations for the page, (that is, it will occur + * during the user's call to cairo_show_page or cairo_copy_page). + */ + cairo_warn cairo_int_status_t + (*start_page) (void *surface); + + /* Required. Will be called twice for each page, once with an + * argument of CAIRO_PAGINATED_MODE_ANALYZE and once with + * CAIRO_PAGINATED_MODE_RENDER. See more details in the + * documentation for _cairo_paginated_surface_create below. + */ + void + (*set_paginated_mode) (void *surface, + cairo_paginated_mode_t mode); +}; + +/* A cairo_paginated_surface provides a very convenient wrapper that + * is well-suited for doing the analysis common to most surfaces that + * have paginated output, (that is, things directed at printers, or + * for saving content in files such as PostScript or PDF files). + * + * To use the paginated surface, you'll first need to create your + * 'real' surface using _cairo_surface_init and the standard + * cairo_surface_backend_t. Then you also call + * _cairo_paginated_surface_create which takes its own, much simpler, + * cairo_paginated_surface_backend. You are free to return the result + * of _cairo_paginated_surface_create from your public + * cairo__surface_create. The paginated backend will be careful + * to not let the user see that they really got a "wrapped" + * surface. See test-paginated-surface.c for a fairly minimal example + * of a paginated-using surface. That should be a reasonable example + * to follow. + * + * What the paginated surface does is first save all drawing + * operations for a page into a meta-surface. Then when the user calls + * cairo_show_page, the paginated surface performs the following + * sequence of operations (using the backend functions passed to + * cairo_paginated_surface_create): + * + * 1. Calls start_page (if non NULL). At this point, it is appropriate + * for the target to emit any page-specific header information into + * its output. + * + * 2. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_ANALYZE + * + * 3. Replays the meta-surface to the target surface, (with an + * analysis surface inserted between which watches the return value + * from each operation). This analysis stage is used to decide which + * operations will require fallbacks. + * + * 4. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_RENDER + * + * 5. Replays a subset of the meta-surface operations to the target surface + * + * 6. Replays the remaining operations to an image surface, sets an + * appropriate clip on the target, then paints the resulting image + * surface to the target. + * + * So, the target will see drawing operations during two separate + * stages, (ANALYZE and RENDER). During the ANALYZE phase the target + * should not actually perform any rendering, (for example, if + * performing output to a file, no output should be generated during + * this stage). Instead the drawing functions simply need to return + * CAIRO_STATUS_SUCCESS or CAIRO_INT_STATUS_UNSUPPORTED to indicate + * whether rendering would be supported. And it should do this as + * quickly as possible. + * + * NOTE: The paginated surface layer assumes that the target surface + * is "blank" by default at the beginning of each page, without any + * need for an explicit erasea operation, (as opposed to an image + * surface, for example, which might have uninitialized content + * originally). As such, it optimizes away CLEAR operations that + * happen at the beginning of each page---the target surface will not + * even see these operations. + */ +cairo_private cairo_surface_t * +_cairo_paginated_surface_create (cairo_surface_t *target, + cairo_content_t content, + int width, + int height, + const cairo_paginated_surface_backend_t *backend); + +cairo_private cairo_surface_t * +_cairo_paginated_surface_get_target (cairo_surface_t *surface); + +cairo_private cairo_bool_t +_cairo_surface_is_paginated (cairo_surface_t *surface); + +#endif /* CAIRO_PAGINATED_H */ diff --git a/gfx/cairo/cairo/src/cairo-paginated-surface-private.h b/gfx/cairo/cairo/src/cairo-paginated-surface-private.h index b5e4d5c9b808..b406cac15002 100644 --- a/gfx/cairo/cairo/src/cairo-paginated-surface-private.h +++ b/gfx/cairo/cairo/src/cairo-paginated-surface-private.h @@ -36,106 +36,37 @@ #ifndef CAIRO_PAGINATED_SURFACE_H #define CAIRO_PAGINATED_SURFACE_H -#include "cairoint.h" +#include "cairo.h" -typedef enum { - CAIRO_PAGINATED_MODE_ANALYZE, /* analyze page regions */ - CAIRO_PAGINATED_MODE_RENDER /* render page contents */ -} cairo_paginated_mode_t; +#include "cairo-surface-private.h" -typedef struct _cairo_paginated_surface_backend { - /* Optional. Will be called once for each page. - * - * NOTE: With respect to the order of drawing operations as seen - * by the target, this call will occur before any drawing - * operations for the relevant page. However, with respect to the - * function calls as made by the user, this call will be *after* - * any drawing operations for the page, (that is, it will occur - * during the user's call to cairo_show_page or cairo_copy_page). - */ - cairo_int_status_t - (*start_page) (void *surface); +typedef struct _cairo_paginated_surface { + cairo_surface_t base; - /* Required. Will be called twice for each page, once with an - * argument of CAIRO_PAGINATED_MODE_ANALYZE and once with - * CAIRO_PAGINATED_MODE_RENDER. See more details in the - * documentation for _cairo_paginated_surface_create below. - */ - void - (*set_paginated_mode) (void *surface, - cairo_paginated_mode_t mode); -} cairo_paginated_surface_backend_t; + /* The target surface to hold the final result. */ + cairo_surface_t *target; -/* A cairo_paginated_surface provides a very convenient wrapper that - * is well-suited for doing the analysis common to most surfaces that - * have paginated output, (that is, things directed at printers, or - * for saving content in files such as PostScript or PDF files). - * - * To use the paginated surface, you'll first need to create your - * 'real' surface using _cairo_surface_init and the standard - * cairo_surface_backend_t. Then you also call - * _cairo_paginated_surface_create which takes its own, much simpler, - * cairo_paginated_surface_backend. You are free to return the result - * of _cairo_paginated_surface_create from your public - * cairo__surface_create. The paginated backend will be careful - * to not let the user see that they really got a "wrapped" - * surface. See test-paginated-surface.c for a fairly minimal example - * of a paginated-using surface. That should be a reasonable example - * to follow. - * - * What the paginated surface does is first save all drawing - * operations for a page into a meta-surface. Then when the user calls - * cairo_show_page, the paginated surface performs the following - * sequence of operations (using the backend functions passed to - * cairo_paginated_surface_create): - * - * 1. Calls start_page (if non NULL). At this point, it is appropriate - * for the target to emit any page-specific header information into - * its output. - * - * 2. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_ANALYZE - * - * 3. Replays the meta-surface to the target surface, (with an - * analysis surface inserted between which watches the return value - * from each operation). This analysis stage is used to decide which - * operations will require fallbacks. - * - * 4. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_RENDER - * - * 5. Replays a subset of the meta-surface operations to the target surface - * - * 6. Replays the remaining operations to an image surface, sets an - * appropriate clip on the target, then paints the resulting image - * surface to the target. - * - * So, the target will see drawing operations during two separate - * stages, (ANALYZE and RENDER). During the ANALYZE phase the target - * should not actually perform any rendering, (for example, if - * performing output to a file, no output should be generated during - * this stage). Instead the drawing functions simply need to return - * CAIRO_STATUS_SUCCESS or CAIRO_INT_STATUS_UNSUPPORTED to indicate - * whether rendering would be supported. And it should do this as - * quickly as possible. - * - * NOTE: The paginated surface layer assumes that the target surface - * is "blank" by default at the beginning of each page, without any - * need for an explicit erasea operation, (as opposed to an image - * surface, for example, which might have uninitialized content - * originally). As such, it optimizes away CLEAR operations that - * happen at the beginning of each page---the target surface will not - * even see these operations. - */ -cairo_private cairo_surface_t * -_cairo_paginated_surface_create (cairo_surface_t *target, - cairo_content_t content, - int width, - int height, - const cairo_paginated_surface_backend_t *backend); + cairo_content_t content; -cairo_private cairo_surface_t * -_cairo_paginated_surface_get_target (cairo_surface_t *surface); + /* XXX: These shouldn't actually exist. We inherit this ugliness + * from _cairo_meta_surface_create. The width/height parameters + * from that function also should not exist. The fix that will + * allow us to remove all of these is to fix acquire_source_image + * to pass an interest rectangle. */ + int width; + int height; -cairo_private cairo_bool_t -_cairo_surface_is_paginated (cairo_surface_t *surface); + /* Paginated-surface specific functions for the target */ + const cairo_paginated_surface_backend_t *backend; + + /* A cairo_meta_surface to record all operations. To be replayed + * against target, and also against image surface as necessary for + * fallbacks. */ + cairo_surface_t *meta; + + int page_num; + cairo_bool_t page_is_blank; + +} cairo_paginated_surface_t; #endif /* CAIRO_PAGINATED_SURFACE_H */ diff --git a/gfx/cairo/cairo/src/cairo-paginated-surface.c b/gfx/cairo/cairo/src/cairo-paginated-surface.c index c8e46124f994..17470949ef91 100644 --- a/gfx/cairo/cairo/src/cairo-paginated-surface.c +++ b/gfx/cairo/cairo/src/cairo-paginated-surface.c @@ -36,45 +36,17 @@ /* The paginated surface layer exists to provide as much code sharing * as possible for the various paginated surface backends in cairo - * (PostScript, PDF, etc.). See cairo-paginated-surface-private.h for + * (PostScript, PDF, etc.). See cairo-paginated-private.h for * more details on how it works and how to use it. */ #include "cairoint.h" +#include "cairo-paginated-private.h" #include "cairo-paginated-surface-private.h" #include "cairo-meta-surface-private.h" #include "cairo-analysis-surface-private.h" -typedef struct _cairo_paginated_surface { - cairo_surface_t base; - - /* The target surface to hold the final result. */ - cairo_surface_t *target; - - cairo_content_t content; - - /* XXX: These shouldn't actually exist. We inherit this ugliness - * from _cairo_meta_surface_create. The width/height parameters - * from that function also should not exist. The fix that will - * allow us to remove all of these is to fix acquire_source_image - * to pass an interest rectangle. */ - int width; - int height; - - /* Paginated-surface specific functions for the target */ - const cairo_paginated_surface_backend_t *backend; - - /* A cairo_meta_surface to record all operations. To be replayed - * against target, and also against image surface as necessary for - * fallbacks. */ - cairo_surface_t *meta; - - int page_num; - cairo_bool_t page_is_blank; - -} cairo_paginated_surface_t; - const cairo_private cairo_surface_backend_t cairo_paginated_surface_backend; static cairo_int_status_t @@ -162,11 +134,15 @@ _cairo_paginated_surface_finish (void *abstract_surface) if (surface->page_is_blank == FALSE || surface->page_num == 1) status = _cairo_paginated_surface_show_page (abstract_surface); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_STATUS_SUCCESS) { cairo_surface_finish (surface->target); + status = cairo_surface_status (surface->target); + } - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_STATUS_SUCCESS) { cairo_surface_finish (surface->meta); + status = cairo_surface_status (surface->meta); + } cairo_surface_destroy (surface->target); @@ -201,15 +177,22 @@ _cairo_paginated_surface_acquire_source_image (void *abstract_surface, { cairo_paginated_surface_t *surface = abstract_surface; cairo_surface_t *image; + cairo_status_t status; cairo_rectangle_int16_t extents; - _cairo_surface_get_extents (surface->target, &extents); + status = _cairo_surface_get_extents (surface->target, &extents); + if (status) + return status; image = _cairo_paginated_surface_create_image_surface (surface, extents.width, extents.height); - _cairo_meta_surface_replay (surface->meta, image); + status = _cairo_meta_surface_replay (surface->meta, image); + if (status) { + cairo_surface_destroy (image); + return status; + } *image_out = (cairo_image_surface_t*) image; *image_extra = NULL; @@ -235,13 +218,16 @@ _paint_page (cairo_paginated_surface_t *surface) analysis = _cairo_analysis_surface_create (surface->target, surface->width, surface->height); + if (analysis == NULL) + return CAIRO_STATUS_NO_MEMORY; surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_ANALYZE); - _cairo_meta_surface_replay (surface->meta, analysis); + status = _cairo_meta_surface_replay (surface->meta, analysis); surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER); - if (analysis->status) { - status = analysis->status; + if (status || analysis->status) { + if (status == CAIRO_STATUS_SUCCESS) + status = analysis->status; cairo_surface_destroy (analysis); return status; } @@ -257,26 +243,29 @@ _paint_page (cairo_paginated_surface_t *surface) surface->height * y_scale); _cairo_surface_set_device_scale (image, x_scale, y_scale); - _cairo_meta_surface_replay (surface->meta, image); + status = _cairo_meta_surface_replay (surface->meta, image); + if (status) + goto CLEANUP_IMAGE; pattern = cairo_pattern_create_for_surface (image); cairo_matrix_init_scale (&matrix, x_scale, y_scale); cairo_pattern_set_matrix (pattern, &matrix); - _cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, pattern); + status = _cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, pattern); cairo_pattern_destroy (pattern); + CLEANUP_IMAGE: cairo_surface_destroy (image); } else { - _cairo_meta_surface_replay (surface->meta, surface->target); + status = _cairo_meta_surface_replay (surface->meta, surface->target); } cairo_surface_destroy (analysis); - return CAIRO_STATUS_SUCCESS; + return status; } static cairo_status_t @@ -298,7 +287,9 @@ _cairo_paginated_surface_copy_page (void *abstract_surface) if (status) return status; - _paint_page (surface); + status = _paint_page (surface); + if (status) + return status; surface->page_num++; @@ -323,9 +314,16 @@ _cairo_paginated_surface_show_page (void *abstract_surface) if (status) return status; - _paint_page (surface); + status = _paint_page (surface); + if (status) + return status; - _cairo_surface_show_page (surface->target); + status = _cairo_surface_show_page (surface->target); + if (status) + return status; + + if (cairo_surface_status (surface->meta)) + return cairo_surface_status (surface->meta); cairo_surface_destroy (surface->meta); @@ -485,6 +483,7 @@ _cairo_paginated_surface_show_glyphs (void *abstract_surface, static cairo_surface_t * _cairo_paginated_surface_snapshot (void *abstract_other) { + cairo_status_t status; cairo_paginated_surface_t *other = abstract_other; /* XXX: Just making a snapshot of other->meta is what we really @@ -505,13 +504,19 @@ _cairo_paginated_surface_snapshot (void *abstract_other) cairo_rectangle_int16_t extents; cairo_surface_t *surface; - _cairo_surface_get_extents (other->target, &extents); + status = _cairo_surface_get_extents (other->target, &extents); + if (status) + return (cairo_surface_t*) &_cairo_surface_nil; surface = _cairo_paginated_surface_create_image_surface (other, extents.width, extents.height); - _cairo_meta_surface_replay (other->meta, surface); + status = _cairo_meta_surface_replay (other->meta, surface); + if (status) { + cairo_surface_destroy (surface); + surface = (cairo_surface_t*) &_cairo_surface_nil; + } return surface; #endif diff --git a/gfx/cairo/cairo/src/cairo-path-bounds.c b/gfx/cairo/cairo/src/cairo-path-bounds.c index 48b4393a74a8..5b60cf1c3931 100644 --- a/gfx/cairo/cairo/src/cairo-path-bounds.c +++ b/gfx/cairo/cairo/src/cairo-path-bounds.c @@ -51,7 +51,7 @@ _cairo_path_bounder_init (cairo_path_bounder_t *bounder); static void _cairo_path_bounder_fini (cairo_path_bounder_t *bounder); -static cairo_status_t +static void _cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *point); static cairo_status_t @@ -81,7 +81,7 @@ _cairo_path_bounder_fini (cairo_path_bounder_t *bounder) bounder->has_point = 0; } -static cairo_status_t +static void _cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *point) { if (bounder->has_point) { @@ -104,8 +104,6 @@ _cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *poi bounder->has_point = 1; } - - return CAIRO_STATUS_SUCCESS; } static cairo_status_t diff --git a/gfx/cairo/cairo/src/cairo-path-fill.c b/gfx/cairo/cairo/src/cairo-path-fill.c index b1b7a120d278..25420297ff25 100644 --- a/gfx/cairo/cairo/src/cairo-path-fill.c +++ b/gfx/cairo/cairo/src/cairo-path-fill.c @@ -88,37 +88,28 @@ _cairo_filler_fini (cairo_filler_t *filler) static cairo_status_t _cairo_filler_move_to (void *closure, cairo_point_t *point) { - cairo_status_t status; cairo_filler_t *filler = closure; cairo_polygon_t *polygon = &filler->polygon; - status = _cairo_polygon_close (polygon); - if (status) - return status; - - status = _cairo_polygon_move_to (polygon, point); - if (status) - return status; + _cairo_polygon_close (polygon); + _cairo_polygon_move_to (polygon, point); filler->current_point = *point; - return CAIRO_STATUS_SUCCESS; + return _cairo_polygon_status (&filler->polygon); } static cairo_status_t _cairo_filler_line_to (void *closure, cairo_point_t *point) { - cairo_status_t status; cairo_filler_t *filler = closure; cairo_polygon_t *polygon = &filler->polygon; - status = _cairo_polygon_line_to (polygon, point); - if (status) - return status; + _cairo_polygon_line_to (polygon, point); filler->current_point = *point; - return CAIRO_STATUS_SUCCESS; + return _cairo_polygon_status (&filler->polygon); } static cairo_status_t @@ -138,15 +129,12 @@ _cairo_filler_curve_to (void *closure, if (status == CAIRO_INT_STATUS_DEGENERATE) return CAIRO_STATUS_SUCCESS; - _cairo_spline_decompose (&spline, filler->tolerance); + status = _cairo_spline_decompose (&spline, filler->tolerance); if (status) goto CLEANUP_SPLINE; - for (i = 1; i < spline.num_points; i++) { - status = _cairo_polygon_line_to (polygon, &spline.points[i]); - if (status) - break; - } + for (i = 1; i < spline.num_points; i++) + _cairo_polygon_line_to (polygon, &spline.points[i]); CLEANUP_SPLINE: _cairo_spline_fini (&spline); @@ -159,15 +147,12 @@ _cairo_filler_curve_to (void *closure, static cairo_status_t _cairo_filler_close_path (void *closure) { - cairo_status_t status; cairo_filler_t *filler = closure; cairo_polygon_t *polygon = &filler->polygon; - status = _cairo_polygon_close (polygon); - if (status) - return status; + _cairo_polygon_close (polygon); - return CAIRO_STATUS_SUCCESS; + return _cairo_polygon_status (polygon); } static cairo_int_status_t @@ -201,7 +186,8 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, if (status) goto BAIL; - status = _cairo_polygon_close (&filler.polygon); + _cairo_polygon_close (&filler.polygon); + status = _cairo_polygon_status (&filler.polygon); if (status) goto BAIL; diff --git a/gfx/cairo/cairo/src/cairo-path-fixed.c b/gfx/cairo/cairo/src/cairo-path-fixed.c index 4845ada21755..dfd30b1c12fb 100644 --- a/gfx/cairo/cairo/src/cairo-path-fixed.c +++ b/gfx/cairo/cairo/src/cairo-path-fixed.c @@ -35,7 +35,6 @@ * Carl D. Worth */ -#include #include "cairoint.h" #include "cairo-path-fixed-private.h" @@ -356,8 +355,8 @@ _cairo_path_fixed_add (cairo_path_fixed_t *path, cairo_point_t *points, int num_points) { - if (path->buf_tail->num_ops + 1 > CAIRO_PATH_BUF_SIZE || - path->buf_tail->num_points + num_points > CAIRO_PATH_BUF_SIZE) + if ((unsigned int) path->buf_tail->num_ops + 1 > CAIRO_PATH_BUF_SIZE || + (unsigned int) path->buf_tail->num_points + num_points > CAIRO_PATH_BUF_SIZE) { cairo_path_buf_t *buf; diff --git a/gfx/cairo/cairo/src/cairo-path-stroke.c b/gfx/cairo/cairo/src/cairo-path-stroke.c index 09bafbf8e71d..d9f7ed2caf74 100644 --- a/gfx/cairo/cairo/src/cairo-path-stroke.c +++ b/gfx/cairo/cairo/src/cairo-path-stroke.c @@ -67,7 +67,7 @@ typedef struct cairo_stroker { } cairo_stroker_t; /* private functions */ -static void +static cairo_status_t _cairo_stroker_init (cairo_stroker_t *stroker, cairo_stroke_style_t *stroke_style, cairo_matrix_t *ctm, @@ -148,7 +148,7 @@ _cairo_stroker_step_dash (cairo_stroker_t *stroker, double step) } } -static void +static cairo_status_t _cairo_stroker_init (cairo_stroker_t *stroker, cairo_stroke_style_t *stroke_style, cairo_matrix_t *ctm, @@ -156,15 +156,18 @@ _cairo_stroker_init (cairo_stroker_t *stroker, double tolerance, cairo_traps_t *traps) { + cairo_status_t status; stroker->style = stroke_style; stroker->ctm = ctm; stroker->ctm_inverse = ctm_inverse; stroker->tolerance = tolerance; stroker->traps = traps; - _cairo_pen_init (&stroker->pen, - stroke_style->line_width / 2.0, - tolerance, ctm); + status = _cairo_pen_init (&stroker->pen, + stroke_style->line_width / 2.0, + tolerance, ctm); + if (status) + return status; stroker->has_current_face = FALSE; stroker->has_first_face = FALSE; @@ -174,6 +177,8 @@ _cairo_stroker_init (cairo_stroker_t *stroker, _cairo_stroker_start_dash (stroker); else stroker->dashed = FALSE; + + return CAIRO_STATUS_SUCCESS; } static void @@ -205,6 +210,7 @@ _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_st { int clockwise = _cairo_stroker_face_clockwise (out, in); cairo_point_t *inpt, *outpt; + cairo_status_t status; if (in->cw.x == out->cw.x && in->cw.y == out->cw.y @@ -231,13 +237,21 @@ _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_st tri[0] = in->point; if (clockwise) { - _cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector, &start); + status = _cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector, &start); + if (status) + return status; step = -1; - _cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector, &stop); + status = _cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector, &stop); + if (status) + return status; } else { - _cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector, &start); + status = _cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector, &start); + if (status) + return status; step = +1; - _cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector, &stop); + status = _cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector, &stop); + if (status) + return status; } i = start; @@ -245,7 +259,9 @@ _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_st while (i != stop) { tri[2] = in->point; _translate_point (&tri[2], &pen->vertices[i].point); - _cairo_traps_tessellate_triangle (stroker->traps, tri); + status = _cairo_traps_tessellate_triangle (stroker->traps, tri); + if (status) + return status; tri[1] = tri[2]; i += step; if (i < 0) @@ -378,17 +394,23 @@ _cairo_stroker_add_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f) cairo_pen_t *pen = &stroker->pen; slope = f->dev_vector; - _cairo_pen_find_active_cw_vertex_index (pen, &slope, &start); + status = _cairo_pen_find_active_cw_vertex_index (pen, &slope, &start); + if (status) + return status; slope.dx = -slope.dx; slope.dy = -slope.dy; - _cairo_pen_find_active_cw_vertex_index (pen, &slope, &stop); + status = _cairo_pen_find_active_cw_vertex_index (pen, &slope, &stop); + if (status) + return status; tri[0] = f->point; tri[1] = f->cw; for (i=start; i != stop; i = (i+1) % pen->num_vertices) { tri[2] = f->point; _translate_point (&tri[2], &pen->vertices[i].point); - _cairo_traps_tessellate_triangle (stroker->traps, tri); + status = _cairo_traps_tessellate_triangle (stroker->traps, tri); + if (status) + return status; tri[1] = tri[2]; } tri[2] = f->ccw; @@ -419,8 +441,14 @@ _cairo_stroker_add_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f) _cairo_polygon_line_to (&polygon, &occw); _cairo_polygon_line_to (&polygon, &f->ccw); _cairo_polygon_close (&polygon); + status = _cairo_polygon_status (&polygon); + + if (status == CAIRO_STATUS_SUCCESS) { + status = _cairo_bentley_ottmann_tessellate_polygon (stroker->traps, + &polygon, + CAIRO_FILL_RULE_WINDING); + } - status = _cairo_bentley_ottmann_tessellate_polygon (stroker->traps, &polygon, CAIRO_FILL_RULE_WINDING); _cairo_polygon_fini (&polygon); return status; @@ -967,9 +995,11 @@ _cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path, if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; - _cairo_stroker_init (&stroker, stroke_style, - ctm, ctm_inverse, tolerance, - traps); + status = _cairo_stroker_init (&stroker, stroke_style, + ctm, ctm_inverse, tolerance, + traps); + if (status) + return status; if (stroker.style->dash) status = _cairo_path_fixed_interpret (path, diff --git a/gfx/cairo/cairo/src/cairo-path.c b/gfx/cairo/cairo/src/cairo-path.c index 7c2374c2a4fb..4c8e09e113b2 100644 --- a/gfx/cairo/cairo/src/cairo-path.c +++ b/gfx/cairo/cairo/src/cairo-path.c @@ -34,9 +34,10 @@ * Carl D. Worth */ +#include "cairoint.h" + #include "cairo-path-private.h" #include "cairo-path-fixed-private.h" -#include "cairo-gstate-private.h" const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 }; @@ -135,6 +136,7 @@ _cairo_path_count (cairo_path_t *path, double tolerance, cairo_bool_t flatten) { + cairo_status_t status; cpc_t cpc; cpc.count = 0; @@ -142,15 +144,17 @@ _cairo_path_count (cairo_path_t *path, cpc.current_point.x = 0; cpc.current_point.y = 0; - _cairo_path_fixed_interpret (path_fixed, - CAIRO_DIRECTION_FORWARD, - _cpc_move_to, - _cpc_line_to, - flatten ? - _cpc_curve_to_flatten : - _cpc_curve_to, - _cpc_close_path, - &cpc); + status = _cairo_path_fixed_interpret (path_fixed, + CAIRO_DIRECTION_FORWARD, + _cpc_move_to, + _cpc_line_to, + flatten ? + _cpc_curve_to_flatten : + _cpc_curve_to, + _cpc_close_path, + &cpc); + if (status) + return -1; return cpc.count; } @@ -275,7 +279,8 @@ _cpp_curve_to_flatten (void *closure, if (status == CAIRO_INT_STATUS_DEGENERATE) return CAIRO_STATUS_SUCCESS; - status = _cairo_spline_decompose (&spline, cpp->gstate->tolerance); + status = _cairo_spline_decompose (&spline, + _cairo_gstate_get_tolerance (cpp->gstate)); if (status) goto out; @@ -305,12 +310,13 @@ _cpp_close_path (void *closure) return CAIRO_STATUS_SUCCESS; } -static void +static cairo_status_t _cairo_path_populate (cairo_path_t *path, cairo_path_fixed_t *path_fixed, cairo_gstate_t *gstate, cairo_bool_t flatten) { + cairo_status_t status; cpp_t cpp; cpp.data = path->data; @@ -318,18 +324,22 @@ _cairo_path_populate (cairo_path_t *path, cpp.current_point.x = 0; cpp.current_point.y = 0; - _cairo_path_fixed_interpret (path_fixed, - CAIRO_DIRECTION_FORWARD, - _cpp_move_to, - _cpp_line_to, - flatten ? - _cpp_curve_to_flatten : - _cpp_curve_to, - _cpp_close_path, - &cpp); + status = _cairo_path_fixed_interpret (path_fixed, + CAIRO_DIRECTION_FORWARD, + _cpp_move_to, + _cpp_line_to, + flatten ? + _cpp_curve_to_flatten : + _cpp_curve_to, + _cpp_close_path, + &cpp); + if (status) + return status; /* Sanity check the count */ assert (cpp.data - path->data == path->num_data); + + return status; } cairo_path_t * @@ -337,6 +347,10 @@ _cairo_path_create_in_error (cairo_status_t status) { cairo_path_t *path; + /* special case NO_MEMORY so as to avoid allocations */ + if (status == CAIRO_STATUS_NO_MEMORY) + return (cairo_path_t*) &_cairo_path_nil; + path = malloc (sizeof (cairo_path_t)); if (path == NULL) return (cairo_path_t*) &_cairo_path_nil; @@ -360,7 +374,12 @@ _cairo_path_create_internal (cairo_path_fixed_t *path_fixed, return (cairo_path_t*) &_cairo_path_nil; path->num_data = _cairo_path_count (path, path_fixed, - gstate->tolerance, flatten); + _cairo_gstate_get_tolerance (gstate), + flatten); + if (path->num_data <= 0) { + free (path); + return (cairo_path_t*) &_cairo_path_nil; + } path->data = malloc (path->num_data * sizeof (cairo_path_data_t)); if (path->data == NULL) { @@ -368,10 +387,8 @@ _cairo_path_create_internal (cairo_path_fixed_t *path_fixed, return (cairo_path_t*) &_cairo_path_nil; } - path->status = CAIRO_STATUS_SUCCESS; - - _cairo_path_populate (path, path_fixed, - gstate, flatten); + path->status = _cairo_path_populate (path, path_fixed, + gstate, flatten); return path; } @@ -460,6 +477,7 @@ _cairo_path_append_to_context (const cairo_path_t *path, { int i; cairo_path_data_t *p; + cairo_status_t status; for (i=0; i < path->num_data; i += path->data[i].header.length) { p = &path->data[i]; @@ -492,6 +510,10 @@ _cairo_path_append_to_context (const cairo_path_t *path, default: return CAIRO_STATUS_INVALID_PATH_DATA; } + + status = cairo_status (cr); + if (status) + return status; } return CAIRO_STATUS_SUCCESS; diff --git a/gfx/cairo/cairo/src/cairo-pattern.c b/gfx/cairo/cairo/src/cairo-pattern.c index f076259b5259..9fafc99186d0 100644 --- a/gfx/cairo/cairo/src/cairo-pattern.c +++ b/gfx/cairo/cairo/src/cairo-pattern.c @@ -30,7 +30,7 @@ #include "cairoint.h" -const cairo_solid_pattern_t cairo_pattern_nil = { +const cairo_solid_pattern_t _cairo_pattern_nil = { { CAIRO_PATTERN_TYPE_SOLID, /* type */ CAIRO_REF_COUNT_INVALID, /* ref_count */ CAIRO_STATUS_NO_MEMORY, /* status */ @@ -40,7 +40,7 @@ const cairo_solid_pattern_t cairo_pattern_nil = { CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */ }; -static const cairo_solid_pattern_t cairo_pattern_nil_null_pointer = { +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 */ @@ -50,6 +50,16 @@ static const cairo_solid_pattern_t cairo_pattern_nil_null_pointer = { CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */ }; +const cairo_solid_pattern_t cairo_pattern_none = { + { CAIRO_PATTERN_TYPE_SOLID, /* type */ + CAIRO_REF_COUNT_INVALID, /* ref_count */ + CAIRO_STATUS_SUCCESS, /* status */ + { 0, 0, 0, NULL }, /* user_data */ + { 1., 0., 0., 1., 0., 0., }, /* matrix */ + CAIRO_FILTER_DEFAULT, /* filter */ + CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */ +}; + /** * _cairo_pattern_set_error: * @pattern: a pattern @@ -82,6 +92,8 @@ _cairo_pattern_set_error (cairo_pattern_t *pattern, static void _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type) { + CAIRO_MUTEX_INITIALIZE (); + pattern->type = type; pattern->ref_count = 1; pattern->status = CAIRO_STATUS_SUCCESS; @@ -98,7 +110,7 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type) cairo_matrix_init_identity (&pattern->matrix); } -static void +static cairo_status_t _cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern, const cairo_gradient_pattern_t *other) { @@ -127,21 +139,23 @@ _cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern, pattern->stops_size = 0; pattern->n_stops = 0; _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY); - return; + return CAIRO_STATUS_NO_MEMORY; } memcpy (pattern->stops, other->stops, other->n_stops * sizeof (pixman_gradient_stop_t)); } + + return CAIRO_STATUS_SUCCESS; } -void +cairo_status_t _cairo_pattern_init_copy (cairo_pattern_t *pattern, const cairo_pattern_t *other) { if (other->status) { _cairo_pattern_set_error (pattern, other->status); - return; + return other->status; } switch (other->type) { @@ -162,12 +176,18 @@ _cairo_pattern_init_copy (cairo_pattern_t *pattern, case CAIRO_PATTERN_TYPE_RADIAL: { cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern; cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other; + cairo_status_t status; + + status = _cairo_gradient_pattern_init_copy (dst, src); + if (status) + return status; - _cairo_gradient_pattern_init_copy (dst, src); } break; } pattern->ref_count = 1; + + return CAIRO_STATUS_SUCCESS; } void @@ -197,10 +217,12 @@ _cairo_pattern_fini (cairo_pattern_t *pattern) void _cairo_pattern_init_solid (cairo_solid_pattern_t *pattern, - const cairo_color_t *color) + const cairo_color_t *color, + cairo_content_t content) { _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID); pattern->color = *color; + pattern->content = content; } void @@ -209,7 +231,7 @@ _cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern, { if (surface->status) { /* Force to solid to simplify the pattern_fini process. */ - pattern->base.type = CAIRO_PATTERN_TYPE_SOLID; + _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID); _cairo_pattern_set_error (&pattern->base, surface->status); return; } @@ -257,29 +279,71 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern, pattern->gradient.c2.radius = _cairo_fixed_from_double (fabs (radius1)); } +/* We use a small freed pattern cache here, because we don't want to + * constantly reallocate simple colors. */ +#define MAX_PATTERN_CACHE_SIZE 4 +static struct { + cairo_solid_pattern_t *patterns[MAX_PATTERN_CACHE_SIZE]; + int size; +} solid_pattern_cache; + cairo_pattern_t * -_cairo_pattern_create_solid (const cairo_color_t *color) +_cairo_pattern_create_solid (const cairo_color_t *color, + cairo_content_t content) { - cairo_solid_pattern_t *pattern; + cairo_solid_pattern_t *pattern = NULL; + + CAIRO_MUTEX_LOCK (_cairo_pattern_solid_pattern_cache_lock); + + if (solid_pattern_cache.size) { + int i = --solid_pattern_cache.size % + ARRAY_LENGTH (solid_pattern_cache.patterns); + pattern = solid_pattern_cache.patterns[i]; + solid_pattern_cache.patterns[i] = NULL; + } + + CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_pattern_cache_lock); + + if (pattern == NULL) { + /* None cached, need to create a new pattern. */ + pattern = malloc (sizeof (cairo_solid_pattern_t)); + } - pattern = malloc (sizeof (cairo_solid_pattern_t)); if (pattern == NULL) - return (cairo_pattern_t *) &cairo_pattern_nil.base; - - _cairo_pattern_init_solid (pattern, color); + pattern = (cairo_solid_pattern_t *) &_cairo_pattern_nil; + else + _cairo_pattern_init_solid (pattern, color, content); return &pattern->base; } +static void +_cairo_pattern_reset_solid_pattern_cache (void) +{ + int i; + + CAIRO_MUTEX_LOCK (_cairo_pattern_solid_pattern_cache_lock); + + for (i = 0; i < MIN (ARRAY_LENGTH (solid_pattern_cache.patterns), solid_pattern_cache.size); i++) { + free (solid_pattern_cache.patterns[i]); + solid_pattern_cache.patterns[i] = NULL; + } + solid_pattern_cache.size = 0; + + CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_pattern_cache_lock); +} + static const cairo_pattern_t * _cairo_pattern_create_in_error (cairo_status_t status) { cairo_pattern_t *pattern; - pattern = _cairo_pattern_create_solid (_cairo_stock_color (CAIRO_STOCK_BLACK)); - if (cairo_pattern_status (pattern)) - return pattern; + if (status == CAIRO_STATUS_NO_MEMORY) + return (cairo_pattern_t *)&_cairo_pattern_nil.base; + pattern = _cairo_pattern_create_solid (_cairo_stock_color (CAIRO_STOCK_BLACK), + CAIRO_CONTENT_COLOR); + /* no-op on a pattern already in error i.e the _cairo_pattern_nil */ _cairo_pattern_set_error (pattern, status); return pattern; @@ -317,7 +381,8 @@ cairo_pattern_create_rgb (double red, double green, double blue) _cairo_color_init_rgb (&color, red, green, blue); - pattern = _cairo_pattern_create_solid (&color); + pattern = _cairo_pattern_create_solid (&color, + CAIRO_CONTENT_COLOR); if (pattern->status) _cairo_error (pattern->status); @@ -360,7 +425,8 @@ cairo_pattern_create_rgba (double red, double green, double blue, _cairo_color_init_rgba (&color, red, green, blue, alpha); - pattern = _cairo_pattern_create_solid (&color); + pattern = _cairo_pattern_create_solid (&color, + CAIRO_CONTENT_COLOR_ALPHA); if (pattern->status) _cairo_error (pattern->status); @@ -389,7 +455,7 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface) cairo_surface_pattern_t *pattern; if (surface == NULL) - return (cairo_pattern_t*) &cairo_pattern_nil_null_pointer; + return (cairo_pattern_t*) &_cairo_pattern_nil_null_pointer; if (surface->status) return (cairo_pattern_t*) _cairo_pattern_create_in_error (surface->status); @@ -397,7 +463,7 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface) pattern = malloc (sizeof (cairo_surface_pattern_t)); if (pattern == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); - return (cairo_pattern_t *)&cairo_pattern_nil.base; + return (cairo_pattern_t *)&_cairo_pattern_nil.base; } _cairo_pattern_init_for_surface (pattern, surface); @@ -440,7 +506,7 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1) pattern = malloc (sizeof (cairo_linear_pattern_t)); if (pattern == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); - return (cairo_pattern_t *) &cairo_pattern_nil.base; + return (cairo_pattern_t *) &_cairo_pattern_nil.base; } _cairo_pattern_init_linear (pattern, x0, y0, x1, y1); @@ -458,7 +524,7 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1) * @radius1: radius of the end circle * * Creates a new radial gradient cairo_pattern_t between the two - * circles defined by (x0, y0, c0) and (x1, y1, c0). Before using the + * circles defined by (cx0, cy0, radius0) and (cx1, cy1, radius1). Before using the * gradient pattern, a number of color stops should be defined using * cairo_pattern_add_color_stop_rgb() or * cairo_pattern_add_color_stop_rgba(). @@ -485,7 +551,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0, pattern = malloc (sizeof (cairo_radial_pattern_t)); if (pattern == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); - return (cairo_pattern_t *) &cairo_pattern_nil.base; + return (cairo_pattern_t *) &_cairo_pattern_nil.base; } _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1); @@ -576,7 +642,25 @@ cairo_pattern_destroy (cairo_pattern_t *pattern) return; _cairo_pattern_fini (pattern); - free (pattern); + + /* maintain a small cache of freed patterns */ + if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { + int i; + + CAIRO_MUTEX_LOCK (_cairo_pattern_solid_pattern_cache_lock); + + i = solid_pattern_cache.size++ % + ARRAY_LENGTH (solid_pattern_cache.patterns); + /* swap an old pattern for this 'cache-hot' pattern */ + if (solid_pattern_cache.patterns[i]) + free (solid_pattern_cache.patterns[i]); + + solid_pattern_cache.patterns[i] = (cairo_solid_pattern_t *) pattern; + + CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_pattern_cache_lock); + } else { + free (pattern); + } } slim_hidden_def (cairo_pattern_destroy); @@ -659,7 +743,7 @@ _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 embedded_size = ARRAY_LENGTH (pattern->stops_embedded); int new_size = 2 * MAX (old_size, 4); /* we have a local buffer at pattern->stops_embedded. try to fulfill the request @@ -750,6 +834,13 @@ _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, * * The color is specified in the same way as in cairo_set_source_rgb(). * + * If two (or more) stops are specified with identical offset values, + * they will be sorted according to the order in which the stops are + * added, (stops added earlier will compare less than stops added + * later). This can be useful for reliably making sharp color + * transitions instead of the typical blend. + * + * * Note: If the pattern is not a gradient pattern, (eg. a linear or * radial pattern), then the pattern will be put into an error status * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. @@ -797,6 +888,12 @@ cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, * * The color is specified in the same way as in cairo_set_source_rgba(). * + * If two (or more) stops are specified with identical offset values, + * they will be sorted according to the order in which the stops are + * added, (stops added earlier will compare less than stops added + * later). This can be useful for reliably making sharp color + * transitions instead of the typical blend. + * * Note: If the pattern is not a gradient pattern, (eg. a linear or * radial pattern), then the pattern will be put into an error status * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. @@ -865,10 +962,18 @@ void cairo_pattern_set_matrix (cairo_pattern_t *pattern, const cairo_matrix_t *matrix) { + cairo_matrix_t inverse; + cairo_status_t status; + if (pattern->status) return; pattern->matrix = *matrix; + + inverse = *matrix; + status = cairo_matrix_invert (&inverse); + if (status) + _cairo_pattern_set_error (pattern, status); } slim_hidden_def (cairo_pattern_set_matrix); @@ -958,7 +1063,8 @@ void _cairo_pattern_transform (cairo_pattern_t *pattern, const cairo_matrix_t *ctm_inverse) { - assert (pattern->status == CAIRO_STATUS_SUCCESS); + if (pattern->status) + return; cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix); } @@ -978,7 +1084,7 @@ _cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern, cairo_fixed_t factors[3]; int i; - /* To classidy a pattern as horizontal or vertical, we first + /* To classify a pattern as horizontal or vertical, we first * compute the (fixed point) factors at the corners of the * pattern. We actually only need 3/4 corners, so we skip the * fourth. @@ -1113,7 +1219,11 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern, pixman_image_set_filter (pixman_image, PIXMAN_FILTER_BILINEAR); _cairo_matrix_to_pixman_matrix (&pattern->base.matrix, &pixman_transform); - pixman_image_set_transform (pixman_image, &pixman_transform); + if (pixman_image_set_transform (pixman_image, &pixman_transform)) { + cairo_surface_destroy (&image->base); + pixman_image_destroy (pixman_image); + return CAIRO_STATUS_NO_MEMORY; + } switch (pattern->base.extend) { case CAIRO_EXTEND_NONE: @@ -1156,6 +1266,35 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern, return status; } +/* We maintain a small cache here, because we don't want to constantly + * recreate surfaces for simple solid colors. */ +#define MAX_SURFACE_CACHE_SIZE 16 +static struct { + struct _cairo_pattern_solid_surface_cache{ + cairo_color_t color; + cairo_surface_t *surface; + } cache[MAX_SURFACE_CACHE_SIZE]; + int size; +} solid_surface_cache; + +static cairo_bool_t +_cairo_pattern_solid_surface_matches ( + const struct _cairo_pattern_solid_surface_cache *cache, + const cairo_solid_pattern_t *pattern, + cairo_surface_t *dst) +{ + if (cache->surface->ref_count != 1) + return FALSE; + + if (! _cairo_color_equal (&cache->color, &pattern->color)) + return FALSE; + + if (! _cairo_surface_is_similar (cache->surface, dst, pattern->content)) + return FALSE; + + return TRUE; +} + static cairo_int_status_t _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern, cairo_surface_t *dst, @@ -1166,20 +1305,94 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern, cairo_surface_t **out, cairo_surface_attributes_t *attribs) { - *out = _cairo_surface_create_similar_solid (dst, - CAIRO_CONTENT_COLOR_ALPHA, - 1, 1, - &pattern->color); - if ((*out)->status) - return CAIRO_STATUS_NO_MEMORY; + static int i; + cairo_surface_t *surface; + cairo_status_t status; + + CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock); + + /* Check cache first */ + if (i < solid_surface_cache.size && + _cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i], + pattern, + dst)) + { + if (! _cairo_surface_reset (solid_surface_cache.cache[i].surface)) + goto DONE; + } + + for (i = 0 ; i < solid_surface_cache.size; i++) { + if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i], + pattern, + dst)) + { + if (! _cairo_surface_reset (solid_surface_cache.cache[i].surface)) + goto DONE; + } + } + + /* Not cached, need to create new */ + surface = _cairo_surface_create_similar_solid (dst, + pattern->content, + 1, 1, + &pattern->color, + &pattern->base); + if (surface->status) { + status = surface->status; + goto UNLOCK; + } + + if (! _cairo_surface_is_similar (surface, dst, pattern->content)) { + /* in the rare event of a substitute surface being returned (e.g. + * malloc failure) don't cache the fallback surface */ + *out = surface; + goto NOCACHE; + } + + /* Cache new */ + if (solid_surface_cache.size < MAX_SURFACE_CACHE_SIZE) { + solid_surface_cache.size++; + } else { + i = rand () % MAX_SURFACE_CACHE_SIZE; + + /* Evict old */ + cairo_surface_destroy (solid_surface_cache.cache[i].surface); + } + + solid_surface_cache.cache[i].color = pattern->color; + solid_surface_cache.cache[i].surface = surface; + +DONE: + *out = cairo_surface_reference (solid_surface_cache.cache[i].surface); + +NOCACHE: attribs->x_offset = attribs->y_offset = 0; cairo_matrix_init_identity (&attribs->matrix); attribs->extend = CAIRO_EXTEND_REPEAT; attribs->filter = CAIRO_FILTER_NEAREST; attribs->acquired = FALSE; - return CAIRO_STATUS_SUCCESS; + status = CAIRO_STATUS_SUCCESS; + +UNLOCK: + CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock); + + return status; +} + +static void +_cairo_pattern_reset_solid_surface_cache (void) +{ + int i; + + CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock); + + for (i = 0; i < solid_surface_cache.size; i++) + cairo_surface_destroy (solid_surface_cache.cache[i].surface); + solid_surface_cache.size = 0; + + CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock); } /** @@ -1203,7 +1416,7 @@ _cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern) solid = (cairo_solid_pattern_t *) pattern; - return CAIRO_ALPHA_IS_OPAQUE (solid->color.alpha); + return CAIRO_COLOR_IS_OPAQUE (&solid->color); } static cairo_bool_t @@ -1212,7 +1425,7 @@ _gradient_is_opaque (const cairo_gradient_pattern_t *gradient) unsigned int i; for (i = 0; i < gradient->n_stops; i++) - if (! CAIRO_ALPHA_IS_OPAQUE (gradient->stops[i].color.alpha)) + if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (gradient->stops[i].color.alpha)) return FALSE; return TRUE; @@ -1302,14 +1515,25 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern, attr->extend = CAIRO_EXTEND_REPEAT; + /* TODO: Instead of rendering pattern->surface four times to + * out, we should first copy pattern->surface to surface similar + * to dst and then copy that four times to out. This may cause + * an extra copy in the case of image destination, but for X servers, + * this will send pattern->surface just once over the wire instead + * of current four. + */ 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; + status = cairo_surface_status (*out); + if (status) { + cairo_surface_destroy (*out); + *out = NULL; + return status; + } (*out)->device_transform = pattern->surface->device_transform; (*out)->device_transform_inverse = pattern->surface->device_transform_inverse; @@ -1334,6 +1558,11 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern, status = cairo_status (cr); cairo_destroy (cr); + if (status) { + cairo_surface_destroy (*out); + *out = NULL; + } + return status; } @@ -1386,11 +1615,16 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern, * 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; + * above. + * + * XXX: The one padding here is to account for filter + * radius. It's a workaround right now, until we get a + * proper fix. (see bug #10508) + */ + x = MAX (0, floor (x1) - 1); + y = MAX (0, floor (y1) - 1); + width = MIN (extents.width, ceil (x2) + 1) - x; + height = MIN (extents.height, ceil (y2) + 1) - y; } x += tx; y += ty; @@ -1405,8 +1639,12 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern, *out = cairo_surface_create_similar (dst, dst->content, width, height); - if (!*out) - return CAIRO_STATUS_NO_MEMORY; + status = cairo_surface_status (*out); + if (status) { + cairo_surface_destroy (*out); + *out = NULL; + return status; + } (*out)->device_transform = pattern->surface->device_transform; (*out)->device_transform_inverse = pattern->surface->device_transform_inverse; @@ -1420,6 +1658,11 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern, status = cairo_status (cr); cairo_destroy (cr); + + if (status) { + cairo_surface_destroy (*out); + *out = NULL; + } } } @@ -1489,14 +1732,18 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern, src->stops->color.blue / 65535.0, src->stops->color.alpha / 65535.0); - _cairo_pattern_init_solid (&solid, &color); + _cairo_pattern_init_solid (&solid, &color, + CAIRO_COLOR_IS_OPAQUE (&color) ? + CAIRO_CONTENT_COLOR : + CAIRO_CONTENT_COLOR_ALPHA); } else { const cairo_color_t *color; color = _cairo_stock_color (CAIRO_STOCK_TRANSPARENT); - _cairo_pattern_init_solid (&solid, color); + _cairo_pattern_init_solid (&solid, color, + CAIRO_CONTENT_ALPHA); } status = _cairo_pattern_acquire_surface_for_solid (&solid, dst, @@ -1598,13 +1845,18 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src, combined = src_solid->color; _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha); - _cairo_pattern_init_solid (&src_tmp.solid, &combined); + _cairo_pattern_init_solid (&src_tmp.solid, &combined, + CAIRO_COLOR_IS_OPAQUE (&combined) ? + CAIRO_CONTENT_COLOR : + CAIRO_CONTENT_COLOR_ALPHA); mask = NULL; } else { - _cairo_pattern_init_copy (&src_tmp.base, src); + status = _cairo_pattern_init_copy (&src_tmp.base, src); + if (status) + return status; } status = _cairo_pattern_acquire_surface (&src_tmp.base, dst, @@ -1623,19 +1875,23 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src, return CAIRO_STATUS_SUCCESS; } - _cairo_pattern_init_copy (&mask_tmp.base, mask); + status = _cairo_pattern_init_copy (&mask_tmp.base, mask); + if (status) + goto CLEANUP_SOURCE; status = _cairo_pattern_acquire_surface (&mask_tmp.base, dst, mask_x, mask_y, width, height, mask_out, mask_attributes); + _cairo_pattern_fini (&mask_tmp.base); + +CLEANUP_SOURCE: if (status) _cairo_pattern_release_surface (&src_tmp.base, *src_out, src_attributes); _cairo_pattern_fini (&src_tmp.base); - _cairo_pattern_fini (&mask_tmp.base); return status; } @@ -1677,7 +1933,9 @@ _cairo_pattern_get_extents (cairo_pattern_t *pattern, return status; imatrix = pattern->matrix; - cairo_matrix_invert (&imatrix); + status = cairo_matrix_invert (&imatrix); + if (status) + return status; /* XXX Use _cairo_matrix_transform_bounding_box here */ for (sy = 0; sy <= 1; sy++) { @@ -1956,3 +2214,10 @@ cairo_pattern_get_radial_circles (cairo_pattern_t *pattern, return CAIRO_STATUS_SUCCESS; } + +void +_cairo_pattern_reset_static_data (void) +{ + _cairo_pattern_reset_solid_pattern_cache (); + _cairo_pattern_reset_solid_surface_cache (); +} diff --git a/gfx/cairo/cairo/src/cairo-pdf-surface-private.h b/gfx/cairo/cairo/src/cairo-pdf-surface-private.h new file mode 100644 index 000000000000..1af2ad06b86b --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-pdf-surface-private.h @@ -0,0 +1,105 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc + * Copyright © 2006 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Kristian Høgsberg + * Carl Worth + */ + +#ifndef CAIRO_PDF_SURFACE_PRIVATE_H +#define CAIRO_PDF_SURFACE_PRIVATE_H + +#include "cairo-pdf.h" + +#include "cairo-surface-private.h" + +typedef struct _cairo_pdf_resource { + unsigned int id; +} cairo_pdf_resource_t; + +typedef struct _cairo_pdf_surface cairo_pdf_surface_t; + +struct _cairo_pdf_surface { + cairo_surface_t base; + + /* Prefer the name "output" here to avoid confusion over the + * structure within a PDF document known as a "stream". */ + cairo_output_stream_t *output; + + double width; + double height; + cairo_matrix_t cairo_to_pdf; + + cairo_array_t objects; + cairo_array_t pages; + cairo_array_t patterns; + cairo_array_t xobjects; + cairo_array_t streams; + cairo_array_t alphas; + cairo_array_t smasks; + cairo_array_t rgb_linear_functions; + cairo_array_t alpha_linear_functions; + + cairo_scaled_font_subsets_t *font_subsets; + cairo_array_t fonts; + + cairo_pdf_resource_t next_available_resource; + cairo_pdf_resource_t pages_resource; + + struct { + cairo_bool_t active; + cairo_pdf_resource_t self; + cairo_pdf_resource_t length; + long start_offset; + cairo_bool_t compressed; + cairo_output_stream_t *old_output; + } current_stream; + + struct { + cairo_pattern_type_t type; + double red; + double green; + double blue; + int alpha; + cairo_pdf_resource_t smask; + cairo_pdf_resource_t pattern; + } emitted_pattern; + + cairo_bool_t has_clip; + + cairo_paginated_mode_t paginated_mode; + + cairo_bool_t force_fallbacks; +}; + +#endif /* CAIRO_PDF_SURFACE_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-pdf-surface.c b/gfx/cairo/cairo/src/cairo-pdf-surface.c index 924b80c03f88..1e73c4c44fa3 100644 --- a/gfx/cairo/cairo/src/cairo-pdf-surface.c +++ b/gfx/cairo/cairo/src/cairo-pdf-surface.c @@ -38,9 +38,9 @@ #include "cairoint.h" #include "cairo-pdf.h" -#include "cairo-pdf-test.h" +#include "cairo-pdf-surface-private.h" #include "cairo-scaled-font-subsets-private.h" -#include "cairo-paginated-surface-private.h" +#include "cairo-paginated-private.h" #include "cairo-path-fixed-private.h" #include "cairo-output-stream-private.h" @@ -64,8 +64,6 @@ * * - Surface patterns. * - * - Alpha channels in gradients. - * * - Should/does cairo support drawing into a scratch surface and then * using that as a fill pattern? For this backend, that would involve * using a tiling pattern (4.6.2). How do you create such a scratch @@ -91,54 +89,23 @@ typedef struct _cairo_pdf_object { long offset; } cairo_pdf_object_t; -typedef struct _cairo_pdf_resource { - unsigned int id; -} cairo_pdf_resource_t; - typedef struct _cairo_pdf_font { unsigned int font_id; unsigned int subset_id; cairo_pdf_resource_t subset_resource; } cairo_pdf_font_t; -typedef struct _cairo_pdf_surface { - cairo_surface_t base; +typedef struct _cairo_pdf_rgb_linear_function { + cairo_pdf_resource_t resource; + double color1[3]; + double color2[3]; +} cairo_pdf_rgb_linear_function_t; - /* Prefer the name "output" here to avoid confusion over the - * structure within a PDF document known as a "stream". */ - cairo_output_stream_t *output; - - double width; - double height; - - cairo_array_t objects; - cairo_array_t pages; - cairo_array_t patterns; - cairo_array_t xobjects; - cairo_array_t streams; - cairo_array_t alphas; - - cairo_scaled_font_subsets_t *font_subsets; - cairo_array_t fonts; - - cairo_pdf_resource_t next_available_resource; - cairo_pdf_resource_t pages_resource; - - struct { - cairo_bool_t active; - cairo_pdf_resource_t self; - cairo_pdf_resource_t length; - long start_offset; - cairo_bool_t compressed; - cairo_output_stream_t *old_output; - } current_stream; - - cairo_bool_t has_clip; - - cairo_paginated_mode_t paginated_mode; -} cairo_pdf_surface_t; - -#define PDF_SURFACE_MAX_GLYPHS_PER_FONT 256 +typedef struct _cairo_pdf_alpha_linear_function { + cairo_pdf_resource_t resource; + double alpha1; + double alpha2; +} cairo_pdf_alpha_linear_function_t; static cairo_pdf_resource_t _cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface); @@ -151,10 +118,10 @@ _cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface, cairo_bool_t compressed, const char *fmt, ...) CAIRO_PRINTF_FORMAT(3, 4); -static void +static cairo_status_t _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface); -static void +static cairo_status_t _cairo_pdf_surface_add_stream (cairo_pdf_surface_t *surface, cairo_pdf_resource_t stream); @@ -210,43 +177,50 @@ _cairo_pdf_surface_update_object (cairo_pdf_surface_t *surface, object->offset = _cairo_output_stream_get_position (surface->output); } -static void +static cairo_status_t _cairo_pdf_surface_add_stream (cairo_pdf_surface_t *surface, cairo_pdf_resource_t stream) { - /* XXX: Should be checking the return value here. */ - _cairo_array_append (&surface->streams, &stream); + return _cairo_array_append (&surface->streams, &stream); } -static void +static cairo_status_t _cairo_pdf_surface_add_pattern (cairo_pdf_surface_t *surface, cairo_pdf_resource_t pattern) { - /* XXX: Should be checking the return value here. */ - _cairo_array_append (&surface->patterns, &pattern); + return _cairo_array_append (&surface->patterns, &pattern); } -static cairo_pdf_resource_t -_cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface, double alpha) +static cairo_status_t +_cairo_pdf_surface_add_smask (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t smask) +{ + return _cairo_array_append (&surface->smasks, &smask); +} + +static cairo_status_t +_cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface, double alpha, int *index) { - cairo_pdf_resource_t resource; int num_alphas, i; double other; + cairo_status_t status; num_alphas = _cairo_array_num_elements (&surface->alphas); for (i = 0; i < num_alphas; i++) { - _cairo_array_copy_element (&surface->alphas, i, &other); - if (alpha == other) { - resource.id = i; - return resource; - } + _cairo_array_copy_element (&surface->alphas, i, &other); + if (alpha == other) { + *index = i; + return CAIRO_STATUS_SUCCESS; + } } - /* XXX: Should be checking the return value here. */ - _cairo_array_append (&surface->alphas, &alpha); + status = _cairo_array_append (&surface->alphas, &alpha); + if (status) + return status; - resource.id = _cairo_array_num_elements (&surface->alphas) - 1; - return resource; + *index = _cairo_array_num_elements (&surface->alphas) - 1; + + return CAIRO_STATUS_SUCCESS; } static cairo_surface_t * @@ -255,6 +229,8 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, double height) { cairo_pdf_surface_t *surface; + cairo_status_t status; + int alpha; surface = malloc (sizeof (cairo_pdf_surface_t)); if (surface == NULL) { @@ -269,6 +245,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, surface->width = width; surface->height = height; + cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, height); _cairo_array_init (&surface->objects, sizeof (cairo_pdf_object_t)); _cairo_array_init (&surface->pages, sizeof (cairo_pdf_resource_t)); @@ -276,13 +253,23 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, _cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t)); _cairo_array_init (&surface->streams, sizeof (cairo_pdf_resource_t)); _cairo_array_init (&surface->alphas, sizeof (double)); + _cairo_array_init (&surface->smasks, sizeof (cairo_pdf_resource_t)); + _cairo_array_init (&surface->rgb_linear_functions, sizeof (cairo_pdf_rgb_linear_function_t)); + _cairo_array_init (&surface->alpha_linear_functions, sizeof (cairo_pdf_alpha_linear_function_t)); - surface->font_subsets = _cairo_scaled_font_subsets_create (PDF_SURFACE_MAX_GLYPHS_PER_FONT, - PDF_SURFACE_MAX_GLYPHS_PER_FONT); + + /* Add alpha=1 as the first element in the list of alpha values as + * this is the most frequently referenced value. */ + status = _cairo_pdf_surface_add_alpha (surface, 1, &alpha); + if (status) { + _cairo_error (status); + goto fail1; + } + + surface->font_subsets = _cairo_scaled_font_subsets_create_composite (); if (! surface->font_subsets) { _cairo_error (CAIRO_STATUS_NO_MEMORY); - free (surface); - return (cairo_surface_t*) &_cairo_surface_nil; + goto fail2; } _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t)); @@ -296,6 +283,8 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE; + surface->force_fallbacks = FALSE; + /* Document header */ _cairo_output_stream_printf (surface->output, "%%PDF-1.4\r\n"); @@ -306,6 +295,11 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, CAIRO_CONTENT_COLOR_ALPHA, width, height, &cairo_pdf_surface_paginated_backend); + +fail1: + free (surface); +fail2: + return (cairo_surface_t*) &_cairo_surface_nil; } /** @@ -502,16 +496,17 @@ _cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface, return surface->current_stream.self; } -static void +static cairo_status_t _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface) { + cairo_status_t status = CAIRO_STATUS_SUCCESS; long length; if (! surface->current_stream.active) - return; + return CAIRO_STATUS_SUCCESS; if (surface->current_stream.compressed) { - _cairo_output_stream_destroy (surface->output); + status = _cairo_output_stream_destroy (surface->output); surface->output = surface->current_stream.old_output; _cairo_output_stream_printf (surface->output, "\r\n"); @@ -533,17 +528,19 @@ _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface) length); surface->current_stream.active = FALSE; + + return status; } static cairo_status_t _cairo_pdf_surface_finish (void *abstract_surface) { - cairo_status_t status; + cairo_status_t status, status2; cairo_pdf_surface_t *surface = abstract_surface; long offset; cairo_pdf_resource_t info, catalog; - _cairo_pdf_surface_close_stream (surface); + status = _cairo_pdf_surface_close_stream (surface); _cairo_pdf_surface_emit_font_subsets (surface); @@ -569,7 +566,9 @@ _cairo_pdf_surface_finish (void *abstract_surface) "%%%%EOF\r\n", offset); - status = _cairo_output_stream_destroy (surface->output); + status2 = _cairo_output_stream_destroy (surface->output); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; _cairo_array_fini (&surface->objects); _cairo_array_fini (&surface->pages); @@ -577,6 +576,9 @@ _cairo_pdf_surface_finish (void *abstract_surface) _cairo_array_fini (&surface->xobjects); _cairo_array_fini (&surface->streams); _cairo_array_fini (&surface->alphas); + _cairo_array_fini (&surface->smasks); + _cairo_array_fini (&surface->rgb_linear_functions); + _cairo_array_fini (&surface->alpha_linear_functions); if (surface->font_subsets) { _cairo_scaled_font_subsets_destroy (surface->font_subsets); @@ -588,13 +590,13 @@ _cairo_pdf_surface_finish (void *abstract_surface) return status; } -static void +static cairo_status_t _cairo_pdf_surface_pause_content_stream (cairo_pdf_surface_t *surface) { - _cairo_pdf_surface_close_stream (surface); + return _cairo_pdf_surface_close_stream (surface); } -static void +static cairo_status_t _cairo_pdf_surface_resume_content_stream (cairo_pdf_surface_t *surface) { cairo_pdf_resource_t stream; @@ -607,12 +609,46 @@ _cairo_pdf_surface_resume_content_stream (cairo_pdf_surface_t *surface) surface->width, surface->height); - _cairo_pdf_surface_add_stream (surface, stream); + return _cairo_pdf_surface_add_stream (surface, stream); +} + +static cairo_status_t +_cairo_pdf_surface_begin_group (cairo_pdf_surface_t *surface, cairo_pdf_resource_t *group) +{ + cairo_pdf_resource_t g; + cairo_status_t status; + + _cairo_pdf_surface_pause_content_stream (surface); + g = _cairo_pdf_surface_open_stream (surface, + TRUE, + " /Type /XObject\r\n" + " /Subtype /Form\r\n" + " /BBox [ 0 0 %f %f ]\r\n" + " /Group <<\r\n" + " /Type /Group\r\n" + " /S /Transparency\r\n" + " /CS /DeviceRGB\r\n" + " >>\r\n", + surface->width, + surface->height); + + status = _cairo_array_append (&surface->xobjects, &g); + *group = g; + + return status; +} + +static void +_cairo_pdf_surface_end_group (cairo_pdf_surface_t *surface) +{ + _cairo_pdf_surface_close_stream (surface); + _cairo_pdf_surface_resume_content_stream (surface); } static cairo_int_status_t _cairo_pdf_surface_start_page (void *abstract_surface) { + cairo_status_t status; cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_resource_t stream; @@ -624,11 +660,9 @@ _cairo_pdf_surface_start_page (void *abstract_surface) surface->width, surface->height); - _cairo_pdf_surface_add_stream (surface, stream); - - _cairo_output_stream_printf (surface->output, - "1 0 0 -1 0 %f cm\r\n", - surface->height); + status = _cairo_pdf_surface_add_stream (surface, stream); + if (status) + return status; return CAIRO_STATUS_SUCCESS; } @@ -716,7 +750,7 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, image->width, image->height); _cairo_output_stream_write (surface->output, alpha_compressed, alpha_compressed_size); _cairo_output_stream_printf (surface->output, "\r\n"); - _cairo_pdf_surface_close_stream (surface); + status = _cairo_pdf_surface_close_stream (surface); free (alpha_compressed); CLEANUP_ALPHA: @@ -728,9 +762,9 @@ _cairo_pdf_surface_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 -_cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface, - cairo_image_surface_t *image, - cairo_pdf_resource_t *image_ret) +_cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface, + cairo_image_surface_t *image, + cairo_pdf_resource_t *image_ret) { cairo_status_t status = CAIRO_STATUS_SUCCESS; char *rgb, *compressed; @@ -830,7 +864,7 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface, _cairo_output_stream_write (surface->output, compressed, compressed_size); _cairo_output_stream_printf (surface->output, "\r\n"); - _cairo_pdf_surface_close_stream (surface); + status = _cairo_pdf_surface_close_stream (surface); CLEANUP_COMPRESSED: free (compressed); @@ -841,33 +875,30 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface, } static cairo_status_t -_cairo_pdf_surface_emit_solid_pattern (cairo_pdf_surface_t *surface, - cairo_solid_pattern_t *pattern) +_cairo_pdf_surface_emit_solid_pattern (cairo_pdf_surface_t *surface, + cairo_solid_pattern_t *pattern) { - cairo_pdf_resource_t alpha; + int alpha; + cairo_status_t status; - alpha = _cairo_pdf_surface_add_alpha (surface, pattern->color.alpha); + status = _cairo_pdf_surface_add_alpha (surface, pattern->color.alpha, &alpha); + if (status) + return status; - /* With some work, we could separate the stroking - * or non-stroking color here as actually needed. */ - _cairo_output_stream_printf (surface->output, - "%f %f %f RG " - "%f %f %f rg " - "/a%d gs\r\n", - pattern->color.red, - pattern->color.green, - pattern->color.blue, - pattern->color.red, - pattern->color.green, - pattern->color.blue, - alpha.id); + surface->emitted_pattern.type = CAIRO_PATTERN_TYPE_SOLID; + surface->emitted_pattern.red = pattern->color.red; + surface->emitted_pattern.green = pattern->color.green; + surface->emitted_pattern.blue = pattern->color.blue; + surface->emitted_pattern.alpha = alpha; + surface->emitted_pattern.smask.id = 0; + surface->emitted_pattern.pattern.id = 0; return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, - cairo_surface_pattern_t *pattern) +_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; @@ -875,7 +906,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, 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_pdf_resource_t image_resource = {0}; /* squelch bogus compiler warning */ cairo_matrix_t cairo_p2d, pdf_p2d; cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base); double xstep, ystep; @@ -883,7 +914,9 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, /* XXX: Should do something clever here for PDF source surfaces ? */ - _cairo_pdf_surface_pause_content_stream (surface); + status = _cairo_pdf_surface_pause_content_stream (surface); + if (status) + return status; status = _cairo_pattern_acquire_surface ((cairo_pattern_t *)pattern, (cairo_surface_t *)surface, @@ -900,7 +933,9 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, if (status) goto BAIL; - _cairo_surface_get_extents (&surface->base, &surface_extents); + status = _cairo_surface_get_extents (&surface->base, &surface_extents); + if (status) + goto BAIL; switch (extend) { /* We implement EXTEND_PAD like EXTEND_NONE for now */ @@ -974,7 +1009,9 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, * pattern cell. */ cairo_p2d = pattern->base.matrix; - cairo_matrix_invert (&cairo_p2d); + status = cairo_matrix_invert (&cairo_p2d); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); cairo_matrix_init_identity (&pdf_p2d); cairo_matrix_translate (&pdf_p2d, 0.0, surface_extents.height); @@ -1006,20 +1043,24 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, image->width, image->height, image_resource.id); - _cairo_pdf_surface_close_stream (surface); + status = _cairo_pdf_surface_close_stream (surface); + if (status) + goto BAIL; - _cairo_pdf_surface_resume_content_stream (surface); + status = _cairo_pdf_surface_resume_content_stream (surface); + if (status) + goto BAIL; - _cairo_pdf_surface_add_pattern (surface, stream); + status = _cairo_pdf_surface_add_pattern (surface, stream); + if (status) + goto BAIL; - alpha = _cairo_pdf_surface_add_alpha (surface, 1.0); - /* With some work, we could separate the stroking - * or non-stroking pattern here as actually needed. */ - _cairo_output_stream_printf (surface->output, - "/Pattern CS /res%d SCN " - "/Pattern cs /res%d scn " - "/a%d gs\r\n", - stream.id, stream.id, alpha.id); + status = _cairo_pdf_surface_add_alpha (surface, 1.0, &surface->emitted_pattern.alpha); + if (status) + goto BAIL; + surface->emitted_pattern.type = CAIRO_PATTERN_TYPE_SURFACE; + surface->emitted_pattern.smask.id = 0; + surface->emitted_pattern.pattern = stream; BAIL: _cairo_surface_release_source_image (pat_surface, image, image_extra); @@ -1030,90 +1071,168 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, } typedef struct _cairo_pdf_color_stop { - double offset; - cairo_pdf_resource_t gradient; - unsigned char color_char[4]; + double offset; + double color[4]; + cairo_pdf_resource_t resource; } cairo_pdf_color_stop_t; -static cairo_pdf_resource_t -_cairo_pdf_surface_emit_linear_colorgradient (cairo_pdf_surface_t *surface, - cairo_pdf_color_stop_t *stop1, - cairo_pdf_color_stop_t *stop2) +static cairo_status_t +cairo_pdf_surface_emit_rgb_linear_function (cairo_pdf_surface_t *surface, + cairo_pdf_color_stop_t *stop1, + cairo_pdf_color_stop_t *stop2, + cairo_pdf_resource_t *function) { - cairo_pdf_resource_t function = _cairo_pdf_surface_new_object (surface); + int num_elems, i; + cairo_pdf_rgb_linear_function_t elem; + cairo_pdf_resource_t res; + cairo_status_t status; + + num_elems = _cairo_array_num_elements (&surface->rgb_linear_functions); + for (i = 0; i < num_elems; i++) { + _cairo_array_copy_element (&surface->rgb_linear_functions, i, &elem); + if (memcmp (&elem.color1[0], &stop1->color[0], sizeof (double)*3) != 0) + continue; + if (memcmp (&elem.color2[0], &stop2->color[0], sizeof (double)*3) != 0) + continue; + *function = elem.resource; + return CAIRO_STATUS_SUCCESS; + } + + res = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, "%d 0 obj\r\n" - "<< /FunctionType 0\r\n" + "<< /FunctionType 2\r\n" " /Domain [ 0 1 ]\r\n" - " /Size [ 2 ]\r\n" - " /BitsPerSample 8\r\n" - " /Range [ 0 1 0 1 0 1 ]\r\n" - " /Length 6\r\n" + " /C0 [ %f %f %f ]\r\n" + " /C1 [ %f %f %f ]\r\n" + " /N 1\r\n" ">>\r\n" - "stream\r\n", - function.id); + "endobj\r\n", + res.id, + stop1->color[0], + stop1->color[1], + stop1->color[2], + stop2->color[0], + stop2->color[1], + stop2->color[2]); - _cairo_output_stream_write (surface->output, stop1->color_char, 3); - _cairo_output_stream_write (surface->output, stop2->color_char, 3); - _cairo_output_stream_printf (surface->output, - "\r\n" - "endstream\r\n" - "endobj\r\n"); + elem.resource = res; + memcpy (&elem.color1[0], &stop1->color[0], sizeof (double)*3); + memcpy (&elem.color2[0], &stop2->color[0], sizeof (double)*3); - return function; + status = _cairo_array_append (&surface->rgb_linear_functions, &elem); + *function = res; + + return status; } -static cairo_pdf_resource_t -_cairo_pdf_surface_emit_stitched_colorgradient (cairo_pdf_surface_t *surface, - unsigned int n_stops, - cairo_pdf_color_stop_t stops[]) +static cairo_status_t +cairo_pdf_surface_emit_alpha_linear_function (cairo_pdf_surface_t *surface, + cairo_pdf_color_stop_t *stop1, + cairo_pdf_color_stop_t *stop2, + cairo_pdf_resource_t *function) { - cairo_pdf_resource_t function; + int num_elems, i; + cairo_pdf_alpha_linear_function_t elem; + cairo_pdf_resource_t res; + cairo_status_t status; + + num_elems = _cairo_array_num_elements (&surface->alpha_linear_functions); + for (i = 0; i < num_elems; i++) { + _cairo_array_copy_element (&surface->alpha_linear_functions, i, &elem); + if (elem.alpha1 != stop1->color[3]) + continue; + if (elem.alpha2 != stop2->color[3]) + continue; + *function = elem.resource; + return CAIRO_STATUS_SUCCESS; + } + + res = _cairo_pdf_surface_new_object (surface); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\r\n" + "<< /FunctionType 2\r\n" + " /Domain [ 0 1 ]\r\n" + " /C0 [ %f ]\r\n" + " /C1 [ %f ]\r\n" + " /N 1\r\n" + ">>\r\n" + "endobj\r\n", + res.id, + stop1->color[3], + stop2->color[3]); + + elem.resource = res; + elem.alpha1 = stop1->color[3]; + elem.alpha2 = stop2->color[3]; + + status = _cairo_array_append (&surface->alpha_linear_functions, &elem); + *function = res; + + return status; +} + +static cairo_status_t +_cairo_pdf_surface_emit_stitched_colorgradient (cairo_pdf_surface_t *surface, + unsigned int n_stops, + cairo_pdf_color_stop_t *stops, + cairo_bool_t is_alpha, + cairo_pdf_resource_t *function) +{ + cairo_pdf_resource_t res; unsigned int i; + cairo_status_t status; /* emit linear gradients between pairs of subsequent stops... */ for (i = 0; i < n_stops-1; i++) { - stops[i].gradient = _cairo_pdf_surface_emit_linear_colorgradient (surface, - &stops[i], - &stops[i+1]); + if (is_alpha) { + status = cairo_pdf_surface_emit_alpha_linear_function (surface, + &stops[i], + &stops[i+1], + &stops[i].resource); + if (status) + return status; + } else { + status = cairo_pdf_surface_emit_rgb_linear_function (surface, + &stops[i], + &stops[i+1], + &stops[i].resource); + if (status) + return status; + } } /* ... and stitch them together */ - function = _cairo_pdf_surface_new_object (surface); + res = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, "%d 0 obj\r\n" "<< /FunctionType 3\r\n" " /Domain [ 0 1 ]\r\n", - function.id); + res.id); _cairo_output_stream_printf (surface->output, " /Functions [ "); for (i = 0; i < n_stops-1; i++) - { _cairo_output_stream_printf (surface->output, - "%d 0 R ", stops[i].gradient.id); - } + "%d 0 R ", stops[i].resource.id); _cairo_output_stream_printf (surface->output, "]\r\n"); _cairo_output_stream_printf (surface->output, " /Bounds [ "); for (i = 1; i < n_stops-1; i++) - { _cairo_output_stream_printf (surface->output, "%f ", stops[i].offset); - } _cairo_output_stream_printf (surface->output, "]\r\n"); _cairo_output_stream_printf (surface->output, " /Encode [ "); for (i = 1; i < n_stops; i++) - { _cairo_output_stream_printf (surface->output, "0 1 "); - } _cairo_output_stream_printf (surface->output, "]\r\n"); @@ -1121,34 +1240,42 @@ _cairo_pdf_surface_emit_stitched_colorgradient (cairo_pdf_surface_t *surface, ">>\r\n" "endobj\r\n"); - return function; + *function = res; + + return CAIRO_STATUS_SUCCESS; } #define COLOR_STOP_EPSILON 1e-6 -static cairo_pdf_resource_t -_cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern) +static cairo_status_t +_cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, + cairo_gradient_pattern_t *pattern, + cairo_pdf_resource_t *color_function, + cairo_pdf_resource_t *alpha_function) { - cairo_pdf_resource_t function; cairo_pdf_color_stop_t *allstops, *stops; - unsigned int i, n_stops; + unsigned int n_stops; + unsigned int i; + cairo_bool_t emit_alpha = FALSE; + cairo_status_t status; - function = _cairo_pdf_surface_new_object (surface); + color_function->id = 0; + alpha_function->id = 0; allstops = malloc ((pattern->n_stops + 2) * sizeof (cairo_pdf_color_stop_t)); - if (allstops == NULL) { - _cairo_error (CAIRO_STATUS_NO_MEMORY); - function.id = 0; - return function; - } + if (allstops == NULL) + return CAIRO_STATUS_NO_MEMORY; + stops = &allstops[1]; n_stops = pattern->n_stops; - for (i = 0; i < pattern->n_stops; i++) { - stops[i].color_char[0] = pattern->stops[i].color.red >> 8; - stops[i].color_char[1] = pattern->stops[i].color.green >> 8; - stops[i].color_char[2] = pattern->stops[i].color.blue >> 8; - stops[i].color_char[3] = pattern->stops[i].color.alpha >> 8; + for (i = 0; i < n_stops; i++) { + stops[i].color[0] = pattern->stops[i].color.red / 65535.0; + stops[i].color[1] = pattern->stops[i].color.green / 65535.0; + stops[i].color[2] = pattern->stops[i].color.blue / 65535.0; + stops[i].color[3] = pattern->stops[i].color.alpha / 65535.0; + if (!CAIRO_ALPHA_IS_OPAQUE (stops[i].color[3])) + emit_alpha = TRUE; stops[i].offset = _cairo_fixed_to_double (pattern->stops[i].x); } @@ -1157,170 +1284,378 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradi if (stops[0].offset > COLOR_STOP_EPSILON) { memcpy (allstops, stops, sizeof (cairo_pdf_color_stop_t)); stops = allstops; - stops[0].offset = 0.0; n_stops++; } + stops[0].offset = 0.0; + if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) { memcpy (&stops[n_stops], &stops[n_stops - 1], sizeof (cairo_pdf_color_stop_t)); - stops[n_stops].offset = 1.0; n_stops++; } + stops[n_stops-1].offset = 1.0; if (n_stops == 2) { - /* no need for stitched function */ - function = _cairo_pdf_surface_emit_linear_colorgradient (surface, &stops[0], &stops[1]); + /* no need for stitched function */ + status = cairo_pdf_surface_emit_rgb_linear_function (surface, + &stops[0], + &stops[1], + color_function); + if (status) + goto BAIL; + + if (emit_alpha) { + status = cairo_pdf_surface_emit_alpha_linear_function (surface, + &stops[0], + &stops[1], + alpha_function); + if (status) + goto BAIL; + } } else { - /* multiple stops: stitch. XXX possible optimization: regulary spaced - * stops do not require stitching. XXX */ - function = _cairo_pdf_surface_emit_stitched_colorgradient (surface, - n_stops, - stops); + /* multiple stops: stitch. XXX possible optimization: regulary spaced + * stops do not require stitching. XXX */ + status = _cairo_pdf_surface_emit_stitched_colorgradient (surface, + n_stops, + stops, + FALSE, + color_function); + if (status) + goto BAIL; + + if (emit_alpha) { + status = _cairo_pdf_surface_emit_stitched_colorgradient (surface, + n_stops, + stops, + TRUE, + alpha_function); + if (status) + goto BAIL; + } } +BAIL: free (allstops); + return status; +} - return function; +static cairo_pdf_resource_t +cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t gradient_mask) +{ + cairo_pdf_resource_t xobj_resource, smask_resource, gstate_resource; + + xobj_resource = _cairo_pdf_surface_open_stream (surface, + TRUE, + " /Type /XObject\r\n" + " /Subtype /Form\r\n" + " /FormType 1\r\n" + " /BBox [ 0 0 %f %f ]\r\n" + " /Resources\r\n" + " << /ExtGState\r\n" + " << /a0 << /ca 1 /CA 1 >>" + " >>\r\n" + " /Pattern\r\n" + " << /res%d %d 0 R >>\r\n" + " >>\r\n" + " /Group\r\n" + " << /Type /Group\r\n" + " /S /Transparency\r\n" + " /CS /DeviceGray\r\n" + " >>\r\n", + surface->width, + surface->height, + gradient_mask.id, + gradient_mask.id); + + _cairo_output_stream_printf (surface->output, + "q\r\n" + "/a0 gs\r\n" + "/Pattern cs /res%d scn\r\n" + "0 0 %f %f re\r\n" + "f\r\n" + "Q\r\n", + gradient_mask.id, + surface->width, + surface->height); + + _cairo_pdf_surface_close_stream (surface); + + smask_resource = _cairo_pdf_surface_new_object (surface); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\r\n" + "<< /Type /Mask\r\n" + " /S /Luminosity\r\n" + " /G %d 0 R\r\n" + " /BC [ 0.0 ]\r\n" + ">>\r\n" + "endobj\r\n", + smask_resource.id, + xobj_resource.id); + + /* Create GState which uses the transparency group as an SMask. */ + gstate_resource = _cairo_pdf_surface_new_object (surface); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\r\n" + "<< /Type /ExtGState\r\n" + " /SMask %d 0 R\r\n" + " /ca 1\r\n" + " /CA 1\r\n" + " /AIS false\r\n" + ">>\r\n" + "endobj\r\n", + gstate_resource.id, + smask_resource.id); + + _cairo_pdf_surface_add_smask (surface, gstate_resource); + + return gstate_resource; } static cairo_status_t -_cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern) +_cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface, + cairo_linear_pattern_t *pattern) { - cairo_pdf_resource_t function, pattern_resource, alpha; - double x0, y0, x1, y1; - cairo_matrix_t p2u; + cairo_pdf_resource_t pattern_resource, smask; + cairo_pdf_resource_t color_function, alpha_function; + double x1, y1, x2, y2; + cairo_matrix_t pat_to_pdf; + cairo_extend_t extend; + cairo_status_t status; - _cairo_pdf_surface_pause_content_stream (surface); + extend = cairo_pattern_get_extend (&pattern->base.base); + status = _cairo_pdf_surface_pause_content_stream (surface); + if (status) + return status; - function = _cairo_pdf_surface_emit_pattern_stops (surface, &pattern->base); - if (function.id == 0) - return CAIRO_STATUS_NO_MEMORY; + status = _cairo_pdf_surface_emit_pattern_stops (surface, + &pattern->base, + &color_function, + &alpha_function); + if (status) + return status; - p2u = pattern->base.base.matrix; - cairo_matrix_invert (&p2u); + pat_to_pdf = pattern->base.base.matrix; + status = cairo_matrix_invert (&pat_to_pdf); + if (status) + return status; - x0 = _cairo_fixed_to_double (pattern->gradient.p1.x); - y0 = _cairo_fixed_to_double (pattern->gradient.p1.y); - cairo_matrix_transform_point (&p2u, &x0, &y0); - x1 = _cairo_fixed_to_double (pattern->gradient.p2.x); - y1 = _cairo_fixed_to_double (pattern->gradient.p2.y); - cairo_matrix_transform_point (&p2u, &x1, &y1); + cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf); + x1 = _cairo_fixed_to_double (pattern->gradient.p1.x); + y1 = _cairo_fixed_to_double (pattern->gradient.p1.y); + x2 = _cairo_fixed_to_double (pattern->gradient.p2.x); + y2 = _cairo_fixed_to_double (pattern->gradient.p2.y); pattern_resource = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, - "%d 0 obj\r\n" - "<< /Type /Pattern\r\n" - " /PatternType 2\r\n" - " /Matrix [ 1 0 0 -1 0 %f ]\r\n" - " /Shading\r\n" - " << /ShadingType 2\r\n" - " /ColorSpace /DeviceRGB\r\n" - " /Coords [ %f %f %f %f ]\r\n" - " /Function %d 0 R\r\n" - " /Extend [ true true ]\r\n" - " >>\r\n" - ">>\r\n" - "endobj\r\n", - pattern_resource.id, - surface->height, - x0, y0, x1, y1, - function.id); + "%d 0 obj\r\n" + "<< /Type /Pattern\r\n" + " /PatternType 2\r\n" + " /Matrix [ %f %f %f %f %f %f ]\r\n" + " /Shading\r\n" + " << /ShadingType 2\r\n" + " /ColorSpace /DeviceRGB\r\n" + " /Coords [ %f %f %f %f ]\r\n" + " /Function %d 0 R\r\n", + pattern_resource.id, + pat_to_pdf.xx, pat_to_pdf.yx, + pat_to_pdf.xy, pat_to_pdf.yy, + pat_to_pdf.x0, pat_to_pdf.y0, + x1, y1, x2, y2, + color_function.id); - _cairo_pdf_surface_add_pattern (surface, pattern_resource); + if (extend == CAIRO_EXTEND_PAD) { + _cairo_output_stream_printf (surface->output, + " /Extend [ true true ]\r\n"); + } else { + _cairo_output_stream_printf (surface->output, + " /Extend [ false false ]\r\n"); + } - alpha = _cairo_pdf_surface_add_alpha (surface, 1.0); - - /* Use pattern */ - /* With some work, we could separate the stroking - * or non-stroking pattern here as actually needed. */ _cairo_output_stream_printf (surface->output, - "/Pattern CS /res%d SCN " - "/Pattern cs /res%d scn " - "/a%d gs\r\n", - pattern_resource.id, - pattern_resource.id, - alpha.id); + " >>\r\n" + ">>\r\n" + "endobj\r\n"); - _cairo_pdf_surface_resume_content_stream (surface); + if (alpha_function.id == 0) { + surface->emitted_pattern.smask.id = 0; + } else { + cairo_pdf_resource_t mask_resource; - return CAIRO_STATUS_SUCCESS; + /* Create pattern for SMask. */ + mask_resource = _cairo_pdf_surface_new_object (surface); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\r\n" + "<< /Type /Pattern\r\n" + " /PatternType 2\r\n" + " /Matrix [ %f %f %f %f %f %f ]\r\n" + " /Shading\r\n" + " << /ShadingType 2\r\n" + " /ColorSpace /DeviceGray\r\n" + " /Coords [ %f %f %f %f ]\r\n" + " /Function %d 0 R\r\n", + mask_resource.id, + pat_to_pdf.xx, pat_to_pdf.yx, + pat_to_pdf.xy, pat_to_pdf.yy, + pat_to_pdf.x0, pat_to_pdf.y0, + x1, y1, x2, y2, + alpha_function.id); + + if (extend == CAIRO_EXTEND_PAD) { + _cairo_output_stream_printf (surface->output, + " /Extend [ true true ]\r\n"); + } else { + _cairo_output_stream_printf (surface->output, + " /Extend [ false false ]\r\n"); + } + + _cairo_output_stream_printf (surface->output, + " >>\r\n" + ">>\r\n" + "endobj\r\n"); + status = _cairo_pdf_surface_add_pattern (surface, mask_resource); + if (status) + return status; + + smask = cairo_pdf_surface_emit_transparency_group (surface, mask_resource); + surface->emitted_pattern.smask = smask; + } + + surface->emitted_pattern.type = CAIRO_PATTERN_TYPE_LINEAR; + status = _cairo_pdf_surface_add_alpha (surface, 1, &surface->emitted_pattern.alpha); + if (status) + return status; + + surface->emitted_pattern.pattern = pattern_resource; + status = _cairo_pdf_surface_add_pattern (surface, pattern_resource); + if (status) + return status; + + return _cairo_pdf_surface_resume_content_stream (surface); } static cairo_status_t -_cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern) +_cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface, + cairo_radial_pattern_t *pattern) { - cairo_pdf_resource_t function, pattern_resource, alpha; - double x0, y0, x1, y1, r0, r1; - cairo_matrix_t p2u; + cairo_pdf_resource_t pattern_resource, smask; + cairo_pdf_resource_t color_function, alpha_function; + double x1, y1, x2, y2, r1, r2; + cairo_matrix_t pat_to_pdf; + cairo_extend_t extend; + cairo_status_t status; - _cairo_pdf_surface_pause_content_stream (surface); + extend = cairo_pattern_get_extend (&pattern->base.base); + status = _cairo_pdf_surface_pause_content_stream (surface); + if (status) + return status; - function = _cairo_pdf_surface_emit_pattern_stops (surface, &pattern->base); - if (function.id == 0) - return CAIRO_STATUS_NO_MEMORY; + status = _cairo_pdf_surface_emit_pattern_stops (surface, + &pattern->base, + &color_function, + &alpha_function); + if (status) + return status; - p2u = pattern->base.base.matrix; - cairo_matrix_invert (&p2u); + pat_to_pdf = pattern->base.base.matrix; + status = cairo_matrix_invert (&pat_to_pdf); + if (status) + return status; - 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.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); + cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf); + x1 = _cairo_fixed_to_double (pattern->gradient.c1.x); + y1 = _cairo_fixed_to_double (pattern->gradient.c1.y); + r1 = _cairo_fixed_to_double (pattern->gradient.c1.radius); + x2 = _cairo_fixed_to_double (pattern->gradient.c2.x); + y2 = _cairo_fixed_to_double (pattern->gradient.c2.y); + r2 = _cairo_fixed_to_double (pattern->gradient.c2.radius); - /* FIXME: This is surely crack, but how should you scale a radius - * in a non-orthogonal coordinate system? */ - cairo_matrix_transform_distance (&p2u, &r0, &r1); - - /* FIXME: There is a difference between the cairo gradient extend - * semantics and PDF extend semantics. PDFs extend=false means - * that nothing is painted outside the gradient boundaries, - * whereas cairo takes this to mean that the end color is padded - * to infinity. Setting extend=true in PDF gives the cairo default - * behavoir, not yet sure how to implement the cairo mirror and - * repeat behaviour. */ pattern_resource = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, - "%d 0 obj\r\n" - "<< /Type /Pattern\r\n" - " /PatternType 2\r\n" - " /Matrix [ 1 0 0 -1 0 %f ]\r\n" - " /Shading\r\n" - " << /ShadingType 3\r\n" - " /ColorSpace /DeviceRGB\r\n" - " /Coords [ %f %f %f %f %f %f ]\r\n" - " /Function %d 0 R\r\n" - " /Extend [ true true ]\r\n" - " >>\r\n" - ">>\r\n" - "endobj\r\n", - pattern_resource.id, - surface->height, - x0, y0, r0, x1, y1, r1, - function.id); + "%d 0 obj\r\n" + "<< /Type /Pattern\r\n" + " /PatternType 2\r\n" + " /Matrix [ %f %f %f %f %f %f ]\r\n" + " /Shading\r\n" + " << /ShadingType 3\r\n" + " /ColorSpace /DeviceRGB\r\n" + " /Coords [ %f %f %f %f %f %f ]\r\n" + " /Function %d 0 R\r\n", + pattern_resource.id, + pat_to_pdf.xx, pat_to_pdf.yx, + pat_to_pdf.xy, pat_to_pdf.yy, + pat_to_pdf.x0, pat_to_pdf.y0, + x1, y1, r1, x2, y2, r2, + color_function.id); - _cairo_pdf_surface_add_pattern (surface, pattern_resource); + if (extend == CAIRO_EXTEND_PAD) { + _cairo_output_stream_printf (surface->output, + " /Extend [ true true ]\r\n"); + } else { + _cairo_output_stream_printf (surface->output, + " /Extend [ false false ]\r\n"); + } - alpha = _cairo_pdf_surface_add_alpha (surface, 1.0); - - /* Use pattern */ - /* With some work, we could separate the stroking - * or non-stroking pattern here as actually needed. */ _cairo_output_stream_printf (surface->output, - "/Pattern CS /res%d SCN " - "/Pattern cs /res%d scn " - "/a%d gs\r\n", - pattern_resource.id, - pattern_resource.id, - alpha.id); + " >>\r\n" + ">>\r\n" + "endobj\r\n"); - _cairo_pdf_surface_resume_content_stream (surface); + if (alpha_function.id == 0) { + surface->emitted_pattern.smask.id = 0; + } else { + cairo_pdf_resource_t mask_resource; - return CAIRO_STATUS_SUCCESS; + /* Create pattern for SMask. */ + mask_resource = _cairo_pdf_surface_new_object (surface); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\r\n" + "<< /Type /Pattern\r\n" + " /PatternType 2\r\n" + " /Matrix [ %f %f %f %f %f %f ]\r\n" + " /Shading\r\n" + " << /ShadingType 3\r\n" + " /ColorSpace /DeviceGray\r\n" + " /Coords [ %f %f %f %f %f %f ]\r\n" + " /Function %d 0 R\r\n", + mask_resource.id, + pat_to_pdf.xx, pat_to_pdf.yx, + pat_to_pdf.xy, pat_to_pdf.yy, + pat_to_pdf.x0, pat_to_pdf.y0, + x1, y1, r1, x2, y2, r2, + alpha_function.id); + + if (extend == CAIRO_EXTEND_PAD) { + _cairo_output_stream_printf (surface->output, + " /Extend [ true true ]\r\n"); + } else { + _cairo_output_stream_printf (surface->output, + " /Extend [ false false ]\r\n"); + } + + _cairo_output_stream_printf (surface->output, + " >>\r\n" + ">>\r\n" + "endobj\r\n"); + + smask = cairo_pdf_surface_emit_transparency_group (surface, mask_resource); + surface->emitted_pattern.smask = smask; + } + + surface->emitted_pattern.type = CAIRO_PATTERN_TYPE_RADIAL; + + status = _cairo_pdf_surface_add_alpha (surface, 1.0, &surface->emitted_pattern.alpha); + if (status) + return status; + + surface->emitted_pattern.pattern = pattern_resource; + + status = _cairo_pdf_surface_add_pattern (surface, pattern_resource); + if (status) + return status; + + return _cairo_pdf_surface_resume_content_stream (surface); } static cairo_status_t @@ -1338,13 +1673,52 @@ _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t * case CAIRO_PATTERN_TYPE_RADIAL: return _cairo_pdf_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern); - } ASSERT_NOT_REACHED; return CAIRO_STATUS_PATTERN_TYPE_MISMATCH; } +static cairo_status_t +_cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface, + cairo_bool_t is_stroke) +{ + if (surface->emitted_pattern.type == CAIRO_PATTERN_TYPE_SOLID) { + _cairo_output_stream_printf (surface->output, + "%f %f %f ", + surface->emitted_pattern.red, + surface->emitted_pattern.green, + surface->emitted_pattern.blue); + + if (is_stroke) + _cairo_output_stream_printf (surface->output, "RG "); + else + _cairo_output_stream_printf (surface->output, "rg "); + + _cairo_output_stream_printf (surface->output, + "/a%d gs\r\n", + surface->emitted_pattern.alpha); + } else { + if (is_stroke) { + _cairo_output_stream_printf (surface->output, + "/Pattern CS /res%d SCN ", + surface->emitted_pattern.pattern); + } else { + _cairo_output_stream_printf (surface->output, + "/Pattern cs /res%d scn ", + surface->emitted_pattern.pattern); + } + + _cairo_output_stream_printf (surface->output, + "/a%d gs ", + surface->emitted_pattern.alpha ); + + _cairo_output_stream_printf (surface->output, "\r\n"); + } + + return CAIRO_STATUS_SUCCESS; +} + static cairo_int_status_t _cairo_pdf_surface_copy_page (void *abstract_surface) { @@ -1389,6 +1763,7 @@ _cairo_pdf_surface_get_extents (void *abstract_surface, typedef struct _pdf_path_info { cairo_output_stream_t *output; + cairo_matrix_t *cairo_to_pdf; cairo_matrix_t *ctm_inverse; } pdf_path_info_t; @@ -1399,6 +1774,8 @@ _cairo_pdf_path_move_to (void *closure, cairo_point_t *point) double x = _cairo_fixed_to_double (point->x); double y = _cairo_fixed_to_double (point->y); + if (info->cairo_to_pdf) + cairo_matrix_transform_point (info->cairo_to_pdf, &x, &y); if (info->ctm_inverse) cairo_matrix_transform_point (info->ctm_inverse, &x, &y); @@ -1415,6 +1792,8 @@ _cairo_pdf_path_line_to (void *closure, cairo_point_t *point) double x = _cairo_fixed_to_double (point->x); double y = _cairo_fixed_to_double (point->y); + if (info->cairo_to_pdf) + cairo_matrix_transform_point (info->cairo_to_pdf, &x, &y); if (info->ctm_inverse) cairo_matrix_transform_point (info->ctm_inverse, &x, &y); @@ -1437,6 +1816,11 @@ _cairo_pdf_path_curve_to (void *closure, double dx = _cairo_fixed_to_double (d->x); double dy = _cairo_fixed_to_double (d->y); + if (info->cairo_to_pdf) { + cairo_matrix_transform_point (info->cairo_to_pdf, &bx, &by); + cairo_matrix_transform_point (info->cairo_to_pdf, &cx, &cy); + cairo_matrix_transform_point (info->cairo_to_pdf, &dx, &dy); + } if (info->ctm_inverse) { cairo_matrix_transform_point (info->ctm_inverse, &bx, &by); cairo_matrix_transform_point (info->ctm_inverse, &cx, &cy); @@ -1485,6 +1869,7 @@ _cairo_pdf_surface_intersect_clip_path (void *abstract_surface, } info.output = surface->output; + info.cairo_to_pdf = &surface->cairo_to_pdf; info.ctm_inverse = NULL; status = _cairo_path_fixed_interpret (path, @@ -1546,10 +1931,10 @@ _cairo_pdf_surface_write_info (cairo_pdf_surface_t *surface) static void _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface) { - cairo_pdf_resource_t page, *res; + cairo_pdf_resource_t page, *res, smask; cairo_pdf_font_t font; int num_pages, num_fonts, i; - int num_alphas, num_resources; + int num_alphas, num_smasks, num_resources; double alpha; _cairo_pdf_surface_update_object (surface, surface->pages_resource); @@ -1571,19 +1956,25 @@ _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface) _cairo_output_stream_printf (surface->output, " /Resources <<\r\n"); num_alphas = _cairo_array_num_elements (&surface->alphas); - if (num_alphas > 0) { + num_smasks = _cairo_array_num_elements (&surface->smasks); + if (num_alphas > 0 || num_smasks > 0) { _cairo_output_stream_printf (surface->output, " /ExtGState <<\r\n"); for (i = 0; i < num_alphas; i++) { - /* With some work, we could separate the stroking - * or non-stroking alpha here as actually needed. */ _cairo_array_copy_element (&surface->alphas, i, &alpha); _cairo_output_stream_printf (surface->output, " /a%d << /CA %f /ca %f >>\r\n", i, alpha, alpha); } + for (i = 0; i < num_smasks; i++) { + _cairo_array_copy_element (&surface->smasks, i, &smask); + _cairo_output_stream_printf (surface->output, + " /sm%d %d 0 R\r\n", + smask.id, smask.id); + } + _cairo_output_stream_printf (surface->output, " >>\r\n"); } @@ -1619,14 +2010,20 @@ _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface) " >>\r\n"); } - _cairo_output_stream_printf (surface->output," /Font <<\r\n"); num_fonts = _cairo_array_num_elements (&surface->fonts); - for (i = 0; i < num_fonts; i++) { - _cairo_array_copy_element (&surface->fonts, i, &font); - _cairo_output_stream_printf (surface->output, " /CairoFont-%d-%d %d 0 R\r\n", - font.font_id, font.subset_id, font.subset_resource.id); + if (num_fonts > 0) { + _cairo_output_stream_printf (surface->output," /Font <<\r\n"); + num_fonts = _cairo_array_num_elements (&surface->fonts); + for (i = 0; i < num_fonts; i++) { + _cairo_array_copy_element (&surface->fonts, i, &font); + _cairo_output_stream_printf (surface->output, + " /CairoFont-%d-%d %d 0 R\r\n", + font.font_id, + font.subset_id, + font.subset_resource.id); + } + _cairo_output_stream_printf (surface->output, " >>\r\n"); } - _cairo_output_stream_printf (surface->output, " >>\r\n"); _cairo_output_stream_printf (surface->output, " >>\r\n"); @@ -1639,12 +2036,14 @@ _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface) } static cairo_pdf_resource_t -_cairo_pdf_surface_emit_toUnicode_stream (cairo_pdf_surface_t *surface, - cairo_scaled_font_subset_t *font_subset) +_cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface, + cairo_scaled_font_subset_t *font_subset, + cairo_bool_t is_composite) { const cairo_scaled_font_backend_t *backend; cairo_pdf_resource_t stream; - unsigned int i; + unsigned int i, num_bfchar; + cairo_status_t status; if (font_subset->to_unicode == NULL) { stream.id = 0; @@ -1666,88 +2065,86 @@ _cairo_pdf_surface_emit_toUnicode_stream (cairo_pdf_surface_t *surface, "12 dict begin\r\n" "begincmap\r\n" "/CIDSystemInfo\r\n" - "<< /Registry (Cairo)\r\n" - " /Ordering (ToUnicode-%d-%d)\r\n" + "<< /Registry (Adobe)\r\n" + " /Ordering (UCS)\r\n" " /Supplement 0\r\n" ">> def\r\n" - "/CMapName /Cairo-ToUnicode-%d-%d def\r\n" + "/CMapName /Adobe-Identity-UCS 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); + "1 begincodespacerange\r\n"); + if (is_composite) { + _cairo_output_stream_printf (surface->output, + "<0000> \r\n"); + } else { + _cairo_output_stream_printf (surface->output, + "<00> \r\n"); + } + + _cairo_output_stream_printf (surface->output, + "endcodespacerange\r\n"); + + num_bfchar = font_subset->num_glyphs - 1; /* The CMap specification has a limit of 100 characters per beginbfchar operator */ _cairo_output_stream_printf (surface->output, "%d beginbfchar\r\n", - font_subset->num_glyphs > 100 ? 100 : font_subset->num_glyphs); - for (i = 0; i < font_subset->num_glyphs; i++) { + num_bfchar > 100 ? 100 : num_bfchar); + for (i = 0; i < num_bfchar; i++) { if (i != 0 && i % 100 == 0) { _cairo_output_stream_printf (surface->output, "endbfchar\r\n" "%d beginbfchar\r\n", - font_subset->num_glyphs - i > 100 ? 100 : font_subset->num_glyphs - i); + num_bfchar - i > 100 ? 100 : num_bfchar - i); + } + if (is_composite) { + _cairo_output_stream_printf (surface->output, + "<%04x> <%04x>\r\n", + i + 1, font_subset->to_unicode[i + 1]); + } else { + _cairo_output_stream_printf (surface->output, + "<%02x> <%04x>\r\n", + i + 1, font_subset->to_unicode[i + 1]); } - _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" + "endcmap\r\n" + "CMapName currentdict /CMap defineresource pop\r\n" + "end\r\n" "end\r\n"); - _cairo_pdf_surface_close_stream (surface); + status = _cairo_pdf_surface_close_stream (surface); + if (status) + stream.id = 0; 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_surface_emit_cff_font (cairo_pdf_surface_t *surface, + cairo_scaled_font_subset_t *font_subset, + cairo_cff_subset_t *subset) { - cairo_pdf_resource_t stream, descriptor, subset_resource, to_unicode_stream; - cairo_status_t status; + cairo_pdf_resource_t stream, descriptor, cidfont_dict; + cairo_pdf_resource_t subset_resource, to_unicode_stream; cairo_pdf_font_t font; - cairo_cff_subset_t subset; unsigned long compressed_length; char *compressed; unsigned int i; - char name[64]; + cairo_status_t status; - snprintf (name, sizeof name, "CairoFont-%d-%d", - font_subset->font_id, font_subset->subset_id); - status = _cairo_cff_subset_init (&subset, name, font_subset); - if (status) - return status; - - compressed = compress_dup (subset.data, subset.data_length, &compressed_length); - if (compressed == NULL) { - _cairo_cff_subset_fini (&subset); + compressed = compress_dup (subset->data, subset->data_length, &compressed_length); + if (compressed == NULL) return CAIRO_STATUS_NO_MEMORY; - } 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" - " /Subtype /Type1C\r\n" + " /Subtype /CIDFontType0C\r\n" ">>\r\n" "stream\r\n", stream.id, @@ -1759,7 +2156,7 @@ _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); + to_unicode_stream = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset, TRUE); descriptor = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, @@ -1778,41 +2175,57 @@ _cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface, ">>\r\n" "endobj\r\n", descriptor.id, - subset.base_font, - subset.x_min, - subset.y_min, - subset.x_max, - subset.y_max, - subset.ascent, - subset.descent, + subset->base_font, + subset->x_min, + subset->y_min, + subset->x_max, + subset->y_max, + subset->ascent, + subset->descent, stream.id); + cidfont_dict = _cairo_pdf_surface_new_object (surface); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\r\n" + "<< /Type /Font\r\n" + " /Subtype /CIDFontType0\r\n" + " /BaseFont /%s\r\n" + " /CIDSystemInfo\r\n" + " << /Registry (Adobe)\r\n" + " /Ordering (Identity)\r\n" + " /Supplement 0\r\n" + " >>\r\n" + " /FontDescriptor %d 0 R\r\n" + " /W [0 [", + cidfont_dict.id, + subset->base_font, + descriptor.id); + + for (i = 0; i < font_subset->num_glyphs; i++) + _cairo_output_stream_printf (surface->output, + " %d", + subset->widths[i]); + + _cairo_output_stream_printf (surface->output, + " ]]\r\n" + ">>\r\n" + "endobj\r\n"); + subset_resource = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, "%d 0 obj\r\n" "<< /Type /Font\r\n" - " /Subtype /Type1\r\n" + " /Subtype /Type0\r\n" " /BaseFont /%s\r\n" - " /FirstChar 0\r\n" - " /LastChar %d\r\n" - " /FontDescriptor %d 0 R\r\n" - " /Widths [", + " /Encoding /Identity-H\r\n" + " /DescendantFonts [ %d 0 R]\r\n", subset_resource.id, - subset.base_font, - font_subset->num_glyphs - 1, - descriptor.id); - - for (i = 0; i < font_subset->num_glyphs; i++) - _cairo_output_stream_printf (surface->output, - " %d", - subset.widths[i]); - - _cairo_output_stream_printf (surface->output, - " ]\r\n"); + subset->base_font, + cidfont_dict.id); if (to_unicode_stream.id != 0) _cairo_output_stream_printf (surface->output, - " /ToUnicode %d 0 R\r\n", + " /ToUnicode %d 0 R\r\n", to_unicode_stream.id); _cairo_output_stream_printf (surface->output, @@ -1822,11 +2235,51 @@ _cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface, font.font_id = font_subset->font_id; font.subset_id = font_subset->subset_id; font.subset_resource = subset_resource; - _cairo_array_append (&surface->fonts, &font); + status = _cairo_array_append (&surface->fonts, &font); + + return status; +} + +static cairo_status_t +_cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface, + cairo_scaled_font_subset_t *font_subset) +{ + cairo_status_t status; + cairo_cff_subset_t subset; + char name[64]; + + snprintf (name, sizeof name, "CairoFont-%d-%d", + font_subset->font_id, font_subset->subset_id); + status = _cairo_cff_subset_init (&subset, name, font_subset); + if (status) + return status; + + status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset); _cairo_cff_subset_fini (&subset); - return CAIRO_STATUS_SUCCESS; + return status; +} + +static cairo_status_t +_cairo_pdf_surface_emit_cff_fallback_font (cairo_pdf_surface_t *surface, + cairo_scaled_font_subset_t *font_subset) +{ + cairo_status_t status; + cairo_cff_subset_t subset; + char name[64]; + + snprintf (name, sizeof name, "CairoFont-%d-%d", + font_subset->font_id, font_subset->subset_id); + status = _cairo_cff_fallback_init (&subset, name, font_subset); + if (status) + return status; + + status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset); + + _cairo_cff_fallback_fini (&subset); + + return status; } static cairo_status_t @@ -1868,7 +2321,7 @@ _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); + to_unicode_stream = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset, FALSE); descriptor = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, @@ -1931,9 +2384,7 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface, font.font_id = font_subset->font_id; font.subset_id = font_subset->subset_id; font.subset_resource = subset_resource; - _cairo_array_append (&surface->fonts, &font); - - return CAIRO_STATUS_SUCCESS; + return _cairo_array_append (&surface->fonts, &font); } #if CAIRO_HAS_FT_FONT @@ -1984,7 +2435,8 @@ 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, encoding, subset_resource, to_unicode_stream; + cairo_pdf_resource_t stream, descriptor, cidfont_dict; + cairo_pdf_resource_t subset_resource, to_unicode_stream; cairo_status_t status; cairo_pdf_font_t font; cairo_truetype_subset_t subset; @@ -2021,7 +2473,7 @@ _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); + to_unicode_stream = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset, TRUE); descriptor = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, @@ -2050,18 +2502,30 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface, (long)(subset.y_max*PDF_UNITS_PER_EM), stream.id); - encoding = _cairo_pdf_surface_new_object (surface); + cidfont_dict = _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); + "%d 0 obj\r\n" + "<< /Type /Font\r\n" + " /Subtype /CIDFontType2\r\n" + " /BaseFont /%s\r\n" + " /CIDSystemInfo\r\n" + " << /Registry (Adobe)\r\n" + " /Ordering (Identity)\r\n" + " /Supplement 0\r\n" + " >>\r\n" + " /FontDescriptor %d 0 R\r\n" + " /W [0 [", + cidfont_dict.id, + subset.base_font, + descriptor.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, + " %ld", + (long)(subset.widths[i]*PDF_UNITS_PER_EM)); _cairo_output_stream_printf (surface->output, - " ]\r\n" + " ]]\r\n" ">>\r\n" "endobj\r\n"); @@ -2069,30 +2533,17 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface, _cairo_output_stream_printf (surface->output, "%d 0 obj\r\n" "<< /Type /Font\r\n" - " /Subtype /TrueType\r\n" + " /Subtype /Type0\r\n" " /BaseFont /%s\r\n" - " /FirstChar 0\r\n" - " /LastChar %d\r\n" - " /FontDescriptor %d 0 R\r\n" - " /Encoding %d 0 R\r\n" - " /Widths [", + " /Encoding /Identity-H\r\n" + " /DescendantFonts [ %d 0 R]\r\n", subset_resource.id, subset.base_font, - font_subset->num_glyphs - 1, - descriptor.id, - encoding.id); - - for (i = 0; i < font_subset->num_glyphs; i++) - _cairo_output_stream_printf (surface->output, - " %ld", - (long)(subset.widths[i]*PDF_UNITS_PER_EM)); - - _cairo_output_stream_printf (surface->output, - " ]\r\n"); + cidfont_dict.id); if (to_unicode_stream.id != 0) _cairo_output_stream_printf (surface->output, - " /ToUnicode %d 0 R\r\n", + " /ToUnicode %d 0 R\r\n", to_unicode_stream.id); _cairo_output_stream_printf (surface->output, @@ -2102,11 +2553,11 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface, font.font_id = font_subset->font_id; font.subset_id = font_subset->subset_id; font.subset_resource = subset_resource; - _cairo_array_append (&surface->fonts, &font); + status = _cairo_array_append (&surface->fonts, &font); _cairo_truetype_subset_fini (&subset); - return CAIRO_STATUS_SUCCESS; + return status; } static cairo_int_status_t @@ -2137,6 +2588,7 @@ _cairo_pdf_surface_emit_outline_glyph (cairo_pdf_surface_t *surface, -_cairo_fixed_to_double (scaled_glyph->bbox.p1.y)); info.output = surface->output; + info.cairo_to_pdf = &surface->cairo_to_pdf; info.ctm_inverse = NULL; status = _cairo_path_fixed_interpret (scaled_glyph->path, @@ -2150,9 +2602,7 @@ _cairo_pdf_surface_emit_outline_glyph (cairo_pdf_surface_t *surface, _cairo_output_stream_printf (surface->output, " f"); - _cairo_pdf_surface_close_stream (surface); - - return CAIRO_STATUS_SUCCESS; + return _cairo_pdf_surface_close_stream (surface); } static cairo_int_status_t @@ -2229,7 +2679,7 @@ _cairo_pdf_surface_emit_bitmap_glyph (cairo_pdf_surface_t *surface, _cairo_output_stream_printf (surface->output, "\r\nEI\r\n"); - _cairo_pdf_surface_close_stream (surface); + status = _cairo_pdf_surface_close_stream (surface); if (image != scaled_glyph->surface) cairo_surface_destroy (&image->base); @@ -2267,6 +2717,7 @@ static cairo_status_t _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, cairo_scaled_font_subset_t *font_subset) { + cairo_status_t status; cairo_pdf_resource_t *glyphs, encoding, char_procs, subset_resource, to_unicode_stream; cairo_pdf_font_t font; cairo_matrix_t matrix; @@ -2339,11 +2790,13 @@ _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); + to_unicode_stream = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset, FALSE); subset_resource = _cairo_pdf_surface_new_object (surface); matrix = font_subset->scaled_font->scale; - cairo_matrix_invert (&matrix); + status = cairo_matrix_invert (&matrix); + /* _cairo_scaled_font_init ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); _cairo_output_stream_printf (surface->output, "%d 0 obj\r\n" "<< /Type /Font\r\n" @@ -2387,9 +2840,7 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, font.font_id = font_subset->font_id; font.subset_id = font_subset->subset_id; font.subset_resource = subset_resource; - _cairo_array_append (&surface->fonts, &font); - - return CAIRO_STATUS_SUCCESS; + return _cairo_array_append (&surface->fonts, &font); } static void @@ -2399,23 +2850,29 @@ _cairo_pdf_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_s cairo_pdf_surface_t *surface = closure; cairo_status_t status; - status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return; + if (font_subset->is_composite) { + status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return; + status = _cairo_pdf_surface_emit_truetype_font_subset (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return; + + status = _cairo_pdf_surface_emit_cff_fallback_font (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return; + } else { #if CAIRO_HAS_FT_FONT - status = _cairo_pdf_surface_emit_type1_font_subset (surface, font_subset); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return; + status = _cairo_pdf_surface_emit_type1_font_subset (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return; #endif - status = _cairo_pdf_surface_emit_truetype_font_subset (surface, font_subset); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return; - - status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return; + status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return; + } } static void @@ -2509,7 +2966,9 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface) surface->has_clip = FALSE; } - _cairo_pdf_surface_close_stream (surface); + status = _cairo_pdf_surface_close_stream (surface); + if (status) + return status; page = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, @@ -2582,44 +3041,62 @@ _surface_pattern_supported (cairo_surface_pattern_t *pattern) return FALSE; } +static cairo_bool_t +_gradient_pattern_supported (cairo_pattern_t *pattern) +{ + cairo_extend_t extend; + + extend = cairo_pattern_get_extend (pattern); + + if (extend == CAIRO_EXTEND_REPEAT || + extend == CAIRO_EXTEND_REFLECT) { + return FALSE; + } + + /* Radial gradients are currently only supported when one circle + * is inside the other. */ + if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) { + double x1, y1, x2, y2, r1, r2, d; + cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern; + + x1 = _cairo_fixed_to_double (radial->gradient.c1.x); + y1 = _cairo_fixed_to_double (radial->gradient.c1.y); + r1 = _cairo_fixed_to_double (radial->gradient.c1.radius); + x2 = _cairo_fixed_to_double (radial->gradient.c2.x); + y2 = _cairo_fixed_to_double (radial->gradient.c2.y); + r2 = _cairo_fixed_to_double (radial->gradient.c2.radius); + + d = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)); + if (d > fabs(r2 - r1)) { + return FALSE; + } + } + + return TRUE; +} + static cairo_bool_t _pattern_supported (cairo_pattern_t *pattern) { if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) return TRUE; + if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || + pattern->type == CAIRO_PATTERN_TYPE_RADIAL) + return _gradient_pattern_supported (pattern); + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) return _surface_pattern_supported ((cairo_surface_pattern_t *) pattern); return FALSE; } -static cairo_bool_t cairo_pdf_force_fallbacks = FALSE; - -/** - * _cairo_pdf_test_force_fallbacks - * - * Force the PDF surface backend to use image fallbacks for every - * operation. - * - * - * This function is only intended for internal - * testing use within the cairo distribution. It is not installed in - * any public header file. - * - **/ -void -_cairo_pdf_test_force_fallbacks (void) -{ - cairo_pdf_force_fallbacks = TRUE; -} - static cairo_int_status_t -__cairo_pdf_surface_operation_supported (cairo_pdf_surface_t *surface, +_cairo_pdf_surface_operation_supported (cairo_pdf_surface_t *surface, cairo_operator_t op, cairo_pattern_t *pattern) { - if (cairo_pdf_force_fallbacks) + if (surface->force_fallbacks) return FALSE; if (! _pattern_supported (pattern)) @@ -2638,7 +3115,7 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface, cairo_operator_t op, cairo_pattern_t *pattern) { - if (__cairo_pdf_surface_operation_supported (surface, op, pattern)) + if (_cairo_pdf_surface_operation_supported (surface, op, pattern)) return CAIRO_STATUS_SUCCESS; else return CAIRO_INT_STATUS_UNSUPPORTED; @@ -2650,6 +3127,7 @@ _cairo_pdf_surface_paint (void *abstract_surface, cairo_pattern_t *source) { cairo_pdf_surface_t *surface = abstract_surface; + cairo_pdf_resource_t group = {0}; /* squelch bogus compiler warning */ cairo_status_t status; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) @@ -2662,17 +3140,38 @@ _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 (__cairo_pdf_surface_operation_supported (op, source)); + assert (_cairo_pdf_surface_operation_supported (op, source)); */ status = _cairo_pdf_surface_emit_pattern (surface, source); if (status) return status; + if (surface->emitted_pattern.smask.id != 0) { + status = _cairo_pdf_surface_begin_group (surface, &group); + if (status) + return status; + } else { + _cairo_output_stream_printf (surface->output, "q "); + } + + _cairo_pdf_surface_select_pattern (surface, FALSE); + _cairo_output_stream_printf (surface->output, "0 0 %f %f re f\r\n", surface->width, surface->height); + if (surface->emitted_pattern.smask.id != 0) { + _cairo_pdf_surface_end_group (surface); + + _cairo_output_stream_printf (surface->output, + "q /sm%d gs /res%d Do Q\r\n", + surface->emitted_pattern.smask, + group.id); + } else { + _cairo_output_stream_printf (surface->output, "Q\r\n"); + } + return _cairo_output_stream_get_status (surface->output); } @@ -2770,30 +3269,44 @@ _cairo_pdf_surface_stroke (void *abstract_surface, cairo_antialias_t antialias) { cairo_pdf_surface_t *surface = abstract_surface; + cairo_pdf_resource_t group = {0}; /* squelch bogus compiler warning */ pdf_path_info_t info; cairo_status_t status; + cairo_matrix_t m; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _cairo_pdf_surface_analyze_operation (surface, op, source); - assert (__cairo_pdf_surface_operation_supported (surface, op, source)); + assert (_cairo_pdf_surface_operation_supported (surface, op, source)); status = _cairo_pdf_surface_emit_pattern (surface, source); if (status) return status; + if (surface->emitted_pattern.smask.id != 0) { + status = _cairo_pdf_surface_begin_group (surface, &group); + if (status) + return status; + } else { + _cairo_output_stream_printf (surface->output, "q "); + } + + _cairo_pdf_surface_select_pattern (surface, TRUE); + status = _cairo_pdf_surface_emit_stroke_style (surface, style); if (status) return status; info.output = surface->output; + info.cairo_to_pdf = NULL; info.ctm_inverse = ctm_inverse; + cairo_matrix_multiply (&m, ctm, &surface->cairo_to_pdf); _cairo_output_stream_printf (surface->output, "q %f %f %f %f %f %f cm\r\n", - ctm->xx, ctm->yx, ctm->xy, ctm->yy, - ctm->x0, ctm->y0); + m.xx, m.yx, m.xy, m.yy, + m.x0, m.y0); status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, @@ -2805,6 +3318,17 @@ _cairo_pdf_surface_stroke (void *abstract_surface, _cairo_output_stream_printf (surface->output, "S Q\r\n"); + if (surface->emitted_pattern.smask.id != 0) { + _cairo_pdf_surface_end_group (surface); + + _cairo_output_stream_printf (surface->output, + "q /sm%d gs /res%d Do Q\r\n", + surface->emitted_pattern.smask, + group.id); + } else { + _cairo_output_stream_printf (surface->output, "Q\r\n"); + } + return status; } @@ -2818,6 +3342,7 @@ _cairo_pdf_surface_fill (void *abstract_surface, cairo_antialias_t antialias) { cairo_pdf_surface_t *surface = abstract_surface; + cairo_pdf_resource_t group = {0}; /* squelch bogus compiler warning */ const char *pdf_operator; cairo_status_t status; pdf_path_info_t info; @@ -2825,15 +3350,24 @@ _cairo_pdf_surface_fill (void *abstract_surface, if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _cairo_pdf_surface_analyze_operation (surface, op, source); - assert (__cairo_pdf_surface_operation_supported (surface, op, source)); + assert (_cairo_pdf_surface_operation_supported (surface, op, source)); status = _cairo_pdf_surface_emit_pattern (surface, source); if (status) return status; - info.output = surface->output; - info.ctm_inverse = NULL; + if (surface->emitted_pattern.smask.id != 0) { + status = _cairo_pdf_surface_begin_group (surface, &group); + if (status) + return status; + } else { + _cairo_output_stream_printf (surface->output, "q "); + } + _cairo_pdf_surface_select_pattern (surface, FALSE); + info.output = surface->output; + info.cairo_to_pdf = &surface->cairo_to_pdf; + info.ctm_inverse = NULL; status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, _cairo_pdf_path_move_to, @@ -2857,9 +3391,22 @@ _cairo_pdf_surface_fill (void *abstract_surface, "%s\r\n", pdf_operator); + if (surface->emitted_pattern.smask.id != 0) { + _cairo_pdf_surface_end_group (surface); + + _cairo_output_stream_printf (surface->output, + "q /sm%d gs /res%d Do Q\r\n", + surface->emitted_pattern.smask, + group.id); + } else { + _cairo_output_stream_printf (surface->output, "Q\r\n"); + } + return status; } +#define GLYPH_POSITION_TOLERANCE 0.001 + static cairo_int_status_t _cairo_pdf_surface_show_glyphs (void *abstract_surface, cairo_operator_t op, @@ -2869,21 +3416,34 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface, cairo_scaled_font_t *scaled_font) { cairo_pdf_surface_t *surface = abstract_surface; + cairo_pdf_resource_t group = {0}; /* squelch bogus compiler warning */ unsigned int current_subset_id = (unsigned int)-1; - unsigned int font_id, subset_id, subset_glyph_index; - cairo_bool_t diagonal; + cairo_scaled_font_subsets_glyph_t subset_glyph; + cairo_bool_t diagonal, in_TJ; cairo_status_t status; - int i; + double Tlm_x = 0, Tlm_y = 0; + double Tm_x = 0, y; + int i, hex_width; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _cairo_pdf_surface_analyze_operation (surface, op, source); - assert (__cairo_pdf_surface_operation_supported (surface, op, source)); + assert (_cairo_pdf_surface_operation_supported (surface, op, source)); status = _cairo_pdf_surface_emit_pattern (surface, source); if (status) return status; + if (surface->emitted_pattern.smask.id != 0) { + status = _cairo_pdf_surface_begin_group (surface, &group); + if (status) + return status; + } else { + _cairo_output_stream_printf (surface->output, "q "); + } + + _cairo_pdf_surface_select_pattern (surface, FALSE); + _cairo_output_stream_printf (surface->output, "BT\r\n"); @@ -2893,41 +3453,146 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface, else diagonal = FALSE; + in_TJ = FALSE; for (i = 0; i < num_glyphs; i++) { - status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets, - scaled_font, glyphs[i].index, - &font_id, &subset_id, &subset_glyph_index); + status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets, + scaled_font, glyphs[i].index, + &subset_glyph); if (status) - return status; + return status; - if (subset_id != current_subset_id) - _cairo_output_stream_printf (surface->output, - "/CairoFont-%d-%d 1 Tf\r\n", - font_id, subset_id); + if (subset_glyph.is_composite) + hex_width = 4; + else + hex_width = 2; - if (subset_id != current_subset_id || !diagonal) { + if (subset_glyph.is_scaled == FALSE) { + y = 0.0; + cairo_matrix_transform_distance (&scaled_font->scale, + &subset_glyph.x_advance, + &y); + } + + if (subset_glyph.subset_id != current_subset_id) { + if (in_TJ) { + _cairo_output_stream_printf (surface->output, ">] TJ\r\n"); + in_TJ = FALSE; + } _cairo_output_stream_printf (surface->output, - "%f %f %f %f %f %f Tm <%02x> Tj\r\n", + "/CairoFont-%d-%d 1 Tf\r\n", + subset_glyph.font_id, + subset_glyph.subset_id); + } + + if (subset_glyph.subset_id != current_subset_id || !diagonal) { + _cairo_output_stream_printf (surface->output, + "%f %f %f %f %f %f Tm\r\n", scaled_font->scale.xx, - scaled_font->scale.yx, + -scaled_font->scale.yx, -scaled_font->scale.xy, - -scaled_font->scale.yy, + scaled_font->scale.yy, glyphs[i].x, - glyphs[i].y, - subset_glyph_index); - current_subset_id = subset_id; + surface->height - glyphs[i].y); + current_subset_id = subset_glyph.subset_id; + Tlm_x = glyphs[i].x; + Tlm_y = glyphs[i].y; + Tm_x = Tlm_x; + } + + if (diagonal) { + if (i < num_glyphs - 1 && + fabs((glyphs[i].y - glyphs[i+1].y)/scaled_font->scale.yy) < GLYPH_POSITION_TOLERANCE && + fabs((glyphs[i].x - glyphs[i+1].x)/scaled_font->scale.xx) < 10) + { + if (!in_TJ) { + if (i != 0) { + _cairo_output_stream_printf (surface->output, + "%f %f Td\r\n", + (glyphs[i].x - Tlm_x)/scaled_font->scale.xx, + -(glyphs[i].y - Tlm_y)/scaled_font->scale.yy); + + Tlm_x = glyphs[i].x; + Tlm_y = glyphs[i].y; + Tm_x = Tlm_x; + } + _cairo_output_stream_printf (surface->output, + "[<%0*x", + hex_width, + subset_glyph.subset_glyph_index); + Tm_x += subset_glyph.x_advance; + in_TJ = TRUE; + } else { + if (fabs((glyphs[i].x - Tm_x)/scaled_font->scale.xx) > GLYPH_POSITION_TOLERANCE) { + double delta = glyphs[i].x - Tm_x; + + _cairo_output_stream_printf (surface->output, + "> %f <", + -1000.0*delta/scaled_font->scale.xx); + Tm_x += delta; + } + _cairo_output_stream_printf (surface->output, + "%0*x", + hex_width, + subset_glyph.subset_glyph_index); + Tm_x += subset_glyph.x_advance; + } + } + else + { + if (in_TJ) { + if (fabs((glyphs[i].x - Tm_x)/scaled_font->scale.xx) > GLYPH_POSITION_TOLERANCE) { + double delta = glyphs[i].x - Tm_x; + + _cairo_output_stream_printf (surface->output, + "> %f <", + -1000.0*delta/scaled_font->scale.xx); + Tm_x += delta; + } + _cairo_output_stream_printf (surface->output, + "%0*x>] TJ\r\n", + hex_width, + subset_glyph.subset_glyph_index); + Tm_x += subset_glyph.x_advance; + in_TJ = FALSE; + } else { + if (i != 0) { + _cairo_output_stream_printf (surface->output, + "%f %f Td ", + (glyphs[i].x - Tlm_x)/scaled_font->scale.xx, + (glyphs[i].y - Tlm_y)/-scaled_font->scale.yy); + Tlm_x = glyphs[i].x; + Tlm_y = glyphs[i].y; + Tm_x = Tlm_x; + } + _cairo_output_stream_printf (surface->output, + "<%0*x> Tj ", + hex_width, + subset_glyph.subset_glyph_index); + Tm_x += subset_glyph.x_advance; + } + } } else { _cairo_output_stream_printf (surface->output, - "%f %f Td <%02x> Tj\r\n", - (glyphs[i].x - glyphs[i-1].x)/scaled_font->scale.xx, - (glyphs[i].y - glyphs[i-1].y)/-scaled_font->scale.yy, - subset_glyph_index); + "<%0*x> Tj\r\n", + hex_width, + subset_glyph.subset_glyph_index); } } _cairo_output_stream_printf (surface->output, "ET\r\n"); + if (surface->emitted_pattern.smask.id != 0) { + _cairo_pdf_surface_end_group (surface); + + _cairo_output_stream_printf (surface->output, + "q /sm%d gs /res%d Do Q\r\n", + surface->emitted_pattern.smask, + group.id); + } else { + _cairo_output_stream_printf (surface->output, "Q\r\n"); + } + return _cairo_output_stream_get_status (surface->output); } @@ -2972,6 +3637,9 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = { _cairo_pdf_surface_fill, _cairo_pdf_surface_show_glyphs, NULL, /* snapshot */ + + NULL, /* is_compatible */ + NULL, /* reset */ }; static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend = { diff --git a/gfx/cairo/cairo/src/cairo-pen.c b/gfx/cairo/cairo/src/cairo-pen.c index 1af8c36a1de7..ec9eb7ac4692 100644 --- a/gfx/cairo/cairo/src/cairo-pen.c +++ b/gfx/cairo/cairo/src/cairo-pen.c @@ -45,15 +45,13 @@ _cairo_pen_compute_slopes (cairo_pen_t *pen); static cairo_status_t _cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_direction_t dir, cairo_polygon_t *polygon); -cairo_status_t +void _cairo_pen_init_empty (cairo_pen_t *pen) { pen->radius = 0; pen->tolerance = 0; pen->vertices = NULL; pen->num_vertices = 0; - - return CAIRO_STATUS_SUCCESS; } cairo_status_t @@ -135,6 +133,7 @@ cairo_status_t _cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points) { cairo_pen_vertex_t *vertices; + cairo_status_t status; int num_vertices; int i; @@ -150,7 +149,9 @@ _cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points) for (i=0; i < num_points; i++) pen->vertices[pen->num_vertices-num_points+i].point = point[i]; - _cairo_hull_compute (pen->vertices, &pen->num_vertices); + status = _cairo_hull_compute (pen->vertices, &pen->num_vertices); + if (status) + return status; _cairo_pen_compute_slopes (pen); @@ -388,15 +389,18 @@ _cairo_pen_stroke_spline_half (cairo_pen_t *pen, final_slope.dy = -final_slope.dy; } - _cairo_pen_find_active_cw_vertex_index (pen, &initial_slope, &active); + status = _cairo_pen_find_active_cw_vertex_index (pen, + &initial_slope, + &active); + if (status) + return status; i = start; while (i != stop) { hull_point.x = point[i].x + pen->vertices[active].point.x; hull_point.y = point[i].y + pen->vertices[active].point.y; - status = _cairo_polygon_line_to (polygon, &hull_point); - if (status) - return status; + + _cairo_polygon_line_to (polygon, &hull_point); if (i + step == stop) slope = final_slope; @@ -437,19 +441,24 @@ _cairo_pen_stroke_spline (cairo_pen_t *pen, status = _cairo_spline_decompose (spline, tolerance); if (status) - return status; + goto BAIL; status = _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_FORWARD, &polygon); if (status) - return status; + goto BAIL; status = _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_REVERSE, &polygon); if (status) - return status; + goto BAIL; _cairo_polygon_close (&polygon); - _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING); + status = _cairo_polygon_status (&polygon); + if (status) + goto BAIL; + + status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING); +BAIL: _cairo_polygon_fini (&polygon); - return CAIRO_STATUS_SUCCESS; + return status; } diff --git a/gfx/cairo/cairo/src/cairo-png.c b/gfx/cairo/cairo/src/cairo-png.c index 006cae3fd2b0..35db3d9aa563 100644 --- a/gfx/cairo/cairo/src/cairo-png.c +++ b/gfx/cairo/cairo/src/cairo-png.c @@ -35,8 +35,9 @@ * Kristian Høgsberg */ -#include #include "cairoint.h" + +#include #include /* Unpremultiplies data and converts native endian ARGB => RGBA bytes */ @@ -82,6 +83,25 @@ convert_data_to_bytes (png_structp png, png_row_infop row_info, png_bytep data) } } +/* Use a couple of simple error callbacks that do not print anything to + * stderr and rely on the user to check for errors via the cairo_status_t + * return. + */ +static void +png_simple_error_callback (png_structp png_save_ptr, + png_const_charp error_msg) +{ + _cairo_error (CAIRO_STATUS_NO_MEMORY); + longjmp (png_save_ptr->jmpbuf, CAIRO_STATUS_NO_MEMORY); +} + +static void +png_simple_warning_callback (png_structp png_save_ptr, + png_const_charp error_msg) +{ +} + + static cairo_status_t write_png (cairo_surface_t *surface, png_rw_ptr write_func, @@ -117,7 +137,9 @@ write_png (cairo_surface_t *surface, for (i = 0; i < image->height; i++) rows[i] = (png_byte *) image->data + i * image->stride; - png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, + png_simple_error_callback, + png_simple_warning_callback); if (png == NULL) { status = CAIRO_STATUS_NO_MEMORY; goto BAIL2; @@ -129,10 +151,9 @@ write_png (cairo_surface_t *surface, goto BAIL3; } - if (setjmp (png_jmpbuf (png))) { - status = CAIRO_STATUS_NO_MEMORY; + status = setjmp (png_jmpbuf (png)); + if (status) goto BAIL3; - } png_set_write_fn (png, closure, write_func, NULL); @@ -154,7 +175,7 @@ write_png (cairo_surface_t *surface, png_color_type = PNG_COLOR_TYPE_GRAY; break; default: - status = CAIRO_STATUS_NULL_POINTER; + status = CAIRO_STATUS_INVALID_FORMAT; goto BAIL3; } @@ -206,8 +227,13 @@ stdio_write_func (png_structp png, png_bytep data, png_size_t size) FILE *fp; fp = png_get_io_ptr (png); - if (fwrite (data, 1, size, fp) != size) - png_error(png, "Write Error"); + while (size) { + size_t ret = fwrite (data, 1, size, fp); + size -= ret; + data += ret; + if (size && ferror (fp)) + png_error(png, "Write Error"); + } } /** @@ -332,20 +358,20 @@ read_png (png_rw_ptr read_func, void *closure) { cairo_surface_t *surface = (cairo_surface_t*) &_cairo_surface_nil; - png_byte *data = NULL; - unsigned int i; png_struct *png = NULL; png_info *info; + png_byte *data = NULL; + png_byte **row_pointers = NULL; png_uint_32 png_width, png_height, stride; int depth, color_type, interlace; + unsigned int i; unsigned int pixel_size; - png_byte **row_pointers = NULL; /* XXX: Perhaps we'll want some other error handlers? */ png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, - NULL, - NULL); + png_simple_error_callback, + png_simple_warning_callback); if (png == NULL) goto BAIL; @@ -373,7 +399,11 @@ read_png (png_rw_ptr read_func, /* expand gray bit depth if needed */ if (color_type == PNG_COLOR_TYPE_GRAY && depth < 8) +#if PNG_LIBPNG_VER >= 10209 + png_set_expand_gray_1_2_4_to_8 (png); +#else png_set_gray_1_2_4_to_8 (png); +#endif /* transform transparency to alpha */ if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha (png); @@ -442,8 +472,13 @@ stdio_read_func (png_structp png, png_bytep data, png_size_t size) FILE *fp; fp = png_get_io_ptr (png); - if (fread (data, 1, size, fp) != size) - png_error(png, "Read Error"); + while (size) { + size_t ret = fread (data, 1, size, fp); + size -= ret; + data += ret; + if (size && ferror (fp)) + png_error(png, "Read Error"); + } } /** diff --git a/gfx/cairo/cairo/src/cairo-polygon.c b/gfx/cairo/cairo/src/cairo-polygon.c index 52c72b710d14..e9fc78b79add 100644 --- a/gfx/cairo/cairo/src/cairo-polygon.c +++ b/gfx/cairo/cairo/src/cairo-polygon.c @@ -34,7 +34,6 @@ * Carl D. Worth */ -#include #include "cairoint.h" /* private functions */ @@ -45,6 +44,8 @@ _cairo_polygon_grow (cairo_polygon_t *polygon); void _cairo_polygon_init (cairo_polygon_t *polygon) { + polygon->status = CAIRO_STATUS_SUCCESS; + polygon->num_edges = 0; polygon->edges_size = 0; @@ -66,13 +67,19 @@ _cairo_polygon_fini (cairo_polygon_t *polygon) polygon->has_current_point = FALSE; } +cairo_status_t +_cairo_polygon_status (cairo_polygon_t *polygon) +{ + return polygon->status; +} + /* make room for at least one more edge */ static cairo_status_t _cairo_polygon_grow (cairo_polygon_t *polygon) { cairo_edge_t *new_edges; int old_size = polygon->edges_size; - int embedded_size = sizeof (polygon->edges_embedded) / sizeof (polygon->edges_embedded[0]); + int embedded_size = ARRAY_LENGTH (polygon->edges_embedded); int new_size = 2 * MAX (old_size, 16); /* we have a local buffer at polygon->edges_embedded. try to fulfill the request @@ -103,22 +110,22 @@ _cairo_polygon_grow (cairo_polygon_t *polygon) return CAIRO_STATUS_SUCCESS; } -cairo_status_t +void _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_point_t *p2) { - cairo_status_t status; cairo_edge_t *edge; + if (polygon->status) + return; + /* drop horizontal edges */ - if (p1->y == p2->y) { + if (p1->y == p2->y) goto DONE; - } if (polygon->num_edges >= polygon->edges_size) { - status = _cairo_polygon_grow (polygon); - if (status) { - return status; - } + polygon->status = _cairo_polygon_grow (polygon); + if (polygon->status) + return; } edge = &polygon->edges[polygon->num_edges]; @@ -136,49 +143,45 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_poin DONE: _cairo_polygon_move_to (polygon, p2); - - return CAIRO_STATUS_SUCCESS; } -cairo_status_t +void _cairo_polygon_move_to (cairo_polygon_t *polygon, cairo_point_t *point) { + if (polygon->status) + return; + if (! polygon->has_current_point) polygon->first_point = *point; + polygon->current_point = *point; polygon->has_current_point = TRUE; - - return CAIRO_STATUS_SUCCESS; } -cairo_status_t +void _cairo_polygon_line_to (cairo_polygon_t *polygon, cairo_point_t *point) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; + if (polygon->status) + return; if (polygon->has_current_point) { - status = _cairo_polygon_add_edge (polygon, &polygon->current_point, point); + _cairo_polygon_add_edge (polygon, &polygon->current_point, point); } else { _cairo_polygon_move_to (polygon, point); } - - return status; } -cairo_status_t +void _cairo_polygon_close (cairo_polygon_t *polygon) { - cairo_status_t status; + if (polygon->status) + return; if (polygon->has_current_point) { - status = _cairo_polygon_add_edge (polygon, - &polygon->current_point, - &polygon->first_point); - if (status) - return status; + _cairo_polygon_add_edge (polygon, + &polygon->current_point, + &polygon->first_point); polygon->has_current_point = FALSE; } - - return CAIRO_STATUS_SUCCESS; } diff --git a/gfx/cairo/cairo/src/cairo-ps-surface-private.h b/gfx/cairo/cairo/src/cairo-ps-surface-private.h new file mode 100644 index 000000000000..2499b992fb96 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-ps-surface-private.h @@ -0,0 +1,80 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2003 University of Southern California + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Kristian Høgsberg + * Keith Packard + */ + +#ifndef CAIRO_PS_SURFACE_PRIVATE_H +#define CAIRO_PS_SURFACE_PRIVATE_H + +#include "cairo-ps.h" + +#include "cairo-surface-private.h" + +typedef struct cairo_ps_surface { + cairo_surface_t base; + + /* Here final_stream corresponds to the stream/file passed to + * cairo_ps_surface_create surface is built. Meanwhile stream is a + * temporary stream in which the file output is built, (so that + * the header can be built and inserted into the target stream + * before the contents of the temporary stream are copied). */ + cairo_output_stream_t *final_stream; + + FILE *tmpfile; + cairo_output_stream_t *stream; + + double width; + double height; + double max_width; + double max_height; + + int num_pages; + + cairo_paginated_mode_t paginated_mode; + + cairo_bool_t force_fallbacks; + + cairo_scaled_font_subsets_t *font_subsets; + + cairo_array_t dsc_header_comments; + cairo_array_t dsc_setup_comments; + cairo_array_t dsc_page_setup_comments; + + cairo_array_t *dsc_comment_target; +} cairo_ps_surface_t; + +#endif /* CAIRO_PS_SURFACE_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-ps-surface.c b/gfx/cairo/cairo/src/cairo-ps-surface.c index 5f43e98c7971..919a498c5bad 100644 --- a/gfx/cairo/cairo/src/cairo-ps-surface.c +++ b/gfx/cairo/cairo/src/cairo-ps-surface.c @@ -39,9 +39,9 @@ #include "cairoint.h" #include "cairo-ps.h" -#include "cairo-ps-test.h" +#include "cairo-ps-surface-private.h" #include "cairo-scaled-font-subsets-private.h" -#include "cairo-paginated-surface-private.h" +#include "cairo-paginated-private.h" #include "cairo-meta-surface-private.h" #include "cairo-output-stream-private.h" @@ -52,40 +52,6 @@ static const cairo_surface_backend_t cairo_ps_surface_backend; static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend; -typedef struct cairo_ps_surface { - cairo_surface_t base; - - /* Here final_stream corresponds to the stream/file passed to - * cairo_ps_surface_create surface is built. Meanwhile stream is a - * temporary stream in which the file output is built, (so that - * the header can be built and inserted into the target stream - * before the contents of the temporary stream are copied). */ - cairo_output_stream_t *final_stream; - - FILE *tmpfile; - cairo_output_stream_t *stream; - - double width; - double height; - double max_width; - double max_height; - - int num_pages; - - cairo_paginated_mode_t paginated_mode; - - cairo_scaled_font_subsets_t *font_subsets; - - cairo_array_t dsc_header_comments; - cairo_array_t dsc_setup_comments; - cairo_array_t dsc_page_setup_comments; - - cairo_array_t *dsc_comment_target; - -} cairo_ps_surface_t; - -#define PS_SURFACE_MAX_GLYPHS_PER_FONT 256 - /* A word wrap stream can be used as a filter to do word wrapping on * top of an existing output stream. The word wrapping is quite * simple, using isspace to determine characters that separate @@ -182,7 +148,7 @@ _word_wrap_stream_create (cairo_output_stream_t *output, int max_column) stream = malloc (sizeof (word_wrap_stream_t)); if (stream == NULL) - return (cairo_output_stream_t *) &cairo_output_stream_nil; + return (cairo_output_stream_t *) &_cairo_output_stream_nil; _cairo_output_stream_init (&stream->base, _word_wrap_stream_write, @@ -297,7 +263,7 @@ _cairo_ps_surface_emit_path (cairo_ps_surface_t *surface, cairo_line_cap_t line_cap) { cairo_output_stream_t *word_wrap; - cairo_status_t status; + cairo_status_t status, status2; ps_path_info_t path_info; word_wrap = _word_wrap_stream_create (stream, 79); @@ -315,7 +281,9 @@ _cairo_ps_surface_emit_path (cairo_ps_surface_t *surface, if (status == CAIRO_STATUS_SUCCESS) status = _cairo_output_stream_get_status (word_wrap); - _cairo_output_stream_destroy (word_wrap); + status2 = _cairo_output_stream_destroy (word_wrap); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; return status; } @@ -484,18 +452,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 = 0; i < font_subset->num_glyphs; i++) + for (i = 1; 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 + 1); + font_subset->num_glyphs); - for (i = 0; i < font_subset->num_glyphs; i++) + for (i = 1; i < font_subset->num_glyphs; i++) _cairo_output_stream_printf (surface->final_stream, - "/g%d %d def\n", i, i + 1); + "/g%d %d def\n", i, i); _cairo_output_stream_printf (surface->final_stream, "end readonly def\n"); @@ -579,6 +547,8 @@ _cairo_ps_surface_emit_bitmap_glyph_data (cairo_ps_surface_t *surface, CAIRO_SCALED_GLYPH_INFO_METRICS| CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); + if (status) + return status; image = scaled_glyph->surface; if (image->format != CAIRO_FORMAT_A1) { @@ -634,7 +604,7 @@ _cairo_ps_surface_emit_bitmap_glyph_data (cairo_ps_surface_t *surface, return CAIRO_STATUS_SUCCESS; } -static void +static cairo_status_t _cairo_ps_surface_emit_glyph (cairo_ps_surface_t *surface, cairo_scaled_font_t *scaled_font, unsigned long scaled_font_glyph_index, @@ -658,6 +628,8 @@ _cairo_ps_surface_emit_glyph (cairo_ps_surface_t *surface, if (status) _cairo_surface_set_error (&surface->base, status); + + return status; } static cairo_status_t @@ -666,6 +638,7 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface, { + cairo_status_t status; cairo_matrix_t matrix; unsigned int i; @@ -678,7 +651,9 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface, font_subset->subset_id); matrix = font_subset->scaled_font->scale; - cairo_matrix_invert (&matrix); + status = cairo_matrix_invert (&matrix); + /* _cairo_scaled_font_init ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); _cairo_output_stream_printf (surface->final_stream, "\t/FontType\t3\n" "\t/FontMatrix\t[%f %f %f %f 0 0]\n" @@ -691,9 +666,11 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface, -matrix.yy); for (i = 0; i < font_subset->num_glyphs; i++) { - _cairo_ps_surface_emit_glyph (surface, - font_subset->scaled_font, - font_subset->glyphs[i], i); + status = _cairo_ps_surface_emit_glyph (surface, + font_subset->scaled_font, + font_subset->glyphs[i], i); + if (status) + return status; } _cairo_output_stream_printf (surface->final_stream, @@ -809,8 +786,7 @@ _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, - PS_SURFACE_MAX_GLYPHS_PER_FONT); + surface->font_subsets = _cairo_scaled_font_subsets_create_simple (); if (! surface->font_subsets) goto CLEANUP_OUTPUT_STREAM; @@ -819,6 +795,7 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream, surface->max_width = width; surface->max_height = height; surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE; + surface->force_fallbacks = FALSE; surface->num_pages = 0; @@ -834,7 +811,8 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream, &cairo_ps_surface_paginated_backend); CLEANUP_OUTPUT_STREAM: - _cairo_output_stream_destroy (surface->stream); + status = _cairo_output_stream_destroy (surface->stream); + /* Ignore status---we're already on a failure path. */ CLEANUP_TMPFILE: fclose (surface->tmpfile); CLEANUP_SURFACE: @@ -1201,7 +1179,7 @@ cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface) static cairo_status_t _cairo_ps_surface_finish (void *abstract_surface) { - cairo_status_t status; + cairo_status_t status, status2; cairo_ps_surface_t *surface = abstract_surface; int i, num_comments; char **comments; @@ -1214,16 +1192,13 @@ _cairo_ps_surface_finish (void *abstract_surface) _cairo_ps_surface_emit_footer (surface); - _cairo_output_stream_close (surface->stream); - status = _cairo_output_stream_get_status (surface->stream); - _cairo_output_stream_destroy (surface->stream); + status = _cairo_output_stream_destroy (surface->stream); fclose (surface->tmpfile); - _cairo_output_stream_close (surface->final_stream); + status2 = _cairo_output_stream_destroy (surface->final_stream); if (status == CAIRO_STATUS_SUCCESS) - status = _cairo_output_stream_get_status (surface->final_stream); - _cairo_output_stream_destroy (surface->final_stream); + status = status2; num_comments = _cairo_array_num_elements (&surface->dsc_header_comments); comments = _cairo_array_index (&surface->dsc_header_comments, 0); @@ -1383,32 +1358,12 @@ pattern_supported (const cairo_pattern_t *pattern) return FALSE; } -static cairo_bool_t cairo_ps_force_fallbacks = FALSE; - -/** - * _cairo_ps_test_force_fallbacks - * - * Force the PS surface backend to use image fallbacks for every - * operation. - * - * - * This function is only intended for internal - * testing use within the cairo distribution. It is not installed in - * any public header file. - * - **/ -void -_cairo_ps_test_force_fallbacks (void) -{ - cairo_ps_force_fallbacks = TRUE; -} - static cairo_int_status_t _cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *pattern) { - if (cairo_ps_force_fallbacks) + if (surface->force_fallbacks) return FALSE; if (! pattern_supported (pattern)) @@ -1542,7 +1497,7 @@ _string_array_stream_create (cairo_output_stream_t *output) stream = malloc (sizeof (string_array_stream_t)); if (stream == NULL) - return (cairo_output_stream_t *) &cairo_output_stream_nil; + return (cairo_output_stream_t *) &_cairo_output_stream_nil; _cairo_output_stream_init (&stream->base, _string_array_stream_write, @@ -1562,7 +1517,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface, cairo_image_surface_t *image, const char *name) { - cairo_status_t status; + cairo_status_t status, status2; unsigned char *rgb, *compressed; unsigned long rgb_size, compressed_size; cairo_surface_t *opaque; @@ -1588,20 +1543,29 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface, _cairo_pattern_init_for_surface (&pattern.surface, &image->base); - _cairo_surface_fill_rectangle (opaque, - CAIRO_OPERATOR_SOURCE, - CAIRO_COLOR_WHITE, - 0, 0, image->width, image->height); + status = _cairo_surface_fill_rectangle (opaque, + CAIRO_OPERATOR_SOURCE, + CAIRO_COLOR_WHITE, + 0, 0, + image->width, image->height); + if (status) { + _cairo_pattern_fini (&pattern.base); + goto bail0; + } - _cairo_surface_composite (CAIRO_OPERATOR_OVER, - &pattern.base, - NULL, - opaque, - 0, 0, - 0, 0, - 0, 0, - image->width, - image->height); + status = _cairo_surface_composite (CAIRO_OPERATOR_OVER, + &pattern.base, + NULL, + opaque, + 0, 0, + 0, 0, + 0, 0, + image->width, + image->height); + if (status) { + _cairo_pattern_fini (&pattern.base); + goto bail0; + } _cairo_pattern_fini (&pattern.base); opaque_image = (cairo_image_surface_t *) opaque; @@ -1646,8 +1610,12 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface, _cairo_output_stream_write (base85_stream, compressed, compressed_size); - _cairo_output_stream_destroy (base85_stream); - _cairo_output_stream_destroy (string_array_stream); + status = _cairo_output_stream_destroy (base85_stream); + status2 = _cairo_output_stream_destroy (string_array_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + if (status) + goto bail3; _cairo_output_stream_printf (surface->stream, "] def\n"); @@ -1679,6 +1647,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface, status = CAIRO_STATUS_SUCCESS; + bail3: free (compressed); bail2: free (rgb); @@ -1705,19 +1674,26 @@ _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface, pattern->color.blue); } -static void +static cairo_status_t _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, cairo_surface_pattern_t *pattern) { + cairo_status_t status; double bbox_width, bbox_height; double xstep, ystep; cairo_matrix_t inverse = pattern->base.matrix; - cairo_matrix_invert (&inverse); + status = cairo_matrix_invert (&inverse); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); if (_cairo_surface_is_meta (pattern->surface)) { _cairo_output_stream_printf (surface->stream, "/MyPattern {\n"); - _cairo_meta_surface_replay (pattern->surface, &surface->base); + + status = _cairo_meta_surface_replay (pattern->surface, &surface->base); + if (status) + return status; + bbox_width = surface->width; bbox_height = surface->height; xstep = surface->width; @@ -1805,6 +1781,8 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, inverse.x0, inverse.y0); _cairo_output_stream_printf (surface->stream, "makepattern setpattern\n"); + + return CAIRO_STATUS_SUCCESS; } static void @@ -1821,12 +1799,13 @@ _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface, /* XXX: NYI */ } -static void +static cairo_status_t _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, cairo_pattern_t *pattern) { /* FIXME: We should keep track of what pattern is currently set in * the postscript file and only emit code if we're setting a * different pattern. */ + cairo_status_t status; switch (pattern->type) { case CAIRO_PATTERN_TYPE_SOLID: @@ -1834,7 +1813,10 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, cairo_pattern_t *pa break; case CAIRO_PATTERN_TYPE_SURFACE: - _cairo_ps_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern); + status = _cairo_ps_surface_emit_surface_pattern (surface, + (cairo_surface_pattern_t *) pattern); + if (status) + return status; break; case CAIRO_PATTERN_TYPE_LINEAR: @@ -1845,6 +1827,8 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, cairo_pattern_t *pa _cairo_ps_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern); break; } + + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t @@ -1930,6 +1914,7 @@ _cairo_ps_surface_paint (void *abstract_surface, cairo_ps_surface_t *surface = abstract_surface; cairo_output_stream_t *stream = surface->stream; cairo_rectangle_int16_t extents, pattern_extents; + cairo_status_t status; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _cairo_ps_surface_analyze_operation (surface, op, source); @@ -1941,17 +1926,25 @@ _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 (__cairo_ps_surface_operation_supported (op, source)); + assert (_cairo_ps_surface_operation_supported (op, source)); */ _cairo_output_stream_printf (stream, "%% _cairo_ps_surface_paint\n"); - _cairo_surface_get_extents (&surface->base, &extents); - _cairo_pattern_get_extents (source, &pattern_extents); + status = _cairo_surface_get_extents (&surface->base, &extents); + if (status) + return status; + + status = _cairo_pattern_get_extents (source, &pattern_extents); + if (status) + return status; + _cairo_rectangle_intersect (&extents, &pattern_extents); - _cairo_ps_surface_emit_pattern (surface, source); + status = _cairo_ps_surface_emit_pattern (surface, source); + if (status) + return status; _cairo_output_stream_printf (stream, "%d %d M\n", extents.x, extents.y); @@ -1965,6 +1958,7 @@ _cairo_ps_surface_paint (void *abstract_surface, extents.x, extents.y + extents.height); _cairo_output_stream_printf (stream, "P F\n"); + return CAIRO_STATUS_SUCCESS; } @@ -2200,7 +2194,7 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface, cairo_ps_surface_t *surface = abstract_surface; cairo_output_stream_t *stream = surface->stream; unsigned int current_subset_id = -1; - unsigned int font_id; + cairo_scaled_font_subsets_glyph_t subset_glyph; cairo_ps_glyph_id_t *glyph_ids; cairo_status_t status; unsigned int num_glyphs_unsigned, i, j, last, end; @@ -2228,11 +2222,11 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface, for (i = 0; i < num_glyphs_unsigned; i++) { status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets, scaled_font, glyphs[i].index, - &font_id, - &(glyph_ids[i].subset_id), - &(glyph_ids[i].glyph_id)); + &subset_glyph); if (status) goto fail; + glyph_ids[i].subset_id = subset_glyph.subset_id; + glyph_ids[i].glyph_id = subset_glyph.subset_glyph_index; } i = 0; @@ -2242,7 +2236,7 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface, "/CairoFont-%d-%d findfont\n" "[ %f %f %f %f 0 0 ] makefont\n" "setfont\n", - font_id, + subset_glyph.font_id, glyph_ids[i].subset_id, scaled_font->scale.xx, scaled_font->scale.yx, diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h index 23d7d4be51fb..cd1b15cd9faa 100644 --- a/gfx/cairo/cairo/src/cairo-quartz-private.h +++ b/gfx/cairo/cairo/src/cairo-quartz-private.h @@ -56,8 +56,11 @@ typedef struct cairo_quartz_surface { /* These are stored while drawing operations are in place, set up * by quartz_setup_source() and quartz_finish_source() */ - CGAffineTransform imageTransform; CGImageRef sourceImage; + cairo_surface_t *sourceImageSurface; + CGAffineTransform sourceImageTransform; + CGRect sourceImageRect; + CGShadingRef sourceShading; CGPatternRef sourcePattern; } cairo_quartz_surface_t; diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c index e390988d2110..dc831c179241 100644 --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c @@ -34,12 +34,12 @@ * Vladimir Vukicevic */ -#include - #include "cairoint.h" #include "cairo-quartz-private.h" +#include + #undef QUARTZ_DEBUG #ifdef QUARTZ_DEBUG @@ -101,6 +101,11 @@ static void quartz_image_to_png (CGImageRef, char *dest); * Cairo path -> Quartz path conversion helpers */ +typedef struct _quartz_stroke { + CGContextRef cgContext; + cairo_matrix_t *ctm_inverse; +} quartz_stroke_t; + /* cairo path -> mutable path */ static cairo_status_t _cairo_path_to_quartz_path_move_to (void *closure, cairo_point_t *point) @@ -140,8 +145,14 @@ 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)); + quartz_stroke_t *stroke = (quartz_stroke_t *)closure; + double x = _cairo_fixed_to_double (point->x); + double y = _cairo_fixed_to_double (point->y); + + if (stroke->ctm_inverse) + cairo_matrix_transform_point (stroke->ctm_inverse, &x, &y); + + CGContextMoveToPoint (stroke->cgContext, x, y); return CAIRO_STATUS_SUCCESS; } @@ -149,12 +160,17 @@ 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)); + quartz_stroke_t *stroke = (quartz_stroke_t *)closure; + double x = _cairo_fixed_to_double (point->x); + double y = _cairo_fixed_to_double (point->y); + + if (stroke->ctm_inverse) + cairo_matrix_transform_point (stroke->ctm_inverse, &x, &y); + + if (CGContextIsPathEmpty (stroke->cgContext)) + CGContextMoveToPoint (stroke->cgContext, x, y); else - CGContextAddLineToPoint ((CGContextRef) closure, - _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y)); + CGContextAddLineToPoint (stroke->cgContext, x, y); return CAIRO_STATUS_SUCCESS; } @@ -165,11 +181,22 @@ _cairo_path_to_quartz_context_curve_to (void *closure, cairo_point_t *p0, cairo_ // _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))); + quartz_stroke_t *stroke = (quartz_stroke_t *)closure; + double x0 = _cairo_fixed_to_double (p0->x); + double y0 = _cairo_fixed_to_double (p0->y); + double x1 = _cairo_fixed_to_double (p1->x); + double y1 = _cairo_fixed_to_double (p1->y); + double x2 = _cairo_fixed_to_double (p2->x); + double y2 = _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)); + if (stroke->ctm_inverse) { + cairo_matrix_transform_point (stroke->ctm_inverse, &x0, &y0); + cairo_matrix_transform_point (stroke->ctm_inverse, &x1, &y1); + cairo_matrix_transform_point (stroke->ctm_inverse, &x2, &y2); + } + + CGContextAddCurveToPoint (stroke->cgContext, + x0, y0, x1, y1, x2, y2); return CAIRO_STATUS_SUCCESS; } @@ -177,7 +204,8 @@ static cairo_status_t _cairo_path_to_quartz_context_close_path (void *closure) { //ND((stderr, "closepath\n")); - CGContextClosePath ((CGContextRef) closure); + quartz_stroke_t *stroke = (quartz_stroke_t *)closure; + CGContextClosePath (stroke->cgContext); return CAIRO_STATUS_SUCCESS; } @@ -286,8 +314,8 @@ _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->b = src->yx; + dst->c = src->xy; dst->d = src->yy; dst->tx = src->x0; dst->ty = src->y0; @@ -365,6 +393,13 @@ _cairo_quartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat) abspat->type != CAIRO_PATTERN_TYPE_RADIAL) return NULL; + /* bandaid for mozilla bug 379321, also visible in the + * linear-gradient-reflect test. + */ + if (abspat->extend == CAIRO_EXTEND_REFLECT || + abspat->extend == CAIRO_EXTEND_REPEAT) + 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; @@ -435,38 +470,30 @@ _cairo_quartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat) return NULL; } - -/* Generic cairo_pattern -> CGPattern function */ -static void -SurfacePatternDrawFunc (void *info, CGContextRef context) +/* generic cairo surface -> cairo_quartz_surface_t function */ +static cairo_quartz_surface_t * +_cairo_quartz_surface_to_quartz (cairo_surface_t *target, cairo_surface_t *pat_surf) { - 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, + /* 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 *ref_type = target; + if (ref_type == NULL) + ref_type = 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, + _cairo_surface_clone_similar (ref_type, pat_surf, rect.x, rect.y, rect.width, rect.height, &new_surf); - cairo_surface_destroy(dummy); + if (target == NULL) + cairo_surface_destroy(ref_type); quartz_surf = (cairo_quartz_surface_t *) new_surf; } else { @@ -476,15 +503,20 @@ SurfacePatternDrawFunc (void *info, CGContextRef context) 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); + return quartz_surf; +} + +/* 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 = _cairo_quartz_surface_to_quartz (NULL, pat_surf); + CGImageRef img = CGBitmapContextCreateImage (quartz_surf->cgContext); if (!img) { // ... give up. @@ -493,7 +525,12 @@ SurfacePatternDrawFunc (void *info, CGContextRef context) return; } - if (flip) { + /* 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? + */ + if (cairo_surface_get_type(pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) { CGContextTranslateCTM (context, 0, CGImageGetHeight(img)); CGContextScaleCTM (context, 1, -1); } @@ -504,6 +541,18 @@ SurfacePatternDrawFunc (void *info, CGContextRef context) imageBounds.origin.y = 0; CGContextDrawImage (context, imageBounds, img); + if (spat->base.extend == CAIRO_EXTEND_REFLECT) { + /* draw 3 more copies of the image, flipped. */ + CGContextTranslateCTM (context, 0, 2 * imageBounds.size.height); + CGContextScaleCTM (context, 1, -1); + CGContextDrawImage (context, imageBounds, img); + CGContextTranslateCTM (context, 2 * imageBounds.size.width, 0); + CGContextScaleCTM (context, -1, 1); + CGContextDrawImage (context, imageBounds, img); + CGContextTranslateCTM (context, 0, 2 * imageBounds.size.height); + CGContextScaleCTM (context, 1, -1); + CGContextDrawImage (context, imageBounds, img); + } CGImageRelease (img); @@ -515,7 +564,11 @@ static cairo_status_t _init_pattern_with_snapshot (cairo_pattern_t *pattern, const cairo_pattern_t *other) { - _cairo_pattern_init_copy (pattern, other); + cairo_status_t status; + + status = _cairo_pattern_init_copy (pattern, other); + if (status) + return status; if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *surface_pattern = @@ -563,8 +616,24 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t _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; + + // 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 (spat->base.extend == CAIRO_EXTEND_REFLECT) { + /* XXX broken; need to emulate by reflecting the image into 4 quadrants + * and then tiling that + */ + pbounds.size.width = 2 * extents.width; + pbounds.size.height = 2 * extents.height; + } else { + pbounds.size.width = extents.width; + pbounds.size.height = extents.height; + } + rw = pbounds.size.width; + rh = pbounds.size.height; m = spat->base.matrix; cairo_matrix_invert(&m); @@ -584,38 +653,6 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t 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 */ @@ -642,12 +679,13 @@ typedef enum { DO_SOLID, DO_SHADING, DO_PATTERN, + DO_IMAGE, DO_UNSUPPORTED } cairo_quartz_action_t; static cairo_quartz_action_t _cairo_quartz_setup_source (cairo_quartz_surface_t *surface, - cairo_pattern_t *source) + cairo_pattern_t *source) { assert (!(surface->sourceImage || surface->sourceShading || surface->sourcePattern)); @@ -676,6 +714,30 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface, surface->sourceShading = shading; return DO_SHADING; + } else if (source->type == CAIRO_PATTERN_TYPE_SURFACE && + source->extend == CAIRO_EXTEND_NONE) + { + cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) source; + cairo_surface_t *pat_surf = spat->surface; + cairo_quartz_surface_t *quartz_surf = _cairo_quartz_surface_to_quartz (surface, pat_surf); + CGImageRef img = CGBitmapContextCreateImage (quartz_surf->cgContext); + cairo_matrix_t m = spat->base.matrix; + cairo_rectangle_int16_t extents; + + if (!img) + return DO_UNSUPPORTED; + + surface->sourceImage = img; + + cairo_matrix_invert(&m); + _cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceImageTransform); + + _cairo_surface_get_extents (pat_surf, &extents); + surface->sourceImageRect = CGRectMake (0, 0, extents.width, extents.height); + + surface->sourceImageSurface = (cairo_surface_t *)quartz_surf; + + return DO_IMAGE; } else if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { CGPatternRef pattern = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source); if (!pattern) @@ -688,7 +750,8 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface, // pattern (which may be stack allocated) CGContextSaveGState(surface->cgContext); - CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL); + CGColorSpaceRef patternSpace; + patternSpace = CGColorSpaceCreatePattern(NULL); CGContextSetFillColorSpace (surface->cgContext, patternSpace); CGContextSetFillPattern (surface->cgContext, pattern, &patternAlpha); CGContextSetStrokeColorSpace (surface->cgContext, patternSpace); @@ -716,7 +779,11 @@ _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 + CGImageRelease(surface->sourceImage); + surface->sourceImage = NULL; + + cairo_surface_destroy(surface->sourceImageSurface); + surface->sourceImageSurface = NULL; } if (surface->sourceShading) { @@ -865,6 +932,15 @@ _cairo_quartz_surface_acquire_source_image (void *abstract_surface, return _cairo_quartz_get_image (surface, image_out, NULL); } +static void +_cairo_quartz_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_destroy ((cairo_surface_t *) image); +} + + static cairo_status_t _cairo_quartz_surface_acquire_dest_image (void *abstract_surface, cairo_rectangle_int16_t *interest_rect, @@ -1086,6 +1162,19 @@ _cairo_quartz_surface_paint (void *abstract_surface, surface->extents.height)); } else if (action == DO_SHADING) { CGContextDrawShading (surface->cgContext, surface->sourceShading); + } else if (action == DO_IMAGE) { + cairo_surface_pattern_t *surface_pattern = + (cairo_surface_pattern_t *) source; + cairo_surface_t *pat_surf = surface_pattern->surface; + CGContextSaveGState (surface->cgContext); + CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform); + if (cairo_surface_get_type(pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) { + CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage)); + CGContextScaleCTM (surface->cgContext, 1, -1); + } + + CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage); + CGContextRestoreGState (surface->cgContext); } else { rv = CAIRO_INT_STATUS_UNSUPPORTED; } @@ -1108,6 +1197,7 @@ _cairo_quartz_surface_fill (void *abstract_surface, cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; cairo_quartz_action_t action; + quartz_stroke_t stroke; ND((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type)); @@ -1126,7 +1216,10 @@ _cairo_quartz_surface_fill (void *abstract_surface, } CGContextBeginPath (surface->cgContext); - _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext); + + stroke.cgContext = surface->cgContext; + stroke.ctm_inverse = NULL; + _cairo_quartz_cairo_path_to_quartz_context (path, &stroke); if (action == DO_SOLID || action == DO_PATTERN) { if (fill_rule == CAIRO_FILL_RULE_WINDING) @@ -1143,6 +1236,21 @@ _cairo_quartz_surface_fill (void *abstract_surface, CGContextEOClip (surface->cgContext); CGContextDrawShading (surface->cgContext, surface->sourceShading); + } else if (action == DO_IMAGE) { + cairo_surface_pattern_t *surface_pattern = + (cairo_surface_pattern_t *) source; + cairo_surface_t *pat_surf = surface_pattern->surface; + if (fill_rule == CAIRO_FILL_RULE_WINDING) + CGContextClip (surface->cgContext); + else + CGContextEOClip (surface->cgContext); + CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform); + if (cairo_surface_get_type(pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) { + CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage)); + CGContextScaleCTM (surface->cgContext, 1, -1); + } + + CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage); } else { rv = CAIRO_INT_STATUS_UNSUPPORTED; } @@ -1169,6 +1277,8 @@ _cairo_quartz_surface_stroke (void *abstract_surface, cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; cairo_quartz_action_t action; + quartz_stroke_t stroke; + CGAffineTransform strokeTransform; ND((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n", surface, op, source->type)); @@ -1184,6 +1294,8 @@ _cairo_quartz_surface_stroke (void *abstract_surface, 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); + _cairo_quartz_cairo_matrix_to_quartz (ctm, &strokeTransform); + CGContextConcatCTM (surface->cgContext, strokeTransform); if (style->dash && style->num_dashes) { #define STATIC_DASH 32 @@ -1211,13 +1323,25 @@ _cairo_quartz_surface_stroke (void *abstract_surface, } CGContextBeginPath (surface->cgContext); - _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext); + + stroke.cgContext = surface->cgContext; + stroke.ctm_inverse = ctm_inverse; + _cairo_quartz_cairo_path_to_quartz_context (path, &stroke); if (action == DO_SOLID || action == DO_PATTERN) { CGContextStrokePath (surface->cgContext); + } else if (action == DO_IMAGE) { + CGContextReplacePathWithStrokedPath (surface->cgContext); + CGContextClip (surface->cgContext); + + CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform); + if (cairo_surface_get_type(((cairo_surface_pattern_t*)source)->surface) == CAIRO_SURFACE_TYPE_QUARTZ) { + CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage)); + CGContextScaleCTM (surface->cgContext, 1, -1); + } + + CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage); } 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); @@ -1262,7 +1386,7 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, action = _cairo_quartz_setup_source (surface, source); if (action == DO_SOLID || action == DO_PATTERN) { CGContextSetTextDrawingMode (surface->cgContext, kCGTextFill); - } else if (action == DO_SHADING) { + } else if (action == DO_IMAGE || action == DO_SHADING) { CGContextSetTextDrawingMode (surface->cgContext, kCGTextClip); } else { /* Unsupported */ @@ -1286,7 +1410,11 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, */ //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); + cairoTextTransform = CGAffineTransformMake (scaled_font->font_matrix.xx, + scaled_font->font_matrix.yx, + scaled_font->font_matrix.xy, + scaled_font->font_matrix.yy, + 0., 0.); textTransform = CGAffineTransformMakeTranslation (glyphs[0].x, glyphs[0].y); textTransform = CGAffineTransformScale (textTransform, 1.0, -1.0); @@ -1314,7 +1442,6 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, cg_advances = (CGSize*) malloc(sizeof(CGSize) * num_glyphs); } -#ifndef MOZILLA_CAIRO_NOT_DEFINED float xprev = glyphs[0].x; float yprev = glyphs[0].y; @@ -1324,29 +1451,13 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, for (i = 1; i < num_glyphs; i++) { cg_glyphs[i] = glyphs[i].index; - float xf = glyphs[i].x; - float yf = glyphs[i].y; + 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; } -#else - 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; - } -#endif /* MOZCAIRO */ #if 0 for (i = 0; i < num_glyphs; i++) { @@ -1364,8 +1475,17 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, free (cg_advances); } - if (action == DO_SHADING) + if (action == DO_IMAGE) { + CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform); + if (cairo_surface_get_type(((cairo_surface_pattern_t*)source)->surface) == CAIRO_SURFACE_TYPE_QUARTZ) { + CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage)); + CGContextScaleCTM (surface->cgContext, 1, -1); + } + + CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage); + } else if (action == DO_SHADING) { CGContextDrawShading (surface->cgContext, surface->sourceShading); + } _cairo_quartz_teardown_source (surface, source); @@ -1421,6 +1541,7 @@ _cairo_quartz_surface_intersect_clip_path (void *abstract_surface, cairo_antialias_t antialias) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + quartz_stroke_t stroke; ND((stderr, "%p _cairo_quartz_surface_intersect_clip_path path: %p\n", surface, path)); @@ -1436,7 +1557,9 @@ _cairo_quartz_surface_intersect_clip_path (void *abstract_surface, CGContextSaveGState (surface->cgContext); } else { CGContextBeginPath (surface->cgContext); - _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext); + stroke.cgContext = surface->cgContext; + stroke.ctm_inverse = NULL; + _cairo_quartz_cairo_path_to_quartz_context (path, &stroke); if (fill_rule == CAIRO_FILL_RULE_WINDING) CGContextClip (surface->cgContext); else @@ -1455,7 +1578,7 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = { _cairo_quartz_surface_create_similar, _cairo_quartz_surface_finish, _cairo_quartz_surface_acquire_source_image, - NULL, /* release_source_image */ + _cairo_quartz_surface_release_source_image, _cairo_quartz_surface_acquire_dest_image, _cairo_quartz_surface_release_dest_image, _cairo_quartz_surface_clone_similar, diff --git a/gfx/cairo/cairo/src/cairo-region.c b/gfx/cairo/cairo/src/cairo-region.c index 057f9fee84d0..c675a189501d 100644 --- a/gfx/cairo/cairo/src/cairo-region.c +++ b/gfx/cairo/cairo/src/cairo-region.c @@ -33,34 +33,7 @@ * Owen Taylor */ -#include - -/** - * _cairo_region_create_from_rectangle: - * @rect: a #cairo_rectangle_int16_t - * - * Creates a region with extents initialized from the given - * rectangle. - * - * Return value: a newly created #pixman_region16_t or %NULL if - * memory couldn't a allocated. - **/ -pixman_region16_t * -_cairo_region_create_from_rectangle (cairo_rectangle_int16_t *rect) -{ - /* We can't use pixman_region_create_simple(), because it doesn't - * have an error return - */ - pixman_region16_t *region = pixman_region_create (); - if (pixman_region_union_rect (region, region, - rect->x, rect->y, - rect->width, rect->height) != PIXMAN_REGION_STATUS_SUCCESS) { - pixman_region_destroy (region); - return NULL; - } - - return region; -} +#include "cairoint.h" /** * _cairo_region_extents_rectangle: diff --git a/gfx/cairo/cairo/src/cairo-rename.h b/gfx/cairo/cairo/src/cairo-rename.h index d62c11815339..0e9873fbc180 100644 --- a/gfx/cairo/cairo/src/cairo-rename.h +++ b/gfx/cairo/cairo/src/cairo-rename.h @@ -1,288 +1,287 @@ -#define _cairo_image_surface_nil_invalid_format __moz__cairo_image_surface_nil_invalid_format -#define _cairo_pdf_test_force_fallbacks _moz__cairo_pdf_test_force_fallbacks -#define _cairo_ps_test_force_fallbacks _moz__cairo_ps_test_force_fallbacks -#define _cairo_scaled_font_test_set_max_glyphs_cached_per_font _moz__cairo_scaled_font_test_set_max_glyphs_cached_per_font -#define _cairo_svg_test_force_fallbacks _moz__cairo_svg_test_force_fallbacks -#define _cairo_xlib_test_disable_render _moz__cairo_xlib_test_disable_render -#define cairo_append_path _moz_cairo_append_path -#define cairo_arc _moz_cairo_arc -#define cairo_arc_negative _moz_cairo_arc_negative -#define cairo_arc_to _moz_cairo_arc_to #define cairo_atsui_font_face_create_for_atsu_font_id _moz_cairo_atsui_font_face_create_for_atsu_font_id #define cairo_beos_surface_create _moz_cairo_beos_surface_create #define cairo_beos_surface_create_for_bitmap _moz_cairo_beos_surface_create_for_bitmap -#define cairo_clip _moz_cairo_clip -#define cairo_clip_extents _moz_cairo_clip_extents -#define cairo_clip_preserve _moz_cairo_clip_preserve -#define cairo_close_path _moz_cairo_close_path -#define cairo_copy_clip_rectangle_list _moz_cairo_copy_clip_rectangle_list -#define cairo_copy_page _moz_cairo_copy_page -#define cairo_copy_path _moz_cairo_copy_path -#define cairo_copy_path_flat _moz_cairo_copy_path_flat -#define cairo_create _moz_cairo_create -#define cairo_curve_to _moz_cairo_curve_to +#define cairo_debug_reset_static_data _moz_cairo_debug_reset_static_data #define cairo_debug_dump_clip _moz_cairo_debug_dump_clip #define cairo_debug_dump_path _moz_cairo_debug_dump_path -#define cairo_debug_dump_trapezoid_array _moz_cairo_debug_dump_trapezoid_array #define cairo_debug_dump_traps _moz_cairo_debug_dump_traps -#define cairo_debug_reset_static_data _moz_cairo_debug_reset_static_data -#define cairo_debug_reset_static_data _moz_cairo_debug_reset_static_data -#define cairo_destroy _moz_cairo_destroy -#define cairo_device_to_user _moz_cairo_device_to_user -#define cairo_device_to_user_distance _moz_cairo_device_to_user_distance +#define cairo_debug_dump_trapezoid_array _moz_cairo_debug_dump_trapezoid_array #define cairo_directfb_surface_create _moz_cairo_directfb_surface_create -#define cairo_fill _moz_cairo_fill -#define cairo_fill_extents _moz_cairo_fill_extents -#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 -#define cairo_font_face_set_user_data _moz_cairo_font_face_set_user_data -#define cairo_font_face_status _moz_cairo_font_face_status -#define cairo_font_options_copy _moz_cairo_font_options_copy -#define cairo_font_options_create _moz_cairo_font_options_create -#define cairo_font_options_destroy _moz_cairo_font_options_destroy -#define cairo_font_options_equal _moz_cairo_font_options_equal -#define cairo_font_options_get_antialias _moz_cairo_font_options_get_antialias -#define cairo_font_options_get_hint_metrics _moz_cairo_font_options_get_hint_metrics -#define cairo_font_options_get_hint_style _moz_cairo_font_options_get_hint_style -#define cairo_font_options_get_subpixel_order _moz_cairo_font_options_get_subpixel_order -#define cairo_font_options_hash _moz_cairo_font_options_hash -#define cairo_font_options_merge _moz_cairo_font_options_merge -#define cairo_font_options_set_antialias _moz_cairo_font_options_set_antialias -#define cairo_font_options_set_hint_metrics _moz_cairo_font_options_set_hint_metrics -#define cairo_font_options_set_hint_style _moz_cairo_font_options_set_hint_style -#define cairo_font_options_set_subpixel_order _moz_cairo_font_options_set_subpixel_order -#define cairo_font_options_status _moz_cairo_font_options_status -#define cairo_ft_font_face_create_for_ft_face _moz_cairo_ft_font_face_create_for_ft_face #define cairo_ft_font_face_create_for_pattern _moz_cairo_ft_font_face_create_for_pattern #define cairo_ft_font_options_substitute _moz_cairo_ft_font_options_substitute +#define cairo_ft_font_face_create_for_ft_face _moz_cairo_ft_font_face_create_for_ft_face #define cairo_ft_scaled_font_lock_face _moz_cairo_ft_scaled_font_lock_face #define cairo_ft_scaled_font_unlock_face _moz_cairo_ft_scaled_font_unlock_face -#define cairo_get_antialias _moz_cairo_get_antialias -#define cairo_get_current_point _moz_cairo_get_current_point -#define cairo_get_dash _moz_cairo_get_dash -#define cairo_get_dash_count _moz_cairo_get_dash_count -#define cairo_get_fill_rule _moz_cairo_get_fill_rule -#define cairo_get_font_face _moz_cairo_get_font_face -#define cairo_get_font_matrix _moz_cairo_get_font_matrix -#define cairo_get_font_options _moz_cairo_get_font_options -#define cairo_get_group_target _moz_cairo_get_group_target -#define cairo_get_line_cap _moz_cairo_get_line_cap -#define cairo_get_line_join _moz_cairo_get_line_join -#define cairo_get_line_width _moz_cairo_get_line_width -#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 -#define cairo_identity_matrix _moz_cairo_identity_matrix -#define cairo_image_surface_create _moz_cairo_image_surface_create -#define cairo_image_surface_create_for_data _moz_cairo_image_surface_create_for_data -#define cairo_image_surface_create_from_png _moz_cairo_image_surface_create_from_png -#define cairo_image_surface_create_from_png_stream _moz_cairo_image_surface_create_from_png_stream -#define cairo_image_surface_get_data _moz_cairo_image_surface_get_data -#define cairo_image_surface_get_format _moz_cairo_image_surface_get_format -#define cairo_image_surface_get_height _moz_cairo_image_surface_get_height -#define cairo_image_surface_get_stride _moz_cairo_image_surface_get_stride -#define cairo_image_surface_get_width _moz_cairo_image_surface_get_width -#define cairo_in_fill _moz_cairo_in_fill -#define cairo_in_stroke _moz_cairo_in_stroke -#define cairo_line_to _moz_cairo_line_to -#define cairo_mask _moz_cairo_mask -#define cairo_mask_surface _moz_cairo_mask_surface -#define cairo_matrix_init _moz_cairo_matrix_init -#define cairo_matrix_init_identity _moz_cairo_matrix_init_identity -#define cairo_matrix_init_rotate _moz_cairo_matrix_init_rotate -#define cairo_matrix_init_scale _moz_cairo_matrix_init_scale -#define cairo_matrix_init_translate _moz_cairo_matrix_init_translate -#define cairo_matrix_invert _moz_cairo_matrix_invert -#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_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_os2_fini _moz_cairo_os2_fini #define cairo_os2_init _moz_cairo_os2_init +#define cairo_os2_fini _moz_cairo_os2_fini #define cairo_os2_surface_create _moz_cairo_os2_surface_create -#define cairo_os2_surface_get_manual_window_refresh _moz_cairo_os2_surface_get_manual_window_refresh -#define cairo_os2_surface_refresh_window _moz_cairo_os2_surface_refresh_window #define cairo_os2_surface_set_hwnd _moz_cairo_os2_surface_set_hwnd -#define cairo_os2_surface_set_manual_window_refresh _moz_cairo_os2_surface_set_manual_window_refresh #define cairo_os2_surface_set_size _moz_cairo_os2_surface_set_size -#define cairo_paint _moz_cairo_paint -#define cairo_paint_with_alpha _moz_cairo_paint_with_alpha -#define cairo_path_destroy _moz_cairo_path_destroy -#define cairo_pattern_add_color_stop_rgb _moz_cairo_pattern_add_color_stop_rgb -#define cairo_pattern_add_color_stop_rgba _moz_cairo_pattern_add_color_stop_rgba -#define cairo_pattern_create_for_surface _moz_cairo_pattern_create_for_surface -#define cairo_pattern_create_linear _moz_cairo_pattern_create_linear -#define cairo_pattern_create_radial _moz_cairo_pattern_create_radial -#define cairo_pattern_create_rgb _moz_cairo_pattern_create_rgb -#define cairo_pattern_create_rgba _moz_cairo_pattern_create_rgba -#define cairo_pattern_destroy _moz_cairo_pattern_destroy -#define cairo_pattern_get_color_stop_count _moz_cairo_pattern_get_color_stop_count -#define cairo_pattern_get_color_stop_rgba _moz_cairo_pattern_get_color_stop_rgba -#define cairo_pattern_get_extend _moz_cairo_pattern_get_extend -#define cairo_pattern_get_filter _moz_cairo_pattern_get_filter -#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_os2_surface_refresh_window _moz_cairo_os2_surface_refresh_window +#define cairo_os2_surface_set_manual_window_refresh _moz_cairo_os2_surface_set_manual_window_refresh +#define cairo_os2_surface_get_manual_window_refresh _moz_cairo_os2_surface_get_manual_window_refresh +#define _cairo_pdf_test_force_fallbacks _moz__cairo_pdf_test_force_fallbacks #define cairo_pdf_surface_create _moz_cairo_pdf_surface_create #define cairo_pdf_surface_create_for_stream _moz_cairo_pdf_surface_create_for_stream #define cairo_pdf_surface_set_size _moz_cairo_pdf_surface_set_size -#define cairo_pop_group _moz_cairo_pop_group -#define cairo_pop_group_to_source _moz_cairo_pop_group_to_source +#define _cairo_ps_test_force_fallbacks _moz__cairo_ps_test_force_fallbacks #define cairo_ps_surface_create _moz_cairo_ps_surface_create #define cairo_ps_surface_create_for_stream _moz_cairo_ps_surface_create_for_stream -#define cairo_ps_surface_dsc_begin_page_setup _moz_cairo_ps_surface_dsc_begin_page_setup -#define cairo_ps_surface_dsc_begin_setup _moz_cairo_ps_surface_dsc_begin_setup -#define cairo_ps_surface_dsc_comment _moz_cairo_ps_surface_dsc_comment #define cairo_ps_surface_set_size _moz_cairo_ps_surface_set_size -#define cairo_push_group _moz_cairo_push_group -#define cairo_push_group_with_content _moz_cairo_push_group_with_content +#define cairo_ps_surface_dsc_comment _moz_cairo_ps_surface_dsc_comment +#define cairo_ps_surface_dsc_begin_setup _moz_cairo_ps_surface_dsc_begin_setup +#define cairo_ps_surface_dsc_begin_page_setup _moz_cairo_ps_surface_dsc_begin_page_setup #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 -#define cairo_rel_curve_to _moz_cairo_rel_curve_to -#define cairo_rel_line_to _moz_cairo_rel_line_to -#define cairo_rel_move_to _moz_cairo_rel_move_to -#define cairo_reset_clip _moz_cairo_reset_clip -#define cairo_restore _moz_cairo_restore -#define cairo_rotate _moz_cairo_rotate -#define cairo_save _moz_cairo_save -#define cairo_scale _moz_cairo_scale -#define cairo_scaled_font_create _moz_cairo_scaled_font_create -#define cairo_scaled_font_destroy _moz_cairo_scaled_font_destroy -#define cairo_scaled_font_extents _moz_cairo_scaled_font_extents -#define cairo_scaled_font_get_ctm _moz_cairo_scaled_font_get_ctm -#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 -#define cairo_set_antialias _moz_cairo_set_antialias -#define cairo_set_dash _moz_cairo_set_dash -#define cairo_set_fill_rule _moz_cairo_set_fill_rule -#define cairo_set_font_face _moz_cairo_set_font_face -#define cairo_set_font_matrix _moz_cairo_set_font_matrix -#define cairo_set_font_options _moz_cairo_set_font_options -#define cairo_set_font_size _moz_cairo_set_font_size -#define cairo_set_line_cap _moz_cairo_set_line_cap -#define cairo_set_line_join _moz_cairo_set_line_join -#define cairo_set_line_width _moz_cairo_set_line_width -#define cairo_set_matrix _moz_cairo_set_matrix -#define cairo_set_miter_limit _moz_cairo_set_miter_limit -#define cairo_set_operator _moz_cairo_set_operator -#define cairo_set_scaled_font _moz_cairo_set_scaled_font -#define cairo_set_source _moz_cairo_set_source -#define cairo_set_source_rgb _moz_cairo_set_source_rgb -#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 -#define cairo_status _moz_cairo_status -#define cairo_status_to_string _moz_cairo_status_to_string -#define cairo_stroke _moz_cairo_stroke -#define cairo_stroke_extents _moz_cairo_stroke_extents -#define cairo_stroke_preserve _moz_cairo_stroke_preserve -#define cairo_stroke_to_path _moz_cairo_stroke_to_path -#define cairo_surface_create_similar _moz_cairo_surface_create_similar -#define cairo_surface_destroy _moz_cairo_surface_destroy -#define cairo_surface_finish _moz_cairo_surface_finish -#define cairo_surface_flush _moz_cairo_surface_flush -#define cairo_surface_get_content _moz_cairo_surface_get_content -#define cairo_surface_get_device_offset _moz_cairo_surface_get_device_offset -#define cairo_surface_get_font_options _moz_cairo_surface_get_font_options -#define cairo_surface_get_reference_count _moz_cairo_surface_get_reference_count -#define cairo_surface_get_type _moz_cairo_surface_get_type -#define cairo_surface_get_user_data _moz_cairo_surface_get_user_data -#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 -#define cairo_surface_set_device_offset _moz_cairo_surface_set_device_offset -#define cairo_surface_set_fallback_resolution _moz_cairo_surface_set_fallback_resolution -#define cairo_surface_set_user_data _moz_cairo_surface_set_user_data -#define cairo_surface_status _moz_cairo_surface_status -#define cairo_surface_write_to_png _moz_cairo_surface_write_to_png -#define cairo_surface_write_to_png_stream _moz_cairo_surface_write_to_png_stream -#define cairo_svg_get_versions _moz_cairo_svg_get_versions +#define _cairo_scaled_font_test_set_max_glyphs_cached_per_font _moz__cairo_scaled_font_test_set_max_glyphs_cached_per_font +#define _cairo_svg_test_force_fallbacks _moz__cairo_svg_test_force_fallbacks #define cairo_svg_surface_create _moz_cairo_svg_surface_create #define cairo_svg_surface_create_for_stream _moz_cairo_svg_surface_create_for_stream #define cairo_svg_surface_restrict_to_version _moz_cairo_svg_surface_restrict_to_version +#define cairo_svg_get_versions _moz_cairo_svg_get_versions #define cairo_svg_version_to_string _moz_cairo_svg_version_to_string -#define cairo_text_extents _moz_cairo_text_extents -#define cairo_text_path _moz_cairo_text_path -#define cairo_transform _moz_cairo_transform -#define cairo_translate _moz_cairo_translate -#define cairo_user_to_device _moz_cairo_user_to_device -#define cairo_user_to_device_distance _moz_cairo_user_to_device_distance -#define cairo_version _moz_cairo_version -#define cairo_version_string _moz_cairo_version_string -#define cairo_win32_font_face_create_for_hfont _moz_cairo_win32_font_face_create_for_hfont -#define cairo_win32_font_face_create_for_logfontw _moz_cairo_win32_font_face_create_for_logfontw -#define cairo_win32_font_face_create_for_logfontw_hfont _moz_cairo_win32_font_face_create_for_logfontw_hfont -#define cairo_win32_scaled_font_done_font _moz_cairo_win32_scaled_font_done_font -#define cairo_win32_scaled_font_get_device_to_logical _moz_cairo_win32_scaled_font_get_device_to_logical -#define cairo_win32_scaled_font_get_logical_to_device _moz_cairo_win32_scaled_font_get_logical_to_device -#define cairo_win32_scaled_font_get_metrics_factor _moz_cairo_win32_scaled_font_get_metrics_factor -#define cairo_win32_scaled_font_select_font _moz_cairo_win32_scaled_font_select_font #define cairo_win32_surface_create _moz_cairo_win32_surface_create #define cairo_win32_surface_create_with_ddb _moz_cairo_win32_surface_create_with_ddb #define cairo_win32_surface_create_with_dib _moz_cairo_win32_surface_create_with_dib #define cairo_win32_surface_get_dc _moz_cairo_win32_surface_get_dc #define cairo_win32_surface_get_image _moz_cairo_win32_surface_get_image +#define cairo_win32_font_face_create_for_logfontw _moz_cairo_win32_font_face_create_for_logfontw +#define cairo_win32_font_face_create_for_hfont _moz_cairo_win32_font_face_create_for_hfont +#define cairo_win32_scaled_font_select_font _moz_cairo_win32_scaled_font_select_font +#define cairo_win32_scaled_font_done_font _moz_cairo_win32_scaled_font_done_font +#define cairo_win32_scaled_font_get_metrics_factor _moz_cairo_win32_scaled_font_get_metrics_factor +#define cairo_win32_scaled_font_get_logical_to_device _moz_cairo_win32_scaled_font_get_logical_to_device +#define cairo_win32_scaled_font_get_device_to_logical _moz_cairo_win32_scaled_font_get_device_to_logical +#define cairo_xcb_surface_create_with_xrender_format _moz_cairo_xcb_surface_create_with_xrender_format #define cairo_xcb_surface_create _moz_cairo_xcb_surface_create #define cairo_xcb_surface_create_for_bitmap _moz_cairo_xcb_surface_create_for_bitmap -#define cairo_xcb_surface_create_with_xrender_format _moz_cairo_xcb_surface_create_with_xrender_format #define cairo_xcb_surface_set_size _moz_cairo_xcb_surface_set_size +#define _cairo_xlib_test_disable_render _moz__cairo_xlib_test_disable_render +#define cairo_xlib_surface_create_with_xrender_format _moz_cairo_xlib_surface_create_with_xrender_format #define cairo_xlib_surface_create _moz_cairo_xlib_surface_create #define cairo_xlib_surface_create_for_bitmap _moz_cairo_xlib_surface_create_for_bitmap -#define cairo_xlib_surface_create_with_xrender_format _moz_cairo_xlib_surface_create_with_xrender_format -#define cairo_xlib_surface_get_depth _moz_cairo_xlib_surface_get_depth +#define cairo_xlib_surface_set_size _moz_cairo_xlib_surface_set_size +#define cairo_xlib_surface_set_drawable _moz_cairo_xlib_surface_set_drawable #define cairo_xlib_surface_get_display _moz_cairo_xlib_surface_get_display #define cairo_xlib_surface_get_drawable _moz_cairo_xlib_surface_get_drawable -#define cairo_xlib_surface_get_height _moz_cairo_xlib_surface_get_height #define cairo_xlib_surface_get_screen _moz_cairo_xlib_surface_get_screen #define cairo_xlib_surface_get_visual _moz_cairo_xlib_surface_get_visual +#define cairo_xlib_surface_get_depth _moz_cairo_xlib_surface_get_depth #define cairo_xlib_surface_get_width _moz_cairo_xlib_surface_get_width -#define cairo_xlib_surface_set_drawable _moz_cairo_xlib_surface_set_drawable -#define cairo_xlib_surface_set_size _moz_cairo_xlib_surface_set_size +#define cairo_xlib_surface_get_height _moz_cairo_xlib_surface_get_height +#define cairo_version _moz_cairo_version +#define cairo_version_string _moz_cairo_version_string +#define cairo_create _moz_cairo_create +#define cairo_reference _moz_cairo_reference +#define cairo_destroy _moz_cairo_destroy +#define cairo_get_reference_count _moz_cairo_get_reference_count +#define cairo_get_user_data _moz_cairo_get_user_data +#define cairo_set_user_data _moz_cairo_set_user_data +#define cairo_save _moz_cairo_save +#define cairo_restore _moz_cairo_restore +#define cairo_push_group _moz_cairo_push_group +#define cairo_push_group_with_content _moz_cairo_push_group_with_content +#define cairo_pop_group _moz_cairo_pop_group +#define cairo_pop_group_to_source _moz_cairo_pop_group_to_source +#define cairo_set_operator _moz_cairo_set_operator +#define cairo_set_source _moz_cairo_set_source +#define cairo_set_source_rgb _moz_cairo_set_source_rgb +#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_antialias _moz_cairo_set_antialias +#define cairo_set_fill_rule _moz_cairo_set_fill_rule +#define cairo_set_line_width _moz_cairo_set_line_width +#define cairo_set_line_cap _moz_cairo_set_line_cap +#define cairo_set_line_join _moz_cairo_set_line_join +#define cairo_set_dash _moz_cairo_set_dash +#define cairo_set_miter_limit _moz_cairo_set_miter_limit +#define cairo_translate _moz_cairo_translate +#define cairo_scale _moz_cairo_scale +#define cairo_rotate _moz_cairo_rotate +#define cairo_transform _moz_cairo_transform +#define cairo_set_matrix _moz_cairo_set_matrix +#define cairo_identity_matrix _moz_cairo_identity_matrix +#define cairo_user_to_device _moz_cairo_user_to_device +#define cairo_user_to_device_distance _moz_cairo_user_to_device_distance +#define cairo_device_to_user _moz_cairo_device_to_user +#define cairo_device_to_user_distance _moz_cairo_device_to_user_distance +#define cairo_new_path _moz_cairo_new_path +#define cairo_move_to _moz_cairo_move_to +#define cairo_new_sub_path _moz_cairo_new_sub_path +#define cairo_line_to _moz_cairo_line_to +#define cairo_curve_to _moz_cairo_curve_to +#define cairo_arc _moz_cairo_arc +#define cairo_arc_negative _moz_cairo_arc_negative +#define cairo_arc_to _moz_cairo_arc_to +#define cairo_rel_move_to _moz_cairo_rel_move_to +#define cairo_rel_line_to _moz_cairo_rel_line_to +#define cairo_rel_curve_to _moz_cairo_rel_curve_to +#define cairo_rectangle _moz_cairo_rectangle +#define cairo_stroke_to_path _moz_cairo_stroke_to_path +#define cairo_close_path _moz_cairo_close_path +#define cairo_paint _moz_cairo_paint +#define cairo_paint_with_alpha _moz_cairo_paint_with_alpha +#define cairo_mask _moz_cairo_mask +#define cairo_mask_surface _moz_cairo_mask_surface +#define cairo_stroke _moz_cairo_stroke +#define cairo_stroke_preserve _moz_cairo_stroke_preserve +#define cairo_fill _moz_cairo_fill +#define cairo_fill_preserve _moz_cairo_fill_preserve +#define cairo_copy_page _moz_cairo_copy_page +#define cairo_show_page _moz_cairo_show_page +#define cairo_in_stroke _moz_cairo_in_stroke +#define cairo_in_fill _moz_cairo_in_fill +#define cairo_stroke_extents _moz_cairo_stroke_extents +#define cairo_fill_extents _moz_cairo_fill_extents +#define cairo_reset_clip _moz_cairo_reset_clip +#define cairo_clip _moz_cairo_clip +#define cairo_clip_preserve _moz_cairo_clip_preserve +#define cairo_clip_extents _moz_cairo_clip_extents +#define cairo_copy_clip_rectangle_list _moz_cairo_copy_clip_rectangle_list +#define cairo_rectangle_list_destroy _moz_cairo_rectangle_list_destroy +#define cairo_font_options_create _moz_cairo_font_options_create +#define cairo_font_options_copy _moz_cairo_font_options_copy +#define cairo_font_options_destroy _moz_cairo_font_options_destroy +#define cairo_font_options_status _moz_cairo_font_options_status +#define cairo_font_options_merge _moz_cairo_font_options_merge +#define cairo_font_options_equal _moz_cairo_font_options_equal +#define cairo_font_options_hash _moz_cairo_font_options_hash +#define cairo_font_options_set_antialias _moz_cairo_font_options_set_antialias +#define cairo_font_options_get_antialias _moz_cairo_font_options_get_antialias +#define cairo_font_options_set_subpixel_order _moz_cairo_font_options_set_subpixel_order +#define cairo_font_options_get_subpixel_order _moz_cairo_font_options_get_subpixel_order +#define cairo_font_options_set_hint_style _moz_cairo_font_options_set_hint_style +#define cairo_font_options_get_hint_style _moz_cairo_font_options_get_hint_style +#define cairo_font_options_set_hint_metrics _moz_cairo_font_options_set_hint_metrics +#define cairo_font_options_get_hint_metrics _moz_cairo_font_options_get_hint_metrics +#define cairo_select_font_face _moz_cairo_select_font_face +#define cairo_set_font_size _moz_cairo_set_font_size +#define cairo_set_font_matrix _moz_cairo_set_font_matrix +#define cairo_get_font_matrix _moz_cairo_get_font_matrix +#define cairo_set_font_options _moz_cairo_set_font_options +#define cairo_get_font_options _moz_cairo_get_font_options +#define cairo_set_font_face _moz_cairo_set_font_face +#define cairo_get_font_face _moz_cairo_get_font_face +#define cairo_set_scaled_font _moz_cairo_set_scaled_font +#define cairo_get_scaled_font _moz_cairo_get_scaled_font +#define cairo_show_text _moz_cairo_show_text +#define cairo_show_glyphs _moz_cairo_show_glyphs +#define cairo_text_path _moz_cairo_text_path +#define cairo_glyph_path _moz_cairo_glyph_path +#define cairo_text_extents _moz_cairo_text_extents +#define cairo_glyph_extents _moz_cairo_glyph_extents +#define cairo_font_extents _moz_cairo_font_extents +#define cairo_font_face_reference _moz_cairo_font_face_reference +#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_status _moz_cairo_font_face_status +#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_set_user_data _moz_cairo_font_face_set_user_data +#define cairo_scaled_font_create _moz_cairo_scaled_font_create +#define cairo_scaled_font_reference _moz_cairo_scaled_font_reference +#define cairo_scaled_font_destroy _moz_cairo_scaled_font_destroy +#define cairo_scaled_font_get_reference_count _moz_cairo_scaled_font_get_reference_count +#define cairo_scaled_font_status _moz_cairo_scaled_font_status +#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_set_user_data _moz_cairo_scaled_font_set_user_data +#define cairo_scaled_font_extents _moz_cairo_scaled_font_extents +#define cairo_scaled_font_text_extents _moz_cairo_scaled_font_text_extents +#define cairo_scaled_font_glyph_extents _moz_cairo_scaled_font_glyph_extents +#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_ctm _moz_cairo_scaled_font_get_ctm +#define cairo_scaled_font_get_font_options _moz_cairo_scaled_font_get_font_options +#define cairo_get_operator _moz_cairo_get_operator +#define cairo_get_source _moz_cairo_get_source +#define cairo_get_tolerance _moz_cairo_get_tolerance +#define cairo_get_antialias _moz_cairo_get_antialias +#define cairo_get_current_point _moz_cairo_get_current_point +#define cairo_get_fill_rule _moz_cairo_get_fill_rule +#define cairo_get_line_width _moz_cairo_get_line_width +#define cairo_get_line_cap _moz_cairo_get_line_cap +#define cairo_get_line_join _moz_cairo_get_line_join +#define cairo_get_miter_limit _moz_cairo_get_miter_limit +#define cairo_get_dash_count _moz_cairo_get_dash_count +#define cairo_get_dash _moz_cairo_get_dash +#define cairo_get_matrix _moz_cairo_get_matrix +#define cairo_get_target _moz_cairo_get_target +#define cairo_get_group_target _moz_cairo_get_group_target +#define cairo_copy_path _moz_cairo_copy_path +#define cairo_copy_path_flat _moz_cairo_copy_path_flat +#define cairo_append_path _moz_cairo_append_path +#define cairo_path_destroy _moz_cairo_path_destroy +#define cairo_status _moz_cairo_status +#define cairo_status_to_string _moz_cairo_status_to_string +#define cairo_surface_create_similar _moz_cairo_surface_create_similar +#define cairo_surface_reference _moz_cairo_surface_reference +#define cairo_surface_finish _moz_cairo_surface_finish +#define cairo_surface_destroy _moz_cairo_surface_destroy +#define cairo_surface_get_reference_count _moz_cairo_surface_get_reference_count +#define cairo_surface_status _moz_cairo_surface_status +#define cairo_surface_get_type _moz_cairo_surface_get_type +#define cairo_surface_get_content _moz_cairo_surface_get_content +#define cairo_surface_write_to_png _moz_cairo_surface_write_to_png +#define cairo_surface_write_to_png_stream _moz_cairo_surface_write_to_png_stream +#define cairo_surface_get_user_data _moz_cairo_surface_get_user_data +#define cairo_surface_set_user_data _moz_cairo_surface_set_user_data +#define cairo_surface_get_font_options _moz_cairo_surface_get_font_options +#define cairo_surface_flush _moz_cairo_surface_flush +#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_set_device_offset _moz_cairo_surface_set_device_offset +#define cairo_surface_get_device_offset _moz_cairo_surface_get_device_offset +#define cairo_surface_set_fallback_resolution _moz_cairo_surface_set_fallback_resolution +#define cairo_image_surface_create _moz_cairo_image_surface_create +#define cairo_image_surface_create_for_data _moz_cairo_image_surface_create_for_data +#define cairo_image_surface_get_data _moz_cairo_image_surface_get_data +#define cairo_image_surface_get_format _moz_cairo_image_surface_get_format +#define cairo_image_surface_get_width _moz_cairo_image_surface_get_width +#define cairo_image_surface_get_height _moz_cairo_image_surface_get_height +#define cairo_image_surface_get_stride _moz_cairo_image_surface_get_stride +#define cairo_image_surface_create_from_png _moz_cairo_image_surface_create_from_png +#define cairo_image_surface_create_from_png_stream _moz_cairo_image_surface_create_from_png_stream +#define cairo_pattern_create_rgb _moz_cairo_pattern_create_rgb +#define cairo_pattern_create_rgba _moz_cairo_pattern_create_rgba +#define cairo_pattern_create_for_surface _moz_cairo_pattern_create_for_surface +#define cairo_pattern_create_linear _moz_cairo_pattern_create_linear +#define cairo_pattern_create_radial _moz_cairo_pattern_create_radial +#define cairo_pattern_reference _moz_cairo_pattern_reference +#define cairo_pattern_destroy _moz_cairo_pattern_destroy +#define cairo_pattern_get_reference_count _moz_cairo_pattern_get_reference_count +#define cairo_pattern_status _moz_cairo_pattern_status +#define cairo_pattern_get_user_data _moz_cairo_pattern_get_user_data +#define cairo_pattern_set_user_data _moz_cairo_pattern_set_user_data +#define cairo_pattern_get_type _moz_cairo_pattern_get_type +#define cairo_pattern_add_color_stop_rgb _moz_cairo_pattern_add_color_stop_rgb +#define cairo_pattern_add_color_stop_rgba _moz_cairo_pattern_add_color_stop_rgba +#define cairo_pattern_set_matrix _moz_cairo_pattern_set_matrix +#define cairo_pattern_get_matrix _moz_cairo_pattern_get_matrix +#define cairo_pattern_set_extend _moz_cairo_pattern_set_extend +#define cairo_pattern_get_extend _moz_cairo_pattern_get_extend +#define cairo_pattern_set_filter _moz_cairo_pattern_set_filter +#define cairo_pattern_get_filter _moz_cairo_pattern_get_filter +#define cairo_pattern_get_rgba _moz_cairo_pattern_get_rgba +#define cairo_pattern_get_surface _moz_cairo_pattern_get_surface +#define cairo_pattern_get_color_stop_rgba _moz_cairo_pattern_get_color_stop_rgba +#define cairo_pattern_get_color_stop_count _moz_cairo_pattern_get_color_stop_count +#define cairo_pattern_get_linear_points _moz_cairo_pattern_get_linear_points +#define cairo_pattern_get_radial_circles _moz_cairo_pattern_get_radial_circles +#define cairo_matrix_init _moz_cairo_matrix_init +#define cairo_matrix_init_identity _moz_cairo_matrix_init_identity +#define cairo_matrix_init_translate _moz_cairo_matrix_init_translate +#define cairo_matrix_init_scale _moz_cairo_matrix_init_scale +#define cairo_matrix_init_rotate _moz_cairo_matrix_init_rotate +#define cairo_matrix_translate _moz_cairo_matrix_translate +#define cairo_matrix_scale _moz_cairo_matrix_scale +#define cairo_matrix_rotate _moz_cairo_matrix_rotate +#define cairo_matrix_invert _moz_cairo_matrix_invert +#define cairo_matrix_multiply _moz_cairo_matrix_multiply +#define cairo_matrix_transform_distance _moz_cairo_matrix_transform_distance +#define cairo_matrix_transform_point _moz_cairo_matrix_transform_point +#define cairo_debug_reset_static_data _moz_cairo_debug_reset_static_data +#define _cairo_image_surface_nil_invalid_format __moz__cairo_image_surface_nil_invalid_format diff --git a/gfx/cairo/cairo/src/cairo-scaled-font-private.h b/gfx/cairo/cairo/src/cairo-scaled-font-private.h new file mode 100644 index 000000000000..fa71644ae389 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-scaled-font-private.h @@ -0,0 +1,112 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_SCALED_FONT_PRIVATE_H +#define CAIRO_SCALED_FONT_PRIVATE_H + +#include "cairo.h" + +#include "cairo-types-private.h" +#include "cairo-mutex-type-private.h" + +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 */ + cairo_matrix_t font_matrix; /* font space => user space */ + cairo_matrix_t ctm; /* user space => device space */ + cairo_font_options_t options; + + /* "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 */ + + /* + * One surface backend may store data in each glyph. + * Whichever surface manages to store its pointer here + * first gets to store data in each glyph + */ + const cairo_surface_backend_t *surface_backend; + void *surface_private; + + /* font backend managing this scaled font */ + const cairo_scaled_font_backend_t *backend; +}; + +#endif /* CAIRO_SCALED_FONT_PRIVATE_H */ 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 510434049ba4..5b9467a9f95e 100644 --- a/gfx/cairo/cairo/src/cairo-scaled-font-subsets-private.h +++ b/gfx/cairo/cairo/src/cairo-scaled-font-subsets-private.h @@ -39,19 +39,17 @@ #include "cairoint.h" -typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t; +typedef struct _cairo_scaled_font_subsets_glyph { + unsigned int font_id; + unsigned int subset_id; + unsigned int subset_glyph_index; + cairo_bool_t is_scaled; + cairo_bool_t is_composite; + double x_advance; +} cairo_scaled_font_subsets_glyph_t; /** - * _cairo_scaled_font_subsets_create: - * - * @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. + * _cairo_scaled_font_subsets_create_scaled: * * Create a new #cairo_scaled_font_subsets_t object which can be used * to create subsets of any number of cairo_scaled_font_t @@ -60,16 +58,57 @@ typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t; * 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_scaled (void); + +/** + * _cairo_scaled_font_subsets_create_simple: + * + * Create a new #cairo_scaled_font_subsets_t object which can be used + * to create font subsets suitable for embedding as Postscript or PDF + * simple fonts. + * + * Glyphs with an outline path available will be mapped to one font + * subset for each font face. Glyphs from bitmap fonts will mapped to + * separate font subsets for each cairo_scaled_font_t object. + * + * The maximum number of glyphs per subset is 256. Each subset + * reserves the first glyph for the .notdef glyph. * * 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_unscaled_per_subset, - int max_glyphs_scaled_per_subset); +_cairo_scaled_font_subsets_create_simple (void); + +/** + * _cairo_scaled_font_subsets_create_composite: + * + * Create a new #cairo_scaled_font_subsets_t object which can be used + * to create font subsets suitable for embedding as Postscript or PDF + * composite fonts. + * + * Glyphs with an outline path available will be mapped to one font + * subset for each font face. Each unscaled subset has a maximum of + * 65536 glyphs except for Type1 fonts which have a maximum of 256 glyphs. + * + * Glyphs from bitmap fonts will mapped to separate font subsets for + * each cairo_scaled_font_t object. Each unscaled subset has a maximum + * of 256 glyphs. + * + * Each subset reserves the first glyph for the .notdef glyph. + * + * 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_composite (void); /** * _cairo_scaled_font_subsets_destroy: @@ -85,6 +124,8 @@ _cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *font_subsets); * @font_subsets: a #cairo_scaled_font_subsets_t * @scaled_font: the font of the glyph to be mapped * @scaled_font_glyph_index: the index of the glyph to be mapped + * @subset_glyph_ret: return structure containing subset font and glyph id + * * @font_id_ret: return value giving the font ID of the mapped glyph * @subset_id_ret: return value giving the subset ID of the mapped glyph within the @font_id_ret * @subset_glyph_index_ret: return value giving the index of the mapped glyph within the @subset_id_ret subset @@ -126,6 +167,17 @@ _cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *font_subsets); * used by #cairo_scaled_font_subset_t as provided by * _cairo_scaled_font_subsets_foreach. * + * The returned values in the cairo_scaled_font_subsets_glyph_t struct are: + * + * @font_id: The font ID of the mapped glyph + * @subset_id : The subset ID of the mapped glyph within the @font_id + * @subset_glyph_index: The index of the mapped glyph within the @subset_id subset + * @is_scaled: If true, the mapped glyph is from a bitmap font, and separate font + * subset is created for each font scale used. If false, the outline of the mapped glyph + * is available. One font subset for each font face is created. + * @x_advance: When @is_scaled is true, @x_advance contains the x_advance for the mapped glyph in device space. + * When @is_scaled is false, @x_advance contains the x_advance for the the mapped glyph from an unhinted 1 point font. + * * Return value: CAIRO_STATUS_SUCCESS if successful, or a non-zero * value indicating an error. Possible errors include * CAIRO_STATUS_NO_MEMORY. @@ -134,9 +186,7 @@ cairo_private cairo_status_t _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *font_subsets, cairo_scaled_font_t *scaled_font, unsigned long scaled_font_glyph_index, - unsigned int *font_id_ret, - unsigned int *subset_id_ret, - unsigned int *subset_glyph_index_ret); + cairo_scaled_font_subsets_glyph_t *subset_glyph_ret); typedef void (*cairo_scaled_font_subset_callback_func_t) (cairo_scaled_font_subset_t *font_subset, @@ -253,6 +303,37 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset, cairo_private void _cairo_cff_subset_fini (cairo_cff_subset_t *cff_subset); +/** + * _cairo_cff_fallback_init: + * @cff_subset: a #cairo_cff_subset_t to initialize + * @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) generate a cff + * file corresponding to @font_subset and initialize @cff_subset + * with information about the subset and the cff data. + * + * Return value: CAIRO_STATUS_SUCCESS if successful, + * CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a + * cff file, or an non-zero value indicating an error. Possible + * errors include CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset, + const char *name, + cairo_scaled_font_subset_t *font_subset); + +/** + * _cairo_cff_fallback_fini: + * @cff_subset: a #cairo_cff_subset_t + * + * Free all resources associated with @cff_subset. After this + * call, @cff_subset should not be used again without a + * subsequent call to _cairo_cff_subset_init() again first. + **/ +cairo_private void +_cairo_cff_fallback_fini (cairo_cff_subset_t *cff_subset); + typedef struct _cairo_truetype_subset { char *base_font; double *widths; @@ -341,6 +422,15 @@ _cairo_type1_subset_init (cairo_type1_subset_t *type_subset, cairo_private void _cairo_type1_subset_fini (cairo_type1_subset_t *subset); +/** + * _cairo_type1_scaled_font_is_type1: + * @scaled_font: a #cairo_scaled_font_t + * + * Return TRUE if @scaled_font is a Type 1 font, otherwise return FALSE. + **/ +cairo_private cairo_bool_t +_cairo_type1_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font); + /** * _cairo_type1_fallback_init_binary: * @type1_subset: a #cairo_type1_subset_t to initialize @@ -394,6 +484,43 @@ _cairo_type1_fallback_init_hex (cairo_type1_subset_t *type_subset, cairo_private void _cairo_type1_fallback_fini (cairo_type1_subset_t *subset); +typedef struct _cairo_type2_charstrings { + int *widths; + long x_min, y_min, x_max, y_max; + long ascent, descent; + cairo_array_t charstrings; +} cairo_type2_charstrings_t; + +/** + * _cairo_type2_charstrings_init: + * @type2_subset: a #cairo_type2_subset_t to initialize + * @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) generate type2 + * charstrings to @font_subset and initialize @type2_subset + * with information about the subset. + * + * Return value: CAIRO_STATUS_SUCCESS if successful, + * CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type2 + * charstrings, or an non-zero value indicating an error. Possible errors + * include CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_type2_charstrings_init (cairo_type2_charstrings_t *charstrings, + cairo_scaled_font_subset_t *font_subset); + +/** + * _cairo_type2_charstrings_fini: + * @subset: a #cairo_type2_charstrings_t + * + * Free all resources associated with @type2_charstring. After this call, + * @type2_charstring should not be used again without a subsequent call to + * _cairo_type2_charstring_init() again first. + **/ +cairo_private void +_cairo_type2_charstrings_fini (cairo_type2_charstrings_t *charstrings); + /** * _cairo_truetype_create_glyph_to_unicode_map: * @font_subset: the #cairo_scaled_font_subset_t to initialize from diff --git a/gfx/cairo/cairo/src/cairo-scaled-font-subsets.c b/gfx/cairo/cairo/src/cairo-scaled-font-subsets.c index d98cba2f862f..65b1cdce2c13 100644 --- a/gfx/cairo/cairo/src/cairo-scaled-font-subsets.c +++ b/gfx/cairo/cairo/src/cairo-scaled-font-subsets.c @@ -42,12 +42,21 @@ #include "cairoint.h" #include "cairo-scaled-font-subsets-private.h" +#define MAX_GLYPHS_PER_SIMPLE_FONT 256 +#define MAX_GLYPHS_PER_COMPOSITE_FONT 65536 + +typedef enum { + CAIRO_SUBSETS_SCALED, + CAIRO_SUBSETS_SIMPLE, + CAIRO_SUBSETS_COMPOSITE +} cairo_subsets_type_t; + struct _cairo_scaled_font_subsets { - int max_glyphs_per_unscaled_subset_limit; + cairo_subsets_type_t type; + int max_glyphs_per_unscaled_subset_used; cairo_hash_table_t *unscaled_sub_fonts; - int max_glyphs_per_scaled_subset_limit; int max_glyphs_per_scaled_subset_used; cairo_hash_table_t *scaled_sub_fonts; @@ -58,6 +67,7 @@ typedef struct _cairo_sub_font { cairo_hash_entry_t base; cairo_bool_t is_scaled; + cairo_bool_t is_composite; cairo_scaled_font_subsets_t *parent; cairo_scaled_font_t *scaled_font; unsigned int font_id; @@ -74,6 +84,7 @@ typedef struct _cairo_sub_font_glyph { unsigned int subset_id; unsigned int subset_glyph_index; + double x_advance; } cairo_sub_font_glyph_t; typedef struct _cairo_sub_font_collection { @@ -107,7 +118,8 @@ _cairo_sub_font_glyphs_equal (const void *key_a, const void *key_b) static cairo_sub_font_glyph_t * _cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index, unsigned int subset_id, - unsigned int subset_glyph_index) + unsigned int subset_glyph_index, + double x_advance) { cairo_sub_font_glyph_t *sub_font_glyph; @@ -118,6 +130,7 @@ _cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index, _cairo_sub_font_glyph_init_key (sub_font_glyph, scaled_font_glyph_index); sub_font_glyph->subset_id = subset_id; sub_font_glyph->subset_glyph_index = subset_glyph_index; + sub_font_glyph->x_advance = x_advance; return sub_font_glyph; } @@ -195,7 +208,8 @@ _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, - cairo_bool_t is_scaled) + cairo_bool_t is_scaled, + cairo_bool_t is_composite) { cairo_sub_font_t *sub_font; @@ -204,10 +218,11 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent, return NULL; sub_font->is_scaled = is_scaled; + sub_font->is_composite = is_composite; _cairo_sub_font_init_key (sub_font, scaled_font); sub_font->parent = parent; - sub_font->scaled_font = cairo_scaled_font_reference (scaled_font); + sub_font->scaled_font = scaled_font; sub_font->font_id = font_id; sub_font->current_subset = 0; @@ -220,6 +235,11 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent, return NULL; } + if (parent->type != CAIRO_SUBSETS_SCALED) { + /* Reserve first glyph in subset for the .notdef glyph */ + sub_font->num_glyphs_in_current_subset++; + } + return sub_font; } @@ -245,10 +265,9 @@ _cairo_sub_font_pluck (void *entry, void *closure) } 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_lookup_glyph (cairo_sub_font_t *sub_font, + unsigned long scaled_font_glyph_index, + cairo_scaled_font_subsets_glyph_t *subset_glyph) { cairo_sub_font_glyph_t key, *sub_font_glyph; @@ -256,8 +275,12 @@ _cairo_sub_font_lookup_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)) { - *subset_id = sub_font_glyph->subset_id; - *subset_glyph_index = sub_font_glyph->subset_glyph_index; + subset_glyph->font_id = sub_font->font_id; + subset_glyph->subset_id = sub_font_glyph->subset_id; + subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index; + subset_glyph->is_scaled = sub_font->is_scaled; + subset_glyph->is_composite = sub_font->is_composite; + subset_glyph->x_advance = sub_font_glyph->x_advance; return CAIRO_STATUS_SUCCESS; } @@ -268,11 +291,11 @@ _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font, static cairo_status_t _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, unsigned long scaled_font_glyph_index, - unsigned int *subset_id, - unsigned int *subset_glyph_index) + cairo_scaled_font_subsets_glyph_t *subset_glyph) { cairo_sub_font_glyph_t key, *sub_font_glyph; cairo_status_t status; + cairo_scaled_glyph_t *scaled_glyph; _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); if (! _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base, @@ -282,11 +305,24 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, { sub_font->current_subset++; sub_font->num_glyphs_in_current_subset = 0; + + if (sub_font->parent->type != CAIRO_SUBSETS_SCALED) { + /* Reserve first glyph in subset for the .notdef glyph */ + sub_font->num_glyphs_in_current_subset++; + } } - sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index, + status = _cairo_scaled_glyph_lookup (sub_font->scaled_font, + scaled_font_glyph_index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + &scaled_glyph); + if (status) + return status; + + sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index, sub_font->current_subset, - sub_font->num_glyphs_in_current_subset++); + sub_font->num_glyphs_in_current_subset++, + scaled_glyph->metrics.x_advance); if (sub_font_glyph == NULL) return CAIRO_STATUS_NO_MEMORY; @@ -302,12 +338,18 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, } status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base); - if (status) + if (status) { + _cairo_sub_font_glyph_destroy (sub_font_glyph); return status; + } } - *subset_id = sub_font_glyph->subset_id; - *subset_glyph_index = sub_font_glyph->subset_glyph_index; + subset_glyph->font_id = sub_font->font_id; + subset_glyph->subset_id = sub_font_glyph->subset_id; + subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index; + subset_glyph->is_scaled = sub_font->is_scaled; + subset_glyph->is_composite = sub_font->is_composite; + subset_glyph->x_advance = sub_font_glyph->x_advance; return CAIRO_STATUS_SUCCESS; } @@ -324,16 +366,24 @@ _cairo_sub_font_collect (void *entry, void *closure) for (i = 0; i <= sub_font->current_subset; i++) { collection->subset_id = i; - collection->num_glyphs = 0; - collection->max_glyph = 0; + if (sub_font->parent->type == CAIRO_SUBSETS_SCALED) { + collection->num_glyphs = 0; + collection->max_glyph = 0; + } else { + /* Assign .notdef glyph to the first glyph in the subset */ + collection->glyphs[0] = 0; + collection->num_glyphs = 1; + collection->max_glyph = 0; + } _cairo_hash_table_foreach (sub_font->sub_font_glyphs, _cairo_sub_font_glyph_collect, collection); - /* Ensure the resulting array has no uninitialized holes */ + /* Ensure the resulting array has no uninitialized holes */ assert (collection->num_glyphs == collection->max_glyph + 1); subset.scaled_font = sub_font->scaled_font; + subset.is_composite = sub_font->is_composite; subset.font_id = sub_font->font_id; subset.subset_id = i; subset.glyphs = collection->glyphs; @@ -355,9 +405,8 @@ _cairo_sub_font_collect (void *entry, void *closure) } } -cairo_scaled_font_subsets_t * -_cairo_scaled_font_subsets_create (int max_glyphs_per_unscaled_subset, - int max_glyphs_per_scaled_subset) +static cairo_scaled_font_subsets_t * +_cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type) { cairo_scaled_font_subsets_t *subsets; @@ -365,12 +414,9 @@ _cairo_scaled_font_subsets_create (int max_glyphs_per_unscaled_subset, if (subsets == NULL) return NULL; - subsets->max_glyphs_per_unscaled_subset_limit = max_glyphs_per_unscaled_subset; + subsets->type = type; 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->unscaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal); @@ -381,7 +427,7 @@ _cairo_scaled_font_subsets_create (int max_glyphs_per_unscaled_subset, subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal); if (! subsets->scaled_sub_fonts) { - free (subsets->unscaled_sub_fonts); + _cairo_hash_table_destroy (subsets->unscaled_sub_fonts); free (subsets); return NULL; } @@ -389,6 +435,24 @@ _cairo_scaled_font_subsets_create (int max_glyphs_per_unscaled_subset, return subsets; } +cairo_scaled_font_subsets_t * +_cairo_scaled_font_subsets_create_scaled (void) +{ + return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SCALED); +} + +cairo_scaled_font_subsets_t * +_cairo_scaled_font_subsets_create_simple (void) +{ + return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SIMPLE); +} + +cairo_scaled_font_subsets_t * +_cairo_scaled_font_subsets_create_composite (void) +{ + return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_COMPOSITE); +} + void _cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets) { @@ -404,44 +468,44 @@ cairo_private cairo_status_t _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, cairo_scaled_font_t *scaled_font, unsigned long scaled_font_glyph_index, - unsigned int *font_id, - unsigned int *subset_id, - unsigned int *subset_glyph_index) + cairo_scaled_font_subsets_glyph_t *subset_glyph) { cairo_sub_font_t key, *sub_font; cairo_scaled_glyph_t *scaled_glyph; + cairo_font_face_t *font_face; + cairo_matrix_t identity; + cairo_font_options_t font_options; + cairo_scaled_font_t *unscaled_font; cairo_status_t status; + int max_glyphs; + cairo_bool_t type1_font; /* Lookup glyph in unscaled subsets */ - if (subsets->max_glyphs_per_unscaled_subset_limit > 0) { + if (subsets->type != CAIRO_SUBSETS_SCALED) { 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; + status = _cairo_sub_font_lookup_glyph (sub_font, + scaled_font_glyph_index, + subset_glyph); + if (status == CAIRO_STATUS_SUCCESS) 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; - } - } + 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_glyph); + if (status == CAIRO_STATUS_SUCCESS) + return CAIRO_STATUS_SUCCESS; } /* Glyph not found. Determine whether the glyph is outline or @@ -450,51 +514,96 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, scaled_font_glyph_index, CAIRO_SCALED_GLYPH_INFO_PATH, &scaled_glyph); - if (status == 0 && subsets->max_glyphs_per_unscaled_subset_limit > 0) { + if (status && status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + if (status == 0 && subsets->type != CAIRO_SUBSETS_SCALED) { /* 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, + font_face = cairo_scaled_font_get_font_face (scaled_font); + cairo_matrix_init_identity (&identity); + _cairo_font_options_init_default (&font_options); + cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF); + unscaled_font = cairo_scaled_font_create (font_face, + &identity, + &identity, + &font_options); + if (unscaled_font->status) + return unscaled_font->status; + + subset_glyph->is_scaled = FALSE; + type1_font = FALSE; +#if CAIRO_HAS_FT_FONT + type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font); +#endif + if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) { + max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT; + subset_glyph->is_composite = TRUE; + } else { + max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT; + subset_glyph->is_composite = FALSE; + } + + sub_font = _cairo_sub_font_create (subsets, + unscaled_font, subsets->num_sub_fonts++, - subsets->max_glyphs_per_unscaled_subset_limit, - FALSE); - if (sub_font == NULL) + max_glyphs, + subset_glyph->is_scaled, + subset_glyph->is_composite); + if (sub_font == NULL) { + cairo_scaled_font_destroy (unscaled_font); return CAIRO_STATUS_NO_MEMORY; + } status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts, &sub_font->base); - if (status) + if (status) { + _cairo_sub_font_destroy (sub_font); return status; + } } - } else if (subsets->max_glyphs_per_scaled_subset_limit > 0) { + } else { /* 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, + subset_glyph->is_scaled = TRUE; + subset_glyph->is_composite = FALSE; + if (subsets->type == CAIRO_SUBSETS_SCALED) + max_glyphs = INT_MAX; + else + max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT; + + sub_font = _cairo_sub_font_create (subsets, + cairo_scaled_font_reference (scaled_font), subsets->num_sub_fonts++, - subsets->max_glyphs_per_scaled_subset_limit, - TRUE); - if (sub_font == NULL) + max_glyphs, + subset_glyph->is_scaled, + subset_glyph->is_composite); + if (sub_font == NULL) { + cairo_scaled_font_destroy (scaled_font); return CAIRO_STATUS_NO_MEMORY; + } status = _cairo_hash_table_insert (subsets->scaled_sub_fonts, &sub_font->base); - if (status) + if (status) { + _cairo_sub_font_destroy (sub_font); 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); + return _cairo_sub_font_map_glyph (sub_font, + scaled_font_glyph_index, + subset_glyph); } static cairo_status_t @@ -509,6 +618,10 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used; else collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used; + + if (! collection.glyphs_size) + return CAIRO_STATUS_SUCCESS; + collection.glyphs = malloc (collection.glyphs_size * sizeof(unsigned long)); if (collection.glyphs == NULL) return CAIRO_STATUS_NO_MEMORY; @@ -540,7 +653,7 @@ _cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *fon } cairo_private cairo_status_t -_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets, +_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) { diff --git a/gfx/cairo/cairo/src/cairo-scaled-font.c b/gfx/cairo/cairo/src/cairo-scaled-font.c index 6efde8002e6b..7a472191bf47 100644 --- a/gfx/cairo/cairo/src/cairo-scaled-font.c +++ b/gfx/cairo/cairo/src/cairo-scaled-font.c @@ -37,7 +37,7 @@ */ #include "cairoint.h" -#include "cairo-scaled-font-test.h" +#include "cairo-scaled-font-private.h" static cairo_bool_t _cairo_scaled_glyph_keys_equal (const void *abstract_key_a, const void *abstract_key_b) @@ -135,6 +135,9 @@ _cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font, cairo_font_type_t cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font) { + if (scaled_font->ref_count == CAIRO_REF_COUNT_INVALID) + return CAIRO_FONT_TYPE_TOY; + return scaled_font->backend->type; } @@ -153,6 +156,7 @@ cairo_scaled_font_status (cairo_scaled_font_t *scaled_font) { return scaled_font->status; } +slim_hidden_def (cairo_scaled_font_status); /* Here we keep a unique mapping from * cairo_font_face_t/matrix/ctm/options => cairo_scaled_font_t. @@ -185,8 +189,6 @@ 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); - static int _cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_key_b); @@ -213,6 +215,7 @@ _cairo_scaled_font_map_lock (void) CLEANUP_SCALED_FONT_MAP: free (cairo_scaled_font_map); + cairo_scaled_font_map = NULL; CLEANUP_MUTEX_LOCK: CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); return NULL; @@ -331,14 +334,7 @@ _cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_ * separately is probably not what we want anyway. Would probably be * much better to have a single cache for glyphs with random * replacement across all glyphs of all fonts. */ -static int max_glyphs_cached_per_font = 256; - -/* For internal testing purposes only. Not part of the supported API. */ -void -_cairo_scaled_font_test_set_max_glyphs_cached_per_font (int max) -{ - max_glyphs_cached_per_font = max; -} +#define MAX_GLYPHS_CACHED_PER_FONT 256 /* * Basic cairo_scaled_font_t object management @@ -352,23 +348,40 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, const cairo_font_options_t *options, const cairo_scaled_font_backend_t *backend) { - scaled_font->ref_count = 1; + cairo_matrix_t inverse; + cairo_status_t status; - _cairo_user_data_array_init (&scaled_font->user_data); + status = cairo_font_options_status ((cairo_font_options_t *) options); + if (status) + return status; + /* Initialize scaled_font->scale early for easier bail out on an + * invalid matrix. */ _cairo_scaled_font_init_key (scaled_font, font_face, font_matrix, ctm, options); - cairo_font_face_reference (font_face); - cairo_matrix_multiply (&scaled_font->scale, &scaled_font->font_matrix, &scaled_font->ctm); - CAIRO_MUTEX_INIT (&scaled_font->mutex); + inverse = scaled_font->scale; + status = cairo_matrix_invert (&inverse); + if (status) + return status; + scaled_font->glyphs = _cairo_cache_create (_cairo_scaled_glyph_keys_equal, _cairo_scaled_glyph_destroy, - max_glyphs_cached_per_font); + MAX_GLYPHS_CACHED_PER_FONT); + if (scaled_font->glyphs == NULL) + return CAIRO_STATUS_NO_MEMORY; + + scaled_font->ref_count = 1; + + _cairo_user_data_array_init (&scaled_font->user_data); + + cairo_font_face_reference (font_face); + + CAIRO_MUTEX_INIT (scaled_font->mutex); scaled_font->surface_backend = NULL; scaled_font->surface_private = NULL; @@ -396,7 +409,7 @@ _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); + MAX_GLYPHS_CACHED_PER_FONT); } void @@ -430,7 +443,7 @@ _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); + CAIRO_MUTEX_FINI (scaled_font->mutex); if (scaled_font->surface_backend != NULL && scaled_font->surface_backend->scaled_font_fini != NULL) @@ -474,9 +487,12 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, if (font_face->status) return (cairo_scaled_font_t *)&_cairo_scaled_font_nil; + if (cairo_font_options_status ((cairo_font_options_t *) options)) + return (cairo_scaled_font_t *)&_cairo_scaled_font_nil; + font_map = _cairo_scaled_font_map_lock (); if (font_map == NULL) - return NULL; + return (cairo_scaled_font_t *)&_cairo_scaled_font_nil; _cairo_scaled_font_init_key (&key, font_face, font_matrix, ctm, options); @@ -501,35 +517,44 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, memmove (&font_map->holdovers[i], &font_map->holdovers[i+1], (font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*)); + + /* reset any error status */ + scaled_font->status = CAIRO_STATUS_SUCCESS; } - /* 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) { + if (scaled_font->status == CAIRO_STATUS_SUCCESS) { + /* 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 (); - return NULL; + return scaled_font; } - status = _cairo_hash_table_insert (font_map->hash_table, - &scaled_font->hash_entry); + /* the font has been put into an error status - abandon the cache */ + _cairo_hash_table_remove (font_map->hash_table, &key.hash_entry); + } + + /* 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 (cairo_scaled_font_t *)&_cairo_scaled_font_nil; + } - 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; - } + status = _cairo_hash_table_insert (font_map->hash_table, + &scaled_font->hash_entry); + _cairo_scaled_font_map_unlock (); + + if (status) { + /* We can't call _cairo_scaled_font_destroy here since it expects + * that the font has already been successfully inserted into the + * hash table. */ + _cairo_scaled_font_fini (scaled_font); + free (scaled_font); + return (cairo_scaled_font_t *)&_cairo_scaled_font_nil; } return scaled_font; @@ -748,10 +773,13 @@ cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font, const char *utf8, cairo_text_extents_t *extents) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_status_t status; cairo_glyph_t *glyphs; int num_glyphs; + if (scaled_font->status) + return; + status = _cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0., utf8, &glyphs, &num_glyphs); if (status) { _cairo_scaled_font_set_error (scaled_font, status); @@ -774,7 +802,7 @@ cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font, * graphics state were set to the same font_face, font_matrix, ctm, * and font_options as @scaled_font). Additionally, the x_advance and * y_advance values indicate the amount by which the current point - * would be advanced by cairo_show_glyphs. + * would be advanced by cairo_show_glyphs(). * * Note that whitespace glyphs do not contribute to the size of the * rectangle (extents.width and extents.height). @@ -785,7 +813,7 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font, int num_glyphs, cairo_text_extents_t *extents) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_status_t status; int i; double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0; cairo_bool_t visible = FALSE; @@ -1100,7 +1128,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, _cairo_pattern_fini (&glyph_pattern.base); if (status) - break; + goto CLEANUP_MASK; } if (mask != NULL) { @@ -1176,6 +1204,42 @@ _scaled_glyph_path_close_path (void *abstract_closure) return _cairo_path_fixed_close_path (closure->path); } +/* Add a single-device-unit rectangle to a path. */ +static cairo_status_t +_add_unit_rectangle_to_path (cairo_path_fixed_t *path, int x, int y) +{ + cairo_status_t status; + + status = _cairo_path_fixed_move_to (path, + _cairo_fixed_from_int (x), + _cairo_fixed_from_int (y)); + if (status) + return status; + + status = _cairo_path_fixed_rel_line_to (path, + _cairo_fixed_from_int (1), + _cairo_fixed_from_int (0)); + if (status) + return status; + + status = _cairo_path_fixed_rel_line_to (path, + _cairo_fixed_from_int (0), + _cairo_fixed_from_int (1)); + if (status) + return status; + + status = _cairo_path_fixed_rel_line_to (path, + _cairo_fixed_from_int (-1), + _cairo_fixed_from_int (0)); + if (status) + return status; + + status = _cairo_path_fixed_close_path (path); + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} /** * _trace_mask_to_path: @@ -1198,6 +1262,7 @@ static cairo_status_t _trace_mask_to_path (cairo_image_surface_t *mask, cairo_path_fixed_t *path) { + cairo_status_t status; cairo_image_surface_t *a1_mask; unsigned char *row, *byte_ptr, byte; int rows, cols, bytes_per_row; @@ -1220,19 +1285,10 @@ _trace_mask_to_path (cairo_image_surface_t *mask, byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte_ptr); for (bit = 7; bit >= 0 && x < a1_mask->width; bit--, x++) { if (byte & (1 << bit)) { - _cairo_path_fixed_move_to (path, - _cairo_fixed_from_int (x + xoff), - _cairo_fixed_from_int (y + yoff)); - _cairo_path_fixed_rel_line_to (path, - _cairo_fixed_from_int (1), - _cairo_fixed_from_int (0)); - _cairo_path_fixed_rel_line_to (path, - _cairo_fixed_from_int (0), - _cairo_fixed_from_int (1)); - _cairo_path_fixed_rel_line_to (path, - _cairo_fixed_from_int (-1), - _cairo_fixed_from_int (0)); - _cairo_path_fixed_close_path (path); + status = _add_unit_rectangle_to_path (path, + x + xoff, y + yoff); + if (status) + return status; } } } @@ -1278,6 +1334,8 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); + if (status) + return status; glyph_path = _cairo_path_fixed_create (); if (glyph_path == NULL) @@ -1302,6 +1360,9 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, &closure); if (glyph_path != scaled_glyph->path) _cairo_path_fixed_destroy (glyph_path); + + if (status) + return status; } return CAIRO_STATUS_SUCCESS; @@ -1601,6 +1662,9 @@ void cairo_scaled_font_get_font_options (cairo_scaled_font_t *scaled_font, cairo_font_options_t *options) { + if (cairo_font_options_status (options)) + return; + if (scaled_font->status) { _cairo_font_options_init_default (options); return; diff --git a/gfx/cairo/cairo/src/cairo-skiplist-private.h b/gfx/cairo/cairo/src/cairo-skiplist-private.h index b152f4b15de7..3a948afcea82 100644 --- a/gfx/cairo/cairo/src/cairo-skiplist-private.h +++ b/gfx/cairo/cairo/src/cairo-skiplist-private.h @@ -26,7 +26,24 @@ #include "cairoint.h" -#define MAX_LEVEL 31 +/* + * Skip lists are described in detail here: + * + * http://citeseer.ist.psu.edu/pugh90skip.html + */ + +/* Note that random_level() called from alloc_node_for_level() depends on + * this being not more than 16. + */ +#define MAX_LEVEL 15 + +/* Returns the index of the free-list to use for a node at level 'level' */ +#define FREELIST_FOR_LEVEL(level) (((level) - 1) / 2) + +/* Returns the maximum level that uses the same free-list as 'level' does */ +#define FREELIST_MAX_LEVEL_FOR(level) (((level) + 1) & ~1) + +#define MAX_FREELIST_LEVEL (FREELIST_FOR_LEVEL (MAX_LEVEL - 1) + 1) /* * Skip list element. In order to use the skip list, the caller must @@ -52,7 +69,7 @@ typedef struct _skip_list { size_t elt_size; size_t data_size; skip_elt_t *chains[MAX_LEVEL]; - skip_elt_t *freelists[MAX_LEVEL]; + skip_elt_t *freelists[MAX_FREELIST_LEVEL]; int max_level; } cairo_skip_list_t; diff --git a/gfx/cairo/cairo/src/cairo-skiplist.c b/gfx/cairo/cairo/src/cairo-skiplist.c index 451ecb06df0e..72ca6ce156ed 100644 --- a/gfx/cairo/cairo/src/cairo-skiplist.c +++ b/gfx/cairo/cairo/src/cairo-skiplist.c @@ -21,11 +21,7 @@ * OF THIS SOFTWARE. */ -#include -#include -#include -#include -#include +#include "cairoint.h" #include "cairo-skiplist-private.h" @@ -236,6 +232,9 @@ _cairo_skip_list_init (cairo_skip_list_t *list, for (i = 0; i < MAX_LEVEL; i++) { list->chains[i] = NULL; + } + + for (i = 0; i < MAX_FREELIST_LEVEL; i++) { list->freelists[i] = NULL; } @@ -251,7 +250,7 @@ _cairo_skip_list_fini (cairo_skip_list_t *list) while ((elt = list->chains[0])) { _cairo_skip_list_delete_given (list, elt); } - for (i=0; ifreelists[i]; while (elt) { skip_elt_t *nextfree = elt->prev; @@ -265,14 +264,17 @@ _cairo_skip_list_fini (cairo_skip_list_t *list) * Generate a random level number, distributed * so that each level is 1/4 as likely as the one before * - * Note that level numbers run 1 <= level <= MAX_LEVEL + * Note that level numbers run 1 <= level < MAX_LEVEL */ static int random_level (void) { - /* tricky bit -- each bit is '1' 75% of the time */ - long int bits = lfsr_random() | lfsr_random(); int level = 0; + /* tricky bit -- each bit is '1' 75% of the time. + * This works because we only use the lower MAX_LEVEL + * bits, and MAX_LEVEL < 16 */ + long int bits = lfsr_random(); + bits |= bits >> 16; while (++level < MAX_LEVEL) { @@ -286,19 +288,23 @@ random_level (void) static void * alloc_node_for_level (cairo_skip_list_t *list, unsigned level) { - if (list->freelists[level-1]) { - skip_elt_t *elt = list->freelists[level-1]; - list->freelists[level-1] = elt->prev; + int freelist_level = FREELIST_FOR_LEVEL (level); + if (list->freelists[freelist_level]) { + skip_elt_t *elt = list->freelists[freelist_level]; + list->freelists[freelist_level] = elt->prev; return ELT_DATA(elt); } - return malloc (list->elt_size + (level-1) * sizeof (skip_elt_t *)); + return malloc (list->elt_size + + (FREELIST_MAX_LEVEL_FOR (level) - 1) * sizeof (skip_elt_t *)); } static void free_elt (cairo_skip_list_t *list, skip_elt_t *elt) { - elt->prev = list->freelists[elt->prev_index]; - list->freelists[elt->prev_index] = elt; + int level = elt->prev_index + 1; + int freelist_level = FREELIST_FOR_LEVEL (level); + elt->prev = list->freelists[freelist_level]; + list->freelists[freelist_level] = elt; } /* @@ -349,6 +355,8 @@ _cairo_skip_list_insert (cairo_skip_list_t *list, void *data, int unique) } data_and_elt = alloc_node_for_level (list, level); + if (data_and_elt == NULL) + return NULL; memcpy (data_and_elt, data, list->data_size); elt = (skip_elt_t *) (data_and_elt + list->data_size); diff --git a/gfx/cairo/cairo/src/cairo-spline.c b/gfx/cairo/cairo/src/cairo-spline.c index 3624bfc348ce..bf87770031f6 100644 --- a/gfx/cairo/cairo/src/cairo-spline.c +++ b/gfx/cairo/cairo/src/cairo-spline.c @@ -80,9 +80,9 @@ _cairo_spline_init (cairo_spline_t *spline, else _cairo_slope_init (&spline->final_slope, &spline->a, &spline->d); + spline->points = spline->points_embedded; + spline->points_size = ARRAY_LENGTH (spline->points_embedded); spline->num_points = 0; - spline->points_size = 0; - spline->points = NULL; return CAIRO_STATUS_SUCCESS; } @@ -90,11 +90,11 @@ _cairo_spline_init (cairo_spline_t *spline, void _cairo_spline_fini (cairo_spline_t *spline) { - if (spline->points && spline->points != spline->points_embedded) + if (spline->points != spline->points_embedded) free (spline->points); - spline->points = NULL; - spline->points_size = 0; + spline->points = spline->points_embedded; + spline->points_size = ARRAY_LENGTH (spline->points_embedded); spline->num_points = 0; } @@ -104,17 +104,8 @@ _cairo_spline_grow (cairo_spline_t *spline) { cairo_point_t *new_points; int old_size = spline->points_size; - int embedded_size = sizeof (spline->points_embedded) / sizeof (spline->points_embedded[0]); int new_size = 2 * MAX (old_size, 16); - /* 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; - } - assert (spline->num_points <= spline->points_size); if (spline->points == spline->points_embedded) { @@ -284,9 +275,8 @@ _cairo_spline_decompose (cairo_spline_t *spline, double tolerance) { cairo_status_t status; - if (spline->points_size) { - _cairo_spline_fini (spline); - } + /* reset the spline, but keep the buffer */ + spline->num_points = 0; status = _cairo_spline_decompose_into (spline, tolerance * tolerance, spline); if (status) diff --git a/gfx/cairo/cairo/src/cairo-surface-fallback.c b/gfx/cairo/cairo/src/cairo-surface-fallback.c index 1a7d6663c5f8..8898aee1b2c2 100644 --- a/gfx/cairo/cairo/src/cairo-surface-fallback.c +++ b/gfx/cairo/cairo/src/cairo-surface-fallback.c @@ -35,6 +35,8 @@ * Carl D. Worth */ +#include "cairoint.h" + #include "cairo-surface-fallback-private.h" #include "cairo-clip-private.h" @@ -363,7 +365,8 @@ _clip_and_composite (cairo_clip_t *clip, return CAIRO_STATUS_SUCCESS; if (op == CAIRO_OPERATOR_CLEAR) { - _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE); + _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE, + CAIRO_CONTENT_COLOR); src = &solid_pattern.base; op = CAIRO_OPERATOR_DEST_OUT; } @@ -418,7 +421,8 @@ _composite_trap_region (cairo_clip_t *clip, cairo_surface_t *clip_surface = clip ? clip->surface : NULL; if (clip_surface && op == CAIRO_OPERATOR_CLEAR) { - _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE); + _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE, + CAIRO_CONTENT_COLOR); src = &solid_pattern.base; op = CAIRO_OPERATOR_DEST_OUT; } @@ -452,8 +456,11 @@ _composite_trap_region (cairo_clip_t *clip, extents->width, extents->height); /* Restore the original clip if we modified it temporarily. */ - if (num_rects >1) - _cairo_surface_set_clip (dst, clip); + if (num_rects > 1) { + cairo_status_t status2 = _cairo_surface_set_clip (dst, clip); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + } if (clip_surface) _cairo_pattern_fini (&mask.base); @@ -485,7 +492,8 @@ _composite_traps_draw_func (void *closure, if (dst_x != 0 || dst_y != 0) _cairo_traps_translate (info->traps, - dst_x, - dst_y); - _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); + _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE, + CAIRO_CONTENT_COLOR); if (!src) src = &pattern.base; @@ -511,145 +519,156 @@ _clip_and_composite_trapezoids (cairo_pattern_t *src, cairo_antialias_t antialias) { cairo_status_t status; - pixman_region16_t *trap_region = NULL; - pixman_region16_t *clear_region = NULL; + pixman_region16_t trap_region; + pixman_region16_t clear_region; + cairo_bool_t has_trap_region = FALSE; + cairo_bool_t has_clear_region = FALSE; cairo_rectangle_int16_t extents; cairo_composite_traps_info_t traps_info; if (traps->num_traps == 0) - return CAIRO_STATUS_SUCCESS; + return CAIRO_STATUS_SUCCESS; status = _cairo_surface_get_extents (dst, &extents); + if (status) - return status; + return status; status = _cairo_traps_extract_region (traps, &trap_region); - if (status) - return status; - if (_cairo_operator_bounded_by_mask (op)) - { - cairo_rectangle_int16_t trap_extents; - if (trap_region) { - status = _cairo_clip_intersect_to_region (clip, trap_region); - if (status) - goto out; - - _cairo_region_extents_rectangle (trap_region, &trap_extents); - } else { - cairo_box_t trap_box; - _cairo_traps_extents (traps, &trap_box); - _cairo_box_round_to_rectangle (&trap_box, &trap_extents); - } - - _cairo_rectangle_intersect (&extents, &trap_extents); - status = _cairo_clip_intersect_to_rectangle (clip, &extents); - if (status) - goto out; + if (CAIRO_INT_STATUS_UNSUPPORTED == status) { + has_trap_region = FALSE; + } else if (status) { + return status; + } else { + has_trap_region = TRUE; } - else - { - cairo_surface_t *clip_surface = clip ? clip->surface : NULL; - if (trap_region && !clip_surface) { - /* If we optimize drawing with an unbounded operator to - * _cairo_surface_fill_rectangles() or to drawing with a - * clip region, then we have an additional region to clear. - */ - clear_region = _cairo_region_create_from_rectangle (&extents); - if (clear_region == NULL) - return CAIRO_STATUS_NO_MEMORY; + if (_cairo_operator_bounded_by_mask (op)) { + cairo_rectangle_int16_t trap_extents; - status = _cairo_clip_intersect_to_region (clip, clear_region); - if (status) - return status; + if (has_trap_region) { + status = _cairo_clip_intersect_to_region (clip, &trap_region); - _cairo_region_extents_rectangle (clear_region, &extents); + if (status) + goto out; - if (pixman_region_subtract (clear_region, clear_region, trap_region) != PIXMAN_REGION_STATUS_SUCCESS) - return CAIRO_STATUS_NO_MEMORY; + _cairo_region_extents_rectangle (&trap_region, &trap_extents); + } else { + cairo_box_t trap_box; + _cairo_traps_extents (traps, &trap_box); + _cairo_box_round_to_rectangle (&trap_box, &trap_extents); + } - if (!pixman_region_not_empty (clear_region)) { - pixman_region_destroy (clear_region); - clear_region = NULL; - } - } else { - status = _cairo_clip_intersect_to_rectangle (clip, &extents); - if (status) - return status; - } + _cairo_rectangle_intersect (&extents, &trap_extents); + status = _cairo_clip_intersect_to_rectangle (clip, &extents); + + if (status) + goto out; + } else { + cairo_surface_t *clip_surface = clip ? clip->surface : NULL; + + if (has_trap_region && !clip_surface) { + /* If we optimize drawing with an unbounded operator to + * _cairo_surface_fill_rectangles() or to drawing with a + * clip region, then we have an additional region to clear. + */ + pixman_region_init_rect (&clear_region, + extents.x, extents.y, + extents.width, extents.height); + + has_clear_region = TRUE; + status = _cairo_clip_intersect_to_region (clip, &clear_region); + + if (status) + goto out; + + _cairo_region_extents_rectangle (&clear_region, &extents); + + if (PIXMAN_REGION_STATUS_SUCCESS != + pixman_region_subtract (&clear_region, &clear_region, &trap_region)) { + status = CAIRO_STATUS_NO_MEMORY; + goto out; + } + + if (!pixman_region_not_empty (&clear_region)) { + pixman_region_fini (&clear_region); + has_clear_region = FALSE; + } + } else { + status = _cairo_clip_intersect_to_rectangle (clip, &extents); + } } if (status) - goto out; + goto out; - if (trap_region) - { - cairo_surface_t *clip_surface = clip ? clip->surface : NULL; + if (has_trap_region) { + cairo_surface_t *clip_surface = clip ? clip->surface : NULL; - if ((src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR) && - !clip_surface) - { - const cairo_color_t *color; + if ((src->type == CAIRO_PATTERN_TYPE_SOLID || + op == CAIRO_OPERATOR_CLEAR) && !clip_surface) { + const cairo_color_t *color; - if (op == CAIRO_OPERATOR_CLEAR) - color = CAIRO_COLOR_TRANSPARENT; - else - color = &((cairo_solid_pattern_t *)src)->color; + if (op == CAIRO_OPERATOR_CLEAR) { + color = CAIRO_COLOR_TRANSPARENT; + } else { + color = &((cairo_solid_pattern_t *)src)->color; + } - /* Solid rectangles special case */ - status = _cairo_surface_fill_region (dst, op, color, trap_region); - if (!status && clear_region) - status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR, - CAIRO_COLOR_TRANSPARENT, - clear_region); + /* Solid rectangles special case */ + status = _cairo_surface_fill_region (dst, op, color, &trap_region); - goto out; - } + if (!status && has_clear_region) + status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + &clear_region); - if ((_cairo_operator_bounded_by_mask (op) && op != CAIRO_OPERATOR_SOURCE) || - !clip_surface) - { - /* For a simple rectangle, we can just use composite(), for more - * rectangles, we have to set a clip region. The cost of rasterizing - * trapezoids is pretty high for most backends currently, so it's - * worthwhile even if a region is needed. - * - * If we have a clip surface, we set it as the mask; this only works - * for bounded operators other than SOURCE; for unbounded operators, - * clip and mask cannot be interchanged. For SOURCE, the operator - * as implemented by the backends is different in it's handling - * of the mask then what we want. - * - * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has - * more than rectangle and the destination doesn't support clip - * regions. In that case, we fall through. - */ - status = _composite_trap_region (clip, src, op, dst, - trap_region, &extents); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - { - if (!status && clear_region) - status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR, - CAIRO_COLOR_TRANSPARENT, - clear_region); - goto out; - } - } + goto out; + } + + if ((_cairo_operator_bounded_by_mask (op) && + op != CAIRO_OPERATOR_SOURCE) || !clip_surface) { + /* For a simple rectangle, we can just use composite(), for more + * rectangles, we have to set a clip region. The cost of rasterizing + * trapezoids is pretty high for most backends currently, so it's + * worthwhile even if a region is needed. + * + * If we have a clip surface, we set it as the mask; this only works + * for bounded operators other than SOURCE; for unbounded operators, + * clip and mask cannot be interchanged. For SOURCE, the operator + * as implemented by the backends is different in it's handling + * of the mask then what we want. + * + * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has + * more than rectangle and the destination doesn't support clip + * regions. In that case, we fall through. + */ + status = _composite_trap_region (clip, src, op, dst, + &trap_region, &extents); + + if (status != CAIRO_INT_STATUS_UNSUPPORTED) { + if (!status && has_clear_region) + status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + &clear_region); + goto out; + } + } } traps_info.traps = traps; traps_info.antialias = antialias; status = _clip_and_composite (clip, op, src, - _composite_traps_draw_func, &traps_info, - dst, &extents); + _composite_traps_draw_func, + &traps_info, dst, &extents); - out: - if (trap_region) - pixman_region_destroy (trap_region); - if (clear_region) - pixman_region_destroy (clear_region); +out: + if (has_trap_region) + pixman_region_fini (&trap_region); + if (has_clear_region) + pixman_region_fini (&clear_region); return status; } @@ -690,16 +709,16 @@ _cairo_surface_fallback_paint (cairo_surface_t *surface, if (status) return status; - _clip_and_composite_trapezoids (source, - op, - surface, - &traps, - surface->clip, - CAIRO_ANTIALIAS_NONE); + status = _clip_and_composite_trapezoids (source, + op, + surface, + &traps, + surface->clip, + CAIRO_ANTIALIAS_NONE); _cairo_traps_fini (&traps); - return CAIRO_STATUS_SUCCESS; + return status; } static cairo_status_t @@ -785,9 +804,35 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface, { cairo_status_t status; cairo_traps_t traps; + cairo_box_t box; + cairo_rectangle_int16_t extents; + + status = _cairo_surface_get_extents (surface, &extents); + if (status) + return status; + + if (_cairo_operator_bounded_by_source (op)) { + cairo_rectangle_int16_t source_extents; + status = _cairo_pattern_get_extents (source, &source_extents); + if (status) + return status; + + _cairo_rectangle_intersect (&extents, &source_extents); + } + + status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); + if (status) + return status; + + box.p1.x = _cairo_fixed_from_int (extents.x); + box.p1.y = _cairo_fixed_from_int (extents.y); + box.p2.x = _cairo_fixed_from_int (extents.x + extents.width); + box.p2.y = _cairo_fixed_from_int (extents.y + extents.height); _cairo_traps_init (&traps); + _cairo_traps_limit (&traps, &box); + status = _cairo_path_fixed_stroke_to_traps (path, stroke_style, ctm, ctm_inverse, @@ -798,16 +843,16 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface, return status; } - _clip_and_composite_trapezoids (source, - op, - surface, - &traps, - surface->clip, - antialias); + status = _clip_and_composite_trapezoids (source, + op, + surface, + &traps, + surface->clip, + antialias); _cairo_traps_fini (&traps); - return CAIRO_STATUS_SUCCESS; + return status; } cairo_status_t @@ -821,9 +866,35 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, { cairo_status_t status; cairo_traps_t traps; + cairo_box_t box; + cairo_rectangle_int16_t extents; + + status = _cairo_surface_get_extents (surface, &extents); + if (status) + return status; + + if (_cairo_operator_bounded_by_source (op)) { + cairo_rectangle_int16_t source_extents; + status = _cairo_pattern_get_extents (source, &source_extents); + if (status) + return status; + + _cairo_rectangle_intersect (&extents, &source_extents); + } + + status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); + if (status) + return status; + + box.p1.x = _cairo_fixed_from_int (extents.x); + box.p1.y = _cairo_fixed_from_int (extents.y); + box.p2.x = _cairo_fixed_from_int (extents.x + extents.width); + box.p2.y = _cairo_fixed_from_int (extents.y + extents.height); _cairo_traps_init (&traps); + _cairo_traps_limit (&traps, &box); + status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, @@ -878,7 +949,8 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure } } - _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); + _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE, + CAIRO_CONTENT_COLOR); if (!src) src = &pattern.base; @@ -979,17 +1051,21 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface) _cairo_pattern_init_for_surface (&pattern.surface, &image->base); - _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, - &pattern.base, - NULL, - snapshot, - 0, 0, - 0, 0, - 0, 0, - image->width, - image->height); + status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, + &pattern.base, + NULL, + snapshot, + 0, 0, + 0, 0, + 0, 0, + image->width, + image->height); _cairo_pattern_fini (&pattern.base); + if (status) { + cairo_surface_destroy (snapshot); + return (cairo_surface_t *) &_cairo_surface_nil; + } _cairo_surface_release_source_image (surface, image, &image_extra); @@ -1158,13 +1234,14 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op, traps = offset_traps; } - _cairo_surface_composite_trapezoids (op, pattern, - &state.image->base, - antialias, - src_x, src_y, - dst_x - state.image_rect.x, - dst_y - state.image_rect.y, - width, height, traps, num_traps); + status = _cairo_surface_composite_trapezoids (op, pattern, + &state.image->base, + antialias, + src_x, src_y, + dst_x - state.image_rect.x, + dst_y - state.image_rect.y, + width, height, + traps, num_traps); if (offset_traps) free (offset_traps); diff --git a/gfx/cairo/cairo/src/cairo-surface-private.h b/gfx/cairo/cairo/src/cairo-surface-private.h new file mode 100644 index 000000000000..6193cf805573 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-surface-private.h @@ -0,0 +1,96 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_SURFACE_PRIVATE_H +#define CAIRO_SURFACE_PRIVATE_H + +#include "cairo.h" + +#include "cairo-types-private.h" + +struct _cairo_surface { + const cairo_surface_backend_t *backend; + + /* We allow surfaces to override the backend->type by shoving something + * else into surface->type. This is for "wrapper" surfaces that want to + * hide their internal type from the user-level API. */ + cairo_surface_type_t type; + + cairo_content_t content; + + unsigned int ref_count; + cairo_status_t status; + cairo_bool_t finished; + cairo_user_data_array_t user_data; + + cairo_matrix_t device_transform; + cairo_matrix_t device_transform_inverse; + + double x_fallback_resolution; + double y_fallback_resolution; + + cairo_clip_t *clip; + + /* + * Each time a clip region is modified, it gets the next value in this + * sequence. This means that clip regions for this surface are uniquely + * identified and updates to the clip can be readily identified + */ + unsigned int next_clip_serial; + /* + * The serial number of the current clip. This is set when + * the surface clipping is set. The gstate can then cheaply + * check whether the surface clipping is already correct before + * performing a rendering operation. + * + * The special value '0' is reserved for the unclipped case. + */ + unsigned int current_clip_serial; + + /* A "snapshot" surface is immutable. See _cairo_surface_snapshot. */ + cairo_bool_t is_snapshot; + + /* + * Surface font options, falling back to backend's default options, + * and set using _cairo_surface_set_font_options(), and propagated by + * cairo_surface_create_similar(). + */ + cairo_bool_t has_font_options; + cairo_font_options_t font_options; +}; + +#endif /* CAIRO_SURFACE_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-surface.c b/gfx/cairo/cairo/src/cairo-surface.c index 92efa00571b7..d7ef33f10e0b 100644 --- a/gfx/cairo/cairo/src/cairo-surface.c +++ b/gfx/cairo/cairo/src/cairo-surface.c @@ -35,9 +35,8 @@ * Carl D. Worth */ -#include - #include "cairoint.h" + #include "cairo-surface-fallback-private.h" #include "cairo-clip-private.h" @@ -81,7 +80,7 @@ DEFINE_NIL_SURFACE(CAIRO_STATUS_FILE_NOT_FOUND, _cairo_surface_nil_file_not_foun 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 +static cairo_status_t _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern, cairo_surface_t *destination, cairo_pattern_t *pattern_out); @@ -180,10 +179,10 @@ _cairo_surface_init (cairo_surface_t *surface, const cairo_surface_backend_t *backend, cairo_content_t content) { + CAIRO_MUTEX_INITIALIZE (); + surface->backend = backend; - surface->content = content; - surface->type = backend->type; surface->ref_count = 1; @@ -289,7 +288,8 @@ cairo_surface_create_similar (cairo_surface_t *other, return _cairo_surface_create_similar_solid (other, content, width, height, - CAIRO_COLOR_TRANSPARENT); + CAIRO_COLOR_TRANSPARENT, + NULL); } slim_hidden_def (cairo_surface_create_similar); @@ -298,7 +298,8 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other, cairo_content_t content, int width, int height, - const cairo_color_t *color) + const cairo_color_t *color, + cairo_pattern_t *pattern) { cairo_status_t status; cairo_surface_t *surface; @@ -311,19 +312,23 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other, return (cairo_surface_t*) &_cairo_surface_nil; } - source = _cairo_pattern_create_solid (color); - if (source->status) { - cairo_surface_destroy (surface); - _cairo_error (CAIRO_STATUS_NO_MEMORY); - return (cairo_surface_t*) &_cairo_surface_nil; - } + if (pattern == NULL) { + source = _cairo_pattern_create_solid (color, content); + if (source->status) { + cairo_surface_destroy (surface); + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } + } else + source = pattern; status = _cairo_surface_paint (surface, color == CAIRO_COLOR_TRANSPARENT ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE, source); - cairo_pattern_destroy (source); + if (source != pattern) + cairo_pattern_destroy (source); if (status) { cairo_surface_destroy (surface); @@ -374,7 +379,7 @@ slim_hidden_def (cairo_surface_reference); /** * cairo_surface_destroy: - * @surface: a #cairo_t + * @surface: a #cairo_surface_t * * Decreases the reference count on @surface by one. If the result is * zero, then @surface and all associated resources are freed. See @@ -401,6 +406,34 @@ cairo_surface_destroy (cairo_surface_t *surface) } slim_hidden_def(cairo_surface_destroy); +/** + * cairo_surface_reset: + * @surface: a #cairo_surface_t + * + * Resets the surface back to defaults such that it may be reused in lieu + * of creating a new surface. + **/ +cairo_status_t +_cairo_surface_reset (cairo_surface_t *surface) +{ + if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID) + return CAIRO_STATUS_SUCCESS; + + assert (surface->ref_count == 1); + + _cairo_user_data_array_fini (&surface->user_data); + + if (surface->backend->reset != NULL) { + cairo_status_t status = surface->backend->reset (surface); + if (status) + return status; + } + + _cairo_surface_init (surface, surface->backend, surface->content); + + return CAIRO_STATUS_SUCCESS; +} + /** * cairo_surface_get_reference_count: * @surface: a #cairo_surface_t @@ -469,10 +502,8 @@ cairo_surface_finish (cairo_surface_t *surface) } status = surface->backend->finish (surface); - if (status) { + if (status) _cairo_surface_set_error (surface, status); - return; - } surface->finished = TRUE; } @@ -570,13 +601,16 @@ void cairo_surface_get_font_options (cairo_surface_t *surface, cairo_font_options_t *options) { + if (cairo_font_options_status (options)) + return; + if (!surface->has_font_options) { surface->has_font_options = TRUE; + _cairo_font_options_init_default (&surface->font_options); + if (!surface->finished && surface->backend->get_font_options) { surface->backend->get_font_options (surface, &surface->font_options); - } else { - _cairo_font_options_init_default (&surface->font_options); } } @@ -1057,6 +1091,35 @@ _cairo_surface_snapshot (cairo_surface_t *surface) return _cairo_surface_fallback_snapshot (surface); } +/** + * _cairo_surface_is_similar + * @surface_a: a #cairo_surface_t + * @surface_b: a #cairo_surface_t + * @content: a #cairo_content_t + * + * Find out whether the given surfaces share the same backend, + * and if so, whether they can be considered similar. + * + * The definition of "similar" depends on the backend. In + * general, it means that the surface is equivalent to one + * that would have been generated by a call to cairo_surface_create_similar. + * + * Return value: TRUE if the surfaces are similar. + **/ +cairo_bool_t +_cairo_surface_is_similar (cairo_surface_t *surface_a, + cairo_surface_t *surface_b, + cairo_content_t content) +{ + if (surface_a->backend != surface_b->backend) + return FALSE; + + if (surface_a->backend->is_similar != NULL) + return surface_a->backend->is_similar (surface_a, surface_b, content); + + return TRUE; +} + cairo_status_t _cairo_surface_composite (cairo_operator_t op, cairo_pattern_t *src, @@ -1170,6 +1233,7 @@ _cairo_surface_fill_region (cairo_surface_t *surface, { int num_rects = pixman_region_num_rects (region); pixman_box16_t *boxes = pixman_region_rects (region); + cairo_rectangle_int16_t stack_rects[CAIRO_STACK_BUFFER_SIZE / sizeof (cairo_rectangle_int16_t)]; cairo_rectangle_int16_t *rects; cairo_status_t status; int i; @@ -1179,9 +1243,12 @@ _cairo_surface_fill_region (cairo_surface_t *surface, if (!num_rects) return CAIRO_STATUS_SUCCESS; - rects = malloc (sizeof (pixman_rectangle_t) * num_rects); - if (!rects) - return CAIRO_STATUS_NO_MEMORY; + rects = stack_rects; + if (num_rects > ARRAY_LENGTH (stack_rects)) { + rects = malloc (sizeof (cairo_rectangle_int16_t) * num_rects); + if (!rects) + return CAIRO_STATUS_NO_MEMORY; + } for (i = 0; i < num_rects; i++) { rects[i].x = boxes[i].x1; @@ -1193,7 +1260,8 @@ _cairo_surface_fill_region (cairo_surface_t *surface, status = _cairo_surface_fill_rectangles (surface, op, color, rects, num_rects); - free (rects); + if (rects != stack_rects) + free (rects); return status; } @@ -1255,7 +1323,9 @@ _cairo_surface_paint (cairo_surface_t *surface, assert (! surface->is_snapshot); - _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); + status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); + if (status) + return status; if (surface->backend->paint) { status = surface->backend->paint (surface, op, &dev_source.base); @@ -1283,20 +1353,26 @@ _cairo_surface_mask (cairo_surface_t *surface, assert (! surface->is_snapshot); - _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); - _cairo_surface_copy_pattern_for_destination (mask, surface, &dev_mask.base); + status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); + if (status) + goto FINISH; + status = _cairo_surface_copy_pattern_for_destination (mask, surface, &dev_mask.base); + if (status) + goto CLEANUP_SOURCE; if (surface->backend->mask) { status = surface->backend->mask (surface, op, &dev_source.base, &dev_mask.base); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - goto FINISH; + goto CLEANUP_MASK; } status = _cairo_surface_fallback_mask (surface, op, &dev_source.base, &dev_mask.base); - FINISH: + CLEANUP_MASK: _cairo_pattern_fini (&dev_mask.base); + CLEANUP_SOURCE: _cairo_pattern_fini (&dev_source.base); + FINISH: return status; } @@ -1321,7 +1397,9 @@ _cairo_surface_stroke (cairo_surface_t *surface, assert (! surface->is_snapshot); - _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); + status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); + if (status) + return status; if (surface->backend->stroke) { status = surface->backend->stroke (surface, op, &dev_source.base, @@ -1360,7 +1438,9 @@ _cairo_surface_fill (cairo_surface_t *surface, assert (! surface->is_snapshot); - _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); + status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); + if (status) + return status; if (surface->backend->fill) { status = surface->backend->fill (surface, op, &dev_source.base, @@ -1430,10 +1510,7 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op, traps, num_traps); } -/* _copy_page and _show_page are unique among _cairo_surface functions - * in that they will actually return CAIRO_INT_STATUS_UNSUPPORTED - * rather than performing any fallbacks. */ -cairo_int_status_t +cairo_status_t _cairo_surface_copy_page (cairo_surface_t *surface) { assert (! surface->is_snapshot); @@ -1444,16 +1521,14 @@ _cairo_surface_copy_page (cairo_surface_t *surface) if (surface->finished) return CAIRO_STATUS_SURFACE_FINISHED; + /* It's fine if some backends don't implement copy_page */ if (surface->backend->copy_page == NULL) - return CAIRO_INT_STATUS_UNSUPPORTED; + return CAIRO_STATUS_SUCCESS; return surface->backend->copy_page (surface); } -/* _show_page and _copy_page are unique among _cairo_surface functions - * in that they will actually return CAIRO_INT_STATUS_UNSUPPORTED - * rather than performing any fallbacks. */ -cairo_int_status_t +cairo_status_t _cairo_surface_show_page (cairo_surface_t *surface) { assert (! surface->is_snapshot); @@ -1464,8 +1539,9 @@ _cairo_surface_show_page (cairo_surface_t *surface) if (surface->finished) return CAIRO_STATUS_SURFACE_FINISHED; + /* It's fine if some backends don't implement show_page */ if (surface->backend->show_page == NULL) - return CAIRO_INT_STATUS_UNSUPPORTED; + return CAIRO_STATUS_SUCCESS; return surface->backend->show_page (surface); } @@ -1700,9 +1776,9 @@ _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip) clip->path, clip->serial); - if (clip->region) + if (clip->has_region) return _cairo_surface_set_clip_region (surface, - clip->region, + &clip->region, clip->serial); } @@ -1764,9 +1840,11 @@ _cairo_surface_show_glyphs (cairo_surface_t *surface, if (!num_glyphs) return CAIRO_STATUS_SUCCESS; - _cairo_surface_copy_pattern_for_destination (source, - surface, - &dev_source.base); + status = _cairo_surface_copy_pattern_for_destination (source, + surface, + &dev_source.base); + if (status) + return status; cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix); @@ -1787,6 +1865,11 @@ _cairo_surface_show_glyphs (cairo_surface_t *surface, font_options); cairo_font_options_destroy (font_options); } + status = cairo_scaled_font_status (dev_scaled_font); + if (status) { + _cairo_pattern_fini (&dev_source.base); + return status; + } CAIRO_MUTEX_LOCK (dev_scaled_font->mutex); @@ -1865,9 +1948,11 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst, { cairo_rectangle_int16_t dst_rectangle; cairo_rectangle_int16_t drawn_rectangle; - pixman_region16_t *drawn_region; - pixman_region16_t *clear_region; - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_bool_t has_drawn_region = FALSE; + cairo_bool_t has_clear_region = FALSE; + pixman_region16_t drawn_region; + pixman_region16_t clear_region; + cairo_status_t status; /* The area that was drawn is the area in the destination rectangle but not within * the source or the mask. @@ -1880,34 +1965,38 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst, drawn_rectangle = dst_rectangle; if (src_rectangle) - _cairo_rectangle_intersect (&drawn_rectangle, src_rectangle); + _cairo_rectangle_intersect (&drawn_rectangle, src_rectangle); if (mask_rectangle) - _cairo_rectangle_intersect (&drawn_rectangle, mask_rectangle); + _cairo_rectangle_intersect (&drawn_rectangle, mask_rectangle); /* Now compute the area that is in dst_rectangle but not in drawn_rectangle */ - drawn_region = _cairo_region_create_from_rectangle (&drawn_rectangle); - clear_region = _cairo_region_create_from_rectangle (&dst_rectangle); - if (!drawn_region || !clear_region) { - status = CAIRO_STATUS_NO_MEMORY; - goto CLEANUP_REGIONS; - } + pixman_region_init_rect (&drawn_region, + drawn_rectangle.x, drawn_rectangle.y, + drawn_rectangle.width, drawn_rectangle.height); + pixman_region_init_rect (&clear_region, + dst_rectangle.x, dst_rectangle.y, + dst_rectangle.width, dst_rectangle.height); - if (pixman_region_subtract (clear_region, clear_region, drawn_region) != PIXMAN_REGION_STATUS_SUCCESS) { - status = CAIRO_STATUS_NO_MEMORY; - goto CLEANUP_REGIONS; + has_drawn_region = TRUE; + has_clear_region = TRUE; + + if (PIXMAN_REGION_STATUS_SUCCESS != + pixman_region_subtract (&clear_region, &clear_region, &drawn_region)) { + status = CAIRO_STATUS_NO_MEMORY; + goto CLEANUP_REGIONS; } status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_SOURCE, - CAIRO_COLOR_TRANSPARENT, - clear_region); + CAIRO_COLOR_TRANSPARENT, + &clear_region); - CLEANUP_REGIONS: - if (drawn_region) - pixman_region_destroy (drawn_region); - if (clear_region) - pixman_region_destroy (clear_region); +CLEANUP_REGIONS: + if (has_drawn_region) + pixman_region_fini (&drawn_region); + if (has_clear_region) + pixman_region_fini (&clear_region); return status; } @@ -2068,16 +2157,19 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst, * Copies the given pattern, taking into account device scale and offsets * of the destination surface. */ -void +static cairo_status_t _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern, cairo_surface_t *destination, cairo_pattern_t *pattern_out) { - _cairo_pattern_init_copy (pattern_out, pattern); + cairo_status_t status; + + status = _cairo_pattern_init_copy (pattern_out, pattern); + if (status) + return status; if (_cairo_surface_has_device_transform (destination)) { cairo_matrix_t device_to_surface = destination->device_transform; - cairo_status_t status; status = cairo_matrix_invert (&device_to_surface); /* We only ever allow for scaling (under the implementation's @@ -2087,6 +2179,8 @@ _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern, _cairo_pattern_transform (pattern_out, &device_to_surface); } + + return CAIRO_STATUS_SUCCESS; } /* LocalWords: rasterized diff --git a/gfx/cairo/cairo/src/cairo-svg-surface-private.h b/gfx/cairo/cairo/src/cairo-svg-surface-private.h new file mode 100644 index 000000000000..e7cd4db8cf05 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-svg-surface-private.h @@ -0,0 +1,74 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc + * Copyright © 2005-2006 Emmanuel Pacaud + * Copyright © 2006 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Kristian Høgsberg + * Emmanuel Pacaud + * Carl Worth + */ + +#ifndef CAIRO_SVG_SURFACE_PRIVATE_H +#define CAIRO_SVG_SURFACE_PRIVATE_H + +#include "cairo-svg.h" + +#include "cairo-surface-private.h" + +typedef struct cairo_svg_document cairo_svg_document_t; + +typedef struct cairo_svg_surface { + cairo_surface_t base; + + cairo_content_t content; + + unsigned int id; + + double width; + double height; + + cairo_svg_document_t *document; + + cairo_output_stream_t *xml_node; + cairo_array_t page_set; + + unsigned int clip_level; + unsigned int base_clip; + cairo_bool_t is_base_clip_emitted; + + cairo_paginated_mode_t paginated_mode; + + cairo_bool_t force_fallbacks; +} cairo_svg_surface_t; + +#endif /* CAIRO_SVG_SURFACE_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-svg-surface.c b/gfx/cairo/cairo/src/cairo-svg-surface.c index 5cb9ce0b97f1..483440ff3d44 100644 --- a/gfx/cairo/cairo/src/cairo-svg-surface.c +++ b/gfx/cairo/cairo/src/cairo-svg-surface.c @@ -40,15 +40,13 @@ #include "cairoint.h" #include "cairo-svg.h" -#include "cairo-svg-test.h" +#include "cairo-svg-surface-private.h" #include "cairo-path-fixed-private.h" #include "cairo-meta-surface-private.h" -#include "cairo-paginated-surface-private.h" +#include "cairo-paginated-private.h" #include "cairo-scaled-font-subsets-private.h" #include "cairo-output-stream-private.h" -typedef struct cairo_svg_document cairo_svg_document_t; -typedef struct cairo_svg_surface cairo_svg_surface_t; typedef struct cairo_svg_page cairo_svg_page_t; static const int invalid_pattern_id = -1; @@ -59,7 +57,7 @@ static const cairo_svg_version_t _cairo_svg_versions[] = CAIRO_SVG_VERSION_1_2 }; -#define CAIRO_SVG_VERSION_LAST ((int)(sizeof (_cairo_svg_versions) / sizeof (_cairo_svg_versions[0]))) +#define CAIRO_SVG_VERSION_LAST ARRAY_LENGTH (_cairo_svg_versions) static cairo_bool_t _cairo_svg_version_has_page_set_support (cairo_svg_version_t version) @@ -81,7 +79,6 @@ static const char * _cairo_svg_internal_version_strings[CAIRO_SVG_VERSION_LAST] struct cairo_svg_page { unsigned int surface_id; - unsigned int clip_id; unsigned int clip_level; cairo_output_stream_t *xml_node; }; @@ -115,27 +112,6 @@ struct cairo_svg_document { cairo_scaled_font_subsets_t *font_subsets; }; -struct cairo_svg_surface { - cairo_surface_t base; - - cairo_content_t content; - - unsigned int id; - - double width; - double height; - - cairo_svg_document_t *document; - - cairo_output_stream_t *xml_node; - cairo_array_t page_set; - - unsigned int clip_level; - unsigned int base_clip; - - cairo_paginated_mode_t paginated_mode; -}; - typedef struct { unsigned int id; cairo_meta_surface_t *meta; @@ -378,13 +354,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document, surface->id = document->surface_id++; surface->base_clip = document->clip_id++; - - _cairo_output_stream_printf (document->xml_node_defs, - "\n" - " \n" - "\n", - surface->base_clip, - width, height); + surface->is_base_clip_emitted = FALSE; surface->xml_node = _cairo_memory_stream_create (); _cairo_array_init (&surface->page_set, sizeof (cairo_svg_page_t)); @@ -398,6 +368,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document, } surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE; + surface->force_fallbacks = FALSE; surface->content = content; return _cairo_paginated_surface_create (&surface->base, @@ -437,7 +408,6 @@ _cairo_svg_surface_store_page (cairo_svg_surface_t *surface) cairo_svg_page_t page; page.surface_id = surface->id; - page.clip_id = surface->base_clip; page.clip_level = surface->clip_level; page.xml_node = surface->xml_node; @@ -447,7 +417,8 @@ _cairo_svg_surface_store_page (cairo_svg_surface_t *surface) for (i = 0; i < page.clip_level; i++) _cairo_output_stream_printf (page.xml_node, "\n"); - _cairo_array_append (&surface->page_set, &page); + if (_cairo_array_append (&surface->page_set, &page) != CAIRO_STATUS_SUCCESS) + return NULL; return _cairo_array_index (&surface->page_set, surface->page_set.num_elements - 1); } @@ -706,38 +677,27 @@ _cairo_svg_document_emit_font_subset (cairo_scaled_font_subset_t *font_subset, } } -static void +static cairo_status_t _cairo_svg_document_emit_font_subsets (cairo_svg_document_t *document) { - _cairo_scaled_font_subsets_foreach_scaled (document->font_subsets, - _cairo_svg_document_emit_font_subset, - document); + cairo_status_t status; + + status = _cairo_scaled_font_subsets_foreach_scaled (document->font_subsets, + _cairo_svg_document_emit_font_subset, + document); + if (status) + return status; + _cairo_scaled_font_subsets_destroy (document->font_subsets); document->font_subsets = NULL; + + return CAIRO_STATUS_SUCCESS; } static cairo_bool_t cairo_svg_force_fallbacks = FALSE; -/** - * _cairo_svg_test_force_fallbacks - * - * Force the SVG surface backend to use image fallbacks for every - * operation. - * - * - * This function is only intended for internal - * testing use within the cairo distribution. It is not installed in - * any public header file. - * - **/ -void -_cairo_svg_test_force_fallbacks (void) -{ - cairo_svg_force_fallbacks = TRUE; -} - static cairo_int_status_t -__cairo_svg_surface_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) { @@ -758,7 +718,7 @@ _cairo_svg_surface_analyze_operation (cairo_svg_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *pattern) { - if (__cairo_svg_surface_operation_supported (surface, op, pattern)) + if (_cairo_svg_surface_operation_supported (surface, op, pattern)) return CAIRO_STATUS_SUCCESS; else return CAIRO_INT_STATUS_UNSUPPORTED; @@ -776,7 +736,7 @@ _cairo_svg_surface_create_similar (void *abstract_src, static cairo_status_t _cairo_svg_surface_finish (void *abstract_surface) { - cairo_status_t status; + cairo_status_t status, status2; cairo_svg_surface_t *surface = abstract_surface; cairo_svg_document_t *document = surface->document; cairo_svg_page_t *page; @@ -787,11 +747,15 @@ _cairo_svg_surface_finish (void *abstract_surface) else status = CAIRO_STATUS_SUCCESS; - _cairo_output_stream_destroy (surface->xml_node); + status2 = _cairo_output_stream_destroy (surface->xml_node); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; for (i = 0; i < surface->page_set.num_elements; i++) { page = _cairo_array_index (&surface->page_set, i); - _cairo_output_stream_destroy (page->xml_node); + status2 = _cairo_output_stream_destroy (page->xml_node); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; } _cairo_array_fini (&surface->page_set); @@ -941,7 +905,9 @@ _cairo_svg_surface_emit_composite_image_pattern (cairo_output_stream_t *outp return status; p2u = pattern->base.matrix; - cairo_matrix_invert (&p2u); + status = cairo_matrix_invert (&p2u); + if (status) + return status; if (pattern_id != invalid_pattern_id) { _cairo_output_stream_printf (output, @@ -978,12 +944,14 @@ _cairo_svg_surface_emit_composite_image_pattern (cairo_output_stream_t *outp return status; } -static int +static cairo_status_t _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, - cairo_meta_surface_t *surface) + cairo_meta_surface_t *surface, + int *id) { + cairo_status_t status; cairo_surface_t *paginated_surface; - cairo_surface_t *svg_surface; + cairo_svg_surface_t *svg_surface; cairo_meta_snapshot_t new_snapshot; cairo_array_t *page_set; @@ -991,7 +959,7 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, cairo_meta_surface_t *meta; cairo_meta_snapshot_t *snapshot; unsigned int num_elements; - unsigned int i, id; + unsigned int i; /* search in already emitted meta snapshots */ num_elements = document->meta_snapshots.num_elements; @@ -1000,7 +968,8 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, meta = snapshot->meta; if (meta->commands.num_elements == surface->commands.num_elements && _cairo_array_index (&meta->commands, 0) == _cairo_array_index (&surface->commands, 0)) { - return snapshot->id; + *id = snapshot->id; + return CAIRO_STATUS_SUCCESS; } } @@ -1009,16 +978,41 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, meta->content, meta->width_pixels, meta->height_pixels); - svg_surface = _cairo_paginated_surface_get_target (paginated_surface); + svg_surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (paginated_surface); cairo_surface_set_fallback_resolution (paginated_surface, document->owner->x_fallback_resolution, document->owner->y_fallback_resolution); - _cairo_meta_surface_replay ((cairo_surface_t *)meta, paginated_surface); - _cairo_surface_show_page (paginated_surface); + + status = _cairo_meta_surface_replay ((cairo_surface_t *)meta, paginated_surface); + if (status) { + cairo_surface_destroy (&meta->base); + return status; + } + + status = _cairo_surface_show_page (paginated_surface); + if (status) { + cairo_surface_destroy (&meta->base); + return status; + } new_snapshot.meta = meta; - new_snapshot.id = ((cairo_svg_surface_t *) svg_surface)->id; - _cairo_array_append (&document->meta_snapshots, &new_snapshot); + new_snapshot.id = svg_surface->id; + status = _cairo_array_append (&document->meta_snapshots, &new_snapshot); + if (status) { + cairo_surface_destroy (&meta->base); + return status; + } + + if (!svg_surface->is_base_clip_emitted) { + svg_surface->is_base_clip_emitted = TRUE; + _cairo_output_stream_printf (document->xml_node_defs, + "\n" + " \n" + "\n", + svg_surface->base_clip, + svg_surface->width, + svg_surface->height); + } if (meta->content == CAIRO_CONTENT_ALPHA) { _cairo_svg_surface_emit_alpha_filter (document); @@ -1026,21 +1020,21 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, "\n", - ((cairo_svg_surface_t *) svg_surface)->id, - ((cairo_svg_surface_t *) svg_surface)->base_clip); + svg_surface->id, + svg_surface->base_clip); } else { _cairo_output_stream_printf (document->xml_node_defs, "\n", - ((cairo_svg_surface_t *) svg_surface)->id, - ((cairo_svg_surface_t *) svg_surface)->base_clip); + svg_surface->id, + svg_surface->base_clip); } - contents = ((cairo_svg_surface_t *) svg_surface)->xml_node; - page_set = &((cairo_svg_surface_t *) svg_surface)->page_set; + contents = svg_surface->xml_node; + page_set = &svg_surface->page_set; if (_cairo_memory_stream_length (contents) > 0) - _cairo_svg_surface_store_page ((cairo_svg_surface_t *) svg_surface); + _cairo_svg_surface_store_page (svg_surface); if (page_set->num_elements > 0) { cairo_svg_page_t *page; @@ -1051,7 +1045,7 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, _cairo_output_stream_printf (document->xml_node_defs, "\n"); - id = new_snapshot.id; + *id = new_snapshot.id; cairo_surface_destroy (paginated_surface); @@ -1062,7 +1056,7 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, /* cairo_surface_destroy (svg_surface); */ - return id; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -1075,14 +1069,19 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output, cairo_svg_document_t *document = surface->document; cairo_meta_surface_t *meta_surface; cairo_matrix_t p2u; + cairo_status_t status; int id; + p2u = pattern->base.matrix; + status = cairo_matrix_invert (&p2u); + if (status) + return status; + meta_surface = (cairo_meta_surface_t *) pattern->surface; - id = _cairo_svg_surface_emit_meta_surface (document, meta_surface); - - p2u = pattern->base.matrix; - cairo_matrix_invert (&p2u); + status = _cairo_svg_surface_emit_meta_surface (document, meta_surface, &id); + if (status) + return status; if (pattern_id != invalid_pattern_id) { _cairo_output_stream_printf (output, @@ -1152,7 +1151,7 @@ _cairo_svg_surface_emit_operator (cairo_output_stream_t *output, _cairo_output_stream_printf (output, "comp-op: %s; ", op_str[op]); } -static void +static cairo_status_t _cairo_svg_surface_emit_solid_pattern (cairo_svg_surface_t *surface, cairo_solid_pattern_t *pattern, cairo_output_stream_t *style, @@ -1166,9 +1165,11 @@ _cairo_svg_surface_emit_solid_pattern (cairo_svg_surface_t *surface, pattern->color.green * 100.0, pattern->color.blue * 100.0, pattern->color.alpha); + + return CAIRO_STATUS_SUCCESS; } -static void +static cairo_status_t _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t *surface, cairo_surface_pattern_t *pattern, cairo_output_stream_t *style, @@ -1185,6 +1186,8 @@ _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t *surface, "%s: url(#pattern%d);", is_stroke ? "color" : "fill", pattern_id); + + return CAIRO_STATUS_SUCCESS; } static void @@ -1366,7 +1369,7 @@ _cairo_svg_surface_emit_pattern_extend (cairo_output_stream_t *output, } } -static void +static cairo_status_t _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface, cairo_linear_pattern_t *pattern, cairo_output_stream_t *style, @@ -1375,6 +1378,12 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface, cairo_svg_document_t *document = surface->document; double x0, y0, x1, y1; cairo_matrix_t p2u; + cairo_status_t status; + + p2u = pattern->base.base.matrix; + status = cairo_matrix_invert (&p2u); + if (status) + return status; x0 = _cairo_fixed_to_double (pattern->gradient.p1.x); y0 = _cairo_fixed_to_double (pattern->gradient.p1.y); @@ -1389,8 +1398,6 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface, x0, y0, x1, y1); _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base), - p2u = pattern->base.base.matrix; - cairo_matrix_invert (&p2u); _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u); _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs ,&pattern->base, 0.0, FALSE, FALSE); @@ -1404,9 +1411,11 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface, document->linear_pattern_id); document->linear_pattern_id++; + + return CAIRO_STATUS_SUCCESS; } -static void +static cairo_status_t _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface, cairo_radial_pattern_t *pattern, cairo_output_stream_t *style, @@ -1418,6 +1427,7 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface, double x0, y0, x1, y1, r0, r1; double fx, fy; cairo_bool_t reverse_stops; + cairo_status_t status; pixman_circle_t *c0, *c1; extend = pattern->base.base.extend; @@ -1440,7 +1450,9 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface, r1 = _cairo_fixed_to_double (c1->radius); p2u = pattern->base.base.matrix; - cairo_matrix_invert (&p2u); + status = cairo_matrix_invert (&p2u); + if (status) + return status; if (pattern->gradient.c1.radius == pattern->gradient.c2.radius) { _cairo_output_stream_printf (document->xml_node_defs, @@ -1571,29 +1583,28 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface, document->radial_pattern_id); document->radial_pattern_id++; + + return CAIRO_STATUS_SUCCESS; } -static void +static cairo_status_t _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: - _cairo_svg_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern, output, is_stroke); - break; + return _cairo_svg_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern, output, is_stroke); case CAIRO_PATTERN_TYPE_SURFACE: - _cairo_svg_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, output, is_stroke); - break; + return _cairo_svg_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, output, is_stroke); case CAIRO_PATTERN_TYPE_LINEAR: - _cairo_svg_surface_emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern, output, is_stroke); - break; + return _cairo_svg_surface_emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern, output, is_stroke); case CAIRO_PATTERN_TYPE_RADIAL: - _cairo_svg_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, output, is_stroke); - break; + return _cairo_svg_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, output, is_stroke); } + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t @@ -1611,7 +1622,7 @@ _cairo_svg_surface_fill (void *abstract_surface, if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _cairo_svg_surface_analyze_operation (surface, op, source); - assert (__cairo_svg_surface_operation_supported (surface, op, source)); + assert (_cairo_svg_surface_operation_supported (surface, op, source)); _cairo_output_stream_printf (surface->xml_node, "paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) @@ -1698,7 +1710,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 (__cairo_svg_surface_operation_supported (surface, op, source)); + assert (_cairo_svg_surface_operation_supported (surface, op, source)); */ /* Emulation of clear and source operators, when no clipping region @@ -1711,8 +1723,12 @@ _cairo_svg_surface_paint (void *abstract_surface, * and an optimiszation in meta surface. */ if (surface->clip_level == 0 && (op == CAIRO_OPERATOR_CLEAR || - op == CAIRO_OPERATOR_SOURCE)) { - _cairo_output_stream_destroy (surface->xml_node); + op == CAIRO_OPERATOR_SOURCE)) + { + status = _cairo_output_stream_destroy (surface->xml_node); + if (status) + return status; + surface->xml_node = _cairo_memory_stream_create (); if (op == CAIRO_OPERATOR_CLEAR) { @@ -1740,6 +1756,7 @@ _cairo_svg_surface_mask (void *abstract_surface, cairo_pattern_t *source, cairo_pattern_t *mask) { + cairo_status_t status; cairo_svg_surface_t *surface = abstract_surface; cairo_svg_document_t *document = surface->document; cairo_output_stream_t *mask_stream; @@ -1748,7 +1765,7 @@ _cairo_svg_surface_mask (void *abstract_surface, if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _cairo_svg_surface_analyze_operation (surface, op, source); - assert (__cairo_svg_surface_operation_supported (surface, op, source)); + assert (_cairo_svg_surface_operation_supported (surface, op, source)); _cairo_svg_surface_emit_alpha_filter (document); @@ -1765,7 +1782,10 @@ _cairo_svg_surface_mask (void *abstract_surface, " \n" "\n"); _cairo_memory_stream_copy (mask_stream, document->xml_node_defs); - _cairo_output_stream_destroy (mask_stream); + + status = _cairo_output_stream_destroy (mask_stream); + if (status) + return status; snprintf (buffer, sizeof buffer, "mask=\"url(#mask%d);\"", document->mask_id); @@ -1795,7 +1815,7 @@ _cairo_svg_surface_stroke (void *abstract_dst, if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _cairo_svg_surface_analyze_operation (surface, op, source); - assert (__cairo_svg_surface_operation_supported (surface, op, source)); + assert (_cairo_svg_surface_operation_supported (surface, op, source)); switch (stroke_style->line_cap) { case CAIRO_LINE_CAP_BUTT: @@ -1877,13 +1897,13 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, cairo_svg_document_t *document = surface->document; cairo_path_fixed_t path; cairo_status_t status; - unsigned int font_id, subset_id, subset_glyph_index; + cairo_scaled_font_subsets_glyph_t subset_glyph; int i; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _cairo_svg_surface_analyze_operation (surface, op, pattern); - assert (__cairo_svg_surface_operation_supported (surface, op, pattern)); + assert (_cairo_svg_surface_operation_supported (surface, op, pattern)); if (num_glyphs <= 0) return CAIRO_STATUS_SUCCESS; @@ -1901,7 +1921,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, for (i = 0; i < num_glyphs; i++) { status = _cairo_scaled_font_subsets_map_glyph (document->font_subsets, scaled_font, glyphs[i].index, - &font_id, &subset_id, &subset_glyph_index); + &subset_glyph); if (status) { glyphs += i; num_glyphs -= i; @@ -1911,7 +1931,8 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, _cairo_output_stream_printf (surface->xml_node, " \n", - font_id, subset_glyph_index, + subset_glyph.font_id, + subset_glyph.subset_glyph_index, glyphs[i].x, glyphs[i].y); } @@ -2034,7 +2055,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, INT_MAX); + document->font_subsets = _cairo_scaled_font_subsets_create_scaled (); if (document->font_subsets == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); free (document); @@ -2092,7 +2113,7 @@ _cairo_svg_document_destroy (cairo_svg_document_t *document) static cairo_status_t _cairo_svg_document_finish (cairo_svg_document_t *document) { - cairo_status_t status; + cairo_status_t status, status2; cairo_output_stream_t *output = document->output_stream; cairo_meta_snapshot_t *snapshot; cairo_svg_surface_t *surface; @@ -2112,7 +2133,10 @@ _cairo_svg_document_finish (cairo_svg_document_t *document) document->width, document->height, _cairo_svg_internal_version_strings [document->svg_version]); - _cairo_svg_document_emit_font_subsets (document); + status = _cairo_svg_document_emit_font_subsets (document); + if (status) + return status; + if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0 || _cairo_memory_stream_length (document->xml_node_defs) > 0) { _cairo_output_stream_printf (output, "\n"); @@ -2136,10 +2160,8 @@ _cairo_svg_document_finish (cairo_svg_document_t *document) page = _cairo_array_index (&surface->page_set, i); _cairo_output_stream_printf (output, "\n"); _cairo_output_stream_printf (output, - "\n", - page->surface_id, - page->clip_id); + "\n", + page->surface_id); _cairo_memory_stream_copy (page->xml_node, output); _cairo_output_stream_printf (output, "\n\n"); } @@ -2147,20 +2169,23 @@ _cairo_svg_document_finish (cairo_svg_document_t *document) } else if (surface->page_set.num_elements > 0) { page = _cairo_array_index (&surface->page_set, surface->page_set.num_elements - 1); _cairo_output_stream_printf (output, - "\n", - page->surface_id, - page->clip_id); + "\n", + page->surface_id); _cairo_memory_stream_copy (page->xml_node, output); _cairo_output_stream_printf (output, "\n"); } _cairo_output_stream_printf (output, "\n"); - _cairo_output_stream_destroy (document->xml_node_glyphs); - _cairo_output_stream_destroy (document->xml_node_defs); + status = _cairo_output_stream_destroy (document->xml_node_glyphs); - status = _cairo_output_stream_destroy (output); + status2 = _cairo_output_stream_destroy (document->xml_node_defs); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + status2 = _cairo_output_stream_destroy (output); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; for (i = 0; i < document->meta_snapshots.num_elements; i++) { snapshot = _cairo_array_index (&document->meta_snapshots, i); diff --git a/gfx/cairo/cairo/src/cairo-traps.c b/gfx/cairo/cairo/src/cairo-traps.c index 062768304b26..f7171ddadf92 100644 --- a/gfx/cairo/cairo/src/cairo-traps.c +++ b/gfx/cairo/cairo/src/cairo-traps.c @@ -43,7 +43,7 @@ static cairo_status_t _cairo_traps_grow (cairo_traps_t *traps); -static cairo_status_t +static void _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom, cairo_line_t *left, cairo_line_t *right); @@ -57,10 +57,21 @@ _cairo_traps_init (cairo_traps_t *traps) traps->num_traps = 0; - traps->traps_size = 0; - traps->traps = NULL; + traps->traps_size = ARRAY_LENGTH (traps->traps_embedded); + traps->traps = traps->traps_embedded; traps->extents.p1.x = traps->extents.p1.y = INT32_MAX; traps->extents.p2.x = traps->extents.p2.y = INT32_MIN; + + traps->has_limits = FALSE; +} + +void +_cairo_traps_limit (cairo_traps_t *traps, + cairo_box_t *limits) +{ + traps->has_limits = TRUE; + + traps->limits = *limits; } void @@ -87,45 +98,104 @@ cairo_status_t _cairo_traps_init_box (cairo_traps_t *traps, cairo_box_t *box) { - _cairo_traps_init (traps); + _cairo_traps_init (traps); + + assert (traps->traps_size >= 1); + + traps->num_traps = 1; + + traps->traps[0].top = box->p1.y; + traps->traps[0].bottom = box->p2.y; + traps->traps[0].left.p1 = box->p1; + traps->traps[0].left.p2.x = box->p1.x; + traps->traps[0].left.p2.y = box->p2.y; + traps->traps[0].right.p1.x = box->p2.x; + traps->traps[0].right.p1.y = box->p1.y; + traps->traps[0].right.p2 = box->p2; + + traps->extents = *box; - traps->status = _cairo_traps_grow (traps); - if (traps->status) return traps->status; - - traps->num_traps = 1; - - traps->traps[0].top = box->p1.y; - traps->traps[0].bottom = box->p2.y; - traps->traps[0].left.p1 = box->p1; - traps->traps[0].left.p2.x = box->p1.x; - traps->traps[0].left.p2.y = box->p2.y; - traps->traps[0].right.p1.x = box->p2.x; - traps->traps[0].right.p1.y = box->p1.y; - traps->traps[0].right.p2 = box->p2; - - traps->extents = *box; - - return traps->status; } -static cairo_status_t +cairo_status_t +_cairo_traps_status (cairo_traps_t *traps) +{ + return traps->status; +} + +static void _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom, cairo_line_t *left, cairo_line_t *right) { cairo_trapezoid_t *trap; if (traps->status) - return traps->status; + return; - if (top == bottom) { - return CAIRO_STATUS_SUCCESS; + /* Note: With the goofy trapezoid specification, (where an + * arbitrary two points on the lines can specified for the left + * and right edges), these limit checks would not work in + * general. For example, one can imagine a trapezoid entirely + * within the limits, but with two points used to specify the left + * edge entirely to the right of the limits. Fortunately, for our + * purposes, cairo will never generate such a crazy + * trapezoid. Instead, cairo always uses for its points the + * extreme positions of the edge that are visible on at least some + * trapezoid. With this constraint, it's impossible for both + * points to be outside the limits while the relevant edge is + * entirely inside the limits. + */ + if (traps->has_limits) { + /* Trivially reject if trapezoid is entirely to the right or + * to the left of the limits. */ + if (left->p1.x >= traps->limits.p2.x && + left->p2.x >= traps->limits.p2.x) + { + return; + } + + if (right->p1.x <= traps->limits.p1.x && + right->p2.x <= traps->limits.p1.x) + { + return; + } + + /* Otherwise, clip the trapezoid to the limits. We only clip + * where an edge is entirely outside the limits. If we wanted + * to be more clever, we could handle cases where a trapezoid + * edge intersects the edge of the limits, but that would + * require slicing this trapezoid into multiple trapezoids, + * and I'm not sure the effort would be worth it. */ + if (top < traps->limits.p1.y) + top = traps->limits.p1.y; + + if (bottom > traps->limits.p2.y) + bottom = traps->limits.p2.y; + + if (left->p1.x < traps->limits.p1.x && + left->p2.x < traps->limits.p1.x) + { + left->p1.x = traps->limits.p1.x; + left->p2.x = traps->limits.p1.x; + } + + if (right->p1.x > traps->limits.p2.x && + right->p2.x > traps->limits.p2.x) + { + right->p1.x = traps->limits.p2.x; + right->p2.x = traps->limits.p2.x; + } + } + + if (top >= bottom) { + return; } if (traps->num_traps >= traps->traps_size) { traps->status = _cairo_traps_grow (traps); if (traps->status) - return traps->status; + return; } trap = &traps->traps[traps->num_traps]; @@ -157,11 +227,9 @@ _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bo traps->extents.p2.x = right->p2.x; traps->num_traps++; - - return traps->status; } -cairo_status_t +void _cairo_traps_add_trap_from_points (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom, cairo_point_t left_p1, cairo_point_t left_p2, cairo_point_t right_p1, cairo_point_t right_p2) @@ -170,7 +238,7 @@ _cairo_traps_add_trap_from_points (cairo_traps_t *traps, cairo_fixed_t top, cair cairo_line_t right; if (traps->status) - return traps->status; + return; left.p1 = left_p1; left.p2 = left_p2; @@ -178,7 +246,7 @@ _cairo_traps_add_trap_from_points (cairo_traps_t *traps, cairo_fixed_t top, cair right.p1 = right_p1; right.p2 = right_p2; - return _cairo_traps_add_trap (traps, top, bottom, &left, &right); + _cairo_traps_add_trap (traps, top, bottom, &left, &right); } /* make room for at least one more trap */ @@ -186,19 +254,7 @@ static cairo_status_t _cairo_traps_grow (cairo_traps_t *traps) { cairo_trapezoid_t *new_traps; - int old_size = traps->traps_size; - 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); + int new_size = 2 * MAX (traps->traps_size, 16); if (traps->status) return traps->status; @@ -206,7 +262,7 @@ _cairo_traps_grow (cairo_traps_t *traps) 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)); + memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded)); } else { new_traps = realloc (traps->traps, new_size * sizeof (cairo_trapezoid_t)); } @@ -219,7 +275,7 @@ _cairo_traps_grow (cairo_traps_t *traps) traps->traps = new_traps; traps->traps_size = new_size; - return traps->status; + return CAIRO_STATUS_SUCCESS; } static int @@ -534,22 +590,15 @@ _cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents) * Determines if a set of trapezoids are exactly representable as a * pixman region, and if so creates such a region. * - * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED + * or %CAIRO_STATUS_NO_MEMORY **/ -cairo_status_t -_cairo_traps_extract_region (cairo_traps_t *traps, - pixman_region16_t **region) +cairo_int_status_t +_cairo_traps_extract_region (cairo_traps_t *traps, + pixman_region16_t *region) { int i; - /* Bail early if we have lots of traps, until we fix the code - * below to not use Union() - */ - if (traps->num_traps > 200) { - *region = NULL; - return CAIRO_STATUS_SUCCESS; - } - for (i = 0; i < traps->num_traps; i++) if (!(traps->traps[i].left.p1.x == traps->traps[i].left.p2.x && traps->traps[i].right.p1.x == traps->traps[i].right.p2.x @@ -557,11 +606,10 @@ _cairo_traps_extract_region (cairo_traps_t *traps, && _cairo_fixed_is_integer(traps->traps[i].bottom) && _cairo_fixed_is_integer(traps->traps[i].left.p1.x) && _cairo_fixed_is_integer(traps->traps[i].right.p1.x))) { - *region = NULL; - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_UNSUPPORTED; } - *region = pixman_region_create (); + pixman_region_init (region); for (i = 0; i < traps->num_traps; i++) { int x = _cairo_fixed_integer_part(traps->traps[i].left.p1.x); @@ -576,9 +624,9 @@ _cairo_traps_extract_region (cairo_traps_t *traps, if (width == 0 || height == 0) continue; - if (pixman_region_union_rect (*region, *region, + if (pixman_region_union_rect (region, region, x, y, width, height) != PIXMAN_REGION_STATUS_SUCCESS) { - pixman_region_destroy (*region); + pixman_region_fini (region); return CAIRO_STATUS_NO_MEMORY; } } diff --git a/gfx/cairo/cairo/src/cairo-truetype-subset.c b/gfx/cairo/cairo/src/cairo-truetype-subset.c index 7e77bb8aaae0..7f168a5352ab 100644 --- a/gfx/cairo/cairo/src/cairo-truetype-subset.c +++ b/gfx/cairo/cairo/src/cairo-truetype-subset.c @@ -34,8 +34,8 @@ * Adrian Johnson */ -#include #include "cairoint.h" + #include "cairo-scaled-font-subsets-private.h" #include "cairo-truetype-subset-private.h" @@ -75,8 +75,6 @@ typedef struct _cairo_truetype_font { static int cairo_truetype_font_use_glyph (cairo_truetype_font_t *font, int glyph); -#define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) ) - #define SFNT_VERSION 0x00010000 #define SFNT_STRING_MAX_LENGTH 65535 @@ -84,7 +82,7 @@ static cairo_status_t _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, cairo_truetype_font_t **font_return) { - cairo_status_t status = CAIRO_STATUS_NO_MEMORY; + cairo_status_t status; cairo_truetype_font_t *font; const cairo_scaled_font_backend_t *backend; tt_head_t head; @@ -131,16 +129,22 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, TT_TAG_name, 0, NULL, &size) != CAIRO_STATUS_SUCCESS) return CAIRO_INT_STATUS_UNSUPPORTED; + name = malloc(size); if (name == NULL) return CAIRO_STATUS_NO_MEMORY; - backend->load_truetype_table (scaled_font_subset->scaled_font, - TT_TAG_name, 0, (unsigned char *) name, - &size); + + status = backend->load_truetype_table (scaled_font_subset->scaled_font, + TT_TAG_name, 0, (unsigned char *) name, + &size); + if (status) + goto fail0; font = malloc (sizeof (cairo_truetype_font_t)); - if (font == NULL) + if (font == NULL) { + status = CAIRO_STATUS_NO_MEMORY; goto fail0; + } font->backend = backend; font->num_glyphs_in_face = be16_to_cpu (maxp.num_glyphs); @@ -149,15 +153,21 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, font->last_offset = 0; font->last_boundary = 0; _cairo_array_init (&font->output, sizeof (char)); - if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS) + status = _cairo_array_grow_by (&font->output, 4096); + if (status) goto fail1; + font->glyphs = calloc (font->num_glyphs_in_face + 1, sizeof (subset_glyph_t)); - if (font->glyphs == NULL) - goto fail2; + if (font->glyphs == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail1; + } font->parent_to_subset = calloc (font->num_glyphs_in_face, sizeof (int)); - if (font->parent_to_subset == NULL) - goto fail3; + if (font->parent_to_subset == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail2; + } font->base.num_glyphs = 0; font->base.x_min = (int16_t) be16_to_cpu (head.x_min); @@ -198,8 +208,11 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, if (font->base.base_font == NULL) { font->base.base_font = malloc (30); - if (font->base.base_font == NULL) - goto fail4; + if (font->base.base_font == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail3; + } + snprintf(font->base.base_font, 30, "CairoFont-%u-%u", scaled_font_subset->font_id, scaled_font_subset->subset_id); @@ -213,12 +226,15 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, font->base.base_font[i] = '\0'; font->base.widths = calloc (font->num_glyphs_in_face, sizeof (int)); - if (font->base.widths == NULL) - goto fail5; + if (font->base.widths == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail4; + } _cairo_array_init (&font->string_offsets, sizeof (unsigned long)); - if (_cairo_array_grow_by (&font->string_offsets, 10) != CAIRO_STATUS_SUCCESS) - goto fail6; + status = _cairo_array_grow_by (&font->string_offsets, 10); + if (status) + goto fail5; font->status = CAIRO_STATUS_SUCCESS; @@ -226,21 +242,22 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, return CAIRO_STATUS_SUCCESS; - fail6: - free (font->base.widths); fail5: - free (font->base.base_font); + _cairo_array_fini (&font->string_offsets); + free (font->base.widths); fail4: - free (font->parent_to_subset); + free (font->base.base_font); fail3: - free (font->glyphs); + free (font->parent_to_subset); fail2: - _cairo_array_fini (&font->output); + free (font->glyphs); fail1: + _cairo_array_fini (&font->output); free (font); fail0: if (name) free (name); + return status; } @@ -322,19 +339,27 @@ cairo_truetype_font_align_output (cairo_truetype_font_t *font) return aligned; } -static void +static cairo_status_t cairo_truetype_font_check_boundary (cairo_truetype_font_t *font, unsigned long boundary) { + cairo_status_t status; + if (boundary - font->last_offset > SFNT_STRING_MAX_LENGTH) { - _cairo_array_append(&font->string_offsets, &font->last_boundary); + status = _cairo_array_append (&font->string_offsets, + &font->last_boundary); + if (status) + return status; + font->last_offset = font->last_boundary; } font->last_boundary = boundary; + + return CAIRO_STATUS_SUCCESS; } -static int +static cairo_status_t cairo_truetype_font_write_cmap_table (cairo_truetype_font_t *font, unsigned long tag) { @@ -360,12 +385,12 @@ cairo_truetype_font_write_cmap_table (cairo_truetype_font_t *font, 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, 0xf000 + font->base.num_glyphs - 1); /* 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, 0x1000); /* 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] */ @@ -373,17 +398,17 @@ cairo_truetype_font_write_cmap_table (cairo_truetype_font_t *font, /* 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, 10 + 2 * font->base.num_glyphs); cairo_truetype_font_write_be16 (font, 0); 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); + cairo_truetype_font_write_be16 (font, i); return font->status; } -static int +static cairo_status_t cairo_truetype_font_write_generic_table (cairo_truetype_font_t *font, unsigned long tag) { @@ -397,11 +422,17 @@ cairo_truetype_font_write_generic_table (cairo_truetype_font_t *font, font->status = CAIRO_INT_STATUS_UNSUPPORTED; return font->status; } + status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer); - /* XXX: Need to check status here. */ - font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, - tag, 0, buffer, &size); - return 0; + if (status) + return status; + + status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + tag, 0, buffer, &size); + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; } static void @@ -438,11 +469,10 @@ cairo_truetype_font_remap_composite_glyph (cairo_truetype_font_t *font, } while (has_more_components); } -static int +static cairo_status_t cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font, unsigned long tag) { - cairo_status_t status; unsigned long start_offset, index, size, next; tt_head_t header; unsigned long begin, end; @@ -455,8 +485,11 @@ cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font, } u; size = sizeof (tt_head_t); - font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, - TT_TAG_head, 0, (unsigned char*) &header, &size); + font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_head, 0, + (unsigned char*) &header, &size); + if (font->status) + return font->status; if (be16_to_cpu (header.index_to_loc_format) == 0) size = sizeof (int16_t) * (font->num_glyphs_in_face + 1); @@ -468,6 +501,7 @@ cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font, font->status = CAIRO_STATUS_NO_MEMORY; return font->status; } + if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, TT_TAG_loca, 0, u.bytes, &size) != CAIRO_STATUS_SUCCESS) { font->status = CAIRO_INT_STATUS_UNSUPPORTED; @@ -489,15 +523,23 @@ cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font, size = end - begin; next = cairo_truetype_font_align_output (font); - cairo_truetype_font_check_boundary (font, next); + + font->status = cairo_truetype_font_check_boundary (font, next); + if (font->status) + break; + font->glyphs[i].location = next - start_offset; - status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer); - if (status) + font->status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer); + if (font->status) break; + if (size != 0) { - font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, - TT_TAG_glyf, begin, buffer, &size); + font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_glyf, begin, buffer, &size); + if (font->status) + break; + cairo_truetype_font_remap_composite_glyph (font, buffer); } } @@ -510,7 +552,7 @@ cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font, return font->status; } -static int +static cairo_status_t cairo_truetype_font_write_head_table (cairo_truetype_font_t *font, unsigned long tag) { @@ -518,36 +560,52 @@ cairo_truetype_font_write_head_table (cairo_truetype_font_t *font, unsigned long size; size = 0; - font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, - tag, 0, NULL, &size); + font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + tag, 0, NULL, &size); + if (font->status) + return font->status; + font->checksum_index = _cairo_array_num_elements (&font->output) + 8; 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); + if (font->status) + return font->status; + + font->status = font->backend->load_truetype_table( font->scaled_font_subset->scaled_font, + tag, 0, buffer, &size); + if (font->status) + return font->status; + /* set checkSumAdjustment to 0 for table checksum calcualtion */ *(uint32_t *)(buffer + 8) = 0; return font->status; } -static int cairo_truetype_font_write_hhea_table (cairo_truetype_font_t *font, unsigned long tag) +static cairo_status_t +cairo_truetype_font_write_hhea_table (cairo_truetype_font_t *font, unsigned long tag) { tt_hhea_t *hhea; unsigned long size; size = sizeof (tt_hhea_t); font->status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &hhea); - font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, - tag, 0, (unsigned char *) hhea, &size); + if (font->status) + return font->status; + + font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + tag, 0, (unsigned char *) hhea, &size); + if (font->status) + return font->status; + hhea->num_hmetrics = cpu_to_be16 ((uint16_t)(font->base.num_glyphs)); + return font->status; } -static int +static cairo_status_t cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font, unsigned long tag) { - cairo_status_t status; unsigned long size; unsigned long long_entry_size; unsigned long short_entry_size; @@ -557,15 +615,22 @@ cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font, int num_hmetrics; size = sizeof (tt_hhea_t); - font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, - TT_TAG_hhea, 0, (unsigned char*) &hhea, &size); + font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_hhea, 0, + (unsigned char*) &hhea, &size); + if (font->status) + return font->status; + num_hmetrics = be16_to_cpu(hhea.num_hmetrics); for (i = 0; i < font->base.num_glyphs; i++) { long_entry_size = 2 * sizeof (int16_t); short_entry_size = sizeof (int16_t); - status = cairo_truetype_font_allocate_write_buffer (font, long_entry_size, - (unsigned char **) &p); + font->status = cairo_truetype_font_allocate_write_buffer (font, long_entry_size, + (unsigned char **) &p); + if (font->status) + return font->status; + if (font->glyphs[i].parent_index < num_hmetrics) { if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, TT_TAG_hmtx, @@ -584,11 +649,13 @@ cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font, font->status = CAIRO_INT_STATUS_UNSUPPORTED; return font->status; } - font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, - TT_TAG_hmtx, - num_hmetrics * long_entry_size + - (font->glyphs[i].parent_index - num_hmetrics) * short_entry_size, - (unsigned char *) (p + 1), &short_entry_size); + font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_hmtx, + num_hmetrics * long_entry_size + + (font->glyphs[i].parent_index - num_hmetrics) * short_entry_size, + (unsigned char *) (p + 1), &short_entry_size); + if (font->status) + return font->status; } font->base.widths[i] = be16_to_cpu (p[0]); } @@ -596,7 +663,7 @@ cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font, return font->status; } -static int +static cairo_status_t cairo_truetype_font_write_loca_table (cairo_truetype_font_t *font, unsigned long tag) { @@ -605,8 +672,11 @@ cairo_truetype_font_write_loca_table (cairo_truetype_font_t *font, unsigned long size; size = sizeof(tt_head_t); - font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, - TT_TAG_head, 0, (unsigned char*) &header, &size); + font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_head, 0, + (unsigned char*) &header, &size); + if (font->status) + return font->status; if (be16_to_cpu (header.index_to_loc_format) == 0) { @@ -620,7 +690,7 @@ cairo_truetype_font_write_loca_table (cairo_truetype_font_t *font, return font->status; } -static int +static cairo_status_t cairo_truetype_font_write_maxp_table (cairo_truetype_font_t *font, unsigned long tag) { @@ -629,39 +699,15 @@ cairo_truetype_font_write_maxp_table (cairo_truetype_font_t *font, size = sizeof (tt_maxp_t); font->status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &maxp); - font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, - tag, 0, (unsigned char *) maxp, &size); + if (font->status) + return font->status; + + font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + tag, 0, (unsigned char *) maxp, &size); + if (font->status) + return font->status; + maxp->num_glyphs = cpu_to_be16 (font->base.num_glyphs); - 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; } @@ -669,7 +715,7 @@ cairo_truetype_font_write_post_table (cairo_truetype_font_t *font, typedef struct table table_t; struct table { unsigned long tag; - int (*write) (cairo_truetype_font_t *font, unsigned long tag); + cairo_status_t (*write) (cairo_truetype_font_t *font, unsigned long tag); int pos; /* position in the font directory */ }; @@ -692,8 +738,7 @@ static const table_t truetype_tables[] = { { 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 }, + { TT_TAG_prep, cairo_truetype_font_write_generic_table, 10 }, }; static cairo_status_t @@ -776,6 +821,7 @@ cairo_truetype_font_generate (cairo_truetype_font_t *font, const unsigned long **string_offsets, unsigned long *num_strings) { + cairo_status_t status; unsigned long start, end, next; uint32_t checksum, *checksum_location; unsigned int i; @@ -795,7 +841,12 @@ cairo_truetype_font_generate (cairo_truetype_font_t *font, next = cairo_truetype_font_align_output (font); cairo_truetype_font_update_entry (font, truetype_tables[i].pos, truetype_tables[i].tag, start, end); - cairo_truetype_font_check_boundary (font, next); + status = cairo_truetype_font_check_boundary (font, next); + if (status) { + font->status = status; + goto fail; + } + start = next; } @@ -832,7 +883,7 @@ cairo_status_t _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset, cairo_scaled_font_subset_t *font_subset) { - cairo_truetype_font_t *font; + cairo_truetype_font_t *font = NULL; cairo_status_t status; const char *data = NULL; /* squelch bogus compiler warning */ unsigned long length = 0; /* squelch bogus compiler warning */ @@ -845,10 +896,6 @@ _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); @@ -860,19 +907,22 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset, goto fail1; truetype_subset->base_font = strdup (font->base.base_font); - if (truetype_subset->base_font == NULL) + if (truetype_subset->base_font == NULL) { + status = CAIRO_STATUS_NO_MEMORY; goto fail1; + } - /* 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. */ + /* The widths array returned must contain only widths for the + * glyphs in font_subset. 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) + if (truetype_subset->widths == NULL) { + status = CAIRO_STATUS_NO_MEMORY; goto fail2; + } 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->widths[i] = (double)font->base.widths[i]/font->base.units_per_em; 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; @@ -882,19 +932,28 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset, truetype_subset->descent = (double)font->base.descent/font->base.units_per_em; truetype_subset->data = malloc (length); - if (truetype_subset->data == NULL) + if (truetype_subset->data == NULL) { + status = CAIRO_STATUS_NO_MEMORY; goto fail3; + } memcpy (truetype_subset->data, data, length); truetype_subset->data_length = length; - offsets_length = num_strings * sizeof (unsigned long); - truetype_subset->string_offsets = malloc (offsets_length); - if (truetype_subset->string_offsets == NULL) - goto fail4; + if (num_strings) { + offsets_length = num_strings * sizeof (unsigned long); + truetype_subset->string_offsets = malloc (offsets_length); + if (truetype_subset->string_offsets == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail4; + } - memcpy (truetype_subset->string_offsets, string_offsets, offsets_length); - truetype_subset->num_string_offsets = num_strings; + memcpy (truetype_subset->string_offsets, string_offsets, offsets_length); + truetype_subset->num_string_offsets = num_strings; + } else { + truetype_subset->string_offsets = NULL; + truetype_subset->num_string_offsets = 0; + } cairo_truetype_font_destroy (font); diff --git a/gfx/cairo/cairo/src/cairo-type1-fallback.c b/gfx/cairo/cairo/src/cairo-type1-fallback.c index a183b28b4973..387277785ac7 100644 --- a/gfx/cairo/cairo/src/cairo-type1-fallback.c +++ b/gfx/cairo/cairo/src/cairo-type1-fallback.c @@ -39,6 +39,11 @@ #include "cairo-path-fixed-private.h" #include "cairo-output-stream-private.h" +typedef enum { + CAIRO_CHARSTRING_TYPE1, + CAIRO_CHARSTRING_TYPE2, +} cairo_charstring_type_t; + typedef struct _cairo_type1_font { int *widths; @@ -90,7 +95,7 @@ cairo_type1_font_create (cairo_scaled_font_subset_t *scaled_font_subset, font_face = cairo_scaled_font_get_font_face (scaled_font_subset->scaled_font); - cairo_matrix_init_scale (&font_matrix, 1000, 1000); + cairo_matrix_init_scale (&font_matrix, 1000, -1000); cairo_matrix_init_identity (&ctm); _cairo_font_options_init_default (&font_options); @@ -101,7 +106,7 @@ cairo_type1_font_create (cairo_scaled_font_subset_t *scaled_font_subset, &font_matrix, &ctm, &font_options); - if (font->type1_scaled_font == NULL) + if (font->type1_scaled_font->status) goto fail; _cairo_array_init (&font->contents, sizeof (unsigned char)); @@ -156,7 +161,9 @@ charstring_encode_command (cairo_array_t *data, int command) * bytes that will be used is 5. */ static void -charstring_encode_integer (cairo_array_t *data, int i) +charstring_encode_integer (cairo_array_t *data, + int i, + cairo_charstring_type_t type) { cairo_status_t status; int orig_size; @@ -174,11 +181,19 @@ charstring_encode_integer (cairo_array_t *data, int i) *p++ = (i >> 8)+ 251; *p++ = i & 0xff; } else { - *p++ = 0xff; - *p++ = i >> 24; - *p++ = (i >> 16) & 0xff; - *p++ = (i >> 8) & 0xff; - *p++ = i & 0xff; + if (type == CAIRO_CHARSTRING_TYPE1) { + *p++ = 0xff; + *p++ = i >> 24; + *p++ = (i >> 16) & 0xff; + *p++ = (i >> 8) & 0xff; + *p++ = i & 0xff; + } else { + *p++ = 0xff; + *p++ = (i >> 8) & 0xff; + *p++ = i & 0xff; + *p++ = 0; + *p++ = 0; + } } /* Ensure the array doesn't grow, which allows this function to @@ -193,6 +208,7 @@ charstring_encode_integer (cairo_array_t *data, int i) typedef struct _ps_path_info { cairo_array_t *data; int current_x, current_y; + cairo_charstring_type_t type; } t1_path_info_t; static cairo_status_t @@ -209,8 +225,8 @@ _charstring_move_to (void *closure, dx = _cairo_fixed_integer_part (point->x) - path_info->current_x; dy = _cairo_fixed_integer_part (point->y) - path_info->current_y; - charstring_encode_integer (path_info->data, dx); - charstring_encode_integer (path_info->data, dy); + charstring_encode_integer (path_info->data, dx, path_info->type); + charstring_encode_integer (path_info->data, dy, path_info->type); path_info->current_x += dx; path_info->current_y += dy; @@ -233,8 +249,8 @@ _charstring_line_to (void *closure, dx = _cairo_fixed_integer_part (point->x) - path_info->current_x; dy = _cairo_fixed_integer_part (point->y) - path_info->current_y; - charstring_encode_integer (path_info->data, dx); - charstring_encode_integer (path_info->data, dy); + charstring_encode_integer (path_info->data, dx, path_info->type); + charstring_encode_integer (path_info->data, dy, path_info->type); path_info->current_x += dx; path_info->current_y += dy; @@ -263,12 +279,12 @@ _charstring_curve_to (void *closure, dy2 = _cairo_fixed_integer_part (point2->y) - path_info->current_y - dy1; dx3 = _cairo_fixed_integer_part (point3->x) - path_info->current_x - dx1 - dx2; dy3 = _cairo_fixed_integer_part (point3->y) - path_info->current_y - dy1 - dy2; - charstring_encode_integer (path_info->data, dx1); - charstring_encode_integer (path_info->data, dy1); - charstring_encode_integer (path_info->data, dx2); - charstring_encode_integer (path_info->data, dy2); - charstring_encode_integer (path_info->data, dx3); - charstring_encode_integer (path_info->data, dy3); + charstring_encode_integer (path_info->data, dx1, path_info->type); + charstring_encode_integer (path_info->data, dy1, path_info->type); + charstring_encode_integer (path_info->data, dx2, path_info->type); + charstring_encode_integer (path_info->data, dy2, path_info->type); + charstring_encode_integer (path_info->data, dx3, path_info->type); + charstring_encode_integer (path_info->data, dy3, path_info->type); path_info->current_x += dx1 + dx2 + dx3; path_info->current_y += dy1 + dy2 + dy3; charstring_encode_command (path_info->data, CHARSTRING_rcurveto); @@ -282,6 +298,9 @@ _charstring_close_path (void *closure) cairo_status_t status; t1_path_info_t *path_info = (t1_path_info_t *) closure; + if (path_info->type == CAIRO_CHARSTRING_TYPE2) + return CAIRO_STATUS_SUCCESS; + status = _cairo_array_grow_by (path_info->data, 2); if (status) return status; @@ -309,7 +328,7 @@ charstring_encrypt (cairo_array_t *data) } static cairo_int_status_t -create_notdef_charstring (cairo_array_t *data) +create_notdef_charstring (cairo_array_t *data, cairo_charstring_type_t type) { cairo_status_t status; @@ -320,13 +339,15 @@ create_notdef_charstring (cairo_array_t *data) if (status) return status; - charstring_encode_integer (data, 0); - charstring_encode_integer (data, 0); + if (type == CAIRO_CHARSTRING_TYPE1) { + charstring_encode_integer (data, 0, type); + charstring_encode_integer (data, 0, type); - /* The width and height is arbitrary. */ - charstring_encode_integer (data, 500); - charstring_encode_integer (data, 500); - charstring_encode_command (data, CHARSTRING_sbw); + /* The width and height is arbitrary. */ + charstring_encode_integer (data, 500, type); + charstring_encode_integer (data, 500, type); + charstring_encode_command (data, CHARSTRING_sbw); + } charstring_encode_command (data, CHARSTRING_endchar); @@ -334,10 +355,11 @@ create_notdef_charstring (cairo_array_t *data) } static cairo_int_status_t -cairo_type1_font_create_charstring (cairo_type1_font_t *font, - int subset_index, - int glyph_index, - cairo_array_t *data) +cairo_type1_font_create_charstring (cairo_type1_font_t *font, + int subset_index, + int glyph_index, + cairo_charstring_type_t type, + cairo_array_t *data) { cairo_int_status_t status; cairo_scaled_glyph_t *scaled_glyph; @@ -369,21 +391,29 @@ cairo_type1_font_create_charstring (cairo_type1_font_t *font, if (metrics->y_bearing + metrics->height > font->y_max) font->y_max = metrics->y_bearing + metrics->height; } - font->widths[subset_index] = metrics->width; + font->widths[subset_index] = metrics->x_advance; status = _cairo_array_grow_by (data, 30); if (status) return status; - charstring_encode_integer (data, (int) scaled_glyph->metrics.x_bearing); - charstring_encode_integer (data, (int) scaled_glyph->metrics.y_bearing); - charstring_encode_integer (data, (int) scaled_glyph->metrics.width); - charstring_encode_integer (data, (int) scaled_glyph->metrics.height); - charstring_encode_command (data, CHARSTRING_sbw); + if (type == CAIRO_CHARSTRING_TYPE1) { + charstring_encode_integer (data, (int) scaled_glyph->metrics.x_bearing, type); + charstring_encode_integer (data, (int) scaled_glyph->metrics.y_bearing, type); + charstring_encode_integer (data, (int) scaled_glyph->metrics.width, type); + charstring_encode_integer (data, (int) scaled_glyph->metrics.height, type); + charstring_encode_command (data, CHARSTRING_sbw); + path_info.current_x = (int) scaled_glyph->metrics.x_bearing; + path_info.current_y = (int) scaled_glyph->metrics.y_bearing; + } else { + charstring_encode_integer (data, (int) scaled_glyph->metrics.width, type); + + path_info.current_x = 0; + path_info.current_y = 0; + } path_info.data = data; - path_info.current_x = (int) scaled_glyph->metrics.x_bearing; - path_info.current_y = (int) scaled_glyph->metrics.y_bearing; + path_info.type = type; status = _cairo_path_fixed_interpret (scaled_glyph->path, CAIRO_DIRECTION_FORWARD, _charstring_move_to, @@ -421,7 +451,7 @@ cairo_type1_font_write_charstrings (cairo_type1_font_t *font, "2 index /CharStrings %d dict dup begin\n", font->scaled_font_subset->num_glyphs + 1); - for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { + for (i = 1; i < font->scaled_font_subset->num_glyphs; i++) { _cairo_array_truncate (&data, 0); /* four "random" bytes required by encryption algorithm */ status = _cairo_array_append_multiple (&data, zeros, 4); @@ -429,6 +459,7 @@ cairo_type1_font_write_charstrings (cairo_type1_font_t *font, goto fail; status = cairo_type1_font_create_charstring (font, i, font->scaled_font_subset->glyphs[i], + CAIRO_CHARSTRING_TYPE1, &data); if (status) goto fail; @@ -448,7 +479,7 @@ cairo_type1_font_write_charstrings (cairo_type1_font_t *font, status = _cairo_array_append_multiple (&data, zeros, 4); if (status) goto fail; - status = create_notdef_charstring (&data); + status = create_notdef_charstring (&data, CAIRO_CHARSTRING_TYPE1); if (status) goto fail; charstring_encrypt (&data); @@ -468,28 +499,18 @@ static void cairo_type1_font_write_header (cairo_type1_font_t *font, const char *name) { - cairo_matrix_t matrix; unsigned int i; const char spaces[50] = " "; - matrix = font->type1_scaled_font->scale; - matrix.xy = -matrix.xy; - matrix.yy = -matrix.yy; - cairo_matrix_invert (&matrix); - _cairo_output_stream_printf (font->output, "%%!FontType1-1.1 %s 1.0\n" "11 dict begin\n" "/FontName /%s def\n" "/PaintType 0 def\n" "/FontType 1 def\n" - "/FontMatrix [%f %f %f %f 0 0] readonly def\n", + "/FontMatrix [0.001 0 0 0.001 0 0] readonly def\n", name, - name, - matrix.xx, - matrix.yx, - matrix.xy, - matrix.yy); + name); /* We don't know the bbox values until after the charstrings have * been generated. Reserve some space and fill in the bbox @@ -558,6 +579,7 @@ cairo_type1_font_write_private_dict (cairo_type1_font_t *font, const char *name) { cairo_int_status_t status; + cairo_status_t status2; cairo_output_stream_t *encrypted_output; font->eexec_key = CAIRO_TYPE1_PRIVATE_DICT_KEY; @@ -597,10 +619,10 @@ cairo_type1_font_write_private_dict (cairo_type1_font_t *font, "dup /FontName get exch definefont pop\n" "mark currentfile closefile\n"); - if (status == CAIRO_STATUS_SUCCESS) - status = _cairo_output_stream_get_status (encrypted_output); fail: - _cairo_output_stream_destroy (encrypted_output); + status2 = _cairo_output_stream_destroy (encrypted_output); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; return status; } @@ -672,14 +694,18 @@ cairo_type1_font_generate (cairo_type1_font_t *font, const char *name) return CAIRO_STATUS_SUCCESS; } -static void +static cairo_status_t cairo_type1_font_destroy (cairo_type1_font_t *font) { + cairo_status_t status; + free (font->widths); cairo_scaled_font_destroy (font->type1_scaled_font); _cairo_array_fini (&font->contents); - _cairo_output_stream_destroy (font->output); + status = _cairo_output_stream_destroy (font->output); free (font); + + return status; } static cairo_status_t @@ -745,14 +771,14 @@ _cairo_type1_fallback_init_internal (cairo_type1_subset_t *type1_subset, type1_subset->data_length = font->data_size; type1_subset->trailer_length = font->trailer_size; - cairo_type1_font_destroy (font); - return CAIRO_STATUS_SUCCESS; + return cairo_type1_font_destroy (font); fail3: free (type1_subset->widths); fail2: free (type1_subset->base_font); fail1: + /* status is already set, ignore further errors */ cairo_type1_font_destroy (font); return status; @@ -785,3 +811,83 @@ _cairo_type1_fallback_fini (cairo_type1_subset_t *subset) free (subset->widths); free (subset->data); } + +cairo_status_t +_cairo_type2_charstrings_init (cairo_type2_charstrings_t *type2_subset, + cairo_scaled_font_subset_t *scaled_font_subset) +{ + cairo_type1_font_t *font; + cairo_status_t status; + unsigned int i; + cairo_array_t charstring; + + status = cairo_type1_font_create (scaled_font_subset, &font, FALSE); + if (status) + return status; + + _cairo_array_init (&type2_subset->charstrings, sizeof (cairo_array_t)); + + type2_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs); + if (type2_subset->widths == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto fail1; + } + + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { + _cairo_array_init (&charstring, sizeof (unsigned char)); + status = _cairo_array_grow_by (&charstring, 32); + if (status) + goto fail2; + + if (i == 0) { + status = create_notdef_charstring (&charstring, CAIRO_CHARSTRING_TYPE2); + } else { + status = cairo_type1_font_create_charstring (font, i, + font->scaled_font_subset->glyphs[i], + CAIRO_CHARSTRING_TYPE2, + &charstring); + } + if (status) + goto fail2; + + status = _cairo_array_append (&type2_subset->charstrings, &charstring); + if (status) + goto fail2; + } + + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) + type2_subset->widths[i] = font->widths[i]; + + type2_subset->x_min = (int) font->x_min; + type2_subset->y_min = (int) font->y_min; + type2_subset->x_max = (int) font->x_max; + type2_subset->y_max = (int) font->y_max; + type2_subset->ascent = (int) font->y_max; + type2_subset->descent = (int) font->y_min; + + cairo_type1_font_destroy (font); + return CAIRO_STATUS_SUCCESS; + +fail2: + _cairo_array_fini (&charstring); + _cairo_type2_charstrings_fini (type2_subset); +fail1: + cairo_type1_font_destroy (font); + return status; +} + +void +_cairo_type2_charstrings_fini (cairo_type2_charstrings_t *type2_subset) +{ + unsigned int i, num_charstrings; + cairo_array_t *charstring; + + num_charstrings = _cairo_array_num_elements (&type2_subset->charstrings); + for (i = 0; i < num_charstrings; i++) { + charstring = _cairo_array_index (&type2_subset->charstrings, i); + _cairo_array_fini (charstring); + } + _cairo_array_fini (&type2_subset->charstrings); + + free (type2_subset->widths); +} diff --git a/gfx/cairo/cairo/src/cairo-type1-subset.c b/gfx/cairo/cairo/src/cairo-type1-subset.c index e4f5015dd7b0..919b1d5c7ac2 100644 --- a/gfx/cairo/cairo/src/cairo-type1-subset.c +++ b/gfx/cairo/cairo/src/cairo-type1-subset.c @@ -46,6 +46,8 @@ #include FT_OUTLINE_H #include FT_TYPE1_TABLES_H +#include + typedef struct _cairo_type1_font_subset { cairo_scaled_font_subset_t *scaled_font_subset; @@ -1133,9 +1135,6 @@ _cairo_type1_subset_init (cairo_type1_subset_t *type1_subset, cairo_type1_font_subset_use_glyph (font, parent_glyph); } - /* Pull in the .notdef glyph */ - cairo_type1_font_subset_use_glyph (font, 0); - status = cairo_type1_font_subset_generate (font, name); if (status) goto fail1; @@ -1195,3 +1194,30 @@ _cairo_type1_subset_fini (cairo_type1_subset_t *subset) free (subset->widths); free (subset->data); } + +cairo_bool_t +_cairo_type1_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font) +{ + cairo_ft_unscaled_font_t *unscaled; + FT_Face face; + PS_FontInfoRec font_info; + cairo_bool_t is_type1 = FALSE; + + unscaled = (cairo_ft_unscaled_font_t *) _cairo_ft_scaled_font_get_unscaled_font (scaled_font); + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return FALSE; + + if (FT_Get_PS_Font_Info(face, &font_info) == 0) + is_type1 = TRUE; + + /* OpenType/CFF fonts also have a PS_FontInfoRec */ +#if HAVE_FT_LOAD_SFNT_TABLE + if (FT_IS_SFNT (face)) + is_type1 = FALSE; +#endif + + _cairo_ft_unscaled_font_unlock_face (unscaled); + + return is_type1; +} diff --git a/gfx/cairo/cairo/src/cairo-types-private.h b/gfx/cairo/cairo/src/cairo-types-private.h new file mode 100644 index 000000000000..37b131e13f3f --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-types-private.h @@ -0,0 +1,128 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_TYPES_PRIVATE_H +#define CAIRO_TYPES_PRIVATE_H + +typedef struct _cairo_array cairo_array_t; +struct _cairo_array { + unsigned int size; + unsigned int num_elements; + unsigned int element_size; + char **elements; + + cairo_bool_t is_snapshot; +}; + +typedef cairo_array_t cairo_user_data_array_t; + +struct _cairo_font_options { + cairo_antialias_t antialias; + cairo_subpixel_order_t subpixel_order; + cairo_hint_style_t hint_style; + cairo_hint_metrics_t hint_metrics; +}; + +typedef struct _cairo_hash_table cairo_hash_table_t; + +typedef struct _cairo_cache { + cairo_hash_table_t *hash_table; + + cairo_destroy_func_t entry_destroy; + + unsigned long max_size; + unsigned long size; + + int freeze_count; +} cairo_cache_t; + +/** + * cairo_hash_entry_t: + * + * A #cairo_hash_entry_t contains both a key and a value for + * cairo_hash_table_t. User-derived types for cairo_hash_entry_t must + * be type-compatible with this structure (eg. they must have an + * unsigned long as the first parameter. The easiest way to get this + * is to use: + * + * typedef _my_entry { + * cairo_hash_entry_t base; + * ... Remainder of key and value fields here .. + * } my_entry_t; + * + * which then allows a pointer to my_entry_t to be passed to any of + * the cairo_hash_table functions as follows without requiring a cast: + * + * _cairo_hash_table_insert (hash_table, &my_entry->base); + * + * IMPORTANT: The caller is reponsible for initializing + * my_entry->base.hash with a hash code derived from the key. The + * essential property of the hash code is that keys_equal must never + * return TRUE for two keys that have different hashes. The best hash + * code will reduce the frequency of two keys with the same code for + * which keys_equal returns FALSE. + * + * Which parts of the entry make up the "key" and which part make up + * the value are entirely up to the caller, (as determined by the + * computation going into base.hash as well as the keys_equal + * function). A few of the cairo_hash_table functions accept an entry + * which will be used exclusively as a "key", (indicated by a + * parameter name of key). In these cases, the value-related fields of + * the entry need not be initialized if so desired. + **/ +typedef struct _cairo_hash_entry { + unsigned long hash; +} cairo_hash_entry_t; + + +typedef struct _cairo_surface_backend cairo_surface_backend_t; +typedef struct _cairo_clip cairo_clip_t; +typedef struct _cairo_output_stream cairo_output_stream_t; +typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t; +typedef struct _cairo_paginated_surface_backend cairo_paginated_surface_backend_t; +typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t; +typedef struct _cairo_font_face_backend cairo_font_face_backend_t; + + +typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t; + +typedef enum { + CAIRO_PAGINATED_MODE_ANALYZE, /* analyze page regions */ + CAIRO_PAGINATED_MODE_RENDER /* render page contents */ +} cairo_paginated_mode_t; + +#endif /* CAIRO_TYPES_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-unicode.c b/gfx/cairo/cairo/src/cairo-unicode.c index 5ca51e1e2aa0..9abb0ebca1d5 100644 --- a/gfx/cairo/cairo/src/cairo-unicode.c +++ b/gfx/cairo/cairo/src/cairo-unicode.c @@ -40,9 +40,7 @@ * Owen Taylor */ -#include - -#include +#include "cairoint.h" #define UTF8_COMPUTE(Char, Mask, Len) \ if (Char < 128) \ diff --git a/gfx/cairo/cairo/src/cairo-wideint-private.h b/gfx/cairo/cairo/src/cairo-wideint-private.h index 7d459ea36448..636d8a6b7df3 100644 --- a/gfx/cairo/cairo/src/cairo-wideint-private.h +++ b/gfx/cairo/cairo/src/cairo-wideint-private.h @@ -64,6 +64,12 @@ # ifndef UINT16_MAX # define UINT16_MAX (65535) # endif +# ifndef INT32_MIN +# define INT32_MIN (-2147483647-1) +# endif +# ifndef INT32_MAX +# define INT32_MAX (2147483647) +# endif #else #error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.) #endif diff --git a/gfx/cairo/cairo/src/cairo-win32-font.c b/gfx/cairo/cairo/src/cairo-win32-font.c index 1fcb358b4ea3..e1f263b67216 100644 --- a/gfx/cairo/cairo/src/cairo-win32-font.c +++ b/gfx/cairo/cairo/src/cairo-win32-font.c @@ -32,9 +32,8 @@ * Contributor(s): */ -#include -#include #include "cairoint.h" + #include "cairo-win32-private.h" #ifndef SPI_GETFONTSMOOTHINGTYPE @@ -227,15 +226,9 @@ _get_system_quality (void) } } -/* If face_hfont is non-NULL then font_matrix must be a simple scale by some - * factor S, ctm must be the identity, logfont->lfHeight must be -S, - * logfont->lfWidth, logfont->lfEscapement, logfont->lfOrientation must - * all be 0, and face_hfont is the result of calling CreateFontIndirectW on - * logfont. - */ static cairo_scaled_font_t * _win32_scaled_font_create (LOGFONTW *logfont, - HFONT face_hfont, + HFONT hfont, cairo_font_face_t *font_face, const cairo_matrix_t *font_matrix, const cairo_matrix_t *ctm, @@ -245,8 +238,6 @@ _win32_scaled_font_create (LOGFONTW *logfont, cairo_matrix_t scale; cairo_status_t status; - _cairo_win32_initialize (); - f = malloc (sizeof(cairo_win32_scaled_font_t)); if (f == NULL) return NULL; @@ -283,29 +274,22 @@ _win32_scaled_font_create (LOGFONTW *logfont, } f->em_square = 0; - f->scaled_hfont = NULL; + f->scaled_hfont = hfont; f->unscaled_hfont = NULL; - if (f->quality == logfont->lfQuality || - (logfont->lfQuality == DEFAULT_QUALITY && - options->antialias == CAIRO_ANTIALIAS_DEFAULT)) { - /* If face_hfont is non-NULL, then we can use it to avoid creating our - * own --- because the constraints on face_hfont mentioned above - * guarantee it was created in exactly the same way that - * _win32_scaled_font_get_scaled_hfont would create it. - */ - f->scaled_hfont = face_hfont; - } - /* don't delete the hfont if we're using the one passed in to us */ - f->delete_scaled_hfont = !f->scaled_hfont; + + /* don't delete the hfont if it was passed in to us */ + f->delete_scaled_hfont = !hfont; cairo_matrix_multiply (&scale, font_matrix, ctm); _compute_transform (f, &scale); - _cairo_scaled_font_init (&f->base, font_face, - font_matrix, ctm, options, - &cairo_win32_scaled_font_backend); + status = _cairo_scaled_font_init (&f->base, font_face, + font_matrix, ctm, options, + &cairo_win32_scaled_font_backend); + + if (status == CAIRO_STATUS_SUCCESS) + status = _cairo_win32_scaled_font_set_metrics (f); - status = _cairo_win32_scaled_font_set_metrics (f); if (status) { cairo_scaled_font_destroy (&f->base); return NULL; @@ -487,8 +471,6 @@ _cairo_win32_scaled_font_create_toy (cairo_toy_font_face_t *toy_face, int face_name_len; cairo_status_t status; - _cairo_win32_initialize (); - status = _cairo_utf8_to_utf16 (toy_face->family, -1, &face_name, &face_name_len); if (status) @@ -1471,16 +1453,14 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font } free(buffer); -CLEANUP_FONT: - _cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base, path); + CLEANUP_FONT: cairo_win32_scaled_font_done_font (&scaled_font->base); CLEANUP_PATH: - if (status != CAIRO_STATUS_SUCCESS) _cairo_path_fixed_destroy (path); @@ -1503,11 +1483,6 @@ const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend = { typedef struct _cairo_win32_font_face cairo_win32_font_face_t; -/* If hfont is non-NULL then logfont->lfHeight must be -S for some S, - * logfont->lfWidth, logfont->lfEscapement, logfont->lfOrientation must - * all be 0, and hfont is the result of calling CreateFontIndirectW on - * logfont. - */ struct _cairo_win32_font_face { cairo_font_face_t base; LOGFONTW logfont; @@ -1521,14 +1496,6 @@ _cairo_win32_font_face_destroy (void *abstract_face) { } -static cairo_bool_t -_is_scale (const cairo_matrix_t *matrix, double scale) -{ - return matrix->xx == scale && matrix->yy == scale && - matrix->xy == 0. && matrix->yx == 0. && - matrix->x0 == 0. && matrix->y0 == 0.; -} - static cairo_status_t _cairo_win32_font_face_scaled_font_create (void *abstract_face, const cairo_matrix_t *font_matrix, @@ -1536,22 +1503,10 @@ _cairo_win32_font_face_scaled_font_create (void *abstract_face, const cairo_font_options_t *options, cairo_scaled_font_t **font) { - HFONT hfont = NULL; - cairo_win32_font_face_t *font_face = abstract_face; - _cairo_win32_initialize (); - - if (font_face->hfont) { - /* Check whether it's OK to go ahead and use the font-face's HFONT. */ - if (_is_scale (ctm, 1.) && - _is_scale (font_matrix, -font_face->logfont.lfHeight)) { - hfont = font_face->hfont; - } - } - *font = _win32_scaled_font_create (&font_face->logfont, - hfont, + font_face->hfont, &font_face->base, font_matrix, ctm, options); if (*font) @@ -1566,46 +1521,6 @@ static const cairo_font_face_backend_t _cairo_win32_font_face_backend = { _cairo_win32_font_face_scaled_font_create }; -/** - * cairo_win32_font_face_create_for_logfontw_hfont: - * @logfont: A #LOGFONTW structure specifying the font to use. - * If hfont is null then the lfHeight, lfWidth, lfOrientation and lfEscapement - * fields of this structure are ignored. Otherwise lfWidth, lfOrientation and - * lfEscapement must be zero. - * @font: An #HFONT that can be used when the font matrix is a scale by - * -lfHeight and the CTM is identity. - * - * Creates a new font for the Win32 font backend based on a - * #LOGFONT. This font can then be used with - * cairo_set_font_face() or cairo_scaled_font_create(). - * The #cairo_scaled_font_t - * returned from cairo_scaled_font_create() is also for the Win32 backend - * and can be used with functions such as cairo_win32_scaled_font_select_font(). - * - * Return value: a newly created #cairo_font_face_t. Free with - * cairo_font_face_destroy() when you are done using it. - **/ -cairo_font_face_t * -cairo_win32_font_face_create_for_logfontw_hfont (LOGFONTW *logfont, HFONT font) -{ - cairo_win32_font_face_t *font_face; - - _cairo_win32_initialize (); - - font_face = malloc (sizeof (cairo_win32_font_face_t)); - if (!font_face) { - _cairo_error (CAIRO_STATUS_NO_MEMORY); - return (cairo_font_face_t *)&_cairo_font_face_nil; - } - - font_face->logfont = *logfont; - font_face->hfont = font; - - _cairo_font_face_init (&font_face->base, &_cairo_win32_font_face_backend); - - return &font_face->base; -} - /** * cairo_win32_font_face_create_for_logfontw: * @logfont: A #LOGFONTW structure specifying the font to use. @@ -1625,7 +1540,20 @@ cairo_win32_font_face_create_for_logfontw_hfont (LOGFONTW *logfont, HFONT font) cairo_font_face_t * cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont) { - return cairo_win32_font_face_create_for_logfontw_hfont (logfont, NULL); + cairo_win32_font_face_t *font_face; + + font_face = malloc (sizeof (cairo_win32_font_face_t)); + if (!font_face) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; + } + + font_face->logfont = *logfont; + font_face->hfont = NULL; + + _cairo_font_face_init (&font_face->base, &_cairo_win32_font_face_backend); + + return &font_face->base; } /** @@ -1645,17 +1573,19 @@ cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont) cairo_font_face_t * cairo_win32_font_face_create_for_hfont (HFONT font) { - LOGFONTW logfont; - GetObject (font, sizeof(logfont), &logfont); + cairo_win32_font_face_t *font_face; - if (logfont.lfEscapement != 0 || logfont.lfOrientation != 0 || - logfont.lfWidth != 0) { - /* We can't use this font because that optimization requires that - * lfEscapement, lfOrientation and lfWidth be zero. */ - font = NULL; + font_face = malloc (sizeof (cairo_win32_font_face_t)); + if (!font_face) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; } - return cairo_win32_font_face_create_for_logfontw_hfont (&logfont, font); + font_face->hfont = font; + + _cairo_font_face_init (&font_face->base, &_cairo_win32_font_face_backend); + + return &font_face->base; } /** diff --git a/gfx/cairo/cairo/src/cairo-win32-private.h b/gfx/cairo/cairo/src/cairo-win32-private.h index 8256b20964f5..08aeafa759c0 100644 --- a/gfx/cairo/cairo/src/cairo-win32-private.h +++ b/gfx/cairo/cairo/src/cairo-win32-private.h @@ -46,11 +46,7 @@ #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; @@ -109,7 +105,4 @@ _cairo_win32_print_gdi_error (const char *context); cairo_bool_t _cairo_surface_is_win32 (cairo_surface_t *surface); -void -_cairo_win32_initialize (void); - #endif /* CAIRO_WIN32_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-win32-surface.c b/gfx/cairo/cairo/src/cairo-win32-surface.c index 58a698f14a5e..450887a1f512 100644 --- a/gfx/cairo/cairo/src/cairo-win32-surface.c +++ b/gfx/cairo/cairo/src/cairo-win32-surface.c @@ -44,13 +44,18 @@ #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500) # define _WIN32_WINNT 0x0500 #endif -#include -#include #include "cairoint.h" + #include "cairo-clip-private.h" #include "cairo-win32-private.h" +#include + +#if defined(__MINGW32__) && !defined(ETO_PDY) +# define ETO_PDY 0x2000 +#endif + #undef DEBUG_COMPOSITE /* for older SDKs */ @@ -327,8 +332,6 @@ _cairo_win32_surface_create_for_dc (HDC original_dc, char *bits; int rowstride; - _cairo_win32_initialize (); - surface = malloc (sizeof (cairo_win32_surface_t)); if (surface == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -473,12 +476,7 @@ _cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface, status = CAIRO_INT_STATUS_UNSUPPORTED; - /* Check for SURFACE_IS_DISPLAY here, because there are a lot - * of printer drivers that lie and say they can BitBlt, but - * just spit out black instead. - */ - if ((local->flags & CAIRO_WIN32_SURFACE_IS_DISPLAY) && - (local->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT) && + if ((local->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT) && BitBlt (local->dc, 0, 0, width, height, @@ -1640,8 +1638,6 @@ cairo_win32_surface_create (HDC hdc) int depth; cairo_format_t format; - _cairo_win32_initialize (); - /* Try to figure out the drawing bounds for the Device context */ if (GetClipBox (hdc, &rect) == ERROR) { @@ -1859,6 +1855,30 @@ cairo_win32_surface_get_image (cairo_surface_t *surface) return ((cairo_win32_surface_t*)surface)->image; } +static cairo_bool_t +_cairo_win32_surface_is_similar (void *surface_a, + void *surface_b, + cairo_content_t content) +{ + cairo_win32_surface_t *a = surface_a; + cairo_win32_surface_t *b = surface_b; + + return a->dc == b->dc; +} + +static cairo_status_t +_cairo_win32_surface_reset (void *abstract_surface) +{ + cairo_win32_surface_t *surface = abstract_surface; + cairo_status_t status; + + status = _cairo_win32_surface_set_clip_region (surface, NULL); + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} + static const cairo_surface_backend_t cairo_win32_surface_backend = { CAIRO_SURFACE_TYPE_WIN32, _cairo_win32_surface_create_similar, @@ -1889,70 +1909,12 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = { NULL, /* fill */ _cairo_win32_surface_show_glyphs, - NULL /* snapshot */ + NULL, /* snapshot */ + _cairo_win32_surface_is_similar, + + _cairo_win32_surface_reset }; -/* - * Without pthread, on win32 we need to initialize all the 'mutex'es - * before use. It is guaranteed that DllMain will get called single - * threaded before any other function. - * Initializing more than finally needed should not matter much. - */ -#if !defined(HAVE_PTHREAD_H) - -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; - -void -_cairo_win32_initialize (void) { - if (_cairo_win32_initialized) - return; - - /* every 'mutex' from CAIRO_MUTEX_DECALRE needs to be initialized here */ - 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; -} - -#if !defined(CAIRO_WIN32_STATIC_BUILD) -BOOL WINAPI -DllMain (HINSTANCE hinstDLL, - DWORD fdwReason, - LPVOID lpvReserved) -{ - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - _cairo_win32_initialize(); - break; - case DLL_PROCESS_DETACH: - 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; -} -#endif -#else -/* Need a function definition here too since it's called outside of ifdefs */ -void -_cairo_win32_initialize (void) -{ -} -#endif - /* Notes: * * Win32 alpha-understanding functions @@ -1966,3 +1928,33 @@ _cairo_win32_initialize (void) * it will still copy over the src alpha, because the SCA value (255) will be * multiplied by all the src components. */ + + +#if !defined(CAIRO_WIN32_STATIC_BUILD) + +/* declare to avoid "no previous prototype for 'DllMain'" warning */ +BOOL WINAPI +DllMain (HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved); + +BOOL WINAPI +DllMain (HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + CAIRO_MUTEX_INITIALIZE (); + break; + + case DLL_PROCESS_DETACH: + CAIRO_MUTEX_FINALIZE (); + break; + } + + return TRUE; +} + +#endif + diff --git a/gfx/cairo/cairo/src/cairo-win32.h b/gfx/cairo/cairo/src/cairo-win32.h index 56643868ddf8..8719d338b8ca 100644 --- a/gfx/cairo/cairo/src/cairo-win32.h +++ b/gfx/cairo/cairo/src/cairo-win32.h @@ -70,9 +70,6 @@ cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont); cairo_public cairo_font_face_t * cairo_win32_font_face_create_for_hfont (HFONT font); -cairo_public cairo_font_face_t * -cairo_win32_font_face_create_for_logfontw_hfont (LOGFONTW *logfont, HFONT font); - cairo_public cairo_status_t cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font, HDC hdc); diff --git a/gfx/cairo/cairo/src/cairo-xcb-surface.c b/gfx/cairo/cairo/src/cairo-xcb-surface.c index 08979611909a..f92904090b1a 100644 --- a/gfx/cairo/cairo/src/cairo-xcb-surface.c +++ b/gfx/cairo/cairo/src/cairo-xcb-surface.c @@ -1577,6 +1577,39 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst, int num_glyphs, cairo_scaled_font_t *scaled_font); +static cairo_bool_t +_cairo_xcb_surface_is_similar (void *surface_a, + void *surface_b, + cairo_content_t content) +{ + cairo_xcb_surface_t *a = surface_a; + cairo_xcb_surface_t *b = surface_b; + xcb_render_pictforminfo_t *xrender_format; + + if (! _cairo_xcb_surface_same_screen (a, b)) + return FALSE; + + /* now check that the target is a similar format */ + xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (b->dpy, + _cairo_format_from_content (content)); + + return a->xrender_format.id == xrender_format->id; +} + +static cairo_status_t +_cairo_xcb_surface_reset (void *abstract_surface) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_status_t status; + + status = _cairo_xcb_surface_set_clip_region (surface, NULL); + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} + + /* XXX: move this to the bottom of the file, XCB and Xlib */ static const cairo_surface_backend_t cairo_xcb_surface_backend = { @@ -1608,7 +1641,11 @@ static const cairo_surface_backend_t cairo_xcb_surface_backend = { NULL, /* stroke */ NULL, /* fill */ _cairo_xcb_surface_show_glyphs, - NULL /* snapshot */ + NULL, /* snapshot */ + + _cairo_xcb_surface_is_similar, + + _cairo_xcb_surface_reset }; /** @@ -2344,7 +2381,8 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst, * so PictOpClear was never used with CompositeText before. */ if (op == CAIRO_OPERATOR_CLEAR) { - _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE); + _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE, + CAIRO_CONTENT_COLOR); src_pattern = &solid_pattern.base; op = CAIRO_OPERATOR_DEST_OUT; } diff --git a/gfx/cairo/cairo/src/cairo-xlib-display.c b/gfx/cairo/cairo/src/cairo-xlib-display.c new file mode 100644 index 000000000000..5de9011104a0 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-xlib-display.c @@ -0,0 +1,453 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Chris Wilson + * + * 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 Chris Wilson. + * + */ + +#include "cairoint.h" + +#include "cairo-xlib-private.h" + +#include + +#include /* For XESetCloseDisplay */ +#include + +typedef int (*cairo_xlib_error_func_t) (Display *display, + XErrorEvent *event); + +struct _cairo_xlib_job { + cairo_xlib_job_t *next; + enum { + RESOURCE, + WORK + } type; + union { + struct { + cairo_xlib_notify_resource_func notify; + XID xid; + } resource; + struct { + cairo_xlib_notify_func notify; + void *data; + void (*destroy) (void *); + } work; + } func; +}; + +static cairo_xlib_display_t *_cairo_xlib_display_list; + +static void +_cairo_xlib_call_close_display_hooks (cairo_xlib_display_t *display) +{ + cairo_xlib_screen_info_t *screen; + cairo_xlib_hook_t *hooks, *list; + + /* call all registered shutdown routines */ + CAIRO_MUTEX_LOCK (display->mutex); + + for (screen = display->screens; screen != NULL; screen = screen->next) + _cairo_xlib_screen_info_close_display (screen); + + hooks = display->close_display_hooks; + while (hooks != NULL) { + display->close_display_hooks = NULL; + CAIRO_MUTEX_UNLOCK (display->mutex); + + list = hooks; + do { + cairo_xlib_hook_t *hook = list; + list = hook->next; + + hook->func (display->display, hook->data); + } while (list != NULL); + + CAIRO_MUTEX_LOCK (display->mutex); + do { + cairo_xlib_hook_t *hook = hooks; + hooks = hook->next; + + _cairo_freelist_free (&display->hook_freelist, hook); + } while (hooks != NULL); + + hooks = display->close_display_hooks; + } + display->closed = TRUE; + + CAIRO_MUTEX_UNLOCK (display->mutex); +} + +static void +_cairo_xlib_display_discard_screens (cairo_xlib_display_t *display) +{ + cairo_xlib_screen_info_t *screens; + + CAIRO_MUTEX_LOCK (display->mutex); + screens = display->screens; + display->screens = NULL; + CAIRO_MUTEX_UNLOCK (display->mutex); + + while (screens != NULL) { + cairo_xlib_screen_info_t *screen = screens; + screens = screen->next; + + _cairo_xlib_screen_info_destroy (screen); + } +} + +cairo_xlib_display_t * +_cairo_xlib_display_reference (cairo_xlib_display_t *display) +{ + if (display == NULL) + return NULL; + + /* use our mutex until we get a real atomic inc */ + CAIRO_MUTEX_LOCK (display->mutex); + + assert (display->ref_count > 0); + display->ref_count++; + + CAIRO_MUTEX_UNLOCK (display->mutex); + + return display; +} + +void +_cairo_xlib_display_destroy (cairo_xlib_display_t *display) +{ + if (display == NULL) + return; + + CAIRO_MUTEX_LOCK (display->mutex); + assert (display->ref_count > 0); + if (--display->ref_count == 0) { + /* destroy all outstanding notifies */ + while (display->workqueue != NULL) { + cairo_xlib_job_t *job = display->workqueue; + display->workqueue = job->next; + + if (job->type == WORK && job->func.work.destroy != NULL) + job->func.work.destroy (job->func.work.data); + + _cairo_freelist_free (&display->wq_freelist, job); + } + _cairo_freelist_fini (&display->wq_freelist); + _cairo_freelist_fini (&display->hook_freelist); + + CAIRO_MUTEX_UNLOCK (display->mutex); + + free (display); + } else + CAIRO_MUTEX_UNLOCK (display->mutex); +} + +static int +_noop_error_handler (Display *display, + XErrorEvent *event) +{ + return False; /* return value is ignored */ +} +static int +_cairo_xlib_close_display (Display *dpy, XExtCodes *codes) +{ + cairo_xlib_display_t *display, **prev, *next; + + /* + * Unhook from the global list + */ + CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex); + prev = &_cairo_xlib_display_list; + for (display = _cairo_xlib_display_list; display; display = next) { + next = display->next; + if (display->display == dpy) { + cairo_xlib_error_func_t old_handler; + + /* drop the list mutex whilst triggering the hooks */ + CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); + + /* protect the notifies from triggering XErrors */ + XSync (dpy, False); + old_handler = XSetErrorHandler (_noop_error_handler); + + _cairo_xlib_display_notify (display); + _cairo_xlib_call_close_display_hooks (display); + _cairo_xlib_display_discard_screens (display); + + /* catch any that arrived before marking the display as closed */ + _cairo_xlib_display_notify (display); + + XSync (dpy, False); + XSetErrorHandler (old_handler); + + CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex); + _cairo_xlib_display_destroy (display); + *prev = next; + break; + } else + prev = &display->next; + } + CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); + + /* Return value in accordance with requirements of + * XESetCloseDisplay */ + return 0; +} + +cairo_xlib_display_t * +_cairo_xlib_display_get (Display *dpy) +{ + cairo_xlib_display_t *display; + cairo_xlib_display_t **prev; + XExtCodes *codes; + + /* 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 (_cairo_xlib_display_mutex); + + for (prev = &_cairo_xlib_display_list; (display = *prev); prev = &(*prev)->next) + { + if (display->display == dpy) { + /* + * MRU the list + */ + if (prev != &_cairo_xlib_display_list) { + *prev = display->next; + display->next = _cairo_xlib_display_list; + _cairo_xlib_display_list = display; + } + break; + } + } + + if (display != NULL) { + display = _cairo_xlib_display_reference (display); + goto UNLOCK; + } + + display = malloc (sizeof (cairo_xlib_display_t)); + if (display == NULL) + goto UNLOCK; + + codes = XAddExtension (dpy); + if (codes == NULL) { + free (display); + display = NULL; + goto UNLOCK; + } + + XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display); + + _cairo_freelist_init (&display->wq_freelist, sizeof (cairo_xlib_job_t)); + _cairo_freelist_init (&display->hook_freelist, sizeof (cairo_xlib_hook_t)); + + display->ref_count = 2; /* add one for the CloseDisplay */ + CAIRO_MUTEX_INIT (display->mutex); + display->display = dpy; + display->screens = NULL; + display->workqueue = NULL; + display->close_display_hooks = NULL; + display->closed = FALSE; + + display->next = _cairo_xlib_display_list; + _cairo_xlib_display_list = display; + +UNLOCK: + CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); + return display; +} + +cairo_bool_t +_cairo_xlib_add_close_display_hook (Display *dpy, void (*func) (Display *, void *), void *data, const void *key) +{ + cairo_xlib_display_t *display; + cairo_xlib_hook_t *hook; + cairo_bool_t ret = FALSE; + + display = _cairo_xlib_display_get (dpy); + if (display == NULL) + return FALSE; + + CAIRO_MUTEX_LOCK (display->mutex); + if (display->closed == FALSE) { + hook = _cairo_freelist_alloc (&display->hook_freelist); + if (hook != NULL) { + hook->func = func; + hook->data = data; + hook->key = key; + + hook->next = display->close_display_hooks; + display->close_display_hooks = hook; + ret = TRUE; + } + } + CAIRO_MUTEX_UNLOCK (display->mutex); + + _cairo_xlib_display_destroy (display); + + return ret; +} + +void +_cairo_xlib_remove_close_display_hooks (Display *dpy, const void *key) +{ + cairo_xlib_display_t *display; + cairo_xlib_hook_t *hook, *next, **prev; + + display = _cairo_xlib_display_get (dpy); + if (display == NULL) + return; + + CAIRO_MUTEX_LOCK (display->mutex); + prev = &display->close_display_hooks; + for (hook = display->close_display_hooks; hook != NULL; hook = next) { + next = hook->next; + if (hook->key == key) { + *prev = hook->next; + _cairo_freelist_free (&display->hook_freelist, hook); + } else + prev = &hook->next; + } + *prev = NULL; + CAIRO_MUTEX_UNLOCK (display->mutex); + + _cairo_xlib_display_destroy (display); +} + +cairo_status_t +_cairo_xlib_display_queue_resource (cairo_xlib_display_t *display, + cairo_xlib_notify_resource_func notify, + XID xid) +{ + cairo_xlib_job_t *job; + cairo_status_t status = CAIRO_STATUS_NO_MEMORY; + + CAIRO_MUTEX_LOCK (display->mutex); + if (display->closed == FALSE) { + job = _cairo_freelist_alloc (&display->wq_freelist); + if (job != NULL) { + job->type = RESOURCE; + job->func.resource.xid = xid; + job->func.resource.notify = notify; + + job->next = display->workqueue; + display->workqueue = job; + + status = CAIRO_STATUS_SUCCESS; + } + } + CAIRO_MUTEX_UNLOCK (display->mutex); + + return status; +} + +cairo_status_t +_cairo_xlib_display_queue_work (cairo_xlib_display_t *display, + cairo_xlib_notify_func notify, + void *data, + void (*destroy) (void *)) +{ + cairo_xlib_job_t *job; + cairo_status_t status = CAIRO_STATUS_NO_MEMORY; + + CAIRO_MUTEX_LOCK (display->mutex); + if (display->closed == FALSE) { + job = _cairo_freelist_alloc (&display->wq_freelist); + if (job != NULL) { + job->type = WORK; + job->func.work.data = data; + job->func.work.notify = notify; + job->func.work.destroy = destroy; + + job->next = display->workqueue; + display->workqueue = job; + + status = CAIRO_STATUS_SUCCESS; + } + } + CAIRO_MUTEX_UNLOCK (display->mutex); + + return status; +} + +void +_cairo_xlib_display_notify (cairo_xlib_display_t *display) +{ + cairo_xlib_job_t *jobs, *job, *freelist; + + CAIRO_MUTEX_LOCK (display->mutex); + jobs = display->workqueue; + while (jobs != NULL) { + display->workqueue = NULL; + CAIRO_MUTEX_UNLOCK (display->mutex); + + /* reverse the list to obtain FIFO order */ + job = NULL; + do { + cairo_xlib_job_t *next = jobs->next; + jobs->next = job; + job = jobs; + jobs = next; + } while (jobs != NULL); + freelist = jobs = job; + + do { + job = jobs; + jobs = job->next; + + switch (job->type){ + case WORK: + job->func.work.notify (display->display, job->func.work.data); + if (job->func.work.destroy != NULL) + job->func.work.destroy (job->func.work.data); + break; + + case RESOURCE: + job->func.resource.notify (display->display, + job->func.resource.xid); + break; + } + } while (jobs != NULL); + + CAIRO_MUTEX_LOCK (display->mutex); + do { + job = freelist; + freelist = job->next; + _cairo_freelist_free (&display->wq_freelist, job); + } while (freelist != NULL); + + jobs = display->workqueue; + } + CAIRO_MUTEX_UNLOCK (display->mutex); +} diff --git a/gfx/cairo/cairo/src/cairo-xlib-private.h b/gfx/cairo/cairo/src/cairo-xlib-private.h index 5dd91b0ac97b..6157775a4ecc 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-private.h +++ b/gfx/cairo/cairo/src/cairo-xlib-private.h @@ -35,43 +35,97 @@ #include "cairoint.h" #include "cairo-xlib.h" +#include "cairo-freelist-private.h" -typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t; +typedef struct _cairo_xlib_display cairo_xlib_display_t; typedef struct _cairo_xlib_hook cairo_xlib_hook_t; +typedef struct _cairo_xlib_job cairo_xlib_job_t; +typedef void (*cairo_xlib_notify_func) (Display *, void *); +typedef void (*cairo_xlib_notify_resource_func) (Display *, XID); struct _cairo_xlib_hook { cairo_xlib_hook_t *next; void (*func) (Display *display, void *data); void *data; - void *key; + const void *key; +}; + +struct _cairo_xlib_display { + cairo_xlib_display_t *next; + unsigned int ref_count; + cairo_mutex_t mutex; + + Display *display; + cairo_xlib_screen_info_t *screens; + + cairo_xlib_job_t *workqueue; + cairo_freelist_t wq_freelist; + + cairo_freelist_t hook_freelist; + cairo_xlib_hook_t *close_display_hooks; + unsigned int closed :1; }; struct _cairo_xlib_screen_info { cairo_xlib_screen_info_t *next; + unsigned int ref_count; - Display *display; + cairo_xlib_display_t *display; Screen *screen; cairo_bool_t has_render; cairo_font_options_t font_options; - cairo_xlib_hook_t *close_display_hooks; + GC gc[9]; + unsigned int gc_needs_clip_reset; }; +cairo_private cairo_xlib_display_t * +_cairo_xlib_display_get (Display *display); + +cairo_private cairo_xlib_display_t * +_cairo_xlib_display_reference (cairo_xlib_display_t *info); +cairo_private void +_cairo_xlib_display_destroy (cairo_xlib_display_t *info); + +cairo_private cairo_bool_t +_cairo_xlib_add_close_display_hook (Display *display, void (*func) (Display *, void *), void *data, const void *key); +cairo_private void +_cairo_xlib_remove_close_display_hooks (Display *display, const void *key); + +cairo_private cairo_status_t +_cairo_xlib_display_queue_work (cairo_xlib_display_t *display, + cairo_xlib_notify_func notify, + void *data, + void (*destroy)(void *)); +cairo_private cairo_status_t +_cairo_xlib_display_queue_resource (cairo_xlib_display_t *display, + cairo_xlib_notify_resource_func notify, + XID resource); +cairo_private void +_cairo_xlib_display_notify (cairo_xlib_display_t *display); + 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 cairo_xlib_screen_info_t * +_cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t *info); cairo_private void -_cairo_xlib_remove_close_display_hook (Display *display, void *key); +_cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info); + +cairo_private void +_cairo_xlib_screen_info_close_display (cairo_xlib_screen_info_t *info); + +cairo_private GC +_cairo_xlib_screen_get_gc (cairo_xlib_screen_info_t *info, int depth); +cairo_private cairo_status_t +_cairo_xlib_screen_put_gc (cairo_xlib_screen_info_t *info, int depth, GC gc, cairo_bool_t reset_clip); #if CAIRO_HAS_XLIB_XRENDER_SURFACE #include "cairo-xlib-xrender.h" -#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 d3707414499d..2e8c913d36bf 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-screen.c +++ b/gfx/cairo/cairo/src/cairo-xlib-screen.c @@ -51,14 +51,13 @@ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ -#include -#include + +#include "cairoint.h" #include "cairo-xlib-private.h" #include -#include /* For XESetCloseDisplay */ #include static int @@ -133,7 +132,7 @@ get_integer_default (Display *dpy, #endif static void -_cairo_xlib_init_screen_font_options (cairo_xlib_screen_info_t *info) +_cairo_xlib_init_screen_font_options (Display *dpy, cairo_xlib_screen_info_t *info) { cairo_bool_t xft_hinting; cairo_bool_t xft_antialias; @@ -143,23 +142,23 @@ _cairo_xlib_init_screen_font_options (cairo_xlib_screen_info_t *info) cairo_subpixel_order_t subpixel_order; cairo_hint_style_t hint_style; - if (!get_boolean_default (info->display, "antialias", &xft_antialias)) + if (!get_boolean_default (dpy, "antialias", &xft_antialias)) xft_antialias = TRUE; - if (!get_boolean_default (info->display, "hinting", &xft_hinting)) + if (!get_boolean_default (dpy, "hinting", &xft_hinting)) xft_hinting = TRUE; - if (!get_integer_default (info->display, "hintstyle", &xft_hintstyle)) + if (!get_integer_default (dpy, "hintstyle", &xft_hintstyle)) xft_hintstyle = FC_HINT_FULL; - if (!get_integer_default (info->display, "rgba", &xft_rgba)) + if (!get_integer_default (dpy, "rgba", &xft_rgba)) { xft_rgba = FC_RGBA_UNKNOWN; #if RENDER_MAJOR > 0 || RENDER_MINOR >= 6 if (info->has_render) { - int render_order = XRenderQuerySubpixelOrder (info->display, + int render_order = XRenderQuerySubpixelOrder (dpy, XScreenNumberOfScreen (info->screen)); switch (render_order) @@ -237,235 +236,183 @@ _cairo_xlib_init_screen_font_options (cairo_xlib_screen_info_t *info) antialias = CAIRO_ANTIALIAS_NONE; } - _cairo_font_options_init_default (&info->font_options); cairo_font_options_set_hint_style (&info->font_options, hint_style); cairo_font_options_set_antialias (&info->font_options, antialias); cairo_font_options_set_subpixel_order (&info->font_options, subpixel_order); + cairo_font_options_set_hint_metrics (&info->font_options, CAIRO_HINT_METRICS_ON); } -CAIRO_MUTEX_DECLARE(_xlib_screen_mutex); - -static cairo_xlib_screen_info_t *_cairo_xlib_screen_list = NULL; - -static int -_cairo_xlib_close_display (Display *dpy, XExtCodes *codes) +cairo_xlib_screen_info_t * +_cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t *info) { - cairo_xlib_screen_info_t *info, **prev, *next; - - /* - * Unhook from the global list - */ - CAIRO_MUTEX_LOCK (_xlib_screen_mutex); - - prev = &_cairo_xlib_screen_list; - for (info = _cairo_xlib_screen_list; info; info = next) { - next = info->next; - if (info->display == dpy) { - *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); - } else { - prev = &info->next; - } - } - *prev = NULL; - CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); - - /* Return value in accordance with requirements of - * XESetCloseDisplay */ - return 0; -} - -static void -_cairo_xlib_screen_info_reset (void) -{ - cairo_xlib_screen_info_t *info, *next; - - /* - * Delete everything in the list. - */ - CAIRO_MUTEX_LOCK (_xlib_screen_mutex); - - 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); - } - - _cairo_xlib_screen_list = NULL; - - CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); - -} - -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; - int event_base, error_base; - XExtCodes *codes; - cairo_bool_t seen_display = FALSE; - - for (prev = &_cairo_xlib_screen_list; (info = *prev); prev = &(*prev)->next) - { - if (info->display == dpy) { - seen_display = TRUE; - if (info->screen == screen || screen == NULL) { - /* - * MRU the list - */ - if (prev != &_cairo_xlib_screen_list) { - *prev = info->next; - info->next = _cairo_xlib_screen_list; - _cairo_xlib_screen_list = info; - } - break; - } - } - } - - if (info) - return info; - - if (screen == NULL) - return NULL; - - info = malloc (sizeof (cairo_xlib_screen_info_t)); - if (!info) + if (info == NULL) return NULL; - if (!seen_display) { - codes = XAddExtension (dpy); - if (!codes) { - free (info); - return NULL; - } - - XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display); - } - - info->display = dpy; - info->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; + assert (info->ref_count > 0); + info->ref_count++; return info; } + +void +_cairo_xlib_screen_info_close_display (cairo_xlib_screen_info_t *info) +{ + int i; + + for (i = 0; i < ARRAY_LENGTH (info->gc); i++) { + if (info->gc[i] != NULL) { + XFreeGC (info->display->display, info->gc[i]); + info->gc[i] = NULL; + } + } +} + +void +_cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info) +{ + cairo_xlib_screen_info_t **prev; + cairo_xlib_screen_info_t *list; + + if (info == NULL) + return; + + assert (info->ref_count > 0); + if (--info->ref_count) + return; + + CAIRO_MUTEX_LOCK (info->display->mutex); + for (prev = &info->display->screens; (list = *prev); prev = &list->next) { + if (list == info) { + *prev = info->next; + break; + } + } + CAIRO_MUTEX_UNLOCK (info->display->mutex); + + _cairo_xlib_screen_info_close_display (info); + + _cairo_xlib_display_destroy (info->display); + + free (info); +} + cairo_xlib_screen_info_t * _cairo_xlib_screen_info_get (Display *dpy, Screen *screen) { - cairo_xlib_screen_info_t *info; + cairo_xlib_display_t *display; + cairo_xlib_screen_info_t *info = NULL, **prev; - /* 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); + display = _cairo_xlib_display_get (dpy); + if (display == NULL) + return NULL; - info = _cairo_xlib_screen_info_get_unlocked (dpy, screen); + CAIRO_MUTEX_LOCK (display->mutex); + if (display->closed) { + CAIRO_MUTEX_UNLOCK (display->mutex); + goto DONE; + } - 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) { + for (prev = &display->screens; (info = *prev); prev = &(*prev)->next) { + if (info->screen == screen) { /* * MRU the list */ - if (prev != &info->close_display_hooks) { - *prev = hook->next; - hook->next = info->close_display_hooks; - info->close_display_hooks = hook; + if (prev != &display->screens) { + *prev = info->next; + info->next = display->screens; + display->screens = info; } break; } } + CAIRO_MUTEX_UNLOCK (display->mutex); - 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; - } + if (info != NULL) { + info = _cairo_xlib_screen_info_reference (info); + } else { + info = malloc (sizeof (cairo_xlib_screen_info_t)); + if (info != NULL) { + info->ref_count = 2; /* Add one for display cache */ + info->display = _cairo_xlib_display_reference (display); + info->screen = screen; + info->has_render = FALSE; + _cairo_font_options_init_default (&info->font_options); + memset (info->gc, 0, sizeof (info->gc)); + info->gc_needs_clip_reset = 0; - success = TRUE; - unlock: - CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); - return success; -} + if (screen) { + int event_base, error_base; + info->has_render = (XRenderQueryExtension (dpy, &event_base, &error_base) && + (XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0)); + _cairo_xlib_init_screen_font_options (dpy, info); + } -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; + CAIRO_MUTEX_LOCK (display->mutex); + info->next = display->screens; + display->screens = info; + CAIRO_MUTEX_UNLOCK (display->mutex); } } -unlock: - CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); +DONE: + _cairo_xlib_display_destroy (display); + + return info; } -void -_cairo_xlib_screen_reset_static_data (void) +static int +depth_to_index (int depth) { - _cairo_xlib_screen_info_reset (); + switch(depth){ + case 1: return 1; + case 8: return 2; + case 12: return 3; + case 15: return 4; + case 16: return 5; + case 24: return 6; + case 30: return 7; + case 32: return 8; + } + return 0; +} + +GC +_cairo_xlib_screen_get_gc (cairo_xlib_screen_info_t *info, int depth) +{ + GC gc; + + depth = depth_to_index (depth); + + gc = info->gc[depth]; + info->gc[depth] = NULL; + + if (info->gc_needs_clip_reset & (1 << depth)) { + XSetClipMask(info->display->display, gc, None); + info->gc_needs_clip_reset &= ~(1 << depth); + } + + return gc; +} + +cairo_status_t +_cairo_xlib_screen_put_gc (cairo_xlib_screen_info_t *info, int depth, GC gc, cairo_bool_t reset_clip) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + depth = depth_to_index (depth); + + if (info->gc[depth] != NULL) { + status = _cairo_xlib_display_queue_work (info->display, + (cairo_xlib_notify_func) XFreeGC, + info->gc[depth], + NULL); + } + + info->gc[depth] = gc; + if (reset_clip) + info->gc_needs_clip_reset |= 1 << depth; + else + info->gc_needs_clip_reset &= ~(1 << depth); + + return status; } diff --git a/gfx/cairo/cairo/src/cairo-xlib-surface-private.h b/gfx/cairo/cairo/src/cairo-xlib-surface-private.h new file mode 100644 index 000000000000..3bbf43e23593 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-xlib-surface-private.h @@ -0,0 +1,100 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + */ + +#ifndef CAIRO_XLIB_SURFACE_PRIVATE_H +#define CAIRO_XLIB_SURFACE_PRIVATE_H + +#include "cairo-xlib.h" + +#include "cairo-surface-private.h" + +typedef struct _cairo_xlib_surface cairo_xlib_surface_t; + +struct _cairo_xlib_surface { + cairo_surface_t base; + + Display *dpy; + cairo_xlib_screen_info_t *screen_info; + + GC gc; + Drawable drawable; + Screen *screen; + cairo_bool_t owns_pixmap; + Visual *visual; + + int use_pixmap; + + int render_major; + int render_minor; + + /* TRUE if the server has a bug with repeating pictures + * + * https://bugs.freedesktop.org/show_bug.cgi?id=3566 + * + * We can't test for this because it depends on whether the + * picture is in video memory or not. + * + * We also use this variable as a guard against a second + * independent bug with transformed repeating pictures: + * + * http://lists.freedesktop.org/archives/cairo/2004-September/001839.html + * + * Both are fixed in xorg >= 6.9 and hopefully in > 6.8.2, so + * we can reuse the test for now. + */ + cairo_bool_t buggy_repeat; + + int width; + int height; + int depth; + + Picture dst_picture, src_picture; + + unsigned int clip_dirty; + cairo_bool_t have_clip_rects; + XRectangle embedded_clip_rects[4]; + XRectangle *clip_rects; + int num_clip_rects; + + XRenderPictFormat *xrender_format; + cairo_filter_t filter; + int repeat; + XTransform xtransform; +}; + +enum { + CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC = 0x01, + CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE = 0x02, + CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL = 0x03 +}; + +#endif /* CAIRO_XLIB_SURFACE_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-xlib-surface.c b/gfx/cairo/cairo/src/cairo-xlib-surface.c index be285cd46a92..db5c15540e4a 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-surface.c +++ b/gfx/cairo/cairo/src/cairo-xlib-surface.c @@ -39,8 +39,8 @@ #include "cairoint.h" #include "cairo-xlib.h" #include "cairo-xlib-xrender.h" -#include "cairo-xlib-test.h" #include "cairo-xlib-private.h" +#include "cairo-xlib-surface-private.h" #include "cairo-clip-private.h" #include #include @@ -49,9 +49,7 @@ typedef int (*cairo_xlib_error_func_t) (Display *display, XErrorEvent *event); -typedef struct _cairo_xlib_surface cairo_xlib_surface_t; - -static void +static cairo_status_t _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface); static void @@ -82,52 +80,11 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, #define CAIRO_ASSUME_PIXMAP 20 -struct _cairo_xlib_surface { - cairo_surface_t base; - - Display *dpy; - cairo_xlib_screen_info_t *screen_info; - - GC gc; - Drawable drawable; - Screen *screen; - cairo_bool_t owns_pixmap; - Visual *visual; - - int use_pixmap; - - int render_major; - int render_minor; - - /* TRUE if the server has a bug with repeating pictures - * - * https://bugs.freedesktop.org/show_bug.cgi?id=3566 - * - * We can't test for this because it depends on whether the - * picture is in video memory or not. - * - * We also use this variable as a guard against a second - * independent bug with transformed repeating pictures: - * - * http://lists.freedesktop.org/archives/cairo/2004-September/001839.html - * - * Both are fixed in xorg >= 6.9 and hopefully in > 6.8.2, so - * we can reuse the test for now. - */ - cairo_bool_t buggy_repeat; - - int width; - int height; - int depth; - - Picture dst_picture, src_picture; - - cairo_bool_t have_clip_rects; - XRectangle *clip_rects; - int num_clip_rects; - - XRenderPictFormat *xrender_format; -}; +static const XTransform identity = { { + { 1 << 16, 0x00000, 0x00000 }, + { 0x00000, 1 << 16, 0x00000 }, + { 0x00000, 0x00000, 1 << 16 }, +} }; #define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \ (((surface)->render_major > major) || \ @@ -151,25 +108,6 @@ struct _cairo_xlib_surface { #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) #define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) -static cairo_bool_t cairo_xlib_render_disabled = FALSE; - -/** - * _cairo_xlib_test_disable_render: - * - * Disables the use of the RENDER extension. - * - * - * This function is only intended for internal - * testing use within the cairo distribution. It is not installed in - * any public header file. - * - **/ -void -_cairo_xlib_test_disable_render (void) -{ - cairo_xlib_render_disabled = TRUE; -} - static int _CAIRO_FORMAT_DEPTH (cairo_format_t format) { @@ -236,6 +174,7 @@ _cairo_xlib_surface_create_similar_with_format (void *abstract_src, xrender_format, width, height); if (surface->base.status != CAIRO_STATUS_SUCCESS) { + XFreePixmap (dpy, pix); _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_surface_t*) &_cairo_surface_nil; } @@ -281,6 +220,8 @@ _cairo_xlib_surface_create_similar (void *abstract_src, cairo_xlib_surface_t *surface; Pixmap pix; + _cairo_xlib_display_notify (src->screen_info->display); + /* Start by examining the surface's XRenderFormat, or if it * doesn't have one, then look one up through its visual (in the * case of a bitmap, it won't even have that). */ @@ -313,6 +254,7 @@ _cairo_xlib_surface_create_similar (void *abstract_src, xrender_format, width, height); if (surface->base.status != CAIRO_STATUS_SUCCESS) { + XFreePixmap (src->dpy, pix); _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_surface_t*) &_cairo_surface_nil; } @@ -326,24 +268,68 @@ static cairo_status_t _cairo_xlib_surface_finish (void *abstract_surface) { cairo_xlib_surface_t *surface = abstract_surface; - if (surface->dst_picture != None) - XRenderFreePicture (surface->dpy, surface->dst_picture); + cairo_xlib_display_t *display = surface->screen_info ? + surface->screen_info->display : + NULL; + cairo_status_t status = CAIRO_STATUS_SUCCESS; - if (surface->src_picture != None) - XRenderFreePicture (surface->dpy, surface->src_picture); + if (surface->dst_picture != None) { + cairo_status_t status2; + status2 = _cairo_xlib_display_queue_resource (display, + XRenderFreePicture, + surface->dst_picture); + if (status2 == CAIRO_STATUS_SUCCESS) + surface->dst_picture = None; + else if (status == CAIRO_STATUS_SUCCESS) + status = status2; + } - if (surface->owns_pixmap) - XFreePixmap (surface->dpy, surface->drawable); + if (surface->src_picture != None) { + cairo_status_t status2; + status2 = _cairo_xlib_display_queue_resource (display, + XRenderFreePicture, + surface->src_picture); + if (status2 == CAIRO_STATUS_SUCCESS) + surface->src_picture = None; + else if (status == CAIRO_STATUS_SUCCESS) + status = status2; + } - if (surface->gc != NULL) - XFreeGC (surface->dpy, surface->gc); + if (surface->owns_pixmap) { + cairo_status_t status2; + status2 = _cairo_xlib_display_queue_resource (display, + (cairo_xlib_notify_resource_func) XFreePixmap, + surface->drawable); + if (status2 == CAIRO_STATUS_SUCCESS) { + surface->owns_pixmap = FALSE; + surface->drawable = None; + } else if (status == CAIRO_STATUS_SUCCESS) + status = status2; + } - if (surface->clip_rects != NULL) + if (surface->gc != NULL) { + cairo_status_t status2; + status2 = _cairo_xlib_screen_put_gc (surface->screen_info, + surface->depth, + surface->gc, + surface->have_clip_rects); + surface->gc = NULL; + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + } + + if (surface->clip_rects != surface->embedded_clip_rects) free (surface->clip_rects); - surface->dpy = NULL; + if (surface->screen_info != NULL) + _cairo_xlib_screen_info_destroy (surface->screen_info); - return CAIRO_STATUS_SUCCESS; + if (surface->dpy != NULL) { + _cairo_xlib_remove_close_display_hooks (surface->dpy, surface); + surface->dpy = NULL; + } + + return status; } static int @@ -587,22 +573,27 @@ _get_image_surface (cairo_xlib_surface_t *surface, * retry, but to keep things simple, we just create a * temporary pixmap */ - Pixmap pixmap = XCreatePixmap (surface->dpy, + Pixmap pixmap; + cairo_status_t status = _cairo_xlib_surface_ensure_gc (surface); + if (status) + return status; + + pixmap = XCreatePixmap (surface->dpy, surface->drawable, x2 - x1, y2 - y1, surface->depth); - _cairo_xlib_surface_ensure_gc (surface); + if (pixmap) { + XCopyArea (surface->dpy, surface->drawable, pixmap, surface->gc, + x1, y1, x2 - x1, y2 - y1, 0, 0); - XCopyArea (surface->dpy, surface->drawable, pixmap, surface->gc, - x1, y1, x2 - x1, y2 - y1, 0, 0); + ximage = XGetImage (surface->dpy, + pixmap, + 0, 0, + x2 - x1, y2 - y1, + AllPlanes, ZPixmap); - ximage = XGetImage (surface->dpy, - pixmap, - 0, 0, - x2 - x1, y2 - y1, - AllPlanes, ZPixmap); - - XFreePixmap (surface->dpy, pixmap); + XFreePixmap (surface->dpy, pixmap); + } } if (!ximage) return CAIRO_STATUS_NO_MEMORY; @@ -701,21 +692,33 @@ _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface) static void _cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface) { - if (surface->have_clip_rects) + if (surface->have_clip_rects) { XRenderSetPictureClipRectangles (surface->dpy, surface->dst_picture, 0, 0, surface->clip_rects, surface->num_clip_rects); + } else { + XRenderPictureAttributes pa; + pa.clip_mask = None; + XRenderChangePicture (surface->dpy, surface->dst_picture, + CPClipMask, &pa); + } + + surface->clip_dirty &= ~CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE; } static void _cairo_xlib_surface_set_gc_clip_rects (cairo_xlib_surface_t *surface) { - if (surface->have_clip_rects) + if (surface->have_clip_rects) { XSetClipRectangles(surface->dpy, surface->gc, 0, 0, surface->clip_rects, surface->num_clip_rects, YXSorted); + } else + XSetClipMask (surface->dpy, surface->gc, None); + + surface->clip_dirty &= ~CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC; } static void @@ -727,22 +730,31 @@ _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface) surface->xrender_format, 0, NULL); _cairo_xlib_surface_set_picture_clip_rects (surface); - } - + } else if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE) + _cairo_xlib_surface_set_picture_clip_rects (surface); } -static void +static cairo_status_t _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface) { XGCValues gcv; - if (surface->gc) - return; + if (surface->gc == NULL) { + surface->gc = _cairo_xlib_screen_get_gc (surface->screen_info, + surface->depth); + if (surface->gc == NULL) { + gcv.graphics_exposures = False; + surface->gc = XCreateGC (surface->dpy, surface->drawable, + GCGraphicsExposures, &gcv); + if (!surface->gc) + return CAIRO_STATUS_NO_MEMORY; + } - gcv.graphics_exposures = False; - surface->gc = XCreateGC (surface->dpy, surface->drawable, - GCGraphicsExposures, &gcv); - _cairo_xlib_surface_set_gc_clip_rects (surface); + _cairo_xlib_surface_set_gc_clip_rects (surface); + } else if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC) + _cairo_xlib_surface_set_gc_clip_rects (surface); + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -758,6 +770,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface, XImage ximage; unsigned int bpp, alpha, red, green, blue; int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst; + cairo_status_t status; pixman_format_get_masks (pixman_image_get_format (image->pixman_image), &bpp, &alpha, &red, &green, &blue); @@ -780,7 +793,9 @@ _draw_image_surface (cairo_xlib_surface_t *surface, XInitImage (&ximage); - _cairo_xlib_surface_ensure_gc (surface); + status = _cairo_xlib_surface_ensure_gc (surface); + if (status) + return status; XPutImage(surface->dpy, surface->drawable, surface->gc, &ximage, src_x, src_y, dst_x, dst_y, width, height); @@ -798,6 +813,8 @@ _cairo_xlib_surface_acquire_source_image (void *abstract_surf cairo_image_surface_t *image; cairo_status_t status; + _cairo_xlib_display_notify (surface->screen_info->display); + status = _get_image_surface (surface, NULL, &image, NULL); if (status) return status; @@ -827,6 +844,8 @@ _cairo_xlib_surface_acquire_dest_image (void *abstract_surfac cairo_image_surface_t *image; cairo_status_t status; + _cairo_xlib_display_notify (surface->screen_info->display); + status = _get_image_surface (surface, interest_rect, &image, image_rect_out); if (status) return status; @@ -876,6 +895,9 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface, { cairo_xlib_surface_t *surface = abstract_surface; cairo_xlib_surface_t *clone; + cairo_status_t status; + + _cairo_xlib_display_notify (surface->screen_info->display); if (src->backend == surface->base.backend ) { cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src; @@ -897,8 +919,12 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface, if (clone->base.status) return CAIRO_STATUS_NO_MEMORY; - _draw_image_surface (clone, image_src, src_x, src_y, - width, height, src_x, src_y); + status = _draw_image_surface (clone, image_src, src_x, src_y, + width, height, src_x, src_y); + if (status) { + cairo_surface_destroy (&clone->base); + return status; + } *clone_out = &clone->base; @@ -929,21 +955,14 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface, xtransform.matrix[2][1] = 0; xtransform.matrix[2][2] = _cairo_fixed_from_double (1); + if (memcmp (&xtransform, &surface->xtransform, sizeof (XTransform)) == 0) + return CAIRO_STATUS_SUCCESS; + if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) - { - static const XTransform identity = { { - { 1 << 16, 0x00000, 0x00000 }, - { 0x00000, 1 << 16, 0x00000 }, - { 0x00000, 0x00000, 1 << 16 }, - } }; - - if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0) - return CAIRO_STATUS_SUCCESS; - return CAIRO_INT_STATUS_UNSUPPORTED; - } XRenderSetPictureTransform (surface->dpy, surface->src_picture, &xtransform); + surface->xtransform = xtransform; return CAIRO_STATUS_SUCCESS; } @@ -957,6 +976,9 @@ _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface, if (!surface->src_picture) return CAIRO_STATUS_SUCCESS; + if (surface->filter == filter) + return CAIRO_STATUS_SUCCESS; + if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) { if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) @@ -994,6 +1016,7 @@ _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface, XRenderSetPictureFilter (surface->dpy, surface->src_picture, (char *) render_filter, NULL, 0); + surface->filter = filter; return CAIRO_STATUS_SUCCESS; } @@ -1007,17 +1030,21 @@ _cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat) if (!surface->src_picture) return CAIRO_STATUS_SUCCESS; + if (surface->repeat == repeat) + return CAIRO_STATUS_SUCCESS; + mask = CPRepeat; pa.repeat = repeat; XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa); + surface->repeat = repeat; return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t -_cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface, - cairo_surface_attributes_t *attributes) +_cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface, + cairo_surface_attributes_t *attributes) { cairo_int_status_t status; @@ -1029,15 +1056,17 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface, switch (attributes->extend) { case CAIRO_EXTEND_NONE: - _cairo_xlib_surface_set_repeat (surface, 0); + status = _cairo_xlib_surface_set_repeat (surface, 0); break; case CAIRO_EXTEND_REPEAT: - _cairo_xlib_surface_set_repeat (surface, 1); + status = _cairo_xlib_surface_set_repeat (surface, 1); break; case CAIRO_EXTEND_REFLECT: case CAIRO_EXTEND_PAD: - return CAIRO_INT_STATUS_UNSUPPORTED; + status = CAIRO_INT_STATUS_UNSUPPORTED; } + if (status) + return status; status = _cairo_xlib_surface_set_filter (surface, attributes->filter); if (status) @@ -1204,7 +1233,12 @@ _recategorize_composite_operation (cairo_xlib_surface_t *dst, { cairo_bool_t is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL); - cairo_bool_t needs_alpha_composite = + cairo_bool_t needs_alpha_composite; + + if (!_cairo_surface_is_xlib (&src->base)) + return DO_UNSUPPORTED; + + needs_alpha_composite = _operator_needs_alpha_composite (op, _surface_has_alpha (src)); if (!have_mask && @@ -1297,6 +1331,9 @@ _cairo_xlib_surface_composite (cairo_operator_t op, cairo_int_status_t status; composite_operation_t operation; int itx, ity; + cairo_bool_t is_integer_translation; + + _cairo_xlib_display_notify (dst->screen_info->display); if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1317,6 +1354,16 @@ _cairo_xlib_surface_composite (cairo_operator_t op, if (status) return status; + /* check for fallback surfaces that we cannot handle ... */ + if (!_cairo_surface_is_xlib (&src->base)) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto BAIL; + } + if (mask != NULL && !_cairo_surface_is_xlib (&mask->base)) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto BAIL; + } + operation = _recategorize_composite_operation (dst, op, src, &src_attr, mask_pattern != NULL); if (operation == DO_UNSUPPORTED) { @@ -1364,7 +1411,9 @@ _cairo_xlib_surface_composite (cairo_operator_t op, break; case DO_XCOPYAREA: - _cairo_xlib_surface_ensure_gc (dst); + status = _cairo_xlib_surface_ensure_gc (dst); + if (status) + goto BAIL; XCopyArea (dst->dpy, src->drawable, dst->drawable, @@ -1384,8 +1433,13 @@ _cairo_xlib_surface_composite (cairo_operator_t op, * _recategorize_composite_operation. */ - _cairo_xlib_surface_ensure_gc (dst); - _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity); + status = _cairo_xlib_surface_ensure_gc (dst); + if (status) + goto BAIL; + is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix, + &itx, &ity); + /* This is a pre-condition for DO_XTILE. */ + assert (is_integer_translation); XSetTSOrigin (dst->dpy, dst->gc, - (itx + src_attr.x_offset), - (ity + src_attr.y_offset)); @@ -1430,6 +1484,8 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, cairo_xlib_surface_t *surface = abstract_surface; XRenderColor render_color; + _cairo_xlib_display_notify (surface->screen_info->display); + if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1562,6 +1618,8 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, int render_src_x, render_src_y; XRenderPictFormat *pict_format; + _cairo_xlib_display_notify (dst->screen_info->display); + if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1669,38 +1727,31 @@ static cairo_int_status_t _cairo_xlib_surface_set_clip_region (void *abstract_surface, pixman_region16_t *region) { - cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; + cairo_xlib_surface_t *surface = abstract_surface; - if (surface->clip_rects) { + if (surface->have_clip_rects == FALSE && region == NULL) + return CAIRO_STATUS_SUCCESS; + + if (surface->clip_rects != surface->embedded_clip_rects) { free (surface->clip_rects); - surface->clip_rects = NULL; + surface->clip_rects = surface->embedded_clip_rects; } surface->have_clip_rects = FALSE; surface->num_clip_rects = 0; - if (region == NULL) { - if (surface->gc) - XSetClipMask (surface->dpy, surface->gc, None); - - if (surface->xrender_format && surface->dst_picture) { - XRenderPictureAttributes pa; - pa.clip_mask = None; - XRenderChangePicture (surface->dpy, surface->dst_picture, - CPClipMask, &pa); - } - } else { + if (region != NULL) { pixman_box16_t *boxes; XRectangle *rects = NULL; int n_boxes, i; n_boxes = pixman_region_num_rects (region); - if (n_boxes > 0) { + if (n_boxes > ARRAY_LENGTH (surface->embedded_clip_rects)) { rects = malloc (sizeof(XRectangle) * n_boxes); if (rects == NULL) return CAIRO_STATUS_NO_MEMORY; - } else { - rects = NULL; + }else { + rects = surface->embedded_clip_rects; } boxes = pixman_region_rects (region); @@ -1715,14 +1766,10 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, surface->have_clip_rects = TRUE; surface->clip_rects = rects; surface->num_clip_rects = n_boxes; - - if (surface->gc) - _cairo_xlib_surface_set_gc_clip_rects (surface); - - if (surface->dst_picture) - _cairo_xlib_surface_set_picture_clip_rects (surface); } + surface->clip_dirty = CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL; + return CAIRO_STATUS_SUCCESS; } @@ -1757,6 +1804,46 @@ static void _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, cairo_scaled_font_t *scaled_font); +static cairo_bool_t +_cairo_xlib_surface_is_similar (void *surface_a, + void *surface_b, + cairo_content_t content) +{ + cairo_xlib_surface_t *a = surface_a; + cairo_xlib_surface_t *b = surface_b; + XRenderPictFormat *xrender_format = b->xrender_format; + + if (!_cairo_xlib_surface_same_screen (a, b)) + return FALSE; + + /* now inspect the content to check that a is similar to b */ + if (xrender_format == NULL && b->visual != NULL) + xrender_format = XRenderFindVisualFormat (b->dpy, b->visual); + + if (xrender_format == NULL || + _xrender_format_to_content (xrender_format) != content) + { + xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (b->dpy, + _cairo_format_from_content (content)); + } + + + return a->xrender_format == xrender_format; +} + +static cairo_status_t +_cairo_xlib_surface_reset (void *abstract_surface) +{ + cairo_xlib_surface_t *surface = abstract_surface; + cairo_status_t status; + + status = _cairo_xlib_surface_set_clip_region (surface, NULL); + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} + static const cairo_surface_backend_t cairo_xlib_surface_backend = { CAIRO_SURFACE_TYPE_XLIB, _cairo_xlib_surface_create_similar, @@ -1786,7 +1873,10 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = { NULL, /* stroke */ NULL, /* fill */ _cairo_xlib_surface_show_glyphs, - NULL /* snapshot */ + NULL, /* snapshot */ + _cairo_xlib_surface_is_similar, + + _cairo_xlib_surface_reset }; /** @@ -1803,6 +1893,35 @@ _cairo_surface_is_xlib (cairo_surface_t *surface) return surface->backend == &cairo_xlib_surface_backend; } +static void +_cairo_xlib_surface_detach_display (Display *dpy, void *data) +{ + cairo_xlib_surface_t *surface = data; + + surface->dpy = NULL; + + if (surface->dst_picture != None) { + XRenderFreePicture (dpy, surface->dst_picture); + surface->dst_picture = None; + } + + if (surface->src_picture != None) { + XRenderFreePicture (dpy, surface->src_picture); + surface->src_picture = None; + } + + if (surface->owns_pixmap) { + XFreePixmap (dpy, surface->drawable); + surface->drawable = None; + surface->owns_pixmap = FALSE; + } + + if (surface->gc != NULL) { + XFreeGC (dpy, surface->gc); + surface->gc = NULL; + } +} + static cairo_surface_t * _cairo_xlib_surface_create_internal (Display *dpy, Drawable drawable, @@ -1824,6 +1943,15 @@ _cairo_xlib_surface_create_internal (Display *dpy, surface = malloc (sizeof (cairo_xlib_surface_t)); if (surface == NULL) { + _cairo_xlib_screen_info_destroy (screen_info); + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } + + if (! _cairo_xlib_add_close_display_hook (dpy, + _cairo_xlib_surface_detach_display, surface, surface)) { + free (surface); + _cairo_xlib_screen_info_destroy (screen_info); _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_surface_t*) &_cairo_surface_nil; } @@ -1849,8 +1977,7 @@ _cairo_xlib_surface_create_internal (Display *dpy, ; } - if (cairo_xlib_render_disabled || - ! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) { + if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) { surface->render_major = -1; surface->render_minor = -1; } @@ -1887,9 +2014,6 @@ _cairo_xlib_surface_create_internal (Display *dpy, } else if (strstr (ServerVendor (dpy), "XFree86") != NULL) { if (VendorRelease (dpy) <= 40500000) surface->buggy_repeat = TRUE; - } else if (strstr (ServerVendor (dpy), "Sun Microsystems, Inc.") != NULL) { - if (VendorRelease (dpy) <= 60900000) - surface->buggy_repeat = TRUE; } surface->dst_picture = None; @@ -1898,9 +2022,12 @@ _cairo_xlib_surface_create_internal (Display *dpy, surface->visual = visual; surface->xrender_format = xrender_format; surface->depth = depth; + surface->filter = CAIRO_FILTER_NEAREST; + surface->repeat = FALSE; + surface->xtransform = identity; surface->have_clip_rects = FALSE; - surface->clip_rects = NULL; + surface->clip_rects = surface->embedded_clip_rects; surface->num_clip_rects = 0; return (cairo_surface_t *) surface; @@ -2022,9 +2149,7 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy, return _cairo_xlib_surface_create_internal (dpy, drawable, screen, NULL, format, width, height, 0); } -#ifdef MOZILLA_CAIRO_NOT_DEFINED slim_hidden_def (cairo_xlib_surface_create_with_xrender_format); -#endif /** * cairo_xlib_surface_set_size: @@ -2079,6 +2204,7 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface, int height) { cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *)abstract_surface; + cairo_status_t status; if (! _cairo_surface_is_xlib (abstract_surface)) { _cairo_surface_set_error (abstract_surface, CAIRO_STATUS_SURFACE_TYPE_MISMATCH); @@ -2090,14 +2216,31 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface, return; if (surface->drawable != drawable) { - if (surface->dst_picture) - XRenderFreePicture (surface->dpy, surface->dst_picture); + if (surface->dst_picture != None) { + status = _cairo_xlib_display_queue_resource ( + surface->screen_info->display, + XRenderFreePicture, + surface->dst_picture); + if (status) { + _cairo_surface_set_error (&surface->base, status); + return; + } - if (surface->src_picture) - XRenderFreePicture (surface->dpy, surface->src_picture); + surface->dst_picture = None; + } - surface->dst_picture = None; - surface->src_picture = None; + if (surface->src_picture != None) { + status = _cairo_xlib_display_queue_resource ( + surface->screen_info->display, + XRenderFreePicture, + surface->src_picture); + if (status) { + _cairo_surface_set_error (&surface->base, status); + return; + } + + surface->src_picture = None; + } surface->drawable = drawable; } @@ -2275,19 +2418,21 @@ typedef struct _cairo_xlib_surface_font_private { static void _cairo_xlib_surface_remove_scaled_font (Display *dpy, - void *data) + void *data) { cairo_scaled_font_t *scaled_font = data; - cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; + cairo_xlib_surface_font_private_t *font_private; + + CAIRO_MUTEX_LOCK (scaled_font->mutex); + font_private = scaled_font->surface_private; + scaled_font->surface_private = NULL; _cairo_scaled_font_reset_cache (scaled_font); + CAIRO_MUTEX_UNLOCK (scaled_font->mutex); - /* separate function to avoid deadlock if we tried to remove the - * close display hook ala _cairo_xlib_surface_scaled_font_fini() */ - if (font_private) { + if (font_private != NULL) { XRenderFreeGlyphSet (font_private->dpy, font_private->glyphset); free (font_private); - scaled_font->surface_private = NULL; } } @@ -2298,15 +2443,18 @@ _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; + if (!_cairo_xlib_add_close_display_hook (dpy, + _cairo_xlib_surface_remove_scaled_font, + scaled_font, scaled_font)) { + free (font_private); + return CAIRO_STATUS_NO_MEMORY; + } + + font_private->dpy = dpy; font_private->format = format; font_private->xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT(dpy, format); @@ -2323,12 +2471,34 @@ _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); + cairo_xlib_display_t *display; + + _cairo_xlib_remove_close_display_hooks (font_private->dpy, scaled_font); + + display = _cairo_xlib_display_get (font_private->dpy); + if (display != NULL) { + cairo_status_t status = _cairo_xlib_display_queue_resource (display, + XRenderFreeGlyphSet, + font_private->glyphset); + (void) status; /* XXX cannot propagate failure */ + _cairo_xlib_display_destroy (display); + } + free (font_private); } } +struct _cairo_xlib_render_free_glyphs { + GlyphSet glyphset; + unsigned long glyph_index; +}; +static void _cairo_xlib_render_free_glyphs (Display *dpy, struct _cairo_xlib_render_free_glyphs *arg) +{ + XRenderFreeGlyphs (dpy, + arg->glyphset, + &arg->glyph_index, 1); +} + static void _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, cairo_scaled_font_t *scaled_font) @@ -2336,10 +2506,26 @@ _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; if (font_private != NULL && scaled_glyph->surface_private != NULL) { - unsigned long glyph_index = _cairo_scaled_glyph_index(scaled_glyph); - XRenderFreeGlyphs (font_private->dpy, - font_private->glyphset, - &glyph_index, 1); + cairo_xlib_display_t *display = _cairo_xlib_display_get (font_private->dpy); + if (display != NULL) { + struct _cairo_xlib_render_free_glyphs *arg = malloc (sizeof (*arg)); + if (arg != NULL) { + cairo_status_t status; + arg->glyphset = font_private->glyphset; + arg->glyph_index = _cairo_scaled_glyph_index (scaled_glyph); + status = _cairo_xlib_display_queue_work (display, + (cairo_xlib_notify_func) _cairo_xlib_render_free_glyphs, + arg, + free); + if (status) { + /* XXX cannot propagate failure */ + free (arg); + } + } + + _cairo_xlib_display_destroy (display); + + } } } @@ -2701,6 +2887,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst, int request_size = 0; _cairo_xlib_surface_ensure_dst_picture (dst); + _cairo_xlib_display_notify (dst->screen_info->display); for (i = 0; i < num_glyphs; i++) { int this_x, this_y; @@ -2795,7 +2982,11 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst, /* Send unsent glyphs to the server */ if (scaled_glyph->surface_private == NULL) { - _cairo_xlib_surface_add_glyph (dst->dpy, scaled_font, scaled_glyph); + status = _cairo_xlib_surface_add_glyph (dst->dpy, + scaled_font, + scaled_glyph); + if (status) + return status; scaled_glyph->surface_private = (void *) 1; } @@ -2890,7 +3081,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, * so PictOpClear was never used with CompositeText before. */ if (op == CAIRO_OPERATOR_CLEAR) { - _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE); + _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE, + CAIRO_CONTENT_COLOR); src_pattern = &solid_pattern.base; op = CAIRO_OPERATOR_DEST_OUT; } @@ -2900,6 +3092,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, 0, 0, 1, 1, (cairo_surface_t **) &src, &attributes); + if (status) + goto BAIL0; } else { cairo_rectangle_int16_t glyph_extents; @@ -2908,38 +3102,43 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, num_glyphs, &glyph_extents); if (status) - goto BAIL; + goto BAIL0; status = _cairo_pattern_acquire_surface (src_pattern, &dst->base, glyph_extents.x, glyph_extents.y, glyph_extents.width, glyph_extents.height, (cairo_surface_t **) &src, &attributes); + if (status) + goto BAIL0; } - if (status) - goto BAIL; - operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE); if (operation == DO_UNSUPPORTED) { status = CAIRO_INT_STATUS_UNSUPPORTED; - goto BAIL; + goto BAIL1; } status = _cairo_xlib_surface_set_attributes (src, &attributes); if (status) - goto BAIL; + goto BAIL1; - _cairo_xlib_surface_emit_glyphs (dst, (cairo_xlib_glyph_t *) glyphs, num_glyphs, - scaled_font, op, src, &attributes); - - BAIL: - _cairo_scaled_font_thaw_cache (scaled_font); + status = _cairo_xlib_surface_emit_glyphs (dst, + (cairo_xlib_glyph_t *) glyphs, + num_glyphs, + scaled_font, + op, + src, + &attributes); + BAIL1: if (src) _cairo_pattern_release_surface (src_pattern, &src->base, &attributes); if (src_pattern == &solid_pattern.base) _cairo_pattern_fini (&solid_pattern.base); + BAIL0: + _cairo_scaled_font_thaw_cache (scaled_font); + _cairo_xlib_display_notify (dst->screen_info->display); return status; } diff --git a/gfx/cairo/cairo/src/cairo-xlib-xrender.h b/gfx/cairo/cairo/src/cairo-xlib-xrender.h index f3b3726ef7a7..f5c35dcd4685 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-xrender.h +++ b/gfx/cairo/cairo/src/cairo-xlib-xrender.h @@ -41,6 +41,7 @@ #if CAIRO_HAS_XLIB_SURFACE +#include #include CAIRO_BEGIN_DECLS diff --git a/gfx/cairo/cairo/src/cairo.c b/gfx/cairo/cairo/src/cairo.c index 21303debd053..6859e45b56c3 100644 --- a/gfx/cairo/cairo/src/cairo.c +++ b/gfx/cairo/cairo/src/cairo.c @@ -44,7 +44,7 @@ #define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */ -static const cairo_t cairo_nil = { +static const cairo_t _cairo_nil = { CAIRO_REF_COUNT_INVALID, /* ref_count */ CAIRO_STATUS_NO_MEMORY, /* status */ { 0, 0, 0, NULL }, /* user_data */ @@ -189,25 +189,28 @@ cairo_t * cairo_create (cairo_surface_t *target) { cairo_t *cr; + cairo_status_t status; + + /* special case OOM in order to avoid another allocation */ + if (target && target->status == CAIRO_STATUS_NO_MEMORY) + return (cairo_t *) &_cairo_nil; cr = malloc (sizeof (cairo_t)); if (cr == NULL) - return (cairo_t *) &cairo_nil; + return (cairo_t *) &_cairo_nil; cr->ref_count = 1; cr->status = CAIRO_STATUS_SUCCESS; _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) { - _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); - } + cr->gstate = cr->gstate_tail; + status = _cairo_gstate_init (cr->gstate, target); + + if (status) + _cairo_set_error (cr, status); return cr; } @@ -260,10 +263,8 @@ cairo_destroy (cairo_t *cr) return; while (cr->gstate != cr->gstate_tail) { - cairo_gstate_t *tmp = cr->gstate; - cr->gstate = tmp->next; - - _cairo_gstate_destroy (tmp); + if (_cairo_gstate_restore (&cr->gstate)) + break; } _cairo_gstate_fini (cr->gstate); @@ -368,20 +369,15 @@ cairo_get_reference_count (cairo_t *cr) void cairo_save (cairo_t *cr) { - cairo_gstate_t *top; + cairo_status_t status; if (cr->status) return; - top = _cairo_gstate_clone (cr->gstate); - - if (top == NULL) { - _cairo_set_error (cr, CAIRO_STATUS_NO_MEMORY); - return; + status = _cairo_gstate_save (&cr->gstate); + if (status) { + _cairo_set_error (cr, status); } - - top->next = cr->gstate; - cr->gstate = top; } slim_hidden_def(cairo_save); @@ -396,20 +392,15 @@ slim_hidden_def(cairo_save); void cairo_restore (cairo_t *cr) { - cairo_gstate_t *top; + cairo_status_t status; if (cr->status) return; - if (cr->gstate == cr->gstate_tail) { - _cairo_set_error (cr, CAIRO_STATUS_INVALID_RESTORE); - return; + status = _cairo_gstate_restore (&cr->gstate); + if (status) { + _cairo_set_error (cr, status); } - - top = cr->gstate; - cr->gstate = top->next; - - _cairo_gstate_destroy (top); } slim_hidden_def(cairo_restore); @@ -488,12 +479,18 @@ cairo_push_group_with_content (cairo_t *cr, cairo_content_t content) { cairo_status_t status; cairo_rectangle_int16_t extents; - cairo_surface_t *group_surface = NULL; + cairo_surface_t *parent_surface, *group_surface = NULL; + if (cr->status) + return; + + parent_surface = _cairo_gstate_get_target (cr->gstate); /* Get the extents that we'll use in creating our new group surface */ - _cairo_surface_get_extents (_cairo_gstate_get_target (cr->gstate), &extents); + status = _cairo_surface_get_extents (parent_surface, &extents); + if (status) + goto bail; status = _cairo_clip_intersect_to_rectangle (_cairo_gstate_get_clip (cr->gstate), &extents); - if (status != CAIRO_STATUS_SUCCESS) + if (status) goto bail; group_surface = cairo_surface_create_similar (_cairo_gstate_get_target (cr->gstate), @@ -510,15 +507,15 @@ cairo_push_group_with_content (cairo_t *cr, cairo_content_t content) * device offsets, so we want to set our own surface offsets from /that/, * and not from the device origin. */ cairo_surface_set_device_offset (group_surface, - cr->gstate->target->device_transform.x0 - extents.x, - cr->gstate->target->device_transform.y0 - extents.y); + parent_surface->device_transform.x0 - extents.x, + parent_surface->device_transform.y0 - extents.y); /* create a new gstate for the redirect */ cairo_save (cr); if (cr->status) goto bail; - _cairo_gstate_redirect_target (cr->gstate, group_surface); + status = _cairo_gstate_redirect_target (cr->gstate, group_surface); bail: cairo_surface_destroy (group_surface); @@ -555,6 +552,9 @@ cairo_pop_group (cairo_t *cr) cairo_pattern_t *group_pattern = NULL; cairo_matrix_t group_matrix; + if (cr->status) + return (cairo_pattern_t*) &_cairo_pattern_nil.base; + /* Grab the active surfaces */ group_surface = _cairo_gstate_get_target (cr->gstate); parent_target = _cairo_gstate_get_parent_target (cr->gstate); @@ -562,13 +562,13 @@ cairo_pop_group (cairo_t *cr) /* Verify that we are at the right nesting level */ if (parent_target == NULL) { _cairo_set_error (cr, CAIRO_STATUS_INVALID_POP_GROUP); - return NULL; + return (cairo_pattern_t*) &_cairo_pattern_nil.base; } /* We need to save group_surface before we restore; we don't need * to reference parent_target and original_target, since the * gstate will still hold refs to them once we restore. */ - cairo_surface_reference (group_surface); + group_surface = cairo_surface_reference (group_surface); cairo_restore (cr); @@ -576,8 +576,8 @@ cairo_pop_group (cairo_t *cr) goto done; group_pattern = cairo_pattern_create_for_surface (group_surface); - if (!group_pattern) { - cr->status = CAIRO_STATUS_NO_MEMORY; + if (cairo_pattern_status (group_pattern)) { + _cairo_set_error (cr, cairo_pattern_status (group_pattern)); goto done; } @@ -623,9 +623,6 @@ cairo_pop_group_to_source (cairo_t *cr) cairo_pattern_t *group_pattern; group_pattern = cairo_pop_group (cr); - if (!group_pattern) - return; - cairo_set_source (cr, group_pattern); cairo_pattern_destroy (group_pattern); } @@ -647,12 +644,14 @@ slim_hidden_def(cairo_pop_group_to_source); void cairo_set_operator (cairo_t *cr, cairo_operator_t op) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_set_operator (cr->gstate, op); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_set_operator (cr->gstate, op); + if (status) + _cairo_set_error (cr, status); } slim_hidden_def (cairo_set_operator); @@ -679,6 +678,9 @@ cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue) if (cr->status) return; + /* push the current pattern to the freed lists */ + cairo_set_source (cr, (cairo_pattern_t *) &cairo_pattern_none); + pattern = cairo_pattern_create_rgb (red, green, blue); cairo_set_source (cr, pattern); cairo_pattern_destroy (pattern); @@ -710,6 +712,9 @@ cairo_set_source_rgba (cairo_t *cr, if (cr->status) return; + /* push the current pattern to the freed lists */ + cairo_set_source (cr, (cairo_pattern_t *) &cairo_pattern_none); + pattern = cairo_pattern_create_rgba (red, green, blue, alpha); cairo_set_source (cr, pattern); cairo_pattern_destroy (pattern); @@ -750,6 +755,9 @@ cairo_set_source_surface (cairo_t *cr, if (cr->status) return; + /* push the current pattern to the freed lists */ + cairo_set_source (cr, (cairo_pattern_t *) &cairo_pattern_none); + pattern = cairo_pattern_create_for_surface (surface); cairo_matrix_init_translate (&matrix, -x, -y); @@ -782,6 +790,8 @@ slim_hidden_def (cairo_set_source_surface); void cairo_set_source (cairo_t *cr, cairo_pattern_t *source) { + cairo_status_t status; + if (cr->status) return; @@ -795,9 +805,9 @@ cairo_set_source (cairo_t *cr, cairo_pattern_t *source) return; } - cr->status = _cairo_gstate_set_source (cr->gstate, source); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_set_source (cr->gstate, source); + if (status) + _cairo_set_error (cr, status); } slim_hidden_def (cairo_set_source); @@ -815,7 +825,7 @@ cairo_pattern_t * cairo_get_source (cairo_t *cr) { if (cr->status) - return (cairo_pattern_t*) &cairo_pattern_nil.base; + return (cairo_pattern_t*) &_cairo_pattern_nil.base; return _cairo_gstate_get_source (cr->gstate); } @@ -836,14 +846,16 @@ cairo_get_source (cairo_t *cr) void cairo_set_tolerance (cairo_t *cr, double tolerance) { + cairo_status_t status; + if (cr->status) return; _cairo_restrict_value (&tolerance, CAIRO_TOLERANCE_MINIMUM, tolerance); - cr->status = _cairo_gstate_set_tolerance (cr->gstate, tolerance); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_set_tolerance (cr->gstate, tolerance); + if (status) + _cairo_set_error (cr, status); } /** @@ -862,12 +874,14 @@ cairo_set_tolerance (cairo_t *cr, double tolerance) void cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_set_antialias (cr->gstate, antialias); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_set_antialias (cr->gstate, antialias); + if (status) + _cairo_set_error (cr, status); } /** @@ -878,18 +892,20 @@ cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias) * Set the current fill rule within the cairo context. The fill rule * is used to determine which regions are inside or outside a complex * (potentially self-intersecting) path. The current fill rule affects - * both cairo_fill and cairo_clip. See #cairo_fill_rule_t for details + * both cairo_fill() and cairo_clip(). See #cairo_fill_rule_t for details * on the semantics of each available fill rule. **/ void cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_set_fill_rule (cr->gstate, fill_rule); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_set_fill_rule (cr->gstate, fill_rule); + if (status) + _cairo_set_error (cr, status); } /** @@ -921,14 +937,16 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule) void cairo_set_line_width (cairo_t *cr, double width) { + cairo_status_t status; + if (cr->status) return; _cairo_restrict_value (&width, 0.0, width); - cr->status = _cairo_gstate_set_line_width (cr->gstate, width); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_set_line_width (cr->gstate, width); + if (status) + _cairo_set_error (cr, status); } /** @@ -948,12 +966,14 @@ cairo_set_line_width (cairo_t *cr, double width) void cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_set_line_cap (cr->gstate, line_cap); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_set_line_cap (cr->gstate, line_cap); + if (status) + _cairo_set_error (cr, status); } /** @@ -973,12 +993,14 @@ cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap) void cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_set_line_join (cr->gstate, line_join); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_set_line_join (cr->gstate, line_join); + if (status) + _cairo_set_error (cr, status); } /** @@ -1019,13 +1041,15 @@ cairo_set_dash (cairo_t *cr, int num_dashes, double offset) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_set_dash (cr->gstate, - dashes, num_dashes, offset); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_set_dash (cr->gstate, + dashes, num_dashes, offset); + if (status) + _cairo_set_error (cr, status); } /** @@ -1044,7 +1068,11 @@ cairo_set_dash (cairo_t *cr, int cairo_get_dash_count (cairo_t *cr) { - return cr->gstate->stroke_style.num_dashes; + int num_dashes; + + _cairo_gstate_get_dash (cr->gstate, NULL, &num_dashes, NULL); + + return num_dashes; } /** @@ -1064,13 +1092,7 @@ cairo_get_dash (cairo_t *cr, double *dashes, double *offset) { - if (dashes) - memcpy (dashes, - cr->gstate->stroke_style.dash, - sizeof (double) * cr->gstate->stroke_style.num_dashes); - - if (offset) - *offset = cr->gstate->stroke_style.dash_offset; + _cairo_gstate_get_dash (cr->gstate, dashes, NULL, offset); } /** @@ -1095,12 +1117,14 @@ cairo_get_dash (cairo_t *cr, void cairo_set_miter_limit (cairo_t *cr, double limit) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_set_miter_limit (cr->gstate, limit); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_set_miter_limit (cr->gstate, limit); + if (status) + _cairo_set_error (cr, status); } /** @@ -1118,12 +1142,14 @@ cairo_set_miter_limit (cairo_t *cr, double limit) void cairo_translate (cairo_t *cr, double tx, double ty) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_translate (cr->gstate, tx, ty); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_translate (cr->gstate, tx, ty); + if (status) + _cairo_set_error (cr, status); } /** @@ -1140,12 +1166,14 @@ cairo_translate (cairo_t *cr, double tx, double ty) void cairo_scale (cairo_t *cr, double sx, double sy) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_scale (cr->gstate, sx, sy); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_scale (cr->gstate, sx, sy); + if (status) + _cairo_set_error (cr, status); } slim_hidden_def (cairo_scale); @@ -1164,12 +1192,14 @@ slim_hidden_def (cairo_scale); void cairo_rotate (cairo_t *cr, double angle) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_rotate (cr->gstate, angle); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_rotate (cr->gstate, angle); + if (status) + _cairo_set_error (cr, status); } /** @@ -1185,12 +1215,14 @@ void cairo_transform (cairo_t *cr, const cairo_matrix_t *matrix) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_transform (cr->gstate, matrix); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_transform (cr->gstate, matrix); + if (status) + _cairo_set_error (cr, status); } /** @@ -1205,12 +1237,14 @@ void cairo_set_matrix (cairo_t *cr, const cairo_matrix_t *matrix) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_set_matrix (cr->gstate, matrix); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_set_matrix (cr->gstate, matrix); + if (status) + _cairo_set_error (cr, status); } /** @@ -1228,9 +1262,7 @@ cairo_identity_matrix (cairo_t *cr) if (cr->status) return; - cr->status = _cairo_gstate_identity_matrix (cr->gstate); - if (cr->status) - _cairo_set_error (cr, cr->status); + _cairo_gstate_identity_matrix (cr->gstate); } /** @@ -1249,9 +1281,7 @@ cairo_user_to_device (cairo_t *cr, double *x, double *y) if (cr->status) return; - cr->status = _cairo_gstate_user_to_device (cr->gstate, x, y); - if (cr->status) - _cairo_set_error (cr, cr->status); + _cairo_gstate_user_to_device (cr->gstate, x, y); } /** @@ -1271,9 +1301,7 @@ cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy) if (cr->status) return; - cr->status = _cairo_gstate_user_to_device_distance (cr->gstate, dx, dy); - if (cr->status) - _cairo_set_error (cr, cr->status); + _cairo_gstate_user_to_device_distance (cr->gstate, dx, dy); } /** @@ -1292,9 +1320,7 @@ cairo_device_to_user (cairo_t *cr, double *x, double *y) if (cr->status) return; - cr->status = _cairo_gstate_device_to_user (cr->gstate, x, y); - if (cr->status) - _cairo_set_error (cr, cr->status); + _cairo_gstate_device_to_user (cr->gstate, x, y); } /** @@ -1314,9 +1340,7 @@ cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy) if (cr->status) return; - cr->status = _cairo_gstate_device_to_user_distance (cr->gstate, dx, dy); - if (cr->status) - _cairo_set_error (cr, cr->status); + _cairo_gstate_device_to_user_distance (cr->gstate, dx, dy); } /** @@ -1348,6 +1372,7 @@ slim_hidden_def(cairo_new_path); void cairo_move_to (cairo_t *cr, double x, double y) { + cairo_status_t status; cairo_fixed_t x_fixed, y_fixed; if (cr->status) @@ -1357,9 +1382,9 @@ 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); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_path_fixed_move_to (cr->path, x_fixed, y_fixed); + if (status) + _cairo_set_error (cr, status); } slim_hidden_def(cairo_move_to); @@ -1406,6 +1431,7 @@ cairo_new_sub_path (cairo_t *cr) void cairo_line_to (cairo_t *cr, double x, double y) { + cairo_status_t status; cairo_fixed_t x_fixed, y_fixed; if (cr->status) @@ -1415,9 +1441,9 @@ 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); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_path_fixed_line_to (cr->path, x_fixed, y_fixed); + if (status) + _cairo_set_error (cr, status); } slim_hidden_def (cairo_line_to); @@ -1446,6 +1472,7 @@ cairo_curve_to (cairo_t *cr, double x2, double y2, double x3, double y3) { + cairo_status_t status; cairo_fixed_t x1_fixed, y1_fixed; cairo_fixed_t x2_fixed, y2_fixed; cairo_fixed_t x3_fixed, y3_fixed; @@ -1466,12 +1493,12 @@ 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, - x1_fixed, y1_fixed, - x2_fixed, y2_fixed, - x3_fixed, y3_fixed); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_path_fixed_curve_to (cr->path, + x1_fixed, y1_fixed, + x2_fixed, y2_fixed, + x3_fixed, y3_fixed); + if (status) + _cairo_set_error (cr, status); } slim_hidden_def (cairo_curve_to); @@ -1516,7 +1543,7 @@ slim_hidden_def (cairo_curve_to); * * cairo_save (cr); * cairo_translate (cr, x + width / 2., y + height / 2.); - * cairo_scale (cr, 1. / (height / 2.), 1. / (width / 2.)); + * cairo_scale (cr, width / 2., height / 2.); * cairo_arc (cr, 0., 0., 1., 0., 2 * M_PI); * cairo_restore (cr); * @@ -1558,7 +1585,7 @@ cairo_arc (cairo_t *cr, * arc is centered at (@xc, @yc), begins at @angle1 and proceeds in * the direction of decreasing angles to end at @angle2. If @angle2 is * greater than @angle1 it will be progressively decreased by 2*M_PI - * until it is greater than @angle1. + * until it is less than @angle1. * * See cairo_arc() for more details. This function differs only in the * direction of the arc between the two angles. @@ -1594,13 +1621,17 @@ cairo_arc_to (cairo_t *cr, double x2, double y2, double radius) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_arc_to (cr->gstate, - x1, y1, - x2, y2, - radius); + status = _cairo_gstate_arc_to (cr->gstate, + x1, y1, + x2, y2, + radius); + if (status) + _cairo_set_error (cr, status); } */ @@ -1624,17 +1655,19 @@ void cairo_rel_move_to (cairo_t *cr, double dx, double dy) { cairo_fixed_t dx_fixed, dy_fixed; + cairo_status_t status; if (cr->status) return; _cairo_gstate_user_to_device_distance (cr->gstate, &dx, &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); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_path_fixed_rel_move_to (cr->path, dx_fixed, dy_fixed); + if (status) + _cairo_set_error (cr, status); } /** @@ -1659,17 +1692,19 @@ void cairo_rel_line_to (cairo_t *cr, double dx, double dy) { cairo_fixed_t dx_fixed, dy_fixed; + cairo_status_t status; if (cr->status) return; _cairo_gstate_user_to_device_distance (cr->gstate, &dx, &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); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_path_fixed_rel_line_to (cr->path, dx_fixed, dy_fixed); + if (status) + _cairo_set_error (cr, status); } slim_hidden_def(cairo_rel_line_to); @@ -1708,6 +1743,7 @@ cairo_rel_curve_to (cairo_t *cr, cairo_fixed_t dx1_fixed, dy1_fixed; cairo_fixed_t dx2_fixed, dy2_fixed; cairo_fixed_t dx3_fixed, dy3_fixed; + cairo_status_t status; if (cr->status) return; @@ -1725,12 +1761,12 @@ 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, - dx1_fixed, dy1_fixed, - dx2_fixed, dy2_fixed, - dx3_fixed, dy3_fixed); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_path_fixed_rel_curve_to (cr->path, + dx1_fixed, dy1_fixed, + dx2_fixed, dy2_fixed, + dx3_fixed, dy3_fixed); + if (status) + _cairo_set_error (cr, status); } /** @@ -1772,12 +1808,14 @@ cairo_rectangle (cairo_t *cr, void cairo_stroke_to_path (cairo_t *cr) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_stroke_path (cr->gstate); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_stroke_path (cr->gstate); + if (status) + _cairo_set_error (cr, status); } */ @@ -1810,12 +1848,14 @@ cairo_stroke_to_path (cairo_t *cr) void cairo_close_path (cairo_t *cr) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_path_fixed_close_path (cr->path); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_path_fixed_close_path (cr->path); + if (status) + _cairo_set_error (cr, status); } slim_hidden_def(cairo_close_path); @@ -1829,12 +1869,14 @@ slim_hidden_def(cairo_close_path); void cairo_paint (cairo_t *cr) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_paint (cr->gstate); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_paint (cr->gstate); + if (status) + _cairo_set_error (cr, status); } slim_hidden_def (cairo_paint); @@ -1852,6 +1894,7 @@ void cairo_paint_with_alpha (cairo_t *cr, double alpha) { + cairo_status_t status; cairo_color_t color; cairo_pattern_union_t pattern; @@ -1868,11 +1911,11 @@ cairo_paint_with_alpha (cairo_t *cr, } _cairo_color_init_rgba (&color, 1., 1., 1., alpha); - _cairo_pattern_init_solid (&pattern.solid, &color); + _cairo_pattern_init_solid (&pattern.solid, &color, CAIRO_CONTENT_ALPHA); - cr->status = _cairo_gstate_mask (cr->gstate, &pattern.base); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_mask (cr->gstate, &pattern.base); + if (status) + _cairo_set_error (cr, status); _cairo_pattern_fini (&pattern.base); } @@ -1891,6 +1934,8 @@ void cairo_mask (cairo_t *cr, cairo_pattern_t *pattern) { + cairo_status_t status; + if (cr->status) return; @@ -1904,9 +1949,9 @@ cairo_mask (cairo_t *cr, return; } - cr->status = _cairo_gstate_mask (cr->gstate, pattern); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_mask (cr->gstate, pattern); + if (status) + _cairo_set_error (cr, status); } slim_hidden_def (cairo_mask); @@ -2000,12 +2045,14 @@ cairo_stroke (cairo_t *cr) void cairo_stroke_preserve (cairo_t *cr) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_stroke (cr->gstate, cr->path); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_stroke (cr->gstate, cr->path); + if (status) + _cairo_set_error (cr, status); } slim_hidden_def(cairo_stroke_preserve); @@ -2041,12 +2088,14 @@ cairo_fill (cairo_t *cr) void cairo_fill_preserve (cairo_t *cr) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_fill (cr->gstate, cr->path); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_fill (cr->gstate, cr->path); + if (status) + _cairo_set_error (cr, status); } slim_hidden_def(cairo_fill_preserve); @@ -2062,12 +2111,14 @@ slim_hidden_def(cairo_fill_preserve); void cairo_copy_page (cairo_t *cr) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_copy_page (cr->gstate); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_copy_page (cr->gstate); + if (status) + _cairo_set_error (cr, status); } /** @@ -2080,12 +2131,14 @@ cairo_copy_page (cairo_t *cr) void cairo_show_page (cairo_t *cr) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_show_page (cr->gstate); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_show_page (cr->gstate); + if (status) + _cairo_set_error (cr, status); } /** @@ -2096,7 +2149,8 @@ cairo_show_page (cairo_t *cr) * * Tests whether the given point is inside the area that would be * affected by a cairo_stroke() operation given the current path and - * stroking parameters. + * stroking parameters. Surface dimensions and clipping are not taken + * into account. * * See cairo_stroke(), cairo_set_line_width(), cairo_set_line_join(), * cairo_set_line_cap(), cairo_set_dash(), and @@ -2108,16 +2162,17 @@ cairo_show_page (cairo_t *cr) cairo_bool_t cairo_in_stroke (cairo_t *cr, double x, double y) { - cairo_bool_t inside; + cairo_status_t status; + cairo_bool_t inside = FALSE; if (cr->status) return 0; - cr->status = _cairo_gstate_in_stroke (cr->gstate, - cr->path, - x, y, &inside); - if (cr->status) - return 0; + status = _cairo_gstate_in_stroke (cr->gstate, + cr->path, + x, y, &inside); + if (status) + _cairo_set_error (cr, status); return inside; } @@ -2130,7 +2185,8 @@ cairo_in_stroke (cairo_t *cr, double x, double y) * * Tests whether the given point is inside the area that would be * affected by a cairo_fill() operation given the current path and - * filling parameters. + * filling parameters. Surface dimensions and clipping are not taken + * into account. * * See cairo_fill(), cairo_set_fill_rule() and cairo_fill_preserve(). * @@ -2140,18 +2196,17 @@ cairo_in_stroke (cairo_t *cr, double x, double y) cairo_bool_t cairo_in_fill (cairo_t *cr, double x, double y) { - cairo_bool_t inside; + cairo_status_t status; + cairo_bool_t inside = FALSE; if (cr->status) return 0; - cr->status = _cairo_gstate_in_fill (cr->gstate, - cr->path, - x, y, &inside); - if (cr->status) { - _cairo_set_error (cr, cr->status); - return 0; - } + status = _cairo_gstate_in_fill (cr->gstate, + cr->path, + x, y, &inside); + if (status) + _cairo_set_error (cr, status); return inside; } @@ -2178,14 +2233,16 @@ void cairo_stroke_extents (cairo_t *cr, double *x1, double *y1, double *x2, double *y2) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_stroke_extents (cr->gstate, - cr->path, - x1, y1, x2, y2); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_stroke_extents (cr->gstate, + cr->path, + x1, y1, x2, y2); + if (status) + _cairo_set_error (cr, status); } /** @@ -2208,14 +2265,16 @@ void cairo_fill_extents (cairo_t *cr, double *x1, double *y1, double *x2, double *y2) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_fill_extents (cr->gstate, - cr->path, - x1, y1, x2, y2); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_fill_extents (cr->gstate, + cr->path, + x1, y1, x2, y2); + if (status) + _cairo_set_error (cr, status); } /** @@ -2273,12 +2332,14 @@ cairo_clip (cairo_t *cr) void cairo_clip_preserve (cairo_t *cr) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_clip (cr->gstate, cr->path); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_clip (cr->gstate, cr->path); + if (status) + _cairo_set_error (cr, status); } slim_hidden_def(cairo_clip_preserve); @@ -2301,12 +2362,14 @@ slim_hidden_def(cairo_clip_preserve); void cairo_reset_clip (cairo_t *cr) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_reset_clip (cr->gstate); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_reset_clip (cr->gstate); + if (status) + _cairo_set_error (cr, status); } /** @@ -2327,12 +2390,14 @@ cairo_clip_extents (cairo_t *cr, double *x1, double *y1, double *x2, double *y2) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2); + if (status) + _cairo_set_error (cr, status); } static cairo_rectangle_list_t * @@ -2340,6 +2405,9 @@ _cairo_rectangle_list_create_in_error (cairo_status_t status) { cairo_rectangle_list_t *list; + if (status == CAIRO_STATUS_NO_MEMORY) + return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; + list = malloc (sizeof (cairo_rectangle_list_t)); if (list == NULL) return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; @@ -2398,12 +2466,14 @@ cairo_select_font_face (cairo_t *cr, cairo_font_slant_t slant, cairo_font_weight_t weight) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_select_font_face (cr->gstate, family, slant, weight); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_select_font_face (cr->gstate, family, slant, weight); + if (status) + _cairo_set_error (cr, status); } /** @@ -2418,12 +2488,14 @@ void cairo_font_extents (cairo_t *cr, cairo_font_extents_t *extents) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_get_font_extents (cr->gstate, extents); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_get_font_extents (cr->gstate, extents); + if (status) + _cairo_set_error (cr, status); } /** @@ -2439,12 +2511,14 @@ void cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_set_font_face (cr->gstate, font_face); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_set_font_face (cr->gstate, font_face); + if (status) + _cairo_set_error (cr, status); } /** @@ -2468,14 +2542,15 @@ cairo_set_font_face (cairo_t *cr, cairo_font_face_t * cairo_get_font_face (cairo_t *cr) { + cairo_status_t status; 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); + status = _cairo_gstate_get_font_face (cr->gstate, &font_face); + if (status) { + _cairo_set_error (cr, status); return (cairo_font_face_t*) &_cairo_font_face_nil; } @@ -2496,12 +2571,14 @@ cairo_get_font_face (cairo_t *cr) void cairo_set_font_size (cairo_t *cr, double size) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_set_font_size (cr->gstate, size); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_set_font_size (cr->gstate, size); + if (status) + _cairo_set_error (cr, status); } /** @@ -2521,12 +2598,14 @@ void cairo_set_font_matrix (cairo_t *cr, const cairo_matrix_t *matrix) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_set_font_matrix (cr->gstate, matrix); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_set_font_matrix (cr->gstate, matrix); + if (status) + _cairo_set_error (cr, status); } /** @@ -2558,12 +2637,18 @@ void cairo_set_font_options (cairo_t *cr, const cairo_font_options_t *options) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_set_font_options (cr->gstate, options); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = cairo_font_options_status ((cairo_font_options_t *) options); + if (status) { + _cairo_set_error (cr, status); + return; + } + + _cairo_gstate_set_font_options (cr->gstate, options); } /** @@ -2581,6 +2666,10 @@ void cairo_get_font_options (cairo_t *cr, cairo_font_options_t *options) { + /* check that we aren't trying to overwrite the nil object */ + if (cairo_font_options_status (options)) + return; + _cairo_gstate_get_font_options (cr->gstate, options); } @@ -2601,29 +2690,29 @@ void cairo_set_scaled_font (cairo_t *cr, const cairo_scaled_font_t *scaled_font) { + cairo_status_t status; + if (cr->status) return; - cr->status = scaled_font->status; - if (cr->status) + status = scaled_font->status; + if (status) goto BAIL; - cr->status = _cairo_gstate_set_font_face (cr->gstate, scaled_font->font_face); - if (cr->status) + status = _cairo_gstate_set_font_face (cr->gstate, scaled_font->font_face); + if (status) goto BAIL; - cr->status = _cairo_gstate_set_font_matrix (cr->gstate, &scaled_font->font_matrix); - if (cr->status) + status = _cairo_gstate_set_font_matrix (cr->gstate, &scaled_font->font_matrix); + if (status) goto BAIL; - cr->status = _cairo_gstate_set_font_options (cr->gstate, &scaled_font->options); - if (cr->status) - goto BAIL; + _cairo_gstate_set_font_options (cr->gstate, &scaled_font->options); return; BAIL: - _cairo_set_error (cr, cr->status); + _cairo_set_error (cr, status); } /** @@ -2649,14 +2738,15 @@ BAIL: cairo_scaled_font_t * cairo_get_scaled_font (cairo_t *cr) { + cairo_status_t status; cairo_scaled_font_t *scaled_font; if (cr->status) return (cairo_scaled_font_t *)&_cairo_scaled_font_nil; - cr->status = _cairo_gstate_get_scaled_font (cr->gstate, &scaled_font); - if (cr->status) { - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_get_scaled_font (cr->gstate, &scaled_font); + if (status) { + _cairo_set_error (cr, status); return (cairo_scaled_font_t *)&_cairo_scaled_font_nil; } @@ -2688,6 +2778,7 @@ cairo_text_extents (cairo_t *cr, const char *utf8, cairo_text_extents_t *extents) { + cairo_status_t status; cairo_glyph_t *glyphs = NULL; int num_glyphs; double x, y; @@ -2707,23 +2798,23 @@ cairo_text_extents (cairo_t *cr, cairo_get_current_point (cr, &x, &y); - cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, - x, y, - &glyphs, &num_glyphs); + status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, + x, y, + &glyphs, &num_glyphs); - if (cr->status) { + if (status) { if (glyphs) free (glyphs); - _cairo_set_error (cr, cr->status); + _cairo_set_error (cr, status); return; } - cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs, extents); + status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs, extents); if (glyphs) free (glyphs); - if (cr->status) - _cairo_set_error (cr, cr->status); + if (status) + _cairo_set_error (cr, status); } /** @@ -2750,13 +2841,15 @@ cairo_glyph_extents (cairo_t *cr, int num_glyphs, cairo_text_extents_t *extents) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs, - extents); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs, + extents); + if (status) + _cairo_set_error (cr, status); } /** @@ -2790,6 +2883,7 @@ void cairo_show_text (cairo_t *cr, const char *utf8) { cairo_text_extents_t extents; + cairo_status_t status; cairo_glyph_t *glyphs = NULL, *last_glyph; int num_glyphs; double x, y; @@ -2802,24 +2896,24 @@ cairo_show_text (cairo_t *cr, const char *utf8) cairo_get_current_point (cr, &x, &y); - cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, + status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, x, y, &glyphs, &num_glyphs); - if (cr->status) + if (status) goto BAIL; if (num_glyphs == 0) return; - cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs); - if (cr->status) + status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs); + if (status) goto BAIL; last_glyph = &glyphs[num_glyphs - 1]; - cr->status = _cairo_gstate_glyph_extents (cr->gstate, - last_glyph, 1, - &extents); - if (cr->status) + status = _cairo_gstate_glyph_extents (cr->gstate, + last_glyph, 1, + &extents); + if (status) goto BAIL; x = last_glyph->x + extents.x_advance; @@ -2830,8 +2924,8 @@ cairo_show_text (cairo_t *cr, const char *utf8) if (glyphs) free (glyphs); - if (cr->status) - _cairo_set_error (cr, cr->status); + if (status) + _cairo_set_error (cr, status); } /** @@ -2840,22 +2934,24 @@ cairo_show_text (cairo_t *cr, const char *utf8) * @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, + * 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) { + cairo_status_t status; + if (cr->status) return; if (num_glyphs == 0) return; - cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs); + if (status) + _cairo_set_error (cr, status); } /** @@ -2885,6 +2981,7 @@ cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs) void cairo_text_path (cairo_t *cr, const char *utf8) { + cairo_status_t status; cairo_text_extents_t extents; cairo_glyph_t *glyphs = NULL, *last_glyph; int num_glyphs; @@ -2895,29 +2992,29 @@ cairo_text_path (cairo_t *cr, const char *utf8) cairo_get_current_point (cr, &x, &y); - cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, - x, y, - &glyphs, &num_glyphs); + status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, + x, y, + &glyphs, &num_glyphs); - if (cr->status) + if (status) goto BAIL; if (num_glyphs == 0) return; - cr->status = _cairo_gstate_glyph_path (cr->gstate, - glyphs, num_glyphs, - cr->path); + status = _cairo_gstate_glyph_path (cr->gstate, + glyphs, num_glyphs, + cr->path); - if (cr->status) + if (status) goto BAIL; last_glyph = &glyphs[num_glyphs - 1]; - cr->status = _cairo_gstate_glyph_extents (cr->gstate, - last_glyph, 1, - &extents); + status = _cairo_gstate_glyph_extents (cr->gstate, + last_glyph, 1, + &extents); - if (cr->status) + if (status) goto BAIL; x = last_glyph->x + extents.x_advance; @@ -2928,8 +3025,8 @@ cairo_text_path (cairo_t *cr, const char *utf8) if (glyphs) free (glyphs); - if (cr->status) - _cairo_set_error (cr, cr->status); + if (status) + _cairo_set_error (cr, status); } /** @@ -2945,14 +3042,16 @@ cairo_text_path (cairo_t *cr, const char *utf8) void cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs) { + cairo_status_t status; + if (cr->status) return; - cr->status = _cairo_gstate_glyph_path (cr->gstate, - glyphs, num_glyphs, - cr->path); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_gstate_glyph_path (cr->gstate, + glyphs, num_glyphs, + cr->path); + if (status) + _cairo_set_error (cr, status); } /** @@ -3013,11 +3112,19 @@ cairo_get_antialias (cairo_t *cr) * * Most path construction functions alter the current point. See the * following for details on how they affect the current point: + * cairo_new_path(), cairo_new_sub_path(), + * cairo_append_path(), cairo_close_path(), + * cairo_move_to(), cairo_line_to(), cairo_curve_to(), + * cairo_rel_move_to(), cairo_rel_line_to(), cairo_rel_curve_to(), + * cairo_arc(), cairo_arc_negative(), cairo_rectangle(), + * cairo_text_path(), cairo_glyph_path(), cairo_stroke_to_path() * - * cairo_new_path(), cairo_move_to(), cairo_line_to(), - * cairo_curve_to(), cairo_arc(), cairo_rel_move_to(), - * cairo_rel_line_to(), cairo_rel_curve_to(), cairo_arc(), - * cairo_text_path(), cairo_stroke_to_path() + * Some functions use and alter the current point but do not otherwise + * change current path: + * cairo_show_text(), cairo_show_glyphs(). + * + * Some functions unset the current path and as a result, current point: + * cairo_fill(), cairo_stroke(). **/ void cairo_get_current_point (cairo_t *cr, double *x_ret, double *y_ret) @@ -3279,6 +3386,8 @@ void cairo_append_path (cairo_t *cr, const cairo_path_t *path) { + cairo_status_t status; + if (cr->status) return; @@ -3301,9 +3410,9 @@ cairo_append_path (cairo_t *cr, return; } - cr->status = _cairo_path_append_to_context (path, cr); - if (cr->status) - _cairo_set_error (cr, cr->status); + status = _cairo_path_append_to_context (path, cr); + if (status) + _cairo_set_error (cr, status); } /** diff --git a/gfx/cairo/cairo/src/cairo.h b/gfx/cairo/cairo/src/cairo.h index a80efde210e2..8c3718f73261 100644 --- a/gfx/cairo/cairo/src/cairo.h +++ b/gfx/cairo/cairo/src/cairo.h @@ -895,7 +895,7 @@ typedef enum _cairo_subpixel_order { /** * cairo_hint_style_t: * @CAIRO_HINT_STYLE_DEFAULT: Use the default hint style for - * for font backend and target device + * font backend and target device * @CAIRO_HINT_STYLE_NONE: Do not hint outlines * @CAIRO_HINT_STYLE_SLIGHT: Hint outlines slightly to improve * contrast while retaining good fidelity to the original diff --git a/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h index d50a7892e72d..07846b837477 100644 --- a/gfx/cairo/cairo/src/cairoint.h +++ b/gfx/cairo/cairo/src/cairoint.h @@ -54,6 +54,7 @@ #include #include #include +#include #ifdef _MSC_VER #define _USE_MATH_DEFINES @@ -74,13 +75,13 @@ CAIRO_BEGIN_DECLS #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_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private +# define slim_hidden_proto_no_warn(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private_no_warn +# 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)) \ - cairo_private + __asm__ (slim_hidden_asmname (internal)) # define slim_hidden_def1(name, internal) \ extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name)) \ __attribute__((__alias__(slim_hidden_asmname(internal)))) @@ -90,8 +91,9 @@ CAIRO_BEGIN_DECLS # define slim_hidden_asmname(name) slim_hidden_asmname1(name) # define slim_hidden_asmname1(name) slim_hidden_ulp #name #else -# define slim_hidden_proto(name) int _cairo_dummy_prototype(void) -# define slim_hidden_def(name) int _cairo_dummy_prototype(void) +# define slim_hidden_proto(name) int _cairo_dummy_prototype(void) +# define slim_hidden_proto_no_warn(name) int _cairo_dummy_prototype(void) +# define slim_hidden_def(name) int _cairo_dummy_prototype(void) #endif #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) @@ -103,13 +105,20 @@ CAIRO_BEGIN_DECLS /* slim_internal.h */ #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun) -#define cairo_private __attribute__((__visibility__("hidden"))) +#define cairo_private_no_warn __attribute__((__visibility__("hidden"))) #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) -#define cairo_private __hidden +#define cairo_private_no_warn __hidden #else /* not gcc >= 3.3 and not Sun Studio >= 8 */ -#define cairo_private +#define cairo_private_no_warn #endif +#ifndef WARN_UNUSED_RESULT +#define WARN_UNUSED_RESULT +#endif +/* Add attribute(warn_unused_result) if supported */ +#define cairo_warn WARN_UNUSED_RESULT +#define cairo_private cairo_private_no_warn cairo_warn + /* This macro allow us to deprecate a function by providing an alias for the old function name to the new function name. With this macro, binary compatibility is preserved. The macro only works on @@ -134,93 +143,6 @@ CAIRO_BEGIN_DECLS #define __attribute__(x) #endif -#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_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 -# define WIN32_LEAN_AND_MEAN -/* We require Windows 2000 features. Although we don't use them here, things - * should still work if this header file ends up being the one to include - * windows.h into a source file, so: */ -# if !defined(WINVER) || (WINVER < 0x0500) -# define WINVER 0x0500 -# endif -# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500) -# define _WIN32_WINNT 0x0500 -# endif -# include - /* the real initialization must take place in DllMain */ -# define CAIRO_MUTEX_DECLARE(name) extern CRITICAL_SECTION name; -# 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) -# define INCL_BASE -# define INCL_PM -# include - -# define CAIRO_MUTEX_DECLARE(name) extern HMTX name -# 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 -cairo_private void _cairo_beos_lock(void*); -cairo_private void _cairo_beos_unlock(void*); - /* the real initialization takes place in a global constructor */ -# define CAIRO_MUTEX_DECLARE(name) extern void* name; -# 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 /* 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 #define MIN(a, b) ((a) < (b) ? (a) : (b)) @@ -239,17 +161,8 @@ typedef void *cairo_mutex_t; #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 +#undef ARRAY_LENGTH +#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0]))) /* Size in bytes of buffer to use off the stack per functions. * Mostly used by text functions. For larger allocations, they'll @@ -266,6 +179,7 @@ do { \ #define CAIRO_REF_COUNT_INVALID ((unsigned int) -1) +#include "cairo-mutex-private.h" #include "cairo-wideint-private.h" typedef int32_t cairo_fixed_16_16_t; @@ -278,8 +192,11 @@ typedef cairo_int128_t cairo_fixed_96_32_t; typedef cairo_fixed_16_16_t cairo_fixed_t; #define CAIRO_ALPHA_IS_OPAQUE(alpha) ((alpha) >= ((double)0xff00 / (double)0xffff)) +#define CAIRO_ALPHA_SHORT_IS_OPAQUE(alpha) ((alpha) >= 0xff00) #define CAIRO_ALPHA_IS_ZERO(alpha) ((alpha) <= 0.0) +#define CAIRO_COLOR_IS_OPAQUE(color) CAIRO_ALPHA_SHORT_IS_OPAQUE ((color)->alpha_short) + /* Reverse the bits in a byte with 7 operations (no 64-bit): * Devised by Sean Anderson, July 13, 2001. * Source: http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits @@ -327,6 +244,7 @@ be32_to_cpu(uint32_t v) #endif +#include "cairo-types-private.h" #include "cairo-hash-private.h" #include "cairo-cache-private.h" @@ -390,33 +308,43 @@ typedef enum cairo_internal_surface_type { CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED } cairo_internal_surface_type_t; -/* For xlib fallbacks, we use image surfaces with formats that match - * the visual of the X server. There are a couple of common X server - * visuals for which we do not have corresponding public - * cairo_format_t values, since we do not plan on always guaranteeing - * that cairo will be able to draw to these formats. +/* For xlib fallbacks, we need image surfaces with formats that match + * the visual of the X server. There are a few common X server visuals + * for which we do not have corresponding public cairo_format_t + * values, since we do not plan on always guaranteeing that cairo will + * be able to draw to these formats. * - * So, currently pixman does provide support for these formats. It's - * possible that in the future we will change the implementation to - * instead convert to a supported format. This would allow us to be - * able to simplify pixman to handle fewer formats. + * Currently pixman does advertise support for these formats, (with an + * interface to construct a format from a set of masks---but pixman + * may not actually have code to support any arbitrary set of + * maskes). So we lodge a cairo_internal_format_t in the internal + * cairo image surface to indicate what's going on. The value isn't + * actually used for much, since it is the set of pixman masks that + * control the rendering. * - * The RGB16_565 case could probably have been handled this same way, - * (and in fact we could still change it to do so, and maybe just - * leave the value in the enum but deprecate it entirely). We can't - * drop the value since it did appear in cairo 1.2.0 so it might - * appear in code, (particularly bindings which are thorough about - * things like that). But we did neglect to update CAIRO_FORMAT_VALID - * for 1.2 so we know that no functional code is out there relying on - * being able to create an image surface with a 565 format, (which is - * good since things like write_to_png are missing support for the 565 - * format. + * But even though the value isn't used, it's still useful to maintain + * this list, as it indicates to use visual formats that have been + * encountered in practice. We can take advantage of this for future + * rewrites of pixman that might support a limited set of formats + * instead of general mask-based rendering, (or at least optimized + * rendering for a limited set of formats). + * + * Another approach that could be taken here is to convert the data at + * the time of the fallback to a supported format. This is similar to + * what needs to be done to support PseudoColor visuals, for example. * * NOTE: The implementation of CAIRO_FORMAT_VALID *must* *not* - * consider these internal formats as valid. */ + * consider these internal formats as valid. + * + * NOTE: When adding a value to this list, be sure to add it to + * _cairo_format_from_pixman_format, (which is probably the assert + * failure you're wanting to eliminate), but also don't forget to add + * it to cairo_content_from_format. + */ typedef enum cairo_internal_format { CAIRO_INTERNAL_FORMAT_ABGR32 = 0x1000, - CAIRO_INTERNAL_FORMAT_BGR24 + CAIRO_INTERNAL_FORMAT_BGR24, + CAIRO_INTERNAL_FORMAT_RGB16_565 } cairo_internal_format_t; typedef enum cairo_direction { @@ -431,7 +359,6 @@ typedef enum _cairo_clip_mode { CAIRO_CLIP_MODE_MASK } cairo_clip_mode_t; typedef struct _cairo_clip_path cairo_clip_path_t; -typedef struct _cairo_clip cairo_clip_t; typedef struct _cairo_edge { cairo_line_t edge; @@ -441,6 +368,8 @@ typedef struct _cairo_edge { } cairo_edge_t; typedef struct _cairo_polygon { + cairo_status_t status; + cairo_point_t first_point; cairo_point_t current_point; cairo_bool_t has_current_point; @@ -481,8 +410,6 @@ typedef struct _cairo_pen { typedef struct _cairo_color cairo_color_t; typedef struct _cairo_image_surface cairo_image_surface_t; -typedef struct _cairo_surface_backend cairo_surface_backend_t; - cairo_private void _cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_int16_t *rectangle); @@ -491,16 +418,6 @@ _cairo_rectangle_intersect (cairo_rectangle_int16_t *dest, cairo_rectangle_int16 /* cairo_array.c structures and functions */ -typedef struct _cairo_array cairo_array_t; -struct _cairo_array { - unsigned int size; - unsigned int num_elements; - unsigned int element_size; - char **elements; - - cairo_bool_t is_snapshot; -}; - cairo_private void _cairo_array_init (cairo_array_t *array, int element_size); @@ -542,8 +459,6 @@ _cairo_array_num_elements (cairo_array_t *array); cairo_private int _cairo_array_size (cairo_array_t *array); -typedef cairo_array_t cairo_user_data_array_t; - cairo_private void _cairo_user_data_array_init (cairo_user_data_array_t *array); @@ -564,8 +479,6 @@ cairo_private unsigned long _cairo_hash_string (const char *c); typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t; -typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t; -typedef struct _cairo_font_face_backend cairo_font_face_backend_t; /* * A cairo_unscaled_font_t is just an opaque handle we use in the @@ -577,13 +490,6 @@ typedef struct _cairo_unscaled_font { const cairo_unscaled_font_backend_t *backend; } cairo_unscaled_font_t; -struct _cairo_font_options { - cairo_antialias_t antialias; - cairo_subpixel_order_t subpixel_order; - cairo_hint_style_t hint_style; - cairo_hint_metrics_t hint_metrics; -}; - typedef struct _cairo_scaled_glyph { cairo_cache_entry_t cache_entry; /* hash is glyph index */ cairo_scaled_font_t *scaled_font; /* font the glyph lives in */ @@ -599,71 +505,7 @@ typedef struct _cairo_scaled_glyph { #define _cairo_scaled_glyph_index(g) ((g)->cache_entry.hash) #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 */ - cairo_matrix_t font_matrix; /* font space => user space */ - cairo_matrix_t ctm; /* user space => device space */ - cairo_font_options_t options; - - /* "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 */ - - /* - * One surface backend may store data in each glyph. - * Whichever surface manages to store its pointer here - * first gets to store data in each glyph - */ - const cairo_surface_backend_t *surface_backend; - void *surface_private; - - /* font backend managing this scaled font */ - const cairo_scaled_font_backend_t *backend; -}; +#include "cairo-scaled-font-private.h" struct _cairo_font_face { /* hash_entry must be first */ @@ -680,12 +522,6 @@ _cairo_font_reset_static_data (void); cairo_private void _cairo_ft_font_reset_static_data (void); -cairo_private void -_cairo_xlib_surface_reset_static_data (void); - -cairo_private void -_cairo_xlib_screen_reset_static_data (void); - /* the font backend interface */ struct _cairo_unscaled_font_backend { @@ -721,12 +557,13 @@ typedef struct _cairo_scaled_font_subset { unsigned long *glyphs; unsigned long *to_unicode; unsigned int num_glyphs; + cairo_bool_t is_composite; } cairo_scaled_font_subset_t; struct _cairo_scaled_font_backend { cairo_font_type_t type; - cairo_status_t + cairo_warn cairo_status_t (*create_toy) (cairo_toy_font_face_t *toy_face, const cairo_matrix_t *font_matrix, const cairo_matrix_t *ctm, @@ -736,7 +573,7 @@ struct _cairo_scaled_font_backend { void (*fini) (void *scaled_font); - cairo_int_status_t + cairo_warn cairo_int_status_t (*scaled_glyph_init) (void *scaled_font, cairo_scaled_glyph_t *scaled_glyph, cairo_scaled_glyph_info_t info); @@ -745,7 +582,7 @@ struct _cairo_scaled_font_backend { * both. This allows the backend to do something more sophisticated * then just converting characters one by one. */ - cairo_int_status_t + cairo_warn cairo_int_status_t (*text_to_glyphs) (void *scaled_font, double x, double y, @@ -756,7 +593,7 @@ struct _cairo_scaled_font_backend { unsigned long (*ucs4_to_index) (void *scaled_font, uint32_t ucs4); - cairo_int_status_t + cairo_warn cairo_int_status_t (*show_glyphs) (void *scaled_font, cairo_operator_t op, cairo_pattern_t *pattern, @@ -770,7 +607,7 @@ struct _cairo_scaled_font_backend { cairo_glyph_t *glyphs, int num_glyphs); - cairo_int_status_t + cairo_warn cairo_int_status_t (*load_truetype_table)(void *scaled_font, unsigned long tag, long offset, @@ -792,7 +629,7 @@ struct _cairo_font_face_backend { void (*destroy) (void *font_face); - cairo_status_t + cairo_warn cairo_status_t (*scaled_font_create) (void *font_face, const cairo_matrix_t *font_matrix, const cairo_matrix_t *ctm, @@ -838,10 +675,10 @@ struct _cairo_surface_backend { int width, int height); - cairo_status_t + cairo_warn cairo_status_t (*finish) (void *surface); - cairo_status_t + cairo_warn cairo_status_t (*acquire_source_image) (void *abstract_surface, cairo_image_surface_t **image_out, void **image_extra); @@ -851,7 +688,7 @@ struct _cairo_surface_backend { cairo_image_surface_t *image, void *image_extra); - cairo_status_t + cairo_warn cairo_status_t (*acquire_dest_image) (void *abstract_surface, cairo_rectangle_int16_t *interest_rect, cairo_image_surface_t **image_out, @@ -875,7 +712,7 @@ struct _cairo_surface_backend { * * 3. It has the same contents as @src within the given rectangle. */ - cairo_status_t + cairo_warn cairo_status_t (*clone_similar) (void *surface, cairo_surface_t *src, int src_x, @@ -885,7 +722,7 @@ struct _cairo_surface_backend { cairo_surface_t **clone_out); /* XXX: dst should be the first argument for consistency */ - cairo_int_status_t + cairo_warn cairo_int_status_t (*composite) (cairo_operator_t op, cairo_pattern_t *src, cairo_pattern_t *mask, @@ -899,7 +736,7 @@ struct _cairo_surface_backend { unsigned int width, unsigned int height); - cairo_int_status_t + cairo_warn cairo_int_status_t (*fill_rectangles) (void *surface, cairo_operator_t op, const cairo_color_t *color, @@ -907,7 +744,7 @@ struct _cairo_surface_backend { int num_rects); /* XXX: dst should be the first argument for consistency */ - cairo_int_status_t + cairo_warn cairo_int_status_t (*composite_trapezoids) (cairo_operator_t op, cairo_pattern_t *pattern, void *dst, @@ -921,10 +758,10 @@ struct _cairo_surface_backend { cairo_trapezoid_t *traps, int num_traps); - cairo_int_status_t + cairo_warn cairo_int_status_t (*copy_page) (void *surface); - cairo_int_status_t + cairo_warn cairo_int_status_t (*show_page) (void *surface); /* Set given region as the clip region for the surface, replacing @@ -940,7 +777,7 @@ struct _cairo_surface_backend { * this is not possible, cairo will use mask surfaces for * clipping. */ - cairo_int_status_t + cairo_warn cairo_int_status_t (*set_clip_region) (void *surface, pixman_region16_t *region); @@ -958,7 +795,7 @@ struct _cairo_surface_backend { * function is not implemented cairo will use set_clip_region() * (if available) and mask surfaces for clipping. */ - cairo_int_status_t + cairo_warn cairo_int_status_t (*intersect_clip_path) (void *dst, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, @@ -975,7 +812,7 @@ struct _cairo_surface_backend { * into the specific surface->get_extents if there is no current * clip. */ - cairo_int_status_t + cairo_warn cairo_int_status_t (*get_extents) (void *surface, cairo_rectangle_int16_t *rectangle); @@ -984,7 +821,7 @@ struct _cairo_surface_backend { * resources. If null, render against this surface, using image * surfaces as glyphs. */ - cairo_int_status_t + cairo_warn cairo_int_status_t (*old_show_glyphs) (cairo_scaled_font_t *font, cairo_operator_t op, cairo_pattern_t *pattern, @@ -1002,10 +839,10 @@ struct _cairo_surface_backend { (*get_font_options) (void *surface, cairo_font_options_t *options); - cairo_status_t + cairo_warn cairo_status_t (*flush) (void *surface); - cairo_status_t + cairo_warn cairo_status_t (*mark_dirty_rectangle) (void *surface, int x, int y, @@ -1022,18 +859,18 @@ struct _cairo_surface_backend { /* OK, I'm starting over somewhat by defining the 5 top-level * drawing operators for the surface backend here with consistent * naming and argument-order conventions. */ - cairo_int_status_t + cairo_warn cairo_int_status_t (*paint) (void *surface, cairo_operator_t op, cairo_pattern_t *source); - cairo_int_status_t + cairo_warn cairo_int_status_t (*mask) (void *surface, cairo_operator_t op, cairo_pattern_t *source, cairo_pattern_t *mask); - cairo_int_status_t + cairo_warn cairo_int_status_t (*stroke) (void *surface, cairo_operator_t op, cairo_pattern_t *source, @@ -1044,7 +881,7 @@ struct _cairo_surface_backend { double tolerance, cairo_antialias_t antialias); - cairo_int_status_t + cairo_warn cairo_int_status_t (*fill) (void *surface, cairo_operator_t op, cairo_pattern_t *source, @@ -1053,7 +890,7 @@ struct _cairo_surface_backend { double tolerance, cairo_antialias_t antialias); - cairo_int_status_t + cairo_warn cairo_int_status_t (*show_glyphs) (void *surface, cairo_operator_t op, cairo_pattern_t *source, @@ -1063,6 +900,14 @@ struct _cairo_surface_backend { cairo_surface_t * (*snapshot) (void *surface); + + cairo_bool_t + (*is_similar) (void *surface_a, + void *surface_b, + cairo_content_t content); + + cairo_warn cairo_status_t + (*reset) (void *surface); }; typedef struct _cairo_format_masks { @@ -1073,56 +918,7 @@ typedef struct _cairo_format_masks { unsigned long blue_mask; } cairo_format_masks_t; -struct _cairo_surface { - const cairo_surface_backend_t *backend; - - /* We allow surfaces to override the backend->type by shoving something - * else into surface->type. This is for "wrapper" surfaces that want to - * hide their internal type from the user-level API. */ - cairo_surface_type_t type; - - cairo_content_t content; - - unsigned int ref_count; - cairo_status_t status; - cairo_bool_t finished; - cairo_user_data_array_t user_data; - - cairo_matrix_t device_transform; - cairo_matrix_t device_transform_inverse; - - double x_fallback_resolution; - double y_fallback_resolution; - - cairo_clip_t *clip; - - /* - * Each time a clip region is modified, it gets the next value in this - * sequence. This means that clip regions for this surface are uniquely - * identified and updates to the clip can be readily identified - */ - unsigned int next_clip_serial; - /* - * The serial number of the current clip. This is set when - * the surface clipping is set. The gstate can then cheaply - * check whether the surface clipping is already correct before - * performing a rendering operation. - * - * The special value '0' is reserved for the unclipped case. - */ - unsigned int current_clip_serial; - - /* A "snapshot" surface is immutable. See _cairo_surface_snapshot. */ - cairo_bool_t is_snapshot; - - /* - * Surface font options, falling back to backend's default options, - * and set using _cairo_surface_set_font_options(), and propagated by - * cairo_surface_create_similar(). - */ - cairo_bool_t has_font_options; - cairo_font_options_t font_options; -}; +#include "cairo-surface-private.h" struct _cairo_image_surface { cairo_surface_t base; @@ -1185,9 +981,11 @@ struct _cairo_pattern { typedef struct _cairo_solid_pattern { cairo_pattern_t base; cairo_color_t color; + cairo_content_t content; } cairo_solid_pattern_t; -extern const cairo_private cairo_solid_pattern_t cairo_pattern_nil; +extern const cairo_private cairo_solid_pattern_t _cairo_pattern_nil; +extern const cairo_private cairo_solid_pattern_t cairo_pattern_none; typedef struct _cairo_surface_pattern { cairo_pattern_t base; @@ -1250,6 +1048,9 @@ typedef struct _cairo_traps { int traps_size; cairo_trapezoid_t *traps; cairo_trapezoid_t traps_embedded[1]; + + cairo_bool_t has_limits; + cairo_box_t limits; } cairo_traps_t; #define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL @@ -1339,16 +1140,16 @@ _cairo_gstate_init (cairo_gstate_t *gstate, cairo_private void _cairo_gstate_fini (cairo_gstate_t *gstate); -cairo_private cairo_gstate_t * -_cairo_gstate_clone (cairo_gstate_t *gstate); +cairo_private cairo_status_t +_cairo_gstate_save (cairo_gstate_t **gstate); -cairo_private void -_cairo_gstate_destroy (cairo_gstate_t *gstate); +cairo_private cairo_status_t +_cairo_gstate_restore (cairo_gstate_t **gstate); cairo_private cairo_bool_t _cairo_gstate_is_redirected (cairo_gstate_t *gstate); -cairo_private void +cairo_private cairo_status_t _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child); cairo_private cairo_surface_t * @@ -1408,6 +1209,9 @@ _cairo_gstate_get_line_join (cairo_gstate_t *gstate); cairo_private cairo_status_t _cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dashes, double offset); +cairo_private void +_cairo_gstate_get_dash (cairo_gstate_t *gstate, double *dash, int *num_dashes, double *offset); + cairo_private cairo_status_t _cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit); @@ -1434,19 +1238,19 @@ cairo_private cairo_status_t _cairo_gstate_set_matrix (cairo_gstate_t *gstate, const cairo_matrix_t *matrix); -cairo_private cairo_status_t +cairo_private void _cairo_gstate_identity_matrix (cairo_gstate_t *gstate); -cairo_private cairo_status_t +cairo_private void _cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y); -cairo_private cairo_status_t +cairo_private void _cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate, double *dx, double *dy); -cairo_private cairo_status_t +cairo_private void _cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y); -cairo_private cairo_status_t +cairo_private void _cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate, double *dx, double *dy); cairo_private void @@ -1552,7 +1356,7 @@ cairo_private void _cairo_gstate_get_font_options (cairo_gstate_t *gstate, cairo_font_options_t *options); -cairo_private cairo_status_t +cairo_private void _cairo_gstate_set_font_options (cairo_gstate_t *gstate, const cairo_font_options_t *options); @@ -1644,7 +1448,11 @@ _cairo_color_get_rgba_premultiplied (cairo_color_t *color, double *blue, double *alpha); -/* cairo-font.c */ +cairo_private cairo_bool_t +_cairo_color_equal (const cairo_color_t *color_a, + const cairo_color_t *color_b); + +/* cairo-font-face.c */ cairo_private void _cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font); @@ -1675,7 +1483,7 @@ cairo_private void _cairo_unscaled_font_init (cairo_unscaled_font_t *font, const cairo_unscaled_font_backend_t *backend); -cairo_private cairo_unscaled_font_t * +cairo_private_no_warn cairo_unscaled_font_t * _cairo_unscaled_font_reference (cairo_unscaled_font_t *font); cairo_private void @@ -1924,12 +1732,16 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other, int width, int height); +/* Note: the color_pattern argument is optional - if provided it will reuse + * that pattern instead of creating a very short-lived fresh solid pattern + */ cairo_private cairo_surface_t * _cairo_surface_create_similar_solid (cairo_surface_t *other, cairo_content_t content, int width, int height, - const cairo_color_t *color); + const cairo_color_t *color, + cairo_pattern_t *color_pattern); cairo_private void _cairo_surface_init (cairo_surface_t *surface, @@ -2032,10 +1844,10 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op, cairo_trapezoid_t *traps, int ntraps); -cairo_private cairo_int_status_t +cairo_private cairo_status_t _cairo_surface_copy_page (cairo_surface_t *surface); -cairo_private cairo_int_status_t +cairo_private cairo_status_t _cairo_surface_show_page (cairo_surface_t *surface); cairo_private cairo_status_t @@ -2074,6 +1886,14 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, cairo_private cairo_surface_t * _cairo_surface_snapshot (cairo_surface_t *surface); +cairo_private cairo_bool_t +_cairo_surface_is_similar (cairo_surface_t *surface_a, + cairo_surface_t *surface_b, + cairo_content_t content); + +cairo_private cairo_status_t +_cairo_surface_reset (cairo_surface_t *surface); + cairo_private unsigned int _cairo_surface_get_current_clip_serial (cairo_surface_t *surface); @@ -2262,7 +2082,7 @@ _cairo_pen_init (cairo_pen_t *pen, double tolerance, cairo_matrix_t *ctm); -cairo_private cairo_status_t +cairo_private void _cairo_pen_init_empty (cairo_pen_t *pen); cairo_private cairo_status_t @@ -2305,15 +2125,18 @@ cairo_private void _cairo_polygon_fini (cairo_polygon_t *polygon); cairo_private cairo_status_t +_cairo_polygon_status (cairo_polygon_t *polygon); + +cairo_private void _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_point_t *p2); -cairo_private cairo_status_t +cairo_private void _cairo_polygon_move_to (cairo_polygon_t *polygon, cairo_point_t *point); -cairo_private cairo_status_t +cairo_private void _cairo_polygon_line_to (cairo_polygon_t *polygon, cairo_point_t *point); -cairo_private cairo_status_t +cairo_private void _cairo_polygon_close (cairo_polygon_t *polygon); /* cairo_spline.c */ @@ -2346,7 +2169,7 @@ _cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix, cairo_private void _cairo_matrix_compute_determinant (const cairo_matrix_t *matrix, double *det); -cairo_private cairo_status_t +cairo_private void _cairo_matrix_compute_scale_factors (const cairo_matrix_t *matrix, double *sx, double *sy, int x_major); @@ -2371,6 +2194,10 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, cairo_private void _cairo_traps_init (cairo_traps_t *traps); +cairo_private void +_cairo_traps_limit (cairo_traps_t *traps, + cairo_box_t *limits); + cairo_private cairo_status_t _cairo_traps_init_box (cairo_traps_t *traps, cairo_box_t *box); @@ -2378,6 +2205,9 @@ _cairo_traps_init_box (cairo_traps_t *traps, cairo_private void _cairo_traps_fini (cairo_traps_t *traps); +cairo_private cairo_status_t +_cairo_traps_status (cairo_traps_t *traps); + cairo_private void _cairo_traps_translate (cairo_traps_t *traps, int x, int y); @@ -2392,7 +2222,7 @@ _cairo_traps_tessellate_polygon (cairo_traps_t *traps, cairo_polygon_t *poly, cairo_fill_rule_t fill_rule); -cairo_private cairo_status_t +cairo_private void _cairo_traps_add_trap_from_points (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom, cairo_point_t left_p1, cairo_point_t left_p2, cairo_point_t right_p1, cairo_point_t right_p2); @@ -2408,9 +2238,9 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y); cairo_private void _cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents); -cairo_private cairo_status_t -_cairo_traps_extract_region (cairo_traps_t *tr, - pixman_region16_t **region); +cairo_private cairo_int_status_t +_cairo_traps_extract_region (cairo_traps_t *tr, + pixman_region16_t *region); cairo_private void _cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps, @@ -2434,13 +2264,14 @@ _cairo_slope_counter_clockwise (cairo_slope_t *a, cairo_slope_t *b); /* cairo_pattern.c */ -cairo_private void +cairo_private cairo_status_t _cairo_pattern_init_copy (cairo_pattern_t *pattern, const cairo_pattern_t *other); cairo_private void -_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern, - const cairo_color_t *color); +_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern, + const cairo_color_t *color, + cairo_content_t content); cairo_private void _cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern, @@ -2459,7 +2290,8 @@ cairo_private void _cairo_pattern_fini (cairo_pattern_t *pattern); cairo_private cairo_pattern_t * -_cairo_pattern_create_solid (const cairo_color_t *color); +_cairo_pattern_create_solid (const cairo_color_t *color, + cairo_content_t content); cairo_private void _cairo_pattern_transform (cairo_pattern_t *pattern, @@ -2505,6 +2337,9 @@ cairo_private cairo_status_t _cairo_pattern_get_extents (cairo_pattern_t *pattern, cairo_rectangle_int16_t *extents); +cairo_private void +_cairo_pattern_reset_static_data (void); + cairo_private cairo_status_t _cairo_gstate_set_antialias (cairo_gstate_t *gstate, cairo_antialias_t antialias); @@ -2514,9 +2349,6 @@ _cairo_gstate_get_antialias (cairo_gstate_t *gstate); /* cairo-region.c */ -cairo_private pixman_region16_t * -_cairo_region_create_from_rectangle (cairo_rectangle_int16_t *rect); - cairo_private void _cairo_region_extents_rectangle (pixman_region16_t *region, cairo_rectangle_int16_t *rect); @@ -2538,9 +2370,6 @@ _cairo_utf8_to_utf16 (const unsigned char *str, cairo_private void _cairo_error (cairo_status_t status); -cairo_private int -_cairo_dtostr (char *buffer, size_t size, double d); - /* Avoid unnecessary PLT entries. */ slim_hidden_proto (cairo_clip_preserve); slim_hidden_proto (cairo_close_path); @@ -2549,7 +2378,7 @@ slim_hidden_proto (cairo_curve_to); slim_hidden_proto (cairo_destroy); slim_hidden_proto (cairo_fill_preserve); slim_hidden_proto (cairo_font_face_destroy); -slim_hidden_proto (cairo_font_face_reference); +slim_hidden_proto_no_warn (cairo_font_face_reference); slim_hidden_proto (cairo_font_options_create); slim_hidden_proto (cairo_font_options_destroy); slim_hidden_proto (cairo_font_options_equal); @@ -2559,6 +2388,7 @@ slim_hidden_proto (cairo_font_options_set_antialias); slim_hidden_proto (cairo_font_options_set_hint_metrics); slim_hidden_proto (cairo_font_options_set_hint_style); slim_hidden_proto (cairo_font_options_set_subpixel_order); +slim_hidden_proto (cairo_font_options_status); slim_hidden_proto (cairo_get_current_point); slim_hidden_proto (cairo_get_matrix); slim_hidden_proto (cairo_get_tolerance); @@ -2588,7 +2418,7 @@ slim_hidden_proto (cairo_pattern_create_rgba); slim_hidden_proto (cairo_pattern_destroy); slim_hidden_proto (cairo_pattern_get_extend); slim_hidden_proto (cairo_pattern_get_type); -slim_hidden_proto (cairo_pattern_reference); +slim_hidden_proto_no_warn (cairo_pattern_reference); slim_hidden_proto (cairo_pattern_set_matrix); slim_hidden_proto (cairo_pattern_status); slim_hidden_proto (cairo_pop_group); @@ -2607,7 +2437,8 @@ slim_hidden_proto (cairo_scaled_font_get_font_face); slim_hidden_proto (cairo_scaled_font_get_font_matrix); slim_hidden_proto (cairo_scaled_font_get_font_options); slim_hidden_proto (cairo_scaled_font_glyph_extents); -slim_hidden_proto (cairo_scaled_font_reference); +slim_hidden_proto_no_warn (cairo_scaled_font_reference); +slim_hidden_proto (cairo_scaled_font_status); slim_hidden_proto (cairo_set_operator); slim_hidden_proto (cairo_set_source); slim_hidden_proto (cairo_set_source_surface); @@ -2621,7 +2452,7 @@ slim_hidden_proto (cairo_surface_get_device_offset); slim_hidden_proto (cairo_surface_get_font_options); slim_hidden_proto (cairo_surface_get_type); slim_hidden_proto (cairo_surface_mark_dirty_rectangle); -slim_hidden_proto (cairo_surface_reference); +slim_hidden_proto_no_warn (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); diff --git a/gfx/cairo/cairo/src/test-fallback-surface.c b/gfx/cairo/cairo/src/test-fallback-surface.c index 21ee19077fbd..b2fa03ef6245 100644 --- a/gfx/cairo/cairo/src/test-fallback-surface.c +++ b/gfx/cairo/cairo/src/test-fallback-surface.c @@ -51,10 +51,10 @@ * there. */ -#include "test-fallback-surface.h" - #include "cairoint.h" +#include "test-fallback-surface.h" + typedef struct _test_fallback_surface { cairo_surface_t base; @@ -80,6 +80,7 @@ _cairo_test_fallback_surface_create (cairo_content_t content, surface = malloc (sizeof (test_fallback_surface_t)); if (surface == NULL) { + cairo_surface_destroy (backing); _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_surface_t*) &_cairo_surface_nil; } @@ -169,6 +170,26 @@ _test_fallback_surface_release_dest_image (void *abstract_surface, image_extra); } +static cairo_status_t +_test_fallback_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) +{ + test_fallback_surface_t *surface = abstract_surface; + + if (src->backend == surface->base.backend) { + *clone_out = cairo_surface_reference (src); + + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + static cairo_int_status_t _test_fallback_surface_get_extents (void *abstract_surface, cairo_rectangle_int16_t *rectangle) @@ -186,7 +207,7 @@ const cairo_surface_backend_t test_fallback_surface_backend = { _test_fallback_surface_release_source_image, _test_fallback_surface_acquire_dest_image, _test_fallback_surface_release_dest_image, - NULL, /* clone_similar */ + _test_fallback_surface_clone_similar, NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ diff --git a/gfx/cairo/cairo/src/test-meta-surface.c b/gfx/cairo/cairo/src/test-meta-surface.c index 6c5877971edc..e2f6a0977bf7 100644 --- a/gfx/cairo/cairo/src/test-meta-surface.c +++ b/gfx/cairo/cairo/src/test-meta-surface.c @@ -45,9 +45,10 @@ * backend. */ +#include "cairoint.h" + #include "test-meta-surface.h" -#include "cairoint.h" #include "cairo-meta-surface-private.h" typedef struct _test_meta_surface { @@ -143,11 +144,14 @@ static cairo_int_status_t _test_meta_surface_show_page (void *abstract_surface) { test_meta_surface_t *surface = abstract_surface; + cairo_status_t status; if (surface->image_reflects_meta) return CAIRO_STATUS_SUCCESS; - _cairo_meta_surface_replay (surface->meta, surface->image); + status = _cairo_meta_surface_replay (surface->meta, surface->image); + if (status) + return status; surface->image_reflects_meta = TRUE; @@ -279,6 +283,7 @@ static cairo_surface_t * _test_meta_surface_snapshot (void *abstract_other) { test_meta_surface_t *other = abstract_other; + cairo_status_t status; /* XXX: Just making a snapshot of other->meta is what we really * want. But this currently triggers a bug somewhere (the "mask" @@ -298,14 +303,20 @@ _test_meta_surface_snapshot (void *abstract_other) cairo_rectangle_int16_t extents; cairo_surface_t *surface; - _cairo_surface_get_extents (other->image, &extents); + status = _cairo_surface_get_extents (other->image, &extents); + if (status) + return (cairo_surface_t*) &_cairo_surface_nil; surface = cairo_surface_create_similar (other->image, CAIRO_CONTENT_COLOR_ALPHA, extents.width, extents.height); - _cairo_meta_surface_replay (other->meta, surface); + status = _cairo_meta_surface_replay (other->meta, surface); + if (status) { + cairo_surface_destroy (surface); + surface = (cairo_surface_t*) &_cairo_surface_nil; + } return surface; #endif diff --git a/gfx/cairo/cairo/src/test-paginated-surface.c b/gfx/cairo/cairo/src/test-paginated-surface.c index d82749f69d9c..53e97eba66ec 100644 --- a/gfx/cairo/cairo/src/test-paginated-surface.c +++ b/gfx/cairo/cairo/src/test-paginated-surface.c @@ -45,11 +45,11 @@ * backend. */ -#include "test-paginated-surface.h" - #include "cairoint.h" -#include "cairo-paginated-surface-private.h" +#include "test-paginated-surface.h" + +#include "cairo-paginated-private.h" typedef struct _test_paginated_surface { cairo_surface_t base; diff --git a/gfx/cairo/libpixman/src/fbcompose.c b/gfx/cairo/libpixman/src/fbcompose.c index ef0be03567f7..4197e344f34a 100644 --- a/gfx/cairo/libpixman/src/fbcompose.c +++ b/gfx/cairo/libpixman/src/fbcompose.c @@ -23,14 +23,11 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ -#ifdef HAVE_CONFIG_H -#include -#endif + +#include "pixmanint.h" + #include "pixman-xserver-compat.h" #include "fbpict.h" -#ifndef MOZILLA_CAIRO_NOT_DEFINED -#include "fbmmx.h" -#endif /* MOZCAIRO */ #ifdef RENDER @@ -1744,7 +1741,7 @@ fbCombineSaturateU (CARD32 *dest, const CARD32 *src, int width) #define CombineXor (CombineAOut|CombineBOut) /* portion covered by a but not b */ -static INLINE CARD8 +static inline CARD8 fbCombineDisjointOutPart (CARD8 a, CARD8 b) { /* min (1, (1-b) / a) */ @@ -1756,7 +1753,7 @@ fbCombineDisjointOutPart (CARD8 a, CARD8 b) } /* portion covered by both a and b */ -static INLINE CARD8 +static inline CARD8 fbCombineDisjointInPart (CARD8 a, CARD8 b) { /* max (1-(1-b)/a,0) */ @@ -1884,7 +1881,7 @@ fbCombineDisjointXorU (CARD32 *dest, const CARD32 *src, int width) } /* portion covered by a but not b */ -static INLINE CARD8 +static inline CARD8 fbCombineConjointOutPart (CARD8 a, CARD8 b) { /* max (1-b/a,0) */ @@ -1898,7 +1895,7 @@ fbCombineConjointOutPart (CARD8 a, CARD8 b) } /* portion covered by both a and b */ -static INLINE CARD8 +static inline CARD8 fbCombineConjointInPart (CARD8 a, CARD8 b) { /* min (1,b/a) */ @@ -2059,89 +2056,80 @@ static CombineFuncU fbCombineFuncU[] = { fbCombineConjointXorU, }; -static FASTCALL void -fbCombineMaskC (CARD32 *src, CARD32 *mask, int width) +static inline void +fbCombineMaskC (CARD32 *src, CARD32 *mask) { - int i; - for (i = 0; i < width; ++i) { - CARD32 a = mask[i]; + CARD32 a = *mask; - CARD32 x; - CARD16 xa; + CARD32 x; + CARD16 xa; - if (!a) - { - src[i] = 0; - continue; - } - - x = src[i]; - if (a == 0xffffffff) - { - x = x >> 24; - x |= x << 8; - x |= x << 16; - mask[i] = x; - continue; - } - - xa = x >> 24; - FbByteMulC(x, a); - src[i] = x; - FbByteMul(a, xa); - mask[i] = a; + if (!a) + { + *src = 0; + return; } + + x = *src; + if (a == 0xffffffff) + { + x = x >> 24; + x |= x << 8; + x |= x << 16; + *mask = x; + return; + } + + xa = x >> 24; + FbByteMulC(x, a); + *src = x; + FbByteMul(a, xa); + *mask = a; } -static FASTCALL void -fbCombineMaskValueC (CARD32 *src, const CARD32 *mask, int width) +static inline void +fbCombineMaskValueC (CARD32 *src, const CARD32 *mask) { - int i; - for (i = 0; i < width; ++i) { - CARD32 a = mask[i]; - CARD32 x; + CARD32 a = *mask; + CARD32 x; - if (!a) - { - src[i] = 0; - continue; - } - - if (a == 0xffffffff) - continue; - - x = src[i]; - FbByteMulC(x, a); - src[i] = x; + if (!a) + { + *src = 0; + return; } + + if (a == 0xffffffff) + return; + + x = *src; + FbByteMulC(x, a); + *src = x; } -static FASTCALL void -fbCombineMaskAlphaC (const CARD32 *src, CARD32 *mask, int width) +static inline void +fbCombineMaskAlphaC (const CARD32 *src, CARD32 *mask) { - int i; - for (i = 0; i < width; ++i) { - CARD32 a = mask[i]; - CARD32 x; + CARD32 a = *mask; + CARD32 x; - if (!a) - continue; + if (!a) + return; - x = src[i] >> 24; - if (x == 0xff) - continue; - if (a == 0xffffffff) - { - x = x >> 24; - x |= x << 8; - x |= x << 16; - mask[i] = x; - continue; - } - - FbByteMul(a, x); - mask[i] = a; + x = *src >> 24; + if (x == 0xff) + return; + if (a == 0xffffffff) + { + x = x >> 24; + x |= x << 8; + x |= x << 16; + *mask = x; + return; } + + FbByteMul(a, x); + *mask = a; } static FASTCALL void @@ -2153,19 +2141,31 @@ fbCombineClearC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) static FASTCALL void fbCombineSrcC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) { - fbCombineMaskValueC(src, mask, width); - memcpy(dest, src, width*sizeof(CARD32)); + int i; + + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 m = mask[i]; + + fbCombineMaskValueC (&s, &m); + + *dest = s; + } } static FASTCALL void fbCombineOverC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) { int i; - fbCombineMaskC(src, mask, width); - for (i = 0; i < width; ++i) { - CARD32 s = src[i]; - CARD32 a = ~mask[i]; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 m = mask[i]; + CARD32 a; + + fbCombineMaskC (&s, &m); + + a = ~m; if (a != 0xffffffff) { if (a) @@ -2183,7 +2183,7 @@ static FASTCALL void fbCombineOverReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) { int i; - fbCombineMaskValueC(src, mask, width); + for (i = 0; i < width; ++i) { CARD32 d = dest[i]; CARD32 a = ~d >> 24; @@ -2191,6 +2191,10 @@ fbCombineOverReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) if (a) { CARD32 s = src[i]; + CARD32 m = mask[i]; + + fbCombineMaskValueC (&s, &m); + if (a != 0xff) { FbByteMulAdd(s, a, d); @@ -2204,14 +2208,17 @@ static FASTCALL void fbCombineInC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) { int i; - fbCombineMaskValueC(src, mask, width); + for (i = 0; i < width; ++i) { CARD32 d = dest[i]; CARD16 a = d >> 24; CARD32 s = 0; if (a) { - s = src[i]; + CARD32 m = mask[i]; + + s = src[i]; + fbCombineMaskValueC (&s, &m); if (a != 0xff) { FbByteMul(s, a); @@ -2225,10 +2232,15 @@ static FASTCALL void fbCombineInReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) { int i; - fbCombineMaskAlphaC(src, mask, width); - for (i = 0; i < width; ++i) { - CARD32 a = mask[i]; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 m = mask[i]; + CARD32 a; + + fbCombineMaskAlphaC (&s, &m); + + a = m; if (a != 0xffffffff) { CARD32 d = 0; @@ -2246,14 +2258,18 @@ static FASTCALL void fbCombineOutC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) { int i; - fbCombineMaskValueC(src, mask, width); + for (i = 0; i < width; ++i) { CARD32 d = dest[i]; CARD16 a = ~d >> 24; CARD32 s = 0; if (a) { - s = src[i]; + CARD32 m = mask[i]; + + s = src[i]; + fbCombineMaskValueC (&s, &m); + if (a != 0xff) { FbByteMul(s, a); @@ -2267,10 +2283,15 @@ static FASTCALL void fbCombineOutReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) { int i; - fbCombineMaskAlphaC(src, mask, width); - for (i = 0; i < width; ++i) { - CARD32 a = ~mask[i]; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 m = mask[i]; + CARD32 a; + + fbCombineMaskAlphaC (&s, &m); + + a = ~m; if (a != 0xffffffff) { CARD32 d = 0; @@ -2288,12 +2309,18 @@ static FASTCALL void fbCombineAtopC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) { int i; - fbCombineMaskC(src, mask, width); + for (i = 0; i < width; ++i) { CARD32 d = dest[i]; CARD32 s = src[i]; - CARD32 ad = ~mask[i]; + CARD32 m = mask[i]; + CARD32 ad; CARD16 as = d >> 24; + + fbCombineMaskC (&s, &m); + + ad = ~m; + FbByteAddMulC(d, ad, s, as); dest[i] = d; } @@ -2303,13 +2330,19 @@ static FASTCALL void fbCombineAtopReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) { int i; - fbCombineMaskC(src, mask, width); + for (i = 0; i < width; ++i) { CARD32 d = dest[i]; CARD32 s = src[i]; - CARD32 ad = mask[i]; + CARD32 m = mask[i]; + CARD32 ad; CARD16 as = ~d >> 24; + + fbCombineMaskC (&s, &m); + + ad = m; + FbByteAddMulC(d, ad, s, as); dest[i] = d; } @@ -2319,12 +2352,18 @@ static FASTCALL void fbCombineXorC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) { int i; - fbCombineMaskC(src, mask, width); + for (i = 0; i < width; ++i) { CARD32 d = dest[i]; CARD32 s = src[i]; - CARD32 ad = ~mask[i]; + CARD32 m = mask[i]; + CARD32 ad; CARD16 as = ~d >> 24; + + fbCombineMaskC (&s, &m); + + ad = ~m; + FbByteAddMulC(d, ad, s, as); dest[i] = d; } @@ -2334,10 +2373,14 @@ static FASTCALL void fbCombineAddC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) { int i; - fbCombineMaskValueC(src, mask, width); + for (i = 0; i < width; ++i) { CARD32 s = src[i]; + CARD32 m = mask[i]; CARD32 d = dest[i]; + + fbCombineMaskValueC (&s, &m); + FbByteAdd(d, s); dest[i] = d; } @@ -2347,7 +2390,7 @@ static FASTCALL void fbCombineSaturateC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) { int i; - fbCombineMaskC(src, mask, width); + for (i = 0; i < width; ++i) { CARD32 s, d; CARD16 sa, sr, sg, sb, da; @@ -2356,10 +2399,14 @@ fbCombineSaturateC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) d = dest[i]; s = src[i]; - sa = (mask[i] >> 24); - sr = (mask[i] >> 16) & 0xff; - sg = (mask[i] >> 8) & 0xff; - sb = (mask[i] ) & 0xff; + m = mask[i]; + + fbCombineMaskC (&s, &m); + + sa = (m >> 24); + sr = (m >> 16) & 0xff; + sg = (m >> 8) & 0xff; + sb = (m ) & 0xff; da = ~d >> 24; if (sb <= da) @@ -2390,7 +2437,7 @@ static FASTCALL void fbCombineDisjointGeneralC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width, CARD8 combine) { int i; - fbCombineMaskC(src, mask, width); + for (i = 0; i < width; ++i) { CARD32 s, d; CARD32 m,n,o,p; @@ -2400,10 +2447,14 @@ fbCombineDisjointGeneralC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width, C CARD8 da; s = src[i]; - sa = mask[i]; + m = mask[i]; d = dest[i]; da = d >> 24; + fbCombineMaskC (&s, &m); + + sa = m; + switch (combine & CombineA) { default: Fa = 0; @@ -2510,7 +2561,7 @@ static FASTCALL void fbCombineConjointGeneralC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width, CARD8 combine) { int i; - fbCombineMaskC(src, mask, width); + for (i = 0; i < width; ++i) { CARD32 s, d; CARD32 m,n,o,p; @@ -2520,10 +2571,14 @@ fbCombineConjointGeneralC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width, C CARD8 da; s = src[i]; - sa = mask[i]; + m = mask[i]; d = dest[i]; da = d >> 24; + fbCombineMaskC (&s, &m); + + sa = m; + switch (combine & CombineA) { default: Fa = 0; @@ -3375,8 +3430,8 @@ static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32 if (pict->filter == PIXMAN_FILTER_NEAREST || pict->filter == PIXMAN_FILTER_FAST) { if (pict->repeat == RepeatNormal) { - if (PIXREGION_NUM_RECTS(pict->pSourceClip) == 1) { - box = pict->pSourceClip->extents; + if (PIXREGION_NUM_RECTS(&pict->sourceClip) == 1) { + box = pict->sourceClip.extents; for (i = 0; i < width; ++i) { if (!mask || mask[i] & maskBits) { @@ -3411,7 +3466,7 @@ static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32 y = MOD(v.vector[1]>>16, pict->pDrawable->height); x = MOD(v.vector[0]>>16, pict->pDrawable->width); } - if (pixman_region_contains_point (pict->pSourceClip, x, y, &box)) + if (pixman_region_contains_point (&pict->sourceClip, x, y, &box)) buffer[i] = fetch(bits + (y + pict->pDrawable->y)*stride, x + pict->pDrawable->x, indexed); else buffer[i] = 0; @@ -3423,8 +3478,8 @@ static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32 } } } else { - if (PIXREGION_NUM_RECTS(pict->pSourceClip) == 1) { - box = pict->pSourceClip->extents; + if (PIXREGION_NUM_RECTS(&pict->sourceClip) == 1) { + box = pict->sourceClip.extents; for (i = 0; i < width; ++i) { if (!mask || mask[i] & maskBits) { @@ -3458,7 +3513,7 @@ static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32 y = v.vector[1]>>16; x = v.vector[0]>>16; } - if (pixman_region_contains_point (pict->pSourceClip, x, y, &box)) + if (pixman_region_contains_point (&pict->sourceClip, x, y, &box)) buffer[i] = fetch(bits + (y + pict->pDrawable->y)*stride, x + pict->pDrawable->x, indexed); else buffer[i] = 0; @@ -3477,8 +3532,8 @@ static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32 unit.vector[1] -= unit.vector[2]/2; if (pict->repeat == RepeatNormal) { - if (PIXREGION_NUM_RECTS(pict->pSourceClip) == 1) { - box = pict->pSourceClip->extents; + if (PIXREGION_NUM_RECTS(&pict->sourceClip) == 1) { + box = pict->sourceClip.extents; for (i = 0; i < width; ++i) { if (!mask || mask[i] & maskBits) { @@ -3581,14 +3636,14 @@ static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32 b = bits + (y1 + pict->pDrawable->y)*stride; - tl = pixman_region_contains_point(pict->pSourceClip, x1, y1, &box) + tl = pixman_region_contains_point(&pict->sourceClip, x1, y1, &box) ? fetch(b, x1 + pict->pDrawable->x, indexed) : 0; - tr = pixman_region_contains_point(pict->pSourceClip, x2, y1, &box) + tr = pixman_region_contains_point(&pict->sourceClip, x2, y1, &box) ? fetch(b, x2 + pict->pDrawable->x, indexed) : 0; b = bits + (y2 + pict->pDrawable->y)*stride; - bl = pixman_region_contains_point(pict->pSourceClip, x1, y2, &box) + bl = pixman_region_contains_point(&pict->sourceClip, x1, y2, &box) ? fetch(b, x1 + pict->pDrawable->x, indexed) : 0; - br = pixman_region_contains_point(pict->pSourceClip, x2, y2, &box) + br = pixman_region_contains_point(&pict->sourceClip, x2, y2, &box) ? fetch(b, x2 + pict->pDrawable->x, indexed) : 0; ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx; @@ -3612,8 +3667,8 @@ static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32 } } } else { - if (PIXREGION_NUM_RECTS(pict->pSourceClip) == 1) { - box = pict->pSourceClip->extents; + if (PIXREGION_NUM_RECTS(&pict->sourceClip) == 1) { + box = pict->sourceClip.extents; for (i = 0; i < width; ++i) { if (!mask || mask[i] & maskBits) { @@ -3714,14 +3769,14 @@ static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32 b = bits + (y1 + pict->pDrawable->y)*stride; x_off = x1 + pict->pDrawable->x; - tl = pixman_region_contains_point(pict->pSourceClip, x1, y1, &box) + tl = pixman_region_contains_point(&pict->sourceClip, x1, y1, &box) ? fetch(b, x_off, indexed) : 0; - tr = pixman_region_contains_point(pict->pSourceClip, x2, y1, &box) + tr = pixman_region_contains_point(&pict->sourceClip, x2, y1, &box) ? fetch(b, x_off + 1, indexed) : 0; b += stride; - bl = pixman_region_contains_point(pict->pSourceClip, x1, y2, &box) + bl = pixman_region_contains_point(&pict->sourceClip, x1, y2, &box) ? fetch(b, x_off, indexed) : 0; - br = pixman_region_contains_point(pict->pSourceClip, x2, y2, &box) + br = pixman_region_contains_point(&pict->sourceClip, x2, y2, &box) ? fetch(b, x_off + 1, indexed) : 0; ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx; @@ -3783,7 +3838,7 @@ static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32 for (x = x1; x < x2; x++) { if (*p) { int tx = (pict->repeat == RepeatNormal) ? MOD (x, pict->pDrawable->width) : x; - if (pixman_region_contains_point (pict->pSourceClip, tx, ty, &box)) { + if (pixman_region_contains_point (&pict->sourceClip, tx, ty, &box)) { FbBits *b = bits + (ty + pict->pDrawable->y)*stride; CARD32 c = fetch(b, tx + pict->pDrawable->x, indexed); @@ -4038,26 +4093,6 @@ 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 - * as helpers). This causes problems with the optimization in - * this function that only fetches the source or mask once if - * possible. If we're on a non-MMX machine, disable this - * optimization as a bandaid fix. - * - * https://bugs.freedesktop.org/show_bug.cgi?id=5777 - */ -#ifdef USE_MMX - if (!fbHaveMMX()) -#endif - { - srcClass = SourcePictClassUnknown; - maskClass = SourcePictClassUnknown; - } -#endif /* MOZCAIRO */ - for (i = 0; i < data->height; ++i) { /* fill first half of scanline with source */ if (fetchSrc) @@ -4219,7 +4254,7 @@ pixman_compositeGeneral (pixman_operator_t op, CARD16 width, CARD16 height) { - pixman_region16_t *region; + pixman_region16_t region; int n; BoxPtr pbox; Bool srcRepeat = FALSE; @@ -4240,22 +4275,11 @@ pixman_compositeGeneral (pixman_operator_t op, if (op == PIXMAN_OPERATOR_OVER && !pMask && !pSrc->transform && !PICT_FORMAT_A(pSrc->format_code) && !pSrc->alphaMap) op = PIXMAN_OPERATOR_SRC; - region = pixman_region_create(); - pixman_region_union_rect (region, region, xDst, yDst, width, height); + pixman_region_init_rect (®ion, xDst, yDst, width, height); - if (!FbComputeCompositeRegion (region, - pSrc, - pMask, - pDst, - xSrc, - ySrc, - xMask, - yMask, - xDst, - yDst, - width, - height)) - return; + if (!FbComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height)) + goto CLEANUP_REGION; compose_data.op = op; compose_data.src = pSrc; @@ -4264,8 +4288,8 @@ pixman_compositeGeneral (pixman_operator_t op, if (width > SCANLINE_BUFFER_LENGTH) scanline_buffer = (CARD32 *) malloc(width * 3 * sizeof(CARD32)); - n = pixman_region_num_rects (region); - pbox = pixman_region_rects (region); + n = pixman_region_num_rects (®ion); + pbox = pixman_region_rects (®ion); while (n--) { h = pbox->y2 - pbox->y1; @@ -4319,10 +4343,12 @@ pixman_compositeGeneral (pixman_operator_t op, } pbox++; } - pixman_region_destroy (region); if (scanline_buffer != _scanline_buffer) free(scanline_buffer); + +CLEANUP_REGION: + pixman_region_fini (®ion); } #endif diff --git a/gfx/cairo/libpixman/src/fbedge.c b/gfx/cairo/libpixman/src/fbedge.c index e06ed20b8df7..1552dfcb6151 100644 --- a/gfx/cairo/libpixman/src/fbedge.c +++ b/gfx/cairo/libpixman/src/fbedge.c @@ -20,6 +20,8 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#include "pixmanint.h" + #include #include "pixman-xserver-compat.h" @@ -77,14 +79,14 @@ * 8 bit alpha */ -static INLINE CARD8 +static inline CARD8 clip255 (int x) { if (x > 255) return 255; return x; } -static INLINE void +static inline void add_saturate_8 (CARD8 *buf, int value, int length) { while (length--) diff --git a/gfx/cairo/libpixman/src/fbmmx.c b/gfx/cairo/libpixman/src/fbmmx.c index 387d4b46e68c..57dcd14b259a 100644 --- a/gfx/cairo/libpixman/src/fbmmx.c +++ b/gfx/cairo/libpixman/src/fbmmx.c @@ -29,9 +29,7 @@ * Based on work by Owen Taylor */ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "pixmanint.h" #include #include "fbpict.h" @@ -147,7 +145,8 @@ static const MMXData c = }; #ifdef _MSC_VER -#define __inline__ __forceinline +#undef inline +#define inline __forceinline #endif #ifdef __GNUC__ @@ -162,7 +161,7 @@ static const MMXData c = */ #define M64(x) (*(__m64*)(void*)(&x)) -static __inline__ __m64 +static inline __m64 shift (__m64 v, int s) { if (s > 0) @@ -173,13 +172,13 @@ shift (__m64 v, int s) return v; } -static __inline__ __m64 +static inline __m64 negate (__m64 mask) { return _mm_xor_si64 (mask, MC(4x00ff)); } -static __inline__ __m64 +static inline __m64 pix_multiply (__m64 a, __m64 b) { __m64 res; @@ -192,7 +191,7 @@ pix_multiply (__m64 a, __m64 b) return res; } -static __inline__ __m64 +static inline __m64 pix_add (__m64 a, __m64 b) { return _mm_adds_pu8 (a, b); @@ -200,19 +199,19 @@ pix_add (__m64 a, __m64 b) #ifdef USE_SSE -static __inline__ __m64 +static inline __m64 expand_alpha (__m64 pixel) { return _mm_shuffle_pi16 (pixel, _MM_SHUFFLE(3, 3, 3, 3)); } -static __inline__ __m64 +static inline __m64 expand_alpha_rev (__m64 pixel) { return _mm_shuffle_pi16 (pixel, _MM_SHUFFLE(0, 0, 0, 0)); } -static __inline__ __m64 +static inline __m64 invert_colors (__m64 pixel) { return _mm_shuffle_pi16 (pixel, _MM_SHUFFLE(3, 0, 1, 2)); @@ -220,7 +219,7 @@ invert_colors (__m64 pixel) #else -static __inline__ __m64 +static inline __m64 expand_alpha (__m64 pixel) { __m64 t1, t2; @@ -234,7 +233,7 @@ expand_alpha (__m64 pixel) return t1; } -static __inline__ __m64 +static inline __m64 expand_alpha_rev (__m64 pixel) { __m64 t1, t2; @@ -251,7 +250,7 @@ expand_alpha_rev (__m64 pixel) return t1; } -static __inline__ __m64 +static inline __m64 invert_colors (__m64 pixel) { __m64 x, y, z; @@ -273,13 +272,13 @@ invert_colors (__m64 pixel) #endif -static __inline__ __m64 +static inline __m64 over (__m64 src, __m64 srca, __m64 dest) { return _mm_adds_pu8 (src, pix_multiply(dest, negate(srca))); } -static __inline__ __m64 +static inline __m64 over_rev_non_pre (__m64 src, __m64 dest) { __m64 srca = expand_alpha (src); @@ -288,7 +287,7 @@ over_rev_non_pre (__m64 src, __m64 dest) return over(pix_multiply(invert_colors(src), srcfaaa), srca, dest); } -static __inline__ __m64 +static inline __m64 in (__m64 src, __m64 mask) { @@ -296,7 +295,7 @@ in (__m64 src, } #ifndef _MSC_VER -static __inline__ __m64 +static inline __m64 in_over (__m64 src, __m64 srca, __m64 mask, @@ -308,19 +307,19 @@ in_over (__m64 src, #define in_over(src, srca, mask, dest) over(in(src, mask), pix_multiply(srca, mask), dest) #endif -static __inline__ __m64 +static inline __m64 load8888 (CARD32 v) { return _mm_unpacklo_pi8 (_mm_cvtsi32_si64 (v), _mm_setzero_si64()); } -static __inline__ __m64 +static inline __m64 pack8888 (__m64 lo, __m64 hi) { return _mm_packs_pu16 (lo, hi); } -static __inline__ CARD32 +static inline CARD32 store8888 (__m64 v) { return _mm_cvtsi64_si32(pack8888(v, _mm_setzero_si64())); @@ -340,7 +339,7 @@ store8888 (__m64 v) * Note the trick here - the top word is shifted by another nibble to * avoid it bumping into the middle word */ -static __inline__ __m64 +static inline __m64 expand565 (__m64 pixel, int pos) { __m64 p = pixel; @@ -360,7 +359,7 @@ expand565 (__m64 pixel, int pos) return _mm_srli_pi16 (pixel, 8); } -static __inline__ __m64 +static inline __m64 expand8888 (__m64 in, int pos) { if (pos == 0) @@ -369,7 +368,7 @@ expand8888 (__m64 in, int pos) return _mm_unpackhi_pi8 (in, _mm_setzero_si64()); } -static __inline__ __m64 +static inline __m64 pack565 (__m64 pixel, __m64 target, int pos) { __m64 p = pixel; @@ -400,7 +399,7 @@ pack565 (__m64 pixel, __m64 target, int pos) } #ifndef _MSC_VER -static __inline__ __m64 +static inline __m64 pix_add_mul (__m64 x, __m64 a, __m64 y, __m64 b) { x = _mm_mullo_pi16 (x, a); @@ -1195,10 +1194,9 @@ fbCompositeSrc_8888x8x8888mmx (pixman_operator_t op, { CARD32 *dstLine, *dst; CARD32 *srcLine, *src; - CARD8 *maskLine; CARD32 mask; __m64 vmask; - FbStride dstStride, srcStride, maskStride; + FbStride dstStride, srcStride; CARD16 w; __m64 srca; @@ -1206,9 +1204,9 @@ fbCompositeSrc_8888x8x8888mmx (pixman_operator_t op, fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); - fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); - mask = *maskLine << 24 | *maskLine << 16 | *maskLine << 8 | *maskLine; + fbComposeGetSolid (pMask, pDst, mask); + mask = mask | mask >> 8 | mask >> 16 | mask >> 24; vmask = load8888 (mask); srca = MC(4x00ff); @@ -1225,7 +1223,7 @@ fbCompositeSrc_8888x8x8888mmx (pixman_operator_t op, __m64 s = load8888 (*src); __m64 d = load8888 (*dst); - *dst = store8888 (over (s, expand_alpha (s), d)); + *dst = store8888 (in_over (s, expand_alpha (s), vmask, d)); w--; dst++; @@ -1234,8 +1232,8 @@ fbCompositeSrc_8888x8x8888mmx (pixman_operator_t op, while (w >= 2) { - __m64 vs = *(__m64 *)dst; - __m64 vd = *(__m64 *)src; + __m64 vs = *(__m64 *)src; + __m64 vd = *(__m64 *)dst; __m64 vsrc0 = expand8888 (vs, 0); __m64 vsrc1 = expand8888 (vs, 1); @@ -1280,10 +1278,9 @@ fbCompositeSrc_x888x8x8888mmx (pixman_operator_t op, { CARD32 *dstLine, *dst; CARD32 *srcLine, *src; - CARD8 *maskLine; CARD32 mask; __m64 vmask; - FbStride dstStride, srcStride, maskStride; + FbStride dstStride, srcStride; CARD16 w; __m64 srca; @@ -1291,9 +1288,9 @@ fbCompositeSrc_x888x8x8888mmx (pixman_operator_t op, fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); - fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); + fbComposeGetSolid (pMask, pDst, mask); - mask = *maskLine << 24 | *maskLine << 16 | *maskLine << 8 | *maskLine; + mask = mask | mask >> 8 | mask >> 16 | mask >> 24; vmask = load8888 (mask); srca = MC(4x00ff); @@ -1657,6 +1654,102 @@ fbCompositeSolidMask_nx8x8888mmx (pixman_operator_t op, _mm_empty(); } +static void +fbSolidFillmmx (FbPixels *pDraw, + int x, + int y, + int width, + int height, + FbBits xor) +{ + FbStride stride; + int bpp; + ullong fill; + __m64 vfill; + CARD32 byte_width; + CARD8 *byte_line; + FbBits *bits; + int xoff, yoff; + + CHECKPOINT(); + + fbGetDrawable(pDraw, bits, stride, bpp, xoff, yoff); + + assert (bpp == 32 || (xor >> 16 == (xor & 0xffff))); + assert (bpp == 16 || bpp == 32); + + if (bpp == 16) + { + stride = stride * sizeof (FbBits) / 2; + byte_line = (CARD8 *)(((CARD16 *)bits) + stride * (y + yoff) + (x + xoff)); + byte_width = 2 * width; + stride *= 2; + } + else + { + stride = stride * sizeof (FbBits) / 4; + byte_line = (CARD8 *)(((CARD32 *)bits) + stride * (y + yoff) + (x + xoff)); + byte_width = 4 * width; + stride *= 4; + } + + fill = ((ullong)xor << 32) | xor; + vfill = M64(fill); + + while (height--) + { + unsigned int w; + CARD8 *d = byte_line; + byte_line += stride; + w = byte_width; + + while (w >= 2 && ((unsigned long)d & 3)) + { + *(CARD16 *)d = xor; + w -= 2; + d += 2; + } + + while (w >= 4 && ((unsigned long)d & 7)) + { + *(CARD32 *)d = xor; + + w -= 4; + d += 4; + } + + while (w >= 64) + { + *(__m64*) (d + 0) = vfill; + *(__m64*) (d + 8) = vfill; + *(__m64*) (d + 16) = vfill; + *(__m64*) (d + 24) = vfill; + *(__m64*) (d + 32) = vfill; + *(__m64*) (d + 40) = vfill; + *(__m64*) (d + 48) = vfill; + *(__m64*) (d + 56) = vfill; + + w -= 64; + d += 64; + } + while (w >= 4) + { + *(CARD32 *)d = xor; + + w -= 4; + d += 4; + } + if (w >= 2) + { + *(CARD16 *)d = xor; + w -= 2; + d += 2; + } + } + + _mm_empty(); +} + void fbCompositeSolidMaskSrc_nx8x8888mmx (pixman_operator_t op, PicturePtr pSrc, @@ -1686,8 +1779,8 @@ fbCompositeSolidMaskSrc_nx8x8888mmx (pixman_operator_t op, srca = src >> 24; if (srca == 0) { - if (fbSolidFillmmx (pDst->pDrawable, xDst, yDst, width, height, 0)) - return; + fbSolidFillmmx (pDst->pDrawable, xDst, yDst, width, height, 0); + return; } srcsrc = (ullong)src << 32 | src; @@ -2591,107 +2684,7 @@ fbCompositeSrcAdd_8888x8888mmx (pixman_operator_t op, _mm_empty(); } -Bool -fbSolidFillmmx (FbPixels *pDraw, - int x, - int y, - int width, - int height, - FbBits xor) -{ - FbStride stride; - int bpp; - ullong fill; - __m64 vfill; - CARD32 byte_width; - CARD8 *byte_line; - FbBits *bits; - int xoff, yoff; - - CHECKPOINT(); - - fbGetDrawable(pDraw, bits, stride, bpp, xoff, yoff); - - if (bpp == 16 && (xor >> 16 != (xor & 0xffff))) - return FALSE; - - if (bpp != 16 && bpp != 32) - return FALSE; - - if (bpp == 16) - { - stride = stride * sizeof (FbBits) / 2; - byte_line = (CARD8 *)(((CARD16 *)bits) + stride * (y + yoff) + (x + xoff)); - byte_width = 2 * width; - stride *= 2; - } - else - { - stride = stride * sizeof (FbBits) / 4; - byte_line = (CARD8 *)(((CARD32 *)bits) + stride * (y + yoff) + (x + xoff)); - byte_width = 4 * width; - stride *= 4; - } - - fill = ((ullong)xor << 32) | xor; - vfill = M64(fill); - - while (height--) - { - unsigned int w; - CARD8 *d = byte_line; - byte_line += stride; - w = byte_width; - - while (w >= 2 && ((unsigned long)d & 3)) - { - *(CARD16 *)d = xor; - w -= 2; - d += 2; - } - - while (w >= 4 && ((unsigned long)d & 7)) - { - *(CARD32 *)d = xor; - - w -= 4; - d += 4; - } - - while (w >= 64) - { - *(__m64*) (d + 0) = vfill; - *(__m64*) (d + 8) = vfill; - *(__m64*) (d + 16) = vfill; - *(__m64*) (d + 24) = vfill; - *(__m64*) (d + 32) = vfill; - *(__m64*) (d + 40) = vfill; - *(__m64*) (d + 48) = vfill; - *(__m64*) (d + 56) = vfill; - - w -= 64; - d += 64; - } - while (w >= 4) - { - *(CARD32 *)d = xor; - - w -= 4; - d += 4; - } - if (w >= 2) - { - *(CARD16 *)d = xor; - w -= 2; - d += 2; - } - } - - _mm_empty(); - return TRUE; -} - -Bool +static void fbCopyAreammx (FbPixels *pSrc, FbPixels *pDst, int src_x, @@ -2720,16 +2713,8 @@ fbCopyAreammx (FbPixels *pSrc, fbGetDrawable(pSrc, src_bits, src_stride, src_bpp, src_xoff, src_yoff); fbGetDrawable(pDst, dst_bits, dst_stride, dst_bpp, dst_xoff, dst_yoff); - if (src_bpp != 16 && src_bpp != 32) - return FALSE; - - if (dst_bpp != 16 && dst_bpp != 32) - return FALSE; - - if (src_bpp != dst_bpp) - { - return FALSE; - } + assert (src_bpp == dst_bpp); + assert (src_bpp == 16 || src_bpp == 32); if (src_bpp == 16) { @@ -2810,7 +2795,6 @@ fbCopyAreammx (FbPixels *pSrc, } _mm_empty(); - return TRUE; } void diff --git a/gfx/cairo/libpixman/src/fbmmx.h b/gfx/cairo/libpixman/src/fbmmx.h index 054ac0b73cd6..9c20cd6a7319 100644 --- a/gfx/cairo/libpixman/src/fbmmx.h +++ b/gfx/cairo/libpixman/src/fbmmx.h @@ -283,16 +283,6 @@ void fbCompositeSrc_8888x8888mmx (pixman_operator_t op, CARD16 width, CARD16 height); pixman_private -Bool fbCopyAreammx (FbPixels *pSrc, - FbPixels *pDst, - int src_x, - int src_y, - int dst_x, - int dst_y, - int width, - int height); - -pixman_private void fbCompositeCopyAreammx (pixman_operator_t op, PicturePtr pSrc, PicturePtr pMask, @@ -305,13 +295,4 @@ void fbCompositeCopyAreammx (pixman_operator_t op, INT16 yDst, CARD16 width, CARD16 height); - -pixman_private -Bool fbSolidFillmmx (FbPixels *pDraw, - int x, - int y, - int width, - int height, - FbBits xor); - #endif /* USE_MMX */ diff --git a/gfx/cairo/libpixman/src/fbpict.c b/gfx/cairo/libpixman/src/fbpict.c index 0bd989fe08df..2d71402f5b0c 100644 --- a/gfx/cairo/libpixman/src/fbpict.c +++ b/gfx/cairo/libpixman/src/fbpict.c @@ -21,9 +21,8 @@ * Author: Keith Packard, SuSE, Inc. */ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "pixmanint.h" + #include "pixman-xserver-compat.h" #ifdef RENDER @@ -1389,7 +1388,7 @@ pixman_composite (pixman_operator_t op, int width, int height) { - pixman_region16_t *region; + pixman_region16_t region; int n; pixman_box16_t *pbox; CompositeFunc func = NULL; @@ -1643,19 +1642,23 @@ pixman_composite (pixman_operator_t op, break; #ifdef USE_MMX case PICT_x8r8g8b8: - case PICT_x8b8g8r8: - if (pDst->format_code == pSrc->format_code && + if ((pDst->format_code == PICT_a8r8g8b8 || + pDst->format_code == PICT_x8r8g8b8) && + pMask->format_code == PICT_a8 && fbHaveMMX()) + func = fbCompositeSrc_x888x8x8888mmx; + break; + case PICT_x8b8g8r8: + if ((pDst->format_code == PICT_a8b8g8r8 || + pDst->format_code == PICT_x8b8g8r8) && pMask->format_code == PICT_a8 && fbHaveMMX()) func = fbCompositeSrc_x888x8x8888mmx; break; -#if 0 /* This case fails rendercheck for me */ case PICT_a8r8g8b8: - if ((pDst->format == PICT_a8r8g8b8 || - pDst->format == PICT_x8r8g8b8) && - pMask->format == PICT_a8 && fbHaveMMX()) + if ((pDst->format_code == PICT_a8r8g8b8 || + pDst->format_code == PICT_x8r8g8b8) && + pMask->format_code == PICT_a8 && fbHaveMMX()) func = fbCompositeSrc_8888x8x8888mmx; break; -#endif case PICT_a8b8g8r8: if ((pDst->format_code == PICT_a8b8g8r8 || pDst->format_code == PICT_x8b8g8r8) && @@ -1932,25 +1935,14 @@ pixman_composite (pixman_operator_t op, if (maskTransform) maskRepeat = 0; - region = pixman_region_create(); - pixman_region_union_rect (region, region, xDst, yDst, width, height); + pixman_region_init_rect (®ion, xDst, yDst, width, height); - if (!FbComputeCompositeRegion (region, - pSrc, - pMask, - pDst, - xSrc, - ySrc, - xMask, - yMask, - xDst, - yDst, - width, - height)) - return; + if (!FbComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height)) + goto CLEANUP_REGION; - n = pixman_region_num_rects (region); - pbox = pixman_region_rects (region); + n = pixman_region_num_rects (®ion); + pbox = pixman_region_rects (®ion); while (n--) { h = pbox->y2 - pbox->y1; @@ -2006,7 +1998,9 @@ pixman_composite (pixman_operator_t op, } pbox++; } - pixman_region_destroy (region); + +CLEANUP_REGION: + pixman_region_fini (®ion); } /* The CPU detection code needs to be in a file not compiled with diff --git a/gfx/cairo/libpixman/src/fbpict.h b/gfx/cairo/libpixman/src/fbpict.h index 0ff0c1123d32..79bd9f54cbad 100644 --- a/gfx/cairo/libpixman/src/fbpict.h +++ b/gfx/cairo/libpixman/src/fbpict.h @@ -327,12 +327,6 @@ #define FASTCALL #endif -#if defined(__GNUC__) -#define INLINE __inline__ -#else -#define INLINE -#endif - typedef struct _FbComposeData { CARD8 op; PicturePtr src; diff --git a/gfx/cairo/libpixman/src/fbtrap.c b/gfx/cairo/libpixman/src/fbtrap.c index b3287511a5b4..bd41cf7ebc4c 100644 --- a/gfx/cairo/libpixman/src/fbtrap.c +++ b/gfx/cairo/libpixman/src/fbtrap.c @@ -1,5 +1,5 @@ /* - * $Id: fbtrap.c,v 1.15 2007/04/04 01:09:16 vladimir%pobox.com Exp $ + * $Id: fbtrap.c,v 1.16 2007/06/11 00:01:31 vladimir%pobox.com Exp $ * * Copyright © 2004 Keith Packard * @@ -22,6 +22,8 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#include "pixmanint.h" + #include "pixman-xserver-compat.h" #ifdef RENDER diff --git a/gfx/cairo/libpixman/src/icblt.c b/gfx/cairo/libpixman/src/icblt.c index 4f0c98e31ae1..69d194514461 100644 --- a/gfx/cairo/libpixman/src/icblt.c +++ b/gfx/cairo/libpixman/src/icblt.c @@ -22,6 +22,8 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#include "pixmanint.h" + #include "pixman-xserver-compat.h" #define InitializeShifts(sx,dx,ls,rs) { \ diff --git a/gfx/cairo/libpixman/src/icbltone.c b/gfx/cairo/libpixman/src/icbltone.c index d67e75d8a348..bdf42b604957 100644 --- a/gfx/cairo/libpixman/src/icbltone.c +++ b/gfx/cairo/libpixman/src/icbltone.c @@ -22,6 +22,8 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#include "pixmanint.h" + #include "pixman-xserver-compat.h" /* diff --git a/gfx/cairo/libpixman/src/iccolor.c b/gfx/cairo/libpixman/src/iccolor.c index 9dd8f5e42c11..df11fa968958 100644 --- a/gfx/cairo/libpixman/src/iccolor.c +++ b/gfx/cairo/libpixman/src/iccolor.c @@ -21,7 +21,7 @@ * Author: Keith Packard, SuSE, Inc. */ -#include "icint.h" +#include "pixmanint.h" #ifdef ICINT_NEED_IC_ONES /* Fall back on HACKMEM 169. */ diff --git a/gfx/cairo/libpixman/src/icformat.c b/gfx/cairo/libpixman/src/icformat.c index bf93a6c9461f..a7b2954599e7 100644 --- a/gfx/cairo/libpixman/src/icformat.c +++ b/gfx/cairo/libpixman/src/icformat.c @@ -21,70 +21,92 @@ * Author: Keith Packard, SuSE, Inc. */ -#include "icint.h" +#include "pixmanint.h" #define Mask(n) ((n) == 32 ? 0xffffffff : (unsigned) ((1 << (n))-1)) -pixman_format_t * -pixman_format_create (pixman_format_name_t name) +int +pixman_format_init (pixman_format_t *format, pixman_format_name_t name) { switch (name) { case PIXMAN_FORMAT_NAME_ARGB32: - return pixman_format_create_masks (32, - 0xff000000, - 0x00ff0000, - 0x0000ff00, - 0x000000ff); + pixman_format_init_masks (format, 32, + 0xff000000, + 0x00ff0000, + 0x0000ff00, + 0x000000ff); + break; + case PIXMAN_FORMAT_NAME_RGB24: - return pixman_format_create_masks (32, - 0x0, - 0xff0000, - 0x00ff00, - 0x0000ff); + pixman_format_init_masks (format, 32, + 0x0, + 0xff0000, + 0x00ff00, + 0x0000ff); + break; + case PIXMAN_FORMAT_NAME_A8: - return pixman_format_create_masks (8, 0xff, - 0, 0, 0); + pixman_format_init_masks (format, 8, + 0xff, + 0, + 0, + 0); + break; + case PIXMAN_FORMAT_NAME_A1: - return pixman_format_create_masks (1, 0x1, - 0, 0, 0); + pixman_format_init_masks (format, 1, + 0x1, + 0, + 0, + 0); + break; + case PIXMAN_FORMAT_NAME_RGB16_565: - return pixman_format_create_masks (16, - 0x0, - 0xf800, - 0x07e0, - 0x001f); + pixman_format_init_masks (format, 16, + 0x0, + 0xf800, + 0x07e0, + 0x001f); + break; + case PIXMAN_FORMAT_NAME_ABGR32: - return pixman_format_create_masks (32, - 0xff000000, - 0x000000ff, - 0x0000ff00, - 0x00ff0000); + pixman_format_init_masks (format, 32, + 0xff000000, + 0x000000ff, + 0x0000ff00, + 0x00ff0000); + break; + case PIXMAN_FORMAT_NAME_BGR24: - return pixman_format_create_masks (32, - 0x0, - 0x000000ff, - 0x0000ff00, - 0x00ff0000); + pixman_format_init_masks (format, 32, + 0x0, + 0x000000ff, + 0x0000ff00, + 0x00ff0000); + break; + + default: + return 0; } - return NULL; + return 1; } /* XXX: There's some nonsense going on here. The macros above help pixman_format_create_masks to encode a format into an int, while - immediately afterwards pixman_format_init goes through the effort of + immediately afterwards pixman_format_init_code goes through the effort of decoding it. This should all be disentagled, (it's probably possible to just eliminate the encoding macros altogether). */ -pixman_format_t * -pixman_format_create_masks (int bpp, - int alpha_mask, - int red_mask, - int green_mask, - int blue_mask) +void +pixman_format_init_masks (pixman_format_t *format, + int bpp, + int alpha_mask, + int red_mask, + int green_mask, + int blue_mask) { int type; int format_code; - pixman_format_t *format; if (red_mask == 0 && green_mask == 0 && blue_mask == 0) type = PICT_TYPE_A; @@ -99,17 +121,11 @@ pixman_format_create_masks (int bpp, _FbOnes (green_mask), _FbOnes (blue_mask)); - format = malloc (sizeof (pixman_format_t)); - if (format == NULL) - return NULL; - - pixman_format_init (format, format_code); - - return format; + pixman_format_init_code (format, format_code); } void -pixman_format_init (pixman_format_t *format, int format_code) +pixman_format_init_code (pixman_format_t *format, int format_code) { memset (format, 0, sizeof (pixman_format_t)); @@ -172,12 +188,6 @@ pixman_format_init (pixman_format_t *format, int format_code) (format->greenMask << format->green)); } -void -pixman_format_destroy (pixman_format_t *format) -{ - free (format); -} - void pixman_format_get_masks (pixman_format_t *format, unsigned int *bpp, diff --git a/gfx/cairo/libpixman/src/icimage.c b/gfx/cairo/libpixman/src/icimage.c index 4d957a0fc379..61a84c5c4c92 100644 --- a/gfx/cairo/libpixman/src/icimage.c +++ b/gfx/cairo/libpixman/src/icimage.c @@ -21,6 +21,8 @@ * Author: Keith Packard, SuSE, Inc. */ +#include "pixmanint.h" + #include "pixman-xserver-compat.h" pixman_image_t * @@ -187,6 +189,8 @@ _pixman_create_source_image (void) pixman_image_t *image; image = (pixman_image_t *) malloc (sizeof (pixman_image_t)); + if (image == NULL) + return NULL; image->pDrawable = NULL; image->pixels = NULL; image->format_code = PICT_a8r8g8b8; @@ -303,8 +307,8 @@ pixman_image_init (pixman_image_t *image) * In the server this was 0 because the composite clip list * can be referenced from a window (and often is) */ - image->freeCompClip = 0; - image->freeSourceClip = 0; + image->hasCompositeClip = 0; + image->hasSourceClip = 0; image->clientClipType = CT_NONE; image->componentAlpha = 0; image->compositeClipSource = 0; @@ -315,7 +319,6 @@ pixman_image_init (pixman_image_t *image) image->clipOrigin.x = 0; image->clipOrigin.y = 0; - image->clientClip = NULL; image->dither = 0L; @@ -324,24 +327,16 @@ pixman_image_init (pixman_image_t *image) image->serialNumber = GC_CHANGE_SERIAL_BIT; */ - if (image->pixels) - { - image->pCompositeClip = pixman_region_create(); - pixman_region_union_rect (image->pCompositeClip, image->pCompositeClip, - 0, 0, image->pixels->width, - image->pixels->height); - image->freeCompClip = 1; + if (image->pixels) { + pixman_region_init_rect (&image->compositeClip, + 0, 0, image->pixels->width, + image->pixels->height); + image->hasCompositeClip = 1; - image->pSourceClip = pixman_region_create (); - pixman_region_union_rect (image->pSourceClip, image->pSourceClip, - 0, 0, image->pixels->width, - image->pixels->height); - image->freeSourceClip = 1; - } - else - { - image->pCompositeClip = NULL; - image->pSourceClip = NULL; + pixman_region_init_rect (&image->sourceClip, + 0, 0, image->pixels->width, + image->pixels->height); + image->hasSourceClip = 1; } image->transform = NULL; @@ -469,14 +464,14 @@ pixman_image_destroy (pixman_image_t *image) { pixman_image_destroyClip (image); - if (image->freeCompClip) { - pixman_region_destroy (image->pCompositeClip); - image->pCompositeClip = NULL; + if (image->hasCompositeClip) { + pixman_region_fini (&image->compositeClip); + image->hasCompositeClip = 0; } - if (image->freeSourceClip) { - pixman_region_destroy (image->pSourceClip); - image->pSourceClip = NULL; + if (image->hasSourceClip) { + pixman_region_fini (&image->sourceClip); + image->hasSourceClip = 0; } if (image->owns_pixels) { @@ -500,17 +495,9 @@ pixman_image_destroy (pixman_image_t *image) void pixman_image_destroyClip (pixman_image_t *image) { - switch (image->clientClipType) { - case CT_NONE: - return; - case CT_PIXMAP: - pixman_image_destroy (image->clientClip); - break; - default: - pixman_region_destroy (image->clientClip); - break; - } - image->clientClip = NULL; + if (CT_NONE != image->clientClipType) + pixman_region_fini (&image->clientClip); + image->clientClipType = CT_NONE; } @@ -519,9 +506,14 @@ pixman_image_set_clip_region (pixman_image_t *image, pixman_region16_t *region) { pixman_image_destroyClip (image); + if (region) { - image->clientClip = pixman_region_create (); - pixman_region_copy (image->clientClip, region); + pixman_region_init (&image->clientClip); + if (pixman_region_copy (&image->clientClip, region) != + PIXMAN_REGION_STATUS_SUCCESS) { + pixman_region_fini (&image->clientClip); + return 1; + } image->clientClipType = CT_REGION; } @@ -529,20 +521,28 @@ pixman_image_set_clip_region (pixman_image_t *image, if (image->pSourcePict) return 0; - if (image->freeCompClip) - pixman_region_destroy (image->pCompositeClip); - image->pCompositeClip = pixman_region_create(); - pixman_region_union_rect (image->pCompositeClip, image->pCompositeClip, - 0, 0, image->pixels->width, image->pixels->height); - image->freeCompClip = 1; + if (image->hasCompositeClip) + pixman_region_fini (&image->compositeClip); + + pixman_region_init_rect (&image->compositeClip, 0, 0, + image->pixels->width, + image->pixels->height); + + image->hasCompositeClip = 1; + if (region) { - pixman_region_translate (image->pCompositeClip, + pixman_region_translate (&image->compositeClip, - image->clipOrigin.x, - image->clipOrigin.y); - pixman_region_intersect (image->pCompositeClip, - image->pCompositeClip, - region); - pixman_region_translate (image->pCompositeClip, + if (pixman_region_intersect (&image->compositeClip, + &image->compositeClip, + region) != PIXMAN_REGION_STATUS_SUCCESS) { + pixman_image_destroyClip (image); + pixman_region_fini (&image->compositeClip); + image->hasCompositeClip = 0; + return 1; + } + pixman_region_translate (&image->compositeClip, image->clipOrigin.x, image->clipOrigin.y); } @@ -552,12 +552,13 @@ pixman_image_set_clip_region (pixman_image_t *image, #define BOUND(v) (int16_t) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v)) -static __inline int +static inline int FbClipImageReg (pixman_region16_t *region, pixman_region16_t *clip, int dx, int dy) { + int ret = 1; if (pixman_region_num_rects (region) == 1 && pixman_region_num_rects (clip) == 1) { @@ -581,14 +582,17 @@ FbClipImageReg (pixman_region16_t *region, } else { + pixman_region_status_t status; + pixman_region_translate (region, dx, dy); - pixman_region_intersect (region, clip, region); + status = pixman_region_intersect (region, clip, region); + ret = status == PIXMAN_REGION_STATUS_SUCCESS; pixman_region_translate (region, -dx, -dy); } - return 1; + return ret; } -static __inline int +static inline int FbClipImageSrc (pixman_region16_t *region, pixman_image_t *image, int dx, @@ -597,225 +601,43 @@ FbClipImageSrc (pixman_region16_t *region, /* XXX what to do with clipping from transformed pictures? */ if (image->transform) return 1; + /* XXX davidr hates this, wants to never use source-based clipping */ - if (image->repeat != PIXMAN_REPEAT_NONE || image->pSourcePict) - { + if (image->repeat != PIXMAN_REPEAT_NONE || image->pSourcePict) { + int ret = 1; /* XXX no source clipping */ if (image->compositeClipSource && - image->clientClipType != CT_NONE) - { + image->clientClipType != CT_NONE) { + pixman_region_status_t status; + pixman_region_translate (region, dx - image->clipOrigin.x, dy - image->clipOrigin.y); - pixman_region_intersect (region, image->clientClip, region); + status = pixman_region_intersect (region, + &image->clientClip, + region); + ret = status == PIXMAN_REGION_STATUS_SUCCESS; pixman_region_translate (region, - (dx - image->clipOrigin.x), - (dy - image->clipOrigin.y)); } - return 1; - } - else - { - pixman_region16_t *clip; - if (image->compositeClipSource) - clip = image->pCompositeClip; - else - clip = image->pSourceClip; - return FbClipImageReg (region, - clip, - dx, - dy); + return ret; + } else { + pixman_region16_t *clip; + + if (image->compositeClipSource) { + clip = (image->hasCompositeClip ? &image->compositeClip : NULL); + } else { + clip = (image->hasSourceClip ? &image->sourceClip : NULL); + } + + return FbClipImageReg (region, clip, dx, dy); } + return 1; } -/* XXX: Need to decide what to do with this -#define NEXT_VAL(_type) (vlist ? (_type) *vlist++ : (_type) ulist++->val) - -#define NEXT_PTR(_type) ((_type) ulist++->ptr) - -int -pixman_image_change (pixman_image_t *image, - Mask vmask, - unsigned int *vlist, - DevUnion *ulist, - int *error_value) -{ - BITS32 index2; - int error = 0; - BITS32 maskQ; - - maskQ = vmask; - while (vmask && !error) - { - index2 = (BITS32) lowbit (vmask); - vmask &= ~index2; - image->stateChanges |= index2; - switch (index2) - { - case CPRepeat: - { - unsigned int newr; - newr = NEXT_VAL(unsigned int); - if (newr <= xTrue) - image->repeat = newr; - else - { - *error_value = newr; - error = BadValue; - } - } - break; - case CPAlphaMap: - { - pixman_image_t *iAlpha; - - iAlpha = NEXT_PTR(pixman_image_t *); - if (iAlpha) - iAlpha->refcnt++; - if (image->alphaMap) - pixman_image_destroy ((void *) image->alphaMap); - image->alphaMap = iAlpha; - } - break; - case CPAlphaXOrigin: - image->alphaOrigin.x = NEXT_VAL(int16_t); - break; - case CPAlphaYOrigin: - image->alphaOrigin.y = NEXT_VAL(int16_t); - break; - case CPClipXOrigin: - image->clipOrigin.x = NEXT_VAL(int16_t); - break; - case CPClipYOrigin: - image->clipOrigin.y = NEXT_VAL(int16_t); - break; - case CPClipMask: - { - pixman_image_t *mask; - int clipType; - - mask = NEXT_PTR(pixman_image_t *); - if (mask) { - clipType = CT_PIXMAP; - mask->refcnt++; - } else { - clipType = CT_NONE; - } - error = pixman_image_change_clip (image, clipType, - (void *)mask, 0); - break; - } - case CPGraphicsExposure: - { - unsigned int newe; - newe = NEXT_VAL(unsigned int); - if (newe <= xTrue) - image->graphicsExposures = newe; - else - { - *error_value = newe; - error = BadValue; - } - } - break; - case CPSubwindowMode: - { - unsigned int news; - news = NEXT_VAL(unsigned int); - if (news == ClipByChildren || news == IncludeInferiors) - image->subWindowMode = news; - else - { - *error_value = news; - error = BadValue; - } - } - break; - case CPPolyEdge: - { - unsigned int newe; - newe = NEXT_VAL(unsigned int); - if (newe == PolyEdgeSharp || newe == PolyEdgeSmooth) - image->polyEdge = newe; - else - { - *error_value = newe; - error = BadValue; - } - } - break; - case CPPolyMode: - { - unsigned int newm; - newm = NEXT_VAL(unsigned int); - if (newm == PolyModePrecise || newm == PolyModeImprecise) - image->polyMode = newm; - else - { - *error_value = newm; - error = BadValue; - } - } - break; - case CPDither: - image->dither = NEXT_VAL(unsigned long); - break; - case CPComponentAlpha: - { - unsigned int newca; - - newca = NEXT_VAL (unsigned int); - if (newca <= xTrue) - image->componentAlpha = newca; - else - { - *error_value = newca; - error = BadValue; - } - } - break; - default: - *error_value = maskQ; - error = BadValue; - break; - } - } - return error; -} -*/ - -/* XXX: Do we need this? -int -SetPictureClipRects (PicturePtr pPicture, - int xOrigin, - int yOrigin, - int nRect, - xRectangle *rects) -{ - ScreenPtr pScreen = pPicture->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - pixman_region16_t *clientClip; - int result; - - clientClip = RECTS_TO_REGION(pScreen, - nRect, rects, CT_UNSORTED); - if (!clientClip) - return 1; - result =(*ps->ChangePictureClip) (pPicture, CT_REGION, - (void *) clientClip, 0); - if (result == 0) - { - pPicture->clipOrigin.x = xOrigin; - pPicture->clipOrigin.y = yOrigin; - pPicture->stateChanges |= CPClipXOrigin|CPClipYOrigin|CPClipMask; - pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT; - } - return result; -} -*/ - int FbComputeCompositeRegion (pixman_region16_t *region, pixman_image_t *iSrc, @@ -844,63 +666,48 @@ FbComputeCompositeRegion (pixman_region16_t *region, y1 = yDst; v = yDst + height; y2 = BOUND(v); + /* Check for empty operation */ - if (x1 >= x2 || - y1 >= y2) - { + if (x1 >= x2 || y1 >= y2) { pixman_region_empty (region); return 1; } + /* clip against src */ if (!FbClipImageSrc (region, iSrc, xDst - xSrc, yDst - ySrc)) - { - pixman_region_destroy (region); return 0; - } - if (iSrc->alphaMap) - { - if (!FbClipImageSrc (region, iSrc->alphaMap, - xDst - (xSrc + iSrc->alphaOrigin.x), - yDst - (ySrc + iSrc->alphaOrigin.y))) - { - pixman_region_destroy (region); - return 0; - } - } + + if (iSrc->alphaMap && + !FbClipImageSrc (region, iSrc->alphaMap, + xDst - (xSrc + iSrc->alphaOrigin.x), + yDst - (ySrc + iSrc->alphaOrigin.y))) + return 0; + /* clip against mask */ - if (iMask) - { + if (iMask) { if (!FbClipImageSrc (region, iMask, xDst - xMask, yDst - yMask)) - { - pixman_region_destroy (region); return 0; - } - if (iMask->alphaMap) - { - if (!FbClipImageSrc (region, iMask->alphaMap, - xDst - (xMask + iMask->alphaOrigin.x), - yDst - (yMask + iMask->alphaOrigin.y))) - { - pixman_region_destroy (region); - return 0; - } - } + + if (iMask->alphaMap && + !FbClipImageSrc (region, iMask->alphaMap, + xDst - (xMask + iMask->alphaOrigin.x), + yDst - (yMask + iMask->alphaOrigin.y))) + return 0; } - if (!FbClipImageReg (region, iDst->pCompositeClip, 0, 0)) - { - pixman_region_destroy (region); + + if (!FbClipImageReg (region, + iDst->hasCompositeClip ? + &iDst->compositeClip : NULL, + 0, 0)) return 0; - } - if (iDst->alphaMap) - { - if (!FbClipImageReg (region, iDst->alphaMap->pCompositeClip, - -iDst->alphaOrigin.x, - -iDst->alphaOrigin.y)) - { - pixman_region_destroy (region); - return 0; - } - } + + if (iDst->alphaMap && + !FbClipImageReg (region, + iDst->hasCompositeClip ? + &iDst->alphaMap->compositeClip : NULL, + -iDst->alphaOrigin.x, -iDst->alphaOrigin.y)) + return 0; + return 1; } diff --git a/gfx/cairo/libpixman/src/icimage.h b/gfx/cairo/libpixman/src/icimage.h index bbf41b99c02f..b983429675ae 100644 --- a/gfx/cairo/libpixman/src/icimage.h +++ b/gfx/cairo/libpixman/src/icimage.h @@ -143,8 +143,8 @@ struct pixman_image { unsigned int subWindowMode : 1; unsigned int polyEdge : 1; unsigned int polyMode : 1; - unsigned int freeCompClip : 1; - unsigned int freeSourceClip : 1; + unsigned int hasCompositeClip : 1; + unsigned int hasSourceClip : 1; unsigned int clientClipType : 2; unsigned int componentAlpha : 1; unsigned int compositeClipSource : 1; @@ -154,15 +154,15 @@ struct pixman_image { FbPoint alphaOrigin; FbPoint clipOrigin; - void *clientClip; unsigned long dither; unsigned long stateChanges; unsigned long serialNumber; - pixman_region16_t *pCompositeClip; - pixman_region16_t *pSourceClip; + pixman_region16_t clientClip; + pixman_region16_t compositeClip; + pixman_region16_t sourceClip; pixman_transform_t *transform; diff --git a/gfx/cairo/libpixman/src/icint.h b/gfx/cairo/libpixman/src/icint.h index 47a2220059b1..97de1a6096b4 100644 --- a/gfx/cairo/libpixman/src/icint.h +++ b/gfx/cairo/libpixman/src/icint.h @@ -33,16 +33,6 @@ #include #include -#ifndef __GNUC__ -#define __inline -#endif - -#if defined(__GNUC__) -#define INLINE __inline__ -#else -#define INLINE -#endif - #undef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #undef MAX @@ -748,16 +738,6 @@ fbStipple (pixman_bits_t *dst, int xRot, int yRot); -/* XXX: Is depth redundant here? */ -struct pixman_format { - int format_code; - int depth; - int red, redMask; - int green, greenMask; - int blue, blueMask; - int alpha, alphaMask; -}; - typedef struct _FbPixels { pixman_bits_t *data; unsigned int width; @@ -788,7 +768,7 @@ fbRasterizeTrapezoid (pixman_image_t *pMask, /* XXX: This is to avoid including gc.h from the server includes */ /* clientClipType field in GC */ #define CT_NONE 0 -#define CT_PIXMAP 1 +/* #define CT_PIXMAP 1 (not used anymore) */ #define CT_REGION 2 #define CT_UNSORTED 6 #define CT_YSORTED 10 @@ -804,7 +784,7 @@ fbRasterizeTrapezoid (pixman_image_t *pMask, in libgcc in case a target does not have one, which should be just as good as the static function below. */ #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -static INLINE int +static inline int _FbOnes(unsigned int mask) { return __builtin_popcount(mask); @@ -818,7 +798,7 @@ _FbOnes(unsigned int mask); /* icformat.c */ pixman_private void -pixman_format_init (pixman_format_t *format, int format_code); +pixman_format_init_code (pixman_format_t *format, int format_code); /* icimage.c */ diff --git a/gfx/cairo/libpixman/src/icpixels.c b/gfx/cairo/libpixman/src/icpixels.c index 605214e71f57..89759715dc90 100644 --- a/gfx/cairo/libpixman/src/icpixels.c +++ b/gfx/cairo/libpixman/src/icpixels.c @@ -20,6 +20,8 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#include "pixmanint.h" + #include "pixman-xserver-compat.h" static void diff --git a/gfx/cairo/libpixman/src/icrect.c b/gfx/cairo/libpixman/src/icrect.c index e4d0c12aade2..2ce58968438c 100644 --- a/gfx/cairo/libpixman/src/icrect.c +++ b/gfx/cairo/libpixman/src/icrect.c @@ -20,7 +20,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -#include "icint.h" +#include "pixmanint.h" typedef void (*FillFunc) (pixman_image_t *dst, int16_t xDst, @@ -176,7 +176,7 @@ pixman_fill_rect_general (pixman_image_t *dst, } } -static void +static int pixman_color_rects (pixman_image_t *dst, pixman_image_t *clipPict, pixman_color_t *color, @@ -185,12 +185,13 @@ pixman_color_rects (pixman_image_t *dst, int xoff, int yoff) { - pixman_bits_t pixel; - pixman_region16_t *clip; - pixman_region16_t *rects_as_region; + pixman_bits_t pixel; + pixman_region16_t clip; + pixman_region16_t rects_as_region; pixman_box16_t *clipped_rects; int i, n_clipped_rects; FillFunc func; + pixman_region_status_t status; pixman_color_to_pixel (&dst->image_format, color, @@ -200,19 +201,34 @@ pixman_color_rects (pixman_image_t *dst, xoff -= dst->pixels->x; yoff -= dst->pixels->y; - clip = pixman_region_create(); - pixman_region_union_rect (clip, clip, - dst->pixels->x, dst->pixels->y, - dst->pixels->width, dst->pixels->height); + pixman_region_init_rect (&clip, + dst->pixels->x, dst->pixels->y, + dst->pixels->width, dst->pixels->height); - pixman_region_intersect (clip, clip, clipPict->pCompositeClip); + status = pixman_region_intersect (&clip, &clip, + clipPict->hasCompositeClip ? + &clipPict->compositeClip : + NULL); + if (status != PIXMAN_REGION_STATUS_SUCCESS) + { + pixman_region_fini (&clip); + return 1; + } if (clipPict->alphaMap) { - pixman_region_translate (clip, + pixman_region_translate (&clip, -clipPict->alphaOrigin.x, -clipPict->alphaOrigin.y); - pixman_region_intersect (clip, clip, clipPict->alphaMap->pCompositeClip); - pixman_region_translate (clip, + status = pixman_region_intersect (&clip, &clip, + clipPict->alphaMap->hasCompositeClip ? + &clipPict->alphaMap->compositeClip : + NULL); + if (status != PIXMAN_REGION_STATUS_SUCCESS) + { + pixman_region_fini (&clip); + return 1; + } + pixman_region_translate (&clip, clipPict->alphaOrigin.x, clipPict->alphaOrigin.y); } @@ -226,19 +242,32 @@ pixman_color_rects (pixman_image_t *dst, } } - rects_as_region = pixman_region_create (); + pixman_region_init (&rects_as_region); + for (i = 0; i < nRect; i++) { - pixman_region_union_rect (rects_as_region, rects_as_region, - rects[i].x, rects[i].y, - rects[i].width, rects[i].height); + status = pixman_region_union_rect (&rects_as_region, &rects_as_region, + rects[i].x, rects[i].y, + rects[i].width, rects[i].height); + if (status != PIXMAN_REGION_STATUS_SUCCESS) + { + break; + } } - pixman_region_intersect (rects_as_region, rects_as_region, clip); - pixman_region_destroy (clip); + /* any earlier failure will also trigger a failure here... */ + status = pixman_region_intersect (&rects_as_region, + &rects_as_region, + &clip); + pixman_region_fini (&clip); + if (status != PIXMAN_REGION_STATUS_SUCCESS) + { + pixman_region_fini (&rects_as_region); + return 1; + } - n_clipped_rects = pixman_region_num_rects (rects_as_region); - clipped_rects = pixman_region_rects (rects_as_region); + n_clipped_rects = pixman_region_num_rects (&rects_as_region); + clipped_rects = pixman_region_rects (&rects_as_region); if (dst->pixels->bpp == 8) func = pixman_fill_rect_8bpp; @@ -258,7 +287,7 @@ pixman_color_rects (pixman_image_t *dst, &pixel); } - pixman_region_destroy (rects_as_region); + pixman_region_fini (&rects_as_region); if (xoff || yoff) { @@ -268,9 +297,11 @@ pixman_color_rects (pixman_image_t *dst, rects[i].y += yoff; } } + + return 0; } -void pixman_fill_rectangle (pixman_operator_t op, +int pixman_fill_rectangle (pixman_operator_t op, pixman_image_t *dst, const pixman_color_t *color, int x, @@ -285,16 +316,17 @@ void pixman_fill_rectangle (pixman_operator_t op, rect.width = width; rect.height = height; - pixman_fill_rectangles (op, dst, color, &rect, 1); + return pixman_fill_rectangles (op, dst, color, &rect, 1); } -void +int pixman_fill_rectangles (pixman_operator_t op, pixman_image_t *dst, const pixman_color_t *color, const pixman_rectangle_t *rects, int nRects) { + int ret = 1; pixman_color_t color_s = *color; if (color_s.alpha == 0xffff) @@ -309,12 +341,16 @@ pixman_fill_rectangles (pixman_operator_t op, { /* We cast away the constness of rects here, because pixman_color_rects temporarily modifies it */ - pixman_color_rects (dst, dst, &color_s, nRects, (pixman_rectangle_t *)rects, 0, 0); - if (dst->alphaMap) - pixman_color_rects (dst->alphaMap, dst, - &color_s, nRects, (pixman_rectangle_t *)rects, - dst->alphaOrigin.x, - dst->alphaOrigin.y); + ret = pixman_color_rects (dst, dst, + &color_s, + nRects, (pixman_rectangle_t *)rects, + 0, 0); + if (!ret && dst->alphaMap) + ret = pixman_color_rects (dst->alphaMap, dst, + &color_s, + nRects, (pixman_rectangle_t *)rects, + dst->alphaOrigin.x, + dst->alphaOrigin.y); } else { @@ -323,7 +359,7 @@ pixman_fill_rectangles (pixman_operator_t op, pixman_image_t *src; pixman_bits_t pixel; - pixman_format_init (&rgbaFormat, PICT_a8r8g8b8); + pixman_format_init_code (&rgbaFormat, PICT_a8r8g8b8); pixels = FbPixelsCreate (1, 1, rgbaFormat.depth); if (!pixels) @@ -357,9 +393,12 @@ pixman_fill_rectangles (pixman_operator_t op, } pixman_image_destroy (src); + ret = 0; bail2: FbPixelsDestroy (pixels); bail1: ; } + + return ret; } diff --git a/gfx/cairo/libpixman/src/icstipple.c b/gfx/cairo/libpixman/src/icstipple.c index 8074d7a98fe1..d14e5aa9301c 100644 --- a/gfx/cairo/libpixman/src/icstipple.c +++ b/gfx/cairo/libpixman/src/icstipple.c @@ -22,6 +22,8 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#include "pixmanint.h" + #include "pixman-xserver-compat.h" #ifndef ICNOPIXADDR diff --git a/gfx/cairo/libpixman/src/ictransform.c b/gfx/cairo/libpixman/src/ictransform.c index 013c8caa5ac5..5ee1f0b00be7 100644 --- a/gfx/cairo/libpixman/src/ictransform.c +++ b/gfx/cairo/libpixman/src/ictransform.c @@ -21,7 +21,7 @@ * Author: Keith Packard, SuSE, Inc. */ -#include "icint.h" +#include "pixmanint.h" #define MAX_FIXED_48_16 ((xFixed_48_16) 0x7fffffff) #define MIN_FIXED_48_16 (-((xFixed_48_16) 1 << 31)) diff --git a/gfx/cairo/libpixman/src/ictrap.c b/gfx/cairo/libpixman/src/ictrap.c index 5a33ab828414..6ef19cf6ce96 100644 --- a/gfx/cairo/libpixman/src/ictrap.c +++ b/gfx/cairo/libpixman/src/ictrap.c @@ -20,7 +20,9 @@ * PERFORMANCE OF THIS SOFTWARE. */ -#include "icint.h" +#include "pixmanint.h" + +#include pixman_image_t * FbCreateAlphaPicture (pixman_image_t *dst, @@ -28,30 +30,24 @@ FbCreateAlphaPicture (pixman_image_t *dst, uint16_t width, uint16_t height) { - pixman_image_t *image; - int own_format = 0; + pixman_format_t local_format; if (width > 32767 || height > 32767) return NULL; if (!format) { - own_format = 1; + int ret; + format = &local_format; if (dst->polyEdge == PolyEdgeSharp) - format = pixman_format_create (PIXMAN_FORMAT_NAME_A1); + ret = pixman_format_init (format, PIXMAN_FORMAT_NAME_A1); else - format = pixman_format_create (PIXMAN_FORMAT_NAME_A8); - if (!format) - return NULL; + ret = pixman_format_init (format, PIXMAN_FORMAT_NAME_A8); + assert (ret); } /* pixman_image_create zeroes out the pixels, so we don't have to */ - image = pixman_image_create (format, width, height); - - if (own_format) - pixman_format_destroy (format); - - return image; + return pixman_image_create (format, width, height); } static pixman_fixed16_16_t @@ -98,10 +94,7 @@ pixman_trapezoid_bounds (int ntrap, const pixman_trapezoid_t *traps, pixman_box1 } } -/* XXX: There are failure cases in this function. Don't we need to - * propagate the errors out? - */ -void +int pixman_composite_trapezoids (pixman_operator_t op, pixman_image_t *src, pixman_image_t *dst, @@ -110,15 +103,17 @@ pixman_composite_trapezoids (pixman_operator_t op, const pixman_trapezoid_t *traps, int ntraps) { - pixman_image_t *image = NULL; - pixman_box16_t traps_bounds, dst_bounds, bounds; - pixman_region16_t *traps_region, *dst_region; - int16_t xDst, yDst; - int16_t xRel, yRel; - pixman_format_t *format; + pixman_image_t *image = NULL; + pixman_box16_t traps_bounds, dst_bounds, bounds; + pixman_region16_t traps_region, dst_region; + int16_t xDst, yDst; + int16_t xRel, yRel; + pixman_format_t format; + pixman_region_status_t status; + int ret; if (ntraps == 0) - return; + return 0; /* * Check for solid alpha add @@ -127,15 +122,14 @@ pixman_composite_trapezoids (pixman_operator_t op, { for (; ntraps; ntraps--, traps++) fbRasterizeTrapezoid (dst, traps, 0, 0); - return; + return 0; } xDst = traps[0].left.p1.x >> 16; yDst = traps[0].left.p1.y >> 16; pixman_trapezoid_bounds (ntraps, traps, &traps_bounds); - - traps_region = pixman_region_create_simple (&traps_bounds); + pixman_region_init_with_extents (&traps_region, &traps_bounds); /* XXX: If the image has a clip region set, we should really be * fetching it here instead, but it looks like we don't yet expose @@ -145,30 +139,30 @@ pixman_composite_trapezoids (pixman_operator_t op, dst_bounds.x2 = pixman_image_get_width (dst); dst_bounds.y2 = pixman_image_get_height (dst); - dst_region = pixman_region_create_simple (&dst_bounds); + pixman_region_init_with_extents (&dst_region, &dst_bounds); + status = pixman_region_intersect (&traps_region, &traps_region, &dst_region); + if (status != PIXMAN_REGION_STATUS_SUCCESS) { + pixman_region_fini (&traps_region); + pixman_region_fini (&dst_region); + return 1; + } - pixman_region_intersect (traps_region, traps_region, dst_region); + bounds = *(pixman_region_extents (&traps_region)); - bounds = *(pixman_region_extents (traps_region)); - - pixman_region_destroy (traps_region); - pixman_region_destroy (dst_region); + pixman_region_fini (&traps_region); + pixman_region_fini (&dst_region); if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) - return; + return 0; - format = pixman_format_create (PIXMAN_FORMAT_NAME_A8); - if (!format) - return; + ret = pixman_format_init (&format, PIXMAN_FORMAT_NAME_A8); + assert (ret); - image = FbCreateAlphaPicture (dst, format, + image = FbCreateAlphaPicture (dst, &format, bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); if (!image) - { - pixman_format_destroy (format); - return; - } + return 1; for (; ntraps; ntraps--, traps++) { @@ -186,7 +180,7 @@ pixman_composite_trapezoids (pixman_operator_t op, bounds.y2 - bounds.y1); pixman_image_destroy (image); - pixman_format_destroy (format); + return 0; } void diff --git a/gfx/cairo/libpixman/src/ictri.c b/gfx/cairo/libpixman/src/ictri.c index 408023994fba..7fb76a5c587b 100644 --- a/gfx/cairo/libpixman/src/ictri.c +++ b/gfx/cairo/libpixman/src/ictri.c @@ -20,7 +20,9 @@ * PERFORMANCE OF THIS SOFTWARE. */ -#include "icint.h" +#include "pixmanint.h" + +#include static void pixman_point_fixed_bounds (int npoint, const pixman_point_fixed_t *points, pixman_box16_t *bounds) @@ -147,62 +149,38 @@ pixman_composite_triangles (pixman_operator_t op, pixman_image_t *image = NULL; int xDst, yDst; int xRel, yRel; - pixman_format_t *format; + pixman_format_t format; + int ret; xDst = tris[0].p1.x >> 16; yDst = tris[0].p1.y >> 16; - format = pixman_format_create (PIXMAN_FORMAT_NAME_A8); + ret = pixman_format_init (&format, PIXMAN_FORMAT_NAME_A8); + assert (ret); + + pixman_triangle_bounds (ntris, tris, &bounds); + if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) + return; + + image = FbCreateAlphaPicture (dst, + &format, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + if (!image) + return; - if (format) - { - pixman_triangle_bounds (ntris, tris, &bounds); - if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) - return; - image = FbCreateAlphaPicture (dst, - format, - bounds.x2 - bounds.x1, - bounds.y2 - bounds.y1); - if (!image) - return; - } for (; ntris; ntris--, tris++) { - if (!format) - { - pixman_triangle_bounds (1, tris, &bounds); - if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) - continue; - image = FbCreateAlphaPicture (dst, - format, - bounds.x2 - bounds.x1, - bounds.y2 - bounds.y1); - if (!image) - break; - } FbRasterizeTriangle (image, tris, -bounds.x1, -bounds.y1); - if (!format) - { - xRel = bounds.x1 + xSrc - xDst; - yRel = bounds.y1 + ySrc - yDst; - pixman_composite (op, src, image, dst, - xRel, yRel, 0, 0, bounds.x1, bounds.y1, - bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); - pixman_image_destroy (image); - } /* XXX adjust xSrc and ySrc */ } - if (format) - { - xRel = bounds.x1 + xSrc - xDst; - yRel = bounds.y1 + ySrc - yDst; - pixman_composite (op, src, image, dst, - xRel, yRel, 0, 0, bounds.x1, bounds.y1, - bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); - pixman_image_destroy (image); - } - pixman_format_destroy (format); + xRel = bounds.x1 + xSrc - xDst; + yRel = bounds.y1 + ySrc - yDst; + pixman_composite (op, src, image, dst, + xRel, yRel, 0, 0, bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); + pixman_image_destroy (image); } void @@ -219,7 +197,8 @@ pixman_composite_tri_strip (pixman_operator_t op, pixman_image_t *image = NULL; int xDst, yDst; int xRel, yRel; - pixman_format_t *format; + pixman_format_t format; + int ret; if (npoints < 3) return; @@ -227,59 +206,34 @@ pixman_composite_tri_strip (pixman_operator_t op, xDst = points[0].x >> 16; yDst = points[0].y >> 16; - format = pixman_format_create (PIXMAN_FORMAT_NAME_A8); + ret = pixman_format_init (&format, PIXMAN_FORMAT_NAME_A8); + assert (ret); + + pixman_point_fixed_bounds (npoints, points, &bounds); + if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) + return; + + image = FbCreateAlphaPicture (dst, + &format, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + if (!image) + return; - if (format) - { - pixman_point_fixed_bounds (npoints, points, &bounds); - if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) - return; - image = FbCreateAlphaPicture (dst, - format, - bounds.x2 - bounds.x1, - bounds.y2 - bounds.y1); - if (!image) - return; - } for (; npoints >= 3; npoints--, points++) { tri.p1 = points[0]; tri.p2 = points[1]; tri.p3 = points[2]; - if (!format) - { - pixman_triangle_bounds (1, &tri, &bounds); - if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) - continue; - image = FbCreateAlphaPicture (dst, - format, - bounds.x2 - bounds.x1, - bounds.y2 - bounds.y1); - if (!image) - continue; - } FbRasterizeTriangle (image, &tri, -bounds.x1, -bounds.y1); - if (!format) - { - xRel = bounds.x1 + xSrc - xDst; - yRel = bounds.y1 + ySrc - yDst; - pixman_composite (op, src, image, dst, - xRel, yRel, 0, 0, bounds.x1, bounds.y1, - bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); - pixman_image_destroy (image); - } - } - if (format) - { - xRel = bounds.x1 + xSrc - xDst; - yRel = bounds.y1 + ySrc - yDst; - pixman_composite (op, src, image, dst, - xRel, yRel, 0, 0, bounds.x1, bounds.y1, - bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); - pixman_image_destroy (image); } - pixman_format_destroy (format); + xRel = bounds.x1 + xSrc - xDst; + yRel = bounds.y1 + ySrc - yDst; + pixman_composite (op, src, image, dst, + xRel, yRel, 0, 0, bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); + pixman_image_destroy (image); } void @@ -297,7 +251,8 @@ pixman_composite_tri_fan (pixman_operator_t op, const pixman_point_fixed_t *first; int xDst, yDst; int xRel, yRel; - pixman_format_t *format; + pixman_format_t format; + int ret; if (npoints < 3) return; @@ -305,20 +260,20 @@ pixman_composite_tri_fan (pixman_operator_t op, xDst = points[0].x >> 16; yDst = points[0].y >> 16; - format = pixman_format_create (PIXMAN_FORMAT_NAME_A8); + ret = pixman_format_init (&format, PIXMAN_FORMAT_NAME_A8); + assert (ret); + + pixman_point_fixed_bounds (npoints, points, &bounds); + if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) + return; + + image = FbCreateAlphaPicture (dst, + &format, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + if (!image) + return; - if (format) - { - pixman_point_fixed_bounds (npoints, points, &bounds); - if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) - return; - image = FbCreateAlphaPicture (dst, - format, - bounds.x2 - bounds.x1, - bounds.y2 - bounds.y1); - if (!image) - return; - } first = points++; npoints--; for (; npoints >= 2; npoints--, points++) @@ -326,38 +281,13 @@ pixman_composite_tri_fan (pixman_operator_t op, tri.p1 = *first; tri.p2 = points[0]; tri.p3 = points[1]; - if (!format) - { - pixman_triangle_bounds (1, &tri, &bounds); - if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) - continue; - image = FbCreateAlphaPicture (dst, - format, - bounds.x2 - bounds.x1, - bounds.y2 - bounds.y1); - if (!image) - continue; - } FbRasterizeTriangle (image, &tri, -bounds.x1, -bounds.y1); - if (!format) - { - xRel = bounds.x1 + xSrc - xDst; - yRel = bounds.y1 + ySrc - yDst; - pixman_composite (op, src, image, dst, - xRel, yRel, 0, 0, bounds.x1, bounds.y1, - bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); - pixman_image_destroy (image); - } - } - if (format) - { - xRel = bounds.x1 + xSrc - xDst; - yRel = bounds.y1 + ySrc - yDst; - pixman_composite (op, src, image, dst, - xRel, yRel, 0, 0, bounds.x1, bounds.y1, - bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); - pixman_image_destroy (image); } - pixman_format_destroy (format); + xRel = bounds.x1 + xSrc - xDst; + yRel = bounds.y1 + ySrc - yDst; + pixman_composite (op, src, image, dst, + xRel, yRel, 0, 0, bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); + pixman_image_destroy (image); } diff --git a/gfx/cairo/libpixman/src/icutil.c b/gfx/cairo/libpixman/src/icutil.c index 55ee293428f1..e9f561c34e5e 100644 --- a/gfx/cairo/libpixman/src/icutil.c +++ b/gfx/cairo/libpixman/src/icutil.c @@ -22,6 +22,8 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#include "pixmanint.h" + #include "pixman-xserver-compat.h" pixman_bits_t diff --git a/gfx/cairo/libpixman/src/pixman-remap.h b/gfx/cairo/libpixman/src/pixman-remap.h index 290df3281235..6004fe7f6d51 100644 --- a/gfx/cairo/libpixman/src/pixman-remap.h +++ b/gfx/cairo/libpixman/src/pixman-remap.h @@ -56,9 +56,10 @@ #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_init _cairo_pixman_region_init +#define pixman_region_init_rect _cairo_pixman_region_init_rect +#define pixman_region_init_with_extents _cairo_pixman_region_init_with_extents +#define pixman_region_fini _cairo_pixman_region_fini #define pixman_region_empty _cairo_pixman_region_empty #define pixman_region_extents _cairo_pixman_region_extents #define pixman_region_intersect _cairo_pixman_region_intersect @@ -77,4 +78,3 @@ #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-xserver-compat.h b/gfx/cairo/libpixman/src/pixman-xserver-compat.h index a09367d2dc33..e475f314d747 100644 --- a/gfx/cairo/libpixman/src/pixman-xserver-compat.h +++ b/gfx/cairo/libpixman/src/pixman-xserver-compat.h @@ -44,7 +44,7 @@ /* First, include the primary internal header file for libpixman. */ -#include "icint.h" +#include "pixmanint.h" /* Then, define any names that the server code will be expecting in * terms of libpixman names. */ @@ -109,7 +109,7 @@ typedef pixman_vector_t* PictVectorPtr; /* And finally, this one prototype must come after the include of * renderedge.h, so it can't live alongside the other prototypes in - * the horrible mess that is icint.h. + * the horrible mess that is pixmanint.h. */ pixman_private void diff --git a/gfx/cairo/libpixman/src/pixman.h b/gfx/cairo/libpixman/src/pixman.h index 9120eb6ed1e4..8a2dd18f3ad2 100644 --- a/gfx/cairo/libpixman/src/pixman.h +++ b/gfx/cairo/libpixman/src/pixman.h @@ -74,10 +74,6 @@ SOFTWARE. * PERFORMANCE OF THIS SOFTWARE. */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - #if HAVE_STDINT_H # include #elif HAVE_INTTYPES_H @@ -100,25 +96,37 @@ SOFTWARE. #include "pixman-remap.h" #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun__) -#define pixman_private __attribute__((__visibility__("hidden"))) +#define pixman_private_no_warn __attribute__((__visibility__("hidden"))) #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) -#define pixman_private __hidden +#define pixman_private_no_warn __hidden #else /* not gcc >= 3.3 and not Sun Studio >= 8 */ -#define pixman_private +#define pixman_private_no_warn #endif +#ifndef WARN_UNUSED_RESULT +#define WARN_UNUSED_RESULT +#endif +/* Add attribute(warn_unused_result) if supported */ +#define pixman_warn WARN_UNUSED_RESULT +#define pixman_private pixman_private_no_warn pixman_warn + #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif /* pixregion.h */ -typedef struct pixman_region16 pixman_region16_t; +typedef struct pixman_region16_data pixman_region16_data_t; typedef struct pixman_box16 { short x1, y1, x2, y2; } pixman_box16_t; +typedef struct pixman_region16 { + pixman_box16_t extents; + pixman_region16_data_t *data; +} pixman_region16_t; + typedef enum { PIXMAN_REGION_STATUS_FAILURE, PIXMAN_REGION_STATUS_SUCCESS @@ -126,14 +134,15 @@ typedef enum { /* creation/destruction */ -pixman_private pixman_region16_t * -pixman_region_create (void); - -pixman_private pixman_region16_t * -pixman_region_create_simple (pixman_box16_t *extents); - pixman_private void -pixman_region_destroy (pixman_region16_t *region); +pixman_region_init(pixman_region16_t *region); +pixman_private void +pixman_region_init_rect(pixman_region16_t *region, + int x, int y, unsigned int width, unsigned int height); +pixman_private void +pixman_region_init_with_extents(pixman_region16_t *region, pixman_box16_t *extents); +pixman_private void +pixman_region_fini (pixman_region16_t *region); /* manipulation */ @@ -240,20 +249,27 @@ typedef enum pixman_format_name { PIXMAN_FORMAT_NAME_BGR24 } pixman_format_name_t; -typedef struct pixman_format pixman_format_t; +/* XXX: Is depth redundant here? */ +typedef struct pixman_format { + int format_code; + int depth; + int red, redMask; + int green, greenMask; + int blue, blueMask; + int alpha, alphaMask; +} pixman_format_t; -pixman_private pixman_format_t * -pixman_format_create (pixman_format_name_t name); -pixman_private pixman_format_t * -pixman_format_create_masks (int bpp, - int alpha_mask, - int red_mask, - int green_mask, - int blue_mask); +pixman_private int +pixman_format_init (pixman_format_t *format, pixman_format_name_t name); pixman_private void -pixman_format_destroy (pixman_format_t *format); +pixman_format_init_masks (pixman_format_t *format, + int bpp, + int alpha_mask, + int red_mask, + int green_mask, + int blue_mask); pixman_private void pixman_format_get_masks (pixman_format_t *format, @@ -442,7 +458,7 @@ pixman_pixel_to_color (const pixman_format_t *format, /* icrect.c */ -pixman_private void +pixman_private int pixman_fill_rectangle (pixman_operator_t op, pixman_image_t *dst, const pixman_color_t *color, @@ -451,7 +467,7 @@ pixman_fill_rectangle (pixman_operator_t op, unsigned int width, unsigned int height); -pixman_private void +pixman_private int pixman_fill_rectangles (pixman_operator_t op, pixman_image_t *dst, const pixman_color_t *color, @@ -460,7 +476,7 @@ pixman_fill_rectangles (pixman_operator_t op, /* ictrap.c */ -pixman_private void +pixman_private int pixman_composite_trapezoids (pixman_operator_t op, pixman_image_t *src, pixman_image_t *dst, diff --git a/gfx/cairo/libpixman/src/pixmanint.h b/gfx/cairo/libpixman/src/pixmanint.h new file mode 100644 index 000000000000..a10a8342fc3b --- /dev/null +++ b/gfx/cairo/libpixman/src/pixmanint.h @@ -0,0 +1,1076 @@ +/* + * Copyright © 2003 Carl Worth + * + * 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 Carl Worth not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Carl Worth makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * CARL WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL CARL WORTH 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. + */ + +#ifndef _PIXMANINT_H_ +#define _PIXMANINT_H_ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#ifdef _MSC_VER +#define snprintf _snprintf +#undef inline +#define inline __inline +#endif + +#include "pixman.h" + +#undef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +/* C89 has implementation-defined behavior for % with negative operands. + C99 has well-defined behavior which is that / with integers rounds toward zero + and a%b is defined so that (a/b)*b + a%b == a. + + The C99 version gives negative remainders rather than the modulus + in [0 .. b-1] that we want. This macro avoids using % with negative + operands to avoid both problems. + + a and b are integers. b > 0. +*/ +#define MOD(a, b) ((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-(a) - 1) % (b) - 1) + +typedef struct _FbPoint { + int16_t x,y ; +} FbPoint; + +typedef unsigned int Mask; + +#define GXcopy 0x3 +#define GXor 0x7 +#define ClipByChildren 0 +#define PolyEdgeSharp 0 +#define PolyModePrecise 0 +#define CPClipMask (1 << 6) +#define CPLastBit 11 + +/* Define any names that the server code will be expecting in + * terms of libpixman names. */ + +typedef uint8_t CARD8; +typedef uint16_t CARD16; +typedef uint32_t CARD32; +typedef int16_t INT16; + +typedef int Bool; +#define FALSE 0 +#define TRUE 1 + +typedef pixman_bits_t FbBits; +typedef pixman_image_t* PicturePtr; +typedef pixman_box16_t BoxRec; +typedef pixman_box16_t* BoxPtr; + +typedef pixman_point_fixed_t xPointFixed; +typedef pixman_line_fixed_t xLineFixed; +typedef pixman_trapezoid_t xTrapezoid; +typedef pixman_triangle_t xTriangle; + +/* These few definitions avoid me needing to include servermd.h and misc.h from Xserver/include */ +#ifndef BITMAP_SCANLINE_PAD +#define BITMAP_SCANLINE_PAD 32 +#define LOG2_BITMAP_PAD 5 +#define LOG2_BYTES_PER_SCANLINE_PAD 2 +#endif + +#define LSBFirst 0 +#define MSBFirst 1 + +#ifdef WORDS_BIGENDIAN +# define IMAGE_BYTE_ORDER MSBFirst +# define BITMAP_BIT_ORDER MSBFirst +#else +# define IMAGE_BYTE_ORDER LSBFirst +# define BITMAP_BIT_ORDER LSBFirst +#endif + +#define MAXSHORT SHRT_MAX +#define MINSHORT SHRT_MIN + +/* XXX: What do we need from here? +#include "picture.h" +*/ + +#include "pixman.h" + +/* XXX: Most of this file is straight from fb.h and I imagine we can + drop quite a bit of it. Once the real ic code starts to come + together I can probably figure out what is not needed here. */ + +#define FB_UNIT (1 << FB_SHIFT) +#define FB_HALFUNIT (1 << (FB_SHIFT-1)) +#define FB_MASK (FB_UNIT - 1) +#define FB_ALLONES ((pixman_bits_t) -1) + +/* whether to bother to include 24bpp support */ +#ifndef ICNO24BIT +#define FB_24BIT +#endif + +/* + * Unless otherwise instructed, ic includes code to advertise 24bpp + * windows with 32bpp image format for application compatibility + */ + +#ifdef FB_24BIT +#ifndef ICNO24_32 +#define FB_24_32BIT +#endif +#endif + +#define FB_STIP_SHIFT LOG2_BITMAP_PAD +#define FB_STIP_UNIT (1 << FB_STIP_SHIFT) +#define FB_STIP_MASK (FB_STIP_UNIT - 1) +#define FB_STIP_ALLONES ((FbStip) -1) + +#define FB_STIP_ODDSTRIDE(s) (((s) & (FB_MASK >> FB_STIP_SHIFT)) != 0) +#define FB_STIP_ODDPTR(p) ((((long) (p)) & (FB_MASK >> 3)) != 0) + +#define FbStipStrideToBitsStride(s) (((s) >> (FB_SHIFT - FB_STIP_SHIFT))) +#define FbBitsStrideToStipStride(s) (((s) << (FB_SHIFT - FB_STIP_SHIFT))) + +#define FbFullMask(n) ((n) == FB_UNIT ? FB_ALLONES : ((((FbBits) 1) << n) - 1)) + +typedef uint32_t FbStip; +typedef int FbStride; + +#ifdef FB_DEBUG +extern void fbValidateDrawable(DrawablePtr d); +extern void fbInitializeDrawable(DrawablePtr d); +extern void fbSetBits (FbStip *bits, int stride, FbStip data); +#define FB_HEAD_BITS (FbStip) (0xbaadf00d) +#define FB_TAIL_BITS (FbStip) (0xbaddf0ad) +#else +#define fbValidateDrawable(d) +#define fdInitializeDrawable(d) +#endif + +#if BITMAP_BIT_ORDER == LSBFirst +#define FbScrLeft(x,n) ((x) >> (n)) +#define FbScrRight(x,n) ((x) << (n)) +/* #define FbLeftBits(x,n) ((x) & ((((FbBits) 1) << (n)) - 1)) */ +#define FbLeftStipBits(x,n) ((x) & ((((FbStip) 1) << (n)) - 1)) +#define FbStipMoveLsb(x,s,n) (FbStipRight (x,(s)-(n))) +#define FbPatternOffsetBits 0 +#else +#define FbScrLeft(x,n) ((x) << (n)) +#define FbScrRight(x,n) ((x) >> (n)) +/* #define FbLeftBits(x,n) ((x) >> (FB_UNIT - (n))) */ +#define FbLeftStipBits(x,n) ((x) >> (FB_STIP_UNIT - (n))) +#define FbStipMoveLsb(x,s,n) (x) +#define FbPatternOffsetBits (sizeof (FbBits) - 1) +#endif + +#define FbStipLeft(x,n) FbScrLeft(x,n) +#define FbStipRight(x,n) FbScrRight(x,n) + +#define FbRotLeft(x,n) FbScrLeft(x,n) | (n ? FbScrRight(x,FB_UNIT-n) : 0) +#define FbRotRight(x,n) FbScrRight(x,n) | (n ? FbScrLeft(x,FB_UNIT-n) : 0) + +#define FbRotStipLeft(x,n) FbStipLeft(x,n) | (n ? FbStipRight(x,FB_STIP_UNIT-n) : 0) +#define FbRotStipRight(x,n) FbStipRight(x,n) | (n ? FbStipLeft(x,FB_STIP_UNIT-n) : 0) + +#define FbLeftMask(x) ( ((x) & FB_MASK) ? \ + FbScrRight(FB_ALLONES,(x) & FB_MASK) : 0) +#define FbRightMask(x) ( ((FB_UNIT - (x)) & FB_MASK) ? \ + FbScrLeft(FB_ALLONES,(FB_UNIT - (x)) & FB_MASK) : 0) + +#define FbLeftStipMask(x) ( ((x) & FB_STIP_MASK) ? \ + FbStipRight(FB_STIP_ALLONES,(x) & FB_STIP_MASK) : 0) +#define FbRightStipMask(x) ( ((FB_STIP_UNIT - (x)) & FB_STIP_MASK) ? \ + FbScrLeft(FB_STIP_ALLONES,(FB_STIP_UNIT - (x)) & FB_STIP_MASK) : 0) + +#define FbBitsMask(x,w) (FbScrRight(FB_ALLONES,(x) & FB_MASK) & \ + FbScrLeft(FB_ALLONES,(FB_UNIT - ((x) + (w))) & FB_MASK)) + +#define FbStipMask(x,w) (FbStipRight(FB_STIP_ALLONES,(x) & FB_STIP_MASK) & \ + FbStipLeft(FB_STIP_ALLONES,(FB_STIP_UNIT - ((x)+(w))) & FB_STIP_MASK)) + +#define FbMaskBits(x,w,l,n,r) { \ + n = (w); \ + r = FbRightMask((x)+n); \ + l = FbLeftMask(x); \ + if (l) { \ + n -= FB_UNIT - ((x) & FB_MASK); \ + if (n < 0) { \ + n = 0; \ + l &= r; \ + r = 0; \ + } \ + } \ + n >>= FB_SHIFT; \ +} + +#ifdef ICNOPIXADDR +#define FbMaskBitsBytes(x,w,copy,l,lb,n,r,rb) FbMaskBits(x,w,l,n,r) +#define FbDoLeftMaskByteRRop(dst,lb,l,and,xor) { \ + *dst = FbDoMaskRRop(*dst,and,xor,l); \ +} +#define FbDoRightMaskByteRRop(dst,rb,r,and,xor) { \ + *dst = FbDoMaskRRop(*dst,and,xor,r); \ +} +#else + +#define FbByteMaskInvalid 0x10 + +#define FbPatternOffset(o,t) ((o) ^ (FbPatternOffsetBits & ~(sizeof (t) - 1))) + +#define FbPtrOffset(p,o,t) ((t *) ((CARD8 *) (p) + (o))) +#define FbSelectPatternPart(xor,o,t) ((xor) >> (FbPatternOffset (o,t) << 3)) +#define FbStorePart(dst,off,t,xor) (*FbPtrOffset(dst,off,t) = \ + FbSelectPart(xor,off,t)) +#ifndef FbSelectPart +#define FbSelectPart(x,o,t) FbSelectPatternPart(x,o,t) +#endif + +#define FbMaskBitsBytes(x,w,copy,l,lb,n,r,rb) { \ + n = (w); \ + lb = 0; \ + rb = 0; \ + r = FbRightMask((x)+n); \ + if (r) { \ + /* compute right byte length */ \ + if ((copy) && (((x) + n) & 7) == 0) { \ + rb = (((x) + n) & FB_MASK) >> 3; \ + } else { \ + rb = FbByteMaskInvalid; \ + } \ + } \ + l = FbLeftMask(x); \ + if (l) { \ + /* compute left byte length */ \ + if ((copy) && ((x) & 7) == 0) { \ + lb = ((x) & FB_MASK) >> 3; \ + } else { \ + lb = FbByteMaskInvalid; \ + } \ + /* subtract out the portion painted by leftMask */ \ + n -= FB_UNIT - ((x) & FB_MASK); \ + if (n < 0) { \ + if (lb != FbByteMaskInvalid) { \ + if (rb == FbByteMaskInvalid) { \ + lb = FbByteMaskInvalid; \ + } else if (rb) { \ + lb |= (rb - lb) << (FB_SHIFT - 3); \ + rb = 0; \ + } \ + } \ + n = 0; \ + l &= r; \ + r = 0; \ + }\ + } \ + n >>= FB_SHIFT; \ +} + +#if FB_SHIFT == 6 +#define FbDoLeftMaskByteRRop6Cases(dst,xor) \ + case (sizeof (FbBits) - 7) | (1 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 7,CARD8,xor); \ + break; \ + case (sizeof (FbBits) - 7) | (2 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 7,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD8,xor); \ + break; \ + case (sizeof (FbBits) - 7) | (3 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 7,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + break; \ + case (sizeof (FbBits) - 7) | (4 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 7,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD8,xor); \ + break; \ + case (sizeof (FbBits) - 7) | (5 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 7,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ + break; \ + case (sizeof (FbBits) - 7) | (6 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 7,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \ + break; \ + case (sizeof (FbBits) - 7): \ + FbStorePart(dst,sizeof (FbBits) - 7,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD32,xor); \ + break; \ + case (sizeof (FbBits) - 6) | (1 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD8,xor); \ + break; \ + case (sizeof (FbBits) - 6) | (2 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + break; \ + case (sizeof (FbBits) - 6) | (3 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD8,xor); \ + break; \ + case (sizeof (FbBits) - 6) | (4 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ + break; \ + case (sizeof (FbBits) - 6) | (5 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \ + break; \ + case (sizeof (FbBits) - 6): \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD32,xor); \ + break; \ + case (sizeof (FbBits) - 5) | (1 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 5,CARD8,xor); \ + break; \ + case (sizeof (FbBits) - 5) | (2 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 5,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD8,xor); \ + break; \ + case (sizeof (FbBits) - 5) | (3 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 5,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ + break; \ + case (sizeof (FbBits) - 5) | (4 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 5,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \ + break; \ + case (sizeof (FbBits) - 5): \ + FbStorePart(dst,sizeof (FbBits) - 5,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD32,xor); \ + break; \ + case (sizeof (FbBits) - 4) | (1 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD8,xor); \ + break; \ + case (sizeof (FbBits) - 4) | (2 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ + break; \ + case (sizeof (FbBits) - 4) | (3 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \ + break; \ + case (sizeof (FbBits) - 4): \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD32,xor); \ + break; + +#define FbDoRightMaskByteRRop6Cases(dst,xor) \ + case 4: \ + FbStorePart(dst,0,CARD32,xor); \ + break; \ + case 5: \ + FbStorePart(dst,0,CARD32,xor); \ + FbStorePart(dst,4,CARD8,xor); \ + break; \ + case 6: \ + FbStorePart(dst,0,CARD32,xor); \ + FbStorePart(dst,4,CARD16,xor); \ + break; \ + case 7: \ + FbStorePart(dst,0,CARD32,xor); \ + FbStorePart(dst,4,CARD16,xor); \ + FbStorePart(dst,6,CARD8,xor); \ + break; +#else +#define FbDoLeftMaskByteRRop6Cases(dst,xor) +#define FbDoRightMaskByteRRop6Cases(dst,xor) +#endif + +#define FbDoLeftMaskByteRRop(dst,lb,l,and,xor) { \ + switch (lb) { \ + FbDoLeftMaskByteRRop6Cases(dst,xor) \ + case (sizeof (FbBits) - 3) | (1 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 3,CARD8,xor); \ + break; \ + case (sizeof (FbBits) - 3) | (2 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 3,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \ + break; \ + case (sizeof (FbBits) - 2) | (1 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \ + break; \ + case sizeof (FbBits) - 3: \ + FbStorePart(dst,sizeof (FbBits) - 3,CARD8,xor); \ + case sizeof (FbBits) - 2: \ + FbStorePart(dst,sizeof (FbBits) - 2,CARD16,xor); \ + break; \ + case sizeof (FbBits) - 1: \ + FbStorePart(dst,sizeof (FbBits) - 1,CARD8,xor); \ + break; \ + default: \ + *dst = FbDoMaskRRop(*dst, and, xor, l); \ + break; \ + } \ +} + +#define FbDoRightMaskByteRRop(dst,rb,r,and,xor) { \ + switch (rb) { \ + case 1: \ + FbStorePart(dst,0,CARD8,xor); \ + break; \ + case 2: \ + FbStorePart(dst,0,CARD16,xor); \ + break; \ + case 3: \ + FbStorePart(dst,0,CARD16,xor); \ + FbStorePart(dst,2,CARD8,xor); \ + break; \ + FbDoRightMaskByteRRop6Cases(dst,xor) \ + default: \ + *dst = FbDoMaskRRop (*dst, and, xor, r); \ + } \ +} +#endif + +#define FbMaskStip(x,w,l,n,r) { \ + n = (w); \ + r = FbRightStipMask((x)+n); \ + l = FbLeftStipMask(x); \ + if (l) { \ + n -= FB_STIP_UNIT - ((x) & FB_STIP_MASK); \ + if (n < 0) { \ + n = 0; \ + l &= r; \ + r = 0; \ + } \ + } \ + n >>= FB_STIP_SHIFT; \ +} + +/* + * These macros are used to transparently stipple + * in copy mode; the expected usage is with 'n' constant + * so all of the conditional parts collapse into a minimal + * sequence of partial word writes + * + * 'n' is the bytemask of which bytes to store, 'a' is the address + * of the FbBits base unit, 'o' is the offset within that unit + * + * The term "lane" comes from the hardware term "byte-lane" which + */ + +#define FbLaneCase1(n,a,o) ((n) == 0x01 ? \ + (*(CARD8 *) ((a)+FbPatternOffset(o,CARD8)) = \ + fgxor) : 0) +#define FbLaneCase2(n,a,o) ((n) == 0x03 ? \ + (*(CARD16 *) ((a)+FbPatternOffset(o,CARD16)) = \ + fgxor) : \ + ((void)FbLaneCase1((n)&1,a,o), \ + FbLaneCase1((n)>>1,a,(o)+1))) +#define FbLaneCase4(n,a,o) ((n) == 0x0f ? \ + (*(CARD32 *) ((a)+FbPatternOffset(o,CARD32)) = \ + fgxor) : \ + ((void)FbLaneCase2((n)&3,a,o), \ + FbLaneCase2((n)>>2,a,(o)+2))) +#define FbLaneCase8(n,a,o) ((n) == 0x0ff ? (*(FbBits *) ((a)+(o)) = fgxor) : \ + ((void)FbLaneCase4((n)&15,a,o), \ + FbLaneCase4((n)>>4,a,(o)+4))) + +#if FB_SHIFT == 6 +#define FbLaneCase(n,a) FbLaneCase8(n,(CARD8 *) (a),0) +#endif + +#if FB_SHIFT == 5 +#define FbLaneCase(n,a) FbLaneCase4(n,(CARD8 *) (a),0) +#endif + +/* Rotate a filled pixel value to the specified alignement */ +#define FbRot24(p,b) (FbScrRight(p,b) | FbScrLeft(p,24-(b))) +#define FbRot24Stip(p,b) (FbStipRight(p,b) | FbStipLeft(p,24-(b))) + +/* step a filled pixel value to the next/previous FB_UNIT alignment */ +#define FbNext24Pix(p) (FbRot24(p,(24-FB_UNIT%24))) +#define FbPrev24Pix(p) (FbRot24(p,FB_UNIT%24)) +#define FbNext24Stip(p) (FbRot24(p,(24-FB_STIP_UNIT%24))) +#define FbPrev24Stip(p) (FbRot24(p,FB_STIP_UNIT%24)) + +/* step a rotation value to the next/previous rotation value */ +#if FB_UNIT == 64 +#define FbNext24Rot(r) ((r) == 16 ? 0 : (r) + 8) +#define FbPrev24Rot(r) ((r) == 0 ? 16 : (r) - 8) + +#if IMAGE_BYTE_ORDER == MSBFirst +#define FbFirst24Rot(x) (((x) + 8) % 24) +#else +#define FbFirst24Rot(x) ((x) % 24) +#endif + +#endif + +#if FB_UNIT == 32 +#define FbNext24Rot(r) ((r) == 0 ? 16 : (r) - 8) +#define FbPrev24Rot(r) ((r) == 16 ? 0 : (r) + 8) + +#if IMAGE_BYTE_ORDER == MSBFirst +#define FbFirst24Rot(x) (((x) + 16) % 24) +#else +#define FbFirst24Rot(x) ((x) % 24) +#endif +#endif + +#define FbNext24RotStip(r) ((r) == 0 ? 16 : (r) - 8) +#define FbPrev24RotStip(r) ((r) == 16 ? 0 : (r) + 8) + +/* Whether 24-bit specific code is needed for this filled pixel value */ +#define FbCheck24Pix(p) ((p) == FbNext24Pix(p)) + +#define FbGetPixels(icpixels, pointer, _stride_, _bpp_, xoff, yoff) { \ + (pointer) = icpixels->data; \ + (_stride_) = icpixels->stride / sizeof(pixman_bits_t); \ + (_bpp_) = icpixels->bpp; \ + (xoff) = icpixels->x; /* XXX: fb.h had this ifdef'd to constant 0. Why? */ \ + (yoff) = icpixels->y; /* XXX: fb.h had this ifdef'd to constant 0. Why? */ \ +} + +#define FbGetStipPixels(icpixels, pointer, _stride_, _bpp_, xoff, yoff) { \ + (pointer) = (FbStip *) icpixels->data; \ + (_stride_) = icpixels->stride / sizeof(FbStip); \ + (_bpp_) = icpixels->bpp; \ + (xoff) = icpixels->x; \ + (yoff) = icpixels->y; \ +} + +#ifdef FB_OLD_SCREEN +#define BitsPerPixel(d) (\ + ((1 << PixmapWidthPaddingInfo[d].padBytesLog2) * 8 / \ + (PixmapWidthPaddingInfo[d].padRoundUp+1))) +#endif + +#define FbPowerOfTwo(w) (((w) & ((w) - 1)) == 0) +/* + * Accelerated tiles are power of 2 width <= FB_UNIT + */ +#define FbEvenTile(w) ((w) <= FB_UNIT && FbPowerOfTwo(w)) +/* + * Accelerated stipples are power of 2 width and <= FB_UNIT/dstBpp + * with dstBpp a power of 2 as well + */ +#define FbEvenStip(w,bpp) ((w) * (bpp) <= FB_UNIT && FbPowerOfTwo(w) && FbPowerOfTwo(bpp)) + +/* + * icblt.c + */ +pixman_private void +fbBlt (pixman_bits_t *src, + FbStride srcStride, + int srcX, + + FbBits *dst, + FbStride dstStride, + int dstX, + + int width, + int height, + + int alu, + FbBits pm, + int bpp, + + Bool reverse, + Bool upsidedown); + +pixman_private void +fbBlt24 (pixman_bits_t *srcLine, + FbStride srcStride, + int srcX, + + FbBits *dstLine, + FbStride dstStride, + int dstX, + + int width, + int height, + + int alu, + FbBits pm, + + Bool reverse, + Bool upsidedown); + +pixman_private void +fbBltStip (FbStip *src, + FbStride srcStride, /* in FbStip units, not FbBits units */ + int srcX, + + FbStip *dst, + FbStride dstStride, /* in FbStip units, not FbBits units */ + int dstX, + + int width, + int height, + + int alu, + FbBits pm, + int bpp); + +/* + * icbltone.c + */ +pixman_private void +fbBltOne (FbStip *src, + FbStride srcStride, + int srcX, + FbBits *dst, + FbStride dstStride, + int dstX, + int dstBpp, + + int width, + int height, + + FbBits fgand, + FbBits fbxor, + FbBits bgand, + FbBits bgxor); + +#ifdef FB_24BIT +pixman_private void +fbBltOne24 (FbStip *src, + FbStride srcStride, /* FbStip units per scanline */ + int srcX, /* bit position of source */ + FbBits *dst, + FbStride dstStride, /* FbBits units per scanline */ + int dstX, /* bit position of dest */ + int dstBpp, /* bits per destination unit */ + + int width, /* width in bits of destination */ + int height, /* height in scanlines */ + + FbBits fgand, /* rrop values */ + FbBits fgxor, + FbBits bgand, + FbBits bgxor); +#endif + +/* + * icstipple.c + */ + +pixman_private void +fbTransparentSpan (pixman_bits_t *dst, + pixman_bits_t stip, + pixman_bits_t fgxor, + int n); + +pixman_private void +fbEvenStipple (pixman_bits_t *dst, + FbStride dstStride, + int dstX, + int dstBpp, + + int width, + int height, + + FbStip *stip, + FbStride stipStride, + int stipHeight, + + FbBits fgand, + FbBits fgxor, + FbBits bgand, + FbBits bgxor, + + int xRot, + int yRot); + +pixman_private void +fbOddStipple (pixman_bits_t *dst, + FbStride dstStride, + int dstX, + int dstBpp, + + int width, + int height, + + FbStip *stip, + FbStride stipStride, + int stipWidth, + int stipHeight, + + FbBits fgand, + FbBits fgxor, + FbBits bgand, + FbBits bgxor, + + int xRot, + int yRot); + +pixman_private void +fbStipple (pixman_bits_t *dst, + FbStride dstStride, + int dstX, + int dstBpp, + + int width, + int height, + + FbStip *stip, + FbStride stipStride, + int stipWidth, + int stipHeight, + Bool even, + + FbBits fgand, + FbBits fgxor, + FbBits bgand, + FbBits bgxor, + + int xRot, + int yRot); + +typedef struct _FbPixels { + pixman_bits_t *data; + unsigned int width; + unsigned int height; + unsigned int depth; + unsigned int bpp; + unsigned int stride; + int x; + int y; + unsigned int refcnt; +} FbPixels; + +/* XXX: This is to avoid including colormap.h from the server includes */ +typedef uint32_t Pixel; + +/* icutil.c */ +pixman_private pixman_bits_t +fbReplicatePixel (Pixel p, int bpp); + +/* fbtrap.c */ + +pixman_private void +fbRasterizeTrapezoid (pixman_image_t *pMask, + const pixman_trapezoid_t *pTrap, + int x_off, + int y_off); + +/* XXX: This is to avoid including gc.h from the server includes */ +/* clientClipType field in GC */ +#define CT_NONE 0 +/* #define CT_PIXMAP 1 (not used anymore) */ +#define CT_REGION 2 +#define CT_UNSORTED 6 +#define CT_YSORTED 10 +#define CT_YXSORTED 14 +#define CT_YXBANDED 18 + +#include "icimage.h" + +/* iccolor.c */ + +/* GCC 3.4 supports a "population count" builtin, which on many targets is + implemented with a single instruction. There is a fallback definition + in libgcc in case a target does not have one, which should be just as + good as the static function below. */ +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +static inline int +_FbOnes(unsigned int mask) +{ + return __builtin_popcount(mask); +} +#else +# define ICINT_NEED_IC_ONES +pixman_private int +_FbOnes(unsigned int mask); +#endif + +/* icformat.c */ + +pixman_private void +pixman_format_init_code (pixman_format_t *format, int format_code); + +/* icimage.c */ + +pixman_private pixman_image_t * +pixman_image_createForPixels (FbPixels *pixels, + pixman_format_t *format); + +pixman_private uint32_t +pixman_gradient_color (pixman_gradient_stop_t *stop1, + pixman_gradient_stop_t *stop2, + uint32_t x); + +#define PictureGradientColor pixman_gradient_color + +/* icpixels.c */ + +pixman_private FbPixels * +FbPixelsCreate (int width, int height, int depth); + +pixman_private FbPixels * +FbPixelsCreateForData (pixman_bits_t *data, int width, int height, int depth, int bpp, int stride); + +pixman_private void +FbPixelsDestroy (FbPixels *pixels); + +/* ictransform.c */ + +pixman_private int +pixman_transform_point (pixman_transform_t *transform, + pixman_vector_t *vector); + +#include "icrop.h" + +/* XXX: For now, I'm just wholesale pasting Xserver/render/picture.h here: */ +#ifndef _PICTURE_H_ +#define _PICTURE_H_ + +typedef struct _DirectFormat *DirectFormatPtr; +typedef struct _PictFormat *PictFormatPtr; + +/* + * While the protocol is generous in format support, the + * sample implementation allows only packed RGB and GBR + * representations for data to simplify software rendering, + */ +#define PICT_FORMAT(bpp,type,a,r,g,b) (((bpp) << 24) | \ + ((type) << 16) | \ + ((a) << 12) | \ + ((r) << 8) | \ + ((g) << 4) | \ + ((b))) + +/* + * gray/color formats use a visual index instead of argb + */ +#define PICT_VISFORMAT(bpp,type,vi) (((bpp) << 24) | \ + ((type) << 16) | \ + ((vi))) + +#define PICT_FORMAT_BPP(f) (((f) >> 24) ) +#define PICT_FORMAT_TYPE(f) (((f) >> 16) & 0xff) +#define PICT_FORMAT_A(f) (((f) >> 12) & 0x0f) +#define PICT_FORMAT_R(f) (((f) >> 8) & 0x0f) +#define PICT_FORMAT_G(f) (((f) >> 4) & 0x0f) +#define PICT_FORMAT_B(f) (((f) ) & 0x0f) +#define PICT_FORMAT_RGB(f) (((f) ) & 0xfff) +#define PICT_FORMAT_VIS(f) (((f) ) & 0xffff) + +#define PICT_TYPE_OTHER 0 +#define PICT_TYPE_A 1 +#define PICT_TYPE_ARGB 2 +#define PICT_TYPE_ABGR 3 +#define PICT_TYPE_COLOR 4 +#define PICT_TYPE_GRAY 5 + +#define PICT_FORMAT_COLOR(f) (PICT_FORMAT_TYPE(f) & 2) + +/* 32bpp formats */ +#define PICT_a8r8g8b8 PICT_FORMAT(32,PICT_TYPE_ARGB,8,8,8,8) +#define PICT_x8r8g8b8 PICT_FORMAT(32,PICT_TYPE_ARGB,0,8,8,8) +#define PICT_a8b8g8r8 PICT_FORMAT(32,PICT_TYPE_ABGR,8,8,8,8) +#define PICT_x8b8g8r8 PICT_FORMAT(32,PICT_TYPE_ABGR,0,8,8,8) + +/* 24bpp formats */ +#define PICT_r8g8b8 PICT_FORMAT(24,PICT_TYPE_ARGB,0,8,8,8) +#define PICT_b8g8r8 PICT_FORMAT(24,PICT_TYPE_ABGR,0,8,8,8) + +/* 16bpp formats */ +#define PICT_r5g6b5 PICT_FORMAT(16,PICT_TYPE_ARGB,0,5,6,5) +#define PICT_b5g6r5 PICT_FORMAT(16,PICT_TYPE_ABGR,0,5,6,5) + +#define PICT_a1r5g5b5 PICT_FORMAT(16,PICT_TYPE_ARGB,1,5,5,5) +#define PICT_x1r5g5b5 PICT_FORMAT(16,PICT_TYPE_ARGB,0,5,5,5) +#define PICT_a1b5g5r5 PICT_FORMAT(16,PICT_TYPE_ABGR,1,5,5,5) +#define PICT_x1b5g5r5 PICT_FORMAT(16,PICT_TYPE_ABGR,0,5,5,5) +#define PICT_a4r4g4b4 PICT_FORMAT(16,PICT_TYPE_ARGB,4,4,4,4) +#define PICT_x4r4g4b4 PICT_FORMAT(16,PICT_TYPE_ARGB,0,4,4,4) +#define PICT_a4b4g4r4 PICT_FORMAT(16,PICT_TYPE_ABGR,4,4,4,4) +#define PICT_x4b4g4r4 PICT_FORMAT(16,PICT_TYPE_ABGR,0,4,4,4) + +/* 8bpp formats */ +#define PICT_a8 PICT_FORMAT(8,PICT_TYPE_A,8,0,0,0) +#define PICT_r3g3b2 PICT_FORMAT(8,PICT_TYPE_ARGB,0,3,3,2) +#define PICT_b2g3r3 PICT_FORMAT(8,PICT_TYPE_ABGR,0,3,3,2) +#define PICT_a2r2g2b2 PICT_FORMAT(8,PICT_TYPE_ARGB,2,2,2,2) +#define PICT_a2b2g2r2 PICT_FORMAT(8,PICT_TYPE_ABGR,2,2,2,2) + +#define PICT_c8 PICT_FORMAT(8,PICT_TYPE_COLOR,0,0,0,0) +#define PICT_g8 PICT_FORMAT(8,PICT_TYPE_GRAY,0,0,0,0) + +/* 4bpp formats */ +#define PICT_a4 PICT_FORMAT(4,PICT_TYPE_A,4,0,0,0) +#define PICT_r1g2b1 PICT_FORMAT(4,PICT_TYPE_ARGB,0,1,2,1) +#define PICT_b1g2r1 PICT_FORMAT(4,PICT_TYPE_ABGR,0,1,2,1) +#define PICT_a1r1g1b1 PICT_FORMAT(4,PICT_TYPE_ARGB,1,1,1,1) +#define PICT_a1b1g1r1 PICT_FORMAT(4,PICT_TYPE_ABGR,1,1,1,1) + +#define PICT_c4 PICT_FORMAT(4,PICT_TYPE_COLOR,0,0,0,0) +#define PICT_g4 PICT_FORMAT(4,PICT_TYPE_GRAY,0,0,0,0) + +/* 1bpp formats */ +#define PICT_a1 PICT_FORMAT(1,PICT_TYPE_A,1,0,0,0) + +#define PICT_g1 PICT_FORMAT(1,PICT_TYPE_GRAY,0,0,0,0) + +/* + * For dynamic indexed visuals (GrayScale and PseudoColor), these control the + * selection of colors allocated for drawing to Pictures. The default + * policy depends on the size of the colormap: + * + * Size Default Policy + * ---------------------------- + * < 64 PolicyMono + * < 256 PolicyGray + * 256 PolicyColor (only on PseudoColor) + * + * The actual allocation code lives in miindex.c, and so is + * austensibly server dependent, but that code does: + * + * PolicyMono Allocate no additional colors, use black and white + * PolicyGray Allocate 13 gray levels (11 cells used) + * PolicyColor Allocate a 4x4x4 cube and 13 gray levels (71 cells used) + * PolicyAll Allocate as big a cube as possible, fill with gray (all) + * + * Here's a picture to help understand how many colors are + * actually allocated (this is just the gray ramp): + * + * gray level + * all 0000 1555 2aaa 4000 5555 6aaa 8000 9555 aaaa bfff d555 eaaa ffff + * b/w 0000 ffff + * 4x4x4 5555 aaaa + * extra 1555 2aaa 4000 6aaa 8000 9555 bfff d555 eaaa + * + * The default colormap supplies two gray levels (black/white), the + * 4x4x4 cube allocates another two and nine more are allocated to fill + * in the 13 levels. When the 4x4x4 cube is not allocated, a total of + * 11 cells are allocated. + */ + +#define PictureCmapPolicyInvalid -1 +#define PictureCmapPolicyDefault 0 +#define PictureCmapPolicyMono 1 +#define PictureCmapPolicyGray 2 +#define PictureCmapPolicyColor 3 +#define PictureCmapPolicyAll 4 + +extern pixman_private int PictureCmapPolicy; + +int PictureParseCmapPolicy (const char *name); + +/* Fixed point updates from Carl Worth, USC, Information Sciences Institute */ + +#ifdef WIN32 +typedef __int64 xFixed_32_32; +#else +# if defined(__alpha__) || defined(__alpha) || \ + defined(ia64) || defined(__ia64__) || \ + defined(__sparc64__) || \ + defined(__s390x__) || \ + defined(x86_64) || defined (__x86_64__) +typedef long xFixed_32_32; +# else +# if defined(__GNUC__) && \ + ((__GNUC__ > 2) || \ + ((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ > 7))) +__extension__ +# endif +typedef long long int xFixed_32_32; +# endif +#endif + +typedef xFixed_32_32 xFixed_48_16; +typedef uint32_t xFixed_1_31; +typedef uint32_t xFixed_1_16; +typedef int32_t xFixed_16_16; + +/* + * An unadorned "xFixed" is the same as xFixed_16_16, + * (since it's quite common in the code) + */ +typedef xFixed_16_16 xFixed; +#define XFIXED_BITS 16 + +#define xFixedToInt(f) (int) ((f) >> XFIXED_BITS) +#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) +#define xFixedCeil(f) xFixedFloor((f) + xFixed1MinusE) + +#define xFixedFraction(f) ((f) & xFixed1MinusE) +#define xFixedMod2(f) ((f) & (xFixed1 | xFixed1MinusE)) + +/* whether 't' is a well defined not obviously empty trapezoid */ +#define xTrapezoidValid(t) ((t)->left.p1.y != (t)->left.p2.y && \ + (t)->right.p1.y != (t)->right.p2.y && \ + (int) ((t)->bottom - (t)->top) > 0) + +/* + * Standard NTSC luminance conversions: + * + * y = r * 0.299 + g * 0.587 + b * 0.114 + * + * Approximate this for a bit more speed: + * + * y = (r * 153 + g * 301 + b * 58) / 512 + * + * This gives 17 bits of luminance; to get 15 bits, lop the low two + */ + +#define CvtR8G8B8toY15(s) (((((s) >> 16) & 0xff) * 153 + \ + (((s) >> 8) & 0xff) * 301 + \ + (((s) ) & 0xff) * 58) >> 2) + +#endif /* _PICTURE_H_ */ + +/* Macros needed by fbpict.c */ + +#define cvt8888to0565(s) ((((s) >> 3) & 0x001f) | \ + (((s) >> 5) & 0x07e0) | \ + (((s) >> 8) & 0xf800)) +#define cvt0565to0888(s) (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \ + ((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) | \ + ((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000))) + +#if IMAGE_BYTE_ORDER == MSBFirst +#define Fetch24(a) ((unsigned long) (a) & 1 ? \ + ((*(a) << 16) | *((CARD16 *) ((a)+1))) : \ + ((*((CARD16 *) (a)) << 8) | *((a)+2))) +#define Store24(a,v) ((unsigned long) (a) & 1 ? \ + ((*(a) = (CARD8) ((v) >> 16)), \ + (*((CARD16 *) ((a)+1)) = (CARD16) (v))) : \ + ((*((CARD16 *) (a)) = (CARD16) ((v) >> 8)), \ + (*((a)+2) = (CARD8) (v)))) +#else +#define Fetch24(a) ((unsigned long) (a) & 1 ? \ + ((*(a)) | (*((CARD16 *) ((a)+1)) << 8)) : \ + ((*((CARD16 *) (a))) | (*((a)+2) << 16))) +#define Store24(a,v) ((unsigned long) (a) & 1 ? \ + ((*(a) = (CARD8) (v)), \ + (*((CARD16 *) ((a)+1)) = (CARD16) ((v) >> 8))) : \ + ((*((CARD16 *) (a)) = (CARD16) (v)),\ + (*((a)+2) = (CARD8) ((v) >> 16)))) +#endif + +#endif /* _PIXMANINT_H_ */ diff --git a/gfx/cairo/libpixman/src/pixregion.c b/gfx/cairo/libpixman/src/pixregion.c index 0404dff4445a..0c214cbc7dbc 100644 --- a/gfx/cairo/libpixman/src/pixregion.c +++ b/gfx/cairo/libpixman/src/pixregion.c @@ -45,18 +45,14 @@ SOFTWARE. ******************************************************************/ +#include "pixmanint.h" + #include #include #include #include "pixregionint.h" -#if defined (__GNUC__) && !defined (NO_INLINES) -#define INLINE __inline -#else -#define INLINE -#endif - #undef assert #ifdef DEBUG_PIXREGION #define assert(expr) {if (!(expr)) \ @@ -77,17 +73,10 @@ static pixman_box16_t pixman_region_emptyBox = {0, 0, 0, 0}; static pixman_region16_data_t pixman_region_emptyData = {0, 0}; static pixman_region16_data_t pixman_brokendata = {0, 0}; -static pixman_region16_t pixman_brokenregion = { { 0, 0, 0, 0 }, &pixman_brokendata }; static pixman_region_status_t pixman_break (pixman_region16_t *pReg); -static void -pixman_init (pixman_region16_t *region, pixman_box16_t *rect); - -static void -pixman_uninit (pixman_region16_t *region); - /* * The functions in this file implement the Region abstraction used extensively * throughout the X11 sample server. A Region is simply a set of disjoint @@ -297,66 +286,36 @@ pixman_region16_valid(reg) #endif /* DEBUG_PIXREGION */ -/* Create a new empty region */ -pixman_region16_t * -pixman_region_create (void) +void +pixman_region_init(pixman_region16_t *region) { - return pixman_region_create_simple (NULL); -} - -/***************************************************************** - * pixman_region_create_simple (extents) - * This routine creates a pixman_region16_t for a simple - * rectangular region. - *****************************************************************/ -pixman_region16_t * -pixman_region_create_simple (pixman_box16_t *extents) -{ - pixman_region16_t *region; - - region = malloc (sizeof (pixman_region16_t)); - if (region == NULL) - return &pixman_brokenregion; - - pixman_init (region, extents); - - return region; -} - -/***************************************************************** - * RegionInit(pReg, rect, size) - * Outer region rect is statically allocated. - *****************************************************************/ - -static void -pixman_init(pixman_region16_t *region, pixman_box16_t *extents) -{ - if (extents) - { - region->extents = *extents; - region->data = NULL; - } - else - { - region->extents = pixman_region_emptyBox; - region->data = &pixman_region_emptyData; - } -} - -static void -pixman_uninit (pixman_region16_t *region) -{ - good (region); - freeData (region); + region->extents = pixman_region_emptyBox; + region->data = &pixman_region_emptyData; } void -pixman_region_destroy (pixman_region16_t *region) +pixman_region_init_rect(pixman_region16_t *region, + int x, int y, unsigned int width, unsigned int height) { - pixman_uninit (region); + region->extents.x1 = x; + region->extents.y1 = y; + region->extents.x2 = x + width; + region->extents.y2 = y + height; + region->data = NULL; +} - if (region != &pixman_brokenregion) - free (region); +void +pixman_region_init_with_extents(pixman_region16_t *region, pixman_box16_t *extents) +{ + region->extents = *extents; + region->data = NULL; +} + +void +pixman_region_fini (pixman_region16_t *region) +{ + good (region); + freeData (region); } int @@ -469,7 +428,7 @@ pixman_region_copy(pixman_region16_t *dst, pixman_region16_t *src) * *----------------------------------------------------------------------- */ -INLINE static int +static inline int pixman_coalesce ( pixman_region16_t * region, /* Region to coalesce */ int prevStart, /* Index of start of previous band */ @@ -552,7 +511,7 @@ pixman_coalesce ( *----------------------------------------------------------------------- */ -INLINE static pixman_region_status_t +static inline pixman_region_status_t pixman_region_appendNonO ( pixman_region16_t * region, pixman_box16_t * r, @@ -594,7 +553,7 @@ pixman_region_appendNonO ( { \ int newRects; \ if ((newRects = rEnd - r)) { \ - RECTALLOC(newReg, newRects); \ + RECTALLOC_BAIL(newReg, newRects, bail); \ memmove((char *)PIXREGION_TOP(newReg),(char *)r, \ newRects * sizeof(pixman_box16_t)); \ newReg->data->numRects += newRects; \ @@ -711,9 +670,13 @@ pixman_op( newReg->data = &pixman_region_emptyData; else if (newReg->data->size) newReg->data->numRects = 0; - if (newSize > newReg->data->size) - if (!pixman_rect_alloc(newReg, newSize)) + if (newSize > newReg->data->size) { + if (!pixman_rect_alloc(newReg, newSize)) { + if (oldData) + free (oldData); return PIXMAN_REGION_STATUS_FAILURE; + } + } /* * Initialize ybot. @@ -770,7 +733,8 @@ pixman_op( bot = MIN(r1->y2, r2y1); if (top != bot) { curBand = newReg->data->numRects; - pixman_region_appendNonO(newReg, r1, r1BandEnd, top, bot); + if (!pixman_region_appendNonO(newReg, r1, r1BandEnd, top, bot)) + goto bail; Coalesce(newReg, prevBand, curBand); } } @@ -781,7 +745,8 @@ pixman_op( bot = MIN(r2->y2, r1y1); if (top != bot) { curBand = newReg->data->numRects; - pixman_region_appendNonO(newReg, r2, r2BandEnd, top, bot); + if (!pixman_region_appendNonO(newReg, r2, r2BandEnd, top, bot)) + goto bail; Coalesce(newReg, prevBand, curBand); } } @@ -797,8 +762,9 @@ pixman_op( ybot = MIN(r1->y2, r2->y2); if (ybot > ytop) { curBand = newReg->data->numRects; - (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, - pOverlap); + if (!(* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, + pOverlap)) + goto bail; Coalesce(newReg, prevBand, curBand); } @@ -823,7 +789,8 @@ pixman_op( /* Do first nonOverlap1Func call, which may be able to coalesce */ FindBand(r1, r1BandEnd, r1End, r1y1); curBand = newReg->data->numRects; - pixman_region_appendNonO(newReg, r1, r1BandEnd, MAX(r1y1, ybot), r1->y2); + if (!pixman_region_appendNonO(newReg, r1, r1BandEnd, MAX(r1y1, ybot), r1->y2)) + goto bail; Coalesce(newReg, prevBand, curBand); /* Just append the rest of the boxes */ AppendRegions(newReg, r1BandEnd, r1End); @@ -832,7 +799,8 @@ pixman_op( /* Do first nonOverlap2Func call, which may be able to coalesce */ FindBand(r2, r2BandEnd, r2End, r2y1); curBand = newReg->data->numRects; - pixman_region_appendNonO(newReg, r2, r2BandEnd, MAX(r2y1, ybot), r2->y2); + if (!pixman_region_appendNonO(newReg, r2, r2BandEnd, MAX(r2y1, ybot), r2->y2)) + goto bail; Coalesce(newReg, prevBand, curBand); /* Append rest of boxes */ AppendRegions(newReg, r2BandEnd, r2End); @@ -858,6 +826,11 @@ pixman_op( } return PIXMAN_REGION_STATUS_SUCCESS; + +bail: + if (oldData) + free(oldData); + return PIXMAN_REGION_STATUS_FAILURE; } /*- @@ -1137,7 +1110,7 @@ pixman_region_unionO ( /* Convenience function for performing union of region with a single rectangle */ pixman_region_status_t pixman_region_union_rect(pixman_region16_t *dest, pixman_region16_t *source, - int x, int y, unsigned int width, unsigned int height) + int x, int y, unsigned int width, unsigned int height) { pixman_region16_t region; diff --git a/gfx/cairo/libpixman/src/pixregionint.h b/gfx/cairo/libpixman/src/pixregionint.h index b5b53fd2257b..385a7f23460b 100644 --- a/gfx/cairo/libpixman/src/pixregionint.h +++ b/gfx/cairo/libpixman/src/pixregionint.h @@ -48,16 +48,11 @@ SOFTWARE. #include "pixman.h" -typedef struct pixman_region16_data { +struct pixman_region16_data { long size; long numRects; /* XXX: And why, exactly, do we have this bogus struct definition? */ /* pixman_box16_t rects[size]; in memory but not explicitly declared */ -} pixman_region16_data_t; - -struct pixman_region16 { - pixman_box16_t extents; - pixman_region16_data_t *data; }; typedef struct pixman_region16_point { diff --git a/gfx/cairo/libpixman/src/renderedge.c b/gfx/cairo/libpixman/src/renderedge.c index 563a4e2119cb..47d08c6276f0 100644 --- a/gfx/cairo/libpixman/src/renderedge.c +++ b/gfx/cairo/libpixman/src/renderedge.c @@ -20,6 +20,8 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#include "pixmanint.h" + #include "pixman-xserver-compat.h" /*