diff options
Diffstat (limited to 'src')
100 files changed, 11440 insertions, 3010 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index bf87efb7..b09fadf4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -84,9 +84,12 @@ TESTS += check-link$(EXEEXT) endif EXTRA_DIST += $(TESTS_SH) check-has-hidden-symbols.c -check_PROGRAMS += check-link +check_PROGRAMS += check-link check-skiplist check_link_LDADD = libcairo.la +check_skiplist_SOURCES = cairo-skiplist.c +check_skiplist_CPPFLAGS = -DMAIN $(AM_CPPFLAGS) + check: headers-standalone PREPROCESS_ARGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) diff --git a/src/Makefile.sources b/src/Makefile.sources index 082b6af8..5f387f43 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -64,6 +64,7 @@ cairo_private = \ cairo-freelist-private.h \ cairo-gstate-private.h \ cairo-hash-private.h \ + cairo-image-info-private.h \ cairo-malloc-private.h \ cairo-meta-surface-private.h \ cairo-mutex-impl-private.h \ @@ -80,6 +81,7 @@ cairo_private = \ cairo-region-private.h \ cairo-scaled-font-private.h \ cairo-skiplist-private.h \ + cairo-spans-private.h \ cairo-surface-fallback-private.h \ cairo-surface-private.h \ cairo-types-private.h \ @@ -108,6 +110,7 @@ cairo_sources = \ cairo-gstate.c \ cairo-hash.c \ cairo-hull.c \ + cairo-image-info.c \ cairo-image-surface.c \ cairo-lzw.c \ cairo-matrix.c \ @@ -120,6 +123,7 @@ cairo_sources = \ cairo-path.c \ cairo-path-fill.c \ cairo-path-fixed.c \ + cairo-path-in-fill.c \ cairo-path-stroke.c \ cairo-pattern.c \ cairo-pen.c \ @@ -129,10 +133,12 @@ cairo_sources = \ cairo-scaled-font.c \ cairo-skiplist.c \ cairo-slope.c \ + cairo-spans.c \ cairo-spline.c \ cairo-stroke-style.c \ cairo-surface.c \ cairo-surface-fallback.c \ + cairo-tor-scan-converter.c \ cairo-system.c \ cairo-traps.c \ cairo-unicode.c \ @@ -246,3 +252,6 @@ cairo_directfb_sources = cairo-directfb-surface.c cairo_sdl_headers = cairo-sdl.h cairo_sdl_sources = cairo-sdl-surface.c + +cairo_script_headers = cairo-script.h +cairo_script_sources = cairo-script-surface.c diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index 4337e92c..50005c21 100644 --- a/src/cairo-analysis-surface.c +++ b/src/cairo-analysis-surface.c @@ -283,9 +283,6 @@ _cairo_analysis_surface_intersect_clip_path (void *abstract_surface, cairo_antialias_t antialias) { cairo_analysis_surface_t *surface = abstract_surface; - double x1, y1, x2, y2; - cairo_rectangle_int_t extent; - cairo_bool_t is_empty; if (path == NULL) { surface->current_clip.x = 0; @@ -293,17 +290,10 @@ _cairo_analysis_surface_intersect_clip_path (void *abstract_surface, surface->current_clip.width = surface->width; surface->current_clip.height = surface->height; } else { - cairo_status_t status; - - status = _cairo_path_fixed_bounds (path, &x1, &y1, &x2, &y2, tolerance); - if (status) - return status; - - extent.x = floor (x1); - extent.y = floor (y1); - extent.width = ceil (x2) - extent.x; - extent.height = ceil (y2) - extent.y; + cairo_rectangle_int_t extent; + cairo_bool_t is_empty; + _cairo_path_fixed_approximate_extents (path, &extent); is_empty = _cairo_rectangle_intersect (&surface->current_clip, &extent); } @@ -322,7 +312,8 @@ _cairo_analysis_surface_get_extents (void *abstract_surface, static cairo_int_status_t _cairo_analysis_surface_paint (void *abstract_surface, cairo_operator_t op, - const cairo_pattern_t *source) + const cairo_pattern_t *source, + cairo_rectangle_int_t *paint_extents) { cairo_analysis_surface_t *surface = abstract_surface; cairo_status_t status, backend_status; @@ -333,7 +324,7 @@ _cairo_analysis_surface_paint (void *abstract_surface, backend_status = CAIRO_INT_STATUS_UNSUPPORTED; else backend_status = (*surface->target->backend->paint) (surface->target, op, - source); + source, NULL); if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) backend_status = _analyze_meta_surface_pattern (surface, source); @@ -346,13 +337,15 @@ _cairo_analysis_surface_paint (void *abstract_surface, cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); - if (status) + if (unlikely (status)) return status; is_empty = _cairo_rectangle_intersect (&extents, &source_extents); } is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip); + if (paint_extents) + *paint_extents = extents; status = _add_operation (surface, &extents, backend_status); @@ -363,7 +356,8 @@ static cairo_int_status_t _cairo_analysis_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_pattern_t *mask) + const cairo_pattern_t *mask, + cairo_rectangle_int_t *mask_extents) { cairo_analysis_surface_t *surface = abstract_surface; cairo_int_status_t status, backend_status; @@ -374,7 +368,7 @@ _cairo_analysis_surface_mask (void *abstract_surface, backend_status = CAIRO_INT_STATUS_UNSUPPORTED; else backend_status = (*surface->target->backend->mask) (surface->target, op, - source, mask); + source, mask, NULL); if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) { cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS; @@ -413,7 +407,7 @@ _cairo_analysis_surface_mask (void *abstract_surface, cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); - if (status) + if (unlikely (status)) return status; is_empty = _cairo_rectangle_intersect (&extents, &source_extents); @@ -423,13 +417,15 @@ _cairo_analysis_surface_mask (void *abstract_surface, cairo_rectangle_int_t mask_extents; status = _cairo_pattern_get_extents (mask, &mask_extents); - if (status) + if (unlikely (status)) return status; is_empty = _cairo_rectangle_intersect (&extents, &mask_extents); } is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip); + if (mask_extents) + *mask_extents = extents; status = _add_operation (surface, &extents, backend_status); @@ -445,7 +441,8 @@ _cairo_analysis_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *stroke_extents) { cairo_analysis_surface_t *surface = abstract_surface; cairo_status_t status, backend_status; @@ -459,7 +456,7 @@ _cairo_analysis_surface_stroke (void *abstract_surface, backend_status = (*surface->target->backend->stroke) (surface->target, op, source, path, style, ctm, ctm_inverse, - tolerance, antialias); + tolerance, antialias, NULL); if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) backend_status = _analyze_meta_surface_pattern (surface, source); @@ -472,7 +469,7 @@ _cairo_analysis_surface_stroke (void *abstract_surface, cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); - if (status) + if (unlikely (status)) return status; is_empty = _cairo_rectangle_intersect (&extents, &source_extents); @@ -492,7 +489,7 @@ _cairo_analysis_surface_stroke (void *abstract_surface, ctm, ctm_inverse, tolerance, &traps); - if (status) { + if (unlikely (status)) { _cairo_traps_fini (&traps); return status; } @@ -502,6 +499,8 @@ _cairo_analysis_surface_stroke (void *abstract_surface, _cairo_box_round_to_rectangle (&box, &extents); } + if (stroke_extents) + *stroke_extents = extents; status = _add_operation (surface, &extents, backend_status); @@ -515,7 +514,8 @@ _cairo_analysis_surface_fill (void *abstract_surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *fill_extents) { cairo_analysis_surface_t *surface = abstract_surface; cairo_status_t status, backend_status; @@ -528,7 +528,7 @@ _cairo_analysis_surface_fill (void *abstract_surface, else backend_status = (*surface->target->backend->fill) (surface->target, op, source, path, fill_rule, - tolerance, antialias); + tolerance, antialias, NULL); if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) backend_status = _analyze_meta_surface_pattern (surface, source); @@ -541,7 +541,7 @@ _cairo_analysis_surface_fill (void *abstract_surface, cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); - if (status) + if (unlikely (status)) return status; is_empty = _cairo_rectangle_intersect (&extents, &source_extents); @@ -560,7 +560,7 @@ _cairo_analysis_surface_fill (void *abstract_surface, fill_rule, tolerance, &traps); - if (status) { + if (unlikely (status)) { _cairo_traps_fini (&traps); return status; } @@ -570,6 +570,8 @@ _cairo_analysis_surface_fill (void *abstract_surface, _cairo_box_round_to_rectangle (&box, &extents); } + if (fill_extents) + *fill_extents = extents; status = _add_operation (surface, &extents, backend_status); @@ -583,7 +585,8 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs) + int *remaining_glyphs, + cairo_rectangle_int_t *show_glyphs_extents) { cairo_analysis_surface_t *surface = abstract_surface; cairo_status_t status, backend_status; @@ -596,7 +599,7 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface, source, glyphs, num_glyphs, scaled_font, - remaining_glyphs); + remaining_glyphs, NULL); else if (surface->target->backend->show_text_glyphs) backend_status = surface->target->backend->show_text_glyphs (surface->target, op, source, @@ -604,7 +607,7 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface, glyphs, num_glyphs, NULL, 0, FALSE, - scaled_font); + scaled_font, NULL); else backend_status = CAIRO_INT_STATUS_UNSUPPORTED; @@ -619,7 +622,7 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface, cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); - if (status) + if (unlikely (status)) return status; is_empty = _cairo_rectangle_intersect (&extents, &source_extents); @@ -632,11 +635,13 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface, glyphs, num_glyphs, &glyph_extents); - if (status) + if (unlikely (status)) return status; is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents); } + if (show_glyphs_extents) + *show_glyphs_extents = extents; status = _add_operation (surface, &extents, backend_status); @@ -662,7 +667,8 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, const cairo_text_cluster_t *clusters, int num_clusters, cairo_text_cluster_flags_t cluster_flags, - cairo_scaled_font_t *scaled_font) + cairo_scaled_font_t *scaled_font, + cairo_rectangle_int_t *show_text_glyphs_extents) { cairo_analysis_surface_t *surface = abstract_surface; cairo_status_t status, backend_status; @@ -677,14 +683,14 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags, - scaled_font); + scaled_font, NULL); if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && surface->target->backend->show_glyphs) { int remaining_glyphs = num_glyphs; backend_status = surface->target->backend->show_glyphs (surface->target, op, source, glyphs, num_glyphs, scaled_font, - &remaining_glyphs); + &remaining_glyphs, NULL); glyphs += num_glyphs - remaining_glyphs; num_glyphs = remaining_glyphs; if (remaining_glyphs == 0) @@ -702,7 +708,7 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); - if (status) + if (unlikely (status)) return status; is_empty = _cairo_rectangle_intersect (&extents, &source_extents); @@ -715,11 +721,13 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, glyphs, num_glyphs, &glyph_extents); - if (status) + if (unlikely (status)) return status; is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents); } + if (show_text_glyphs_extents) + *show_text_glyphs_extents = extents; status = _add_operation (surface, &extents, backend_status); @@ -738,6 +746,8 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = { NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ NULL, /* set_clip_region */ @@ -772,11 +782,11 @@ _cairo_analysis_surface_create (cairo_surface_t *target, cairo_status_t status; status = target->status; - if (status) + if (unlikely (status)) return _cairo_surface_create_in_error (status); surface = malloc (sizeof (cairo_analysis_surface_t)); - if (surface == NULL) + if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); /* I believe the content type here is truly arbitrary. I'm quite @@ -898,13 +908,15 @@ typedef cairo_int_status_t typedef cairo_int_status_t (*_paint_func) (void *surface, cairo_operator_t op, - const cairo_pattern_t *source); + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents); typedef cairo_int_status_t (*_mask_func) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_pattern_t *mask); + const cairo_pattern_t *mask, + cairo_rectangle_int_t *extents); typedef cairo_int_status_t (*_stroke_func) (void *surface, @@ -915,7 +927,8 @@ typedef cairo_int_status_t cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias); + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents); typedef cairo_int_status_t (*_fill_func) (void *surface, @@ -924,7 +937,8 @@ typedef cairo_int_status_t cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias); + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents); typedef cairo_int_status_t (*_show_glyphs_func) (void *surface, @@ -933,7 +947,8 @@ typedef cairo_int_status_t cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs); + int *remaining_glyphs, + cairo_rectangle_int_t *extents); static const cairo_surface_backend_t cairo_null_surface_backend = { CAIRO_INTERNAL_SURFACE_TYPE_NULL, @@ -948,6 +963,8 @@ static const cairo_surface_backend_t cairo_null_surface_backend = { NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ (_set_clip_region_func) _return_success, /* set_clip_region */ @@ -979,7 +996,7 @@ _cairo_null_surface_create (cairo_content_t content) cairo_surface_t *surface; surface = malloc (sizeof (cairo_surface_t)); - if (surface == NULL) { + if (unlikely (surface == NULL)) { return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } diff --git a/src/cairo-array.c b/src/cairo-array.c index f38cfe3e..9c084b9e 100644 --- a/src/cairo-array.c +++ b/src/cairo-array.c @@ -138,7 +138,7 @@ _cairo_array_grow_by (cairo_array_t *array, unsigned int additional) if (array->elements == NULL) { array->elements = malloc (sizeof (char *)); - if (array->elements == NULL) + if (unlikely (array->elements == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); *array->elements = NULL; @@ -148,7 +148,7 @@ _cairo_array_grow_by (cairo_array_t *array, unsigned int additional) new_elements = _cairo_realloc_ab (*array->elements, array->size, array->element_size); - if (new_elements == NULL) { + if (unlikely (new_elements == NULL)) { array->size = old_size; return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -279,7 +279,7 @@ _cairo_array_append_multiple (cairo_array_t *array, assert (! array->is_snapshot); status = _cairo_array_allocate (array, num_elements, &dest); - if (status) + if (unlikely (status)) return status; memcpy (dest, elements, num_elements * array->element_size); @@ -310,7 +310,7 @@ _cairo_array_allocate (cairo_array_t *array, assert (! array->is_snapshot); status = _cairo_array_grow_by (array, num_elements); - if (status) + if (unlikely (status)) return status; assert (array->num_elements + num_elements <= array->size); @@ -489,7 +489,7 @@ _cairo_user_data_array_set_data (cairo_user_data_array_t *array, } status = _cairo_array_append (array, &new_slot); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; diff --git a/src/cairo-base85-stream.c b/src/cairo-base85-stream.c index 88974039..9d42ef48 100644 --- a/src/cairo-base85-stream.c +++ b/src/cairo-base85-stream.c @@ -117,13 +117,14 @@ _cairo_base85_stream_create (cairo_output_stream_t *output) return _cairo_output_stream_create_in_error (output->status); stream = malloc (sizeof (cairo_base85_stream_t)); - if (stream == NULL) { + if (unlikely (stream == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_output_stream_t *) &_cairo_output_stream_nil; } _cairo_output_stream_init (&stream->base, _cairo_base85_stream_write, + NULL, _cairo_base85_stream_close); stream->output = output; stream->pending = 0; diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c index b22731df..cd150218 100644 --- a/src/cairo-bentley-ottmann.c +++ b/src/cairo-bentley-ottmann.c @@ -87,7 +87,7 @@ struct _cairo_bo_edge { cairo_bo_point32_t top; cairo_bo_point32_t middle; cairo_bo_point32_t bottom; - cairo_bool_t reversed; + int dir; cairo_bo_edge_t *prev; cairo_bo_edge_t *next; cairo_bo_trap_t *deferred_trap; @@ -979,7 +979,7 @@ _cairo_bo_event_queue_init (cairo_bo_event_queue_t *event_queue, sizeof (cairo_bo_event_t) + sizeof (cairo_bo_event_t *), sizeof (cairo_bo_event_t *)); - if (events == NULL) + if (unlikely (events == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); sorted_event_ptrs = (cairo_bo_event_t **) (events + num_events); @@ -1079,8 +1079,8 @@ _cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line, cairo_bo_edge_t **prev_of_next, **next_of_prev; sweep_line_elt = _cairo_skip_list_insert (&sweep_line->active_edges, &edge, - 1 /* unique inserts*/); - if (sweep_line_elt == NULL) + 1 /* unique inserts*/); + if (unlikely (sweep_line_elt == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); next_elt = sweep_line_elt->elt.next[0]; @@ -1439,10 +1439,7 @@ _active_edges_to_traps (cairo_bo_edge_t *head, for (edge = head; edge; edge = edge->next) { if (fill_rule == CAIRO_FILL_RULE_WINDING) { - if (edge->reversed) - in_out++; - else - in_out--; + in_out += edge->dir; if (in_out == 0) { status = _cairo_bo_edge_end_trap (edge, top, bo_traps); if (status) @@ -1662,11 +1659,10 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps, has_limits = _cairo_traps_get_limit (traps, &limit); - if (polygon->num_edges < ARRAY_LENGTH (stack_edges)) { - edges = stack_edges; - } else { + edges = stack_edges; + if (polygon->num_edges > ARRAY_LENGTH (stack_edges)) { edges = _cairo_malloc_ab (polygon->num_edges, sizeof (cairo_bo_edge_t)); - if (edges == NULL) + if (unlikely (edges == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -1734,10 +1730,7 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps, edge->top.y = top.y; edge->bottom.x = bot.x; edge->bottom.y = bot.y; - /* XXX: The 'clockWise' name that cairo_polygon_t uses is - * totally bogus. It's really a (negated!) description of - * whether the edge is reversed. */ - edge->reversed = (! polygon->edges[i].clockWise); + edge->dir = polygon->edges[i].dir; edge->deferred_trap = NULL; edge->prev = NULL; edge->next = NULL; diff --git a/src/cairo-beos-surface.cpp b/src/cairo-beos-surface.cpp index ec4aff03..e527272e 100644 --- a/src/cairo-beos-surface.cpp +++ b/src/cairo-beos-surface.cpp @@ -895,6 +895,8 @@ static const struct _cairo_surface_backend cairo_beos_surface_backend = { _cairo_beos_surface_composite, /* composite */ _cairo_beos_surface_fill_rectangles, NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ _cairo_beos_surface_set_clip_region, diff --git a/src/cairo-cache-private.h b/src/cairo-cache-private.h index 4ae63ade..5ac8cc8b 100644 --- a/src/cairo-cache-private.h +++ b/src/cairo-cache-private.h @@ -109,17 +109,16 @@ _cairo_cache_freeze (cairo_cache_t *cache); cairo_private void _cairo_cache_thaw (cairo_cache_t *cache); -cairo_private cairo_bool_t +cairo_private void * _cairo_cache_lookup (cairo_cache_t *cache, - cairo_cache_entry_t *key, - cairo_cache_entry_t **entry_return); + cairo_cache_entry_t *key); cairo_private cairo_status_t _cairo_cache_insert (cairo_cache_t *cache, cairo_cache_entry_t *entry); cairo_private void -_cairo_cache_foreach (cairo_cache_t *cache, +_cairo_cache_foreach (cairo_cache_t *cache, cairo_cache_callback_func_t cache_callback, void *closure); diff --git a/src/cairo-cache.c b/src/cairo-cache.c index 1c458dff..07c8b71f 100644 --- a/src/cairo-cache.c +++ b/src/cairo-cache.c @@ -44,7 +44,7 @@ _cairo_cache_remove (cairo_cache_t *cache, static void _cairo_cache_shrink_to_accommodate (cairo_cache_t *cache, - unsigned long additional); + unsigned long additional); static cairo_status_t _cairo_cache_init (cairo_cache_t *cache, @@ -53,7 +53,7 @@ _cairo_cache_init (cairo_cache_t *cache, unsigned long max_size) { cache->hash_table = _cairo_hash_table_create (keys_equal); - if (cache->hash_table == NULL) + if (unlikely (cache->hash_table == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); cache->entry_destroy = entry_destroy; @@ -67,24 +67,19 @@ _cairo_cache_init (cairo_cache_t *cache, } static void -_cairo_cache_fini (cairo_cache_t *cache) +_cairo_cache_pluck (void *entry, void *closure) { - cairo_cache_entry_t *entry; - - /* We have to manually remove all entries from the cache ourselves - * rather than relying on _cairo_hash_table_destroy() to do that - * since otherwise the cache->entry_destroy callback would not get - * called on each entry. */ - - while (1) { - entry = _cairo_hash_table_random_entry (cache->hash_table, NULL); - if (entry == NULL) - break; - _cairo_cache_remove (cache, entry); - } + _cairo_cache_remove (closure, entry); +} +static void +_cairo_cache_fini (cairo_cache_t *cache) +{ + _cairo_hash_table_foreach (cache->hash_table, + _cairo_cache_pluck, + cache); + assert (cache->size == 0); _cairo_hash_table_destroy (cache->hash_table); - cache->size = 0; } /** @@ -130,13 +125,13 @@ _cairo_cache_create (cairo_cache_keys_equal_func_t keys_equal, cairo_cache_t *cache; cache = malloc (sizeof (cairo_cache_t)); - if (cache == NULL) { + if (unlikely (cache == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); return NULL; } status = _cairo_cache_init (cache, keys_equal, entry_destroy, max_size); - if (status) { + if (unlikely (status)) { free (cache); return NULL; } @@ -222,14 +217,12 @@ _cairo_cache_thaw (cairo_cache_t *cache) * @key, (which will now be in *entry_return). %FALSE otherwise, (in * which case *entry_return will be %NULL). **/ -cairo_bool_t +void * _cairo_cache_lookup (cairo_cache_t *cache, - cairo_cache_entry_t *key, - cairo_cache_entry_t **entry_return) + cairo_cache_entry_t *key) { return _cairo_hash_table_lookup (cache->hash_table, - (cairo_hash_entry_t *) key, - (cairo_hash_entry_t **) entry_return); + (cairo_hash_entry_t *) key); } /** @@ -247,7 +240,7 @@ _cairo_cache_remove_random (cairo_cache_t *cache) cairo_cache_entry_t *entry; entry = _cairo_hash_table_random_entry (cache->hash_table, NULL); - if (entry == NULL) + if (unlikely (entry == NULL)) return FALSE; _cairo_cache_remove (cache, entry); @@ -300,7 +293,7 @@ _cairo_cache_insert (cairo_cache_t *cache, status = _cairo_hash_table_insert (cache->hash_table, (cairo_hash_entry_t *) entry); - if (status) + if (unlikely (status)) return status; cache->size += entry->size; @@ -356,8 +349,20 @@ unsigned long _cairo_hash_string (const char *c) { /* This is the djb2 hash. */ - unsigned long hash = 5381; + unsigned long hash = _CAIRO_HASH_INIT_VALUE; while (c && *c) hash = ((hash << 5) + hash) + *c++; return hash; } + +unsigned long +_cairo_hash_bytes (unsigned long hash, + const void *ptr, + unsigned int length) +{ + const uint8_t *bytes = ptr; + /* This is the djb2 hash. */ + while (length--) + hash = ((hash << 5) + hash) + *bytes++; + return hash; +} diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c index 9a4e3d6a..75e1ab51 100644 --- a/src/cairo-cff-subset.c +++ b/src/cairo-cff-subset.c @@ -298,7 +298,7 @@ cff_index_read (cairo_array_t *index, unsigned char **ptr, unsigned char *end_pt element.is_copy = FALSE; element.data = data + start; status = _cairo_array_append (index, &element); - if (status) + if (unlikely (status)) return status; start = end; } @@ -324,7 +324,7 @@ cff_index_write (cairo_array_t *index, cairo_array_t *output) num_elem = _cairo_array_num_elements (index); count = cpu_to_be16 ((uint16_t) num_elem); status = _cairo_array_append_multiple (output, &count, 2); - if (status) + if (unlikely (status)) return status; if (num_elem == 0) @@ -347,13 +347,13 @@ cff_index_write (cairo_array_t *index, cairo_array_t *output) buf[0] = (unsigned char) offset_size; status = _cairo_array_append (output, buf); - if (status) + if (unlikely (status)) return status; offset = 1; encode_index_offset (buf, offset_size, offset); status = _cairo_array_append_multiple (output, buf, offset_size); - if (status) + if (unlikely (status)) return status; for (i = 0; i < num_elem; i++) { @@ -361,7 +361,7 @@ cff_index_write (cairo_array_t *index, cairo_array_t *output) offset += element->length; encode_index_offset (buf, offset_size, offset); status = _cairo_array_append_multiple (output, buf, offset_size); - if (status) + if (unlikely (status)) return status; } @@ -370,7 +370,7 @@ cff_index_write (cairo_array_t *index, cairo_array_t *output) status = _cairo_array_append_multiple (output, element->data, element->length); - if (status) + if (unlikely (status)) return status; } return CAIRO_STATUS_SUCCESS; @@ -399,13 +399,13 @@ cff_index_append_copy (cairo_array_t *index, element.length = length; element.is_copy = TRUE; element.data = malloc (element.length); - if (element.data == NULL) + if (unlikely (element.data == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (element.data, object, element.length); status = _cairo_array_append (index, &element); - if (status) { + if (unlikely (status)) { free (element.data); return status; } @@ -440,8 +440,8 @@ static cairo_status_t cff_dict_init (cairo_hash_table_t **dict) { *dict = _cairo_hash_table_create (_cairo_cff_dict_equal); - if (*dict == NULL) - return CAIRO_STATUS_NO_MEMORY; + if (unlikely (*dict == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_SUCCESS; } @@ -462,12 +462,12 @@ cff_dict_create_operator (int operator, cff_dict_operator_t *op; op = malloc (sizeof (cff_dict_operator_t)); - if (op == NULL) + if (unlikely (op == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_dict_init_key (op, operator); op->operand = malloc (size); - if (op->operand == NULL) { + if (unlikely (op->operand == NULL)) { free (op); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -496,7 +496,7 @@ cff_dict_read (cairo_hash_table_t *dict, unsigned char *p, int dict_size) size = operand_length (p); if (size != 0) { status = _cairo_array_append_multiple (&operands, p, size); - if (status) + if (unlikely (status)) goto fail; p += size; @@ -506,11 +506,11 @@ cff_dict_read (cairo_hash_table_t *dict, unsigned char *p, int dict_size) _cairo_array_index (&operands, 0), _cairo_array_num_elements (&operands), &op); - if (status) + if (unlikely (status)) goto fail; status = _cairo_hash_table_insert (dict, &op->base); - if (status) + if (unlikely (status)) goto fail; _cairo_array_truncate (&operands, 0); @@ -529,9 +529,8 @@ 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)) - { + op = _cairo_hash_table_lookup (dict, &key.base); + if (op != NULL) { free (op->operand); _cairo_hash_table_remove (dict, (cairo_hash_entry_t *) op); free (op); @@ -546,9 +545,8 @@ cff_dict_get_operands (cairo_hash_table_t *dict, 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)) - { + op = _cairo_hash_table_lookup (dict, &key.base); + if (op != NULL) { *size = op->operand_length; return op->operand; } @@ -566,12 +564,11 @@ cff_dict_set_operands (cairo_hash_table_t *dict, cairo_status_t status; _cairo_dict_init_key (&key, operator); - if (_cairo_hash_table_lookup (dict, &key.base, - (cairo_hash_entry_t **) &op)) - { + op = _cairo_hash_table_lookup (dict, &key.base); + if (op != NULL) { free (op->operand); op->operand = malloc (size); - if (op->operand == NULL) + if (unlikely (op->operand == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (op->operand, operand, size); @@ -580,11 +577,11 @@ cff_dict_set_operands (cairo_hash_table_t *dict, else { status = cff_dict_create_operator (operator, operand, size, &op); - if (status) + if (unlikely (status)) return status; status = _cairo_hash_table_insert (dict, &op->base); - if (status) + if (unlikely (status)) return status; } @@ -599,9 +596,8 @@ cff_dict_get_location (cairo_hash_table_t *dict, 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)) - { + op = _cairo_hash_table_lookup (dict, &key.base); + if (op != NULL) { *size = op->operand_length; return op->operand_offset; } @@ -660,8 +656,8 @@ cff_dict_write (cairo_hash_table_t *dict, cairo_array_t *output) /* 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)) + op = _cairo_hash_table_lookup (dict, &key.base); + if (op != NULL) cairo_dict_write_operator (op, &write_info); _cairo_hash_table_foreach (dict, _cairo_dict_collect, &write_info); @@ -728,7 +724,7 @@ cairo_cff_font_read_private_dict (cairo_cff_font_t *font, unsigned char *p; status = cff_dict_read (private_dict, ptr, size); - if (status) + if (unlikely (status)) return status; operand = cff_dict_get_operands (private_dict, LOCAL_SUB_OP, &i); @@ -736,13 +732,13 @@ cairo_cff_font_read_private_dict (cairo_cff_font_t *font, decode_integer (operand, &offset); p = ptr + offset; status = cff_index_read (local_sub_index, &p, font->data_end); - if (status) + if (unlikely (status)) return status; /* Use maximum sized encoding to reserve space for later modification. */ end_buf = encode_integer_max (buf, 0); status = cff_dict_set_operands (private_dict, LOCAL_SUB_OP, buf, end_buf - buf); - if (status) + if (unlikely (status)) return status; } @@ -755,7 +751,7 @@ 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) + if (unlikely (font->fdselect == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); type = *p++; @@ -797,37 +793,37 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr) cff_index_init (&index); status = cff_index_read (&index, &ptr, font->data_end); - if (status) + if (unlikely (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) { + if (unlikely (font->fd_dict == NULL)) { status = _cairo_error (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) { + if (unlikely (font->fd_private_dict == NULL)) { status = _cairo_error (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) { + if (unlikely (font->fd_local_sub_index == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail; } for (i = 0; i < font->num_fontdicts; i++) { status = cff_dict_init (&font->fd_dict[i]); - if (status) + if (unlikely (status)) goto fail; element = _cairo_array_index (&index, i); status = cff_dict_read (font->fd_dict[i], element->data, element->length); - if (status) + if (unlikely (status)) goto fail; operand = cff_dict_get_operands (font->fd_dict[i], PRIVATE_OP, &size); @@ -838,7 +834,7 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr) operand = decode_integer (operand, &size); decode_integer (operand, &offset); status = cff_dict_init (&font->fd_private_dict[i]); - if (status) + if (unlikely (status)) goto fail; cff_index_init (&font->fd_local_sub_index[i]); @@ -847,7 +843,7 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr) &font->fd_local_sub_index[i], font->data + offset, size); - if (status) + if (unlikely (status)) goto fail; /* Set integer operand to max value to use max size encoding to reserve @@ -855,7 +851,7 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr) 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) + if (unlikely (status)) goto fail; } @@ -882,12 +878,12 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font) cff_index_init (&index); status = cff_index_read (&index, &font->current_ptr, font->data_end); - if (status) + if (unlikely (status)) goto fail; element = _cairo_array_index (&index, 0); status = cff_dict_read (font->top_dict, element->data, element->length); - if (status) + if (unlikely (status)) goto fail; if (cff_dict_get_operands (font->top_dict, ROS_OP, &size) != NULL) @@ -899,7 +895,7 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font) decode_integer (operand, &offset); p = font->data + offset; status = cff_index_read (&font->charstrings_index, &p, font->data_end); - if (status) + if (unlikely (status)) goto fail; font->num_glyphs = _cairo_array_num_elements (&font->charstrings_index); @@ -907,13 +903,13 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font) operand = cff_dict_get_operands (font->top_dict, FDSELECT_OP, &size); decode_integer (operand, &offset); status = cairo_cff_font_read_fdselect (font, font->data + offset); - if (status) + if (unlikely (status)) goto fail; operand = cff_dict_get_operands (font->top_dict, FDARRAY_OP, &size); decode_integer (operand, &offset); status = cairo_cff_font_read_cid_fontdict (font, font->data + offset); - if (status) + if (unlikely (status)) goto fail; } else { operand = cff_dict_get_operands (font->top_dict, PRIVATE_OP, &size); @@ -924,7 +920,7 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font) &font->local_sub_index, font->data + offset, size); - if (status) + if (unlikely (status)) goto fail; } @@ -932,22 +928,22 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font) end_buf = encode_integer_max (buf, 0); status = cff_dict_set_operands (font->top_dict, CHARSTRINGS_OP, buf, end_buf - buf); - if (status) + if (unlikely (status)) goto fail; status = cff_dict_set_operands (font->top_dict, FDSELECT_OP, buf, end_buf - buf); - if (status) + if (unlikely (status)) goto fail; status = cff_dict_set_operands (font->top_dict, FDARRAY_OP, buf, end_buf - buf); - if (status) + if (unlikely (status)) goto fail; status = cff_dict_set_operands (font->top_dict, CHARSET_OP, buf, end_buf - buf); - if (status) + if (unlikely (status)) goto fail; cff_dict_remove (font->top_dict, ENCODING_OP); @@ -995,7 +991,7 @@ cairo_cff_font_read_font (cairo_cff_font_t *font) for (i = 0; i < ARRAY_LENGTH (font_read_funcs); i++) { status = font_read_funcs[i] (font); - if (status) + if (unlikely (status)) return status; } @@ -1016,26 +1012,26 @@ cairo_cff_font_set_ros_strings (cairo_cff_font_t *font) status = cff_index_append_copy (&font->strings_subset_index, (unsigned char *)registry, strlen(registry)); - if (status) + if (unlikely (status)) return status; sid2 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index); status = cff_index_append_copy (&font->strings_subset_index, (unsigned char *)ordering, strlen(ordering)); - if (status) + if (unlikely (status)) return status; p = encode_integer (buf, sid1); p = encode_integer (p, sid2); p = encode_integer (p, 0); status = cff_dict_set_operands (font->top_dict, ROS_OP, buf, p - buf); - if (status) + if (unlikely (status)) return status; p = encode_integer (buf, font->scaled_font_subset->num_glyphs); status = cff_dict_set_operands (font->top_dict, CIDCOUNT_OP, buf, p - buf); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -1064,12 +1060,12 @@ cairo_cff_font_subset_dict_string(cairo_cff_font_t *font, element = _cairo_array_index (&font->strings_index, sid - NUM_STD_STRINGS); 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) + if (unlikely (status)) return status; p = encode_integer (buf, sid); status = cff_dict_set_operands (dict, operator, buf, p - buf); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -1096,7 +1092,7 @@ cairo_cff_font_subset_dict_strings (cairo_cff_font_t *font, for (i = 0; i < ARRAY_LENGTH (dict_strings); i++) { status = cairo_cff_font_subset_dict_string (font, dict, dict_strings[i]); - if (status) + if (unlikely (status)) return status; } @@ -1116,7 +1112,7 @@ cairo_cff_font_subset_charstrings (cairo_cff_font_t *font) status = cff_index_append (&font->charstrings_subset_index, element->data, element->length); - if (status) + if (unlikely (status)) return status; } @@ -1132,19 +1128,19 @@ cairo_cff_font_subset_fontdict (cairo_cff_font_t *font) font->fdselect_subset = calloc (font->scaled_font_subset->num_glyphs, sizeof (int)); - if (font->fdselect_subset == NULL) + if (unlikely (font->fdselect_subset == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); font->fd_subset_map = calloc (font->num_fontdicts, sizeof (int)); - if (font->fd_subset_map == NULL) + if (unlikely (font->fd_subset_map == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); font->private_dict_offset = calloc (font->num_fontdicts, sizeof (int)); - if (font->private_dict_offset == NULL) + if (unlikely (font->private_dict_offset == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); reverse_map = calloc (font->num_fontdicts, sizeof (int)); - if (reverse_map == NULL) + if (unlikely (reverse_map == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); for (i = 0; i < font->num_fontdicts; i++) @@ -1174,7 +1170,7 @@ cairo_cff_font_create_cid_fontdict (cairo_cff_font_t *font) font->num_fontdicts = 1; font->fd_dict = malloc (sizeof (cairo_hash_table_t *)); - if (font->fd_dict == NULL) + if (unlikely (font->fd_dict == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); if (cff_dict_init (&font->fd_dict[0])) { @@ -1185,11 +1181,11 @@ cairo_cff_font_create_cid_fontdict (cairo_cff_font_t *font) } font->fd_subset_map = malloc (sizeof (int)); - if (font->fd_subset_map == NULL) + if (unlikely (font->fd_subset_map == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); font->private_dict_offset = malloc (sizeof (int)); - if (font->private_dict_offset == NULL) + if (unlikely (font->private_dict_offset == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); font->fd_subset_map[0] = 0; @@ -1200,7 +1196,7 @@ cairo_cff_font_create_cid_fontdict (cairo_cff_font_t *font) end_buf = encode_integer_max (buf, 0); end_buf = encode_integer_max (end_buf, 0); status = cff_dict_set_operands (font->fd_dict[0], PRIVATE_OP, buf, end_buf - buf); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -1213,17 +1209,17 @@ cairo_cff_font_subset_strings (cairo_cff_font_t *font) unsigned int i; status = cairo_cff_font_subset_dict_strings (font, font->top_dict); - if (status) + if (unlikely (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) + if (unlikely (status)) return status; status = cairo_cff_font_subset_dict_strings (font, font->fd_private_dict[font->fd_subset_map[i]]); - if (status) + if (unlikely (status)) return status; } } else { @@ -1239,22 +1235,22 @@ cairo_cff_font_subset_font (cairo_cff_font_t *font) cairo_status_t status; status = cairo_cff_font_set_ros_strings (font); - if (status) + if (unlikely (status)) return status; status = cairo_cff_font_subset_charstrings (font); - if (status) + if (unlikely (status)) return status; if (font->is_cid) status = cairo_cff_font_subset_fontdict (font); else status = cairo_cff_font_create_cid_fontdict (font); - if (status) + if (unlikely (status)) return status; status = cairo_cff_font_subset_strings (font); - if (status) + if (unlikely (status)) return status; return status; @@ -1302,11 +1298,11 @@ cairo_cff_font_write_name (cairo_cff_font_t *font) status = cff_index_append_copy (&index, (unsigned char *) font->subset_font_name, strlen(font->subset_font_name)); - if (status) + if (unlikely (status)) goto FAIL; status = cff_index_write (&index, &font->output); - if (status) + if (unlikely (status)) goto FAIL; FAIL: @@ -1330,27 +1326,27 @@ cairo_cff_font_write_top_dict (cairo_cff_font_t *font) count = cpu_to_be16 (1); status = _cairo_array_append_multiple (&font->output, &count, 2); - if (status) + if (unlikely (status)) return status; buf[0] = offset_size; status = _cairo_array_append (&font->output, buf); - if (status) + if (unlikely (status)) return status; encode_index_offset (buf, offset_size, 1); status = _cairo_array_append_multiple (&font->output, buf, offset_size); - if (status) + if (unlikely (status)) return status; /* Reserve space for last element of offset array and update after * dict is written */ offset_index = _cairo_array_num_elements (&font->output); status = _cairo_array_append_multiple (&font->output, buf, offset_size); - if (status) + if (unlikely (status)) return status; dict_start = _cairo_array_num_elements (&font->output); status = cff_dict_write (font->top_dict, &font->output); - if (status) + if (unlikely (status)) return status; dict_size = _cairo_array_num_elements (&font->output) - dict_start; @@ -1385,13 +1381,13 @@ cairo_cff_font_write_fdselect (cairo_cff_font_t *font) if (font->is_cid) { data = 0; status = _cairo_array_append (&font->output, &data); - if (status) + if (unlikely (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) + if (unlikely (status)) return status; } } else { @@ -1399,7 +1395,7 @@ cairo_cff_font_write_fdselect (cairo_cff_font_t *font) uint16_t word; status = _cairo_array_grow_by (&font->output, 9); - if (status) + if (unlikely (status)) return status; byte = 3; @@ -1435,7 +1431,7 @@ cairo_cff_font_write_charset (cairo_cff_font_t *font) cairo_cff_font_set_topdict_operator_to_cur_pos (font, CHARSET_OP); status = _cairo_array_grow_by (&font->output, 5); - if (status) + if (unlikely (status)) return status; byte = 2; @@ -1474,22 +1470,22 @@ cairo_cff_font_write_cid_fontdict (cairo_cff_font_t *font) 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) + if (unlikely (status)) return status; status = _cairo_array_append (&font->output, &offset_size); - if (status) + if (unlikely (status)) return status; status = _cairo_array_allocate (&font->output, (font->num_subset_fontdicts + 1)*offset_size, (void **) &offset_array); - if (status) + if (unlikely (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) + if (unlikely (status)) return status; *offset_array++ = cpu_to_be32(_cairo_array_num_elements (&font->output) - offset_base); } @@ -1513,7 +1509,7 @@ cairo_cff_font_write_private_dict (cairo_cff_font_t *font, /* Write private dict and update offset and size in top dict */ font->private_dict_offset[dict_num] = _cairo_array_num_elements (&font->output); status = cff_dict_write (private_dict, &font->output); - if (status) + if (unlikely (status)) return status; size = _cairo_array_num_elements (&font->output) - font->private_dict_offset[dict_num]; @@ -1552,7 +1548,7 @@ cairo_cff_font_write_local_sub (cairo_cff_font_t *font, p = _cairo_array_index (&font->output, offset); memcpy (p, buf, buf_end - buf); status = cff_index_write (local_sub_index, &font->output); - if (status) + if (unlikely (status)) return status; } @@ -1573,7 +1569,7 @@ cairo_cff_font_write_cid_private_dict_and_local_sub (cairo_cff_font_t *font) i, font->fd_dict[font->fd_subset_map[i]], font->fd_private_dict[font->fd_subset_map[i]]); - if (status) + if (unlikely (status)) return status; } @@ -1583,7 +1579,7 @@ cairo_cff_font_write_cid_private_dict_and_local_sub (cairo_cff_font_t *font) i, font->fd_private_dict[font->fd_subset_map[i]], &font->fd_local_sub_index[font->fd_subset_map[i]]); - if (status) + if (unlikely (status)) return status; } } else { @@ -1591,14 +1587,14 @@ cairo_cff_font_write_cid_private_dict_and_local_sub (cairo_cff_font_t *font) 0, font->fd_dict[0], font->private_dict); - if (status) + if (unlikely (status)) return status; status = cairo_cff_font_write_local_sub (font, 0, font->private_dict, &font->local_sub_index); - if (status) + if (unlikely (status)) return status; } @@ -1629,7 +1625,7 @@ cairo_cff_font_write_subset (cairo_cff_font_t *font) for (i = 0; i < ARRAY_LENGTH (font_write_funcs); i++) { status = font_write_funcs[i] (font); - if (status) + if (unlikely (status)) return status; } @@ -1644,15 +1640,15 @@ cairo_cff_font_generate (cairo_cff_font_t *font, cairo_int_status_t status; status = cairo_cff_font_read_font (font); - if (status) + if (unlikely (status)) return status; status = cairo_cff_font_subset_font (font); - if (status) + if (unlikely (status)) return status; status = cairo_cff_font_write_subset (font); - if (status) + if (unlikely (status)) return status; *data = _cairo_array_index (&font->output, 0); @@ -1678,7 +1674,7 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font) status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, TT_TAG_hhea, 0, (unsigned char*) &hhea, &size); - if (status) + if (unlikely (status)) return status; num_hmetrics = be16_to_cpu (hhea.num_hmetrics); @@ -1691,7 +1687,7 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font) TT_TAG_hmtx, glyph_index * long_entry_size, buf, &short_entry_size); - if (status) + if (unlikely (status)) return status; } else @@ -1700,7 +1696,7 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font) TT_TAG_hmtx, (num_hmetrics - 1) * long_entry_size, buf, &short_entry_size); - if (status) + if (unlikely (status)) return status; } font->widths[i] = be16_to_cpu (*((int16_t*)buf)); @@ -1731,47 +1727,47 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset, data_length = 0; status = backend->load_truetype_table( scaled_font_subset->scaled_font, TT_TAG_CFF, 0, NULL, &data_length); - if (status) + if (unlikely (status)) return status; size = sizeof (tt_head_t); status = backend->load_truetype_table (scaled_font_subset->scaled_font, TT_TAG_head, 0, (unsigned char *) &head, &size); - if (status) + if (unlikely (status)) return status; size = sizeof (tt_hhea_t); status = backend->load_truetype_table (scaled_font_subset->scaled_font, TT_TAG_hhea, 0, (unsigned char *) &hhea, &size); - if (status) + if (unlikely (status)) return status; size = 0; status = backend->load_truetype_table (scaled_font_subset->scaled_font, TT_TAG_hmtx, 0, NULL, &size); - if (status) + if (unlikely (status)) return status; size = 0; status = backend->load_truetype_table (scaled_font_subset->scaled_font, TT_TAG_name, 0, NULL, &size); - if (status) + if (unlikely (status)) return status; name = malloc (size); - if (name == NULL) + if (unlikely (name == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = backend->load_truetype_table (scaled_font_subset->scaled_font, TT_TAG_name, 0, (unsigned char *) name, &size); - if (status) + if (unlikely (status)) goto fail1; font = malloc (sizeof (cairo_cff_font_t)); - if (font == NULL) { + if (unlikely (font == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail1; } @@ -1781,11 +1777,11 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset, _cairo_array_init (&font->output, sizeof (char)); status = _cairo_array_grow_by (&font->output, 4096); - if (status) + if (unlikely (status)) goto fail2; font->subset_font_name = strdup (subset_name); - if (font->subset_font_name == NULL) { + if (unlikely (font->subset_font_name == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail2; } @@ -1821,7 +1817,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset, if (font->font_name == NULL) { font->font_name = malloc (30); - if (font->font_name == NULL) { + if (unlikely (font->font_name == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail3; } @@ -1838,35 +1834,35 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset, font->font_name[i] = '\0'; font->widths = calloc (font->scaled_font_subset->num_glyphs, sizeof (int)); - if (font->widths == NULL) { + if (unlikely (font->widths == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail4; } status = cairo_cff_font_create_set_widths (font); - if (status) + if (unlikely (status)) goto fail5; font->data_length = data_length; font->data = malloc (data_length); - if (font->data == NULL) { + if (unlikely (font->data == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail5; } status = font->backend->load_truetype_table ( font->scaled_font_subset->scaled_font, TT_TAG_CFF, 0, font->data, &font->data_length); - if (status) + if (unlikely (status)) goto fail6; font->data_end = font->data + font->data_length; status = cff_dict_init (&font->top_dict); - if (status) + if (unlikely (status)) goto fail6; status = cff_dict_init (&font->private_dict); - if (status) + if (unlikely (status)) goto fail7; cff_index_init (&font->strings_index); @@ -1975,21 +1971,21 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset, unsigned int i; status = _cairo_cff_font_create (font_subset, &font, subset_name); - if (status) + if (unlikely (status)) return status; status = cairo_cff_font_generate (font, &data, &length); - if (status) + if (unlikely (status)) goto fail1; cff_subset->base_font = strdup (font->font_name); - if (cff_subset->base_font == NULL) { + if (unlikely (cff_subset->base_font == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail1; } cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs); - if (cff_subset->widths == NULL) { + if (unlikely (cff_subset->widths == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail2; } @@ -2004,7 +2000,7 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset, cff_subset->descent = font->descent; cff_subset->data = malloc (length); - if (cff_subset->data == NULL) { + if (unlikely (cff_subset->data == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail3; } @@ -2043,7 +2039,7 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset cairo_cff_font_t *font; font = malloc (sizeof (cairo_cff_font_t)); - if (font == NULL) + if (unlikely (font == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); font->backend = NULL; @@ -2051,17 +2047,17 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset _cairo_array_init (&font->output, sizeof (char)); status = _cairo_array_grow_by (&font->output, 4096); - if (status) + if (unlikely (status)) goto fail1; font->subset_font_name = strdup (subset_name); - if (font->subset_font_name == NULL) { + if (unlikely (font->subset_font_name == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail1; } font->font_name = strdup (subset_name); - if (font->subset_font_name == NULL) { + if (unlikely (font->subset_font_name == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail2; } @@ -2074,7 +2070,7 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset font->descent = 0; font->widths = calloc (font->scaled_font_subset->num_glyphs, sizeof (int)); - if (font->widths == NULL) { + if (unlikely (font->widths == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail3; } @@ -2084,11 +2080,11 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset font->data_end = NULL; status = cff_dict_init (&font->top_dict); - if (status) + if (unlikely (status)) goto fail4; status = cff_dict_init (&font->private_dict); - if (status) + if (unlikely (status)) goto fail5; cff_index_init (&font->strings_index); @@ -2151,37 +2147,37 @@ cairo_cff_font_fallback_generate (cairo_cff_font_t *font, end_buf = encode_integer (end_buf, type2_subset->y_max); status = cff_dict_set_operands (font->top_dict, FONTBBOX_OP, buf, end_buf - buf); - if (status) + if (unlikely (status)) return status; end_buf = encode_integer_max (buf, 0); status = cff_dict_set_operands (font->top_dict, CHARSTRINGS_OP, buf, end_buf - buf); - if (status) + if (unlikely (status)) return status; status = cff_dict_set_operands (font->top_dict, FDSELECT_OP, buf, end_buf - buf); - if (status) + if (unlikely (status)) return status; status = cff_dict_set_operands (font->top_dict, FDARRAY_OP, buf, end_buf - buf); - if (status) + if (unlikely (status)) return status; status = cff_dict_set_operands (font->top_dict, CHARSET_OP, buf, end_buf - buf); - if (status) + if (unlikely (status)) return status; status = cairo_cff_font_set_ros_strings (font); - if (status) + if (unlikely (status)) return status; /* Create CID FD dictionary */ status = cairo_cff_font_create_cid_fontdict (font); - if (status) + if (unlikely (status)) return status; /* Create charstrings */ @@ -2192,12 +2188,12 @@ cairo_cff_font_fallback_generate (cairo_cff_font_t *font, _cairo_array_index (charstring, 0), _cairo_array_num_elements (charstring)); - if (status) + if (unlikely (status)) return status; } status = cairo_cff_font_write_subset (font); - if (status) + if (unlikely (status)) return status; *data = _cairo_array_index (&font->output, 0); @@ -2219,25 +2215,25 @@ _cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset, cairo_type2_charstrings_t type2_subset; status = _cairo_cff_font_fallback_create (font_subset, &font, subset_name); - if (status) + if (unlikely (status)) return status; status = _cairo_type2_charstrings_init (&type2_subset, font_subset); - if (status) + if (unlikely (status)) goto fail1; status = cairo_cff_font_fallback_generate (font, &type2_subset, &data, &length); - if (status) + if (unlikely (status)) goto fail2; cff_subset->base_font = strdup (font->font_name); - if (cff_subset->base_font == NULL) { + if (unlikely (cff_subset->base_font == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail2; } cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs); - if (cff_subset->widths == NULL) { + if (unlikely (cff_subset->widths == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail3; } @@ -2252,7 +2248,7 @@ _cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset, cff_subset->descent = type2_subset.y_min; cff_subset->data = malloc (length); - if (cff_subset->data == NULL) { + if (unlikely (cff_subset->data == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail4; } diff --git a/src/cairo-clip.c b/src/cairo-clip.c index 93bc151c..cd423a44 100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c @@ -49,7 +49,7 @@ _cairo_clip_path_destroy (cairo_clip_path_t *clip_path); void _cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target) { - if (target) + if (target && target->backend) clip->mode = _cairo_surface_get_clip_mode (target); else clip->mode = CAIRO_CLIP_MODE_MASK; @@ -88,7 +88,7 @@ _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other) cairo_status_t status; status = _cairo_region_copy (&clip->region, &other->region); - if (status) { + if (unlikely (status)) { _cairo_region_fini (&clip->region); cairo_surface_destroy (clip->surface); return status; @@ -143,30 +143,11 @@ _cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t *clip_path, cairo_rectangle_int_t *rectangle) { while (clip_path) { - cairo_status_t status; - cairo_traps_t traps; - cairo_box_t extents; - cairo_rectangle_int_t extents_rect; - - _cairo_box_from_rectangle (&extents, rectangle); - - _cairo_traps_init (&traps); - _cairo_traps_limit (&traps, &extents); - - status = _cairo_path_fixed_fill_to_traps (&clip_path->path, - clip_path->fill_rule, - clip_path->tolerance, - &traps); - if (status) { - _cairo_traps_fini (&traps); - return status; - } + cairo_rectangle_int_t extents; - _cairo_traps_extents (&traps, &extents); - _cairo_traps_fini (&traps); + _cairo_path_fixed_approximate_extents (&clip_path->path, &extents); - _cairo_box_round_to_rectangle (&extents, &extents_rect); - if (! _cairo_rectangle_intersect (rectangle, &extents_rect)) + if (! _cairo_rectangle_intersect (rectangle, &extents)) return CAIRO_STATUS_SUCCESS; clip_path = clip_path->prev; @@ -193,7 +174,7 @@ _cairo_clip_intersect_to_rectangle (cairo_clip_t *clip, if (clip->path) { status = _cairo_clip_path_intersect_to_rectangle (clip->path, rectangle); - if (status) + if (unlikely (status)) return status; } @@ -210,7 +191,7 @@ _cairo_clip_intersect_to_rectangle (cairo_clip_t *clip, _cairo_region_fini (&intersection); - if (status) + if (unlikely (status)) return status; } @@ -247,7 +228,7 @@ _cairo_clip_intersect_to_region (cairo_clip_t *clip, if (clip->has_region) { status = _cairo_region_intersect (region, &clip->region, region); - if (status) + if (unlikely (status)) return status; } @@ -260,7 +241,7 @@ _cairo_clip_intersect_to_region (cairo_clip_t *clip, _cairo_region_fini (&clip_rect); - if (status) + if (unlikely (status)) return status; } @@ -317,11 +298,11 @@ _cairo_clip_intersect_path (cairo_clip_t *clip, return CAIRO_INT_STATUS_UNSUPPORTED; clip_path = malloc (sizeof (cairo_clip_path_t)); - if (clip_path == NULL) + if (unlikely (clip_path == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_path_fixed_init_copy (&clip_path->path, path); - if (status) { + if (unlikely (status)) { free (clip_path); return status; } @@ -381,7 +362,6 @@ _cairo_clip_intersect_region (cairo_clip_t *clip, return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_traps_extract_region (traps, ®ion); - if (status) return status; @@ -423,7 +403,7 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip, cairo_box_t extents; cairo_rectangle_int_t surface_rect, target_rect; cairo_surface_t *surface = NULL; - cairo_status_t status; + cairo_status_t status = CAIRO_STATUS_SUCCESS; if (clip->all_clipped) return CAIRO_STATUS_SUCCESS; @@ -478,9 +458,10 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip, I believe the best possible operation would probably an unbounded SRC operator. Using SRC we could potentially avoid having to initialize the surface which would be ideal from an efficiency point of view. - However, _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_SOURCE) is - bounded by the mask. - + However, CAIRO_OPERATOR_SOURCE is bounded by the trapezoid mask and + _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_SOURCE) will assert + because it assumes CAIRO_OPERATOR_SOURCE has been converted into other + operations. */ surface = _cairo_surface_create_similar_solid (target, @@ -510,7 +491,7 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip, _cairo_pattern_fini (&pattern.base); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (surface); return status; } @@ -535,7 +516,7 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip, _cairo_pattern_fini (&pattern.base); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (surface); return status; } @@ -553,6 +534,133 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip, return status; } +static cairo_status_t +_cairo_clip_intersect_mask_using_spans (cairo_clip_t *clip, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_surface_t *target) +{ + cairo_span_renderer_t *renderer = NULL; + cairo_pattern_union_t pattern; + cairo_rectangle_int_t surface_rect; + cairo_surface_t *surface = NULL; + cairo_status_t status; + cairo_operator_t op; + cairo_composite_rectangles_t rects; + + if (clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + + _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE, + CAIRO_CONTENT_COLOR); + + /* If we have a clip surface we're going to use IN to combine our + * new clip with the old clip. The ADD is done to a transparent + * surface, as that's a fast way of doing it currently. We should + * really be using SOURCE instead, but _cairo_surface_composite() + * checks that it's not called with SOURCE or DEST. */ + op = clip->surface ? CAIRO_OPERATOR_IN : CAIRO_OPERATOR_ADD; + + /* Test if the target can composite spans. We're going to assume + * this is a good indicator of whether a similar surface is going + * to be able to composite spans too. */ + if ( !_cairo_surface_check_span_renderer (op, + &pattern.base, + target, + antialias, + NULL)) + { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto BAIL; + } + + /* We'll create a new surface the size of the intersection of the + * old mask surface and the extents of the new clip path. */ + { + cairo_rectangle_int_t target_rect; + + _cairo_path_fixed_approximate_extents (path, &surface_rect); + + if (clip->surface != NULL && + !_cairo_rectangle_intersect (&surface_rect, &clip->surface_rect)) + goto SUCCESS; + + status = _cairo_surface_get_extents (target, &target_rect); + if (status != CAIRO_STATUS_SUCCESS && + !_cairo_rectangle_intersect (&surface_rect, &target_rect)) + goto SUCCESS; + } + + /* Make the new mask surface and optionally initialise it from the + * previous clip if we have one. */ + surface = _cairo_surface_create_similar_solid (target, + CAIRO_CONTENT_ALPHA, + surface_rect.width, + surface_rect.height, + CAIRO_COLOR_TRANSPARENT); + if (surface->status) { + _cairo_pattern_fini (&pattern.base); + return surface->status; + } + + if (clip->surface) { + cairo_surface_pattern_t old_clip; + _cairo_pattern_init_for_surface (&old_clip, clip->surface); + status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, + &old_clip.base, + NULL, + surface, + surface_rect.x - clip->surface_rect.x, + surface_rect.y - clip->surface_rect.y, + 0, 0, + 0, 0, + surface_rect.width, + surface_rect.height); + _cairo_pattern_fini (&old_clip.base); + if (status) + goto BAIL; + } + + _cairo_composite_rectangles_init (&rects, + surface_rect.x, + surface_rect.y, + surface_rect.width, + surface_rect.height); + rects.dst.x = 0; + rects.dst.y = 0; + + /* Render the new clipping path into the new mask surface. We've + * chosen op to either combine the new clip path with the existing + * clip mask (if there is one) or just render it. */ + status =_cairo_path_fixed_fill_using_spans (op, &pattern.base, + path, surface, + fill_rule, tolerance, + antialias, &rects); + if (status) + goto BAIL; + + SUCCESS: + if (clip->surface != NULL) + cairo_surface_destroy (clip->surface); + clip->surface = surface; + clip->surface_rect = surface_rect; + clip->serial = _cairo_surface_allocate_clip_serial (target); + surface = NULL; + + if (surface_rect.width == 0 || surface_rect.height == 0) + _cairo_clip_set_all_clipped (clip, target); + + BAIL: + if (renderer) + renderer->destroy(renderer); + if (surface) + cairo_surface_destroy (surface); + _cairo_pattern_fini (&pattern.base); + return status; +} + cairo_status_t _cairo_clip_clip (cairo_clip_t *clip, cairo_path_fixed_t *path, @@ -564,6 +672,7 @@ _cairo_clip_clip (cairo_clip_t *clip, cairo_status_t status; cairo_rectangle_int_t rectangle; cairo_traps_t traps; + cairo_box_t ignored_box; if (clip->all_clipped) return CAIRO_STATUS_SUCCESS; @@ -583,6 +692,18 @@ _cairo_clip_clip (cairo_clip_t *clip, if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; + /* TODO: allow ANTIALIAS_NONE when we have a mono scan converter + * again. */ + if (antialias != CAIRO_ANTIALIAS_NONE && + !_cairo_path_fixed_is_box (path, &ignored_box) && + !_cairo_path_fixed_is_region (path)) + { + status = _cairo_clip_intersect_mask_using_spans ( + clip, path, fill_rule, tolerance, antialias, target); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + _cairo_traps_init (&traps); /* Limit the traps to the target surface @@ -599,7 +720,7 @@ _cairo_clip_clip (cairo_clip_t *clip, fill_rule, tolerance, &traps); - if (status) + if (unlikely (status)) goto bail; status = _cairo_clip_intersect_region (clip, &traps, target); @@ -682,7 +803,7 @@ _cairo_clip_init_deep_copy (cairo_clip_t *clip, } else { if (other->has_region) { status = _cairo_region_copy (&clip->region, &other->region); - if (status) + if (unlikely (status)) goto BAIL; clip->has_region = TRUE; @@ -697,7 +818,7 @@ _cairo_clip_init_deep_copy (cairo_clip_t *clip, other->surface_rect.height, &dx, &dy, &clip->surface); - if (status) + if (unlikely (status)) goto BAIL; clip->surface_rect = other->surface_rect; @@ -778,7 +899,7 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate) if (n_boxes) { rectangles = _cairo_malloc_ab (n_boxes, sizeof (cairo_rectangle_t)); - if (rectangles == NULL) { + if (unlikely (rectangles == NULL)) { _cairo_region_boxes_fini (&clip->region, boxes); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; @@ -808,7 +929,7 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate) n_boxes = 1; rectangles = malloc(sizeof (cairo_rectangle_t)); - if (rectangles == NULL) { + if (unlikely (rectangles == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; } @@ -824,7 +945,7 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate) DONE: list = malloc (sizeof (cairo_rectangle_list_t)); - if (list == NULL) { + if (unlikely (list == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); free (rectangles); return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; diff --git a/src/cairo-compiler-private.h b/src/cairo-compiler-private.h index b93fd829..44d9de30 100644 --- a/src/cairo-compiler-private.h +++ b/src/cairo-compiler-private.h @@ -139,6 +139,23 @@ #define cairo_const #endif +#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) +#define _CAIRO_BOOLEAN_EXPR(expr) \ + __extension__ ({ \ + int _cairo_boolean_var_; \ + if (expr) \ + _cairo_boolean_var_ = 1; \ + else \ + _cairo_boolean_var_ = 0; \ + _cairo_boolean_var_; \ +}) +#define likely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 1)) +#define unlikely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 0)) +#else +#define likely(expr) (expr) +#define unlikely(expr) (expr) +#endif + #ifndef __GNUC__ #undef __attribute__ #define __attribute__(x) diff --git a/src/cairo-debug.c b/src/cairo-debug.c index 61156f0d..6dd5787a 100644 --- a/src/cairo-debug.c +++ b/src/cairo-debug.c @@ -67,6 +67,8 @@ cairo_debug_reset_static_data (void) _cairo_ft_font_reset_static_data (); #endif + _cairo_intern_string_reset_static_data (); + _cairo_scaled_font_reset_static_data (); _cairo_pattern_reset_static_data (); diff --git a/src/cairo-deflate-stream.c b/src/cairo-deflate-stream.c index bf2784a2..863189f4 100644 --- a/src/cairo-deflate-stream.c +++ b/src/cairo-deflate-stream.c @@ -121,13 +121,14 @@ _cairo_deflate_stream_create (cairo_output_stream_t *output) return _cairo_output_stream_create_in_error (output->status); stream = malloc (sizeof (cairo_deflate_stream_t)); - if (stream == NULL) { + if (unlikely (stream == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_output_stream_t *) &_cairo_output_stream_nil; } _cairo_output_stream_init (&stream->base, _cairo_deflate_stream_write, + NULL, _cairo_deflate_stream_close); stream->output = output; diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c index 351e00d8..c31cf62c 100644 --- a/src/cairo-directfb-surface.c +++ b/src/cairo-directfb-surface.c @@ -455,7 +455,7 @@ _cairo_directfb_surface_create_similar (void *abstract_src, format = _cairo_format_from_content (content); surface = calloc (1, sizeof (cairo_directfb_surface_t)); - if (surface == NULL) + if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); surface->dfb = source->dfb; @@ -549,6 +549,7 @@ _cairo_directfb_surface_release_source_image (void *abstract_su cairo_image_surface_t *image, void *image_extra) { + cairo_directfb_surface_t *surface = abstract_surface; IDirectFBSurface *buffer = image_extra; D_DEBUG_AT (CairoDFB_Acquire, @@ -1305,12 +1306,14 @@ _cairo_directfb_surface_set_clip_region (void *abstract_surface, surface->has_clip = TRUE; + n_boxes = 0; status = _cairo_region_get_boxes (region, &n_boxes, &boxes); - if (n_boxes == 0) - return CAIRO_STATUS_SUCCESS; if (status) return status; + if (n_boxes == 0) + return CAIRO_STATUS_SUCCESS; + if (surface->n_clips != n_boxes) { if (surface->clips) free (surface->clips); @@ -1687,7 +1690,8 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs) + int *remaining_glyphs, + cairo_rectangle_int_t *extents) { cairo_directfb_surface_t *dst = abstract_dst; cairo_directfb_font_cache_t *cache; @@ -1812,6 +1816,8 @@ _cairo_directfb_surface_backend = { #else NULL,/*composite_trapezoids*/ #endif + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ _cairo_directfb_surface_set_clip_region,/* set_clip_region */ diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c index d8e662f1..5ac2cd2f 100644 --- a/src/cairo-font-face-twin.c +++ b/src/cairo-font-face-twin.c @@ -119,7 +119,8 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font, int n_snap_y; } info = {FALSE}; - cairo_set_line_width (cr, 0.06); + cairo_set_tolerance (cr, 0.01); + cairo_set_line_width (cr, 0.066); cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); diff --git a/src/cairo-font-face.c b/src/cairo-font-face.c index 6cea3958..a78c2aab 100644 --- a/src/cairo-font-face.c +++ b/src/cairo-font-face.c @@ -398,7 +398,7 @@ _cairo_toy_font_face_init (cairo_toy_font_face_t *font_face, char *family_copy; family_copy = strdup (family); - if (family_copy == NULL) + if (unlikely (family_copy == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_toy_font_face_init_key (font_face, family_copy, @@ -467,10 +467,12 @@ cairo_toy_font_face_create (const char *family, /* Make sure we've got valid UTF-8 for the family */ status = _cairo_utf8_to_ucs4 (family, -1, NULL, NULL); - if (status == CAIRO_STATUS_INVALID_STRING) - return (cairo_font_face_t*) &_cairo_font_face_invalid_string; - else if (status) + if (unlikely (status)) { + if (status == CAIRO_STATUS_INVALID_STRING) + return (cairo_font_face_t*) &_cairo_font_face_invalid_string; + return (cairo_font_face_t*) &_cairo_font_face_nil; + } switch (slant) { case CAIRO_FONT_SLANT_NORMAL: @@ -493,17 +495,16 @@ cairo_toy_font_face_create (const char *family, family = CAIRO_FONT_FAMILY_DEFAULT; hash_table = _cairo_toy_font_face_hash_table_lock (); - if (hash_table == NULL) + if (unlikely (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)) - { - if (! font_face->base.status) { + font_face = _cairo_hash_table_lookup (hash_table, + &key.base.hash_entry); + if (font_face != NULL) { + if (font_face->base.status == CAIRO_STATUS_SUCCESS) { /* We increment the reference count here manually to avoid double-locking. */ _cairo_reference_count_inc (&font_face->base.ref_count); @@ -512,23 +513,23 @@ cairo_toy_font_face_create (const char *family, } /* remove the bad font from the hash table */ - _cairo_hash_table_remove (hash_table, &key.base.hash_entry); + _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry); font_face->base.hash_entry.hash = 0; } /* Otherwise create it and insert into hash table. */ font_face = malloc (sizeof (cairo_toy_font_face_t)); - if (font_face == NULL) { + if (unlikely (font_face == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto UNWIND_HASH_TABLE_LOCK; } status = _cairo_toy_font_face_init (font_face, family, slant, weight); - if (status) + if (unlikely (status)) goto UNWIND_FONT_FACE_MALLOC; status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry); - if (status) + if (unlikely (status)) goto UNWIND_FONT_FACE_INIT; _cairo_toy_font_face_hash_table_unlock (); @@ -615,7 +616,7 @@ _cairo_toy_font_face_scaled_font_create (void *abstract_font_face return font_face->base.status; status = cairo_font_options_status ((cairo_font_options_t *) options); - if (status) + if (unlikely (status)) return status; if (CAIRO_SCALED_FONT_BACKEND_DEFAULT != &_cairo_user_scaled_font_backend && diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index cd112532..773f6ea0 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -182,7 +182,7 @@ _cairo_ft_unscaled_font_map_create (void) assert (cairo_ft_unscaled_font_map == NULL); font_map = malloc (sizeof (cairo_ft_unscaled_font_map_t)); - if (font_map == NULL) { + if (unlikely (font_map == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); goto FAIL; } @@ -190,7 +190,7 @@ _cairo_ft_unscaled_font_map_create (void) font_map->hash_table = _cairo_hash_table_create (_cairo_ft_unscaled_font_keys_equal); - if (font_map->hash_table == NULL) + if (unlikely (font_map->hash_table == NULL)) goto FAIL; if (FT_Init_FreeType (&font_map->ft_library)) @@ -261,7 +261,7 @@ _cairo_ft_unscaled_font_map_lock (void) { _cairo_ft_unscaled_font_map_create (); - if (cairo_ft_unscaled_font_map == NULL) { + if (unlikely (cairo_ft_unscaled_font_map == NULL)) { CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return NULL; @@ -340,8 +340,9 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, unscaled->face = NULL; filename_copy = strdup (filename); - if (filename_copy == NULL) + if (unlikely (filename_copy == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); + _cairo_ft_unscaled_font_init_key (unscaled, FALSE, filename_copy, id, NULL); } @@ -416,15 +417,15 @@ _cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face, cairo_status_t status; font_map = _cairo_ft_unscaled_font_map_lock (); - if (font_map == NULL) + if (unlikely (font_map == NULL)) goto UNWIND; _cairo_ft_unscaled_font_init_key (&key, from_face, filename, id, font_face); /* Return existing unscaled font if it exists in the hash table. */ - if (_cairo_hash_table_lookup (font_map->hash_table, &key.base.hash_entry, - (cairo_hash_entry_t **) &unscaled)) - { + unscaled = _cairo_hash_table_lookup (font_map->hash_table, + &key.base.hash_entry); + if (unscaled != NULL) { _cairo_unscaled_font_reference (&unscaled->base); _cairo_ft_unscaled_font_map_unlock (); return unscaled; @@ -432,18 +433,18 @@ _cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face, /* Otherwise create it and insert into hash table. */ unscaled = malloc (sizeof (cairo_ft_unscaled_font_t)); - if (unscaled == NULL) { + if (unlikely (unscaled == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); goto UNWIND_FONT_MAP_LOCK; } status = _cairo_ft_unscaled_font_init (unscaled, from_face, filename, id, font_face); - if (status) + if (unlikely (status)) goto UNWIND_UNSCALED_MALLOC; status = _cairo_hash_table_insert (font_map->hash_table, &unscaled->base.hash_entry); - if (status) + if (unlikely (status)) goto UNWIND_UNSCALED_FONT_INIT; _cairo_ft_unscaled_font_map_unlock (); @@ -621,7 +622,7 @@ _compute_transform (cairo_ft_font_transform_t *sf, status = _cairo_matrix_compute_basis_scale_factors (scale, &x_scale, &y_scale, 1); - if (status) + if (unlikely (status)) return status; /* FreeType docs say this about x_scale and y_scale: @@ -671,7 +672,7 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled, unscaled->current_scale = *scale; status = _compute_transform (&sf, scale); - if (status) + if (unlikely (status)) return status; unscaled->x_scale = sf.x_scale; @@ -874,7 +875,7 @@ _get_bitmap_surface (FT_Bitmap *bitmap, stride = bitmap->pitch; stride_rgba = (width_rgba * 4 + 3) & ~3; data_rgba = calloc (stride_rgba, height); - if (data_rgba == NULL) { + if (unlikely (data_rgba == NULL)) { if (own_buffer) free (bitmap->buffer); return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -1073,7 +1074,7 @@ _render_glyph_outline (FT_Face face, bitmap.width = width * hmul; bitmap.rows = height * vmul; bitmap.buffer = calloc (stride, bitmap.rows); - if (bitmap.buffer == NULL) + if (unlikely (bitmap.buffer == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); FT_Outline_Translate (outline, -cbox.xMin*hmul, -cbox.yMin*vmul); @@ -1084,7 +1085,7 @@ _render_glyph_outline (FT_Face face, } status = _get_bitmap_surface (&bitmap, TRUE, font_options, surface); - if (status) + if (unlikely (status)) return status; } @@ -1125,7 +1126,7 @@ _render_glyph_bitmap (FT_Face face, return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _get_bitmap_surface (&glyphslot->bitmap, FALSE, font_options, surface); - if (status) + if (unlikely (status)) return status; /* @@ -1212,13 +1213,13 @@ _transform_glyph_bitmap (cairo_matrix_t * shape, transformed_to_original = original_to_transformed; status = cairo_matrix_invert (&transformed_to_original); - if (status) + if (unlikely (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) + if (unlikely (image->status)) return image->status; /* Initialize it to empty @@ -1227,7 +1228,7 @@ _transform_glyph_bitmap (cairo_matrix_t * shape, CAIRO_COLOR_TRANSPARENT, 0, 0, width, height); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (image); return status; } @@ -1245,7 +1246,7 @@ _transform_glyph_bitmap (cairo_matrix_t * shape, _cairo_pattern_fini (&pattern.base); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (image); return status; } @@ -1512,7 +1513,7 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled, return _cairo_error (CAIRO_STATUS_NO_MEMORY); scaled_font = malloc (sizeof(cairo_ft_scaled_font_t)); - if (scaled_font == NULL) { + if (unlikely (scaled_font == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto FAIL; } @@ -1527,7 +1528,7 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled, font_face, font_matrix, ctm, options, &_cairo_ft_scaled_font_backend); - if (status) { + if (unlikely (status)) { _cairo_unscaled_font_destroy (&unscaled->base); free (scaled_font); goto FAIL; @@ -1535,7 +1536,7 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled, status = _cairo_ft_unscaled_font_set_scale (unscaled, &scaled_font->base.scale); - if (status) { + if (unlikely (status)) { _cairo_unscaled_font_destroy (&unscaled->base); free (scaled_font); goto FAIL; @@ -1626,7 +1627,7 @@ _cairo_ft_scaled_font_create_toy (cairo_toy_font_face_t *toy_face, cairo_matrix_multiply (&scale, font_matrix, ctm); status = _compute_transform (&sf, &scale); - if (status) + if (unlikely (status)) return status; pattern = FcPatternCreate (); @@ -1686,7 +1687,7 @@ _cairo_ft_scaled_font_create_toy (cairo_toy_font_face_t *toy_face, } status = _cairo_ft_font_options_substitute (font_options, pattern); - if (status) + if (unlikely (status)) goto FREE_PATTERN; FcDefaultSubstitute (pattern); @@ -1863,7 +1864,7 @@ _decompose_glyph_outline (FT_Face face, } status = _cairo_path_fixed_close_path (path); - if (status) { + if (unlikely (status)) { _cairo_path_fixed_destroy (path); return status; } @@ -1918,7 +1919,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, &scaled_font->base.scale); - if (status) + if (unlikely (status)) goto FAIL; /* Ignore global advance unconditionally */ @@ -2066,14 +2067,16 @@ _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 (likely (status == CAIRO_STATUS_SUCCESS) && + unscaled->have_shape) + { status = _transform_glyph_bitmap (&unscaled->current_shape, &surface); - if (status) + if (unlikely (status)) cairo_surface_destroy (&surface->base); } } - if (status) + if (unlikely (status)) goto FAIL; _cairo_scaled_glyph_set_surface (scaled_glyph, @@ -2115,7 +2118,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, else status = CAIRO_INT_STATUS_UNSUPPORTED; - if (status) + if (unlikely (status)) goto FAIL; _cairo_scaled_glyph_set_path (scaled_glyph, @@ -2530,7 +2533,7 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern) cairo_ft_options_t ft_options; unscaled = _cairo_ft_unscaled_font_create_for_pattern (pattern); - if (unscaled == NULL) { + if (unlikely (unscaled == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_font_face_t *)&_cairo_font_face_nil; } @@ -2597,7 +2600,7 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face, cairo_ft_options_t ft_options; unscaled = _cairo_ft_unscaled_font_create_from_face (face); - if (unscaled == NULL) { + if (unlikely (unscaled == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_font_face_t *)&_cairo_font_face_nil; } @@ -2658,14 +2661,14 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font) return NULL; face = _cairo_ft_unscaled_font_lock_face (scaled_font->unscaled); - if (face == NULL) { + if (unlikely (face == NULL)) { status = _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) { + if (unlikely (status)) { _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled); status = _cairo_scaled_font_set_error (&scaled_font->base, status); return NULL; @@ -2739,6 +2742,18 @@ _cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font) return FALSE; } +unsigned int +_cairo_ft_scaled_font_get_load_flags (cairo_scaled_font_t *scaled_font) +{ + cairo_ft_scaled_font_t *ft_scaled_font; + + if (! _cairo_scaled_font_is_ft (scaled_font)) + return 0; + + ft_scaled_font = (cairo_ft_scaled_font_t *) scaled_font; + return ft_scaled_font->ft_options.load_flags; +} + void _cairo_ft_font_reset_static_data (void) { diff --git a/src/cairo-ft-private.h b/src/cairo-ft-private.h index 3e7d3de0..00f7f77c 100644 --- a/src/cairo-ft-private.h +++ b/src/cairo-ft-private.h @@ -64,6 +64,9 @@ _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled); cairo_private cairo_bool_t _cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font); +cairo_private unsigned int +_cairo_ft_scaled_font_get_load_flags (cairo_scaled_font_t *scaled_font); + CAIRO_END_DECLS #endif /* CAIRO_HAS_FT_FONT */ diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index 5bdfa700..f049f401 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -33,8 +33,10 @@ typedef struct _cairo_glitz_surface { glitz_surface_t *surface; glitz_format_t *format; - cairo_bool_t has_clip; - cairo_region_t clip; + + cairo_bool_t has_clip; + glitz_box_t *clip_boxes; + int num_clip_boxes; } cairo_glitz_surface_t; static const cairo_surface_backend_t * @@ -45,10 +47,8 @@ _cairo_glitz_surface_finish (void *abstract_surface) { cairo_glitz_surface_t *surface = abstract_surface; - if (surface->has_clip) { - glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); - _cairo_region_fini (&surface->clip); - } + if (surface->clip_boxes) + free (surface->clip_boxes); glitz_surface_destroy (surface->surface); @@ -106,78 +106,40 @@ _cairo_glitz_surface_create_similar (void *abstract_src, return crsurface; } -static cairo_bool_t -_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format) -{ - switch (masks->bpp) { - case 32: - if (masks->alpha_mask == 0xff000000 && - masks->red_mask == 0x00ff0000 && - masks->green_mask == 0x0000ff00 && - masks->blue_mask == 0x000000ff) - { - *format = CAIRO_FORMAT_ARGB32; - return TRUE; - } - if (masks->alpha_mask == 0x00000000 && - masks->red_mask == 0x00ff0000 && - masks->green_mask == 0x0000ff00 && - masks->blue_mask == 0x000000ff) - { - *format = CAIRO_FORMAT_RGB24; - return TRUE; - } - break; - case 8: - if (masks->alpha_mask == 0xff) - { - *format = CAIRO_FORMAT_A8; - return TRUE; - } - break; - case 1: - if (masks->alpha_mask == 0x1) - { - *format = CAIRO_FORMAT_A1; - return TRUE; - } - break; - } - return FALSE; -} - static cairo_status_t -_cairo_glitz_get_boxes_from_region (cairo_region_t *region, glitz_box_t **boxes, int *nboxes) +_cairo_glitz_get_boxes_from_region (cairo_region_t *region, + glitz_box_t **boxes, + int *nboxes) { - cairo_box_int_t *cboxes; - cairo_status_t status; - int n, i; + pixman_box32_t *pboxes; + cairo_status_t status = CAIRO_STATUS_SUCCESS; - status = _cairo_region_get_boxes (region, &n, &cboxes); - if (status) - return status; + int n, i; + n = 0; + pboxes = pixman_region32_rectangles (®ion->rgn, &n); if (n == 0) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto done; + *nboxes = 0; + return CAIRO_STATUS_SUCCESS; } - *boxes = _cairo_malloc_ab (n, sizeof(glitz_box_t)); - if (*boxes == NULL) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto done; + if (n > *nboxes) { + *boxes = _cairo_malloc_ab (n, sizeof (glitz_box_t)); + if (*boxes == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto done; + } } for (i = 0; i < n; i++) { - (*boxes)[i].x1 = cboxes[i].p1.x; - (*boxes)[i].y1 = cboxes[i].p1.y; - (*boxes)[i].x2 = cboxes[i].p2.x; - (*boxes)[i].y2 = cboxes[i].p2.y; + (*boxes)[i].x1 = pboxes[i].x1; + (*boxes)[i].y1 = pboxes[i].y1; + (*boxes)[i].x2 = pboxes[i].x2; + (*boxes)[i].y2 = pboxes[i].y2; } *nboxes = n; done: - _cairo_region_boxes_fini (region, cboxes); return status; } @@ -188,94 +150,62 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, cairo_rectangle_int_t *rect_out) { cairo_image_surface_t *image; - int x1, y1, x2, y2; - int width, height; - unsigned char *pixels; + cairo_rectangle_int_t extents; + cairo_format_t format; cairo_format_masks_t masks; glitz_buffer_t *buffer; glitz_pixel_format_t pf; - cairo_format_t format; - x1 = 0; - y1 = 0; - x2 = glitz_surface_get_width (surface->surface); - y2 = glitz_surface_get_height (surface->surface); + extents.x = 0; + extents.y = 0; + extents.width = glitz_surface_get_width (surface->surface); + extents.height = glitz_surface_get_height (surface->surface); - if (interest) - { - if (interest->x > x1) - x1 = interest->x; - if (interest->y > y1) - y1 = interest->y; - if (interest->x + interest->width < x2) - x2 = interest->x + interest->width; - if (interest->y + interest->height < y2) - y2 = interest->y + interest->height; - - if (x1 >= x2 || y1 >= y2) - { + if (interest != NULL) { + if (! _cairo_rectangle_intersect (&extents, interest)) { *image_out = NULL; return CAIRO_STATUS_SUCCESS; } } - width = x2 - x1; - height = y2 - y1; - - if (rect_out) - { - rect_out->x = x1; - rect_out->y = y1; - rect_out->width = width; - rect_out->height = height; - } + if (rect_out != NULL) + *rect_out = extents; if (surface->format->color.fourcc == GLITZ_FOURCC_RGB) { if (surface->format->color.red_size > 0) { - masks.bpp = 32; - if (surface->format->color.alpha_size > 0) - masks.alpha_mask = 0xff000000; + format = CAIRO_FORMAT_ARGB32; else - masks.alpha_mask = 0x0; - - masks.red_mask = 0xff0000; - masks.green_mask = 0xff00; - masks.blue_mask = 0xff; + format = CAIRO_FORMAT_RGB24; } else { - masks.bpp = 8; - masks.blue_mask = masks.green_mask = masks.red_mask = 0x0; - masks.alpha_mask = 0xff; + format = CAIRO_FORMAT_A8; } - } else { - masks.bpp = 32; - masks.alpha_mask = 0xff000000; - masks.red_mask = 0xff0000; - masks.green_mask = 0xff00; - masks.blue_mask = 0xff; - } + } else + format = CAIRO_FORMAT_ARGB32; + + image = (cairo_image_surface_t*) + cairo_image_surface_create (format, extents.width, extents.height); + if (image->base.status) + return image->base.status; + _pixman_format_to_masks (image->pixman_format, &masks); pf.fourcc = GLITZ_FOURCC_RGB; pf.masks.bpp = masks.bpp; pf.masks.alpha_mask = masks.alpha_mask; - pf.masks.red_mask = masks.red_mask; + pf.masks.red_mask = masks.red_mask; pf.masks.green_mask = masks.green_mask; - pf.masks.blue_mask = masks.blue_mask; + pf.masks.blue_mask = masks.blue_mask; pf.xoffset = 0; pf.skip_lines = 0; /* XXX: we should eventually return images with negative stride, need to verify that libpixman have no problem with this first. */ - pf.bytes_per_line = (((width * masks.bpp) / 8) + 3) & -4; + pf.bytes_per_line = image->stride; pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; - pixels = _cairo_malloc_ab (height, pf.bytes_per_line); - if (!pixels) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - buffer = glitz_buffer_create_for_data (pixels); - if (!buffer) { - free (pixels); + buffer = glitz_buffer_create_for_data (image->data); + if (buffer == NULL) { + cairo_surface_destroy (&image->base); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -285,8 +215,8 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, 0, 0, NULL, 0); glitz_get_pixels (surface->surface, - x1, y1, - width, height, + extents.x, extents.y, + extents.width, extents.height, &pf, buffer); @@ -294,97 +224,15 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, /* restore the clip, if any */ if (surface->has_clip) { - glitz_box_t *box; - cairo_status_t status; - int n; - - status = _cairo_glitz_get_boxes_from_region (&surface->clip, &box, &n); - if (status) { - free (pixels); - return status; - } - - glitz_surface_set_clip_region (surface->surface, 0, 0, box, n); - - free (box); - } - - /* - * Prefer to use a standard pixman format instead of the - * general masks case. - */ - if (_CAIRO_MASK_FORMAT (&masks, &format)) { - image = (cairo_image_surface_t *) - cairo_image_surface_create_for_data (pixels, - format, - x2 - x1, - y2 - y1, - pf.bytes_per_line); - if (image->base.status) - goto FAIL; - } else { - /* - * XXX This can't work. We must convert the data to one of the - * supported pixman formats. Pixman needs another function - * which takes data in an arbitrary format and converts it - * to something supported by that library. - */ - image = (cairo_image_surface_t *) - _cairo_image_surface_create_with_masks (pixels, - &masks, - x2 - x1, - y2 - y1, - pf.bytes_per_line); - if (image->base.status) - goto FAIL; + glitz_surface_set_clip_region (surface->surface, + 0, 0, + surface->clip_boxes, + surface->num_clip_boxes); } - _cairo_image_surface_assume_ownership_of_data (image); - *image_out = image; return CAIRO_STATUS_SUCCESS; - -FAIL: - free (pixels); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); -} - -static void -cairo_format_get_masks (cairo_format_t format, - uint32_t *bpp, - uint32_t *alpha, - uint32_t *red, - uint32_t *green, - uint32_t *blue) -{ - *red = 0x0; - *green = 0x0; - *blue = 0x0; - *alpha = 0x0; - - switch (format) - { - case CAIRO_FORMAT_ARGB32: - *alpha = 0xff000000; - case CAIRO_FORMAT_RGB24: - default: - *bpp = 32; - *red = 0x00ff0000; - *green = 0x0000ff00; - *blue = 0x000000ff; - break; - - case CAIRO_FORMAT_A8: - *bpp = 8; - *alpha = 0xff; - break; - - case CAIRO_FORMAT_A1: - *bpp = 1; - *alpha = 0x1; - break; - } } static cairo_status_t @@ -400,36 +248,33 @@ _cairo_glitz_surface_set_image (void *abstract_surface, cairo_glitz_surface_t *surface = abstract_surface; glitz_buffer_t *buffer; glitz_pixel_format_t pf; - uint32_t bpp, am, rm, gm, bm; + cairo_format_masks_t masks; char *data; - cairo_format_get_masks (image->format, &bpp, &am, &rm, &gm, &bm); + _pixman_format_to_masks (image->pixman_format, &masks); pf.fourcc = GLITZ_FOURCC_RGB; - pf.masks.bpp = bpp; - pf.masks.alpha_mask = am; - pf.masks.red_mask = rm; - pf.masks.green_mask = gm; - pf.masks.blue_mask = bm; + pf.masks.bpp = masks.bpp; + pf.masks.alpha_mask = masks.alpha_mask; + pf.masks.red_mask = masks.red_mask; + pf.masks.green_mask = masks.green_mask; + pf.masks.blue_mask = masks.blue_mask; pf.xoffset = src_x; pf.skip_lines = src_y; /* check for negative stride */ - if (image->stride < 0) - { + if (image->stride < 0) { pf.bytes_per_line = -image->stride; pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP; data = (char *) image->data + image->stride * (image->height - 1); - } - else - { + } else { pf.bytes_per_line = image->stride; pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; data = (char *) image->data; } buffer = glitz_buffer_create_for_data (data); - if (!buffer) + if (buffer == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); glitz_set_pixels (surface->surface, @@ -533,43 +378,27 @@ _cairo_glitz_surface_clone_similar (void *abstract_surface, else if (_cairo_surface_is_image (src)) { cairo_image_surface_t *image_src = (cairo_image_surface_t *) src; - cairo_content_t content; - cairo_rectangle_int_t image_extent; - cairo_rectangle_int_t extent; - - content = _cairo_content_from_format (image_src->format); clone = (cairo_glitz_surface_t *) - _cairo_glitz_surface_create_similar (surface, content, - image_src->width, - image_src->height); + _cairo_glitz_surface_create_similar (surface, src->content, + width, height); if (clone == NULL) return CAIRO_INT_STATUS_UNSUPPORTED; if (clone->base.status) return clone->base.status; - image_extent.x = 0; - image_extent.y = 0; - image_extent.width = image_src->width; - image_extent.height = image_src->height; - extent.x = src_x; - extent.y = src_y; - extent.width = width; - extent.height = height; - - _cairo_rectangle_intersect(&extent, &image_extent); - status = _cairo_glitz_surface_set_image (clone, image_src, - extent.x, extent.y, - extent.width, extent.height, - extent.x, extent.y); + src_x, src_y, + width, height, + 0, 0); if (status) { cairo_surface_destroy (&clone->base); return status; } *clone_out = &clone->base; - + *clone_offset_x = src_x; + *clone_offset_y = src_y; return CAIRO_STATUS_SUCCESS; } @@ -582,17 +411,17 @@ _cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface, { glitz_transform_t transform; - transform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx); - transform.matrix[0][1] = _cairo_fixed_from_double (matrix->xy); - transform.matrix[0][2] = _cairo_fixed_from_double (matrix->x0); + transform.matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx); + transform.matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy); + transform.matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0); - transform.matrix[1][0] = _cairo_fixed_from_double (matrix->yx); - transform.matrix[1][1] = _cairo_fixed_from_double (matrix->yy); - transform.matrix[1][2] = _cairo_fixed_from_double (matrix->y0); + transform.matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx); + transform.matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy); + transform.matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0); transform.matrix[2][0] = 0; transform.matrix[2][1] = 0; - transform.matrix[2][2] = _cairo_fixed_from_double (1); + transform.matrix[2][2] = _cairo_fixed_16_16_from_double (1); glitz_surface_set_transform (surface->surface, &transform); } @@ -836,22 +665,22 @@ _cairo_glitz_pattern_acquire_surface (const cairo_pattern_t *pattern, { cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern; - params[0] = grad->p1.x; - params[1] = grad->p1.y; - params[2] = grad->p2.x; - params[3] = grad->p2.y; + params[0] = _cairo_fixed_to_16_16 (grad->p1.x); + params[1] = _cairo_fixed_to_16_16 (grad->p1.y); + params[2] = _cairo_fixed_to_16_16 (grad->p2.x); + params[3] = _cairo_fixed_to_16_16 (grad->p2.y); attr->filter = GLITZ_FILTER_LINEAR_GRADIENT; } else { cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern; - params[0] = grad->c1.x; - params[1] = grad->c1.y; - params[2] = grad->r1; - params[3] = grad->c2.x; - params[4] = grad->c2.y; - params[5] = grad->r2; + params[0] = _cairo_fixed_to_16_16 (grad->c1.x); + params[1] = _cairo_fixed_to_16_16 (grad->c1.y); + params[2] = _cairo_fixed_to_16_16 (grad->r1); + params[3] = _cairo_fixed_to_16_16 (grad->c2.x); + params[4] = _cairo_fixed_to_16_16 (grad->c2.y); + params[5] = _cairo_fixed_to_16_16 (grad->r2); attr->filter = GLITZ_FILTER_RADIAL_GRADIENT; } @@ -1081,11 +910,6 @@ _cairo_glitz_surface_composite (cairo_operator_t op, mask_y + mask_attr.base.y_offset, dst_x, dst_y, width, height); - - if (mask_attr.n_params) - free (mask_attr.params); - - _cairo_glitz_pattern_release_surface (mask_pattern, mask, &mask_attr); } else { @@ -1100,14 +924,50 @@ _cairo_glitz_surface_composite (cairo_operator_t op, width, height); } + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) + status = CAIRO_INT_STATUS_UNSUPPORTED; + + if (status == CAIRO_STATUS_SUCCESS && + ! _cairo_operator_bounded_by_source (op)) + { + int src_width, src_height; + int mask_width, mask_height; + + src_width = glitz_surface_get_width (src->surface); + src_height = glitz_surface_get_height (src->surface); + if (mask) + { + mask_width = glitz_surface_get_width (mask->surface); + mask_height = glitz_surface_get_height (mask->surface); + } + else + { + mask_width = 0; + mask_height = 0; + } + status = _cairo_surface_composite_fixup_unbounded (&dst->base, + &src_attr.base, + src_width, src_height, + mask ? &mask_attr.base : NULL, + mask_width, mask_height, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, width, height); + } + + if (mask) + { + if (mask_attr.n_params) + free (mask_attr.params); + + _cairo_glitz_pattern_release_surface (mask_pattern, mask, &mask_attr); + } + if (src_attr.n_params) free (src_attr.params); _cairo_glitz_pattern_release_surface (src_pattern, src, &src_attr); - if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; - return CAIRO_STATUS_SUCCESS; } @@ -1120,24 +980,47 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, { cairo_glitz_surface_t *dst = abstract_dst; cairo_glitz_surface_t *src; + glitz_rectangle_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (glitz_rectangle_t)]; + glitz_rectangle_t *glitz_rects = stack_rects; + glitz_rectangle_t *current_rect; + int i; + + if (n_rects > ARRAY_LENGTH (stack_rects)) { + glitz_rects = _cairo_malloc_ab (n_rects, sizeof (glitz_rectangle_t)); + if (glitz_rects == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + for (i = 0; i < n_rects; i++) { + glitz_rects[i].x = rects[i].x; + glitz_rects[i].y = rects[i].y; + glitz_rects[i].width = rects[i].width; + glitz_rects[i].height = rects[i].height; + } switch (op) { + case CAIRO_OPERATOR_CLEAR: case CAIRO_OPERATOR_SOURCE: { glitz_color_t glitz_color; + glitz_format_t *format; glitz_color.red = color->red_short; glitz_color.green = color->green_short; glitz_color.blue = color->blue_short; glitz_color.alpha = color->alpha_short; - glitz_set_rectangles (dst->surface, &glitz_color, - (glitz_rectangle_t *) rects, n_rects); - } break; - case CAIRO_OPERATOR_CLEAR: { - static const glitz_color_t glitz_color = { 0, 0, 0, 0 }; + /* + * XXX even if the dst surface don't have an alpha channel, the + * above alpha still effect the dst surface because the + * underlying glitz drawable may have an alpha channel. So + * replacing the color with an opaque one is needed. + */ + format = glitz_surface_get_format (dst->surface); + if (format->color.alpha_size == 0) + glitz_color.alpha = 0xffff; - glitz_set_rectangles (dst->surface, &glitz_color, - (glitz_rectangle_t *) rects, n_rects); + glitz_set_rectangles (dst->surface, &glitz_color, + glitz_rects, n_rects); } break; case CAIRO_OPERATOR_SATURATE: return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1154,7 +1037,11 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, case CAIRO_OPERATOR_ADD: default: if (_glitz_ensure_target (dst->surface)) + { + if (glitz_rects != stack_rects) + free (glitz_rects); return CAIRO_INT_STATUS_UNSUPPORTED; + } src = (cairo_glitz_surface_t *) _cairo_surface_create_similar_solid (&dst->base, @@ -1162,10 +1049,15 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, 1, 1, (cairo_color_t *) color); if (src->base.status) + { + if (glitz_rects != stack_rects) + free (glitz_rects); return src->base.status; + } glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT); + current_rect = glitz_rects; while (n_rects--) { glitz_composite (_glitz_operator (op), @@ -1174,15 +1066,18 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, dst->surface, 0, 0, 0, 0, - rects->x, rects->y, - rects->width, rects->height); - rects++; + current_rect->x, current_rect->y, + current_rect->width, current_rect->height); + current_rect++; } cairo_surface_destroy (&src->base); break; } + if (glitz_rects != stack_rects) + free (glitz_rects); + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1203,8 +1098,6 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, cairo_trapezoid_t *traps, int n_traps) { - cairo_pattern_union_t tmp_src_pattern; - const cairo_pattern_t *src_pattern; cairo_glitz_surface_attributes_t attributes; cairo_glitz_surface_t *dst = abstract_dst; cairo_glitz_surface_t *src; @@ -1213,13 +1106,15 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, void *data = NULL; cairo_int_status_t status; unsigned short alpha; + pixman_trapezoid_t stack_traps[CAIRO_STACK_ARRAY_LENGTH (pixman_trapezoid_t)]; + pixman_trapezoid_t *pixman_traps = stack_traps; + int i; if (antialias != CAIRO_ANTIALIAS_DEFAULT && antialias != CAIRO_ANTIALIAS_GRAY) + { return CAIRO_INT_STATUS_UNSUPPORTED; - - if (dst->base.status) - return dst->base.status; + } if (op == CAIRO_OPERATOR_SATURATE) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1227,34 +1122,36 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, if (_glitz_ensure_target (dst->surface)) return CAIRO_INT_STATUS_UNSUPPORTED; - if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) - { - 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, - src_x, src_y, - width, height, - &src, &attributes); - src_pattern = &tmp_src_pattern.base; + /* Convert traps to pixman traps */ + if (n_traps > ARRAY_LENGTH (stack_traps)) { + pixman_traps = _cairo_malloc_ab (n_traps, sizeof (pixman_trapezoid_t)); + if (pixman_traps == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); } - else - { - status = _cairo_glitz_pattern_acquire_surface (pattern, dst, - src_x, src_y, - width, height, - &src, &attributes); - src_pattern = pattern; + + for (i = 0; i < n_traps; i++) { + pixman_traps[i].top = _cairo_fixed_to_16_16 (traps[i].top); + pixman_traps[i].bottom = _cairo_fixed_to_16_16 (traps[i].bottom); + pixman_traps[i].left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x); + pixman_traps[i].left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y); + pixman_traps[i].left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x); + pixman_traps[i].left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y); + pixman_traps[i].right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x); + pixman_traps[i].right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y); + pixman_traps[i].right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x); + pixman_traps[i].right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y); } - alpha = 0xffff; + status = _cairo_glitz_pattern_acquire_surface (pattern, dst, + src_x, src_y, + width, height, + &src, &attributes); if (status) - return status; + goto FAIL; - if (op == CAIRO_OPERATOR_ADD || n_traps <= 1) - { + alpha = 0xffff; + + if (op == CAIRO_OPERATOR_ADD || n_traps <= 1) { static const glitz_color_t clear_black = { 0, 0, 0, 0 }; glitz_color_t color; glitz_geometry_format_t format; @@ -1276,17 +1173,12 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, CAIRO_CONTENT_ALPHA, 2, 1); if (mask == NULL) { - _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); - if (src_pattern == &tmp_src_pattern.base) - _cairo_pattern_fini (&tmp_src_pattern.base); - return CAIRO_INT_STATUS_UNSUPPORTED; + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto FAIL; } if (mask->base.status) { - _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); - if (src_pattern == &tmp_src_pattern.base) - _cairo_pattern_fini (&tmp_src_pattern.base); - - return mask->base.status; + status = mask->base.status; + goto FAIL; } color.red = color.green = color.blue = color.alpha = 0xffff; @@ -1301,20 +1193,15 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, size *= format.vertex.bytes_per_vertex; - while (n_traps) - { - if (data_size < size) - { + while (n_traps) { + if (data_size < size) { void *p; + data_size = size; p = realloc (data, data_size); - if (!p) - { - _cairo_glitz_pattern_release_surface (src_pattern, src, - &attributes); - if (src_pattern == &tmp_src_pattern.base) - _cairo_pattern_fini (&tmp_src_pattern.base); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (p == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto FAIL; } data = p; @@ -1322,13 +1209,10 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, glitz_buffer_destroy (buffer); buffer = glitz_buffer_create_for_data (data); - if (!buffer) { + if (buffer == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); free (data); - _cairo_glitz_pattern_release_surface (src_pattern, src, - &attributes); - if (src_pattern == &tmp_src_pattern.base) - _cairo_pattern_fini (&tmp_src_pattern.base); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto FAIL; } } @@ -1336,7 +1220,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, glitz_add_trapezoids (buffer, offset, size - offset, format.vertex.type, mask->surface, - (glitz_trapezoid_t *) traps, n_traps, + (glitz_trapezoid_t *) pixman_traps, n_traps, &n_trap_added); n_traps -= n_trap_added; @@ -1350,21 +1234,16 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, glitz_set_array (dst->surface, 0, 3, offset / format.vertex.bytes_per_vertex, 0, 0); - } - else - { + } else { cairo_image_surface_t *image; unsigned char *ptr; int stride; stride = (width + 3) & -4; data = calloc (stride, height); - if (!data) - { - _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); - if (src_pattern == &tmp_src_pattern.base) - _cairo_pattern_fini (&tmp_src_pattern.base); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (data == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto FAIL; } /* using negative stride */ @@ -1375,34 +1254,33 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, CAIRO_FORMAT_A8, width, height, -stride); - if (image->base.status) - { - cairo_surface_destroy (&src->base); + status = image->base.status; + if (status) { free (data); - return image->base.status; + goto FAIL; } pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y, - n_traps, (pixman_trapezoid_t *) traps); + n_traps, (pixman_trapezoid_t *) pixman_traps); mask = (cairo_glitz_surface_t *) _cairo_surface_create_similar_scratch (&dst->base, CAIRO_CONTENT_ALPHA, width, height); - if (mask->base.status) { - _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); + status = mask->base.status; + if (status) { free (data); cairo_surface_destroy (&image->base); - return mask->base.status; + goto FAIL; } status = _cairo_glitz_surface_set_image (mask, image, 0, 0, width, height, 0, 0); - cairo_surface_destroy(&image->base); + cairo_surface_destroy (&image->base); if (status) - return status; + goto FAIL; } _cairo_glitz_surface_set_attributes (src, &attributes); @@ -1429,17 +1307,33 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, free (data); - _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); - if (src_pattern == &tmp_src_pattern.base) - _cairo_pattern_fini (&tmp_src_pattern.base); + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto FAIL; + } - if (mask) + if (! _cairo_operator_bounded_by_mask (op)) { + status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base, + &attributes.base, + glitz_surface_get_width (src->surface), + glitz_surface_get_height (src->surface), + width, height, + src_x, src_y, + 0, 0, + dst_x, dst_y, + width, height); + } + +FAIL: + _cairo_glitz_pattern_release_surface (pattern, src, &attributes); + + if (mask != NULL) cairo_surface_destroy (&mask->base); - if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (pixman_traps != stack_traps) + free (pixman_traps); - return CAIRO_STATUS_SUCCESS; + return status; } static cairo_int_status_t @@ -1448,43 +1342,23 @@ _cairo_glitz_surface_set_clip_region (void *abstract_surface, { cairo_glitz_surface_t *surface = abstract_surface; - if (region) - { - glitz_box_t *box; - int n; + if (region != NULL) { cairo_status_t status; - if (!surface->has_clip) { - _cairo_region_init (&surface->clip); - surface->has_clip = TRUE; - } - - status = _cairo_region_copy (&surface->clip, region); - if (status) { - _cairo_region_fini (&surface->clip); - surface->has_clip = FALSE; - return status; - } - - status = _cairo_glitz_get_boxes_from_region (&surface->clip, &box, &n); - if (status) { - _cairo_region_fini (&surface->clip); - surface->has_clip = FALSE; + status = _cairo_glitz_get_boxes_from_region (region, + &surface->clip_boxes, + &surface->num_clip_boxes); + if (status) return status; - } - - glitz_surface_set_clip_region (surface->surface, 0, 0, box, n); - free (box); - } - else - { + glitz_surface_set_clip_region (surface->surface, + 0, 0, + surface->clip_boxes, + surface->num_clip_boxes); + surface->has_clip = TRUE; + } else { glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); - - if (surface->has_clip) { - _cairo_region_fini (&surface->clip); - surface->has_clip = FALSE; - } + surface->has_clip = FALSE; } return CAIRO_STATUS_SUCCESS; @@ -1498,7 +1372,7 @@ _cairo_glitz_surface_get_extents (void *abstract_surface, rectangle->x = 0; rectangle->y = 0; - rectangle->width = glitz_surface_get_width (surface->surface); + rectangle->width = glitz_surface_get_width (surface->surface); rectangle->height = glitz_surface_get_height (surface->surface); return CAIRO_STATUS_SUCCESS; @@ -1996,7 +1870,7 @@ _cairo_glitz_surface_add_glyph (cairo_glitz_surface_t *surface, glitz_point_fixed_t p1, p2; glitz_pixel_format_t pf; glitz_buffer_t *buffer; - unsigned int bpp, am, rm, gm, bm; + cairo_format_masks_t masks; cairo_int_status_t status; glyph_private = scaled_glyph->surface_private; @@ -2051,14 +1925,14 @@ _cairo_glitz_surface_add_glyph (cairo_glitz_surface_t *surface, return _cairo_error (CAIRO_STATUS_NO_MEMORY); } - cairo_format_get_masks (glyph_surface->format, &bpp, &am, &rm, &gm, &bm); + _pixman_format_to_masks (glyph_surface->pixman_format, &masks); pf.fourcc = GLITZ_FOURCC_RGB; - pf.masks.bpp = bpp; - pf.masks.alpha_mask = am; - pf.masks.red_mask = rm; - pf.masks.green_mask = gm; - pf.masks.blue_mask = bm; + pf.masks.bpp = masks.bpp; + pf.masks.alpha_mask = masks.alpha_mask; + pf.masks.red_mask = masks.red_mask; + pf.masks.green_mask = masks.green_mask; + pf.masks.blue_mask = masks.blue_mask; pf.bytes_per_line = glyph_surface->stride; pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP; @@ -2140,6 +2014,10 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, if (op == CAIRO_OPERATOR_SATURATE) return CAIRO_INT_STATUS_UNSUPPORTED; + /* XXX Unbounded operators are not handled correctly */ + if (! _cairo_operator_bounded_by_mask (op)) + return CAIRO_INT_STATUS_UNSUPPORTED; + if (_glitz_ensure_target (dst->surface)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -2415,6 +2293,8 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = { _cairo_glitz_surface_composite, _cairo_glitz_surface_fill_rectangles, _cairo_glitz_surface_composite_trapezoids, + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ _cairo_glitz_surface_set_clip_region, @@ -2476,14 +2356,17 @@ cairo_glitz_surface_create (glitz_surface_t *surface) format = glitz_surface_get_format (surface); _cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend, - _glitz_format_to_content(format)); + _glitz_format_to_content (format)); glitz_surface_reference (surface); crsurface->surface = surface; crsurface->format = format; - crsurface->has_clip = FALSE; - return (cairo_surface_t *) crsurface; + crsurface->has_clip = FALSE; + crsurface->clip_boxes = NULL; + crsurface->num_clip_boxes = 0; + + return &crsurface->base; } slim_hidden_def (cairo_glitz_surface_create); diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 75e1a63f..4cf3c87a 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -113,11 +113,11 @@ _cairo_gstate_init (cairo_gstate_t *gstate, return _cairo_error (CAIRO_STATUS_NULL_POINTER); status = target->status; - if (status) + if (unlikely (status)) return status; status = gstate->source->status; - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -142,7 +142,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) status = _cairo_stroke_style_init_copy (&gstate->stroke_style, &other->stroke_style); - if (status) + if (unlikely (status)) return status; gstate->fill_rule = other->fill_rule; @@ -155,7 +155,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) _cairo_font_options_init_copy (&gstate->font_options , &other->font_options); status = _cairo_clip_init_copy (&gstate->clip, &other->clip); - if (status) { + if (unlikely (status)) { _cairo_stroke_style_fini (&gstate->stroke_style); cairo_font_face_destroy (gstate->font_face); cairo_scaled_font_destroy (gstate->scaled_font); @@ -221,13 +221,13 @@ _cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist) top = *freelist; if (top == NULL) { top = malloc (sizeof (cairo_gstate_t)); - if (top == NULL) + if (unlikely (top == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } else *freelist = top->next; status = _cairo_gstate_init_copy (top, *gstate); - if (status) { + if (unlikely (status)) { top->next = *freelist; *freelist = top; return status; @@ -297,7 +297,7 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child) _cairo_clip_reset (&gstate->clip); status = _cairo_clip_init_deep_copy (&gstate->clip, &gstate->next->clip, child); - if (status) + if (unlikely (status)) return status; /* The clip is in surface backend coordinates for the previous target; @@ -512,7 +512,7 @@ _cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dash } gstate->stroke_style.dash = _cairo_malloc_ab (gstate->stroke_style.num_dashes, sizeof (double)); - if (gstate->stroke_style.dash == NULL) { + if (unlikely (gstate->stroke_style.dash == NULL)) { gstate->stroke_style.num_dashes = 0; return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -668,7 +668,7 @@ _cairo_gstate_transform (cairo_gstate_t *gstate, tmp = *matrix; status = cairo_matrix_invert (&tmp); - if (status) + if (unlikely (status)) return status; _cairo_gstate_unset_scaled_font (gstate); @@ -783,20 +783,17 @@ _cairo_gstate_stroke_to_path (cairo_gstate_t *gstate) } */ -cairo_status_t +void _cairo_gstate_path_extents (cairo_gstate_t *gstate, cairo_path_fixed_t *path, double *x1, double *y1, double *x2, double *y2) { - cairo_status_t status; double px1, py1, px2, py2; - status = _cairo_path_fixed_bounds (path, - &px1, &py1, &px2, &py2, - gstate->tolerance); - if (status) - return status; + _cairo_path_fixed_bounds (path, + &px1, &py1, &px2, &py2, + gstate->tolerance); _cairo_gstate_backend_to_user_rectangle (gstate, &px1, &py1, &px2, &py2, @@ -809,8 +806,6 @@ _cairo_gstate_path_extents (cairo_gstate_t *gstate, *x2 = px2; if (y2) *y2 = py2; - - return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -832,7 +827,7 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate, if (_cairo_surface_has_device_transform (surface)) { status = _cairo_pattern_init_copy (*pattern, original); - if (status) + if (unlikely (status)) return status; have_copy = TRUE; @@ -844,7 +839,7 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate, if (! _cairo_matrix_is_identity (ctm_inverse)) { if (! have_copy) { status = _cairo_pattern_init_copy (*pattern, original); - if (status) + if (unlikely (status)) return status; have_copy = TRUE; @@ -889,17 +884,17 @@ _cairo_gstate_paint (cairo_gstate_t *gstate) return gstate->source->status; status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (status) + if (unlikely (status)) return status; pattern = &pattern_stack.base; status = _cairo_gstate_copy_transformed_source (gstate, &pattern); - if (status) + if (unlikely (status)) return status; status = _cairo_surface_paint (gstate->target, gstate->op, - pattern); + pattern, NULL); if (pattern == &pattern_stack.base) _cairo_pattern_fini (pattern); @@ -922,23 +917,23 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, return gstate->source->status; status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (status) + if (unlikely (status)) return status; source_pattern = &source_pattern_stack.base; status = _cairo_gstate_copy_transformed_source (gstate, &source_pattern); - if (status) + if (unlikely (status)) return status; mask_pattern = &mask_pattern_stack.base; status = _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern, mask); - if (status) + if (unlikely (status)) goto CLEANUP_SOURCE; status = _cairo_surface_mask (gstate->target, gstate->op, source_pattern, - mask_pattern); + mask_pattern, NULL); if (mask_pattern == &mask_pattern_stack.base) _cairo_pattern_fini (&mask_pattern_stack.base); @@ -963,13 +958,13 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) return CAIRO_STATUS_SUCCESS; status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (status) + if (unlikely (status)) return status; source_pattern = &source_pattern_stack.base; status = _cairo_gstate_copy_transformed_source (gstate, &source_pattern); - if (status) + if (unlikely (status)) return status; status = _cairo_surface_stroke (gstate->target, @@ -980,7 +975,7 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) &gstate->ctm, &gstate->ctm_inverse, gstate->tolerance, - gstate->antialias); + gstate->antialias, NULL); if (source_pattern == &source_pattern_stack.base) _cairo_pattern_fini (&source_pattern_stack.base); @@ -1020,7 +1015,7 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate, &gstate->ctm_inverse, gstate->tolerance, &traps); - if (status) + if (unlikely (status)) goto BAIL; *inside_ret = _cairo_traps_contain (&traps, x, y); @@ -1042,12 +1037,12 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) return gstate->source->status; status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (status) + if (unlikely (status)) return status; pattern = &pattern_stack.base; status = _cairo_gstate_copy_transformed_source (gstate, &pattern); - if (status) + if (unlikely (status)) return status; status = _cairo_surface_fill (gstate->target, @@ -1056,7 +1051,8 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) path, gstate->fill_rule, gstate->tolerance, - gstate->antialias); + gstate->antialias, + NULL); if (pattern == &pattern_stack.base) _cairo_pattern_fini (&pattern_stack.base); @@ -1064,40 +1060,20 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) return status; } -cairo_status_t +void _cairo_gstate_in_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path, double x, double y, cairo_bool_t *inside_ret) { - cairo_status_t status; - cairo_box_t limit; - cairo_traps_t traps; - _cairo_gstate_user_to_backend (gstate, &x, &y); - limit.p1.x = _cairo_fixed_from_double (x) - 1; - limit.p1.y = _cairo_fixed_from_double (y) - 1; - limit.p2.x = limit.p1.x + 2; - limit.p2.y = limit.p1.y + 2; - - _cairo_traps_init (&traps); - _cairo_traps_limit (&traps, &limit); - - status = _cairo_path_fixed_fill_to_traps (path, - gstate->fill_rule, - gstate->tolerance, - &traps); - if (status) - goto BAIL; - - *inside_ret = _cairo_traps_contain (&traps, x, y); - -BAIL: - _cairo_traps_fini (&traps); - - return status; + _cairo_path_fixed_in_fill (path, + gstate->fill_rule, + gstate->tolerance, + x, y, + inside_ret); } cairo_status_t @@ -1347,7 +1323,7 @@ _cairo_gstate_int_clip_extents (cairo_gstate_t *gstate, cairo_status_t status; status = _cairo_surface_get_extents (gstate->target, extents); - if (status) + if (unlikely (status)) return status; status = _cairo_clip_intersect_to_rectangle (&gstate->clip, extents); @@ -1367,7 +1343,7 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate, cairo_status_t status; status = _cairo_gstate_int_clip_extents (gstate, &extents); - if (status) + if (unlikely (status)) return status; px1 = extents.x; @@ -1486,7 +1462,7 @@ _cairo_gstate_get_font_face (cairo_gstate_t *gstate, cairo_status_t status; status = _cairo_gstate_ensure_font_face (gstate); - if (status) + if (unlikely (status)) return status; *font_face = gstate->font_face; @@ -1501,7 +1477,7 @@ _cairo_gstate_get_scaled_font (cairo_gstate_t *gstate, cairo_status_t status; status = _cairo_gstate_ensure_scaled_font (gstate); - if (status) + if (unlikely (status)) return status; *scaled_font = gstate->scaled_font; @@ -1617,7 +1593,7 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate) return gstate->scaled_font->status; status = _cairo_gstate_ensure_font_face (gstate); - if (status) + if (unlikely (status)) return status; cairo_surface_get_font_options (gstate->target, &options); @@ -1629,7 +1605,7 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate) &options); status = cairo_scaled_font_status (scaled_font); - if (status) + if (unlikely (status)) return status; gstate->scaled_font = scaled_font; @@ -1642,7 +1618,7 @@ _cairo_gstate_get_font_extents (cairo_gstate_t *gstate, cairo_font_extents_t *extents) { cairo_status_t status = _cairo_gstate_ensure_scaled_font (gstate); - if (status) + if (unlikely (status)) return status; cairo_scaled_font_extents (gstate->scaled_font, extents); @@ -1665,7 +1641,7 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, cairo_status_t status; status = _cairo_gstate_ensure_scaled_font (gstate); - if (status) + if (unlikely (status)) return status; return cairo_scaled_font_text_to_glyphs (gstate->scaled_font, x, y, @@ -1702,7 +1678,7 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate, cairo_status_t status; status = _cairo_gstate_ensure_scaled_font (gstate); - if (status) + if (unlikely (status)) return status; cairo_scaled_font_glyph_extents (gstate->scaled_font, @@ -1732,18 +1708,18 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, return gstate->source->status; status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (status) + if (unlikely (status)) return status; status = _cairo_gstate_ensure_scaled_font (gstate); - if (status) + if (unlikely (status)) return status; if (num_glyphs <= ARRAY_LENGTH (stack_transformed_glyphs)) { transformed_glyphs = stack_transformed_glyphs; } else { transformed_glyphs = cairo_glyph_allocate (num_glyphs); - if (transformed_glyphs == NULL) + if (unlikely (transformed_glyphs == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -1757,7 +1733,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, source_pattern = &source_pattern_stack.base; status = _cairo_gstate_copy_transformed_source (gstate, &source_pattern); - if (status) + if (unlikely (status)) goto CLEANUP_GLYPHS; /* Just in case */ @@ -1783,7 +1759,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, transformed_glyphs, num_glyphs, clusters, num_clusters, cluster_flags, - gstate->scaled_font); + gstate->scaled_font, NULL); } else { cairo_path_fixed_t path; @@ -1800,7 +1776,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, &path, CAIRO_FILL_RULE_WINDING, gstate->tolerance, - gstate->scaled_font->options.antialias); + gstate->scaled_font->options.antialias, NULL); _cairo_path_fixed_fini (&path); } @@ -1826,21 +1802,22 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)]; status = _cairo_gstate_ensure_scaled_font (gstate); - if (status) + if (unlikely (status)) return status; - if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs)) + if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs)) { transformed_glyphs = stack_transformed_glyphs; - else - transformed_glyphs = cairo_glyph_allocate (num_glyphs); - if (transformed_glyphs == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else { + transformed_glyphs = cairo_glyph_allocate (num_glyphs); + if (unlikely (transformed_glyphs == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } status = _cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs, transformed_glyphs, NULL); - if (status) + if (unlikely (status)) goto CLEANUP_GLYPHS; status = _cairo_scaled_font_glyph_path (gstate->scaled_font, diff --git a/src/cairo-hash-private.h b/src/cairo-hash-private.h index 9101f2ed..a0be097a 100644 --- a/src/cairo-hash-private.h +++ b/src/cairo-hash-private.h @@ -63,10 +63,9 @@ _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal); cairo_private void _cairo_hash_table_destroy (cairo_hash_table_t *hash_table); -cairo_private cairo_bool_t +cairo_private void * _cairo_hash_table_lookup (cairo_hash_table_t *hash_table, - cairo_hash_entry_t *key, - cairo_hash_entry_t **entry_return); + cairo_hash_entry_t *key); cairo_private void * _cairo_hash_table_random_entry (cairo_hash_table_t *hash_table, @@ -81,7 +80,7 @@ _cairo_hash_table_remove (cairo_hash_table_t *hash_table, cairo_hash_entry_t *key); cairo_private void -_cairo_hash_table_foreach (cairo_hash_table_t *hash_table, +_cairo_hash_table_foreach (cairo_hash_table_t *hash_table, cairo_hash_callback_func_t hash_callback, void *closure); diff --git a/src/cairo-hash.c b/src/cairo-hash.c index 2317eb17..973281d4 100644 --- a/src/cairo-hash.c +++ b/src/cairo-hash.c @@ -52,12 +52,11 @@ * Appears in the table as any non-%NULL, non-DEAD_ENTRY pointer. */ -static cairo_hash_entry_t dead_entry = { 0 }; -#define DEAD_ENTRY (&dead_entry) +#define DEAD_ENTRY ((cairo_hash_entry_t *) 0x1) #define ENTRY_IS_FREE(entry) ((entry) == NULL) #define ENTRY_IS_DEAD(entry) ((entry) == DEAD_ENTRY) -#define ENTRY_IS_LIVE(entry) ((entry) && ! ENTRY_IS_DEAD(entry)) +#define ENTRY_IS_LIVE(entry) ((entry) > DEAD_ENTRY) /* We expect keys will not be destroyed frequently, so our table does not * contain any explicit shrinking code nor any chain-coalescing code for @@ -109,7 +108,7 @@ static const cairo_hash_table_arrangement_t hash_table_arrangements [] = { { 4194304, 9227641, 9227639 }, { 8388608, 18455029, 18455027 }, { 16777216, 36911011, 36911009 }, - { 33554432, 73819861, 73819859 }, + { 33554432, 73819861, 73819859 }, { 67108864, 147639589, 147639587 }, { 134217728, 295279081, 295279079 }, { 268435456, 590559793, 590559791 } @@ -149,7 +148,7 @@ _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal) cairo_hash_table_t *hash_table; hash_table = malloc (sizeof (cairo_hash_table_t)); - if (hash_table == NULL) { + if (unlikely (hash_table == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return NULL; } @@ -160,7 +159,7 @@ _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal) hash_table->entries = calloc (hash_table->arrangement->size, sizeof(cairo_hash_entry_t *)); - if (hash_table->entries == NULL) { + if (unlikely (hash_table->entries == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); free (hash_table); return NULL; @@ -206,85 +205,36 @@ _cairo_hash_table_destroy (cairo_hash_table_t *hash_table) free (hash_table); } -/** - * _cairo_hash_table_lookup_internal: - * - * @hash_table: a #cairo_hash_table_t to search - * @key: the key to search on - * @hash_code: the hash_code for @key - * @key_unique: If %TRUE, then caller asserts that no key already - * exists that will compare equal to #key, so search can be - * optimized. If unsure, set to %FALSE and the code will always work. - * - * Search the hashtable for a live entry for which - * hash_table->keys_equal returns true. If no such entry exists then - * return the first available (free or dead entry). - * - * If the key_unique flag is set, then the search will never call - * hash_table->keys_equal and will act as if it always returned - * false. This is useful as a performance optimization in special - * circumstances where the caller knows that there is no existing - * entry in the hash table with a matching key. - * - * Return value: The matching entry in the hash table (if - * any). Otherwise, the first available entry. The caller should check - * entry->state to check whether a match was found or not. - **/ static cairo_hash_entry_t ** -_cairo_hash_table_lookup_internal (cairo_hash_table_t *hash_table, - cairo_hash_entry_t *key, - cairo_bool_t key_is_unique) +_cairo_hash_table_lookup_unique_key (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key) { - cairo_hash_entry_t **entry, **first_available = NULL; unsigned long table_size, i, idx, step; + cairo_hash_entry_t **entry; table_size = hash_table->arrangement->size; - idx = key->hash % table_size; - step = 0; - - for (i = 0; i < table_size; ++i) - { - entry = &hash_table->entries[idx]; - if (ENTRY_IS_FREE(*entry)) - { - return entry; - } - else if (ENTRY_IS_DEAD(*entry)) - { - if (key_is_unique) { - return entry; - } else { - if (! first_available) - first_available = entry; - } - } - else /* ENTRY_IS_LIVE(*entry) */ - { - if (! key_is_unique) - if (hash_table->keys_equal (key, *entry)) - return entry; - } - - if (step == 0) { - step = key->hash % hash_table->arrangement->rehash; - if (step == 0) - step = 1; - } + entry = &hash_table->entries[idx]; + if (! ENTRY_IS_LIVE (*entry)) + return entry; + i = 1; + step = key->hash % hash_table->arrangement->rehash; + if (step == 0) + step = 1; + do { idx += step; if (idx >= table_size) idx -= table_size; - } - /* - * The table should not have permitted you to get here if you were just - * looking for a free slot: there should have been room. - */ - assert (key_is_unique == 0); + entry = &hash_table->entries[idx]; + if (! ENTRY_IS_LIVE (*entry)) + return entry; + } while (++i < table_size); - return first_available; + ASSERT_NOT_REACHED; + return NULL; } /** @@ -299,10 +249,9 @@ _cairo_hash_table_lookup_internal (cairo_hash_table_t *hash_table, * %CAIRO_STATUS_NO_MEMORY if out of memory. **/ static cairo_status_t -_cairo_hash_table_resize (cairo_hash_table_t *hash_table) +_cairo_hash_table_resize (cairo_hash_table_t *hash_table) { cairo_hash_table_t tmp; - cairo_hash_entry_t **entry; unsigned long new_size, i; /* This keeps the hash table between 25% and 50% full. */ @@ -331,16 +280,13 @@ _cairo_hash_table_resize (cairo_hash_table_t *hash_table) new_size = tmp.arrangement->size; tmp.entries = calloc (new_size, sizeof (cairo_hash_entry_t*)); - if (tmp.entries == NULL) + if (unlikely (tmp.entries == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); for (i = 0; i < hash_table->arrangement->size; ++i) { if (ENTRY_IS_LIVE (hash_table->entries[i])) { - entry = _cairo_hash_table_lookup_internal (&tmp, - hash_table->entries[i], - TRUE); - assert (ENTRY_IS_FREE(*entry)); - *entry = hash_table->entries[i]; + *_cairo_hash_table_lookup_unique_key (&tmp, hash_table->entries[i]) + = hash_table->entries[i]; } } @@ -355,32 +301,48 @@ _cairo_hash_table_resize (cairo_hash_table_t *hash_table) * _cairo_hash_table_lookup: * @hash_table: a hash table * @key: the key of interest - * @entry_return: pointer for return value. * * Performs a lookup in @hash_table looking for an entry which has a * key that matches @key, (as determined by the keys_equal() function * passed to _cairo_hash_table_create). * - * Return value: %TRUE if there is an entry in the hash table that - * matches the given key, (which will now be in *entry_return). %FALSE - * otherwise, (in which case *entry_return will be %NULL). + * Return value: the matching entry, of %NULL if no match was found. **/ -cairo_bool_t +void * _cairo_hash_table_lookup (cairo_hash_table_t *hash_table, - cairo_hash_entry_t *key, - cairo_hash_entry_t **entry_return) + cairo_hash_entry_t *key) { cairo_hash_entry_t **entry; + unsigned long table_size, i, idx, step; - /* See if we have an entry in the table already. */ - entry = _cairo_hash_table_lookup_internal (hash_table, key, FALSE); - if (ENTRY_IS_LIVE(*entry)) { - *entry_return = *entry; - return TRUE; - } + table_size = hash_table->arrangement->size; + idx = key->hash % table_size; + entry = &hash_table->entries[idx]; + + if (ENTRY_IS_LIVE (*entry)) { + if (hash_table->keys_equal (key, *entry)) + return *entry; + } else if (ENTRY_IS_FREE (*entry)) + return NULL; - *entry_return = NULL; - return FALSE; + i = 1; + step = key->hash % hash_table->arrangement->rehash; + if (step == 0) + step = 1; + do { + idx += step; + if (idx >= table_size) + idx -= table_size; + + entry = &hash_table->entries[idx]; + if (ENTRY_IS_LIVE (*entry)) { + if (hash_table->keys_equal (key, *entry)) + return *entry; + } else if (ENTRY_IS_FREE (*entry)) + return NULL; + } while (++i < table_size); + + return NULL; } /** @@ -448,8 +410,8 @@ _cairo_hash_table_random_entry (cairo_hash_table_t *hash_table, * * Insert the entry #key_and_value into the hash table. * - * WARNING: It is a fatal error if an entry exists in the hash table - * with a matching key, (this function will halt). + * WARNING: There must not be an existing entry in the hash table + * with a matching key. * * WARNING: It is a fatal error to insert an element while * an iterator is running @@ -466,42 +428,61 @@ _cairo_hash_table_insert (cairo_hash_table_t *hash_table, cairo_hash_entry_t *key_and_value) { cairo_status_t status; - cairo_hash_entry_t **entry; /* Insert is illegal while an iterator is running. */ assert (hash_table->iterating == 0); - entry = _cairo_hash_table_lookup_internal (hash_table, - key_and_value, FALSE); - - if (ENTRY_IS_LIVE(*entry)) - { - /* User is being bad, let's crash. */ - ASSERT_NOT_REACHED; - } - - *entry = key_and_value; hash_table->live_entries++; - status = _cairo_hash_table_resize (hash_table); - if (status) { + if (unlikely (status)) { /* abort the insert... */ - *entry = DEAD_ENTRY; hash_table->live_entries--; return status; } + *_cairo_hash_table_lookup_unique_key (hash_table, + key_and_value) = key_and_value; + return CAIRO_STATUS_SUCCESS; } +static cairo_hash_entry_t ** +_cairo_hash_table_lookup_exact_key (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key) +{ + unsigned long table_size, i, idx, step; + cairo_hash_entry_t **entry; + + table_size = hash_table->arrangement->size; + idx = key->hash % table_size; + + entry = &hash_table->entries[idx]; + if (*entry == key) + return entry; + + i = 1; + step = key->hash % hash_table->arrangement->rehash; + if (step == 0) + step = 1; + do { + idx += step; + if (idx >= table_size) + idx -= table_size; + + entry = &hash_table->entries[idx]; + if (*entry == key) + return entry; + } while (++i < table_size); + + ASSERT_NOT_REACHED; + return NULL; +} /** * _cairo_hash_table_remove: * @hash_table: a hash table * @key: key of entry to be removed * - * Remove an entry from the hash table which has a key that matches - * @key, if any (as determined by the keys_equal() function passed to - * _cairo_hash_table_create). + * Remove an entry from the hash table which points to @key. * * Return value: %CAIRO_STATUS_SUCCESS if successful or * %CAIRO_STATUS_NO_MEMORY if out of memory. @@ -510,13 +491,7 @@ void _cairo_hash_table_remove (cairo_hash_table_t *hash_table, cairo_hash_entry_t *key) { - cairo_hash_entry_t **entry; - - entry = _cairo_hash_table_lookup_internal (hash_table, key, FALSE); - if (! ENTRY_IS_LIVE(*entry)) - return; - - *entry = DEAD_ENTRY; + *_cairo_hash_table_lookup_exact_key (hash_table, key) = DEAD_ENTRY; hash_table->live_entries--; /* Check for table resize. Don't do this when iterating as this will diff --git a/src/cairo-hull.c b/src/cairo-hull.c index 008ba7fd..a699a524 100644 --- a/src/cairo-hull.c +++ b/src/cairo-hull.c @@ -200,7 +200,7 @@ _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices) if (num_hull > ARRAY_LENGTH (hull_stack)) { hull = _cairo_malloc_ab (num_hull, sizeof (cairo_hull_t)); - if (hull == NULL) + if (unlikely (hull == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } else { hull = hull_stack; diff --git a/src/cairo-image-info-private.h b/src/cairo-image-info-private.h new file mode 100644 index 00000000..6e1c4ad7 --- /dev/null +++ b/src/cairo-image-info-private.h @@ -0,0 +1,63 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson <ajohnson@redneon.com> + */ + +#ifndef CAIRO_IMAGE_INFO_PRIVATE_H +#define CAIRO_IMAGE_INFO_PRIVATE_H + +#include "cairoint.h" + +typedef struct _cairo_image_info { + int width; + int height; + int num_components; + int bits_per_component; +} cairo_image_info_t; + +cairo_private cairo_int_status_t +_cairo_image_info_get_jpeg_info (cairo_image_info_t *info, + const unsigned char *data, + long length); + +cairo_private cairo_int_status_t +_cairo_image_info_get_jpx_info (cairo_image_info_t *info, + const unsigned char *data, + long length); + +cairo_private cairo_int_status_t +_cairo_image_info_get_png_info (cairo_image_info_t *info, + const unsigned char *data, + long length); + +#endif /* CAIRO_IMAGE_INFO_PRIVATE_H */ diff --git a/src/cairo-image-info.c b/src/cairo-image-info.c new file mode 100644 index 00000000..8fc77055 --- /dev/null +++ b/src/cairo-image-info.c @@ -0,0 +1,290 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson <ajohnson@redneon.com> + */ + +#include "cairoint.h" +#include "cairo-image-info-private.h" + +static uint32_t +_get_be32 (const unsigned char *p) +{ + return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; +} + +/* JPEG (image/jpeg) + * + * http://www.w3.org/Graphics/JPEG/itu-t81.pdf + */ + +/* Markers with no parameters. All other markers are followed by a two + * byte length of the parameters. */ +#define TEM 0x01 +#define RST_begin 0xd0 +#define RST_end 0xd7 +#define SOI 0xd8 +#define EOI 0xd9 + +/* Start of frame markers. */ +#define SOF0 0xc0 +#define SOF1 0xc1 +#define SOF2 0xc2 +#define SOF3 0xc3 +#define SOF5 0xc5 +#define SOF6 0xc6 +#define SOF7 0xc7 +#define SOF9 0xc9 +#define SOF10 0xca +#define SOF11 0xcb +#define SOF13 0xcd +#define SOF14 0xce +#define SOF15 0xcf + +static const unsigned char * +_jpeg_skip_segment (const unsigned char *p) +{ + int len; + + p++; + len = (p[0] << 8) | p[1]; + + return p + len; +} + +static void +_jpeg_extract_info (cairo_image_info_t *info, const unsigned char *p) +{ + info->width = (p[6] << 8) + p[7]; + info->height = (p[4] << 8) + p[5]; + info->num_components = p[8]; + info->bits_per_component = p[3]; +} + +cairo_int_status_t +_cairo_image_info_get_jpeg_info (cairo_image_info_t *info, + const unsigned char *data, + long length) +{ + const unsigned char *p = data; + + while (p + 1 < data + length) { + if (*p != 0xff) + return CAIRO_INT_STATUS_UNSUPPORTED; + p++; + + switch (*p) { + /* skip fill bytes */ + case 0xff: + p++; + break; + + case TEM: + case SOI: + case EOI: + p++; + break; + + case SOF0: + case SOF1: + case SOF2: + case SOF3: + case SOF5: + case SOF6: + case SOF7: + case SOF9: + case SOF10: + case SOF11: + case SOF13: + case SOF14: + case SOF15: + /* Start of frame found. Extract the image parameters. */ + if (p + 8 > data + length) + return CAIRO_INT_STATUS_UNSUPPORTED; + + _jpeg_extract_info (info, p); + return CAIRO_STATUS_SUCCESS; + + default: + if (*p >= RST_begin && *p <= RST_end) { + p++; + break; + } + + if (p + 2 > data + length) + return CAIRO_INT_STATUS_UNSUPPORTED; + + p = _jpeg_skip_segment (p); + break; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +/* JPEG 2000 (image/jp2) + * + * http://www.jpeg.org/public/15444-1annexi.pdf + */ + +#define JPX_FILETYPE 0x66747970 +#define JPX_JP2_HEADER 0x6A703268 +#define JPX_IMAGE_HEADER 0x69686472 + +static const unsigned char _jpx_signature[] = { + 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a +}; + +static const unsigned char * +_jpx_next_box (const unsigned char *p) +{ + return p + _get_be32 (p); +} + +static const unsigned char * +_jpx_get_box_contents (const unsigned char *p) +{ + return p + 8; +} + +static cairo_bool_t +_jpx_match_box (const unsigned char *p, const unsigned char *end, uint32_t type) +{ + uint32_t length; + + if (p + 8 < end) { + length = _get_be32 (p); + if (_get_be32 (p + 4) == type && p + length < end) + return TRUE; + } + + return FALSE; +} + +static const unsigned char * +_jpx_find_box (const unsigned char *p, const unsigned char *end, uint32_t type) +{ + while (p < end) { + if (_jpx_match_box (p, end, type)) + return p; + p = _jpx_next_box (p); + } + + return NULL; +} + +static void +_jpx_extract_info (const unsigned char *p, cairo_image_info_t *info) +{ + info->height = _get_be32 (p); + info->width = _get_be32 (p + 4); + info->num_components = (p[8] << 8) + p[9]; + info->bits_per_component = p[10]; +} + +cairo_int_status_t +_cairo_image_info_get_jpx_info (cairo_image_info_t *info, + const unsigned char *data, + long length) +{ + const unsigned char *p = data; + const unsigned char *end = data + length; + + /* First 12 bytes must be the JPEG 2000 signature box. */ + if (length < ARRAY_LENGTH(_jpx_signature) || + memcmp(p, _jpx_signature, ARRAY_LENGTH(_jpx_signature)) != 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + p += ARRAY_LENGTH(_jpx_signature); + + /* Next box must be a File Type Box */ + if (! _jpx_match_box (p, end, JPX_FILETYPE)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + p = _jpx_next_box (p); + + /* Locate the JP2 header box. */ + p = _jpx_find_box (p, end, JPX_JP2_HEADER); + if (!p) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Step into the JP2 header box. First box must be the Image + * Header */ + p = _jpx_get_box_contents (p); + if (! _jpx_match_box (p, end, JPX_IMAGE_HEADER)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Get the image info */ + p = _jpx_get_box_contents (p); + _jpx_extract_info (p, info); + + return CAIRO_STATUS_SUCCESS; +} + +/* PNG (image/png) + * + * http://www.w3.org/TR/2003/REC-PNG-20031110/ + */ + +#define PNG_IHDR 0x49484452 + +static const unsigned char _png_magic[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; + +cairo_int_status_t +_cairo_image_info_get_png_info (cairo_image_info_t *info, + const unsigned char *data, + long length) +{ + const unsigned char *p = data; + const unsigned char *end = data + length; + + if (length < 8 || memcmp (data, _png_magic, 8) != 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + p += 8; + + /* The first chunk must be IDHR. IDHR has 13 bytes of data plus + * the 12 bytes of overhead for the chunk. */ + if (p + 13 + 12 > end) + return CAIRO_INT_STATUS_UNSUPPORTED; + + p += 4; + if (_get_be32 (p) != PNG_IHDR) + return CAIRO_INT_STATUS_UNSUPPORTED; + + p += 4; + info->width = _get_be32 (p); + p += 4; + info->height = _get_be32 (p); + + return CAIRO_STATUS_SUCCESS; +} diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 12614c1a..f484466a 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -131,7 +131,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, cairo_image_surface_t *surface; surface = malloc (sizeof (cairo_image_surface_t)); - if (surface == NULL) + if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); _cairo_surface_init (&surface->base, &_cairo_image_surface_backend, @@ -203,7 +203,7 @@ _pixman_format_from_masks (cairo_format_masks_t *masks, } /* A mask consisting of N bits set to 1. */ -#define MASK(N) ((1 << (N))-1) +#define MASK(N) ((1UL << (N))-1) void _pixman_format_to_masks (pixman_format_code_t format, @@ -327,7 +327,7 @@ _cairo_image_surface_create_with_pixman_format (unsigned char *data, pixman_image = pixman_image_create_bits (pixman_format, width, height, (uint32_t *) data, stride); - if (pixman_image == NULL) + if (unlikely (pixman_image == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); surface = _cairo_image_surface_create_for_pixman_image (pixman_image, @@ -731,7 +731,7 @@ _cairo_image_surface_finish (void *abstract_surface) void _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface) { - surface->owns_data = 1; + surface->owns_data = TRUE; } static cairo_status_t @@ -806,11 +806,12 @@ _cairo_image_surface_clone_similar (void *abstract_surface, static cairo_status_t _cairo_image_surface_set_matrix (cairo_image_surface_t *surface, - const cairo_matrix_t *matrix) + const cairo_matrix_t *matrix, + double xc, double yc) { pixman_transform_t pixman_transform; - _cairo_matrix_to_pixman_matrix (matrix, &pixman_transform); + _cairo_matrix_to_pixman_matrix (matrix, &pixman_transform, xc, yc); if (! pixman_image_set_transform (surface->pixman_image, &pixman_transform)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -862,12 +863,14 @@ _cairo_image_surface_set_filter (cairo_image_surface_t *surface, static cairo_status_t _cairo_image_surface_set_attributes (cairo_image_surface_t *surface, - cairo_surface_attributes_t *attributes) + cairo_surface_attributes_t *attributes, + double xc, double yc) { cairo_int_status_t status; - status = _cairo_image_surface_set_matrix (surface, &attributes->matrix); - if (status) + status = _cairo_image_surface_set_matrix (surface, &attributes->matrix, + xc, yc); + if (unlikely (status)) return status; switch (attributes->extend) { @@ -886,7 +889,7 @@ _cairo_image_surface_set_attributes (cairo_image_surface_t *surface, } status = _cairo_image_surface_set_filter (surface, attributes->filter); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -965,17 +968,21 @@ _cairo_image_surface_composite (cairo_operator_t op, (cairo_surface_t **) &src, (cairo_surface_t **) &mask, &src_attr, &mask_attr); - if (status) + if (unlikely (status)) return status; - status = _cairo_image_surface_set_attributes (src, &src_attr); - if (status) - goto CLEANUP_SURFACES; + status = _cairo_image_surface_set_attributes (src, &src_attr, + dst_x + width / 2., + dst_y + height / 2.); + if (unlikely (status)) + goto CLEANUP_SURFACES; if (mask) { - status = _cairo_image_surface_set_attributes (mask, &mask_attr); - if (status) + status = _cairo_image_surface_set_attributes (mask, &mask_attr, + dst_x + width / 2., + dst_y + height / 2.); + if (unlikely (status)) goto CLEANUP_SURFACES; pixman_image_composite (_pixman_operator (op), @@ -1044,7 +1051,7 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, if (num_rects > ARRAY_LENGTH (stack_rects)) { pixman_rects = _cairo_malloc_ab (num_rects, sizeof (pixman_rectangle16_t)); - if (pixman_rects == NULL) + if (unlikely (pixman_rects == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -1057,10 +1064,11 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, /* XXX: pixman_fill_rectangles() should be implemented */ if (! pixman_image_fill_rectangles (_pixman_operator (op), - surface->pixman_image, - &pixman_color, - num_rects, - pixman_rects)) { + surface->pixman_image, + &pixman_color, + num_rects, + pixman_rects)) + { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -1070,6 +1078,15 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, return status; } +static cairo_format_t +_cairo_mask_format_from_antialias (cairo_antialias_t antialias) +{ + if (antialias == CAIRO_ANTIALIAS_NONE) + return CAIRO_FORMAT_A1; + return CAIRO_FORMAT_A8; +} + + static cairo_int_status_t _cairo_image_surface_composite_trapezoids (cairo_operator_t op, const cairo_pattern_t *pattern, @@ -1087,13 +1104,10 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, cairo_surface_attributes_t attributes; cairo_image_surface_t *dst = abstract_dst; cairo_image_surface_t *src; - cairo_int_status_t status; - pixman_image_t *mask; - pixman_format_code_t format; - uint32_t *mask_data; + cairo_int_status_t status; + cairo_image_surface_t *mask = NULL; pixman_trapezoid_t stack_traps[CAIRO_STACK_ARRAY_LENGTH (pixman_trapezoid_t)]; pixman_trapezoid_t *pixman_traps = stack_traps; - int mask_stride; int i; if (height == 0 || width == 0) @@ -1102,7 +1116,7 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, /* Convert traps to pixman traps */ if (num_traps > ARRAY_LENGTH (stack_traps)) { pixman_traps = _cairo_malloc_ab (num_traps, sizeof (pixman_trapezoid_t)); - if (pixman_traps == NULL) + if (unlikely (pixman_traps == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -1148,47 +1162,28 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, src_x, src_y, width, height, (cairo_surface_t **) &src, &attributes); - if (status) + if (unlikely (status)) goto finish; - status = _cairo_image_surface_set_attributes (src, &attributes); - if (status) + status = _cairo_image_surface_set_attributes (src, &attributes, + dst_x + width / 2., + dst_y + height / 2.); + if (unlikely (status)) goto CLEANUP_SOURCE; - switch (antialias) { - case CAIRO_ANTIALIAS_NONE: - format = PIXMAN_a1; - mask_stride = ((width + 31) / 8) & ~0x03; - break; - case CAIRO_ANTIALIAS_GRAY: - case CAIRO_ANTIALIAS_SUBPIXEL: - case CAIRO_ANTIALIAS_DEFAULT: - default: - format = PIXMAN_a8; - mask_stride = (width + 3) & ~3; - break; - } - - /* The image must be initially transparent */ - mask_data = calloc (mask_stride, height); - if (mask_data == NULL) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + mask = (cairo_image_surface_t *) + cairo_image_surface_create ( + _cairo_mask_format_from_antialias (antialias), + width, height); + if (cairo_surface_status (&mask->base) != CAIRO_STATUS_SUCCESS) goto CLEANUP_SOURCE; - } - mask = pixman_image_create_bits (format, width, height, - mask_data, mask_stride); - if (mask == NULL) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto CLEANUP_IMAGE_DATA; - } - - pixman_add_trapezoids (mask, - dst_x, - dst_y, + pixman_add_trapezoids (mask->pixman_image, - dst_x, - dst_y, num_traps, pixman_traps); pixman_image_composite (_pixman_operator (op), src->pixman_image, - mask, + mask->pixman_image, dst->pixman_image, src_x + attributes.x_offset, src_y + attributes.y_offset, @@ -1198,15 +1193,13 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, if (! _cairo_operator_bounded_by_mask (op)) status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base, - &attributes, src->width, src->height, + &attributes, + src->width, src->height, width, height, src_x, src_y, 0, 0, dst_x, dst_y, width, height); - pixman_image_unref (mask); - - CLEANUP_IMAGE_DATA: - free (mask_data); + cairo_surface_destroy (&mask->base); CLEANUP_SOURCE: _cairo_pattern_release_surface (pattern, &src->base, &attributes); @@ -1218,6 +1211,216 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, return status; } +typedef struct _cairo_image_surface_span_renderer { + cairo_span_renderer_t base; + + cairo_operator_t op; + const cairo_pattern_t *pattern; + cairo_antialias_t antialias; + + cairo_image_surface_t *src; + cairo_surface_attributes_t src_attributes; + cairo_image_surface_t *mask; + cairo_image_surface_t *dst; + + cairo_composite_rectangles_t composite_rectangles; +} cairo_image_surface_span_renderer_t; + +static cairo_status_t +_cairo_image_surface_span_renderer_render_row ( + void *abstract_renderer, + int y, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + cairo_image_surface_span_renderer_t *renderer = abstract_renderer; + int xmin = renderer->composite_rectangles.mask.x; + int xmax = xmin + renderer->composite_rectangles.width; + uint8_t *row; + int prev_x = xmin; + int prev_alpha = 0; + unsigned i; + + /* Make sure we're within y-range. */ + y -= renderer->composite_rectangles.mask.y; + if (y < 0 || y >= renderer->composite_rectangles.height) + return CAIRO_STATUS_SUCCESS; + + row = (uint8_t*)(renderer->mask->data) + y*(size_t)renderer->mask->stride - xmin; + + /* Find the first span within x-range. */ + for (i=0; i < num_spans && spans[i].x < xmin; i++) {} + if (i>0) + prev_alpha = spans[i-1].coverage; + + /* Set the intermediate spans. */ + for (; i < num_spans; i++) { + int x = spans[i].x; + + if (x >= xmax) + break; + + if (prev_alpha != 0) { + /* We implement setting rendering the most common single + * pixel wide span case to avoid the overhead of a memset + * call. Open coding setting longer spans didn't show a + * noticeable improvement over memset. */ + if (x == prev_x + 1) { + row[prev_x] = prev_alpha; + } + else { + memset(row + prev_x, prev_alpha, x - prev_x); + } + } + + prev_x = x; + prev_alpha = spans[i].coverage; + } + + if (prev_alpha != 0 && prev_x < xmax) { + memset(row + prev_x, prev_alpha, xmax - prev_x); + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_image_surface_span_renderer_destroy (void *abstract_renderer) +{ + cairo_image_surface_span_renderer_t *renderer = abstract_renderer; + if (!renderer) return; + + if (renderer->src != NULL) { + _cairo_pattern_release_surface (renderer->pattern, + &renderer->src->base, + &renderer->src_attributes); + } + + if (renderer->mask != NULL) + cairo_surface_destroy (&renderer->mask->base); + + free (renderer); +} + +static cairo_status_t +_cairo_image_surface_span_renderer_finish (void *abstract_renderer) +{ + cairo_image_surface_span_renderer_t *renderer = abstract_renderer; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + if (renderer->src == NULL || renderer->mask == NULL) + return CAIRO_STATUS_SUCCESS; + + status = cairo_surface_status (&renderer->mask->base); + if (status == CAIRO_STATUS_SUCCESS) { + cairo_composite_rectangles_t *rects = &renderer->composite_rectangles; + cairo_image_surface_t *src = renderer->src; + cairo_image_surface_t *dst = renderer->dst; + cairo_surface_attributes_t *src_attributes = &renderer->src_attributes; + int width = rects->width; + int height = rects->height; + + pixman_image_composite (_pixman_operator (renderer->op), + src->pixman_image, + renderer->mask->pixman_image, + dst->pixman_image, + rects->src.x + src_attributes->x_offset, + rects->src.y + src_attributes->y_offset, + 0, 0, /* mask.x, mask.y */ + rects->dst.x, rects->dst.y, + width, height); + + if (! _cairo_operator_bounded_by_mask (renderer->op)) + status = _cairo_surface_composite_shape_fixup_unbounded ( + &dst->base, + src_attributes, + src->width, src->height, + rects->width, rects->height, + rects->src.x, rects->src.y, + 0, 0, /* mask.x, mask.y */ + rects->dst.x, rects->dst.y, + rects->width, rects->height); + } + if (status != CAIRO_STATUS_SUCCESS) + return _cairo_span_renderer_set_error (abstract_renderer, + status); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_image_surface_check_span_renderer (cairo_operator_t op, + const cairo_pattern_t *pattern, + void *abstract_dst, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects) +{ + (void) op; + (void) pattern; + (void) abstract_dst; + (void) antialias; + (void) rects; + return TRUE; +} + +static cairo_span_renderer_t * +_cairo_image_surface_create_span_renderer (cairo_operator_t op, + const cairo_pattern_t *pattern, + void *abstract_dst, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects) +{ + cairo_image_surface_t *dst = abstract_dst; + cairo_image_surface_span_renderer_t *renderer + = calloc(1, sizeof(*renderer)); + cairo_status_t status; + int width = rects->width; + int height = rects->height; + + if (renderer == NULL) + return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY); + + renderer->base.destroy = _cairo_image_surface_span_renderer_destroy; + renderer->base.finish = _cairo_image_surface_span_renderer_finish; + renderer->base.render_row = + _cairo_image_surface_span_renderer_render_row; + renderer->op = op; + renderer->pattern = pattern; + renderer->antialias = antialias; + renderer->dst = dst; + + renderer->composite_rectangles = *rects; + + status = _cairo_pattern_acquire_surface ( + renderer->pattern, &renderer->dst->base, + rects->src.x, rects->src.y, + width, height, + (cairo_surface_t **) &renderer->src, + &renderer->src_attributes); + if (status) + goto unwind; + + status = _cairo_image_surface_set_attributes ( + renderer->src, &renderer->src_attributes, + rects->dst.x + width/2, rects->dst.y + height/2); + if (status) + goto unwind; + + /* TODO: support rendering to A1 surfaces (or: go add span + * compositing to pixman.) */ + renderer->mask = (cairo_image_surface_t *) + cairo_image_surface_create (CAIRO_FORMAT_A8, + width, height); + + status = cairo_surface_status (&renderer->mask->base); + + unwind: + if (status != CAIRO_STATUS_SUCCESS) { + _cairo_image_surface_span_renderer_destroy (renderer); + return _cairo_span_renderer_create_in_error (status); + } + return &renderer->base; +} + cairo_int_status_t _cairo_image_surface_set_clip_region (void *abstract_surface, cairo_region_t *region) @@ -1293,6 +1496,8 @@ const cairo_surface_backend_t _cairo_image_surface_backend = { _cairo_image_surface_composite, _cairo_image_surface_fill_rectangles, _cairo_image_surface_composite_trapezoids, + _cairo_image_surface_create_span_renderer, + _cairo_image_surface_check_span_renderer, NULL, /* copy_page */ NULL, /* show_page */ _cairo_image_surface_set_clip_region, @@ -1343,7 +1548,7 @@ _cairo_image_surface_clone (cairo_image_surface_t *surface, status = cairo_status (cr); cairo_destroy (cr); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (&clone->base); return (cairo_image_surface_t *) _cairo_surface_create_in_error (status); } diff --git a/src/cairo-lzw.c b/src/cairo-lzw.c index 1241225d..a4fdf738 100644 --- a/src/cairo-lzw.c +++ b/src/cairo-lzw.c @@ -73,7 +73,7 @@ _lzw_buf_init (lzw_buf_t *buf, int size) buf->pending_bits = 0; buf->data = malloc (size); - if (buf->data == NULL) { + if (unlikely (buf->data == NULL)) { buf->data_size = 0; buf->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); return; @@ -98,7 +98,7 @@ _lzw_buf_grow (lzw_buf_t *buf) if (new_size / 2 == buf->data_size) new_data = realloc (buf->data, new_size); - if (new_data == NULL) { + if (unlikely (new_data == NULL)) { free (buf->data); buf->data_size = 0; buf->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -137,7 +137,7 @@ _lzw_buf_store_bits (lzw_buf_t *buf, uint16_t value, int num_bits) while (buf->pending_bits >= 8) { if (buf->num_data >= buf->data_size) { status = _lzw_buf_grow (buf); - if (status) + if (unlikely (status)) return; } buf->data[buf->num_data++] = buf->pending >> (buf->pending_bits - 8); @@ -167,7 +167,7 @@ _lzw_buf_store_pending (lzw_buf_t *buf) if (buf->num_data >= buf->data_size) { status = _lzw_buf_grow (buf); - if (status) + if (unlikely (status)) return; } diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c index b644dec8..6dfe537f 100644 --- a/src/cairo-matrix.c +++ b/src/cairo-matrix.c @@ -865,7 +865,9 @@ _cairo_matrix_transformed_circle_major_axis (cairo_matrix_t *matrix, double radi void _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, - pixman_transform_t *pixman_transform) + pixman_transform_t *pixman_transform, + double xc, + double yc) { static const pixman_transform_t pixman_identity_transform = {{ {1 << 16, 0, 0}, @@ -875,11 +877,9 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, if (_cairo_matrix_is_identity (matrix)) { *pixman_transform = pixman_identity_transform; - } - else { + } else { cairo_matrix_t inv; - double x,y; - pixman_vector_t vector; + unsigned max_iterations; pixman_transform->matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx); pixman_transform->matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy); @@ -899,9 +899,10 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, * for cairo, while pixman uses rounded versions of xx ... yy. * This error increases as a and b get larger. * - * To compensate for this, we fix the point (0, 0) in pattern + * To compensate for this, we fix the point (xc, yc) in pattern * space and adjust pixman's transform to agree with cairo's at - * that point. */ + * that point. + */ if (_cairo_matrix_is_translation (matrix)) return; @@ -911,22 +912,38 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS) return; - /* find the device space coordinate that maps to (0, 0) */ - x = 0, y = 0; - cairo_matrix_transform_point (&inv, &x, &y); - - /* transform the resulting device space coordinate back - * to the pattern space, using pixman's transform */ - vector.vector[0] = _cairo_fixed_16_16_from_double (x); - vector.vector[1] = _cairo_fixed_16_16_from_double (y); - vector.vector[2] = 1 << 16; - - if (! pixman_transform_point_3d (pixman_transform, &vector)) - return; - - /* Ideally, the vector should now be (0, 0). We can now compensate - * for the resulting error */ - pixman_transform->matrix[0][2] -= vector.vector[0]; - pixman_transform->matrix[1][2] -= vector.vector[1]; + /* find the pattern space coordinate that maps to (xc, yc) */ + xc += .5; yc += .5; /* offset for the pixel centre */ + max_iterations = 5; + do { + double x,y; + pixman_vector_t vector; + cairo_fixed_16_16_t dx, dy; + + vector.vector[0] = _cairo_fixed_16_16_from_double (xc); + vector.vector[1] = _cairo_fixed_16_16_from_double (yc); + vector.vector[2] = 1 << 16; + + if (! pixman_transform_point_3d (pixman_transform, &vector)) + return; + + x = pixman_fixed_to_double (vector.vector[0]); + y = pixman_fixed_to_double (vector.vector[1]); + cairo_matrix_transform_point (&inv, &x, &y); + + /* Ideally, the vector should now be (xc, yc). + * We can now compensate for the resulting error. + */ + x -= xc; + y -= yc; + cairo_matrix_transform_distance (matrix, &x, &y); + dx = _cairo_fixed_16_16_from_double (x); + dy = _cairo_fixed_16_16_from_double (y); + pixman_transform->matrix[0][2] -= dx; + pixman_transform->matrix[1][2] -= dy; + + if (dx == 0 && dy == 0) + break; + } while (--max_iterations); } } diff --git a/src/cairo-meta-surface-private.h b/src/cairo-meta-surface-private.h index 9a1b169c..8d5e096e 100644 --- a/src/cairo-meta-surface-private.h +++ b/src/cairo-meta-surface-private.h @@ -67,6 +67,7 @@ typedef enum { typedef struct _cairo_command_header { cairo_command_type_t type; cairo_meta_region_type_t region; + cairo_rectangle_int_t extents; } cairo_command_header_t; typedef struct _cairo_command_paint { diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c index faf48558..0f6e6324 100644 --- a/src/cairo-meta-surface.c +++ b/src/cairo-meta-surface.c @@ -84,7 +84,7 @@ _cairo_meta_surface_create (cairo_content_t content, cairo_meta_surface_t *meta; meta = malloc (sizeof (cairo_meta_surface_t)); - if (meta == NULL) + if (unlikely (meta == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); _cairo_surface_init (&meta->base, &cairo_meta_surface_backend, @@ -197,7 +197,7 @@ _cairo_meta_surface_acquire_source_image (void *abstract_surface, surface->height_pixels); status = _cairo_meta_surface_replay (&surface->base, image); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (image); return status; } @@ -219,26 +219,31 @@ _cairo_meta_surface_release_source_image (void *abstract_surface, static cairo_int_status_t _cairo_meta_surface_paint (void *abstract_surface, cairo_operator_t op, - const cairo_pattern_t *source) + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; cairo_command_paint_t *command; command = malloc (sizeof (cairo_command_paint_t)); - if (command == NULL) + if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); command->header.type = CAIRO_COMMAND_PAINT; command->header.region = CAIRO_META_REGION_ALL; + command->header.extents.x = 0; + command->header.extents.y = 0; + command->header.extents.width = meta->width_pixels; + command->header.extents.height = meta->height_pixels; command->op = op; status = _cairo_pattern_init_snapshot (&command->source.base, source); - if (status) + if (unlikely (status)) goto CLEANUP_COMMAND; status = _cairo_array_append (&meta->commands, &command); - if (status) + if (unlikely (status)) goto CLEANUP_SOURCE; /* An optimisation that takes care to not replay what was done @@ -260,30 +265,35 @@ static cairo_int_status_t _cairo_meta_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_pattern_t *mask) + const cairo_pattern_t *mask, + cairo_rectangle_int_t *extents) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; cairo_command_mask_t *command; command = malloc (sizeof (cairo_command_mask_t)); - if (command == NULL) + if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); command->header.type = CAIRO_COMMAND_MASK; command->header.region = CAIRO_META_REGION_ALL; + command->header.extents.x = 0; + command->header.extents.y = 0; + command->header.extents.width = meta->width_pixels; + command->header.extents.height = meta->height_pixels; command->op = op; status = _cairo_pattern_init_snapshot (&command->source.base, source); - if (status) + if (unlikely (status)) goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->mask.base, mask); - if (status) + if (unlikely (status)) goto CLEANUP_SOURCE; status = _cairo_array_append (&meta->commands, &command); - if (status) + if (unlikely (status)) goto CLEANUP_MASK; return CAIRO_STATUS_SUCCESS; @@ -306,30 +316,35 @@ _cairo_meta_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; cairo_command_stroke_t *command; command = malloc (sizeof (cairo_command_stroke_t)); - if (command == NULL) + if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); command->header.type = CAIRO_COMMAND_STROKE; command->header.region = CAIRO_META_REGION_ALL; + command->header.extents.x = 0; + command->header.extents.y = 0; + command->header.extents.width = meta->width_pixels; + command->header.extents.height = meta->height_pixels; command->op = op; status = _cairo_pattern_init_snapshot (&command->source.base, source); - if (status) + if (unlikely (status)) goto CLEANUP_COMMAND; status = _cairo_path_fixed_init_copy (&command->path, path); - if (status) + if (unlikely (status)) goto CLEANUP_SOURCE; status = _cairo_stroke_style_init_copy (&command->style, style); - if (status) + if (unlikely (status)) goto CLEANUP_PATH; command->ctm = *ctm; @@ -338,7 +353,7 @@ _cairo_meta_surface_stroke (void *abstract_surface, command->antialias = antialias; status = _cairo_array_append (&meta->commands, &command); - if (status) + if (unlikely (status)) goto CLEANUP_STYLE; return CAIRO_STATUS_SUCCESS; @@ -361,26 +376,31 @@ _cairo_meta_surface_fill (void *abstract_surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; cairo_command_fill_t *command; command = malloc (sizeof (cairo_command_fill_t)); - if (command == NULL) + if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); command->header.type = CAIRO_COMMAND_FILL; command->header.region = CAIRO_META_REGION_ALL; + command->header.extents.x = 0; + command->header.extents.y = 0; + command->header.extents.width = meta->width_pixels; + command->header.extents.height = meta->height_pixels; command->op = op; status = _cairo_pattern_init_snapshot (&command->source.base, source); - if (status) + if (unlikely (status)) goto CLEANUP_COMMAND; status = _cairo_path_fixed_init_copy (&command->path, path); - if (status) + if (unlikely (status)) goto CLEANUP_SOURCE; command->fill_rule = fill_rule; @@ -388,7 +408,7 @@ _cairo_meta_surface_fill (void *abstract_surface, command->antialias = antialias; status = _cairo_array_append (&meta->commands, &command); - if (status) + if (unlikely (status)) goto CLEANUP_PATH; return CAIRO_STATUS_SUCCESS; @@ -419,22 +439,27 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface, const cairo_text_cluster_t *clusters, int num_clusters, cairo_text_cluster_flags_t cluster_flags, - cairo_scaled_font_t *scaled_font) + cairo_scaled_font_t *scaled_font, + cairo_rectangle_int_t *extents) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; cairo_command_show_text_glyphs_t *command; command = malloc (sizeof (cairo_command_show_text_glyphs_t)); - if (command == NULL) + if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); command->header.type = CAIRO_COMMAND_SHOW_TEXT_GLYPHS; command->header.region = CAIRO_META_REGION_ALL; + command->header.extents.x = 0; + command->header.extents.y = 0; + command->header.extents.width = meta->width_pixels; + command->header.extents.height = meta->height_pixels; command->op = op; status = _cairo_pattern_init_snapshot (&command->source.base, source); - if (status) + if (unlikely (status)) goto CLEANUP_COMMAND; command->utf8 = NULL; @@ -446,7 +471,7 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface, if (utf8_len) { command->utf8 = malloc (utf8_len); - if (command->utf8 == NULL) { + if (unlikely (command->utf8 == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_ARRAYS; } @@ -454,7 +479,7 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface, } if (num_glyphs) { command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0])); - if (command->glyphs == NULL) { + if (unlikely (command->glyphs == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_ARRAYS; } @@ -462,7 +487,7 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface, } if (num_clusters) { command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0])); - if (command->clusters == NULL) { + if (unlikely (command->clusters == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_ARRAYS; } @@ -474,7 +499,7 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface, command->scaled_font = cairo_scaled_font_reference (scaled_font); status = _cairo_array_append (&meta->commands, &command); - if (status) + if (unlikely (status)) goto CLEANUP_SCALED_FONT; return CAIRO_STATUS_SUCCESS; @@ -512,7 +537,7 @@ _cairo_meta_surface_snapshot (void *abstract_other) cairo_meta_surface_t *meta; meta = malloc (sizeof (cairo_meta_surface_t)); - if (meta == NULL) + if (unlikely (meta == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); _cairo_surface_init (&meta->base, &cairo_meta_surface_backend, @@ -542,7 +567,7 @@ _cairo_meta_surface_intersect_clip_path (void *dst, cairo_status_t status; command = malloc (sizeof (cairo_command_intersect_clip_path_t)); - if (command == NULL) + if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); command->header.type = CAIRO_COMMAND_INTERSECT_CLIP_PATH; @@ -550,7 +575,7 @@ _cairo_meta_surface_intersect_clip_path (void *dst, if (path) { status = _cairo_path_fixed_init_copy (&command->path, path); - if (status) { + if (unlikely (status)) { free (command); return status; } @@ -565,7 +590,7 @@ _cairo_meta_surface_intersect_clip_path (void *dst, command->antialias = antialias; status = _cairo_array_append (&meta->commands, &command); - if (status) { + if (unlikely (status)) { if (path) _cairo_path_fixed_fini (&command->path); free (command); @@ -622,6 +647,8 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = { NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ NULL, /* set_clip_region */ @@ -741,7 +768,7 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface, ASSERT_NOT_REACHED; } - if (status) + if (unlikely (status)) break; } @@ -789,14 +816,14 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, * ensure the current clip gets set on the surface. */ if (command->header.type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) { status = _cairo_surface_set_clip (target, &clip); - if (status) + if (unlikely (status)) break; } dev_path = _cairo_command_get_path (command); if (dev_path && has_device_transform) { status = _cairo_path_fixed_init_copy (&path_copy, dev_path); - if (status) + if (unlikely (status)) break; _cairo_path_fixed_transform (&path_copy, device_transform); dev_path = &path_copy; @@ -806,13 +833,13 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, case CAIRO_COMMAND_PAINT: status = _cairo_surface_paint (target, command->paint.op, - &command->paint.source.base); + &command->paint.source.base, &command->header.extents); break; case CAIRO_COMMAND_MASK: status = _cairo_surface_mask (target, command->mask.op, &command->mask.source.base, - &command->mask.mask.base); + &command->mask.mask.base, &command->header.extents); break; case CAIRO_COMMAND_STROKE: { @@ -834,7 +861,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, &dev_ctm, &dev_ctm_inverse, command->stroke.tolerance, - command->stroke.antialias); + command->stroke.antialias, &command->header.extents); break; } case CAIRO_COMMAND_FILL: @@ -881,7 +908,8 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, &dev_ctm, &dev_ctm_inverse, stroke_command->stroke.tolerance, - stroke_command->stroke.antialias); + stroke_command->stroke.antialias, + &stroke_command->header.extents); i++; } else status = _cairo_surface_fill (target, @@ -890,7 +918,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, dev_path, command->fill.fill_rule, command->fill.tolerance, - command->fill.antialias); + command->fill.antialias, &command->header.extents); break; } case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: @@ -904,7 +932,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, * copy the array before handing it to the backend. */ dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); - if (dev_glyphs == NULL) { + if (unlikely (dev_glyphs == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); break; } @@ -927,7 +955,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, dev_glyphs, num_glyphs, command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters, command->show_text_glyphs.cluster_flags, - command->show_text_glyphs.scaled_font); + command->show_text_glyphs.scaled_font, &command->header.extents); free (dev_glyphs); break; @@ -960,7 +988,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, } } - if (status) + if (unlikely (status)) break; } diff --git a/src/cairo-misc.c b/src/cairo-misc.c index 27050a24..6f707a66 100644 --- a/src/cairo-misc.c +++ b/src/cairo-misc.c @@ -287,7 +287,7 @@ _cairo_validate_text_clusters (const char *utf8, /* Make sure we've got valid UTF-8 for the cluster */ status = _cairo_utf8_to_ucs4 (utf8+n_bytes, cluster_bytes, NULL, NULL); - if (status) + if (unlikely (status)) return CAIRO_STATUS_INVALID_CLUSTERS; n_bytes += cluster_bytes ; @@ -617,7 +617,7 @@ _cairo_lround (double d) #include <windows.h> #include <io.h> -/* tmpfile() replacment for Windows. +/* tmpfile() replacement for Windows. * * On Windows tmpfile() creates the file in the root directory. This * may fail due to unsufficient privileges. @@ -667,3 +667,108 @@ _cairo_win32_tmpfile (void) } #endif /* _WIN32 */ + +typedef struct _cairo_intern_string { + cairo_hash_entry_t hash_entry; + int len; + char *string; +} cairo_intern_string_t; + +static cairo_hash_table_t *_cairo_intern_string_ht; + +static unsigned long +_intern_string_hash (const char *str, int len) +{ + const signed char *p = (const signed char *) str; + unsigned int h = *p; + + for (p += 1; --len; p++) + h = (h << 5) - h + *p; + + return h; +} + +static cairo_bool_t +_intern_string_equal (const void *_a, const void *_b) +{ + const cairo_intern_string_t *a = _a; + const cairo_intern_string_t *b = _b; + + if (a->len != b->len) + return FALSE; + + return memcmp (a->string, b->string, a->len) == 0; +} + +cairo_status_t +_cairo_intern_string (const char **str_inout, int len) +{ + char *str = (char *) *str_inout; + cairo_intern_string_t tmpl, *istring; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + if (len < 0) + len = strlen (str); + tmpl.hash_entry.hash = _intern_string_hash (str, len); + tmpl.len = len; + tmpl.string = (char *) str; + + CAIRO_MUTEX_LOCK (_cairo_intern_string_mutex); + if (_cairo_intern_string_ht == NULL) { + _cairo_intern_string_ht = _cairo_hash_table_create (_intern_string_equal); + if (unlikely (_cairo_intern_string_ht == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + } + + istring = _cairo_hash_table_lookup (_cairo_intern_string_ht, + &tmpl.hash_entry); + if (istring == NULL) { + istring = malloc (sizeof (cairo_intern_string_t) + len + 1); + if (likely (istring != NULL)) { + istring->hash_entry.hash = tmpl.hash_entry.hash; + istring->len = tmpl.len; + istring->string = (char *) (istring + 1); + memcpy (istring->string, str, len); + istring->string[len] = '\0'; + + status = _cairo_hash_table_insert (_cairo_intern_string_ht, + &istring->hash_entry); + if (unlikely (status)) { + free (istring); + goto BAIL; + } + } else { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + } + + *str_inout = istring->string; + + BAIL: + CAIRO_MUTEX_UNLOCK (_cairo_intern_string_mutex); + return status; +} + +static void +_intern_string_pluck (void *entry, void *closure) +{ + _cairo_hash_table_remove (closure, entry); + free (entry); +} + +void +_cairo_intern_string_reset_static_data (void) +{ + CAIRO_MUTEX_LOCK (_cairo_intern_string_mutex); + if (_cairo_intern_string_ht != NULL) { + _cairo_hash_table_foreach (_cairo_intern_string_ht, + _intern_string_pluck, + _cairo_intern_string_ht); + _cairo_hash_table_destroy(_cairo_intern_string_ht); + _cairo_intern_string_ht = NULL; + } + CAIRO_MUTEX_UNLOCK (_cairo_intern_string_mutex); +} diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h index 6fdb389a..f5f654d5 100644 --- a/src/cairo-mutex-list-private.h +++ b/src/cairo-mutex-list-private.h @@ -40,6 +40,7 @@ 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_intern_string_mutex) CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex) CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex) diff --git a/src/cairo-os2-private.h b/src/cairo-os2-private.h index 5fa28295..e71a6dc9 100644 --- a/src/cairo-os2-private.h +++ b/src/cairo-os2-private.h @@ -41,17 +41,6 @@ #include "cairo-os2.h" #include "cairoint.h" -#define INCL_DOS -#define INCL_DOSSEMAPHORES -#define INCL_DOSERRORS -#define INCL_WIN -#define INCL_GPI -#ifdef __WATCOMC__ -# include <os2.h> -#else -# include <os2emx.h> -#endif - typedef struct _cairo_os2_surface { cairo_surface_t base; diff --git a/src/cairo-os2-surface.c b/src/cairo-os2-surface.c index bff649ae..02840e33 100644 --- a/src/cairo-os2-surface.c +++ b/src/cairo-os2-surface.c @@ -43,11 +43,6 @@ #include <float.h> #ifdef BUILD_CAIRO_DLL -# define INCL_WIN -# define INCL_GPI -# define INCL_DOS -# define INCL_DOSERRORS -# include <os2emx.h> # include "cairo-os2.h" # ifndef __WATCOMC__ # include <emx/startup.h> @@ -1331,6 +1326,8 @@ static const cairo_surface_backend_t cairo_os2_surface_backend = { NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ NULL, /* set_clip_region */ diff --git a/src/cairo-os2.h b/src/cairo-os2.h index d0a13e47..0d18674b 100644 --- a/src/cairo-os2.h +++ b/src/cairo-os2.h @@ -38,8 +38,16 @@ #ifndef _CAIRO_OS2_H_ #define _CAIRO_OS2_H_ +#define INCL_DOS +#define INCL_DOSSEMAPHORES +#define INCL_DOSERRORS +#define INCL_WIN +#define INCL_GPI + #include "cairo.h" +#include <os2.h> + CAIRO_BEGIN_DECLS /* The OS/2 Specific Cairo API */ diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h index 787d0616..2b3d584e 100644 --- a/src/cairo-output-stream-private.h +++ b/src/cairo-output-stream-private.h @@ -43,14 +43,20 @@ #include <stdio.h> #include <stdarg.h> -typedef cairo_status_t (*cairo_output_stream_write_func_t) (cairo_output_stream_t *output_stream, - const unsigned char *data, - unsigned int length); +typedef cairo_status_t +(*cairo_output_stream_write_func_t) (cairo_output_stream_t *output_stream, + const unsigned char *data, + unsigned int length); -typedef cairo_status_t (*cairo_output_stream_close_func_t) (cairo_output_stream_t *output_stream); +typedef cairo_status_t +(*cairo_output_stream_flush_func_t) (cairo_output_stream_t *output_stream); + +typedef cairo_status_t +(*cairo_output_stream_close_func_t) (cairo_output_stream_t *output_stream); struct _cairo_output_stream { cairo_output_stream_write_func_t write_func; + cairo_output_stream_flush_func_t flush_func; cairo_output_stream_close_func_t close_func; unsigned long position; cairo_status_t status; @@ -62,6 +68,7 @@ extern const cairo_private cairo_output_stream_t _cairo_output_stream_nil; cairo_private void _cairo_output_stream_init (cairo_output_stream_t *stream, cairo_output_stream_write_func_t write_func, + cairo_output_stream_flush_func_t flush_func, cairo_output_stream_close_func_t close_func); cairo_private cairo_status_t @@ -93,6 +100,10 @@ _cairo_output_stream_create (cairo_write_func_t write_func, cairo_private cairo_output_stream_t * _cairo_output_stream_create_in_error (cairo_status_t status); +/* Tries to flush any buffer maintained by the stream or its delegates. */ +cairo_private cairo_status_t +_cairo_output_stream_flush (cairo_output_stream_t *stream); + /* Returns the final status value associated with this object, just * before its last gasp. This final status value will capture any * status failure returned by the stream's close_func as well. */ @@ -161,6 +172,11 @@ _cairo_memory_stream_copy (cairo_output_stream_t *base, cairo_private int _cairo_memory_stream_length (cairo_output_stream_t *stream); +cairo_private cairo_status_t +_cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream, + unsigned char **data_out, + unsigned int *length_out); + cairo_private cairo_output_stream_t * _cairo_null_stream_create (void); diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c index bae6ac4f..71154339 100644 --- a/src/cairo-output-stream.c +++ b/src/cairo-output-stream.c @@ -70,9 +70,11 @@ void _cairo_output_stream_init (cairo_output_stream_t *stream, cairo_output_stream_write_func_t write_func, + cairo_output_stream_flush_func_t flush_func, cairo_output_stream_close_func_t close_func) { stream->write_func = write_func; + stream->flush_func = flush_func; stream->close_func = close_func; stream->position = 0; stream->status = CAIRO_STATUS_SUCCESS; @@ -87,6 +89,7 @@ _cairo_output_stream_fini (cairo_output_stream_t *stream) const cairo_output_stream_t _cairo_output_stream_nil = { NULL, /* write_func */ + NULL, /* flush_func */ NULL, /* close_func */ 0, /* position */ CAIRO_STATUS_NO_MEMORY, @@ -95,6 +98,7 @@ const cairo_output_stream_t _cairo_output_stream_nil = { static const cairo_output_stream_t _cairo_output_stream_nil_write_error = { NULL, /* write_func */ + NULL, /* flush_func */ NULL, /* close_func */ 0, /* position */ CAIRO_STATUS_WRITE_ERROR, @@ -143,12 +147,13 @@ _cairo_output_stream_create (cairo_write_func_t write_func, cairo_output_stream_with_closure_t *stream; stream = malloc (sizeof (cairo_output_stream_with_closure_t)); - if (stream == NULL) { + if (unlikely (stream == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_output_stream_t *) &_cairo_output_stream_nil; } - _cairo_output_stream_init (&stream->base, closure_write, closure_close); + _cairo_output_stream_init (&stream->base, + closure_write, NULL, closure_close); stream->write_func = write_func; stream->close_func = close_func; stream->closure = closure; @@ -168,18 +173,42 @@ _cairo_output_stream_create_in_error (cairo_status_t status) return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error; stream = malloc (sizeof (cairo_output_stream_t)); - if (stream == NULL) { + if (unlikely (stream == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_output_stream_t *) &_cairo_output_stream_nil; } - _cairo_output_stream_init (stream, NULL, NULL); + _cairo_output_stream_init (stream, NULL, NULL, NULL); stream->status = status; return stream; } cairo_status_t +_cairo_output_stream_flush (cairo_output_stream_t *stream) +{ + cairo_status_t status; + + if (stream->closed) + return stream->status; + + if (stream == &_cairo_output_stream_nil || + stream == &_cairo_output_stream_nil_write_error) + { + return stream->status; + } + + if (stream->flush_func) { + status = stream->flush_func (stream); + /* Don't overwrite a pre-existing status failure. */ + if (stream->status == CAIRO_STATUS_SUCCESS) + stream->status = status; + } + + return stream->status; +} + +cairo_status_t _cairo_output_stream_close (cairo_output_stream_t *stream) { cairo_status_t status; @@ -569,12 +598,13 @@ _cairo_output_stream_create_for_file (FILE *file) } stream = malloc (sizeof *stream); - if (stream == NULL) { + if (unlikely (stream == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_output_stream_t *) &_cairo_output_stream_nil; } - _cairo_output_stream_init (&stream->base, stdio_write, stdio_flush); + _cairo_output_stream_init (&stream->base, + stdio_write, stdio_flush, stdio_flush); stream->file = file; return &stream->base; @@ -602,13 +632,14 @@ _cairo_output_stream_create_for_filename (const char *filename) } stream = malloc (sizeof *stream); - if (stream == NULL) { + if (unlikely (stream == NULL)) { fclose (file); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_output_stream_t *) &_cairo_output_stream_nil; } - _cairo_output_stream_init (&stream->base, stdio_write, stdio_close); + _cairo_output_stream_init (&stream->base, + stdio_write, stdio_flush, stdio_close); stream->file = file; return &stream->base; @@ -645,17 +676,43 @@ _cairo_memory_stream_create (void) memory_stream_t *stream; stream = malloc (sizeof *stream); - if (stream == NULL) { + if (unlikely (stream == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_output_stream_t *) &_cairo_output_stream_nil; } - _cairo_output_stream_init (&stream->base, memory_write, memory_close); + _cairo_output_stream_init (&stream->base, memory_write, NULL, memory_close); _cairo_array_init (&stream->array, 1); return &stream->base; } +cairo_status_t +_cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream, + unsigned char **data_out, + unsigned int *length_out) +{ + memory_stream_t *stream; + cairo_status_t status; + + status = abstract_stream->status; + if (unlikely (status)) + return _cairo_output_stream_destroy (abstract_stream); + + stream = (memory_stream_t *) abstract_stream; + + *length_out = _cairo_array_num_elements (&stream->array); + *data_out = malloc (*length_out); + if (unlikely (*data_out == NULL)) { + status = _cairo_output_stream_destroy (abstract_stream); + assert (status == CAIRO_STATUS_SUCCESS); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + memcpy (*data_out, _cairo_array_index (&stream->array, 0), *length_out); + + return _cairo_output_stream_destroy (abstract_stream); +} + void _cairo_memory_stream_copy (cairo_output_stream_t *base, cairo_output_stream_t *dest) @@ -670,7 +727,7 @@ _cairo_memory_stream_copy (cairo_output_stream_t *base, return; } - _cairo_output_stream_write (dest, + _cairo_output_stream_write (dest, _cairo_array_index (&stream->array, 0), _cairo_array_num_elements (&stream->array)); } @@ -696,12 +753,12 @@ _cairo_null_stream_create (void) cairo_output_stream_t *stream; stream = malloc (sizeof *stream); - if (stream == NULL) { + if (unlikely (stream == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_output_stream_t *) &_cairo_output_stream_nil; } - _cairo_output_stream_init (stream, null_write, NULL); + _cairo_output_stream_init (stream, null_write, NULL, NULL); return stream; } diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c index ec9419bb..ce4e4def 100644 --- a/src/cairo-paginated-surface.c +++ b/src/cairo-paginated-surface.c @@ -77,7 +77,7 @@ _cairo_paginated_surface_create (cairo_surface_t *target, cairo_status_t status; surface = malloc (sizeof (cairo_paginated_surface_t)); - if (surface == NULL) { + if (unlikely (surface == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto FAIL; } @@ -99,7 +99,7 @@ _cairo_paginated_surface_create (cairo_surface_t *target, surface->meta = _cairo_meta_surface_create (content, width, height); status = cairo_surface_status (surface->meta); - if (status) + if (unlikely (status)) goto FAIL_CLEANUP_SURFACE; surface->page_num = 1; @@ -151,7 +151,7 @@ _cairo_paginated_surface_set_size (cairo_surface_t *surface, paginated_surface->meta = _cairo_meta_surface_create (paginated_surface->content, width, height); status = cairo_surface_status (paginated_surface->meta); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (surface, status); return CAIRO_STATUS_SUCCESS; @@ -215,7 +215,7 @@ _cairo_paginated_surface_acquire_source_image (void *abstract_surface, cairo_rectangle_int_t extents; status = _cairo_surface_get_extents (surface->target, &extents); - if (status) + if (unlikely (status)) return status; image = _cairo_paginated_surface_create_image_surface (surface, @@ -223,7 +223,7 @@ _cairo_paginated_surface_acquire_source_image (void *abstract_surface, extents.height); status = _cairo_meta_surface_replay (surface->meta, image); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (image); return status; } @@ -267,7 +267,7 @@ _paint_fallback_image (cairo_paginated_surface_t *surface, cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale); status = _cairo_meta_surface_replay (surface->meta, image); - if (status) + if (unlikely (status)) goto CLEANUP_IMAGE; _cairo_pattern_init_for_surface (&pattern, image); @@ -279,7 +279,7 @@ _paint_fallback_image (cairo_paginated_surface_t *surface, status = _cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, - &pattern.base); + &pattern.base, NULL); _cairo_pattern_fini (&pattern.base); CLEANUP_IMAGE: @@ -318,7 +318,7 @@ _paint_page (cairo_paginated_surface_t *surface) _cairo_analysis_surface_get_bounding_box (analysis, &bbox); status = surface->backend->set_bounding_box (surface->target, &bbox); - if (status) + if (unlikely (status)) goto FAIL; } @@ -327,7 +327,7 @@ _paint_page (cairo_paginated_surface_t *surface) status = surface->backend->set_fallback_images_required (surface->target, has_fallbacks); - if (status) + if (unlikely (status)) goto FAIL; } @@ -360,7 +360,7 @@ _paint_page (cairo_paginated_surface_t *surface) surface->target, CAIRO_META_REGION_NATIVE); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); - if (status) + if (unlikely (status)) goto FAIL; } @@ -375,7 +375,7 @@ _paint_page (cairo_paginated_surface_t *surface) box.p2.x = surface->width; box.p2.y = surface->height; status = _paint_fallback_image (surface, &box); - if (status) + if (unlikely (status)) goto FAIL; } @@ -393,16 +393,19 @@ _paint_page (cairo_paginated_surface_t *surface) CAIRO_FILL_RULE_WINDING, CAIRO_GSTATE_TOLERANCE_DEFAULT, CAIRO_ANTIALIAS_DEFAULT); - if (status) + if (unlikely (status)) goto FAIL; region = _cairo_analysis_surface_get_unsupported (analysis); + + num_boxes = 0; status = _cairo_region_get_boxes (region, &num_boxes, &boxes); - if (status) + if (unlikely (status)) goto FAIL; + for (i = 0; i < num_boxes; i++) { status = _paint_fallback_image (surface, &boxes[i]); - if (status) { + if (unlikely (status)) { _cairo_region_boxes_fini (region, boxes); goto FAIL; } @@ -436,11 +439,11 @@ _cairo_paginated_surface_copy_page (void *abstract_surface) cairo_paginated_surface_t *surface = abstract_surface; status = _start_page (surface); - if (status) + if (unlikely (status)) return status; status = _paint_page (surface); - if (status) + if (unlikely (status)) return status; surface->page_num++; @@ -463,20 +466,20 @@ _cairo_paginated_surface_show_page (void *abstract_surface) cairo_paginated_surface_t *surface = abstract_surface; status = _start_page (surface); - if (status) + if (unlikely (status)) return status; status = _paint_page (surface); - if (status) + if (unlikely (status)) return status; cairo_surface_show_page (surface->target); status = cairo_surface_status (surface->target); - if (status) + if (unlikely (status)) return status; status = cairo_surface_status (surface->meta); - if (status) + if (unlikely (status)) return status; cairo_surface_destroy (surface->meta); @@ -485,7 +488,7 @@ _cairo_paginated_surface_show_page (void *abstract_surface) surface->width, surface->height); status = cairo_surface_status (surface->meta); - if (status) + if (unlikely (status)) return status; surface->page_num++; @@ -529,7 +532,8 @@ _cairo_paginated_surface_get_font_options (void *abstract_surfa static cairo_int_status_t _cairo_paginated_surface_paint (void *abstract_surface, cairo_operator_t op, - const cairo_pattern_t *source) + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents) { cairo_paginated_surface_t *surface = abstract_surface; @@ -539,18 +543,19 @@ _cairo_paginated_surface_paint (void *abstract_surface, surface->page_is_blank = FALSE; - return _cairo_surface_paint (surface->meta, op, source); + return _cairo_surface_paint (surface->meta, op, source, NULL); } static cairo_int_status_t _cairo_paginated_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_pattern_t *mask) + const cairo_pattern_t *mask, + cairo_rectangle_int_t *extents) { cairo_paginated_surface_t *surface = abstract_surface; - return _cairo_surface_mask (surface->meta, op, source, mask); + return _cairo_surface_mask (surface->meta, op, source, mask, NULL); } static cairo_int_status_t @@ -562,7 +567,8 @@ _cairo_paginated_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_paginated_surface_t *surface = abstract_surface; @@ -575,7 +581,7 @@ _cairo_paginated_surface_stroke (void *abstract_surface, return _cairo_surface_stroke (surface->meta, op, source, path, style, ctm, ctm_inverse, - tolerance, antialias); + tolerance, antialias, NULL); } static cairo_int_status_t @@ -585,7 +591,8 @@ _cairo_paginated_surface_fill (void *abstract_surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_paginated_surface_t *surface = abstract_surface; @@ -597,7 +604,7 @@ _cairo_paginated_surface_fill (void *abstract_surface, return _cairo_surface_fill (surface->meta, op, source, path, fill_rule, - tolerance, antialias); + tolerance, antialias, NULL); } static cairo_bool_t @@ -619,7 +626,8 @@ _cairo_paginated_surface_show_text_glyphs (void *abstract_surface, const cairo_text_cluster_t *clusters, int num_clusters, cairo_text_cluster_flags_t cluster_flags, - cairo_scaled_font_t *scaled_font) + cairo_scaled_font_t *scaled_font, + cairo_rectangle_int_t *extents) { cairo_paginated_surface_t *surface = abstract_surface; cairo_int_status_t status; @@ -645,7 +653,7 @@ _cairo_paginated_surface_show_text_glyphs (void *abstract_surface, glyphs, num_glyphs, clusters, num_clusters, cluster_flags, - scaled_font); + scaled_font, NULL); return status; } @@ -670,6 +678,8 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = { NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ _cairo_paginated_surface_copy_page, _cairo_paginated_surface_show_page, NULL, /* set_clip_region */ diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c index 70867e31..6245cd26 100644 --- a/src/cairo-path-bounds.c +++ b/src/cairo-path-bounds.c @@ -132,13 +132,69 @@ _cairo_path_bounder_line_to (void *closure, cairo_point_t *point) } static cairo_status_t +_cairo_path_bounder_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d) +{ + cairo_path_bounder_t *bounder = closure; + + if (bounder->has_move_to_point) { + _cairo_path_bounder_add_point (bounder, + &bounder->move_to_point); + bounder->has_move_to_point = FALSE; + } + + _cairo_path_bounder_add_point (bounder, b); + _cairo_path_bounder_add_point (bounder, c); + _cairo_path_bounder_add_point (bounder, d); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t _cairo_path_bounder_close_path (void *closure) { return CAIRO_STATUS_SUCCESS; } -/* XXX: Perhaps this should compute a PixRegion rather than 4 doubles */ -cairo_status_t +/* This computes the extents of all the points in the path, not those of + * the damage area (i.e it does not consider winding and it only inspects + * the control points of the curves, not the flattened path). + */ +void +_cairo_path_fixed_approximate_extents (cairo_path_fixed_t *path, + cairo_rectangle_int_t *extents) +{ + cairo_path_bounder_t bounder; + cairo_status_t status; + + _cairo_path_bounder_init (&bounder); + + status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, + _cairo_path_bounder_move_to, + _cairo_path_bounder_line_to, + _cairo_path_bounder_curve_to, + _cairo_path_bounder_close_path, + &bounder); + assert (status == CAIRO_STATUS_SUCCESS); + + if (bounder.has_point) { + extents->x = _cairo_fixed_integer_floor (bounder.min_x); + extents->y = _cairo_fixed_integer_floor (bounder.min_y); + extents->width = + _cairo_fixed_integer_ceil (bounder.max_x) - extents->x; + extents->height = + _cairo_fixed_integer_ceil (bounder.max_y) - extents->y; + } else { + extents->x = extents->y = 0; + extents->width = extents->height = 0; + } + + _cairo_path_bounder_fini (&bounder); +} + +void _cairo_path_fixed_bounds (cairo_path_fixed_t *path, double *x1, double *y1, double *x2, double *y2, @@ -155,8 +211,9 @@ _cairo_path_fixed_bounds (cairo_path_fixed_t *path, _cairo_path_bounder_close_path, &bounder, tolerance); + assert (status == CAIRO_STATUS_SUCCESS); - if (status == CAIRO_STATUS_SUCCESS && bounder.has_point) { + if (bounder.has_point) { *x1 = _cairo_fixed_to_double (bounder.min_x); *y1 = _cairo_fixed_to_double (bounder.min_y); *x2 = _cairo_fixed_to_double (bounder.max_x); @@ -169,6 +226,4 @@ _cairo_path_fixed_bounds (cairo_path_fixed_t *path, } _cairo_path_bounder_fini (&bounder); - - return status; } diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c index 1cef20e4..7af91d20 100644 --- a/src/cairo-path-fill.c +++ b/src/cairo-path-fill.c @@ -118,30 +118,23 @@ _cairo_filler_curve_to (void *closure, cairo_point_t *c, cairo_point_t *d) { - int i; - cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_filler_t *filler = closure; - cairo_polygon_t *polygon = &filler->polygon; cairo_spline_t spline; - status = _cairo_spline_init (&spline, &filler->current_point, b, c, d); - - if (status == CAIRO_INT_STATUS_DEGENERATE) + if (! _cairo_spline_init (&spline, + (cairo_add_point_func_t) _cairo_polygon_line_to, + &filler->polygon, + &filler->current_point, b, c, d)) + { return CAIRO_STATUS_SUCCESS; + } - status = _cairo_spline_decompose (&spline, filler->tolerance); - if (status) - goto CLEANUP_SPLINE; - - for (i = 1; i < spline.num_points; i++) - _cairo_polygon_line_to (polygon, &spline.points[i]); - - CLEANUP_SPLINE: + _cairo_spline_decompose (&spline, filler->tolerance); _cairo_spline_fini (&spline); filler->current_point = *d; - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -157,6 +150,7 @@ _cairo_filler_close_path (void *closure) static cairo_int_status_t _cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, cairo_traps_t *traps); cairo_status_t @@ -170,7 +164,7 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, /* Before we do anything else, we use a special-case filler for * a device-axis aligned rectangle if possible. */ - status = _cairo_path_fixed_fill_rectangle (path, traps); + status = _cairo_path_fixed_fill_rectangle (path, fill_rule, traps); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; @@ -183,18 +177,18 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, _cairo_filler_curve_to, _cairo_filler_close_path, &filler); - if (status) + if (unlikely (status)) goto BAIL; _cairo_polygon_close (&filler.polygon); status = _cairo_polygon_status (&filler.polygon); - if (status) + if (unlikely (status)) goto BAIL; status = _cairo_bentley_ottmann_tessellate_polygon (filler.traps, &filler.polygon, fill_rule); - if (status) + if (unlikely (status)) goto BAIL; BAIL: @@ -212,27 +206,77 @@ BAIL: */ static cairo_int_status_t _cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, cairo_traps_t *traps) { - if (_cairo_path_fixed_is_box (path, NULL)) { - cairo_point_t *p = path->buf_head.base.points; - cairo_point_t *top_left, *bot_right; - - top_left = &p[0]; - bot_right = &p[2]; - if (top_left->x > bot_right->x || top_left->y > bot_right->y) { - int n; - - /* not a simple cairo_rectangle() */ - for (n = 0; n < 4; n++) { - if (p[n].x <= top_left->x && p[n].y <= top_left->y) - top_left = &p[n]; - if (p[n].x >= bot_right->x && p[n].y >= bot_right->y) - bot_right = &p[n]; + cairo_box_t box; + + if (_cairo_path_fixed_is_box (path, &box)) { + if (box.p1.x > box.p2.x) { + cairo_fixed_t t; + + t = box.p1.x; + box.p1.x = box.p2.x; + box.p2.x = t; + } + + if (box.p1.y > box.p2.y) { + cairo_fixed_t t; + + t = box.p1.y; + box.p1.y = box.p2.y; + box.p2.y = t; + } + + return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2); + } else if (fill_rule == CAIRO_FILL_RULE_WINDING) { + cairo_path_fixed_iter_t iter; + int last_cw = -1; + + /* Support a series of rectangles as can be expected to describe a + * GdkRegion clip region during exposes. + */ + _cairo_path_fixed_iter_init (&iter, path); + while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) { + cairo_status_t status; + int cw = 0; + + if (box.p1.x > box.p2.x) { + cairo_fixed_t t; + + t = box.p1.x; + box.p1.x = box.p2.x; + box.p2.x = t; + + cw = ! cw; + } + + if (box.p1.y > box.p2.y) { + cairo_fixed_t t; + + t = box.p1.y; + box.p1.y = box.p2.y; + box.p2.y = t; + + cw = ! cw; } + + if (last_cw < 0) { + last_cw = cw; + } else if (last_cw != cw) { + _cairo_traps_clear (traps); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + status = _cairo_traps_tessellate_rectangle (traps, + &box.p1, &box.p2); + if (unlikely (status)) + return status; } + if (_cairo_path_fixed_iter_at_end (&iter)) + return CAIRO_STATUS_SUCCESS; - return _cairo_traps_tessellate_rectangle (traps, top_left, bot_right); + _cairo_traps_clear (traps); } return CAIRO_INT_STATUS_UNSUPPORTED; diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h index 4a5990d4..0ade9880 100644 --- a/src/cairo-path-fixed-private.h +++ b/src/cairo-path-fixed-private.h @@ -37,6 +37,7 @@ #define CAIRO_PATH_FIXED_PRIVATE_H #include "cairo-types-private.h" +#include "cairo-compiler-private.h" enum cairo_path_op { CAIRO_PATH_OP_MOVE_TO = 0, @@ -53,9 +54,9 @@ typedef char cairo_path_op_t; typedef struct _cairo_path_buf { struct _cairo_path_buf *next, *prev; - int buf_size; - int num_ops; - int num_points; + unsigned int buf_size; + unsigned int num_ops; + unsigned int num_points; cairo_path_op_t *op; cairo_point_t *points; @@ -77,4 +78,31 @@ struct _cairo_path_fixed { cairo_path_buf_fixed_t buf_head; }; +cairo_private unsigned long +_cairo_path_fixed_hash (const cairo_path_fixed_t *path); + +cairo_private unsigned long +_cairo_path_fixed_size (const cairo_path_fixed_t *path); + +cairo_private cairo_bool_t +_cairo_path_fixed_equal (const cairo_path_fixed_t *a, + const cairo_path_fixed_t *b); + +typedef struct _cairo_path_fixed_iter { + cairo_path_buf_t *buf; + unsigned int n_op; + unsigned int n_point; +} cairo_path_fixed_iter_t; + +cairo_private void +_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter, + cairo_path_fixed_t *path); + +cairo_private cairo_bool_t +_cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter, + cairo_box_t *box); + +cairo_private cairo_bool_t +_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter); + #endif /* CAIRO_PATH_FIXED_PRIVATE_H */ diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index 90861198..dd25bb88 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -120,7 +120,7 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path, buf_size = MAX (num_ops, (num_points + 1) / 2); if (buf_size) { buf = _cairo_path_buf_create (buf_size); - if (buf == NULL) { + if (unlikely (buf == NULL)) { _cairo_path_fixed_fini (path); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -144,6 +144,170 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path, return CAIRO_STATUS_SUCCESS; } +unsigned long +_cairo_path_fixed_hash (const cairo_path_fixed_t *path) +{ + unsigned long hash = 0; + const cairo_path_buf_t *buf; + int num_points, num_ops; + + hash = _cairo_hash_bytes (hash, + &path->current_point, + sizeof (path->current_point)); + hash = _cairo_hash_bytes (hash, + &path->last_move_point, + sizeof (path->last_move_point)); + + num_ops = path->buf_head.base.num_ops; + num_points = path->buf_head.base.num_points; + for (buf = path->buf_head.base.next; + buf != NULL; + buf = buf->next) + { + hash = _cairo_hash_bytes (hash, buf->op, + buf->num_ops * sizeof (buf->op[0])); + hash = _cairo_hash_bytes (hash, buf->points, + buf->num_points * sizeof (buf->points[0])); + + num_ops += buf->num_ops; + num_points += buf->num_points; + } + + hash = _cairo_hash_bytes (hash, &num_ops, sizeof (num_ops)); + hash = _cairo_hash_bytes (hash, &num_points, sizeof (num_points)); + + return hash; +} + +unsigned long +_cairo_path_fixed_size (const cairo_path_fixed_t *path) +{ + const cairo_path_buf_t *buf; + int num_points, num_ops; + + num_ops = path->buf_head.base.num_ops; + num_points = path->buf_head.base.num_points; + for (buf = path->buf_head.base.next; + buf != NULL; + buf = buf->next) + { + num_ops += buf->num_ops; + num_points += buf->num_points; + } + + return num_ops * sizeof (buf->op[0]) + + num_points * sizeof (buf->points[0]); +} + +cairo_bool_t +_cairo_path_fixed_equal (const cairo_path_fixed_t *a, + const cairo_path_fixed_t *b) +{ + const cairo_path_buf_t *buf_a, *buf_b; + const cairo_path_op_t *ops_a, *ops_b; + const cairo_point_t *points_a, *points_b; + int num_points_a, num_ops_a; + int num_points_b, num_ops_b; + + if (a == b) + return TRUE; + + if (a != NULL) { + num_ops_a = a->buf_head.base.num_ops; + num_points_a = a->buf_head.base.num_points; + for (buf_a = a->buf_head.base.next; + buf_a != NULL; + buf_a = buf_a->next) + { + num_ops_a += buf_a->num_ops; + num_points_a += buf_a->num_points; + } + } else + num_ops_a = num_points_a = 0; + + if (b != NULL) { + num_ops_b = b->buf_head.base.num_ops; + num_points_b = b->buf_head.base.num_points; + for (buf_b = b->buf_head.base.next; + buf_b != NULL; + buf_b = buf_b->next) + { + num_ops_b += buf_b->num_ops; + num_points_b += buf_b->num_points; + } + } else + num_ops_b = num_points_b = 0; + + if (num_ops_a == 0 && num_ops_b == 0) + return TRUE; + + if (num_ops_a != num_ops_b || num_points_a != num_points_b) + return FALSE; + + assert (a != NULL && b != NULL); + + buf_a = &a->buf_head.base; + num_points_a = buf_a->num_points; + num_ops_a = buf_a->num_ops; + ops_a = buf_a->op; + points_a = buf_a->points; + + buf_b = &b->buf_head.base; + num_points_b = buf_b->num_points; + num_ops_b = buf_b->num_ops; + ops_b = buf_b->op; + points_b = buf_b->points; + + while (TRUE) { + int num_ops = MIN (num_ops_a, num_ops_b); + int num_points = MIN (num_points_a, num_points_b); + + if (memcmp (ops_a, ops_b, num_ops * sizeof (cairo_path_op_t))) + return FALSE; + if (memcmp (points_a, points_b, num_points * sizeof (cairo_point_t))) + return FALSE; + + num_ops_a -= num_ops; + ops_a += num_ops; + num_points_a -= num_points; + points_a += num_points; + if (num_ops_a == 0 || num_points_a == 0) { + if (num_ops_a || num_points_a) + return FALSE; + + buf_a = buf_a->next; + if (buf_a == NULL) + break; + + num_points_a = buf_a->num_points; + num_ops_a = buf_a->num_ops; + ops_a = buf_a->op; + points_a = buf_a->points; + } + + num_ops_b -= num_ops; + ops_b += num_ops; + num_points_b -= num_points; + points_b += num_points; + if (num_ops_b == 0 || num_points_b == 0) { + if (num_ops_b || num_points_b) + return FALSE; + + buf_b = buf_b->next; + if (buf_b == NULL) + break; + + num_points_b = buf_b->num_points; + num_ops_b = buf_b->num_ops; + ops_b = buf_b->op; + points_b = buf_b->points; + } + } + + return TRUE; +} + + cairo_path_fixed_t * _cairo_path_fixed_create (void) { @@ -208,7 +372,7 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path, *last_move_to_point = point; } else { status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1); - if (status) + if (unlikely (status)) return status; } @@ -262,7 +426,7 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path, else status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1); - if (status) + if (unlikely (status)) return status; path->current_point = point; @@ -303,12 +467,12 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path, if (! path->has_current_point) { status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point[0], 1); - if (status) + if (unlikely (status)) return status; } status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3); - if (status) + if (unlikely (status)) return status; path->current_point = point[2]; @@ -355,13 +519,13 @@ _cairo_path_fixed_close_path (cairo_path_fixed_t *path) return CAIRO_STATUS_SUCCESS; status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0); - if (status) + if (unlikely (status)) return status; status = _cairo_path_fixed_move_to (path, path->last_move_point.x, path->last_move_point.y); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -393,7 +557,7 @@ _cairo_path_fixed_add (cairo_path_fixed_t *path, buf->num_points + num_points > 2 * buf->buf_size) { buf = _cairo_path_buf_create (buf->buf_size * 2); - if (buf == NULL) + if (unlikely (buf == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_path_fixed_add_buf (path, buf); @@ -528,7 +692,7 @@ _cairo_path_fixed_interpret (const cairo_path_fixed_t *path, status = (*close_path) (closure); break; } - if (status) + if (unlikely (status)) return status; if (forward) { @@ -595,7 +759,7 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path, cairo_fixed_t scaley) { cairo_path_buf_t *buf = &path->buf_head.base; - int i; + unsigned int i; while (buf) { for (i = 0; i < buf->num_points; i++) { @@ -626,7 +790,7 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path, cairo_matrix_t *matrix) { cairo_path_buf_t *buf; - int i; + unsigned int i; double dx, dy; if (matrix->yx == 0.0 && matrix->xy == 0.0) { @@ -726,33 +890,24 @@ _cpf_curve_to (void *closure, cairo_point_t *p3) { cpf_t *cpf = closure; - cairo_status_t status; cairo_spline_t spline; - int i; cairo_point_t *p0 = &cpf->current_point; - status = _cairo_spline_init (&spline, p0, p1, p2, p3); - if (status == CAIRO_INT_STATUS_DEGENERATE) + if (! _cairo_spline_init (&spline, + (cairo_add_point_func_t) cpf->line_to, + cpf->closure, + p0, p1, p2, p3)) + { return CAIRO_STATUS_SUCCESS; - - status = _cairo_spline_decompose (&spline, cpf->tolerance); - if (status) - goto out; - - for (i=1; i < spline.num_points; i++) { - status = cpf->line_to (cpf->closure, &spline.points[i]); - if (status) - goto out; } - cpf->current_point = *p3; + _cairo_spline_decompose (&spline, cpf->tolerance); + _cairo_spline_fini (&spline); - status = CAIRO_STATUS_SUCCESS; + cpf->current_point = *p3; - out: - _cairo_spline_fini (&spline); - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -775,6 +930,15 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path, { cpf_t flattener; + if (!path->has_curve_to) { + return _cairo_path_fixed_interpret (path, dir, + move_to, + line_to, + NULL, + close_path, + closure); + } + flattener.tolerance = tolerance; flattener.move_to = move_to; flattener.line_to = line_to; @@ -847,10 +1011,8 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path, buf->points[2].y == buf->points[3].y && buf->points[3].x == buf->points[0].x) { - if (box) { - box->p1 = buf->points[0]; - box->p2 = buf->points[2]; - } + box->p1 = buf->points[0]; + box->p2 = buf->points[2]; return TRUE; } @@ -859,10 +1021,8 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path, buf->points[2].x == buf->points[3].x && buf->points[3].y == buf->points[0].y) { - if (box) { - box->p1 = buf->points[0]; - box->p2 = buf->points[2]; - } + box->p1 = buf->points[0]; + box->p2 = buf->points[2]; return TRUE; } @@ -894,3 +1054,224 @@ _cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path, return FALSE; } + +void +_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter, + cairo_path_fixed_t *path) +{ + iter->buf = &path->buf_head.base; + iter->n_op = 0; + iter->n_point = 0; +} + +static cairo_bool_t +_cairo_path_fixed_iter_next_op (cairo_path_fixed_iter_t *iter) +{ + if (++iter->n_op >= iter->buf->num_ops) { + iter->buf = iter->buf->next; + iter->n_op = 0; + iter->n_point = 0; + } + + return iter->buf != NULL; +} + +cairo_bool_t +_cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter, + cairo_box_t *box) +{ + cairo_point_t points[5]; + cairo_path_fixed_iter_t iter; + + if (_iter->buf == NULL) + return FALSE; + + iter = *_iter; + + if (iter.n_op == iter.buf->num_ops && + ! _cairo_path_fixed_iter_next_op (&iter)) + { + return FALSE; + } + + /* Check whether the ops are those that would be used for a rectangle */ + if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_MOVE_TO) + return FALSE; + points[0] = iter.buf->points[iter.n_point++]; + if (! _cairo_path_fixed_iter_next_op (&iter)) + return FALSE; + + if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO) + return FALSE; + points[1] = iter.buf->points[iter.n_point++]; + if (! _cairo_path_fixed_iter_next_op (&iter)) + return FALSE; + + if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO) + return FALSE; + points[2] = iter.buf->points[iter.n_point++]; + if (! _cairo_path_fixed_iter_next_op (&iter)) + return FALSE; + + if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO) + return FALSE; + points[3] = iter.buf->points[iter.n_point++]; + if (! _cairo_path_fixed_iter_next_op (&iter)) + return FALSE; + + /* Now, there are choices. The rectangle might end with a LINE_TO + * (to the original point), but this isn't required. If it + * doesn't, then it must end with a CLOSE_PATH (which may be implicit). */ + if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_LINE_TO) + { + points[4] = iter.buf->points[iter.n_point++]; + if (points[4].x != points[0].x || points[4].y != points[0].y) + return FALSE; + } + else if (! (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_CLOSE_PATH || + iter.buf->op[iter.n_op] == CAIRO_PATH_OP_MOVE_TO)) + { + return FALSE; + } + if (! _cairo_path_fixed_iter_next_op (&iter)) + return FALSE; + + /* Ok, we may have a box, if the points line up */ + if (points[0].y == points[1].y && + points[1].x == points[2].x && + points[2].y == points[3].y && + points[3].x == points[0].x) + { + box->p1 = points[0]; + box->p2 = points[2]; + *_iter = iter; + return TRUE; + } + + if (points[0].x == points[1].x && + points[1].y == points[2].y && + points[2].x == points[3].x && + points[3].y == points[0].y) + { + box->p1 = points[0]; + box->p2 = points[2]; + *_iter = iter; + return TRUE; + } + + return FALSE; +} + +cairo_bool_t +_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter) +{ + if (iter->buf == NULL) + return TRUE; + + if (iter->n_op == iter->buf->num_ops) + return TRUE; + + if (iter->buf->op[iter->n_op] == CAIRO_PATH_OP_MOVE_TO && + iter->buf->num_ops == iter->n_op + 1) + { + return TRUE; + } + + return FALSE; +} + +/* Closure for path region testing. Every move_to must be to integer + * coordinates, there must be no curves, and every line_to or + * close_path must represent an axis aligned line to an integer point. + * We're relying on the path interpreter always sending a single + * move_to at the start of any subpath, not receiving having any + * superfluous move_tos, and the path intepreter bailing with our + * first non-successful error. */ +typedef struct cairo_path_region_tester { + cairo_point_t last_move_point; + cairo_point_t current_point; +} cprt_t; + +static cairo_status_t +_cprt_line_to (void *closure, + cairo_point_t *p2) +{ + cprt_t *self = closure; + cairo_point_t *p1 = &self->current_point; + if (p2->x == p1->x) { + if (_cairo_fixed_is_integer(p2->y)) { + *p1 = *p2; + return CAIRO_STATUS_SUCCESS; + } + } + else if (p2->y == p1->y) { + if (_cairo_fixed_is_integer(p2->x)) { + *p1 = *p2; + return CAIRO_STATUS_SUCCESS; + } + } + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_status_t +_cprt_close_path (void *closure) +{ + cprt_t *self = closure; + return _cprt_line_to (closure, &self->last_move_point); +} + +static cairo_status_t +_cprt_move_to (void *closure, + cairo_point_t *p) +{ + cprt_t *self = closure; + cairo_status_t status = _cprt_close_path (closure); + if (status) return status; + if (_cairo_fixed_is_integer(p->x) && + _cairo_fixed_is_integer(p->y)) + { + self->current_point = *p; + self->last_move_point = *p; + return CAIRO_STATUS_SUCCESS; + } + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_status_t +_cprt_curve_to (void *closure, + cairo_point_t *p0, + cairo_point_t *p1, + cairo_point_t *p2) +{ + (void)closure; + (void)p0; + (void)p1; + (void)p2; + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +/** + * Check whether the given path is representable as a region. + * That is, if the path contains only axis aligned lines between + * integer coordinates in device space. + */ +cairo_bool_t +_cairo_path_fixed_is_region (cairo_path_fixed_t *path) +{ + cprt_t cprt; + cairo_status_t status; + if (path->has_curve_to) + return FALSE; + cprt.current_point.x = 0; + cprt.current_point.y = 0; + cprt.last_move_point.x = 0; + cprt.last_move_point.y = 0; + status = _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + _cprt_move_to, + _cprt_line_to, + _cprt_curve_to, + _cprt_close_path, + &cprt); + return status == CAIRO_STATUS_SUCCESS; +} diff --git a/src/cairo-path-in-fill.c b/src/cairo-path-in-fill.c new file mode 100644 index 00000000..0362bfb6 --- /dev/null +++ b/src/cairo-path-in-fill.c @@ -0,0 +1,262 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 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. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +#include "cairoint.h" +#include "cairo-path-fixed-private.h" + +typedef struct cairo_in_fill { + double tolerance; + int winding; + + cairo_fixed_t x, y; + + cairo_bool_t has_current_point; + cairo_point_t current_point; + cairo_point_t first_point; +} cairo_in_fill_t; + +static void +_cairo_in_fill_init (cairo_in_fill_t *in_fill, + double tolerance, + double x, + double y) +{ + in_fill->winding = 0; + in_fill->tolerance = tolerance; + + in_fill->x = _cairo_fixed_from_double (x); + in_fill->y = _cairo_fixed_from_double (y); + + in_fill->has_current_point = FALSE; + in_fill->current_point.x = 0; + in_fill->current_point.y = 0; +} + +static void +_cairo_in_fill_fini (cairo_in_fill_t *in_fill) +{ +} + +static int +edge_compare_for_y_against_x (const cairo_point_t *p1, + const cairo_point_t *p2, + cairo_fixed_t y, + cairo_fixed_t x) +{ + cairo_fixed_t adx, ady; + cairo_fixed_t dx, dy; + cairo_int64_t L, R; + + adx = p2->x - p1->x; + dx = x - p1->x; + + if (adx == 0) + return -dx; + if ((adx ^ dx) < 0) + return adx; + + dy = y - p1->y; + ady = p2->y - p1->y; + + L = _cairo_int32x32_64_mul (dy, adx); + R = _cairo_int32x32_64_mul (dx, ady); + + return _cairo_int64_cmp (L, R); +} + +static void +_cairo_in_fill_add_edge (cairo_in_fill_t *in_fill, + const cairo_point_t *p1, + const cairo_point_t *p2) +{ + int dir; + + /* count the number of edge crossing to -∞ */ + + dir = 1; + if (p2->y < p1->y) { + const cairo_point_t *tmp; + + tmp = p1; + p1 = p2; + p2 = tmp; + + dir = -1; + } + + /* edge is entirely above or below, note the shortening rule */ + if (p2->y <= in_fill->y || p1->y > in_fill->y) + return; + + /* edge lies wholly to the right */ + if (p1->x >= in_fill->x && p2->x >= in_fill->x) + return; + + if ((p1->x <= in_fill->x && p2->x <= in_fill->x) || + edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) <= 0) + { + in_fill->winding += dir; + } +} + +static cairo_status_t +_cairo_in_fill_move_to (void *closure, cairo_point_t *point) +{ + cairo_in_fill_t *in_fill = closure; + + /* implicit close path */ + if (in_fill->has_current_point) { + _cairo_in_fill_add_edge (in_fill, + &in_fill->current_point, + &in_fill->first_point); + } + + in_fill->first_point = *point; + in_fill->current_point = *point; + in_fill->has_current_point = TRUE; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_in_fill_line_to (void *closure, cairo_point_t *point) +{ + cairo_in_fill_t *in_fill = closure; + + if (in_fill->has_current_point) + _cairo_in_fill_add_edge (in_fill, &in_fill->current_point, point); + + in_fill->current_point = *point; + in_fill->has_current_point = TRUE; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_in_fill_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d) +{ + cairo_in_fill_t *in_fill = closure; + cairo_spline_t spline; + cairo_fixed_t top, bot, left; + + /* first reject based on bbox */ + bot = top = in_fill->current_point.y; + if (b->y < top) top = b->y; + if (b->y > bot) bot = b->y; + if (c->y < top) top = c->y; + if (c->y > bot) bot = c->y; + if (d->y < top) top = d->y; + if (d->y > bot) bot = d->y; + if (bot < in_fill->y || top > in_fill->y) + return CAIRO_STATUS_SUCCESS; + + left = in_fill->current_point.x; + if (b->x < left) left = b->x; + if (c->x < left) left = c->x; + if (d->x < left) left = d->x; + if (left > in_fill->x) + return CAIRO_STATUS_SUCCESS; + + /* XXX Investigate direct inspection of the inflections? */ + if (! _cairo_spline_init (&spline, + (cairo_add_point_func_t) _cairo_in_fill_line_to, + in_fill, + &in_fill->current_point, b, c, d)) + { + return CAIRO_STATUS_SUCCESS; + } + + _cairo_spline_decompose (&spline, in_fill->tolerance); + _cairo_spline_fini (&spline); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_in_fill_close_path (void *closure) +{ + cairo_in_fill_t *in_fill = closure; + + if (in_fill->has_current_point) { + _cairo_in_fill_add_edge (in_fill, + &in_fill->current_point, + &in_fill->first_point); + + in_fill->has_current_point = FALSE; + } + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_path_fixed_in_fill (cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + double x, + double y, + cairo_bool_t *is_inside) +{ + cairo_in_fill_t in_fill; + cairo_status_t status; + + _cairo_in_fill_init (&in_fill, tolerance, x, y); + + status = _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + _cairo_in_fill_move_to, + _cairo_in_fill_line_to, + _cairo_in_fill_curve_to, + _cairo_in_fill_close_path, + &in_fill); + assert (status == CAIRO_STATUS_SUCCESS); + + switch (fill_rule) { + case CAIRO_FILL_RULE_EVEN_ODD: + *is_inside = in_fill.winding & 1; + break; + case CAIRO_FILL_RULE_WINDING: + *is_inside = in_fill.winding != 0; + break; + default: + ASSERT_NOT_REACHED; + *is_inside = FALSE; + break; + } + + _cairo_in_fill_fini (&in_fill); +} diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c index efccbcfe..8c3064ea 100644 --- a/src/cairo-path-stroke.c +++ b/src/cairo-path-stroke.c @@ -175,7 +175,7 @@ _cairo_stroker_init (cairo_stroker_t *stroker, status = _cairo_pen_init (&stroker->pen, stroke_style->line_width / 2.0, tolerance, ctm); - if (status) + if (unlikely (status)) return status; stroker->has_current_face = FALSE; @@ -283,13 +283,17 @@ _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); + start = + _cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector); + stop = + _cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector); step = -1; - _cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector, &stop); } else { - _cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector, &start); + start = + _cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector); + stop = + _cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector); step = +1; - _cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector, &stop); } i = start; @@ -494,10 +498,10 @@ _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); + start = _cairo_pen_find_active_cw_vertex_index (pen, &slope); slope.dx = -slope.dx; slope.dy = -slope.dy; - _cairo_pen_find_active_cw_vertex_index (pen, &slope, &stop); + stop = _cairo_pen_find_active_cw_vertex_index (pen, &slope); tri[0] = f->point; tri[1] = f->cw; @@ -654,22 +658,22 @@ _cairo_stroker_add_caps (cairo_stroker_t *stroker) _compute_face (&stroker->first_point, &slope, dx, dy, stroker, &face); status = _cairo_stroker_add_leading_cap (stroker, &face); - if (status) + if (unlikely (status)) return status; status = _cairo_stroker_add_trailing_cap (stroker, &face); - if (status) + if (unlikely (status)) return status; } if (stroker->has_first_face) { status = _cairo_stroker_add_leading_cap (stroker, &stroker->first_face); - if (status) + if (unlikely (status)) return status; } if (stroker->has_current_face) { status = _cairo_stroker_add_trailing_cap (stroker, &stroker->current_face); - if (status) + if (unlikely (status)) return status; } @@ -757,7 +761,7 @@ _cairo_stroker_move_to (void *closure, cairo_point_t *point) /* Cap the start and end of the previous sub path as needed */ status = _cairo_stroker_add_caps (stroker); - if (status) + if (unlikely (status)) return status; stroker->first_point = *point; @@ -802,13 +806,13 @@ _cairo_stroker_line_to (void *closure, cairo_point_t *point) _compute_normalized_device_slope (&slope_dx, &slope_dy, stroker->ctm_inverse, NULL); status = _cairo_stroker_add_sub_edge (stroker, p1, p2, &dev_slope, slope_dx, slope_dy, &start, &end); - if (status) + if (unlikely (status)) return status; if (stroker->has_current_face) { /* Join with final face from previous segment */ status = _cairo_stroker_join (stroker, &stroker->current_face, &start); - if (status) + if (unlikely (status)) return status; } else if (!stroker->has_first_face) { /* Save sub path's first face in case needed for closing join */ @@ -886,7 +890,7 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point) &dev_slope, slope_dx, slope_dy, &sub_start, &sub_end); - if (status) + if (unlikely (status)) return status; if (stroker->has_current_face) { @@ -894,7 +898,7 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point) status = _cairo_stroker_join (stroker, &stroker->current_face, &sub_start); - if (status) + if (unlikely (status)) return status; stroker->has_current_face = FALSE; @@ -905,14 +909,14 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point) } else { /* Cap dash start if not connecting to a previous segment */ status = _cairo_stroker_add_leading_cap (stroker, &sub_start); - if (status) + if (unlikely (status)) return status; } if (remain) { /* Cap dash end if not at end of segment */ status = _cairo_stroker_add_trailing_cap (stroker, &sub_end); - if (status) + if (unlikely (status)) return status; } else { stroker->current_face = sub_end; @@ -923,7 +927,7 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point) /* Cap final face from previous segment */ status = _cairo_stroker_add_trailing_cap (stroker, &stroker->current_face); - if (status) + if (unlikely (status)) return status; stroker->has_current_face = FALSE; @@ -951,7 +955,7 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point) status = _cairo_stroker_add_leading_cap (stroker, &stroker->current_face); - if (status) + if (unlikely (status)) return status; stroker->has_current_face = TRUE; @@ -968,40 +972,51 @@ _cairo_stroker_curve_to (void *closure, cairo_point_t *c, cairo_point_t *d) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_stroker_t *stroker = closure; - cairo_spline_t spline; - cairo_pen_t pen; + cairo_pen_stroke_spline_t spline_pen; cairo_stroke_face_t start, end; cairo_point_t extra_points[4]; cairo_point_t *a = &stroker->current_point; double initial_slope_dx, initial_slope_dy; double final_slope_dx, final_slope_dy; + cairo_status_t status; - status = _cairo_spline_init (&spline, a, b, c, d); + status = _cairo_pen_stroke_spline_init (&spline_pen, + &stroker->pen, + a, b, c, d); if (status == CAIRO_INT_STATUS_DEGENERATE) return _cairo_stroker_line_to (closure, d); + else if (unlikely (status)) + return status; - status = _cairo_pen_init_copy (&pen, &stroker->pen); - if (status) - goto CLEANUP_SPLINE; - - initial_slope_dx = _cairo_fixed_to_double (spline.initial_slope.dx); - initial_slope_dy = _cairo_fixed_to_double (spline.initial_slope.dy); - final_slope_dx = _cairo_fixed_to_double (spline.final_slope.dx); - final_slope_dy = _cairo_fixed_to_double (spline.final_slope.dy); + initial_slope_dx = _cairo_fixed_to_double (spline_pen.spline.initial_slope.dx); + initial_slope_dy = _cairo_fixed_to_double (spline_pen.spline.initial_slope.dy); + final_slope_dx = _cairo_fixed_to_double (spline_pen.spline.final_slope.dx); + final_slope_dy = _cairo_fixed_to_double (spline_pen.spline.final_slope.dy); - if (_compute_normalized_device_slope (&initial_slope_dx, &initial_slope_dy, stroker->ctm_inverse, NULL)) - _compute_face (a, &spline.initial_slope, initial_slope_dx, initial_slope_dy, stroker, &start); + if (_compute_normalized_device_slope (&initial_slope_dx, &initial_slope_dy, + stroker->ctm_inverse, NULL)) + { + _compute_face (a, + &spline_pen.spline.initial_slope, + initial_slope_dx, initial_slope_dy, + stroker, &start); + } - if (_compute_normalized_device_slope (&final_slope_dx, &final_slope_dy, stroker->ctm_inverse, NULL)) - _compute_face (d, &spline.final_slope, final_slope_dx, final_slope_dy, stroker, &end); + if (_compute_normalized_device_slope (&final_slope_dx, &final_slope_dy, + stroker->ctm_inverse, NULL)) + { + _compute_face (d, + &spline_pen.spline.final_slope, + final_slope_dx, final_slope_dy, + stroker, &end); + } if (stroker->has_current_face) { status = _cairo_stroker_join (stroker, &stroker->current_face, &start); - if (status) + if (unlikely (status)) goto CLEANUP_PEN; - } else if (!stroker->has_first_face) { + } else if (! stroker->has_first_face) { stroker->first_face = start; stroker->has_first_face = TRUE; } @@ -1021,18 +1036,16 @@ _cairo_stroker_curve_to (void *closure, extra_points[3].x -= end.point.x; extra_points[3].y -= end.point.y; - status = _cairo_pen_add_points (&pen, extra_points, 4); - if (status) + status = _cairo_pen_add_points (&spline_pen.pen, extra_points, 4); + if (unlikely (status)) goto CLEANUP_PEN; - status = _cairo_pen_stroke_spline (&pen, &spline, stroker->tolerance, stroker->traps); - if (status) - goto CLEANUP_PEN; + status = _cairo_pen_stroke_spline (&spline_pen, + stroker->tolerance, + stroker->traps); CLEANUP_PEN: - _cairo_pen_fini (&pen); - CLEANUP_SPLINE: - _cairo_spline_fini (&spline); + _cairo_pen_stroke_spline_fini (&spline_pen); stroker->current_point = *d; @@ -1063,16 +1076,20 @@ _cairo_stroker_curve_to_dashed (void *closure, cairo_point_t *c, cairo_point_t *d) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_stroker_t *stroker = closure; cairo_spline_t spline; cairo_point_t *a = &stroker->current_point; cairo_line_join_t line_join_save; - int i; - status = _cairo_spline_init (&spline, a, b, c, d); - if (status == CAIRO_INT_STATUS_DEGENERATE) + if (! _cairo_spline_init (&spline, + stroker->dashed ? + (cairo_add_point_func_t) _cairo_stroker_line_to_dashed : + (cairo_add_point_func_t) _cairo_stroker_line_to, + stroker, + a, b, c, d)) + { return _cairo_stroker_line_to_dashed (closure, d); + } /* If the line width is so small that the pen is reduced to a single point, then we have nothing to do. */ @@ -1084,26 +1101,14 @@ _cairo_stroker_curve_to_dashed (void *closure, line_join_save = stroker->style->line_join; stroker->style->line_join = CAIRO_LINE_JOIN_ROUND; - status = _cairo_spline_decompose (&spline, stroker->tolerance); - if (status) - goto CLEANUP_GSTATE; - - for (i = 1; i < spline.num_points; i++) { - if (stroker->dashed) - status = _cairo_stroker_line_to_dashed (stroker, &spline.points[i]); - else - status = _cairo_stroker_line_to (stroker, &spline.points[i]); - if (status) - break; - } + _cairo_spline_decompose (&spline, stroker->tolerance); - CLEANUP_GSTATE: stroker->style->line_join = line_join_save; CLEANUP_SPLINE: _cairo_spline_fini (&spline); - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -1116,18 +1121,18 @@ _cairo_stroker_close_path (void *closure) status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point); else status = _cairo_stroker_line_to (stroker, &stroker->first_point); - if (status) + if (unlikely (status)) return status; if (stroker->has_first_face && stroker->has_current_face) { /* Join first and final faces of sub path */ status = _cairo_stroker_join (stroker, &stroker->current_face, &stroker->first_face); - if (status) + if (unlikely (status)) return status; } else { /* Cap the start and end of the sub path as needed */ status = _cairo_stroker_add_caps (stroker); - if (status) + if (unlikely (status)) return status; } @@ -1170,7 +1175,7 @@ _cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path, status = _cairo_stroker_init (&stroker, stroke_style, ctm, ctm_inverse, tolerance, traps); - if (status) + if (unlikely (status)) return status; if (stroker.style->dash) @@ -1189,7 +1194,7 @@ _cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path, _cairo_stroker_curve_to, _cairo_stroker_close_path, &stroker); - if (status) + if (unlikely (status)) goto BAIL; /* Cap the start and end of the final sub path as needed */ @@ -1249,7 +1254,7 @@ _cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker, if (stroker->segments == stroker->segments_embedded) { new_segments = _cairo_malloc_ab (new_size, sizeof (cairo_line_t)); - if (new_segments == NULL) + if (unlikely (new_segments == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (new_segments, stroker->segments, @@ -1257,7 +1262,7 @@ _cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker, } else { new_segments = _cairo_realloc_ab (stroker->segments, new_size, sizeof (cairo_line_t)); - if (new_segments == NULL) + if (unlikely (new_segments == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -1381,7 +1386,7 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker) } status = _cairo_traps_tessellate_rectangle (stroker->traps, a, b); - if (status) + if (unlikely (status)) return status; } @@ -1398,7 +1403,7 @@ _cairo_rectilinear_stroker_move_to (void *closure, cairo_status_t status; status = _cairo_rectilinear_stroker_emit_segments (stroker); - if (status) + if (unlikely (status)) return status; stroker->current_point = *point; @@ -1444,13 +1449,13 @@ _cairo_rectilinear_stroker_close_path (void *closure) status = _cairo_rectilinear_stroker_line_to (stroker, &stroker->first_point); - if (status) + if (unlikely (status)) return status; stroker->open_sub_path = FALSE; status = _cairo_rectilinear_stroker_emit_segments (stroker); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -1507,7 +1512,7 @@ _cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path, NULL, _cairo_rectilinear_stroker_close_path, &rectilinear_stroker); - if (status) + if (unlikely (status)) goto BAIL; status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker); @@ -1515,7 +1520,7 @@ _cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path, BAIL: _cairo_rectilinear_stroker_fini (&rectilinear_stroker); - if (status) + if (unlikely (status)) _cairo_traps_clear (traps); return status; diff --git a/src/cairo-path.c b/src/cairo-path.c index c6639f3f..84dfc0c4 100644 --- a/src/cairo-path.c +++ b/src/cairo-path.c @@ -127,7 +127,7 @@ _cairo_path_count (cairo_path_t *path, &cpc); } - if (status) + if (unlikely (status)) return -1; return cpc.count; @@ -283,7 +283,7 @@ _cairo_path_populate (cairo_path_t *path, &cpp); } - if (status) + if (unlikely (status)) return status; /* Sanity check the count */ @@ -302,7 +302,7 @@ _cairo_path_create_in_error (cairo_status_t status) return (cairo_path_t*) &_cairo_path_nil; path = malloc (sizeof (cairo_path_t)); - if (path == NULL) { + if (unlikely (path == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_path_t*) &_cairo_path_nil; } @@ -322,7 +322,7 @@ _cairo_path_create_internal (cairo_path_fixed_t *path_fixed, cairo_path_t *path; path = malloc (sizeof (cairo_path_t)); - if (path == NULL) { + if (unlikely (path == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_path_t*) &_cairo_path_nil; } @@ -337,8 +337,8 @@ _cairo_path_create_internal (cairo_path_fixed_t *path_fixed, if (path->num_data) { path->data = _cairo_malloc_ab (path->num_data, - sizeof (cairo_path_data_t)); - if (path->data == NULL) { + sizeof (cairo_path_data_t)); + if (unlikely (path->data == NULL)) { free (path); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_path_t*) &_cairo_path_nil; @@ -474,7 +474,7 @@ _cairo_path_append_to_context (const cairo_path_t *path, } status = cairo_status (cr); - if (status) + if (unlikely (status)) return status; } diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 02b0674f..aa580d55 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -140,7 +140,7 @@ _cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern, { pattern->stops = _cairo_malloc_ab (other->stops_size, sizeof (cairo_gradient_stop_t)); - if (pattern->stops == NULL) { + if (unlikely (pattern->stops == NULL)) { pattern->stops_size = 0; pattern->n_stops = 0; return _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY); @@ -181,7 +181,7 @@ _cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_status_t status; status = _cairo_gradient_pattern_init_copy (dst, src); - if (status) + if (unlikely (status)) return status; } break; @@ -203,7 +203,7 @@ _cairo_pattern_init_snapshot (cairo_pattern_t *pattern, /* We don't bother doing any fancy copy-on-write implementation * for the pattern's data. It's generally quite tiny. */ status = _cairo_pattern_init_copy (pattern, other); - if (status) + if (unlikely (status)) return status; /* But we do let the surface snapshot stuff be as fancy as it @@ -272,11 +272,11 @@ _cairo_pattern_create_copy (cairo_pattern_t **pattern, *pattern = malloc (sizeof (cairo_radial_pattern_t)); break; } - if (*pattern == NULL) + if (unlikely (*pattern == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_pattern_init_copy (*pattern, other); - if (status) { + if (unlikely (status)) { free (*pattern); return status; } @@ -379,18 +379,17 @@ _cairo_pattern_create_solid (const cairo_color_t *color, CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_pattern_cache_lock); - if (pattern == NULL) { + if (unlikely (pattern == NULL)) { /* None cached, need to create a new pattern. */ pattern = malloc (sizeof (cairo_solid_pattern_t)); + if (unlikely (pattern == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_pattern_t *) &_cairo_pattern_nil; + } } - if (pattern == NULL) { - _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); - pattern = (cairo_solid_pattern_t *) &_cairo_pattern_nil; - } else { - _cairo_pattern_init_solid (pattern, color, content); - CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1); - } + _cairo_pattern_init_solid (pattern, color, content); + CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1); return &pattern->base; } @@ -535,7 +534,7 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface) return (cairo_pattern_t*) _cairo_pattern_create_in_error (surface->status); pattern = malloc (sizeof (cairo_surface_pattern_t)); - if (pattern == NULL) { + if (unlikely (pattern == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_pattern_t *)&_cairo_pattern_nil.base; } @@ -581,7 +580,7 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1) cairo_linear_pattern_t *pattern; pattern = malloc (sizeof (cairo_linear_pattern_t)); - if (pattern == NULL) { + if (unlikely (pattern == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_pattern_t *) &_cairo_pattern_nil.base; } @@ -629,7 +628,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0, cairo_radial_pattern_t *pattern; pattern = malloc (sizeof (cairo_radial_pattern_t)); - if (pattern == NULL) { + if (unlikely (pattern == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_pattern_t *) &_cairo_pattern_nil.base; } @@ -686,7 +685,6 @@ cairo_pattern_get_type (cairo_pattern_t *pattern) { return pattern->type; } -slim_hidden_def (cairo_pattern_get_type); /** * cairo_pattern_status: @@ -847,11 +845,11 @@ _cairo_pattern_gradient_grow (cairo_gradient_pattern_t *pattern) memcpy (new_stops, pattern->stops, old_size * sizeof (cairo_gradient_stop_t)); } else { new_stops = _cairo_realloc_ab (pattern->stops, - new_size, + new_size, sizeof (cairo_gradient_stop_t)); } - if (new_stops == NULL) + if (unlikely (new_stops == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); pattern->stops = new_stops; @@ -873,7 +871,7 @@ _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, if (pattern->n_stops >= pattern->stops_size) { cairo_status_t status = _cairo_pattern_gradient_grow (pattern); - if (status) { + if (unlikely (status)) { status = _cairo_pattern_set_error (&pattern->base, status); return; } @@ -1064,7 +1062,7 @@ cairo_pattern_set_matrix (cairo_pattern_t *pattern, inverse = *matrix; status = cairo_matrix_invert (&inverse); - if (status) + if (unlikely (status)) status = _cairo_pattern_set_error (pattern, status); } slim_hidden_def (cairo_pattern_set_matrix); @@ -1256,8 +1254,9 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat cairo_matrix_t matrix = pattern->base.matrix; if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) { - pixman_stops = _cairo_malloc_ab (pattern->n_stops, sizeof(pixman_gradient_stop_t)); - if (pixman_stops == NULL) + pixman_stops = _cairo_malloc_ab (pattern->n_stops, + sizeof(pixman_gradient_stop_t)); + if (unlikely (pixman_stops == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -1341,7 +1340,7 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat if (pixman_stops != pixman_stops_static) free (pixman_stops); - if (pixman_image == NULL) + if (unlikely (pixman_image == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); if (_cairo_surface_is_image (dst)) @@ -1403,7 +1402,8 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat return image->base.status; } - _cairo_matrix_to_pixman_matrix (&matrix, &pixman_transform); + _cairo_matrix_to_pixman_matrix (&matrix, &pixman_transform, + width/2., height/2.); if (!pixman_image_set_transform (pixman_image, &pixman_transform)) { cairo_surface_destroy (&image->base); pixman_image_unref (pixman_image); @@ -1519,7 +1519,7 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt dst)) { status = _cairo_surface_reset (solid_surface_cache.cache[i].surface); - if (status) + if (unlikely (status)) goto UNLOCK; goto DONE; @@ -1531,7 +1531,7 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt dst)) { status = _cairo_surface_reset (solid_surface_cache.cache[i].surface); - if (status) + if (unlikely (status)) goto UNLOCK; goto DONE; @@ -1551,11 +1551,11 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt /* Reuse the surface instead of evicting */ status = _cairo_surface_reset (surface); - if (status) + if (unlikely (status)) goto EVICT; status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern); - if (status) + if (unlikely (status)) goto EVICT; cairo_surface_reference (surface); @@ -1839,14 +1839,14 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat int w, h; status = _cairo_surface_get_extents (surface, &extents); - if (status) + if (unlikely (status)) goto BAIL; - status = _cairo_surface_clone_similar (dst, pattern->surface, + status = _cairo_surface_clone_similar (dst, surface, extents.x, extents.y, extents.width, extents.height, &extents.x, &extents.y, &src); - if (status) + if (unlikely (status)) goto BAIL; w = 2 * extents.width; @@ -1914,14 +1914,14 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat cairo_surface_destroy (src); - if (status) + if (unlikely (status)) goto BAIL; attr->extend = CAIRO_EXTEND_REPEAT; } status = _cairo_surface_get_extents (surface, &extents); - if (status) + if (unlikely (status)) goto BAIL; /* We first transform the rectangle to the coordinate space of the @@ -1969,7 +1969,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat extents.x, extents.y, extents.width, extents.height, &x, &y, out); - if (status) + if (unlikely (status)) goto BAIL; if (x != 0 || y != 0) { @@ -1999,8 +1999,11 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat assert (invert_status == CAIRO_STATUS_SUCCESS); if (m.x0 != 0. || m.y0 != 0.) { - x = floor (m.x0); - y = floor (m.y0); + /* pixman also limits the [xy]_offset to 16 bits so evenly + * spread the bits between the two. + */ + x = floor (m.x0 / 2); + y = floor (m.y0 / 2); attr->x_offset -= x; attr->y_offset -= y; cairo_matrix_init_translate (&m, x, y); @@ -2181,7 +2184,7 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src, src_x, src_y, width, height, src_out, src_attributes); - if (status) + if (unlikely (status)) goto BAIL; if (mask == NULL) { @@ -2193,7 +2196,7 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src, mask_x, mask_y, width, height, mask_out, mask_attributes); - if (status) + if (unlikely (status)) _cairo_pattern_release_surface (src, *src_out, src_attributes); BAIL: @@ -2234,7 +2237,7 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, status = _cairo_surface_get_extents (surface, &surface_extents); if (status == CAIRO_INT_STATUS_UNSUPPORTED) goto UNBOUNDED; - if (status) + if (unlikely (status)) return status; /* The filter can effectively enlarge the extents of the @@ -2290,6 +2293,261 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, return CAIRO_STATUS_SUCCESS; } + +static unsigned long +_cairo_solid_pattern_hash (unsigned long hash, + const cairo_pattern_t *pattern) +{ + const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; + + hash = _cairo_hash_bytes (hash, &solid->content, sizeof (solid->content)); + hash = _cairo_hash_bytes (hash, &solid->color, sizeof (solid->color)); + + return hash; +} + +static unsigned long +_cairo_gradient_color_stops_hash (unsigned long hash, + const cairo_gradient_pattern_t *gradient) +{ + unsigned int n; + + hash = _cairo_hash_bytes (hash, + &gradient->n_stops, + sizeof (gradient->n_stops)); + + for (n = 0; n < gradient->n_stops; n++) { + hash = _cairo_hash_bytes (hash, + &gradient->stops[n].offset, + sizeof (double)); + hash = _cairo_hash_bytes (hash, + &gradient->stops[n].color, + sizeof (cairo_color_t)); + } + + return hash; +} + +static unsigned long +_cairo_linear_pattern_hash (unsigned long hash, + const cairo_pattern_t *pattern) +{ + const cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern; + + hash = _cairo_hash_bytes (hash, &linear->p1, sizeof (linear->p1)); + hash = _cairo_hash_bytes (hash, &linear->p2, sizeof (linear->p2)); + + return _cairo_gradient_color_stops_hash (hash, &linear->base); +} + +static unsigned long +_cairo_radial_pattern_hash (unsigned long hash, const cairo_pattern_t *pattern) +{ + const cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern; + + hash = _cairo_hash_bytes (hash, &radial->c1, sizeof (radial->c1)); + hash = _cairo_hash_bytes (hash, &radial->r1, sizeof (radial->r1)); + hash = _cairo_hash_bytes (hash, &radial->c2, sizeof (radial->c2)); + hash = _cairo_hash_bytes (hash, &radial->r2, sizeof (radial->r2)); + + return _cairo_gradient_color_stops_hash (hash, &radial->base); +} + +static unsigned long +_cairo_surface_pattern_hash (unsigned long hash, + const cairo_pattern_t *pattern) +{ + /* XXX requires cow-snapshots */ + return hash; +} + +unsigned long +_cairo_pattern_hash (const cairo_pattern_t *pattern) +{ + unsigned long hash = _CAIRO_HASH_INIT_VALUE; + + if (pattern->status) + return 0; + + hash = _cairo_hash_bytes (hash, &pattern->type, sizeof (pattern->type)); + hash = _cairo_hash_bytes (hash, &pattern->matrix, sizeof (pattern->matrix)); + hash = _cairo_hash_bytes (hash, &pattern->filter, sizeof (pattern->filter)); + hash = _cairo_hash_bytes (hash, &pattern->extend, sizeof (pattern->extend)); + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + return _cairo_solid_pattern_hash (hash, pattern); + case CAIRO_PATTERN_TYPE_LINEAR: + return _cairo_linear_pattern_hash (hash, pattern); + case CAIRO_PATTERN_TYPE_RADIAL: + return _cairo_radial_pattern_hash (hash, pattern); + case CAIRO_PATTERN_TYPE_SURFACE: + return _cairo_surface_pattern_hash (hash, pattern); + default: + ASSERT_NOT_REACHED; + return FALSE; + } +} + +static unsigned long +_cairo_gradient_pattern_color_stops_size (const cairo_pattern_t *pattern) +{ + cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern; + + return gradient->n_stops * (sizeof (double) + sizeof (cairo_color_t)); +} + +unsigned long +_cairo_pattern_size (const cairo_pattern_t *pattern) +{ + if (pattern->status) + return 0; + + /* XXX */ + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + return sizeof (cairo_solid_pattern_t); + break; + case CAIRO_PATTERN_TYPE_SURFACE: + return sizeof (cairo_surface_pattern_t); + break; + case CAIRO_PATTERN_TYPE_LINEAR: + return sizeof (cairo_linear_pattern_t) + + _cairo_gradient_pattern_color_stops_size (pattern); + break; + case CAIRO_PATTERN_TYPE_RADIAL: + return sizeof (cairo_radial_pattern_t) + + _cairo_gradient_pattern_color_stops_size (pattern); + default: + ASSERT_NOT_REACHED; + return 0; + } +} + + +static cairo_bool_t +_cairo_solid_pattern_equal (const cairo_pattern_t *A, + const cairo_pattern_t *B) +{ + const cairo_solid_pattern_t *a = (cairo_solid_pattern_t *) A; + const cairo_solid_pattern_t *b = (cairo_solid_pattern_t *) B; + + if (a->content != b->content) + return FALSE; + + return _cairo_color_equal (&a->color, &b->color); +} + +static cairo_bool_t +_cairo_gradient_color_stops_equal (const cairo_gradient_pattern_t *a, + const cairo_gradient_pattern_t *b) +{ + unsigned int n; + + if (a->n_stops != b->n_stops) + return FALSE; + + for (n = 0; n < a->n_stops; n++) { + if (a->stops[n].offset != b->stops[n].offset) + return FALSE; + if (! _cairo_color_equal (&a->stops[n].color, &b->stops[n].color)) + return FALSE; + } + + return TRUE; +} + +static cairo_bool_t +_cairo_linear_pattern_equal (const cairo_pattern_t *A, + const cairo_pattern_t *B) +{ + const cairo_linear_pattern_t *a = (cairo_linear_pattern_t *) A; + const cairo_linear_pattern_t *b = (cairo_linear_pattern_t *) B; + + if (a->p1.x != b->p1.x) + return FALSE; + + if (a->p1.y != b->p1.y) + return FALSE; + + if (a->p2.x != b->p2.x) + return FALSE; + + if (a->p2.y != b->p2.y) + return FALSE; + + return _cairo_gradient_color_stops_equal (&a->base, &b->base); +} + +static cairo_bool_t +_cairo_radial_pattern_equal (const cairo_pattern_t *A, + const cairo_pattern_t *B) +{ + const cairo_radial_pattern_t *a = (cairo_radial_pattern_t *) A; + const cairo_radial_pattern_t *b = (cairo_radial_pattern_t *) B; + + if (a->c1.x != b->c1.x) + return FALSE; + + if (a->c1.y != b->c1.y) + return FALSE; + + if (a->r1 != b->r1) + return FALSE; + + if (a->c2.x != b->c2.x) + return FALSE; + + if (a->c2.y != b->c2.y) + return FALSE; + + if (a->r2 != b->r2) + return FALSE; + + return _cairo_gradient_color_stops_equal (&a->base, &b->base); +} + +static cairo_bool_t +_cairo_surface_pattern_equal (const cairo_pattern_t *A, + const cairo_pattern_t *B) +{ + /* XXX requires cow-snapshots */ + return FALSE; +} + +cairo_bool_t +_cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b) +{ + if (a->status || b->status) + return FALSE; + + if (a->type != b->type) + return FALSE; + + if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t))) + return FALSE; + + if (a->filter != b->filter) + return FALSE; + + if (a->extend != b->extend) + return FALSE; + + switch (a->type) { + case CAIRO_PATTERN_TYPE_SOLID: + return _cairo_solid_pattern_equal (a, b); + case CAIRO_PATTERN_TYPE_LINEAR: + return _cairo_linear_pattern_equal (a, b); + case CAIRO_PATTERN_TYPE_RADIAL: + return _cairo_radial_pattern_equal (a, b); + case CAIRO_PATTERN_TYPE_SURFACE: + return _cairo_surface_pattern_equal (a, b); + default: + ASSERT_NOT_REACHED; + return FALSE; + } +} + /** * cairo_pattern_get_rgba * @pattern: a #cairo_pattern_t diff --git a/src/cairo-pdf-operators-private.h b/src/cairo-pdf-operators-private.h index 7ff843b1..4ef0fcae 100644 --- a/src/cairo-pdf-operators-private.h +++ b/src/cairo-pdf-operators-private.h @@ -68,6 +68,7 @@ typedef struct _cairo_pdf_operators { cairo_scaled_font_subsets_t *font_subsets; cairo_pdf_operators_use_font_subset_t use_font_subset; void *use_font_subset_closure; + cairo_bool_t use_actual_text; cairo_bool_t in_text_object; /* inside BT/ET pair */ /* PDF text state */ @@ -115,6 +116,10 @@ cairo_private void _cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators, cairo_matrix_t *cairo_to_pdf); +cairo_private void +_cairo_pdf_operators_enable_actual_text (cairo_pdf_operators_t *pdf_operators, + cairo_bool_t enable); + cairo_private cairo_status_t _cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators); diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c index 819318a1..ea5c5148 100644 --- a/src/cairo-pdf-operators.c +++ b/src/cairo-pdf-operators.c @@ -68,6 +68,7 @@ _cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators, pdf_operators->in_text_object = FALSE; pdf_operators->num_glyphs = 0; pdf_operators->has_line_style = FALSE; + pdf_operators->use_actual_text = FALSE; } cairo_status_t @@ -105,6 +106,13 @@ _cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operato pdf_operators->has_line_style = FALSE; } +cairo_private void +_cairo_pdf_operators_enable_actual_text (cairo_pdf_operators_t *pdf_operators, + cairo_bool_t enable) +{ + pdf_operators->use_actual_text = enable; +} + /* Finish writing out any pending commands to the stream. This * function must be called by the surface before emitting anything * into the PDF stream. @@ -293,13 +301,14 @@ _word_wrap_stream_create (cairo_output_stream_t *output, int max_column) return _cairo_output_stream_create_in_error (output->status); stream = malloc (sizeof (word_wrap_stream_t)); - if (stream == NULL) { + if (unlikely (stream == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_output_stream_t *) &_cairo_output_stream_nil; } _cairo_output_stream_init (&stream->base, _word_wrap_stream_write, + NULL, _word_wrap_stream_close); stream->output = output; stream->max_column = max_column; @@ -438,7 +447,7 @@ _cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators, word_wrap = _word_wrap_stream_create (pdf_operators->stream, 72); status = _cairo_output_stream_get_status (word_wrap); - if (status) + if (unlikely (status)) return _cairo_output_stream_destroy (word_wrap); info.output = word_wrap; @@ -479,7 +488,7 @@ _cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators, path, &pdf_operators->cairo_to_pdf, CAIRO_LINE_CAP_ROUND); - if (status) + if (unlikely (status)) return status; } @@ -560,7 +569,7 @@ _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, */ if (num_dashes % 2) { dash = _cairo_malloc_abc (num_dashes, 2, sizeof (double)); - if (dash == NULL) + if (unlikely (dash == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (dash, style->dash, num_dashes * sizeof (double)); @@ -576,7 +585,7 @@ _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, */ if (dash == style->dash) { dash = _cairo_malloc_ab (num_dashes, sizeof (double)); - if (dash == NULL) + if (unlikely (dash == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (dash, style->dash, num_dashes * sizeof (double)); } @@ -705,7 +714,7 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators, if (pdf_operators->in_text_object) { status = _cairo_pdf_operators_end_text (pdf_operators); - if (status) + if (unlikely (status)) return status; } @@ -744,7 +753,7 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators, _cairo_matrix_factor_out_scale (&m, &scale); path_transform = m; status = cairo_matrix_invert (&path_transform); - if (status) + if (unlikely (status)) return status; cairo_matrix_multiply (&m, &m, &pdf_operators->cairo_to_pdf); @@ -753,7 +762,7 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators, status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style, scale); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; - if (status) + if (unlikely (status)) return status; if (has_ctm) { @@ -769,7 +778,7 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators, path, &path_transform, style->line_cap); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (pdf_operators->stream, "%s", pdf_operator); @@ -806,7 +815,7 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators, if (pdf_operators->in_text_object) { status = _cairo_pdf_operators_end_text (pdf_operators); - if (status) + if (unlikely (status)) return status; } @@ -814,7 +823,7 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators, path, &pdf_operators->cairo_to_pdf, CAIRO_LINE_CAP_ROUND); - if (status) + if (unlikely (status)) return status; switch (fill_rule) { @@ -955,7 +964,7 @@ _cairo_pdf_operators_flush_glyphs (cairo_pdf_operators_t *pdf_operators) word_wrap_stream = _word_wrap_stream_create (pdf_operators->stream, 72); status = _cairo_output_stream_get_status (word_wrap_stream); - if (status) + if (unlikely (status)) return _cairo_output_stream_destroy (word_wrap_stream); /* Check if glyph advance used to position every glyph */ @@ -1014,7 +1023,7 @@ _cairo_pdf_operators_set_text_matrix (cairo_pdf_operators_t *pdf_operators, /* We require the matrix to be invertable. */ inverse = *matrix; status = cairo_matrix_invert (&inverse); - if (status) + if (unlikely (status)) return status; pdf_operators->text_matrix = *matrix; @@ -1103,7 +1112,7 @@ _cairo_pdf_operators_set_font_subset (cairo_pdf_operators_t *pdf_ope status = pdf_operators->use_font_subset (subset_glyph->font_id, subset_glyph->subset_id, pdf_operators->use_font_subset_closure); - if (status) + if (unlikely (status)) return status; } pdf_operators->font_id = subset_glyph->font_id; @@ -1134,7 +1143,7 @@ _cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators) cairo_status_t status; status = _cairo_pdf_operators_flush_glyphs (pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (pdf_operators->stream, "ET\n"); @@ -1168,7 +1177,7 @@ _cairo_pdf_operators_begin_actualtext (cairo_pdf_operators_t *pdf_operators, _cairo_output_stream_printf (pdf_operators->stream, "/Span << /ActualText <feff"); if (utf8_len) { status = _cairo_utf8_to_utf16 (utf8, utf8_len, &utf16, &utf16_len); - if (status) + if (unlikely (status)) return status; for (i = 0; i < utf16_len; i++) { @@ -1203,11 +1212,11 @@ _cairo_pdf_operators_emit_glyph (cairo_pdf_operators_t *pdf_operator pdf_operators->subset_id != subset_glyph->subset_id) { status = _cairo_pdf_operators_flush_glyphs (pdf_operators); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_set_font_subset (pdf_operators, subset_glyph); - if (status) + if (unlikely (status)) return status; pdf_operators->is_new_text_object = FALSE; @@ -1232,14 +1241,14 @@ _cairo_pdf_operators_emit_glyph (cairo_pdf_operators_t *pdf_operator fabs(y - pdf_operators->cur_y) > GLYPH_POSITION_TOLERANCE) { status = _cairo_pdf_operators_flush_glyphs (pdf_operators); - if (status) + if (unlikely (status)) return status; x = glyph->x; y = glyph->y; cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y); status = _cairo_pdf_operators_set_text_position (pdf_operators, x, y); - if (status) + if (unlikely (status)) return status; x = 0.0; @@ -1287,14 +1296,14 @@ _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators, utf8, utf8_len, &subset_glyph); - if (status) + if (unlikely (status)) return status; if (subset_glyph.utf8_is_mapped || utf8_len < 0) { status = _cairo_pdf_operators_emit_glyph (pdf_operators, glyphs, &subset_glyph); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -1304,11 +1313,11 @@ _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators, /* Fallback to using ActualText to map zero or more glyphs to a * unicode string. */ status = _cairo_pdf_operators_flush_glyphs (pdf_operators); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_begin_actualtext (pdf_operators, utf8, utf8_len); - if (status) + if (unlikely (status)) return status; cur_glyph = glyphs; @@ -1320,13 +1329,13 @@ _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators, cur_glyph->index, NULL, -1, &subset_glyph); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_emit_glyph (pdf_operators, cur_glyph, &subset_glyph); - if (status) + if (unlikely (status)) return status; if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)) @@ -1335,7 +1344,7 @@ _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators, cur_glyph++; } status = _cairo_pdf_operators_flush_glyphs (pdf_operators); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_end_actualtext (pdf_operators); @@ -1365,13 +1374,13 @@ _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators, status = cairo_matrix_invert (&pdf_operators->font_matrix_inverse); if (status == CAIRO_STATUS_INVALID_MATRIX) return CAIRO_STATUS_SUCCESS; - if (status) + if (unlikely (status)) return status; pdf_operators->is_new_text_object = FALSE; if (pdf_operators->in_text_object == FALSE) { status = _cairo_pdf_operators_begin_text (pdf_operators); - if (status) + if (unlikely (status)) return status; /* Force Tm and Tf to be emitted when starting a new text @@ -1392,7 +1401,7 @@ _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators, ! _cairo_matrix_scale_equal (&pdf_operators->text_matrix, &text_matrix)) { status = _cairo_pdf_operators_flush_glyphs (pdf_operators); - if (status) + if (unlikely (status)) return status; x = glyphs[0].x; @@ -1403,7 +1412,7 @@ _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators, status = _cairo_pdf_operators_set_text_matrix (pdf_operators, &text_matrix); if (status == CAIRO_STATUS_INVALID_MATRIX) return CAIRO_STATUS_SUCCESS; - if (status) + if (unlikely (status)) return status; } @@ -1423,7 +1432,7 @@ _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators, clusters[i].num_glyphs, cluster_flags, scaled_font); - if (status) + if (unlikely (status)) return status; cur_text += clusters[i].num_bytes; @@ -1439,7 +1448,7 @@ _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators, 1, FALSE, scaled_font); - if (status) + if (unlikely (status)) return status; } } diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h index ab222ded..d2fa43c4 100644 --- a/src/cairo-pdf-surface-private.h +++ b/src/cairo-pdf-surface-private.h @@ -63,6 +63,7 @@ typedef struct _cairo_pdf_group_resources { typedef struct _cairo_pdf_pattern { double width; double height; + cairo_rectangle_int_t extents; cairo_pattern_t *pattern; cairo_pdf_resource_t pattern_res; cairo_pdf_resource_t gstate_res; @@ -127,12 +128,14 @@ struct _cairo_pdf_surface { cairo_pdf_resource_t next_available_resource; cairo_pdf_resource_t pages_resource; + cairo_pdf_version_t pdf_version; cairo_bool_t compress_content; cairo_pdf_resource_t content; cairo_pdf_resource_t content_resources; cairo_pdf_group_resources_t resources; cairo_bool_t has_fallback_images; + cairo_bool_t header_emitted; struct { cairo_bool_t active; diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index b2a5619e..5862c4b5 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -45,6 +45,7 @@ #include "cairo-pdf-surface-private.h" #include "cairo-pdf-operators-private.h" #include "cairo-analysis-surface-private.h" +#include "cairo-image-info-private.h" #include "cairo-meta-surface-private.h" #include "cairo-output-stream-private.h" #include "cairo-paginated-private.h" @@ -110,6 +111,20 @@ * XObject instead of using an indirect object. */ +static const cairo_pdf_version_t _cairo_pdf_versions[] = +{ + CAIRO_PDF_VERSION_1_4, + CAIRO_PDF_VERSION_1_5 +}; + +#define CAIRO_PDF_VERSION_LAST ARRAY_LENGTH (_cairo_pdf_versions) + +static const char * _cairo_pdf_version_strings[CAIRO_PDF_VERSION_LAST] = +{ + "PDF 1.4", + "PDF 1.5" +}; + typedef struct _cairo_pdf_object { long offset; } cairo_pdf_object_t; @@ -192,7 +207,7 @@ _cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface) object.offset = _cairo_output_stream_get_position (surface->output); status = _cairo_array_append (&surface->objects, &object); - if (status) { + if (unlikely (status)) { resource.id = 0; return resource; } @@ -234,7 +249,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, cairo_status_t status, status_ignored; surface = malloc (sizeof (cairo_pdf_surface_t)); - if (surface == NULL) { + if (unlikely (surface == NULL)) { /* destroy stream on behalf of caller */ status = _cairo_output_stream_destroy (output); return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); @@ -272,6 +287,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, goto BAIL1; } + surface->pdf_version = CAIRO_PDF_VERSION_1_5; surface->compress_content = TRUE; surface->pdf_stream.active = FALSE; surface->pdf_stream.old_output = NULL; @@ -284,6 +300,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, surface->force_fallbacks = FALSE; surface->select_pattern_gstate_saved = FALSE; surface->current_pattern_is_solid_color = FALSE; + surface->header_emitted = FALSE; _cairo_pdf_operators_init (&surface->pdf_operators, surface->output, @@ -292,12 +309,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, _cairo_pdf_operators_set_font_subsets_callback (&surface->pdf_operators, _cairo_pdf_surface_add_font, surface); - - /* Document header */ - _cairo_output_stream_printf (surface->output, - "%%PDF-1.4\n"); - _cairo_output_stream_printf (surface->output, - "%%%c%c%c%c\n", 181, 237, 174, 251); + _cairo_pdf_operators_enable_actual_text(&surface->pdf_operators, TRUE); surface->paginated_surface = _cairo_paginated_surface_create ( &surface->base, @@ -437,6 +449,83 @@ _extract_pdf_surface (cairo_surface_t *surface, } /** + * cairo_pdf_surface_restrict_to_version: + * @surface: a PDF #cairo_surface_t + * @version: PDF version + * + * Restricts the generated PDF file to @version. See cairo_pdf_get_versions() + * for a list of available version values that can be used here. + * + * This function should only be called before any drawing operations + * have been performed on the given surface. The simplest way to do + * this is to call this function immediately after creating the + * surface. + * + * Since: 1.10 + **/ +void +cairo_pdf_surface_restrict_to_version (cairo_surface_t *abstract_surface, + cairo_pdf_version_t version) +{ + cairo_pdf_surface_t *surface = NULL; /* hide compiler warning */ + cairo_status_t status; + + status = _extract_pdf_surface (abstract_surface, &surface); + if (status) { + status = _cairo_surface_set_error (abstract_surface, status); + return; + } + + if (version < CAIRO_PDF_VERSION_LAST) + surface->pdf_version = version; + + _cairo_pdf_operators_enable_actual_text(&surface->pdf_operators, + version >= CAIRO_PDF_VERSION_1_5); +} + +/** + * cairo_pdf_get_versions: + * @versions: supported version list + * @num_versions: list length + * + * Used to retrieve the list of supported versions. See + * cairo_pdf_surface_restrict_to_version(). + * + * Since: 1.10 + **/ +void +cairo_pdf_get_versions (cairo_pdf_version_t const **versions, + int *num_versions) +{ + if (versions != NULL) + *versions = _cairo_pdf_versions; + + if (num_versions != NULL) + *num_versions = CAIRO_PDF_VERSION_LAST; +} + +/** + * cairo_pdf_version_to_string: + * @version: a version id + * + * Get the string representation of the given @version id. This function + * will return %NULL if @version isn't valid. See cairo_pdf_get_versions() + * for a way to get the list of valid version ids. + * + * Return value: the string associated to given version. + * + * Since: 1.10 + **/ +const char * +cairo_pdf_version_to_string (cairo_pdf_version_t version) +{ + if (version >= CAIRO_PDF_VERSION_LAST) + return NULL; + + return _cairo_pdf_version_strings[version]; +} + +/** * cairo_pdf_surface_set_size: * @surface: a PDF #cairo_surface_t * @width_in_points: new surface width, in points (1 point == 1/72.0 inch) @@ -462,7 +551,7 @@ cairo_pdf_surface_set_size (cairo_surface_t *surface, cairo_status_t status; status = _extract_pdf_surface (surface, &pdf_surface); - if (status) { + if (unlikely (status)) { status = _cairo_surface_set_error (surface, status); return; } @@ -473,7 +562,7 @@ cairo_pdf_surface_set_size (cairo_surface_t *surface, status = _cairo_paginated_surface_set_size (pdf_surface->paginated_surface, width_in_points, height_in_points); - if (status) + if (unlikely (status)) status = _cairo_surface_set_error (surface, status); } @@ -550,7 +639,7 @@ _cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface, } status = _cairo_array_append (&res->alphas, &alpha); - if (status) + if (unlikely (status)) return status; *index = _cairo_array_num_elements (&res->alphas) - 1; @@ -613,7 +702,7 @@ _cairo_pdf_surface_add_font (unsigned int font_id, return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_array_append (&surface->fonts, &font); - if (status) + if (unlikely (status)) return status; return _cairo_array_append (&res->fonts, &font); @@ -728,7 +817,7 @@ _cairo_pdf_surface_create_smask_group (cairo_pdf_surface_t *surface) cairo_pdf_smask_group_t *group; group = calloc (1, sizeof (cairo_pdf_smask_group_t)); - if (group == NULL) { + if (unlikely (group == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return NULL; } @@ -775,6 +864,7 @@ _cairo_pdf_surface_add_smask_group (cairo_pdf_surface_t *surface, static cairo_status_t _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface, const cairo_pattern_t *pattern, + cairo_rectangle_int_t *extents, cairo_pdf_resource_t *pattern_res, cairo_pdf_resource_t *gstate_res) { @@ -808,7 +898,7 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface, } status = _cairo_pattern_create_copy (&pdf_pattern.pattern, pattern); - if (status) + if (unlikely (status)) return status; pdf_pattern.pattern_res = _cairo_pdf_surface_new_object (surface); @@ -833,11 +923,20 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface, pdf_pattern.width = surface->width; pdf_pattern.height = surface->height; + if (extents) { + pdf_pattern.extents = *extents; + } else { + pdf_pattern.extents.x = 0; + pdf_pattern.extents.y = 0; + pdf_pattern.extents.width = surface->width; + pdf_pattern.extents.height = surface->height; + } + *pattern_res = pdf_pattern.pattern_res; *gstate_res = pdf_pattern.gstate_res; status = _cairo_array_append (&surface->patterns, &pdf_pattern); - if (status) { + if (unlikely (status)) { cairo_pattern_destroy (pdf_pattern.pattern); return status; } @@ -923,7 +1022,7 @@ _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface) return CAIRO_STATUS_SUCCESS; status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; if (surface->pdf_stream.compressed) { @@ -1052,7 +1151,7 @@ _cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t *surface) cairo_status_t status; status = _cairo_pdf_surface_open_group (surface, NULL); - if (status) + if (unlikely (status)) return status; surface->group_stream.is_knockout = TRUE; @@ -1070,7 +1169,7 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface, assert (surface->group_stream.active == TRUE); status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; if (surface->compress_content) { @@ -1138,7 +1237,7 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface, surface->compress_content, NULL); } - if (status) + if (unlikely (status)) return status; surface->content = surface->pdf_stream.self; @@ -1157,12 +1256,12 @@ _cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface) assert (surface->group_stream.active == FALSE); status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, "Q\n"); status = _cairo_pdf_surface_close_stream (surface); - if (status) + if (unlikely (status)) return status; _cairo_pdf_surface_update_object (surface, surface->content_resources); @@ -1280,6 +1379,27 @@ _cairo_pdf_surface_start_page (void *abstract_surface) { cairo_pdf_surface_t *surface = abstract_surface; + /* Document header */ + if (! surface->header_emitted) { + const char *version; + + switch (surface->pdf_version) { + case CAIRO_PDF_VERSION_1_4: + version = "1.4"; + break; + default: + case CAIRO_PDF_VERSION_1_5: + version = "1.5"; + break; + } + + _cairo_output_stream_printf (surface->output, + "%%PDF-%s\n", version); + _cairo_output_stream_printf (surface->output, + "%%%c%c%c%c\n", 181, 237, 174, 251); + surface->header_emitted = TRUE; + } + _cairo_pdf_group_resources_clear (&surface->resources); return CAIRO_STATUS_SUCCESS; @@ -1294,7 +1414,7 @@ _cairo_pdf_surface_has_fallback_images (void *abstract_surface, surface->has_fallback_images = has_fallbacks; status = _cairo_pdf_surface_open_content_stream (surface, has_fallbacks); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -1341,7 +1461,7 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, alpha = _cairo_malloc_ab (image->height, image->width); } - if (alpha == NULL) { + if (unlikely (alpha == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP; } @@ -1395,7 +1515,7 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, " /BitsPerComponent %d\n", image->width, image->height, image->format == CAIRO_FORMAT_A1 ? 1 : 8); - if (status) + if (unlikely (status)) goto CLEANUP_ALPHA; *stream_ret = surface->pdf_stream.self; @@ -1437,7 +1557,7 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface, rgb_size = image->height * image->width * 3; rgb = _cairo_malloc_abc (image->width, image->height, 3); - if (rgb == NULL) { + if (unlikely (rgb == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP; } @@ -1481,7 +1601,7 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface, image->format == CAIRO_FORMAT_A8 || image->format == CAIRO_FORMAT_A1) { status = _cairo_pdf_surface_emit_smask (surface, image, &smask); - if (status) + if (unlikely (status)) goto CLEANUP_RGB; if (smask.id) @@ -1525,7 +1645,7 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface, IMAGE_DICTIONARY, image->width, image->height, interpolate); - if (status) + if (unlikely (status)) goto CLEANUP_RGB; #undef IMAGE_DICTIONARY @@ -1540,27 +1660,188 @@ CLEANUP: return status; } +static cairo_int_status_t +_cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface, + cairo_surface_t *source, + cairo_pdf_resource_t *res, + int *width, + int *height) +{ + cairo_status_t status; + const unsigned char *mime_data; + unsigned int mime_data_length; + cairo_image_info_t info; + + if (surface->pdf_version < CAIRO_PDF_VERSION_1_5) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JP2, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_image_info_get_jpx_info (&info, mime_data, mime_data_length); + if (status) + return status; + + status = _cairo_pdf_surface_open_stream (surface, + NULL, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /Width %d\n" + " /Height %d\n" + " /ColorSpace /DeviceRGB\n" + " /Filter /JPXDecode\n", + info.width, + info.height); + if (status) + return status; + + *res = surface->pdf_stream.self; + _cairo_output_stream_write (surface->output, mime_data, mime_data_length); + _cairo_output_stream_printf (surface->output, "\n"); + status = _cairo_pdf_surface_close_stream (surface); + + *width = info.width; + *height = info.height; + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, + cairo_surface_t *source, + cairo_pdf_resource_t *res, + int *width, + int *height) +{ + cairo_status_t status; + const unsigned char *mime_data; + unsigned int mime_data_length; + cairo_image_info_t info; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length); + if (unlikely (status)) + return status; + + if (info.num_components != 1 && info.num_components != 3) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_pdf_surface_open_stream (surface, + NULL, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /Width %d\n" + " /Height %d\n" + " /ColorSpace %s\n" + " /BitsPerComponent %d\n" + " /Filter /DCTDecode\n", + info.width, + info.height, + info.num_components == 1 ? "/DeviceGray" : "/DeviceRGB", + info.bits_per_component); + if (unlikely (status)) + return status; + + *res = surface->pdf_stream.self; + _cairo_output_stream_write (surface->output, mime_data, mime_data_length); + _cairo_output_stream_printf (surface->output, "\n"); + status = _cairo_pdf_surface_close_stream (surface); + + *width = info.width; + *height = info.height; + + return status; +} + static cairo_status_t _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface, - cairo_surface_pattern_t *pattern, + cairo_pdf_pattern_t *pdf_pattern, cairo_pdf_resource_t *resource, int *width, - int *height) + int *height, + int *origin_x, + int *origin_y) { cairo_image_surface_t *image; + cairo_surface_t *pad_image; void *image_extra; cairo_status_t status; + cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern; + int x = 0; + int y = 0; + + status = _cairo_pdf_surface_emit_jpx_image (surface, pattern->surface, + resource, width, height); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_pdf_surface_emit_jpeg_image (surface, pattern->surface, + resource, width, height); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra); - if (status) + if (unlikely (status)) goto BAIL; - status = _cairo_pdf_surface_emit_image (surface, image, resource, pattern->base.filter); - if (status) + pad_image = &image->base; + if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD) { + cairo_box_t box; + cairo_rectangle_int_t rect; + cairo_surface_pattern_t pad_pattern; + + /* get the operation extents in pattern space */ + _cairo_box_from_rectangle (&box, &pdf_pattern->extents); + _cairo_matrix_transform_bounding_box_fixed (&pattern->base.matrix, &box, NULL); + _cairo_box_round_to_rectangle (&box, &rect); + x = -rect.x; + y = -rect.y; + + pad_image = _cairo_image_surface_create_with_content (pattern->surface->content, + rect.width, + rect.height); + if (pad_image->status) { + status = pad_image->status; + goto BAIL; + } + + _cairo_pattern_init_for_surface (&pad_pattern, &image->base); + cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y); + pad_pattern.base.extend = CAIRO_EXTEND_PAD; + status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, + &pad_pattern.base, + NULL, + pad_image, + 0, 0, + 0, 0, + 0, 0, + rect.width, + rect.height); + _cairo_pattern_fini (&pad_pattern.base); + if (unlikely (status)) + goto BAIL; + } + + status = _cairo_pdf_surface_emit_image (surface, (cairo_image_surface_t *)pad_image, + resource, pattern->base.filter); + if (unlikely (status)) goto BAIL; - *width = image->width; - *height = image->height; + *width = ((cairo_image_surface_t *)pad_image)->width; + *height = ((cairo_image_surface_t *)pad_image)->height; + *origin_x = x; + *origin_y = y; + + if (pad_image != &image->base) + cairo_surface_destroy (pad_image); BAIL: _cairo_surface_release_source_image (pattern->surface, image, image_extra); @@ -1581,7 +1862,7 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface, int alpha = 0; status = _cairo_surface_get_extents (meta_surface, &meta_extents); - if (status) + if (unlikely (status)) return status; old_width = surface->width; @@ -1598,13 +1879,13 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface, surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER; _cairo_pdf_group_resources_clear (&surface->resources); status = _cairo_pdf_surface_open_content_stream (surface, TRUE); - if (status) + if (unlikely (status)) return status; *resource = surface->content; if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) { status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -1617,11 +1898,11 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface, status = _cairo_meta_surface_replay_region (meta_surface, &surface->base, CAIRO_META_REGION_NATIVE); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); - if (status) + if (unlikely (status)) return status; status = _cairo_surface_set_clip (&surface->base, old_clip); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_close_content_stream (surface); @@ -1647,6 +1928,8 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, cairo_rectangle_int_t surface_extents; int pattern_width = 0; /* squelch bogus compiler warning */ int pattern_height = 0; /* squelch bogus compiler warning */ + int origin_x = 0; /* squelch bogus compiler warning */ + int origin_y = 0; /* squelch bogus compiler warning */ int bbox_x, bbox_y; char draw_surface[200]; @@ -1657,33 +1940,34 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, status = _cairo_pdf_surface_emit_meta_surface (surface, meta_surface, &pattern_resource); - if (status) + if (unlikely (status)) return status; status = _cairo_surface_get_extents (meta_surface, &pattern_extents); - if (status) + if (unlikely (status)) return status; pattern_width = pattern_extents.width; pattern_height = pattern_extents.height; } else { status = _cairo_pdf_surface_emit_image_surface (surface, - pattern, + pdf_pattern, &pattern_resource, &pattern_width, - &pattern_height); - if (status) + &pattern_height, + &origin_x, + &origin_y); + if (unlikely (status)) return status; } status = _cairo_surface_get_extents (&surface->base, &surface_extents); - if (status) + if (unlikely (status)) return status; bbox_x = pattern_width; bbox_y = pattern_height; switch (extend) { - /* We implement EXTEND_PAD like EXTEND_NONE for now */ case CAIRO_EXTEND_PAD: case CAIRO_EXTEND_NONE: { @@ -1767,6 +2051,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, cairo_matrix_translate (&pdf_p2d, 0.0, surface_extents.height); cairo_matrix_scale (&pdf_p2d, 1.0, -1.0); cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d); + cairo_matrix_translate (&pdf_p2d, -origin_x, -origin_y); cairo_matrix_translate (&pdf_p2d, 0.0, pattern_height); cairo_matrix_scale (&pdf_p2d, 1.0, -1.0); @@ -1789,7 +2074,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, pdf_p2d.x0, pdf_p2d.y0, pattern_resource.id, pattern_resource.id); - if (status) + if (unlikely (status)) return status; if (_cairo_surface_is_meta (pattern->surface)) { @@ -1827,7 +2112,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, } status = _cairo_pdf_surface_close_stream (surface); - if (status) + if (unlikely (status)) return status; return _cairo_output_stream_get_status (surface->output); @@ -1959,14 +2244,14 @@ _cairo_pdf_surface_emit_stitched_colorgradient (cairo_pdf_surface_t *surface, &stops[i], &stops[i+1], &stops[i].resource); - if (status) + if (unlikely (status)) return status; } else { status = cairo_pdf_surface_emit_rgb_linear_function (surface, &stops[i], &stops[i+1], &stops[i].resource); - if (status) + if (unlikely (status)) return status; } } @@ -2048,7 +2333,7 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, alpha_function->id = 0; allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_pdf_color_stop_t)); - if (allstops == NULL) + if (unlikely (allstops == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); stops = &allstops[1]; @@ -2095,7 +2380,7 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, &stops[0], &stops[1], color_function); - if (status) + if (unlikely (status)) goto BAIL; if (emit_alpha) { @@ -2103,7 +2388,7 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, &stops[0], &stops[1], alpha_function); - if (status) + if (unlikely (status)) goto BAIL; } } else { @@ -2114,7 +2399,7 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, stops, FALSE, color_function); - if (status) + if (unlikely (status)) goto BAIL; if (emit_alpha) { @@ -2123,7 +2408,7 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, stops, TRUE, alpha_function); - if (status) + if (unlikely (status)) goto BAIL; } } @@ -2225,7 +2510,7 @@ cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t *surface, surface->height, gradient_mask.id, gradient_mask.id); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -2240,7 +2525,7 @@ cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t *surface, surface->height); status = _cairo_pdf_surface_close_stream (surface); - if (status) + if (unlikely (status)) return status; smask_resource = _cairo_pdf_surface_new_object (surface); @@ -2363,7 +2648,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface, &pattern->base, &color_function, &alpha_function); - if (status) + if (unlikely (status)) return status; if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT || @@ -2373,7 +2658,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface, &color_function, repeat_begin, repeat_end); - if (status) + if (unlikely (status)) return status; if (alpha_function.id != 0) { @@ -2382,7 +2667,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface, &alpha_function, repeat_begin, repeat_end); - if (status) + if (unlikely (status)) return status; } } @@ -2462,13 +2747,13 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface, ">>\n" "endobj\n"); status = _cairo_pdf_surface_add_pattern (surface, mask_resource); - if (status) + if (unlikely (status)) return status; status = cairo_pdf_surface_emit_transparency_group (surface, pdf_pattern->gstate_res, mask_resource); - if (status) + if (unlikely (status)) return status; } @@ -2494,7 +2779,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface, &pattern->base, &color_function, &alpha_function); - if (status) + if (unlikely (status)) return status; pat_to_pdf = pattern->base.base.matrix; @@ -2585,7 +2870,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface, status = cairo_pdf_surface_emit_transparency_group (surface, pdf_pattern->gstate_res, mask_resource); - if (status) + if (unlikely (status)) return status; } @@ -2668,7 +2953,7 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface, surface->current_color_is_stroke != is_stroke) { status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -2692,11 +2977,11 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface, surface->current_color_alpha != solid_color->alpha) { status = _cairo_pdf_surface_add_alpha (surface, solid_color->alpha, &alpha); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -2708,15 +2993,15 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface, surface->current_pattern_is_solid_color = TRUE; } else { status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_add_pattern (surface, pattern_res); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; /* fill-stroke calls select_pattern twice. Don't save if the @@ -2750,7 +3035,7 @@ _cairo_pdf_surface_unselect_pattern (cairo_pdf_surface_t *surface) if (surface->select_pattern_gstate_saved) { status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, "Q\n"); @@ -2768,11 +3053,11 @@ _cairo_pdf_surface_show_page (void *abstract_surface) cairo_int_status_t status; status = _cairo_pdf_surface_close_content_stream (surface); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_write_page (surface); - if (status) + if (unlikely (status)) return status; _cairo_pdf_surface_clear (surface); @@ -2811,7 +3096,7 @@ _cairo_pdf_surface_intersect_clip_path (void *abstract_surface, if (path == NULL) { status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, "Q q\n"); @@ -2898,7 +3183,7 @@ _cairo_pdf_surface_emit_unicode_for_glyph (cairo_pdf_surface_t *surface, if (utf8 && *utf8) { status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len); - if (status) + if (unlikely (status)) return status; } @@ -2940,7 +3225,7 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface, NULL, surface->compress_content, NULL); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -2992,7 +3277,7 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface, } status = _cairo_pdf_surface_emit_unicode_for_glyph (surface, font_subset->utf8[i + 1]); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -3032,14 +3317,14 @@ _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface, NULL, TRUE, " /Subtype /CIDFontType0C\n"); - if (status) + if (unlikely (status)) return status; stream = surface->pdf_stream.self; _cairo_output_stream_write (surface->output, subset->data, subset->data_length); status = _cairo_pdf_surface_close_stream (surface); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_emit_to_unicode_stream (surface, @@ -3147,7 +3432,7 @@ _cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface, 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) + if (unlikely (status)) return status; status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset); @@ -3168,7 +3453,7 @@ _cairo_pdf_surface_emit_cff_fallback_font (cairo_pdf_surface_t *surface, 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) + if (unlikely (status)) return status; status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset); @@ -3205,13 +3490,13 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface, " /Length3 0\n", subset->header_length, subset->data_length); - if (status) + if (unlikely (status)) return status; stream = surface->pdf_stream.self; _cairo_output_stream_write (surface->output, subset->data, length); status = _cairo_pdf_surface_close_stream (surface); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_emit_to_unicode_stream (surface, @@ -3299,7 +3584,7 @@ _cairo_pdf_surface_emit_type1_font_subset (cairo_pdf_surface_t *surface, snprintf (name, sizeof name, "CairoFont-%d-%d", font_subset->font_id, font_subset->subset_id); status = _cairo_type1_subset_init (&subset, name, font_subset, FALSE); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset); @@ -3320,7 +3605,7 @@ _cairo_pdf_surface_emit_type1_fallback_font (cairo_pdf_surface_t *surface, snprintf (name, sizeof name, "CairoFont-%d-%d", font_subset->font_id, font_subset->subset_id); status = _cairo_type1_fallback_init_binary (&subset, name, font_subset); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset); @@ -3349,7 +3634,7 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface, return CAIRO_STATUS_SUCCESS; status = _cairo_truetype_subset_init (&subset, font_subset); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_open_stream (surface, @@ -3357,7 +3642,7 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface, TRUE, " /Length1 %lu\n", subset.data_length); - if (status) { + if (unlikely (status)) { _cairo_truetype_subset_fini (&subset); return status; } @@ -3366,7 +3651,7 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface, _cairo_output_stream_write (surface->output, subset.data, subset.data_length); status = _cairo_pdf_surface_close_stream (surface); - if (status) { + if (unlikely (status)) { _cairo_truetype_subset_fini (&subset); return status; } @@ -3537,7 +3822,7 @@ _cairo_pdf_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_su for (i = 0; i < font_subset->num_glyphs; i++) { status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface, font_subset->glyphs[i]); - if (status) + if (unlikely (status)) break; } @@ -3572,11 +3857,11 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, return CAIRO_STATUS_SUCCESS; glyphs = _cairo_malloc_ab (font_subset->num_glyphs, sizeof (cairo_pdf_resource_t)); - if (glyphs == NULL) + if (unlikely (glyphs == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); widths = _cairo_malloc_ab (font_subset->num_glyphs, sizeof (double)); - if (widths == NULL) { + if (unlikely (widths == NULL)) { free (glyphs); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -3595,7 +3880,7 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, NULL, surface->compress_content, NULL); - if (status) + if (unlikely (status)) break; glyphs[i] = surface->pdf_stream.self; @@ -3604,11 +3889,11 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, font_subset->glyphs[i], &bbox, &widths[i]); - if (status) + if (unlikely (status)) break; status = _cairo_pdf_surface_close_stream (surface); - if (status) + if (unlikely (status)) break; if (i == 0) { @@ -3628,7 +3913,7 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, } } cairo_surface_destroy (type3_surface); - if (status) { + if (unlikely (status)) { free (glyphs); free (widths); return status; @@ -3787,19 +4072,19 @@ _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface) status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets, _cairo_pdf_surface_analyze_user_font_subset, surface); - if (status) + if (unlikely (status)) goto BAIL; status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets, _cairo_pdf_surface_emit_unscaled_font_subset, surface); - if (status) + if (unlikely (status)) goto BAIL; status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets, _cairo_pdf_surface_emit_scaled_font_subset, surface); - if (status) + if (unlikely (status)) goto BAIL; status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets, @@ -3874,35 +4159,36 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, /* Create mask group */ status = _cairo_pdf_surface_open_group (surface, NULL); - if (status) + if (unlikely (status)) return status; pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask, &pattern_res, &gstate_res); - if (status) + status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask, NULL, + &pattern_res, &gstate_res); + if (unlikely (status)) return status; if (gstate_res.id != 0) { smask_group = _cairo_pdf_surface_create_smask_group (surface); - if (smask_group == NULL) + if (unlikely (smask_group == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); smask_group->operation = PDF_PAINT; smask_group->source = cairo_pattern_reference (group->mask); smask_group->source_res = pattern_res; status = _cairo_pdf_surface_add_smask_group (surface, smask_group); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (smask_group); return status; } status = _cairo_pdf_surface_add_smask (surface, gstate_res); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -3911,7 +4197,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, smask_group->group_res.id); } else { status = _cairo_pdf_surface_select_pattern (surface, group->mask, pattern_res, FALSE); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -3919,45 +4205,46 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, surface->width, surface->height); status = _cairo_pdf_surface_unselect_pattern (surface); - if (status) + if (unlikely (status)) return status; } status = _cairo_pdf_surface_close_group (surface, &mask_group); - if (status) + if (unlikely (status)) return status; /* Create source group */ status = _cairo_pdf_surface_open_group (surface, &group->source_res); - if (status) + if (unlikely (status)) return status; pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source, &pattern_res, &gstate_res); - if (status) + status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source, NULL, + &pattern_res, &gstate_res); + if (unlikely (status)) return status; if (gstate_res.id != 0) { smask_group = _cairo_pdf_surface_create_smask_group (surface); - if (smask_group == NULL) + if (unlikely (smask_group == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); smask_group->operation = PDF_PAINT; smask_group->source = cairo_pattern_reference (group->source); smask_group->source_res = pattern_res; status = _cairo_pdf_surface_add_smask_group (surface, smask_group); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (smask_group); return status; } status = _cairo_pdf_surface_add_smask (surface, gstate_res); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -3966,7 +4253,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, smask_group->group_res.id); } else { status = _cairo_pdf_surface_select_pattern (surface, group->source, pattern_res, FALSE); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -3974,12 +4261,12 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, surface->width, surface->height); status = _cairo_pdf_surface_unselect_pattern (surface); - if (status) + if (unlikely (status)) return status; } status = _cairo_pdf_surface_close_group (surface, NULL); - if (status) + if (unlikely (status)) return status; /* Create an smask based on the alpha component of mask_group */ @@ -4032,14 +4319,14 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface, return _cairo_pdf_surface_write_mask_group (surface, group); status = _cairo_pdf_surface_open_group (surface, &group->group_res); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_select_pattern (surface, group->source, group->source_res, group->operation == PDF_STROKE); - if (status) + if (unlikely (status)) return status; switch (group->operation) { @@ -4072,11 +4359,11 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface, group->scaled_font); break; } - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_unselect_pattern (surface); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_close_group (surface, NULL); @@ -4111,14 +4398,14 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface for (; group_index < _cairo_array_num_elements (&surface->smask_groups); group_index++) { _cairo_array_copy_element (&surface->smask_groups, group_index, &group); status = _cairo_pdf_surface_write_smask_group (surface, group); - if (status) + if (unlikely (status)) return status; } for (; pattern_index < _cairo_array_num_elements (&surface->patterns); pattern_index++) { _cairo_array_copy_element (&surface->patterns, pattern_index, &pattern); status = _cairo_pdf_surface_emit_pattern (surface, &pattern); - if (status) + if (unlikely (status)) return status; } } @@ -4136,7 +4423,7 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface) _cairo_pdf_group_resources_clear (&surface->resources); if (surface->has_fallback_images) { status = _cairo_pdf_surface_open_knockout_group (surface); - if (status) + if (unlikely (status)) return status; len = _cairo_array_num_elements (&surface->knockout_group); @@ -4146,34 +4433,34 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface) "/x%d Do\n", res.id); status = _cairo_pdf_surface_add_xobject (surface, res); - if (status) + if (unlikely (status)) return status; } _cairo_output_stream_printf (surface->output, "/x%d Do\n", surface->content.id); status = _cairo_pdf_surface_add_xobject (surface, surface->content); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_close_group (surface, &knockout); - if (status) + if (unlikely (status)) return status; _cairo_pdf_group_resources_clear (&surface->resources); status = _cairo_pdf_surface_open_content_stream (surface, FALSE); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, "/x%d Do\n", knockout.id); status = _cairo_pdf_surface_add_xobject (surface, knockout); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_close_content_stream (surface); - if (status) + if (unlikely (status)) return status; } @@ -4203,11 +4490,11 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface) surface->content_resources.id); status = _cairo_array_append (&surface->pages, &page); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_write_patterns_and_smask_groups (surface); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -4225,7 +4512,7 @@ _cairo_pdf_surface_analyze_surface_pattern_transparency (cairo_pdf_surface_t status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra); - if (status) + if (unlikely (status)) return status; if (image->base.status) @@ -4346,8 +4633,12 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface, if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; - if ( _cairo_surface_is_meta (surface_pattern->surface)) - return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN; + if ( _cairo_surface_is_meta (surface_pattern->surface)) { + if (pattern->extend == CAIRO_EXTEND_PAD) + return CAIRO_INT_STATUS_UNSUPPORTED; + else + return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN; + } } } @@ -4406,11 +4697,11 @@ _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface) cairo_status_t status; status = _cairo_pdf_surface_close_content_stream (surface); - if (status) + if (unlikely (status)) return status; status = _cairo_array_append (&surface->knockout_group, &surface->content); - if (status) + if (unlikely (status)) return status; _cairo_pdf_group_resources_clear (&surface->resources); @@ -4420,7 +4711,8 @@ _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface) static cairo_int_status_t _cairo_pdf_surface_paint (void *abstract_surface, cairo_operator_t op, - const cairo_pattern_t *source) + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents) { cairo_pdf_surface_t *surface = abstract_surface; cairo_status_t status; @@ -4431,7 +4723,7 @@ _cairo_pdf_surface_paint (void *abstract_surface, return _cairo_pdf_surface_analyze_operation (surface, op, source); } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) { status = _cairo_pdf_surface_start_fallback (surface); - if (status) + if (unlikely (status)) return status; } @@ -4439,40 +4731,41 @@ _cairo_pdf_surface_paint (void *abstract_surface, pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res); + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents, + &pattern_res, &gstate_res); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; - if (status) + if (unlikely (status)) return status; if (gstate_res.id != 0) { group = _cairo_pdf_surface_create_smask_group (surface); - if (group == NULL) + if (unlikely (group == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); group->operation = PDF_PAINT; status = _cairo_pattern_create_copy (&group->source, source); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (group); return status; } group->source_res = pattern_res; status = _cairo_pdf_surface_add_smask_group (surface, group); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (group); return status; } status = _cairo_pdf_surface_add_smask (surface, gstate_res); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_add_xobject (surface, group->group_res); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -4481,7 +4774,7 @@ _cairo_pdf_surface_paint (void *abstract_surface, group->group_res.id); } else { status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -4489,7 +4782,7 @@ _cairo_pdf_surface_paint (void *abstract_surface, surface->width, surface->height); status = _cairo_pdf_surface_unselect_pattern (surface); - if (status) + if (unlikely (status)) return status; } @@ -4500,7 +4793,8 @@ static cairo_int_status_t _cairo_pdf_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_pattern_t *mask) + const cairo_pattern_t *mask, + cairo_rectangle_int_t *extents) { cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_smask_group_t *group; @@ -4521,7 +4815,7 @@ _cairo_pdf_surface_mask (void *abstract_surface, mask_status); } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) { status = _cairo_pdf_surface_start_fallback (surface); - if (status) + if (unlikely (status)) return status; } @@ -4529,17 +4823,17 @@ _cairo_pdf_surface_mask (void *abstract_surface, assert (_cairo_pdf_surface_operation_supported (surface, op, mask)); group = _cairo_pdf_surface_create_smask_group (surface); - if (group == NULL) + if (unlikely (group == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); group->operation = PDF_MASK; status = _cairo_pattern_create_copy (&group->source, source); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (group); return status; } status = _cairo_pattern_create_copy (&group->mask, mask); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (group); return status; } @@ -4550,21 +4844,21 @@ _cairo_pdf_surface_mask (void *abstract_surface, } status = _cairo_pdf_surface_add_smask_group (surface, group); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (group); return status; } status = _cairo_pdf_surface_add_smask (surface, group->group_res); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_add_xobject (surface, group->source_res); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -4584,7 +4878,8 @@ _cairo_pdf_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_pdf_surface_t *surface = abstract_surface; cairo_status_t status; @@ -4598,26 +4893,27 @@ _cairo_pdf_surface_stroke (void *abstract_surface, pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res); + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents, + &pattern_res, &gstate_res); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; - if (status) + if (unlikely (status)) return status; if (gstate_res.id != 0) { group = _cairo_pdf_surface_create_smask_group (surface); - if (group == NULL) + if (unlikely (group == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); group->operation = PDF_STROKE; status = _cairo_pattern_create_copy (&group->source, source); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (group); return status; } group->source_res = pattern_res; status = _cairo_path_fixed_init_copy (&group->path, path); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (group); return status; } @@ -4626,21 +4922,21 @@ _cairo_pdf_surface_stroke (void *abstract_surface, group->ctm = *ctm; group->ctm_inverse = *ctm_inverse; status = _cairo_pdf_surface_add_smask_group (surface, group); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (group); return status; } status = _cairo_pdf_surface_add_smask (surface, gstate_res); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_add_xobject (surface, group->group_res); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -4649,7 +4945,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface, group->group_res.id); } else { status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, TRUE); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_stroke (&surface->pdf_operators, @@ -4657,11 +4953,11 @@ _cairo_pdf_surface_stroke (void *abstract_surface, style, ctm, ctm_inverse); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_unselect_pattern (surface); - if (status) + if (unlikely (status)) return status; } @@ -4675,7 +4971,8 @@ _cairo_pdf_surface_fill (void *abstract_surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_pdf_surface_t *surface = abstract_surface; cairo_status_t status; @@ -4686,7 +4983,7 @@ _cairo_pdf_surface_fill (void *abstract_surface, return _cairo_pdf_surface_analyze_operation (surface, op, source); } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) { status = _cairo_pdf_surface_start_fallback (surface); - if (status) + if (unlikely (status)) return status; } @@ -4694,47 +4991,48 @@ _cairo_pdf_surface_fill (void *abstract_surface, pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res); + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents, + &pattern_res, &gstate_res); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; - if (status) + if (unlikely (status)) return status; if (gstate_res.id != 0) { group = _cairo_pdf_surface_create_smask_group (surface); - if (group == NULL) + if (unlikely (group == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); group->operation = PDF_FILL; status = _cairo_pattern_create_copy (&group->source, source); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (group); return status; } group->source_res = pattern_res; status = _cairo_path_fixed_init_copy (&group->path, path); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (group); return status; } group->fill_rule = fill_rule; status = _cairo_pdf_surface_add_smask_group (surface, group); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (group); return status; } status = _cairo_pdf_surface_add_smask (surface, gstate_res); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_add_xobject (surface, group->group_res); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -4743,17 +5041,17 @@ _cairo_pdf_surface_fill (void *abstract_surface, group->group_res.id); } else { status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_fill (&surface->pdf_operators, path, fill_rule); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_unselect_pattern (surface); - if (status) + if (unlikely (status)) return status; } @@ -4774,7 +5072,8 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, cairo_matrix_t *stroke_ctm, cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, - cairo_antialias_t stroke_antialias) + cairo_antialias_t stroke_antialias, + cairo_rectangle_int_t *extents) { cairo_pdf_surface_t *surface = abstract_surface; cairo_status_t status; @@ -4802,9 +5101,10 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, fill_pattern_res.id = 0; gstate_res.id = 0; status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source, + extents, &fill_pattern_res, &gstate_res); - if (status) + if (unlikely (status)) return status; assert (gstate_res.id == 0); @@ -4813,9 +5113,10 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, gstate_res.id = 0; status = _cairo_pdf_surface_add_pdf_pattern (surface, stroke_source, + extents, &stroke_pattern_res, &gstate_res); - if (status) + if (unlikely (status)) return status; assert (gstate_res.id == 0); @@ -4824,12 +5125,12 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, * select both at the same time */ status = _cairo_pdf_surface_select_pattern (surface, fill_source, fill_pattern_res, FALSE); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_select_pattern (surface, stroke_source, stroke_pattern_res, TRUE); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_fill_stroke (&surface->pdf_operators, @@ -4838,11 +5139,11 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, stroke_style, stroke_ctm, stroke_ctm_inverse); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_unselect_pattern (surface); - if (status) + if (unlikely (status)) return status; return _cairo_output_stream_get_status (surface->output); @@ -4865,7 +5166,8 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, const cairo_text_cluster_t *clusters, int num_clusters, cairo_text_cluster_flags_t cluster_flags, - cairo_scaled_font_t *scaled_font) + cairo_scaled_font_t *scaled_font, + cairo_rectangle_int_t *extents) { cairo_pdf_surface_t *surface = abstract_surface; cairo_status_t status; @@ -4879,20 +5181,21 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res); + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents, + &pattern_res, &gstate_res); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; - if (status) + if (unlikely (status)) return status; if (gstate_res.id != 0) { group = _cairo_pdf_surface_create_smask_group (surface); - if (group == NULL) + if (unlikely (group == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); group->operation = PDF_SHOW_GLYPHS; status = _cairo_pattern_create_copy (&group->source, source); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (group); return status; } @@ -4900,7 +5203,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, if (utf8_len) { group->utf8 = malloc (utf8_len); - if (group->utf8 == NULL) { + if (unlikely (group->utf8 == NULL)) { _cairo_pdf_smask_group_destroy (group); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -4910,7 +5213,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, if (num_glyphs) { group->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); - if (group->glyphs == NULL) { + if (unlikely (group->glyphs == NULL)) { _cairo_pdf_smask_group_destroy (group); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -4920,7 +5223,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, if (num_clusters) { group->clusters = _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t)); - if (group->clusters == NULL) { + if (unlikely (group->clusters == NULL)) { _cairo_pdf_smask_group_destroy (group); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -4930,21 +5233,21 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, group->scaled_font = cairo_scaled_font_reference (scaled_font); status = _cairo_pdf_surface_add_smask_group (surface, group); - if (status) { + if (unlikely (status)) { _cairo_pdf_smask_group_destroy (group); return status; } status = _cairo_pdf_surface_add_smask (surface, gstate_res); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_add_xobject (surface, group->group_res); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -4953,7 +5256,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, group->group_res.id); } else { status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE); - if (status) + if (unlikely (status)) return status; /* Each call to show_glyphs() with a transclucent pattern must @@ -4962,7 +5265,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, * each other. */ if (! _cairo_pattern_is_opaque (source)) { status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; } @@ -4972,11 +5275,11 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, clusters, num_clusters, cluster_flags, scaled_font); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_surface_unselect_pattern (surface); - if (status) + if (unlikely (status)) return status; } @@ -5005,6 +5308,8 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = { NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* _cairo_pdf_surface_copy_page */ _cairo_pdf_surface_show_page, NULL, /* set_clip_region */ diff --git a/src/cairo-pdf.h b/src/cairo-pdf.h index 1a066b3a..294f36d2 100644 --- a/src/cairo-pdf.h +++ b/src/cairo-pdf.h @@ -43,6 +43,19 @@ CAIRO_BEGIN_DECLS +/** + * cairo_pdf_version_t: + * @CAIRO_PDF_VERSION_1_4: The version 1.4 of the PDF specification. + * @CAIRO_PDF_VERSION_1_5: The version 1.5 of the PDF specification. + * + * #cairo_pdf_version_t is used to describe the version number of the PDF + * specification that a generated PDF file will conform to. + */ +typedef enum _cairo_pdf_version { + CAIRO_PDF_VERSION_1_4, + CAIRO_PDF_VERSION_1_5 +} cairo_pdf_version_t; + cairo_public cairo_surface_t * cairo_pdf_surface_create (const char *filename, double width_in_points, @@ -55,6 +68,17 @@ cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, double height_in_points); cairo_public void +cairo_pdf_surface_restrict_to_version (cairo_surface_t *surface, + cairo_pdf_version_t version); + +cairo_public void +cairo_pdf_get_versions (cairo_pdf_version_t const **versions, + int *num_versions); + +cairo_public const char * +cairo_pdf_version_to_string (cairo_pdf_version_t version); + +cairo_public void cairo_pdf_surface_set_size (cairo_surface_t *surface, double width_in_points, double height_in_points); diff --git a/src/cairo-pen.c b/src/cairo-pen.c index 425b3b96..4158f175 100644 --- a/src/cairo-pen.c +++ b/src/cairo-pen.c @@ -1,6 +1,7 @@ /* cairo - a vector graphics library with display and print output * * Copyright © 2002 University of Southern California + * Copyright © 2008 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 @@ -32,6 +33,7 @@ * * Contributor(s): * Carl D. Worth <cworth@cworth.org> + * Chris Wilson <chris@chris-wilson.co.uk> */ #include "cairoint.h" @@ -42,9 +44,6 @@ _cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *mat static void _cairo_pen_compute_slopes (cairo_pen_t *pen); -static void -_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_direction_t dir, cairo_polygon_t *polygon); - cairo_status_t _cairo_pen_init (cairo_pen_t *pen, double radius, @@ -66,7 +65,7 @@ _cairo_pen_init (cairo_pen_t *pen, if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) { pen->vertices = _cairo_malloc_ab (pen->num_vertices, sizeof (cairo_pen_vertex_t)); - if (pen->vertices == NULL) + if (unlikely (pen->vertices == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } else { pen->vertices = pen->vertices_embedded; @@ -104,7 +103,7 @@ _cairo_pen_fini (cairo_pen_t *pen) } cairo_status_t -_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other) +_cairo_pen_init_copy (cairo_pen_t *pen, const cairo_pen_t *other) { *pen = *other; @@ -113,7 +112,7 @@ _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other) if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) { pen->vertices = _cairo_malloc_ab (pen->num_vertices, sizeof (cairo_pen_vertex_t)); - if (pen->vertices == NULL) + if (unlikely (pen->vertices == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -140,7 +139,7 @@ _cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points) if (pen->vertices == pen->vertices_embedded) { vertices = _cairo_malloc_ab (num_vertices, sizeof (cairo_pen_vertex_t)); - if (vertices == NULL) + if (unlikely (vertices == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (vertices, pen->vertices, @@ -149,7 +148,7 @@ _cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points) vertices = _cairo_realloc_ab (pen->vertices, num_vertices, sizeof (cairo_pen_vertex_t)); - if (vertices == NULL) + if (unlikely (vertices == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -163,7 +162,7 @@ _cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points) pen->vertices[pen->num_vertices-num_points+i].point = point[i]; status = _cairo_hull_compute (pen->vertices, &pen->num_vertices); - if (status) + if (unlikely (status)) return status; _cairo_pen_compute_slopes (pen); @@ -323,10 +322,9 @@ _cairo_pen_compute_slopes (cairo_pen_t *pen) * pen's "extra points" from the spline's initial and final slopes are * properly found when beginning the spline stroking.] */ -void -_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen, - cairo_slope_t *slope, - int *active) +int +_cairo_pen_find_active_cw_vertex_index (const cairo_pen_t *pen, + const cairo_slope_t *slope) { int i; @@ -344,7 +342,7 @@ _cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen, if (i == pen->num_vertices) i = 0; - *active = i; + return i; } /* Find active pen vertex for counterclockwise edge of stroke at the given slope. @@ -352,13 +350,12 @@ _cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen, * Note: See the comments for _cairo_pen_find_active_cw_vertex_index * for some details about the strictness of the inequalities here. */ -void -_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen, - cairo_slope_t *slope, - int *active) +int +_cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen, + const cairo_slope_t *slope) { - int i; cairo_slope_t slope_reverse; + int i; slope_reverse = *slope; slope_reverse.dx = -slope_reverse.dx; @@ -378,56 +375,26 @@ _cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen, if (i < 0) i = pen->num_vertices - 1; - *active = i; + return i; } -static void -_cairo_pen_stroke_spline_half (cairo_pen_t *pen, - cairo_spline_t *spline, - cairo_direction_t dir, - cairo_polygon_t *polygon) +static int +_cairo_pen_stroke_spline_add_convolved_point (cairo_pen_stroke_spline_t *stroker, + const cairo_point_t *last_point, + const cairo_slope_t *slope, + cairo_point_t *last_hull_point, + int active, + int step) { - int i; - int start, stop, step; - int active = 0; - cairo_point_t hull_point; - cairo_slope_t slope, initial_slope, final_slope; - cairo_point_t *point = spline->points; - int num_points = spline->num_points; - - if (dir == CAIRO_DIRECTION_FORWARD) { - start = 0; - stop = num_points; - step = 1; - initial_slope = spline->initial_slope; - final_slope = spline->final_slope; - } else { - start = num_points - 1; - stop = -1; - step = -1; - initial_slope = spline->final_slope; - initial_slope.dx = -initial_slope.dx; - initial_slope.dy = -initial_slope.dy; - final_slope = spline->initial_slope; - final_slope.dx = -final_slope.dx; - final_slope.dy = -final_slope.dy; - } - - _cairo_pen_find_active_cw_vertex_index (pen, - &initial_slope, - &active); + do { + cairo_point_t hull_point; - 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; - - _cairo_polygon_line_to (polygon, &hull_point); - - if (i + step == stop) - slope = final_slope; - else - _cairo_slope_init (&slope, &point[i], &point[i+step]); + hull_point.x = last_point->x + stroker->pen.vertices[active].point.x; + hull_point.y = last_point->y + stroker->pen.vertices[active].point.y; + _cairo_polygon_add_edge (&stroker->polygon, + last_hull_point, &hull_point, + step); + *last_hull_point = hull_point; /* The strict inequalities here ensure that if a spline slope * compares identically with either of the slopes of the @@ -439,53 +406,164 @@ _cairo_pen_stroke_spline_half (cairo_pen_t *pen, * consider it unequal and reject. This is due to the inherent * ambiguity when comparing slopes that differ by exactly * pi. */ - if (_cairo_slope_compare (&slope, &pen->vertices[active].slope_ccw) > 0) { - if (++active == pen->num_vertices) + if (_cairo_slope_compare (slope, + &stroker->pen.vertices[active].slope_ccw) > 0) + { + if (++active == stroker->pen.num_vertices) active = 0; - } else if (_cairo_slope_compare (&slope, &pen->vertices[active].slope_cw) < 0) { + } + else if (_cairo_slope_compare (slope, + &stroker->pen.vertices[active].slope_cw) < 0) + { if (--active == -1) - active = pen->num_vertices - 1; - } else { - i += step; + active = stroker->pen.num_vertices - 1; } - } + else + { + return active; + } + } while (TRUE); } + /* Compute outline of a given spline using the pen. - The trapezoids needed to fill that outline will be added to traps -*/ + * The trapezoids needed to fill that outline will be added to traps + */ cairo_status_t -_cairo_pen_stroke_spline (cairo_pen_t *pen, - cairo_spline_t *spline, - double tolerance, - cairo_traps_t *traps) +_cairo_pen_stroke_spline (cairo_pen_stroke_spline_t *stroker, + double tolerance, + cairo_traps_t *traps) { cairo_status_t status; - cairo_polygon_t polygon; + cairo_slope_t slope; /* If the line width is so small that the pen is reduced to a single point, then we have nothing to do. */ - if (pen->num_vertices <= 1) + if (stroker->pen.num_vertices <= 1) return CAIRO_STATUS_SUCCESS; - _cairo_polygon_init (&polygon); - - status = _cairo_spline_decompose (spline, tolerance); - if (status) + /* open the polygon */ + slope = stroker->spline.initial_slope; + stroker->forward_vertex = + _cairo_pen_find_active_cw_vertex_index (&stroker->pen, &slope); + stroker->forward_hull_point.x = stroker->last_point.x + + stroker->pen.vertices[stroker->forward_vertex].point.x; + stroker->forward_hull_point.y = stroker->last_point.y + + stroker->pen.vertices[stroker->forward_vertex].point.y; + + slope.dx = -slope.dx; + slope.dy = -slope.dy; + stroker->backward_vertex = + _cairo_pen_find_active_cw_vertex_index (&stroker->pen, &slope); + stroker->backward_hull_point.x = stroker->last_point.x + + stroker->pen.vertices[stroker->backward_vertex].point.x; + stroker->backward_hull_point.y = stroker->last_point.y + + stroker->pen.vertices[stroker->backward_vertex].point.y; + + _cairo_polygon_add_edge (&stroker->polygon, + &stroker->backward_hull_point, + &stroker->forward_hull_point, + 1); + + _cairo_spline_decompose (&stroker->spline, tolerance); + + /* close the polygon */ + slope = stroker->spline.final_slope; + _cairo_pen_stroke_spline_add_convolved_point (stroker, + &stroker->last_point, + &slope, + &stroker->forward_hull_point, + stroker->forward_vertex, + 1); + + slope.dx = -slope.dx; + slope.dy = -slope.dy; + _cairo_pen_stroke_spline_add_convolved_point (stroker, + &stroker->last_point, + &slope, + &stroker->backward_hull_point, + stroker->backward_vertex, + -1); + + _cairo_polygon_add_edge (&stroker->polygon, + &stroker->forward_hull_point, + &stroker->backward_hull_point, + 1); + + status = _cairo_polygon_status (&stroker->polygon); + if (unlikely (status)) goto BAIL; - _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_FORWARD, &polygon); + status = _cairo_bentley_ottmann_tessellate_polygon (traps, + &stroker->polygon, + CAIRO_FILL_RULE_WINDING); +BAIL: - _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_REVERSE, &polygon); + return status; +} - _cairo_polygon_close (&polygon); - status = _cairo_polygon_status (&polygon); - if (status) - goto BAIL; +static void +_cairo_pen_stroke_spline_add_point (cairo_pen_stroke_spline_t *stroker, + const cairo_point_t *point) +{ + cairo_slope_t slope; + + _cairo_slope_init (&slope, &stroker->last_point, point); + stroker->forward_vertex = + _cairo_pen_stroke_spline_add_convolved_point (stroker, + &stroker->last_point, + &slope, + &stroker->forward_hull_point, + stroker->forward_vertex, + 1); + + slope.dx = -slope.dx; + slope.dy = -slope.dy; + stroker->backward_vertex = + _cairo_pen_stroke_spline_add_convolved_point (stroker, + &stroker->last_point, + &slope, + &stroker->backward_hull_point, + stroker->backward_vertex, + -1); + stroker->last_point = *point; +} - status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING); -BAIL: - _cairo_polygon_fini (&polygon); +cairo_int_status_t +_cairo_pen_stroke_spline_init (cairo_pen_stroke_spline_t *stroker, + const cairo_pen_t *pen, + const cairo_point_t *a, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d) +{ + cairo_int_status_t status; - return status; + if (! _cairo_spline_init (&stroker->spline, + (cairo_add_point_func_t) _cairo_pen_stroke_spline_add_point, + stroker, + a, b, c, d)) + { + return CAIRO_INT_STATUS_DEGENERATE; + } + + status = _cairo_pen_init_copy (&stroker->pen, pen); + if (unlikely (status)) { + _cairo_spline_fini (&stroker->spline); + return status; + } + + _cairo_polygon_init (&stroker->polygon); + + stroker->last_point = *a; + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_pen_stroke_spline_fini (cairo_pen_stroke_spline_t *stroker) +{ + _cairo_polygon_fini (&stroker->polygon); + _cairo_spline_fini (&stroker->spline); + _cairo_pen_fini (&stroker->pen); } diff --git a/src/cairo-png.c b/src/cairo-png.c index 06e7cb55..fd16c4dc 100644 --- a/src/cairo-png.c +++ b/src/cairo-png.c @@ -37,10 +37,19 @@ */ #include "cairoint.h" +#include "cairo-output-stream-private.h" +#include <stdio.h> #include <errno.h> #include <png.h> +struct png_read_closure_t { + cairo_read_func_t read_func; + void *closure; + cairo_output_stream_t *png_data; +}; + + /* Unpremultiplies data and converts native endian ARGB => RGBA bytes */ static void unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data) @@ -139,6 +148,8 @@ write_png (cairo_surface_t *surface, png_info *info; png_byte **volatile rows = NULL; png_color_16 white; + const unsigned char *mime_data; + unsigned int mime_data_length; int png_color_type; int depth; @@ -148,7 +159,7 @@ write_png (cairo_surface_t *surface, if (status == CAIRO_INT_STATUS_UNSUPPORTED) return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); - else if (status) + else if (unlikely (status)) return status; /* PNG complains about "Image width or height is zero in IHDR" */ @@ -158,7 +169,7 @@ write_png (cairo_surface_t *surface, } rows = _cairo_malloc_ab (image->height, sizeof (png_byte*)); - if (rows == NULL) { + if (unlikely (rows == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto BAIL1; } @@ -169,13 +180,13 @@ write_png (cairo_surface_t *surface, png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status, png_simple_error_callback, png_simple_warning_callback); - if (png == NULL) { + if (unlikely (png == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto BAIL2; } info = png_create_info_struct (png); - if (info == NULL) { + if (unlikely (info == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto BAIL3; } @@ -187,10 +198,25 @@ write_png (cairo_surface_t *surface, png_set_write_fn (png, closure, write_func, png_simple_output_flush_fn); + /* XXX This is very questionable. + * This breaks the read_from_png(); draw(); write_to_png(); cycle, but + * that is affected by mime-data in general. OTOH, by using mime-data + * here we are consistent with the other backends. + */ + cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_PNG, + &mime_data, &mime_data_length); + if (mime_data != NULL) { + write_func (png, (png_bytep) mime_data, mime_data_length); + goto BAIL3; + } + switch (image->format) { case CAIRO_FORMAT_ARGB32: depth = 8; - png_color_type = PNG_COLOR_TYPE_RGB_ALPHA; + if (_cairo_image_analyze_transparency (image) == CAIRO_IMAGE_IS_OPAQUE) + png_color_type = PNG_COLOR_TYPE_RGB; + else + png_color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; case CAIRO_FORMAT_RGB24: depth = 8; @@ -237,12 +263,12 @@ write_png (cairo_surface_t *surface, */ png_write_info (png, info); - if (image->format == CAIRO_FORMAT_ARGB32) + if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) { png_set_write_user_transform_fn (png, unpremultiply_data); - else if (image->format == CAIRO_FORMAT_RGB24) + } else if (png_color_type == PNG_COLOR_TYPE_RGB) { png_set_write_user_transform_fn (png, convert_data_to_bytes); - if (image->format == CAIRO_FORMAT_RGB24) png_set_filler (png, 0, PNG_FILLER_AFTER); + } png_write_image (png, rows); png_write_end (png, info); @@ -335,7 +361,7 @@ stream_write_func (png_structp png, png_bytep data, png_size_t size) png_closure = png_get_io_ptr (png); status = png_closure->write_func (png_closure->closure, data, size); - if (status) { + if (unlikely (status)) { cairo_status_t *error = png_get_error_ptr (png); if (*error == CAIRO_STATUS_SUCCESS) *error = status; @@ -433,9 +459,45 @@ convert_bytes_to_data (png_structp png, png_row_infop row_info, png_bytep data) } } +static cairo_status_t +stdio_read_func (void *closure, unsigned char *data, unsigned int size) +{ + FILE *file = closure; + + while (size) { + size_t ret; + + ret = fread (data, 1, size, file); + size -= ret; + data += ret; + + if (size && (feof (file) || ferror (file))) + return _cairo_error (CAIRO_STATUS_READ_ERROR); + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +stream_read_func (png_structp png, png_bytep data, png_size_t size) +{ + cairo_status_t status; + struct png_read_closure_t *png_closure; + + png_closure = png_get_io_ptr (png); + status = png_closure->read_func (png_closure->closure, data, size); + if (unlikely (status)) { + cairo_status_t *error = png_get_error_ptr (png); + if (*error == CAIRO_STATUS_SUCCESS) + *error = status; + png_error (png, NULL); + } + + _cairo_output_stream_write (png_closure->png_data, data, size); +} + static cairo_surface_t * -read_png (png_rw_ptr read_func, - void *closure) +read_png (struct png_read_closure_t *png_closure) { cairo_surface_t *surface; png_struct *png = NULL; @@ -447,24 +509,28 @@ read_png (png_rw_ptr read_func, unsigned int i; cairo_format_t format; cairo_status_t status; + unsigned char *mime_data; + unsigned int mime_data_length; + + png_closure->png_data = _cairo_memory_stream_create (); /* XXX: Perhaps we'll want some other error handlers? */ png = png_create_read_struct (PNG_LIBPNG_VER_STRING, &status, png_simple_error_callback, png_simple_warning_callback); - if (png == NULL) { + if (unlikely (png == NULL)) { surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); goto BAIL; } info = png_create_info_struct (png); - if (info == NULL) { + if (unlikely (info == NULL)) { surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); goto BAIL; } - png_set_read_fn (png, closure, read_func); + png_set_read_fn (png, png_closure, stream_read_func); status = CAIRO_STATUS_SUCCESS; #ifdef PNG_SETJMP_SUPPORTED @@ -479,7 +545,7 @@ read_png (png_rw_ptr read_func, png_get_IHDR (png, info, &png_width, &png_height, &depth, &color_type, &interlace, NULL, NULL); - if (status) { /* catch any early warnings */ + if (unlikely (status)) { /* catch any early warnings */ surface = _cairo_surface_create_in_error (status); goto BAIL; } @@ -555,13 +621,13 @@ read_png (png_rw_ptr read_func, } data = _cairo_malloc_ab (png_height, stride); - if (data == NULL) { + if (unlikely (data == NULL)) { surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); goto BAIL; } row_pointers = _cairo_malloc_ab (png_height, sizeof (char *)); - if (row_pointers == NULL) { + if (unlikely (row_pointers == NULL)) { surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); goto BAIL; } @@ -572,7 +638,7 @@ read_png (png_rw_ptr read_func, png_read_image (png, row_pointers); png_read_end (png, info); - if (status) { /* catch any late warnings - probably hit an error already */ + if (unlikely (status)) { /* catch any late warnings - probably hit an error already */ surface = _cairo_surface_create_in_error (status); goto BAIL; } @@ -586,34 +652,43 @@ read_png (png_rw_ptr read_func, _cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface); data = NULL; + status = _cairo_memory_stream_destroy (png_closure->png_data, + &mime_data, + &mime_data_length); + if (unlikely (status)) { + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + goto BAIL; + } + png_closure->png_data = NULL; + + status = cairo_surface_set_mime_data (surface, + CAIRO_MIME_TYPE_PNG, + mime_data, + mime_data_length, + free, + mime_data); + if (unlikely (status)) { + free (mime_data); + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + goto BAIL; + } + BAIL: - if (row_pointers) + if (row_pointers != NULL) free (row_pointers); - if (data) + if (data != NULL) free (data); - if (png) + if (png != NULL) png_destroy_read_struct (&png, &info, NULL); + if (png_closure->png_data != NULL) { + cairo_status_t status_ignored; - return surface; -} - -static void -stdio_read_func (png_structp png, png_bytep data, png_size_t size) -{ - FILE *fp; - - fp = png_get_io_ptr (png); - while (size) { - size_t ret = fread (data, 1, size, fp); - size -= ret; - data += ret; - if (size && (feof (fp) || ferror (fp))) { - cairo_status_t *error = png_get_error_ptr (png); - if (*error == CAIRO_STATUS_SUCCESS) - *error = _cairo_error (CAIRO_STATUS_READ_ERROR); - png_error (png, NULL); - } + status_ignored = _cairo_output_stream_destroy (png_closure->png_data); } + + return surface; } /** @@ -635,11 +710,11 @@ stdio_read_func (png_structp png, png_bytep data, png_size_t size) cairo_surface_t * cairo_image_surface_create_from_png (const char *filename) { - FILE *fp; + struct png_read_closure_t png_closure; cairo_surface_t *surface; - fp = fopen (filename, "rb"); - if (fp == NULL) { + png_closure.closure = fopen (filename, "rb"); + if (png_closure.closure == NULL) { cairo_status_t status; switch (errno) { case ENOMEM: @@ -655,32 +730,13 @@ cairo_image_surface_create_from_png (const char *filename) return _cairo_surface_create_in_error (status); } - surface = read_png (stdio_read_func, fp); - - fclose (fp); + png_closure.read_func = stdio_read_func; - return surface; -} + surface = read_png (&png_closure); -struct png_read_closure_t { - cairo_read_func_t read_func; - void *closure; -}; - -static void -stream_read_func (png_structp png, png_bytep data, png_size_t size) -{ - cairo_status_t status; - struct png_read_closure_t *png_closure; + fclose (png_closure.closure); - png_closure = png_get_io_ptr (png); - status = png_closure->read_func (png_closure->closure, data, size); - if (status) { - cairo_status_t *error = png_get_error_ptr (png); - if (*error == CAIRO_STATUS_SUCCESS) - *error = status; - png_error (png, NULL); - } + return surface; } /** @@ -704,5 +760,5 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, png_closure.read_func = read_func; png_closure.closure = closure; - return read_png (stream_read_func, &png_closure); + return read_png (&png_closure); } diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c index 1392bfa1..0b0fa991 100644 --- a/src/cairo-polygon.c +++ b/src/cairo-polygon.c @@ -73,7 +73,7 @@ _cairo_polygon_grow (cairo_polygon_t *polygon) new_size, sizeof (cairo_edge_t)); } - if (new_edges == NULL) { + if (unlikely (new_edges == NULL)) { polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); return FALSE; } @@ -84,16 +84,17 @@ _cairo_polygon_grow (cairo_polygon_t *polygon) return TRUE; } -static void +void _cairo_polygon_add_edge (cairo_polygon_t *polygon, const cairo_point_t *p1, - const cairo_point_t *p2) + const cairo_point_t *p2, + int dir) { cairo_edge_t *edge; /* drop horizontal edges */ if (p1->y == p2->y) - goto DONE; + return; if (polygon->num_edges == polygon->edges_size) { if (! _cairo_polygon_grow (polygon)) @@ -104,15 +105,12 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon, if (p1->y < p2->y) { edge->edge.p1 = *p1; edge->edge.p2 = *p2; - edge->clockWise = 1; + edge->dir = dir; } else { edge->edge.p1 = *p2; edge->edge.p2 = *p1; - edge->clockWise = 0; + edge->dir = -dir; } - - DONE: - _cairo_polygon_move_to (polygon, p2); } void @@ -131,9 +129,9 @@ _cairo_polygon_line_to (cairo_polygon_t *polygon, const cairo_point_t *point) { if (polygon->has_current_point) - _cairo_polygon_add_edge (polygon, &polygon->current_point, point); - else - _cairo_polygon_move_to (polygon, point); + _cairo_polygon_add_edge (polygon, &polygon->current_point, point, 1); + + _cairo_polygon_move_to (polygon, point); } void @@ -142,7 +140,8 @@ _cairo_polygon_close (cairo_polygon_t *polygon) if (polygon->has_current_point) { _cairo_polygon_add_edge (polygon, &polygon->current_point, - &polygon->first_point); + &polygon->first_point, + 1); polygon->has_current_point = FALSE; } diff --git a/src/cairo-ps-surface-private.h b/src/cairo-ps-surface-private.h index e78833d0..98d2750a 100644 --- a/src/cairo-ps-surface-private.h +++ b/src/cairo-ps-surface-private.h @@ -68,6 +68,7 @@ typedef struct cairo_ps_surface { int bbox_x1, bbox_y1, bbox_x2, bbox_y2; cairo_matrix_t cairo_to_ps; cairo_image_surface_t *image; + cairo_image_surface_t *acquired_image; void *image_extra; cairo_bool_t use_string_datasource; diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index fbfdc3e5..a13be1d8 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -63,6 +63,7 @@ #include "cairo-meta-surface-private.h" #include "cairo-output-stream-private.h" #include "cairo-type3-glyph-surface-private.h" +#include "cairo-image-info-private.h" #include <stdio.h> #include <ctype.h> @@ -79,6 +80,10 @@ static const cairo_surface_backend_t cairo_ps_surface_backend; static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend; +static void +_cairo_ps_surface_release_surface (cairo_ps_surface_t *surface, + cairo_surface_pattern_t *pattern); + static const cairo_ps_level_t _cairo_ps_levels[] = { CAIRO_PS_LEVEL_2, @@ -257,7 +262,7 @@ _cairo_ps_surface_emit_type1_font_subset (cairo_ps_surface_t *surface, snprintf (name, sizeof name, "f-%d-%d", font_subset->font_id, font_subset->subset_id); status = _cairo_type1_subset_init (&subset, name, font_subset, TRUE); - if (status) + if (unlikely (status)) return status; /* FIXME: Figure out document structure convention for fonts */ @@ -288,7 +293,7 @@ _cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t *surface, snprintf (name, sizeof name, "f-%d-%d", font_subset->font_id, font_subset->subset_id); status = _cairo_type1_fallback_init_hex (&subset, name, font_subset); - if (status) + if (unlikely (status)) return status; /* FIXME: Figure out document structure convention for fonts */ @@ -317,7 +322,7 @@ _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface, unsigned int i, begin, end; status = _cairo_truetype_subset_init (&subset, font_subset); - if (status) + if (unlikely (status)) return status; /* FIXME: Figure out document structure convention for fonts */ @@ -458,7 +463,7 @@ _cairo_ps_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_sub for (i = 0; i < font_subset->num_glyphs; i++) { status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface, font_subset->glyphs[i]); - if (status) + if (unlikely (status)) break; } @@ -522,7 +527,7 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface, font_subset->glyphs[i], &bbox, &width); - if (status) + if (unlikely (status)) break; _cairo_output_stream_printf (surface->final_stream, @@ -544,7 +549,7 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface, } } cairo_surface_destroy (type3_surface); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->final_stream, @@ -630,19 +635,19 @@ _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface) status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets, _cairo_ps_surface_analyze_user_font_subset, surface); - if (status) + if (unlikely (status)) goto BAIL; status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets, _cairo_ps_surface_emit_unscaled_font_subset, surface); - if (status) + if (unlikely (status)) goto BAIL; status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets, _cairo_ps_surface_emit_scaled_font_subset, surface); - if (status) + if (unlikely (status)) goto BAIL; status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets, @@ -700,7 +705,7 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream, cairo_ps_surface_t *surface; surface = malloc (sizeof (cairo_ps_surface_t)); - if (surface == NULL) { + if (unlikely (surface == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP; } @@ -725,11 +730,11 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream, surface->stream = _cairo_output_stream_create_for_file (surface->tmpfile); status = _cairo_output_stream_get_status (surface->stream); - if (status) + if (unlikely (status)) goto CLEANUP_OUTPUT_STREAM; surface->font_subsets = _cairo_scaled_font_subsets_create_simple (); - if (surface->font_subsets == NULL) { + if (unlikely (surface->font_subsets == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_OUTPUT_STREAM; } @@ -930,7 +935,7 @@ cairo_ps_surface_restrict_to_level (cairo_surface_t *surface, cairo_status_t status; status = _extract_ps_surface (surface, &ps_surface); - if (status) { + if (unlikely (status)) { status = _cairo_surface_set_error (surface, status); return; } @@ -1005,7 +1010,7 @@ cairo_ps_surface_set_eps (cairo_surface_t *surface, cairo_status_t status; status = _extract_ps_surface (surface, &ps_surface); - if (status) { + if (unlikely (status)) { status = _cairo_surface_set_error (surface, status); return; } @@ -1030,7 +1035,7 @@ cairo_ps_surface_get_eps (cairo_surface_t *surface) cairo_status_t status; status = _extract_ps_surface (surface, &ps_surface); - if (status) { + if (unlikely (status)) { status = _cairo_surface_set_error (surface, status); return FALSE; } @@ -1064,7 +1069,7 @@ cairo_ps_surface_set_size (cairo_surface_t *surface, cairo_status_t status; status = _extract_ps_surface (surface, &ps_surface); - if (status) { + if (unlikely (status)) { status = _cairo_surface_set_error (surface, status); return; } @@ -1077,7 +1082,7 @@ cairo_ps_surface_set_size (cairo_surface_t *surface, status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface, width_in_points, height_in_points); - if (status) + if (unlikely (status)) status = _cairo_surface_set_error (surface, status); } @@ -1178,7 +1183,7 @@ cairo_ps_surface_dsc_comment (cairo_surface_t *surface, char *comment_copy; status = _extract_ps_surface (surface, &ps_surface); - if (status) { + if (unlikely (status)) { status = _cairo_surface_set_error (surface, status); return; } @@ -1196,13 +1201,13 @@ cairo_ps_surface_dsc_comment (cairo_surface_t *surface, /* Then, copy the comment and store it in the appropriate array. */ comment_copy = strdup (comment); - if (comment_copy == NULL) { + if (unlikely (comment_copy == NULL)) { status = _cairo_surface_set_error (surface, CAIRO_STATUS_NO_MEMORY); return; } status = _cairo_array_append (ps_surface->dsc_comment_target, &comment_copy); - if (status) { + if (unlikely (status)) { free (comment_copy); status = _cairo_surface_set_error (surface, status); return; @@ -1232,7 +1237,7 @@ cairo_ps_surface_dsc_begin_setup (cairo_surface_t *surface) cairo_status_t status; status = _extract_ps_surface (surface, &ps_surface); - if (status) { + if (unlikely (status)) { status = _cairo_surface_set_error (surface, status); return; } @@ -1267,7 +1272,7 @@ cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface) cairo_status_t status; status = _extract_ps_surface (surface, &ps_surface); - if (status) { + if (unlikely (status)) { status = _cairo_surface_set_error (surface, status); return; } @@ -1299,11 +1304,11 @@ _cairo_ps_surface_finish (void *abstract_surface) _cairo_ps_surface_emit_header (surface); status = _cairo_ps_surface_emit_font_subsets (surface); - if (status) + if (unlikely (status)) goto CLEANUP; status = _cairo_ps_surface_emit_body (surface); - if (status) + if (unlikely (status)) goto CLEANUP; _cairo_ps_surface_emit_footer (surface); @@ -1357,7 +1362,7 @@ _cairo_ps_surface_end_page (cairo_ps_surface_t *surface) cairo_int_status_t status; status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->stream, @@ -1373,7 +1378,7 @@ _cairo_ps_surface_show_page (void *abstract_surface) cairo_int_status_t status; status = _cairo_ps_surface_end_page (surface); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->stream, "showpage\n"); @@ -1402,7 +1407,7 @@ _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra); - if (status) + if (unlikely (status)) return status; if (image->base.status) @@ -1567,8 +1572,12 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface, if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; - if ( _cairo_surface_is_meta (surface_pattern->surface)) - return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN; + if ( _cairo_surface_is_meta (surface_pattern->surface)) { + if (pattern->extend == CAIRO_EXTEND_PAD) + return CAIRO_INT_STATUS_UNSUPPORTED; + else + return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN; + } } if (op == CAIRO_OPERATOR_SOURCE) @@ -1724,13 +1733,14 @@ _string_array_stream_create (cairo_output_stream_t *output) string_array_stream_t *stream; stream = malloc (sizeof (string_array_stream_t)); - if (stream == NULL) { + if (unlikely (stream == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_output_stream_t *) &_cairo_output_stream_nil; } _cairo_output_stream_init (&stream->base, _string_array_stream_write, + NULL, _string_array_stream_close); stream->output = output; stream->column = 0; @@ -1750,13 +1760,14 @@ _base85_array_stream_create (cairo_output_stream_t *output) string_array_stream_t *stream; stream = malloc (sizeof (string_array_stream_t)); - if (stream == NULL) { + if (unlikely (stream == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_output_stream_t *) &_cairo_output_stream_nil; } _cairo_output_stream_init (&stream->base, _string_array_stream_write, + NULL, _string_array_stream_close); stream->output = output; stream->column = 0; @@ -1798,7 +1809,7 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface, background_color, 0, 0, image->width, image->height); - if (status) + if (unlikely (status)) goto fail; status = _cairo_surface_composite (CAIRO_OPERATOR_OVER, @@ -1810,7 +1821,7 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface, 0, 0, image->width, image->height); - if (status) + if (unlikely (status)) goto fail; _cairo_pattern_fini (&pattern.base); @@ -1827,7 +1838,7 @@ fail: static cairo_status_t _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface, - unsigned char *data, + const unsigned char *data, unsigned long length, cairo_bool_t use_strings) { @@ -1840,12 +1851,12 @@ _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface, string_array_stream = _base85_array_stream_create (surface->stream); status = _cairo_output_stream_get_status (string_array_stream); - if (status) + if (unlikely (status)) return _cairo_output_stream_destroy (string_array_stream); base85_stream = _cairo_base85_stream_create (string_array_stream); status = _cairo_output_stream_get_status (base85_stream); - if (status) { + if (unlikely (status)) { status2 = _cairo_output_stream_destroy (string_array_stream); return _cairo_output_stream_destroy (base85_stream); } @@ -1907,7 +1918,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface, status = _cairo_ps_surface_flatten_image_transparency (surface, image, &opaque_image); - if (status) + if (unlikely (status)) return status; use_mask = FALSE; @@ -1929,7 +1940,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface, data_size = image->height * image->width * 3; } data = malloc (data_size); - if (data == NULL) { + if (unlikely (data == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto bail1; } @@ -1978,7 +1989,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface, * instead. */ data_compressed_size = data_size; data_compressed = _cairo_lzw_compress (data, &data_compressed_size); - if (data_compressed == NULL) { + if (unlikely (data_compressed == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto bail2; } @@ -1993,7 +2004,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface, data_compressed, data_compressed_size, TRUE); - if (status) + if (unlikely (status)) goto bail3; _cairo_output_stream_printf (surface->stream, @@ -2111,6 +2122,92 @@ bail1: } static cairo_status_t +_cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface, + cairo_surface_t *source, + int width, + int height) +{ + cairo_status_t status; + const unsigned char *mime_data; + unsigned int mime_data_length; + cairo_image_info_t info; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length); + if (unlikely (status)) + return status; + + if (info.num_components != 1 && info.num_components != 3) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (surface->use_string_datasource) { + /* Emit the image data as a base85-encoded string which will + * be used as the data source for the image operator later. */ + _cairo_output_stream_printf (surface->stream, + "/CairoImageData [\n"); + + status = _cairo_ps_surface_emit_base85_string (surface, + mime_data, + mime_data_length, + TRUE); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->stream, + "] def\n"); + _cairo_output_stream_printf (surface->stream, + "/CairoImageDataIndex 0 def\n"); + } + + _cairo_output_stream_printf (surface->stream, + "/%s setcolorspace\n" + "8 dict dup begin\n" + " /ImageType 1 def\n" + " /Width %d def\n" + " /Height %d def\n" + " /BitsPerComponent %d def\n" + " /Decode [ 0 1 0 1 0 1 ] def\n", + info.num_components == 1 ? "DeviceGray" : "DeviceRGB", + info.width, + info.height, + info.bits_per_component); + + if (surface->use_string_datasource) { + _cairo_output_stream_printf (surface->stream, + " /DataSource {\n" + " CairoImageData CairoImageDataIndex get\n" + " /CairoImageDataIndex CairoImageDataIndex 1 add def\n" + " CairoImageDataIndex CairoImageData length 1 sub gt\n" + " { /CairoImageDataIndex 0 def } if\n" + " } /ASCII85Decode filter /DCTDecode filter def\n"); + } else { + _cairo_output_stream_printf (surface->stream, + " /DataSource currentfile /ASCII85Decode filter /DCTDecode filter def\n"); + } + + _cairo_output_stream_printf (surface->stream, + " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n" + "end\n" + "image\n", + info.height); + + if (!surface->use_string_datasource) { + /* Emit the image data as a base85-encoded string which will + * be used as the data source for the image operator. */ + status = _cairo_ps_surface_emit_base85_string (surface, + mime_data, + mime_data_length, + FALSE); + } + + return status; +} + +static cairo_status_t _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface, cairo_surface_t *meta_surface) { @@ -2122,7 +2219,7 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface, cairo_status_t status; status = _cairo_surface_get_extents (meta_surface, &meta_extents); - if (status) + if (unlikely (status)) return status; old_content = surface->content; @@ -2154,11 +2251,11 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface, status = _cairo_meta_surface_replay_region (meta_surface, &surface->base, CAIRO_META_REGION_NATIVE); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->stream, @@ -2170,7 +2267,7 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface, _cairo_pdf_operators_reset (&surface->pdf_operators); surface->cairo_to_ps = old_cairo_to_ps; status = _cairo_surface_set_clip (&surface->base, old_clip); - if (status) + if (unlikely (status)) return status; _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators, @@ -2224,40 +2321,93 @@ _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface, static cairo_status_t _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface, cairo_surface_pattern_t *pattern, + cairo_rectangle_int_t *extents, int *width, int *height, - cairo_operator_t op) + int *origin_x, + int *origin_y) { cairo_status_t status; + cairo_surface_t *pad_image; + int x = 0; + int y = 0; if (_cairo_surface_is_meta (pattern->surface)) { cairo_surface_t *meta_surface = pattern->surface; cairo_rectangle_int_t pattern_extents; status = _cairo_surface_get_extents (meta_surface, &pattern_extents); - if (status) + if (unlikely (status)) return status; *width = pattern_extents.width; *height = pattern_extents.height; } else { status = _cairo_surface_acquire_source_image (pattern->surface, - &surface->image, + &surface->acquired_image, &surface->image_extra); - if (status) + if (unlikely (status)) return status; + pad_image = &surface->acquired_image->base; + if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD) { + cairo_box_t box; + cairo_rectangle_int_t rect; + cairo_surface_pattern_t pad_pattern; + + /* get the operation extents in pattern space */ + _cairo_box_from_rectangle (&box, extents); + _cairo_matrix_transform_bounding_box_fixed (&pattern->base.matrix, &box, NULL); + _cairo_box_round_to_rectangle (&box, &rect); + x = -rect.x; + y = -rect.y; + + pad_image = _cairo_image_surface_create_with_content (pattern->surface->content, + rect.width, + rect.height); + if (pad_image->status) { + status = pad_image->status; + goto BAIL; + } + + _cairo_pattern_init_for_surface (&pad_pattern, &surface->acquired_image->base); + cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y); + pad_pattern.base.extend = CAIRO_EXTEND_PAD; + status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, + &pad_pattern.base, + NULL, + pad_image, + 0, 0, + 0, 0, + 0, 0, + rect.width, + rect.height); + _cairo_pattern_fini (&pad_pattern.base); + if (unlikely (status)) + goto BAIL; + } + + surface->image = (cairo_image_surface_t *) pad_image; *width = surface->image->width; *height = surface->image->height; + *origin_x = x; + *origin_y = y; } return CAIRO_STATUS_SUCCESS; + +BAIL: + _cairo_ps_surface_release_surface (surface, pattern); + + return status; } static cairo_status_t _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface, cairo_surface_pattern_t *pattern, - cairo_operator_t op) + cairo_operator_t op, + int width, + int height) { cairo_status_t status; @@ -2267,6 +2417,13 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface, status = _cairo_ps_surface_emit_meta_surface (surface, meta_surface); } else { + if (cairo_pattern_get_extend (&pattern->base) != CAIRO_EXTEND_PAD) { + status = _cairo_ps_surface_emit_jpeg_image (surface, pattern->surface, + width, height); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + status = _cairo_ps_surface_emit_image (surface, surface->image, op, pattern->base.filter); } @@ -2279,25 +2436,29 @@ _cairo_ps_surface_release_surface (cairo_ps_surface_t *surface, cairo_surface_pattern_t *pattern) { if (!_cairo_surface_is_meta (pattern->surface)) - _cairo_surface_release_source_image (pattern->surface, surface->image, + _cairo_surface_release_source_image (pattern->surface, + surface->acquired_image, surface->image_extra); } static cairo_status_t _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface, cairo_surface_pattern_t *pattern, + cairo_rectangle_int_t *extents, cairo_operator_t op) { cairo_status_t status; int width, height; cairo_matrix_t cairo_p2d, ps_p2d; + int origin_x = 0; + int origin_y = 0; status = _cairo_ps_surface_acquire_surface (surface, pattern, - &width, - &height, - op); - if (status) + extents, + &width, &height, + &origin_x, &origin_y); + if (unlikely (status)) return status; cairo_p2d = pattern->base.matrix; @@ -2329,6 +2490,7 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface, ps_p2d = surface->cairo_to_ps; cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d); + cairo_matrix_translate (&ps_p2d, -origin_x, -origin_y); cairo_matrix_translate (&ps_p2d, 0.0, height); cairo_matrix_scale (&ps_p2d, 1.0, -1.0); @@ -2340,7 +2502,7 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface, ps_p2d.x0, ps_p2d.y0); } - status = _cairo_ps_surface_emit_surface (surface, pattern, op); + status = _cairo_ps_surface_emit_surface (surface, pattern, op, width, height); _cairo_ps_surface_release_surface (surface, pattern); return status; @@ -2349,6 +2511,7 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface, static cairo_status_t _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, cairo_surface_pattern_t *pattern, + cairo_rectangle_int_t *extents, cairo_operator_t op) { cairo_status_t status; @@ -2358,6 +2521,8 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, cairo_matrix_t cairo_p2d, ps_p2d; cairo_rectangle_int_t surface_extents; cairo_bool_t old_use_string_datasource; + int origin_x = 0; + int origin_y = 0; cairo_p2d = pattern->base.matrix; status = cairo_matrix_invert (&cairo_p2d); @@ -2366,19 +2531,19 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, ps_p2d = surface->cairo_to_ps; cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d); + cairo_matrix_translate (&ps_p2d, -origin_x, -origin_y); cairo_matrix_translate (&ps_p2d, 0.0, pattern_height); cairo_matrix_scale (&ps_p2d, 1.0, -1.0); status = _cairo_ps_surface_acquire_surface (surface, pattern, - &pattern_width, - &pattern_height, - op); - if (status) + extents, + &pattern_width, &pattern_height, + &origin_x, &origin_y); + if (unlikely (status)) return status; switch (pattern->base.extend) { - /* We implement EXTEND_PAD like EXTEND_NONE for now */ case CAIRO_EXTEND_PAD: case CAIRO_EXTEND_NONE: { @@ -2435,8 +2600,9 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, surface->content == CAIRO_CONTENT_COLOR ? 0 : 1, xstep, ystep); } - status = _cairo_ps_surface_emit_surface (surface, pattern, op); - if (status) + status = _cairo_ps_surface_emit_surface (surface, pattern, op, + pattern_width, pattern_height); + if (unlikely (status)) return status; surface->use_string_datasource = old_use_string_datasource; @@ -2483,7 +2649,7 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, ">>\n"); status = _cairo_surface_get_extents (&surface->base, &surface_extents); - if (status) + if (unlikely (status)) return status; cairo_p2d = pattern->base.matrix; @@ -2583,7 +2749,7 @@ _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t *surface, unsigned int i, n_stops; allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_ps_color_stop_t)); - if (allstops == NULL) + if (unlikely (allstops == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); stops = &allstops[1]; @@ -2789,7 +2955,7 @@ _cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface, status = _cairo_ps_surface_emit_pattern_stops (surface, &pattern->base); - if (status) + if (unlikely (status)) return status; if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT || @@ -2798,7 +2964,7 @@ _cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface, &pattern->base, repeat_begin, repeat_end); - if (status) + if (unlikely (status)) return status; } @@ -2876,7 +3042,7 @@ _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface, r2 = _cairo_fixed_to_double (pattern->r2); status = _cairo_ps_surface_emit_pattern_stops (surface, &pattern->base); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->stream, @@ -2914,7 +3080,8 @@ _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface, static cairo_status_t _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, const cairo_pattern_t *pattern, - cairo_operator_t op) + cairo_rectangle_int_t *extents, + cairo_operator_t op) { cairo_status_t status; @@ -2925,7 +3092,7 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, ! _cairo_color_equal (&surface->current_color, &solid->color)) { status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern); @@ -2939,7 +3106,7 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, surface->current_pattern_is_solid_color = FALSE; status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; switch (pattern->type) { @@ -2951,22 +3118,23 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, case CAIRO_PATTERN_TYPE_SURFACE: status = _cairo_ps_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, + extents, op); - if (status) + if (unlikely (status)) return status; break; case CAIRO_PATTERN_TYPE_LINEAR: status = _cairo_ps_surface_emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern); - if (status) + if (unlikely (status)) return status; break; case CAIRO_PATTERN_TYPE_RADIAL: status = _cairo_ps_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern); - if (status) + if (unlikely (status)) return status; break; } @@ -2995,7 +3163,7 @@ _cairo_ps_surface_intersect_clip_path (void *abstract_surface, if (path == NULL) { status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (stream, "Q q\n"); @@ -3043,7 +3211,8 @@ _cairo_ps_surface_get_font_options (void *abstract_surface, static cairo_int_status_t _cairo_ps_surface_paint (void *abstract_surface, cairo_operator_t op, - const cairo_pattern_t *source) + const cairo_pattern_t *source, + cairo_rectangle_int_t *paint_extents) { cairo_ps_surface_t *surface = abstract_surface; cairo_output_stream_t *stream = surface->stream; @@ -3061,11 +3230,11 @@ _cairo_ps_surface_paint (void *abstract_surface, #endif status = _cairo_surface_get_extents (&surface->base, &extents); - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; if (source->type == CAIRO_PATTERN_TYPE_SURFACE && @@ -3078,17 +3247,17 @@ _cairo_ps_surface_paint (void *abstract_surface, status = _cairo_ps_surface_paint_surface (surface, (cairo_surface_pattern_t *) source, - op); - if (status) + paint_extents, op); + if (unlikely (status)) return status; _cairo_output_stream_printf (stream, "Q\n"); } else { - status = _cairo_ps_surface_emit_pattern (surface, source, op); + status = _cairo_ps_surface_emit_pattern (surface, source, paint_extents, op); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (stream, "0 0 %d %d rectfill\n", @@ -3108,7 +3277,8 @@ _cairo_ps_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_ps_surface_t *surface = abstract_surface; cairo_int_status_t status; @@ -3123,7 +3293,7 @@ _cairo_ps_surface_stroke (void *abstract_surface, "%% _cairo_ps_surface_stroke\n"); #endif - status = _cairo_ps_surface_emit_pattern (surface, source, op); + status = _cairo_ps_surface_emit_pattern (surface, source, extents, op); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; @@ -3141,7 +3311,8 @@ _cairo_ps_surface_fill (void *abstract_surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_ps_surface_t *surface = abstract_surface; cairo_int_status_t status; @@ -3161,7 +3332,7 @@ _cairo_ps_surface_fill (void *abstract_surface, source->extend == CAIRO_EXTEND_PAD)) { status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->stream, "q\n"); @@ -3169,23 +3340,23 @@ _cairo_ps_surface_fill (void *abstract_surface, status = _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule); - if (status) + if (unlikely (status)) return status; status = _cairo_ps_surface_paint_surface (surface, (cairo_surface_pattern_t *) source, - op); - if (status) + extents, op); + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->stream, "Q\n"); _cairo_pdf_operators_reset (&surface->pdf_operators); } else { - status = _cairo_ps_surface_emit_pattern (surface, source, op); + status = _cairo_ps_surface_emit_pattern (surface, source, extents, op); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; - if (status) + if (unlikely (status)) return status; status = _cairo_pdf_operators_fill (&surface->pdf_operators, @@ -3203,7 +3374,8 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs) + int *remaining_glyphs, + cairo_rectangle_int_t *extents) { cairo_ps_surface_t *surface = abstract_surface; cairo_status_t status; @@ -3221,11 +3393,11 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface, if (num_glyphs <= 0) return CAIRO_STATUS_SUCCESS; - status = _cairo_ps_surface_emit_pattern (surface, source, op); + status = _cairo_ps_surface_emit_pattern (surface, source, extents, op); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; - if (status) + if (unlikely (status)) return status; return _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators, @@ -3331,6 +3503,8 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = { NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* cairo_ps_surface_copy_page */ _cairo_ps_surface_show_page, NULL, /* set_clip_region */ diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c index 3eee2c11..3bfd9e21 100644 --- a/src/cairo-quartz-image-surface.c +++ b/src/cairo-quartz-image-surface.c @@ -163,6 +163,8 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = { NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ NULL, /* set_clip_region */ diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index fc9439e3..34661853 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -631,7 +631,7 @@ static void ComputeGradientValue (void *info, const float *in, float *out) { double fdist = *in; - cairo_gradient_pattern_t *grad = (cairo_gradient_pattern_t*) info; + const cairo_gradient_pattern_t *grad = (cairo_gradient_pattern_t*) info; unsigned int i; /* Put fdist back in the 0.0..1.0 range if we're doing @@ -680,15 +680,21 @@ ComputeGradientValue (void *info, const float *in, float *out) } static CGFunctionRef -CreateGradientFunction (cairo_gradient_pattern_t *gpat) +CreateGradientFunction (const cairo_gradient_pattern_t *gpat) { + cairo_pattern_t *pat; float input_value_range[2] = { 0.f, 1.f }; float output_value_ranges[8] = { 0.f, 1.f, 0.f, 1.f, 0.f, 1.f, 0.f, 1.f }; CGFunctionCallbacks callbacks = { 0, ComputeGradientValue, (CGFunctionReleaseInfoCallback) cairo_pattern_destroy }; - return CGFunctionCreate (_cairo_pattern_create_copy (&gpat->base), + if (_cairo_pattern_create_copy (&pat, &gpat->base)) + /* quartz doesn't deal very well with malloc failing, so there's + * not much point in us trying either */ + return NULL; + + return CGFunctionCreate (pat, 1, input_value_range, 4, @@ -698,10 +704,11 @@ CreateGradientFunction (cairo_gradient_pattern_t *gpat) static CGFunctionRef CreateRepeatingGradientFunction (cairo_quartz_surface_t *surface, - cairo_gradient_pattern_t *gpat, + const cairo_gradient_pattern_t *gpat, CGPoint *start, CGPoint *end, CGAffineTransform matrix) { + cairo_pattern_t *pat; float input_value_range[2]; float output_value_ranges[8] = { 0.f, 1.f, 0.f, 1.f, 0.f, 1.f, 0.f, 1.f }; CGFunctionCallbacks callbacks = { @@ -766,7 +773,12 @@ CreateRepeatingGradientFunction (cairo_quartz_surface_t *surface, input_value_range[0] = 0.0 - 1.0 * rep_start; input_value_range[1] = 1.0 + 1.0 * rep_end; - return CGFunctionCreate (_cairo_pattern_create_copy (&gpat->base), + if (_cairo_pattern_create_copy (&pat, &gpat->base)) + /* quartz doesn't deal very well with malloc failing, so there's + * not much point in us trying either */ + return NULL; + + return CGFunctionCreate (pat, 1, input_value_range, 4, @@ -904,7 +916,7 @@ SurfacePatternReleaseInfoFunc (void *ainfo) static cairo_int_status_t _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t *dest, - cairo_pattern_t *apattern, + const cairo_pattern_t *apattern, CGPatternRef *cgpat) { cairo_surface_pattern_t *spattern; @@ -1013,7 +1025,7 @@ typedef enum { static cairo_quartz_action_t _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface, - cairo_pattern_t *source) + const cairo_pattern_t *source) { CGRect clipBox = CGContextGetClipBoundingBox (surface->cgContext); CGAffineTransform ctm; @@ -1022,6 +1034,7 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface, cairo_surface_t *fallback; cairo_t *fallback_cr; CGImageRef img; + cairo_pattern_t *source_copy; cairo_status_t status; @@ -1050,7 +1063,13 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface, /* Paint the source onto our temporary */ fallback_cr = cairo_create (fallback); cairo_set_operator (fallback_cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source (fallback_cr, source); + + /* Use a copy of the pattern because it is const and could be allocated + * on the stack */ + status = _cairo_pattern_create_copy (&source_copy, source); + cairo_set_source (fallback_cr, source_copy); + cairo_pattern_destroy (source_copy); + cairo_paint (fallback_cr); cairo_destroy (fallback_cr); @@ -1070,9 +1089,9 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface, static cairo_quartz_action_t _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface, - cairo_linear_pattern_t *lpat) + const cairo_linear_pattern_t *lpat) { - cairo_pattern_t *abspat = (cairo_pattern_t *) lpat; + const cairo_pattern_t *abspat = &lpat->base.base; cairo_matrix_t mat; CGPoint start, end; CGFunctionRef gradFunc; @@ -1085,7 +1104,7 @@ _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface, return DO_SOLID; } - cairo_pattern_get_matrix (abspat, &mat); + mat = abspat->matrix; cairo_matrix_invert (&mat); _cairo_quartz_cairo_matrix_to_quartz (&mat, &surface->sourceTransform); @@ -1099,10 +1118,10 @@ _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface, if (abspat->extend == CAIRO_EXTEND_NONE || abspat->extend == CAIRO_EXTEND_PAD) { - gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) lpat); + gradFunc = CreateGradientFunction (&lpat->base); } else { gradFunc = CreateRepeatingGradientFunction (surface, - (cairo_gradient_pattern_t*) lpat, + &lpat->base, &start, &end, surface->sourceTransform); } @@ -1119,9 +1138,9 @@ _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface, static cairo_quartz_action_t _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface, - cairo_radial_pattern_t *rpat) + const cairo_radial_pattern_t *rpat) { - cairo_pattern_t *abspat = (cairo_pattern_t *)rpat; + const cairo_pattern_t *abspat = &rpat->base.base; cairo_matrix_t mat; CGPoint start, end; CGFunctionRef gradFunc; @@ -1142,10 +1161,10 @@ _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface, * Radial shadings). So, instead, let's just render an image * for pixman to draw the shading into, and use that. */ - return _cairo_quartz_setup_fallback_source (surface, (cairo_pattern_t*) rpat); + return _cairo_quartz_setup_fallback_source (surface, &rpat->base.base); } - cairo_pattern_get_matrix (abspat, &mat); + mat = abspat->matrix; cairo_matrix_invert (&mat); _cairo_quartz_cairo_matrix_to_quartz (&mat, &surface->sourceTransform); @@ -1156,7 +1175,7 @@ _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface, end = CGPointMake (_cairo_fixed_to_double (rpat->c2.x), _cairo_fixed_to_double (rpat->c2.y)); - gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) rpat); + gradFunc = CreateGradientFunction (&rpat->base); surface->sourceShading = CGShadingCreateRadial (rgb, start, @@ -1174,7 +1193,7 @@ _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface, static cairo_quartz_action_t _cairo_quartz_setup_source (cairo_quartz_surface_t *surface, - cairo_pattern_t *source) + const cairo_pattern_t *source) { assert (!(surface->sourceImage || surface->sourceShading || surface->sourcePattern)); @@ -1199,13 +1218,13 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface, } if (source->type == CAIRO_PATTERN_TYPE_LINEAR) { - cairo_linear_pattern_t *lpat = (cairo_linear_pattern_t *)source; + const cairo_linear_pattern_t *lpat = (const cairo_linear_pattern_t *)source; return _cairo_quartz_setup_linear_source (surface, lpat); } if (source->type == CAIRO_PATTERN_TYPE_RADIAL) { - cairo_radial_pattern_t *rpat = (cairo_radial_pattern_t *)source; + const cairo_radial_pattern_t *rpat = (const cairo_radial_pattern_t *)source; return _cairo_quartz_setup_radial_source (surface, rpat); } @@ -1213,7 +1232,7 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface, if (source->type == CAIRO_PATTERN_TYPE_SURFACE && (source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT))) { - cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) source; + const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source; cairo_surface_t *pat_surf = spat->surface; CGImageRef img; cairo_matrix_t m = spat->base.matrix; @@ -1320,7 +1339,7 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface, static void _cairo_quartz_teardown_source (cairo_quartz_surface_t *surface, - cairo_pattern_t *source) + const cairo_pattern_t *source) { CGContextSetInterpolationQuality (surface->cgContext, surface->oldInterpolationQuality); @@ -1667,7 +1686,8 @@ _cairo_quartz_surface_get_extents (void *abstract_surface, static cairo_int_status_t _cairo_quartz_surface_paint (void *abstract_surface, cairo_operator_t op, - cairo_pattern_t *source) + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -1718,11 +1738,12 @@ _cairo_quartz_surface_paint (void *abstract_surface, static cairo_int_status_t _cairo_quartz_surface_fill (void *abstract_surface, cairo_operator_t op, - cairo_pattern_t *source, + const cairo_pattern_t *source, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -1823,13 +1844,14 @@ _cairo_quartz_surface_fill (void *abstract_surface, static cairo_int_status_t _cairo_quartz_surface_stroke (void *abstract_surface, cairo_operator_t op, - cairo_pattern_t *source, + const cairo_pattern_t *source, cairo_path_fixed_t *path, cairo_stroke_style_t *style, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -1969,11 +1991,12 @@ _cairo_quartz_surface_stroke (void *abstract_surface, static cairo_int_status_t _cairo_quartz_surface_show_glyphs (void *abstract_surface, cairo_operator_t op, - cairo_pattern_t *source, + const cairo_pattern_t *source, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs) + int *remaining_glyphs, + cairo_rectangle_int_t *extents) { CGAffineTransform textTransform, ctm; #define STATIC_BUF_SIZE 64 @@ -2178,22 +2201,23 @@ BAIL: static cairo_int_status_t _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface, cairo_operator_t op, - cairo_pattern_t *source, - cairo_surface_pattern_t *mask) + const cairo_pattern_t *source, + const cairo_surface_pattern_t *mask, + cairo_rectangle_int_t *extents) { - cairo_rectangle_int_t extents; + cairo_rectangle_int_t mask_extents; CGRect rect; CGImageRef img; cairo_surface_t *pat_surf = mask->surface; cairo_status_t status = CAIRO_STATUS_SUCCESS; CGAffineTransform ctm, mask_matrix; - status = _cairo_surface_get_extents (pat_surf, &extents); + status = _cairo_surface_get_extents (pat_surf, &mask_extents); if (status) return status; // everything would be masked out, so do nothing - if (extents.width == 0 || extents.height == 0) + if (mask_extents.width == 0 || mask_extents.height == 0) return CAIRO_STATUS_SUCCESS; status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img); @@ -2202,7 +2226,7 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface, if (status) return status; - rect = CGRectMake (0.0f, 0.0f, extents.width, extents.height); + rect = CGRectMake (0.0f, 0.0f, mask_extents.width, mask_extents.height); CGContextSaveGState (surface->cgContext); @@ -2219,7 +2243,7 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface, CGContextSetCTM (surface->cgContext, ctm); - status = _cairo_quartz_surface_paint (surface, op, source); + status = _cairo_quartz_surface_paint (surface, op, source, extents); CGContextRestoreGState (surface->cgContext); @@ -2243,8 +2267,9 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface, static cairo_int_status_t _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface, cairo_operator_t op, - cairo_pattern_t *source, - cairo_pattern_t *mask) + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_rectangle_int_t *extents) { int width = surface->extents.width - surface->extents.x; int height = surface->extents.height - surface->extents.y; @@ -2253,6 +2278,7 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface, cairo_t *gradient_surf_cr = NULL; cairo_surface_pattern_t surface_pattern; + cairo_pattern_t *mask_copy; cairo_int_status_t status; /* Render the gradient to a surface */ @@ -2260,7 +2286,13 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface, width, height); gradient_surf_cr = cairo_create(gradient_surf); - cairo_set_source (gradient_surf_cr, mask); + + /* make a copy of the pattern because because cairo_set_source doesn't take + * a 'const cairo_pattern_t *' */ + _cairo_pattern_create_copy (&mask_copy, mask); + cairo_set_source (gradient_surf_cr, mask_copy); + cairo_pattern_destroy (mask_copy); + cairo_set_operator (gradient_surf_cr, CAIRO_OPERATOR_SOURCE); cairo_paint (gradient_surf_cr); status = cairo_status (gradient_surf_cr); @@ -2271,7 +2303,7 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface, _cairo_pattern_init_for_surface (&surface_pattern, gradient_surf); - status = _cairo_quartz_surface_mask_with_surface (surface, op, source, &surface_pattern); + status = _cairo_quartz_surface_mask_with_surface (surface, op, source, &surface_pattern, extents); _cairo_pattern_fini (&surface_pattern.base); @@ -2285,8 +2317,9 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface, static cairo_int_status_t _cairo_quartz_surface_mask (void *abstract_surface, cairo_operator_t op, - cairo_pattern_t *source, - cairo_pattern_t *mask) + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_rectangle_int_t *extents) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -2301,7 +2334,7 @@ _cairo_quartz_surface_mask (void *abstract_surface, cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask; CGContextSetAlpha (surface->cgContext, solid_mask->color.alpha); - rv = _cairo_quartz_surface_paint (surface, op, source); + rv = _cairo_quartz_surface_paint (surface, op, source, extents); CGContextSetAlpha (surface->cgContext, 1.0); return rv; @@ -2311,9 +2344,9 @@ _cairo_quartz_surface_mask (void *abstract_surface, if (CGContextClipToMaskPtr) { /* For these, we can skip creating a temporary surface, since we already have one */ if (mask->type == CAIRO_PATTERN_TYPE_SURFACE && mask->extend == CAIRO_EXTEND_NONE) - return _cairo_quartz_surface_mask_with_surface (surface, op, source, (cairo_surface_pattern_t *) mask); + return _cairo_quartz_surface_mask_with_surface (surface, op, source, (cairo_surface_pattern_t *) mask, extents); - return _cairo_quartz_surface_mask_with_generic (surface, op, source, mask); + return _cairo_quartz_surface_mask_with_generic (surface, op, source, mask, extents); } /* So, CGContextClipToMask is not present in 10.3.9, so we're @@ -2390,6 +2423,8 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = { NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ NULL, /* set_clip_region */ diff --git a/src/cairo-rectangle.c b/src/cairo-rectangle.c index 2143f0c6..9a68409c 100644 --- a/src/cairo-rectangle.c +++ b/src/cairo-rectangle.c @@ -223,3 +223,24 @@ _cairo_box_contains_point (cairo_box_t *box, cairo_point_t *point) return FALSE; return TRUE; } + +void +_cairo_composite_rectangles_init( + cairo_composite_rectangles_t *rects, + int all_x, + int all_y, + int width, + int height) +{ + rects->src.x = all_x; + rects->src.y = all_y; + rects->mask.x = all_x; + rects->mask.y = all_y; + rects->clip.x = all_x; + rects->clip.y = all_y; + rects->dst.x = all_x; + rects->dst.y = all_y; + + rects->width = width; + rects->height = height; +} diff --git a/src/cairo-region.c b/src/cairo-region.c index a89c4d07..53a359b3 100644 --- a/src/cairo-region.c +++ b/src/cairo-region.c @@ -64,7 +64,7 @@ _cairo_region_init_boxes (cairo_region_t *region, if (count > ARRAY_LENGTH (stack_pboxes)) { pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t)); - if (pboxes == NULL) + if (unlikely (pboxes == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -114,16 +114,17 @@ _cairo_region_get_boxes (cairo_region_t *region, int *num_boxes, cairo_box_int_t int i; pboxes = pixman_region32_rectangles (®ion->rgn, &nboxes); - if (nboxes == 0) { *num_boxes = 0; - *boxes = NULL; return CAIRO_STATUS_SUCCESS; } - cboxes = _cairo_malloc_ab (nboxes, sizeof(cairo_box_int_t)); - if (cboxes == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (nboxes > *num_boxes) { + cboxes = _cairo_malloc_ab (nboxes, sizeof (cairo_box_int_t)); + if (unlikely (cboxes == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else + cboxes = *boxes; for (i = 0; i < nboxes; i++) { cboxes[i].p1.x = pboxes[i].x1; diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h index c1d87ae0..86a50bbb 100644 --- a/src/cairo-scaled-font-private.h +++ b/src/cairo-scaled-font-private.h @@ -94,10 +94,11 @@ struct _cairo_scaled_font { cairo_bool_t finished; /* "live" scaled_font members */ - cairo_matrix_t scale; /* font space => device space */ - cairo_matrix_t scale_inverse; /* device space => font space */ - double max_scale; /* maximum x/y expansion of scale */ - cairo_font_extents_t extents; /* user space */ + cairo_matrix_t scale; /* font space => device space */ + cairo_matrix_t scale_inverse; /* device space => font space */ + double max_scale; /* maximum x/y expansion of scale */ + cairo_font_extents_t extents; /* user space */ + cairo_font_extents_t fs_extents; /* font space */ /* The mutex protects modification to all subsequent fields. */ cairo_mutex_t mutex; diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c index 815c4d8b..c802c314 100644 --- a/src/cairo-scaled-font-subsets.c +++ b/src/cairo-scaled-font-subsets.c @@ -163,7 +163,7 @@ _cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index, cairo_sub_font_glyph_t *sub_font_glyph; sub_font_glyph = malloc (sizeof (cairo_sub_font_glyph_t)); - if (sub_font_glyph == NULL) { + if (unlikely (sub_font_glyph == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return NULL; } @@ -267,7 +267,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent, cairo_scaled_font_subsets_glyph_t subset_glyph; sub_font = malloc (sizeof (cairo_sub_font_t)); - if (sub_font == NULL) + if (unlikely (sub_font == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); sub_font->is_scaled = is_scaled; @@ -284,7 +284,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent, sub_font->max_glyphs_per_subset = max_glyphs_per_subset; sub_font->sub_font_glyphs = _cairo_hash_table_create (_cairo_sub_font_glyphs_equal); - if (sub_font->sub_font_glyphs == NULL) { + if (unlikely (sub_font->sub_font_glyphs == NULL)) { free (sub_font); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -294,7 +294,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent, * Type 3 fonts */ if (! _cairo_font_face_is_user (scaled_font->font_face)) { status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &subset_glyph); - if (status) { + if (unlikely (status)) { _cairo_hash_table_destroy (sub_font->sub_font_glyphs); free (sub_font); return status; @@ -349,7 +349,7 @@ _cairo_sub_font_glyph_lookup_unicode (cairo_sub_font_glyph_t *sub_font_glyph, status = scaled_font->backend->index_to_ucs4 (scaled_font, scaled_font_glyph_index, &unicode); - if (status) + if (unlikely (status)) return status; } @@ -360,7 +360,7 @@ _cairo_sub_font_glyph_lookup_unicode (cairo_sub_font_glyph_t *sub_font_glyph, len = _cairo_ucs4_to_utf8 (unicode, buf); if (len > 0) { sub_font_glyph->utf8 = malloc (len + 1); - if (sub_font_glyph->utf8 == NULL) + if (unlikely (sub_font_glyph->utf8 == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (sub_font_glyph->utf8, buf, len); @@ -420,9 +420,9 @@ _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font, cairo_sub_font_glyph_t key, *sub_font_glyph; _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); - if (_cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base, - (cairo_hash_entry_t **) &sub_font_glyph)) - { + sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs, + &key.base); + if (sub_font_glyph != NULL) { 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; @@ -450,9 +450,9 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, cairo_status_t status; _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); - if (! _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base, - (cairo_hash_entry_t **) &sub_font_glyph)) - { + sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs, + &key.base); + if (sub_font_glyph == NULL) { cairo_scaled_glyph_t *scaled_glyph; if (sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset) @@ -466,7 +466,7 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, * except for Type 3 fonts */ if (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)) { status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &tmp_subset_glyph); - if (status) + if (unlikely (status)) return status; } } @@ -477,7 +477,7 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); - if (status) { + if (unlikely (status)) { _cairo_scaled_font_thaw_cache (sub_font->scaled_font); return status; } @@ -489,19 +489,19 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, scaled_glyph->metrics.y_advance); _cairo_scaled_font_thaw_cache (sub_font->scaled_font); - if (sub_font_glyph == NULL) + if (unlikely (sub_font_glyph == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_sub_font_glyph_lookup_unicode (sub_font_glyph, sub_font->scaled_font, scaled_font_glyph_index); - if (status) { + if (unlikely (status)) { _cairo_sub_font_glyph_destroy (sub_font_glyph); return status; } status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base); - if (status) { + if (unlikely (status)) { _cairo_sub_font_glyph_destroy (sub_font_glyph); return status; } @@ -596,8 +596,8 @@ _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type) { cairo_scaled_font_subsets_t *subsets; - subsets = malloc (sizeof (cairo_scaled_font_subsets_t)); - if (subsets == NULL) { + subsets = malloc (sizeof (cairo_scaled_font_subsets_t)); + if (unlikely (subsets == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return NULL; } @@ -679,9 +679,9 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, 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)) - { + sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, + &key.base); + if (sub_font != NULL) { if (_cairo_sub_font_lookup_glyph (sub_font, scaled_font_glyph_index, utf8, utf8_len, @@ -693,9 +693,9 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, /* Lookup glyph in scaled subsets */ 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_hash_table_lookup (subsets->scaled_sub_fonts, + &key.base); + if (sub_font != NULL) { if (_cairo_sub_font_lookup_glyph (sub_font, scaled_font_glyph_index, utf8, utf8_len, @@ -732,9 +732,9 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, /* 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_hash_table_lookup (subsets->unscaled_sub_fonts, + &key.base); + if (sub_font == NULL) { font_face = cairo_scaled_font_get_font_face (scaled_font); cairo_matrix_init_identity (&identity); _cairo_font_options_init_default (&font_options); @@ -744,7 +744,7 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, &identity, &identity, &font_options); - if (unscaled_font->status) + if (unlikely (unscaled_font->status)) return unscaled_font->status; subset_glyph->is_scaled = FALSE; @@ -768,7 +768,7 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, subset_glyph->is_composite, &sub_font); - if (status) { + if (unlikely (status)) { cairo_scaled_font_destroy (unscaled_font); return status; } @@ -776,7 +776,7 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts, &sub_font->base); - if (status) { + if (unlikely (status)) { _cairo_sub_font_destroy (sub_font); return status; } @@ -791,9 +791,9 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, /* 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_hash_table_lookup (subsets->scaled_sub_fonts, + &key.base); + if (sub_font == NULL) { subset_glyph->is_scaled = TRUE; subset_glyph->is_composite = FALSE; if (subsets->type == CAIRO_SUBSETS_SCALED) @@ -808,14 +808,14 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, subset_glyph->is_scaled, subset_glyph->is_composite, &sub_font); - if (status) { + if (unlikely (status)) { cairo_scaled_font_destroy (scaled_font); return status; } status = _cairo_hash_table_insert (subsets->scaled_sub_fonts, &sub_font->base); - if (status) { + if (unlikely (status)) { _cairo_sub_font_destroy (sub_font); return status; } @@ -866,7 +866,7 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long)); collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *)); - if (collection.glyphs == NULL || collection.utf8 == NULL) { + if (unlikely (collection.glyphs == NULL || collection.utf8 == NULL)) { if (collection.glyphs != NULL) free (collection.glyphs); if (collection.utf8 != NULL) @@ -957,7 +957,7 @@ static cairo_status_t create_string_entry (char *s, cairo_string_entry_t **entry) { *entry = malloc (sizeof (cairo_string_entry_t)); - if (*entry == NULL) + if (unlikely (*entry == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_string_init_key (*entry, s); @@ -965,24 +965,31 @@ create_string_entry (char *s, cairo_string_entry_t **entry) return CAIRO_STATUS_SUCCESS; } +static void +_pluck_entry (void *entry, void *closure) +{ + _cairo_hash_table_remove (closure, entry); + free (entry); +} + cairo_int_status_t _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset) { unsigned int i; - cairo_status_t status; cairo_hash_table_t *names; cairo_string_entry_t key, *entry; char buf[30]; char *utf8; uint16_t *utf16; int utf16_len; + cairo_status_t status = CAIRO_STATUS_SUCCESS; names = _cairo_hash_table_create (_cairo_string_equal); - if (names == NULL) + if (unlikely (names == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); subset->glyph_names = calloc (subset->num_glyphs, sizeof (char *)); - if (subset->glyph_names == NULL) { + if (unlikely (subset->glyph_names == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_HASH; } @@ -990,17 +997,17 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset i = 0; if (! _cairo_font_face_is_user (subset->scaled_font->font_face)) { subset->glyph_names[0] = strdup (".notdef"); - if (subset->glyph_names[0] == NULL) { + if (unlikely (subset->glyph_names[0] == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_HASH; } status = create_string_entry (subset->glyph_names[0], &entry); - if (status) + if (unlikely (status)) goto CLEANUP_HASH; status = _cairo_hash_table_insert (names, &entry->base); - if (status) { + if (unlikely (status)) { free (entry); goto CLEANUP_HASH; } @@ -1013,52 +1020,44 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset utf16_len = 0; if (utf8 && *utf8) { status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len); - if (status) + if (unlikely (status)) return status; /* FIXME */ } if (utf16_len == 1) { - snprintf (buf, sizeof(buf), "uni%04X", (int)(utf16[0])); + snprintf (buf, sizeof (buf), "uni%04X", (int) utf16[0]); _cairo_string_init_key (&key, buf); - if (_cairo_hash_table_lookup (names, &key.base, - (cairo_hash_entry_t **) &entry)) { - snprintf (buf, sizeof(buf), "g%d", i); - } + entry = _cairo_hash_table_lookup (names, &key.base); + if (entry != NULL) + snprintf (buf, sizeof (buf), "g%d", i); } else { - snprintf (buf, sizeof(buf), "g%d", i); + snprintf (buf, sizeof (buf), "g%d", i); } if (utf16) free (utf16); subset->glyph_names[i] = strdup (buf); - if (subset->glyph_names[i] == NULL) { + if (unlikely (subset->glyph_names[i] == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_HASH; } status = create_string_entry (subset->glyph_names[i], &entry); - if (status) + if (unlikely (status)) goto CLEANUP_HASH; status = _cairo_hash_table_insert (names, &entry->base); - if (status) { + if (unlikely (status)) { free (entry); goto CLEANUP_HASH; } } CLEANUP_HASH: - while (1) { - entry = _cairo_hash_table_random_entry (names, NULL); - if (entry == NULL) - break; - - _cairo_hash_table_remove (names, (cairo_hash_entry_t *) entry); - free (entry); - } + _cairo_hash_table_foreach (names, _pluck_entry, names); _cairo_hash_table_destroy (names); - if (status == CAIRO_STATUS_SUCCESS) + if (likely (status == CAIRO_STATUS_SUCCESS)) return CAIRO_STATUS_SUCCESS; if (subset->glyph_names != NULL) { diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index bfeeaf66..ca86f512 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -201,6 +201,7 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = { { 1., 0., 0., 1., 0, 0}, /* scale_inverse */ 1., /* max_scale */ { 0., 0., 0., 0., 0. }, /* extents */ + { 0., 0., 0., 0., 0. }, /* fs_extents */ CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */ NULL, /* glyphs */ NULL, /* surface_backend */ @@ -320,14 +321,14 @@ _cairo_scaled_font_map_lock (void) if (cairo_scaled_font_map == NULL) { cairo_scaled_font_map = malloc (sizeof (cairo_scaled_font_map_t)); - if (cairo_scaled_font_map == NULL) + if (unlikely (cairo_scaled_font_map == NULL)) goto CLEANUP_MUTEX_LOCK; cairo_scaled_font_map->mru_scaled_font = NULL; cairo_scaled_font_map->hash_table = _cairo_hash_table_create (_cairo_scaled_font_keys_equal); - if (cairo_scaled_font_map->hash_table == NULL) + if (unlikely (cairo_scaled_font_map->hash_table == NULL)) goto CLEANUP_SCALED_FONT_MAP; cairo_scaled_font_map->num_holdovers = 0; @@ -359,7 +360,7 @@ _cairo_scaled_font_map_destroy (void) CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex); font_map = cairo_scaled_font_map; - if (font_map == NULL) { + if (unlikely (font_map == NULL)) { goto CLEANUP_MUTEX_LOCK; } @@ -424,11 +425,11 @@ _cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t assert (CAIRO_MUTEX_IS_LOCKED (_cairo_scaled_font_map_mutex)); status = scaled_font->status; - if (status) + if (unlikely (status)) return status; placeholder_scaled_font = malloc (sizeof (cairo_scaled_font_t)); - if (placeholder_scaled_font == NULL) + if (unlikely (placeholder_scaled_font == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); /* full initialization is wasteful, but who cares... */ @@ -438,14 +439,14 @@ _cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t &scaled_font->ctm, &scaled_font->options, NULL); - if (status) + if (unlikely (status)) goto FREE_PLACEHOLDER; placeholder_scaled_font->placeholder = TRUE; status = _cairo_hash_table_insert (cairo_scaled_font_map->hash_table, &placeholder_scaled_font->hash_entry); - if (status) + if (unlikely (status)) goto FINI_PLACEHOLDER; CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); @@ -465,19 +466,18 @@ void _cairo_scaled_font_unregister_placeholder_and_lock_font_map (cairo_scaled_font_t *scaled_font) { cairo_scaled_font_t *placeholder_scaled_font; - cairo_bool_t found; CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex); - found = _cairo_hash_table_lookup (cairo_scaled_font_map->hash_table, - &scaled_font->hash_entry, - (cairo_hash_entry_t**) &placeholder_scaled_font); - assert (found); + placeholder_scaled_font = + _cairo_hash_table_lookup (cairo_scaled_font_map->hash_table, + &scaled_font->hash_entry); + assert (placeholder_scaled_font != NULL); assert (placeholder_scaled_font->placeholder); assert (CAIRO_MUTEX_IS_LOCKED (placeholder_scaled_font->mutex)); _cairo_hash_table_remove (cairo_scaled_font_map->hash_table, - &scaled_font->hash_entry); + &placeholder_scaled_font->hash_entry); CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); @@ -599,7 +599,7 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, cairo_status_t status; status = cairo_font_options_status ((cairo_font_options_t *) options); - if (status) + if (unlikely (status)) return status; _cairo_scaled_font_init_key (scaled_font, font_face, @@ -613,7 +613,7 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, fabs (scaled_font->scale.yx) + fabs (scaled_font->scale.yy)); scaled_font->scale_inverse = scaled_font->scale; status = cairo_matrix_invert (&scaled_font->scale_inverse); - if (status) { + if (unlikely (status)) { /* If the font scale matrix is rank 0, just using an all-zero inverse matrix * makes everything work correctly. This make font size 0 work without * producing an error. @@ -638,7 +638,7 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, scaled_font->glyphs = _cairo_cache_create (_cairo_scaled_glyph_keys_equal, _cairo_scaled_glyph_destroy, MAX_GLYPHS_CACHED_PER_FONT); - if (scaled_font->glyphs == NULL) + if (unlikely (scaled_font->glyphs == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); CAIRO_REFERENCE_COUNT_INIT (&scaled_font->ref_count, 1); @@ -692,10 +692,12 @@ _cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font, cairo_status_t status; double font_scale_x, font_scale_y; + scaled_font->fs_extents = *fs_metrics; + status = _cairo_matrix_compute_basis_scale_factors (&scaled_font->font_matrix, &font_scale_x, &font_scale_y, 1); - if (status) + if (unlikely (status)) return status; /* @@ -780,7 +782,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, return _cairo_scaled_font_create_in_error (font_face->status); status = cairo_font_options_status ((cairo_font_options_t *) options); - if (status) + if (unlikely (status)) return _cairo_scaled_font_create_in_error (status); /* Note that degenerate ctm or font_matrix *are* allowed. @@ -789,13 +791,13 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, if (font_face->backend->get_implementation != NULL) { /* indirect implementation, lookup the face that is used for the key */ status = font_face->backend->get_implementation (font_face, &impl_face); - if (status) + if (unlikely (status)) return _cairo_scaled_font_create_in_error (status); } else impl_face = font_face; font_map = _cairo_scaled_font_map_lock (); - if (font_map == NULL) + if (unlikely (font_map == NULL)) return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); _cairo_scaled_font_init_key (&key, impl_face, @@ -818,13 +820,14 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, } /* the font has been put into an error status - abandon the cache */ - _cairo_hash_table_remove (font_map->hash_table, &key.hash_entry); + _cairo_hash_table_remove (font_map->hash_table, + &scaled_font->hash_entry); scaled_font->hash_entry.hash = ZOMBIE; } else { - while (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry, - (cairo_hash_entry_t**) &scaled_font)) + while ((scaled_font = _cairo_hash_table_lookup (font_map->hash_table, + &key.hash_entry))) { if (! scaled_font->placeholder) break; @@ -877,7 +880,8 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, } /* the font has been put into an error status - abandon the cache */ - _cairo_hash_table_remove (font_map->hash_table, &key.hash_entry); + _cairo_hash_table_remove (font_map->hash_table, + &scaled_font->hash_entry); scaled_font->hash_entry.hash = ZOMBIE; } } @@ -885,7 +889,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, /* 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 (unlikely (status)) { _cairo_scaled_font_map_unlock (); status = _cairo_font_face_set_error (font_face, status); return _cairo_scaled_font_create_in_error (status); @@ -901,7 +905,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, _cairo_scaled_font_map_unlock (); - if (status) { + if (unlikely (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. */ @@ -931,9 +935,9 @@ _cairo_scaled_font_create_in_error (cairo_status_t status) CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex); scaled_font = _cairo_scaled_font_nil_objects[status]; - if (scaled_font == NULL) { + if (unlikely (scaled_font == NULL)) { scaled_font = malloc (sizeof (cairo_scaled_font_t)); - if (scaled_font == NULL) { + if (unlikely (scaled_font == NULL)) { CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_scaled_font_t *) &_cairo_scaled_font_nil; @@ -1036,7 +1040,8 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font) lru = font_map->holdovers[0]; assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&lru->ref_count)); - _cairo_hash_table_remove (font_map->hash_table, &lru->hash_entry); + _cairo_hash_table_remove (font_map->hash_table, + &lru->hash_entry); font_map->num_holdovers--; memmove (&font_map->holdovers[0], @@ -1216,7 +1221,7 @@ cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font, &glyphs, &num_glyphs, NULL, NULL, NULL); - if (status) { + if (unlikely (status)) { status = _cairo_scaled_font_set_error (scaled_font, status); goto ZERO_EXTENTS; } @@ -1299,7 +1304,7 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); - if (status) { + if (unlikely (status)) { status = _cairo_scaled_font_set_error (scaled_font, status); goto UNLOCK; } @@ -1516,7 +1521,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, cairo_text_cluster_t *orig_clusters; status = scaled_font->status; - if (status) + if (unlikely (status)) return status; /* A slew of sanity checks */ @@ -1579,7 +1584,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, /* validate input so backend does not have to */ status = _cairo_utf8_to_ucs4 (utf8, utf8_len, NULL, &num_chars); - if (status) + if (unlikely (status)) goto BAIL; _cairo_scaled_font_freeze_cache (scaled_font); @@ -1637,7 +1642,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, if (*num_glyphs < num_chars) { *glyphs = cairo_glyph_allocate (num_chars); - if (*glyphs == NULL) { + if (unlikely (*glyphs == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto DONE; } @@ -1647,7 +1652,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, if (clusters) { if (*num_clusters < num_chars) { *clusters = cairo_text_cluster_allocate (num_chars); - if (*clusters == NULL) { + if (unlikely (*clusters == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto DONE; } @@ -1677,7 +1682,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, (*glyphs)[i].index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); - if (status) { + if (unlikely (status)) { goto DONE; } @@ -1688,7 +1693,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, DONE: /* error that should be logged on scaled_font happened */ _cairo_scaled_font_thaw_cache (scaled_font); - if (status) { + if (unlikely (status)) { *num_glyphs = 0; if (*glyphs != orig_glyphs) { cairo_glyph_free (*glyphs); @@ -1747,7 +1752,7 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); - if (status) + if (unlikely (status)) break; /* XXX glyph images are snapped to pixel locations */ @@ -1766,7 +1771,7 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font, } _cairo_scaled_font_thaw_cache (scaled_font); - if (status) + if (unlikely (status)) return _cairo_scaled_font_set_error (scaled_font, status); if (min.x < max.x && min.y < max.y) { @@ -1848,7 +1853,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); - if (status) + if (unlikely (status)) goto CLEANUP_MASK; glyph_surface = scaled_glyph->surface; @@ -1859,10 +1864,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, mask_format = glyph_surface->format; mask = cairo_image_surface_create (mask_format, width, height); - if (mask->status) { - status = mask->status; + status = mask->status; + if (unlikely (status)) goto CLEANUP_MASK; - } } /* If we have glyphs of different formats, we "upgrade" the mask @@ -1907,7 +1911,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, _cairo_pattern_fini (&mask_pattern.base); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (new_mask); goto CLEANUP_MASK; } @@ -1935,7 +1939,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, _cairo_pattern_fini (&glyph_pattern.base); - if (status) + if (unlikely (status)) goto CLEANUP_MASK; } @@ -2022,29 +2026,29 @@ _add_unit_rectangle_to_path (cairo_path_fixed_t *path, int x, int y) status = _cairo_path_fixed_move_to (path, _cairo_fixed_from_int (x), _cairo_fixed_from_int (y)); - if (status) + if (unlikely (status)) return status; status = _cairo_path_fixed_rel_line_to (path, _cairo_fixed_from_int (1), _cairo_fixed_from_int (0)); - if (status) + if (unlikely (status)) return status; status = _cairo_path_fixed_rel_line_to (path, _cairo_fixed_from_int (0), _cairo_fixed_from_int (1)); - if (status) + if (unlikely (status)) return status; status = _cairo_path_fixed_rel_line_to (path, _cairo_fixed_from_int (-1), _cairo_fixed_from_int (0)); - if (status) + if (unlikely (status)) return status; status = _cairo_path_fixed_close_path (path); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -2084,7 +2088,7 @@ _trace_mask_to_path (cairo_image_surface_t *mask, a1_mask = _cairo_image_surface_clone (mask, CAIRO_FORMAT_A1); status = cairo_surface_status (&a1_mask->base); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (&a1_mask->base); return status; } @@ -2099,7 +2103,7 @@ _trace_mask_to_path (cairo_image_surface_t *mask, if (byte & (1 << bit)) { status = _add_unit_rectangle_to_path (path, x - xoff, y - yoff); - if (status) + if (unlikely (status)) goto BAIL; } } @@ -2124,7 +2128,7 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, cairo_path_fixed_t *glyph_path; status = scaled_font->status; - if (status) + if (unlikely (status)) return status; closure.path = path; @@ -2148,17 +2152,17 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); - if (status) + if (unlikely (status)) goto BAIL; glyph_path = _cairo_path_fixed_create (); - if (glyph_path == NULL) { + if (unlikely (glyph_path == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto BAIL; } status = _trace_mask_to_path (scaled_glyph->surface, glyph_path); - if (status) { + if (unlikely (status)) { _cairo_path_fixed_destroy (glyph_path); goto BAIL; } @@ -2177,7 +2181,7 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, if (glyph_path != scaled_glyph->path) _cairo_path_fixed_destroy (glyph_path); - if (status) + if (unlikely (status)) goto BAIL; } BAIL: @@ -2208,6 +2212,8 @@ _cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph, double min_device_x = 0.0, max_device_x = 0.0, min_device_y = 0.0, max_device_y = 0.0; double device_x_advance, device_y_advance; + scaled_glyph->fs_metrics = *fs_metrics; + for (hm = 0.0; hm <= 1.0; hm += 1.0) for (wm = 0.0; wm <= 1.0; wm += 1.0) { double x, y; @@ -2348,14 +2354,13 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, * Check cache for glyph */ info |= CAIRO_SCALED_GLYPH_INFO_METRICS; - if (!_cairo_cache_lookup (scaled_font->glyphs, &key, - (cairo_cache_entry_t **) &scaled_glyph)) - { + scaled_glyph = _cairo_cache_lookup (scaled_font->glyphs, &key); + if (scaled_glyph == NULL) { /* * On miss, create glyph and insert into cache */ scaled_glyph = malloc (sizeof (cairo_scaled_glyph_t)); - if (scaled_glyph == NULL) { + if (unlikely (scaled_glyph == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP; } @@ -2371,7 +2376,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, /* ask backend to initialize metrics and shape fields */ status = (*scaled_font->backend-> scaled_glyph_init) (scaled_font, scaled_glyph, info); - if (status) { + if (unlikely (status)) { _cairo_scaled_glyph_destroy (scaled_glyph); goto CLEANUP; } @@ -2379,7 +2384,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, /* on success, the cache takes ownership of the scaled_glyph */ status = _cairo_cache_insert (scaled_font->glyphs, &scaled_glyph->cache_entry); - if (status) { + if (unlikely (status)) { _cairo_scaled_glyph_destroy (scaled_glyph); goto CLEANUP; } @@ -2404,7 +2409,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, if (need_info) { status = (*scaled_font->backend-> scaled_glyph_init) (scaled_font, scaled_glyph, need_info); - if (status) + if (unlikely (status)) goto CLEANUP; /* Don't trust the scaled_glyph_init() return value, the font @@ -2432,7 +2437,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, } CLEANUP: - if (status) { + if (unlikely (status)) { /* It's not an error for the backend to not support the info we want. */ if (status != CAIRO_INT_STATUS_UNSUPPORTED) status = _cairo_scaled_font_set_error (scaled_font, status); diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c new file mode 100644 index 00000000..cf2809f5 --- /dev/null +++ b/src/cairo-script-surface.c @@ -0,0 +1,2600 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 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. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +/* The script surface is one that records all operations performed on + * it in the form of a procedural script, similar in fashion to + * PostScript but using Cairo's imaging model. In essence, this is + * equivalent to the meta-surface, but as there is no impedance mismatch + * between Cairo and CairoScript, we can generate output immediately + * without having to copy and hold the data in memory. + */ + +#include "cairoint.h" + +#include "cairo-script.h" + +#include "cairo-analysis-surface-private.h" +#include "cairo-ft-private.h" +#include "cairo-meta-surface-private.h" +#include "cairo-output-stream-private.h" + +#define _cairo_output_stream_puts(S, STR) \ + _cairo_output_stream_write ((S), (STR), strlen (STR)) + +#define static cairo_warn static + +typedef struct _cairo_script_vmcontext cairo_script_vmcontext_t; +typedef struct _cairo_script_surface cairo_script_surface_t; +typedef struct _cairo_script_implicit_context cairo_script_implicit_context_t; +typedef struct _cairo_script_surface_font_private cairo_script_surface_font_private_t; + +struct _cairo_script_vmcontext { + int ref; + + cairo_output_stream_t *stream; + cairo_script_mode_t mode; + + struct _bitmap { + unsigned long min; + unsigned long count; + unsigned int map[64]; + struct _bitmap *next; + } surface_id, font_id; + + cairo_script_surface_t *current_target; + + cairo_script_surface_font_private_t *fonts; +}; + +struct _cairo_script_surface_font_private { + cairo_script_vmcontext_t *ctx; + cairo_bool_t has_sfnt; + unsigned long id; + unsigned long subset_glyph_index; + cairo_script_surface_font_private_t *prev, *next; + cairo_scaled_font_t *parent; +}; + +struct _cairo_script_implicit_context { + cairo_operator_t current_operator; + cairo_fill_rule_t current_fill_rule; + double current_tolerance; + cairo_antialias_t current_antialias; + cairo_stroke_style_t current_style; + cairo_pattern_t *current_source; + cairo_matrix_t current_ctm; + cairo_matrix_t current_font_matrix; + cairo_font_options_t current_font_options; + cairo_scaled_font_t *current_scaled_font; + cairo_path_fixed_t current_path; +}; + +struct _cairo_script_surface { + cairo_surface_t base; + + cairo_script_vmcontext_t *ctx; + + unsigned long id; + + double width, height; + + /* implicit flattened context */ + cairo_script_implicit_context_t cr; +}; + +static const cairo_surface_backend_t _cairo_script_surface_backend; + +static cairo_script_surface_t * +_cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx, + double width, + double height); + +static void +_cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font); + +static void +_cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr); + +static void +_bitmap_release_id (struct _bitmap *b, unsigned long token) +{ + struct _bitmap **prev = NULL; + + do { + if (token < b->min + sizeof (b->map) * CHAR_BIT) { + unsigned int bit, elem; + + token -= b->min; + elem = token / (sizeof (b->map[0]) * CHAR_BIT); + bit = token % (sizeof (b->map[0]) * CHAR_BIT); + b->map[elem] &= ~(1 << bit); + if (! --b->count && prev) { + *prev = b->next; + free (b); + } + return; + } + prev = &b->next; + b = b->next; + } while (b != NULL); +} + +static cairo_status_t +_bitmap_next_id (struct _bitmap *b, + unsigned long *id) +{ + struct _bitmap *bb, **prev = NULL; + unsigned long min = 0; + + do { + if (b->min != min) + break; + + if (b->count < sizeof (b->map) * CHAR_BIT) { + unsigned int n, m, bit; + for (n = 0; n < ARRAY_LENGTH (b->map); n++) { + if (b->map[n] == (unsigned int) -1) + continue; + + for (m=0, bit=1; m<sizeof (b->map[0])*CHAR_BIT; m++, bit<<=1) { + if ((b->map[n] & bit) == 0) { + b->map[n] |= bit; + b->count++; + *id = n * sizeof (b->map[0])*CHAR_BIT + m + b->min; + return CAIRO_STATUS_SUCCESS; + } + } + } + } + min += sizeof (b->map) * CHAR_BIT; + + prev = &b->next; + b = b->next; + } while (b != NULL); + + bb = malloc (sizeof (struct _bitmap)); + if (unlikely (bb == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + *prev = bb; + bb->next = b; + bb->min = min; + bb->count = 1; + bb->map[0] = 0x1; + memset (bb->map + 1, 0, sizeof (bb->map) - sizeof (bb->map[0])); + *id = min; + + return CAIRO_STATUS_SUCCESS; +} + +static const char * +_direction_to_string (cairo_bool_t backward) +{ + static const char *names[] = { + "FORWARD", + "BACKWARD" + }; + assert (backward < ARRAY_LENGTH (names)); + return names[backward]; +} + +static const char * +_operator_to_string (cairo_operator_t op) +{ + static const char *names[] = { + "CLEAR", /* CAIRO_OPERATOR_CLEAR */ + + "SOURCE", /* CAIRO_OPERATOR_SOURCE */ + "OVER", /* CAIRO_OPERATOR_OVER */ + "IN", /* CAIRO_OPERATOR_IN */ + "OUT", /* CAIRO_OPERATOR_OUT */ + "ATOP", /* CAIRO_OPERATOR_ATOP */ + + "DEST", /* CAIRO_OPERATOR_DEST */ + "DEST_OVER", /* CAIRO_OPERATOR_DEST_OVER */ + "DEST_IN", /* CAIRO_OPERATOR_DEST_IN */ + "DEST_OUT", /* CAIRO_OPERATOR_DEST_OUT */ + "DEST_ATOP", /* CAIRO_OPERATOR_DEST_ATOP */ + + "XOR", /* CAIRO_OPERATOR_XOR */ + "ADD", /* CAIRO_OPERATOR_ADD */ + "SATURATE" /* CAIRO_OPERATOR_SATURATE */ + }; + assert (op < ARRAY_LENGTH (names)); + return names[op]; +} + +static const char * +_extend_to_string (cairo_extend_t extend) +{ + static const char *names[] = { + "EXTEND_NONE", /* CAIRO_EXTEND_NONE */ + "EXTEND_REPEAT", /* CAIRO_EXTEND_REPEAT */ + "EXTEND_REFLECT", /* CAIRO_EXTEND_REFLECT */ + "EXTEND_PAD" /* CAIRO_EXTEND_PAD */ + }; + assert (extend < ARRAY_LENGTH (names)); + return names[extend]; +} + +static const char * +_filter_to_string (cairo_filter_t filter) +{ + static const char *names[] = { + "FILTER_FAST", /* CAIRO_FILTER_FAST */ + "FILTER_GOOD", /* CAIRO_FILTER_GOOD */ + "FILTER_BEST", /* CAIRO_FILTER_BEST */ + "FILTER_NEAREST", /* CAIRO_FILTER_NEAREST */ + "FILTER_BILINEAR", /* CAIRO_FILTER_BILINEAR */ + "FILTER_GAUSSIAN", /* CAIRO_FILTER_GAUSSIAN */ + }; + assert (filter < ARRAY_LENGTH (names)); + return names[filter]; +} + +static const char * +_fill_rule_to_string (cairo_fill_rule_t rule) +{ + static const char *names[] = { + "WINDING", /* CAIRO_FILL_RULE_WINDING */ + "EVEN_ODD" /* CAIRO_FILL_RILE_EVEN_ODD */ + }; + assert (rule < ARRAY_LENGTH (names)); + return names[rule]; +} + +static const char * +_antialias_to_string (cairo_antialias_t antialias) +{ + static const char *names[] = { + "ANTIALIAS_DEFAULT", /* CAIRO_ANTIALIAS_DEFAULT */ + "ANTIALIAS_NONE", /* CAIRO_ANTIALIAS_NONE */ + "ANTIALIAS_GRAY", /* CAIRO_ANTIALIAS_GRAY */ + "ANTIALIAS_SUBPIXEL" /* CAIRO_ANTIALIAS_SUBPIXEL */ + }; + assert (antialias < ARRAY_LENGTH (names)); + return names[antialias]; +} + +static const char * +_line_cap_to_string (cairo_line_cap_t line_cap) +{ + static const char *names[] = { + "LINE_CAP_BUTT", /* CAIRO_LINE_CAP_BUTT */ + "LINE_CAP_ROUND", /* CAIRO_LINE_CAP_ROUND */ + "LINE_CAP_SQUARE" /* CAIRO_LINE_CAP_SQUARE */ + }; + assert (line_cap < ARRAY_LENGTH (names)); + return names[line_cap]; +} + +static const char * +_line_join_to_string (cairo_line_join_t line_join) +{ + static const char *names[] = { + "LINE_JOIN_MITER", /* CAIRO_LINE_JOIN_MITER */ + "LINE_JOIN_ROUND", /* CAIRO_LINE_JOIN_ROUND */ + "LINE_JOIN_BEVEL", /* CAIRO_LINE_JOIN_BEVEL */ + }; + assert (line_join < ARRAY_LENGTH (names)); + return names[line_join]; +} + +static cairo_bool_t +_cairo_script_surface_owns_context (cairo_script_surface_t *surface) +{ + return surface->ctx->current_target == surface; +} + +static cairo_status_t +_emit_context (cairo_script_surface_t *surface) +{ + if (_cairo_script_surface_owns_context (surface)) + return CAIRO_STATUS_SUCCESS; + + if (surface->ctx->current_target != NULL) + _cairo_output_stream_puts (surface->ctx->stream, "pop\n"); + + surface->ctx->current_target = surface; + + if (surface->id == (unsigned long) -1) { + cairo_status_t status; + + status = _bitmap_next_id (&surface->ctx->surface_id, + &surface->id); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->ctx->stream, + "dict\n" + " /width %f set\n" + " /height %f set\n", + surface->width, + surface->height); + if (surface->base.x_fallback_resolution != + CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT || + surface->base.y_fallback_resolution != + CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT) + { + _cairo_output_stream_printf (surface->ctx->stream, + " /fallback-resolution [%f %f] set\n", + surface->base.x_fallback_resolution, + surface->base.y_fallback_resolution); + } + if (surface->base.device_transform.x0 != 0. || + surface->base.device_transform.y0 != 0.) + { + /* XXX device offset is encoded into the pattern matrices etc. */ + _cairo_output_stream_printf (surface->ctx->stream, + " %%/device-offset [%f %f] set\n", + surface->base.device_transform.x0, + surface->base.device_transform.y0); + } + _cairo_output_stream_printf (surface->ctx->stream, + " surface dup /s%lu exch def\n" + "context dup /c%lu exch def\n", + surface->id, + surface->id); + } else { + _cairo_output_stream_printf (surface->ctx->stream, + "c%lu\n", + surface->id); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_operator (cairo_script_surface_t *surface, + cairo_operator_t op) +{ + assert (_cairo_script_surface_owns_context (surface)); + + if (surface->cr.current_operator == op) + return CAIRO_STATUS_SUCCESS; + + surface->cr.current_operator = op; + + _cairo_output_stream_printf (surface->ctx->stream, + "//%s set_operator\n", + _operator_to_string (op)); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_fill_rule (cairo_script_surface_t *surface, + cairo_fill_rule_t fill_rule) +{ + assert (_cairo_script_surface_owns_context (surface)); + + if (surface->cr.current_fill_rule == fill_rule) + return CAIRO_STATUS_SUCCESS; + + surface->cr.current_fill_rule = fill_rule; + + _cairo_output_stream_printf (surface->ctx->stream, + "//%s set_fill_rule\n", + _fill_rule_to_string (fill_rule)); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_tolerance (cairo_script_surface_t *surface, + double tolerance, + cairo_bool_t force) +{ + assert (_cairo_script_surface_owns_context (surface)); + + if (! force && surface->cr.current_tolerance == tolerance) + return CAIRO_STATUS_SUCCESS; + + surface->cr.current_tolerance = tolerance; + + _cairo_output_stream_printf (surface->ctx->stream, + "%f set_tolerance\n", + tolerance); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_antialias (cairo_script_surface_t *surface, + cairo_antialias_t antialias) +{ + assert (_cairo_script_surface_owns_context (surface)); + + if (surface->cr.current_antialias == antialias) + return CAIRO_STATUS_SUCCESS; + + surface->cr.current_antialias = antialias; + + _cairo_output_stream_printf (surface->ctx->stream, + "//%s set_antialias\n", + _antialias_to_string (antialias)); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_line_width (cairo_script_surface_t *surface, + double line_width, + cairo_bool_t force) +{ + assert (_cairo_script_surface_owns_context (surface)); + + if (! force && surface->cr.current_style.line_width == line_width) + return CAIRO_STATUS_SUCCESS; + + surface->cr.current_style.line_width = line_width; + + _cairo_output_stream_printf (surface->ctx->stream, + "%f set_line_width\n", + line_width); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_line_cap (cairo_script_surface_t *surface, + cairo_line_cap_t line_cap) +{ + assert (_cairo_script_surface_owns_context (surface)); + + if (surface->cr.current_style.line_cap == line_cap) + return CAIRO_STATUS_SUCCESS; + + surface->cr.current_style.line_cap = line_cap; + + _cairo_output_stream_printf (surface->ctx->stream, + "//%s set_line_cap\n", + _line_cap_to_string (line_cap)); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_line_join (cairo_script_surface_t *surface, + cairo_line_join_t line_join) +{ + assert (_cairo_script_surface_owns_context (surface)); + + if (surface->cr.current_style.line_join == line_join) + return CAIRO_STATUS_SUCCESS; + + surface->cr.current_style.line_join = line_join; + + _cairo_output_stream_printf (surface->ctx->stream, + "//%s set_line_join\n", + _line_join_to_string (line_join)); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_miter_limit (cairo_script_surface_t *surface, + double miter_limit, + cairo_bool_t force) +{ + assert (_cairo_script_surface_owns_context (surface)); + + if (! force && surface->cr.current_style.miter_limit == miter_limit) + return CAIRO_STATUS_SUCCESS; + + surface->cr.current_style.miter_limit = miter_limit; + + _cairo_output_stream_printf (surface->ctx->stream, + "%f set_miter_limit\n", + miter_limit); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_dash (cairo_script_surface_t *surface, + const double *dash, + unsigned int num_dashes, + double offset, + cairo_bool_t force) +{ + unsigned int n; + + assert (_cairo_script_surface_owns_context (surface)); + + if (force && + num_dashes == 0 && + surface->cr.current_style.num_dashes == 0) + { + return CAIRO_STATUS_SUCCESS; + } + + if (! force && + (surface->cr.current_style.num_dashes == num_dashes && + (num_dashes == 0 || + (surface->cr.current_style.dash_offset == offset && + memcmp (surface->cr.current_style.dash, dash, + sizeof (double) * num_dashes))))) + { + return CAIRO_STATUS_SUCCESS; + } + + + if (num_dashes) { + surface->cr.current_style.dash = _cairo_realloc_ab + (surface->cr.current_style.dash, + num_dashes, + sizeof (double)); + memcpy (surface->cr.current_style.dash, dash, + sizeof (double) * num_dashes); + } else { + if (surface->cr.current_style.dash != NULL) { + free (surface->cr.current_style.dash); + surface->cr.current_style.dash = NULL; + } + } + + surface->cr.current_style.num_dashes = num_dashes; + surface->cr.current_style.dash_offset = offset; + + _cairo_output_stream_printf (surface->ctx->stream, "["); + for (n = 0; n < num_dashes; n++) { + _cairo_output_stream_printf (surface->ctx->stream, "%f", dash[n]); + if (n < num_dashes-1) + _cairo_output_stream_puts (surface->ctx->stream, " "); + } + _cairo_output_stream_printf (surface->ctx->stream, + "] %f set_dash\n", + offset); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_stroke_style (cairo_script_surface_t *surface, + const cairo_stroke_style_t *style, + cairo_bool_t force) +{ + cairo_status_t status; + + assert (_cairo_script_surface_owns_context (surface)); + + status = _emit_line_width (surface, style->line_width, force); + if (unlikely (status)) + return status; + + status = _emit_line_cap (surface, style->line_cap); + if (unlikely (status)) + return status; + + status = _emit_line_join (surface, style->line_join); + if (unlikely (status)) + return status; + + status = _emit_miter_limit (surface, style->miter_limit, force); + if (unlikely (status)) + return status; + + status = _emit_dash (surface, + style->dash, style->num_dashes, style->dash_offset, + force); + if (unlikely (status)) + return status; + + return CAIRO_STATUS_SUCCESS; +} + +static const char * +_format_to_string (cairo_format_t format) +{ + static const char *names[] = { + "ARGB32", /* CAIRO_FORMAT_ARGB32 */ + "RGB24", /* CAIRO_FORMAT_RGB24 */ + "A8", /* CAIRO_FORMAT_A8 */ + "A1" /* CAIRO_FORMAT_A1 */ + }; + assert (format < ARRAY_LENGTH (names)); + return names[format]; +} + +static cairo_status_t +_emit_solid_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; + + if (solid->content & CAIRO_CONTENT_ALPHA && + ! CAIRO_COLOR_IS_OPAQUE (&solid->color)) + { + if (! (solid->content & CAIRO_CONTENT_COLOR) || + (solid->color.red_short == 0 && + solid->color.green_short == 0 && + solid->color.blue_short == 0)) + { + _cairo_output_stream_printf (surface->ctx->stream, + "%f a", + solid->color.alpha); + } + else + { + _cairo_output_stream_printf (surface->ctx->stream, + "%f %f %f %f rgba", + solid->color.red, + solid->color.green, + solid->color.blue, + solid->color.alpha); + } + } + else + { + if (solid->color.red_short == solid->color.green_short && + solid->color.red_short == solid->color.blue_short) + { + _cairo_output_stream_printf (surface->ctx->stream, + "%f g", + solid->color.red); + } + else + { + _cairo_output_stream_printf (surface->ctx->stream, + "%f %f %f rgb", + solid->color.red, + solid->color.green, + solid->color.blue); + } + } + + return CAIRO_STATUS_SUCCESS; +} + + +static cairo_status_t +_emit_gradient_color_stops (cairo_gradient_pattern_t *gradient, + cairo_output_stream_t *output) +{ + unsigned int n; + + for (n = 0; n < gradient->n_stops; n++) { + _cairo_output_stream_printf (output, + " %f %f %f %f %f add_color_stop\n ", + gradient->stops[n].offset, + gradient->stops[n].color.red, + gradient->stops[n].color.green, + gradient->stops[n].color.blue, + gradient->stops[n].color.alpha); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_linear_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_linear_pattern_t *linear; + + linear = (cairo_linear_pattern_t *) pattern; + + _cairo_output_stream_printf (surface->ctx->stream, + "%f %f %f %f linear\n ", + _cairo_fixed_to_double (linear->p1.x), + _cairo_fixed_to_double (linear->p1.y), + _cairo_fixed_to_double (linear->p2.x), + _cairo_fixed_to_double (linear->p2.y)); + return _emit_gradient_color_stops (&linear->base, surface->ctx->stream); +} + +static cairo_status_t +_emit_radial_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_radial_pattern_t *radial; + + radial = (cairo_radial_pattern_t *) pattern; + + _cairo_output_stream_printf (surface->ctx->stream, + "%f %f %f %f %f %f radial\n ", + _cairo_fixed_to_double (radial->c1.x), + _cairo_fixed_to_double (radial->c1.y), + _cairo_fixed_to_double (radial->r1), + _cairo_fixed_to_double (radial->c2.x), + _cairo_fixed_to_double (radial->c2.y), + _cairo_fixed_to_double (radial->r2)); + return _emit_gradient_color_stops (&radial->base, surface->ctx->stream); +} + +static cairo_status_t +_emit_meta_surface_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_surface_pattern_t *surface_pattern; + cairo_surface_t *source; + cairo_surface_t *null_surface; + cairo_surface_t *analysis_surface; + cairo_surface_t *similar; + cairo_status_t status; + cairo_box_t bbox; + + surface_pattern = (cairo_surface_pattern_t *) pattern; + source = surface_pattern->surface; + + /* first measure the extents */ + null_surface = _cairo_null_surface_create (source->content); + analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1); + cairo_surface_destroy (null_surface); + + status = analysis_surface->status; + if (unlikely (status)) + return status; + + status = _cairo_meta_surface_replay (source, analysis_surface); + _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox); + cairo_surface_destroy (analysis_surface); + if (unlikely (status)) + return status; + + similar = cairo_surface_create_similar (&surface->base, + source->content, + _cairo_fixed_to_double (bbox.p2.x-bbox.p1.x), + _cairo_fixed_to_double (bbox.p2.y-bbox.p1.y)); + if (similar->status) + return similar->status; + + status = _cairo_meta_surface_replay (source, similar); + if (unlikely (status)) { + cairo_surface_destroy (similar); + return status; + } + + status = _emit_context (surface); + if (unlikely (status)) { + cairo_surface_destroy (similar); + return status; + } + + _cairo_output_stream_printf (surface->ctx->stream, + "s%lu pattern\n ", + ((cairo_script_surface_t *) similar)->id); + cairo_surface_destroy (similar); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_script_surface_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_surface_pattern_t *surface_pattern; + cairo_script_surface_t *source; + + surface_pattern = (cairo_surface_pattern_t *) pattern; + source = (cairo_script_surface_t *) surface_pattern->surface; + + _cairo_output_stream_printf (surface->ctx->stream, + "s%lu pattern\n ", source->id); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_write_image_surface (cairo_output_stream_t *output, + const cairo_image_surface_t *image) +{ + int stride, row, width; + uint8_t row_stack[CAIRO_STACK_BUFFER_SIZE]; + uint8_t *rowdata; + uint8_t *data; + + stride = image->stride; + width = image->width; + data = image->data; +#if WORDS_BIGENDIAN + switch (image->format) { + case CAIRO_FORMAT_A1: + for (row = image->height; row--; ) { + _cairo_output_stream_write (output, data, (width+7)/8); + data += stride; + } + break; + case CAIRO_FORMAT_A8: + for (row = image->height; row--; ) { + _cairo_output_stream_write (output, data, width); + data += stride; + } + break; + case CAIRO_FORMAT_RGB24: + for (row = image->height; row--; ) { + int col; + rowdata = data; + for (col = width; col--; ) { + _cairo_output_stream_write (output, rowdata, 3); + rowdata+=4; + } + data += stride; + } + break; + case CAIRO_FORMAT_ARGB32: + for (row = image->height; row--; ) { + _cairo_output_stream_write (output, data, 4*width); + data += stride; + } + break; + default: + ASSERT_NOT_REACHED; + break; + } +#else + if (stride > ARRAY_LENGTH (row_stack)) { + rowdata = malloc (stride); + if (unlikely (rowdata == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else + rowdata = row_stack; + + switch (image->format) { + case CAIRO_FORMAT_A1: + for (row = image->height; row--; ) { + int col; + for (col = 0; col < (width + 7)/8; col++) + rowdata[col] = CAIRO_BITSWAP8 (data[col]); + _cairo_output_stream_write (output, rowdata, (width+7)/8); + data += stride; + } + break; + case CAIRO_FORMAT_A8: + for (row = image->height; row--; ) { + _cairo_output_stream_write (output, data, width); + data += stride; + } + break; + case CAIRO_FORMAT_RGB24: + for (row = image->height; row--; ) { + uint8_t *src = data; + int col; + for (col = 0; col < width; col++) { + rowdata[3*col+2] = *src++; + rowdata[3*col+1] = *src++; + rowdata[3*col+0] = *src++; + src++; + } + _cairo_output_stream_write (output, rowdata, 3*width); + data += stride; + } + break; + case CAIRO_FORMAT_ARGB32: + for (row = image->height; row--; ) { + uint32_t *src = (uint32_t *) data; + uint32_t *dst = (uint32_t *) rowdata; + int col; + for (col = 0; col < width; col++) + dst[col] = bswap_32 (src[col]); + _cairo_output_stream_write (output, rowdata, 4*width); + data += stride; + } + break; + default: + ASSERT_NOT_REACHED; + break; + } + if (rowdata != row_stack) + free (rowdata); +#endif + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_emit_png_surface (cairo_script_surface_t *surface, + cairo_image_surface_t *image) +{ + cairo_output_stream_t *base85_stream; + cairo_status_t status; + const uint8_t *mime_data; + unsigned int mime_data_length; + + cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_PNG, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_output_stream_printf (surface->ctx->stream, + "dict\n" + " /width %d set\n" + " /height %d set\n" + " /format //%s set\n" + " /mime-type (image/png) set\n" + " /source <~", + image->width, image->height, + _format_to_string (image->format)); + + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + _cairo_output_stream_write (base85_stream, mime_data, mime_data_length); + status = _cairo_output_stream_destroy (base85_stream); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (surface->ctx->stream, + " set\n image"); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_image_surface (cairo_script_surface_t *surface, + cairo_image_surface_t *image) +{ + cairo_output_stream_t *base85_stream; + cairo_output_stream_t *zlib_stream; + cairo_status_t status, status2; + const uint8_t *mime_data; + unsigned int mime_data_length; + + status = _emit_png_surface (surface, image); + if (_cairo_status_is_error (status)) { + return status; + } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + _cairo_output_stream_printf (surface->ctx->stream, + "dict\n" + " /width %d set\n" + " /height %d set\n" + " /format //%s set\n" + " /source <~", + image->width, image->height, + _format_to_string (image->format)); + + if (image->width * image->height > 8) { + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + zlib_stream = _cairo_deflate_stream_create (base85_stream); + + status = _write_image_surface (zlib_stream, image); + + status2 = _cairo_output_stream_destroy (zlib_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + status2 = _cairo_output_stream_destroy (base85_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (surface->ctx->stream, + " /deflate filter set\n image"); + } else { + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + status = _write_image_surface (base85_stream, image); + status2 = _cairo_output_stream_destroy (base85_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + _cairo_output_stream_puts (surface->ctx->stream, + " set\n image"); + } + } + + cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JPEG, + &mime_data, &mime_data_length); + if (mime_data != NULL) { + _cairo_output_stream_printf (surface->ctx->stream, + "\n (%s) <~", + CAIRO_MIME_TYPE_JPEG); + + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + _cairo_output_stream_write (base85_stream, mime_data, mime_data_length); + status = _cairo_output_stream_destroy (base85_stream); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (surface->ctx->stream, + " set_mime_data\n "); + } + + _cairo_output_stream_puts (surface->ctx->stream, + " pattern\n "); + + return status; +} + +static cairo_status_t +_emit_image_surface_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_surface_pattern_t *surface_pattern; + cairo_surface_t *source; + cairo_image_surface_t *image; + void *image_extra; + cairo_status_t status; + + surface_pattern = (cairo_surface_pattern_t *) pattern; + source = surface_pattern->surface; + + /* XXX snapshot-cow */ + status = _cairo_surface_acquire_source_image (source, &image, &image_extra); + if (unlikely (status)) + return status; + + status = _emit_image_surface (surface, image); + + _cairo_surface_release_source_image (source, image, image_extra); + + return status; +} + +static cairo_status_t +_emit_surface_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_surface_pattern_t *surface_pattern; + cairo_surface_t *source; + + surface_pattern = (cairo_surface_pattern_t *) pattern; + source = surface_pattern->surface; + + switch ((int) source->type) { + case CAIRO_INTERNAL_SURFACE_TYPE_META: + return _emit_meta_surface_pattern (surface, pattern); + case CAIRO_SURFACE_TYPE_SCRIPT: + return _emit_script_surface_pattern (surface, pattern); + default: + return _emit_image_surface_pattern (surface, pattern); + } +} + +static cairo_status_t +_emit_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_status_t status; + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + /* solid colors do not need filter/extend/matrix */ + return _emit_solid_pattern (surface, pattern); + + case CAIRO_PATTERN_TYPE_LINEAR: + status = _emit_linear_pattern (surface, pattern); + break; + case CAIRO_PATTERN_TYPE_RADIAL: + status = _emit_radial_pattern (surface, pattern); + break; + case CAIRO_PATTERN_TYPE_SURFACE: + status = _emit_surface_pattern (surface, pattern); + break; + + default: + ASSERT_NOT_REACHED; + status = CAIRO_INT_STATUS_UNSUPPORTED; + } + if (unlikely (status)) + return status; + + if (! _cairo_matrix_is_identity (&pattern->matrix)) { + _cairo_output_stream_printf (surface->ctx->stream, + " [%f %f %f %f %f %f] set_matrix\n ", + pattern->matrix.xx, pattern->matrix.yx, + pattern->matrix.xy, pattern->matrix.yy, + pattern->matrix.x0, pattern->matrix.y0); + } + + _cairo_output_stream_printf (surface->ctx->stream, + " //%s set_extend\n " + " //%s set_filter\n ", + _extend_to_string (pattern->extend), + _filter_to_string (pattern->filter)); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_identity (cairo_script_surface_t *surface, + cairo_bool_t *matrix_updated) +{ + assert (_cairo_script_surface_owns_context (surface)); + + if (_cairo_matrix_is_identity (&surface->cr.current_ctm)) + return CAIRO_STATUS_SUCCESS; + + _cairo_output_stream_puts (surface->ctx->stream, + "identity set_matrix\n"); + + *matrix_updated = TRUE; + cairo_matrix_init_identity (&surface->cr.current_ctm); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_source (cairo_script_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source) +{ + cairo_bool_t matrix_updated = FALSE; + cairo_status_t status; + + assert (_cairo_script_surface_owns_context (surface)); + + if (op == CAIRO_OPERATOR_CLEAR) { + /* the source is ignored, so don't change it */ + return CAIRO_STATUS_SUCCESS; + } + + if (surface->cr.current_source == source) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_pattern_equal (surface->cr.current_source, source)) + return CAIRO_STATUS_SUCCESS; + + cairo_pattern_destroy (surface->cr.current_source); + status = _cairo_pattern_create_copy (&surface->cr.current_source, + source); + if (unlikely (status)) + return status; + + status = _emit_identity (surface, &matrix_updated); + if (unlikely (status)) + return status; + + status = _emit_pattern (surface, source); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (surface->ctx->stream, + " set_source\n"); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_path_move_to (void *closure, cairo_point_t *point) +{ + _cairo_output_stream_printf (closure, + " %f %f m", + _cairo_fixed_to_double (point->x), + _cairo_fixed_to_double (point->y)); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_path_line_to (void *closure, cairo_point_t *point) +{ + _cairo_output_stream_printf (closure, + " %f %f l", + _cairo_fixed_to_double (point->x), + _cairo_fixed_to_double (point->y)); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_path_curve_to (void *closure, + cairo_point_t *p1, + cairo_point_t *p2, + cairo_point_t *p3) +{ + _cairo_output_stream_printf (closure, + " %f %f %f %f %f %f c", + _cairo_fixed_to_double (p1->x), + _cairo_fixed_to_double (p1->y), + _cairo_fixed_to_double (p2->x), + _cairo_fixed_to_double (p2->y), + _cairo_fixed_to_double (p3->x), + _cairo_fixed_to_double (p3->y)); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_path_close (void *closure) +{ + _cairo_output_stream_printf (closure, + " h"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_path (cairo_script_surface_t *surface, + cairo_path_fixed_t *path) +{ + cairo_box_t box; + cairo_status_t status; + + assert (_cairo_script_surface_owns_context (surface)); + assert (_cairo_matrix_is_identity (&surface->cr.current_ctm)); + + if (_cairo_path_fixed_equal (&surface->cr.current_path, path)) + return CAIRO_STATUS_SUCCESS; + + _cairo_path_fixed_fini (&surface->cr.current_path); + + _cairo_output_stream_puts (surface->ctx->stream, "n"); + + if (path == NULL) { + _cairo_path_fixed_init (&surface->cr.current_path); + } else if (_cairo_path_fixed_is_rectangle (path, &box)) { + double x1 = _cairo_fixed_to_double (box.p1.x); + double y1 = _cairo_fixed_to_double (box.p1.y); + double x2 = _cairo_fixed_to_double (box.p2.x); + double y2 = _cairo_fixed_to_double (box.p2.y); + + status = _cairo_path_fixed_init_copy (&surface->cr.current_path, path); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->ctx->stream, + " %f %f %f %f rectangle", + x1, y1, x2 - x1, y2 - y1); + } else { + cairo_status_t status; + + status = _cairo_path_fixed_init_copy (&surface->cr.current_path, path); + if (unlikely (status)) + return status; + + status = _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + _path_move_to, + _path_line_to, + _path_curve_to, + _path_close, + surface->ctx->stream); + if (unlikely (status)) + return status; + } + + _cairo_output_stream_puts (surface->ctx->stream, "\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_matrix (cairo_script_surface_t *surface, + const cairo_matrix_t *ctm, + cairo_bool_t *matrix_updated) +{ + assert (_cairo_script_surface_owns_context (surface)); + + if (memcmp (&surface->cr.current_ctm, ctm, sizeof (cairo_matrix_t)) == 0) + return CAIRO_STATUS_SUCCESS; + + *matrix_updated = TRUE; + surface->cr.current_ctm = *ctm; + + if (_cairo_matrix_is_identity (ctm)) { + _cairo_output_stream_puts (surface->ctx->stream, + "identity set_matrix\n"); + } else { + _cairo_output_stream_printf (surface->ctx->stream, + "[%f %f %f %f %f %f] set_matrix\n", + ctm->xx, ctm->yx, + ctm->xy, ctm->yy, + ctm->x0, ctm->y0); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_font_matrix (cairo_script_surface_t *surface, + const cairo_matrix_t *font_matrix) +{ + assert (_cairo_script_surface_owns_context (surface)); + + if (memcmp (&surface->cr.current_font_matrix, + font_matrix, + sizeof (cairo_matrix_t)) == 0) + { + return CAIRO_STATUS_SUCCESS; + } + + surface->cr.current_font_matrix = *font_matrix; + + if (_cairo_matrix_is_identity (font_matrix)) { + _cairo_output_stream_puts (surface->ctx->stream, + "identity set_font_matrix\n"); + } else { + _cairo_output_stream_printf (surface->ctx->stream, + "[%f %f %f %f %f %f] set_font_matrix\n", + font_matrix->xx, font_matrix->yx, + font_matrix->xy, font_matrix->yy, + font_matrix->x0, font_matrix->y0); + } + + return CAIRO_STATUS_SUCCESS; +} + +static const char * +_content_to_string (cairo_content_t content) +{ + switch (content) { + case CAIRO_CONTENT_ALPHA: return "ALPHA"; + case CAIRO_CONTENT_COLOR: return "COLOR"; + default: + case CAIRO_CONTENT_COLOR_ALPHA: return "COLOR_ALPHA"; + } +} + +static cairo_surface_t * +_cairo_script_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + cairo_script_surface_t *surface, *other; + cairo_script_vmcontext_t *ctx; + cairo_status_t status; + + other = abstract_surface; + ctx = other->ctx; + + if (other->id == (unsigned long) -1) { + cairo_status_t status; + + status = _bitmap_next_id (&ctx->surface_id, + &other->id); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + _cairo_output_stream_printf (ctx->stream, + "dict\n" + " /width %f set\n" + " /height %f set\n" + " surface dup /s%lu exch def\n" + "context /c%lu exch def\n", + other->width, + other->height, + other->id, + other->id); + } + + + surface = _cairo_script_surface_create_internal (ctx, width, height); + if (surface->base.status) + return &surface->base; + + status = _bitmap_next_id (&ctx->surface_id, + &surface->id); + if (unlikely (status)) { + cairo_surface_destroy (&surface->base); + return _cairo_surface_create_in_error (status); + } + + if (ctx->current_target != NULL) + _cairo_output_stream_printf (ctx->stream, "pop\n"); + + _cairo_output_stream_printf (ctx->stream, + "s%lu %u %u //%s similar dup /s%lu exch def\n" + "context dup /c%lu exch def\n", + other->id, width, height, + _content_to_string (content), + surface->id, + surface->id); + + ctx->current_target = surface; + + return &surface->base; +} + +static cairo_status_t +_vmcontext_destroy (cairo_script_vmcontext_t *ctx) +{ + cairo_status_t status; + + if (--ctx->ref) + return _cairo_output_stream_flush (ctx->stream); + + while (ctx->fonts != NULL ){ + cairo_script_surface_font_private_t *font = ctx->fonts; + ctx->fonts = font->next; + _cairo_script_surface_scaled_font_fini (font->parent); + } + + status = _cairo_output_stream_destroy (ctx->stream); + + free (ctx); + + return status; +} + +static cairo_status_t +_cairo_script_surface_finish (void *abstract_surface) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_status_t status; + + cairo_pattern_destroy (surface->cr.current_source); + _cairo_path_fixed_fini (&surface->cr.current_path); + + if (surface->ctx->current_target == surface) { + _cairo_output_stream_printf (surface->ctx->stream, + "pop\n"); + surface->ctx->current_target = NULL; + } + + _cairo_output_stream_printf (surface->ctx->stream, + "/c%lu undef\n" + "/s%lu undef\n", + surface->id, + surface->id); + + _bitmap_release_id (&surface->ctx->surface_id, surface->id); + + status = _vmcontext_destroy (surface->ctx); + + return status; +} + +static cairo_int_status_t +_cairo_script_surface_copy_page (void *abstract_surface) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_status_t status; + + status = _emit_context (surface); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (surface->ctx->stream, "copy_page\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_script_surface_show_page (void *abstract_surface) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_status_t status; + + status = _emit_context (surface); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (surface->ctx->stream, "show_page\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_script_surface_intersect_clip_path (void *abstract_surface, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_bool_t matrix_updated = FALSE; + cairo_status_t status; + + status = _emit_context (surface); + if (unlikely (status)) + return status; + + if (path == NULL) { + _cairo_output_stream_puts (surface->ctx->stream, "reset_clip\n"); + return CAIRO_STATUS_SUCCESS; + } + + status = _emit_identity (surface, &matrix_updated); + if (unlikely (status)) + return status; + + status = _emit_fill_rule (surface, fill_rule); + if (unlikely (status)) + return status; + + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (unlikely (status)) + return status; + + status = _emit_antialias (surface, antialias); + if (unlikely (status)) + return status; + + status = _emit_path (surface, path); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (surface->ctx->stream, "clip+\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_script_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_status_t status; + + status = _emit_context (surface); + if (unlikely (status)) + return status; + + status = _emit_operator (surface, op); + if (unlikely (status)) + return status; + + status = _emit_source (surface, op, source); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (surface->ctx->stream, + "paint\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_script_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_rectangle_int_t *extents) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_status_t status; + + status = _emit_context (surface); + if (unlikely (status)) + return status; + + status = _emit_operator (surface, op); + if (unlikely (status)) + return status; + + status = _emit_source (surface, op, source); + if (unlikely (status)) + return status; + + status = _emit_pattern (surface, mask); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (surface->ctx->stream, + " mask\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_script_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_stroke_style_t *style, + cairo_matrix_t *ctm, + cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_bool_t matrix_updated = FALSE; + cairo_status_t status; + + status = _emit_context (surface); + if (unlikely (status)) + return status; + + status = _emit_identity (surface, &matrix_updated); + if (unlikely (status)) + return status; + + status = _emit_path (surface, path); + if (unlikely (status)) + return status; + + status = _emit_source (surface, op, source); + if (unlikely (status)) + return status; + + status = _emit_matrix (surface, ctm, &matrix_updated); + if (unlikely (status)) + return status; + + status = _emit_operator (surface, op); + if (unlikely (status)) + return status; + + status = _emit_stroke_style (surface, style, matrix_updated); + if (unlikely (status)) + return status; + + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (unlikely (status)) + return status; + + status = _emit_antialias (surface, antialias); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (surface->ctx->stream, "stroke+\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_script_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_bool_t matrix_updated = FALSE; + cairo_status_t status; + + status = _emit_context (surface); + if (unlikely (status)) + return status; + + status = _emit_operator (surface, op); + if (unlikely (status)) + return status; + + status = _emit_identity (surface, &matrix_updated); + if (unlikely (status)) + return status; + + status = _emit_source (surface, op, source); + if (unlikely (status)) + return status; + + status = _emit_fill_rule (surface, fill_rule); + if (unlikely (status)) + return status; + + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (unlikely (status)) + return status; + + status = _emit_antialias (surface, antialias); + if (unlikely (status)) + return status; + + status = _emit_path (surface, path); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (surface->ctx->stream, "fill+\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_script_surface_has_show_text_glyphs (void *abstract_surface) +{ + return TRUE; +} + +static const char * +_subpixel_order_to_string (cairo_subpixel_order_t subpixel_order) +{ + static const char *names[] = { + "SUBPIXEL_ORDER_DEFAULT", /* CAIRO_SUBPIXEL_ORDER_DEFAULT */ + "SUBPIXEL_ORDER_RGB", /* CAIRO_SUBPIXEL_ORDER_RGB */ + "SUBPIXEL_ORDER_BGR", /* CAIRO_SUBPIXEL_ORDER_BGR */ + "SUBPIXEL_ORDER_VRGB", /* CAIRO_SUBPIXEL_ORDER_VRGB */ + "SUBPIXEL_ORDER_VBGR" /* CAIRO_SUBPIXEL_ORDER_VBGR */ + }; + return names[subpixel_order]; +} +static const char * +_hint_style_to_string (cairo_hint_style_t hint_style) +{ + static const char *names[] = { + "HINT_STYLE_DEFAULT", /* CAIRO_HINT_STYLE_DEFAULT */ + "HINT_STYLE_NONE", /* CAIRO_HINT_STYLE_NONE */ + "HINT_STYLE_SLIGHT", /* CAIRO_HINT_STYLE_SLIGHT */ + "HINT_STYLE_MEDIUM", /* CAIRO_HINT_STYLE_MEDIUM */ + "HINT_STYLE_FULL" /* CAIRO_HINT_STYLE_FULL */ + }; + return names[hint_style]; +} +static const char * +_hint_metrics_to_string (cairo_hint_metrics_t hint_metrics) +{ + static const char *names[] = { + "HINT_METRICS_DEFAULT", /* CAIRO_HINT_METRICS_DEFAULT */ + "HINT_METRICS_OFF", /* CAIRO_HINT_METRICS_OFF */ + "HINT_METRICS_ON" /* CAIRO_HINT_METRICS_ON */ + }; + return names[hint_metrics]; +} + +static cairo_status_t +_emit_font_options (cairo_script_surface_t *surface, + cairo_font_options_t *font_options) +{ + if (cairo_font_options_equal (&surface->cr.current_font_options, + font_options)) + { + return CAIRO_STATUS_SUCCESS; + } + + _cairo_output_stream_printf (surface->ctx->stream, "dict\n"); + + if (font_options->antialias != surface->cr.current_font_options.antialias) { + _cairo_output_stream_printf (surface->ctx->stream, + " /antialias //%s set\n", + _antialias_to_string (font_options->antialias)); + } + + if (font_options->subpixel_order != + surface->cr.current_font_options.subpixel_order) + { + _cairo_output_stream_printf (surface->ctx->stream, + " /subpixel-order //%s set\n", + _subpixel_order_to_string (font_options->subpixel_order)); + } + + if (font_options->hint_style != + surface->cr.current_font_options.hint_style) + { + _cairo_output_stream_printf (surface->ctx->stream, + " /hint-style //%s set\n", + _hint_style_to_string (font_options->hint_style)); + } + + if (font_options->hint_metrics != + surface->cr.current_font_options.hint_metrics) + { + _cairo_output_stream_printf (surface->ctx->stream, + " /hint-metrics //%s set\n", + _hint_metrics_to_string (font_options->hint_metrics)); + } + + _cairo_output_stream_printf (surface->ctx->stream, + " set_font_options\n"); + + surface->cr.current_font_options = *font_options; + + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font) +{ + cairo_script_surface_font_private_t *font_private; + + font_private = scaled_font->surface_private; + if (font_private != NULL) { + _cairo_output_stream_printf (font_private->ctx->stream, + "/f%lu undef\n", + font_private->id); + + _bitmap_release_id (&font_private->ctx->font_id, font_private->id); + + if (font_private->prev != NULL) + font_private->prev = font_private->next; + else + font_private->ctx->fonts = font_private->next; + + if (font_private->next != NULL) + font_private->next = font_private->prev; + + free (font_private); + + scaled_font->surface_private = NULL; + } +} + +static cairo_status_t +_emit_type42_font (cairo_script_surface_t *surface, + cairo_scaled_font_t *scaled_font) +{ + const cairo_scaled_font_backend_t *backend; + cairo_script_surface_font_private_t *font_private; + cairo_output_stream_t *base85_stream; + cairo_output_stream_t *zlib_stream; + cairo_status_t status, status2; + unsigned long size; + unsigned int load_flags; + uint8_t *buf; + + backend = scaled_font->backend; + if (backend->load_truetype_table == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + size = 0; + status = backend->load_truetype_table (scaled_font, 0, 0, NULL, &size); + if (unlikely (status)) + return status; + + buf = malloc (size); + if (unlikely (buf == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = backend->load_truetype_table (scaled_font, 0, 0, buf, NULL); + if (unlikely (status)) { + free (buf); + return status; + } + + load_flags = _cairo_ft_scaled_font_get_load_flags (scaled_font); + _cairo_output_stream_printf (surface->ctx->stream, + "dict\n" + " /type 42 set\n" + " /size %lu set\n" + " /index 0 set\n" + " /flags %d set\n" + " /source <~", + size, load_flags); + + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + zlib_stream = _cairo_deflate_stream_create (base85_stream); + + _cairo_output_stream_write (zlib_stream, buf, size); + free (buf); + + status2 = _cairo_output_stream_destroy (zlib_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + status2 = _cairo_output_stream_destroy (base85_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + font_private = scaled_font->surface_private; + _cairo_output_stream_printf (surface->ctx->stream, + " /deflate filter set\n" + " font dup /f%lu exch def set_font_face\n", + font_private->id); + + return status; +} + +static cairo_status_t +_emit_scaled_font_init (cairo_script_surface_t *surface, + cairo_scaled_font_t *scaled_font) +{ + cairo_script_surface_font_private_t *font_private; + cairo_status_t status; + + font_private = malloc (sizeof (cairo_script_surface_font_private_t)); + if (unlikely (font_private == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + font_private->ctx = surface->ctx; + font_private->parent = scaled_font; + font_private->subset_glyph_index = 0; + font_private->has_sfnt = TRUE; + + font_private->next = font_private->ctx->fonts; + font_private->prev = NULL; + if (font_private->ctx->fonts != NULL) + font_private->ctx->fonts->prev = font_private; + font_private->ctx->fonts = font_private; + + status = _bitmap_next_id (&surface->ctx->font_id, + &font_private->id); + if (unlikely (status)) { + free (font_private); + return status; + } + + scaled_font->surface_private = font_private; + scaled_font->surface_backend = &_cairo_script_surface_backend; + + status = _emit_context (surface); + if (unlikely (status)) + return status; + + status = _emit_type42_font (surface, scaled_font); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + font_private->has_sfnt = FALSE; + _cairo_output_stream_printf (surface->ctx->stream, + "dict\n" + " /type 3 set\n" + " /metrics [%f %f %f %f %f] set\n" + " /glyphs array set\n" + " font dup /f%lu exch def set_font_face\n", + scaled_font->fs_extents.ascent, + scaled_font->fs_extents.descent, + scaled_font->fs_extents.height, + scaled_font->fs_extents.max_x_advance, + scaled_font->fs_extents.max_y_advance, + font_private->id); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_scaled_font (cairo_script_surface_t *surface, + cairo_scaled_font_t *scaled_font) +{ + cairo_matrix_t matrix; + cairo_font_options_t options; + cairo_bool_t matrix_updated = FALSE; + cairo_status_t status; + cairo_script_surface_font_private_t *font_private; + + cairo_scaled_font_get_ctm (scaled_font, &matrix); + status = _emit_matrix (surface, &matrix, &matrix_updated); + if (unlikely (status)) + return status; + + if (! matrix_updated && surface->cr.current_scaled_font == scaled_font) + return CAIRO_STATUS_SUCCESS; + + cairo_scaled_font_get_font_matrix (scaled_font, &matrix); + status = _emit_font_matrix (surface, &matrix); + if (unlikely (status)) + return status; + + cairo_scaled_font_get_font_options (scaled_font, &options); + status = _emit_font_options (surface, &options); + if (unlikely (status)) + return status; + + surface->cr.current_scaled_font = scaled_font; + + assert (scaled_font->surface_backend == NULL || + scaled_font->surface_backend == &_cairo_script_surface_backend); + + font_private = scaled_font->surface_private; + if (font_private == NULL) { + status = _emit_scaled_font_init (surface, scaled_font); + if (unlikely (status)) + return status; + } else { + status = _emit_context (surface); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->ctx->stream, + "f%lu set_font_face\n", + font_private->id); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_scaled_glyph_vector (cairo_script_surface_t *surface, + cairo_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) +{ + cairo_script_surface_font_private_t *font_private; + cairo_script_implicit_context_t old_cr; + cairo_status_t status; + unsigned long index; + + font_private = scaled_font->surface_private; + index = ++font_private->subset_glyph_index; + scaled_glyph->surface_private = (void *) index; + + _cairo_output_stream_printf (surface->ctx->stream, + "%lu dict\n" + " /metrics [%f %f %f %f %f %f] set\n" + " /render {\n", + index, + scaled_glyph->fs_metrics.x_bearing, + scaled_glyph->fs_metrics.y_bearing, + scaled_glyph->fs_metrics.width, + scaled_glyph->fs_metrics.height, + scaled_glyph->fs_metrics.x_advance, + scaled_glyph->fs_metrics.y_advance); + + if (! _cairo_matrix_is_identity (&scaled_font->scale_inverse)) { + _cairo_output_stream_printf (surface->ctx->stream, + "[%f %f %f %f %f %f] transform\n", + scaled_font->scale_inverse.xx, + scaled_font->scale_inverse.yx, + scaled_font->scale_inverse.xy, + scaled_font->scale_inverse.yy, + scaled_font->scale_inverse.x0, + scaled_font->scale_inverse.y0); + } + + old_cr = surface->cr; + _cairo_script_implicit_context_init (&surface->cr); + status = _cairo_meta_surface_replay (scaled_glyph->meta_surface, + &surface->base); + surface->cr = old_cr; + + _cairo_output_stream_puts (surface->ctx->stream, "} set set\n"); + + return status; +} + +static cairo_status_t +_emit_scaled_glyph_bitmap (cairo_script_surface_t *surface, + cairo_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) +{ + cairo_script_surface_font_private_t *font_private; + cairo_status_t status; + unsigned long index; + + font_private = scaled_font->surface_private; + index = ++font_private->subset_glyph_index; + scaled_glyph->surface_private = (void *) index; + + _cairo_output_stream_printf (surface->ctx->stream, + "%lu dict\n" + " /metrics [%f %f %f %f %f %f] set\n" + " /render {\n" + "%f %f translate\n", + index, + scaled_glyph->fs_metrics.x_bearing, + scaled_glyph->fs_metrics.y_bearing, + scaled_glyph->fs_metrics.width, + scaled_glyph->fs_metrics.height, + scaled_glyph->fs_metrics.x_advance, + scaled_glyph->fs_metrics.y_advance, + scaled_glyph->fs_metrics.x_bearing, + scaled_glyph->fs_metrics.y_bearing); + + status = _emit_image_surface (surface, scaled_glyph->surface); + if (unlikely (status)) + return status; + + if (! _cairo_matrix_is_identity (&scaled_font->font_matrix)) { + _cairo_output_stream_printf (surface->ctx->stream, + " [%f %f %f %f %f %f] set_matrix\n", + scaled_font->font_matrix.xx, + scaled_font->font_matrix.yx, + scaled_font->font_matrix.xy, + scaled_font->font_matrix.yy, + scaled_font->font_matrix.x0, + scaled_font->font_matrix.y0); + } + _cairo_output_stream_puts (surface->ctx->stream, + "mask\n} set set\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_scaled_glyph_prologue (cairo_script_surface_t *surface, + cairo_scaled_font_t *scaled_font) +{ + cairo_script_surface_font_private_t *font_private; + + assert (scaled_font->surface_backend == &_cairo_script_surface_backend); + + font_private = scaled_font->surface_private; + + _cairo_output_stream_printf (surface->ctx->stream, + "f%lu /glyphs get\n", + font_private->id); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_scaled_glyphs (cairo_script_surface_t *surface, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + unsigned int num_glyphs) +{ + cairo_script_surface_font_private_t *font_private; + cairo_status_t status; + unsigned int n; + cairo_bool_t have_glyph_prologue = FALSE; + + if (num_glyphs == 0) + return CAIRO_STATUS_SUCCESS; + + font_private = scaled_font->surface_private; + if (font_private->has_sfnt) + return CAIRO_STATUS_SUCCESS; + + _cairo_scaled_font_freeze_cache (scaled_font); + for (n = 0; n < num_glyphs; n++) { + cairo_scaled_glyph_t *scaled_glyph; + + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[n].index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + &scaled_glyph); + if (unlikely (status)) + break; + + if (scaled_glyph->surface_private != NULL) + continue; + + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[n].index, + CAIRO_SCALED_GLYPH_INFO_META_SURFACE, + &scaled_glyph); + if (_cairo_status_is_error (status)) + break; + + if (status == CAIRO_STATUS_SUCCESS) { + if (! have_glyph_prologue) { + status = _emit_scaled_glyph_prologue (surface, scaled_font); + if (unlikely (status)) + break; + + have_glyph_prologue = TRUE; + } + + status = _emit_scaled_glyph_vector (surface, + scaled_font, + scaled_glyph); + if (unlikely (status)) + break; + + continue; + } + + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[n].index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + &scaled_glyph); + if (_cairo_status_is_error (status)) + break; + + if (status == CAIRO_STATUS_SUCCESS) { + if (! have_glyph_prologue) { + status = _emit_scaled_glyph_prologue (surface, scaled_font); + if (unlikely (status)) + break; + + have_glyph_prologue = TRUE; + } + + status = _emit_scaled_glyph_bitmap (surface, + scaled_font, + scaled_glyph); + if (unlikely (status)) + break; + + continue; + } + } + _cairo_scaled_font_thaw_cache (scaled_font); + + if (have_glyph_prologue) { + _cairo_output_stream_puts (surface->ctx->stream, "pop pop\n"); + } + + return status; +} + +static cairo_int_status_t +_cairo_script_surface_show_text_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t backward, + cairo_scaled_font_t *scaled_font, + cairo_rectangle_int_t *extents) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_script_surface_font_private_t *font_private; + cairo_scaled_glyph_t *scaled_glyph; + cairo_matrix_t matrix; + cairo_status_t status; + double x, y, ix, iy; + int n; + cairo_output_stream_t *base85_stream = NULL; + + status = _emit_context (surface); + if (unlikely (status)) + return status; + + status = _emit_operator (surface, op); + if (unlikely (status)) + return status; + + status = _emit_source (surface, op, source); + if (unlikely (status)) + return status; + + status = _emit_scaled_font (surface, scaled_font); + if (unlikely (status)) + return status; + + status = _emit_scaled_glyphs (surface, scaled_font, glyphs, num_glyphs); + if (unlikely (status)) + return status; + + /* (utf8) [cx cy [glyphs]] [clusters] backward show_text_glyphs */ + /* [cx cy [glyphs]] show_glyphs */ + + if (utf8 != NULL && clusters != NULL) { + _cairo_output_stream_printf (surface->ctx->stream, + "(%s) ", + utf8); + } + + matrix = surface->cr.current_ctm; + status = cairo_matrix_invert (&matrix); + assert (status == CAIRO_STATUS_SUCCESS); + + ix = x = glyphs[0].x; + iy = y = glyphs[0].y; + cairo_matrix_transform_point (&matrix, &ix, &iy); + ix -= scaled_font->font_matrix.x0; + iy -= scaled_font->font_matrix.y0; + + _cairo_scaled_font_freeze_cache (scaled_font); + font_private = scaled_font->surface_private; + + _cairo_output_stream_printf (surface->ctx->stream, + "[%f %f ", + ix, iy); + + for (n = 0; n < num_glyphs; n++) { + if (font_private->has_sfnt) { + if (glyphs[n].index > 256) + break; + } else { + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[n].index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + &scaled_glyph); + if (unlikely (status)) { + _cairo_scaled_font_thaw_cache (scaled_font); + return status; + } + } + } + + if (n == num_glyphs) { + _cairo_output_stream_puts (surface->ctx->stream, "<~"); + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + } else + _cairo_output_stream_puts (surface->ctx->stream, "["); + + for (n = 0; n < num_glyphs; n++) { + double dx, dy; + + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[n].index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + &scaled_glyph); + if (unlikely (status)) + break; + + if (fabs (glyphs[n].x - x) > 1e-5 || fabs (glyphs[n].y - y) > 1e-5) { + ix = x = glyphs[n].x; + iy = y = glyphs[n].y; + cairo_matrix_transform_point (&matrix, &ix, &iy); + ix -= scaled_font->font_matrix.x0; + iy -= scaled_font->font_matrix.y0; + if (base85_stream != NULL) { + status = _cairo_output_stream_destroy (base85_stream); + if (unlikely (status)) { + base85_stream = NULL; + break; + } + + _cairo_output_stream_printf (surface->ctx->stream, + " %f %f <~", + ix, iy); + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + } else { + _cairo_output_stream_printf (surface->ctx->stream, + " ] %f %f [ ", + ix, iy); + } + } + if (base85_stream != NULL) { + uint8_t c; + + if (font_private->has_sfnt) + c = glyphs[n].index; + else + c = (uint8_t) (long unsigned) scaled_glyph->surface_private; + + _cairo_output_stream_write (base85_stream, &c, 1); + } else { + if (font_private->has_sfnt) + _cairo_output_stream_printf (surface->ctx->stream, " %lu", + glyphs[n].index); + else + _cairo_output_stream_printf (surface->ctx->stream, " %lu", + (long unsigned) scaled_glyph->surface_private); + } + + dx = scaled_glyph->metrics.x_advance; + dy = scaled_glyph->metrics.y_advance; + cairo_matrix_transform_distance (&scaled_font->ctm, &dx, &dy); + x += dx; + y += dy; + } + _cairo_scaled_font_thaw_cache (scaled_font); + + if (base85_stream != NULL) { + cairo_status_t status2; + + status2 = _cairo_output_stream_destroy (base85_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + } else { + _cairo_output_stream_puts (surface->ctx->stream, " ]"); + } + if (unlikely (status)) + return status; + + if (utf8 != NULL && clusters != NULL) { + for (n = 0; n < num_clusters; n++) { + if (clusters[n].num_bytes > UCHAR_MAX || + clusters[n].num_glyphs > UCHAR_MAX) + { + break; + } + } + + if (n < num_clusters) { + _cairo_output_stream_puts (surface->ctx->stream, "] [ "); + for (n = 0; n < num_clusters; n++) { + _cairo_output_stream_printf (surface->ctx->stream, + "%d %d ", + clusters[n].num_bytes, + clusters[n].num_glyphs); + } + _cairo_output_stream_puts (surface->ctx->stream, "]"); + } + else + { + _cairo_output_stream_puts (surface->ctx->stream, "] <~"); + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + for (n = 0; n < num_clusters; n++) { + uint8_t c[2]; + c[0] = clusters[n].num_bytes; + c[1] = clusters[n].num_glyphs; + _cairo_output_stream_write (base85_stream, c, 2); + } + status = _cairo_output_stream_destroy (base85_stream); + if (unlikely (status)) + return status; + } + + _cairo_output_stream_printf (surface->ctx->stream, + " //%s show_text_glyphs\n", + _direction_to_string (backward)); + } else { + _cairo_output_stream_puts (surface->ctx->stream, + "] show_glyphs\n"); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_script_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_script_surface_t *surface = abstract_surface; + + if (surface->width < 0 || surface->height < 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + rectangle->x = 0; + rectangle->y = 0; + rectangle->width = surface->width; + rectangle->height = surface->height; + + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t +_cairo_script_surface_backend = { + CAIRO_SURFACE_TYPE_SCRIPT, + _cairo_script_surface_create_similar, + _cairo_script_surface_finish, + NULL, //_cairo_script_surface_acquire_source_image, + NULL, //_cairo_script_surface_release_source_image, + NULL, /* acquire_dest_image */ + NULL, /* release_dest_image */ + NULL, /* clone_similar */ + NULL, /* composite */ + NULL, /* fill_rectangles */ + NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ + _cairo_script_surface_copy_page, + _cairo_script_surface_show_page, + NULL, /* set_clip_region */ + _cairo_script_surface_intersect_clip_path, + _cairo_script_surface_get_extents, + NULL, /* old_show_glyphs */ + NULL, /* get_font_options */ + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + _cairo_script_surface_scaled_font_fini, + NULL, /* scaled_glyph_fini */ + + /* The 5 high level operations */ + _cairo_script_surface_paint, + _cairo_script_surface_mask, + _cairo_script_surface_stroke, + _cairo_script_surface_fill, + NULL, + + NULL, //_cairo_script_surface_snapshot, + + NULL, /* is_similar */ + NULL, /* reset */ + NULL, /* fill_stroke */ + NULL, /* create_solid_pattern_surface */ + + /* The alternate high-level text operation */ + _cairo_script_surface_has_show_text_glyphs, + _cairo_script_surface_show_text_glyphs +}; + +static cairo_bool_t +_cairo_surface_is_script (cairo_surface_t *surface) +{ + return surface->backend == &_cairo_script_surface_backend; +} + +static cairo_script_vmcontext_t * +_cairo_script_vmcontext_create (cairo_output_stream_t *stream) +{ + cairo_script_vmcontext_t *ctx; + + ctx = malloc (sizeof (cairo_script_vmcontext_t)); + if (unlikely (ctx == NULL)) + return NULL; + + memset (ctx, 0, sizeof (cairo_script_vmcontext_t)); + + ctx->stream = stream; + ctx->mode = CAIRO_SCRIPT_MODE_ASCII; + + return ctx; +} + +static void +_cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr) +{ + cr->current_operator = CAIRO_GSTATE_OPERATOR_DEFAULT; + cr->current_fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT; + cr->current_tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT; + cr->current_antialias = CAIRO_ANTIALIAS_DEFAULT; + _cairo_stroke_style_init (&cr->current_style); + cr->current_source = (cairo_pattern_t *) &_cairo_pattern_black.base; + _cairo_path_fixed_init (&cr->current_path); + cairo_matrix_init_identity (&cr->current_ctm); + cairo_matrix_init_identity (&cr->current_font_matrix); + _cairo_font_options_init_default (&cr->current_font_options); + cr->current_scaled_font = NULL; +} + +static cairo_script_surface_t * +_cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx, + double width, + double height) +{ + cairo_script_surface_t *surface; + + if (unlikely (ctx == NULL)) + return (cairo_script_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + surface = malloc (sizeof (cairo_script_surface_t)); + if (unlikely (surface == NULL)) + return (cairo_script_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &_cairo_script_surface_backend, + CAIRO_CONTENT_COLOR_ALPHA); + + surface->ctx = ctx; + ctx->ref++; + + surface->width = width; + surface->height = height; + + surface->id = (unsigned long) -1; + + _cairo_script_implicit_context_init (&surface->cr); + + return surface; +} + +cairo_surface_t * +cairo_script_surface_create (const char *filename, + double width, + double height) +{ + cairo_output_stream_t *stream; + cairo_script_surface_t *surface; + + stream = _cairo_output_stream_create_for_filename (filename); + if (_cairo_output_stream_get_status (stream)) + return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream)); + + + surface = _cairo_script_surface_create_internal + (_cairo_script_vmcontext_create (stream), width, height); + if (surface->base.status) + return &surface->base; + + _cairo_output_stream_puts (surface->ctx->stream, "%!CairoScript\n"); + return &surface->base; +} + +cairo_surface_t * +cairo_script_surface_create_for_stream (cairo_write_func_t write_func, + void *closure, + double width, + double height) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create (write_func, NULL, closure); + if (_cairo_output_stream_get_status (stream)) + return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream)); + + return &_cairo_script_surface_create_internal + (_cairo_script_vmcontext_create (stream), width, height)->base; +} + +void +cairo_script_surface_set_mode (cairo_surface_t *abstract_surface, + cairo_script_mode_t mode) +{ + cairo_script_surface_t *surface; + cairo_status_t status_ignored; + + if (! _cairo_surface_is_script (abstract_surface)) { + status_ignored = _cairo_surface_set_error (abstract_surface, + CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return; + } + + if (abstract_surface->status) + return; + + surface = (cairo_script_surface_t *) abstract_surface; + surface->ctx->mode = mode; +} + +cairo_script_mode_t +cairo_script_surface_get_mode (cairo_surface_t *abstract_surface) +{ + cairo_script_surface_t *surface; + + if (! _cairo_surface_is_script (abstract_surface) || + abstract_surface->status) + { + return CAIRO_SCRIPT_MODE_ASCII; + } + + surface = (cairo_script_surface_t *) abstract_surface; + return surface->ctx->mode; +} diff --git a/src/cairo-script.h b/src/cairo-script.h new file mode 100644 index 00000000..9c428e3b --- /dev/null +++ b/src/cairo-script.h @@ -0,0 +1,74 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 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 + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +#ifndef CAIRO_SCRIPT_H +#define CAIRO_SCRIPT_H + +#include "cairo.h" + +#if CAIRO_HAS_SCRIPT_SURFACE + +CAIRO_BEGIN_DECLS + +cairo_public cairo_surface_t * +cairo_script_surface_create (const char *filename, + double width, + double height); + +cairo_public cairo_surface_t * +cairo_script_surface_create_for_stream (cairo_write_func_t write_func, + void *closure, + double width, + double height); + +typedef enum { + CAIRO_SCRIPT_MODE_BINARY, + CAIRO_SCRIPT_MODE_ASCII +} cairo_script_mode_t; + +cairo_public void +cairo_script_surface_set_mode (cairo_surface_t *surface, + cairo_script_mode_t mode); + +cairo_public cairo_script_mode_t +cairo_script_surface_get_mode (cairo_surface_t *surface); + +CAIRO_END_DECLS + +#else /*CAIRO_HAS_SCRIPT_SURFACE*/ +# error Cairo was not compiled with support for the CairoScript backend +#endif /*CAIRO_HAS_SCRIPT_SURFACE*/ + +#endif /*CAIRO_SCRIPT_H*/ diff --git a/src/cairo-sdl-surface.c b/src/cairo-sdl-surface.c index b9d604e6..1f97fb47 100644 --- a/src/cairo-sdl-surface.c +++ b/src/cairo-sdl-surface.c @@ -52,7 +52,7 @@ _cairo_sdl_surface_create_internal (SDL_Surface *sdl, cairo_sdl_surface_t *surface; surface = malloc (sizeof (cairo_sdl_surface_t)); - if (surface == NULL) + if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); _cairo_surface_init (&surface->base, @@ -240,7 +240,7 @@ _cairo_sdl_surface_composite (cairo_operator_t op, src_x, src_y, width, height, (cairo_surface_t **) &src, &src_attr); - if (status) + if (unlikely (status)) return status; is_integer_translation = @@ -322,8 +322,9 @@ _cairo_sdl_surface_flush (void *abstract_surface) int n_boxes, i; cairo_status_t status; + n_boxes = 0; status = _cairo_region_get_boxes (&surface->update, &n_boxes, &boxes); - if (status) + if (unlikely (status)) return status; if (n_boxes == 0) return CAIRO_STATUS_SUCCESS; @@ -356,6 +357,8 @@ static const cairo_surface_backend_t _cairo_sdl_surface_backend = { _cairo_sdl_surface_composite, NULL, /* fill rectangles */ NULL, /* composite traps */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ _cairo_sdl_surface_set_clip_region, diff --git a/src/cairo-skiplist.c b/src/cairo-skiplist.c index e2b793e1..d03a6bfc 100644 --- a/src/cairo-skiplist.c +++ b/src/cairo-skiplist.c @@ -28,201 +28,23 @@ #define ELT_DATA(elt) (void *) ((char*) (elt) - list->data_size) #define NEXT_TO_ELT(next) (skip_elt_t *) ((char *) (next) - offsetof (skip_elt_t, next)) -/* Four 256 element lookup tables back to back implementing a linear - * feedback shift register of degree 32. */ -static unsigned const _cairo_lfsr_random_lut[1024] = { - 0x00000000, 0x9a795537, 0xae8bff59, 0x34f2aa6e, 0xc76eab85, 0x5d17feb2, - 0x69e554dc, 0xf39c01eb, 0x14a4023d, 0x8edd570a, 0xba2ffd64, 0x2056a853, - 0xd3caa9b8, 0x49b3fc8f, 0x7d4156e1, 0xe73803d6, 0x2948047a, 0xb331514d, - 0x87c3fb23, 0x1dbaae14, 0xee26afff, 0x745ffac8, 0x40ad50a6, 0xdad40591, - 0x3dec0647, 0xa7955370, 0x9367f91e, 0x091eac29, 0xfa82adc2, 0x60fbf8f5, - 0x5409529b, 0xce7007ac, 0x529008f4, 0xc8e95dc3, 0xfc1bf7ad, 0x6662a29a, - 0x95fea371, 0x0f87f646, 0x3b755c28, 0xa10c091f, 0x46340ac9, 0xdc4d5ffe, - 0xe8bff590, 0x72c6a0a7, 0x815aa14c, 0x1b23f47b, 0x2fd15e15, 0xb5a80b22, - 0x7bd80c8e, 0xe1a159b9, 0xd553f3d7, 0x4f2aa6e0, 0xbcb6a70b, 0x26cff23c, - 0x123d5852, 0x88440d65, 0x6f7c0eb3, 0xf5055b84, 0xc1f7f1ea, 0x5b8ea4dd, - 0xa812a536, 0x326bf001, 0x06995a6f, 0x9ce00f58, 0xa52011e8, 0x3f5944df, - 0x0babeeb1, 0x91d2bb86, 0x624eba6d, 0xf837ef5a, 0xccc54534, 0x56bc1003, - 0xb18413d5, 0x2bfd46e2, 0x1f0fec8c, 0x8576b9bb, 0x76eab850, 0xec93ed67, - 0xd8614709, 0x4218123e, 0x8c681592, 0x161140a5, 0x22e3eacb, 0xb89abffc, - 0x4b06be17, 0xd17feb20, 0xe58d414e, 0x7ff41479, 0x98cc17af, 0x02b54298, - 0x3647e8f6, 0xac3ebdc1, 0x5fa2bc2a, 0xc5dbe91d, 0xf1294373, 0x6b501644, - 0xf7b0191c, 0x6dc94c2b, 0x593be645, 0xc342b372, 0x30deb299, 0xaaa7e7ae, - 0x9e554dc0, 0x042c18f7, 0xe3141b21, 0x796d4e16, 0x4d9fe478, 0xd7e6b14f, - 0x247ab0a4, 0xbe03e593, 0x8af14ffd, 0x10881aca, 0xdef81d66, 0x44814851, - 0x7073e23f, 0xea0ab708, 0x1996b6e3, 0x83efe3d4, 0xb71d49ba, 0x2d641c8d, - 0xca5c1f5b, 0x50254a6c, 0x64d7e002, 0xfeaeb535, 0x0d32b4de, 0x974be1e9, - 0xa3b94b87, 0x39c01eb0, 0xd03976e7, 0x4a4023d0, 0x7eb289be, 0xe4cbdc89, - 0x1757dd62, 0x8d2e8855, 0xb9dc223b, 0x23a5770c, 0xc49d74da, 0x5ee421ed, - 0x6a168b83, 0xf06fdeb4, 0x03f3df5f, 0x998a8a68, 0xad782006, 0x37017531, - 0xf971729d, 0x630827aa, 0x57fa8dc4, 0xcd83d8f3, 0x3e1fd918, 0xa4668c2f, - 0x90942641, 0x0aed7376, 0xedd570a0, 0x77ac2597, 0x435e8ff9, 0xd927dace, - 0x2abbdb25, 0xb0c28e12, 0x8430247c, 0x1e49714b, 0x82a97e13, 0x18d02b24, - 0x2c22814a, 0xb65bd47d, 0x45c7d596, 0xdfbe80a1, 0xeb4c2acf, 0x71357ff8, - 0x960d7c2e, 0x0c742919, 0x38868377, 0xa2ffd640, 0x5163d7ab, 0xcb1a829c, - 0xffe828f2, 0x65917dc5, 0xabe17a69, 0x31982f5e, 0x056a8530, 0x9f13d007, - 0x6c8fd1ec, 0xf6f684db, 0xc2042eb5, 0x587d7b82, 0xbf457854, 0x253c2d63, - 0x11ce870d, 0x8bb7d23a, 0x782bd3d1, 0xe25286e6, 0xd6a02c88, 0x4cd979bf, - 0x7519670f, 0xef603238, 0xdb929856, 0x41ebcd61, 0xb277cc8a, 0x280e99bd, - 0x1cfc33d3, 0x868566e4, 0x61bd6532, 0xfbc43005, 0xcf369a6b, 0x554fcf5c, - 0xa6d3ceb7, 0x3caa9b80, 0x085831ee, 0x922164d9, 0x5c516375, 0xc6283642, - 0xf2da9c2c, 0x68a3c91b, 0x9b3fc8f0, 0x01469dc7, 0x35b437a9, 0xafcd629e, - 0x48f56148, 0xd28c347f, 0xe67e9e11, 0x7c07cb26, 0x8f9bcacd, 0x15e29ffa, - 0x21103594, 0xbb6960a3, 0x27896ffb, 0xbdf03acc, 0x890290a2, 0x137bc595, - 0xe0e7c47e, 0x7a9e9149, 0x4e6c3b27, 0xd4156e10, 0x332d6dc6, 0xa95438f1, - 0x9da6929f, 0x07dfc7a8, 0xf443c643, 0x6e3a9374, 0x5ac8391a, 0xc0b16c2d, - 0x0ec16b81, 0x94b83eb6, 0xa04a94d8, 0x3a33c1ef, 0xc9afc004, 0x53d69533, - 0x67243f5d, 0xfd5d6a6a, 0x1a6569bc, 0x801c3c8b, 0xb4ee96e5, 0x2e97c3d2, - 0xdd0bc239, 0x4772970e, 0x73803d60, 0xe9f96857, 0x00000000, 0x3a0bb8f9, - 0x741771f2, 0x4e1cc90b, 0xe82ee3e4, 0xd2255b1d, 0x9c399216, 0xa6322aef, - 0x4a2492ff, 0x702f2a06, 0x3e33e30d, 0x04385bf4, 0xa20a711b, 0x9801c9e2, - 0xd61d00e9, 0xec16b810, 0x944925fe, 0xae429d07, 0xe05e540c, 0xda55ecf5, - 0x7c67c61a, 0x466c7ee3, 0x0870b7e8, 0x327b0f11, 0xde6db701, 0xe4660ff8, - 0xaa7ac6f3, 0x90717e0a, 0x364354e5, 0x0c48ec1c, 0x42542517, 0x785f9dee, - 0xb2eb1ecb, 0x88e0a632, 0xc6fc6f39, 0xfcf7d7c0, 0x5ac5fd2f, 0x60ce45d6, - 0x2ed28cdd, 0x14d93424, 0xf8cf8c34, 0xc2c434cd, 0x8cd8fdc6, 0xb6d3453f, - 0x10e16fd0, 0x2aead729, 0x64f61e22, 0x5efda6db, 0x26a23b35, 0x1ca983cc, - 0x52b54ac7, 0x68bef23e, 0xce8cd8d1, 0xf4876028, 0xba9ba923, 0x809011da, - 0x6c86a9ca, 0x568d1133, 0x1891d838, 0x229a60c1, 0x84a84a2e, 0xbea3f2d7, - 0xf0bf3bdc, 0xcab48325, 0xffaf68a1, 0xc5a4d058, 0x8bb81953, 0xb1b3a1aa, - 0x17818b45, 0x2d8a33bc, 0x6396fab7, 0x599d424e, 0xb58bfa5e, 0x8f8042a7, - 0xc19c8bac, 0xfb973355, 0x5da519ba, 0x67aea143, 0x29b26848, 0x13b9d0b1, - 0x6be64d5f, 0x51edf5a6, 0x1ff13cad, 0x25fa8454, 0x83c8aebb, 0xb9c31642, - 0xf7dfdf49, 0xcdd467b0, 0x21c2dfa0, 0x1bc96759, 0x55d5ae52, 0x6fde16ab, - 0xc9ec3c44, 0xf3e784bd, 0xbdfb4db6, 0x87f0f54f, 0x4d44766a, 0x774fce93, - 0x39530798, 0x0358bf61, 0xa56a958e, 0x9f612d77, 0xd17de47c, 0xeb765c85, - 0x0760e495, 0x3d6b5c6c, 0x73779567, 0x497c2d9e, 0xef4e0771, 0xd545bf88, - 0x9b597683, 0xa152ce7a, 0xd90d5394, 0xe306eb6d, 0xad1a2266, 0x97119a9f, - 0x3123b070, 0x0b280889, 0x4534c182, 0x7f3f797b, 0x9329c16b, 0xa9227992, - 0xe73eb099, 0xdd350860, 0x7b07228f, 0x410c9a76, 0x0f10537d, 0x351beb84, - 0x65278475, 0x5f2c3c8c, 0x1130f587, 0x2b3b4d7e, 0x8d096791, 0xb702df68, - 0xf91e1663, 0xc315ae9a, 0x2f03168a, 0x1508ae73, 0x5b146778, 0x611fdf81, - 0xc72df56e, 0xfd264d97, 0xb33a849c, 0x89313c65, 0xf16ea18b, 0xcb651972, - 0x8579d079, 0xbf726880, 0x1940426f, 0x234bfa96, 0x6d57339d, 0x575c8b64, - 0xbb4a3374, 0x81418b8d, 0xcf5d4286, 0xf556fa7f, 0x5364d090, 0x696f6869, - 0x2773a162, 0x1d78199b, 0xd7cc9abe, 0xedc72247, 0xa3dbeb4c, 0x99d053b5, - 0x3fe2795a, 0x05e9c1a3, 0x4bf508a8, 0x71feb051, 0x9de80841, 0xa7e3b0b8, - 0xe9ff79b3, 0xd3f4c14a, 0x75c6eba5, 0x4fcd535c, 0x01d19a57, 0x3bda22ae, - 0x4385bf40, 0x798e07b9, 0x3792ceb2, 0x0d99764b, 0xabab5ca4, 0x91a0e45d, - 0xdfbc2d56, 0xe5b795af, 0x09a12dbf, 0x33aa9546, 0x7db65c4d, 0x47bde4b4, - 0xe18fce5b, 0xdb8476a2, 0x9598bfa9, 0xaf930750, 0x9a88ecd4, 0xa083542d, - 0xee9f9d26, 0xd49425df, 0x72a60f30, 0x48adb7c9, 0x06b17ec2, 0x3cbac63b, - 0xd0ac7e2b, 0xeaa7c6d2, 0xa4bb0fd9, 0x9eb0b720, 0x38829dcf, 0x02892536, - 0x4c95ec3d, 0x769e54c4, 0x0ec1c92a, 0x34ca71d3, 0x7ad6b8d8, 0x40dd0021, - 0xe6ef2ace, 0xdce49237, 0x92f85b3c, 0xa8f3e3c5, 0x44e55bd5, 0x7eeee32c, - 0x30f22a27, 0x0af992de, 0xaccbb831, 0x96c000c8, 0xd8dcc9c3, 0xe2d7713a, - 0x2863f21f, 0x12684ae6, 0x5c7483ed, 0x667f3b14, 0xc04d11fb, 0xfa46a902, - 0xb45a6009, 0x8e51d8f0, 0x624760e0, 0x584cd819, 0x16501112, 0x2c5ba9eb, - 0x8a698304, 0xb0623bfd, 0xfe7ef2f6, 0xc4754a0f, 0xbc2ad7e1, 0x86216f18, - 0xc83da613, 0xf2361eea, 0x54043405, 0x6e0f8cfc, 0x201345f7, 0x1a18fd0e, - 0xf60e451e, 0xcc05fde7, 0x821934ec, 0xb8128c15, 0x1e20a6fa, 0x242b1e03, - 0x6a37d708, 0x503c6ff1, 0x00000000, 0xca4f08ea, 0x0ee744e3, 0xc4a84c09, - 0x1dce89c6, 0xd781812c, 0x1329cd25, 0xd966c5cf, 0x3b9d138c, 0xf1d21b66, - 0x357a576f, 0xff355f85, 0x26539a4a, 0xec1c92a0, 0x28b4dea9, 0xe2fbd643, - 0x773a2718, 0xbd752ff2, 0x79dd63fb, 0xb3926b11, 0x6af4aede, 0xa0bba634, - 0x6413ea3d, 0xae5ce2d7, 0x4ca73494, 0x86e83c7e, 0x42407077, 0x880f789d, - 0x5169bd52, 0x9b26b5b8, 0x5f8ef9b1, 0x95c1f15b, 0xee744e30, 0x243b46da, - 0xe0930ad3, 0x2adc0239, 0xf3bac7f6, 0x39f5cf1c, 0xfd5d8315, 0x37128bff, - 0xd5e95dbc, 0x1fa65556, 0xdb0e195f, 0x114111b5, 0xc827d47a, 0x0268dc90, - 0xc6c09099, 0x0c8f9873, 0x994e6928, 0x530161c2, 0x97a92dcb, 0x5de62521, - 0x8480e0ee, 0x4ecfe804, 0x8a67a40d, 0x4028ace7, 0xa2d37aa4, 0x689c724e, - 0xac343e47, 0x667b36ad, 0xbf1df362, 0x7552fb88, 0xb1fab781, 0x7bb5bf6b, - 0x4691c957, 0x8cdec1bd, 0x48768db4, 0x8239855e, 0x5b5f4091, 0x9110487b, - 0x55b80472, 0x9ff70c98, 0x7d0cdadb, 0xb743d231, 0x73eb9e38, 0xb9a496d2, - 0x60c2531d, 0xaa8d5bf7, 0x6e2517fe, 0xa46a1f14, 0x31abee4f, 0xfbe4e6a5, - 0x3f4caaac, 0xf503a246, 0x2c656789, 0xe62a6f63, 0x2282236a, 0xe8cd2b80, - 0x0a36fdc3, 0xc079f529, 0x04d1b920, 0xce9eb1ca, 0x17f87405, 0xddb77cef, - 0x191f30e6, 0xd350380c, 0xa8e58767, 0x62aa8f8d, 0xa602c384, 0x6c4dcb6e, - 0xb52b0ea1, 0x7f64064b, 0xbbcc4a42, 0x718342a8, 0x937894eb, 0x59379c01, - 0x9d9fd008, 0x57d0d8e2, 0x8eb61d2d, 0x44f915c7, 0x805159ce, 0x4a1e5124, - 0xdfdfa07f, 0x1590a895, 0xd138e49c, 0x1b77ec76, 0xc21129b9, 0x085e2153, - 0xccf66d5a, 0x06b965b0, 0xe442b3f3, 0x2e0dbb19, 0xeaa5f710, 0x20eafffa, - 0xf98c3a35, 0x33c332df, 0xf76b7ed6, 0x3d24763c, 0x8d2392ae, 0x476c9a44, - 0x83c4d64d, 0x498bdea7, 0x90ed1b68, 0x5aa21382, 0x9e0a5f8b, 0x54455761, - 0xb6be8122, 0x7cf189c8, 0xb859c5c1, 0x7216cd2b, 0xab7008e4, 0x613f000e, - 0xa5974c07, 0x6fd844ed, 0xfa19b5b6, 0x3056bd5c, 0xf4fef155, 0x3eb1f9bf, - 0xe7d73c70, 0x2d98349a, 0xe9307893, 0x237f7079, 0xc184a63a, 0x0bcbaed0, - 0xcf63e2d9, 0x052cea33, 0xdc4a2ffc, 0x16052716, 0xd2ad6b1f, 0x18e263f5, - 0x6357dc9e, 0xa918d474, 0x6db0987d, 0xa7ff9097, 0x7e995558, 0xb4d65db2, - 0x707e11bb, 0xba311951, 0x58cacf12, 0x9285c7f8, 0x562d8bf1, 0x9c62831b, - 0x450446d4, 0x8f4b4e3e, 0x4be30237, 0x81ac0add, 0x146dfb86, 0xde22f36c, - 0x1a8abf65, 0xd0c5b78f, 0x09a37240, 0xc3ec7aaa, 0x074436a3, 0xcd0b3e49, - 0x2ff0e80a, 0xe5bfe0e0, 0x2117ace9, 0xeb58a403, 0x323e61cc, 0xf8716926, - 0x3cd9252f, 0xf6962dc5, 0xcbb25bf9, 0x01fd5313, 0xc5551f1a, 0x0f1a17f0, - 0xd67cd23f, 0x1c33dad5, 0xd89b96dc, 0x12d49e36, 0xf02f4875, 0x3a60409f, - 0xfec80c96, 0x3487047c, 0xede1c1b3, 0x27aec959, 0xe3068550, 0x29498dba, - 0xbc887ce1, 0x76c7740b, 0xb26f3802, 0x782030e8, 0xa146f527, 0x6b09fdcd, - 0xafa1b1c4, 0x65eeb92e, 0x87156f6d, 0x4d5a6787, 0x89f22b8e, 0x43bd2364, - 0x9adbe6ab, 0x5094ee41, 0x943ca248, 0x5e73aaa2, 0x25c615c9, 0xef891d23, - 0x2b21512a, 0xe16e59c0, 0x38089c0f, 0xf24794e5, 0x36efd8ec, 0xfca0d006, - 0x1e5b0645, 0xd4140eaf, 0x10bc42a6, 0xdaf34a4c, 0x03958f83, 0xc9da8769, - 0x0d72cb60, 0xc73dc38a, 0x52fc32d1, 0x98b33a3b, 0x5c1b7632, 0x96547ed8, - 0x4f32bb17, 0x857db3fd, 0x41d5fff4, 0x8b9af71e, 0x6961215d, 0xa32e29b7, - 0x678665be, 0xadc96d54, 0x74afa89b, 0xbee0a071, 0x7a48ec78, 0xb007e492, - 0x00000000, 0x803e706b, 0x9a05b5e1, 0x1a3bc58a, 0xae723ef5, 0x2e4c4e9e, - 0x34778b14, 0xb449fb7f, 0xc69d28dd, 0x46a358b6, 0x5c989d3c, 0xdca6ed57, - 0x68ef1628, 0xe8d16643, 0xf2eaa3c9, 0x72d4d3a2, 0x1743048d, 0x977d74e6, - 0x8d46b16c, 0x0d78c107, 0xb9313a78, 0x390f4a13, 0x23348f99, 0xa30afff2, - 0xd1de2c50, 0x51e05c3b, 0x4bdb99b1, 0xcbe5e9da, 0x7fac12a5, 0xff9262ce, - 0xe5a9a744, 0x6597d72f, 0x2e86091a, 0xaeb87971, 0xb483bcfb, 0x34bdcc90, - 0x80f437ef, 0x00ca4784, 0x1af1820e, 0x9acff265, 0xe81b21c7, 0x682551ac, - 0x721e9426, 0xf220e44d, 0x46691f32, 0xc6576f59, 0xdc6caad3, 0x5c52dab8, - 0x39c50d97, 0xb9fb7dfc, 0xa3c0b876, 0x23fec81d, 0x97b73362, 0x17894309, - 0x0db28683, 0x8d8cf6e8, 0xff58254a, 0x7f665521, 0x655d90ab, 0xe563e0c0, - 0x512a1bbf, 0xd1146bd4, 0xcb2fae5e, 0x4b11de35, 0x5d0c1234, 0xdd32625f, - 0xc709a7d5, 0x4737d7be, 0xf37e2cc1, 0x73405caa, 0x697b9920, 0xe945e94b, - 0x9b913ae9, 0x1baf4a82, 0x01948f08, 0x81aaff63, 0x35e3041c, 0xb5dd7477, - 0xafe6b1fd, 0x2fd8c196, 0x4a4f16b9, 0xca7166d2, 0xd04aa358, 0x5074d333, - 0xe43d284c, 0x64035827, 0x7e389dad, 0xfe06edc6, 0x8cd23e64, 0x0cec4e0f, - 0x16d78b85, 0x96e9fbee, 0x22a00091, 0xa29e70fa, 0xb8a5b570, 0x389bc51b, - 0x738a1b2e, 0xf3b46b45, 0xe98faecf, 0x69b1dea4, 0xddf825db, 0x5dc655b0, - 0x47fd903a, 0xc7c3e051, 0xb51733f3, 0x35294398, 0x2f128612, 0xaf2cf679, - 0x1b650d06, 0x9b5b7d6d, 0x8160b8e7, 0x015ec88c, 0x64c91fa3, 0xe4f76fc8, - 0xfeccaa42, 0x7ef2da29, 0xcabb2156, 0x4a85513d, 0x50be94b7, 0xd080e4dc, - 0xa254377e, 0x226a4715, 0x3851829f, 0xb86ff2f4, 0x0c26098b, 0x8c1879e0, - 0x9623bc6a, 0x161dcc01, 0xba182468, 0x3a265403, 0x201d9189, 0xa023e1e2, - 0x146a1a9d, 0x94546af6, 0x8e6faf7c, 0x0e51df17, 0x7c850cb5, 0xfcbb7cde, - 0xe680b954, 0x66bec93f, 0xd2f73240, 0x52c9422b, 0x48f287a1, 0xc8ccf7ca, - 0xad5b20e5, 0x2d65508e, 0x375e9504, 0xb760e56f, 0x03291e10, 0x83176e7b, - 0x992cabf1, 0x1912db9a, 0x6bc60838, 0xebf87853, 0xf1c3bdd9, 0x71fdcdb2, - 0xc5b436cd, 0x458a46a6, 0x5fb1832c, 0xdf8ff347, 0x949e2d72, 0x14a05d19, - 0x0e9b9893, 0x8ea5e8f8, 0x3aec1387, 0xbad263ec, 0xa0e9a666, 0x20d7d60d, - 0x520305af, 0xd23d75c4, 0xc806b04e, 0x4838c025, 0xfc713b5a, 0x7c4f4b31, - 0x66748ebb, 0xe64afed0, 0x83dd29ff, 0x03e35994, 0x19d89c1e, 0x99e6ec75, - 0x2daf170a, 0xad916761, 0xb7aaa2eb, 0x3794d280, 0x45400122, 0xc57e7149, - 0xdf45b4c3, 0x5f7bc4a8, 0xeb323fd7, 0x6b0c4fbc, 0x71378a36, 0xf109fa5d, - 0xe714365c, 0x672a4637, 0x7d1183bd, 0xfd2ff3d6, 0x496608a9, 0xc95878c2, - 0xd363bd48, 0x535dcd23, 0x21891e81, 0xa1b76eea, 0xbb8cab60, 0x3bb2db0b, - 0x8ffb2074, 0x0fc5501f, 0x15fe9595, 0x95c0e5fe, 0xf05732d1, 0x706942ba, - 0x6a528730, 0xea6cf75b, 0x5e250c24, 0xde1b7c4f, 0xc420b9c5, 0x441ec9ae, - 0x36ca1a0c, 0xb6f46a67, 0xaccfafed, 0x2cf1df86, 0x98b824f9, 0x18865492, - 0x02bd9118, 0x8283e173, 0xc9923f46, 0x49ac4f2d, 0x53978aa7, 0xd3a9facc, - 0x67e001b3, 0xe7de71d8, 0xfde5b452, 0x7ddbc439, 0x0f0f179b, 0x8f3167f0, - 0x950aa27a, 0x1534d211, 0xa17d296e, 0x21435905, 0x3b789c8f, 0xbb46ece4, - 0xded13bcb, 0x5eef4ba0, 0x44d48e2a, 0xc4eafe41, 0x70a3053e, 0xf09d7555, - 0xeaa6b0df, 0x6a98c0b4, 0x184c1316, 0x9872637d, 0x8249a6f7, 0x0277d69c, - 0xb63e2de3, 0x36005d88, 0x2c3b9802, 0xac05e869}; - -static unsigned _cairo_lfsr_random_state = 0x12345678; - -static unsigned -lfsr_random(void) +static uint32_t +hars_petruska_f54_1_random (void) { - unsigned next; - next = _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>> 0) & 0xFF) + 0*256]; - next ^= _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>> 8) & 0xFF) + 1*256]; - next ^= _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>>16) & 0xFF) + 2*256]; - next ^= _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>>24) & 0xFF) + 3*256]; - return _cairo_lfsr_random_state = next; +# define rol(x,k) ((x << k) | (x >> (32-k))) + static uint32_t x = 0; + x = (x ^ rol(x, 5) ^ rol(x, 24)) + 0x37798849; + return x; +# undef rol } /* * Initialize an empty skip list */ void -_cairo_skip_list_init (cairo_skip_list_t *list, - cairo_skip_list_compare_t compare, - size_t elt_size) +_cairo_skip_list_init (cairo_skip_list_t *list, + cairo_skip_list_compare_t compare, + size_t elt_size) { int i; @@ -269,20 +91,22 @@ _cairo_skip_list_fini (cairo_skip_list_t *list) static int random_level (void) { - 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) - { - if (bits & 1) - break; + uint32_t bits = hars_petruska_f54_1_random (); +#if HAVE_FFS + return ffs (-(1<<MAX_LEVEL) | bits | bits >> 16); +#else + int level = 1; + + bits |= -(1<<MAX_LEVEL) | bits >> 16; + while ((bits & 1) == 0) { + level++; bits >>= 1; } return level; +#endif } static void * @@ -359,7 +183,7 @@ _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) { + if (unlikely (data_and_elt == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return NULL; } @@ -483,3 +307,39 @@ _cairo_skip_list_delete_given (cairo_skip_list_t *list, skip_elt_t *given) list->max_level--; free_elt (list, elt); } + +#if MAIN +typedef struct { + int n; + skip_elt_t elt; +} test_elt_t; + +static int +test_cmp (void *list, void *A, void *B) +{ + const test_elt_t *a = A, *b = B; + return a->n - b->n; +} + +int +main (void) +{ + cairo_skip_list_t list; + test_elt_t elt; + int n; + + _cairo_skip_list_init (&list, test_cmp, sizeof (test_elt_t)); + for (n = 0; n < 10000000; n++) { + void *elt_and_data; + elt.n = n; + elt_and_data = _cairo_skip_list_insert (&list, &elt, TRUE); + assert (elt_and_data != NULL); + } + _cairo_skip_list_fini (&list); + + return 0; +} + +/* required supporting stubs */ +cairo_status_t _cairo_error (cairo_status_t status) { return status; } +#endif diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h new file mode 100644 index 00000000..c285f949 --- /dev/null +++ b/src/cairo-spans-private.h @@ -0,0 +1,144 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright (c) 2008 M Joonas Pihlaja + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef CAIRO_SPANS_PRIVATE_H +#define CAIRO_SPANS_PRIVATE_H +#include "cairo-types-private.h" +#include "cairo-compiler-private.h" + +/* Number of bits of precision used for alpha. */ +#define CAIRO_SPANS_UNIT_COVERAGE_BITS 8 +#define CAIRO_SPANS_UNIT_COVERAGE ((1 << CAIRO_SPANS_UNIT_COVERAGE_BITS)-1) + +/* A structure representing an open-ended horizontal span of constant + * pixel coverage. */ +typedef struct _cairo_half_open_span { + /* The inclusive x-coordinate of the start of the span. */ + int x; + + /* The pixel coverage for the pixels to the right. */ + int coverage; +} cairo_half_open_span_t; + +/* Span renderer interface. Instances of renderers are provided by + * surfaces if they want to composite spans instead of trapezoids. */ +typedef struct _cairo_span_renderer cairo_span_renderer_t; +struct _cairo_span_renderer { + /* Called to destroy the renderer. */ + cairo_destroy_func_t destroy; + + /* Render the spans on row y of the source by whatever compositing + * method is required. The function should ignore spans outside + * the bounding box set by the init() function. */ + cairo_status_t (*render_row)( + void *abstract_renderer, + int y, + const cairo_half_open_span_t *coverages, + unsigned num_coverages); + + /* Called after all rows have been rendered to perform whatever + * final rendering step is required. This function is called just + * once before the renderer is destroyed. */ + cairo_status_t (*finish)( + void *abstract_renderer); + + /* Private status variable. */ + cairo_status_t status; +}; + +/* Scan converter interface. */ +typedef struct _cairo_scan_converter cairo_scan_converter_t; +struct _cairo_scan_converter { + /* Destroy this scan converter. */ + cairo_destroy_func_t destroy; + + /* Add an edge to the converter. */ + cairo_status_t + (*add_edge)( + void *abstract_converter, + cairo_fixed_t x1, + cairo_fixed_t y1, + cairo_fixed_t x2, + cairo_fixed_t y2); + + /* Generates coverage spans for rows for the added edges and calls + * the renderer function for each row. After generating spans the + * only valid thing to do with the converter is to destroy it. */ + cairo_status_t + (*generate)( + void *abstract_converter, + cairo_span_renderer_t *renderer); + + /* Private status. Read with _cairo_scan_converter_status(). */ + cairo_status_t status; +}; + +/* Scan converter constructors. */ + +cairo_private cairo_scan_converter_t * +_cairo_tor_scan_converter_create( + int xmin, + int ymin, + int xmax, + int ymax, + cairo_fill_rule_t fill_rule); + +/* cairo-spans.c: */ + +cairo_private cairo_scan_converter_t * +_cairo_scan_converter_create_in_error (cairo_status_t error); + +cairo_private cairo_status_t +_cairo_scan_converter_status (void *abstract_converter); + +cairo_private cairo_status_t +_cairo_scan_converter_set_error (void *abstract_converter, + cairo_status_t error); + +cairo_private cairo_span_renderer_t * +_cairo_span_renderer_create_in_error (cairo_status_t error); + +cairo_private cairo_status_t +_cairo_span_renderer_status (void *abstract_renderer); + +/* Set the renderer into an error state. This sets all the method + * pointers except ->destroy() of the renderer to no-op + * implementations that just return the error status. */ +cairo_private cairo_status_t +_cairo_span_renderer_set_error (void *abstract_renderer, + cairo_status_t error); + +cairo_private cairo_status_t +_cairo_path_fixed_fill_using_spans ( + cairo_operator_t op, + const cairo_pattern_t *pattern, + cairo_path_fixed_t *path, + cairo_surface_t *dst, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects); +#endif /* CAIRO_SPANS_PRIVATE_H */ diff --git a/src/cairo-spans.c b/src/cairo-spans.c new file mode 100644 index 00000000..e441143b --- /dev/null +++ b/src/cairo-spans.c @@ -0,0 +1,395 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright (c) 2008 M Joonas Pihlaja + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "cairoint.h" + +typedef struct { + cairo_scan_converter_t *converter; + cairo_point_t current_point; + cairo_point_t first_point; +} scan_converter_filler_t; + +static void +scan_converter_filler_init ( + scan_converter_filler_t *filler, + cairo_scan_converter_t *converter) +{ + filler->converter = converter; + filler->current_point.x = 0; + filler->current_point.y = 0; + filler->first_point = filler->current_point; +} + +static cairo_status_t +scan_converter_filler_move_to ( + void *closure, + cairo_point_t *p) +{ + scan_converter_filler_t *filler = closure; + filler->current_point.x = p->x; + filler->current_point.y = p->y; + filler->first_point = filler->current_point; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +scan_converter_filler_line_to ( + void *closure, + cairo_point_t *p) +{ + scan_converter_filler_t *filler = closure; + cairo_status_t status; + cairo_point_t to; + + to.x = p->x; + to.y = p->y; + + status = filler->converter->add_edge ( + filler->converter, + filler->current_point.x, filler->current_point.y, + to.x, to.y); + + filler->current_point = to; + + return status; +} + +static cairo_status_t +scan_converter_filler_close_path ( + void *closure) +{ + scan_converter_filler_t *filler = closure; + cairo_status_t status; + + if (filler->first_point.x == filler->current_point.x && + filler->first_point.y == filler->current_point.y) + { + return CAIRO_STATUS_SUCCESS; + } + + status = filler->converter->add_edge ( + filler->converter, + filler->current_point.x, filler->current_point.y, + filler->first_point.x, filler->first_point.y); + + filler->current_point = filler->first_point; + + return status; +} + +static cairo_status_t +_cairo_path_fixed_fill_to_scan_converter ( + cairo_path_fixed_t *path, + double tolerance, + cairo_scan_converter_t *converter) +{ + scan_converter_filler_t filler; + cairo_status_t status; + + scan_converter_filler_init (&filler, converter); + + status = _cairo_path_fixed_interpret_flat ( + path, CAIRO_DIRECTION_FORWARD, + scan_converter_filler_move_to, + scan_converter_filler_line_to, + scan_converter_filler_close_path, + &filler, tolerance); + if (status) + return status; + + return scan_converter_filler_close_path (&filler); +} + +static cairo_scan_converter_t * +_create_scan_converter (cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects) +{ + if (antialias == CAIRO_ANTIALIAS_NONE) { + ASSERT_NOT_REACHED; + return _cairo_scan_converter_create_in_error ( + CAIRO_INT_STATUS_UNSUPPORTED); + } + else { + return _cairo_tor_scan_converter_create ( + rects->mask.x, + rects->mask.y, + rects->mask.x + rects->width, + rects->mask.y + rects->height, + fill_rule); + } +} + +cairo_status_t +_cairo_path_fixed_fill_using_spans ( + cairo_operator_t op, + const cairo_pattern_t *pattern, + cairo_path_fixed_t *path, + cairo_surface_t *dst, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects) +{ + cairo_status_t status; + cairo_span_renderer_t *renderer = _cairo_surface_create_span_renderer ( + op, pattern, dst, antialias, rects); + cairo_scan_converter_t *converter = _create_scan_converter ( + fill_rule, antialias, rects); + + status = _cairo_path_fixed_fill_to_scan_converter ( + path, tolerance, converter); + if (status) + goto BAIL; + + status = converter->generate (converter, renderer); + if (status) + goto BAIL; + + status = renderer->finish (renderer); + if (status) + goto BAIL; + + BAIL: + renderer->destroy (renderer); + converter->destroy (converter); + return status; +} + +static void +_cairo_nil_destroy (void *abstract) +{ + (void) abstract; +} + +static cairo_status_t +_cairo_nil_scan_converter_add_edge (void *abstract_converter, + cairo_fixed_t x1, + cairo_fixed_t y1, + cairo_fixed_t x2, + cairo_fixed_t y2) +{ + (void) abstract_converter; + (void) x1; + (void) y1; + (void) x2; + (void) y2; + return _cairo_scan_converter_status (abstract_converter); +} + +static cairo_status_t +_cairo_nil_scan_converter_generate (void *abstract_converter, + cairo_span_renderer_t *renderer) +{ + (void) abstract_converter; + (void) renderer; + return _cairo_scan_converter_status (abstract_converter); +} + +cairo_status_t +_cairo_scan_converter_status (void *abstract_converter) +{ + cairo_scan_converter_t *converter = abstract_converter; + return converter->status; +} + +cairo_status_t +_cairo_scan_converter_set_error (void *abstract_converter, + cairo_status_t error) +{ + cairo_scan_converter_t *converter = abstract_converter; + if (error == CAIRO_STATUS_SUCCESS) + ASSERT_NOT_REACHED; + if (converter->status == CAIRO_STATUS_SUCCESS) { + converter->add_edge = _cairo_nil_scan_converter_add_edge; + converter->generate = _cairo_nil_scan_converter_generate; + converter->status = error; + } + return converter->status; +} + +static void +_cairo_nil_scan_converter_init (cairo_scan_converter_t *converter, + cairo_status_t status) +{ + converter->destroy = _cairo_nil_destroy; + converter->status = CAIRO_STATUS_SUCCESS; + status = _cairo_scan_converter_set_error (converter, status); +} + +cairo_scan_converter_t * +_cairo_scan_converter_create_in_error (cairo_status_t status) +{ +#define RETURN_NIL {\ + static cairo_scan_converter_t nil;\ + _cairo_nil_scan_converter_init (&nil, status);\ + return &nil;\ + } + switch (status) { + case CAIRO_STATUS_SUCCESS: + ASSERT_NOT_REACHED; + break; + case CAIRO_STATUS_INVALID_RESTORE: RETURN_NIL; + case CAIRO_STATUS_INVALID_POP_GROUP: RETURN_NIL; + case CAIRO_STATUS_NO_CURRENT_POINT: RETURN_NIL; + case CAIRO_STATUS_INVALID_MATRIX: RETURN_NIL; + case CAIRO_STATUS_INVALID_STATUS: RETURN_NIL; + case CAIRO_STATUS_NULL_POINTER: RETURN_NIL; + case CAIRO_STATUS_INVALID_STRING: RETURN_NIL; + case CAIRO_STATUS_INVALID_PATH_DATA: RETURN_NIL; + case CAIRO_STATUS_READ_ERROR: RETURN_NIL; + case CAIRO_STATUS_WRITE_ERROR: RETURN_NIL; + case CAIRO_STATUS_SURFACE_FINISHED: RETURN_NIL; + case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_INVALID_CONTENT: RETURN_NIL; + case CAIRO_STATUS_INVALID_FORMAT: RETURN_NIL; + case CAIRO_STATUS_INVALID_VISUAL: RETURN_NIL; + case CAIRO_STATUS_FILE_NOT_FOUND: RETURN_NIL; + case CAIRO_STATUS_INVALID_DASH: RETURN_NIL; + case CAIRO_STATUS_INVALID_DSC_COMMENT: RETURN_NIL; + case CAIRO_STATUS_INVALID_INDEX: RETURN_NIL; + case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: RETURN_NIL; + case CAIRO_STATUS_TEMP_FILE_ERROR: RETURN_NIL; + case CAIRO_STATUS_INVALID_STRIDE: RETURN_NIL; + case CAIRO_STATUS_FONT_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_USER_FONT_IMMUTABLE: RETURN_NIL; + case CAIRO_STATUS_USER_FONT_ERROR: RETURN_NIL; + case CAIRO_STATUS_NEGATIVE_COUNT: RETURN_NIL; + case CAIRO_STATUS_INVALID_CLUSTERS: RETURN_NIL; + case CAIRO_STATUS_INVALID_SLANT: RETURN_NIL; + case CAIRO_STATUS_INVALID_WEIGHT: RETURN_NIL; + case CAIRO_STATUS_NO_MEMORY: RETURN_NIL; + default: + break; + } + status = CAIRO_STATUS_NO_MEMORY; + RETURN_NIL; +#undef RETURN_NIL +} + +static cairo_status_t +_cairo_nil_span_renderer_render_row ( + void *abstract_renderer, + int y, + const cairo_half_open_span_t *coverages, + unsigned num_coverages) +{ + (void) y; + (void) coverages; + (void) num_coverages; + return _cairo_span_renderer_status (abstract_renderer); +} + +static cairo_status_t +_cairo_nil_span_renderer_finish (void *abstract_renderer) +{ + return _cairo_span_renderer_status (abstract_renderer); +} + +cairo_status_t +_cairo_span_renderer_status (void *abstract_renderer) +{ + cairo_span_renderer_t *renderer = abstract_renderer; + return renderer->status; +} + +cairo_status_t +_cairo_span_renderer_set_error ( + void *abstract_renderer, + cairo_status_t error) +{ + cairo_span_renderer_t *renderer = abstract_renderer; + if (error == CAIRO_STATUS_SUCCESS) { + ASSERT_NOT_REACHED; + } + if (renderer->status == CAIRO_STATUS_SUCCESS) { + renderer->render_row = _cairo_nil_span_renderer_render_row; + renderer->finish = _cairo_nil_span_renderer_finish; + renderer->status = error; + } + return renderer->status; +} + +static void +_cairo_nil_span_renderer_init (cairo_span_renderer_t *renderer, + cairo_status_t status) +{ + renderer->destroy = _cairo_nil_destroy; + renderer->status = CAIRO_STATUS_SUCCESS; + status = _cairo_span_renderer_set_error (renderer, status); +} + +cairo_span_renderer_t * +_cairo_span_renderer_create_in_error (cairo_status_t status) +{ +#define RETURN_NIL {\ + static cairo_span_renderer_t nil;\ + _cairo_nil_span_renderer_init (&nil, status);\ + return &nil;\ + } + switch (status) { + case CAIRO_STATUS_SUCCESS: + ASSERT_NOT_REACHED; + break; + case CAIRO_STATUS_INVALID_RESTORE: RETURN_NIL; + case CAIRO_STATUS_INVALID_POP_GROUP: RETURN_NIL; + case CAIRO_STATUS_NO_CURRENT_POINT: RETURN_NIL; + case CAIRO_STATUS_INVALID_MATRIX: RETURN_NIL; + case CAIRO_STATUS_INVALID_STATUS: RETURN_NIL; + case CAIRO_STATUS_NULL_POINTER: RETURN_NIL; + case CAIRO_STATUS_INVALID_STRING: RETURN_NIL; + case CAIRO_STATUS_INVALID_PATH_DATA: RETURN_NIL; + case CAIRO_STATUS_READ_ERROR: RETURN_NIL; + case CAIRO_STATUS_WRITE_ERROR: RETURN_NIL; + case CAIRO_STATUS_SURFACE_FINISHED: RETURN_NIL; + case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_INVALID_CONTENT: RETURN_NIL; + case CAIRO_STATUS_INVALID_FORMAT: RETURN_NIL; + case CAIRO_STATUS_INVALID_VISUAL: RETURN_NIL; + case CAIRO_STATUS_FILE_NOT_FOUND: RETURN_NIL; + case CAIRO_STATUS_INVALID_DASH: RETURN_NIL; + case CAIRO_STATUS_INVALID_DSC_COMMENT: RETURN_NIL; + case CAIRO_STATUS_INVALID_INDEX: RETURN_NIL; + case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: RETURN_NIL; + case CAIRO_STATUS_TEMP_FILE_ERROR: RETURN_NIL; + case CAIRO_STATUS_INVALID_STRIDE: RETURN_NIL; + case CAIRO_STATUS_FONT_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_USER_FONT_IMMUTABLE: RETURN_NIL; + case CAIRO_STATUS_USER_FONT_ERROR: RETURN_NIL; + case CAIRO_STATUS_NEGATIVE_COUNT: RETURN_NIL; + case CAIRO_STATUS_INVALID_CLUSTERS: RETURN_NIL; + case CAIRO_STATUS_INVALID_SLANT: RETURN_NIL; + case CAIRO_STATUS_INVALID_WEIGHT: RETURN_NIL; + case CAIRO_STATUS_NO_MEMORY: RETURN_NIL; + default: + break; + } + status = CAIRO_STATUS_NO_MEMORY; + RETURN_NIL; +#undef RETURN_NIL +} diff --git a/src/cairo-spline.c b/src/cairo-spline.c index b39257e2..b5285447 100644 --- a/src/cairo-spline.c +++ b/src/cairo-spline.c @@ -36,29 +36,16 @@ #include "cairoint.h" -static cairo_status_t -_cairo_spline_grow (cairo_spline_t *spline); - -static cairo_status_t -_cairo_spline_add_point (cairo_spline_t *spline, const cairo_point_t *point); - -static void -_lerp_half (const cairo_point_t *a, const cairo_point_t *b, cairo_point_t *result); - -static void -_de_casteljau (cairo_spline_knots_t *s1, cairo_spline_knots_t *s2); - -static double -_cairo_spline_error_squared (const cairo_spline_knots_t *spline); - -static cairo_status_t -_cairo_spline_decompose_into (cairo_spline_knots_t *spline, double tolerance_squared, cairo_spline_t *result); - -cairo_int_status_t +cairo_bool_t _cairo_spline_init (cairo_spline_t *spline, + void (*add_point_func) (void*, const cairo_point_t *), + void *closure, const cairo_point_t *a, const cairo_point_t *b, const cairo_point_t *c, const cairo_point_t *d) { + spline->add_point_func = add_point_func; + spline->closure = closure; + spline->knots.a = *a; spline->knots.b = *b; spline->knots.c = *c; @@ -71,7 +58,7 @@ _cairo_spline_init (cairo_spline_t *spline, else if (a->x != d->x || a->y != d->y) _cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.d); else - return CAIRO_INT_STATUS_DEGENERATE; + return FALSE; if (c->x != d->x || c->y != d->y) _cairo_slope_init (&spline->final_slope, &spline->knots.c, &spline->knots.d); @@ -80,74 +67,25 @@ _cairo_spline_init (cairo_spline_t *spline, else _cairo_slope_init (&spline->final_slope, &spline->knots.a, &spline->knots.d); - spline->points = spline->points_embedded; - spline->points_size = ARRAY_LENGTH (spline->points_embedded); - spline->num_points = 0; - - return CAIRO_STATUS_SUCCESS; + return TRUE; } void _cairo_spline_fini (cairo_spline_t *spline) { - if (spline->points != spline->points_embedded) - free (spline->points); - - spline->points = spline->points_embedded; - spline->points_size = ARRAY_LENGTH (spline->points_embedded); - spline->num_points = 0; } -/* make room for at least one more point */ -static cairo_status_t -_cairo_spline_grow (cairo_spline_t *spline) -{ - cairo_point_t *new_points; - int old_size = spline->points_size; - int new_size = 2 * MAX (old_size, 16); - - assert (spline->num_points <= spline->points_size); - - if (spline->points == spline->points_embedded) { - new_points = _cairo_malloc_ab (new_size, sizeof (cairo_point_t)); - if (new_points) - memcpy (new_points, spline->points, old_size * sizeof (cairo_point_t)); - } else { - new_points = _cairo_realloc_ab (spline->points, - new_size, sizeof (cairo_point_t)); - } - - if (new_points == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - spline->points = new_points; - spline->points_size = new_size; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t +static void _cairo_spline_add_point (cairo_spline_t *spline, const cairo_point_t *point) { - cairo_status_t status; cairo_point_t *prev; - if (spline->num_points) { - prev = &spline->points[spline->num_points - 1]; - if (prev->x == point->x && prev->y == point->y) - return CAIRO_STATUS_SUCCESS; - } - - if (spline->num_points >= spline->points_size) { - status = _cairo_spline_grow (spline); - if (status) - return status; - } - - spline->points[spline->num_points] = *point; - spline->num_points++; + prev = &spline->last_point; + if (prev->x == point->x && prev->y == point->y) + return; - return CAIRO_STATUS_SUCCESS; + spline->add_point_func (spline->closure, point); + spline->last_point = *point; } static void @@ -243,45 +181,30 @@ _cairo_spline_error_squared (const cairo_spline_knots_t *knots) return cerr; } -static cairo_status_t +static void _cairo_spline_decompose_into (cairo_spline_knots_t *s1, double tolerance_squared, cairo_spline_t *result) { cairo_spline_knots_t s2; - cairo_status_t status; - if (_cairo_spline_error_squared (s1) < tolerance_squared) - return _cairo_spline_add_point (result, &s1->a); + if (_cairo_spline_error_squared (s1) < tolerance_squared) { + _cairo_spline_add_point (result, &s1->a); + return; + } _de_casteljau (s1, &s2); - status = _cairo_spline_decompose_into (s1, tolerance_squared, result); - if (status) - return status; - - status = _cairo_spline_decompose_into (&s2, tolerance_squared, result); - if (status) - return status; - - return CAIRO_STATUS_SUCCESS; + _cairo_spline_decompose_into (s1, tolerance_squared, result); + _cairo_spline_decompose_into (&s2, tolerance_squared, result); } -cairo_status_t +void _cairo_spline_decompose (cairo_spline_t *spline, double tolerance) { - cairo_status_t status; cairo_spline_knots_t s1; - /* reset the spline, but keep the buffer */ - spline->num_points = 0; - s1 = spline->knots; - status = _cairo_spline_decompose_into (&s1, tolerance * tolerance, spline); - if (status) - return status; - - status = _cairo_spline_add_point (spline, &spline->knots.d); - if (status) - return status; + spline->last_point = s1.a; + _cairo_spline_decompose_into (&s1, tolerance * tolerance, spline); - return CAIRO_STATUS_SUCCESS; + _cairo_spline_add_point (spline, &spline->knots.d); } diff --git a/src/cairo-stroke-style.c b/src/cairo-stroke-style.c index 3bc234e9..edc4f889 100644 --- a/src/cairo-stroke-style.c +++ b/src/cairo-stroke-style.c @@ -63,7 +63,7 @@ _cairo_stroke_style_init_copy (cairo_stroke_style_t *style, style->dash = NULL; } else { style->dash = _cairo_malloc_ab (style->num_dashes, sizeof (double)); - if (style->dash == NULL) + if (unlikely (style->dash == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (style->dash, other->dash, diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c index a5dcd57a..88975e9a 100644 --- a/src/cairo-surface-fallback.c +++ b/src/cairo-surface-fallback.c @@ -79,7 +79,7 @@ _fallback_init (fallback_state_t *state, status = _cairo_surface_acquire_dest_image (dst, &state->extents, &state->image, &state->image_rect, &state->image_extra); - if (status) + if (unlikely (status)) return status; /* XXX: This NULL value tucked away in state->image is a rather @@ -131,7 +131,7 @@ _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern, NULL, mask, extents->x, extents->y, extents); - if (status) + if (unlikely (status)) goto CLEANUP_SURFACE; if (clip && clip->surface) @@ -139,7 +139,7 @@ _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern, mask, extents->x, extents->y, extents); - if (status) + if (unlikely (status)) goto CLEANUP_SURFACE; _cairo_pattern_init_for_surface (mask_pattern, mask); @@ -169,7 +169,7 @@ _clip_and_composite_with_mask (cairo_clip_t *clip, clip, draw_func, draw_closure, dst, extents); - if (status) + if (unlikely (status)) return status; status = _cairo_surface_composite (op, @@ -226,14 +226,14 @@ _clip_and_composite_combine (cairo_clip_t *clip, _cairo_pattern_fini (&dst_pattern.base); - if (status) + if (unlikely (status)) goto CLEANUP_SURFACE; status = (*draw_func) (draw_closure, op, src, intermediate, extents->x, extents->y, extents); - if (status) + if (unlikely (status)) goto CLEANUP_SURFACE; /* Combine that with the clip @@ -242,7 +242,7 @@ _clip_and_composite_combine (cairo_clip_t *clip, intermediate, extents->x, extents->y, extents); - if (status) + if (unlikely (status)) goto CLEANUP_SURFACE; /* Punch the clip out of the destination @@ -251,7 +251,7 @@ _clip_and_composite_combine (cairo_clip_t *clip, dst, 0, 0, extents); - if (status) + if (unlikely (status)) goto CLEANUP_SURFACE; /* Now add the two results together @@ -293,7 +293,7 @@ _clip_and_composite_source (cairo_clip_t *clip, clip, draw_func, draw_closure, dst, extents); - if (status) + if (unlikely (status)) return status; /* Compute dest' = dest OUT (mask IN clip) @@ -305,7 +305,7 @@ _clip_and_composite_source (cairo_clip_t *clip, extents->x, extents->y, extents->width, extents->height); - if (status) + if (unlikely (status)) goto CLEANUP_MASK_PATTERN; /* Now compute (src IN (mask IN clip)) ADD dest' @@ -439,7 +439,7 @@ _composite_trap_region (cairo_clip_t *clip, status = _cairo_surface_set_clip_region (dst, trap_region, clip_serial); - if (status) + if (unlikely (status)) return status; } @@ -531,7 +531,7 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src, return CAIRO_STATUS_SUCCESS; status = _cairo_surface_get_extents (dst, &extents); - if (status) + if (unlikely (status)) return status; status = _cairo_traps_extract_region (traps, &trap_region); @@ -548,7 +548,7 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src, if (has_trap_region) { status = _cairo_clip_intersect_to_region (clip, &trap_region); - if (status) + if (unlikely (status)) goto out; _cairo_region_get_extents (&trap_region, &trap_extents); @@ -564,7 +564,7 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src, } status = _cairo_clip_intersect_to_rectangle (clip, &extents); - if (status) + if (unlikely (status)) goto out; } else { cairo_surface_t *clip_surface = clip ? clip->surface : NULL; @@ -579,13 +579,13 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src, has_clear_region = TRUE; status = _cairo_clip_intersect_to_region (clip, &clear_region); - if (status) + if (unlikely (status)) goto out; _cairo_region_get_extents (&clear_region, &extents); status = _cairo_region_subtract (&clear_region, &clear_region, &trap_region); - if (status) + if (unlikely (status)) goto out; if (!_cairo_region_not_empty (&clear_region)) { @@ -597,7 +597,7 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src, } } - if (status) + if (unlikely (status)) goto out; if (has_trap_region) { @@ -670,6 +670,53 @@ out: return status; } +typedef struct { + cairo_path_fixed_t *path; + cairo_fill_rule_t fill_rule; + double tolerance; + cairo_antialias_t antialias; +} cairo_composite_spans_fill_info_t; + +static cairo_status_t +_composite_spans_fill_func (void *closure, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents) +{ + cairo_composite_rectangles_t rects; + cairo_composite_spans_fill_info_t *info = closure; + cairo_pattern_union_t pattern; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + _cairo_composite_rectangles_init ( + &rects, extents->x, extents->y, + extents->width, extents->height); + + /* The incoming dst_x/y are where we're pretending the origin of + * the dst surface is -- *not* the offset of a rectangle where + * we'd like to place the result. */ + rects.dst.x -= dst_x; + rects.dst.y -= dst_y; + + /* We're called without a source pattern from + * _create_composite_mask_pattern(). */ + _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE, + CAIRO_CONTENT_COLOR); + if (src == NULL) + src = &pattern.base; + + status = _cairo_path_fixed_fill_using_spans ( + op, src, info->path, dst, + info->fill_rule, info->tolerance, info->antialias, + &rects); + + _cairo_pattern_fini (&pattern.base); + return status; +} + cairo_status_t _cairo_surface_fallback_paint (cairo_surface_t *surface, cairo_operator_t op, @@ -681,14 +728,14 @@ _cairo_surface_fallback_paint (cairo_surface_t *surface, cairo_traps_t traps; status = _cairo_surface_get_extents (surface, &extents); - if (status) + if (unlikely (status)) return status; if (_cairo_operator_bounded_by_source (op)) { cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); - if (status) + if (unlikely (status)) return status; if (! _cairo_rectangle_intersect (&extents, &source_extents)) @@ -696,7 +743,7 @@ _cairo_surface_fallback_paint (cairo_surface_t *surface, } status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); - if (status) + if (unlikely (status)) return status; _cairo_box_from_rectangle (&box, &extents); @@ -752,12 +799,12 @@ _cairo_surface_fallback_mask (cairo_surface_t *surface, cairo_rectangle_int_t extents, source_extents, mask_extents; status = _cairo_surface_get_extents (surface, &extents); - if (status) + if (unlikely (status)) return status; if (_cairo_operator_bounded_by_source (op)) { status = _cairo_pattern_get_extents (source, &source_extents); - if (status) + if (unlikely (status)) return status; if (! _cairo_rectangle_intersect (&extents, &source_extents)) @@ -766,7 +813,7 @@ _cairo_surface_fallback_mask (cairo_surface_t *surface, if (_cairo_operator_bounded_by_mask (op)) { status = _cairo_pattern_get_extents (mask, &mask_extents); - if (status) + if (unlikely (status)) return status; if (! _cairo_rectangle_intersect (&extents, &mask_extents)) @@ -774,7 +821,7 @@ _cairo_surface_fallback_mask (cairo_surface_t *surface, } status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); - if (status) + if (unlikely (status)) return status; status = _clip_and_composite (surface->clip, op, @@ -804,13 +851,13 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface, cairo_rectangle_int_t extents; status = _cairo_surface_get_extents (surface, &extents); - if (status) + if (unlikely (status)) return status; if (_cairo_operator_bounded_by_source (op)) { cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); - if (status) + if (unlikely (status)) return status; if (! _cairo_rectangle_intersect (&extents, &source_extents)) @@ -818,7 +865,7 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface, } status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); - if (status) + if (unlikely (status)) return status; if (extents.width == 0 || extents.height == 0) @@ -834,7 +881,7 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface, ctm, ctm_inverse, tolerance, &traps); - if (status) + if (unlikely (status)) goto FAIL; status = _clip_and_composite_trapezoids (source, @@ -865,14 +912,14 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, cairo_rectangle_int_t extents; status = _cairo_surface_get_extents (surface, &extents); - if (status) + if (unlikely (status)) return status; if (_cairo_operator_bounded_by_source (op)) { cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); - if (status) + if (unlikely (status)) return status; if (! _cairo_rectangle_intersect (&extents, &source_extents)) @@ -880,14 +927,51 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, } status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); - if (status) + if (unlikely (status)) return status; if (extents.width == 0 || extents.height == 0) return CAIRO_STATUS_SUCCESS; - _cairo_box_from_rectangle (&box, &extents); + /* Ask if the surface would like to render this combination of + * op/source/dst/antialias with spans or not, but don't actually + * make a renderer yet. We'll try to hit the region optimisations + * in _clip_and_composite_trapezoids() if it looks like the path + * is a region. */ + /* TODO: Until we have a mono scan converter we won't even try + * to use spans for CAIRO_ANTIALIAS_NONE. */ + /* TODO: The region filling code should be lifted from + * _clip_and_composite_trapezoids() and given first priority + * explicitly before deciding between spans and trapezoids. */ + if (antialias != CAIRO_ANTIALIAS_NONE && + !_cairo_path_fixed_is_box (path, &box) && + !_cairo_path_fixed_is_region (path) && + _cairo_surface_check_span_renderer ( + op, source, surface, antialias, NULL)) + { + cairo_composite_spans_fill_info_t info; + info.path = path; + info.fill_rule = fill_rule; + info.tolerance = tolerance; + info.antialias = antialias; + + if (_cairo_operator_bounded_by_mask (op)) { + cairo_rectangle_int_t path_extents; + _cairo_path_fixed_approximate_extents (path, &path_extents); + if (! _cairo_rectangle_intersect (&extents, &path_extents)) + return CAIRO_STATUS_SUCCESS; + } + return _clip_and_composite ( + surface->clip, op, source, + _composite_spans_fill_func, + &info, + surface, + &extents); + } + + /* Fall back to trapezoid fills. */ + _cairo_box_from_rectangle (&box, &extents); _cairo_traps_init (&traps); _cairo_traps_limit (&traps, &box); @@ -895,7 +979,7 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, fill_rule, tolerance, &traps); - if (status) { + if (unlikely (status)) { _cairo_traps_fini (&traps); return status; } @@ -992,7 +1076,7 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, cairo_show_glyphs_info_t glyph_info; status = _cairo_surface_get_extents (surface, &extents); - if (status) + if (unlikely (status)) return status; if (_cairo_operator_bounded_by_mask (op)) { @@ -1002,7 +1086,7 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, glyphs, num_glyphs, &glyph_extents); - if (status) + if (unlikely (status)) return status; if (! _cairo_rectangle_intersect (&extents, &glyph_extents)) @@ -1010,7 +1094,7 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, } status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); - if (status) + if (unlikely (status)) return status; glyph_info.font = scaled_font; @@ -1036,10 +1120,16 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface) cairo_surface_pattern_t pattern; cairo_image_surface_t *image; void *image_extra; + const char *mime_types[] = { + CAIRO_MIME_TYPE_JPEG, + CAIRO_MIME_TYPE_PNG, + CAIRO_MIME_TYPE_JP2, + NULL + }, **mime_type; status = _cairo_surface_acquire_source_image (surface, &image, &image_extra); - if (status) + if (unlikely (status)) return _cairo_surface_create_in_error (status); snapshot = cairo_image_surface_create (image->format, @@ -1067,7 +1157,7 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface) _cairo_surface_release_source_image (surface, image, image_extra); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (snapshot); return _cairo_surface_create_in_error (status); } @@ -1075,6 +1165,14 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface) snapshot->device_transform = surface->device_transform; snapshot->device_transform_inverse = surface->device_transform_inverse; + for (mime_type = mime_types; *mime_type; mime_type++) { + status = _cairo_surface_copy_mime_data (snapshot, surface, *mime_type); + if (unlikely (status)) { + cairo_surface_destroy (snapshot); + return _cairo_surface_create_in_error (status); + } + } + snapshot->is_snapshot = TRUE; return snapshot; @@ -1098,7 +1196,7 @@ _cairo_surface_fallback_composite (cairo_operator_t op, cairo_status_t status; status = _fallback_init (&state, dst, dst_x, dst_y, width, height); - if (status) { + if (unlikely (status)) { if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; return status; @@ -1159,7 +1257,7 @@ _cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface, } status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1); - if (status) { + if (unlikely (status)) { if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; return status; @@ -1169,7 +1267,7 @@ _cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface, if (state.image_rect.x != 0 || state.image_rect.y != 0) { offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t)); - if (offset_rects == NULL) { + if (unlikely (offset_rects == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto DONE; } @@ -1215,7 +1313,7 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op, cairo_status_t status; status = _fallback_init (&state, dst, dst_x, dst_y, width, height); - if (status) { + if (unlikely (status)) { if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; return status; diff --git a/src/cairo-surface.c b/src/cairo-surface.c index ff75cc2f..077af5b4 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -40,28 +40,19 @@ #include "cairo-surface-fallback-private.h" #include "cairo-clip-private.h" +#include "cairo-meta-surface-private.h" #define DEFINE_NIL_SURFACE(status, name) \ const cairo_surface_t name = { \ - &_cairo_image_surface_backend, /* backend */ \ - CAIRO_SURFACE_TYPE_IMAGE, \ - CAIRO_CONTENT_COLOR, \ + NULL, /* backend */ \ + CAIRO_SURFACE_TYPE_IMAGE, /* type */ \ + CAIRO_CONTENT_COLOR, /* content */ \ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ \ status, /* status */ \ FALSE, /* finished */ \ - { 0, /* size */ \ - 0, /* num_elements */ \ - 0, /* element_size */ \ - NULL, /* elements */ \ - }, /* user_data */ \ - { 1.0, 0.0, \ - 0.0, 1.0, \ - 0.0, 0.0 \ - }, /* device_transform */ \ - { 1.0, 0.0, \ - 0.0, 1.0, \ - 0.0, 0.0 \ - }, /* device_transform_inverse */ \ + { 0, 0, 0, NULL, }, /* user_data */ \ + { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, /* device_transform */ \ + { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, /* device_transform_inverse */ \ 0.0, /* x_resolution */ \ 0.0, /* y_resolution */ \ 0.0, /* x_fallback_resolution */ \ @@ -246,7 +237,7 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other, } /* If any error occurred, then return the nil surface we received. */ - if (surface->status) + if (unlikely (surface->status)) return surface; if (other->has_font_options || other->backend != surface->backend) { @@ -327,11 +318,11 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other, status = _cairo_surface_paint (surface, color == CAIRO_COLOR_TRANSPARENT ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE, - &solid_pattern.base); + &solid_pattern.base, NULL); _cairo_pattern_fini (&solid_pattern.base); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (surface); return _cairo_surface_create_in_error (status); } @@ -373,7 +364,7 @@ _cairo_surface_repaint_solid_pattern_surface (cairo_surface_t *other, */ return CAIRO_INT_STATUS_UNSUPPORTED; - return _cairo_surface_paint (solid_surface, CAIRO_OPERATOR_SOURCE, &solid_pattern->base); + return _cairo_surface_paint (solid_surface, CAIRO_OPERATOR_SOURCE, &solid_pattern->base, NULL); } cairo_clip_mode_t @@ -464,7 +455,7 @@ _cairo_surface_reset (cairo_surface_t *surface) if (surface->backend->reset != NULL) { cairo_status_t status = surface->backend->reset (surface); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (surface, status); } @@ -532,7 +523,7 @@ cairo_surface_finish (cairo_surface_t *surface) /* call finish even if in error mode */ if (surface->backend->finish) { status = surface->backend->finish (surface); - if (status) + if (unlikely (status)) status = _cairo_surface_set_error (surface, status); } @@ -590,6 +581,163 @@ cairo_surface_set_user_data (cairo_surface_t *surface, } /** + * cairo_surface_get_mime_data: + * @surface: a #cairo_surface_t + * @mime_type: the mime type of the image data + * @data: the image data to attached to the surface + * @length: the length of the image data + * + * Return mime data previously attached to @surface using the + * specified mime type. If no data has been attached with the given + * mime type, @data is set %NULL. + * + * Since: 1.10 + **/ +void +cairo_surface_get_mime_data (cairo_surface_t *surface, + const char *mime_type, + const unsigned char **data, + unsigned int *length) +{ + cairo_status_t status; + cairo_mime_data_t *mime_data; + + *data = NULL; + *length = 0; + if (surface->status) + return; + + status = _cairo_intern_string (&mime_type, -1); + if (unlikely (status)) { + status = _cairo_surface_set_error (surface, status); + return; + } + + mime_data = _cairo_user_data_array_get_data (&surface->user_data, + (cairo_user_data_key_t *) mime_type); + if (mime_data == NULL) + return; + + *data = mime_data->data; + *length = mime_data->length; +} +slim_hidden_def (cairo_surface_get_mime_data); + +static void +_cairo_mime_data_destroy (void *ptr) +{ + cairo_mime_data_t *mime_data = ptr; + + if (! _cairo_reference_count_dec_and_test (&mime_data->ref_count)) + return; + + if (mime_data->destroy && mime_data->closure) + mime_data->destroy (mime_data->closure); + + free (mime_data); +} + +/** + * cairo_surface_set_mime_data: + * @surface: a #cairo_surface_t + * @mime_type: the mime type of the image data + * @data: the image data to attach to the surface + * @length: the length of the image data + * @destroy: a #cairo_destroy_func_t which will be called when the + * surface is destroyed or when new image data is attached using the + * same mime type. + * @closure: the data to be passed to the @destroy notifier + * + * Attach an image in the format @mime_type to @surface. To remove + * the data from a surface, call this function with same mime type + * and %NULL for @data. + * + * Since: 1.10 + * + * 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_surface_set_mime_data (cairo_surface_t *surface, + const char *mime_type, + const unsigned char *data, + unsigned int length, + cairo_destroy_func_t destroy, + void *closure) +{ + cairo_status_t status; + cairo_mime_data_t *mime_data; + + if (surface->status) + return surface->status; + + status = _cairo_intern_string (&mime_type, -1); + if (unlikely (status)) + return _cairo_surface_set_error (surface, status); + + if (data != NULL) { + mime_data = malloc (sizeof (cairo_mime_data_t)); + if (unlikely (mime_data == NULL)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_NO_MEMORY)); + + CAIRO_REFERENCE_COUNT_INIT (&mime_data->ref_count, 1); + + mime_data->data = (unsigned char *) data; + mime_data->length = length; + mime_data->destroy = destroy; + mime_data->closure = closure; + } else + mime_data = NULL; + + status = _cairo_user_data_array_set_data (&surface->user_data, + (cairo_user_data_key_t *) mime_type, + mime_data, + _cairo_mime_data_destroy); + if (unlikely (status)) + return _cairo_surface_set_error (surface, status); + + return CAIRO_STATUS_SUCCESS; +} +slim_hidden_def (cairo_surface_set_mime_data); + +cairo_status_t +_cairo_surface_copy_mime_data (cairo_surface_t *dst, + cairo_surface_t *src, + const char *mime_type) +{ + cairo_status_t status; + cairo_mime_data_t *mime_data; + + if (dst->status) + return dst->status; + + if (src->status) + return _cairo_surface_set_error (dst, src->status); + + status = _cairo_intern_string (&mime_type, -1); + if (unlikely (status)) + return _cairo_surface_set_error (dst, status); + + mime_data = _cairo_user_data_array_get_data (&src->user_data, + (cairo_user_data_key_t *) mime_type); + if (mime_data == NULL) + return CAIRO_STATUS_SUCCESS; + + _cairo_reference_count_inc (&mime_data->ref_count); + + status = _cairo_user_data_array_set_data (&dst->user_data, + (cairo_user_data_key_t *) mime_type, + mime_data, + _cairo_mime_data_destroy); + if (unlikely (status)) { + _cairo_mime_data_destroy (mime_data); + return _cairo_surface_set_error (dst, status); + } + + return CAIRO_STATUS_SUCCESS; +} + +/** * _cairo_surface_set_font_options: * @surface: a #cairo_surface_t * @options: a #cairo_font_options_t object that contains the @@ -691,7 +839,7 @@ cairo_surface_flush (cairo_surface_t *surface) if (surface->backend->flush) { status = surface->backend->flush (surface); - if (status) + if (unlikely (status)) status = _cairo_surface_set_error (surface, status); } } @@ -769,7 +917,7 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, y + surface->device_transform.y0, width, height); - if (status) + if (unlikely (status)) status = _cairo_surface_set_error (surface, status); } } @@ -1140,10 +1288,10 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, cairo_image_surface_t *image; void *image_extra; - if (surface->status) + if (unlikely (surface->status)) return surface->status; - if (surface->finished) + if (unlikely (surface->finished)) return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); if (surface->backend->clone_similar) { @@ -1155,6 +1303,31 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, clone_out); if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + /* First check to see if we can replay to a similar surface */ + if (_cairo_surface_is_meta (src)) { + cairo_surface_t *similar; + + similar = cairo_surface_create_similar (surface, + src->content, + width, height); + status = similar->status; + if (unlikely (status)) + return status; + + cairo_surface_set_device_offset (similar, -src_x, -src_y); + + status = _cairo_meta_surface_replay (src, similar); + if (unlikely (status)) { + cairo_surface_destroy (similar); + return status; + } + + *clone_out = similar; + *clone_offset_x = src_x; + *clone_offset_y = src_y; + return CAIRO_STATUS_SUCCESS; + } + /* If we failed, try again with an image surface */ status = _cairo_surface_acquire_source_image (src, &image, &image_extra); if (status == CAIRO_STATUS_SUCCESS) { @@ -1182,7 +1355,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, clone_out); /* We should never get UNSUPPORTED here, so if we have an error, bail. */ - if (status) + if (unlikely (status)) return status; /* Update the clone's device_transform (which the underlying surface @@ -1362,6 +1535,7 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface, * * Return value: %CAIRO_STATUS_SUCCESS or the error that occurred **/ +COMPILE_TIME_ASSERT (sizeof (cairo_box_int_t) <= sizeof (cairo_rectangle_int_t)); cairo_status_t _cairo_surface_fill_region (cairo_surface_t *surface, cairo_operator_t op, @@ -1369,8 +1543,8 @@ _cairo_surface_fill_region (cairo_surface_t *surface, cairo_region_t *region) { int num_boxes; - cairo_box_int_t *boxes = NULL; cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)]; + cairo_box_int_t *boxes = (cairo_box_int_t *) stack_rects; cairo_rectangle_int_t *rects = stack_rects; cairo_status_t status; int i; @@ -1381,31 +1555,31 @@ _cairo_surface_fill_region (cairo_surface_t *surface, assert (! surface->is_snapshot); num_boxes = _cairo_region_num_boxes (region); - if (num_boxes == 0) return CAIRO_STATUS_SUCCESS; /* handle the common case of a single box without allocation */ if (num_boxes > 1) { + num_boxes = sizeof (stack_rects) / sizeof (cairo_box_int_t); status = _cairo_region_get_boxes (region, &num_boxes, &boxes); - if (status) + if (unlikely (status)) return status; if (num_boxes > ARRAY_LENGTH (stack_rects)) { rects = _cairo_malloc_ab (num_boxes, sizeof (cairo_rectangle_int_t)); - if (!rects) { + if (rects == NULL) { _cairo_region_boxes_fini (region, boxes); return _cairo_surface_set_error (surface, - CAIRO_STATUS_NO_MEMORY); + _cairo_error (CAIRO_STATUS_NO_MEMORY)); } } for (i = 0; i < num_boxes; i++) { rects[i].x = boxes[i].p1.x; rects[i].y = boxes[i].p1.y; - rects[i].width = boxes[i].p2.x - boxes[i].p1.x; - rects[i].height = boxes[i].p2.y - boxes[i].p1.y; + rects[i].width = boxes[i].p2.x - rects[i].x; + rects[i].height = boxes[i].p2.y - rects[i].y; } } else _cairo_region_get_extents (region, &rects[0]); @@ -1413,7 +1587,7 @@ _cairo_surface_fill_region (cairo_surface_t *surface, status = _cairo_surface_fill_rectangles (surface, op, color, rects, num_boxes); - if (boxes != NULL) + if (boxes != (cairo_box_int_t *) stack_rects) _cairo_region_boxes_fini (region, boxes); if (rects != stack_rects) @@ -1473,7 +1647,8 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, cairo_status_t _cairo_surface_paint (cairo_surface_t *surface, cairo_operator_t op, - const cairo_pattern_t *source) + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents) { cairo_status_t status; cairo_pattern_union_t dev_source; @@ -1486,11 +1661,11 @@ _cairo_surface_paint (cairo_surface_t *surface, status = _cairo_surface_copy_pattern_for_destination (&source, surface, &dev_source.base); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (surface, status); if (surface->backend->paint) { - status = surface->backend->paint (surface, op, source); + status = surface->backend->paint (surface, op, source, extents); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto FINISH; } @@ -1508,7 +1683,8 @@ cairo_status_t _cairo_surface_mask (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_pattern_t *mask) + const cairo_pattern_t *mask, + cairo_rectangle_int_t *extents) { cairo_status_t status; cairo_pattern_union_t dev_source; @@ -1522,17 +1698,17 @@ _cairo_surface_mask (cairo_surface_t *surface, status = _cairo_surface_copy_pattern_for_destination (&source, surface, &dev_source.base); - if (status) + if (unlikely (status)) goto FINISH; status = _cairo_surface_copy_pattern_for_destination (&mask, surface, &dev_mask.base); - if (status) + if (unlikely (status)) goto CLEANUP_SOURCE; if (surface->backend->mask) { - status = surface->backend->mask (surface, op, source, mask); + status = surface->backend->mask (surface, op, source, mask, extents); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto CLEANUP_MASK; } @@ -1564,7 +1740,8 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, cairo_matrix_t *stroke_ctm, cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, - cairo_antialias_t stroke_antialias) + cairo_antialias_t stroke_antialias, + cairo_rectangle_int_t *extents) { cairo_status_t status; @@ -1580,13 +1757,13 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, status = _cairo_surface_copy_pattern_for_destination (&stroke_source, surface, &dev_stroke_source.base); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (surface, status); status = _cairo_surface_copy_pattern_for_destination (&fill_source, surface, &dev_fill_source.base); - if (status) { + if (unlikely (status)) { if (stroke_source == &dev_stroke_source.base) _cairo_pattern_fini (&dev_stroke_source.base); @@ -1600,7 +1777,8 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, stroke_op, stroke_source, stroke_style, &dev_ctm, &dev_ctm_inverse, - stroke_tolerance, stroke_antialias); + stroke_tolerance, stroke_antialias, + extents); if (stroke_source == &dev_stroke_source.base) _cairo_pattern_fini (&dev_stroke_source.base); @@ -1613,14 +1791,14 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, } status = _cairo_surface_fill (surface, fill_op, fill_source, path, - fill_rule, fill_tolerance, fill_antialias); - if (status) + fill_rule, fill_tolerance, fill_antialias, NULL); + if (unlikely (status)) return _cairo_surface_set_error (surface, status); status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path, stroke_style, stroke_ctm, stroke_ctm_inverse, - stroke_tolerance, stroke_antialias); - if (status) + stroke_tolerance, stroke_antialias, NULL); + if (unlikely (status)) return _cairo_surface_set_error (surface, status); return CAIRO_STATUS_SUCCESS; @@ -1635,7 +1813,8 @@ _cairo_surface_stroke (cairo_surface_t *surface, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_status_t status; cairo_pattern_union_t dev_source; @@ -1652,14 +1831,14 @@ _cairo_surface_stroke (cairo_surface_t *surface, status = _cairo_surface_copy_pattern_for_destination (&source, surface, &dev_source.base); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (surface, status); if (surface->backend->stroke) { status = surface->backend->stroke (surface, op, source, path, stroke_style, &dev_ctm, &dev_ctm_inverse, - tolerance, antialias); + tolerance, antialias, extents); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto FINISH; @@ -1687,7 +1866,8 @@ _cairo_surface_fill (cairo_surface_t *surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_status_t status; cairo_pattern_union_t dev_source; @@ -1700,13 +1880,13 @@ _cairo_surface_fill (cairo_surface_t *surface, status = _cairo_surface_copy_pattern_for_destination (&source, surface, &dev_source.base); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (surface, status); if (surface->backend->fill) { status = surface->backend->fill (surface, op, source, path, fill_rule, - tolerance, antialias); + tolerance, antialias, extents); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto FINISH; @@ -1773,6 +1953,59 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op, traps, num_traps)); } +cairo_span_renderer_t * +_cairo_surface_create_span_renderer (cairo_operator_t op, + const cairo_pattern_t *pattern, + cairo_surface_t *dst, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects) +{ + assert (! dst->is_snapshot); + + if (dst->status) + return _cairo_span_renderer_create_in_error (dst->status); + + if (dst->finished) + return _cairo_span_renderer_create_in_error (CAIRO_STATUS_SURFACE_FINISHED); + + if (dst->backend->create_span_renderer) { + return dst->backend->create_span_renderer (op, + pattern, dst, + antialias, + rects); + } + ASSERT_NOT_REACHED; + return _cairo_span_renderer_create_in_error (CAIRO_INT_STATUS_UNSUPPORTED); +} + +cairo_bool_t +_cairo_surface_check_span_renderer (cairo_operator_t op, + const cairo_pattern_t *pattern, + cairo_surface_t *dst, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects) +{ + cairo_int_status_t status; + + assert (! dst->is_snapshot); + + if (dst->status) + return FALSE; + + if (dst->finished) { + status = _cairo_surface_set_error (dst, CAIRO_STATUS_SURFACE_FINISHED); + return FALSE; + } + + if (dst->backend->check_span_renderer) { + return dst->backend->check_span_renderer (op, + pattern, dst, + antialias, + rects); + } + return FALSE; +} + /** * cairo_surface_copy_page: * @surface: a #cairo_surface_t @@ -1917,13 +2150,13 @@ _cairo_surface_reset_clip (cairo_surface_t *surface) CAIRO_FILL_RULE_WINDING, 0, CAIRO_ANTIALIAS_DEFAULT); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (surface, status); } if (surface->backend->set_clip_region != NULL) { status = surface->backend->set_clip_region (surface, NULL); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (surface, status); } @@ -1952,11 +2185,13 @@ _cairo_surface_set_clip_region (cairo_surface_t *surface, assert (surface->backend->set_clip_region != NULL); - surface->current_clip_serial = serial; - status = surface->backend->set_clip_region (surface, region); + if (unlikely (status)) + return _cairo_surface_set_error (surface, status); - return _cairo_surface_set_error (surface, status); + surface->current_clip_serial = serial; + + return CAIRO_STATUS_SUCCESS; } cairo_int_status_t @@ -1999,7 +2234,7 @@ _cairo_surface_set_clip_path_recursive (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; status = _cairo_surface_set_clip_path_recursive (surface, clip_path->prev); - if (status) + if (unlikely (status)) return status; return _cairo_surface_intersect_clip_path (surface, @@ -2038,11 +2273,11 @@ _cairo_surface_set_clip_path (cairo_surface_t *surface, CAIRO_FILL_RULE_WINDING, 0, CAIRO_ANTIALIAS_DEFAULT); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (surface, status); status = _cairo_surface_set_clip_path_recursive (surface, clip_path); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (surface, status); surface->current_clip_serial = serial; @@ -2258,7 +2493,8 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, const cairo_text_cluster_t *clusters, int num_clusters, cairo_text_cluster_flags_t cluster_flags, - cairo_scaled_font_t *scaled_font) + cairo_scaled_font_t *scaled_font, + cairo_rectangle_int_t *extents) { cairo_status_t status; cairo_scaled_font_t *dev_scaled_font = scaled_font; @@ -2275,7 +2511,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, status = _cairo_surface_copy_pattern_for_destination (&source, surface, &dev_source.base); - if (status) + if (unlikely (status)) return _cairo_surface_set_error (surface, status); if (_cairo_surface_has_device_transform (surface) && @@ -2294,7 +2530,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, &font_options); } status = cairo_scaled_font_status (dev_scaled_font); - if (status) { + if (unlikely (status)) { if (source == &dev_source.base) _cairo_pattern_fini (&dev_source.base); @@ -2314,7 +2550,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags, - dev_scaled_font); + dev_scaled_font, extents); } if (status == CAIRO_INT_STATUS_UNSUPPORTED && surface->backend->show_glyphs) { int remaining_glyphs = num_glyphs; @@ -2322,7 +2558,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, source, glyphs, num_glyphs, dev_scaled_font, - &remaining_glyphs); + &remaining_glyphs, extents); glyphs += num_glyphs - remaining_glyphs; num_glyphs = remaining_glyphs; if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0) @@ -2336,7 +2572,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, source, glyphs, num_glyphs, dev_scaled_font, - &remaining_glyphs); + &remaining_glyphs, extents); glyphs += num_glyphs - remaining_glyphs; num_glyphs = remaining_glyphs; if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0) @@ -2355,7 +2591,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags, - dev_scaled_font); + dev_scaled_font, extents); } } @@ -2461,7 +2697,7 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst, status = _cairo_region_subtract (&clear_region, &clear_region, &drawn_region); - if (status) + if (unlikely (status)) goto CLEANUP_REGIONS; EMPTY: @@ -2650,7 +2886,7 @@ _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t **pattern, return CAIRO_STATUS_SUCCESS; status = _cairo_pattern_init_copy (pattern_copy, *pattern); - if (status) + if (unlikely (status)) return status; _cairo_pattern_transform (pattern_copy, diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index a50f13b8..cfd9a2d5 100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -43,12 +43,13 @@ #include "cairoint.h" #include "cairo-svg.h" #include "cairo-analysis-surface-private.h" -#include "cairo-svg-surface-private.h" +#include "cairo-image-info-private.h" #include "cairo-meta-surface-private.h" #include "cairo-output-stream-private.h" #include "cairo-path-fixed-private.h" #include "cairo-paginated-private.h" #include "cairo-scaled-font-subsets-private.h" +#include "cairo-svg-surface-private.h" typedef struct cairo_svg_page cairo_svg_page_t; @@ -284,7 +285,7 @@ cairo_svg_surface_restrict_to_version (cairo_surface_t *abstract_surface, cairo_status_t status; status = _extract_svg_surface (abstract_surface, &surface); - if (status) { + if (unlikely (status)) { status = _cairo_surface_set_error (abstract_surface, status); return; } @@ -346,7 +347,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document, cairo_status_t status, status_ignored; surface = malloc (sizeof (cairo_svg_surface_t)); - if (surface == NULL) + if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); _cairo_surface_init (&surface->base, &cairo_svg_surface_backend, @@ -365,7 +366,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document, surface->xml_node = _cairo_memory_stream_create (); status = _cairo_output_stream_get_status (surface->xml_node); - if (status) + if (unlikely (status)) goto CLEANUP; _cairo_array_init (&surface->page_set, sizeof (cairo_svg_page_t)); @@ -377,7 +378,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document, "fill:rgb(0,0,0);\"/>\n", width, height); status = _cairo_output_stream_get_status (surface->xml_node); - if (status) + if (unlikely (status)) goto CLEANUP; } @@ -420,7 +421,7 @@ _cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t *stream, status = _cairo_svg_document_create (stream, width, height, version, &document); - if (status) { + if (unlikely (status)) { surface = _cairo_surface_create_in_error (status); /* consume the output stream on behalf of caller */ status = _cairo_output_stream_destroy (stream); @@ -481,7 +482,7 @@ _cairo_svg_surface_copy_page (void *abstract_surface) cairo_svg_page_t *page; page = _cairo_svg_surface_store_page (surface); - if (page == NULL) + if (unlikely (page == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_memory_stream_copy (page->xml_node, surface->xml_node); @@ -495,7 +496,7 @@ _cairo_svg_surface_show_page (void *abstract_surface) { cairo_svg_surface_t *surface = abstract_surface; - if (_cairo_svg_surface_store_page (surface) == NULL) + if (unlikely (_cairo_svg_surface_store_page (surface) == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_SUCCESS; @@ -613,7 +614,7 @@ _cairo_svg_surface_emit_path (cairo_output_stream_t *output, _cairo_svg_path_curve_to, _cairo_svg_path_close_path, &info); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (output, "\""); @@ -634,14 +635,14 @@ _cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t *document, CAIRO_SCALED_GLYPH_INFO_METRICS| CAIRO_SCALED_GLYPH_INFO_PATH, &scaled_glyph); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (document->xml_node_glyphs, "<path style=\"stroke:none;\" "); status = _cairo_svg_surface_emit_path (document->xml_node_glyphs, scaled_glyph->path, NULL); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (document->xml_node_glyphs, @@ -667,7 +668,7 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document, CAIRO_SCALED_GLYPH_INFO_METRICS| CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); - if (status) + if (unlikely (status)) return status; image = scaled_glyph->surface; @@ -723,7 +724,7 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t *document, status = _cairo_svg_document_emit_bitmap_glyph_data (document, scaled_font, scaled_font_glyph_index); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (document->xml_node_glyphs, "</symbol>\n"); @@ -745,7 +746,7 @@ _cairo_svg_document_emit_font_subset (cairo_scaled_font_subset_t *font_subset, font_subset->scaled_font, font_subset->glyphs[i], font_subset->font_id, i); - if (status) + if (unlikely (status)) break; } _cairo_scaled_font_thaw_cache (font_subset->scaled_font); @@ -761,7 +762,7 @@ _cairo_svg_document_emit_font_subsets (cairo_svg_document_t *document) status = _cairo_scaled_font_subsets_foreach_scaled (document->font_subsets, _cairo_svg_document_emit_font_subset, document); - if (status) + if (unlikely (status)) goto FAIL; status = _cairo_scaled_font_subsets_foreach_user (document->font_subsets, @@ -976,12 +977,92 @@ base64_write_func (void *closure, } static cairo_int_status_t +_cairo_surface_base64_encode_jpeg (cairo_surface_t *surface, + cairo_output_stream_t *output) +{ + const unsigned char *mime_data; + unsigned int mime_data_length; + cairo_image_info_t image_info; + base64_write_closure_t info; + cairo_status_t status; + + cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_JPEG, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_image_info_get_jpeg_info (&image_info, mime_data, mime_data_length); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (output, "data:image/jpeg;base64,"); + + info.output = output; + info.in_mem = 0; + info.trailing = 0; + + status = base64_write_func (&info, mime_data, mime_data_length); + if (unlikely (status)) + return status; + + if (info.in_mem > 0) { + memset (info.src + info.in_mem, 0, 3 - info.in_mem); + info.trailing = 3 - info.in_mem; + info.in_mem = 3; + status = base64_write_func (&info, NULL, 0); + } + + return status; +} + +static cairo_int_status_t +_cairo_surface_base64_encode_png (cairo_surface_t *surface, + cairo_output_stream_t *output) +{ + const unsigned char *mime_data; + unsigned int mime_data_length; + base64_write_closure_t info; + cairo_status_t status; + + cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_PNG, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_output_stream_printf (output, "data:image/png;base64,"); + + info.output = output; + info.in_mem = 0; + info.trailing = 0; + + status = base64_write_func (&info, mime_data, mime_data_length); + if (unlikely (status)) + return status; + + if (info.in_mem > 0) { + memset (info.src + info.in_mem, 0, 3 - info.in_mem); + info.trailing = 3 - info.in_mem; + info.in_mem = 3; + status = base64_write_func (&info, NULL, 0); + } + + return status; +} + +static cairo_int_status_t _cairo_surface_base64_encode (cairo_surface_t *surface, cairo_output_stream_t *output) { cairo_status_t status; base64_write_closure_t info; - unsigned int i; + + status = _cairo_surface_base64_encode_jpeg (surface, output); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_surface_base64_encode_png (surface, output); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; info.output = output; info.in_mem = 0; @@ -992,12 +1073,11 @@ _cairo_surface_base64_encode (cairo_surface_t *surface, status = cairo_surface_write_to_png_stream (surface, base64_write_func, (void *) &info); - if (status) + if (unlikely (status)) return status; if (info.in_mem > 0) { - for (i = info.in_mem; i < 3; i++) - info.src[i] = '\x0'; + memset (info.src + info.in_mem, 0, 3 - info.in_mem); info.trailing = 3 - info.in_mem; info.in_mem = 3; status = base64_write_func (&info, NULL, 0); @@ -1046,7 +1126,7 @@ _cairo_svg_surface_emit_composite_image_pattern (cairo_output_stream_t *output cairo_matrix_t p2u; status = _cairo_surface_get_extents (pattern->surface, &extents); - if (status) + if (unlikely (status)) return status; p2u = pattern->base.matrix; @@ -1134,7 +1214,7 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, document->owner->y_fallback_resolution); status = _cairo_meta_surface_replay (&meta->base, paginated_surface); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (&meta->base); cairo_surface_destroy (paginated_surface); return status; @@ -1142,7 +1222,7 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, cairo_surface_show_page (paginated_surface); status = cairo_surface_status (paginated_surface); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (&meta->base); cairo_surface_destroy (paginated_surface); return status; @@ -1151,7 +1231,7 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, new_snapshot.meta = meta; new_snapshot.id = svg_surface->id; status = _cairo_array_append (&document->meta_snapshots, &new_snapshot); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (&meta->base); cairo_surface_destroy (paginated_surface); return status; @@ -1188,7 +1268,7 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, page_set = &svg_surface->page_set; if (_cairo_memory_stream_length (contents) > 0) { - if (_cairo_svg_surface_store_page (svg_surface) == NULL) { + if (unlikely (_cairo_svg_surface_store_page (svg_surface) == NULL)) { cairo_surface_destroy (paginated_surface); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -1241,7 +1321,7 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output, meta_surface = (cairo_meta_surface_t *) pattern->surface; status = _cairo_svg_surface_emit_meta_surface (document, meta_surface, &id); - if (status) + if (unlikely (status)) return status; if (pattern_id != invalid_pattern_id) { @@ -1327,7 +1407,7 @@ _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t *surface, status = _cairo_svg_surface_emit_composite_pattern (document->xml_node_defs, surface, CAIRO_OPERATOR_SOURCE, pattern, pattern_id, parent_matrix, NULL); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (style, @@ -1369,7 +1449,7 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output, if (emulate_reflect || reverse_stops) { n_stops = emulate_reflect ? pattern->n_stops * 2 - 2: pattern->n_stops; stops = _cairo_malloc_ab (n_stops, sizeof (cairo_gradient_stop_t)); - if (stops == NULL) + if (unlikely (stops == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); for (i = 0; i < pattern->n_stops; i++) { @@ -1554,7 +1634,7 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface, status = _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs, &pattern->base, 0.0, FALSE, FALSE); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (document->xml_node_defs, @@ -1732,7 +1812,7 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface, &pattern->base, offset, reverse_stops, emulate_reflect); - if (status) + if (unlikely (status)) return status; if (pattern->base.base.extend == CAIRO_EXTEND_NONE) @@ -1847,7 +1927,7 @@ _cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output, line_join); status = _cairo_svg_surface_emit_pattern (surface, source, output, TRUE, parent_matrix); - if (status) + if (unlikely (status)) return status; _cairo_svg_surface_emit_operator_for_style (output, surface, op); @@ -1890,7 +1970,8 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface, cairo_matrix_t *stroke_ctm, cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, - cairo_antialias_t stroke_antialias) + cairo_antialias_t stroke_antialias, + cairo_rectangle_int_t *extents) { cairo_svg_surface_t *surface = abstract_surface; cairo_status_t status; @@ -1898,18 +1979,18 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface, _cairo_output_stream_printf (surface->xml_node, "<path style=\""); status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, fill_op, fill_source, fill_rule, stroke_ctm_inverse); - if (status) + if (unlikely (status)) return status; status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, stroke_op, stroke_source, stroke_style, stroke_ctm_inverse); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->xml_node, "\" "); status = _cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse); - if (status) + if (unlikely (status)) return status; _cairo_svg_surface_emit_transform (surface->xml_node, " transform", stroke_ctm, NULL); @@ -1925,7 +2006,8 @@ _cairo_svg_surface_fill (void *abstract_surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_svg_surface_t *surface = abstract_surface; cairo_status_t status; @@ -1937,13 +2019,13 @@ _cairo_svg_surface_fill (void *abstract_surface, _cairo_output_stream_printf (surface->xml_node, "<path style=\" stroke:none;"); status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule, NULL); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->xml_node, "\" "); status = _cairo_svg_surface_emit_path (surface->xml_node, path, NULL); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->xml_node, "/>\n"); @@ -1997,7 +2079,7 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output, surface->width, surface->height); _cairo_svg_surface_emit_operator_for_style (output, surface, op); status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (output, "stroke:none;\""); @@ -2013,7 +2095,8 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output, static cairo_int_status_t _cairo_svg_surface_paint (void *abstract_surface, cairo_operator_t op, - const cairo_pattern_t *source) + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents) { cairo_status_t status; cairo_svg_surface_t *surface = abstract_surface; @@ -2033,7 +2116,7 @@ _cairo_svg_surface_paint (void *abstract_surface, * and an optimization in meta surface. */ if (surface->clip_level == 0 && op == CAIRO_OPERATOR_CLEAR) { status = _cairo_output_stream_destroy (surface->xml_node); - if (status) { + if (unlikely (status)) { surface->xml_node = NULL; return status; } @@ -2065,9 +2148,10 @@ _cairo_svg_surface_paint (void *abstract_surface, static cairo_int_status_t _cairo_svg_surface_mask (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_pattern_t *mask) + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_rectangle_int_t *extents) { cairo_status_t status; cairo_svg_surface_t *surface = abstract_surface; @@ -2120,7 +2204,7 @@ _cairo_svg_surface_mask (void *abstract_surface, mask_id, discard_filter ? "" : " <g filter=\"url(#alpha)\">\n"); status = _cairo_svg_surface_emit_paint (mask_stream, surface, CAIRO_OPERATOR_OVER, mask, source, NULL); - if (status) { + if (unlikely (status)) { cairo_status_t ignore = _cairo_output_stream_destroy (mask_stream); return status; (void) ignore; @@ -2133,13 +2217,13 @@ _cairo_svg_surface_mask (void *abstract_surface, _cairo_memory_stream_copy (mask_stream, document->xml_node_defs); status = _cairo_output_stream_destroy (mask_stream); - if (status) + if (unlikely (status)) return status; snprintf (buffer, sizeof buffer, "mask=\"url(#mask%d)\"", mask_id); status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, op, source, 0, buffer); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -2154,7 +2238,8 @@ _cairo_svg_surface_stroke (void *abstract_dst, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_svg_surface_t *surface = abstract_dst; cairo_status_t status; @@ -2167,13 +2252,13 @@ _cairo_svg_surface_stroke (void *abstract_dst, _cairo_output_stream_printf (surface->xml_node, "<path style=\"fill:none;"); status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, op, source, stroke_style, ctm_inverse); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->xml_node, "\" "); status = _cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse); - if (status) + if (unlikely (status)) return status; _cairo_svg_surface_emit_transform (surface->xml_node, " transform", ctm, NULL); @@ -2189,7 +2274,8 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs) + int *remaining_glyphs, + cairo_rectangle_int_t *extents) { cairo_svg_surface_t *surface = abstract_surface; cairo_svg_document_t *document = surface->document; @@ -2215,7 +2301,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, _cairo_output_stream_printf (surface->xml_node, "<g style=\""); status = _cairo_svg_surface_emit_pattern (surface, pattern, surface->xml_node, FALSE, NULL); - if (status) + if (unlikely (status)) return status; _cairo_svg_surface_emit_operator_for_style (surface->xml_node, surface, op); @@ -2235,7 +2321,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, goto FALLBACK; } - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->xml_node, @@ -2255,13 +2341,13 @@ FALLBACK: status = _cairo_scaled_font_glyph_path (scaled_font,(cairo_glyph_t *) glyphs, num_glyphs, &path); - if (status) { + if (unlikely (status)) { _cairo_path_fixed_fini (&path); return status; } status = _cairo_svg_surface_fill (abstract_surface, op, pattern, - &path, CAIRO_FILL_RULE_WINDING, 0.0, CAIRO_ANTIALIAS_SUBPIXEL); + &path, CAIRO_FILL_RULE_WINDING, 0.0, CAIRO_ANTIALIAS_SUBPIXEL, NULL); _cairo_path_fixed_fini (&path); @@ -2293,7 +2379,7 @@ _cairo_svg_surface_intersect_clip_path (void *dst, " <path ", document->clip_id); status = _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (document->xml_node_defs, @@ -2336,6 +2422,8 @@ static const cairo_surface_backend_t cairo_svg_surface_backend = { NULL, /* _cairo_svg_surface_composite, */ NULL, /* _cairo_svg_surface_fill_rectangles, */ NULL, /* _cairo_svg_surface_composite_trapezoids,*/ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ _cairo_svg_surface_copy_page, _cairo_svg_surface_show_page, NULL, /* set_clip_region */ @@ -2372,12 +2460,12 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream, return output_stream->status; document = malloc (sizeof (cairo_svg_document_t)); - if (document == NULL) + if (unlikely (document == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); /* The use of defs for font glyphs imposes no per-subset limit. */ document->font_subsets = _cairo_scaled_font_subsets_create_scaled (); - if (document->font_subsets == NULL) { + if (unlikely (document->font_subsets == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_DOCUMENT; } @@ -2399,12 +2487,12 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream, document->xml_node_defs = _cairo_memory_stream_create (); status = _cairo_output_stream_get_status (document->xml_node_defs); - if (status) + if (unlikely (status)) goto CLEANUP_NODE_DEFS; document->xml_node_glyphs = _cairo_memory_stream_create (); status = _cairo_output_stream_get_status (document->xml_node_glyphs); - if (status) + if (unlikely (status)) goto CLEANUP_NODE_GLYPHS; document->alpha_filter = FALSE; @@ -2521,7 +2609,7 @@ _cairo_svg_document_finish (cairo_svg_document_t *document) surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner); if (surface->xml_node != NULL && _cairo_memory_stream_length (surface->xml_node) > 0) { - if (_cairo_svg_surface_store_page (surface) == NULL) { + if (unlikely (_cairo_svg_surface_store_page (surface) == NULL)) { if (status == CAIRO_STATUS_SUCCESS) status = _cairo_error (CAIRO_STATUS_NO_MEMORY); } diff --git a/src/cairo-tor-scan-converter.c b/src/cairo-tor-scan-converter.c new file mode 100644 index 00000000..20104a7f --- /dev/null +++ b/src/cairo-tor-scan-converter.c @@ -0,0 +1,2003 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* glitter-paths - polygon scan converter + * + * Copyright (c) 2008 M Joonas Pihlaja + * Copyright (c) 2007 David Turner + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/* This is the Glitter paths scan converter incorporated into cairo. + * The source is from commit 734c53237a867a773640bd5b64816249fa1730f8 + * of + * + * http://gitweb.freedesktop.org/?p=users/joonas/glitter-paths + */ +/* Glitter-paths is a stand alone polygon rasteriser derived from + * David Turner's reimplementation of Tor Anderssons's 15x17 + * supersampling rasteriser from the Apparition graphics library. The + * main new feature here is cheaply choosing per-scan line between + * doing fully analytical coverage computation for an entire row at a + * time vs. using a supersampling approach. + * + * David Turner's code can be found at + * + * http://david.freetype.org/rasterizer-shootout/raster-comparison-20070813.tar.bz2 + * + * In particular this file incorporates large parts of ftgrays_tor10.h + * from raster-comparison-20070813.tar.bz2 + */ +/* Overview + * + * A scan converter's basic purpose to take polygon edges and convert + * them into an RLE compressed A8 mask. This one works in two phases: + * gathering edges and generating spans. + * + * 1) As the user feeds the scan converter edges they are vertically + * clipped and bucketted into a _polygon_ data structure. The edges + * are also snapped from the user's coordinates to the subpixel grid + * coordinates used during scan conversion. + * + * user + * | + * | edges + * V + * polygon buckets + * + * 2) Generating spans works by performing a vertical sweep of pixel + * rows from top to bottom and maintaining an _active_list_ of edges + * that intersect the row. From the active list the fill rule + * determines which edges are the left and right edges of the start of + * each span, and their contribution is then accumulated into a pixel + * coverage list (_cell_list_) as coverage deltas. Once the coverage + * deltas of all edges are known we can form spans of constant pixel + * coverage by summing the deltas during a traversal of the cell list. + * At the end of a pixel row the cell list is sent to a coverage + * blitter for rendering to some target surface. + * + * The pixel coverages are computed by either supersampling the row + * and box filtering a mono rasterisation, or by computing the exact + * coverages of edges in the active list. The supersampling method is + * used whenever some edge starts or stops within the row or there are + * edge intersections in the row. + * + * polygon bucket for \ + * current pixel row | + * | | + * | activate new edges | Repeat GRID_Y times if we + * V \ are supersampling this row, + * active list / or just once if we're computing + * | | analytical coverage. + * | coverage deltas | + * V | + * pixel coverage list / + * | + * V + * coverage blitter + */ +#include "cairoint.h" +#include "cairo-spans-private.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +/*------------------------------------------------------------------------- + * cairo specific config + */ +#define I static + +/* Prefer cairo's status type. */ +#define GLITTER_HAVE_STATUS_T 1 +#define GLITTER_STATUS_SUCCESS CAIRO_STATUS_SUCCESS +#define GLITTER_STATUS_NO_MEMORY CAIRO_STATUS_NO_MEMORY +typedef cairo_status_t glitter_status_t; + +/* The input coordinate scale and the rasterisation grid scales. */ +#define GLITTER_INPUT_BITS CAIRO_FIXED_FRAC_BITS +#define GRID_X_BITS CAIRO_FIXED_FRAC_BITS +#define GRID_Y 15 + +/* Set glitter up to use a cairo span renderer to do the coverage + * blitting. */ +struct pool; +struct cell_list; + +static glitter_status_t +blit_with_span_renderer( + struct cell_list *coverages, + cairo_span_renderer_t *span_renderer, + struct pool *span_pool, + int y, + int xmin, + int xmax); + +#define GLITTER_BLIT_COVERAGES_ARGS \ + cairo_span_renderer_t *span_renderer, \ + struct pool *span_pool + +#define GLITTER_BLIT_COVERAGES(cells, y, xmin, xmax) do { \ + cairo_status_t status = blit_with_span_renderer (cells, \ + span_renderer, \ + span_pool, \ + y, xmin, xmax); \ + if (unlikely (status)) \ + return status; \ +} while (0) + +/*------------------------------------------------------------------------- + * glitter-paths.h + */ + +/* "Input scaled" numbers are fixed precision reals with multiplier + * 2**GLITTER_INPUT_BITS. Input coordinates are given to glitter as + * pixel scaled numbers. These get converted to the internal grid + * scaled numbers as soon as possible. Internal overflow is possible + * if GRID_X/Y inside glitter-paths.c is larger than + * 1<<GLITTER_INPUT_BITS. */ +#ifndef GLITTER_INPUT_BITS +# define GLITTER_INPUT_BITS 8 +#endif +#define GLITTER_INPUT_SCALE (1<<GLITTER_INPUT_BITS) +typedef int glitter_input_scaled_t; + +#if !GLITTER_HAVE_STATUS_T +typedef enum { + GLITTER_STATUS_SUCCESS = 0, + GLITTER_STATUS_NO_MEMORY +} glitter_status_t; +#endif + +#ifndef I +# define I /*static*/ +#endif + +/* Opaque type for scan converting. */ +typedef struct glitter_scan_converter glitter_scan_converter_t; + +/* Reset a scan converter to accept polygon edges and set the clip box + * in pixels. Allocates O(ymax-ymin) bytes of memory. The clip box + * is set to integer pixel coordinates xmin <= x < xmax, ymin <= y < + * ymax. */ +I glitter_status_t +glitter_scan_converter_reset( + glitter_scan_converter_t *converter, + int xmin, int ymin, + int xmax, int ymax); + +/* Add a new polygon edge from pixel (x1,y1) to (x2,y2) to the scan + * converter. The coordinates represent pixel positions scaled by + * 2**GLITTER_PIXEL_BITS. If this function fails then the scan + * converter should be reset or destroyed. Dir must be +1 or -1, + * with the latter reversing the orientation of the edge. */ +I glitter_status_t +glitter_scan_converter_add_edge( + glitter_scan_converter_t *converter, + glitter_input_scaled_t x1, glitter_input_scaled_t y1, + glitter_input_scaled_t x2, glitter_input_scaled_t y2, + int dir); + +/* Render the polygon in the scan converter to the given A8 format + * image raster. Only the pixels accessible as pixels[y*stride+x] for + * x,y inside the clip box are written to, where xmin <= x < xmax, + * ymin <= y < ymax. The image is assumed to be clear on input. + * + * If nonzero_fill is true then the interior of the polygon is + * computed with the non-zero fill rule. Otherwise the even-odd fill + * rule is used. + * + * The scan converter must be reset or destroyed after this call. */ +#ifndef GLITTER_BLIT_COVERAGES_ARGS +# define GLITTER_BLIT_COVERAGES_ARGS unsigned char *raster_pixels, long raster_stride +#endif +I glitter_status_t +glitter_scan_converter_render( + glitter_scan_converter_t *converter, + int nonzero_fill, + GLITTER_BLIT_COVERAGES_ARGS); + +/*------------------------------------------------------------------------- + * glitter-paths.c: Implementation internal types + */ +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +/* All polygon coordinates are snapped onto a subsample grid. "Grid + * scaled" numbers are fixed precision reals with multiplier GRID_X or + * GRID_Y. */ +typedef int grid_scaled_t; +typedef int grid_scaled_x_t; +typedef int grid_scaled_y_t; + +/* Default x/y scale factors. + * You can either define GRID_X/Y_BITS to get a power-of-two scale + * or define GRID_X/Y separately. */ +#if !defined(GRID_X) && !defined(GRID_X_BITS) +# define GRID_X_BITS 8 +#endif +#if !defined(GRID_Y) && !defined(GRID_Y_BITS) +# define GRID_Y 15 +#endif + +/* Use GRID_X/Y_BITS to define GRID_X/Y if they're available. */ +#ifdef GRID_X_BITS +# define GRID_X (1 << GRID_X_BITS) +#endif +#ifdef GRID_Y_BITS +# define GRID_Y (1 << GRID_Y_BITS) +#endif + +/* The GRID_X_TO_INT_FRAC macro splits a grid scaled coordinate into + * integer and fractional parts. The integer part is floored. */ +#if defined(GRID_X_TO_INT_FRAC) + /* do nothing */ +#elif defined(GRID_X_BITS) +# define GRID_X_TO_INT_FRAC(x, i, f) \ + _GRID_TO_INT_FRAC_shift(x, i, f, GRID_X_BITS) +#else +# define GRID_X_TO_INT_FRAC(x, i, f) \ + _GRID_TO_INT_FRAC_general(x, i, f, GRID_X) +#endif + +#define _GRID_TO_INT_FRAC_general(t, i, f, m) do { \ + (i) = (t) / (m); \ + (f) = (t) % (m); \ + if ((f) < 0) { \ + --(i); \ + (f) += (m); \ + } \ +} while (0) + +#define _GRID_TO_INT_FRAC_shift(t, i, f, b) do { \ + (f) = (t) & ((1 << (b)) - 1); \ + (i) = (t) >> (b); \ +} while (0) + +/* A grid area is a real in [0,1] scaled by 2*GRID_X*GRID_Y. We want + * to be able to represent exactly areas of subpixel trapezoids whose + * vertices are given in grid scaled coordinates. The scale factor + * comes from needing to accurately represent the area 0.5*dx*dy of a + * triangle with base dx and height dy in grid scaled numbers. */ +typedef int grid_area_t; +#define GRID_XY (2*GRID_X*GRID_Y) /* Unit area on the grid. */ + +/* GRID_AREA_TO_ALPHA(area): map [0,GRID_XY] to [0,255]. */ +#if GRID_XY == 510 +# define GRID_AREA_TO_ALPHA(c) (((c)+1) >> 1) +#elif GRID_XY == 255 +# define GRID_AREA_TO_ALPHA(c) (c) +#elif GRID_XY == 64 +# define GRID_AREA_TO_ALPHA(c) (((c) << 2) | -(((c) & 0x40) >> 6)) +#elif GRID_XY == 128 +# define GRID_AREA_TO_ALPHA(c) ((((c) << 1) | -((c) >> 7)) & 255) +#elif GRID_XY == 256 +# define GRID_AREA_TO_ALPHA(c) (((c) | -((c) >> 8)) & 255) +#elif GRID_XY == 15 +# define GRID_AREA_TO_ALPHA(c) (((c) << 4) + (c)) +#elif GRID_XY == 2*256*15 +# define GRID_AREA_TO_ALPHA(c) (((c) + ((c)<<4)) >> 9) +#else +# define GRID_AREA_TO_ALPHA(c) ((c)*255 / GRID_XY) /* tweak me for rounding */ +#endif + +#define UNROLL3(x) x x x + +struct quorem { + int quo; + int rem; +}; + +/* Header for a chunk of memory in a memory pool. */ +struct _pool_chunk { + /* # bytes used in this chunk. */ + size_t size; + + /* # bytes total in this chunk */ + size_t capacity; + + /* Pointer to the previous chunk or %NULL if this is the sentinel + * chunk in the pool header. */ + struct _pool_chunk *prev_chunk; + + /* Actual data starts here. Well aligned for pointers. */ + unsigned char data[0]; +}; + +/* A memory pool. This is supposed to be embedded on the stack or + * within some other structure. It may optionally be followed by an + * embedded array from which requests are fulfilled until + * malloc needs to be called to allocate a first real chunk. */ +struct pool { + /* Chunk we're allocating from. */ + struct _pool_chunk *current; + + /* Free list of previously allocated chunks. All have >= default + * capacity. */ + struct _pool_chunk *first_free; + + /* The default capacity of a chunk. */ + size_t default_capacity; + + /* Header for the sentinel chunk. Directly following the pool + * struct should be some space for embedded elements from which + * the sentinel chunk allocates from. */ + struct _pool_chunk sentinel[1]; +}; + +/* A polygon edge. */ +struct edge { + /* Next in y-bucket or active list. */ + struct edge *next; + + /* Current x coordinate while the edge is on the active + * list. Initialised to the x coordinate of the top of the + * edge. The quotient is in grid_scaled_x_t units and the + * remainder is mod dy in grid_scaled_y_t units.*/ + struct quorem x; + + /* Advance of the current x when moving down a subsample line. */ + struct quorem dxdy; + + /* Advance of the current x when moving down a full pixel + * row. Only initialised when the height of the edge is large + * enough that there's a chance the edge could be stepped by a + * full row's worth of subsample rows at a time. */ + struct quorem dxdy_full; + + /* The clipped y of the top of the edge. */ + grid_scaled_y_t ytop; + + /* y2-y1 after orienting the edge downwards. */ + grid_scaled_y_t dy; + + /* Number of subsample rows remaining to scan convert of this + * edge. */ + grid_scaled_y_t height_left; + + /* Original sign of the edge: +1 for downwards, -1 for upwards + * edges. */ + int dir; +}; + +/* Number of subsample rows per y-bucket. Must be GRID_Y. */ +#define EDGE_Y_BUCKET_HEIGHT GRID_Y + +#define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/EDGE_Y_BUCKET_HEIGHT) + +/* A collection of sorted and vertically clipped edges of the polygon. + * Edges are moved from the polygon to an active list while scan + * converting. */ +struct polygon { + /* The vertical clip extents. */ + grid_scaled_y_t ymin, ymax; + + /* Array of edges all starting in the same bucket. An edge is put + * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when + * it is added to the polygon. */ + struct edge **y_buckets; + + struct { + struct pool base[1]; + struct edge embedded[32]; + } edge_pool; +}; + +/* A cell records the effect on pixel coverage of polygon edges + * passing through a pixel. It contains two accumulators of pixel + * coverage. + * + * Consider the effects of a polygon edge on the coverage of a pixel + * it intersects and that of the following one. The coverage of the + * following pixel is the height of the edge multiplied by the width + * of the pixel, and the coverage of the pixel itself is the area of + * the trapezoid formed by the edge and the right side of the pixel. + * + * +-----------------------+-----------------------+ + * | | | + * | | | + * |_______________________|_______________________| + * | \...................|.......................|\ + * | \..................|.......................| | + * | \.................|.......................| | + * | \....covered.....|.......................| | + * | \....area.......|.......................| } covered height + * | \..............|.......................| | + * |uncovered\.............|.......................| | + * | area \............|.......................| | + * |___________\...........|.......................|/ + * | | | + * | | | + * | | | + * +-----------------------+-----------------------+ + * + * Since the coverage of the following pixel will always be a multiple + * of the width of the pixel, we can store the height of the covered + * area instead. The coverage of the pixel itself is the total + * coverage minus the area of the uncovered area to the left of the + * edge. As it's faster to compute the uncovered area we only store + * that and subtract it from the total coverage later when forming + * spans to blit. + * + * The heights and areas are signed, with left edges of the polygon + * having positive sign and right edges having negative sign. When + * two edges intersect they swap their left/rightness so their + * contribution above and below the intersection point must be + * computed separately. */ +struct cell { + struct cell *next; + int x; + grid_area_t uncovered_area; + grid_scaled_y_t covered_height; +}; + +/* A cell list represents the scan line sparsely as cells ordered by + * ascending x. It is geared towards scanning the cells in order + * using an internal cursor. */ +struct cell_list { + /* Points to the left-most cell in the scan line. */ + struct cell *head; + + /* Cursor state for iterating through the cell list. Points to + * a pointer to the current cell: either &cell_list->head or the next + * field of the previous cell. */ + struct cell **cursor; + + /* Cells in the cell list are owned by the cell list and are + * allocated from this pool. */ + struct { + struct pool base[1]; + struct cell embedded[32]; + } cell_pool; +}; + +struct cell_pair { + struct cell *cell1; + struct cell *cell2; +}; + +/* The active list contains edges in the current scan line ordered by + * the x-coordinate of the intercept of the edge and the scan line. */ +struct active_list { + /* Leftmost edge on the current scan line. */ + struct edge *head; + + /* A lower bound on the height of the active edges is used to + * estimate how soon some active edge ends. We can't advance the + * scan conversion by a full pixel row if an edge ends somewhere + * within it. */ + grid_scaled_y_t min_height; +}; + +struct glitter_scan_converter { + struct polygon polygon[1]; + struct active_list active[1]; + struct cell_list coverages[1]; + + /* Clip box. */ + grid_scaled_x_t xmin, xmax; + grid_scaled_y_t ymin, ymax; +}; + +/* Compute the floored division a/b. Assumes / and % perform symmetric + * division. */ +inline static struct quorem +floored_divrem(int a, int b) +{ + struct quorem qr; + qr.quo = a/b; + qr.rem = a%b; + if ((a^b)<0 && qr.rem) { + qr.quo -= 1; + qr.rem += b; + } + return qr; +} + +/* Compute the floored division (x*a)/b. Assumes / and % perform symmetric + * division. */ +static struct quorem +floored_muldivrem(int x, int a, int b) +{ + struct quorem qr; + long long xa = (long long)x*a; + qr.quo = xa/b; + qr.rem = xa%b; + if ((xa>=0) != (b>=0) && qr.rem) { + qr.quo -= 1; + qr.rem += b; + } + return qr; +} + +static void +_pool_chunk_init( + struct _pool_chunk *p, + struct _pool_chunk *prev_chunk, + size_t capacity) +{ + p->prev_chunk = prev_chunk; + p->size = 0; + p->capacity = capacity; +} + +static struct _pool_chunk * +_pool_chunk_create( + struct _pool_chunk *prev_chunk, + size_t size) +{ + struct _pool_chunk *p; + size_t size_with_head = size + sizeof(struct _pool_chunk); + if (size_with_head < size) + return NULL; + p = malloc(size_with_head); + if (p) + _pool_chunk_init(p, prev_chunk, size); + return p; +} + +static void +pool_init( + struct pool *pool, + size_t default_capacity, + size_t embedded_capacity) +{ + pool->current = pool->sentinel; + pool->first_free = NULL; + pool->default_capacity = default_capacity; + _pool_chunk_init(pool->sentinel, NULL, embedded_capacity); +} + +static void +pool_fini(struct pool *pool) +{ + struct _pool_chunk *p = pool->current; + do { + while (NULL != p) { + struct _pool_chunk *prev = p->prev_chunk; + if (p != pool->sentinel) + free(p); + p = prev; + } + p = pool->first_free; + pool->first_free = NULL; + } while (NULL != p); + pool_init(pool, 0, 0); +} + +/* Satisfy an allocation by first allocating a new large enough chunk + * and adding it to the head of the pool's chunk list. This function + * is called as a fallback if pool_alloc() couldn't do a quick + * allocation from the current chunk in the pool. */ +static void * +_pool_alloc_from_new_chunk( + struct pool *pool, + size_t size) +{ + struct _pool_chunk *chunk; + void *obj; + size_t capacity; + + /* If the allocation is smaller than the default chunk size then + * try getting a chunk off the free list. Force alloc of a new + * chunk for large requests. */ + capacity = size; + chunk = NULL; + if (size < pool->default_capacity) { + capacity = pool->default_capacity; + chunk = pool->first_free; + if (chunk) { + pool->first_free = chunk->prev_chunk; + _pool_chunk_init(chunk, pool->current, chunk->capacity); + } + } + + if (NULL == chunk) { + chunk = _pool_chunk_create( + pool->current, + capacity); + if (NULL == chunk) + return NULL; + } + pool->current = chunk; + + obj = &chunk->data[chunk->size]; + chunk->size += size; + return obj; +} + +/* Allocate size bytes from the pool. The first allocated address + * returned from a pool is aligned to sizeof(void*). Subsequent + * addresses will maintain alignment as long as multiples of void* are + * allocated. Returns the address of a new memory area or %NULL on + * allocation failures. The pool retains ownership of the returned + * memory. */ +inline static void * +pool_alloc( + struct pool *pool, + size_t size) +{ + struct _pool_chunk *chunk = pool->current; + + if (size <= chunk->capacity - chunk->size) { + void *obj = &chunk->data[chunk->size]; + chunk->size += size; + return obj; + } + else { + return _pool_alloc_from_new_chunk(pool, size); + } +} + +/* Relinquish all pool_alloced memory back to the pool. */ +static void +pool_reset(struct pool *pool) +{ + /* Transfer all used chunks to the chunk free list. */ + struct _pool_chunk *chunk = pool->current; + if (chunk != pool->sentinel) { + while (chunk->prev_chunk != pool->sentinel) { + chunk = chunk->prev_chunk; + } + chunk->prev_chunk = pool->first_free; + pool->first_free = pool->current; + } + /* Reset the sentinel as the current chunk. */ + pool->current = pool->sentinel; + pool->sentinel->size = 0; +} + +/* Rewinds the cell list's cursor to the beginning. After rewinding + * we're good to cell_list_find() the cell any x coordinate. */ +inline static void +cell_list_rewind(struct cell_list *cells) +{ + cells->cursor = &cells->head; +} + +/* Rewind the cell list if its cursor has been advanced past x. */ +inline static void +cell_list_maybe_rewind(struct cell_list *cells, int x) +{ + struct cell *tail = *cells->cursor; + if (tail && tail->x > x) { + cell_list_rewind(cells); + } +} + +static void +cell_list_init(struct cell_list *cells) +{ + pool_init(cells->cell_pool.base, + 256*sizeof(struct cell), + sizeof(cells->cell_pool.embedded)); + cells->head = NULL; + cell_list_rewind(cells); +} + +static void +cell_list_fini(struct cell_list *cells) +{ + pool_fini(cells->cell_pool.base); + cell_list_init(cells); +} + +/* Empty the cell list. This is called at the start of every pixel + * row. */ +inline static void +cell_list_reset(struct cell_list *cells) +{ + cell_list_rewind(cells); + cells->head = NULL; + pool_reset(cells->cell_pool.base); +} + +/* Find a cell at the given x-coordinate. Returns %NULL if a new cell + * needed to be allocated but couldn't be. Cells must be found with + * non-decreasing x-coordinate until the cell list is rewound using + * cell_list_rewind(). Ownership of the returned cell is retained by + * the cell list. */ +inline static struct cell * +cell_list_find(struct cell_list *cells, int x) +{ + struct cell **cursor = cells->cursor; + struct cell *tail; + + while (1) { + UNROLL3({ + tail = *cursor; + if (NULL == tail || tail->x >= x) { + break; + } + cursor = &tail->next; + }); + } + cells->cursor = cursor; + if (tail && tail->x == x) { + return tail; + } else { + struct cell *cell = pool_alloc( + cells->cell_pool.base, + sizeof(struct cell)); + if (NULL == cell) + return NULL; + *cursor = cell; + cell->next = tail; + cell->x = x; + cell->uncovered_area = 0; + cell->covered_height = 0; + return cell; + } +} + +/* Find two cells at x1 and x2. This is exactly equivalent + * to + * + * pair.cell1 = cell_list_find(cells, x1); + * pair.cell2 = cell_list_find(cells, x2); + * + * except with less function call overhead. */ +inline static struct cell_pair +cell_list_find2(struct cell_list *cells, int x1, int x2) +{ + struct cell_pair pair; + struct cell **cursor = cells->cursor; + struct cell *cell1; + struct cell *cell2; + struct cell *newcell; + + /* Find first cell at x1. */ + while (1) { + UNROLL3({ + cell1 = *cursor; + if (NULL == cell1 || cell1->x > x1) + break; + if (cell1->x == x1) + goto found_first; + cursor = &cell1->next; + }); + } + + /* New first cell at x1. */ + newcell = pool_alloc( + cells->cell_pool.base, + sizeof(struct cell)); + if (NULL != newcell) { + *cursor = newcell; + newcell->next = cell1; + newcell->x = x1; + newcell->uncovered_area = 0; + newcell->covered_height = 0; + } + cell1 = newcell; + found_first: + + /* Find second cell at x2. */ + while (1) { + UNROLL3({ + cell2 = *cursor; + if (NULL == cell2 || cell2->x > x2) + break; + if (cell2->x == x2) + goto found_second; + cursor = &cell2->next; + }); + } + + /* New second cell at x2. */ + newcell = pool_alloc( + cells->cell_pool.base, + sizeof(struct cell)); + if (NULL != newcell) { + *cursor = newcell; + newcell->next = cell2; + newcell->x = x2; + newcell->uncovered_area = 0; + newcell->covered_height = 0; + } + cell2 = newcell; + found_second: + + cells->cursor = cursor; + pair.cell1 = cell1; + pair.cell2 = cell2; + return pair; +} + +/* Add an unbounded subpixel span covering subpixels >= x to the + * coverage cells. */ +static glitter_status_t +cell_list_add_unbounded_subspan( + struct cell_list *cells, + grid_scaled_x_t x) +{ + struct cell *cell; + int ix, fx; + + GRID_X_TO_INT_FRAC(x, ix, fx); + + cell = cell_list_find(cells, ix); + if (cell) { + cell->uncovered_area += 2*fx; + cell->covered_height++; + return GLITTER_STATUS_SUCCESS; + } + return GLITTER_STATUS_NO_MEMORY; +} + +/* Add a subpixel span covering [x1, x2) to the coverage cells. */ +inline static glitter_status_t +cell_list_add_subspan( + struct cell_list *cells, + grid_scaled_x_t x1, + grid_scaled_x_t x2) +{ + int ix1, fx1; + int ix2, fx2; + + GRID_X_TO_INT_FRAC(x1, ix1, fx1); + GRID_X_TO_INT_FRAC(x2, ix2, fx2); + + if (ix1 != ix2) { + struct cell_pair p; + p = cell_list_find2(cells, ix1, ix2); + if (p.cell1 && p.cell2) { + p.cell1->uncovered_area += 2*fx1; + ++p.cell1->covered_height; + p.cell2->uncovered_area -= 2*fx2; + --p.cell2->covered_height; + return GLITTER_STATUS_SUCCESS; + } + } + else { + struct cell *cell = cell_list_find(cells, ix1); + if (cell) { + cell->uncovered_area += 2*(fx1-fx2); + return GLITTER_STATUS_SUCCESS; + } + } + return GLITTER_STATUS_NO_MEMORY; +} + +/* Adds the analytical coverage of an edge crossing the current pixel + * row to the coverage cells and advances the edge's x position to the + * following row. + * + * This function is only called when we know that during this pixel row: + * + * 1) The relative order of all edges on the active list doesn't + * change. In particular, no edges intersect within this row to pixel + * precision. + * + * 2) No new edges start in this row. + * + * 3) No existing edges end mid-row. + * + * This function depends on being called with all edges from the + * active list in the order they appear on the list (i.e. with + * non-decreasing x-coordinate.) */ +static glitter_status_t +cell_list_render_edge( + struct cell_list *cells, + struct edge *edge, + int sign) +{ + struct quorem x1 = edge->x; + struct quorem x2 = x1; + grid_scaled_y_t y1, y2, dy; + grid_scaled_x_t dx; + int ix1, ix2; + grid_scaled_x_t fx1, fx2; + + x2.quo += edge->dxdy_full.quo; + x2.rem += edge->dxdy_full.rem; + if (x2.rem >= 0) { + ++x2.quo; + x2.rem -= edge->dy; + } + edge->x = x2; + + GRID_X_TO_INT_FRAC(x1.quo, ix1, fx1); + GRID_X_TO_INT_FRAC(x2.quo, ix2, fx2); + + /* Edge is entirely within a column? */ + if (ix1 == ix2) { + /* We always know that ix1 is >= the cell list cursor in this + * case due to the no-intersections precondition. */ + struct cell *cell = cell_list_find(cells, ix1); + if (NULL == cell) + return GLITTER_STATUS_NO_MEMORY; + cell->covered_height += sign*GRID_Y; + cell->uncovered_area += sign*(fx1 + fx2)*GRID_Y; + return GLITTER_STATUS_SUCCESS; + } + + /* Orient the edge left-to-right. */ + dx = x2.quo - x1.quo; + if (dx >= 0) { + y1 = 0; + y2 = GRID_Y; + } else { + int tmp; + tmp = ix1; ix1 = ix2; ix2 = tmp; + tmp = fx1; fx1 = fx2; fx2 = tmp; + dx = -dx; + sign = -sign; + y1 = GRID_Y; + y2 = 0; + } + dy = y2 - y1; + + /* Add coverage for all pixels [ix1,ix2] on this row crossed + * by the edge. */ + { + struct cell_pair pair; + struct quorem y = floored_divrem((GRID_X - fx1)*dy, dx); + + /* When rendering a previous edge on the active list we may + * advance the cell list cursor past the leftmost pixel of the + * current edge even though the two edges don't intersect. + * e.g. consider two edges going down and rightwards: + * + * --\_+---\_+-----+-----+---- + * \_ \_ | | + * | \_ | \_ | | + * | \_| \_| | + * | \_ \_ | + * ----+-----+-\---+-\---+---- + * + * The left edge touches cells past the starting cell of the + * right edge. Fortunately such cases are rare. + * + * The rewinding is never necessary if the current edge stays + * within a single column because we've checked before calling + * this function that the active list order won't change. */ + cell_list_maybe_rewind(cells, ix1); + + pair = cell_list_find2(cells, ix1, ix1+1); + if (!pair.cell1 || !pair.cell2) + return GLITTER_STATUS_NO_MEMORY; + + pair.cell1->uncovered_area += sign*y.quo*(GRID_X + fx1); + pair.cell1->covered_height += sign*y.quo; + y.quo += y1; + + if (ix1+1 < ix2) { + struct quorem dydx_full = floored_divrem(GRID_X*dy, dx); + struct cell *cell = pair.cell2; + + ++ix1; + do { + grid_scaled_y_t y_skip = dydx_full.quo; + y.rem += dydx_full.rem; + if (y.rem >= dx) { + ++y_skip; + y.rem -= dx; + } + + y.quo += y_skip; + + y_skip *= sign; + cell->uncovered_area += y_skip*GRID_X; + cell->covered_height += y_skip; + + ++ix1; + cell = cell_list_find(cells, ix1); + if (NULL == cell) + return GLITTER_STATUS_NO_MEMORY; + } while (ix1 != ix2); + + pair.cell2 = cell; + } + pair.cell2->uncovered_area += sign*(y2 - y.quo)*fx2; + pair.cell2->covered_height += sign*(y2 - y.quo); + } + + return GLITTER_STATUS_SUCCESS; +} + +static void +polygon_init(struct polygon *polygon) +{ + polygon->ymin = polygon->ymax = 0; + polygon->y_buckets = NULL; + pool_init(polygon->edge_pool.base, + (8192 - sizeof(struct _pool_chunk))/sizeof(struct edge), + sizeof(polygon->edge_pool.embedded)); +} + +static void +polygon_fini(struct polygon *polygon) +{ + free(polygon->y_buckets); + pool_fini(polygon->edge_pool.base); + polygon_init(polygon); +} + +static void * +realloc_and_clear(void *p, size_t a, size_t b) +{ + size_t total = a*b; + if (b && total / b != a) + return NULL; + p = realloc(p, total); + if (p) + memset(p, 0, total); + return p; +} + +/* Empties the polygon of all edges. The polygon is then prepared to + * receive new edges and clip them to the vertical range + * [ymin,ymax). */ +static glitter_status_t +polygon_reset( + struct polygon *polygon, + grid_scaled_y_t ymin, + grid_scaled_y_t ymax) +{ + void *p; + unsigned h = ymax - ymin; + unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + EDGE_Y_BUCKET_HEIGHT-1, + ymin); + + pool_reset(polygon->edge_pool.base); + + if (h > 0x7FFFFFFFU - EDGE_Y_BUCKET_HEIGHT) + goto bail_no_mem; /* even if you could, you wouldn't want to. */ + + if (num_buckets > 0) { + p = realloc_and_clear( + polygon->y_buckets, + num_buckets, + sizeof(struct edge*)); + if (NULL == p) + goto bail_no_mem; + } + else { + free(polygon->y_buckets); + p = NULL; + } + polygon->y_buckets = p; + + polygon->ymin = ymin; + polygon->ymax = ymax; + return GLITTER_STATUS_SUCCESS; + + bail_no_mem: + free(polygon->y_buckets); + polygon->y_buckets = NULL; + polygon->ymin = 0; + polygon->ymax = 0; + return GLITTER_STATUS_NO_MEMORY; +} + +static void +_polygon_insert_edge_into_its_y_bucket( + struct polygon *polygon, + struct edge *e) +{ + unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin); + struct edge **ptail = &polygon->y_buckets[ix]; + e->next = *ptail; + *ptail = e; +} + +inline static glitter_status_t +polygon_add_edge( + struct polygon *polygon, + int x0, int y0, + int x1, int y1, + int dir) +{ + struct edge *e; + grid_scaled_x_t dx; + grid_scaled_y_t dy; + grid_scaled_y_t ytop, ybot; + grid_scaled_y_t ymin = polygon->ymin; + grid_scaled_y_t ymax = polygon->ymax; + + if (y0 == y1) + return GLITTER_STATUS_SUCCESS; + + if (y0 > y1) { + int tmp; + tmp = x0; x0 = x1; x1 = tmp; + tmp = y0; y0 = y1; y1 = tmp; + dir = -dir; + } + + if (y0 >= ymax || y1 <= ymin) + return GLITTER_STATUS_SUCCESS; + + e = pool_alloc(polygon->edge_pool.base, + sizeof(struct edge)); + if (NULL == e) + return GLITTER_STATUS_NO_MEMORY; + + dx = x1 - x0; + dy = y1 - y0; + e->dy = dy; + e->dxdy = floored_divrem(dx, dy); + + if (ymin <= y0) { + ytop = y0; + e->x.quo = x0; + e->x.rem = 0; + } + else { + ytop = ymin; + e->x = floored_muldivrem(ymin - y0, dx, dy); + e->x.quo += x0; + } + + e->dir = dir; + e->ytop = ytop; + ybot = y1 < ymax ? y1 : ymax; + e->height_left = ybot - ytop; + + if (e->height_left >= GRID_Y) { + e->dxdy_full = floored_muldivrem(GRID_Y, dx, dy); + } + else { + e->dxdy_full.quo = 0; + e->dxdy_full.rem = 0; + } + + _polygon_insert_edge_into_its_y_bucket(polygon, e); + + e->x.rem -= dy; /* Bias the remainder for faster + * edge advancement. */ + return GLITTER_STATUS_SUCCESS; +} + +static void +active_list_reset( + struct active_list *active) +{ + active->head = NULL; + active->min_height = 0; +} + +static void +active_list_init(struct active_list *active) +{ + active_list_reset(active); +} + +static void +active_list_fini( + struct active_list *active) +{ + active_list_reset(active); +} + +/* Merge the edges in an unsorted list of edges into a sorted + * list. The sort order is edges ascending by edge->x.quo. Returns + * the new head of the sorted list. */ +static struct edge * +merge_unsorted_edges(struct edge *sorted_head, struct edge *unsorted_head) +{ + struct edge *head = unsorted_head; + struct edge **cursor = &sorted_head; + int x; + + while (NULL != head) { + struct edge *prev = *cursor; + struct edge *next = head->next; + x = head->x.quo; + + if (NULL == prev || x < prev->x.quo) { + cursor = &sorted_head; + } + + while (1) { + UNROLL3({ + prev = *cursor; + if (NULL == prev || prev->x.quo >= x) + break; + cursor = &prev->next; + }); + } + + head->next = *cursor; + *cursor = head; + + head = next; + } + return sorted_head; +} + +/* Test if the edges on the active list can be safely advanced by a + * full row without intersections or any edges ending. */ +inline static int +active_list_can_step_full_row( + struct active_list *active) +{ + /* Recomputes the minimum height of all edges on the active + * list if we have been dropping edges. */ + if (active->min_height <= 0) { + struct edge *e = active->head; + int min_height = INT_MAX; + + while (NULL != e) { + if (e->height_left < min_height) + min_height = e->height_left; + e = e->next; + } + + active->min_height = min_height; + } + + /* Check for intersections only if no edges end during the next + * row. */ + if (active->min_height >= GRID_Y) { + grid_scaled_x_t prev_x = INT_MIN; + struct edge *e = active->head; + while (NULL != e) { + struct quorem x = e->x; + + x.quo += e->dxdy_full.quo; + x.rem += e->dxdy_full.rem; + if (x.rem >= 0) + ++x.quo; + + if (x.quo <= prev_x) + return 0; + prev_x = x.quo; + e = e->next; + } + return 1; + } + return 0; +} + +/* Merges edges on the given subpixel row from the polygon to the + * active_list. */ +inline static void +active_list_merge_edges_from_polygon( + struct active_list *active, + grid_scaled_y_t y, + struct polygon *polygon) +{ + /* Split off the edges on the current subrow and merge them into + * the active list. */ + unsigned ix = EDGE_Y_BUCKET_INDEX(y, polygon->ymin); + int min_height = active->min_height; + struct edge *subrow_edges = NULL; + struct edge **ptail = &polygon->y_buckets[ix]; + + while (1) { + struct edge *tail = *ptail; + if (NULL == tail) break; + + if (y == tail->ytop) { + *ptail = tail->next; + tail->next = subrow_edges; + subrow_edges = tail; + if (tail->height_left < min_height) + min_height = tail->height_left; + } + else { + ptail = &tail->next; + } + } + active->head = merge_unsorted_edges(active->head, subrow_edges); + active->min_height = min_height; +} + +/* Advance the edges on the active list by one subsample row by + * updating their x positions. Drop edges from the list that end. */ +inline static void +active_list_substep_edges( + struct active_list *active) +{ + struct edge **cursor = &active->head; + grid_scaled_x_t prev_x = INT_MIN; + struct edge *unsorted = NULL; + + while (1) { + struct edge *edge; + + UNROLL3({ + edge = *cursor; + if (NULL == edge) + break; + + if (0 != --edge->height_left) { + edge->x.quo += edge->dxdy.quo; + edge->x.rem += edge->dxdy.rem; + if (edge->x.rem >= 0) { + ++edge->x.quo; + edge->x.rem -= edge->dy; + } + + if (edge->x.quo < prev_x) { + *cursor = edge->next; + edge->next = unsorted; + unsorted = edge; + } else { + prev_x = edge->x.quo; + cursor = &edge->next; + } + + } else { + *cursor = edge->next; + } + }); + } + + if (unsorted) + active->head = merge_unsorted_edges(active->head, unsorted); +} + +inline static glitter_status_t +apply_nonzero_fill_rule_for_subrow( + struct active_list *active, + struct cell_list *coverages) +{ + struct edge *edge = active->head; + int winding = 0; + int xstart; + int xend; + int status; + + cell_list_rewind(coverages); + + while (NULL != edge) { + xstart = edge->x.quo; + winding = edge->dir; + while (1) { + edge = edge->next; + if (NULL == edge) { + return cell_list_add_unbounded_subspan( + coverages, xstart); + } + winding += edge->dir; + if (0 == winding) + break; + } + + xend = edge->x.quo; + status = cell_list_add_subspan(coverages, xstart, xend); + if (status) + return status; + + edge = edge->next; + } + + return GLITTER_STATUS_SUCCESS; +} + +static glitter_status_t +apply_evenodd_fill_rule_for_subrow( + struct active_list *active, + struct cell_list *coverages) +{ + struct edge *edge = active->head; + int xstart; + int xend; + int status; + + cell_list_rewind(coverages); + + while (NULL != edge) { + xstart = edge->x.quo; + + edge = edge->next; + if (NULL == edge) { + return cell_list_add_unbounded_subspan( + coverages, xstart); + } + + xend = edge->x.quo; + status = cell_list_add_subspan(coverages, xstart, xend); + if (status) + return status; + + edge = edge->next; + } + + return GLITTER_STATUS_SUCCESS; +} + +static glitter_status_t +apply_nonzero_fill_rule_and_step_edges( + struct active_list *active, + struct cell_list *coverages) +{ + struct edge **cursor = &active->head; + struct edge *left_edge; + int status; + + left_edge = *cursor; + while (NULL != left_edge) { + struct edge *right_edge; + int winding = left_edge->dir; + + left_edge->height_left -= GRID_Y; + if (left_edge->height_left) { + cursor = &left_edge->next; + } + else { + *cursor = left_edge->next; + } + + while (1) { + right_edge = *cursor; + + if (NULL == right_edge) { + return cell_list_render_edge( + coverages, left_edge, +1); + } + + right_edge->height_left -= GRID_Y; + if (right_edge->height_left) { + cursor = &right_edge->next; + } + else { + *cursor = right_edge->next; + } + + winding += right_edge->dir; + if (0 == winding) + break; + + right_edge->x.quo += right_edge->dxdy_full.quo; + right_edge->x.rem += right_edge->dxdy_full.rem; + if (right_edge->x.rem >= 0) { + ++right_edge->x.quo; + right_edge->x.rem -= right_edge->dy; + } + } + + status = cell_list_render_edge( + coverages, left_edge, +1); + if (status) + return status; + status = cell_list_render_edge( + coverages, right_edge, -1); + if (status) + return status; + + left_edge = *cursor; + } + + return GLITTER_STATUS_SUCCESS; +} + +static glitter_status_t +apply_evenodd_fill_rule_and_step_edges( + struct active_list *active, + struct cell_list *coverages) +{ + struct edge **cursor = &active->head; + struct edge *left_edge; + int status; + + left_edge = *cursor; + while (NULL != left_edge) { + struct edge *right_edge; + + left_edge->height_left -= GRID_Y; + if (left_edge->height_left) { + cursor = &left_edge->next; + } + else { + *cursor = left_edge->next; + } + + right_edge = *cursor; + + if (NULL == right_edge) { + return cell_list_render_edge( + coverages, left_edge, +1); + } + + right_edge->height_left -= GRID_Y; + if (right_edge->height_left) { + cursor = &right_edge->next; + } + else { + *cursor = right_edge->next; + } + + status = cell_list_render_edge( + coverages, left_edge, +1); + if (status) + return status; + status = cell_list_render_edge( + coverages, right_edge, -1); + if (status) + return status; + + left_edge = *cursor; + } + + return GLITTER_STATUS_SUCCESS; +} + +/* If the user hasn't configured a coverage blitter, use a default one + * that blits spans directly to an A8 raster. */ +#ifndef GLITTER_BLIT_COVERAGES + +inline static void +blit_span( + unsigned char *row_pixels, + int x, unsigned len, + grid_area_t coverage) +{ + int alpha = GRID_AREA_TO_ALPHA(coverage); + if (1 == len) { + row_pixels[x] = alpha; + } + else { + memset(row_pixels + x, alpha, len); + } +} + +#define GLITTER_BLIT_COVERAGES(coverages, y, xmin, xmax) \ + blit_cells(coverages, raster_pixels + (y)*raster_stride, xmin, xmax) + +static void +blit_cells( + struct cell_list *cells, + unsigned char *row_pixels, + int xmin, int xmax) +{ + struct cell *cell = cells->head; + int prev_x = xmin; + int coverage = 0; + if (NULL == cell) + return; + + while (NULL != cell && cell->x < xmin) { + coverage += cell->covered_height; + cell = cell->next; + } + coverage *= GRID_X*2; + + for (; NULL != cell; cell = cell->next) { + int x = cell->x; + int area; + if (x >= xmax) + break; + if (x > prev_x && 0 != coverage) { + blit_span(row_pixels, prev_x, x - prev_x, coverage); + } + + coverage += cell->covered_height * GRID_X*2; + area = coverage - cell->uncovered_area; + if (area) { + blit_span(row_pixels, x, 1, area); + } + prev_x = x+1; + } + + if (0 != coverage && prev_x < xmax) { + blit_span(row_pixels, prev_x, xmax - prev_x, coverage); + } +} +#endif /* GLITTER_BLIT_COVERAGES */ + +static void +_glitter_scan_converter_init(glitter_scan_converter_t *converter) +{ + polygon_init(converter->polygon); + active_list_init(converter->active); + cell_list_init(converter->coverages); + converter->xmin=0; + converter->ymin=0; + converter->xmax=0; + converter->ymax=0; +} + +static void +_glitter_scan_converter_fini(glitter_scan_converter_t *converter) +{ + polygon_fini(converter->polygon); + active_list_fini(converter->active); + cell_list_fini(converter->coverages); + converter->xmin=0; + converter->ymin=0; + converter->xmax=0; + converter->ymax=0; +} + +static grid_scaled_t +int_to_grid_scaled(int i, int scale) +{ + /* Clamp to max/min representable scaled number. */ + if (i >= 0) { + if (i >= INT_MAX/scale) + i = INT_MAX/scale; + } + else { + if (i <= INT_MIN/scale) + i = INT_MIN/scale; + } + return i*scale; +} + +#define int_to_grid_scaled_x(x) int_to_grid_scaled((x), GRID_X) +#define int_to_grid_scaled_y(x) int_to_grid_scaled((x), GRID_Y) + +I glitter_status_t +glitter_scan_converter_reset( + glitter_scan_converter_t *converter, + int xmin, int ymin, + int xmax, int ymax) +{ + glitter_status_t status; + + converter->xmin = 0; converter->xmax = 0; + converter->ymin = 0; converter->ymax = 0; + + xmin = int_to_grid_scaled_x(xmin); + ymin = int_to_grid_scaled_y(ymin); + xmax = int_to_grid_scaled_x(xmax); + ymax = int_to_grid_scaled_y(ymax); + + active_list_reset(converter->active); + cell_list_reset(converter->coverages); + status = polygon_reset(converter->polygon, ymin, ymax); + if (status) + return status; + + converter->xmin = xmin; + converter->xmax = xmax; + converter->ymin = ymin; + converter->ymax = ymax; + return GLITTER_STATUS_SUCCESS; +} + +/* INPUT_TO_GRID_X/Y (in_coord, out_grid_scaled, grid_scale) + * These macros convert an input coordinate in the client's + * device space to the rasterisation grid. + */ +/* Gah.. this bit of ugly defines INPUT_TO_GRID_X/Y so as to use + * shifts if possible, and something saneish if not. + */ +#if !defined(INPUT_TO_GRID_Y) && defined(GRID_Y_BITS) && GRID_Y_BITS <= GLITTER_INPUT_BITS +# define INPUT_TO_GRID_Y(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_Y_BITS) +#else +# define INPUT_TO_GRID_Y(in, out) INPUT_TO_GRID_general(in, out, GRID_Y) +#endif + +#if !defined(INPUT_TO_GRID_X) && defined(GRID_X_BITS) && GRID_X_BITS <= GLITTER_INPUT_BITS +# define INPUT_TO_GRID_X(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_X_BITS) +#else +# define INPUT_TO_GRID_X(in, out) INPUT_TO_GRID_general(in, out, GRID_X) +#endif + +#define INPUT_TO_GRID_general(in, out, grid_scale) do { \ + long long tmp__ = (long long)(grid_scale) * (in); \ + tmp__ >>= GLITTER_INPUT_BITS; \ + (out) = tmp__; \ +} while (0) + +I glitter_status_t +glitter_scan_converter_add_edge( + glitter_scan_converter_t *converter, + glitter_input_scaled_t x1, glitter_input_scaled_t y1, + glitter_input_scaled_t x2, glitter_input_scaled_t y2, + int dir) +{ + /* XXX: possible overflows if GRID_X/Y > 2**GLITTER_INPUT_BITS */ + grid_scaled_y_t sx1, sy1; + grid_scaled_y_t sx2, sy2; + + INPUT_TO_GRID_Y(y1, sy1); + INPUT_TO_GRID_Y(y2, sy2); + if (sy1 == sy2) + return GLITTER_STATUS_SUCCESS; + + INPUT_TO_GRID_X(x1, sx1); + INPUT_TO_GRID_X(x2, sx2); + + return polygon_add_edge( + converter->polygon, sx1, sy1, sx2, sy2, dir); +} + +#ifndef GLITTER_BLIT_COVERAGES_BEGIN +# define GLITTER_BLIT_COVERAGES_BEGIN +#endif + +#ifndef GLITTER_BLIT_COVERAGES_END +# define GLITTER_BLIT_COVERAGES_END +#endif + +#ifndef GLITTER_BLIT_COVERAGES_EMPTY +# define GLITTER_BLIT_COVERAGES_EMPTY(y, xmin, xmax) +#endif + +I glitter_status_t +glitter_scan_converter_render( + glitter_scan_converter_t *converter, + int nonzero_fill, + GLITTER_BLIT_COVERAGES_ARGS) +{ + int i; + int ymax_i = converter->ymax / GRID_Y; + int ymin_i = converter->ymin / GRID_Y; + int xmin_i, xmax_i; + int h = ymax_i - ymin_i; + struct polygon *polygon = converter->polygon; + struct cell_list *coverages = converter->coverages; + struct active_list *active = converter->active; + + xmin_i = converter->xmin / GRID_X; + xmax_i = converter->xmax / GRID_X; + if (xmin_i >= xmax_i) + return GLITTER_STATUS_SUCCESS; + + /* Let the coverage blitter initialise itself. */ + GLITTER_BLIT_COVERAGES_BEGIN; + + /* Render each pixel row. */ + for (i=0; i<h; i++) { + int do_full_step = 0; + glitter_status_t status = 0; + + /* Determine if we can ignore this row or use the full pixel + * stepper. */ + if (GRID_Y == EDGE_Y_BUCKET_HEIGHT + && !polygon->y_buckets[i]) + { + if (!active->head) { + GLITTER_BLIT_COVERAGES_EMPTY(i+ymin_i, xmin_i, xmax_i); + continue; + } + do_full_step = active_list_can_step_full_row(active); + } + + cell_list_reset(coverages); + + if (do_full_step) { + /* Step by a full pixel row's worth. */ + if (nonzero_fill) { + status = apply_nonzero_fill_rule_and_step_edges( + active, coverages); + } + else { + status = apply_evenodd_fill_rule_and_step_edges( + active, coverages); + } + } + else { + /* Subsample this row. */ + grid_scaled_y_t suby; + for (suby = 0; suby < GRID_Y; suby++) { + grid_scaled_y_t y = (i+ymin_i)*GRID_Y + suby; + + active_list_merge_edges_from_polygon( + active, y, polygon); + + if (nonzero_fill) + status |= apply_nonzero_fill_rule_for_subrow( + active, coverages); + else + status |= apply_evenodd_fill_rule_for_subrow( + active, coverages); + + active_list_substep_edges(active); + } + } + + if (status) + return status; + + GLITTER_BLIT_COVERAGES(coverages, i+ymin_i, xmin_i, xmax_i); + + if (!active->head) { + active->min_height = INT_MAX; + } + else { + active->min_height -= GRID_Y; + } + } + + /* Clean up the coverage blitter. */ + GLITTER_BLIT_COVERAGES_END; + + return GLITTER_STATUS_SUCCESS; +} + +/*------------------------------------------------------------------------- + * cairo specific implementation: the coverage blitter and + * scan converter subclass. */ + +static glitter_status_t +blit_with_span_renderer( + struct cell_list *cells, + cairo_span_renderer_t *renderer, + struct pool *span_pool, + int y, + int xmin, + int xmax) +{ + struct cell *cell = cells->head; + int prev_x = xmin; + int cover = 0; + cairo_half_open_span_t *spans; + unsigned num_spans; + if (cell == NULL) + return CAIRO_STATUS_SUCCESS; + + /* Skip cells to the left of the clip region. */ + while (cell != NULL && cell->x < xmin) { + cover += cell->covered_height; + cell = cell->next; + } + cover *= GRID_X*2; + + /* Count number of cells remaining. */ + { + struct cell *next = cell; + num_spans = 0; + while (next) { + next = next->next; + ++num_spans; + } + num_spans = 2*num_spans + 1; + } + + /* Allocate enough spans for the row. */ + pool_reset (span_pool); + spans = pool_alloc (span_pool, sizeof(spans[0])*num_spans); + if (spans == NULL) + return GLITTER_STATUS_NO_MEMORY; + + num_spans = 0; + + /* Form the spans from the coverages and areas. */ + for (; cell != NULL; cell = cell->next) { + int x = cell->x; + int area; + if (x >= xmax) + break; + + if (x > prev_x) { + spans[num_spans].x = prev_x; + spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover); + ++num_spans; + } + + cover += cell->covered_height*GRID_X*2; + area = cover - cell->uncovered_area; + + spans[num_spans].x = x; + spans[num_spans].coverage = GRID_AREA_TO_ALPHA (area); + ++num_spans; + + prev_x = x+1; + } + + if (prev_x < xmax) { + spans[num_spans].x = prev_x; + spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover); + ++num_spans; + } + + /* Dump them into the renderer. */ + return renderer->render_row (renderer, y, spans, num_spans); +} + +struct _cairo_tor_scan_converter { + cairo_scan_converter_t base; + glitter_scan_converter_t converter[1]; + cairo_fill_rule_t fill_rule; + + struct { + struct pool base[1]; + cairo_half_open_span_t embedded[32]; + } span_pool; +}; + +typedef struct _cairo_tor_scan_converter cairo_tor_scan_converter_t; + +static void +_cairo_tor_scan_converter_destroy(void *abstract_converter) +{ + cairo_tor_scan_converter_t *self = abstract_converter; + if (self == NULL) { + return; + } + _glitter_scan_converter_fini (self->converter); + pool_fini (self->span_pool.base); + free(self); +} + +static cairo_status_t +_cairo_tor_scan_converter_add_edge( + void *abstract_converter, + cairo_fixed_t x1, + cairo_fixed_t y1, + cairo_fixed_t x2, + cairo_fixed_t y2) +{ + cairo_tor_scan_converter_t *self = abstract_converter; + cairo_status_t status; + status = glitter_scan_converter_add_edge ( + self->converter, + x1, y1, x2, y2, +1); + if (status) { + return _cairo_scan_converter_set_error (self, + _cairo_error (status)); + } + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_tor_scan_converter_generate( + void *abstract_converter, + cairo_span_renderer_t *renderer) +{ + cairo_tor_scan_converter_t *self = abstract_converter; + cairo_status_t status = glitter_scan_converter_render ( + self->converter, + self->fill_rule == CAIRO_FILL_RULE_WINDING, + renderer, + self->span_pool.base); + if (status) { + return _cairo_scan_converter_set_error (self, + _cairo_error (status)); + } + return CAIRO_STATUS_SUCCESS; +} + +cairo_scan_converter_t * +_cairo_tor_scan_converter_create( + int xmin, + int ymin, + int xmax, + int ymax, + cairo_fill_rule_t fill_rule) +{ + cairo_status_t status; + cairo_tor_scan_converter_t *self = + calloc (1, sizeof(struct _cairo_tor_scan_converter)); + if (self == NULL) + goto bail_nomem; + + self->base.destroy = &_cairo_tor_scan_converter_destroy; + self->base.add_edge = &_cairo_tor_scan_converter_add_edge; + self->base.generate = &_cairo_tor_scan_converter_generate; + + pool_init (self->span_pool.base, + 250 * sizeof(self->span_pool.embedded[0]), + sizeof(self->span_pool.embedded)); + + _glitter_scan_converter_init (self->converter); + status = glitter_scan_converter_reset ( + self->converter, xmin, ymin, xmax, ymax); + if (status != CAIRO_STATUS_SUCCESS) + goto bail; + + self->fill_rule = fill_rule; + + return &self->base; + + bail: + self->base.destroy(&self->base); + bail_nomem: + return _cairo_scan_converter_create_in_error (CAIRO_STATUS_NO_MEMORY); +} diff --git a/src/cairo-traps.c b/src/cairo-traps.c index 5cf13d9c..2494696c 100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -140,7 +140,7 @@ _cairo_traps_grow (cairo_traps_t *traps) new_size, sizeof (cairo_trapezoid_t)); } - if (new_traps == NULL) { + if (unlikely (new_traps == NULL)) { traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); return FALSE; } @@ -690,7 +690,7 @@ _cairo_traps_extract_region (const cairo_traps_t *traps, if (traps->num_traps > ARRAY_LENGTH (stack_boxes)) { boxes = _cairo_malloc_ab (traps->num_traps, sizeof (cairo_box_int_t)); - if (boxes == NULL) + if (unlikely (boxes == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -721,7 +721,7 @@ _cairo_traps_extract_region (const cairo_traps_t *traps, if (boxes != stack_boxes) free (boxes); - if (status) + if (unlikely (status)) _cairo_region_fini (region); return status; @@ -760,15 +760,15 @@ _cairo_traps_path (const cairo_traps_t *traps, _sanitize_trap (&trap); status = _cairo_path_fixed_move_to (path, trap.left.p1.x, trap.top); - if (status) return status; + if (unlikely (status)) return status; status = _cairo_path_fixed_line_to (path, trap.right.p1.x, trap.top); - if (status) return status; + if (unlikely (status)) return status; status = _cairo_path_fixed_line_to (path, trap.right.p2.x, trap.bottom); - if (status) return status; + if (unlikely (status)) return status; status = _cairo_path_fixed_line_to (path, trap.left.p2.x, trap.bottom); - if (status) return status; + if (unlikely (status)) return status; status = _cairo_path_fixed_close_path (path); - if (status) return status; + if (unlikely (status)) return status; } return CAIRO_STATUS_SUCCESS; diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c index e8be4b44..4662eaa3 100644 --- a/src/cairo-truetype-subset.c +++ b/src/cairo-truetype-subset.c @@ -146,7 +146,7 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, TT_TAG_head, 0, (unsigned char *) &head, &size); - if (status) + if (unlikely (status)) return status; size = sizeof (tt_maxp_t); @@ -154,7 +154,7 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, TT_TAG_maxp, 0, (unsigned char *) &maxp, &size); - if (status) + if (unlikely (status)) return status; size = sizeof (tt_hhea_t); @@ -162,7 +162,7 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, TT_TAG_hhea, 0, (unsigned char *) &hhea, &size); - if (status) + if (unlikely (status)) return status; size = 0; @@ -170,22 +170,22 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, TT_TAG_name, 0, NULL, &size); - if (status) + if (unlikely (status)) return status; - name = malloc(size); - if (name == NULL) + name = malloc (size); + if (unlikely (name == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = backend->load_truetype_table (scaled_font_subset->scaled_font, TT_TAG_name, 0, (unsigned char *) name, &size); - if (status) + if (unlikely (status)) goto fail0; font = malloc (sizeof (cairo_truetype_font_t)); - if (font == NULL) { + if (unlikely (font == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail0; } @@ -198,17 +198,17 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, font->last_boundary = 0; _cairo_array_init (&font->output, sizeof (char)); status = _cairo_array_grow_by (&font->output, 4096); - if (status) + if (unlikely (status)) goto fail1; font->glyphs = calloc (font->num_glyphs_in_face + 1, sizeof (subset_glyph_t)); - if (font->glyphs == NULL) { + if (unlikely (font->glyphs == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail1; } font->parent_to_subset = calloc (font->num_glyphs_in_face, sizeof (int)); - if (font->parent_to_subset == NULL) { + if (unlikely (font->parent_to_subset == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail2; } @@ -252,7 +252,7 @@ _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) { + if (unlikely (font->base.base_font == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail3; } @@ -270,14 +270,14 @@ _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) { + if (unlikely (font->base.widths == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail4; } _cairo_array_init (&font->string_offsets, sizeof (unsigned long)); status = _cairo_array_grow_by (&font->string_offsets, 10); - if (status) + if (unlikely (status)) goto fail5; font->status = CAIRO_STATUS_SUCCESS; @@ -328,7 +328,7 @@ cairo_truetype_font_allocate_write_buffer (cairo_truetype_font_t *font, return font->status; status = _cairo_array_allocate (&font->output, length, (void **) buffer); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); return CAIRO_STATUS_SUCCESS; @@ -345,7 +345,7 @@ cairo_truetype_font_write (cairo_truetype_font_t *font, return; status = _cairo_array_append_multiple (&font->output, data, length); - if (status) + if (unlikely (status)) status = _cairo_truetype_font_set_error (font, status); } @@ -391,7 +391,7 @@ cairo_truetype_font_align_output (cairo_truetype_font_t *font, status = cairo_truetype_font_allocate_write_buffer (font, pad, &padding); - if (status) + if (unlikely (status)) return status; memset (padding, 0, pad); @@ -413,7 +413,7 @@ cairo_truetype_font_check_boundary (cairo_truetype_font_t *font, { status = _cairo_array_append (&font->string_offsets, &font->last_boundary); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); font->last_offset = font->last_boundary; @@ -486,16 +486,16 @@ cairo_truetype_font_write_generic_table (cairo_truetype_font_t *font, size = 0; status = font->backend->load_truetype_table(font->scaled_font_subset->scaled_font, tag, 0, NULL, &size); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, tag, 0, buffer, &size); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); return CAIRO_STATUS_SUCCESS; @@ -533,7 +533,7 @@ cairo_truetype_font_remap_composite_glyph (cairo_truetype_font_t *font, flags = be16_to_cpu (composite_glyph->flags); has_more_components = flags & TT_MORE_COMPONENTS; status = cairo_truetype_font_use_glyph (font, be16_to_cpu (composite_glyph->index), &index); - if (status) + if (unlikely (status)) return status; composite_glyph->index = cpu_to_be16 (index); @@ -575,21 +575,21 @@ cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font, status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, TT_TAG_head, 0, (unsigned char*) &header, &size); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); - + if (be16_to_cpu (header.index_to_loc_format) == 0) size = sizeof (int16_t) * (font->num_glyphs_in_face + 1); else size = sizeof (int32_t) * (font->num_glyphs_in_face + 1); u.bytes = malloc (size); - if (u.bytes == NULL) + if (unlikely (u.bytes == NULL)) return _cairo_truetype_font_set_error (font, CAIRO_STATUS_NO_MEMORY); status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, TT_TAG_loca, 0, u.bytes, &size); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); start_offset = _cairo_array_num_elements (&font->output); @@ -612,33 +612,33 @@ cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font, size = end - begin; status = cairo_truetype_font_align_output (font, &next); - if (status) + if (unlikely (status)) goto FAIL; status = cairo_truetype_font_check_boundary (font, next); - if (status) + if (unlikely (status)) goto FAIL; font->glyphs[i].location = next - start_offset; status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer); - if (status) + if (unlikely (status)) goto FAIL; if (size != 0) { status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, TT_TAG_glyf, begin, buffer, &size); - if (status) + if (unlikely (status)) goto FAIL; status = cairo_truetype_font_remap_composite_glyph (font, buffer, size); - if (status) + if (unlikely (status)) goto FAIL; } } status = cairo_truetype_font_align_output (font, &next); - if (status) + if (unlikely (status)) goto FAIL; font->glyphs[i].location = next - start_offset; @@ -664,17 +664,17 @@ cairo_truetype_font_write_head_table (cairo_truetype_font_t *font, size = 0; status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, tag, 0, NULL, &size); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); font->checksum_index = _cairo_array_num_elements (&font->output) + 8; status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, tag, 0, buffer, &size); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); /* set checkSumAdjustment to 0 for table checksum calcualtion */ @@ -695,12 +695,12 @@ cairo_truetype_font_write_hhea_table (cairo_truetype_font_t *font, unsigned long size = sizeof (tt_hhea_t); status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &hhea); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, tag, 0, (unsigned char *) hhea, &size); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); hhea->num_hmetrics = cpu_to_be16 ((uint16_t)(font->base.num_glyphs)); @@ -728,7 +728,7 @@ cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font, status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, TT_TAG_hhea, 0, (unsigned char*) &hhea, &size); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); num_hmetrics = be16_to_cpu(hhea.num_hmetrics); @@ -739,7 +739,7 @@ cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font, status = cairo_truetype_font_allocate_write_buffer (font, long_entry_size, (unsigned char **) &p); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); if (font->glyphs[i].parent_index < num_hmetrics) { @@ -747,7 +747,7 @@ cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font, TT_TAG_hmtx, font->glyphs[i].parent_index * long_entry_size, (unsigned char *) p, &long_entry_size); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); } else @@ -756,7 +756,7 @@ cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font, TT_TAG_hmtx, (num_hmetrics - 1) * long_entry_size, (unsigned char *) p, &short_entry_size); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, @@ -764,7 +764,7 @@ cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font, num_hmetrics * long_entry_size + (font->glyphs[i].parent_index - num_hmetrics) * short_entry_size, (unsigned char *) (p + 1), &short_entry_size); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); } font->base.widths[i] = be16_to_cpu (p[0]); @@ -789,7 +789,7 @@ cairo_truetype_font_write_loca_table (cairo_truetype_font_t *font, status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, TT_TAG_head, 0, (unsigned char*) &header, &size); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); if (be16_to_cpu (header.index_to_loc_format) == 0) @@ -817,12 +817,12 @@ cairo_truetype_font_write_maxp_table (cairo_truetype_font_t *font, size = sizeof (tt_maxp_t); status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &maxp); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, tag, 0, (unsigned char *) maxp, &size); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); maxp->num_glyphs = cpu_to_be16 (font->base.num_glyphs); @@ -862,7 +862,7 @@ cairo_truetype_font_write_offset_table (cairo_truetype_font_t *font) table_buffer_length = font->num_tables * 16; status = cairo_truetype_font_allocate_write_buffer (font, table_buffer_length, &table_buffer); - if (status) + if (unlikely (status)) return _cairo_truetype_font_set_error (font, status); return CAIRO_STATUS_SUCCESS; @@ -920,28 +920,28 @@ cairo_truetype_font_generate (cairo_truetype_font_t *font, return font->status; status = cairo_truetype_font_write_offset_table (font); - if (status) + if (unlikely (status)) goto FAIL; status = cairo_truetype_font_align_output (font, &start); - if (status) + if (unlikely (status)) goto FAIL; end = 0; for (i = 0; i < font->num_tables; i++) { status = font->truetype_tables[i].write (font, font->truetype_tables[i].tag); - if (status) + if (unlikely (status)) goto FAIL; end = _cairo_array_num_elements (&font->output); status = cairo_truetype_font_align_output (font, &next); - if (status) + if (unlikely (status)) goto FAIL; cairo_truetype_font_update_entry (font, font->truetype_tables[i].pos, font->truetype_tables[i].tag, start, end); status = cairo_truetype_font_check_boundary (font, next); - if (status) + if (unlikely (status)) goto FAIL; start = next; @@ -1081,24 +1081,24 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset, unsigned long num_strings = 0; status = _cairo_truetype_font_create (font_subset, &font); - if (status) + if (unlikely (status)) return status; for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { unsigned short parent_glyph = font->scaled_font_subset->glyphs[i]; status = cairo_truetype_font_use_glyph (font, parent_glyph, &parent_glyph); - if (status) + if (unlikely (status)) goto fail1; } cairo_truetype_font_create_truetype_table_list (font); status = cairo_truetype_font_generate (font, &data, &length, &string_offsets, &num_strings); - if (status) + if (unlikely (status)) goto fail1; truetype_subset->base_font = strdup (font->base.base_font); - if (truetype_subset->base_font == NULL) { + if (unlikely (truetype_subset->base_font == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail1; } @@ -1108,7 +1108,7 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset, * font_subset->num_glyphs are omitted. */ truetype_subset->widths = calloc (sizeof (double), font->scaled_font_subset->num_glyphs); - if (truetype_subset->widths == NULL) { + if (unlikely (truetype_subset->widths == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail2; } @@ -1124,7 +1124,7 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset, if (length) { truetype_subset->data = malloc (length); - if (truetype_subset->data == NULL) { + if (unlikely (truetype_subset->data == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail3; } @@ -1137,7 +1137,7 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset, if (num_strings) { offsets_length = num_strings * sizeof (unsigned long); truetype_subset->string_offsets = malloc (offsets_length); - if (truetype_subset->string_offsets == NULL) { + if (unlikely (truetype_subset->string_offsets == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail4; } @@ -1199,7 +1199,7 @@ _cairo_truetype_reverse_cmap (cairo_scaled_font_t *scaled_font, TT_TAG_cmap, table_offset, (unsigned char *) &buf, &size); - if (status) + if (unlikely (status)) return status; /* All table formats have the same first two words */ @@ -1209,14 +1209,14 @@ _cairo_truetype_reverse_cmap (cairo_scaled_font_t *scaled_font, size = be16_to_cpu (map->length); map = malloc (size); - if (map == NULL) + if (unlikely (map == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = backend->load_truetype_table (scaled_font, TT_TAG_cmap, table_offset, (unsigned char *) map, &size); - if (status) + if (unlikely (status)) goto fail; num_segments = be16_to_cpu (map->segCountX2)/2; @@ -1299,21 +1299,21 @@ _cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font, TT_TAG_cmap, 0, (unsigned char *) &buf, &size); - if (status) + if (unlikely (status)) return status; cmap = (tt_cmap_t *) buf; num_tables = be16_to_cpu (cmap->num_tables); size = 4 + num_tables*sizeof(tt_cmap_index_t); cmap = _cairo_malloc_ab_plus_c (num_tables, sizeof (tt_cmap_index_t), 4); - if (cmap == NULL) + if (unlikely (cmap == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = backend->load_truetype_table (scaled_font, TT_TAG_cmap, 0, (unsigned char *) cmap, &size); - if (status) + if (unlikely (status)) goto cleanup; /* Find a table with Unicode mapping */ diff --git a/src/cairo-type1-fallback.c b/src/cairo-type1-fallback.c index 83ddc448..91c00542 100644 --- a/src/cairo-type1-fallback.c +++ b/src/cairo-type1-fallback.c @@ -85,12 +85,11 @@ cairo_type1_font_create (cairo_scaled_font_subset_t *scaled_font_subset, cairo_status_t status; font = calloc (1, sizeof (cairo_type1_font_t)); - if (font == NULL) + if (unlikely (font == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - font->widths = calloc (scaled_font_subset->num_glyphs, - sizeof (int)); - if (font->widths == NULL) { + font->widths = calloc (scaled_font_subset->num_glyphs, sizeof (int)); + if (unlikely (font->widths == NULL)) { free (font); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -112,7 +111,7 @@ cairo_type1_font_create (cairo_scaled_font_subset_t *scaled_font_subset, &ctm, &font_options); status = font->type1_scaled_font->status; - if (status) + if (unlikely (status)) goto fail; _cairo_array_init (&font->contents, sizeof (unsigned char)); @@ -227,7 +226,7 @@ _charstring_move_to (void *closure, cairo_status_t status; status = _cairo_array_grow_by (path_info->data, 12); - if (status) + if (unlikely (status)) return status; dx = _cairo_fixed_integer_part (point->x) - path_info->current_x; @@ -251,7 +250,7 @@ _charstring_line_to (void *closure, cairo_status_t status; status = _cairo_array_grow_by (path_info->data, 12); - if (status) + if (unlikely (status)) return status; dx = _cairo_fixed_integer_part (point->x) - path_info->current_x; @@ -277,7 +276,7 @@ _charstring_curve_to (void *closure, cairo_status_t status; status = _cairo_array_grow_by (path_info->data, 32); - if (status) + if (unlikely (status)) return status; dx1 = _cairo_fixed_integer_part (point1->x) - path_info->current_x; @@ -309,7 +308,7 @@ _charstring_close_path (void *closure) return CAIRO_STATUS_SUCCESS; status = _cairo_array_grow_by (path_info->data, 2); - if (status) + if (unlikely (status)) return status; charstring_encode_command (path_info->data, CHARSTRING_closepath); @@ -363,7 +362,7 @@ cairo_type1_font_create_charstring (cairo_type1_font_t *font, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); } - if (status) + if (unlikely (status)) return status; metrics = &scaled_glyph->metrics; @@ -385,7 +384,7 @@ cairo_type1_font_create_charstring (cairo_type1_font_t *font, font->widths[subset_index] = metrics->x_advance; status = _cairo_array_grow_by (data, 30); - if (status) + if (unlikely (status)) return status; if (type == CAIRO_CHARSTRING_TYPE1) { @@ -413,12 +412,12 @@ cairo_type1_font_create_charstring (cairo_type1_font_t *font, _charstring_curve_to, _charstring_close_path, &path_info); - if (status) + if (unlikely (status)) return status; } status = _cairo_array_grow_by (data, 1); - if (status) + if (unlikely (status)) return status; charstring_encode_command (path_info.data, CHARSTRING_endchar); @@ -437,7 +436,7 @@ cairo_type1_font_write_charstrings (cairo_type1_font_t *font, _cairo_array_init (&data, sizeof (unsigned char)); status = _cairo_array_grow_by (&data, 1024); - if (status) + if (unlikely (status)) goto fail; _cairo_output_stream_printf (encrypted_output, @@ -449,14 +448,14 @@ cairo_type1_font_write_charstrings (cairo_type1_font_t *font, _cairo_array_truncate (&data, 0); /* four "random" bytes required by encryption algorithm */ status = _cairo_array_append_multiple (&data, zeros, 4); - if (status) + if (unlikely (status)) goto fail; status = cairo_type1_font_create_charstring (font, i, font->scaled_font_subset->glyphs[i], CAIRO_CHARSTRING_TYPE1, &data); - if (status) + if (unlikely (status)) goto fail; charstring_encrypt (&data); @@ -590,7 +589,7 @@ cairo_type1_font_write_private_dict (cairo_type1_font_t *font, _cairo_output_stream_printf (encrypted_output, " dup /Private 9 dict dup begin\n" "/RD {string currentfile exch readstring pop}" - " executeonly def\n" + " bind executeonly def\n" "/ND {noaccess def} executeonly def\n" "/NP {noaccess put} executeonly def\n" "/BlueValues [] def\n" @@ -599,7 +598,7 @@ cairo_type1_font_write_private_dict (cairo_type1_font_t *font, "/password 5839 def\n"); status = cairo_type1_font_write_charstrings (font, encrypted_output); - if (status) + if (unlikely (status)) goto fail; _cairo_output_stream_printf (encrypted_output, @@ -651,7 +650,7 @@ cairo_type1_font_write (cairo_type1_font_t *font, font->header_size = _cairo_output_stream_get_position (font->output); status = cairo_type1_font_write_private_dict (font, name); - if (status) + if (unlikely (status)) return status; font->data_size = _cairo_output_stream_get_position (font->output) - @@ -671,7 +670,7 @@ cairo_type1_font_generate (cairo_type1_font_t *font, const char *name) cairo_int_status_t status; status = _cairo_array_grow_by (&font->contents, 4096); - if (status) + if (unlikely (status)) return status; font->output = _cairo_output_stream_create (cairo_type1_write_stream, NULL, font); @@ -679,7 +678,7 @@ cairo_type1_font_generate (cairo_type1_font_t *font, const char *name) return _cairo_output_stream_destroy (font->output); status = cairo_type1_font_write (font, name); - if (status) + if (unlikely (status)) return status; font->data = _cairo_array_index (&font->contents, 0); @@ -714,21 +713,21 @@ _cairo_type1_fallback_init_internal (cairo_type1_subset_t *type1_subset, unsigned int i, len; status = cairo_type1_font_create (scaled_font_subset, &font, hex_encode); - if (status) + if (unlikely (status)) return status; status = cairo_type1_font_generate (font, name); - if (status) + if (unlikely (status)) goto fail1; type1_subset->base_font = strdup (name); - if (type1_subset->base_font == NULL) { + if (unlikely (type1_subset->base_font == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail1; } type1_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs); - if (type1_subset->widths == NULL) { + if (unlikely (type1_subset->widths == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail2; } @@ -745,7 +744,7 @@ _cairo_type1_fallback_init_internal (cairo_type1_subset_t *type1_subset, length = font->header_size + font->data_size + font->trailer_size; type1_subset->data = malloc (length); - if (type1_subset->data == NULL) { + if (unlikely (type1_subset->data == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail3; } @@ -816,13 +815,13 @@ _cairo_type2_charstrings_init (cairo_type2_charstrings_t *type2_subset, cairo_array_t charstring; status = cairo_type1_font_create (scaled_font_subset, &font, FALSE); - if (status) + if (unlikely (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) { + if (unlikely (type2_subset->widths == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail1; } @@ -831,18 +830,18 @@ _cairo_type2_charstrings_init (cairo_type2_charstrings_t *type2_subset, 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) + if (unlikely (status)) goto fail2; status = cairo_type1_font_create_charstring (font, i, font->scaled_font_subset->glyphs[i], CAIRO_CHARSTRING_TYPE2, &charstring); - if (status) + if (unlikely (status)) goto fail2; status = _cairo_array_append (&type2_subset->charstrings, &charstring); - if (status) + if (unlikely (status)) goto fail2; } _cairo_scaled_font_thaw_cache (font->type1_scaled_font); diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c index ddc4ce76..fe74dc6c 100644 --- a/src/cairo-type1-subset.c +++ b/src/cairo-type1-subset.c @@ -126,7 +126,7 @@ _cairo_type1_font_subset_init (cairo_type1_font_subset_t *font, ft_unscaled_font = (cairo_ft_unscaled_font_t *) unscaled_font; face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font); - if (face == NULL) + if (unlikely (face == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); if (FT_Get_PS_Font_Info(face, &font_info) != 0) { @@ -154,7 +154,7 @@ _cairo_type1_font_subset_init (cairo_type1_font_subset_t *font, if (face->family_name) { font->base.base_font = strdup (face->family_name); - if (font->base.base_font == NULL) { + if (unlikely (font->base.base_font == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail2; } @@ -167,7 +167,7 @@ _cairo_type1_font_subset_init (cairo_type1_font_subset_t *font, } font->glyphs = calloc (face->num_glyphs, sizeof font->glyphs[0]); - if (font->glyphs == NULL) { + if (unlikely (font->glyphs == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail3; } @@ -467,7 +467,7 @@ cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font) end = (unsigned char *) in + font->eexec_segment_size; font->cleartext = malloc (font->eexec_segment_size); - if (font->cleartext == NULL) + if (unlikely (font->cleartext == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); out = font->cleartext; @@ -553,21 +553,27 @@ cairo_type1_font_subset_get_glyph_names_and_widths (cairo_type1_font_subset_t *f error = FT_Load_Glyph (font->face, i, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM); - if (error != 0) { - printf ("could not load glyph %d\n", i); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (error != FT_Err_Ok) { + /* propagate fatal errors from FreeType */ + if (error == FT_Err_Out_Of_Memory) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + return CAIRO_INT_STATUS_UNSUPPORTED; } font->glyphs[i].width = font->face->glyph->metrics.horiAdvance; error = FT_Get_Glyph_Name(font->face, i, buffer, sizeof buffer); - if (error != 0) { - printf ("could not get glyph name for glyph %d\n", i); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (error != FT_Err_Ok) { + /* propagate fatal errors from FreeType */ + if (error == FT_Err_Out_Of_Memory) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + return CAIRO_INT_STATUS_UNSUPPORTED; } font->glyphs[i].name = strdup (buffer); - if (font->glyphs[i].name == NULL) + if (unlikely (font->glyphs[i].name == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -832,7 +838,7 @@ cairo_type1_font_subset_look_for_seac(cairo_type1_font_subset_t *font, int command; charstring = malloc (encrypted_charstring_length); - if (charstring == NULL) + if (unlikely (charstring == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); cairo_type1_font_subset_decrypt_charstring ((const unsigned char *) @@ -860,11 +866,11 @@ cairo_type1_font_subset_look_for_seac(cairo_type1_font_subset_t *font, * make sure those glyphs are present in the subset * under their standard names. */ status = use_standard_encoding_glyph (font, stack[3]); - if (status) + if (unlikely (status)) return status; status = use_standard_encoding_glyph (font, stack[4]); - if (status) + if (unlikely (status)) return status; sp = 0; @@ -900,18 +906,18 @@ write_used_glyphs (cairo_type1_font_subset_t *font, "/%.*s %d %s ", name_length, name, charstring_length, font->rd); status = cairo_type1_font_subset_write_encrypted (font, buffer, length); - if (status) + if (unlikely (status)) return status; status = cairo_type1_font_subset_write_encrypted (font, charstring, charstring_length); - if (status) + if (unlikely (status)) return status; length = snprintf (buffer, sizeof buffer, "%s\n", font->nd); status = cairo_type1_font_subset_write_encrypted (font, buffer, length); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -977,7 +983,7 @@ cairo_type1_font_subset_for_each_glyph (cairo_type1_font_subset_t *font, cairo_status_t status = func (font, name, name_length, charstring, charstring_length); - if (status) + if (unlikely (status)) return status; } } @@ -1034,7 +1040,7 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font, dict_start = p; status = cairo_type1_font_subset_get_glyph_names_and_widths (font); - if (status) + if (unlikely (status)) return status; /* Now that we have the private dictionary broken down in @@ -1046,7 +1052,7 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font, font->cleartext_end, cairo_type1_font_subset_look_for_seac, &p); - if (status) + if (unlikely (status)) return status; closefile_token = find_token (p, font->cleartext_end, "closefile"); @@ -1054,13 +1060,13 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font, return CAIRO_INT_STATUS_UNSUPPORTED; status = cairo_type1_font_subset_get_glyph_names_and_widths (font); - if (status) + if (unlikely (status)) return status; /* We're ready to start outputting. First write the header, * i.e. the public part of the font dict.*/ status = cairo_type1_font_subset_write_header (font, name); - if (status) + if (unlikely (status)) return status; font->base.header_size = _cairo_output_stream_get_position (font->output); @@ -1070,21 +1076,21 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font, * to the /CharStrings token. */ status = cairo_type1_font_subset_write_encrypted (font, font->cleartext, charstrings - font->cleartext); - if (status) + if (unlikely (status)) return status; /* Write out new charstring count */ length = snprintf (buffer, sizeof buffer, "/CharStrings %d", font->num_glyphs); status = cairo_type1_font_subset_write_encrypted (font, buffer, length); - if (status) + if (unlikely (status)) return status; /* Write out text between the charstring count and the first * charstring definition */ status = cairo_type1_font_subset_write_encrypted (font, glyph_count_end, dict_start - glyph_count_end); - if (status) + if (unlikely (status)) return status; /* Write out the charstring definitions for each of the glyphs in @@ -1094,14 +1100,14 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font, font->cleartext_end, write_used_glyphs, &p); - if (status) + if (unlikely (status)) return status; /* Output what's left between the end of the glyph definitions and * the end of the private dict to the output. */ status = cairo_type1_font_subset_write_encrypted (font, p, closefile_token - p + strlen ("closefile") + 1); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_write (font->output, "\n", 1); @@ -1152,11 +1158,11 @@ cairo_type1_font_subset_write (cairo_type1_font_subset_t *font, cairo_status_t status; status = cairo_type1_font_subset_find_segments (font); - if (status) + if (unlikely (status)) return status; status = cairo_type1_font_subset_decrypt_eexec_segment (font); - if (status) + if (unlikely (status)) return status; /* Determine which glyph definition delimiters to use. */ @@ -1175,14 +1181,14 @@ cairo_type1_font_subset_write (cairo_type1_font_subset_t *font, font->hex_column = 0; status = cairo_type1_font_subset_write_private_dict (font, name); - if (status) + if (unlikely (status)) return status; font->base.data_size = _cairo_output_stream_get_position (font->output) - font->base.header_size; status = cairo_type1_font_subset_write_trailer (font); - if (status) + if (unlikely (status)) return status; font->base.trailer_size = @@ -1204,12 +1210,12 @@ cairo_type1_font_subset_generate (void *abstract_font, ft_unscaled_font = (cairo_ft_unscaled_font_t *) font->base.unscaled_font; font->face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font); - if (font->face == NULL) + if (unlikely (font->face == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); font->type1_length = font->face->stream->size; font->type1_data = malloc (font->type1_length); - if (font->type1_data == NULL) { + if (unlikely (font->type1_data == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail; } @@ -1233,7 +1239,7 @@ cairo_type1_font_subset_generate (void *abstract_font, } status = _cairo_array_grow_by (&font->contents, 4096); - if (status) + if (unlikely (status)) goto fail; font->output = _cairo_output_stream_create (type1_font_write, NULL, font); @@ -1243,7 +1249,7 @@ cairo_type1_font_subset_generate (void *abstract_font, } status = cairo_type1_font_subset_write (font, name); - if (status) + if (unlikely (status)) goto fail; font->base.data = _cairo_array_index (&font->contents, 0); @@ -1300,7 +1306,7 @@ _cairo_type1_subset_init (cairo_type1_subset_t *type1_subset, unscaled_font = _cairo_ft_scaled_font_get_unscaled_font (scaled_font_subset->scaled_font); status = _cairo_type1_font_subset_init (&font, unscaled_font, hex_encode); - if (status) + if (unlikely (status)) return status; for (i = 0; i < scaled_font_subset->num_glyphs; i++) { @@ -1309,7 +1315,7 @@ _cairo_type1_subset_init (cairo_type1_subset_t *type1_subset, } status = cairo_type1_font_subset_generate (&font, name); - if (status) + if (unlikely (status)) goto fail1; if (font.base.base_font) { @@ -1319,11 +1325,11 @@ _cairo_type1_subset_init (cairo_type1_subset_t *type1_subset, scaled_font_subset->font_id, scaled_font_subset->subset_id); type1_subset->base_font = strdup (buf); } - if (type1_subset->base_font == NULL) + if (unlikely (type1_subset->base_font == NULL)) goto fail1; type1_subset->widths = calloc (sizeof (int), font.num_glyphs); - if (type1_subset->widths == NULL) + if (unlikely (type1_subset->widths == NULL)) goto fail2; for (i = 0; i < font.base.num_glyphs; i++) { if (font.glyphs[i].subset_index < 0) @@ -1343,7 +1349,7 @@ _cairo_type1_subset_init (cairo_type1_subset_t *type1_subset, font.base.data_size + font.base.trailer_size; type1_subset->data = malloc (length); - if (type1_subset->data == NULL) + if (unlikely (type1_subset->data == NULL)) goto fail3; memcpy (type1_subset->data, diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c index 58048aca..b3a48313 100644 --- a/src/cairo-type3-glyph-surface.c +++ b/src/cairo-type3-glyph-surface.c @@ -55,7 +55,7 @@ _cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font, cairo_matrix_t invert_y_axis; surface = malloc (sizeof (cairo_type3_glyph_surface_t)); - if (surface == NULL) + if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); _cairo_surface_init (&surface->base, &cairo_type3_glyph_surface_backend, @@ -96,7 +96,7 @@ _cairo_type3_glyph_surface_emit_image (cairo_type3_glyph_surface_t *surface, } else { image_mask = _cairo_image_surface_clone (image, CAIRO_FORMAT_A1); status = cairo_surface_status (&image->base); - if (status) + if (unlikely (status)) return status; } @@ -182,7 +182,8 @@ _cairo_type3_glyph_surface_intersect_clip_path (void *abstract_surface, static cairo_int_status_t _cairo_type3_glyph_surface_paint (void *abstract_surface, cairo_operator_t op, - const cairo_pattern_t *source) + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents) { cairo_type3_glyph_surface_t *surface = abstract_surface; const cairo_surface_pattern_t *pattern; @@ -195,7 +196,7 @@ _cairo_type3_glyph_surface_paint (void *abstract_surface, pattern = (const cairo_surface_pattern_t *) source; status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra); - if (status) + if (unlikely (status)) goto fail; status = _cairo_type3_glyph_surface_emit_image_pattern (surface, @@ -212,9 +213,10 @@ static cairo_int_status_t _cairo_type3_glyph_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_pattern_t *mask) + const cairo_pattern_t *mask, + cairo_rectangle_int_t *extents) { - return _cairo_type3_glyph_surface_paint (abstract_surface, op, mask); + return _cairo_type3_glyph_surface_paint (abstract_surface, op, mask, extents); } static cairo_int_status_t @@ -226,7 +228,8 @@ _cairo_type3_glyph_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_type3_glyph_surface_t *surface = abstract_surface; @@ -244,7 +247,8 @@ _cairo_type3_glyph_surface_fill (void *abstract_surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_type3_glyph_surface_t *surface = abstract_surface; cairo_int_status_t status; @@ -263,7 +267,8 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs) + int *remaining_glyphs, + cairo_rectangle_int_t *extents) { cairo_type3_glyph_surface_t *surface = abstract_surface; cairo_int_status_t status; @@ -277,7 +282,7 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface, /* We require the matrix to be invertable. */ ctm_inverse = scaled_font->ctm; status = cairo_matrix_invert (&ctm_inverse); - if (status) + if (unlikely (status)) return CAIRO_INT_STATUS_IMAGE_FALLBACK; cairo_matrix_multiply (&new_ctm, &scaled_font->ctm, &ctm_inverse); @@ -310,6 +315,8 @@ static const cairo_surface_backend_t cairo_type3_glyph_surface_backend = { NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* cairo_type3_glyph_surface_copy_page */ NULL, /* _cairo_type3_glyph_surface_show_page */ NULL, /* set_clip_region */ @@ -352,7 +359,7 @@ _cairo_type3_glyph_surface_emit_fallback_image (cairo_type3_glyph_surface_t *sur CAIRO_SCALED_GLYPH_INFO_METRICS | CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); - if (status) + if (unlikely (status)) return status; image = scaled_glyph->surface; @@ -414,7 +421,7 @@ _cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface, status = _cairo_meta_surface_replay (scaled_glyph->meta_surface, &surface->base); - if (status) + if (unlikely (status)) goto cleanup; status2 = _cairo_pdf_operators_flush (&surface->pdf_operators); diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h index 12e1a20e..d8d5a2c0 100644 --- a/src/cairo-types-private.h +++ b/src/cairo-types-private.h @@ -41,8 +41,10 @@ #include "cairo.h" #include "cairo-fixed-type-private.h" +#include "cairo-reference-count-private.h" typedef struct _cairo_array cairo_array_t; +typedef struct _cairo_backend cairo_backend_t; typedef struct _cairo_cache cairo_cache_t; typedef struct _cairo_clip cairo_clip_t; typedef struct _cairo_clip_path cairo_clip_path_t; @@ -52,6 +54,7 @@ typedef struct _cairo_gstate cairo_gstate_t; typedef struct _cairo_hash_entry cairo_hash_entry_t; typedef struct _cairo_hash_table cairo_hash_table_t; typedef struct _cairo_image_surface cairo_image_surface_t; +typedef struct _cairo_mime_data cairo_mime_data_t; typedef struct _cairo_output_stream cairo_output_stream_t; typedef struct _cairo_paginated_surface_backend cairo_paginated_surface_backend_t; typedef struct _cairo_path_fixed cairo_path_fixed_t; @@ -249,6 +252,30 @@ typedef struct _cairo_box_int { cairo_point_int_t p2; } cairo_box_int_t; + +/* Rectangles that take part in a composite operation. + * + * This defines four translations that define which pixels of the + * source pattern, mask, clip and destination surface take part in a + * general composite operation. The idea is that the pixels at + * + * (i,j)+(src.x, src.y) of the source, + * (i,j)+(mask.x, mask.y) of the mask, + * (i,j)+(clip.x, clip.y) of the clip and + * (i,j)+(dst.x, dst.y) of the destination + * + * all combine together to form the result at (i,j)+(dst.x,dst.y), + * for i,j ranging in [0,width) and [0,height) respectively. + */ +typedef struct _cairo_composite_rectangles { + cairo_point_int_t src; + cairo_point_int_t mask; + cairo_point_int_t clip; + cairo_point_int_t dst; + int width; + int height; +} cairo_composite_rectangles_t; + typedef enum _cairo_direction { CAIRO_DIRECTION_FORWARD, CAIRO_DIRECTION_REVERSE @@ -262,9 +289,7 @@ typedef enum _cairo_clip_mode { typedef struct _cairo_edge { cairo_line_t edge; - int clockWise; - - cairo_fixed_t current_x; + int dir; } cairo_edge_t; typedef struct _cairo_polygon { @@ -284,15 +309,16 @@ typedef struct _cairo_spline_knots { cairo_point_t a, b, c, d; } cairo_spline_knots_t; typedef struct _cairo_spline { + void (*add_point_func) (void *, const cairo_point_t *); + void *closure; + cairo_spline_knots_t knots; cairo_slope_t initial_slope; cairo_slope_t final_slope; - int num_points; - int points_size; - cairo_point_t *points; - cairo_point_t points_embedded[64]; + cairo_bool_t has_point; + cairo_point_t last_point; } cairo_spline_t; typedef struct _cairo_pen_vertex { @@ -342,4 +368,12 @@ typedef enum _cairo_image_transparency { CAIRO_IMAGE_UNKNOWN } cairo_image_transparency_t; +struct _cairo_mime_data { + cairo_reference_count_t ref_count; + unsigned char *data; + unsigned int length; + cairo_destroy_func_t destroy; + void *closure; +}; + #endif /* CAIRO_TYPES_PRIVATE_H */ diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c index c272966a..6670b536 100644 --- a/src/cairo-user-font.c +++ b/src/cairo-user-font.c @@ -127,7 +127,7 @@ _cairo_user_scaled_glyph_init (void *abstract_font, cairo_destroy (cr); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (meta_surface); return status; } @@ -152,7 +152,7 @@ _cairo_user_scaled_glyph_init (void *abstract_font, analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1); cairo_surface_destroy (null_surface); status = analysis_surface->status; - if (status) + if (unlikely (status)) return status; _cairo_analysis_surface_set_ctm (analysis_surface, @@ -162,7 +162,7 @@ _cairo_user_scaled_glyph_init (void *abstract_font, _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox); cairo_surface_destroy (analysis_surface); - if (status) + if (unlikely (status)) return status; _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2); @@ -215,7 +215,7 @@ _cairo_user_scaled_glyph_init (void *abstract_font, - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y)); status = _cairo_meta_surface_replay (meta_surface, surface); - if (status) { + if (unlikely (status)) { cairo_surface_destroy(surface); return status; } @@ -232,7 +232,7 @@ _cairo_user_scaled_glyph_init (void *abstract_font, status = _cairo_meta_surface_get_path (meta_surface, path); - if (status) { + if (unlikely (status)) { _cairo_path_fixed_destroy (path); return status; } @@ -355,7 +355,7 @@ _cairo_user_scaled_font_get_implementation (cairo_toy_font_face_t *toy_face, face, (cairo_destroy_func_t) cairo_font_face_destroy); - if (status) { + if (unlikely (status)) { cairo_font_face_destroy (face); return status; } @@ -376,7 +376,7 @@ _cairo_user_scaled_font_create_toy (cairo_toy_font_face_t *toy_face, cairo_status_t status; status = _cairo_user_scaled_font_get_implementation (toy_face, &face); - if (status) + if (unlikely (status)) return status; status = _cairo_user_font_face_scaled_font_create (face, @@ -384,7 +384,7 @@ _cairo_user_scaled_font_create_toy (cairo_toy_font_face_t *toy_face, ctm, font_options, font); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -420,7 +420,7 @@ _cairo_user_font_face_scaled_font_create (void *abstract_ font_face->immutable = TRUE; user_scaled_font = malloc (sizeof (cairo_user_scaled_font_t)); - if (user_scaled_font == NULL) + if (unlikely (user_scaled_font == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_scaled_font_init (&user_scaled_font->base, @@ -428,7 +428,7 @@ _cairo_user_font_face_scaled_font_create (void *abstract_ font_matrix, ctm, options, &_cairo_user_scaled_font_backend); - if (status) { + if (unlikely (status)) { free (user_scaled_font); return status; } diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c index 553ef406..94927aeb 100644 --- a/src/cairo-win32-printing-surface.c +++ b/src/cairo-win32-printing-surface.c @@ -1,7 +1,7 @@ /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ /* Cairo - a vector graphics library with display and print output * - * Copyright © 2007 Adrian Johnson + * Copyright © 2007, 2008 Adrian Johnson * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -52,6 +52,7 @@ #include "cairo-win32-private.h" #include "cairo-meta-surface-private.h" #include "cairo-scaled-font-subsets-private.h" +#include "cairo-image-info-private.h" #include <windows.h> @@ -75,6 +76,14 @@ # define GRADIENT_FILL_RECT_H 0x00 #endif +#if !defined(CHECKJPEGFORMAT) +# define CHECKJPEGFORMAT 0x1017 +#endif + +#if !defined(CHECKPNGFORMAT) +# define CHECKPNGFORMAT 0x1018 +#endif + #define PELS_72DPI ((LONG)(72. / 0.0254)) static const cairo_surface_backend_t cairo_win32_printing_surface_backend; @@ -99,6 +108,20 @@ _cairo_win32_printing_surface_init_ps_mode (cairo_win32_surface_t *surface) surface->flags |= CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT; } +static void +_cairo_win32_printing_surface_init_image_support (cairo_win32_surface_t *surface) +{ + DWORD word; + + word = CHECKJPEGFORMAT; + if (ExtEscape(surface->dc, QUERYESCSUPPORT, sizeof(word), (char *)&word, 0, (char *)NULL) > 0) + surface->flags |= CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG; + + word = CHECKPNGFORMAT; + if (ExtEscape(surface->dc, QUERYESCSUPPORT, sizeof(word), (char *)&word, 0, (char *)NULL) > 0) + surface->flags |= CAIRO_WIN32_SURFACE_CAN_CHECK_PNG; +} + static cairo_int_status_t analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern) { @@ -486,6 +509,83 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa return status; } +static cairo_int_status_t +_cairo_win32_printing_surface_check_jpeg (cairo_win32_surface_t *surface, + cairo_surface_t *source, + const unsigned char **data, + unsigned int *length, + cairo_image_info_t *info) +{ + const unsigned char *mime_data; + unsigned int mime_data_length; + cairo_int_status_t status; + DWORD result; + + if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_image_info_get_jpeg_info (info, mime_data, mime_data_length); + if (status) + return status; + + result = 0; + if (ExtEscape(surface->dc, CHECKJPEGFORMAT, mime_data_length, (char *) mime_data, + sizeof(result), (char *) &result) <= 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (result != 1) + return CAIRO_INT_STATUS_UNSUPPORTED; + + *data = mime_data; + *length = mime_data_length; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_win32_printing_surface_check_png (cairo_win32_surface_t *surface, + cairo_surface_t *source, + const unsigned char **data, + unsigned int *length, + cairo_image_info_t *info) +{ + const unsigned char *mime_data; + unsigned int mime_data_length; + + cairo_int_status_t status; + DWORD result; + + if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_CHECK_PNG)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_PNG, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_image_info_get_png_info (info, mime_data, mime_data_length); + if (status) + return status; + + result = 0; + if (ExtEscape(surface->dc, CHECKPNGFORMAT, mime_data_length, (char *) mime_data, + sizeof(result), (char *) &result) <= 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (result != 1) + return CAIRO_INT_STATUS_UNSUPPORTED; + + *data = mime_data; + *length = mime_data_length; + + return CAIRO_STATUS_SUCCESS; +} + static cairo_status_t _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surface, cairo_surface_pattern_t *pattern) @@ -503,6 +603,11 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf int x_tile, y_tile, left, right, top, bottom; RECT clip; const cairo_color_t *background_color; + const unsigned char *mime_data; + unsigned int mime_size; + cairo_image_info_t mime_info; + cairo_bool_t use_mime; + DWORD mime_type; /* If we can't use StretchDIBits with this surface, we can't do anything * here. @@ -532,7 +637,26 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf goto CLEANUP_IMAGE; } - if (image->format != CAIRO_FORMAT_RGB24) { + mime_type = BI_JPEG; + status = _cairo_win32_printing_surface_check_jpeg (surface, + pattern->surface, + &mime_data, + &mime_size, + &mime_info); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + mime_type = BI_PNG; + status = _cairo_win32_printing_surface_check_png (surface, + pattern->surface, + &mime_data, + &mime_size, + &mime_info); + } + if (status && status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + use_mime = (status == CAIRO_STATUS_SUCCESS); + + if (!use_mime && image->format != CAIRO_FORMAT_RGB24) { cairo_surface_pattern_t opaque_pattern; opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, @@ -577,14 +701,14 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf } bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bi.bmiHeader.biWidth = opaque_image->width; - bi.bmiHeader.biHeight = -opaque_image->height; - bi.bmiHeader.biSizeImage = 0; + bi.bmiHeader.biWidth = use_mime ? mime_info.width : opaque_image->width; + bi.bmiHeader.biHeight = use_mime ? - mime_info.height : -opaque_image->height; + bi.bmiHeader.biSizeImage = use_mime ? mime_size : 0; bi.bmiHeader.biXPelsPerMeter = PELS_72DPI; bi.bmiHeader.biYPelsPerMeter = PELS_72DPI; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; - bi.bmiHeader.biCompression = BI_RGB; + bi.bmiHeader.biCompression = use_mime ? mime_type : BI_RGB; bi.bmiHeader.biClrUsed = 0; bi.bmiHeader.biClrImportant = 0; @@ -626,9 +750,9 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf opaque_image->height, 0, 0, - opaque_image->width, - opaque_image->height, - opaque_image->data, + use_mime ? mime_info.width : opaque_image->width, + use_mime ? mime_info.height : opaque_image->height, + use_mime ? mime_data : opaque_image->data, &bi, DIB_RGB_COLORS, SRCCOPY)) @@ -1037,7 +1161,8 @@ _cairo_win32_printing_surface_get_font_options (void *abstract_ static cairo_int_status_t _cairo_win32_printing_surface_paint (void *abstract_surface, cairo_operator_t op, - const cairo_pattern_t *source) + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents) { cairo_win32_surface_t *surface = abstract_surface; cairo_solid_pattern_t clear; @@ -1114,7 +1239,8 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface, cairo_matrix_t *stroke_ctm, cairo_matrix_t *stroke_ctm_inverse, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_win32_surface_t *surface = abstract_surface; cairo_int_status_t status; @@ -1235,7 +1361,8 @@ _cairo_win32_printing_surface_fill (void *abstract_surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { cairo_win32_surface_t *surface = abstract_surface; cairo_int_status_t status; @@ -1294,7 +1421,8 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs) + int *remaining_glyphs, + cairo_rectangle_int_t *extents) { cairo_win32_surface_t *surface = abstract_surface; cairo_status_t status = CAIRO_STATUS_SUCCESS; @@ -1414,7 +1542,8 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac status = _cairo_win32_surface_show_glyphs (surface, op, source, glyphs, num_glyphs, scaled_font, - remaining_glyphs); + remaining_glyphs, + extents); if (surface->has_ctm) cairo_scaled_font_destroy (scaled_font); @@ -1589,6 +1718,7 @@ cairo_win32_printing_surface_create (HDC hdc) surface->flags |= CAIRO_WIN32_SURFACE_FOR_PRINTING; _cairo_win32_printing_surface_init_ps_mode (surface); + _cairo_win32_printing_surface_init_image_support (surface); _cairo_surface_init (&surface->base, &cairo_win32_printing_surface_backend, CAIRO_CONTENT_COLOR_ALPHA); @@ -1622,6 +1752,8 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend = { NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ _cairo_win32_printing_surface_show_page, NULL, /* set_clip_region */ diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h index 09f63286..51564d04 100644 --- a/src/cairo-win32-private.h +++ b/src/cairo-win32-private.h @@ -117,6 +117,12 @@ enum { /* Whether we can use GradientFill rectangles with this surface */ CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT = (1<<6), + + /* Whether we can use the CHECKJPEGFORMAT escape function */ + CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG = (1<<7), + + /* Whether we can use the CHECKJPEGFORMAT escape function */ + CAIRO_WIN32_SURFACE_CAN_CHECK_PNG = (1<<8), }; cairo_status_t @@ -145,7 +151,8 @@ _cairo_win32_surface_show_glyphs (void *surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs); + int *remaining_glyphs, + cairo_rectangle_int_t *extents); cairo_surface_t * _cairo_win32_surface_create_similar (void *abstract_src, diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c index 05f5188c..03a8f61a 100644 --- a/src/cairo-win32-surface.c +++ b/src/cairo-win32-surface.c @@ -872,6 +872,9 @@ _cairo_win32_surface_composite_inner (cairo_win32_surface_t *src, return CAIRO_STATUS_SUCCESS; } +/* from pixman-private.h */ +#define MOD(a,b) ((a) < 0 ? ((b) - ((-(a) - 1) % (b))) - 1 : (a) % (b)) + static cairo_int_status_t _cairo_win32_surface_composite (cairo_operator_t op, const cairo_pattern_t *pattern, @@ -1153,8 +1156,8 @@ _cairo_win32_surface_composite (cairo_operator_t op, uint32_t rendered_width = 0, rendered_height = 0; uint32_t to_render_height, to_render_width; int32_t piece_x, piece_y; - int32_t src_start_x = src_r.x % src_extents.width; - int32_t src_start_y = src_r.y % src_extents.height; + int32_t src_start_x = MOD(src_r.x, src_extents.width); + int32_t src_start_y = MOD(src_r.y, src_extents.height); if (needs_scale) goto UNSUPPORTED; @@ -1469,11 +1472,12 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface, /* Create a GDI region for the cairo region */ _cairo_region_get_extents (region, &extents); + num_boxes = 0; status = _cairo_region_get_boxes (region, &num_boxes, &boxes); if (status) return status; - if (num_boxes == 1 && + if (num_boxes == 1 && boxes[0].p1.x == 0 && boxes[0].p1.y == 0 && boxes[0].p2.x == surface->extents.width && @@ -1566,7 +1570,8 @@ _cairo_win32_surface_show_glyphs (void *surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs) + int *remaining_glyphs, + cairo_rectangle_int_t *extents) { #if CAIRO_HAS_WIN32_FONT cairo_win32_surface_t *dst = surface; @@ -1977,6 +1982,8 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = { _cairo_win32_surface_composite, _cairo_win32_surface_fill_rectangles, NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ _cairo_win32_surface_set_clip_region, diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index d5146592..6f246f80 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -1560,6 +1560,7 @@ _cairo_xcb_surface_set_clip_region (void *abstract_surface, xcb_rectangle_t *rects = NULL; int n_boxes, i; + n_boxes = 0; status = _cairo_region_get_boxes (region, &n_boxes, &boxes); if (status) return status; @@ -1683,6 +1684,8 @@ static const cairo_surface_backend_t cairo_xcb_surface_backend = { _cairo_xcb_surface_composite, _cairo_xcb_surface_fill_rectangles, _cairo_xcb_surface_composite_trapezoids, + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ _cairo_xcb_surface_set_clip_region, @@ -2416,6 +2419,9 @@ _cairo_xcb_surface_emit_glyphs (cairo_xcb_surface_t *dst, } } + /* We wouldn't want to leak memory, would we? */ + free(output_glyphs); + return CAIRO_STATUS_SUCCESS; } diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c index 14e50d60..e85174b7 100644 --- a/src/cairo-xlib-display.c +++ b/src/cairo-xlib-display.c @@ -248,7 +248,7 @@ _cairo_xlib_display_get (Display *dpy, } display = malloc (sizeof (cairo_xlib_display_t)); - if (display == NULL) { + if (unlikely (display == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto UNLOCK; } @@ -262,7 +262,7 @@ _cairo_xlib_display_get (Display *dpy, XRenderQueryVersion (dpy, &render_major, &render_minor); codes = XAddExtension (dpy); - if (codes == NULL) { + if (unlikely (codes == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); free (display); display = NULL; @@ -287,25 +287,54 @@ _cairo_xlib_display_get (Display *dpy, sizeof (display->cached_xrender_formats)); display->buggy_repeat = FALSE; + + /* This buggy_repeat condition is very complicated because there + * are multiple X server code bases (with multiple versioning + * schemes within a code base), and multiple bugs. + * + * The X servers: + * + * 1. The Vendor=="XFree86" code base with release numbers such + * as 4.7.0 (VendorRelease==40700000). + * + * 2. The Vendor=="X.Org" code base (a descendant of the + * XFree86 code base). It originally had things like + * VendorRelease==60700000 for release 6.7.0 but then changed + * its versioning scheme so that, for example, + * VendorRelease==10400000 for the 1.4.0 X server within the + * X.Org 7.3 release. + * + * The bugs: + * + * 1. The original bug that led to the buggy_repeat + * workaround. This was a bug that Owen Taylor investigated, + * understood well, and characterized against carious X + * servers. Confirmed X servers with this bug include: + * + * "XFree86" <= 40500000 + * "X.Org" <= 60802000 (only with old numbering >= 60700000) + * + * 2. A separate bug resulting in a crash of the X server when + * using cairo's extend-reflect test case, (which, surprisingly + * enough was not passing RepeatReflect to the X server, but + * instead using RepeatNormal in a workaround). Nobody to date + * has understood the bug well, but it appears to be gone as of + * the X.Org 1.4.0 server. This bug is coincidentally avoided + * by using the same buggy_repeat workaround. Confirmed X + * servers with this bug include: + * + * "X.org" == 60900000 (old versioning scheme) + * "X.org" < 10400000 (new numbering scheme) + * + * For the old-versioning-scheme X servers we don't know + * exactly when second the bug started, but since bug 1 is + * present through 6.8.2 and bug 2 is present in 6.9.0 it seems + * safest to just blacklist all old-versioning-scheme X servers, + * (just using VendorRelase < 70000000), as buggy_repeat=TRUE. + */ if (strstr (ServerVendor (dpy), "X.Org") != NULL) { - /* When modularized, the X.Org server VendorRelease was - * bogusly reset to a very small number, without any change in - * the ServerVendor string. We avoid considering the new - * servers with the small number as buggy by restricting the - * test to known bad releases. But there could be a problem - * again in the future if X.Org server versions ever climb - * back up to 6.7 or 6.8. */ - if (VendorRelease (dpy) >= 60700000 && VendorRelease (dpy) <= 60802000) + if (VendorRelease (dpy) >= 60700000 && VendorRelease (dpy) < 70000000) display->buggy_repeat = TRUE; - - /* But even the new modular server has bugs, (bad enough to - * crash the X server), that it so happens we can avoid with - * the exact same buggy_repeat workaround. We've verified that - * this bug exists as least as late as version 1.3.0.0, (which - * is in Fedora 8), and is gone again in version 1.4.99.901 - * (from a Fedora 9 Beta). Versions between those are still - * unknown, but until we learn more, we'll assume that any 1.3 - * version is buggy. */ if (VendorRelease (dpy) < 10400000) display->buggy_repeat = TRUE; } else if (strstr (ServerVendor (dpy), "XFree86") != NULL) { diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c index 9dd411ed..3b1ae2e1 100644 --- a/src/cairo-xlib-screen.c +++ b/src/cairo-xlib-screen.c @@ -352,7 +352,7 @@ _cairo_xlib_screen_info_get (cairo_xlib_display_t *display, info = _cairo_xlib_screen_info_reference (info); } else { info = malloc (sizeof (cairo_xlib_screen_info_t)); - if (info == NULL) + if (unlikely (info == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); CAIRO_REFERENCE_COUNT_INIT (&info->ref_count, 2); /* Add one for display cache */ @@ -485,7 +485,7 @@ _cairo_xlib_screen_get_visual_info (cairo_xlib_screen_info_t *info, XScreenNumberOfScreen (info->screen), visual->visualid, &ret); - if (status) + if (unlikely (status)) return status; CAIRO_MUTEX_LOCK (info->mutex); @@ -506,7 +506,7 @@ _cairo_xlib_screen_get_visual_info (cairo_xlib_screen_info_t *info, status = _cairo_array_append (&info->visuals, &ret); CAIRO_MUTEX_UNLOCK (info->mutex); - if (status) { + if (unlikely (status)) { _cairo_xlib_visual_info_destroy (dpy, ret); return status; } diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h index e06fd978..fe37e5fb 100644 --- a/src/cairo-xlib-surface-private.h +++ b/src/cairo-xlib-surface-private.h @@ -85,7 +85,8 @@ struct _cairo_xlib_surface { unsigned int clip_dirty; cairo_bool_t have_clip_rects; - XRectangle embedded_clip_rects[4]; + cairo_bool_t gc_has_clip_rects; + XRectangle embedded_clip_rects[8]; XRectangle *clip_rects; int num_clip_rects; diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 7efe8287..68d81922 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -86,7 +86,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs); + int *remaining_glyphs, + cairo_rectangle_int_t *extents); /* * Instead of taking two round trips for each blending request, @@ -146,9 +147,8 @@ _cairo_xlib_surface_create_similar_with_format (void *abstract_src, if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)) return NULL; - xrender_format = _cairo_xlib_display_get_xrender_format ( - src->display, - format); + xrender_format = _cairo_xlib_display_get_xrender_format (src->display, + format); if (xrender_format == NULL) return NULL; @@ -306,7 +306,7 @@ _cairo_xlib_surface_finish (void *abstract_surface) status2 = _cairo_xlib_screen_put_gc (surface->screen_info, surface->depth, surface->gc, - surface->have_clip_rects); + surface->gc_has_clip_rects); surface->gc = NULL; if (status == CAIRO_STATUS_SUCCESS) status = status2; @@ -671,7 +671,7 @@ _get_image_surface (cairo_xlib_surface_t *surface, Pixmap pixmap; status = _cairo_xlib_surface_ensure_gc (surface); - if (status) + if (unlikely (status)) return status; pixmap = XCreatePixmap (surface->dpy, @@ -716,7 +716,7 @@ _get_image_surface (cairo_xlib_surface_t *surface, ximage->height, ximage->bytes_per_line); status = image->base.status; - if (status) + if (unlikely (status)) goto BAIL; /* Let the surface take ownership of the data */ @@ -777,14 +777,14 @@ _get_image_surface (cairo_xlib_surface_t *surface, status = _cairo_xlib_screen_get_visual_info (surface->screen_info, surface->visual, &visual_info); - if (status) + if (unlikely (status)) goto BAIL; } image = (cairo_image_surface_t *) cairo_image_surface_create (format, ximage->width, ximage->height); status = image->base.status; - if (status) + if (unlikely (status)) goto BAIL; data = cairo_image_surface_get_data (&image->base); @@ -821,7 +821,7 @@ _get_image_surface (cairo_xlib_surface_t *surface, BAIL: XDestroyImage (ximage); - if (status) { + if (unlikely (status)) { if (image) { cairo_surface_destroy (&image->base); image = NULL; @@ -870,6 +870,7 @@ _cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface) static void _cairo_xlib_surface_set_gc_clip_rects (cairo_xlib_surface_t *surface) { + surface->gc_has_clip_rects = surface->have_clip_rects; if (surface->have_clip_rects) { XSetClipRectangles(surface->dpy, surface->gc, 0, 0, @@ -908,7 +909,7 @@ _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface) gcv.graphics_exposures = False; surface->gc = XCreateGC (surface->dpy, surface->drawable, GCGraphicsExposures, &gcv); - if (!surface->gc) + if (unlikely (surface->gc == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } } @@ -988,7 +989,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface, ximage.bits_per_pixel); ximage.bytes_per_line = stride; ximage.data = _cairo_malloc_ab (stride, ximage.height); - if (ximage.data == NULL) + if (unlikely (ximage.data == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); own_data = TRUE; @@ -1012,7 +1013,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface, status = _cairo_xlib_screen_get_visual_info (surface->screen_info, surface->visual, &visual_info); - if (status) + if (unlikely (status)) goto BAIL; } @@ -1069,7 +1070,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface, } status = _cairo_xlib_surface_ensure_gc (surface); - if (status) + if (unlikely (status)) goto BAIL; XPutImage(surface->dpy, surface->drawable, surface->gc, @@ -1095,7 +1096,7 @@ _cairo_xlib_surface_acquire_source_image (void *abstract_surf _cairo_xlib_display_notify (surface->display); status = _get_image_surface (surface, NULL, &image, NULL); - if (status) + if (unlikely (status)) return status; *image_out = image; @@ -1126,7 +1127,7 @@ _cairo_xlib_surface_acquire_dest_image (void *abstract_surfac _cairo_xlib_display_notify (surface->display); status = _get_image_surface (surface, interest_rect, &image, image_rect_out); - if (status) + if (unlikely (status)) return status; *image_out = image; @@ -1215,7 +1216,7 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface, src_x, src_y, width, height, 0, 0); - if (status) { + if (unlikely (status)) { cairo_surface_destroy (&clone->base); return status; } @@ -1262,7 +1263,7 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac _cairo_image_surface_create_with_content (solid_pattern->content, width, height); status = image->base.status; - if (status) + if (unlikely (status)) goto BAIL; pixmap = XCreatePixmap (other->dpy, @@ -1278,26 +1279,26 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac width, height, other->depth); status = surface->base.status; - if (status) + if (unlikely (status)) goto BAIL; status = _cairo_surface_paint (&image->base, CAIRO_OPERATOR_SOURCE, - &solid_pattern->base); - if (status) + &solid_pattern->base, NULL); + if (unlikely (status)) goto BAIL; status = _draw_image_surface (surface, image, 0, 0, width, height, 0, 0); - if (status) + if (unlikely (status)) goto BAIL; BAIL: cairo_surface_destroy (&image->base); - if (status) { + if (unlikely (status)) { if (pixmap != None) XFreePixmap (other->dpy, pixmap); cairo_surface_destroy (&surface->base); @@ -1311,24 +1312,28 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac static cairo_status_t _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface, - cairo_matrix_t *matrix) + cairo_matrix_t *matrix, + double xc, + double yc) { XTransform xtransform; if (!surface->src_picture) return CAIRO_STATUS_SUCCESS; - + /* Casting between pixman_transform_t and XTransform is safe because * they happen to be the exact same type. */ - _cairo_matrix_to_pixman_matrix (matrix, (pixman_transform_t *)&xtransform); + _cairo_matrix_to_pixman_matrix (matrix, + (pixman_transform_t *) &xtransform, + xc, yc); if (memcmp (&xtransform, &surface->xtransform, sizeof (XTransform)) == 0) return CAIRO_STATUS_SUCCESS; if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) return CAIRO_INT_STATUS_UNSUPPORTED; - + XRenderSetPictureTransform (surface->dpy, surface->src_picture, &xtransform); surface->xtransform = xtransform; @@ -1410,14 +1415,17 @@ _cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat) static cairo_int_status_t _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface, - cairo_surface_attributes_t *attributes) + cairo_surface_attributes_t *attributes, + double xc, + double yc) { cairo_int_status_t status; _cairo_xlib_surface_ensure_src_picture (surface); - status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix); - if (status) + status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix, + xc, yc); + if (unlikely (status)) return status; switch (attributes->extend) { @@ -1434,7 +1442,7 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface, } status = _cairo_xlib_surface_set_filter (surface, attributes->filter); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -1719,7 +1727,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, (cairo_surface_t **) &src, (cairo_surface_t **) &mask, &src_attr, &mask_attr); - if (status) + if (unlikely (status)) return status; /* check for fallback surfaces that we cannot handle ... */ @@ -1745,14 +1753,18 @@ _cairo_xlib_surface_composite (cairo_operator_t op, switch (operation) { case DO_RENDER: - status = _cairo_xlib_surface_set_attributes (src, &src_attr); - if (status) + status = _cairo_xlib_surface_set_attributes (src, &src_attr, + dst_x + width / 2., + dst_y + height / 2.); + if (unlikely (status)) goto BAIL; _cairo_xlib_surface_ensure_dst_picture (dst); if (mask) { - status = _cairo_xlib_surface_set_attributes (mask, &mask_attr); - if (status) + status = _cairo_xlib_surface_set_attributes (mask, &mask_attr, + dst_x + width / 2., + dst_y + height/ 2.); + if (unlikely (status)) goto BAIL; XRenderComposite (dst->dpy, @@ -1783,7 +1795,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, case DO_XCOPYAREA: status = _cairo_xlib_surface_ensure_gc (dst); - if (status) + if (unlikely (status)) goto BAIL; is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix, @@ -1811,7 +1823,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, */ status = _cairo_xlib_surface_ensure_gc (dst); - if (status) + if (unlikely (status)) goto BAIL; is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity); @@ -1866,7 +1878,7 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface, _cairo_pattern_init_solid (&solid, color, CAIRO_CONTENT_COLOR); status = _cairo_xlib_surface_ensure_gc (surface); - if (status) + if (unlikely (status)) return status; status = _cairo_pattern_acquire_surface (&solid.base, &surface->base, @@ -1875,7 +1887,7 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface, ARRAY_LENGTH (dither_pattern), &solid_surface, &attrs); - if (status) + if (unlikely (status)) return status; if (! _cairo_surface_is_xlib (solid_surface)) { @@ -1911,8 +1923,6 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, { cairo_xlib_surface_t *surface = abstract_surface; XRenderColor render_color; - XRectangle static_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)]; - XRectangle *xrects = static_xrects; int i; _cairo_xlib_display_notify (surface->display); @@ -1948,9 +1958,12 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, rects->width, rects->height); } else { + XRectangle static_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)]; + XRectangle *xrects = static_xrects; + if (num_rects > ARRAY_LENGTH (static_xrects)) { xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle)); - if (xrects == NULL) + if (unlikely (xrects == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -2122,7 +2135,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, src_x, src_y, width, height, (cairo_surface_t **) &src, &attributes); - if (status) + if (unlikely (status)) return status; operation = _recategorize_composite_operation (dst, op, src, @@ -2160,8 +2173,10 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, render_src_y = src_y + render_reference_y - dst_y; _cairo_xlib_surface_ensure_dst_picture (dst); - status = _cairo_xlib_surface_set_attributes (src, &attributes); - if (status) + status = _cairo_xlib_surface_set_attributes (src, &attributes, + dst_x + width / 2., + dst_y + height / 2.); + if (unlikely (status)) goto BAIL; if (!_cairo_operator_bounded_by_mask (op)) { @@ -2209,7 +2224,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, if (num_traps > ARRAY_LENGTH (xtraps_stack)) { xtraps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid)); - if (xtraps == NULL) { + if (unlikely (xtraps == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto BAIL; } @@ -2246,6 +2261,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, return status; } +COMPILE_TIME_ASSERT (sizeof (XRectangle) <= sizeof (cairo_box_int_t)); static cairo_int_status_t _cairo_xlib_surface_set_clip_region (void *abstract_surface, cairo_region_t *region) @@ -2283,14 +2299,16 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, _cairo_region_init_rect (&bound, &rect); _cairo_region_init (&bounded); status = _cairo_region_intersect (&bounded, &bound, region); - if (status) { + if (unlikely (status)) { _cairo_region_fini (&bound); _cairo_region_fini (&bounded); return status; } + n_boxes = sizeof (surface->embedded_clip_rects) / sizeof (cairo_box_int_t); + boxes = (cairo_box_int_t *) surface->embedded_clip_rects; status = _cairo_region_get_boxes (&bounded, &n_boxes, &boxes); - if (status) { + if (unlikely (status)) { _cairo_region_fini (&bound); _cairo_region_fini (&bounded); return status; @@ -2298,24 +2316,24 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, if (n_boxes > ARRAY_LENGTH (surface->embedded_clip_rects)) { rects = _cairo_malloc_ab (n_boxes, sizeof (XRectangle)); - if (rects == NULL) { + if (unlikely (rects == NULL)) { _cairo_region_boxes_fini (&bounded, boxes); _cairo_region_fini (&bound); _cairo_region_fini (&bounded); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } - } else { + } else rects = surface->embedded_clip_rects; - } for (i = 0; i < n_boxes; i++) { rects[i].x = boxes[i].p1.x; rects[i].y = boxes[i].p1.y; - rects[i].width = boxes[i].p2.x - boxes[i].p1.x; - rects[i].height = boxes[i].p2.y - boxes[i].p1.y; + rects[i].width = boxes[i].p2.x - rects[i].x; + rects[i].height = boxes[i].p2.y - rects[i].y; } - _cairo_region_boxes_fini (&bounded, boxes); + if (boxes != (cairo_box_int_t *) surface->embedded_clip_rects) + _cairo_region_boxes_fini (&bounded, boxes); _cairo_region_fini (&bounded); _cairo_region_fini (&bound); @@ -2410,7 +2428,7 @@ _cairo_xlib_surface_reset (void *abstract_surface) cairo_status_t status; status = _cairo_xlib_surface_set_clip_region (surface, NULL); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -2428,6 +2446,8 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = { _cairo_xlib_surface_composite, _cairo_xlib_surface_fill_rectangles, _cairo_xlib_surface_composite_trapezoids, + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ _cairo_xlib_surface_set_clip_region, @@ -2545,17 +2565,17 @@ _cairo_xlib_surface_create_internal (Display *dpy, return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL)); status = _cairo_xlib_display_get (dpy, &display); - if (status) + if (unlikely (status)) return _cairo_surface_create_in_error (status); status = _cairo_xlib_screen_info_get (display, screen, &screen_info); - if (status) { + if (unlikely (status)) { _cairo_xlib_display_destroy (display); return _cairo_surface_create_in_error (status); } surface = malloc (sizeof (cairo_xlib_surface_t)); - if (surface == NULL) { + if (unlikely (surface == NULL)) { _cairo_xlib_screen_info_destroy (screen_info); _cairo_xlib_display_destroy (display); return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); @@ -2619,6 +2639,7 @@ _cairo_xlib_surface_create_internal (Display *dpy, surface->xtransform = identity; surface->have_clip_rects = FALSE; + surface->gc_has_clip_rects = FALSE; surface->clip_rects = surface->embedded_clip_rects; surface->num_clip_rects = 0; surface->clip_dirty = 0; @@ -2883,7 +2904,7 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface, surface->display, XRenderFreePicture, surface->dst_picture); - if (status) { + if (unlikely (status)) { status = _cairo_surface_set_error (&surface->base, status); return; } @@ -2896,7 +2917,7 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface, surface->display, XRenderFreePicture, surface->src_picture); - if (status) { + if (unlikely (status)) { status = _cairo_surface_set_error (&surface->base, status); return; } @@ -3148,12 +3169,12 @@ _cairo_xlib_surface_font_init (Display *dpy, int i; font_private = malloc (sizeof (cairo_xlib_surface_font_private_t)); - if (font_private == NULL) + if (unlikely (font_private == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); font_private->scaled_font = scaled_font; status = _cairo_xlib_display_get (dpy, &font_private->display); - if (status) { + if (unlikely (status)) { free (font_private); return status; } @@ -3269,7 +3290,7 @@ _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, to_free, free); /* XXX cannot propagate failure */ - if (status) + if (unlikely (status)) free (to_free); to_free = glyphset_info->pending_free_glyphs = NULL; @@ -3277,7 +3298,7 @@ _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, if (to_free == NULL) { to_free = malloc (sizeof (cairo_xlib_font_glyphset_free_glyphs_t)); - if (to_free == NULL) { + if (unlikely (to_free == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return; /* XXX cannot propagate failure */ } @@ -3425,7 +3446,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy, CAIRO_SCALED_GLYPH_INFO_METRICS | CAIRO_SCALED_GLYPH_INFO_SURFACE, pscaled_glyph); - if (status) + if (unlikely (status)) return status; scaled_glyph = *pscaled_glyph; @@ -3437,7 +3458,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy, if (scaled_font->surface_private == NULL) { status = _cairo_xlib_surface_font_init (dpy, scaled_font); - if (status) + if (unlikely (status)) return status; } @@ -3464,7 +3485,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy, tmp_surface = cairo_image_surface_create (glyphset_info->format, 1, 1); status = tmp_surface->status; - if (status) + if (unlikely (status)) goto BAIL; cr = cairo_create (tmp_surface); @@ -3478,7 +3499,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy, glyph_surface = (cairo_image_surface_t *) tmp_surface; - if (status) + if (unlikely (status)) goto BAIL; } @@ -3494,7 +3515,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy, glyph_surface->width, glyph_surface->height); status = tmp_surface->status; - if (status) + if (unlikely (status)) goto BAIL; tmp_surface->device_transform = glyph_surface->base.device_transform; @@ -3509,7 +3530,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy, glyph_surface = (cairo_image_surface_t *) tmp_surface; - if (status) + if (unlikely (status)) goto BAIL; } @@ -3559,7 +3580,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy, unsigned char *new, *n; new = malloc (c); - if (new == NULL) { + if (unlikely (new == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto BAIL; } @@ -3703,7 +3724,7 @@ _emit_glyphs_chunk (cairo_xlib_surface_t *dst, elts = stack_elts; } else { elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8)); - if (elts == NULL) + if (unlikely (elts == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -3844,7 +3865,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst, status = _cairo_xlib_surface_add_glyph (dst->dpy, scaled_font, &scaled_glyph); - if (status) { + if (unlikely (status)) { if (status == CAIRO_INT_STATUS_UNSUPPORTED) /* Break so we flush glyphs so far and let fallback code * handle the rest */ @@ -3966,7 +3987,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs) + int *remaining_glyphs, + cairo_rectangle_int_t *extents) { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_xlib_surface_t *dst = (cairo_xlib_surface_t*) abstract_dst; @@ -4034,7 +4056,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, 0, 0, 1, 1, (cairo_surface_t **) &src, &attributes); - if (status) + if (unlikely (status)) goto BAIL0; } else { cairo_rectangle_int_t glyph_extents; @@ -4043,7 +4065,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, glyphs, num_glyphs, &glyph_extents); - if (status) + if (unlikely (status)) goto BAIL0; status = _cairo_pattern_acquire_surface (src_pattern, &dst->base, @@ -4051,7 +4073,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, glyph_extents.width, glyph_extents.height, (cairo_surface_t **) &src, &attributes); - if (status) + if (unlikely (status)) goto BAIL0; } @@ -4062,8 +4084,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, goto BAIL1; } - status = _cairo_xlib_surface_set_attributes (src, &attributes); - if (status) + status = _cairo_xlib_surface_set_attributes (src, &attributes, 0, 0); + if (unlikely (status)) goto BAIL1; _cairo_scaled_font_freeze_cache (scaled_font); diff --git a/src/cairo-xlib-visual.c b/src/cairo-xlib-visual.c index f6eb1ee9..7dbe86c2 100644 --- a/src/cairo-xlib-visual.c +++ b/src/cairo-xlib-visual.c @@ -78,7 +78,7 @@ _cairo_xlib_visual_info_create (Display *dpy, ramp_index_to_short[i] = (0xffff * i + ((RAMP_SIZE-1)>>1)) / (RAMP_SIZE-1); info = malloc (sizeof (cairo_xlib_visual_info_t)); - if (info == NULL) + if (unlikely (info == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); info->visualid = visualid; diff --git a/src/cairo-xlib-xrender-private.h b/src/cairo-xlib-xrender-private.h index 329262c7..eee585cc 100644 --- a/src/cairo-xlib-xrender-private.h +++ b/src/cairo-xlib-xrender-private.h @@ -45,6 +45,24 @@ #include <X11/extensions/Xrender.h> #include <X11/extensions/renderproto.h> +/* We require Render >= 0.6. The following defines were only added in + * 0.10. Make sure they are defined. + */ + +/* Filters included in 0.10 */ +#ifndef FilterConvolution +#define FilterConvolution "convolution" +#endif + +/* Extended repeat attributes included in 0.10 */ +#ifndef RepeatNone +#define RepeatNone 0 +#define RepeatNormal 1 +#define RepeatPad 2 +#define RepeatReflect 3 +#endif + + #else /* !CAIRO_HAS_XLIB_XRENDER_SURFACE */ /* Provide dummy symbols and macros to get it compile and take the fallback diff --git a/src/cairo.c b/src/cairo.c index 06353319..b33c03b7 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -152,7 +152,7 @@ cairo_create (cairo_surface_t *target) return (cairo_t *) &_cairo_nil; cr = malloc (sizeof (cairo_t)); - if (cr == NULL) { + if (unlikely (cr == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_t *) &_cairo_nil; } @@ -166,9 +166,9 @@ cairo_create (cairo_surface_t *target) cr->gstate = cr->gstate_tail; cr->gstate_freelist = NULL; - status = _cairo_gstate_init (cr->gstate, target); - if (status) + status = _cairo_gstate_init (cr->gstate, target); + if (unlikely (status)) _cairo_set_error (cr, status); return cr; @@ -212,6 +212,8 @@ cairo_reference (cairo_t *cr) void cairo_destroy (cairo_t *cr) { + cairo_surface_t *surface; + if (cr == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count)) return; @@ -225,6 +227,15 @@ cairo_destroy (cairo_t *cr) break; } + /* The context is expected (>99% of all use cases) to be held for the + * duration of a single expose event/sequence of graphic operations. + * Therefore, on destroy we explicitly flush the Cairo pipeline of any + * pending operations. + */ + surface = _cairo_gstate_get_original_target (cr->gstate); + if (surface != NULL) + cairo_surface_flush (surface); + _cairo_gstate_fini (cr->gstate); while (cr->gstate_freelist != NULL) { cairo_gstate_t *gstate = cr->gstate_freelist; @@ -338,7 +349,7 @@ cairo_save (cairo_t *cr) return; status = _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def(cairo_save); @@ -360,7 +371,7 @@ cairo_restore (cairo_t *cr) return; status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def(cairo_restore); @@ -414,7 +425,6 @@ cairo_push_group (cairo_t *cr) { cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA); } -slim_hidden_def(cairo_push_group); /** * cairo_push_group_with_content: @@ -448,10 +458,10 @@ cairo_push_group_with_content (cairo_t *cr, cairo_content_t content) parent_surface = _cairo_gstate_get_target (cr->gstate); /* Get the extents that we'll use in creating our new group surface */ status = _cairo_surface_get_extents (parent_surface, &extents); - if (status) + if (unlikely (status)) goto bail; status = _cairo_clip_intersect_to_rectangle (_cairo_gstate_get_clip (cr->gstate), &extents); - if (status) + if (unlikely (status)) goto bail; group_surface = cairo_surface_create_similar (_cairo_gstate_get_target (cr->gstate), @@ -459,7 +469,7 @@ cairo_push_group_with_content (cairo_t *cr, cairo_content_t content) extents.width, extents.height); status = cairo_surface_status (group_surface); - if (status) + if (unlikely (status)) goto bail; /* Set device offsets on the new surface so that logically it appears at @@ -480,7 +490,7 @@ cairo_push_group_with_content (cairo_t *cr, cairo_content_t content) bail: cairo_surface_destroy (group_surface); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def(cairo_push_group_with_content); @@ -597,7 +607,6 @@ cairo_pop_group_to_source (cairo_t *cr) cairo_set_source (cr, group_pattern); cairo_pattern_destroy (group_pattern); } -slim_hidden_def(cairo_pop_group_to_source); /** * cairo_set_operator: @@ -619,7 +628,7 @@ cairo_set_operator (cairo_t *cr, cairo_operator_t op) return; status = _cairo_gstate_set_operator (cr->gstate, op); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def (cairo_set_operator); @@ -781,7 +790,7 @@ cairo_set_source (cairo_t *cr, cairo_pattern_t *source) } status = _cairo_gstate_set_source (cr->gstate, source); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def (cairo_set_source); @@ -829,9 +838,10 @@ cairo_set_tolerance (cairo_t *cr, double tolerance) _cairo_restrict_value (&tolerance, CAIRO_TOLERANCE_MINIMUM, tolerance); status = _cairo_gstate_set_tolerance (cr->gstate, tolerance); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } +slim_hidden_def (cairo_set_tolerance); /** * cairo_set_antialias: @@ -855,7 +865,7 @@ cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias) return; status = _cairo_gstate_set_antialias (cr->gstate, antialias); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -881,7 +891,7 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule) return; status = _cairo_gstate_set_fill_rule (cr->gstate, fill_rule); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -922,7 +932,7 @@ cairo_set_line_width (cairo_t *cr, double width) _cairo_restrict_value (&width, 0.0, width); status = _cairo_gstate_set_line_width (cr->gstate, width); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def (cairo_set_line_width); @@ -952,7 +962,7 @@ cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap) return; status = _cairo_gstate_set_line_cap (cr->gstate, line_cap); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def (cairo_set_line_cap); @@ -982,7 +992,7 @@ cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join) return; status = _cairo_gstate_set_line_join (cr->gstate, line_join); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def (cairo_set_line_join); @@ -1032,7 +1042,7 @@ cairo_set_dash (cairo_t *cr, status = _cairo_gstate_set_dash (cr->gstate, dashes, num_dashes, offset); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -1122,7 +1132,7 @@ cairo_set_miter_limit (cairo_t *cr, double limit) return; status = _cairo_gstate_set_miter_limit (cr->gstate, limit); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -1147,7 +1157,7 @@ cairo_translate (cairo_t *cr, double tx, double ty) return; status = _cairo_gstate_translate (cr->gstate, tx, ty); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -1171,7 +1181,7 @@ cairo_scale (cairo_t *cr, double sx, double sy) return; status = _cairo_gstate_scale (cr->gstate, sx, sy); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def (cairo_scale); @@ -1197,7 +1207,7 @@ cairo_rotate (cairo_t *cr, double angle) return; status = _cairo_gstate_rotate (cr->gstate, angle); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -1220,7 +1230,7 @@ cairo_transform (cairo_t *cr, return; status = _cairo_gstate_transform (cr->gstate, matrix); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -1242,7 +1252,7 @@ cairo_set_matrix (cairo_t *cr, return; status = _cairo_gstate_set_matrix (cr->gstate, matrix); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def (cairo_set_matrix); @@ -1383,7 +1393,7 @@ cairo_move_to (cairo_t *cr, double x, double y) y_fixed = _cairo_fixed_from_double (y); status = _cairo_path_fixed_move_to (cr->path, x_fixed, y_fixed); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def(cairo_move_to); @@ -1442,7 +1452,7 @@ cairo_line_to (cairo_t *cr, double x, double y) y_fixed = _cairo_fixed_from_double (y); status = _cairo_path_fixed_line_to (cr->path, x_fixed, y_fixed); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def (cairo_line_to); @@ -1497,7 +1507,7 @@ cairo_curve_to (cairo_t *cr, x1_fixed, y1_fixed, x2_fixed, y2_fixed, x3_fixed, y3_fixed); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def (cairo_curve_to); @@ -1631,7 +1641,7 @@ cairo_arc_to (cairo_t *cr, x1, y1, x2, y2, radius); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } */ @@ -1667,7 +1677,7 @@ cairo_rel_move_to (cairo_t *cr, double dx, double dy) dy_fixed = _cairo_fixed_from_double (dy); status = _cairo_path_fixed_rel_move_to (cr->path, dx_fixed, dy_fixed); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -1704,7 +1714,7 @@ cairo_rel_line_to (cairo_t *cr, double dx, double dy) dy_fixed = _cairo_fixed_from_double (dy); status = _cairo_path_fixed_rel_line_to (cr->path, dx_fixed, dy_fixed); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def(cairo_rel_line_to); @@ -1765,7 +1775,7 @@ cairo_rel_curve_to (cairo_t *cr, dx1_fixed, dy1_fixed, dx2_fixed, dy2_fixed, dx3_fixed, dy3_fixed); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -1817,7 +1827,7 @@ cairo_stroke_to_path (cairo_t *cr) /* The code in _cairo_meta_surface_get_path has a poorman's stroke_to_path */ status = _cairo_gstate_stroke_path (cr->gstate); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } #endif @@ -1857,7 +1867,7 @@ cairo_close_path (cairo_t *cr) return; status = _cairo_path_fixed_close_path (cr->path); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def(cairo_close_path); @@ -1897,8 +1907,6 @@ void cairo_path_extents (cairo_t *cr, double *x1, double *y1, double *x2, double *y2) { - cairo_status_t status; - if (cr->status) { if (x1) *x1 = 0.0; @@ -1912,13 +1920,10 @@ cairo_path_extents (cairo_t *cr, return; } - status = _cairo_gstate_path_extents (cr->gstate, - cr->path, - x1, y1, x2, y2); - if (status) - _cairo_set_error (cr, status); + _cairo_gstate_path_extents (cr->gstate, + cr->path, + x1, y1, x2, y2); } -slim_hidden_def (cairo_path_extents); /** * cairo_paint: @@ -1936,7 +1941,7 @@ cairo_paint (cairo_t *cr) return; status = _cairo_gstate_paint (cr->gstate); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def (cairo_paint); @@ -1975,7 +1980,7 @@ cairo_paint_with_alpha (cairo_t *cr, _cairo_pattern_init_solid (&pattern, &color, CAIRO_CONTENT_ALPHA); status = _cairo_gstate_mask (cr->gstate, &pattern.base); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); _cairo_pattern_fini (&pattern.base); @@ -2011,7 +2016,7 @@ cairo_mask (cairo_t *cr, } status = _cairo_gstate_mask (cr->gstate, pattern); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def (cairo_mask); @@ -2113,7 +2118,7 @@ cairo_stroke_preserve (cairo_t *cr) return; status = _cairo_gstate_stroke (cr->gstate, cr->path); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def(cairo_stroke_preserve); @@ -2156,7 +2161,7 @@ cairo_fill_preserve (cairo_t *cr) return; status = _cairo_gstate_fill (cr->gstate, cr->path); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def(cairo_fill_preserve); @@ -2182,7 +2187,7 @@ cairo_copy_page (cairo_t *cr) return; status = _cairo_gstate_copy_page (cr->gstate); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -2205,7 +2210,7 @@ cairo_show_page (cairo_t *cr) return; status = _cairo_gstate_show_page (cr->gstate); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -2239,7 +2244,7 @@ cairo_in_stroke (cairo_t *cr, double x, double y) status = _cairo_gstate_in_stroke (cr->gstate, cr->path, x, y, &inside); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); return inside; @@ -2264,17 +2269,14 @@ cairo_in_stroke (cairo_t *cr, double x, double y) cairo_bool_t cairo_in_fill (cairo_t *cr, double x, double y) { - cairo_status_t status; - cairo_bool_t inside = FALSE; + cairo_bool_t inside; if (cr->status) return 0; - status = _cairo_gstate_in_fill (cr->gstate, - cr->path, - x, y, &inside); - if (status) - _cairo_set_error (cr, status); + _cairo_gstate_in_fill (cr->gstate, + cr->path, + x, y, &inside); return inside; } @@ -2409,7 +2411,7 @@ cairo_stroke_extents (cairo_t *cr, status = _cairo_gstate_stroke_extents (cr->gstate, cr->path, x1, y1, x2, y2); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -2460,7 +2462,7 @@ cairo_fill_extents (cairo_t *cr, status = _cairo_gstate_fill_extents (cr->gstate, cr->path, x1, y1, x2, y2); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -2525,7 +2527,7 @@ cairo_clip_preserve (cairo_t *cr) return; status = _cairo_gstate_clip (cr->gstate, cr->path); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def(cairo_clip_preserve); @@ -2555,7 +2557,7 @@ cairo_reset_clip (cairo_t *cr) return; status = _cairo_gstate_reset_clip (cr->gstate); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -2593,7 +2595,7 @@ cairo_clip_extents (cairo_t *cr, } status = _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -2679,7 +2681,7 @@ cairo_select_font_face (cairo_t *cr, return; status = _cairo_gstate_select_font_face (cr->gstate, family, slant, weight); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -2707,7 +2709,7 @@ cairo_font_extents (cairo_t *cr, return; status = _cairo_gstate_get_font_extents (cr->gstate, extents); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -2730,7 +2732,7 @@ cairo_set_font_face (cairo_t *cr, return; status = _cairo_gstate_set_font_face (cr->gstate, font_face); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -2762,7 +2764,7 @@ cairo_get_font_face (cairo_t *cr) return (cairo_font_face_t*) &_cairo_font_face_nil; status = _cairo_gstate_get_font_face (cr->gstate, &font_face); - if (status) { + if (unlikely (status)) { _cairo_set_error (cr, status); return (cairo_font_face_t*) &_cairo_font_face_nil; } @@ -2794,7 +2796,7 @@ cairo_set_font_size (cairo_t *cr, double size) return; status = _cairo_gstate_set_font_size (cr->gstate, size); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } slim_hidden_def (cairo_set_font_size); @@ -2822,7 +2824,7 @@ cairo_set_font_matrix (cairo_t *cr, return; status = _cairo_gstate_set_font_matrix (cr->gstate, matrix); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -2866,7 +2868,7 @@ cairo_set_font_options (cairo_t *cr, return; status = cairo_font_options_status ((cairo_font_options_t *) options); - if (status) { + if (unlikely (status)) { _cairo_set_error (cr, status); return; } @@ -2930,15 +2932,15 @@ cairo_set_scaled_font (cairo_t *cr, } status = scaled_font->status; - if (status) + if (unlikely (status)) goto BAIL; status = _cairo_gstate_set_font_face (cr->gstate, scaled_font->font_face); - if (status) + if (unlikely (status)) goto BAIL; status = _cairo_gstate_set_font_matrix (cr->gstate, &scaled_font->font_matrix); - if (status) + if (unlikely (status)) goto BAIL; _cairo_gstate_set_font_options (cr->gstate, &scaled_font->options); @@ -2979,7 +2981,7 @@ cairo_get_scaled_font (cairo_t *cr) return _cairo_scaled_font_create_in_error (cr->status); status = _cairo_gstate_get_scaled_font (cr->gstate, &scaled_font); - if (status) { + if (unlikely (status)) { _cairo_set_error (cr, status); return _cairo_scaled_font_create_in_error (status); } @@ -3045,7 +3047,7 @@ cairo_text_extents (cairo_t *cr, extents); cairo_glyph_free (glyphs); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -3100,7 +3102,7 @@ cairo_glyph_extents (cairo_t *cr, status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs, extents); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -3136,12 +3138,14 @@ 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; - cairo_text_cluster_t *clusters = NULL; + cairo_glyph_t *glyphs, *last_glyph; + cairo_text_cluster_t *clusters; int utf8_len, num_glyphs, num_clusters; cairo_text_cluster_flags_t cluster_flags; double x, y; cairo_bool_t has_show_text_glyphs; + cairo_glyph_t stack_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)]; + cairo_text_cluster_t stack_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)]; if (cr->status) return; @@ -3156,13 +3160,19 @@ cairo_show_text (cairo_t *cr, const char *utf8) has_show_text_glyphs = cairo_surface_has_show_text_glyphs (cairo_get_target (cr)); + glyphs = stack_glyphs; + num_glyphs = ARRAY_LENGTH (stack_glyphs); + + clusters = stack_clusters; + num_clusters = ARRAY_LENGTH (stack_clusters); + status = _cairo_gstate_text_to_glyphs (cr->gstate, x, y, utf8, utf8_len, &glyphs, &num_glyphs, has_show_text_glyphs ? &clusters : NULL, &num_clusters, &cluster_flags); - if (status) + if (unlikely (status)) goto BAIL; if (num_glyphs == 0) @@ -3173,14 +3183,14 @@ cairo_show_text (cairo_t *cr, const char *utf8) glyphs, num_glyphs, clusters, num_clusters, cluster_flags); - if (status) + if (unlikely (status)) goto BAIL; last_glyph = &glyphs[num_glyphs - 1]; status = _cairo_gstate_glyph_extents (cr->gstate, last_glyph, 1, &extents); - if (status) + if (unlikely (status)) goto BAIL; x = last_glyph->x + extents.x_advance; @@ -3188,10 +3198,12 @@ cairo_show_text (cairo_t *cr, const char *utf8) cairo_move_to (cr, x, y); BAIL: - cairo_glyph_free (glyphs); - cairo_text_cluster_free (clusters); + if (glyphs != stack_glyphs) + cairo_glyph_free (glyphs); + if (clusters != stack_clusters) + cairo_text_cluster_free (clusters); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -3231,7 +3243,7 @@ cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs) glyphs, num_glyphs, NULL, 0, FALSE); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -3334,7 +3346,7 @@ cairo_show_text_glyphs (cairo_t *cr, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -3386,7 +3398,7 @@ cairo_text_path (cairo_t *cr, const char *utf8) NULL, NULL, NULL); - if (status) + if (unlikely (status)) goto BAIL; if (num_glyphs == 0) @@ -3396,7 +3408,7 @@ cairo_text_path (cairo_t *cr, const char *utf8) glyphs, num_glyphs, cr->path); - if (status) + if (unlikely (status)) goto BAIL; last_glyph = &glyphs[num_glyphs - 1]; @@ -3404,7 +3416,7 @@ cairo_text_path (cairo_t *cr, const char *utf8) last_glyph, 1, &extents); - if (status) + if (unlikely (status)) goto BAIL; x = last_glyph->x + extents.x_advance; @@ -3414,7 +3426,7 @@ cairo_text_path (cairo_t *cr, const char *utf8) BAIL: cairo_glyph_free (glyphs); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -3452,7 +3464,7 @@ cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs) status = _cairo_gstate_glyph_path (cr->gstate, glyphs, num_glyphs, cr->path); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } @@ -3872,7 +3884,7 @@ cairo_append_path (cairo_t *cr, } status = _cairo_path_append_to_context (path, cr); - if (status) + if (unlikely (status)) _cairo_set_error (cr, status); } diff --git a/src/cairo.h b/src/cairo.h index 7b7fe486..5e27478c 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -1883,6 +1883,7 @@ cairo_surface_status (cairo_surface_t *surface); * @CAIRO_SURFACE_TYPE_WIN32_PRINTING: The surface is a win32 printing surface * @CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: The surface is of type quartz_image * @CAIRO_SURFACE_TYPE_SDL: The surface is of type SDL, since 1.10 + * @CAIRO_SURFACE_TYPE_SCRIPT: The surface is of type script, since 1.10 * * #cairo_surface_type_t is used to describe the type of a given * surface. The surface types are also known as "backends" or "surface @@ -1922,7 +1923,8 @@ typedef enum _cairo_surface_type { CAIRO_SURFACE_TYPE_OS2, CAIRO_SURFACE_TYPE_WIN32_PRINTING, CAIRO_SURFACE_TYPE_QUARTZ_IMAGE, - CAIRO_SURFACE_TYPE_SDL + CAIRO_SURFACE_TYPE_SDL, + CAIRO_SURFACE_TYPE_SCRIPT } cairo_surface_type_t; cairo_public cairo_surface_type_t @@ -1954,6 +1956,24 @@ cairo_surface_set_user_data (cairo_surface_t *surface, void *user_data, cairo_destroy_func_t destroy); +#define CAIRO_MIME_TYPE_JPEG "image/jpeg" +#define CAIRO_MIME_TYPE_PNG "image/png" +#define CAIRO_MIME_TYPE_JP2 "image/jp2" + +cairo_public void +cairo_surface_get_mime_data (cairo_surface_t *surface, + const char *mime_type, + const unsigned char **data, + unsigned int *length); + +cairo_public cairo_status_t +cairo_surface_set_mime_data (cairo_surface_t *surface, + const char *mime_type, + const unsigned char *data, + unsigned int length, + cairo_destroy_func_t destroy, + void *closure); + cairo_public void cairo_surface_get_font_options (cairo_surface_t *surface, cairo_font_options_t *options); diff --git a/src/cairoint.h b/src/cairoint.h index 3e11604e..5a2a909c 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -234,6 +234,7 @@ be32_to_cpu(uint32_t v) #include "cairo-types-private.h" #include "cairo-cache-private.h" #include "cairo-reference-count-private.h" +#include "cairo-spans-private.h" cairo_private void _cairo_box_from_doubles (cairo_box_t *box, @@ -263,6 +264,13 @@ _cairo_box_intersects_line_segment (cairo_box_t *box, cairo_line_t *line); cairo_private cairo_bool_t _cairo_box_contains_point (cairo_box_t *box, cairo_point_t *point); +cairo_private void +_cairo_composite_rectangles_init (cairo_composite_rectangles_t *rects, + int all_x, + int all_y, + int width, + int height); + /* cairo-array.c structures and functions */ cairo_private void @@ -322,9 +330,16 @@ _cairo_user_data_array_set_data (cairo_user_data_array_t *array, void *user_data, cairo_destroy_func_t destroy); +#define _CAIRO_HASH_INIT_VALUE 5381 + cairo_private unsigned long _cairo_hash_string (const char *c); +cairo_private unsigned long +_cairo_hash_bytes (unsigned long hash, + const void *bytes, + unsigned int length); + /* * A #cairo_unscaled_font_t is just an opaque handle we use in the * glyph cache. @@ -339,6 +354,7 @@ 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 */ cairo_text_extents_t metrics; /* user-space metrics */ + cairo_text_extents_t fs_metrics; /* font-space metrics */ cairo_box_t bbox; /* device-space bounds */ int16_t x_advance; /* device-space rounded X advance */ int16_t y_advance; /* device-space rounded Y advance */ @@ -618,6 +634,20 @@ struct _cairo_surface_backend { cairo_trapezoid_t *traps, int num_traps); + cairo_warn cairo_span_renderer_t * + (*create_span_renderer) (cairo_operator_t op, + const cairo_pattern_t *pattern, + void *dst, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects); + + cairo_warn cairo_bool_t + (*check_span_renderer) (cairo_operator_t op, + const cairo_pattern_t *pattern, + void *dst, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects); + cairo_warn cairo_int_status_t (*copy_page) (void *surface); @@ -726,13 +756,15 @@ struct _cairo_surface_backend { cairo_warn cairo_int_status_t (*paint) (void *surface, cairo_operator_t op, - const cairo_pattern_t *source); + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents); cairo_warn cairo_int_status_t (*mask) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_pattern_t *mask); + const cairo_pattern_t *mask, + cairo_rectangle_int_t *extents); cairo_warn cairo_int_status_t (*stroke) (void *surface, @@ -743,7 +775,8 @@ struct _cairo_surface_backend { cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias); + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents); cairo_warn cairo_int_status_t (*fill) (void *surface, @@ -752,7 +785,8 @@ struct _cairo_surface_backend { cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias); + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents); cairo_warn cairo_int_status_t (*show_glyphs) (void *surface, @@ -761,7 +795,8 @@ struct _cairo_surface_backend { cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs); + int *remaining_glyphs, + cairo_rectangle_int_t *extents); cairo_surface_t * (*snapshot) (void *surface); @@ -788,7 +823,8 @@ struct _cairo_surface_backend { cairo_matrix_t *stroke_ctm, cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, - cairo_antialias_t stroke_antialias); + cairo_antialias_t stroke_antialias, + cairo_rectangle_int_t *extents); cairo_surface_t * (*create_solid_pattern_surface) @@ -809,7 +845,8 @@ struct _cairo_surface_backend { const cairo_text_cluster_t *clusters, int num_clusters, cairo_text_cluster_flags_t cluster_flags, - cairo_scaled_font_t *scaled_font); + cairo_scaled_font_t *scaled_font, + cairo_rectangle_int_t *extents); }; #include "cairo-surface-private.h" @@ -820,9 +857,6 @@ struct _cairo_image_surface { pixman_format_code_t pixman_format; cairo_format_t format; unsigned char *data; - cairo_bool_t owns_data; - cairo_bool_t has_clip; - cairo_image_transparency_t transparency; int width; int height; @@ -830,6 +864,10 @@ struct _cairo_image_surface { int depth; pixman_image_t *pixman_image; + + unsigned owns_data : 1; + unsigned has_clip : 1; + unsigned transparency : 2; }; extern const cairo_private cairo_surface_backend_t _cairo_image_surface_backend; @@ -926,7 +964,8 @@ typedef struct _cairo_traps { int num_traps; int traps_size; cairo_trapezoid_t *traps; - cairo_trapezoid_t traps_embedded[1]; + /* embed enough storage for a stroked rectangle */ + cairo_trapezoid_t traps_embedded[4]; cairo_bool_t has_limits; cairo_box_t limits; @@ -1122,7 +1161,7 @@ _cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate, double *x2, double *y2, cairo_bool_t *is_tight); -cairo_private cairo_status_t +cairo_private void _cairo_gstate_path_extents (cairo_gstate_t *gstate, cairo_path_fixed_t *path, double *x1, double *y1, @@ -1175,7 +1214,7 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate, double y, cairo_bool_t *inside_ret); -cairo_private cairo_status_t +cairo_private void _cairo_gstate_in_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path, double x, @@ -1282,6 +1321,13 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, int num_glyphs, cairo_path_fixed_t *path); +cairo_private cairo_status_t +_cairo_gstate_set_antialias (cairo_gstate_t *gstate, + cairo_antialias_t antialias); + +cairo_private cairo_antialias_t +_cairo_gstate_get_antialias (cairo_gstate_t *gstate); + cairo_private cairo_bool_t _cairo_operator_bounded_by_mask (cairo_operator_t op) cairo_pure; @@ -1393,6 +1439,12 @@ _cairo_validate_text_clusters (const char *utf8, int num_clusters, cairo_text_cluster_flags_t cluster_flags); +cairo_private cairo_status_t +_cairo_intern_string (const char **str_inout, int len); + +cairo_private void +_cairo_intern_string_reset_static_data (void); + /* cairo-path-fixed.c */ cairo_private void _cairo_path_fixed_init (cairo_path_fixed_t *path); @@ -1497,7 +1549,11 @@ _cairo_path_fixed_append (cairo_path_fixed_t *path, const cairo_path_fixed_t *other, cairo_direction_t dir); -cairo_private cairo_status_t +cairo_private void +_cairo_path_fixed_approximate_extents (cairo_path_fixed_t *path, + cairo_rectangle_int_t *extents); + +cairo_private void _cairo_path_fixed_bounds (cairo_path_fixed_t *path, double *x1, double *y1, double *x2, double *y2, @@ -1518,6 +1574,18 @@ cairo_private cairo_bool_t _cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path, cairo_box_t *box); +cairo_private cairo_bool_t +_cairo_path_fixed_is_region (cairo_path_fixed_t *path); + +/* cairo-path-in-fill.c */ +cairo_private void +_cairo_path_fixed_in_fill (cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + double x, + double y, + cairo_bool_t *is_inside); + /* cairo-path-fill.c */ cairo_private cairo_status_t _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, @@ -1662,6 +1730,11 @@ cairo_private cairo_surface_t * _cairo_surface_create_in_error (cairo_status_t status); cairo_private cairo_status_t +_cairo_surface_copy_mime_data (cairo_surface_t *dst, + cairo_surface_t *src, + const char *mime_type); + +cairo_private cairo_status_t _cairo_surface_set_error (cairo_surface_t *surface, cairo_status_t status); @@ -1743,13 +1816,15 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, cairo_private cairo_status_t _cairo_surface_paint (cairo_surface_t *surface, cairo_operator_t op, - const cairo_pattern_t *source); + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents); cairo_private cairo_status_t _cairo_surface_mask (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_pattern_t *mask); + const cairo_pattern_t *mask, + cairo_rectangle_int_t *extents); cairo_private cairo_status_t _cairo_surface_fill_stroke (cairo_surface_t *surface, @@ -1765,7 +1840,8 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, cairo_matrix_t *stroke_ctm, cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, - cairo_antialias_t stroke_antialias); + cairo_antialias_t stroke_antialias, + cairo_rectangle_int_t *extents); cairo_private cairo_status_t _cairo_surface_stroke (cairo_surface_t *surface, @@ -1776,7 +1852,8 @@ _cairo_surface_stroke (cairo_surface_t *surface, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias); + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents); cairo_private cairo_status_t _cairo_surface_fill (cairo_surface_t *surface, @@ -1785,7 +1862,8 @@ _cairo_surface_fill (cairo_surface_t *surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias); + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents); cairo_private cairo_status_t _cairo_surface_show_text_glyphs (cairo_surface_t *surface, @@ -1798,7 +1876,8 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, const cairo_text_cluster_t *clusters, int num_clusters, cairo_text_cluster_flags_t cluster_flags, - cairo_scaled_font_t *scaled_font); + cairo_scaled_font_t *scaled_font, + cairo_rectangle_int_t *extents); cairo_private cairo_status_t _cairo_surface_composite_trapezoids (cairo_operator_t op, @@ -1814,6 +1893,22 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op, cairo_trapezoid_t *traps, int ntraps); +cairo_private cairo_span_renderer_t * +_cairo_surface_create_span_renderer ( + cairo_operator_t op, + const cairo_pattern_t *pattern, + cairo_surface_t *dst, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects); + +cairo_private cairo_bool_t +_cairo_surface_check_span_renderer ( + cairo_operator_t op, + const cairo_pattern_t *pattern, + cairo_surface_t *dst, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects); + cairo_private cairo_status_t _cairo_surface_acquire_source_image (cairo_surface_t *surface, cairo_image_surface_t **image_out, @@ -2082,7 +2177,7 @@ cairo_private void _cairo_pen_init_empty (cairo_pen_t *pen); cairo_private cairo_status_t -_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other); +_cairo_pen_init_copy (cairo_pen_t *pen, const cairo_pen_t *other); cairo_private void _cairo_pen_fini (cairo_pen_t *pen); @@ -2097,21 +2192,40 @@ _cairo_pen_add_points_for_slopes (cairo_pen_t *pen, cairo_point_t *c, cairo_point_t *d); -cairo_private void -_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen, - cairo_slope_t *slope, - int *active); +cairo_private int +_cairo_pen_find_active_cw_vertex_index (const cairo_pen_t *pen, + const cairo_slope_t *slope); -cairo_private void -_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen, - cairo_slope_t *slope, - int *active); +cairo_private int +_cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen, + const cairo_slope_t *slope); + +typedef struct _cairo_pen_stroke_spline { + cairo_pen_t pen; + cairo_spline_t spline; + cairo_polygon_t polygon; + cairo_point_t last_point; + cairo_point_t forward_hull_point; + cairo_point_t backward_hull_point; + int forward_vertex; + int backward_vertex; +} cairo_pen_stroke_spline_t; + +cairo_private cairo_int_status_t +_cairo_pen_stroke_spline_init (cairo_pen_stroke_spline_t *stroker, + const cairo_pen_t *pen, + const cairo_point_t *a, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d); cairo_private cairo_status_t -_cairo_pen_stroke_spline (cairo_pen_t *pen, - cairo_spline_t *spline, - double tolerance, - cairo_traps_t *traps); +_cairo_pen_stroke_spline (cairo_pen_stroke_spline_t *pen, + double tolerance, + cairo_traps_t *traps); + +cairo_private void +_cairo_pen_stroke_spline_fini (cairo_pen_stroke_spline_t *stroker); /* cairo-polygon.c */ cairo_private void @@ -2121,6 +2235,12 @@ cairo_private void _cairo_polygon_fini (cairo_polygon_t *polygon); cairo_private void +_cairo_polygon_add_edge (cairo_polygon_t *polygon, + const cairo_point_t *p1, + const cairo_point_t *p2, + int dir); + +cairo_private void _cairo_polygon_move_to (cairo_polygon_t *polygon, const cairo_point_t *point); @@ -2134,14 +2254,16 @@ _cairo_polygon_close (cairo_polygon_t *polygon); #define _cairo_polygon_status(P) (P)->status /* cairo-spline.c */ -cairo_private cairo_int_status_t +typedef void (*cairo_add_point_func_t) (void*, const cairo_point_t *); + +cairo_private cairo_bool_t _cairo_spline_init (cairo_spline_t *spline, - const cairo_point_t *a, - const cairo_point_t *b, - const cairo_point_t *c, - const cairo_point_t *d); + cairo_add_point_func_t add_point_func, + void *closure, + const cairo_point_t *a, const cairo_point_t *b, + const cairo_point_t *c, const cairo_point_t *d); -cairo_private cairo_status_t +cairo_private void _cairo_spline_decompose (cairo_spline_t *spline, double tolerance); cairo_private void @@ -2193,7 +2315,9 @@ _cairo_matrix_transformed_circle_major_axis(cairo_matrix_t *matrix, double radiu cairo_private void _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, - pixman_transform_t *pixman_transform); + pixman_transform_t *pixman_transform, + double xc, + double yc); /* cairo-traps.c */ cairo_private void @@ -2363,15 +2487,18 @@ cairo_private cairo_status_t _cairo_pattern_get_extents (const cairo_pattern_t *pattern, cairo_rectangle_int_t *extents); -cairo_private void -_cairo_pattern_reset_static_data (void); +cairo_private unsigned long +_cairo_pattern_hash (const cairo_pattern_t *pattern); -cairo_private cairo_status_t -_cairo_gstate_set_antialias (cairo_gstate_t *gstate, - cairo_antialias_t antialias); +cairo_private unsigned long +_cairo_pattern_size (const cairo_pattern_t *pattern); -cairo_private cairo_antialias_t -_cairo_gstate_get_antialias (cairo_gstate_t *gstate); +cairo_private cairo_bool_t +_cairo_pattern_equal (const cairo_pattern_t *a, + const cairo_pattern_t *b); + +cairo_private void +_cairo_pattern_reset_static_data (void); /* cairo-region.c */ @@ -2435,6 +2562,7 @@ 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_format_stride_for_width); slim_hidden_proto (cairo_get_current_point); slim_hidden_proto (cairo_get_line_width); slim_hidden_proto (cairo_get_matrix); @@ -2448,7 +2576,6 @@ slim_hidden_proto (cairo_image_surface_get_data); slim_hidden_proto (cairo_image_surface_get_height); slim_hidden_proto (cairo_image_surface_get_stride); slim_hidden_proto (cairo_image_surface_get_width); -slim_hidden_proto (cairo_format_stride_for_width); slim_hidden_proto (cairo_line_to); slim_hidden_proto (cairo_mask); slim_hidden_proto (cairo_matrix_init); @@ -2465,19 +2592,15 @@ slim_hidden_proto (cairo_matrix_translate); slim_hidden_proto (cairo_move_to); slim_hidden_proto (cairo_new_path); slim_hidden_proto (cairo_paint); -slim_hidden_proto (cairo_path_extents); slim_hidden_proto (cairo_pattern_create_for_surface); slim_hidden_proto (cairo_pattern_create_rgb); 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_no_warn (cairo_pattern_reference); slim_hidden_proto (cairo_pattern_set_matrix); slim_hidden_proto (cairo_pattern_status); slim_hidden_proto (cairo_pop_group); -slim_hidden_proto (cairo_pop_group_to_source); -slim_hidden_proto (cairo_push_group); slim_hidden_proto (cairo_push_group_with_content); slim_hidden_proto (cairo_rel_line_to); slim_hidden_proto (cairo_restore); @@ -2490,23 +2613,24 @@ slim_hidden_proto (cairo_scaled_font_get_ctm); 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_text_to_glyphs); slim_hidden_proto (cairo_scaled_font_glyph_extents); slim_hidden_proto_no_warn (cairo_scaled_font_reference); slim_hidden_proto (cairo_scaled_font_status); -slim_hidden_proto (cairo_set_font_size); +slim_hidden_proto (cairo_scaled_font_text_to_glyphs); slim_hidden_proto (cairo_set_font_options); +slim_hidden_proto (cairo_set_font_size); slim_hidden_proto (cairo_set_line_cap); slim_hidden_proto (cairo_set_line_join); slim_hidden_proto (cairo_set_line_width); slim_hidden_proto (cairo_set_matrix); slim_hidden_proto (cairo_set_operator); slim_hidden_proto (cairo_set_source); -slim_hidden_proto (cairo_set_source); slim_hidden_proto (cairo_set_source_surface); +slim_hidden_proto (cairo_set_tolerance); slim_hidden_proto (cairo_status); slim_hidden_proto (cairo_stroke); slim_hidden_proto (cairo_stroke_preserve); +slim_hidden_proto (cairo_surface_copy_page); slim_hidden_proto (cairo_surface_create_similar); slim_hidden_proto (cairo_surface_destroy); slim_hidden_proto (cairo_surface_finish); @@ -2514,15 +2638,17 @@ slim_hidden_proto (cairo_surface_flush); slim_hidden_proto (cairo_surface_get_content); slim_hidden_proto (cairo_surface_get_device_offset); slim_hidden_proto (cairo_surface_get_font_options); +slim_hidden_proto (cairo_surface_get_mime_data); slim_hidden_proto (cairo_surface_get_type); slim_hidden_proto (cairo_surface_has_show_text_glyphs); slim_hidden_proto (cairo_surface_mark_dirty_rectangle); 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_copy_page); +slim_hidden_proto (cairo_surface_set_mime_data); slim_hidden_proto (cairo_surface_show_page); slim_hidden_proto (cairo_surface_status); +slim_hidden_proto (cairo_surface_write_to_png_stream); slim_hidden_proto (cairo_text_cluster_allocate); slim_hidden_proto (cairo_text_cluster_free); slim_hidden_proto (cairo_toy_font_face_create); diff --git a/src/check-doc-syntax.sh b/src/check-doc-syntax.sh index abf526da..a5c84628 100755 --- a/src/check-doc-syntax.sh +++ b/src/check-doc-syntax.sh @@ -64,7 +64,7 @@ if echo $FILES | xargs grep . /dev/null | sed -e '/<programlisting>/,/<\/program echo " '$func_regexp'" fi >&2 -note_regexp='NOTE' +note_regexp='\<NOTE\>' if echo $FILES | xargs grep "$note_regexp" /dev/null; then stat=1 echo Error: some source files contain the string 'NOTE'. diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c index 883941df..8acd91ee 100644 --- a/src/test-fallback-surface.c +++ b/src/test-fallback-surface.c @@ -79,7 +79,7 @@ _cairo_test_fallback_surface_create (cairo_content_t content, return backing; surface = malloc (sizeof (test_fallback_surface_t)); - if (surface == NULL) { + if (unlikely (surface == NULL)) { cairo_surface_destroy (backing); return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } @@ -214,6 +214,8 @@ static const cairo_surface_backend_t test_fallback_surface_backend = { NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ NULL, /* set_clip_region */ diff --git a/src/test-meta-surface.c b/src/test-meta-surface.c index f19cbd69..42bf6b0c 100644 --- a/src/test-meta-surface.c +++ b/src/test-meta-surface.c @@ -77,7 +77,7 @@ _cairo_test_meta_surface_create (cairo_content_t content, cairo_status_t status; surface = malloc (sizeof (test_meta_surface_t)); - if (surface == NULL) { + if (unlikely (surface == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto FAIL; } @@ -194,26 +194,28 @@ _test_meta_surface_get_extents (void *abstract_surface, static cairo_int_status_t _test_meta_surface_paint (void *abstract_surface, cairo_operator_t op, - const cairo_pattern_t *source) + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents) { test_meta_surface_t *surface = abstract_surface; surface->image_reflects_meta = FALSE; - return _cairo_surface_paint (surface->meta, op, source); + return _cairo_surface_paint (surface->meta, op, source, extents); } static cairo_int_status_t _test_meta_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_pattern_t *mask) + const cairo_pattern_t *mask, + cairo_rectangle_int_t *extents) { test_meta_surface_t *surface = abstract_surface; surface->image_reflects_meta = FALSE; - return _cairo_surface_mask (surface->meta, op, source, mask); + return _cairo_surface_mask (surface->meta, op, source, mask, extents); } static cairo_int_status_t @@ -225,7 +227,8 @@ _test_meta_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { test_meta_surface_t *surface = abstract_surface; @@ -234,7 +237,7 @@ _test_meta_surface_stroke (void *abstract_surface, return _cairo_surface_stroke (surface->meta, op, source, path, style, ctm, ctm_inverse, - tolerance, antialias); + tolerance, antialias, extents); } static cairo_int_status_t @@ -244,7 +247,8 @@ _test_meta_surface_fill (void *abstract_surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { test_meta_surface_t *surface = abstract_surface; @@ -252,7 +256,7 @@ _test_meta_surface_fill (void *abstract_surface, return _cairo_surface_fill (surface->meta, op, source, path, fill_rule, - tolerance, antialias); + tolerance, antialias, extents); } static cairo_bool_t @@ -274,7 +278,8 @@ _test_meta_surface_show_text_glyphs (void *abstract_surface, const cairo_text_cluster_t *clusters, int num_clusters, cairo_text_cluster_flags_t cluster_flags, - cairo_scaled_font_t *scaled_font) + cairo_scaled_font_t *scaled_font, + cairo_rectangle_int_t *extents) { test_meta_surface_t *surface = abstract_surface; @@ -284,7 +289,7 @@ _test_meta_surface_show_text_glyphs (void *abstract_surface, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags, - scaled_font); + scaled_font, extents); } @@ -308,6 +313,8 @@ static const cairo_surface_backend_t test_meta_surface_backend = { NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ _test_meta_surface_show_page, NULL, /* set_clip_region */ diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c index ba80a107..4c566470 100644 --- a/src/test-paginated-surface.c +++ b/src/test-paginated-surface.c @@ -80,7 +80,7 @@ _cairo_test_paginated_surface_create_for_data (unsigned char *data, return target; surface = malloc (sizeof (test_paginated_surface_t)); - if (surface == NULL) { + if (unlikely (surface == NULL)) { cairo_surface_destroy (target); return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } @@ -169,28 +169,30 @@ _test_paginated_surface_get_extents (void *abstract_surface, static cairo_int_status_t _test_paginated_surface_paint (void *abstract_surface, cairo_operator_t op, - const cairo_pattern_t *source) + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents) { test_paginated_surface_t *surface = abstract_surface; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return CAIRO_STATUS_SUCCESS; - return _cairo_surface_paint (surface->target, op, source); + return _cairo_surface_paint (surface->target, op, source, extents); } static cairo_int_status_t _test_paginated_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_pattern_t *mask) + const cairo_pattern_t *mask, + cairo_rectangle_int_t *extents) { test_paginated_surface_t *surface = abstract_surface; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return CAIRO_STATUS_SUCCESS; - return _cairo_surface_mask (surface->target, op, source, mask); + return _cairo_surface_mask (surface->target, op, source, mask, extents); } static cairo_int_status_t @@ -202,7 +204,8 @@ _test_paginated_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { test_paginated_surface_t *surface = abstract_surface; @@ -212,7 +215,7 @@ _test_paginated_surface_stroke (void *abstract_surface, return _cairo_surface_stroke (surface->target, op, source, path, style, ctm, ctm_inverse, - tolerance, antialias); + tolerance, antialias, extents); } static cairo_int_status_t @@ -222,7 +225,8 @@ _test_paginated_surface_fill (void *abstract_surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_rectangle_int_t *extents) { test_paginated_surface_t *surface = abstract_surface; @@ -231,7 +235,7 @@ _test_paginated_surface_fill (void *abstract_surface, return _cairo_surface_fill (surface->target, op, source, path, fill_rule, - tolerance, antialias); + tolerance, antialias, extents); } static cairo_bool_t @@ -253,7 +257,8 @@ _test_paginated_surface_show_text_glyphs (void *abstract_surface, const cairo_text_cluster_t *clusters, int num_clusters, cairo_text_cluster_flags_t cluster_flags, - cairo_scaled_font_t *scaled_font) + cairo_scaled_font_t *scaled_font, + cairo_rectangle_int_t *extents) { test_paginated_surface_t *surface = abstract_surface; @@ -264,7 +269,7 @@ _test_paginated_surface_show_text_glyphs (void *abstract_surface, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags, - scaled_font); + scaled_font, extents); } @@ -293,6 +298,8 @@ static const cairo_surface_backend_t test_paginated_surface_backend = { NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ _test_paginated_surface_set_clip_region, |